From 05e4157bedbe4f20a3efc6f147cdb5ef6f0d6f11 Mon Sep 17 00:00:00 2001 From: Vlad Mihalachi Date: Sat, 14 Mar 2015 13:11:56 +0100 Subject: [PATCH] Version 1.15 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ∙ It is a "beta" release, feel free to send you feedback on github.com! ∙ Added Save As! (and rename option) ∙ Added Replace All! ∙ The default encoding now is UTF-16 ∙ Removed donations items, if you want to donate please buy the pro version! ∙ Minor bug fixes --- .idea/dictionaries/mac.xml | 3 + app-pro/build.gradle | 10 +- app-pro/manifest-merger-release-report.txt | 188 ++++ app/build.gradle | 12 +- app/manifest-merger-release-report.txt | 238 +++++ build/intermediates/dex-cache/cache.xml | 491 +++++++-- build/intermediates/model_data.bin | Bin 520246 -> 648130 bytes libraries/FloatingActionButton/build.gradle | 6 +- .../test/BuildConfig.java | 13 + .../faizmalkani/floatingactionbutton/R.java | 27 + .../floatingactionbutton/test/R.java | 173 ++++ .../bundles/debug/AndroidManifest.xml | 2 +- .../bundles/debug/aapt/AndroidManifest.xml | 14 + .../bundles/release/AndroidManifest.xml | 2 +- .../bundles/release/aapt/AndroidManifest.xml | 14 + .../aidl/androidTest/debug/dependency.store | Bin 0 -> 5 bytes .../mergeAssets/androidTest/debug/merger.xml | 2 + .../androidTest/debug/merger.xml | 2 + .../androidTest/debug/AndroidManifest.xml | 20 + .../tmp/manifestMerger1204657370108759986.xml | 16 + .../tmp/manifestMerger5288530001266894344.xml | 16 + .../tmp/manifestMerger7191608954865808767.xml | 16 + .../res/androidTest/debug/values/values.xml | 4 + .../symbols/androidTest/debug/R.txt | 13 + .../aar/FloatingActionButton-debug.aar | Bin 6437 -> 6872 bytes .../aar/FloatingActionButton-release.aar | Bin 6370 -> 6805 bytes libraries/RootCommands/build.gradle | 6 +- libraries/sharedCode/build.gradle | 9 +- .../turboeditor/activity/MainActivity.java | 306 +++--- .../dialogfragment/EncodingDialog.java | 1 + .../dialogfragment/FindTextDialog.java | 2 +- .../dialogfragment/NewFileDetailsDialog.java | 35 +- .../dialogfragment/SaveFileDialog.java | 2 +- .../sharedcode/turboeditor/iab/Donation.java | 78 -- .../turboeditor/iab/DonationAdapter.java | 98 -- .../turboeditor/iab/DonationFragment.java | 370 ------- .../turboeditor/iab/DonationItems.java | 53 - .../turboeditor/iab/utils/Base64.java | 582 ----------- .../turboeditor/iab/utils/IabException.java | 54 - .../turboeditor/iab/utils/IabHelper.java | 966 ------------------ .../turboeditor/iab/utils/IabResult.java | 63 -- .../turboeditor/iab/utils/Inventory.java | 110 -- .../turboeditor/iab/utils/Purchase.java | 98 -- .../turboeditor/iab/utils/Security.java | 124 --- .../turboeditor/iab/utils/SkuDetails.java | 76 -- .../PreferenceChangeType.java} | 21 +- .../preferences/PreferenceHelper.java | 2 +- .../preferences/SettingsFragment.java | 42 +- .../turboeditor/task/SaveFileTask.java | 3 +- .../turboeditor/texteditor/LineUtils.java | 4 +- .../turboeditor/texteditor/Patterns.java | 8 +- .../turboeditor/texteditor/SearchResult.java | 5 +- .../turboeditor/util/EventBusEvents.java | 115 --- .../turboeditor/util/ProCheckUtils.java | 11 +- .../turboeditor/views/DialogHelper.java | 6 - .../src/main/res/layout/activity_home.xml | 29 +- .../dialog_fragment_new_file_details.xml | 10 + .../src/main/res/layout/donation_dialog.xml | 89 -- .../src/main/res/layout/donation_iab_item.xml | 50 - .../src/main/res/layout/fragment_settings.xml | 15 - .../src/main/res/menu/fragment_editor.xml | 21 +- .../main/res/menu/fragment_editor_search.xml | 5 + .../sharedCode/src/main/res/raw/changelog.xml | 15 + .../src/main/res/values-de-rDE/strings.xml | 4 +- .../res/values-de-rDE/strings_dialogs.xml | 10 +- .../res/values-de-rDE/strings_donation.xml | 24 +- .../src/main/res/values-es-rES/strings.xml | 2 +- .../res/values-es-rES/strings_donation.xml | 2 +- .../src/main/res/values-fi-rFI/strings.xml | 4 +- .../res/values-fi-rFI/strings_dialogs.xml | 4 +- .../res/values-fi-rFI/strings_donation.xml | 2 +- .../src/main/res/values-hi-rIN/strings.xml | 10 +- .../src/main/res/values-hu-rHU/strings.xml | 16 +- .../res/values-hu-rHU/strings_dialogs.xml | 14 +- .../res/values-hu-rHU/strings_donation.xml | 26 +- .../src/main/res/values-in-rID/strings.xml | 62 +- .../res/values-in-rID/strings_dialogs.xml | 21 +- .../res/values-in-rID/strings_donation.xml | 27 +- .../src/main/res/values-pl-rPL/strings.xml | 18 +- .../res/values-pl-rPL/strings_dialogs.xml | 4 +- .../res/values-pl-rPL/strings_donation.xml | 4 +- .../src/main/res/values-pt-rBR/strings.xml | 4 +- .../src/main/res/values-ru-rRU/strings.xml | 8 +- .../res/values-ru-rRU/strings_donation.xml | 24 +- .../src/main/res/values-sk-rSK/strings.xml | 229 ++--- .../strings_dialogs.xml} | 57 +- .../res/values-sk-rSK/strings_donation.xml | 37 + .../src/main/res/values-sv-rSE/strings.xml | 90 +- .../res/values-sv-rSE/strings_dialogs.xml | 14 +- .../res/values-sv-rSE/strings_donation.xml | 37 - .../res/values-tr-rTR/strings_dialogs.xml | 9 +- .../res/values-tr-rTR/strings_donation.xml | 4 +- .../src/main/res/values-uk-rUA/strings.xml | 102 +- .../res/values-uk-rUA/strings_dialogs.xml | 18 +- .../res/values-uk-rUA/strings_donation.xml | 26 +- .../sharedCode/src/main/res/values/ids.xml | 4 + .../src/main/res/values/strings.xml | 3 + 97 files changed, 1897 insertions(+), 3789 deletions(-) create mode 100644 .idea/dictionaries/mac.xml create mode 100644 app-pro/manifest-merger-release-report.txt create mode 100644 app/manifest-merger-release-report.txt create mode 100644 libraries/FloatingActionButton/build/generated/source/buildConfig/androidTest/debug/com/faizmalkani/floatingactionbutton/test/BuildConfig.java create mode 100644 libraries/FloatingActionButton/build/generated/source/r/androidTest/debug/com/faizmalkani/floatingactionbutton/R.java create mode 100644 libraries/FloatingActionButton/build/generated/source/r/androidTest/debug/com/faizmalkani/floatingactionbutton/test/R.java create mode 100644 libraries/FloatingActionButton/build/intermediates/bundles/debug/aapt/AndroidManifest.xml create mode 100644 libraries/FloatingActionButton/build/intermediates/bundles/release/aapt/AndroidManifest.xml create mode 100644 libraries/FloatingActionButton/build/intermediates/incremental/aidl/androidTest/debug/dependency.store create mode 100644 libraries/FloatingActionButton/build/intermediates/incremental/mergeAssets/androidTest/debug/merger.xml create mode 100644 libraries/FloatingActionButton/build/intermediates/incremental/mergeResources/androidTest/debug/merger.xml create mode 100644 libraries/FloatingActionButton/build/intermediates/manifests/androidTest/debug/AndroidManifest.xml create mode 100644 libraries/FloatingActionButton/build/intermediates/manifests/tmp/manifestMerger1204657370108759986.xml create mode 100644 libraries/FloatingActionButton/build/intermediates/manifests/tmp/manifestMerger5288530001266894344.xml create mode 100644 libraries/FloatingActionButton/build/intermediates/manifests/tmp/manifestMerger7191608954865808767.xml create mode 100644 libraries/FloatingActionButton/build/intermediates/res/androidTest/debug/values/values.xml create mode 100644 libraries/FloatingActionButton/build/intermediates/symbols/androidTest/debug/R.txt delete mode 100644 libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/Donation.java delete mode 100644 libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/DonationAdapter.java delete mode 100644 libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/DonationFragment.java delete mode 100644 libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/DonationItems.java delete mode 100644 libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/utils/Base64.java delete mode 100644 libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/utils/IabException.java delete mode 100644 libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/utils/IabHelper.java delete mode 100644 libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/utils/IabResult.java delete mode 100644 libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/utils/Inventory.java delete mode 100644 libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/utils/Purchase.java delete mode 100644 libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/utils/Security.java delete mode 100644 libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/utils/SkuDetails.java rename libraries/sharedCode/src/main/java/sharedcode/turboeditor/{iab/utils/Base64DecoderException.java => preferences/PreferenceChangeType.java} (65%) delete mode 100644 libraries/sharedCode/src/main/java/sharedcode/turboeditor/util/EventBusEvents.java delete mode 100644 libraries/sharedCode/src/main/res/layout/donation_dialog.xml delete mode 100644 libraries/sharedCode/src/main/res/layout/donation_iab_item.xml rename libraries/sharedCode/src/main/res/{values/integers.xml => values-sk-rSK/strings_dialogs.xml} (50%) create mode 100644 libraries/sharedCode/src/main/res/values-sk-rSK/strings_donation.xml delete mode 100644 libraries/sharedCode/src/main/res/values-sv-rSE/strings_donation.xml diff --git a/.idea/dictionaries/mac.xml b/.idea/dictionaries/mac.xml new file mode 100644 index 0000000..e6a791d --- /dev/null +++ b/.idea/dictionaries/mac.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/app-pro/build.gradle b/app-pro/build.gradle index de9601e..0a81e4c 100644 --- a/app-pro/build.gradle +++ b/app-pro/build.gradle @@ -20,15 +20,15 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 21 - buildToolsVersion '21.1.2' + compileSdkVersion 22 + buildToolsVersion '22' defaultConfig { applicationId "com.maskyn.fileeditorpro" minSdkVersion 11 - targetSdkVersion 21 - versionCode 35 - versionName "1.13.2" + targetSdkVersion 22 + versionCode 39 + versionName "1.15.1" } compileOptions { diff --git a/app-pro/manifest-merger-release-report.txt b/app-pro/manifest-merger-release-report.txt new file mode 100644 index 0000000..d568c69 --- /dev/null +++ b/app-pro/manifest-merger-release-report.txt @@ -0,0 +1,188 @@ +-- Merging decision tree log --- +manifest +ADDED from AndroidManifest.xml:20:1 + xmlns:android + ADDED from AndroidManifest.xml:20:11 + package + ADDED from AndroidManifest.xml:21:5 + INJECTED from AndroidManifest.xml:0:0 + INJECTED from AndroidManifest.xml:0:0 + android:versionName + INJECTED from AndroidManifest.xml:0:0 + INJECTED from AndroidManifest.xml:0:0 + android:versionCode + INJECTED from AndroidManifest.xml:0:0 + INJECTED from AndroidManifest.xml:0:0 + android:installLocation + ADDED from AndroidManifest.xml:22:5 +uses-permission#android.permission.WRITE_EXTERNAL_STORAGE +ADDED from AndroidManifest.xml:24:5 + android:name + ADDED from AndroidManifest.xml:24:22 +uses-permission#android.permission.ACCESS_SUPERUSER +ADDED from AndroidManifest.xml:25:5 + android:name + ADDED from AndroidManifest.xml:25:22 +supports-screens +ADDED from AndroidManifest.xml:27:5 + android:resizeable + ADDED from AndroidManifest.xml:31:9 + android:largeScreens + ADDED from AndroidManifest.xml:29:9 + android:anyDensity + ADDED from AndroidManifest.xml:28:9 + android:normalScreens + ADDED from AndroidManifest.xml:30:9 + android:xlargeScreens + ADDED from AndroidManifest.xml:33:9 + android:smallScreens + ADDED from AndroidManifest.xml:32:9 +application +ADDED from AndroidManifest.xml:35:5 +MERGED from turbo-editor.libraries:RootCommands:unspecified:11:5 +MERGED from turbo-editor.libraries:FloatingActionButton:unspecified:11:5 +MERGED from com.android.support:appcompat-v7:21.0.3:16:5 +MERGED from com.android.support:support-v4:21.0.3:16:5 +MERGED from com.github.gabrielemariotti.changeloglib:library:1.5.1:11:5 + android:supportsRtl + ADDED from AndroidManifest.xml:41:9 + android:label + ADDED from AndroidManifest.xml:38:9 + android:allowBackup + ADDED from AndroidManifest.xml:36:9 + android:icon + ADDED from AndroidManifest.xml:37:9 + android:hardwareAccelerated + ADDED from AndroidManifest.xml:39:9 + android:largeHeap + ADDED from AndroidManifest.xml:40:9 + android:name + ADDED from AndroidManifest.xml:42:9 +activity#com.maskyn.fileeditorpro.HomeActivity +ADDED from AndroidManifest.xml:47:9 + android:windowSoftInputMode + ADDED from AndroidManifest.xml:51:13 + android:configChanges + ADDED from AndroidManifest.xml:49:13 + android:theme + ADDED from AndroidManifest.xml:52:13 + android:name + ADDED from AndroidManifest.xml:48:13 + android:launchMode + ADDED from AndroidManifest.xml:50:13 +intent-filter#android.intent.action.MAIN+android.intent.category.LAUNCHER+android.intent.category.MULTIWINDOW_LAUNCHER +ADDED from AndroidManifest.xml:53:13 +action#android.intent.action.MAIN +ADDED from AndroidManifest.xml:54:17 + android:name + ADDED from AndroidManifest.xml:54:25 +category#android.intent.category.LAUNCHER +ADDED from AndroidManifest.xml:56:17 + android:name + ADDED from AndroidManifest.xml:56:27 +category#android.intent.category.MULTIWINDOW_LAUNCHER +ADDED from AndroidManifest.xml:57:17 + android:name + ADDED from AndroidManifest.xml:57:27 +intent-filter#android.intent.action.EDIT+android.intent.action.PICK+android.intent.action.VIEW+android.intent.category.BROWSABLE+android.intent.category.DEFAULT +ADDED from AndroidManifest.xml:59:13 +action#android.intent.action.VIEW +ADDED from AndroidManifest.xml:60:17 + android:name + ADDED from AndroidManifest.xml:60:25 +action#android.intent.action.EDIT +ADDED from AndroidManifest.xml:61:17 + android:name + ADDED from AndroidManifest.xml:61:25 +action#android.intent.action.PICK +ADDED from AndroidManifest.xml:62:17 + android:name + ADDED from AndroidManifest.xml:62:25 +category#android.intent.category.DEFAULT +ADDED from AndroidManifest.xml:64:17 + android:name + ADDED from AndroidManifest.xml:64:27 +category#android.intent.category.BROWSABLE +ADDED from AndroidManifest.xml:65:17 + android:name + ADDED from AndroidManifest.xml:65:27 +data +ADDED from AndroidManifest.xml:67:17 + android:scheme + ADDED from AndroidManifest.xml:67:23 +intent-filter#android.intent.action.SEND+android.intent.category.DEFAULT +ADDED from AndroidManifest.xml:76:13 +action#android.intent.action.SEND +ADDED from AndroidManifest.xml:77:17 + android:name + ADDED from AndroidManifest.xml:77:25 +activity#sharedcode.turboeditor.activity.SelectFileActivity +ADDED from AndroidManifest.xml:82:9 + android:label + ADDED from AndroidManifest.xml:85:13 + android:configChanges + ADDED from AndroidManifest.xml:84:13 + android:theme + ADDED from AndroidManifest.xml:87:13 + android:parentActivityName + ADDED from AndroidManifest.xml:86:13 + android:name + ADDED from AndroidManifest.xml:83:13 +meta-data#android.support.PARENT_ACTIVITY +ADDED from AndroidManifest.xml:88:13 + android:name + ADDED from AndroidManifest.xml:89:17 + android:value + ADDED from AndroidManifest.xml:90:17 +activity#sharedcode.turboeditor.preferences.ExtraSettingsActivity +ADDED from AndroidManifest.xml:93:9 + android:label + ADDED from AndroidManifest.xml:95:13 + android:parentActivityName + ADDED from AndroidManifest.xml:96:13 + android:name + ADDED from AndroidManifest.xml:94:13 +meta-data#com.sec.android.support.multiwindow +ADDED from AndroidManifest.xml:102:9 + android:name + ADDED from AndroidManifest.xml:103:13 + android:value + ADDED from AndroidManifest.xml:104:13 +meta-data#com.sec.android.multiwindow.DEFAULT_SIZE_W +ADDED from AndroidManifest.xml:105:9 + android:name + ADDED from AndroidManifest.xml:106:13 + android:value + ADDED from AndroidManifest.xml:107:13 +meta-data#com.sec.android.multiwindow.DEFAULT_SIZE_H +ADDED from AndroidManifest.xml:108:9 + android:name + ADDED from AndroidManifest.xml:109:13 + android:value + ADDED from AndroidManifest.xml:110:13 +meta-data#com.sec.android.multiwindow.MINIMUM_SIZE_W +ADDED from AndroidManifest.xml:111:9 + android:name + ADDED from AndroidManifest.xml:112:13 + android:value + ADDED from AndroidManifest.xml:113:13 +meta-data#com.sec.android.multiwindow.MINIMUM_SIZE_H +ADDED from AndroidManifest.xml:114:9 + android:name + ADDED from AndroidManifest.xml:115:13 + android:value + ADDED from AndroidManifest.xml:116:13 +uses-sdk +INJECTED from AndroidManifest.xml:0:0 reason: use-sdk injection requested +MERGED from turbo-editor.libraries:sharedCode:unspecified:25:5 +MERGED from turbo-editor.libraries:RootCommands:unspecified:7:5 +MERGED from turbo-editor.libraries:FloatingActionButton:unspecified:7:5 +MERGED from com.android.support:appcompat-v7:21.0.3:15:5 +MERGED from com.android.support:support-v4:21.0.3:15:5 +MERGED from com.github.gabrielemariotti.changeloglib:library:1.5.1:7:5 + android:targetSdkVersion + INJECTED from AndroidManifest.xml:0:0 + INJECTED from AndroidManifest.xml:0:0 + android:minSdkVersion + INJECTED from AndroidManifest.xml:0:0 + INJECTED from AndroidManifest.xml:0:0 diff --git a/app/build.gradle b/app/build.gradle index b67292b..1f58456 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -40,14 +40,14 @@ repositories { android { - compileSdkVersion 21 - buildToolsVersion '21.1.2' + compileSdkVersion 22 + buildToolsVersion '22' defaultConfig { applicationId "com.maskyn.fileeditor" minSdkVersion 11 - targetSdkVersion 21 - versionCode 35 - versionName "1.13.2" + targetSdkVersion 22 + versionCode 39 + versionName "1.15.1" } compileOptions { sourceCompatibility JavaVersion.VERSION_1_7 @@ -71,7 +71,7 @@ android { dependencies { compile fileTree(dir: 'libs', include: '*.jar') compile project(':libraries:sharedCode') - compile 'com.google.android.gms:play-services:6.1.71' + compile 'com.google.android.gms:play-services-ads:6.5.+' compile('com.crashlytics.sdk.android:crashlytics:2.+@aar') { transitive = true; } diff --git a/app/manifest-merger-release-report.txt b/app/manifest-merger-release-report.txt new file mode 100644 index 0000000..d8317cf --- /dev/null +++ b/app/manifest-merger-release-report.txt @@ -0,0 +1,238 @@ +-- Merging decision tree log --- +manifest +ADDED from AndroidManifest.xml:21:1 + xmlns:android + ADDED from AndroidManifest.xml:21:11 + package + ADDED from AndroidManifest.xml:22:5 + INJECTED from AndroidManifest.xml:0:0 + INJECTED from AndroidManifest.xml:0:0 + android:versionName + INJECTED from AndroidManifest.xml:0:0 + INJECTED from AndroidManifest.xml:0:0 + android:versionCode + INJECTED from AndroidManifest.xml:0:0 + INJECTED from AndroidManifest.xml:0:0 + android:installLocation + ADDED from AndroidManifest.xml:23:5 +uses-permission#android.permission.WRITE_EXTERNAL_STORAGE +ADDED from AndroidManifest.xml:25:5 + android:name + ADDED from AndroidManifest.xml:25:22 +uses-permission#android.permission.ACCESS_SUPERUSER +ADDED from AndroidManifest.xml:26:5 + android:name + ADDED from AndroidManifest.xml:26:22 +uses-permission#android.permission.INTERNET +ADDED from AndroidManifest.xml:27:5 +MERGED from com.crashlytics.sdk.android:crashlytics:2.2.0:11:5 + android:name + ADDED from AndroidManifest.xml:27:22 +uses-permission#android.permission.ACCESS_NETWORK_STATE +ADDED from AndroidManifest.xml:28:5 + android:name + ADDED from AndroidManifest.xml:28:22 +uses-permission#com.android.vending.BILLING +ADDED from AndroidManifest.xml:29:5 + android:name + ADDED from AndroidManifest.xml:29:22 +supports-screens +ADDED from AndroidManifest.xml:31:5 + android:resizeable + ADDED from AndroidManifest.xml:35:9 + android:largeScreens + ADDED from AndroidManifest.xml:33:9 + android:anyDensity + ADDED from AndroidManifest.xml:32:9 + android:normalScreens + ADDED from AndroidManifest.xml:34:9 + android:xlargeScreens + ADDED from AndroidManifest.xml:37:9 + android:smallScreens + ADDED from AndroidManifest.xml:36:9 +application +ADDED from AndroidManifest.xml:39:5 +MERGED from turbo-editor.libraries:RootCommands:unspecified:11:5 +MERGED from turbo-editor.libraries:FloatingActionButton:unspecified:11:5 +MERGED from com.android.support:appcompat-v7:21.0.3:16:5 +MERGED from com.android.support:support-v4:21.0.3:16:5 +MERGED from com.github.gabrielemariotti.changeloglib:library:1.5.1:11:5 +MERGED from com.google.android.gms:play-services-ads:6.5.87:19:5 +MERGED from com.google.android.gms:play-services-base:6.5.87:20:5 +MERGED from com.android.support:support-v4:21.0.3:16:5 +MERGED from com.crashlytics.sdk.android:crashlytics:2.2.0:13:5 +MERGED from com.crashlytics.sdk.android:answers:1.1.0:11:5 +MERGED from io.fabric.sdk.android:fabric:1.1.0:11:5 +MERGED from com.crashlytics.sdk.android:beta:1.1.0:11:5 +MERGED from io.fabric.sdk.android:fabric:1.1.0:11:5 +MERGED from io.fabric.sdk.android:fabric:1.1.0:11:5 + android:supportsRtl + ADDED from AndroidManifest.xml:45:9 + android:label + ADDED from AndroidManifest.xml:42:9 + android:allowBackup + ADDED from AndroidManifest.xml:40:9 + android:icon + ADDED from AndroidManifest.xml:41:9 + android:hardwareAccelerated + ADDED from AndroidManifest.xml:43:9 + android:largeHeap + ADDED from AndroidManifest.xml:44:9 + android:name + ADDED from AndroidManifest.xml:46:9 +meta-data#com.google.android.gms.version +ADDED from AndroidManifest.xml:51:9 +MERGED from com.google.android.gms:play-services-base:6.5.87:21:9 + android:name + ADDED from AndroidManifest.xml:51:20 + android:value + ADDED from AndroidManifest.xml:52:13 +activity#com.maskyn.fileeditor.HomeActivity +ADDED from AndroidManifest.xml:53:9 + android:windowSoftInputMode + ADDED from AndroidManifest.xml:57:13 + android:configChanges + ADDED from AndroidManifest.xml:55:13 + android:theme + ADDED from AndroidManifest.xml:58:13 + android:name + ADDED from AndroidManifest.xml:54:13 + android:launchMode + ADDED from AndroidManifest.xml:56:13 +intent-filter#android.intent.action.MAIN+android.intent.category.LAUNCHER+android.intent.category.MULTIWINDOW_LAUNCHER +ADDED from AndroidManifest.xml:59:13 +action#android.intent.action.MAIN +ADDED from AndroidManifest.xml:60:17 + android:name + ADDED from AndroidManifest.xml:60:25 +category#android.intent.category.LAUNCHER +ADDED from AndroidManifest.xml:62:17 + android:name + ADDED from AndroidManifest.xml:62:27 +category#android.intent.category.MULTIWINDOW_LAUNCHER +ADDED from AndroidManifest.xml:63:17 + android:name + ADDED from AndroidManifest.xml:63:27 +intent-filter#android.intent.action.EDIT+android.intent.action.PICK+android.intent.action.VIEW+android.intent.category.BROWSABLE+android.intent.category.DEFAULT +ADDED from AndroidManifest.xml:65:13 +action#android.intent.action.VIEW +ADDED from AndroidManifest.xml:66:17 + android:name + ADDED from AndroidManifest.xml:66:25 +action#android.intent.action.EDIT +ADDED from AndroidManifest.xml:67:17 + android:name + ADDED from AndroidManifest.xml:67:25 +action#android.intent.action.PICK +ADDED from AndroidManifest.xml:68:17 + android:name + ADDED from AndroidManifest.xml:68:25 +category#android.intent.category.DEFAULT +ADDED from AndroidManifest.xml:70:17 + android:name + ADDED from AndroidManifest.xml:70:27 +category#android.intent.category.BROWSABLE +ADDED from AndroidManifest.xml:71:17 + android:name + ADDED from AndroidManifest.xml:71:27 +data +ADDED from AndroidManifest.xml:73:17 + android:scheme + ADDED from AndroidManifest.xml:73:23 +intent-filter#android.intent.action.SEND+android.intent.category.DEFAULT +ADDED from AndroidManifest.xml:82:13 +action#android.intent.action.SEND +ADDED from AndroidManifest.xml:83:17 + android:name + ADDED from AndroidManifest.xml:83:25 +activity#sharedcode.turboeditor.activity.SelectFileActivity +ADDED from AndroidManifest.xml:88:9 + android:label + ADDED from AndroidManifest.xml:91:13 + android:configChanges + ADDED from AndroidManifest.xml:90:13 + android:theme + ADDED from AndroidManifest.xml:93:13 + android:parentActivityName + ADDED from AndroidManifest.xml:92:13 + android:name + ADDED from AndroidManifest.xml:89:13 +meta-data#android.support.PARENT_ACTIVITY +ADDED from AndroidManifest.xml:94:9 + android:name + ADDED from AndroidManifest.xml:95:13 + android:value + ADDED from AndroidManifest.xml:96:13 +activity#sharedcode.turboeditor.preferences.ExtraSettingsActivity +ADDED from AndroidManifest.xml:99:9 + android:label + ADDED from AndroidManifest.xml:101:13 + android:parentActivityName + ADDED from AndroidManifest.xml:102:13 + android:name + ADDED from AndroidManifest.xml:100:13 +meta-data#com.sec.android.support.multiwindow +ADDED from AndroidManifest.xml:108:9 + android:name + ADDED from AndroidManifest.xml:109:13 + android:value + ADDED from AndroidManifest.xml:110:13 +meta-data#com.sec.android.multiwindow.DEFAULT_SIZE_W +ADDED from AndroidManifest.xml:111:9 + android:name + ADDED from AndroidManifest.xml:112:13 + android:value + ADDED from AndroidManifest.xml:113:13 +meta-data#com.sec.android.multiwindow.DEFAULT_SIZE_H +ADDED from AndroidManifest.xml:114:9 + android:name + ADDED from AndroidManifest.xml:115:13 + android:value + ADDED from AndroidManifest.xml:116:13 +meta-data#com.sec.android.multiwindow.MINIMUM_SIZE_W +ADDED from AndroidManifest.xml:117:9 + android:name + ADDED from AndroidManifest.xml:118:13 + android:value + ADDED from AndroidManifest.xml:119:13 +meta-data#com.sec.android.multiwindow.MINIMUM_SIZE_H +ADDED from AndroidManifest.xml:120:9 + android:name + ADDED from AndroidManifest.xml:121:13 + android:value + ADDED from AndroidManifest.xml:122:13 +activity#com.google.android.gms.ads.AdActivity +ADDED from AndroidManifest.xml:124:9 + android:configChanges + ADDED from AndroidManifest.xml:125:13 + android:name + ADDED from AndroidManifest.xml:124:19 +meta-data#com.crashlytics.ApiKey +ADDED from AndroidManifest.xml:126:9 + android:name + ADDED from AndroidManifest.xml:126:20 + android:value + ADDED from AndroidManifest.xml:126:58 +uses-sdk +INJECTED from AndroidManifest.xml:0:0 reason: use-sdk injection requested +MERGED from turbo-editor.libraries:sharedCode:unspecified:25:5 +MERGED from turbo-editor.libraries:RootCommands:unspecified:7:5 +MERGED from turbo-editor.libraries:FloatingActionButton:unspecified:7:5 +MERGED from com.android.support:appcompat-v7:21.0.3:15:5 +MERGED from com.android.support:support-v4:21.0.3:15:5 +MERGED from com.github.gabrielemariotti.changeloglib:library:1.5.1:7:5 +MERGED from com.google.android.gms:play-services-ads:6.5.87:18:5 +MERGED from com.google.android.gms:play-services-base:6.5.87:18:5 +MERGED from com.android.support:support-v4:21.0.3:15:5 +MERGED from com.crashlytics.sdk.android:crashlytics:2.2.0:7:5 +MERGED from com.crashlytics.sdk.android:answers:1.1.0:7:5 +MERGED from io.fabric.sdk.android:fabric:1.1.0:7:5 +MERGED from com.crashlytics.sdk.android:beta:1.1.0:7:5 +MERGED from io.fabric.sdk.android:fabric:1.1.0:7:5 +MERGED from io.fabric.sdk.android:fabric:1.1.0:7:5 + android:targetSdkVersion + INJECTED from AndroidManifest.xml:0:0 + INJECTED from AndroidManifest.xml:0:0 + android:minSdkVersion + INJECTED from AndroidManifest.xml:0:0 + INJECTED from AndroidManifest.xml:0:0 diff --git a/build/intermediates/dex-cache/cache.xml b/build/intermediates/dex-cache/cache.xml index bf62108..25c48a6 100644 --- a/build/intermediates/dex-cache/cache.xml +++ b/build/intermediates/dex-cache/cache.xml @@ -1,96 +1,397 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build/intermediates/model_data.bin b/build/intermediates/model_data.bin index 4df665b9ec612507d984e15f5ae19b44d357eaf8..6036517976f6b6a9b520eb3b1476f633d85d0a98 100644 GIT binary patch literal 648130 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�M z8}u9e9L!5)=WnE=W;(^~XHN4y9kF$LXUxet z!g^|z=cQE_5-Jra>Hb%Eg|EDjRH_8}Zrf&nUj;7Thx2~T6$h(I7(!))A4U3Mw2m5) z8^Eg9;9rxk$J_$M8!AAx2+;bdXnN&<|x(T(*!b{ zeB64f#K%is>+&lJKZRC3gFVmoicH5Ue3WPTYON<+em+~TRa(g}$SbyTr}|R5W~&_y zy&H)j%sGtk$cmu#a?Pbc-O1i!^pxMT?{lmjd^SO=O$b8~vBRFT?*V?!pnOA<(!!y1g(7Gm)>3E&-al( z<*vM0g2_Eo?KQl!+YF7_bf1W1bN%)q`@TTy-s@@xT|Ln_jaIaA?g94vu2$+F%UK-9Qs(r z>g3>j)3)2d(e##!xUrJ7Y0IfD$0eFL&T_7BA-7f!P=NsjBaEA^cMgJ$ z$(AiSktoQQ!lYViwJ?md7||ZhDvxF{$Ays~fg93o_tkZMzLer`SKFAu&ok}v?onYf zG|iBPRQapo>II-0Z)C8>GcU+{koOh)63qF+_SKN;tMg$H4e}PEtQiX{;&G+=0C}A+ z#-g`sOj;tBQKlAD2Vuuj0B|>iKDcP5hNNY_8B_p|qp(jp)LejJkoN>8+@>FXa>tLh z{bAVKWd18if`qm*8^nLrqYk`j0a&mZAWnkpNRX%iET5dVQ=`e{MuAwCAl4VeI{?`N zp1WkJ9|4{a{MXL{|4T#`utY+0T|zk#rYTHNUZ&2T?Drcb2a82Epcj?2ea28CL#C?L;>*!xpQAY-cQ))PGt9UC!sbc07RY~ z8fFvO&zryS7@oek9AWmEaMy|`Zj^IxDdRx&kD@Ta{d(vf$lFy{Y~Pqwe>WJei~u+* z9Ad`Lp#j@Jys)+4O(@!cG#}wjVoPde%Jq*-D|V%U2?u;Tmk;io4RcH-6A_Rs0US$5 zO!#-r1}SG6f_1>5-@hAqIsJ7C^VLn?ze)n^qj_5I{T=cuo z2SafZ5An1qHCmU>qC%5D7G=oe48y!&MkEJtz}-YtcM+LID5mkC*kRIuGQ;UG0Pxvl zDYoe`L}bDgKGpaXvI+S{jS3jFZUzw@otcXDGsrVLJc)#;S|)2?faQ%4E@RLoVarWj zCGAI_GAT$Gf{>SU9Mt2;Oe^_)GP)LDZD90OfD#O8ywWg(nk`IP#ar=A(wD>|C@PR& z%~c#go!T!Y(sR_v9-RQz(F`;1vF)P|;R_~zzF*6oFDSfPd2_y2DahUfhE0V8A+j6^HMfGELWePqiI*xKhEz!aA*_{?>x;~oSr<_{FRwz4clHLe zf?8x@&}$$0w4tMiV-wOphvutPV-w`{jpw5{Ekn63DPLfrlWI*o`HV3N=q7)q0ofz_ zdUn8>wF#=KK}%XoRFzufomKY%7FOm^ zN}W}S{9#qrW@&2OSpB%KgVPYH?z*Xw-%R%cbJq#i2iXv8`t7OYFxp_?)it)q?!MZxfi$(YM3u2RT7Y7XIvgs|K% z+Go;QoTgM>5tbygxc7xX7l{jHnkCqt+J0#Il}-NWay@-g7!j*mJb=RPP!~ZXsko{* zpF;%gQM}nj5j5mA96TE~Aoyg3iU-e{514(+1*u;!sG3?qFyvY(Q1vi%&yinU=yW=5gc0W|PQ92eYH@-FG1{Ly4i?;-W`k ziU6Dof#D3mXK&>Y*pD?J6H*_hALoR?dcGgKV3!)NG3X!Fq8K1ZSAG%zz_~%f+;C7?KJ6PR6vh8(`5)9Zq9fnO@Ab@+SP2 z+Q1}^rH|cgjviaI7`xJ^5Vb;gCKzZ)wS^efqX4m?#YD2OZHqCge|Df^RLJ|BJ)Ty& zB!fqa47a2yxJ2r=X*9A)kfZZlDfeAw9OW=RlRj-w(!E&J0hJHehZ{i1(-9@1DoUG zRu?Y5#-hgutu#zbu6L0x7wN)vO)k>qB3%?=#7TrqB5=E^i9|SAUD;txe|a)LfOht7 zq)yG-ty*>LsuW{6J0&eZXuL}C{bJCSD~~J!%29|OFEUTl>D)6@Ps)#?a7!dJ#}~ zS7;#t18T=G$15hLc2r?n){mMBVKS<@9J-EW0{W4<#GEb!7pnJ1UG?|Y2is|v3{$yv z=1Ug5q9uaKDgPQalKSf@30?n3*Z&dj0%%uw39y7YBs4CkbNwG(|Hp8kG=!J$xr%+` zT>nR*>gUP*ENS-u41+g&?zMPL zWSYyqR~{;6f{Z1S&QjlsuP~kfAPZnujW>4HcqPzTa0-dgP1054xfrEuU-<;Yg&@g8 z3ogv;zz~xLC13soIl%aXJ6LW$UmK`VN` zaNwgQR=vXq&iM_S_&xsM2tS31lxR79yl(|URc+ZauW9gaKTn>iRmix zZuyG5Pd6YD3M=xMXmT}qxZblw7{%4(K?35V|Jc>!9o(9{&om%sWFHN$$z#H$3srgV z=4tj!Cv|msU9ZdAX@E^Lm6(;N#n4Ya(~Y@q-h>xZ8=6$+nMQA=$);GFXPQJS#fi{O zQXCt+1+#d`RX?t=hvcKbZ-|p*W@vl$d5`{WSD#0b6O@Ru5O8w!d2(ceq@L;MVNDeC z$`?8hx{&%j@yK?e9Zj<`19|UNR0p1BJzFGKl~!rk-__`Ou13$nw>kK>oTLm>D@Pu} z=HO%wzDwcW^)&%NtxS5T*J2$h-4Y?^N$8}yG^U@Ucd8O}*DT+d?fg`_@TQqnF@_v5C6;Pt{NLZ<5q?1mc#v~?2qWm>+ zQ9>J+Bfp!wsKd<|GxF4=sms5j4JwX&D|eE|4OKOn`$8=VDG^1N=YR={{U#_m8^*xH zBc-xcpeBZT^lSCeC2@ZVTbO4tM*R}Dx=_Mn*5gv_Mkq1WqAx-USE(g`yul^o>GK7z z8y8$o4(WSJtxMz`P3eogrb)UC5IS=wDfY5*l4|{CYCbqC<8i6=)(amcpPC!PkT17h z^eCOD!~(!l>;Cf%9-TOq6ix3k)N+u=y(clIH zW8-=7Wxr}%Hd|qiil(zMhr*K)LhFrx$Y+$PV|-u%gU?){Ti<4`l;B)2&K`S#lX+q! zbA1zn!$dL&%kkHsLH>dxMQ1{n4wir!v~-#qSW^19pGI)_;yhVRY~gwi-xwiD_23*n zPoI&-PXCtbnn&Ml&@~^pc?60*Pr|?VAy3mnATCg5RIEpe_rsMj3U}0kQm`Us^4(9u zXn?`Uh|(%nyRT0+H^V(r48E!|@J3;!drBlI<5>*>N^?K0X(!}*7^-_r+e^OHDl18I8193z9NvrSY^%{iXEKoTIZReqjwD@5LL;F1uF`Wm z8^K^T?8hVMOd}i(t$A@ZN{Cv9P8AO{t9_N!cIKC@gEE3rQm^FK51>D++ z9d`BmD476k*I9R?A^z;XqwcHxn(3CK?h_4di0Y&xO|V_88pSw=qz1KCRyb}g-L_vl zPvThW8Z95`YP7nU06kxH(|RuQjteyIP{g`fvUXAJtzV)GJG<27sC6?5AN&Y)PX%sv zr#q?$HxpUpo7{5jy590d9=qm?>Aq6@o8453Hyc$zRMptUuU-7Q&G_}5(16s%ujNo( zak$YOvMEkulE)DP^L$Jauyyh4;TDa_x%hQ)IuYc%xcD{3*R#ZIUHsa+8`8qOJxFM% zJ${{^B+=FQHALNA{928#XNebW*Q3;LtH<5;@6{i$=L>Gyw+C_-tBjqAVK+y~F1qtR zR=X{l@=b^1*!AZr@Ktxujn~``chrSfzu%H?Zp-ewsIjxzdDq>C9`2^=uKvO%&ReS6 z4wr(wS*t?DHXZx|yeR#A?C%6ONAWfd_wr2D_h8-r<^s|1E7hYc`(uO)JRr$BCkU<2 zLwJwXqx>Ps=6#U-x$xYN;Hh{gNIeQRJfL1g^OqDSiwdLQ47&4v7+o2zhDib#;?y^A zZiwQ2AtN;^Pk$kgFE73P%j@`g~D|>T!4UyhxilZy>8rra@#ABkS#zP;Ho-6@u85v8z$`M zwZI>wC&5}bH09I@b#T2Fq0BM(yg4_v*!wBZ9=4TyS}x#xShz)b9o-ViPU~$4`w8AD za@QblO(owfEFdK4Vo|O+2gtXJSEvh1lAwQ{)CDn71^pM+ghjGf*3o1Tj@T(ome3^L z7%c{a5Ei@?g&VPtJ31_#k48QM0l3`9V*AVlq0w+@0~gdWqI^mvid{m$SQ(CRnlqFq zvouL@HrVu`tcAO3u}C;}ELSkVUGR(Q6bWrBNH$XM39~1?_|u8!$vE>;@wqJMLL#Bi^fNZtKw!UUGfr;&KTa;R6rg(*&**w z{Rv$nHM{5ms^44|SA2UVbcrkPo+qf;o$jbNsQ!d5ag$s22-Tm^B`#)}UUs|yy?gCQ zJ{0q-s9RMI^(S<(LkKBwwr5gTr&Rm%68gHng`LRX^*`Cg7ahW)r-y8RqQ1!uhpsDxCGF zHxaIypQgF+b?hYnQPq)K($}2hVzxVKrQa}5`l7+roVCGw!1Yhl{IwjAwpq7wziu(vzWWx66sJ(W9|FmUan8Z<55h|7euOS$IyP!NFnAbEG4~2Sjmip zUdJ*o54JJDgt)|y+0XbC=VR61TOVwv_!YpopEQ174Z3EBh4M-1m?}M#35gofXz(N^ z@h{2WdAC3<^}1&h*gDUpvkOAWulB+GN>d{Ce$oZ zxon!4-YdXDL&yjti`8me)UC`}nEYAziEjSmPayBm)5trovQB<4VeM;b`{27kb*ylr zv+w0BL6a)up;GL>?4e8ZaIk2S(?Y1VcAx-q)@${k zbQBWjYORX|A13#{%yP%ctb>_JVC2rY_aV{kL;r;@S5q{I_%Z5MEQ2sluhI!n7N4em zSM3f!ly$htPpiAIRuVs^-cxnk_{lk|wdp6XH^Zj;?(zT5C03X6F@!^GbSm40so;;y z6R2!oKtbY#G%pXa>pa>G1|s|>b1KW_G@7B(z;r-IMWlWI*hkleS+H^ooK*eWpu&Aw zRpE?NvFmk`hM1~r)hH)@!))8+E;%G ztk!9YorL%3)*Sn$!Nkv^4gkKhrf$?mq32N;1-f~xTo3x&%Te^I9}mI$;B>}-6jRiU z$ls=wMusoXJZt{V<>Xu(k79Aw7iOi%a}1G+|%M`Vb?V8%v2n)Mtd5NijtHRFllY)h+rr#R#9gD0@{hLOwf2j-Dk6t z0)J2@1x!{$V5&-r&eH*7Q}pb=1#F zToYyo2(duc1N1E6hmyCY!W3u2M1aKk#?2E@&v`ei@Wdb;Q?w2fM+lSU4Y-LX2+Hr! zb&;uGQulK@riMc0XCFQ`A--LRL8*N`mv5X^Nyd} z8%JPQUPzKjCecAMeA>PsGZ<3F*3AEwr^|?32V#0X*bU+k?O%ca#Nhx>1Xtb8f@`NM zFJLkSs*F)L?8s{HJ6#_;`*;TaC{m@2P^< zo?%w0=ubf2N`3iq5DbDrsi$#3l5Jz* zwr@=E(~>;Fs8? zK7SU{ZzlNIJz4m5>VG0@UJeHl^8Re4SF(ci+1|!_74n{$a%@OALf*=hFN+CU$ot_b zze2-Wa4;&7oG!aihJdm*4%zV_Yb_LX;v4b;3q`&7YPzaQ19JI8S67Ll_^au_g>r^X z7u!E&PB^6`JFb*xi^YQU5?$4)l6=BOBD+?Wz1chRz7<|jj1cVQlzP=olJt#2J{$zQVLxE= zDLiC@V2{e&On{bN|RQVoR1c5CivArY5CqVk8y>pP?Zm%lEjZ9T{slZ zCL%Xrp+1QpBVR9}mE&g_RZ1v^0A#;q6-|YDmGN!vVJxFp2_Ikwxsce|D-ihIn)vYm zH*15z3RME~rgAoZsE857mnsi9>Tlyn1(W(0{kVi(IQHQseNReQ65^X=tU^&Ly+LtS zOBhe$TbD+CKO%z_o_6uIifWSlYQm*Np+3jnV|z}fStvx6cQ{oFC6fGJMwdeAE59gH zrtmbVFQ>FA^z%T^P$K9{2nl#}MX+YL##mC_%-&}EAirPCH?bz5*u)Ec4lpzko9y}G zJ;cu&l)OUK69!_7V?z}hw(!Q-*H^~fHGSx;SVF52zaqa{%yx7FY})e6g@S(^kNVJZ zR=x2sM}YV*p$1w$kojVMq)0GZz98H_#o|v`MLP9DuRva*_Je>`N_f-oV`a4;{4AR}^1i=_hbEB9 zL{vA3pChkO7f2sh`M$)Zx$8&afSZA=uy1dSUHktP{y6>%@W&$`p^*o@TlF#I-R+OZ zw5uu$9!z5I@JG-5AK!lOAHU;Ls{p8k!GB)^Kh zN7CrR(i+a{8}01)!$Bf{42J)nZ{qj=myiC_zkB*Olehl)rFZ_Fe{uK(G*-Mj!gqWR z*nS*9m?=mm>BB#K=Oh2-pG~DcdAV|3DbrA#Gzk$@&8#q_P#HF z^WihU_j~={LEecC+`(3R@K-kf=!Jjw2M_%HKl7{q_pkiSzy7&>;Buj2fjz#ILxlhD z1E2r@|FZYD7XIDaM}PL;|M8i(K%>vrWQzV+R`;d%{)5l_<4^qB-+uIGKe+pEU;oOp O5JbN7RPR*p$^QYrohE_+ delta 41414 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 be a color value, in the form of "#rgb", "#argb", +"#rrggbb", or "#aarrggbb". +

This may also be a reference to a resource (in the form +"@[package:]type:name") or +theme attribute (in the form +"?[package:][type:]name") +containing a value of this type. + */ + public static final int colour=0x7f010001; + /**

Must be an integer value, such as "100". +

This may also be a reference to a resource (in the form +"@[package:]type:name") or +theme attribute (in the form +"?[package:][type:]name") +containing a value of this type. + */ + public static final int drawable=0x7f010000; + /**

Must be an integer value, such as "100". +

This may also be a reference to a resource (in the form +"@[package:]type:name") or +theme attribute (in the form +"?[package:][type:]name") +containing a value of this type. + */ + public static final int shadowColor=0x7f010005; + /**

Must be a floating point value, such as "1.2". +

This may also be a reference to a resource (in the form +"@[package:]type:name") or +theme attribute (in the form +"?[package:][type:]name") +containing a value of this type. + */ + public static final int shadowDx=0x7f010003; + /**

Must be a floating point value, such as "1.2". +

This may also be a reference to a resource (in the form +"@[package:]type:name") or +theme attribute (in the form +"?[package:][type:]name") +containing a value of this type. + */ + public static final int shadowDy=0x7f010004; + /**

Must be a floating point value, such as "1.2". +

This may also be a reference to a resource (in the form +"@[package:]type:name") or +theme attribute (in the form +"?[package:][type:]name") +containing a value of this type. + */ + public static final int shadowRadius=0x7f010002; + } + public static final class styleable { + /** Attributes that can be used with a FloatingActionButton. +

Includes the following attributes:

+ + + + + + + + + + +
AttributeDescription
{@link #FloatingActionButton_colour com.faizmalkani.floatingactionbutton.test:colour}
{@link #FloatingActionButton_drawable com.faizmalkani.floatingactionbutton.test:drawable}
{@link #FloatingActionButton_shadowColor com.faizmalkani.floatingactionbutton.test:shadowColor}
{@link #FloatingActionButton_shadowDx com.faizmalkani.floatingactionbutton.test:shadowDx}
{@link #FloatingActionButton_shadowDy com.faizmalkani.floatingactionbutton.test:shadowDy}
{@link #FloatingActionButton_shadowRadius com.faizmalkani.floatingactionbutton.test:shadowRadius}
+ @see #FloatingActionButton_colour + @see #FloatingActionButton_drawable + @see #FloatingActionButton_shadowColor + @see #FloatingActionButton_shadowDx + @see #FloatingActionButton_shadowDy + @see #FloatingActionButton_shadowRadius + */ + public static final int[] FloatingActionButton = { + 0x7f010000, 0x7f010001, 0x7f010002, 0x7f010003, + 0x7f010004, 0x7f010005 + }; + /** +

This symbol is the offset where the {@link com.faizmalkani.floatingactionbutton.test.R.attr#colour} + attribute's value can be found in the {@link #FloatingActionButton} array. + + +

Must be a color value, in the form of "#rgb", "#argb", +"#rrggbb", or "#aarrggbb". +

This may also be a reference to a resource (in the form +"@[package:]type:name") or +theme attribute (in the form +"?[package:][type:]name") +containing a value of this type. + @attr name com.faizmalkani.floatingactionbutton.test:colour + */ + public static final int FloatingActionButton_colour = 1; + /** +

This symbol is the offset where the {@link com.faizmalkani.floatingactionbutton.test.R.attr#drawable} + attribute's value can be found in the {@link #FloatingActionButton} array. + + +

Must be an integer value, such as "100". +

This may also be a reference to a resource (in the form +"@[package:]type:name") or +theme attribute (in the form +"?[package:][type:]name") +containing a value of this type. + @attr name com.faizmalkani.floatingactionbutton.test:drawable + */ + public static final int FloatingActionButton_drawable = 0; + /** +

This symbol is the offset where the {@link com.faizmalkani.floatingactionbutton.test.R.attr#shadowColor} + attribute's value can be found in the {@link #FloatingActionButton} array. + + +

Must be an integer value, such as "100". +

This may also be a reference to a resource (in the form +"@[package:]type:name") or +theme attribute (in the form +"?[package:][type:]name") +containing a value of this type. + @attr name com.faizmalkani.floatingactionbutton.test:shadowColor + */ + public static final int FloatingActionButton_shadowColor = 5; + /** +

This symbol is the offset where the {@link com.faizmalkani.floatingactionbutton.test.R.attr#shadowDx} + attribute's value can be found in the {@link #FloatingActionButton} array. + + +

Must be a floating point value, such as "1.2". +

This may also be a reference to a resource (in the form +"@[package:]type:name") or +theme attribute (in the form +"?[package:][type:]name") +containing a value of this type. + @attr name com.faizmalkani.floatingactionbutton.test:shadowDx + */ + public static final int FloatingActionButton_shadowDx = 3; + /** +

This symbol is the offset where the {@link com.faizmalkani.floatingactionbutton.test.R.attr#shadowDy} + attribute's value can be found in the {@link #FloatingActionButton} array. + + +

Must be a floating point value, such as "1.2". +

This may also be a reference to a resource (in the form +"@[package:]type:name") or +theme attribute (in the form +"?[package:][type:]name") +containing a value of this type. + @attr name com.faizmalkani.floatingactionbutton.test:shadowDy + */ + public static final int FloatingActionButton_shadowDy = 4; + /** +

This symbol is the offset where the {@link com.faizmalkani.floatingactionbutton.test.R.attr#shadowRadius} + attribute's value can be found in the {@link #FloatingActionButton} array. + + +

Must be a floating point value, such as "1.2". +

This may also be a reference to a resource (in the form +"@[package:]type:name") or +theme attribute (in the form +"?[package:][type:]name") +containing a value of this type. + @attr name com.faizmalkani.floatingactionbutton.test:shadowRadius + */ + public static final int FloatingActionButton_shadowRadius = 2; + }; +} diff --git a/libraries/FloatingActionButton/build/intermediates/bundles/debug/AndroidManifest.xml b/libraries/FloatingActionButton/build/intermediates/bundles/debug/AndroidManifest.xml index 28dac35..ef7ef47 100644 --- a/libraries/FloatingActionButton/build/intermediates/bundles/debug/AndroidManifest.xml +++ b/libraries/FloatingActionButton/build/intermediates/bundles/debug/AndroidManifest.xml @@ -6,7 +6,7 @@ + android:targetSdkVersion="22" /> diff --git a/libraries/FloatingActionButton/build/intermediates/bundles/debug/aapt/AndroidManifest.xml b/libraries/FloatingActionButton/build/intermediates/bundles/debug/aapt/AndroidManifest.xml new file mode 100644 index 0000000..ef7ef47 --- /dev/null +++ b/libraries/FloatingActionButton/build/intermediates/bundles/debug/aapt/AndroidManifest.xml @@ -0,0 +1,14 @@ + + + + + + + + + \ No newline at end of file diff --git a/libraries/FloatingActionButton/build/intermediates/bundles/release/AndroidManifest.xml b/libraries/FloatingActionButton/build/intermediates/bundles/release/AndroidManifest.xml index 28dac35..ef7ef47 100644 --- a/libraries/FloatingActionButton/build/intermediates/bundles/release/AndroidManifest.xml +++ b/libraries/FloatingActionButton/build/intermediates/bundles/release/AndroidManifest.xml @@ -6,7 +6,7 @@ + android:targetSdkVersion="22" /> diff --git a/libraries/FloatingActionButton/build/intermediates/bundles/release/aapt/AndroidManifest.xml b/libraries/FloatingActionButton/build/intermediates/bundles/release/aapt/AndroidManifest.xml new file mode 100644 index 0000000..ef7ef47 --- /dev/null +++ b/libraries/FloatingActionButton/build/intermediates/bundles/release/aapt/AndroidManifest.xml @@ -0,0 +1,14 @@ + + + + + + + + + \ No newline at end of file diff --git a/libraries/FloatingActionButton/build/intermediates/incremental/aidl/androidTest/debug/dependency.store b/libraries/FloatingActionButton/build/intermediates/incremental/aidl/androidTest/debug/dependency.store new file mode 100644 index 0000000000000000000000000000000000000000..8b8400dcf9e65fb815794fe016943dc09d0e8a05 GIT binary patch literal 5 Mcmb + \ No newline at end of file diff --git a/libraries/FloatingActionButton/build/intermediates/incremental/mergeResources/androidTest/debug/merger.xml b/libraries/FloatingActionButton/build/intermediates/incremental/mergeResources/androidTest/debug/merger.xml new file mode 100644 index 0000000..ed571c2 --- /dev/null +++ b/libraries/FloatingActionButton/build/intermediates/incremental/mergeResources/androidTest/debug/merger.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/libraries/FloatingActionButton/build/intermediates/manifests/androidTest/debug/AndroidManifest.xml b/libraries/FloatingActionButton/build/intermediates/manifests/androidTest/debug/AndroidManifest.xml new file mode 100644 index 0000000..700e38f --- /dev/null +++ b/libraries/FloatingActionButton/build/intermediates/manifests/androidTest/debug/AndroidManifest.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/libraries/FloatingActionButton/build/intermediates/manifests/tmp/manifestMerger1204657370108759986.xml b/libraries/FloatingActionButton/build/intermediates/manifests/tmp/manifestMerger1204657370108759986.xml new file mode 100644 index 0000000..b5967be --- /dev/null +++ b/libraries/FloatingActionButton/build/intermediates/manifests/tmp/manifestMerger1204657370108759986.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/libraries/FloatingActionButton/build/intermediates/manifests/tmp/manifestMerger5288530001266894344.xml b/libraries/FloatingActionButton/build/intermediates/manifests/tmp/manifestMerger5288530001266894344.xml new file mode 100644 index 0000000..b5967be --- /dev/null +++ b/libraries/FloatingActionButton/build/intermediates/manifests/tmp/manifestMerger5288530001266894344.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/libraries/FloatingActionButton/build/intermediates/manifests/tmp/manifestMerger7191608954865808767.xml b/libraries/FloatingActionButton/build/intermediates/manifests/tmp/manifestMerger7191608954865808767.xml new file mode 100644 index 0000000..5bae12c --- /dev/null +++ b/libraries/FloatingActionButton/build/intermediates/manifests/tmp/manifestMerger7191608954865808767.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/libraries/FloatingActionButton/build/intermediates/res/androidTest/debug/values/values.xml b/libraries/FloatingActionButton/build/intermediates/res/androidTest/debug/values/values.xml new file mode 100644 index 0000000..8a1db4a --- /dev/null +++ b/libraries/FloatingActionButton/build/intermediates/res/androidTest/debug/values/values.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/libraries/FloatingActionButton/build/intermediates/symbols/androidTest/debug/R.txt b/libraries/FloatingActionButton/build/intermediates/symbols/androidTest/debug/R.txt new file mode 100644 index 0000000..a11b389 --- /dev/null +++ b/libraries/FloatingActionButton/build/intermediates/symbols/androidTest/debug/R.txt @@ -0,0 +1,13 @@ +int attr colour 0x7f010001 +int attr drawable 0x7f010000 +int attr shadowColor 0x7f010005 +int attr shadowDx 0x7f010003 +int attr shadowDy 0x7f010004 +int attr shadowRadius 0x7f010002 +int[] styleable FloatingActionButton { 0x7f010000, 0x7f010001, 0x7f010002, 0x7f010003, 0x7f010004, 0x7f010005 } +int styleable FloatingActionButton_colour 1 +int styleable FloatingActionButton_drawable 0 +int styleable FloatingActionButton_shadowColor 5 +int styleable FloatingActionButton_shadowDx 3 +int styleable FloatingActionButton_shadowDy 4 +int styleable FloatingActionButton_shadowRadius 2 diff --git a/libraries/FloatingActionButton/build/outputs/aar/FloatingActionButton-debug.aar b/libraries/FloatingActionButton/build/outputs/aar/FloatingActionButton-debug.aar index ffcf644723903f3f8a68c403301bfbf182544f3d..394c81bee587a47e10995f67861c7f853e5feab7 100644 GIT binary patch delta 932 zcmZ2#bi-6Qz?+$ci-CcIgTZ56u3ODog;)0`3M?q}hHqS@d5_v<+Cam*>=v$O}!EA9l_= zo>%bT>=NTiUBB-%higixz7RG1HYdIEDxXnyv0C$E0r7by&vMGxIv9?VrwM*H$X8YbF zlK)pt+rIXv@?U3#C6SNitmbMwoNat0qqn8{PCRFXwB5Yy<3g-QL%!Ia@cJwpC(E|) z?~5P2i}@HuSU|p=EF^lu?%0ATHwGYJ0ueyK3dD(t1tt2-3|PVjDA~-&z#surG*M1$ zpu;MQmSKe&1e5QHDnLSxNlYEg*sLqY!Uz#E6<6kjr=iJ-;$c?&z>rGLNh~f-E!N9Q zEDG>uWD;RUB(@3sp1do80cisadQhmtz>-GR$sff%|%gYl%SgcPOd<0 zuqZ*8@C~MAa+SEe8OT{6IanOCz!WkFFuZl-5@%p2N-fq$H+{0Tgp{=&RI)5Frxc5t zBe{xe)&Wf`0eTf^B^)eij1-?dLBdhm3Yb(tAy9(Fe4yXt6G8HsDLFvfS=m6^xquK9 KB5j~F#sC1J%Ssvm delta 507 zcmca%y3|NIz?+$ci-CcIgCTWFx2vv?3d>yv28L!v1_t5D8zsc*b0?hjJE9=c`n{Ix zP~CxD7fqH=Q-mZuY($n>pKb`*qmNnHX(Ahv7}7BiXA=Ck8+8P<3^Ci#8}6KMWF(d6$1Cp*^Ar+@e7pMOxIZCEO8 zFm26e&DEv5WmV7p5Z}7*-C6k;@=S`lQvDZd{Wl2V*3q6`c{dL?q}hHqS@d5_v<+Cam*>=v$O}!EA9l_= zo>%bT>=NTiUBB-%higixz7RG1HYdIEDxXnyv0C$E0r7by&vMGxIv9?VrwM*H$X8YbF zlK)pt+rIXv@?U3#C6SNitmbMwoNat0qqn8{PCRFXwB5Yy<3g-QL%!Ia@cJwpC(E|) z?~5P2oB0^`3bTN`JNdlG3A^J9qTCpOfC)qZ0V@zECKi11h%StQ?@MdHZVMZju3H+YCD}hGa0OJD`6)>=*@sJ1uLy%rcMG3MN zY_SK?BEaz0u}>5lmk2GINGTnt5EhvTYc|95Og0yn&j-03BnL|!AYVfO$o%7CkT5_P z4>2920;Yo-s-A%Xq~kSIM_FP{DKPNRHBL5^kYW-OpX@8)$n;%&@&pM{TXYv70tIBA b955v&W~Sr-O=4vO*~A5eps;fWB~byv28L!v1_t5Dc@kpvxf9O%9Z?Wz{a(v; zsP4e7izZ7a_f(s!y<6{Kz2pz8URF)jOfO&I)Zp{x3GAi<$G&=1vT`^PF*y*Fg=(^&N!|Y)-E(n-DqMSW>2a$EPL6`Np>< zRw+%grKg)3#fMMQ!x zZdZ^#%U@9{@$=u}%jTQ;8TSgafP6mrg2)L7)R=7fjS z)0#G zz)+N0tdFi^@@h#b>y1#!vc#NHENYJADy~@vG^Yd@UqF>`u%z*h=p-pe>AhkM42i|X isU?`kPm+|9e*%)uOvwS-&B_MS%mIXlfo5@vgLnV{legCZ diff --git a/libraries/RootCommands/build.gradle b/libraries/RootCommands/build.gradle index 9485108..44db86f 100644 --- a/libraries/RootCommands/build.gradle +++ b/libraries/RootCommands/build.gradle @@ -15,12 +15,12 @@ dependencies { } android { - compileSdkVersion 21 - buildToolsVersion '21.1.2' + compileSdkVersion 22 + buildToolsVersion '22' defaultConfig { minSdkVersion 7 - targetSdkVersion 21 + targetSdkVersion 22 } compileOptions { sourceCompatibility JavaVersion.VERSION_1_7 diff --git a/libraries/sharedCode/build.gradle b/libraries/sharedCode/build.gradle index cfb8ba1..7982fc1 100644 --- a/libraries/sharedCode/build.gradle +++ b/libraries/sharedCode/build.gradle @@ -26,12 +26,12 @@ android { disable 'MissingTranslation', 'ExtraTranslation' } - compileSdkVersion 21 - buildToolsVersion '21.1.2' + compileSdkVersion 22 + buildToolsVersion '22' defaultConfig { minSdkVersion 11 - targetSdkVersion 21 + targetSdkVersion 22 versionCode 1 versionName "1.0" } @@ -61,9 +61,6 @@ dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile project(':libraries:RootCommands') compile project(':libraries:FloatingActionButton') - //compile('de.greenrobot:eventbus:2.2.1') { - // exclude module: 'support-v4' - // } // compile 'com.googlecode.juniversalchardet:juniversalchardet:1.0.3' compile 'org.apache.commons:commons-lang3:3.1' compile files('libs/juniversalchardet-1.0.3.jar') diff --git a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/activity/MainActivity.java b/libraries/sharedCode/src/main/java/sharedcode/turboeditor/activity/MainActivity.java index a4dbfd0..aed4331 100644 --- a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/activity/MainActivity.java +++ b/libraries/sharedCode/src/main/java/sharedcode/turboeditor/activity/MainActivity.java @@ -57,7 +57,6 @@ import android.view.KeyEvent; import android.view.Menu; import android.view.MenuItem; import android.view.View; -import android.view.WindowManager; import android.view.inputmethod.InputMethodManager; import android.widget.AdapterView; import android.widget.EditText; @@ -74,8 +73,10 @@ import org.sufficientlysecure.rootcommands.Toolbox; import java.io.File; import java.io.UnsupportedEncodingException; +import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedList; +import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -87,6 +88,7 @@ import sharedcode.turboeditor.dialogfragment.FindTextDialog; import sharedcode.turboeditor.dialogfragment.NewFileDetailsDialog; import sharedcode.turboeditor.dialogfragment.NumberPickerDialog; import sharedcode.turboeditor.dialogfragment.SaveFileDialog; +import sharedcode.turboeditor.preferences.PreferenceChangeType; import sharedcode.turboeditor.preferences.PreferenceHelper; import sharedcode.turboeditor.task.SaveFileTask; import sharedcode.turboeditor.texteditor.EditTextPadding; @@ -99,7 +101,6 @@ import sharedcode.turboeditor.texteditor.SearchResult; import sharedcode.turboeditor.util.AccessStorageApi; import sharedcode.turboeditor.util.AnimationUtils; import sharedcode.turboeditor.util.AppInfoHelper; -import sharedcode.turboeditor.util.EventBusEvents; import sharedcode.turboeditor.util.IHomeActivity; import sharedcode.turboeditor.util.MimeTypes; import sharedcode.turboeditor.util.ProCheckUtils; @@ -108,29 +109,19 @@ import sharedcode.turboeditor.views.CustomDrawerLayout; import sharedcode.turboeditor.views.DialogHelper; import sharedcode.turboeditor.views.GoodScrollView; -import static sharedcode.turboeditor.util.EventBusEvents.APreferenceValueWasChanged.Type.ENCODING; -import static sharedcode.turboeditor.util.EventBusEvents.APreferenceValueWasChanged.Type.FONT_SIZE; -import static sharedcode.turboeditor.util.EventBusEvents.APreferenceValueWasChanged.Type.LINE_NUMERS; -import static sharedcode.turboeditor.util.EventBusEvents.APreferenceValueWasChanged.Type.MONOSPACE; -import static sharedcode.turboeditor.util.EventBusEvents.APreferenceValueWasChanged.Type.READ_ONLY; -import static sharedcode.turboeditor.util.EventBusEvents.APreferenceValueWasChanged.Type.SYNTAX; -import static sharedcode.turboeditor.util.EventBusEvents.APreferenceValueWasChanged.Type.TEXT_SUGGESTIONS; -import static sharedcode.turboeditor.util.EventBusEvents.APreferenceValueWasChanged.Type.THEME_CHANGE; -import static sharedcode.turboeditor.util.EventBusEvents.APreferenceValueWasChanged.Type.WRAP_CONTENT; - public abstract class MainActivity extends ActionBarActivity implements IHomeActivity, FindTextDialog .SearchDialogInterface, GoodScrollView.ScrollInterface, PageSystem.PageSystemInterface, PageSystemButtons.PageButtonsInterface, NumberPickerDialog.INumberPickerDialog, SaveFileDialog.ISaveDialog, AdapterView.OnItemClickListener, AdapterDrawer.Callbacks{ //region VARIABLES + private static final int READ_REQUEST_CODE = 42; private static final int ID_SELECT_ALL = android.R.id.selectAll; private static final int ID_CUT = android.R.id.cut; private static final int ID_COPY = android.R.id.copy; private static final int ID_PASTE = android.R.id.paste; private static final int SELECT_FILE_CODE = 121; - private static final int KITKAT_OPEN_REQUEST_CODE = 41; private static final int SYNTAX_DELAY_MILLIS_SHORT = 250; private static final int SYNTAX_DELAY_MILLIS_LONG = 1500; private static final int ID_UNDO = R.id.im_undo; @@ -167,11 +158,10 @@ public abstract class MainActivity extends ActionBarActivity implements IHomeAct private static String sFilePath = ""; private static Editor mEditor; private static HorizontalScrollView horizontalScroll; - private boolean searchingText; private static SearchResult searchResult; private static PageSystem pageSystem; private static PageSystemButtons pageSystemButtons; - private static String currentEncoding = "UTF-8"; + private static String currentEncoding = "UTF-16"; private static Toolbar toolbar; /* @@ -236,7 +226,7 @@ public abstract class MainActivity extends ActionBarActivity implements IHomeAct super.onPause(); if (PreferenceHelper.getAutoSave(getBaseContext()) && mEditor.canSaveFile()) { - saveTheFile(); + saveTheFile(false); mEditor.fileSaved(); // so it doesn't ask to save in onDetach } } @@ -311,7 +301,7 @@ public abstract class MainActivity extends ActionBarActivity implements IHomeAct // Set the default title getSupportActionBar().setTitle(getString(R.string.nome_app_turbo_editor)); - onEvent(new EventBusEvents.ClosedAFile()); + closedTheFile(); mDrawerLayout.openDrawer(Gravity.START); mDrawerLayout.closeDrawer(Gravity.END); @@ -335,15 +325,15 @@ public abstract class MainActivity extends ActionBarActivity implements IHomeAct path = AccessStorageApi.getPath(getBaseContext(), data.getData()); } - if (requestCode == KITKAT_OPEN_REQUEST_CODE) { + if (requestCode == READ_REQUEST_CODE) { path = AccessStorageApi.getPath(getBaseContext(), data.getData()); } if (!TextUtils.isEmpty(path)) { File file = new File(path); if (file.isFile() && file.exists()) { - onEvent(new EventBusEvents.NewFileToOpen(new File - (path))); + newFileToOpen(new File + (path), ""); } } @@ -355,7 +345,7 @@ public abstract class MainActivity extends ActionBarActivity implements IHomeAct // Path of the file selected String filePath = files.get(position).getAbsolutePath(); // Send the event that a file was selected - onEvent(new EventBusEvents.NewFileToOpen(new File(filePath))); + newFileToOpen(new File(filePath), ""); } //endregion @@ -364,7 +354,7 @@ public abstract class MainActivity extends ActionBarActivity implements IHomeAct @Override public boolean onCreateOptionsMenu(Menu menu) { - if (fileOpened && searchingText) + if (fileOpened && searchResult != null) getMenuInflater().inflate(R.menu.fragment_editor_search, menu); else if (fileOpened) getMenuInflater().inflate(R.menu.fragment_editor, menu); @@ -374,14 +364,18 @@ public abstract class MainActivity extends ActionBarActivity implements IHomeAct @Override public boolean onPrepareOptionsMenu(Menu menu) { - if (fileOpened && searchingText) { + if (fileOpened && searchResult != null) { MenuItem imReplace = menu.findItem(R.id.im_replace); + MenuItem imReplaceAll = menu.findItem(R.id.im_replace_all); MenuItem imPrev = menu.findItem(R.id.im_previous_item); MenuItem imNext = menu.findItem(R.id.im_next_item); if (imReplace != null) imReplace.setVisible(searchResult.canReplaceSomething()); + if (imReplaceAll != null) + imReplaceAll.setVisible(searchResult.canReplaceSomething()); + if (imPrev != null) imPrev.setVisible(searchResult.hasPrevious()); @@ -432,8 +426,11 @@ public abstract class MainActivity extends ActionBarActivity implements IHomeAct Toast.makeText(getBaseContext(), "drawer click", Toast.LENGTH_SHORT).show(); mDrawerLayout.closeDrawer(Gravity.END); return true; - } else if (i == R.id.im_save) { - saveTheFile(); + } else if (i == R.id.im_save_normaly) { + saveTheFile(false); + + } else if (i == R.id.im_save_as) { + saveTheFile(true); } else if (i == R.id.im_undo) { mEditor.onTextContextMenuItem(ID_UNDO); @@ -445,11 +442,14 @@ public abstract class MainActivity extends ActionBarActivity implements IHomeAct FindTextDialog.newInstance(mEditor.getText().toString()).show(getFragmentManager() .beginTransaction(), "dialog"); } else if (i == R.id.im_cancel) { - searchingText = false; + searchResult = null; invalidateOptionsMenu(); } else if (i == R.id.im_replace) { - replaceText(); + replaceText(false); + + } else if (i == R.id.im_replace_all) { + replaceText(true); } else if (i == R.id.im_next_item) { nextResult(); @@ -475,27 +475,30 @@ public abstract class MainActivity extends ActionBarActivity implements IHomeAct } else if (i == R.id.im_info) { FileInfoDialog.newInstance(sFilePath).show(getFragmentManager().beginTransaction(), "dialog"); } - - else if (i == R.id.im_donate) { - DialogHelper.showDonateDialog(this); - } return super.onOptionsItemSelected(item); } //endregion // region OTHER THINGS - void replaceText() { - int start = searchResult.foundIndex.get(searchResult.index); - int end = start + searchResult.textLength; - mEditor.setText(mEditor.getText().replace(start, end, searchResult.textToReplace)); - searchResult.doneReplace(); + void replaceText(boolean all) { + if (all) { + mEditor.setText(mEditor.getText().toString().replaceAll(searchResult.whatToSearch, searchResult.textToReplace)); - invalidateOptionsMenu(); + searchResult = null; + invalidateOptionsMenu(); + } else { + int start = searchResult.foundIndex.get(searchResult.index); + int end = start + searchResult.textLength; + mEditor.setText(mEditor.getText().replace(start, end, searchResult.textToReplace)); + searchResult.doneReplace(); - if (searchResult.hasNext()) - nextResult(); - else if (searchResult.hasPrevious()) - previousResult(); + invalidateOptionsMenu(); + + if (searchResult.hasNext()) + nextResult(); + else if (searchResult.hasPrevious()) + previousResult(); + } } void nextResult() { @@ -561,14 +564,18 @@ public abstract class MainActivity extends ActionBarActivity implements IHomeAct invalidateOptionsMenu(); } - private void saveTheFile() { + private void saveTheFile(boolean saveAs) { File file = new File(sFilePath); - if (!file.getName().isEmpty()) + if (!file.getName().isEmpty() && !saveAs) new SaveFileTask(this, sFilePath, pageSystem.getAllText(mEditor.getText() .toString()), currentEncoding).execute(); else { - NewFileDetailsDialog.newInstance - (pageSystem.getAllText(mEditor.getText().toString()), currentEncoding).show(getFragmentManager().beginTransaction(), "dialog"); + NewFileDetailsDialog.newInstance( + file.getParent(), + file.getName(), + pageSystem.getAllText(mEditor.getText().toString()), + currentEncoding + ).show(getFragmentManager().beginTransaction(), "dialog"); } } @@ -631,12 +638,6 @@ public abstract class MainActivity extends ActionBarActivity implements IHomeAct verticalScroll.addView(mEditor); } - if (PreferenceHelper.getReadOnly(this)) { - getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN); - } else { - getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED); - } - verticalScroll.setScrollInterface(this); pageSystem = new PageSystem(this, this, "", null); @@ -655,7 +656,6 @@ public abstract class MainActivity extends ActionBarActivity implements IHomeAct mEditor.resetVariables(); searchResult = null; - searchingText = false; invalidateOptionsMenu(); @@ -692,11 +692,11 @@ public abstract class MainActivity extends ActionBarActivity implements IHomeAct || Intent.ACTION_PICK.equals(action) && type != null) { // Post event - onEvent(new EventBusEvents.NewFileToOpen(new File(intent - .getData().getPath()))); + newFileToOpen(new File(intent + .getData().getPath()), ""); } else if (Intent.ACTION_SEND.equals(action) && type != null) { if ("text/plain".equals(type)) { - onEvent(new EventBusEvents.NewFileToOpen(intent.getStringExtra(Intent.EXTRA_TEXT))); + newFileToOpen(null, intent.getStringExtra(Intent.EXTRA_TEXT)); } } } @@ -784,11 +784,11 @@ public abstract class MainActivity extends ActionBarActivity implements IHomeAct //endregion //region EVENTBUS - void onEvent(final EventBusEvents.NewFileToOpen event) { + public void newFileToOpen(final File newFile, final String newFileText) { if (fileOpened && mEditor.canSaveFile()) { SaveFileDialog.newInstance(sFilePath, pageSystem.getAllText(mEditor - .getText().toString()), currentEncoding, true, event.getFile().getAbsolutePath()).show(getFragmentManager(), + .getText().toString()), currentEncoding, true, newFile.getAbsolutePath()).show(getFragmentManager(), "dialog"); return; } @@ -814,10 +814,13 @@ public abstract class MainActivity extends ActionBarActivity implements IHomeAct @Override protected Void doInBackground(Void... params) { - file = event.getFile(); + file = newFile; + if (file == null) { + file = new File(""); + } try { if (!file.exists() || !file.isFile()) { - fileText = event.getFileText(); + fileText = newFileText; sFilePath = file.getAbsolutePath(); fileExtension = "txt"; return null; @@ -839,7 +842,7 @@ public abstract class MainActivity extends ActionBarActivity implements IHomeAct File tempFile = new File(getFilesDir(), "temp.root.file"); if (!tempFile.exists()) tempFile.createNewFile(); - tb.copyFile(event.getFile().getAbsolutePath(), + tb.copyFile(file.getAbsolutePath(), tempFile.getAbsolutePath(), false, false); file = new File(tempFile.getAbsolutePath()); } @@ -879,13 +882,13 @@ public abstract class MainActivity extends ActionBarActivity implements IHomeAct if (!message.isEmpty()) { Toast.makeText(MainActivity.this, message, Toast.LENGTH_LONG).show(); - onEvent(new EventBusEvents.CannotOpenAFile()); + cannotOpenFile(); } else { pageSystem = new PageSystem(MainActivity.this, MainActivity.this, fileText, new File(sFilePath)); currentEncoding = encoding; - onEvent(new EventBusEvents.AFileIsSelected(sFilePath)); + aFileWasSelected(sFilePath); showTextEditor(); @@ -904,11 +907,13 @@ public abstract class MainActivity extends ActionBarActivity implements IHomeAct }.execute(); } - public void onEvent(EventBusEvents.SavedAFile event) { + public void savedAFile(String filePath) { - sFilePath = event.getPath(); + sFilePath = filePath; fileExtension = FilenameUtils.getExtension(sFilePath).toLowerCase(); + toolbar.setTitle(FilenameUtils.getName(sFilePath)); + mEditor.clearHistory(); mEditor.fileSaved(); invalidateOptionsMenu(); @@ -919,10 +924,8 @@ public abstract class MainActivity extends ActionBarActivity implements IHomeAct e.printStackTrace(); } - refreshList(event.getPath(), true, false); - arrayAdapter.selectView(event.getPath()); - - showInterstitial(); + refreshList(filePath, true, false); + arrayAdapter.selectView(filePath); } /** @@ -931,7 +934,7 @@ public abstract class MainActivity extends ActionBarActivity implements IHomeAct * * @param event The event called */ - void onEvent(EventBusEvents.CannotOpenAFile event) { + public void cannotOpenFile() { // mDrawerLayout.openDrawer(Gravity.LEFT); // @@ -942,13 +945,17 @@ public abstract class MainActivity extends ActionBarActivity implements IHomeAct hideTextEditor(); } - public void onEvent(EventBusEvents.APreferenceValueWasChanged event) { + public void aPreferenceValueWasChanged(final PreferenceChangeType type) { + this.aPreferenceValueWasChanged(new ArrayList() {{add(type);}}); + } - if (event.hasType(EventBusEvents.APreferenceValueWasChanged.Type.THEME_CHANGE)) { + public void aPreferenceValueWasChanged(List types) { + + if (types.contains(PreferenceChangeType.THEME_CHANGE)) { ThemeUtils.setWindowsBackground(this); } - if (event.hasType(WRAP_CONTENT)) { + if (types.contains(PreferenceChangeType.WRAP_CONTENT)) { if (PreferenceHelper.getWrapContent(this)) { horizontalScroll.removeView(mEditor); verticalScroll.removeView(horizontalScroll); @@ -958,41 +965,42 @@ public abstract class MainActivity extends ActionBarActivity implements IHomeAct verticalScroll.addView(horizontalScroll); horizontalScroll.addView(mEditor); } - } else if (event.hasType(LINE_NUMERS)) { + } else if (types.contains(PreferenceChangeType.LINE_NUMERS)) { mEditor.disableTextChangedListener(); mEditor.replaceTextKeepCursor(null, true); mEditor.enableTextChangedListener(); if (PreferenceHelper.getLineNumbers(this)) { - mEditor.setPadding(EditTextPadding.getPaddingWithLineNumbers(this, - PreferenceHelper.getFontSize(this)), - EditTextPadding.getPaddingTop(this), 0, 0); + mEditor.setPadding( + EditTextPadding.getPaddingWithLineNumbers(this, PreferenceHelper.getFontSize(this)), + EditTextPadding.getPaddingTop(this), + EditTextPadding.getPaddingTop(this), + 0); } else { - mEditor.setPadding(EditTextPadding.getPaddingWithoutLineNumbers(this) - , EditTextPadding.getPaddingTop(this), 0, 0); + mEditor.setPadding( + EditTextPadding.getPaddingWithoutLineNumbers(this), + EditTextPadding.getPaddingTop(this), + EditTextPadding.getPaddingTop(this), + 0); } - } else if (event.hasType(SYNTAX)) { + } else if (types.contains(PreferenceChangeType.SYNTAX)) { mEditor.disableTextChangedListener(); mEditor.replaceTextKeepCursor(null, true); mEditor.enableTextChangedListener(); - } else if (event.hasType(MONOSPACE)) { + } else if (types.contains(PreferenceChangeType.MONOSPACE)) { if (PreferenceHelper.getUseMonospace(this)) mEditor.setTypeface(Typeface.MONOSPACE); else mEditor.setTypeface(Typeface.DEFAULT); - } else if (event.hasType(THEME_CHANGE)) { + } else if (types.contains(PreferenceChangeType.THEME_CHANGE)) { if (PreferenceHelper.getLightTheme(this)) { mEditor.setTextColor(getResources().getColor(R.color.textColorInverted)); } else { mEditor.setTextColor(getResources().getColor(R.color.textColor)); } - } else if (event.hasType(TEXT_SUGGESTIONS) || event.hasType(READ_ONLY)) { + } else if (types.contains(PreferenceChangeType.TEXT_SUGGESTIONS) || types.contains(PreferenceChangeType.READ_ONLY)) { if (PreferenceHelper.getReadOnly(this)) { - getWindow().setSoftInputMode(WindowManager.LayoutParams - .SOFT_INPUT_STATE_ALWAYS_HIDDEN); mEditor.setReadOnly(true); } else { - getWindow().setSoftInputMode(WindowManager.LayoutParams - .SOFT_INPUT_STATE_UNSPECIFIED); mEditor.setReadOnly(false); if (PreferenceHelper.getSuggestionActive(this)) { mEditor.setInputType(InputType.TYPE_CLASS_TEXT | InputType @@ -1009,17 +1017,22 @@ public abstract class MainActivity extends ActionBarActivity implements IHomeAct mEditor.setTypeface(Typeface.MONOSPACE); else mEditor.setTypeface(Typeface.DEFAULT); - } else if (event.hasType(FONT_SIZE)) { + } else if (types.contains(PreferenceChangeType.FONT_SIZE)) { if (PreferenceHelper.getLineNumbers(this)) { - mEditor.setPadding(EditTextPadding.getPaddingWithLineNumbers(this, - PreferenceHelper.getFontSize(this)), - EditTextPadding.getPaddingTop(this), 0, 0); + mEditor.setPadding( + EditTextPadding.getPaddingWithLineNumbers(this, PreferenceHelper.getFontSize(this)), + EditTextPadding.getPaddingTop(this), + EditTextPadding.getPaddingTop(this), + 0); } else { - mEditor.setPadding(EditTextPadding.getPaddingWithoutLineNumbers(this) - , EditTextPadding.getPaddingTop(this), 0, 0); + mEditor.setPadding( + EditTextPadding.getPaddingWithoutLineNumbers(this), + EditTextPadding.getPaddingTop(this), + EditTextPadding.getPaddingTop(this), + 0); } mEditor.setTextSize(PreferenceHelper.getFontSize(this)); - } else if (event.hasType(ENCODING)) { + } else if (types.contains(PreferenceChangeType.ENCODING)) { String oldEncoding, newEncoding; oldEncoding = currentEncoding; newEncoding = PreferenceHelper.getEncoding(this); @@ -1033,7 +1046,7 @@ public abstract class MainActivity extends ActionBarActivity implements IHomeAct try { final byte[] oldText = mEditor.getText().toString().getBytes(oldEncoding); mEditor.disableTextChangedListener(); - mEditor.replaceTextKeepCursor(new String(oldText, "UTF-8"), true); + mEditor.replaceTextKeepCursor(new String(oldText, "UTF-16"), true); mEditor.enableTextChangedListener(); } catch (UnsupportedEncodingException ignored2) { } @@ -1041,24 +1054,43 @@ public abstract class MainActivity extends ActionBarActivity implements IHomeAct } } - void onEvent(EventBusEvents.AFileIsSelected event) { - arrayAdapter.selectView(event.getPath()); + public void aFileWasSelected(String filePath) { + arrayAdapter.selectView(filePath); } - void onEvent(EventBusEvents.ClosedAFile event) { + public void closedTheFile() { arrayAdapter.selectView(""); } //endregion //region Calls from the layout public void OpenFile(View view) { - Intent subActivity = new Intent(MainActivity.this, SelectFileActivity.class); - subActivity.putExtra("action", SelectFileActivity.Actions.SelectFile); - AnimationUtils.startActivityWithScale(this, subActivity, true, SELECT_FILE_CODE, view); + +// if (Device.hasKitKatApi()) { +// // ACTION_OPEN_DOCUMENT is the intent to choose a file via the system's file +// // browser. +// Intent intent = new Intent(Intent.ACTION_GET_CONTENT); +// +// // Filter to only show results that can be "opened", such as a +// // file (as opposed to a list of contacts or timezones) +// //intent.addCategory(Intent.CATEGORY_OPENABLE); +// +// // Filter to show only images, using the image MIME data type. +// // If one wanted to search for ogg vorbis files, the type would be "audio/ogg". +// // To search for all documents available via installed storage providers, +// // it would be "*/*". +// intent.setType("*/*"); +// +// startActivityForResult(intent, READ_REQUEST_CODE); +// } else { + Intent subActivity = new Intent(MainActivity.this, SelectFileActivity.class); + subActivity.putExtra("action", SelectFileActivity.Actions.SelectFile); + AnimationUtils.startActivityWithScale(this, subActivity, true, SELECT_FILE_CODE, view); +// } } public void CreateFile(View view) { - onEvent(new EventBusEvents.NewFileToOpen("")); // do not send the event to others + newFileToOpen(null, ""); // do not send the event to others } public void OpenInfo(View view) { @@ -1137,7 +1169,6 @@ public abstract class MainActivity extends ActionBarActivity implements IHomeAct @Override public void onSearchDone(SearchResult searchResult) { MainActivity.searchResult = searchResult; - searchingText = true; invalidateOptionsMenu(); final int line = LineUtils.getLineFromIndex(searchResult.foundIndex.getFirst @@ -1165,7 +1196,7 @@ public abstract class MainActivity extends ActionBarActivity implements IHomeAct @Override public void onPageChanged(int page) { pageSystemButtons.updateVisibility(false); - searchingText = false; + searchResult = null; mEditor.clearHistory(); invalidateOptionsMenu(); } @@ -1175,7 +1206,7 @@ public abstract class MainActivity extends ActionBarActivity implements IHomeAct pageSystemButtons.updateVisibility(Math.abs(t) > 10); if (!PreferenceHelper.getSyntaxHighlight(this) || (mEditor.hasSelection() && - !searchingText) || updateHandler == null || colorRunnable_duringScroll == null) + searchResult == null) || updateHandler == null || colorRunnable_duringScroll == null) return; updateHandler.removeCallbacks(colorRunnable_duringEditing); @@ -1219,16 +1250,16 @@ public abstract class MainActivity extends ActionBarActivity implements IHomeAct public void userDoesntWantToSave(boolean openNewFile, String pathOfNewFile) { Editor.canSaveFile = false; if(openNewFile) - onEvent(new EventBusEvents.NewFileToOpen(new File(pathOfNewFile))); + newFileToOpen(new File(pathOfNewFile), ""); else - onEvent(new EventBusEvents.CannotOpenAFile()); + cannotOpenFile(); } @Override public void CancelItem(int position, boolean andCloseOpenedFile) { refreshList(files.get(position).getAbsolutePath(), false, true); if (andCloseOpenedFile) - onEvent(new EventBusEvents.CannotOpenAFile()); + cannotOpenFile(); } //endregion @@ -1271,11 +1302,11 @@ public abstract class MainActivity extends ActionBarActivity implements IHomeAct private static int firstVisibleIndex, firstColoredIndex; private static int deviceHeight; private static int editorHeight; - private static boolean[] hasNewLineArray; + private static boolean[] isGoodLineArray; private static int[] realLines; private static boolean wrapContent; - private static int lastLine; - private static int firstLine; + //private static int lastLine; + //private static int firstLine; private static CharSequence textToHighlight; private static int lastVisibleIndex; private static int i; @@ -1306,12 +1337,17 @@ public abstract class MainActivity extends ActionBarActivity implements IHomeAct setTextColor(getResources().getColor(R.color.textColor)); } if (PreferenceHelper.getLineNumbers(getContext())) { - setPadding(EditTextPadding.getPaddingWithLineNumbers(getContext(), - PreferenceHelper.getFontSize(getContext())), - EditTextPadding.getPaddingTop(getContext()), 0, 0); + setPadding( + EditTextPadding.getPaddingWithLineNumbers(getContext(), PreferenceHelper.getFontSize(getContext())), + EditTextPadding.getPaddingTop(getContext()), + EditTextPadding.getPaddingTop(getContext()), + 0); } else { - setPadding(EditTextPadding.getPaddingWithoutLineNumbers(getContext()), - EditTextPadding.getPaddingTop(getContext()), 0, 0); + setPadding( + EditTextPadding.getPaddingWithoutLineNumbers(getContext()), + EditTextPadding.getPaddingTop(getContext()), + EditTextPadding.getPaddingTop(getContext()), + 0); } if (PreferenceHelper.getReadOnly(getContext())) { @@ -1397,24 +1433,20 @@ public abstract class MainActivity extends ActionBarActivity implements IHomeAct lineUtils.updateHasNewLineArray(pageSystem .getStartingLine(), lineCount, getLayout(), getText().toString()); - hasNewLineArray = lineUtils.getToCountLinesArray(); + isGoodLineArray = lineUtils.getGoodLines(); realLines = lineUtils.getRealLines(); } - editorHeight = getHeight(); - firstLine = lineUtils.getFirstVisibleLine(verticalScroll, editorHeight, lineCount); - lastLine = lineUtils.getLastVisibleLine(verticalScroll, editorHeight, lineCount, deviceHeight); + //editorHeight = getHeight(); if (PreferenceHelper.getLineNumbers(getContext())) { wrapContent = PreferenceHelper.getWrapContent(getContext()); - i = firstLine; - while (i < lastLine) { + for (i = 0; i < lineCount; i++) { // if last line we count it anyway if (!wrapContent - || hasNewLineArray[i] - || i == lastLine - 1) { + || isGoodLineArray[i]) { realLine = realLines[i]; canvas.drawText(String.valueOf(realLine), @@ -1422,7 +1454,6 @@ public abstract class MainActivity extends ActionBarActivity implements IHomeAct paddingTop + lineHeight * (i + 1), mPaintNumbers); } - i++; } } @@ -1456,7 +1487,7 @@ public abstract class MainActivity extends ActionBarActivity implements IHomeAct return onTextContextMenuItem(ID_REDO); } case KeyEvent.KEYCODE_S: - ((MainActivity) getContext()).saveTheFile(); + ((MainActivity) getContext()).saveTheFile(false); return true; default: return super.onKeyDown(keyCode, event); @@ -1638,20 +1669,23 @@ public abstract class MainActivity extends ActionBarActivity implements IHomeAct cursorPos = getSelectionStart(); cursorPosEnd = getSelectionEnd(); } + disableTextChangedListener(); - if (PreferenceHelper.getSyntaxHighlight(getContext())) + if (PreferenceHelper.getSyntaxHighlight(getContext())) { setText(highlight(textToUpdate == null ? getEditableText() : Editable.Factory .getInstance().newEditable(textToUpdate), textToUpdate != null)); - else - setText(textToUpdate == null ? getText().toString() : textToUpdate); + } + else { + setText(textToUpdate == null ? getEditableText() : textToUpdate); + } enableTextChangedListener(); if (mantainCursorPos) firstVisibleIndex = cursorPos; - if (firstVisibleIndex > -1) { + if (firstVisibleIndex > -1 && firstVisibleIndex < length()) { if (cursorPosEnd != cursorPos) setSelection(cursorPos, cursorPosEnd); else @@ -1667,7 +1701,7 @@ public abstract class MainActivity extends ActionBarActivity implements IHomeAct removeTextChangedListener(mChangeListener); } - public CharSequence highlight(Editable editable, boolean newText) { + public Editable highlight(Editable editable, boolean newText) { editable.clearSpans(); if (editable.length() == 0) { @@ -1677,10 +1711,8 @@ public abstract class MainActivity extends ActionBarActivity implements IHomeAct editorHeight = getHeight(); if (!newText && editorHeight > 0) { - firstLine = lineUtils.getFirstVisibleLine(verticalScroll, editorHeight, lineCount); - lastLine = lineUtils.getLastVisibleLine(verticalScroll, editorHeight, lineCount, deviceHeight); - firstVisibleIndex = getLayout().getLineStart(firstLine); - lastVisibleIndex = getLayout().getLineStart(lastLine); + firstVisibleIndex = getLayout().getLineStart(lineUtils.getFirstVisibleLine(verticalScroll, editorHeight, lineCount)); + lastVisibleIndex = getLayout().getLineStart(lineUtils.getLastVisibleLine(verticalScroll, editorHeight, lineCount, deviceHeight)); } else { firstVisibleIndex = 0; lastVisibleIndex = CHARS_TO_COLOR; @@ -1701,8 +1733,7 @@ public abstract class MainActivity extends ActionBarActivity implements IHomeAct if (fileExtension.contains("htm") || fileExtension.contains("xml")) { - color(Patterns.HTML_OPEN_TAGS, editable, textToHighlight, firstColoredIndex); - color(Patterns.HTML_CLOSE_TAGS, editable, textToHighlight, firstColoredIndex); + color(Patterns.HTML_TAGS, editable, textToHighlight, firstColoredIndex); color(Patterns.HTML_ATTRS, editable, textToHighlight, firstColoredIndex); color(Patterns.GENERAL_STRINGS, editable, textToHighlight, firstColoredIndex); color(Patterns.XML_COMMENTS, editable, textToHighlight, firstColoredIndex); @@ -1768,8 +1799,7 @@ public abstract class MainActivity extends ActionBarActivity implements IHomeAct CharSequence textToHighlight, int start) { int color = 0; - if (pattern.equals(Patterns.HTML_OPEN_TAGS) - || pattern.equals(Patterns.HTML_CLOSE_TAGS) + if (pattern.equals(Patterns.HTML_TAGS) || pattern.equals(Patterns.GENERAL_KEYWORDS) || pattern.equals(Patterns.SQL_KEYWORDS) || pattern.equals(Patterns.PY_KEYWORDS) diff --git a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/dialogfragment/EncodingDialog.java b/libraries/sharedCode/src/main/java/sharedcode/turboeditor/dialogfragment/EncodingDialog.java index 369d4a7..ee7d769 100644 --- a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/dialogfragment/EncodingDialog.java +++ b/libraries/sharedCode/src/main/java/sharedcode/turboeditor/dialogfragment/EncodingDialog.java @@ -60,6 +60,7 @@ public class EncodingDialog extends DialogFragment implements AdapterView.OnItem Constants.CHARSET_UTF_32BE, Constants.CHARSET_UTF_32LE, Constants.CHARSET_UTF_8, + "UTF-16", Constants.CHARSET_WINDOWS_1251, Constants.CHARSET_WINDOWS_1252, Constants.CHARSET_WINDOWS_1253, diff --git a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/dialogfragment/FindTextDialog.java b/libraries/sharedCode/src/main/java/sharedcode/turboeditor/dialogfragment/FindTextDialog.java index a628871..ec3557c 100644 --- a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/dialogfragment/FindTextDialog.java +++ b/libraries/sharedCode/src/main/java/sharedcode/turboeditor/dialogfragment/FindTextDialog.java @@ -193,7 +193,7 @@ public class FindTextDialog extends DialogFragment { return; // else we return positions and other things else { - SearchResult searchResult = new SearchResult(foundIndex, textToFind.length(), replaceCheck.isChecked(), textToReplace.getText().toString()); + SearchResult searchResult = new SearchResult(foundIndex, textToFind.length(), replaceCheck.isChecked(), textToFind.getText().toString(), textToReplace.getText().toString()); searchDialogInterface.onSearchDone(searchResult); } } else { diff --git a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/dialogfragment/NewFileDetailsDialog.java b/libraries/sharedCode/src/main/java/sharedcode/turboeditor/dialogfragment/NewFileDetailsDialog.java index 14e3b4f..d34d9a3 100644 --- a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/dialogfragment/NewFileDetailsDialog.java +++ b/libraries/sharedCode/src/main/java/sharedcode/turboeditor/dialogfragment/NewFileDetailsDialog.java @@ -24,16 +24,21 @@ import android.app.Dialog; import android.app.DialogFragment; import android.content.DialogInterface; import android.os.Bundle; +import android.text.TextUtils; import android.view.View; import android.view.WindowManager; +import android.widget.CheckBox; import android.widget.EditText; +import org.apache.commons.io.FileUtils; + import java.io.File; import sharedcode.turboeditor.R; import sharedcode.turboeditor.activity.MainActivity; import sharedcode.turboeditor.preferences.PreferenceHelper; import sharedcode.turboeditor.task.SaveFileTask; +import sharedcode.turboeditor.util.ViewUtils; import sharedcode.turboeditor.views.DialogHelper; // ... @@ -41,10 +46,13 @@ public class NewFileDetailsDialog extends DialogFragment { private EditText mName; private EditText mFolder; + private CheckBox mDeleteCurrentFile; - public static NewFileDetailsDialog newInstance(String fileText, String fileEncoding) { + public static NewFileDetailsDialog newInstance(String currentPath, String currentName, String fileText, String fileEncoding) { final NewFileDetailsDialog f = new NewFileDetailsDialog(); final Bundle args = new Bundle(); + args.putString("path", currentPath); + args.putString("name", currentName); args.putString("fileText", fileText); args.putString("fileEncoding", fileEncoding); f.setArguments(args); @@ -55,15 +63,29 @@ public class NewFileDetailsDialog extends DialogFragment { public Dialog onCreateDialog(Bundle savedInstanceState) { View view = new DialogHelper.Builder(getActivity()) - .setTitle(R.string.file) + .setTitle(R.string.save_as) .setView(R.layout.dialog_fragment_new_file_details) .createSkeletonView(); this.mName = (EditText) view.findViewById(android.R.id.text1); this.mFolder = (EditText) view.findViewById(android.R.id.text2); - this.mName.setText(".txt"); - this.mFolder.setText(PreferenceHelper.getWorkingFolder(getActivity())); + boolean noName = TextUtils.isEmpty(getArguments().getString("name")); + boolean noPath = TextUtils.isEmpty(getArguments().getString("path")); + + if (noName) { + this.mName.setText(".txt"); + } else { + this.mName.setText(getArguments().getString("name")); + } + if (noPath) { + this.mFolder.setText(PreferenceHelper.getWorkingFolder(getActivity())); + } else { + this.mFolder.setText(getArguments().getString("path")); + } + + this.mDeleteCurrentFile = (CheckBox) view.findViewById(R.id.delete_current_file); + ViewUtils.setVisible(mDeleteCurrentFile, !noName); // Show soft keyboard automatically this.mName.requestFocus(); @@ -76,6 +98,11 @@ public class NewFileDetailsDialog extends DialogFragment { new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { + + if (mDeleteCurrentFile.isChecked()) { + FileUtils.deleteQuietly(new File(getArguments().getString("path"), getArguments().getString("name"))); + } + if (!mName.getText().toString().isEmpty() && !mFolder.getText().toString().isEmpty()) { File file = new File(mFolder.getText().toString(), mName.getText().toString()); new SaveFileTask((MainActivity) getActivity(), file.getPath(), getArguments().getString("fileText"), getArguments().getString("fileEncoding")).execute(); diff --git a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/dialogfragment/SaveFileDialog.java b/libraries/sharedCode/src/main/java/sharedcode/turboeditor/dialogfragment/SaveFileDialog.java index bd7f44c..c60f236 100644 --- a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/dialogfragment/SaveFileDialog.java +++ b/libraries/sharedCode/src/main/java/sharedcode/turboeditor/dialogfragment/SaveFileDialog.java @@ -80,7 +80,7 @@ public class SaveFileDialog extends DialogFragment { encoding).execute(); else { NewFileDetailsDialog dialogFrag = - NewFileDetailsDialog.newInstance(text, + NewFileDetailsDialog.newInstance("","",text, encoding); dialogFrag.show(getFragmentManager().beginTransaction(), "dialog"); diff --git a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/Donation.java b/libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/Donation.java deleted file mode 100644 index 2a0bc10..0000000 --- a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/Donation.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2014 Vlad Mihalachi - * - * This file is part of Turbo Editor. - * - * Turbo Editor is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Turbo Editor is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package sharedcode.turboeditor.iab; - - -import org.apache.commons.lang3.builder.EqualsBuilder; -import org.apache.commons.lang3.builder.HashCodeBuilder; - -/** - * The helper class of donation item. - * - * @author Artem Chepurnoy - */ -public class Donation { - - public final int amount; - public final String sku; - public final String text; - - public Donation(int amount, String text) { - this.amount = amount; - this.text = text; - - // Notice that all of them are defined in - // my Play Store's account! - this.sku = "donation_" + amount; - } - - /** - * {@inheritDoc} - */ - @Override - public int hashCode() { - return new HashCodeBuilder(9, 51) - .append(amount) - .append(text) - .append(sku) - .toHashCode(); - } - - /** - * {@inheritDoc} - */ - @Override - public boolean equals(Object o) { - if (o == null) - return false; - if (o == this) - return true; - if (!(o instanceof Donation)) - return false; - - Donation donation = (Donation) o; - return new EqualsBuilder() - .append(amount, donation.amount) - .append(text, donation.text) - .append(sku, donation.sku) - .isEquals(); - } - -} diff --git a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/DonationAdapter.java b/libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/DonationAdapter.java deleted file mode 100644 index 958f807..0000000 --- a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/DonationAdapter.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2014 Vlad Mihalachi - * - * This file is part of Turbo Editor. - * - * Turbo Editor is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Turbo Editor is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package sharedcode.turboeditor.iab; - -import android.content.Context; -import android.content.res.Resources; -import android.graphics.Paint; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.TextView; - -import java.util.HashSet; - -import sharedcode.turboeditor.R; - -/** - * Created by achep on 06.05.14 for AcDisplay. - * - * @author Artem Chepurnoy - */ -public class DonationAdapter extends ArrayAdapter { - - private final HashSet mInventorySet; - private final LayoutInflater mInflater; - private final String mDonationAmountLabel; - - private final int mColorNormal; - private final int mColorPurchased; - - public DonationAdapter(Context context, Donation[] items, HashSet inventory) { - super(context, 0, items); - - mInventorySet = inventory; - mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - - Resources res = context.getResources(); - mDonationAmountLabel = res.getString(R.string.donation_item_label); - mColorNormal = res.getColor(R.color.donation_normal); - mColorPurchased = res.getColor(R.color.donation_purchased); - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - final Donation donation = getItem(position); - final Holder holder; - final View view; - - if (convertView == null) { - holder = new Holder(); - view = mInflater.inflate(R.layout.donation_iab_item, parent, false); - assert view != null; - - holder.title = (TextView) view.findViewById(android.R.id.title); - holder.summary = (TextView) view.findViewById(android.R.id.summary); - - view.setTag(holder); - } else { - view = convertView; - holder = (Holder) view.getTag(); - } - - boolean bought = mInventorySet.contains(donation.sku); - - String amount = Integer.toString(donation.amount); - holder.title.setText(String.format(mDonationAmountLabel, amount)); - holder.title.setTextColor(bought ? mColorNormal : mColorPurchased); - holder.summary.setText(donation.text); - holder.summary.setPaintFlags(bought - ? holder.summary.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG - : holder.summary.getPaintFlags() & (~Paint.STRIKE_THRU_TEXT_FLAG)); - - return view; - } - - private static class Holder { - TextView title; - TextView summary; - } -} diff --git a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/DonationFragment.java b/libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/DonationFragment.java deleted file mode 100644 index 12e592f..0000000 --- a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/DonationFragment.java +++ /dev/null @@ -1,370 +0,0 @@ -/* - * Copyright (C) 2014 Vlad Mihalachi - * - * This file is part of Turbo Editor. - * - * Turbo Editor is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Turbo Editor is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package sharedcode.turboeditor.iab; - -import android.app.Activity; -import android.app.AlertDialog; -import android.app.Dialog; -import android.app.DialogFragment; -import android.content.ActivityNotFoundException; -import android.content.DialogInterface; -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.text.Html; -import android.text.Spannable; -import android.text.SpannableString; -import android.text.method.LinkMovementMethod; -import android.text.style.ImageSpan; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.Button; -import android.widget.GridView; -import android.widget.LinearLayout; -import android.widget.ProgressBar; -import android.widget.TextView; - -import java.util.HashSet; - -import sharedcode.turboeditor.R; -import sharedcode.turboeditor.iab.utils.IabHelper; -import sharedcode.turboeditor.iab.utils.IabResult; -import sharedcode.turboeditor.iab.utils.Inventory; -import sharedcode.turboeditor.iab.utils.Purchase; -import sharedcode.turboeditor.preferences.PreferenceHelper; -import sharedcode.turboeditor.util.Build; -import sharedcode.turboeditor.util.ToastUtils; -import sharedcode.turboeditor.util.ViewUtils; -import sharedcode.turboeditor.views.DialogHelper; - -/** - * Fragment that represents an ability to donate to me. Be sure to redirect - * {@link android.app.Activity#onActivityResult(int, int, android.content.Intent)} - * to this fragment! - * - * @author Artem Chepurnoy - */ -public class DonationFragment extends DialogFragment { - - public static final int RC_REQUEST = 10001; - private static final String TAG = "DonationFragment"; - private final HashSet mInventorySet = new HashSet<>(); - private GridView mGridView; - private ProgressBar mProgressBar; - private TextView mError; - private IabHelper mHelper; - private final IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = - new IabHelper.OnIabPurchaseFinishedListener() { - public void onIabPurchaseFinished(IabResult result, Purchase purchase) { - if (mHelper == null) return; - if (result.isFailure()) { - complain("Error purchasing: " + result); - setWaitScreen(false); - return; - } - - if (!verifyDeveloperPayload(purchase)) { - complain("Error purchasing. Authenticity verification failed."); - setWaitScreen(false); - return; - } - - // else, it is a success, the user has donated! - String sku = purchase.getSku(); - mInventorySet.add(sku); - PreferenceHelper.setHasDonated(getActivity(), true); - } - }; - private Donation[] mDonationList; - private final IabHelper.QueryInventoryFinishedListener mGotInventoryListener = - new IabHelper.QueryInventoryFinishedListener() { - public void onQueryInventoryFinished(IabResult result, Inventory inventory) { - if (mHelper == null) return; - if (result.isFailure()) { - complain("Failed to query inventory: " + result); - return; - } - - mInventorySet.clear(); - for (Donation donation : mDonationList) { - Purchase purchase = inventory.getPurchase(donation.sku); - boolean isBought = (purchase != null && verifyDeveloperPayload(purchase)); - - if (isBought) { - mInventorySet.add(donation.sku); - PreferenceHelper.setHasDonated(getActivity(), true); - } - } - - /* - // Fake items to debug user interface. - mInventorySet.add(mDonationList[0].sku); - mInventorySet.add(mDonationList[1].sku); - mInventorySet.add(mDonationList[2].sku); - */ - - updateUi(); - setWaitScreen(false); - } - }; - - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - mDonationList = DonationItems.get(getResources()); - } - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - Activity activity = getActivity(); - assert activity != null; - - View view = new DialogHelper.Builder(activity) - .setTitle(R.string.donation_title) - .setView(R.layout.donation_dialog) - .createSkeletonView(); - AlertDialog.Builder builder = new AlertDialog.Builder(activity) - .setView(view) - .setNegativeButton(android.R.string.cancel, null); - - TextView info = (TextView) view.findViewById(R.id.info); - info.setText(Html.fromHtml(getString(R.string.donation_info))); - info.setMovementMethod(new LinkMovementMethod()); - - mError = (TextView) view.findViewById(R.id.error); - mProgressBar = (ProgressBar) view.findViewById(android.R.id.progress); - mGridView = (GridView) view.findViewById(R.id.grid); - mGridView.setAdapter(new DonationAdapter(getActivity(), mDonationList, mInventorySet)); - mGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() { - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - DonationAdapter adapter = (DonationAdapter) parent.getAdapter(); - Donation donation = adapter.getItem(position); - - if (!mInventorySet.contains(donation.sku)) { - /** - * See {@link sharedcode.turboeditor.iab.DonationFragment#verifyDeveloperPayload(Purchase)}. - */ - String payload = ""; - try { - mHelper.launchPurchaseFlow( - getActivity(), donation.sku, RC_REQUEST, - mPurchaseFinishedListener, payload); - } catch (Exception e) { - ToastUtils.showShort(getActivity(), "Failed to launch a purchase flow."); - } - } else { - ToastUtils.showShort(getActivity(), getString(R.string.donation_item_bought)); - } - } - }); - - final AlertDialog alertDialog; - - // Show PayPal button. - final Intent paypalIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(Build.Links.DONATE)); - builder.setNeutralButton(R.string.paypal, null); - - alertDialog = builder.create(); - alertDialog.setOnShowListener(new DialogInterface.OnShowListener() { - - @Override - public void onShow(DialogInterface dialog) { - Data[] datas = new Data[]{ - new Data( - alertDialog.getButton(DialogInterface.BUTTON_NEUTRAL), - paypalIntent, R.drawable.ic_action_paypal) - }; - - ImageSpan span; - SpannableString text; - for (final Data data : datas) { - final Button btn = data.button; - if (btn != null) { - span = new ImageSpan(getActivity(), data.iconResource); - - // Replace text with an icon. - // This is a workaround to fix compound button's aligment. - text = new SpannableString(" "); - text.setSpan(span, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - btn.setText(text); - - // Eat default weight. - btn.setLayoutParams(new LinearLayout.LayoutParams( - ViewGroup.LayoutParams.WRAP_CONTENT, - ViewGroup.LayoutParams.WRAP_CONTENT)); - - btn.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - startPaymentIntentWithWarningAlertDialog(data.intent); - } - }); - } - } - } - - final class Data { - - private final Button button; - private final Intent intent; - private final int iconResource; - - private Data(Button button, Intent intent, int iconResource) { - this.button = button; - this.intent = intent; - this.iconResource = iconResource; - } - } - }); - - initBilling(); - - return alertDialog; - } - - /** - * Shows a warning alert dialog to note, that those methods - * may suck hard and nobody will care about it.
- * Starts an intent if user is agree with it. - */ - private void startPaymentIntentWithWarningAlertDialog(final Intent intent) { - CharSequence messageText = getString(R.string.donation_no_responsibility); - new DialogHelper.Builder(getActivity()) - .setMessage(messageText) - .wrap() - .setNegativeButton(android.R.string.cancel, null) - .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - try { - startActivity(intent); - dismiss(); // Dismiss main fragment - } catch (ActivityNotFoundException e) { /* hell no */ } - } - }) - .create() - .show(); - } - - private void setWaitScreen(boolean loading) { - ViewUtils.setVisible(mProgressBar, loading); - ViewUtils.setVisible(mGridView, !loading); - ViewUtils.setVisible(mError, false); - } - - private void setErrorScreen(String errorMessage, final Runnable runnable) { - mProgressBar.setVisibility(View.GONE); - mGridView.setVisibility(View.GONE); - mError.setVisibility(View.VISIBLE); - mError.setText(errorMessage); - mError.setOnClickListener(runnable != null ? new View.OnClickListener() { - @Override - public void onClick(View v) { - runnable.run(); - } - } : null); - } - - /** - * Updates GUI to display changes. - */ - private void updateUi() { - DonationAdapter adapter = (DonationAdapter) mGridView.getAdapter(); - adapter.notifyDataSetChanged(); - } - - @Override - public void onDestroy() { - super.onDestroy(); - disposeBilling(); - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - if (mHelper.handleActivityResult(requestCode, resultCode, data)) { - return; - } - - super.onActivityResult(requestCode, resultCode, data); - } - - /** - * Releases billing service. - * - * @see #initBilling() - */ - private void disposeBilling() { - if (mHelper != null) { - mHelper.dispose(); - mHelper = null; - } - } - - /** - * Make sure you call {@link #disposeBilling()}! - * - * @see #disposeBilling() - */ - private void initBilling() { - setWaitScreen(true); - disposeBilling(); - - String base64EncodedPublicKey = Build.GOOGLE_PLAY_PUBLIC_KEY; - mHelper = new IabHelper(getActivity(), base64EncodedPublicKey); - mHelper.enableDebugLogging(Build.DEBUG); - mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() { - public void onIabSetupFinished(IabResult result) { - if (mHelper == null) return; - if (!result.isSuccess()) { - setErrorScreen(getString(R.string.donation_error_iab_setup), new Runnable() { - @Override - public void run() { - // Try to initialize billings again. - initBilling(); - } - }); - return; - } - - setWaitScreen(false); - mHelper.queryInventoryAsync(mGotInventoryListener); - } - }); - } - - private boolean verifyDeveloperPayload(Purchase purchase) { - // TODO: This method itself is a big question. - // Personally, I think that this whole ‘best practices’ part - // is confusing and is trying to make you do work that the API - // should really be doing. Since the purchase is tied to a Google account, - // and the Play Store obviously saves this information, they should - // just give you this in the purchase details. Getting a proper user ID - // requires additional permissions that you shouldn’t need to add just - // to cover for the deficiencies of the IAB API. - return true; - } - - private void complain(String message) { - ToastUtils.showShort(getActivity(), message); - } - -} diff --git a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/DonationItems.java b/libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/DonationItems.java deleted file mode 100644 index 34a3db1..0000000 --- a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/DonationItems.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2014 Vlad Mihalachi - * - * This file is part of Turbo Editor. - * - * Turbo Editor is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Turbo Editor is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package sharedcode.turboeditor.iab; - -import android.content.res.Resources; - -import sharedcode.turboeditor.R; - -/** - * Created by achep on 07.05.14 for AcDisplay. - * - * @author Artem Chepurnoy - */ -public class DonationItems { - - public static Donation[] get(Resources res) { - int[] data = new int[]{ - 2, R.string.donation_2, - 4, R.string.donation_4, - 10, R.string.donation_10, - 20, R.string.donation_20, - 50, R.string.donation_50, - 99, R.string.donation_99, - }; - - Donation[] donation = new Donation[data.length / 2]; - - int length = donation.length; - for (int i = 0; i < length; i++) { - donation[i] = new Donation(data[i * 2], - res.getString(data[i * 2 + 1])); - } - return donation; - } - -} diff --git a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/utils/Base64.java b/libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/utils/Base64.java deleted file mode 100644 index 94b7d50..0000000 --- a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/utils/Base64.java +++ /dev/null @@ -1,582 +0,0 @@ -// Portions copyright 2002, Google, Inc. -// -// 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 sharedcode.turboeditor.iab.utils; - -// This code was converted from code at http://iharder.sourceforge.net/base64/ -// Lots of extraneous features were removed. -/* The original code said: - *

- * I am placing this code in the Public Domain. Do with it as you will. - * This software comes with no guarantees or warranties but with - * plenty of well-wishing instead! - * Please visit - * http://iharder.net/xmlizable - * periodically to check for updates or to contribute improvements. - *

- * - * @author Robert Harder - * @author rharder@usa.net - * @version 1.3 - */ - -/** - * Base64 converter class. This code is not a complete MIME encoder; - * it simply converts binary data to base64 data and back. - *

- *

Note {@link CharBase64} is a GWT-compatible implementation of this - * class. - */ -public class Base64 { - /** - * Specify encoding (value is {@code true}). - */ - public final static boolean ENCODE = true; - - /** - * Specify decoding (value is {@code false}). - */ - public final static boolean DECODE = false; - - /** - * The equals sign (=) as a byte. - */ - private final static byte EQUALS_SIGN = (byte) '='; - - /** - * The new line character (\n) as a byte. - */ - private final static byte NEW_LINE = (byte) '\n'; - - /** - * The 64 valid Base64 values. - */ - private final static byte[] ALPHABET = - {(byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', - (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', - (byte) 'L', (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P', - (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', - (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z', - (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', - (byte) 'f', (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', - (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o', - (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', - (byte) 'u', (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', - (byte) 'z', (byte) '0', (byte) '1', (byte) '2', (byte) '3', - (byte) '4', (byte) '5', (byte) '6', (byte) '7', (byte) '8', - (byte) '9', (byte) '+', (byte) '/'}; - - /** - * The 64 valid web safe Base64 values. - */ - private final static byte[] WEBSAFE_ALPHABET = - {(byte) 'A', (byte) 'B', (byte) 'C', (byte) 'D', (byte) 'E', (byte) 'F', - (byte) 'G', (byte) 'H', (byte) 'I', (byte) 'J', (byte) 'K', - (byte) 'L', (byte) 'M', (byte) 'N', (byte) 'O', (byte) 'P', - (byte) 'Q', (byte) 'R', (byte) 'S', (byte) 'T', (byte) 'U', - (byte) 'V', (byte) 'W', (byte) 'X', (byte) 'Y', (byte) 'Z', - (byte) 'a', (byte) 'b', (byte) 'c', (byte) 'd', (byte) 'e', - (byte) 'f', (byte) 'g', (byte) 'h', (byte) 'i', (byte) 'j', - (byte) 'k', (byte) 'l', (byte) 'm', (byte) 'n', (byte) 'o', - (byte) 'p', (byte) 'q', (byte) 'r', (byte) 's', (byte) 't', - (byte) 'u', (byte) 'v', (byte) 'w', (byte) 'x', (byte) 'y', - (byte) 'z', (byte) '0', (byte) '1', (byte) '2', (byte) '3', - (byte) '4', (byte) '5', (byte) '6', (byte) '7', (byte) '8', - (byte) '9', (byte) '-', (byte) '_'}; - - /** - * Translates a Base64 value to either its 6-bit reconstruction value - * or a negative number indicating some other meaning. - */ - private final static byte[] DECODABET = {-9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 0 - 8 - -5, -5, // Whitespace: Tab and Linefeed - -9, -9, // Decimal 11 - 12 - -5, // Whitespace: Carriage Return - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26 - -9, -9, -9, -9, -9, // Decimal 27 - 31 - -5, // Whitespace: Space - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42 - 62, // Plus sign at decimal 43 - -9, -9, -9, // Decimal 44 - 46 - 63, // Slash at decimal 47 - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine - -9, -9, -9, // Decimal 58 - 60 - -1, // Equals sign at decimal 61 - -9, -9, -9, // Decimal 62 - 64 - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' through 'N' - 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O' through 'Z' - -9, -9, -9, -9, -9, -9, // Decimal 91 - 96 - 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a' through 'm' - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n' through 'z' - -9, -9, -9, -9, -9 // Decimal 123 - 127 - /* ,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 128 - 139 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */ - }; - - /** - * The web safe decodabet - */ - private final static byte[] WEBSAFE_DECODABET = - {-9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 0 - 8 - -5, -5, // Whitespace: Tab and Linefeed - -9, -9, // Decimal 11 - 12 - -5, // Whitespace: Carriage Return - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26 - -9, -9, -9, -9, -9, // Decimal 27 - 31 - -5, // Whitespace: Space - -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 44 - 62, // Dash '-' sign at decimal 45 - -9, -9, // Decimal 46-47 - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine - -9, -9, -9, // Decimal 58 - 60 - -1, // Equals sign at decimal 61 - -9, -9, -9, // Decimal 62 - 64 - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters 'A' through 'N' - 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters 'O' through 'Z' - -9, -9, -9, -9, // Decimal 91-94 - 63, // Underscore '_' at decimal 95 - -9, // Decimal 96 - 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters 'a' through 'm' - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters 'n' through 'z' - -9, -9, -9, -9, -9 // Decimal 123 - 127 - /* ,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 128 - 139 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243 - -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */ - }; - - // Indicates white space in encoding - private final static byte WHITE_SPACE_ENC = -5; - // Indicates equals sign in encoding - private final static byte EQUALS_SIGN_ENC = -1; - - /** - * Defeats instantiation. - */ - private Base64() { - } - - /* ******** E N C O D I N G M E T H O D S ******** */ - - /** - * Encodes up to three bytes of the array source - * and writes the resulting four Base64 bytes to destination. - * The source and destination arrays can be manipulated - * anywhere along their length by specifying - * srcOffset and destOffset. - * This method does not check to make sure your arrays - * are large enough to accommodate srcOffset + 3 for - * the source array or destOffset + 4 for - * the destination array. - * The actual number of significant bytes in your array is - * given by numSigBytes. - * - * @param source the array to convert - * @param srcOffset the index where conversion begins - * @param numSigBytes the number of significant bytes in your array - * @param destination the array to hold the conversion - * @param destOffset the index where output will be put - * @param alphabet is the encoding alphabet - * @return the destination array - * @since 1.3 - */ - private static byte[] encode3to4(byte[] source, int srcOffset, - int numSigBytes, byte[] destination, int destOffset, byte[] alphabet) { - // 1 2 3 - // 01234567890123456789012345678901 Bit position - // --------000000001111111122222222 Array position from threeBytes - // --------| || || || | Six bit groups to index alphabet - // >>18 >>12 >> 6 >> 0 Right shift necessary - // 0x3f 0x3f 0x3f Additional AND - - // Create buffer with zero-padding if there are only one or two - // significant bytes passed in the array. - // We have to shift left 24 in order to flush out the 1's that appear - // when Java treats a value as negative that is cast from a byte to an int. - int inBuff = - (numSigBytes > 0 ? ((source[srcOffset] << 24) >>> 8) : 0) - | (numSigBytes > 1 ? ((source[srcOffset + 1] << 24) >>> 16) : 0) - | (numSigBytes > 2 ? ((source[srcOffset + 2] << 24) >>> 24) : 0); - - switch (numSigBytes) { - case 3: - destination[destOffset] = alphabet[(inBuff >>> 18)]; - destination[destOffset + 1] = alphabet[(inBuff >>> 12) & 0x3f]; - destination[destOffset + 2] = alphabet[(inBuff >>> 6) & 0x3f]; - destination[destOffset + 3] = alphabet[(inBuff) & 0x3f]; - return destination; - case 2: - destination[destOffset] = alphabet[(inBuff >>> 18)]; - destination[destOffset + 1] = alphabet[(inBuff >>> 12) & 0x3f]; - destination[destOffset + 2] = alphabet[(inBuff >>> 6) & 0x3f]; - destination[destOffset + 3] = EQUALS_SIGN; - return destination; - case 1: - destination[destOffset] = alphabet[(inBuff >>> 18)]; - destination[destOffset + 1] = alphabet[(inBuff >>> 12) & 0x3f]; - destination[destOffset + 2] = EQUALS_SIGN; - destination[destOffset + 3] = EQUALS_SIGN; - return destination; - default: - return destination; - } // end switch - } // end encode3to4 - - /** - * Encodes a byte array into Base64 notation. - * Equivalent to calling - * {@code encodeBytes(source, 0, source.length)} - * - * @param source The data to convert - * @since 1.4 - */ - public static String encode(byte[] source) { - return encode(source, 0, source.length, ALPHABET, true); - } - - /** - * Encodes a byte array into web safe Base64 notation. - * - * @param source The data to convert - * @param doPadding is {@code true} to pad result with '=' chars - * if it does not fall on 3 byte boundaries - */ - public static String encodeWebSafe(byte[] source, boolean doPadding) { - return encode(source, 0, source.length, WEBSAFE_ALPHABET, doPadding); - } - - /** - * Encodes a byte array into Base64 notation. - * - * @param source the data to convert - * @param off offset in array where conversion should begin - * @param len length of data to convert - * @param alphabet the encoding alphabet - * @param doPadding is {@code true} to pad result with '=' chars - * if it does not fall on 3 byte boundaries - * @since 1.4 - */ - public static String encode(byte[] source, int off, int len, byte[] alphabet, - boolean doPadding) { - byte[] outBuff = encode(source, off, len, alphabet, Integer.MAX_VALUE); - int outLen = outBuff.length; - - // If doPadding is false, set length to truncate '=' - // padding characters - while (doPadding == false && outLen > 0) { - if (outBuff[outLen - 1] != '=') { - break; - } - outLen -= 1; - } - - return new String(outBuff, 0, outLen); - } - - /** - * Encodes a byte array into Base64 notation. - * - * @param source the data to convert - * @param off offset in array where conversion should begin - * @param len length of data to convert - * @param alphabet is the encoding alphabet - * @param maxLineLength maximum length of one line. - * @return the BASE64-encoded byte array - */ - public static byte[] encode(byte[] source, int off, int len, byte[] alphabet, - int maxLineLength) { - int lenDiv3 = (len + 2) / 3; // ceil(len / 3) - int len43 = lenDiv3 * 4; - byte[] outBuff = new byte[len43 // Main 4:3 - + (len43 / maxLineLength)]; // New lines - - int d = 0; - int e = 0; - int len2 = len - 2; - int lineLength = 0; - for (; d < len2; d += 3, e += 4) { - - // The following block of code is the same as - // encode3to4( source, d + off, 3, outBuff, e, alphabet ); - // but inlined for faster encoding (~20% improvement) - int inBuff = - ((source[d + off] << 24) >>> 8) - | ((source[d + 1 + off] << 24) >>> 16) - | ((source[d + 2 + off] << 24) >>> 24); - outBuff[e] = alphabet[(inBuff >>> 18)]; - outBuff[e + 1] = alphabet[(inBuff >>> 12) & 0x3f]; - outBuff[e + 2] = alphabet[(inBuff >>> 6) & 0x3f]; - outBuff[e + 3] = alphabet[(inBuff) & 0x3f]; - - lineLength += 4; - if (lineLength == maxLineLength) { - outBuff[e + 4] = NEW_LINE; - e++; - lineLength = 0; - } // end if: end of line - } // end for: each piece of array - - if (d < len) { - encode3to4(source, d + off, len - d, outBuff, e, alphabet); - - lineLength += 4; - if (lineLength == maxLineLength) { - // Add a last newline - outBuff[e + 4] = NEW_LINE; - e++; - } - e += 4; - } - - assert (e == outBuff.length); - return outBuff; - } - - - /* ******** D E C O D I N G M E T H O D S ******** */ - - - /** - * Decodes four bytes from array source - * and writes the resulting bytes (up to three of them) - * to destination. - * The source and destination arrays can be manipulated - * anywhere along their length by specifying - * srcOffset and destOffset. - * This method does not check to make sure your arrays - * are large enough to accommodate srcOffset + 4 for - * the source array or destOffset + 3 for - * the destination array. - * This method returns the actual number of bytes that - * were converted from the Base64 encoding. - * - * @param source the array to convert - * @param srcOffset the index where conversion begins - * @param destination the array to hold the conversion - * @param destOffset the index where output will be put - * @param decodabet the decodabet for decoding Base64 content - * @return the number of decoded bytes converted - * @since 1.3 - */ - private static int decode4to3(byte[] source, int srcOffset, - byte[] destination, int destOffset, byte[] decodabet) { - // Example: Dk== - if (source[srcOffset + 2] == EQUALS_SIGN) { - int outBuff = - ((decodabet[source[srcOffset]] << 24) >>> 6) - | ((decodabet[source[srcOffset + 1]] << 24) >>> 12); - - destination[destOffset] = (byte) (outBuff >>> 16); - return 1; - } else if (source[srcOffset + 3] == EQUALS_SIGN) { - // Example: DkL= - int outBuff = - ((decodabet[source[srcOffset]] << 24) >>> 6) - | ((decodabet[source[srcOffset + 1]] << 24) >>> 12) - | ((decodabet[source[srcOffset + 2]] << 24) >>> 18); - - destination[destOffset] = (byte) (outBuff >>> 16); - destination[destOffset + 1] = (byte) (outBuff >>> 8); - return 2; - } else { - // Example: DkLE - int outBuff = - ((decodabet[source[srcOffset]] << 24) >>> 6) - | ((decodabet[source[srcOffset + 1]] << 24) >>> 12) - | ((decodabet[source[srcOffset + 2]] << 24) >>> 18) - | ((decodabet[source[srcOffset + 3]] << 24) >>> 24); - - destination[destOffset] = (byte) (outBuff >> 16); - destination[destOffset + 1] = (byte) (outBuff >> 8); - destination[destOffset + 2] = (byte) (outBuff); - return 3; - } - } // end decodeToBytes - - - /** - * Decodes data from Base64 notation. - * - * @param s the string to decode (decoded in default encoding) - * @return the decoded data - * @since 1.4 - */ - public static byte[] decode(String s) throws Base64DecoderException { - byte[] bytes = s.getBytes(); - return decode(bytes, 0, bytes.length); - } - - /** - * Decodes data from web safe Base64 notation. - * Web safe encoding uses '-' instead of '+', '_' instead of '/' - * - * @param s the string to decode (decoded in default encoding) - * @return the decoded data - */ - public static byte[] decodeWebSafe(String s) throws Base64DecoderException { - byte[] bytes = s.getBytes(); - return decodeWebSafe(bytes, 0, bytes.length); - } - - /** - * Decodes Base64 content in byte array format and returns - * the decoded byte array. - * - * @param source The Base64 encoded data - * @return decoded data - * @throws Base64DecoderException - * @since 1.3 - */ - public static byte[] decode(byte[] source) throws Base64DecoderException { - return decode(source, 0, source.length); - } - - /** - * Decodes web safe Base64 content in byte array format and returns - * the decoded data. - * Web safe encoding uses '-' instead of '+', '_' instead of '/' - * - * @param source the string to decode (decoded in default encoding) - * @return the decoded data - */ - public static byte[] decodeWebSafe(byte[] source) - throws Base64DecoderException { - return decodeWebSafe(source, 0, source.length); - } - - /** - * Decodes Base64 content in byte array format and returns - * the decoded byte array. - * - * @param source the Base64 encoded data - * @param off the offset of where to begin decoding - * @param len the length of characters to decode - * @return decoded data - * @throws Base64DecoderException - * @since 1.3 - */ - public static byte[] decode(byte[] source, int off, int len) - throws Base64DecoderException { - return decode(source, off, len, DECODABET); - } - - /** - * Decodes web safe Base64 content in byte array format and returns - * the decoded byte array. - * Web safe encoding uses '-' instead of '+', '_' instead of '/' - * - * @param source the Base64 encoded data - * @param off the offset of where to begin decoding - * @param len the length of characters to decode - * @return decoded data - */ - public static byte[] decodeWebSafe(byte[] source, int off, int len) - throws Base64DecoderException { - return decode(source, off, len, WEBSAFE_DECODABET); - } - - /** - * Decodes Base64 content using the supplied decodabet and returns - * the decoded byte array. - * - * @param source the Base64 encoded data - * @param off the offset of where to begin decoding - * @param len the length of characters to decode - * @param decodabet the decodabet for decoding Base64 content - * @return decoded data - */ - public static byte[] decode(byte[] source, int off, int len, byte[] decodabet) - throws Base64DecoderException { - int len34 = len * 3 / 4; - byte[] outBuff = new byte[2 + len34]; // Upper limit on size of output - int outBuffPosn = 0; - - byte[] b4 = new byte[4]; - int b4Posn = 0; - int i = 0; - byte sbiCrop = 0; - byte sbiDecode = 0; - for (i = 0; i < len; i++) { - sbiCrop = (byte) (source[i + off] & 0x7f); // Only the low seven bits - sbiDecode = decodabet[sbiCrop]; - - if (sbiDecode >= WHITE_SPACE_ENC) { // White space Equals sign or better - if (sbiDecode >= EQUALS_SIGN_ENC) { - // An equals sign (for padding) must not occur at position 0 or 1 - // and must be the last byte[s] in the encoded value - if (sbiCrop == EQUALS_SIGN) { - int bytesLeft = len - i; - byte lastByte = (byte) (source[len - 1 + off] & 0x7f); - if (b4Posn == 0 || b4Posn == 1) { - throw new Base64DecoderException( - "invalid padding byte '=' at byte offset " + i); - } else if ((b4Posn == 3 && bytesLeft > 2) - || (b4Posn == 4 && bytesLeft > 1)) { - throw new Base64DecoderException( - "padding byte '=' falsely signals end of encoded value " - + "at offset " + i - ); - } else if (lastByte != EQUALS_SIGN && lastByte != NEW_LINE) { - throw new Base64DecoderException( - "encoded value has invalid trailing byte"); - } - break; - } - - b4[b4Posn++] = sbiCrop; - if (b4Posn == 4) { - outBuffPosn += decode4to3(b4, 0, outBuff, outBuffPosn, decodabet); - b4Posn = 0; - } - } - } else { - throw new Base64DecoderException("Bad Base64 input character at " + i - + ": " + source[i + off] + "(decimal)"); - } - } - - // Because web safe encoding allows non padding base64 encodes, we - // need to pad the rest of the b4 buffer with equal signs when - // b4Posn != 0. There can be at most 2 equal signs at the end of - // four characters, so the b4 buffer must have two or three - // characters. This also catches the case where the input is - // padded with EQUALS_SIGN - if (b4Posn != 0) { - if (b4Posn == 1) { - throw new Base64DecoderException("single trailing character at offset " - + (len - 1)); - } - b4[b4Posn++] = EQUALS_SIGN; - outBuffPosn += decode4to3(b4, 0, outBuff, outBuffPosn, decodabet); - } - - byte[] out = new byte[outBuffPosn]; - System.arraycopy(outBuff, 0, out, 0, outBuffPosn); - return out; - } -} diff --git a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/utils/IabException.java b/libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/utils/IabException.java deleted file mode 100644 index 2e00564..0000000 --- a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/utils/IabException.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2014 Vlad Mihalachi - * - * This file is part of Turbo Editor. - * - * Turbo Editor is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Turbo Editor is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package sharedcode.turboeditor.iab.utils; - -/** - * Exception thrown when something went wrong with in-app billing. - * An IabException has an associated IabResult (an error). - * To get the IAB result that caused this exception to be thrown, - * call {@link #getResult()}. - */ -public class IabException extends Exception { - IabResult mResult; - - public IabException(IabResult r) { - this(r, null); - } - - public IabException(int response, String message) { - this(new IabResult(response, message)); - } - - public IabException(IabResult r, Exception cause) { - super(r.getMessage(), cause); - mResult = r; - } - - public IabException(int response, String message, Exception cause) { - this(new IabResult(response, message), cause); - } - - /** - * Returns the IAB result (error) that this exception signals. - */ - public IabResult getResult() { - return mResult; - } -} \ No newline at end of file diff --git a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/utils/IabHelper.java b/libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/utils/IabHelper.java deleted file mode 100644 index 61060f0..0000000 --- a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/utils/IabHelper.java +++ /dev/null @@ -1,966 +0,0 @@ -/* - * Copyright (C) 2014 Vlad Mihalachi - * - * This file is part of Turbo Editor. - * - * Turbo Editor is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Turbo Editor is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package sharedcode.turboeditor.iab.utils; - -import android.app.Activity; -import android.app.PendingIntent; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.IntentSender.SendIntentException; -import android.content.ServiceConnection; -import android.content.pm.ResolveInfo; -import android.os.Bundle; -import android.os.Handler; -import android.os.IBinder; -import android.os.RemoteException; -import android.text.TextUtils; -import android.util.Log; - - -import org.json.JSONException; -import com.android.vending.billing.*; - -import java.util.ArrayList; -import java.util.List; - - -/** - * Provides convenience methods for in-app billing. You can create one instance of this - * class for your application and use it to process in-app billing operations. - * It provides synchronous (blocking) and asynchronous (non-blocking) methods for - * many common in-app billing operations, as well as automatic signature - * verification. - *

- * After instantiating, you must perform setup in order to start using the object. - * To perform setup, call the {@link #startSetup} method and provide a listener; - * that listener will be notified when setup is complete, after which (and not before) - * you may call other methods. - *

- * After setup is complete, you will typically want to request an inventory of owned - * items and subscriptions. See {@link #queryInventory}, {@link #queryInventoryAsync} - * and related methods. - *

- * When you are done with this object, don't forget to call {@link #dispose} - * to ensure proper cleanup. This object holds a binding to the in-app billing - * service, which will leak unless you dispose of it correctly. If you created - * the object on an Activity's onCreate method, then the recommended - * place to dispose of it is the Activity's onDestroy method. - *

- * A note about threading: When using this object from a background thread, you may - * call the blocking versions of methods; when using from a UI thread, call - * only the asynchronous versions and handle the results via callbacks. - * Also, notice that you can only call one asynchronous operation at a time; - * attempting to start a second asynchronous operation while the first one - * has not yet completed will result in an exception being thrown. - * - * @author Bruno Oliveira (Google) - */ -public class IabHelper { - // Billing response codes - public static final int BILLING_RESPONSE_RESULT_OK = 0; - public static final int BILLING_RESPONSE_RESULT_USER_CANCELED = 1; - public static final int BILLING_RESPONSE_RESULT_BILLING_UNAVAILABLE = 3; - public static final int BILLING_RESPONSE_RESULT_ITEM_UNAVAILABLE = 4; - public static final int BILLING_RESPONSE_RESULT_DEVELOPER_ERROR = 5; - public static final int BILLING_RESPONSE_RESULT_ERROR = 6; - public static final int BILLING_RESPONSE_RESULT_ITEM_ALREADY_OWNED = 7; - public static final int BILLING_RESPONSE_RESULT_ITEM_NOT_OWNED = 8; - // IAB Helper error codes - public static final int IABHELPER_ERROR_BASE = -1000; - public static final int IABHELPER_REMOTE_EXCEPTION = -1001; - public static final int IABHELPER_BAD_RESPONSE = -1002; - public static final int IABHELPER_VERIFICATION_FAILED = -1003; - public static final int IABHELPER_SEND_INTENT_FAILED = -1004; - public static final int IABHELPER_USER_CANCELLED = -1005; - public static final int IABHELPER_UNKNOWN_PURCHASE_RESPONSE = -1006; - public static final int IABHELPER_MISSING_TOKEN = -1007; - public static final int IABHELPER_UNKNOWN_ERROR = -1008; - public static final int IABHELPER_SUBSCRIPTIONS_NOT_AVAILABLE = -1009; - public static final int IABHELPER_INVALID_CONSUMPTION = -1010; - // Keys for the responses from InAppBillingService - public static final String RESPONSE_CODE = "RESPONSE_CODE"; - public static final String RESPONSE_GET_SKU_DETAILS_LIST = "DETAILS_LIST"; - public static final String RESPONSE_BUY_INTENT = "BUY_INTENT"; - public static final String RESPONSE_INAPP_PURCHASE_DATA = "INAPP_PURCHASE_DATA"; - public static final String RESPONSE_INAPP_SIGNATURE = "INAPP_DATA_SIGNATURE"; - public static final String RESPONSE_INAPP_ITEM_LIST = "INAPP_PURCHASE_ITEM_LIST"; - public static final String RESPONSE_INAPP_PURCHASE_DATA_LIST = "INAPP_PURCHASE_DATA_LIST"; - public static final String RESPONSE_INAPP_SIGNATURE_LIST = "INAPP_DATA_SIGNATURE_LIST"; - public static final String INAPP_CONTINUATION_TOKEN = "INAPP_CONTINUATION_TOKEN"; - // Item types - public static final String ITEM_TYPE_INAPP = "inapp"; - public static final String ITEM_TYPE_SUBS = "subs"; - // some fields on the getSkuDetails response bundle - public static final String GET_SKU_DETAILS_ITEM_LIST = "ITEM_ID_LIST"; - public static final String GET_SKU_DETAILS_ITEM_TYPE_LIST = "ITEM_TYPE_LIST"; - // Is debug logging enabled? - boolean mDebugLog = false; - String mDebugTag = "IabHelper"; - // Is setup done? - boolean mSetupDone = false; - // Has this object been disposed of? (If so, we should ignore callbacks, etc) - boolean mDisposed = false; - boolean mIsBound = false; - // Are subscriptions supported? - boolean mSubscriptionsSupported = false; - // Is an asynchronous operation in progress? - // (only one at a time can be in progress) - boolean mAsyncInProgress = false; - // (for logging/debugging) - // if mAsyncInProgress == true, what asynchronous operation is in progress? - String mAsyncOperation = ""; - // Context we were passed during initialization - Context mContext; - // Connection to the service - IInAppBillingService mService; - ServiceConnection mServiceConn; - // The request code used to launch purchase flow - int mRequestCode; - // The item type of the current purchase flow - String mPurchasingItemType; - // Public key for verifying signature, in base64 encoding - String mSignatureBase64 = null; - // The listener registered on launchPurchaseFlow, which we have to call back when - // the purchase finishes - OnIabPurchaseFinishedListener mPurchaseListener; - - /** - * Creates an instance. After creation, it will not yet be ready to use. You must perform - * setup by calling {@link #startSetup} and wait for setup to complete. This constructor does not - * block and is safe to call from a UI thread. - * - * @param ctx Your application or Activity context. Needed to bind to the in-app billing service. - * @param base64PublicKey Your application's public key, encoded in base64. - * This is used for verification of purchase signatures. You can find your app's base64-encoded - * public key in your application's page on Google Play Developer Console. Note that this - * is NOT your "developer public key". - */ - public IabHelper(Context ctx, String base64PublicKey) { - mContext = ctx.getApplicationContext(); - mSignatureBase64 = base64PublicKey; - logDebug("IAB helper created."); - } - - /** - * Returns a human-readable description for the given response code. - * - * @param code The response code - * @return A human-readable string explaining the result code. - * It also includes the result code numerically. - */ - public static String getResponseDesc(int code) { - String[] iab_msgs = ("0:OK/1:User Canceled/2:Unknown/" + - "3:Billing Unavailable/4:Item unavailable/" + - "5:Developer Error/6:Error/7:Item Already Owned/" + - "8:Item not owned").split("/"); - String[] iabhelper_msgs = ("0:OK/-1001:Remote exception during initialization/" + - "-1002:Bad response received/" + - "-1003:Purchase signature verification failed/" + - "-1004:Send intent failed/" + - "-1005:User cancelled/" + - "-1006:Unknown purchase response/" + - "-1007:Missing token/" + - "-1008:Unknown error/" + - "-1009:Subscriptions not available/" + - "-1010:Invalid consumption attempt").split("/"); - - if (code <= IABHELPER_ERROR_BASE) { - int index = IABHELPER_ERROR_BASE - code; - if (index >= 0 && index < iabhelper_msgs.length) return iabhelper_msgs[index]; - else return String.valueOf(code) + ":Unknown IAB Helper Error"; - } else if (code < 0 || code >= iab_msgs.length) - return String.valueOf(code) + ":Unknown"; - else - return iab_msgs[code]; - } - - /** - * Enables or disable debug logging through LogCat. - */ - public void enableDebugLogging(boolean enable, String tag) { - checkNotDisposed(); - mDebugLog = enable; - mDebugTag = tag; - } - - public void enableDebugLogging(boolean enable) { - checkNotDisposed(); - mDebugLog = enable; - } - - /** - * Starts the setup process. This will start up the setup process asynchronously. - * You will be notified through the listener when the setup process is complete. - * This method is safe to call from a UI thread. - * - * @param listener The listener to notify when the setup process is complete. - */ - public void startSetup(final OnIabSetupFinishedListener listener) { - // If already set up, can't do it again. - checkNotDisposed(); - if (mSetupDone) throw new IllegalStateException("IAB helper is already set up."); - - // Connection to IAB service - logDebug("Starting in-app billing setup."); - mServiceConn = new ServiceConnection() { - @Override - public void onServiceDisconnected(ComponentName name) { - logDebug("Billing service disconnected."); - mService = null; - } - - @Override - public void onServiceConnected(ComponentName name, IBinder service) { - if (mDisposed) return; - logDebug("Billing service connected."); - mService = IInAppBillingService.Stub.asInterface(service); - String packageName = mContext.getPackageName(); - try { - logDebug("Checking for in-app billing 3 support."); - - // check for in-app billing v3 support - int response = mService.isBillingSupported(3, packageName, ITEM_TYPE_INAPP); - if (response != BILLING_RESPONSE_RESULT_OK) { - if (listener != null) listener.onIabSetupFinished(new IabResult(response, - "Error checking for billing v3 support.")); - - // if in-app purchases aren't supported, neither are subscriptions. - mSubscriptionsSupported = false; - return; - } - logDebug("In-app billing version 3 supported for " + packageName); - - // check for v3 subscriptions support - response = mService.isBillingSupported(3, packageName, ITEM_TYPE_SUBS); - if (response == BILLING_RESPONSE_RESULT_OK) { - logDebug("Subscriptions AVAILABLE."); - mSubscriptionsSupported = true; - } else { - logDebug("Subscriptions NOT AVAILABLE. Response: " + response); - } - - mSetupDone = true; - } catch (RemoteException e) { - if (listener != null) { - listener.onIabSetupFinished(new IabResult(IABHELPER_REMOTE_EXCEPTION, - "RemoteException while setting up in-app billing.")); - } - e.printStackTrace(); - return; - } - - if (listener != null) { - listener.onIabSetupFinished(new IabResult(BILLING_RESPONSE_RESULT_OK, "Setup successful.")); - } - } - }; - - Intent serviceIntent = new Intent("com.android.vending.billing.InAppBillingService.BIND"); - serviceIntent.setPackage("com.android.vending"); - List ri = mContext.getPackageManager().queryIntentServices(serviceIntent, 0); - if (ri != null && !ri.isEmpty()) { - // service available to handle that Intent - mIsBound = mContext.bindService(serviceIntent, mServiceConn, Context.BIND_AUTO_CREATE); - } else { - // no service available to handle that Intent - if (listener != null) { - listener.onIabSetupFinished( - new IabResult(BILLING_RESPONSE_RESULT_BILLING_UNAVAILABLE, - "Billing service unavailable on device.") - ); - } - } - } - - /** - * Dispose of object, releasing resources. It's very important to call this - * method when you are done with this object. It will release any resources - * used by it such as service connections. Naturally, once the object is - * disposed of, it can't be used again. - */ - public void dispose() { - logDebug("Disposing."); - mSetupDone = false; - if (mServiceConn != null) { - logDebug("Unbinding from service."); - if (mContext != null && mIsBound) { - mContext.unbindService(mServiceConn); - } - } - mDisposed = true; - mContext = null; - mServiceConn = null; - mService = null; - mPurchaseListener = null; - } - - private void checkNotDisposed() { - if (mDisposed) - throw new IllegalStateException("IabHelper was disposed of, so it cannot be used."); - } - - /** - * Returns whether subscriptions are supported. - */ - public boolean subscriptionsSupported() { - checkNotDisposed(); - return mSubscriptionsSupported; - } - - public void launchPurchaseFlow(Activity act, String sku, int requestCode, OnIabPurchaseFinishedListener listener) { - launchPurchaseFlow(act, sku, requestCode, listener, ""); - } - - public void launchPurchaseFlow(Activity act, String sku, int requestCode, - OnIabPurchaseFinishedListener listener, String extraData) { - launchPurchaseFlow(act, sku, ITEM_TYPE_INAPP, requestCode, listener, extraData); - } - - public void launchSubscriptionPurchaseFlow(Activity act, String sku, int requestCode, - OnIabPurchaseFinishedListener listener) { - launchSubscriptionPurchaseFlow(act, sku, requestCode, listener, ""); - } - - public void launchSubscriptionPurchaseFlow(Activity act, String sku, int requestCode, - OnIabPurchaseFinishedListener listener, String extraData) { - launchPurchaseFlow(act, sku, ITEM_TYPE_SUBS, requestCode, listener, extraData); - } - - /** - * Initiate the UI flow for an in-app purchase. Call this method to initiate an in-app purchase, - * which will involve bringing up the Google Play screen. The calling activity will be paused while - * the user interacts with Google Play, and the result will be delivered via the activity's - * {@link android.app.Activity#onActivityResult} method, at which point you must call - * this object's {@link #handleActivityResult} method to continue the purchase flow. This method - * MUST be called from the UI thread of the Activity. - * - * @param act The calling activity. - * @param sku The sku of the item to purchase. - * @param itemType indicates if it's a product or a subscription (ITEM_TYPE_INAPP or ITEM_TYPE_SUBS) - * @param requestCode A request code (to differentiate from other responses -- - * as in {@link android.app.Activity#startActivityForResult}). - * @param listener The listener to notify when the purchase process finishes - * @param extraData Extra data (developer payload), which will be returned with the purchase data - * when the purchase completes. This extra data will be permanently bound to that purchase - * and will always be returned when the purchase is queried. - */ - public void launchPurchaseFlow(Activity act, String sku, String itemType, int requestCode, - OnIabPurchaseFinishedListener listener, String extraData) { - checkNotDisposed(); - checkSetupDone("launchPurchaseFlow"); - flagStartAsync("launchPurchaseFlow"); - IabResult result; - - if (itemType.equals(ITEM_TYPE_SUBS) && !mSubscriptionsSupported) { - IabResult r = new IabResult(IABHELPER_SUBSCRIPTIONS_NOT_AVAILABLE, - "Subscriptions are not available."); - flagEndAsync(); - if (listener != null) listener.onIabPurchaseFinished(r, null); - return; - } - - try { - logDebug("Constructing buy intent for " + sku + ", item type: " + itemType); - Bundle buyIntentBundle = mService.getBuyIntent(3, mContext.getPackageName(), sku, itemType, extraData); - int response = getResponseCodeFromBundle(buyIntentBundle); - if (response != BILLING_RESPONSE_RESULT_OK) { - logError("Unable to buy item, Error response: " + getResponseDesc(response)); - flagEndAsync(); - result = new IabResult(response, "Unable to buy item"); - if (listener != null) listener.onIabPurchaseFinished(result, null); - return; - } - - PendingIntent pendingIntent = buyIntentBundle.getParcelable(RESPONSE_BUY_INTENT); - logDebug("Launching buy intent for " + sku + ". Request code: " + requestCode); - mRequestCode = requestCode; - mPurchaseListener = listener; - mPurchasingItemType = itemType; - act.startIntentSenderForResult(pendingIntent.getIntentSender(), - requestCode, new Intent(), - 0, 0, - 0); - } catch (SendIntentException e) { - logError("SendIntentException while launching purchase flow for sku " + sku); - e.printStackTrace(); - flagEndAsync(); - - result = new IabResult(IABHELPER_SEND_INTENT_FAILED, "Failed to send intent."); - if (listener != null) listener.onIabPurchaseFinished(result, null); - } catch (RemoteException e) { - logError("RemoteException while launching purchase flow for sku " + sku); - e.printStackTrace(); - flagEndAsync(); - - result = new IabResult(IABHELPER_REMOTE_EXCEPTION, "Remote exception while starting purchase flow"); - if (listener != null) listener.onIabPurchaseFinished(result, null); - } - } - - /** - * Handles an activity result that's part of the purchase flow in in-app billing. If you - * are calling {@link #launchPurchaseFlow}, then you must call this method from your - * Activity's {@link android.app.Activity@onActivityResult} method. This method - * MUST be called from the UI thread of the Activity. - * - * @param requestCode The requestCode as you received it. - * @param resultCode The resultCode as you received it. - * @param data The data (Intent) as you received it. - * @return Returns true if the result was related to a purchase flow and was handled; - * false if the result was not related to a purchase, in which case you should - * handle it normally. - */ - public boolean handleActivityResult(int requestCode, int resultCode, Intent data) { - IabResult result; - if (requestCode != mRequestCode) return false; - - checkNotDisposed(); - checkSetupDone("handleActivityResult"); - - // end of async purchase operation that started on launchPurchaseFlow - flagEndAsync(); - - if (data == null) { - logError("Null data in IAB activity result."); - result = new IabResult(IABHELPER_BAD_RESPONSE, "Null data in IAB result"); - if (mPurchaseListener != null) mPurchaseListener.onIabPurchaseFinished(result, null); - return true; - } - - int responseCode = getResponseCodeFromIntent(data); - String purchaseData = data.getStringExtra(RESPONSE_INAPP_PURCHASE_DATA); - String dataSignature = data.getStringExtra(RESPONSE_INAPP_SIGNATURE); - - if (resultCode == Activity.RESULT_OK && responseCode == BILLING_RESPONSE_RESULT_OK) { - logDebug("Successful resultcode from purchase activity."); - logDebug("Purchase data: " + purchaseData); - logDebug("Data signature: " + dataSignature); - logDebug("Extras: " + data.getExtras()); - logDebug("Expected item type: " + mPurchasingItemType); - - if (purchaseData == null || dataSignature == null) { - logError("BUG: either purchaseData or dataSignature is null."); - logDebug("Extras: " + data.getExtras().toString()); - result = new IabResult(IABHELPER_UNKNOWN_ERROR, "IAB returned null purchaseData or dataSignature"); - if (mPurchaseListener != null) - mPurchaseListener.onIabPurchaseFinished(result, null); - return true; - } - - @SuppressWarnings("UnusedAssignment") Purchase purchase = null; - try { - purchase = new Purchase(mPurchasingItemType, purchaseData, dataSignature); - String sku = purchase.getSku(); - - // Verify signature - if (!Security.verifyPurchase(mSignatureBase64, purchaseData, dataSignature)) { - logError("Purchase signature verification FAILED for sku " + sku); - result = new IabResult(IABHELPER_VERIFICATION_FAILED, "Signature verification failed for sku " + sku); - if (mPurchaseListener != null) - mPurchaseListener.onIabPurchaseFinished(result, purchase); - return true; - } - logDebug("Purchase signature successfully verified."); - } catch (JSONException e) { - logError("Failed to parse purchase data."); - e.printStackTrace(); - result = new IabResult(IABHELPER_BAD_RESPONSE, "Failed to parse purchase data."); - if (mPurchaseListener != null) - mPurchaseListener.onIabPurchaseFinished(result, null); - return true; - } - - if (mPurchaseListener != null) { - mPurchaseListener.onIabPurchaseFinished(new IabResult(BILLING_RESPONSE_RESULT_OK, "Success"), purchase); - } - } else if (resultCode == Activity.RESULT_OK) { - // result code was OK, but in-app billing response was not OK. - logDebug("Result code was OK but in-app billing response was not OK: " + getResponseDesc(responseCode)); - if (mPurchaseListener != null) { - result = new IabResult(responseCode, "Problem purchashing item."); - mPurchaseListener.onIabPurchaseFinished(result, null); - } - } else if (resultCode == Activity.RESULT_CANCELED) { - logDebug("Purchase canceled - Response: " + getResponseDesc(responseCode)); - result = new IabResult(IABHELPER_USER_CANCELLED, "User canceled."); - if (mPurchaseListener != null) mPurchaseListener.onIabPurchaseFinished(result, null); - } else { - logError("Purchase failed. Result code: " + Integer.toString(resultCode) - + ". Response: " + getResponseDesc(responseCode)); - result = new IabResult(IABHELPER_UNKNOWN_PURCHASE_RESPONSE, "Unknown purchase response."); - if (mPurchaseListener != null) mPurchaseListener.onIabPurchaseFinished(result, null); - } - return true; - } - - public Inventory queryInventory(boolean querySkuDetails, List moreSkus) throws IabException { - return queryInventory(querySkuDetails, moreSkus, null); - } - - /** - * Queries the inventory. This will query all owned items from the server, as well as - * information on additional skus, if specified. This method may block or take long to execute. - * Do not call from a UI thread. For that, use the non-blocking version {@link #refreshInventoryAsync}. - * - * @param querySkuDetails if true, SKU details (price, description, etc) will be queried as well - * as purchase information. - * @param moreItemSkus additional PRODUCT skus to query information on, regardless of ownership. - * Ignored if null or if querySkuDetails is false. - * @param moreSubsSkus additional SUBSCRIPTIONS skus to query information on, regardless of ownership. - * Ignored if null or if querySkuDetails is false. - * @throws IabException if a problem occurs while refreshing the inventory. - */ - public Inventory queryInventory(boolean querySkuDetails, List moreItemSkus, - List moreSubsSkus) throws IabException { - checkNotDisposed(); - checkSetupDone("queryInventory"); - try { - Inventory inv = new Inventory(); - int r = queryPurchases(inv, ITEM_TYPE_INAPP); - if (r != BILLING_RESPONSE_RESULT_OK) { - throw new IabException(r, "Error refreshing inventory (querying owned items)."); - } - - if (querySkuDetails) { - r = querySkuDetails(ITEM_TYPE_INAPP, inv, moreItemSkus); - if (r != BILLING_RESPONSE_RESULT_OK) { - throw new IabException(r, "Error refreshing inventory (querying prices of items)."); - } - } - - // if subscriptions are supported, then also query for subscriptions - if (mSubscriptionsSupported) { - r = queryPurchases(inv, ITEM_TYPE_SUBS); - if (r != BILLING_RESPONSE_RESULT_OK) { - throw new IabException(r, "Error refreshing inventory (querying owned subscriptions)."); - } - - if (querySkuDetails) { - r = querySkuDetails(ITEM_TYPE_SUBS, inv, moreItemSkus); - if (r != BILLING_RESPONSE_RESULT_OK) { - throw new IabException(r, "Error refreshing inventory (querying prices of subscriptions)."); - } - } - } - - return inv; - } catch (RemoteException e) { - throw new IabException(IABHELPER_REMOTE_EXCEPTION, "Remote exception while refreshing inventory.", e); - } catch (JSONException e) { - throw new IabException(IABHELPER_BAD_RESPONSE, "Error parsing JSON response while refreshing inventory.", e); - } - } - - /** - * Asynchronous wrapper for inventory query. This will perform an inventory - * query as described in {@link #queryInventory}, but will do so asynchronously - * and call back the specified listener upon completion. This method is safe to - * call from a UI thread. - * - * @param querySkuDetails as in {@link #queryInventory} - * @param moreSkus as in {@link #queryInventory} - * @param listener The listener to notify when the refresh operation completes. - */ - public void queryInventoryAsync(final boolean querySkuDetails, - final List moreSkus, - final QueryInventoryFinishedListener listener) { - final Handler handler = new Handler(); - checkNotDisposed(); - checkSetupDone("queryInventory"); - flagStartAsync("refresh inventory"); - (new Thread(new Runnable() { - public void run() { - IabResult result = new IabResult(BILLING_RESPONSE_RESULT_OK, "Inventory refresh successful."); - Inventory inv = null; - try { - inv = queryInventory(querySkuDetails, moreSkus); - } catch (IabException ex) { - result = ex.getResult(); - } - - flagEndAsync(); - - final IabResult result_f = result; - final Inventory inv_f = inv; - if (!mDisposed && listener != null) { - handler.post(new Runnable() { - public void run() { - listener.onQueryInventoryFinished(result_f, inv_f); - } - }); - } - } - })).start(); - } - - public void queryInventoryAsync(QueryInventoryFinishedListener listener) { - queryInventoryAsync(true, null, listener); - } - - public void queryInventoryAsync(boolean querySkuDetails, QueryInventoryFinishedListener listener) { - queryInventoryAsync(querySkuDetails, null, listener); - } - - /** - * Consumes a given in-app product. Consuming can only be done on an item - * that's owned, and as a result of consumption, the user will no longer own it. - * This method may block or take long to return. Do not call from the UI thread. - * For that, see {@link #consumeAsync}. - * - * @param itemInfo The PurchaseInfo that represents the item to consume. - * @throws IabException if there is a problem during consumption. - */ - void consume(Purchase itemInfo) throws IabException { - checkNotDisposed(); - checkSetupDone("consume"); - - if (!itemInfo.mItemType.equals(ITEM_TYPE_INAPP)) { - throw new IabException(IABHELPER_INVALID_CONSUMPTION, - "Items of type '" + itemInfo.mItemType + "' can't be consumed."); - } - - try { - String token = itemInfo.getToken(); - String sku = itemInfo.getSku(); - if (token == null || token.equals("")) { - logError("Can't consume " + sku + ". No token."); - throw new IabException(IABHELPER_MISSING_TOKEN, "PurchaseInfo is missing token for sku: " - + sku + " " + itemInfo); - } - - logDebug("Consuming sku: " + sku + ", token: " + token); - int response = mService.consumePurchase(3, mContext.getPackageName(), token); - if (response == BILLING_RESPONSE_RESULT_OK) { - logDebug("Successfully consumed sku: " + sku); - } else { - logDebug("Error consuming consuming sku " + sku + ". " + getResponseDesc(response)); - throw new IabException(response, "Error consuming sku " + sku); - } - } catch (RemoteException e) { - throw new IabException(IABHELPER_REMOTE_EXCEPTION, "Remote exception while consuming. PurchaseInfo: " + itemInfo, e); - } - } - - /** - * Asynchronous wrapper to item consumption. Works like {@link #consume}, but - * performs the consumption in the background and notifies completion through - * the provided listener. This method is safe to call from a UI thread. - * - * @param purchase The purchase to be consumed. - * @param listener The listener to notify when the consumption operation finishes. - */ - public void consumeAsync(Purchase purchase, OnConsumeFinishedListener listener) { - checkNotDisposed(); - checkSetupDone("consume"); - List purchases = new ArrayList<>(); - purchases.add(purchase); - consumeAsyncInternal(purchases, listener, null); - } - - /** - * Same as {@link consumeAsync}, but for multiple items at once. - * - * @param purchases The list of PurchaseInfo objects representing the purchases to consume. - * @param listener The listener to notify when the consumption operation finishes. - */ - public void consumeAsync(List purchases, OnConsumeMultiFinishedListener listener) { - checkNotDisposed(); - checkSetupDone("consume"); - consumeAsyncInternal(purchases, null, listener); - } - - // Checks that setup was done; if not, throws an exception. - void checkSetupDone(String operation) { - if (!mSetupDone) { - logError("Illegal state for operation (" + operation + "): IAB helper is not set up."); - throw new IllegalStateException("IAB helper is not set up. Can't perform operation: " + operation); - } - } - - // Workaround to bug where sometimes response codes come as Long instead of Integer - int getResponseCodeFromBundle(Bundle b) { - Object o = b.get(RESPONSE_CODE); - if (o == null) { - logDebug("Bundle with null response code, assuming OK (known issue)"); - return BILLING_RESPONSE_RESULT_OK; - } else if (o instanceof Integer) return (Integer) o; - else if (o instanceof Long) return (int) ((Long) o).longValue(); - else { - logError("Unexpected type for bundle response code."); - logError(o.getClass().getName()); - throw new RuntimeException("Unexpected type for bundle response code: " + o.getClass().getName()); - } - } - - // Workaround to bug where sometimes response codes come as Long instead of Integer - int getResponseCodeFromIntent(Intent i) { - Object o = i.getExtras().get(RESPONSE_CODE); - if (o == null) { - logError("Intent with no response code, assuming OK (known issue)"); - return BILLING_RESPONSE_RESULT_OK; - } else if (o instanceof Integer) return (Integer) o; - else if (o instanceof Long) return (int) ((Long) o).longValue(); - else { - logError("Unexpected type for intent response code."); - logError(o.getClass().getName()); - throw new RuntimeException("Unexpected type for intent response code: " + o.getClass().getName()); - } - } - - void flagStartAsync(String operation) { - if (mAsyncInProgress) throw new IllegalStateException("Can't start async operation (" + - operation + ") because another async operation(" + mAsyncOperation + ") is in progress."); - mAsyncOperation = operation; - mAsyncInProgress = true; - logDebug("Starting async operation: " + operation); - } - - void flagEndAsync() { - logDebug("Ending async operation: " + mAsyncOperation); - mAsyncOperation = ""; - mAsyncInProgress = false; - } - - int queryPurchases(Inventory inv, String itemType) throws JSONException, RemoteException { - // Query purchases - logDebug("Querying owned items, item type: " + itemType); - logDebug("Package name: " + mContext.getPackageName()); - boolean verificationFailed = false; - String continueToken = null; - - do { - logDebug("Calling getPurchases with continuation token: " + continueToken); - Bundle ownedItems = mService.getPurchases(3, mContext.getPackageName(), - itemType, continueToken); - - int response = getResponseCodeFromBundle(ownedItems); - logDebug("Owned items response: " + String.valueOf(response)); - if (response != BILLING_RESPONSE_RESULT_OK) { - logDebug("getPurchases() failed: " + getResponseDesc(response)); - return response; - } - if (!ownedItems.containsKey(RESPONSE_INAPP_ITEM_LIST) - || !ownedItems.containsKey(RESPONSE_INAPP_PURCHASE_DATA_LIST) - || !ownedItems.containsKey(RESPONSE_INAPP_SIGNATURE_LIST)) { - logError("Bundle returned from getPurchases() doesn't contain required fields."); - return IABHELPER_BAD_RESPONSE; - } - - ArrayList ownedSkus = ownedItems.getStringArrayList( - RESPONSE_INAPP_ITEM_LIST); - ArrayList purchaseDataList = ownedItems.getStringArrayList( - RESPONSE_INAPP_PURCHASE_DATA_LIST); - ArrayList signatureList = ownedItems.getStringArrayList( - RESPONSE_INAPP_SIGNATURE_LIST); - - for (int i = 0; i < purchaseDataList.size(); ++i) { - String purchaseData = purchaseDataList.get(i); - String signature = signatureList.get(i); - String sku = ownedSkus.get(i); - if (Security.verifyPurchase(mSignatureBase64, purchaseData, signature)) { - logDebug("Sku is owned: " + sku); - Purchase purchase = new Purchase(itemType, purchaseData, signature); - - if (TextUtils.isEmpty(purchase.getToken())) { - logWarn("BUG: empty/null token!"); - logDebug("Purchase data: " + purchaseData); - } - - // Record ownership and token - inv.addPurchase(purchase); - } else { - logWarn("Purchase signature verification **FAILED**. Not adding item."); - logDebug(" Purchase data: " + purchaseData); - logDebug(" Signature: " + signature); - verificationFailed = true; - } - } - - continueToken = ownedItems.getString(INAPP_CONTINUATION_TOKEN); - logDebug("Continuation token: " + continueToken); - } while (!TextUtils.isEmpty(continueToken)); - - return verificationFailed ? IABHELPER_VERIFICATION_FAILED : BILLING_RESPONSE_RESULT_OK; - } - - int querySkuDetails(String itemType, Inventory inv, List moreSkus) - throws RemoteException, JSONException { - logDebug("Querying SKU details."); - ArrayList skuList = new ArrayList<>(); - skuList.addAll(inv.getAllOwnedSkus(itemType)); - if (moreSkus != null) { - for (String sku : moreSkus) { - if (!skuList.contains(sku)) { - skuList.add(sku); - } - } - } - - if (skuList.size() == 0) { - logDebug("queryPrices: nothing to do because there are no SKUs."); - return BILLING_RESPONSE_RESULT_OK; - } - - Bundle querySkus = new Bundle(); - querySkus.putStringArrayList(GET_SKU_DETAILS_ITEM_LIST, skuList); - Bundle skuDetails = mService.getSkuDetails(3, mContext.getPackageName(), - itemType, querySkus); - - if (!skuDetails.containsKey(RESPONSE_GET_SKU_DETAILS_LIST)) { - int response = getResponseCodeFromBundle(skuDetails); - if (response != BILLING_RESPONSE_RESULT_OK) { - logDebug("getSkuDetails() failed: " + getResponseDesc(response)); - return response; - } else { - logError("getSkuDetails() returned a bundle with neither an error nor a detail list."); - return IABHELPER_BAD_RESPONSE; - } - } - - ArrayList responseList = skuDetails.getStringArrayList( - RESPONSE_GET_SKU_DETAILS_LIST); - - for (String thisResponse : responseList) { - SkuDetails d = new SkuDetails(itemType, thisResponse); - logDebug("Got sku details: " + d); - inv.addSkuDetails(d); - } - return BILLING_RESPONSE_RESULT_OK; - } - - void consumeAsyncInternal(final List purchases, - final OnConsumeFinishedListener singleListener, - final OnConsumeMultiFinishedListener multiListener) { - final Handler handler = new Handler(); - flagStartAsync("consume"); - (new Thread(new Runnable() { - public void run() { - final List results = new ArrayList<>(); - for (Purchase purchase : purchases) { - try { - consume(purchase); - results.add(new IabResult(BILLING_RESPONSE_RESULT_OK, "Successful consume of sku " + purchase.getSku())); - } catch (IabException ex) { - results.add(ex.getResult()); - } - } - - flagEndAsync(); - if (!mDisposed && singleListener != null) { - handler.post(new Runnable() { - public void run() { - singleListener.onConsumeFinished(purchases.get(0), results.get(0)); - } - }); - } - if (!mDisposed && multiListener != null) { - handler.post(new Runnable() { - public void run() { - multiListener.onConsumeMultiFinished(purchases, results); - } - }); - } - } - })).start(); - } - - void logDebug(String msg) { - if (mDebugLog) Log.d(mDebugTag, msg); - } - - void logError(String msg) { - Log.e(mDebugTag, "In-app billing error: " + msg); - } - - void logWarn(String msg) { - Log.w(mDebugTag, "In-app billing warning: " + msg); - } - - /** - * Callback for setup process. This listener's {@link #onIabSetupFinished} method is called - * when the setup process is complete. - */ - public interface OnIabSetupFinishedListener { - /** - * Called to notify that setup is complete. - * - * @param result The result of the setup process. - */ - public void onIabSetupFinished(IabResult result); - } - - - /** - * Callback that notifies when a purchase is finished. - */ - public interface OnIabPurchaseFinishedListener { - /** - * Called to notify that an in-app purchase finished. If the purchase was successful, - * then the sku parameter specifies which item was purchased. If the purchase failed, - * the sku and extraData parameters may or may not be null, depending on how far the purchase - * process went. - * - * @param result The result of the purchase. - * @param info The purchase information (null if purchase failed) - */ - public void onIabPurchaseFinished(IabResult result, Purchase info); - } - - /** - * Listener that notifies when an inventory query operation completes. - */ - public interface QueryInventoryFinishedListener { - /** - * Called to notify that an inventory query operation completed. - * - * @param result The result of the operation. - * @param inv The inventory. - */ - public void onQueryInventoryFinished(IabResult result, Inventory inv); - } - - /** - * Callback that notifies when a consumption operation finishes. - */ - public interface OnConsumeFinishedListener { - /** - * Called to notify that a consumption has finished. - * - * @param purchase The purchase that was (or was to be) consumed. - * @param result The result of the consumption operation. - */ - public void onConsumeFinished(Purchase purchase, IabResult result); - } - - /** - * Callback that notifies when a multi-item consumption operation finishes. - */ - public interface OnConsumeMultiFinishedListener { - /** - * Called to notify that a consumption of multiple items has finished. - * - * @param purchases The purchases that were (or were to be) consumed. - * @param results The results of each consumption operation, corresponding to each - * sku. - */ - public void onConsumeMultiFinished(List purchases, List results); - } -} diff --git a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/utils/IabResult.java b/libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/utils/IabResult.java deleted file mode 100644 index c01c194..0000000 --- a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/utils/IabResult.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2014 Vlad Mihalachi - * - * This file is part of Turbo Editor. - * - * Turbo Editor is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Turbo Editor is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package sharedcode.turboeditor.iab.utils; - -/** - * Represents the result of an in-app billing operation. - * A result is composed of a response code (an integer) and possibly a - * message (String). You can get those by calling - * {@link #getResponse} and {@link #getMessage()}, respectively. You - * can also inquire whether a result is a success or a failure by - * calling {@link #isSuccess()} and {@link #isFailure()}. - */ -public class IabResult { - int mResponse; - String mMessage; - - public IabResult(int response, String message) { - mResponse = response; - if (message == null || message.trim().length() == 0) { - mMessage = IabHelper.getResponseDesc(response); - } else { - mMessage = message + " (response: " + IabHelper.getResponseDesc(response) + ")"; - } - } - - public int getResponse() { - return mResponse; - } - - public String getMessage() { - return mMessage; - } - - public boolean isSuccess() { - return mResponse == IabHelper.BILLING_RESPONSE_RESULT_OK; - } - - public boolean isFailure() { - return !isSuccess(); - } - - public String toString() { - return "IabResult: " + getMessage(); - } -} - diff --git a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/utils/Inventory.java b/libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/utils/Inventory.java deleted file mode 100644 index c3b3b23..0000000 --- a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/utils/Inventory.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2014 Vlad Mihalachi - * - * This file is part of Turbo Editor. - * - * Turbo Editor is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Turbo Editor is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package sharedcode.turboeditor.iab.utils; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Represents a block of information about in-app items. - * An Inventory is returned by such methods as {@link IabHelper#queryInventory}. - */ -public class Inventory { - Map mSkuMap = new HashMap<>(); - Map mPurchaseMap = new HashMap<>(); - - Inventory() { - } - - /** - * Returns the listing details for an in-app product. - */ - public SkuDetails getSkuDetails(String sku) { - return mSkuMap.get(sku); - } - - /** - * Returns purchase information for a given product, or null if there is no purchase. - */ - public Purchase getPurchase(String sku) { - return mPurchaseMap.get(sku); - } - - /** - * Returns whether or not there exists a purchase of the given product. - */ - public boolean hasPurchase(String sku) { - return mPurchaseMap.containsKey(sku); - } - - /** - * Return whether or not details about the given product are available. - */ - public boolean hasDetails(String sku) { - return mSkuMap.containsKey(sku); - } - - /** - * Erase a purchase (locally) from the inventory, given its product ID. This just - * modifies the Inventory object locally and has no effect on the server! This is - * useful when you have an existing Inventory object which you know to be up to date, - * and you have just consumed an item successfully, which means that erasing its - * purchase data from the Inventory you already have is quicker than querying for - * a new Inventory. - */ - public void erasePurchase(String sku) { - if (mPurchaseMap.containsKey(sku)) mPurchaseMap.remove(sku); - } - - /** - * Returns a list of all owned product IDs. - */ - List getAllOwnedSkus() { - return new ArrayList<>(mPurchaseMap.keySet()); - } - - /** - * Returns a list of all owned product IDs of a given type - */ - List getAllOwnedSkus(String itemType) { - List result = new ArrayList<>(); - for (Purchase p : mPurchaseMap.values()) { - if (p.getItemType().equals(itemType)) result.add(p.getSku()); - } - return result; - } - - /** - * Returns a list of all purchases. - */ - List getAllPurchases() { - return new ArrayList<>(mPurchaseMap.values()); - } - - void addSkuDetails(SkuDetails d) { - mSkuMap.put(d.getSku(), d); - } - - void addPurchase(Purchase p) { - mPurchaseMap.put(p.getSku(), p); - } -} diff --git a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/utils/Purchase.java b/libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/utils/Purchase.java deleted file mode 100644 index d63575b..0000000 --- a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/utils/Purchase.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2014 Vlad Mihalachi - * - * This file is part of Turbo Editor. - * - * Turbo Editor is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Turbo Editor is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package sharedcode.turboeditor.iab.utils; - -import org.json.JSONException; -import org.json.JSONObject; - -/** - * Represents an in-app billing purchase. - */ -public class Purchase { - String mItemType; // ITEM_TYPE_INAPP or ITEM_TYPE_SUBS - String mOrderId; - String mPackageName; - String mSku; - long mPurchaseTime; - int mPurchaseState; - String mDeveloperPayload; - String mToken; - String mOriginalJson; - String mSignature; - - public Purchase(String itemType, String jsonPurchaseInfo, String signature) throws JSONException { - mItemType = itemType; - mOriginalJson = jsonPurchaseInfo; - JSONObject o = new JSONObject(mOriginalJson); - mOrderId = o.optString("orderId"); - mPackageName = o.optString("packageName"); - mSku = o.optString("productId"); - mPurchaseTime = o.optLong("purchaseTime"); - mPurchaseState = o.optInt("purchaseState"); - mDeveloperPayload = o.optString("developerPayload"); - mToken = o.optString("token", o.optString("purchaseToken")); - mSignature = signature; - } - - public String getItemType() { - return mItemType; - } - - public String getOrderId() { - return mOrderId; - } - - public String getPackageName() { - return mPackageName; - } - - public String getSku() { - return mSku; - } - - public long getPurchaseTime() { - return mPurchaseTime; - } - - public int getPurchaseState() { - return mPurchaseState; - } - - public String getDeveloperPayload() { - return mDeveloperPayload; - } - - public String getToken() { - return mToken; - } - - public String getOriginalJson() { - return mOriginalJson; - } - - public String getSignature() { - return mSignature; - } - - @Override - public String toString() { - return "PurchaseInfo(type:" + mItemType + "):" + mOriginalJson; - } -} diff --git a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/utils/Security.java b/libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/utils/Security.java deleted file mode 100644 index adaed71..0000000 --- a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/utils/Security.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2014 Vlad Mihalachi - * - * This file is part of Turbo Editor. - * - * Turbo Editor is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Turbo Editor is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package sharedcode.turboeditor.iab.utils; - -import android.text.TextUtils; -import android.util.Log; - -import java.security.InvalidKeyException; -import java.security.KeyFactory; -import java.security.NoSuchAlgorithmException; -import java.security.PublicKey; -import java.security.Signature; -import java.security.SignatureException; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.X509EncodedKeySpec; - -/** - * Security-related methods. For a secure implementation, all of this code - * should be implemented on a server that communicates with the - * application on the device. For the sake of simplicity and clarity of this - * example, this code is included here and is executed on the device. If you - * must verify the purchases on the phone, you should obfuscate this code to - * make it harder for an attacker to replace the code with stubs that treat all - * purchases as verified. - */ -public class Security { - private static final String TAG = "IABUtil/Security"; - - private static final String KEY_FACTORY_ALGORITHM = "RSA"; - private static final String SIGNATURE_ALGORITHM = "SHA1withRSA"; - - /** - * Verifies that the data was signed with the given signature, and returns - * the verified purchase. The data is in JSON format and signed - * with a private key. The data also contains the {@link PurchaseState} - * and product ID of the purchase. - * - * @param base64PublicKey the base64-encoded public key to use for verifying. - * @param signedData the signed JSON string (signed, not encrypted) - * @param signature the signature for the data, signed with the private key - */ - public static boolean verifyPurchase(String base64PublicKey, String signedData, String signature) { - if (TextUtils.isEmpty(signedData) || TextUtils.isEmpty(base64PublicKey) || - TextUtils.isEmpty(signature)) { - Log.e(TAG, "Purchase verification failed: missing data."); - return false; - } - - PublicKey key = Security.generatePublicKey(base64PublicKey); - return Security.verify(key, signedData, signature); - } - - /** - * Generates a PublicKey instance from a string containing the - * Base64-encoded public key. - * - * @param encodedPublicKey Base64-encoded public key - * @throws IllegalArgumentException if encodedPublicKey is invalid - */ - public static PublicKey generatePublicKey(String encodedPublicKey) { - try { - byte[] decodedKey = Base64.decode(encodedPublicKey); - KeyFactory keyFactory = KeyFactory.getInstance(KEY_FACTORY_ALGORITHM); - return keyFactory.generatePublic(new X509EncodedKeySpec(decodedKey)); - } catch (NoSuchAlgorithmException e) { - throw new RuntimeException(e); - } catch (InvalidKeySpecException e) { - Log.e(TAG, "Invalid key specification."); - throw new IllegalArgumentException(e); - } catch (Base64DecoderException e) { - Log.e(TAG, "Base64 decoding failed."); - throw new IllegalArgumentException(e); - } - } - - /** - * Verifies that the signature from the server matches the computed - * signature on the data. Returns true if the data is correctly signed. - * - * @param publicKey public key associated with the developer account - * @param signedData signed data from server - * @param signature server signature - * @return true if the data and signature match - */ - public static boolean verify(PublicKey publicKey, String signedData, String signature) { - Signature sig; - try { - sig = Signature.getInstance(SIGNATURE_ALGORITHM); - sig.initVerify(publicKey); - sig.update(signedData.getBytes()); - if (!sig.verify(Base64.decode(signature))) { - Log.e(TAG, "Signature verification failed."); - return false; - } - return true; - } catch (NoSuchAlgorithmException e) { - Log.e(TAG, "NoSuchAlgorithmException."); - } catch (InvalidKeyException e) { - Log.e(TAG, "Invalid key specification."); - } catch (SignatureException e) { - Log.e(TAG, "Signature exception."); - } catch (Base64DecoderException e) { - Log.e(TAG, "Base64 decoding failed."); - } - return false; - } -} diff --git a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/utils/SkuDetails.java b/libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/utils/SkuDetails.java deleted file mode 100644 index acdd42f..0000000 --- a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/utils/SkuDetails.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2014 Vlad Mihalachi - * - * This file is part of Turbo Editor. - * - * Turbo Editor is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Turbo Editor is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package sharedcode.turboeditor.iab.utils; - -import org.json.JSONException; -import org.json.JSONObject; - -/** - * Represents an in-app product's listing details. - */ -public class SkuDetails { - String mItemType; - String mSku; - String mType; - String mPrice; - String mTitle; - String mDescription; - String mJson; - - public SkuDetails(String jsonSkuDetails) throws JSONException { - this(IabHelper.ITEM_TYPE_INAPP, jsonSkuDetails); - } - - public SkuDetails(String itemType, String jsonSkuDetails) throws JSONException { - mItemType = itemType; - mJson = jsonSkuDetails; - JSONObject o = new JSONObject(mJson); - mSku = o.optString("productId"); - mType = o.optString("type"); - mPrice = o.optString("price"); - mTitle = o.optString("title"); - mDescription = o.optString("description"); - } - - public String getSku() { - return mSku; - } - - public String getType() { - return mType; - } - - public String getPrice() { - return mPrice; - } - - public String getTitle() { - return mTitle; - } - - public String getDescription() { - return mDescription; - } - - @Override - public String toString() { - return "SkuDetails:" + mJson; - } -} diff --git a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/utils/Base64DecoderException.java b/libraries/sharedCode/src/main/java/sharedcode/turboeditor/preferences/PreferenceChangeType.java similarity index 65% rename from libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/utils/Base64DecoderException.java rename to libraries/sharedCode/src/main/java/sharedcode/turboeditor/preferences/PreferenceChangeType.java index 8f4c024..a6432c7 100644 --- a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/iab/utils/Base64DecoderException.java +++ b/libraries/sharedCode/src/main/java/sharedcode/turboeditor/preferences/PreferenceChangeType.java @@ -17,21 +17,8 @@ * along with this program. If not, see . */ -package sharedcode.turboeditor.iab.utils; +package sharedcode.turboeditor.preferences; -/** - * Exception thrown when encountering an invalid Base64 input character. - * - * @author nelson - */ -public class Base64DecoderException extends Exception { - private static final long serialVersionUID = 1L; - - public Base64DecoderException() { - super(); - } - - public Base64DecoderException(String s) { - super(s); - } -} +public enum PreferenceChangeType { + FONT_SIZE, ENCODING, SYNTAX, WRAP_CONTENT, MONOSPACE, LINE_NUMERS, THEME_CHANGE, TEXT_SUGGESTIONS, READ_ONLY, + } \ No newline at end of file diff --git a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/preferences/PreferenceHelper.java b/libraries/sharedCode/src/main/java/sharedcode/turboeditor/preferences/PreferenceHelper.java index 5b024d1..ca0aaa7 100644 --- a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/preferences/PreferenceHelper.java +++ b/libraries/sharedCode/src/main/java/sharedcode/turboeditor/preferences/PreferenceHelper.java @@ -74,7 +74,7 @@ public final class PreferenceHelper { } public static String getEncoding(Context context) { - return getPrefs(context).getString("editor_encoding", "UTF-8"); + return getPrefs(context).getString("editor_encoding", "UTF-16"); } public static int getFontSize(Context context) { diff --git a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/preferences/SettingsFragment.java b/libraries/sharedCode/src/main/java/sharedcode/turboeditor/preferences/SettingsFragment.java index 5db0fc2..e17666f 100644 --- a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/preferences/SettingsFragment.java +++ b/libraries/sharedCode/src/main/java/sharedcode/turboeditor/preferences/SettingsFragment.java @@ -32,20 +32,7 @@ import sharedcode.turboeditor.R; import sharedcode.turboeditor.activity.MainActivity; import sharedcode.turboeditor.dialogfragment.EncodingDialog; import sharedcode.turboeditor.dialogfragment.NumberPickerDialog; -import sharedcode.turboeditor.util.ProCheckUtils; import sharedcode.turboeditor.util.ViewUtils; -import sharedcode.turboeditor.views.DialogHelper; - -import static sharedcode.turboeditor.util.EventBusEvents.APreferenceValueWasChanged; -import static sharedcode.turboeditor.util.EventBusEvents.APreferenceValueWasChanged.Type.ENCODING; -import static sharedcode.turboeditor.util.EventBusEvents.APreferenceValueWasChanged.Type.FONT_SIZE; -import static sharedcode.turboeditor.util.EventBusEvents.APreferenceValueWasChanged.Type.LINE_NUMERS; -import static sharedcode.turboeditor.util.EventBusEvents.APreferenceValueWasChanged.Type.MONOSPACE; -import static sharedcode.turboeditor.util.EventBusEvents.APreferenceValueWasChanged.Type.READ_ONLY; -import static sharedcode.turboeditor.util.EventBusEvents.APreferenceValueWasChanged.Type.SYNTAX; -import static sharedcode.turboeditor.util.EventBusEvents.APreferenceValueWasChanged.Type.TEXT_SUGGESTIONS; -import static sharedcode.turboeditor.util.EventBusEvents.APreferenceValueWasChanged.Type.THEME_CHANGE; -import static sharedcode.turboeditor.util.EventBusEvents.APreferenceValueWasChanged.Type.WRAP_CONTENT; public class SettingsFragment extends Fragment implements NumberPickerDialog.INumberPickerDialog, EncodingDialog.DialogListener { @@ -118,16 +105,12 @@ public class SettingsFragment extends Fragment implements NumberPickerDialog.INu fontSizeView = (TextView) rootView.findViewById(R.id.drawer_button_font_size); encodingView = (TextView) rootView.findViewById(R.id.drawer_button_encoding); extraOptionsView = (TextView) rootView.findViewById(R.id.drawer_button_extra_options); - donateView = (TextView) rootView.findViewById(R.id.drawer_button_go_pro); - - if(ProCheckUtils.isPro(getActivity(), false)) - ViewUtils.setVisible(donateView, false); swLineNumbers.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { PreferenceHelper.setLineNumbers(getActivity(), isChecked); - ((MainActivity) getActivity()).onEvent(new APreferenceValueWasChanged(LINE_NUMERS)); + ((MainActivity) getActivity()).aPreferenceValueWasChanged(PreferenceChangeType.LINE_NUMERS); } }); @@ -136,7 +119,7 @@ public class SettingsFragment extends Fragment implements NumberPickerDialog.INu public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { sColorSyntax = isChecked; PreferenceHelper.setSyntaxHighlight(getActivity(), isChecked); - ((MainActivity) getActivity()).onEvent(new APreferenceValueWasChanged(SYNTAX)); + ((MainActivity) getActivity()).aPreferenceValueWasChanged(PreferenceChangeType.SYNTAX); } }); @@ -145,7 +128,7 @@ public class SettingsFragment extends Fragment implements NumberPickerDialog.INu @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { PreferenceHelper.setWrapContent(getActivity(), isChecked); - ((MainActivity) getActivity()).onEvent(new APreferenceValueWasChanged(WRAP_CONTENT)); + ((MainActivity) getActivity()).aPreferenceValueWasChanged(PreferenceChangeType.WRAP_CONTENT); } }); @@ -154,7 +137,7 @@ public class SettingsFragment extends Fragment implements NumberPickerDialog.INu public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { sUseMonospace = isChecked; PreferenceHelper.setUseMonospace(getActivity(), isChecked); - ((MainActivity) getActivity()).onEvent(new APreferenceValueWasChanged(MONOSPACE)); + ((MainActivity) getActivity()).aPreferenceValueWasChanged(PreferenceChangeType.MONOSPACE); } }); @@ -163,7 +146,7 @@ public class SettingsFragment extends Fragment implements NumberPickerDialog.INu @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { PreferenceHelper.setReadOnly(getActivity(), isChecked); - ((MainActivity) getActivity()).onEvent(new APreferenceValueWasChanged(READ_ONLY)); + ((MainActivity) getActivity()).aPreferenceValueWasChanged(PreferenceChangeType.READ_ONLY); } }); @@ -200,18 +183,11 @@ public class SettingsFragment extends Fragment implements NumberPickerDialog.INu } }); - donateView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - DialogHelper.showDonateDialog(getActivity()); - } - }); - swLightTheme.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { PreferenceHelper.setLightTheme(getActivity(), isChecked); - ((MainActivity) getActivity()).onEvent(new APreferenceValueWasChanged(THEME_CHANGE)); + ((MainActivity) getActivity()).aPreferenceValueWasChanged(PreferenceChangeType.THEME_CHANGE); } }); @@ -219,7 +195,7 @@ public class SettingsFragment extends Fragment implements NumberPickerDialog.INu @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { PreferenceHelper.setSuggestionsActive(getActivity(), isChecked); - ((MainActivity) getActivity()).onEvent(new APreferenceValueWasChanged(TEXT_SUGGESTIONS)); + ((MainActivity) getActivity()).aPreferenceValueWasChanged(PreferenceChangeType.TEXT_SUGGESTIONS); } }); @@ -257,13 +233,13 @@ public class SettingsFragment extends Fragment implements NumberPickerDialog.INu @Override public void onNumberPickerDialogDismissed(NumberPickerDialog.Actions action, int value) { PreferenceHelper.setFontSize(getActivity(), value); - ((MainActivity) getActivity()).onEvent(new APreferenceValueWasChanged(FONT_SIZE)); + ((MainActivity) getActivity()).aPreferenceValueWasChanged(PreferenceChangeType.FONT_SIZE); } @Override public void onEncodingSelected(String result) { PreferenceHelper.setEncoding(getActivity(), result); - ((MainActivity) getActivity()).onEvent(new APreferenceValueWasChanged(ENCODING)); + ((MainActivity) getActivity()).aPreferenceValueWasChanged(PreferenceChangeType.ENCODING); } } diff --git a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/task/SaveFileTask.java b/libraries/sharedCode/src/main/java/sharedcode/turboeditor/task/SaveFileTask.java index 69b8bb2..0819b6a 100644 --- a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/task/SaveFileTask.java +++ b/libraries/sharedCode/src/main/java/sharedcode/turboeditor/task/SaveFileTask.java @@ -32,7 +32,6 @@ import java.util.concurrent.TimeoutException; import sharedcode.turboeditor.R; import sharedcode.turboeditor.activity.MainActivity; import sharedcode.turboeditor.root.RootUtils; -import sharedcode.turboeditor.util.EventBusEvents; public class SaveFileTask extends AsyncTask { @@ -101,6 +100,6 @@ public class SaveFileTask extends AsyncTask { super.onPostExecute(aVoid); Toast.makeText(activity, message, Toast.LENGTH_LONG).show(); if (message.equals(positiveMessage)) - activity.onEvent(new EventBusEvents.SavedAFile(filePath)); + activity.savedAFile(filePath); } } \ No newline at end of file diff --git a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/texteditor/LineUtils.java b/libraries/sharedCode/src/main/java/sharedcode/turboeditor/texteditor/LineUtils.java index f6505ce..40e6502 100644 --- a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/texteditor/LineUtils.java +++ b/libraries/sharedCode/src/main/java/sharedcode/turboeditor/texteditor/LineUtils.java @@ -27,7 +27,7 @@ public class LineUtils { private boolean[] toCountLinesArray; private int[] realLines; - public boolean[] getToCountLinesArray() { + public boolean[] getGoodLines() { return toCountLinesArray; } @@ -81,6 +81,8 @@ public class LineUtils { } } + toCountLinesArray[lineCount-1] = true; + int realLine = startingLine; // the first line is not 0, is 1. We start counting from 1 for (i = 0; i < toCountLinesArray.length; i++) { diff --git a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/texteditor/Patterns.java b/libraries/sharedCode/src/main/java/sharedcode/turboeditor/texteditor/Patterns.java index 483fb96..cca92e6 100644 --- a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/texteditor/Patterns.java +++ b/libraries/sharedCode/src/main/java/sharedcode/turboeditor/texteditor/Patterns.java @@ -35,10 +35,8 @@ public class Patterns { // Strings public static final Pattern GENERAL_STRINGS = Pattern.compile("\"(.*?)\"|'(.*?)'"); - public static final Pattern HTML_OPEN_TAGS = Pattern.compile( - "<([A-Za-z][A-Za-z0-9]*)\\b[^>]*>"); - public static final Pattern HTML_CLOSE_TAGS = Pattern.compile( - "]*>"); + public static final Pattern HTML_TAGS = Pattern.compile( + "<([A-Za-z][A-Za-z0-9]*)\\b[^>]*>|]*>"); public static final Pattern HTML_ATTRS = Pattern.compile( "(\\S+)=[\"']?((?:.(?![\"']?\\s+(?:\\S+)=|[>\"']))+.)[\"']?"); @@ -54,7 +52,7 @@ public class Patterns { //public static final Pattern CSS_NUMBERS = Pattern.compile( // "/^auto$|^[+-]?[0-9]+\\.?([0-9]+)?(px|em|ex|%|in|cm|mm|pt|pc)?$/ig"); public static final Pattern SYMBOLS = Pattern.compile( - "(!|,|\\(|\\)|\\+|\\-|\\*|<|>|=|\\.|\\?|;|\\{|\\}|\\[|\\])"); + "(!|,|\\(|\\)|\\+|\\-|\\*|<|>|=|\\.|\\?|;|\\{|\\}|\\[|\\]|\\|)"); public static final Pattern NUMBERS_OR_SYMBOLS = Pattern.compile(NUMBERS.pattern()+"|"+SYMBOLS.pattern()); public static final Pattern GENERAL_KEYWORDS = Pattern.compile( "\\b(alignas|alignof|and|and_eq|asm|auto|bitand|bitorbool|break|case|catch|char|" diff --git a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/texteditor/SearchResult.java b/libraries/sharedCode/src/main/java/sharedcode/turboeditor/texteditor/SearchResult.java index 1105101..2475db4 100644 --- a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/texteditor/SearchResult.java +++ b/libraries/sharedCode/src/main/java/sharedcode/turboeditor/texteditor/SearchResult.java @@ -28,11 +28,14 @@ public class SearchResult { public boolean isReplace; public String textToReplace; public int index; + public String whatToSearch; - public SearchResult(LinkedList foundIndex, int textLength, boolean isReplace, String textToReplace) { + + public SearchResult(LinkedList foundIndex, int textLength, boolean isReplace, String whatToSearch, String textToReplace) { this.foundIndex = foundIndex; this.textLength = textLength; this.isReplace = isReplace; + this.whatToSearch = whatToSearch; this.textToReplace = textToReplace; } diff --git a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/util/EventBusEvents.java b/libraries/sharedCode/src/main/java/sharedcode/turboeditor/util/EventBusEvents.java deleted file mode 100644 index 9505a42..0000000 --- a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/util/EventBusEvents.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (C) 2014 Vlad Mihalachi - * - * This file is part of Turbo Editor. - * - * Turbo Editor is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Turbo Editor is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package sharedcode.turboeditor.util; - -import java.io.File; -import java.util.List; - -public class EventBusEvents { - public static class CannotOpenAFile { - - } - - public static class NewFileToOpen { - - private final File file; - private final String fileText; - - public NewFileToOpen(File file) { - this.file = file; - this.fileText = ""; - } - - public NewFileToOpen(String fileText) { - this.file = new File(""); - this.fileText = fileText; - } - - public File getFile() { - return file; - } - - public String getFileText() { - return fileText; - } - } - - public static class AFileIsSelected { - - private final String path; - - public AFileIsSelected(String path) { - this.path = path; - } - - public String getPath() { - return path; - } - } - - public static class APreferenceValueWasChanged { - private Type type; - private List types; - - public APreferenceValueWasChanged(Type type) { - this.type = type; - } - - public APreferenceValueWasChanged(List types) { - this.types = types; - } - - public boolean hasType(Type value) { - - if (type != null) { - return value == type; - } else { - return types.contains(value); - } - - } - - public enum Type { - FONT_SIZE, ENCODING, SYNTAX, WRAP_CONTENT, MONOSPACE, LINE_NUMERS, THEME_CHANGE, TEXT_SUGGESTIONS, READ_ONLY, - } - } - - public static class SaveAFile { - } - - public static class SavedAFile { - private final String path; - - public SavedAFile(String path) { - this.path = path; - } - - public String getPath() { - return path; - } - } - - public static class ClosedAFile { - } - - public static class InvalideTheMenu { - } - -} diff --git a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/util/ProCheckUtils.java b/libraries/sharedCode/src/main/java/sharedcode/turboeditor/util/ProCheckUtils.java index c9af73c..a7a1268 100644 --- a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/util/ProCheckUtils.java +++ b/libraries/sharedCode/src/main/java/sharedcode/turboeditor/util/ProCheckUtils.java @@ -21,21 +21,20 @@ package sharedcode.turboeditor.util; import android.content.Context; -import sharedcode.turboeditor.preferences.PreferenceHelper; - public class ProCheckUtils { public static boolean isPro(Context context, boolean includeDonations) { - String packageName = context.getPackageName(); - + // happy new year + return true; + /* if (Build.FOR_AMAZON) return true; - else if (packageName.equals("com.maskyn.fileeditorpro")) + else if (context.getPackageName().equals("com.maskyn.fileeditorpro")) return true; else if (includeDonations && PreferenceHelper.hasDonated(context)) return true; else - return false; + return false;*/ } public static boolean isPro(Context context) { diff --git a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/views/DialogHelper.java b/libraries/sharedCode/src/main/java/sharedcode/turboeditor/views/DialogHelper.java index 19e2ee0..a5b9fc2 100644 --- a/libraries/sharedCode/src/main/java/sharedcode/turboeditor/views/DialogHelper.java +++ b/libraries/sharedCode/src/main/java/sharedcode/turboeditor/views/DialogHelper.java @@ -39,7 +39,6 @@ import org.apache.commons.lang3.builder.HashCodeBuilder; import sharedcode.turboeditor.R; import sharedcode.turboeditor.dialogfragment.AboutDialog; -import sharedcode.turboeditor.iab.DonationFragment; /** * Helper class for showing fragment dialogs. @@ -48,13 +47,8 @@ public class DialogHelper { public static final String TAG_FRAGMENT_ABOUT = "dialog_about"; public static final String TAG_FRAGMENT_HELP = "dialog_help"; - public static final String TAG_FRAGMENT_DONATION = "dialog_donate"; public static final String TAG_FRAGMENT_FEEDBACK = "dialog_feedback"; - public static void showDonateDialog(Activity activity) { - showDialog(activity, DonationFragment.class, TAG_FRAGMENT_DONATION); - } - public static void showAboutDialog(Activity activity) { showDialog(activity, AboutDialog.class, TAG_FRAGMENT_ABOUT); } diff --git a/libraries/sharedCode/src/main/res/layout/activity_home.xml b/libraries/sharedCode/src/main/res/layout/activity_home.xml index 1cb26e4..d2a6573 100644 --- a/libraries/sharedCode/src/main/res/layout/activity_home.xml +++ b/libraries/sharedCode/src/main/res/layout/activity_home.xml @@ -18,16 +18,11 @@ ~ You should have received a copy of the GNU General Public License ~ along with this program. If not, see . --> - - + @@ -43,6 +38,14 @@ android:textColor="@android:color/secondary_text_dark" android:id="@id/no_file_opened_messagge"/> + + + + - + @@ -153,7 +156,7 @@ - - diff --git a/libraries/sharedCode/src/main/res/layout/dialog_fragment_new_file_details.xml b/libraries/sharedCode/src/main/res/layout/dialog_fragment_new_file_details.xml index 1964a11..b2749f8 100644 --- a/libraries/sharedCode/src/main/res/layout/dialog_fragment_new_file_details.xml +++ b/libraries/sharedCode/src/main/res/layout/dialog_fragment_new_file_details.xml @@ -58,4 +58,14 @@ android:hint="@string/folder" android:padding="5dp" android:textSize="12sp"/> + + diff --git a/libraries/sharedCode/src/main/res/layout/donation_dialog.xml b/libraries/sharedCode/src/main/res/layout/donation_dialog.xml deleted file mode 100644 index 2132d23..0000000 --- a/libraries/sharedCode/src/main/res/layout/donation_dialog.xml +++ /dev/null @@ -1,89 +0,0 @@ - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/libraries/sharedCode/src/main/res/layout/donation_iab_item.xml b/libraries/sharedCode/src/main/res/layout/donation_iab_item.xml deleted file mode 100644 index d931d87..0000000 --- a/libraries/sharedCode/src/main/res/layout/donation_iab_item.xml +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/libraries/sharedCode/src/main/res/layout/fragment_settings.xml b/libraries/sharedCode/src/main/res/layout/fragment_settings.xml index 7e93fb1..a152708 100644 --- a/libraries/sharedCode/src/main/res/layout/fragment_settings.xml +++ b/libraries/sharedCode/src/main/res/layout/fragment_settings.xml @@ -32,21 +32,6 @@ android:orientation="vertical" > - - +

+ + + + + - diff --git a/libraries/sharedCode/src/main/res/menu/fragment_editor_search.xml b/libraries/sharedCode/src/main/res/menu/fragment_editor_search.xml index 266aebd..70adc42 100644 --- a/libraries/sharedCode/src/main/res/menu/fragment_editor_search.xml +++ b/libraries/sharedCode/src/main/res/menu/fragment_editor_search.xml @@ -49,6 +49,11 @@ app:showAsAction="always" android:title="@string/replace"> + + Spenden - Donate to developer + An den Entwickler spenden open source app. - You can show your appreciation and support development by donating: + Turbo Editor ist eine freie und quelloffene Anwendung. + Du kannst deine Anerkennung zeigen, in dem du die Entwicklung mit Spenden unterstützt: ]]> - You\'ve donated for this item already. - An ice cream - Cup of coffee - Electricity bills - The right pillow - Solid-state drive - Sound system - Failed to setup in-app-billing service! - Notice that Google is not responsible for that payments method. + Du hast bereits gespendet. + Eine Kugel Eis + Tasse Kaffee + Stromrechnung + Das richtige Kissen + SSD Festplatte + Sound-System + Fehler beim Einrichten des In-App-Bezahlservices! + Beachten Sie, dass Google für diese Zahlungsmethode nicht verantwortlich ist. diff --git a/libraries/sharedCode/src/main/res/values-es-rES/strings.xml b/libraries/sharedCode/src/main/res/values-es-rES/strings.xml index 6f0241b..4e88eab 100644 --- a/libraries/sharedCode/src/main/res/values-es-rES/strings.xml +++ b/libraries/sharedCode/src/main/res/values-es-rES/strings.xml @@ -28,7 +28,7 @@ Ajuste de línea Ver en la web Archivo - archivo + Carpeta Tema claro Ir a línea Ir a página… diff --git a/libraries/sharedCode/src/main/res/values-es-rES/strings_donation.xml b/libraries/sharedCode/src/main/res/values-es-rES/strings_donation.xml index 17ef599..078efe3 100644 --- a/libraries/sharedCode/src/main/res/values-es-rES/strings_donation.xml +++ b/libraries/sharedCode/src/main/res/values-es-rES/strings_donation.xml @@ -20,7 +20,7 @@ --> Donar - Donate to developer + Donar al desarrollador open source app. You can show your appreciation and support development by donating: diff --git a/libraries/sharedCode/src/main/res/values-fi-rFI/strings.xml b/libraries/sharedCode/src/main/res/values-fi-rFI/strings.xml index fbb5d27..d04b4e7 100644 --- a/libraries/sharedCode/src/main/res/values-fi-rFI/strings.xml +++ b/libraries/sharedCode/src/main/res/values-fi-rFI/strings.xml @@ -30,7 +30,7 @@ Tiedosto Kansio Vaalea teema - Siirry riville + Siirry riville… Siirry sivulle… Löydä Korvaa @@ -51,7 +51,7 @@ Auta kääntämisessä Muutosloki Sama kirjainkoko - Saat lisää vaihtoehtoja napsauttamalla + Saat lisää vaihtoehtoja pitkällä painalluksella Automaattinen tallennus Vain luku Lähetä virheraportit diff --git a/libraries/sharedCode/src/main/res/values-fi-rFI/strings_dialogs.xml b/libraries/sharedCode/src/main/res/values-fi-rFI/strings_dialogs.xml index e8ce99d..7e74ba6 100644 --- a/libraries/sharedCode/src/main/res/values-fi-rFI/strings_dialogs.xml +++ b/libraries/sharedCode/src/main/res/values-fi-rFI/strings_dialogs.xml @@ -22,12 +22,12 @@ Sulje Tietoja avoimen lähdekoodin sovellus. + Turbo Editor on ilmainen ja avoimen lähdekoodin sovellus. Tekijänoikeudet 2013-2014 Vlad Mihalachi. Kaikki oikeudet pidätetään.

Suuret kiitokset kaikille, jotka auttoivat käännöksien parissa tai - lahjoittivat minulle.
+ lahjoittivat minulle.

Jos haluat lähettää palautetta, kerro se siitä XDA-ketjussa ]]>
diff --git a/libraries/sharedCode/src/main/res/values-fi-rFI/strings_donation.xml b/libraries/sharedCode/src/main/res/values-fi-rFI/strings_donation.xml index ea9cee6..140a157 100644 --- a/libraries/sharedCode/src/main/res/values-fi-rFI/strings_donation.xml +++ b/libraries/sharedCode/src/main/res/values-fi-rFI/strings_donation.xml @@ -28,7 +28,7 @@ Olet lahjoittanut tälle kohteelle jo. Jäätelöä Kuppi kahvia - Sähkölasku + Sähkölaskut Oikea tyyny SSD-levy Äänijärjestelmä diff --git a/libraries/sharedCode/src/main/res/values-hi-rIN/strings.xml b/libraries/sharedCode/src/main/res/values-hi-rIN/strings.xml index ba3c203..d6f2178 100644 --- a/libraries/sharedCode/src/main/res/values-hi-rIN/strings.xml +++ b/libraries/sharedCode/src/main/res/values-hi-rIN/strings.xml @@ -20,13 +20,13 @@ --> - Use monospace - Recent files + Monospace को उपयोग करें + हाल ही की दस्तावेज Font size Connection Name - Line Numbers - Wrap content - View it on the web + पंक्ति क्रमांक + सामग्री लपेटें + यह वेब पर देखें File Folder Light Theme diff --git a/libraries/sharedCode/src/main/res/values-hu-rHU/strings.xml b/libraries/sharedCode/src/main/res/values-hu-rHU/strings.xml index 1d5ce96..eb89e39 100644 --- a/libraries/sharedCode/src/main/res/values-hu-rHU/strings.xml +++ b/libraries/sharedCode/src/main/res/values-hu-rHU/strings.xml @@ -31,7 +31,7 @@ Mappa Világos téma Sorhoz ugrás - Go to Page… + Ugrás oldalra… Keresés Csere Megosztás @@ -54,11 +54,11 @@ Hosszú-kattintás a további beállításokhoz Automatikus mentés Csak olvasható - Send error reports - Extra options - Split the text if too long - Ignore back button - Donate + Hibajelentés küldése + Extra beállítások + A szöveg részekre bontása ha túl hosszú + Vissza-gomb figyelmen kívül hagyása + Támogatás Kódolás Megosztás Információ @@ -71,6 +71,6 @@ Megnyit A(z) %1$s fájl sikeresen mentve! Fájl megnyitása - No - New file + Nem + Új fájl diff --git a/libraries/sharedCode/src/main/res/values-hu-rHU/strings_dialogs.xml b/libraries/sharedCode/src/main/res/values-hu-rHU/strings_dialogs.xml index ad64876..f5ee4a1 100644 --- a/libraries/sharedCode/src/main/res/values-hu-rHU/strings_dialogs.xml +++ b/libraries/sharedCode/src/main/res/values-hu-rHU/strings_dialogs.xml @@ -19,16 +19,16 @@ ~ along with this program. If not, see . --> - Close - About + Bezárás + Névjegy open source app. + A Turbo Editor szabad és nyílt forráskódú alkalmazás. Copyright 2013-2014 Vlad Mihalachi. All Rights Reserved.

- Many thanks to all who - helped with translations or - donated to me.
+ Köszönet mindazoknak akik + segítettek a fordításban vagy + támogatást adtak.

- If you want to send feedback here is the XDA thread + Visszajelzéseket az XDA fórumon lehet küldeni ]]>
diff --git a/libraries/sharedCode/src/main/res/values-hu-rHU/strings_donation.xml b/libraries/sharedCode/src/main/res/values-hu-rHU/strings_donation.xml index 9b2bcc8..e51221a 100644 --- a/libraries/sharedCode/src/main/res/values-hu-rHU/strings_donation.xml +++ b/libraries/sharedCode/src/main/res/values-hu-rHU/strings_donation.xml @@ -19,19 +19,19 @@ ~ along with this program. If not, see . --> - Donate - Donate to developer + Támogatás + Támogatás a fejlesztőnek open source app. - You can show your appreciation and support development by donating: + A Turbo Editor egy szabad és nyílt forrású alkalmazás. + Mutassa meg mennyire értékeli és támogathassa a fejlesztést: ]]> - You\'ve donated for this item already. - An ice cream - Cup of coffee - Electricity bills - The right pillow - Solid-state drive - Sound system - Failed to setup in-app-billing service! - Notice that Google is not responsible for that payments method. + Ön már támogatta ezt. + Egy jégkrém + Egy csésze kávé + Villany számla + A jobb oldali párna + Szilárdtest-meghajtó + Hang-rendszer + Nem sikerült beállítani az alkalmazáson belüli fizetést! + Ne felejtse el, hogy a Google nem felel a fizetési módszerekért. diff --git a/libraries/sharedCode/src/main/res/values-in-rID/strings.xml b/libraries/sharedCode/src/main/res/values-in-rID/strings.xml index d4f7cbb..ef66929 100644 --- a/libraries/sharedCode/src/main/res/values-in-rID/strings.xml +++ b/libraries/sharedCode/src/main/res/values-in-rID/strings.xml @@ -25,52 +25,52 @@ Ukuran font Nama Sambungan Nomor Baris - Wrap Konten + Rapatkan Konten Lihat di web File Folder Tema Terang Pergi ke Baris - Go to Page… - Cari - Replace + Pergi ke halaman... + Temukan + Ganti Bagikan - Keyboard suggestions and Swipe + Saran keyboard dan usapan Pengkodean-Otomatis - Set as the working folder - This is the working folder - Do you want to save the changes to the file %s? - Regular Expression - Text to find - Text to replace - Next - Previous - Please wait… - %s occurrences was found + Jadikan sebagai folder kerja + Ini adalah folder kerja + Apakah Anda ingin menyimpan perubahan pada file ini %s? + Ekspresi Reguler + Ketik untuk mencari + Ketik untuk mengganti + Lanjut + Sebelum + Harap tunggu... + %s kejadian ditemukan v%s - Translate - Changelog - Match case - Long click for more options - Auto save - Read only - Send error reports - Extra options - Split the text if too long - Ignore back button - Donate + Terjemahkan + Daftar perubahan + Penyesuaian + Klik tahan untuk opsi lanjut + Simpan otomatis + Hanya baca + Kirim laporan kesalahan + Opsi ekstra + Membagi teks jika terlalu panjang + Abaikan tombol kembali + Donasi Pengkodean Bagikan Info - Editor Turbo + Turbo Editor Preferensi Simpan - Highlight syntax - Batal + Sorot sintaks + Batalkan Ulangi Buka File %1$s berhasil disimpan! Buka file - No - New file + Tidak + File baru
diff --git a/libraries/sharedCode/src/main/res/values-in-rID/strings_dialogs.xml b/libraries/sharedCode/src/main/res/values-in-rID/strings_dialogs.xml index ad64876..cee0958 100644 --- a/libraries/sharedCode/src/main/res/values-in-rID/strings_dialogs.xml +++ b/libraries/sharedCode/src/main/res/values-in-rID/strings_dialogs.xml @@ -19,16 +19,15 @@ ~ along with this program. If not, see . --> - Close - About + Tutup + Tentang open source app. - Copyright 2013-2014 Vlad Mihalachi. All Rights Reserved.
-
- Many thanks to all who - helped with translations or - donated to me.
-
- If you want to send feedback here is the XDA thread - ]]>
+Turbo Editor adalah sebuah aplikasi gratis dan open source app. +Copyright 2013-2014 Vlad Mihalachi. All Rights Reserved.
+
+Banyak terima kasih saya ucapkan kepada +yang telah membantu menerjemahkan aplikasi ini or +donasi kepada saya.
+
+Jika Anda ingin mengirim saran atau kritik Artikel di XDA ]]>
diff --git a/libraries/sharedCode/src/main/res/values-in-rID/strings_donation.xml b/libraries/sharedCode/src/main/res/values-in-rID/strings_donation.xml index 9b2bcc8..f6905c7 100644 --- a/libraries/sharedCode/src/main/res/values-in-rID/strings_donation.xml +++ b/libraries/sharedCode/src/main/res/values-in-rID/strings_donation.xml @@ -19,19 +19,18 @@ ~ along with this program. If not, see . --> - Donate - Donate to developer + Donasi + Donasi untuk pengembang open source app. - You can show your appreciation and support development by donating: - ]]> - You\'ve donated for this item already. - An ice cream - Cup of coffee - Electricity bills - The right pillow - Solid-state drive - Sound system - Failed to setup in-app-billing service! - Notice that Google is not responsible for that payments method. +Turbo Editor adalah sebuah aplikasi gratis dani open source app. +Anda dapat melihat apresiasi Anda dan dukungan pada pengembang dengan memberikan donasi: ]]> + Anda telah mendonasikan untuk item ini. + Sebuah es krim + Secangkir kopi + Tagihan listrik + Bantal yang tepat + Solid-state drive (SSD) + Sistem suara + Gagal dalam menyeting layanan pembelian dalam aplikasi! + Perhatikan bahwa Google tidak bertanggung jawab untuk metode pembayaran. diff --git a/libraries/sharedCode/src/main/res/values-pl-rPL/strings.xml b/libraries/sharedCode/src/main/res/values-pl-rPL/strings.xml index f9be2d0..2c0a860 100644 --- a/libraries/sharedCode/src/main/res/values-pl-rPL/strings.xml +++ b/libraries/sharedCode/src/main/res/values-pl-rPL/strings.xml @@ -31,7 +31,7 @@ Folder Jasny motyw Idź do linii - Go to Page… + Idź do strony… Znajdź Zastąp Udostępnij @@ -47,18 +47,18 @@ Poprzedni Proszę czekać… Znaleziono %s wystąpień - v%s + wersja %s Tłumacz Lista zmian Uwzględnij wielkość liter Przytrzymaj dłużej aby zobaczyć więcej opcji Automatyczny zapis Tylko do odczytu - Send error reports - Extra options - Split the text if too long - Ignore back button - Donate + Wyślij raport o błędach + Dodatkowe opcje + Podziel tekst, jeśli jest zbyt długi + Ignoruj przycisk \"Wstecz\" + Wesprzyj mnie Kodowanie Udostępnij Informacje @@ -71,6 +71,6 @@ Otwórz Plik %1$s został pomyślnie zapisany! Otwórz plik - No - New file + Nie + Nowy plik diff --git a/libraries/sharedCode/src/main/res/values-pl-rPL/strings_dialogs.xml b/libraries/sharedCode/src/main/res/values-pl-rPL/strings_dialogs.xml index ad64876..c081ac9 100644 --- a/libraries/sharedCode/src/main/res/values-pl-rPL/strings_dialogs.xml +++ b/libraries/sharedCode/src/main/res/values-pl-rPL/strings_dialogs.xml @@ -19,8 +19,8 @@ ~ along with this program. If not, see . --> - Close - About + Zamknij + O aplikacji i autorach open source app. Copyright 2013-2014 Vlad Mihalachi. All Rights Reserved.
diff --git a/libraries/sharedCode/src/main/res/values-pl-rPL/strings_donation.xml b/libraries/sharedCode/src/main/res/values-pl-rPL/strings_donation.xml index 9b2bcc8..96c9dff 100644 --- a/libraries/sharedCode/src/main/res/values-pl-rPL/strings_donation.xml +++ b/libraries/sharedCode/src/main/res/values-pl-rPL/strings_donation.xml @@ -19,8 +19,8 @@ ~ along with this program. If not, see . --> - Donate - Donate to developer + Wesprzyj mnie + Wspomóż twórcę open source app. You can show your appreciation and support development by donating: diff --git a/libraries/sharedCode/src/main/res/values-pt-rBR/strings.xml b/libraries/sharedCode/src/main/res/values-pt-rBR/strings.xml index 0e19838..f46e1c6 100644 --- a/libraries/sharedCode/src/main/res/values-pt-rBR/strings.xml +++ b/libraries/sharedCode/src/main/res/values-pt-rBR/strings.xml @@ -71,6 +71,6 @@ Abrir O arquivo %1$s foi salvo com sucesso! Abrir um arquivo - No - New file + Não + Novo arquivo diff --git a/libraries/sharedCode/src/main/res/values-ru-rRU/strings.xml b/libraries/sharedCode/src/main/res/values-ru-rRU/strings.xml index 9788828..9158cfb 100644 --- a/libraries/sharedCode/src/main/res/values-ru-rRU/strings.xml +++ b/libraries/sharedCode/src/main/res/values-ru-rRU/strings.xml @@ -30,13 +30,13 @@ Файл Каталог Светлая тема - Перейти к строке + Перейти к строке… Перейти на страницу… Поиск Заменить Поделиться - Car - Copy + Показывать варианты исправлений + Автоопределение кодировки Установить в качестве рабочего каталога Это рабочий каталог Сохранить изменения в файле %s? @@ -54,7 +54,7 @@ Долгое нажатие для дополнительных опций Автосохранение Только для чтения - Отправить отчёт об ошибке + Отправлять отчёты об ошибках Дополнительные опции Разбивать длинный текст Игнорировать кнопку Назад diff --git a/libraries/sharedCode/src/main/res/values-ru-rRU/strings_donation.xml b/libraries/sharedCode/src/main/res/values-ru-rRU/strings_donation.xml index a99fd86..9549f7f 100644 --- a/libraries/sharedCode/src/main/res/values-ru-rRU/strings_donation.xml +++ b/libraries/sharedCode/src/main/res/values-ru-rRU/strings_donation.xml @@ -20,18 +20,18 @@ --> Поддержать - Donate to developer + Пожертвовать разработчику open source app. - You can show your appreciation and support development by donating: + Turbo Editor является бесплатной и open source программой. + Вы можете выразить свою признательность и поддержку, пожертвовав: ]]> - You\'ve donated for this item already. - An ice cream - Cup of coffee - Electricity bills - The right pillow - Solid-state drive - Sound system - Failed to setup in-app-billing service! - Notice that Google is not responsible for that payments method. + Вы уже пожертвовали. + Мороженое + Чашка кофе + Счета за электричество + Отличная подушка + Твердотельный накопитель + Звуковая система + Не удалось запустить внутреннюю службу биллинга! + Имейте в виду, что Google не несет ответственности за данный способ оплаты. diff --git a/libraries/sharedCode/src/main/res/values-sk-rSK/strings.xml b/libraries/sharedCode/src/main/res/values-sk-rSK/strings.xml index 7bb7364..938d451 100644 --- a/libraries/sharedCode/src/main/res/values-sk-rSK/strings.xml +++ b/libraries/sharedCode/src/main/res/values-sk-rSK/strings.xml @@ -1,153 +1,76 @@ - - - - - - - Nový účet - Aktívne - Vymazať - Mažem súbory… - Načítavanie… - Aktuálna miestna zložka - Súkromný kľúč - Svetlá - Kódovanie - Zdieľať - Nový lokálny súbor - Nový vzdialený priečinok - New remote file - New local file - Odpojiť sa - Predvol. miestna zložka - Kde oi chcete stiahnuť? - Stiahnuť - Sťahovanie dokončené - Duplikát - Hotovo - Domov - Hosť - Info - Lokálny - Prihlasujem sa… - Upraviť - Presunúť - Schovať - Turbo Klient - Turbo Editor - Užív. meno - Pasívny - Heslo - Heslo - Ponechajte prázdne, pre výzvu pri každej relácii - Port - Predvoľby - vzdialený - Pre zmenu témy, reštartujte aplikáciu - Premenovať - Root - Uložiť - Tmavá - Vybrať - Vyberte účet - Ste si istý? - Niečo zlyhalo - Nepresúvajte rovnaký súbor - Téma - Typ pripojenia - Typ protokolu - Ďalšia zložka - Napíš heslo - Nahrať - Nahrávanie dokončené - Čo chceš robiť? - Syntax highlight - Vrátiť späť - Prerobiť - Synchronizovať - Vzdial. zložka na synchronizáciu - Miestna zložka na synchronizáciu - Ohodnotiť - Nemožno kontaktovať Google Play - Podpor rozvoj ďalších skvelých funkcií. - Vylepšiť na Premium - Vylepši na Premium a podpor tým vývoj Turbo klienta! - Stiahnuť odomknutú verziu - Čo pre teba Turbo klient znamená? Stanov si vlastnú cenu! - Vylepši na Premium, pre odomknutie týchto funkcií: - Power to open and modify any type of file. - Backup service to backup and restore your data safely. - Unlock the Premium features - I really like this app! - I love this app! - Backup the accounts - Restore the accounts - Backup and share the accounts - Importing the accounts… - Exporting the accounts... - No backups found - Cannot open the file - Temporary folder does not exist - An error occurred - Ui - Remove - Modification date - Name - Size - Sort - Open - The file %1$s was modified, do you want to upload it? - The file %1$s was saved with success! - Create a new account - Create a new account to start. - Type - Send feedback - Copy URL - Cut - paste - Advanced - Auto - Bytes - Unit of measurement for file size - Open Source licenses - Show open source licenses - Open a file - Open this time only - Change the list type - Use monospace - Recent files - Font size - Connection Name - Line Numbers - Wrap content - View it on the web - The file size is too big - Search - Add - File - Folder - Light Theme - Goto Line - Find - Find and Replace - Root Permission - Zdieľať - Text Suggestions - + + + + + + Použiť neproporcionálne + Nedávne súbory + Veľkosť písma + Názov pripojenia + Čísla riadkov + Zalomiť obsah + Zobraziť na webe + Súbor + Adresár + Svetlá téma + Prejsť na riadok… + Prejsť na stránku… + Nájsť + Nahradiť + Zdieľať + Návrhy opráv a písanie gestami + Automatické kódovanie + Nastaviť ako pracovný adresár + Toto je pracovný adresár + Chcete uložiť zmeny v súbore %s? + Presný výraz + Text, ktorý chcete nájsť + Text, ktorý chcete nahradiť + Ďalšie + Predchádzajúce + Prosím, počkajte… + %s výskytov bolo nájdených + v%s + Preložiť + Zoznam zmien + Rozlišovať malé a veľké písmená + Podržte dlhšie pre viac možností + Automatické ukladanie + Iba na čítanie + Odoslať správy o chybách + Ďalšie voľby + Rozdeliť text, ak je príliš dlhý + Ignorovať tlačidlo späť + Prispieť + Kódovanie + Zdieľať + Informácie + Turbo Editor + Predvoľby + Uložiť + Zvýrazniť syntax + Späť + Znova + Otvoriť + Súbor %1$s bol úspešne uložený! + Otvoriť súbor + Nie + Nový súbor + diff --git a/libraries/sharedCode/src/main/res/values/integers.xml b/libraries/sharedCode/src/main/res/values-sk-rSK/strings_dialogs.xml similarity index 50% rename from libraries/sharedCode/src/main/res/values/integers.xml rename to libraries/sharedCode/src/main/res/values-sk-rSK/strings_dialogs.xml index 5768659..f03d946 100644 --- a/libraries/sharedCode/src/main/res/values/integers.xml +++ b/libraries/sharedCode/src/main/res/values-sk-rSK/strings_dialogs.xml @@ -1,23 +1,34 @@ - - - - - 4194304 - + + + + + Zatvoriť + O aplikácii + zdrojový kód je voľné dostupný. + Copyright 2013-2014 Vlad Mihalachi. Všetky práva vyhradené.
+
+ Veľká vďaka všetkým + prekladateľom aj tým, + ktorí mi poslali dar.
+
+ Svoj názor na aplikáciu môžete vyjadriť v téme na XDA + ]]>
+
diff --git a/libraries/sharedCode/src/main/res/values-sk-rSK/strings_donation.xml b/libraries/sharedCode/src/main/res/values-sk-rSK/strings_donation.xml new file mode 100644 index 0000000..e98076a --- /dev/null +++ b/libraries/sharedCode/src/main/res/values-sk-rSK/strings_donation.xml @@ -0,0 +1,37 @@ + + + + + Prispieť + Podporiť vývojára + zdrojový kód je voľné dostupný. + Môžete ukázať svoje uznanie a podporiť rozvoj tým, že pošlete dar: + ]]> + Už ste pre túto položku poslali dar. + Zmrzlina + Šálka kávy + Účet za elektrinu + Správny vankúš + SSD disk + Domáce kino + Zlyhalo nastavenie služby nákupu v aplikácii! + Prosím, berte na vedomie, že Google nie je zodpovedný za túto metódu platby. + diff --git a/libraries/sharedCode/src/main/res/values-sv-rSE/strings.xml b/libraries/sharedCode/src/main/res/values-sv-rSE/strings.xml index bfcb5d9..e80f6d5 100644 --- a/libraries/sharedCode/src/main/res/values-sv-rSE/strings.xml +++ b/libraries/sharedCode/src/main/res/values-sv-rSE/strings.xml @@ -21,56 +21,56 @@ Använd monospace - Senaste filer + Senaste filerna Storlek för typsnitt Benämning för anslutningen Radnummer - Wrap content - View it on the web - File - Folder - Light Theme - Go to Line… - Go to Page… - Find - Replace - Share - Keyboard suggestions and Swipe - Auto-Encoding - Set as the working folder - This is the working folder - Do you want to save the changes to the file %s? - Regular Expression - Text to find - Text to replace - Next - Previous - Please wait… - %s occurrences was found + Linda in innehåll + Kolla på det i webbläsaren + Fil + Mapp + Ljust Tema + Gå Till Linje… + Gå Till Sida… + Hitta + Byt Ut + Dela + Tangentbordsförslag och Swipe + Auto-Kodning + Sätt som nuvarande mapp + Det här är den nuvarande mappen + Vill du spara ändringarna till filen %s? + Reguljära uttryck + Text att hitta + Text som ska ersätta + Nästa + Förra + Var god vänta… + %s träffar hittade v%s - Translate - Changelog - Match case - Long click for more options - Auto save - Read only - Send error reports - Extra options - Split the text if too long - Ignore back button - Donate + Översätt + Ändringar + Matcha stor/liten bokstav + Långtryck för fler inställningar + Autospara + Läs endast läge + Skicka felrapport + Extra inställningar + Dela upp texten om den är för lång + Ignorera Tillbakaknappen + Donera Encoding - Share + Dela Info Turbo Editor - Preferences - Save - Syntax highlight - Undo - Redo - Open - The file %1$s was saved with success! - Open a file - No - New file + Inställningar + Spara + Syntax Markering + Ångra + Återställ + Öppna + Filen %1$s sparades! + Öppna en fil + Nej + Ny fil diff --git a/libraries/sharedCode/src/main/res/values-sv-rSE/strings_dialogs.xml b/libraries/sharedCode/src/main/res/values-sv-rSE/strings_dialogs.xml index ad64876..56411c1 100644 --- a/libraries/sharedCode/src/main/res/values-sv-rSE/strings_dialogs.xml +++ b/libraries/sharedCode/src/main/res/values-sv-rSE/strings_dialogs.xml @@ -19,16 +19,16 @@ ~ along with this program. If not, see . --> - Close - About + Stäng + Om open source app. + Turbo Editor är en gratis och öppen källkod app. Copyright 2013-2014 Vlad Mihalachi. All Rights Reserved.

- Many thanks to all who - helped with translations or - donated to me.
+ Många tack till alla som + hjälpt med översättningar eller + donerat.

- If you want to send feedback here is the XDA thread + Om du vill skicka feedback är detta XDA Tråden ]]>
diff --git a/libraries/sharedCode/src/main/res/values-sv-rSE/strings_donation.xml b/libraries/sharedCode/src/main/res/values-sv-rSE/strings_donation.xml deleted file mode 100644 index 9b2bcc8..0000000 --- a/libraries/sharedCode/src/main/res/values-sv-rSE/strings_donation.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - Donate - Donate to developer - open source app. - You can show your appreciation and support development by donating: - ]]> - You\'ve donated for this item already. - An ice cream - Cup of coffee - Electricity bills - The right pillow - Solid-state drive - Sound system - Failed to setup in-app-billing service! - Notice that Google is not responsible for that payments method. - diff --git a/libraries/sharedCode/src/main/res/values-tr-rTR/strings_dialogs.xml b/libraries/sharedCode/src/main/res/values-tr-rTR/strings_dialogs.xml index a90ae36..ee3095f 100644 --- a/libraries/sharedCode/src/main/res/values-tr-rTR/strings_dialogs.xml +++ b/libraries/sharedCode/src/main/res/values-tr-rTR/strings_dialogs.xml @@ -21,13 +21,10 @@ Kapat Hakkında - açık kaynak bir uygulamadır. + açık kaynak bir uygulamadır. Telif hakkı 2013-2014 Vlad Mihalachi. Tüm Hakları Saklıdır.

- Tüm çevirileriyle - veya bağışlarıyla yardımcı olanlara çok teşekkürler.
+ Tüm çevirileriyle veya bağışlarıyla yardımcı olanlara çok teşekkürler.

- Geri bildirim göndermek istiyorsanız XDA konusunu kullanabilirsiniz - ]]>
+ Geri bildirim göndermek istiyorsanız XDA konusunu kullanabilirsiniz]]>
diff --git a/libraries/sharedCode/src/main/res/values-tr-rTR/strings_donation.xml b/libraries/sharedCode/src/main/res/values-tr-rTR/strings_donation.xml index d6e4c1f..141cee0 100644 --- a/libraries/sharedCode/src/main/res/values-tr-rTR/strings_donation.xml +++ b/libraries/sharedCode/src/main/res/values-tr-rTR/strings_donation.xml @@ -26,8 +26,8 @@ Bağış yaparak gelişimini destekleyebilir ve beğeninizi gösterebilirsiniz: ]]>
Zaten bu öğe için bağış yaptınız. - Bir dondurma - Bir fincan kahve + Dondurma + Kahve Elektrik faturaları Ortopedik yastık Solid-state sürücü diff --git a/libraries/sharedCode/src/main/res/values-uk-rUA/strings.xml b/libraries/sharedCode/src/main/res/values-uk-rUA/strings.xml index ba3c203..c0500a1 100644 --- a/libraries/sharedCode/src/main/res/values-uk-rUA/strings.xml +++ b/libraries/sharedCode/src/main/res/values-uk-rUA/strings.xml @@ -20,57 +20,57 @@ --> - Use monospace - Recent files - Font size - Connection Name - Line Numbers - Wrap content - View it on the web - File - Folder - Light Theme - Go to Line… - Go to Page… - Find - Replace - Share - Keyboard suggestions and Swipe - Auto-Encoding - Set as the working folder - This is the working folder - Do you want to save the changes to the file %s? - Regular Expression - Text to find - Text to replace - Next - Previous - Please wait… - %s occurrences was found + Моноширний шрифт + Нещодавні файли + Розмір шрифту + Назва з\'єднання + Нумерація рядків + Перенесення рядків + Переглянути в броузері + Файл + Папка + Світла тема + Перейти на рядок… + Перейти на сторінку… + Пошук + Замінити + Поділитись + Клавіатурні підказки і свайп + Автоматичне кодування + Встановити як робочу папку + Це робоча папка + Зберегти зміни у файлі %s? + Регулярний вираз + Текст для пошуку + Текст для заміни + Далі + Назад + Будь ласка, зачекайте… + Знайдено %s v%s - Translate - Changelog - Match case - Long click for more options - Auto save - Read only - Send error reports - Extra options - Split the text if too long - Ignore back button - Donate - Encoding - Share - Info + Перекласти + Історія змін + Враховувати регістр + Утримуйте для додаткових опцій + Автоматичне збереження + Тільки для читання + Відправляти звіти про помилки + Додаткові опції + Розділення тексту, якщо занадто довгий + Ігнорувати кнопку Назад + Пожертвувати + Кодування + Поділитись + Інформація Turbo Editor - Preferences - Save - Syntax highlight - Undo - Redo - Open - The file %1$s was saved with success! - Open a file - No - New file + Налаштування + Зберегти + Підсвітка синтаксису + Скасувати + Повторити + Відкрити + Файл %1$s було успішно збережено! + Відкрити файл + Ні + Новий файл diff --git a/libraries/sharedCode/src/main/res/values-uk-rUA/strings_dialogs.xml b/libraries/sharedCode/src/main/res/values-uk-rUA/strings_dialogs.xml index ad64876..8a45f35 100644 --- a/libraries/sharedCode/src/main/res/values-uk-rUA/strings_dialogs.xml +++ b/libraries/sharedCode/src/main/res/values-uk-rUA/strings_dialogs.xml @@ -1,5 +1,4 @@ - + + + - Close - About + Закрити + Про програму open source app. + Turbo Editor це безкоштовна програма з відкритим вихідним кодом. Copyright 2013-2014 Vlad Mihalachi. All Rights Reserved.

- Many thanks to all who - helped with translations or - donated to me.
+ Велике спасибі всім хто + допомагає з перекладами або + підтримує мене

- If you want to send feedback here is the XDA thread + Зворотній зв\'язок тема на XDA ]]>
diff --git a/libraries/sharedCode/src/main/res/values-uk-rUA/strings_donation.xml b/libraries/sharedCode/src/main/res/values-uk-rUA/strings_donation.xml index 9b2bcc8..9c85e10 100644 --- a/libraries/sharedCode/src/main/res/values-uk-rUA/strings_donation.xml +++ b/libraries/sharedCode/src/main/res/values-uk-rUA/strings_donation.xml @@ -19,19 +19,19 @@ ~ along with this program. If not, see . --> - Donate - Donate to developer + Пожертвувати + Пожертва розробнику open source app. - You can show your appreciation and support development by donating: + Turbo Editor це безкоштовна програма з відкритим вихідним кодом. + Ви можете показати вашу вдячність і підтримати проект пожертвами: ]]> - You\'ve donated for this item already. - An ice cream - Cup of coffee - Electricity bills - The right pillow - Solid-state drive - Sound system - Failed to setup in-app-billing service! - Notice that Google is not responsible for that payments method. + Ви вже пожертвували. + Морозиво + Чашка кави + Рахунки за електрику + Хорошу подушку + SSD диск + Аудіо систему + Не вдалося виконати in-app-billing сервіс! + Зверніть увагу, що Google не відповідає за цей метод платежу. diff --git a/libraries/sharedCode/src/main/res/values/ids.xml b/libraries/sharedCode/src/main/res/values/ids.xml index c549bfe..de50092 100644 --- a/libraries/sharedCode/src/main/res/values/ids.xml +++ b/libraries/sharedCode/src/main/res/values/ids.xml @@ -28,6 +28,8 @@ + + @@ -46,6 +48,7 @@ + @@ -62,6 +65,7 @@ + diff --git a/libraries/sharedCode/src/main/res/values/strings.xml b/libraries/sharedCode/src/main/res/values/strings.xml index 72871dc..11ca75a 100644 --- a/libraries/sharedCode/src/main/res/values/strings.xml +++ b/libraries/sharedCode/src/main/res/values/strings.xml @@ -64,6 +64,7 @@ Turbo Editor Preferences Save + Save as Syntax highlight Undo Redo @@ -72,4 +73,6 @@ Open a file No New file + Delete current file + Replace all