25 Commits

Author SHA1 Message Date
78407c292a New material things 2014-10-25 14:35:31 +02:00
4d26fa7f3d Updated translations from crowdin 2014-10-18 15:47:54 +02:00
4b16119b53 Version 1.13 2014-10-18 15:20:23 +02:00
bf4dcd51b8 Merge pull request #41 from RyDroid/gitignore
Adding some rules to .gitignore
2014-10-18 15:02:54 +02:00
e52a3cb9f5 Merge pull request #42 from RyDroid/mime-types
Adding and reorganizing a little mime types
2014-10-18 15:02:27 +02:00
5702a6c24f Adding and reorganizing a little mime types 2014-10-18 01:29:07 +02:00
ffcd50616e Adding some rules to .gitignore 2014-10-18 01:25:09 +02:00
46842a5343 Version 1.12 2014-10-12 18:11:19 +02:00
df5a302129 Some fixes 2014-10-07 18:55:18 +02:00
04faa104ed Merge pull request #30 from DF1E/master
update LinuxShell from SimpleExplorer
2014-10-02 19:03:37 +02:00
a20f93f0f6 remove old info from LinuxShell 2014-10-02 18:33:44 +02:00
564e55385f update LinuxShell from SimpleExplorer
https://github.com/DF1E/SimpleExplorer/blob/master/src/com/dnielfe/manager/commands/RootCommands.java
2014-10-02 18:25:12 +02:00
2c62965a02 Version 1.11 2014-09-30 20:01:43 +02:00
eaab21069b Some minor but major changes
New advance settings screen, new setting to ignore the back button, new
behaviour of the left and right panels, now the app highlightes all the
visible text
2014-09-28 10:55:13 +02:00
2dbab5220a fixed a visual issue 2014-09-27 17:48:57 +02:00
520c4c53c0 Readded the jar, and fixed a keyboard issue 2014-09-27 15:20:05 +02:00
2fefb3963c Update README.md 2014-09-27 14:49:52 +02:00
e0eb01168e Update README.md 2014-09-26 12:53:13 +02:00
30294f72b5 Update README.md 2014-09-26 12:07:42 +02:00
ed621d369e Update README.md 2014-09-26 12:06:32 +02:00
6507331360 Update README.md 2014-09-26 11:40:00 +02:00
ec4742149b Update README.md 2014-09-26 11:36:05 +02:00
97dd211dc2 Removed the jar "juniversalchardet" 2014-09-26 11:24:19 +02:00
fc67e5930e Added the "pro" module
The pro version doesn't have ads so it doesn't require crashlytics and
play-services
2014-09-25 20:00:25 +02:00
44d4a2828b Small change 2014-09-25 14:31:27 +02:00
361 changed files with 13500 additions and 13024 deletions

5
.gitignore vendored
View File

@ -11,6 +11,7 @@
# Generated files
bin/
gen/
doc/
# Proguard folder generated by Eclipse
proguard/
@ -18,8 +19,6 @@ proguard/
# Log Files
*.log
app-pro/
# Built application files
/*/build/
@ -59,3 +58,5 @@ local.properties
.Trashes
ehthumbs.db
Thumbs.db
*~
#*#

174
.idea/codeStyleSettings.xml generated Normal file
View File

@ -0,0 +1,174 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectCodeStyleSettingsManager">
<option name="PER_PROJECT_SETTINGS">
<value>
<option name="CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
<option name="NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND" value="99" />
<option name="PACKAGES_TO_USE_IMPORT_ON_DEMAND">
<value />
</option>
<option name="IMPORT_LAYOUT_TABLE">
<value>
<package name="android" withSubpackages="true" static="false" />
<emptyLine />
<package name="com" withSubpackages="true" static="false" />
<emptyLine />
<package name="junit" withSubpackages="true" static="false" />
<emptyLine />
<package name="net" withSubpackages="true" static="false" />
<emptyLine />
<package name="org" withSubpackages="true" static="false" />
<emptyLine />
<package name="java" withSubpackages="true" static="false" />
<emptyLine />
<package name="javax" withSubpackages="true" static="false" />
<emptyLine />
<package name="" withSubpackages="true" static="false" />
<emptyLine />
<package name="" withSubpackages="true" static="true" />
<emptyLine />
</value>
</option>
<option name="RIGHT_MARGIN" value="100" />
<AndroidXmlCodeStyleSettings>
<option name="USE_CUSTOM_SETTINGS" value="true" />
</AndroidXmlCodeStyleSettings>
<XML>
<option name="XML_LEGACY_SETTINGS_IMPORTED" value="true" />
</XML>
<codeStyleSettings language="XML">
<option name="FORCE_REARRANGE_MODE" value="1" />
<indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions>
<arrangement>
<rules>
<rule>
<match>
<AND>
<NAME>xmlns:android</NAME>
<XML_NAMESPACE>Namespace:</XML_NAMESPACE>
</AND>
</match>
</rule>
<rule>
<match>
<AND>
<NAME>xmlns:.*</NAME>
<XML_NAMESPACE>Namespace:</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
<rule>
<match>
<AND>
<NAME>.*:id</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
<rule>
<match>
<AND>
<NAME>.*:name</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
<rule>
<match>
<AND>
<NAME>name</NAME>
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
<rule>
<match>
<AND>
<NAME>style</NAME>
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
<rule>
<match>
<AND>
<NAME>.*:layout_width</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
<rule>
<match>
<AND>
<NAME>.*:layout_height</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
<rule>
<match>
<AND>
<NAME>.*:layout_.*</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
<rule>
<match>
<AND>
<NAME>.*:width</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
<rule>
<match>
<AND>
<NAME>.*:height</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_NAMESPACE>.*</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</rules>
</arrangement>
</codeStyleSettings>
</value>
</option>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default (1)" />
</component>
</project>

View File

@ -4,6 +4,11 @@
<option name="myLocal" value="false" />
<inspection_tool class="AndroidLintMissingQuantity" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="AndroidLintMissingTranslation" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="AndroidLintNewApi" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="AndroidLintUnusedQuantity" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="LoggerInitializedWithForeignClass" enabled="false" level="WARNING" enabled_by_default="false">
<option name="loggerClassName" value="org.apache.log4j.Logger,org.slf4j.LoggerFactory,org.apache.commons.logging.LogFactory,java.util.logging.Logger" />
<option name="loggerFactoryMethodName" value="getLogger,getLogger,getLog,getLogger" />
</inspection_tool>
</profile>
</component>

View File

@ -1,38 +1,32 @@
# Turbo Editor
[![Crowdin](https://d322cqt584bo4o.cloudfront.net/turbo-client/localized.png)](https://crowdin.com/project/turbo-client)
Simple, powerful and Open Source file editor for Android licensed under the GPLv3 license.
Simple, powerful and Open Source text editor for Android licensed under the GPLv3 license.
### Download
[![Play Store](http://developer.android.com/images/brand/en_generic_rgb_wo_60.png)](http://play.google.com/store/apps/details?id=com.maskyn.fileeditorpro)
[![F-Droid](https://lh5.googleusercontent.com/-zezQqsBye0c/VCUpPVjcKEI/AAAAAAAAAIQ/HbcG5f1qMIw/w129-h45-no/getitonfdroid.png)](https://f-droid.org/repository/browse/?fdid=com.maskyn.fileeditorpro)
### Contribute
You can contribute to this project in many ways:
* Browse our issues, comment on proposals, report bugs.
* Clone the balanced-dashboard repo, make some changes according to our
development guidelines and issue a pull-request with your changes.
* Help to translate the application on [Crowdin][crowdin]
* [Donate][donate]
------
### Development guidelines
1. Fork it (`git clone git://github.com/vmihalachi/turbo-editor.git`)
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Write your code
4. Commit your changes (`git commit -am 'Add some feature'`)
5. Push to the branch (`git push origin my-new-feature`)
6. Create new [pull request](https://help.github.com/articles/using-pull-requests)
* Be a part of the Google Plus [Community][community googleplus]
* Discuss with us on [XDA thread][xda thread]
* Help to maintain this project active and [Donate][donate]
------
###Donate
* Make a [Paypal][donate paypal] donation
* Flattr this project [![Flattr this git repo](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=vmihalachi&url=https://raw.github.com/vmihalachi/turbo-editor&title=Turbo Editor&language=&tags=github&category=software)
[![Paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=26VWS2TSAMUJA)
[![Flattr this git repo](http://api.flattr.com/button/flattr-badge-large.png)](https://flattr.com/submit/auto?user_id=vmihalachi&url=https://github.com/vmihalachi/turbo-editor&title=Turbo Editor&language=java&tags=github&category=software)
------
###Download
* From the [Play Store][download playstore]
* Want to try beta releases? Be a part of the Google Plus [Community][community googleplus]!
###Images
![](https://lh3.googleusercontent.com/-0GHukwGQPW4/VCUpEhKnZCI/AAAAAAAAAH4/cclI70K79_Q/w347-h520-no/PhoneCustom_7.png)![](https://lh3.googleusercontent.com/-OvazluFl_QQ/VCUo9DAje9I/AAAAAAAAAHQ/i7n1uCpU1hE/w347-h520-no/PhoneCustom_1.png)![](https://lh4.googleusercontent.com/-zh4CYdQPecg/VCUpD3QXpAI/AAAAAAAAAHw/ulL5-V0iJUw/w347-h520-no/PhoneCustom_6.png)![](https://lh4.googleusercontent.com/-LT3k4z9JHo8/VCUo_0jnZRI/AAAAAAAAAHg/Npk9UlkXIV8/w347-h520-no/PhoneCustom_4.png)![](https://lh5.googleusercontent.com/-hXvsf-WYvBs/VCUo9sYfR-I/AAAAAAAAAHY/TTfAgiV_7ko/w347-h520-no/PhoneCustom_3.png)![](https://lh6.googleusercontent.com/-Qib82pK6mZU/VCUpAgYmUdI/AAAAAAAAAHo/zoPVmwcatbQ/w347-h520-no/PhoneCustom_5.png)![](https://lh5.googleusercontent.com/-SERL7X-JHuc/VCax0QSlCGI/AAAAAAAAAJA/hu8dvbvJGBM/w375-h563-no/PhoneCustom_2.png)
------
### Developer
@ -56,8 +50,8 @@ See the [LICENSE][license] file that accompanies this distribution for the full
[license]: https://github.com/vmihalachi/turbo-editor/LICENSE
[donate]: https://github.com/vmihalachi/turbo-editor#donate
[donate paypal]: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=PUQXSX6MTXHZ2
[xda thread]: http://forum.xda-developers.com/android/apps-games/app-turbo-editor-text-editor-t2832016
[community googleplus]: https://plus.google.com/u/0/communities/111974095419108178946
[download playstore]: https://play.google.com/store/apps/details?id=com.maskyn.fileeditor
[crowdin]: https://crowdin.net/project/turbo-client
[developer site]: http://vmihalachi.com/
[crowdin]: https://crowdin.net/project/turbo-client

1
app-pro/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/build

56
app-pro/build.gradle Normal file
View File

@ -0,0 +1,56 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
apply plugin: 'com.android.application'
android {
compileSdkVersion 21
buildToolsVersion '21.0.2'
defaultConfig {
applicationId "com.maskyn.fileeditorpro"
minSdkVersion 11
targetSdkVersion 21
versionCode 31
versionName "1.12"
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
buildTypes {
release {
runProguard false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
lintOptions {
abortOnError false
}
packagingOptions {
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/NOTICE.txt'
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile project(':libraries:sharedCode')
}

17
app-pro/proguard-rules.pro vendored Normal file
View File

@ -0,0 +1,17 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in C:/Users/Vlad/AppData/Local/Android/android-sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

View File

@ -17,15 +17,16 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package sharedcode.turboeditor.util;
package com.maskyn.fileeditorpro;
import android.widget.ScrollView;
import android.app.Application;
import android.test.ApplicationTestCase;
import sharedcode.turboeditor.views.GoodScrollView;
public interface EditorInterface {
public GoodScrollView getVerticalScrollView();
public String getFilePath();
public PageSystem getPageSystem();
public void updateTextSyntax();
/**
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
*/
public class ApplicationTest extends ApplicationTestCase<Application> {
public ApplicationTest() {
super(Application.class);
}
}

View File

@ -0,0 +1,120 @@
<!--
~ 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 <http://www.gnu.org/licenses/>.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.maskyn.fileeditorpro"
android:installLocation="auto">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_SUPERUSER" />
<supports-screens
android:anyDensity="true"
android:largeScreens="true"
android:normalScreens="true"
android:resizeable="true"
android:smallScreens="true"
android:xlargeScreens="true" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/nome_app_turbo_editor"
android:hardwareAccelerated="true"
android:largeHeap="true"
android:supportsRtl="true"
android:name="sharedcode.turboeditor.activity.MyApp"
>
<!-- android:alwaysRetainTaskState="true" -->
<activity
android:name=".HomeActivity"
android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen"
android:launchMode="singleTop"
android:windowSoftInputMode="stateUnspecified|adjustResize"
android:theme="@style/AppThemeEditorDark">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.MULTIWINDOW_LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.EDIT" />
<action android:name="android.intent.action.PICK" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="file" />
<data android:mimeType="text/*" />
<data android:pathPattern="*.txt" />
<data android:pathPattern="*.html" />
<data android:pathPattern="*.css" />
<data android:pathPattern="*.js" />
<data android:pathPattern="*.md"/>
<data android:pathPattern="*.php" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
<activity
android:name="sharedcode.turboeditor.activity.SelectFileActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/open_a_file"
android:parentActivityName=".HomeActivity"
android:theme="@style/AppThemeBaseLight">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".HomeActivity" />
</activity>
<activity
android:name="sharedcode.turboeditor.preferences.ExtraSettingsActivity"
android:label="@string/extra_options"
android:parentActivityName=".HomeActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".HomeActivity" />
</activity>
<meta-data
android:name="com.sec.android.support.multiwindow"
android:value="true" />
<meta-data
android:name="com.sec.android.multiwindow.DEFAULT_SIZE_W"
android:value="632.0dip" />
<meta-data
android:name="com.sec.android.multiwindow.DEFAULT_SIZE_H"
android:value="598.0dip" />
<meta-data
android:name="com.sec.android.multiwindow.MINIMUM_SIZE_W"
android:value="632.0dip" />
<meta-data
android:name="com.sec.android.multiwindow.MINIMUM_SIZE_H"
android:value="598.0dip" />
</application>
</manifest>

View File

@ -17,9 +17,16 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package sharedcode.turboeditor.util;
package com.maskyn.fileeditorpro;
public class Constants {
public static final int MAX_FILE_SIZE = 20_000;
public static final boolean FOR_AMAZON = false;
import android.os.Bundle;
import sharedcode.turboeditor.activity.BaseHomeActivity;
public class HomeActivity extends BaseHomeActivity {
@Override
public void displayInterstitial() {
// nothing to do here
}
}

View File

@ -19,33 +19,35 @@
buildscript {
repositories {
maven { url 'http://download.crashlytics.com/maven' }
mavenCentral()
maven { url 'https://maven.fabric.io/repo' }
}
dependencies {
classpath 'com.crashlytics.tools.gradle:crashlytics-gradle:1.+'
classpath 'io.fabric.tools:gradle:1.+'
}
}
apply plugin: 'com.android.application'
apply plugin: 'crashlytics'
apply plugin: 'io.fabric'
repositories {
maven { url 'http://download.crashlytics.com/maven' }
mavenCentral()
maven { url 'https://maven.fabric.io/repo' }
}
android {
compileSdkVersion 20
buildToolsVersion "20.0.0"
compileSdkVersion 21
buildToolsVersion '21.0.2'
defaultConfig {
applicationId "com.maskyn.fileeditor"
minSdkVersion 14
targetSdkVersion 20
versionCode 26
versionName "1.10"
minSdkVersion 11
targetSdkVersion 21
versionCode 31
versionName "1.13"
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
@ -57,12 +59,20 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
lintOptions {
abortOnError false
}
packagingOptions {
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/NOTICE.txt'
}
}
dependencies {
compile fileTree(dir: 'libs', include: '*.jar')
compile project(':libraries:sharedCode')
compile 'com.google.android.gms:play-services:5.0.89'
compile 'com.crashlytics.android:crashlytics:1.+'
compile 'com.google.android.gms:play-services:6.1.11'
compile('com.crashlytics.sdk.android:crashlytics:2.+@aar') {
transitive = true;
}
}

View File

@ -26,6 +26,7 @@
<uses-permission android:name="android.permission.ACCESS_SUPERUSER" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="com.android.vending.BILLING" />
<supports-screens
android:anyDensity="true"
@ -39,9 +40,10 @@
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/nome_app_turbo_editor"
android:hardwareAccelerated="false"
android:hardwareAccelerated="true"
android:largeHeap="true"
android:supportsRtl="true"
android:name="sharedcode.turboeditor.activity.MyApp"
>
<!-- android:alwaysRetainTaskState="true" -->
@ -52,8 +54,8 @@
android:name=".HomeActivity"
android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen"
android:launchMode="singleTop"
android:windowSoftInputMode="stateUnspecified|adjustPan"
android:theme="@style/AppTheme.Light.Editor">
android:windowSoftInputMode="stateUnspecified|adjustResize"
android:theme="@style/AppThemeEditorDark">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@ -83,35 +85,24 @@
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
<activity
android:name="sharedcode.turboeditor.activity.PreferenceAbout"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/info"
android:parentActivityName=".HomeActivity"
android:theme="@style/AppTheme.Dark">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.maskyn.fileeditor.activity.HomeActivity" />
</activity>
<activity
android:name="sharedcode.turboeditor.activity.LicensesActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/open_source_license"
android:parentActivityName="sharedcode.turboeditor.activity.PreferenceAbout"
android:theme="@style/AppTheme.Light">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.maskyn.fileeditor.activity.PreferenceAbout" />
</activity>
<activity
android:name="sharedcode.turboeditor.activity.SelectFileActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/open_a_file"
android:parentActivityName=".HomeActivity"
android:theme="@style/AppTheme.Light">
android:theme="@style/AppThemeBaseLight">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.maskyn.fileeditor.activity.HomeActivity" />
android:value=".HomeActivity" />
</activity>
<activity
android:name="sharedcode.turboeditor.preferences.ExtraSettingsActivity"
android:label="@string/extra_options"
android:parentActivityName=".HomeActivity">
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".HomeActivity" />
</activity>
<meta-data

View File

@ -20,6 +20,8 @@
package com.maskyn.fileeditor;
import android.app.Activity;
import android.preference.PreferenceManager;
import com.google.android.gms.ads.AdRequest;
import com.google.android.gms.ads.InterstitialAd;
@ -28,32 +30,21 @@ import java.util.Calendar;
import sharedcode.turboeditor.preferences.PreferenceHelper;
public class AdsHelper {
private Activity activity;
private InterstitialAd interstitial;
public AdsHelper(Activity activity) {
this.activity = activity;
int today = Calendar.getInstance().get(Calendar.DAY_OF_MONTH);
int lastDayAdShowed = PreferenceHelper.getLastDayAdShowed(activity);
boolean showAd = today != lastDayAdShowed;
if (showAd) {
interstitial = new InterstitialAd(activity);
interstitial.setAdUnitId("ca-app-pub-5679083452234719/7178038180");
interstitial = new InterstitialAd(activity);
interstitial.setAdUnitId("ca-app-pub-5679083452234719/7178038180");
// Create ad request.
AdRequest adRequest = new AdRequest.Builder().build();
// Create ad request.
AdRequest adRequest = new AdRequest.Builder().build();
// Begin loading your interstitial.
interstitial.loadAd(adRequest);
}
// Begin loading your interstitial.
interstitial.loadAd(adRequest);
}
public void displayInterstitial() {
if (interstitial != null && interstitial.isLoaded()) {
interstitial.show();
int today = Calendar.getInstance().get(Calendar.DAY_OF_MONTH);
PreferenceHelper.setLastDayAdShowed(activity, today);
}
interstitial.show();
}
}

View File

@ -22,8 +22,11 @@ package com.maskyn.fileeditor;
import android.os.Bundle;
import com.crashlytics.android.Crashlytics;
import io.fabric.sdk.android.Fabric;
import sharedcode.turboeditor.activity.BaseHomeActivity;
import sharedcode.turboeditor.preferences.PreferenceHelper;
import sharedcode.turboeditor.util.ProCheckUtils;
public class HomeActivity extends BaseHomeActivity {
@ -34,13 +37,15 @@ public class HomeActivity extends BaseHomeActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(PreferenceHelper.getSendErrorReports(this))
Crashlytics.start(this);
Fabric.with(this, new Crashlytics());
// setup the ads
adsHelper = new AdsHelper(this);
if(!ProCheckUtils.isPro(this))
adsHelper = new AdsHelper(this);
}
@Override
public void displayInterstitial() {
adsHelper.displayInterstitial();
if(adsHelper != null && !ProCheckUtils.isPro(this))
adsHelper.displayInterstitial();
}
}

View File

@ -24,7 +24,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.12.+'
classpath 'com.android.tools.build:gradle:0.13.+'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files

View File

@ -1,30 +1,209 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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 <http://www.gnu.org/licenses/>.
-->
<pre-dex-items>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app\build\intermediates\pre-dexed\debug\eventbus-2.2.1-32e81c5612ed132ff771b5425053d87f4f6c68c5.jar"
jar="C:\Users\Vlad\.gradle\caches\modules-2\files-2.1\de.greenrobot\eventbus\2.2.1\a18ff12a9ab5ae52fd30d42f134517997568231e\eventbus-2.2.1.jar"
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\pre-dexed\debug\commons-io-2.4-63b64e68cd19031cd252ac65a3ef94421c1bf0f4.jar"
jar="C:\Users\Vlad\.gradle\caches\modules-2\files-2.1\commons-io\commons-io\2.4\b1b6ea3b7e4aa4f492509a4952029cd8e48019ad\commons-io-2.4.jar"
jumboMode="false"
revision="21.0.2"
sha1="b1b6ea3b7e4aa4f492509a4952029cd8e48019ad"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app\build\intermediates\pre-dexed\release\classes-4dd6beddde59ff8bd6c22bd0d65ac974f7e489d2.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app\build\intermediates\exploded-aar\turbo-editor.libraries\sharedCode\unspecified\classes.jar"
jumboMode="false"
revision="21.0.2"
sha1="4291d7fc866f70dc187c66c7063f806100c4d879"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app\build\intermediates\pre-dexed\debug\commons-io-2.4-63b64e68cd19031cd252ac65a3ef94421c1bf0f4.jar"
jar="C:\Users\Vlad\.gradle\caches\modules-2\files-2.1\commons-io\commons-io\2.4\b1b6ea3b7e4aa4f492509a4952029cd8e48019ad\commons-io-2.4.jar"
jumboMode="false"
revision="20.0.0"
sha1="b1b6ea3b7e4aa4f492509a4952029cd8e48019ad"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app\build\intermediates\pre-dexed\release\classes-579a5ce52888f504a812e0f68758a11f20a21c15.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app\build\intermediates\exploded-aar\TurboMaterialEditor.libraries\sharedCode\unspecified\classes.jar"
jumboMode="false"
revision="20.0.0"
sha1="a593d4ce7ccdfa1eac8d97a82db64f23614b59a1"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app\build\intermediates\pre-dexed\debug\classes-40c5f3698ba688207904eaae4b4b57dbf850297e.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app\build\intermediates\exploded-aar\com.crashlytics.sdk.android\answers\1.0.0\classes.jar"
jumboMode="false"
revision="21.0.2"
sha1="a8c73f3b98c2732c03ea09378ca322b56dea153a"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\pre-dexed\debug\commons-lang3-3.1-84728078c80f2c8637e0c3fe426ad61433c75bb6.jar"
jar="C:\Users\Vlad\.gradle\caches\modules-2\files-2.1\org.apache.commons\commons-lang3\3.1\905075e6c80f206bbe6cf1e809d2caa69f420c76\commons-lang3-3.1.jar"
jumboMode="false"
revision="21.0.2"
sha1="905075e6c80f206bbe6cf1e809d2caa69f420c76"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app\build\intermediates\pre-dexed\debug\classes-52b3d51bec6ecfeacbc105275c0e6a98b8869b1b.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app\build\intermediates\exploded-aar\com.crashlytics.sdk.android\crashlytics\2.0.0\classes.jar"
jumboMode="false"
revision="21.0.2"
sha1="832029c6f15447b2cb64ca4f8cf12172c9091857"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app\build\intermediates\pre-dexed\debug\classes-515446996fed08836a9331ef47b508a0383ffa22.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app\build\intermediates\exploded-aar\turbo-editor.libraries\RootCommands\unspecified\classes.jar"
jumboMode="false"
revision="21.0.2"
sha1="e3bacad84e40c773d40010a5520810920887a920"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\pre-dexed\debug\classes-9b612f0cb16e63277808158fe971bb4f40c98d29.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\exploded-aar\com.github.gabrielemariotti.changeloglib\library\1.5.1\classes.jar"
jumboMode="false"
revision="20.0.0"
sha1="74a89f0f8b56d9f11d70b8d8134cf4109f4797dc"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app-pro\build\intermediates\pre-dexed\debug\support-v4-19.0.1-f87b13e7ed00736c2050eda75093bf42b0503c64.jar"
jar="C:\Users\Vlad\AppData\Local\Android\android-sdk\extras\android\m2repository\com\android\support\support-v4\19.0.1\support-v4-19.0.1.jar"
jumboMode="false"
revision="20.0.0"
sha1="587da9a481ffd341d2fa091704489b89845ddacd"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app\build\intermediates\pre-dexed\debug\classes-c9a98cf79b48106440348a9fa210060d1b8b2647.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app\build\intermediates\exploded-aar\TurboMaterialEditor.libraries\RootCommands\unspecified\classes.jar"
jumboMode="false"
revision="20.0.0"
sha1="cdecd8167dfb75d5785decb911fc4516445dd6a6"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app\build\intermediates\pre-dexed\debug\classes-2ad27a3265673aeeb8f40e4322d8e19509329c96.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app\build\intermediates\exploded-aar\com.github.gabrielemariotti.changeloglib\library\1.5.1\classes.jar"
jumboMode="false"
revision="20.0.0"
sha1="74a89f0f8b56d9f11d70b8d8134cf4109f4797dc"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\pre-dexed\debug\library-2.4.0-6b043a8574fb97c742ca3065362b2a29e8f870bc.jar"
jar="C:\Users\Vlad\.gradle\caches\modules-2\files-2.1\com.nineoldandroids\library\2.4.0\e9b63380f3a242dbdbf103a2355ad7e43bad17cb\library-2.4.0.jar"
jumboMode="false"
revision="19.1.0"
sha1="e9b63380f3a242dbdbf103a2355ad7e43bad17cb"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\pre-dexed\debug\juniversalchardet-1.0.3-65b2b356e3f2da4b67e00aba70923d6321852204.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\exploded-aar\turbo-editor.libraries\sharedCode\unspecified\libs\juniversalchardet-1.0.3.jar"
jumboMode="false"
revision="20.0.0"
sha1="591d72211acc0b909b79c840e0b3ed9a0982d807"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\pre-dexed\debug\classes-82d5b6cab7f16bad663de7c7008673037efb0e1b.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\exploded-aar\turbo-editor.libraries\FloatingActionButton\unspecified\classes.jar"
jumboMode="false"
revision="21.0.2"
sha1="a1fbf4d4c1f1e1fe357b9ed1de15f4eea2217274"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app\build\intermediates\pre-dexed\debug\classes-7a329e7f23515542bf02d96773d08da1d2333a7b.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app\build\intermediates\exploded-aar\turbo-editor.libraries\FloatingActionButton\unspecified\classes.jar"
jumboMode="false"
revision="21.0.2"
sha1="a1fbf4d4c1f1e1fe357b9ed1de15f4eea2217274"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app\build\intermediates\pre-dexed\debug\classes-d44090b77791e486eccbc4d8859b00a83623bf2b.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app\build\intermediates\exploded-aar\com.google.android.gms\play-services\6.1.11\classes.jar"
jumboMode="false"
revision="21.0.2"
sha1="0f700f6802ba1a1f1fa7ac26d5db0666a89d75a6"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app\build\intermediates\pre-dexed\debug\juniversalchardet-1.0.3-sources-436707958bb47977373cb4a2d842cdbf635fd840.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app\build\intermediates\exploded-aar\turbo-editor.libraries\sharedCode\unspecified\libs\juniversalchardet-1.0.3-sources.jar"
jumboMode="false"
revision="21.0.2"
sha1="77979eaa98f90806f984155f44f63cc1fb60ac25"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\pre-dexed\debug\classes-30cc9565ecef1e8ae8577530d7ddd41993d192d7.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\exploded-aar\turbo-editor.libraries\RootCommands\unspecified\classes.jar"
jumboMode="false"
revision="20.0.0"
sha1="85e7b55f468c5591965a5171179d3858b46822a9"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app\build\intermediates\pre-dexed\debug\classes-a8678f35ea62f18f2f7b60a15203aa6c74b5e559.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app\build\intermediates\exploded-aar\com.google.android.gms\play-services\5.0.89\classes.jar"
jumboMode="false"
revision="20.0.0"
sha1="d71573c9c5ea98a8db47ad6ff993a63d492b3bfa"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\pre-dexed\debug\juniversalchardet-1.0.3-sources-58cfedaebe3b94ec0eaa2ede4e66aae8dbe309b0.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\exploded-aar\turbo-editor.libraries\sharedCode\unspecified\libs\juniversalchardet-1.0.3-sources.jar"
jumboMode="false"
revision="19.1.0"
sha1="77979eaa98f90806f984155f44f63cc1fb60ac25"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app\build\intermediates\pre-dexed\debug\juniversalchardet-1.0.3-2e38d54a78dd518320bb6abe3d8931a19ff26792.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app\build\intermediates\exploded-aar\TurboMaterialEditor.libraries\sharedCode\unspecified\libs\juniversalchardet-1.0.3.jar"
jumboMode="false"
revision="20.0.0"
sha1="591d72211acc0b909b79c840e0b3ed9a0982d807"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\pre-dexed\debug\classes-9b612f0cb16e63277808158fe971bb4f40c98d29.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\exploded-aar\com.github.gabrielemariotti.changeloglib\library\1.5.1\classes.jar"
jumboMode="false"
revision="19.1.0"
sha1="74a89f0f8b56d9f11d70b8d8134cf4109f4797dc"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app\build\intermediates\pre-dexed\debug\juniversalchardet-1.0.3-9db20cdcb8ae72104757d81297c98978c65bd91b.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app\build\intermediates\exploded-aar\turbo-editor.libraries\sharedCode\unspecified\libs\juniversalchardet-1.0.3.jar"
jumboMode="false"
revision="21.0.2"
sha1="591d72211acc0b909b79c840e0b3ed9a0982d807"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\pre-dexed\debug\library-2.4.0-6b043a8574fb97c742ca3065362b2a29e8f870bc.jar"
jar="C:\Users\Vlad\.gradle\caches\modules-2\files-2.1\com.nineoldandroids\library\2.4.0\e9b63380f3a242dbdbf103a2355ad7e43bad17cb\library-2.4.0.jar"
jumboMode="false"
revision="21.0.2"
sha1="e9b63380f3a242dbdbf103a2355ad7e43bad17cb"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\pre-dexed\debug\commons-lang3-3.1-84728078c80f2c8637e0c3fe426ad61433c75bb6.jar"
jar="C:\Users\Vlad\.gradle\caches\modules-2\files-2.1\org.apache.commons\commons-lang3\3.1\905075e6c80f206bbe6cf1e809d2caa69f420c76\commons-lang3-3.1.jar"
jumboMode="false"
revision="20.0.0"
sha1="905075e6c80f206bbe6cf1e809d2caa69f420c76"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\pre-dexed\debug\commons-io-2.4-63b64e68cd19031cd252ac65a3ef94421c1bf0f4.jar"
jar="C:\Users\Vlad\.gradle\caches\modules-2\files-2.1\commons-io\commons-io\2.4\b1b6ea3b7e4aa4f492509a4952029cd8e48019ad\commons-io-2.4.jar"
jumboMode="false"
revision="19.1.0"
sha1="b1b6ea3b7e4aa4f492509a4952029cd8e48019ad"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app-pro\build\intermediates\pre-dexed\debug\classes-bfc447e4dbe83598b94dbdc8e38492cbbda6ebb2.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app-pro\build\intermediates\exploded-aar\TurboMaterialEditor.libraries\RootCommands\unspecified\classes.jar"
jumboMode="false"
revision="20.0.0"
sha1="cdecd8167dfb75d5785decb911fc4516445dd6a6"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app\build\intermediates\pre-dexed\debug\classes-91de6979bb6be1b46cde32b462c23831eadd01d4.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app\build\intermediates\exploded-aar\com.github.gabrielemariotti.changeloglib\library\1.5.1\classes.jar"
jumboMode="false"
revision="21.0.2"
sha1="74a89f0f8b56d9f11d70b8d8134cf4109f4797dc"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\pre-dexed\debug\library-2.4.0-6b043a8574fb97c742ca3065362b2a29e8f870bc.jar"
jar="C:\Users\Vlad\.gradle\caches\modules-2\files-2.1\com.nineoldandroids\library\2.4.0\e9b63380f3a242dbdbf103a2355ad7e43bad17cb\library-2.4.0.jar"
jumboMode="false"
revision="20.0.0"
sha1="e9b63380f3a242dbdbf103a2355ad7e43bad17cb"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\pre-dexed\debug\juniversalchardet-1.0.3-65b2b356e3f2da4b67e00aba70923d6321852204.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\exploded-aar\turbo-editor.libraries\sharedCode\unspecified\libs\juniversalchardet-1.0.3.jar"
jumboMode="false"
revision="19.1.0"
sha1="591d72211acc0b909b79c840e0b3ed9a0982d807"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\pre-dexed\debug\classes-9b612f0cb16e63277808158fe971bb4f40c98d29.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\exploded-aar\com.github.gabrielemariotti.changeloglib\library\1.5.1\classes.jar"
jumboMode="false"
revision="21.0.2"
sha1="74a89f0f8b56d9f11d70b8d8134cf4109f4797dc"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\pre-dexed\debug\juniversalchardet-1.0.3-sources-58cfedaebe3b94ec0eaa2ede4e66aae8dbe309b0.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\exploded-aar\turbo-editor.libraries\sharedCode\unspecified\libs\juniversalchardet-1.0.3-sources.jar"
jumboMode="false"
revision="20.0.0"
sha1="77979eaa98f90806f984155f44f63cc1fb60ac25"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\pre-dexed\debug\eventbus-2.2.1-32e81c5612ed132ff771b5425053d87f4f6c68c5.jar"
jar="C:\Users\Vlad\.gradle\caches\modules-2\files-2.1\de.greenrobot\eventbus\2.2.1\a18ff12a9ab5ae52fd30d42f134517997568231e\eventbus-2.2.1.jar"
jumboMode="false"
revision="19.1.0"
sha1="a18ff12a9ab5ae52fd30d42f134517997568231e"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app-pro\build\intermediates\pre-dexed\debug\juniversalchardet-1.0.3-24b647622164ce26bc5d0be361e05056efc68e13.jar"
@ -32,60 +211,12 @@
jumboMode="false"
revision="20.0.0"
sha1="591d72211acc0b909b79c840e0b3ed9a0982d807"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app-pro\build\intermediates\pre-dexed\debug\support-v4-19.0.1-f87b13e7ed00736c2050eda75093bf42b0503c64.jar"
jar="C:\Users\Vlad\AppData\Local\Android\android-sdk\extras\android\m2repository\com\android\support\support-v4\19.0.1\support-v4-19.0.1.jar"
jumboMode="false"
revision="20.0.0"
sha1="587da9a481ffd341d2fa091704489b89845ddacd"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app\build\intermediates\pre-dexed\debug\commons-io-2.4-63b64e68cd19031cd252ac65a3ef94421c1bf0f4.jar"
jar="C:\Users\Vlad\.gradle\caches\modules-2\files-2.1\commons-io\commons-io\2.4\b1b6ea3b7e4aa4f492509a4952029cd8e48019ad\commons-io-2.4.jar"
jumboMode="false"
revision="20.0.0"
sha1="b1b6ea3b7e4aa4f492509a4952029cd8e48019ad"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app\build\intermediates\pre-dexed\debug\classes-da434e33e14290126d2ad09adf85ad0bbd76f025.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app\build\intermediates\exploded-aar\TurboMaterialEditor.libraries\FloatingActionButton\unspecified\classes.jar"
jumboMode="false"
revision="20.0.0"
sha1="2f3117da0016b1126fafe7fb332a45d2f910d76c"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app-pro\build\intermediates\pre-dexed\debug\classes-a52f37b7ca7cde7ab02ff10bba80d1c496284125.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app-pro\build\intermediates\exploded-aar\TurboMaterialEditor.libraries\FloatingActionButton\unspecified\classes.jar"
jumboMode="false"
revision="20.0.0"
sha1="2f3117da0016b1126fafe7fb332a45d2f910d76c"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app\build\intermediates\pre-dexed\debug\support-v4-19.1.0-cf7033c44b86e758f85990185111614bac3ecfa8.jar"
jar="C:\Users\Vlad\AppData\Local\Android\android-sdk\extras\android\m2repository\com\android\support\support-v4\19.1.0\support-v4-19.1.0.jar"
jumboMode="false"
revision="20.0.0"
sha1="85f201b380937e61a9dce6ca90ccf6872abbfb67"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app\build\intermediates\pre-dexed\debug\juniversalchardet-1.0.3-2e38d54a78dd518320bb6abe3d8931a19ff26792.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app\build\intermediates\exploded-aar\TurboMaterialEditor.libraries\sharedCode\unspecified\libs\juniversalchardet-1.0.3.jar"
jumboMode="false"
revision="20.0.0"
sha1="591d72211acc0b909b79c840e0b3ed9a0982d807"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app\build\intermediates\pre-dexed\debug\classes-2ad27a3265673aeeb8f40e4322d8e19509329c96.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app\build\intermediates\exploded-aar\com.github.gabrielemariotti.changeloglib\library\1.5.1\classes.jar"
jumboMode="false"
revision="20.0.0"
sha1="74a89f0f8b56d9f11d70b8d8134cf4109f4797dc"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app-pro\build\intermediates\pre-dexed\debug\classes-bfc447e4dbe83598b94dbdc8e38492cbbda6ebb2.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app-pro\build\intermediates\exploded-aar\TurboMaterialEditor.libraries\RootCommands\unspecified\classes.jar"
jumboMode="false"
revision="20.0.0"
sha1="cdecd8167dfb75d5785decb911fc4516445dd6a6"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app\build\intermediates\pre-dexed\release\classes-579a5ce52888f504a812e0f68758a11f20a21c15.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app\build\intermediates\exploded-aar\TurboMaterialEditor.libraries\sharedCode\unspecified\classes.jar"
jumboMode="false"
revision="20.0.0"
sha1="a593d4ce7ccdfa1eac8d97a82db64f23614b59a1"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app-pro\build\intermediates\pre-dexed\debug\classes-0a2ec632e1127b260f2b888ca5539fd41a1a638b.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app-pro\build\intermediates\exploded-aar\com.github.gabrielemariotti.changeloglib\library\1.5.1\classes.jar"
@ -93,17 +224,41 @@
revision="20.0.0"
sha1="74a89f0f8b56d9f11d70b8d8134cf4109f4797dc"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app\build\intermediates\pre-dexed\debug\classes-a8678f35ea62f18f2f7b60a15203aa6c74b5e559.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app\build\intermediates\exploded-aar\com.google.android.gms\play-services\5.0.89\classes.jar"
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app\build\intermediates\pre-dexed\debug\classes-33698a085ac2060587beda19b5b3900d3dffd1e7.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app\build\intermediates\exploded-aar\com.android.support\support-v4\21.0.0\classes.jar"
jumboMode="false"
revision="20.0.0"
sha1="d71573c9c5ea98a8db47ad6ff993a63d492b3bfa"/>
revision="21.0.2"
sha1="686344a780033e4ba22b926cd225f8d4941247e6"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app-pro\build\intermediates\pre-dexed\release\classes-3e47e18f46719c7bf296f4b49ff03aaa3d406ba6.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app-pro\build\intermediates\exploded-aar\TurboMaterialEditor.libraries\sharedCode\unspecified\classes.jar"
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app\build\intermediates\pre-dexed\debug\support-v4-19.1.0-cf7033c44b86e758f85990185111614bac3ecfa8.jar"
jar="C:\Users\Vlad\AppData\Local\Android\android-sdk\extras\android\m2repository\com\android\support\support-v4\19.1.0\support-v4-19.1.0.jar"
jumboMode="false"
revision="20.0.0"
sha1="a593d4ce7ccdfa1eac8d97a82db64f23614b59a1"/>
sha1="85f201b380937e61a9dce6ca90ccf6872abbfb67"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app\build\intermediates\pre-dexed\debug\internal_impl-21.0.0-74269e33561519e0fdabab9550f16a5986255be9.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app\build\intermediates\exploded-aar\com.android.support\support-v4\21.0.0\libs\internal_impl-21.0.0.jar"
jumboMode="false"
revision="21.0.2"
sha1="1609e6d42d0480b0f4188e2c29f75388fa12a8f0"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\pre-dexed\debug\eventbus-2.2.1-32e81c5612ed132ff771b5425053d87f4f6c68c5.jar"
jar="C:\Users\Vlad\.gradle\caches\modules-2\files-2.1\de.greenrobot\eventbus\2.2.1\a18ff12a9ab5ae52fd30d42f134517997568231e\eventbus-2.2.1.jar"
jumboMode="false"
revision="21.0.2"
sha1="a18ff12a9ab5ae52fd30d42f134517997568231e"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\pre-dexed\debug\classes-30cc9565ecef1e8ae8577530d7ddd41993d192d7.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\exploded-aar\turbo-editor.libraries\RootCommands\unspecified\classes.jar"
jumboMode="false"
revision="21.0.2"
sha1="e3bacad84e40c773d40010a5520810920887a920"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\pre-dexed\debug\classes-bcfe21eb1248db73c27c811996e28274cf39b024.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\exploded-aar\turbo-editor.libraries\sharedCode\unspecified\classes.jar"
jumboMode="false"
revision="19.1.0"
sha1="8203f36efafa2a6ef438b83fc86b9bdc469e7368"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app\build\intermediates\pre-dexed\release\crashlytics-1.1.13-7bbec76a44aa9cc3279ec6bff22b2c929a8abf67.jar"
jar="C:\Users\Vlad\.gradle\caches\modules-2\files-2.1\com.crashlytics.android\crashlytics\1.1.13\e821eafa1bf489a26bdb71f95078c26785b37a1\crashlytics-1.1.13.jar"
@ -111,10 +266,106 @@
revision="20.0.0"
sha1="0e821eafa1bf489a26bdb71f95078c26785b37a1"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app\build\intermediates\pre-dexed\debug\classes-c9a98cf79b48106440348a9fa210060d1b8b2647.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app\build\intermediates\exploded-aar\TurboMaterialEditor.libraries\RootCommands\unspecified\classes.jar"
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\pre-dexed\debug\support-annotations-21.0.0-7b7e20ddbdfce40d4a29c1e68c2dbbc5bb512ab5.jar"
jar="C:\Users\Vlad\AppData\Local\Android\android-sdk\extras\android\m2repository\com\android\support\support-annotations\21.0.0\support-annotations-21.0.0.jar"
jumboMode="false"
revision="21.0.2"
sha1="1a578b9607b36266c63d43a4fa0ab5664dbe911e"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\pre-dexed\debug\classes-fb4f15a411cfb0bffc51b68ad64a4794d3d67ae4.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\exploded-aar\com.android.support\appcompat-v7\21.0.0\classes.jar"
jumboMode="false"
revision="21.0.2"
sha1="95fd37732ec852e99f07eeb516a3650172f1d136"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\pre-dexed\debug\classes-bcfe21eb1248db73c27c811996e28274cf39b024.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\exploded-aar\turbo-editor.libraries\sharedCode\unspecified\classes.jar"
jumboMode="false"
revision="20.0.0"
sha1="cdecd8167dfb75d5785decb911fc4516445dd6a6"/>
sha1="991591ff9dbe9e472a47cf66fe6c120f89a68eaa"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\pre-dexed\debug\classes-82d5b6cab7f16bad663de7c7008673037efb0e1b.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\exploded-aar\turbo-editor.libraries\FloatingActionButton\unspecified\classes.jar"
jumboMode="false"
revision="19.1.0"
sha1="2e2f6526f3c5fb34230d14e52bdc24addb67ea9f"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\pre-dexed\debug\juniversalchardet-1.0.3-65b2b356e3f2da4b67e00aba70923d6321852204.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\exploded-aar\turbo-editor.libraries\sharedCode\unspecified\libs\juniversalchardet-1.0.3.jar"
jumboMode="false"
revision="21.0.2"
sha1="591d72211acc0b909b79c840e0b3ed9a0982d807"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app\build\intermediates\pre-dexed\debug\eventbus-2.2.1-32e81c5612ed132ff771b5425053d87f4f6c68c5.jar"
jar="C:\Users\Vlad\.gradle\caches\modules-2\files-2.1\de.greenrobot\eventbus\2.2.1\a18ff12a9ab5ae52fd30d42f134517997568231e\eventbus-2.2.1.jar"
jumboMode="false"
revision="20.0.0"
sha1="a18ff12a9ab5ae52fd30d42f134517997568231e"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app\build\intermediates\pre-dexed\debug\classes-e4e5a16633bd011fd3d270f1bcdf565f2bd9f2b3.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app\build\intermediates\exploded-aar\com.crashlytics.sdk.android\beta\1.0.0\classes.jar"
jumboMode="false"
revision="21.0.2"
sha1="068f232cbc319d814ad6ad01fd0ed0ac6d6c5414"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app\build\intermediates\pre-dexed\debug\classes-39edd57531ecc124992725bca5e8b42be236e3ec.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app\build\intermediates\exploded-aar\io.fabric.sdk.android\fabric\1.0.0\classes.jar"
jumboMode="false"
revision="21.0.2"
sha1="20a6dfbe395a3557a58a3d9f4460c15b0ce04d1e"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app-pro\build\intermediates\pre-dexed\debug\classes-a52f37b7ca7cde7ab02ff10bba80d1c496284125.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app-pro\build\intermediates\exploded-aar\TurboMaterialEditor.libraries\FloatingActionButton\unspecified\classes.jar"
jumboMode="false"
revision="20.0.0"
sha1="2f3117da0016b1126fafe7fb332a45d2f910d76c"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\pre-dexed\debug\juniversalchardet-1.0.3-sources-58cfedaebe3b94ec0eaa2ede4e66aae8dbe309b0.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\exploded-aar\turbo-editor.libraries\sharedCode\unspecified\libs\juniversalchardet-1.0.3-sources.jar"
jumboMode="false"
revision="21.0.2"
sha1="77979eaa98f90806f984155f44f63cc1fb60ac25"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\pre-dexed\debug\classes-82d5b6cab7f16bad663de7c7008673037efb0e1b.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\exploded-aar\turbo-editor.libraries\FloatingActionButton\unspecified\classes.jar"
jumboMode="false"
revision="20.0.0"
sha1="df1a8540495d6724b8582db31fcdd49b04d8b707"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\pre-dexed\debug\classes-30cc9565ecef1e8ae8577530d7ddd41993d192d7.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\exploded-aar\turbo-editor.libraries\RootCommands\unspecified\classes.jar"
jumboMode="false"
revision="19.1.0"
sha1="cb3d22565863773944a8c15de408e864e34d6da1"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app\build\intermediates\pre-dexed\debug\classes-aa4ad551e94dc47c364b1b7f46bb2eb1b6ceed85.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app\build\intermediates\exploded-aar\com.android.support\appcompat-v7\21.0.0\classes.jar"
jumboMode="false"
revision="21.0.2"
sha1="95fd37732ec852e99f07eeb516a3650172f1d136"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\pre-dexed\debug\classes-e90e1f4e06d0f5aa27166f2f8f5fcea319efbd95.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\exploded-aar\com.android.support\support-v4\21.0.0\classes.jar"
jumboMode="false"
revision="21.0.2"
sha1="686344a780033e4ba22b926cd225f8d4941247e6"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\pre-dexed\release\classes-bcfe21eb1248db73c27c811996e28274cf39b024.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\exploded-aar\turbo-editor.libraries\sharedCode\unspecified\classes.jar"
jumboMode="false"
revision="21.0.2"
sha1="4291d7fc866f70dc187c66c7063f806100c4d879"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app-pro\build\intermediates\pre-dexed\release\classes-3e47e18f46719c7bf296f4b49ff03aaa3d406ba6.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\TurboMaterialEditor\app-pro\build\intermediates\exploded-aar\TurboMaterialEditor.libraries\sharedCode\unspecified\classes.jar"
jumboMode="false"
revision="20.0.0"
sha1="a593d4ce7ccdfa1eac8d97a82db64f23614b59a1"/>
<item
dex="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\pre-dexed\debug\internal_impl-21.0.0-b15535acecaec42d04239e17e0a03ab072a43104.jar"
jar="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\app-pro\build\intermediates\exploded-aar\com.android.support\support-v4\21.0.0\libs\internal_impl-21.0.0.jar"
jumboMode="false"
revision="21.0.2"
sha1="1609e6d42d0480b0f4188e2c29f75388fa12a8f0"/>
</pre-dex-items>

Binary file not shown.

View File

@ -1,25 +1,6 @@
#
# 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 <http://www.gnu.org/licenses/>.
#
#Wed Apr 10 15:27:10 PDT 2013
#Wed Oct 22 18:10:25 CEST 2014
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=http\://services.gradle.org/distributions/gradle-1.12-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-2.1-all.zip

View File

@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.faizmalkani.floatingactionbutton">

View File

@ -1,12 +1,12 @@
apply plugin: 'com.android.library'
android {
compileSdkVersion 19
buildToolsVersion "20.0.0"
compileSdkVersion 21
buildToolsVersion '21.0.2'
defaultConfig {
applicationId 'com.faizmalkani.floatingactionbutton'
minSdkVersion 14
targetSdkVersion 19
minSdkVersion 7
targetSdkVersion 21
versionName "1.0"
versionCode 1
}
@ -22,7 +22,12 @@ android {
assets.srcDirs = ['assets']
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
}
dependencies {
compile 'com.nineoldandroids:library:2.4.0'
}

View File

@ -5,9 +5,14 @@ package com.faizmalkani.floatingactionbutton;
public final class BuildConfig {
public static final boolean DEBUG = Boolean.parseBoolean("true");
public static final String PACKAGE_NAME = "com.faizmalkani.floatingactionbutton";
public static final String APPLICATION_ID = "com.faizmalkani.floatingactionbutton";
public static final String BUILD_TYPE = "debug";
public static final String FLAVOR = "";
public static final int VERSION_CODE = 1;
public static final String VERSION_NAME = "1.0";
/**
* @deprecated Use {@link #APPLICATION_ID}
*/
@Deprecated
public static final String PACKAGE_NAME = "com.faizmalkani.floatingactionbutton";
}

View File

@ -5,9 +5,14 @@ package com.faizmalkani.floatingactionbutton;
public final class BuildConfig {
public static final boolean DEBUG = false;
public static final String PACKAGE_NAME = "com.faizmalkani.floatingactionbutton";
public static final String APPLICATION_ID = "com.faizmalkani.floatingactionbutton";
public static final String BUILD_TYPE = "release";
public static final String FLAVOR = "";
public static final int VERSION_CODE = 1;
public static final String VERSION_NAME = "1.0";
/**
* @deprecated Use {@link #APPLICATION_ID}
*/
@Deprecated
public static final String PACKAGE_NAME = "com.faizmalkani.floatingactionbutton";
}

View File

@ -5,9 +5,14 @@ package com.faizmalkani.floatingactionbutton.test;
public final class BuildConfig {
public static final boolean DEBUG = Boolean.parseBoolean("true");
public static final String PACKAGE_NAME = "com.faizmalkani.floatingactionbutton.test";
public static final String APPLICATION_ID = "com.faizmalkani.floatingactionbutton.test";
public static final String BUILD_TYPE = "debug";
public static final String FLAVOR = "";
public static final int VERSION_CODE = 1;
public static final String VERSION_NAME = "1.0";
/**
* @deprecated Use {@link #APPLICATION_ID}
*/
@Deprecated
public static final String PACKAGE_NAME = "com.faizmalkani.floatingactionbutton.test";
}

View File

@ -17,7 +17,7 @@ theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
*/
public static int color=0x7f010001;
public static int colour=0x7f010001;
/** <p>Must be an integer value, such as "<code>100</code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
@ -66,14 +66,14 @@ containing a value of this type.
<colgroup align="left" />
<colgroup align="left" />
<tr><th>Attribute</th><th>Description</th></tr>
<tr><td><code>{@link #FloatingActionButton_color com.faizmalkani.floatingactionbutton:color}</code></td><td></td></tr>
<tr><td><code>{@link #FloatingActionButton_colour com.faizmalkani.floatingactionbutton:colour}</code></td><td></td></tr>
<tr><td><code>{@link #FloatingActionButton_drawable com.faizmalkani.floatingactionbutton:drawable}</code></td><td></td></tr>
<tr><td><code>{@link #FloatingActionButton_shadowColor com.faizmalkani.floatingactionbutton:shadowColor}</code></td><td></td></tr>
<tr><td><code>{@link #FloatingActionButton_shadowDx com.faizmalkani.floatingactionbutton:shadowDx}</code></td><td></td></tr>
<tr><td><code>{@link #FloatingActionButton_shadowDy com.faizmalkani.floatingactionbutton:shadowDy}</code></td><td></td></tr>
<tr><td><code>{@link #FloatingActionButton_shadowRadius com.faizmalkani.floatingactionbutton:shadowRadius}</code></td><td></td></tr>
</table>
@see #FloatingActionButton_color
@see #FloatingActionButton_colour
@see #FloatingActionButton_drawable
@see #FloatingActionButton_shadowColor
@see #FloatingActionButton_shadowDx
@ -85,7 +85,7 @@ containing a value of this type.
0x7f010004, 0x7f010005
};
/**
<p>This symbol is the offset where the {@link com.faizmalkani.floatingactionbutton.R.attr#color}
<p>This symbol is the offset where the {@link com.faizmalkani.floatingactionbutton.R.attr#colour}
attribute's value can be found in the {@link #FloatingActionButton} array.
@ -96,9 +96,9 @@ containing a value of this type.
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
@attr name com.faizmalkani.floatingactionbutton:color
@attr name com.faizmalkani.floatingactionbutton:colour
*/
public static final int FloatingActionButton_color = 1;
public static int FloatingActionButton_colour = 1;
/**
<p>This symbol is the offset where the {@link com.faizmalkani.floatingactionbutton.R.attr#drawable}
attribute's value can be found in the {@link #FloatingActionButton} array.
@ -112,7 +112,7 @@ theme attribute (in the form
containing a value of this type.
@attr name com.faizmalkani.floatingactionbutton:drawable
*/
public static final int FloatingActionButton_drawable = 0;
public static int FloatingActionButton_drawable = 0;
/**
<p>This symbol is the offset where the {@link com.faizmalkani.floatingactionbutton.R.attr#shadowColor}
attribute's value can be found in the {@link #FloatingActionButton} array.
@ -126,7 +126,7 @@ theme attribute (in the form
containing a value of this type.
@attr name com.faizmalkani.floatingactionbutton:shadowColor
*/
public static final int FloatingActionButton_shadowColor = 5;
public static int FloatingActionButton_shadowColor = 5;
/**
<p>This symbol is the offset where the {@link com.faizmalkani.floatingactionbutton.R.attr#shadowDx}
attribute's value can be found in the {@link #FloatingActionButton} array.
@ -140,7 +140,7 @@ theme attribute (in the form
containing a value of this type.
@attr name com.faizmalkani.floatingactionbutton:shadowDx
*/
public static final int FloatingActionButton_shadowDx = 3;
public static int FloatingActionButton_shadowDx = 3;
/**
<p>This symbol is the offset where the {@link com.faizmalkani.floatingactionbutton.R.attr#shadowDy}
attribute's value can be found in the {@link #FloatingActionButton} array.
@ -154,7 +154,7 @@ theme attribute (in the form
containing a value of this type.
@attr name com.faizmalkani.floatingactionbutton:shadowDy
*/
public static final int FloatingActionButton_shadowDy = 4;
public static int FloatingActionButton_shadowDy = 4;
/**
<p>This symbol is the offset where the {@link com.faizmalkani.floatingactionbutton.R.attr#shadowRadius}
attribute's value can be found in the {@link #FloatingActionButton} array.
@ -168,6 +168,6 @@ theme attribute (in the form
containing a value of this type.
@attr name com.faizmalkani.floatingactionbutton:shadowRadius
*/
public static final int FloatingActionButton_shadowRadius = 2;
public static int FloatingActionButton_shadowRadius = 2;
};
}

View File

@ -17,7 +17,7 @@ theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
*/
public static int color=0x7f010001;
public static int colour=0x7f010001;
/** <p>Must be an integer value, such as "<code>100</code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
@ -66,14 +66,14 @@ containing a value of this type.
<colgroup align="left" />
<colgroup align="left" />
<tr><th>Attribute</th><th>Description</th></tr>
<tr><td><code>{@link #FloatingActionButton_color com.faizmalkani.floatingactionbutton:color}</code></td><td></td></tr>
<tr><td><code>{@link #FloatingActionButton_colour com.faizmalkani.floatingactionbutton:colour}</code></td><td></td></tr>
<tr><td><code>{@link #FloatingActionButton_drawable com.faizmalkani.floatingactionbutton:drawable}</code></td><td></td></tr>
<tr><td><code>{@link #FloatingActionButton_shadowColor com.faizmalkani.floatingactionbutton:shadowColor}</code></td><td></td></tr>
<tr><td><code>{@link #FloatingActionButton_shadowDx com.faizmalkani.floatingactionbutton:shadowDx}</code></td><td></td></tr>
<tr><td><code>{@link #FloatingActionButton_shadowDy com.faizmalkani.floatingactionbutton:shadowDy}</code></td><td></td></tr>
<tr><td><code>{@link #FloatingActionButton_shadowRadius com.faizmalkani.floatingactionbutton:shadowRadius}</code></td><td></td></tr>
</table>
@see #FloatingActionButton_color
@see #FloatingActionButton_colour
@see #FloatingActionButton_drawable
@see #FloatingActionButton_shadowColor
@see #FloatingActionButton_shadowDx
@ -85,7 +85,7 @@ containing a value of this type.
0x7f010004, 0x7f010005
};
/**
<p>This symbol is the offset where the {@link com.faizmalkani.floatingactionbutton.R.attr#color}
<p>This symbol is the offset where the {@link com.faizmalkani.floatingactionbutton.R.attr#colour}
attribute's value can be found in the {@link #FloatingActionButton} array.
@ -96,9 +96,9 @@ containing a value of this type.
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
@attr name com.faizmalkani.floatingactionbutton:color
@attr name com.faizmalkani.floatingactionbutton:colour
*/
public static final int FloatingActionButton_color = 1;
public static int FloatingActionButton_colour = 1;
/**
<p>This symbol is the offset where the {@link com.faizmalkani.floatingactionbutton.R.attr#drawable}
attribute's value can be found in the {@link #FloatingActionButton} array.
@ -112,7 +112,7 @@ theme attribute (in the form
containing a value of this type.
@attr name com.faizmalkani.floatingactionbutton:drawable
*/
public static final int FloatingActionButton_drawable = 0;
public static int FloatingActionButton_drawable = 0;
/**
<p>This symbol is the offset where the {@link com.faizmalkani.floatingactionbutton.R.attr#shadowColor}
attribute's value can be found in the {@link #FloatingActionButton} array.
@ -126,7 +126,7 @@ theme attribute (in the form
containing a value of this type.
@attr name com.faizmalkani.floatingactionbutton:shadowColor
*/
public static final int FloatingActionButton_shadowColor = 5;
public static int FloatingActionButton_shadowColor = 5;
/**
<p>This symbol is the offset where the {@link com.faizmalkani.floatingactionbutton.R.attr#shadowDx}
attribute's value can be found in the {@link #FloatingActionButton} array.
@ -140,7 +140,7 @@ theme attribute (in the form
containing a value of this type.
@attr name com.faizmalkani.floatingactionbutton:shadowDx
*/
public static final int FloatingActionButton_shadowDx = 3;
public static int FloatingActionButton_shadowDx = 3;
/**
<p>This symbol is the offset where the {@link com.faizmalkani.floatingactionbutton.R.attr#shadowDy}
attribute's value can be found in the {@link #FloatingActionButton} array.
@ -154,7 +154,7 @@ theme attribute (in the form
containing a value of this type.
@attr name com.faizmalkani.floatingactionbutton:shadowDy
*/
public static final int FloatingActionButton_shadowDy = 4;
public static int FloatingActionButton_shadowDy = 4;
/**
<p>This symbol is the offset where the {@link com.faizmalkani.floatingactionbutton.R.attr#shadowRadius}
attribute's value can be found in the {@link #FloatingActionButton} array.
@ -168,6 +168,6 @@ theme attribute (in the form
containing a value of this type.
@attr name com.faizmalkani.floatingactionbutton:shadowRadius
*/
public static final int FloatingActionButton_shadowRadius = 2;
public static int FloatingActionButton_shadowRadius = 2;
};
}

View File

@ -8,7 +8,7 @@ package com.faizmalkani.floatingactionbutton;
public final class R {
public static final class attr {
public static final int color = 0x7f010001;
public static final int colour = 0x7f010001;
public static final int drawable = 0x7f010000;
public static final int shadowColor = 0x7f010005;
public static final int shadowDx = 0x7f010003;
@ -17,7 +17,7 @@ public final class R {
}
public static final class styleable {
public static final int[] FloatingActionButton = { 0x7f010000, 0x7f010001, 0x7f010002, 0x7f010003, 0x7f010004, 0x7f010005 };
public static final int FloatingActionButton_color = 1;
public static final int FloatingActionButton_colour = 1;
public static final int FloatingActionButton_drawable = 0;
public static final int FloatingActionButton_shadowColor = 5;
public static final int FloatingActionButton_shadowDx = 3;

View File

@ -17,7 +17,7 @@ theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
*/
public static final int color=0x7f010001;
public static final int colour=0x7f010001;
/** <p>Must be an integer value, such as "<code>100</code>".
<p>This may also be a reference to a resource (in the form
"<code>@[<i>package</i>:]<i>type</i>:<i>name</i></code>") or
@ -66,14 +66,14 @@ containing a value of this type.
<colgroup align="left" />
<colgroup align="left" />
<tr><th>Attribute</th><th>Description</th></tr>
<tr><td><code>{@link #FloatingActionButton_color com.faizmalkani.floatingactionbutton.test:color}</code></td><td></td></tr>
<tr><td><code>{@link #FloatingActionButton_colour com.faizmalkani.floatingactionbutton.test:colour}</code></td><td></td></tr>
<tr><td><code>{@link #FloatingActionButton_drawable com.faizmalkani.floatingactionbutton.test:drawable}</code></td><td></td></tr>
<tr><td><code>{@link #FloatingActionButton_shadowColor com.faizmalkani.floatingactionbutton.test:shadowColor}</code></td><td></td></tr>
<tr><td><code>{@link #FloatingActionButton_shadowDx com.faizmalkani.floatingactionbutton.test:shadowDx}</code></td><td></td></tr>
<tr><td><code>{@link #FloatingActionButton_shadowDy com.faizmalkani.floatingactionbutton.test:shadowDy}</code></td><td></td></tr>
<tr><td><code>{@link #FloatingActionButton_shadowRadius com.faizmalkani.floatingactionbutton.test:shadowRadius}</code></td><td></td></tr>
</table>
@see #FloatingActionButton_color
@see #FloatingActionButton_colour
@see #FloatingActionButton_drawable
@see #FloatingActionButton_shadowColor
@see #FloatingActionButton_shadowDx
@ -85,7 +85,7 @@ containing a value of this type.
0x7f010004, 0x7f010005
};
/**
<p>This symbol is the offset where the {@link com.faizmalkani.floatingactionbutton.test.R.attr#color}
<p>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.
@ -96,9 +96,9 @@ containing a value of this type.
theme attribute (in the form
"<code>?[<i>package</i>:][<i>type</i>:]<i>name</i></code>")
containing a value of this type.
@attr name com.faizmalkani.floatingactionbutton.test:color
@attr name com.faizmalkani.floatingactionbutton.test:colour
*/
public static final int FloatingActionButton_color = 1;
public static final int FloatingActionButton_colour = 1;
/**
<p>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.

View File

@ -5,8 +5,8 @@
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="19" />
android:minSdkVersion="7"
android:targetSdkVersion="21" />
<application android:allowBackup="true" >
</application>

View File

@ -1,11 +1,11 @@
int attr color 0x7f010001
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_color 1
int styleable FloatingActionButton_colour 1
int styleable FloatingActionButton_drawable 0
int styleable FloatingActionButton_shadowColor 5
int styleable FloatingActionButton_shadowDx 3

View File

@ -1,16 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- From: file:/C:/Users/Vlad/Documents/AndroidStudioProjects/turbo-editor/libraries/FloatingActionButton/res/values/attrs.xml -->
<eat-comment />
<declare-styleable name="FloatingActionButton">
<attr name="drawable" format="integer" />
<attr name="color" format="color" />
<attr name="shadowRadius" format="float" />
<attr name="shadowDx" format="float" />
<attr name="shadowDy" format="float" />
<attr name="shadowColor" format="integer" />
</declare-styleable>
<declare-styleable name="FloatingActionButton"><attr format="integer" name="drawable"/><attr format="color" name="colour"/><attr format="float" name="shadowRadius"/><attr format="float" name="shadowDx"/><attr format="float" name="shadowDy"/><attr format="integer" name="shadowColor"/></declare-styleable>
</resources>

View File

@ -5,8 +5,8 @@
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="19" />
android:minSdkVersion="7"
android:targetSdkVersion="21" />
<application android:allowBackup="true" >
</application>

View File

@ -1,11 +1,11 @@
int attr color 0x7f010001
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_color 1
int styleable FloatingActionButton_colour 1
int styleable FloatingActionButton_drawable 0
int styleable FloatingActionButton_shadowColor 5
int styleable FloatingActionButton_shadowDx 3

View File

@ -1,16 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- From: file:/C:/Users/Vlad/Documents/AndroidStudioProjects/turbo-editor/libraries/FloatingActionButton/res/values/attrs.xml -->
<eat-comment />
<declare-styleable name="FloatingActionButton">
<attr name="drawable" format="integer" />
<attr name="color" format="color" />
<attr name="shadowRadius" format="float" />
<attr name="shadowDx" format="float" />
<attr name="shadowDy" format="float" />
<attr name="shadowColor" format="integer" />
</declare-styleable>
<declare-styleable name="FloatingActionButton"><attr format="integer" name="drawable"/><attr format="color" name="colour"/><attr format="float" name="shadowRadius"/><attr format="float" name="shadowDx"/><attr format="float" name="shadowDy"/><attr format="integer" name="shadowColor"/></declare-styleable>
</resources>

View File

@ -1,11 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<merger version="2" >
<dataSet config="main" >
<source path="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\libraries\FloatingActionButton\assets" />
</dataSet>
<dataSet config="debug" >
<source path="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\libraries\FloatingActionButton\src\debug\assets" />
</dataSet>
</merger>
<merger version="3"><dataSet config="main"><source path="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\libraries\FloatingActionButton\assets"/></dataSet><dataSet config="debug"><source path="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\libraries\FloatingActionButton\src\debug\assets"/></dataSet></merger>

View File

@ -1,11 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<merger version="2" >
<dataSet config="main" >
<source path="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\libraries\FloatingActionButton\assets" />
</dataSet>
<dataSet config="release" >
<source path="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\libraries\FloatingActionButton\src\release\assets" />
</dataSet>
</merger>
<merger version="3"><dataSet config="main"><source path="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\libraries\FloatingActionButton\assets"/></dataSet><dataSet config="release"><source path="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\libraries\FloatingActionButton\src\release\assets"/></dataSet></merger>

View File

@ -1,11 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<merger version="2" >
<dataSet config="debug" >
<source path="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\libraries\FloatingActionButton\build\intermediates\bundles\debug\assets" />
</dataSet>
<dataSet config="main" >
<source path="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\libraries\FloatingActionButton\src\androidTest\assets" />
</dataSet>
</merger>
<merger version="3"><dataSet config="debug"><source path="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\libraries\FloatingActionButton\build\intermediates\bundles\debug\assets"/></dataSet><dataSet config="main"><source path="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\libraries\FloatingActionButton\src\androidTest\assets"/></dataSet></merger>

View File

@ -1,38 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<merger version="2" >
<dataSet config="debug" >
<source path="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\libraries\FloatingActionButton\build\intermediates\bundles\debug\res" >
<file
path="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\libraries\FloatingActionButton\build\intermediates\bundles\debug\res\values\values.xml"
qualifiers="" >
<declare-styleable name="FloatingActionButton" >
<attr
name="drawable"
format="integer" />
<attr
name="color"
format="color" />
<attr
name="shadowRadius"
format="float" />
<attr
name="shadowDx"
format="float" />
<attr
name="shadowDy"
format="float" />
<attr
name="shadowColor"
format="integer" />
</declare-styleable>
</file>
</source>
</dataSet>
<dataSet config="main" >
<source path="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\libraries\FloatingActionButton\src\androidTest\res" />
<source path="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\libraries\FloatingActionButton\build\generated\res\rs\test\debug" />
<source path="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\libraries\FloatingActionButton\build\generated\res\generated\test\debug" />
</dataSet>
</merger>
<merger version="3"><dataSet config="debug"><source path="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\libraries\FloatingActionButton\build\intermediates\bundles\debug\res"><file path="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\libraries\FloatingActionButton\build\intermediates\bundles\debug\res\values\values.xml" qualifiers=""><declare-styleable name="FloatingActionButton"><attr format="integer" name="drawable"/><attr format="color" name="colour"/><attr format="float" name="shadowRadius"/><attr format="float" name="shadowDx"/><attr format="float" name="shadowDy"/><attr format="integer" name="shadowColor"/></declare-styleable></file></source></dataSet><dataSet config="main"><source path="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\libraries\FloatingActionButton\src\androidTest\res"/><source path="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\libraries\FloatingActionButton\build\generated\res\rs\test\debug"/><source path="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\libraries\FloatingActionButton\build\generated\res\generated\test\debug"/></dataSet><mergedItems><configuration qualifiers=""><declare-styleable name="FloatingActionButton"><attr format="integer" name="drawable"/><attr format="color" name="colour"/><attr format="float" name="shadowRadius"/><attr format="float" name="shadowDx"/><attr format="float" name="shadowDy"/><attr format="integer" name="shadowColor"/></declare-styleable></configuration></mergedItems></merger>

View File

@ -1,38 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<merger version="2" >
<dataSet config="main" >
<source path="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\libraries\FloatingActionButton\res" >
<file
path="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\libraries\FloatingActionButton\res\values\attrs.xml"
qualifiers="" >
<declare-styleable name="FloatingActionButton" >
<attr
name="drawable"
format="integer" />
<attr
name="color"
format="color" />
<attr
name="shadowRadius"
format="float" />
<attr
name="shadowDx"
format="float" />
<attr
name="shadowDy"
format="float" />
<attr
name="shadowColor"
format="integer" />
</declare-styleable>
</file>
</source>
<source path="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\libraries\FloatingActionButton\build\generated\res\rs\debug" />
<source path="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\libraries\FloatingActionButton\build\generated\res\generated\debug" />
</dataSet>
<dataSet config="debug" >
<source path="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\libraries\FloatingActionButton\src\debug\res" />
</dataSet>
</merger>
<merger version="3"><dataSet config="main"><source path="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\libraries\FloatingActionButton\res"><file path="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\libraries\FloatingActionButton\res\values\attrs.xml" qualifiers=""><declare-styleable name="FloatingActionButton">
<attr format="integer" name="drawable"/>
<attr format="color" name="colour"/>
<attr format="float" name="shadowRadius"/>
<attr format="float" name="shadowDx"/>
<attr format="float" name="shadowDy"/>
<attr format="integer" name="shadowColor"/>
</declare-styleable></file></source><source path="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\libraries\FloatingActionButton\build\generated\res\rs\debug"/><source path="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\libraries\FloatingActionButton\build\generated\res\generated\debug"/></dataSet><dataSet config="debug"><source path="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\libraries\FloatingActionButton\src\debug\res"/></dataSet><mergedItems><configuration qualifiers=""><declare-styleable name="FloatingActionButton"><attr format="integer" name="drawable"/><attr format="color" name="colour"/><attr format="float" name="shadowRadius"/><attr format="float" name="shadowDx"/><attr format="float" name="shadowDy"/><attr format="integer" name="shadowColor"/></declare-styleable></configuration></mergedItems></merger>

View File

@ -1,38 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<merger version="2" >
<dataSet config="main" >
<source path="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\libraries\FloatingActionButton\res" >
<file
path="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\libraries\FloatingActionButton\res\values\attrs.xml"
qualifiers="" >
<declare-styleable name="FloatingActionButton" >
<attr
name="drawable"
format="integer" />
<attr
name="color"
format="color" />
<attr
name="shadowRadius"
format="float" />
<attr
name="shadowDx"
format="float" />
<attr
name="shadowDy"
format="float" />
<attr
name="shadowColor"
format="integer" />
</declare-styleable>
</file>
</source>
<source path="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\libraries\FloatingActionButton\build\generated\res\rs\release" />
<source path="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\libraries\FloatingActionButton\build\generated\res\generated\release" />
</dataSet>
<dataSet config="release" >
<source path="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\libraries\FloatingActionButton\src\release\res" />
</dataSet>
</merger>
<merger version="3"><dataSet config="main"><source path="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\libraries\FloatingActionButton\res"><file path="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\libraries\FloatingActionButton\res\values\attrs.xml" qualifiers=""><declare-styleable name="FloatingActionButton">
<attr format="integer" name="drawable"/>
<attr format="color" name="colour"/>
<attr format="float" name="shadowRadius"/>
<attr format="float" name="shadowDx"/>
<attr format="float" name="shadowDy"/>
<attr format="integer" name="shadowColor"/>
</declare-styleable></file></source><source path="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\libraries\FloatingActionButton\build\generated\res\rs\release"/><source path="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\libraries\FloatingActionButton\build\generated\res\generated\release"/></dataSet><dataSet config="release"><source path="C:\Users\Vlad\Documents\AndroidStudioProjects\turbo-editor\libraries\FloatingActionButton\src\release\res"/></dataSet><mergedItems><configuration qualifiers=""><declare-styleable name="FloatingActionButton"><attr format="integer" name="drawable"/><attr format="color" name="colour"/><attr format="float" name="shadowRadius"/><attr format="float" name="shadowDx"/><attr format="float" name="shadowDy"/><attr format="integer" name="shadowColor"/></declare-styleable></configuration></mergedItems></merger>

View File

@ -3,8 +3,8 @@
package="com.faizmalkani.floatingactionbutton.test" >
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="19" />
android:minSdkVersion="7"
android:targetSdkVersion="21" />
<instrumentation
android:name="android.test.InstrumentationTestRunner"

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.faizmalkani.floatingactionbutton.test">
<uses-sdk android:minSdkVersion="7" android:targetSdkVersion="21" />
<application>
<uses-library android:name="android.test.runner" />
</application>
<instrumentation android:name="android.test.InstrumentationTestRunner"
android:targetPackage="com.faizmalkani.floatingactionbutton.test"
android:handleProfiling="false"
android:functionalTest="false"
android:label="Tests for com.faizmalkani.floatingactionbutton.test"/>
</manifest>

View File

@ -1,16 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- From: file:/C:/Users/Vlad/Documents/AndroidStudioProjects/turbo-editor/libraries/FloatingActionButton/build/intermediates/bundles/debug/res/values/values.xml -->
<eat-comment />
<declare-styleable name="FloatingActionButton">
<attr name="drawable" format="integer" />
<attr name="color" format="color" />
<attr name="shadowRadius" format="float" />
<attr name="shadowDx" format="float" />
<attr name="shadowDy" format="float" />
<attr name="shadowColor" format="integer" />
</declare-styleable>
<declare-styleable name="FloatingActionButton"><attr format="integer" name="drawable"/><attr format="color" name="colour"/><attr format="float" name="shadowRadius"/><attr format="float" name="shadowDx"/><attr format="float" name="shadowDy"/><attr format="integer" name="shadowColor"/></declare-styleable>
</resources>

View File

@ -1,11 +1,11 @@
int attr color 0x7f010001
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_color 1
int styleable FloatingActionButton_colour 1
int styleable FloatingActionButton_drawable 0
int styleable FloatingActionButton_shadowColor 5
int styleable FloatingActionButton_shadowDx 3

View File

@ -1,4 +1,3 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#

View File

@ -1,10 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="FloatingActionButton">
<attr name="drawable" format="integer"/>
<attr name="color" format="color"/>
<attr name="colour" format="color"/>
<attr name="shadowRadius" format="float"/>
<attr name="shadowDx" format="float"/>
<attr name="shadowDy" format="float"/>

View File

@ -1,10 +1,27 @@
/*
* Copyright (c) 2014 SBG Apps
*
* 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 com.faizmalkani.floatingactionbutton;
import android.view.View;
import android.widget.AbsListView;
/**
* Created by Stéphane on 09/07/2014.
*/
class DirectionScrollListener implements AbsListView.OnScrollListener {
private static final int DIRECTION_CHANGE_THRESHOLD = 1;
@ -34,10 +51,7 @@ class DirectionScrollListener implements AbsListView.OnScrollListener {
goingDown = firstVisibleItem > mPrevPosition;
}
if (changed && mUpdated) {
if(goingDown)
mFloatingActionButton.hideFab();
else
mFloatingActionButton.showFab();
mFloatingActionButton.hide(goingDown);
}
mPrevPosition = firstVisibleItem;
mPrevTop = firstViewTop;

View File

@ -1,9 +1,7 @@
package com.faizmalkani.floatingactionbutton;
import android.animation.ObjectAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
@ -11,135 +9,146 @@ import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.Interpolator;
import android.widget.AbsListView;
public class FloatingActionButton extends View
{
Context _context;
Paint mButtonPaint, mDrawablePaint;
Bitmap mBitmap;
int mScreenHeight;
float currentY;
boolean mHidden = false;
import com.nineoldandroids.animation.ObjectAnimator;
import com.nineoldandroids.view.ViewHelper;
ObjectAnimator mShowAnimation;
ObjectAnimator mHideAnimation;
public class FloatingActionButton extends View {
public FloatingActionButton(Context context, AttributeSet attributeSet)
{
super(context, attributeSet);
_context = context;
init(Color.WHITE);
private final Interpolator mInterpolator = new AccelerateDecelerateInterpolator();
private final Paint mButtonPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final Paint mDrawablePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private Bitmap mBitmap;
private int mColor;
private boolean mHidden = false;
/**
* The FAB button's Y position when it is displayed.
*/
private float mYDisplayed = -1;
/**
* The FAB button's Y position when it is hidden.
*/
private float mYHidden = -1;
public FloatingActionButton(Context context) {
this(context, null);
}
@SuppressLint("NewApi")
public FloatingActionButton(Context context)
{
super(context);
_context = context;
init(Color.WHITE);
}
public void setColor(int fabColor)
{
init(fabColor);
}
public void setDrawable(Drawable fabDrawable)
{
mBitmap = ((BitmapDrawable) fabDrawable).getBitmap();
invalidate();
public FloatingActionButton(Context context, AttributeSet attributeSet) {
this(context, attributeSet, 0);
}
public void init(int fabColor)
{
setWillNotDraw(false);
this.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
mButtonPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mButtonPaint.setColor(fabColor);
public FloatingActionButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.FloatingActionButton);
mColor = a.getColor(R.styleable.FloatingActionButton_colour, Color.WHITE);
mButtonPaint.setStyle(Paint.Style.FILL);
mButtonPaint.setShadowLayer(10.0f, 0.0f, 3.5f, Color.argb(100, 0, 0, 0));
mDrawablePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
invalidate();
mButtonPaint.setColor(mColor);
float radius, dx, dy;
radius = a.getFloat(R.styleable.FloatingActionButton_shadowRadius, 10.0f);
dx = a.getFloat(R.styleable.FloatingActionButton_shadowDx, 0.0f);
dy = a.getFloat(R.styleable.FloatingActionButton_shadowDy, 3.5f);
int color = a.getInteger(R.styleable.FloatingActionButton_shadowColor, Color.argb(100, 0, 0, 0));
mButtonPaint.setShadowLayer(radius, dx, dy, color);
WindowManager mWindowManager = (WindowManager) _context.getSystemService(Context.WINDOW_SERVICE);
Drawable drawable = a.getDrawable(R.styleable.FloatingActionButton_drawable);
if (null != drawable) {
mBitmap = ((BitmapDrawable) drawable).getBitmap();
}
setWillNotDraw(false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
WindowManager mWindowManager = (WindowManager)
context.getSystemService(Context.WINDOW_SERVICE);
Display display = mWindowManager.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
mScreenHeight = size.y;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
display.getSize(size);
mYHidden = size.y;
} else mYHidden = display.getHeight();
}
mShowAnimation = ObjectAnimator.ofFloat(this, "Y", currentY);
mHideAnimation = ObjectAnimator.ofFloat(this, "Y", mScreenHeight);
public static int darkenColor(int color) {
float[] hsv = new float[3];
Color.colorToHSV(color, hsv);
hsv[2] *= 0.8f;
return Color.HSVToColor(hsv);
}
public void setColor(int color) {
mColor = color;
mButtonPaint.setColor(mColor);
invalidate();
}
public void setDrawable(Drawable drawable) {
mBitmap = ((BitmapDrawable) drawable).getBitmap();
invalidate();
}
@Override
protected void onDraw(Canvas canvas)
{
setClickable(true);
canvas.drawCircle(getWidth()/2, getHeight()/2,(float) (getWidth()/2.6), mButtonPaint);
canvas.drawBitmap(mBitmap, (getWidth() - mBitmap.getWidth()) / 2, (getHeight() - mBitmap.getHeight()) / 2, mDrawablePaint);
protected void onDraw(Canvas canvas) {
canvas.drawCircle(getWidth() / 2, getHeight() / 2, (float) (getWidth() / 2.6), mButtonPaint);
if (null != mBitmap) {
canvas.drawBitmap(mBitmap, (getWidth() - mBitmap.getWidth()) / 2,
(getHeight() - mBitmap.getHeight()) / 2, mDrawablePaint);
}
}
@Override
public boolean onTouchEvent(MotionEvent event)
{
if(event.getAction() == MotionEvent.ACTION_UP)
{
setAlpha(1.0f);
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
// Perform the default behavior
super.onLayout(changed, left, top, right, bottom);
// Store the FAB button's displayed Y position if we are not already aware of it
if (mYDisplayed == -1) {
mYDisplayed = ViewHelper.getY(this);
}
else if(event.getAction() == MotionEvent.ACTION_DOWN)
{
setAlpha(0.6f);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int color;
if (event.getAction() == MotionEvent.ACTION_UP) {
color = mColor;
} else {
color = darkenColor(mColor);
}
mButtonPaint.setColor(color);
invalidate();
return super.onTouchEvent(event);
}
public int dpToPx(int dp)
{
DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics();
return Math.round(dp * (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT));
}
public void hide(boolean hide) {
// If the hidden state is being updated
if (mHidden != hide) {
public void hideFab()
{
if(!mHidden && mShowAnimation != null && !mShowAnimation.isRunning())
{
currentY = getY();
mHideAnimation = ObjectAnimator.ofFloat(this, "Y", mScreenHeight);
mHideAnimation.setInterpolator(new AccelerateInterpolator());
mHideAnimation.start();
mHidden = true;
// Store the new hidden state
mHidden = hide;
// Animate the FAB to it's new Y position
ObjectAnimator animator = ObjectAnimator.ofFloat(this, "y", mHidden ? mYHidden : mYDisplayed).setDuration(500);
animator.setInterpolator(mInterpolator);
animator.start();
}
}
public void showFab()
{
if(mHidden && mHideAnimation != null && !mHideAnimation.isRunning())
{
mShowAnimation = ObjectAnimator.ofFloat(this, "Y", currentY);
mShowAnimation.setInterpolator(new DecelerateInterpolator());
mShowAnimation.start();
mHidden = false;
}
}
public boolean isHidden(){
return mHidden;
}
public void listenTo(AbsListView listView) {
if (null != listView) {
listView.setOnScrollListener(new DirectionScrollListener(this));
}
}
}

View File

@ -15,12 +15,16 @@ dependencies {
}
android {
compileSdkVersion 20
buildToolsVersion "20.0.0"
compileSdkVersion 21
buildToolsVersion '21.0.2'
defaultConfig {
minSdkVersion 7
targetSdkVersion 20
targetSdkVersion 21
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
}

View File

@ -24,13 +24,13 @@ android {
disable 'MissingTranslation', 'ExtraTranslation'
}
compileSdkVersion 20
buildToolsVersion "20.0.0"
compileSdkVersion 21
buildToolsVersion '21.0.2'
defaultConfig {
applicationId "sharedcode.turboeditor"
minSdkVersion 14
targetSdkVersion 20
minSdkVersion 11
targetSdkVersion 21
versionCode 1
versionName "1.0"
}
@ -45,17 +45,32 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
lintOptions {
abortOnError false
}
packagingOptions {
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/NOTICE.txt'
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile project(':libraries:RootCommands')
compile project(':libraries:FloatingActionButton')
compile "com.android.support:support-v4:19.0.+"
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')
compile ("com.android.support:appcompat-v7:21.+") {
exclude group: 'com.android.support', module: 'support-v4'
}
compile 'com.android.support:support-v4:21.+'
compile 'com.github.gabrielemariotti.changeloglib:library:1.5.1'
compile 'commons-io:commons-io:2.4'
compile 'com.android.support:support-annotations:20.0.0'
}

View File

@ -1,3 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2014 Vlad Mihalachi
~
@ -15,10 +16,8 @@
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="sharedcode.turboeditor">
package="sharedcode.turboeditor" >
</manifest>

View File

@ -0,0 +1,144 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.vending.billing;
import android.os.Bundle;
/**
* InAppBillingService is the service that provides in-app billing version 3 and beyond.
* This service provides the following features:
* 1. Provides a new API to get details of in-app items published for the app including
* price, type, title and description.
* 2. The purchase flow is synchronous and purchase information is available immediately
* after it completes.
* 3. Purchase information of in-app purchases is maintained within the Google Play system
* till the purchase is consumed.
* 4. An API to consume a purchase of an inapp item. All purchases of one-time
* in-app items are consumable and thereafter can be purchased again.
* 5. An API to get current purchases of the user immediately. This will not contain any
* consumed purchases.
*
* All calls will give a response code with the following possible values
* RESULT_OK = 0 - success
* RESULT_USER_CANCELED = 1 - user pressed back or canceled a dialog
* RESULT_BILLING_UNAVAILABLE = 3 - this billing API version is not supported for the type requested
* RESULT_ITEM_UNAVAILABLE = 4 - requested SKU is not available for purchase
* RESULT_DEVELOPER_ERROR = 5 - invalid arguments provided to the API
* RESULT_ERROR = 6 - Fatal error during the API action
* RESULT_ITEM_ALREADY_OWNED = 7 - Failure to purchase since item is already owned
* RESULT_ITEM_NOT_OWNED = 8 - Failure to consume since item is not owned
*/
interface IInAppBillingService {
/**
* Checks support for the requested billing API version, package and in-app type.
* Minimum API version supported by this interface is 3.
* @param apiVersion the billing version which the app is using
* @param packageName the package name of the calling app
* @param type type of the in-app item being purchased "inapp" for one-time purchases
* and "subs" for subscription.
* @return RESULT_OK(0) on success, corresponding result code on failures
*/
int isBillingSupported(int apiVersion, String packageName, String type);
/**
* Provides details of a list of SKUs
* Given a list of SKUs of a valid type in the skusBundle, this returns a bundle
* with a list JSON strings containing the productId, price, title and description.
* This API can be called with a maximum of 20 SKUs.
* @param apiVersion billing API version that the Third-party is using
* @param packageName the package name of the calling app
* @param skusBundle bundle containing a StringArrayList of SKUs with key "ITEM_ID_LIST"
* @return Bundle containing the following key-value pairs
* "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on
* failure as listed above.
* "DETAILS_LIST" with a StringArrayList containing purchase information
* in JSON format similar to:
* '{ "productId" : "exampleSku", "type" : "inapp", "price" : "$5.00",
* "title : "Example Title", "description" : "This is an example description" }'
*/
Bundle getSkuDetails(int apiVersion, String packageName, String type, in Bundle skusBundle);
/**
* Returns a pending intent to launch the purchase flow for an in-app item by providing a SKU,
* the type, a unique purchase token and an optional developer payload.
* @param apiVersion billing API version that the app is using
* @param packageName package name of the calling app
* @param sku the SKU of the in-app item as published in the developer console
* @param type the type of the in-app item ("inapp" for one-time purchases
* and "subs" for subscription).
* @param developerPayload optional argument to be sent back with the purchase information
* @return Bundle containing the following key-value pairs
* "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on
* failure as listed above.
* "BUY_INTENT" - PendingIntent to start the purchase flow
*
* The Pending intent should be launched with startIntentSenderForResult. When purchase flow
* has completed, the onActivityResult() will give a resultCode of OK or CANCELED.
* If the purchase is successful, the result data will contain the following key-value pairs
* "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on
* failure as listed above.
* "INAPP_PURCHASE_DATA" - String in JSON format similar to
* '{"orderId":"12999763169054705758.1371079406387615",
* "packageName":"com.example.app",
* "productId":"exampleSku",
* "purchaseTime":1345678900000,
* "purchaseToken" : "122333444455555",
* "developerPayload":"example developer payload" }'
* "INAPP_DATA_SIGNATURE" - String containing the signature of the purchase data that
* was signed with the private key of the developer
* TODO: change this to app-specific keys.
*/
Bundle getBuyIntent(int apiVersion, String packageName, String sku, String type,
String developerPayload);
/**
* Returns the current SKUs owned by the user of the type and package name specified along with
* purchase information and a signature of the data to be validated.
* This will return all SKUs that have been purchased in V3 and managed items purchased using
* V1 and V2 that have not been consumed.
* @param apiVersion billing API version that the app is using
* @param packageName package name of the calling app
* @param type the type of the in-app items being requested
* ("inapp" for one-time purchases and "subs" for subscription).
* @param continuationToken to be set as null for the first call, if the number of owned
* skus are too many, a continuationToken is returned in the response bundle.
* This method can be called again with the continuation token to get the next set of
* owned skus.
* @return Bundle containing the following key-value pairs
* "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on
* failure as listed above.
* "INAPP_PURCHASE_ITEM_LIST" - StringArrayList containing the list of SKUs
* "INAPP_PURCHASE_DATA_LIST" - StringArrayList containing the purchase information
* "INAPP_DATA_SIGNATURE_LIST"- StringArrayList containing the signatures
* of the purchase information
* "INAPP_CONTINUATION_TOKEN" - String containing a continuation token for the
* next set of in-app purchases. Only set if the
* user has more owned skus than the current list.
*/
Bundle getPurchases(int apiVersion, String packageName, String type, String continuationToken);
/**
* Consume the last purchase of the given SKU. This will result in this item being removed
* from all subsequent responses to getPurchases() and allow re-purchase of this item.
* @param apiVersion billing API version that the app is using
* @param packageName package name of the calling app
* @param purchaseToken token in the purchase information JSON that identifies the purchase
* to be consumed
* @return 0 if consumption succeeded. Appropriate error values for failures.
*/
int consumePurchase(int apiVersion, String packageName, String purchaseToken);
}

View File

@ -20,6 +20,7 @@
package sharedcode.turboeditor.activity;
import android.app.Activity;
import android.app.FragmentManager;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
@ -30,20 +31,16 @@ import android.widget.ListView;
import android.widget.TextView;
import sharedcode.turboeditor.R;
import sharedcode.turboeditor.preferences.PreferenceHelper;
import sharedcode.turboeditor.util.ThemeUtils;
public class LicensesActivity extends Activity implements AdapterView.OnItemClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
ThemeUtils.setTheme(this);
super.onCreate(savedInstanceState);
boolean light = PreferenceHelper.getLightTheme(this);
if (light) {
setTheme(R.style.AppTheme_Light);
} else {
setTheme(R.style.AppTheme_Dark);
}
setContentView(R.layout.activity_licenses);
ListView listView = (ListView) findViewById(android.R.id.list);
listView.setOnItemClickListener(this);

View File

@ -0,0 +1,44 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package sharedcode.turboeditor.activity;
import android.app.Application;
import android.view.ViewConfiguration;
import java.lang.reflect.Field;
public class MyApp extends Application {
@Override
public void onCreate() {
super.onCreate();
// force to sow the overflow menu icon
try {
ViewConfiguration config = ViewConfiguration.get(this);
Field menuKeyField = ViewConfiguration.class.getDeclaredField("sHasPermanentMenuKey");
if (menuKeyField != null) {
menuKeyField.setAccessible(true);
menuKeyField.setBoolean(config, false);
}
} catch (Exception ex) {
// Ignore
}
}
}

View File

@ -1,166 +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 <http://www.gnu.org/licenses/>.
*/
package sharedcode.turboeditor.activity;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import sharedcode.turboeditor.R;
import sharedcode.turboeditor.util.AppInfoHelper;
import sharedcode.turboeditor.util.Constants;
import sharedcode.turboeditor.util.ProCheckUtils;
public class PreferenceAbout extends Activity {
@Override
public void onCreate(final Bundle savedInstanceState) {
setTheme(R.style.AppTheme_Dark);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_about);
TextView changeLogText = (TextView) findViewById(R.id.changelog_text);
TextView proVersionText = (TextView) findViewById(R.id.pro_version_text);
try {
changeLogText.setText(String.format(getString(R.string.app_version), getPackageManager().getPackageInfo(getPackageName(), 0).versionName));
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
proVersionText.setVisibility(ProCheckUtils.isPro(getBaseContext()) ? View.GONE : View.VISIBLE);
}
@Override
protected void onDestroy() {
//checkout.stop();
super.onDestroy();
}
public void OpenPlayStore(View view) {
try {
if (Constants.FOR_AMAZON) {
String url = "amzn://apps/android?p=com.maskyn.fileeditor";
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url))
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
} else {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://search?q=pub:Maskyn"))
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
}
} catch (Exception e) {
}
}
public void GoToProVersion(View view) {
try {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=com.maskyn.fileeditorpro"))
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
} catch (Exception e) {
}
}
public void OpenGithub(View view) {
String url = "https://github.com/vmihalachi/TurboEditor";
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url))
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
}
public void SendFeedback(View view) {
String url = "http://forum.xda-developers.com/android/apps-games/app-turbo-editor-text-editor-t2832016";
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url))
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
}
public void SendMail(View view) {
Intent i = new Intent(Intent.ACTION_SEND);
i.setType("message/rfc822");
i.putExtra(Intent.EXTRA_EMAIL, new String[]{"maskyngames@gmail.com"});
i.putExtra(Intent.EXTRA_SUBJECT, AppInfoHelper.getApplicationName(getBaseContext()) + " " + AppInfoHelper.getCurrentVersion(getBaseContext()));
i.putExtra(Intent.EXTRA_TEXT, "");
try {
startActivity(Intent.createChooser(i, getString(R.string.nome_app_turbo_editor)));
} catch (android.content.ActivityNotFoundException ex) {
}
}
public void OpenTranslatePage(View view) {
String url = "http://crowdin.net/project/turbo-client";
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url))
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
}
public void OpenGooglePlusCommunity(View view) {
String url = "https://plus.google.com/u/0/communities/111974095419108178946";
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url))
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
}
/*void setupClickablePreferences() {
final Preference email = findPreference("aboutactivity_authoremail"),
changelog = findPreference("aboutactivity_changelog"),
open_source_licenses = findPreference("aboutactivity_open_source_licenses"),
market = findPreference("aboutactivity_authormarket");
if (email != null) {
email.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(final Preference preference) {
return false;
}
});
}
if (changelog != null) {
changelog.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(final Preference preference) {
ChangelogDialogFragment.showChangeLogDialog(getFragmentManager());
return false;
}
});
}
if (open_source_licenses != null) {
open_source_licenses.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(final Preference preference) {
startActivity(new Intent(PreferenceAbout.this, LicensesActivity.class));
return false;
}
});
}
if (market != null) {
market.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(final Preference preference) {
return false;
}
});
}
}*/
}

View File

@ -19,29 +19,25 @@
package sharedcode.turboeditor.activity;
import android.app.Activity;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.widget.SearchView;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Filter;
import android.widget.ListView;
import android.widget.PopupMenu;
import android.widget.SearchView;
import android.widget.TextView;
import android.widget.Toast;
import com.faizmalkani.floatingactionbutton.FloatingActionButton;
import sharedcode.turboeditor.R;
import sharedcode.turboeditor.adapter.AdapterDetailedList;
import sharedcode.turboeditor.fragment.EditDialogFragment;
import sharedcode.turboeditor.util.AlphanumComparator;
import sharedcode.turboeditor.util.Constants;
import sharedcode.turboeditor.preferences.PreferenceHelper;
import sharedcode.turboeditor.util.RootUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
@ -57,28 +53,36 @@ import java.util.Comparator;
import java.util.LinkedList;
import java.util.concurrent.TimeoutException;
public class SelectFileActivity extends Activity implements SearchView.OnQueryTextListener, AdapterView.OnItemClickListener, EditDialogFragment.EditDialogListener {
private String currentFolder;
import sharedcode.turboeditor.R;
import sharedcode.turboeditor.adapter.AdapterDetailedList;
import sharedcode.turboeditor.fragment.EditTextDialog;
import sharedcode.turboeditor.preferences.PreferenceHelper;
import sharedcode.turboeditor.root.RootUtils;
import sharedcode.turboeditor.util.AlphanumComparator;
import sharedcode.turboeditor.util.Build;
import sharedcode.turboeditor.util.ThemeUtils;
public class SelectFileActivity extends ActionBarActivity implements SearchView.OnQueryTextListener, AdapterView.OnItemClickListener, EditTextDialog.EditDialogListener {
private String currentFolder = PreferenceHelper.SD_CARD_ROOT;
private ListView listView;
private boolean wantAFile;
private boolean wantAFile = true;
private MenuItem mSearchViewMenuItem;
private SearchView mSearchView;
private Filter filter;
@Override
protected void onCreate(Bundle savedInstanceState) {
boolean light = PreferenceHelper.getLightTheme(this);
if (light) {
setTheme(R.style.AppTheme_Light);
} else {
setTheme(R.style.AppTheme_Dark);
}
ThemeUtils.setTheme(this);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_select_file);
getActionBar().setDisplayHomeAsUpEnabled(true);
Toolbar toolbar = (Toolbar) findViewById(R.id.my_awesome_toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
final Actions action = (Actions) getIntent().getExtras().getSerializable("action");
wantAFile = action == Actions.SelectFile;
@ -87,7 +91,7 @@ public class SelectFileActivity extends Activity implements SearchView.OnQueryTe
listView.setOnItemClickListener(this);
listView.setTextFilterEnabled(true);
FloatingActionButton mFab = (FloatingActionButton)findViewById(R.id.fabbutton);
FloatingActionButton mFab = (FloatingActionButton) findViewById(R.id.fabbutton);
mFab.setColor(getResources().getColor(R.color.fab_light));
mFab.setDrawable(getResources().getDrawable(R.drawable.ic_fab_add));
@ -101,14 +105,14 @@ public class SelectFileActivity extends Activity implements SearchView.OnQueryTe
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
final EditDialogFragment dialogFrag;
final EditTextDialog dialogFrag;
int i = item.getItemId();
if (i == R.id.im_new_file) {
dialogFrag = EditDialogFragment.newInstance(EditDialogFragment.Actions.NewFile);
dialogFrag = EditTextDialog.newInstance(EditTextDialog.Actions.NewFile);
dialogFrag.show(getFragmentManager().beginTransaction(), "dialog");
return true;
} else if (i == R.id.im_new_folder) {
dialogFrag = EditDialogFragment.newInstance(EditDialogFragment.Actions.NewFolder);
dialogFrag = EditTextDialog.newInstance(EditTextDialog.Actions.NewFolder);
dialogFrag.show(getFragmentManager().beginTransaction(), "dialog");
return true;
} else {
@ -147,10 +151,13 @@ public class SelectFileActivity extends Activity implements SearchView.OnQueryTe
}
public boolean onQueryTextChange(String newText) {
if (filter == null)
return true;
if (TextUtils.isEmpty(newText)) {
listView.clearTextFilter();
filter.filter(null);
} else {
listView.setFilterText(newText);
filter.filter(newText);
}
return true;
}
@ -205,7 +212,7 @@ public class SelectFileActivity extends Activity implements SearchView.OnQueryTe
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_select_file, menu);
mSearchViewMenuItem = menu.findItem(R.id.im_search);
mSearchView = (SearchView) mSearchViewMenuItem.getActionView();
mSearchView = (SearchView) MenuItemCompat.getActionView(mSearchViewMenuItem);
mSearchView.setIconifiedByDefault(true);
mSearchView.setOnQueryTextListener(this);
mSearchView.setSubmitButtonEnabled(false);
@ -218,15 +225,15 @@ public class SelectFileActivity extends Activity implements SearchView.OnQueryTe
MenuItem imSetAsWorkingFolder = menu.findItem(R.id.im_set_as_working_folder);
MenuItem imIsWorkingFolder = menu.findItem(R.id.im_is_working_folder);
MenuItem imSelectFolder = menu.findItem(R.id.im_select_folder);
if(imSetAsWorkingFolder != null){
if (imSetAsWorkingFolder != null) {
// set the imSetAsWorkingFolder visible only if the two folder dont concide
imSetAsWorkingFolder.setVisible(!currentFolder.equals(PreferenceHelper.getWorkingFolder(SelectFileActivity.this)));
}
if(imIsWorkingFolder != null) {
if (imIsWorkingFolder != null) {
// set visible is the other is invisible
imIsWorkingFolder.setVisible(!imSetAsWorkingFolder.isVisible());
}
if(imSelectFolder != null) {
if (imSelectFolder != null) {
imSelectFolder.setVisible(!wantAFile);
}
return super.onPrepareOptionsMenu(menu);
@ -242,6 +249,9 @@ public class SelectFileActivity extends Activity implements SearchView.OnQueryTe
PreferenceHelper.setWorkingFolder(SelectFileActivity.this, currentFolder);
invalidateOptionsMenu();
return true;
} else if (i == R.id.im_is_working_folder) {
Toast.makeText(getBaseContext(), R.string.is_the_working_folder, Toast.LENGTH_SHORT).show();
return true;
} else if (i == R.id.im_select_folder) {
returnData(currentFolder);
return true;
@ -251,11 +261,11 @@ public class SelectFileActivity extends Activity implements SearchView.OnQueryTe
@Override
public void onFinishEditDialog(final String inputText, final String hint, final EditDialogFragment.Actions actions) {
if (actions == EditDialogFragment.Actions.NewFile && !TextUtils.isEmpty(inputText)) {
public void onFinishEditDialog(final String inputText, final String hint, final EditTextDialog.Actions actions) {
if (actions == EditTextDialog.Actions.NewFile && !TextUtils.isEmpty(inputText)) {
File file = new File(currentFolder, inputText);
returnData(file.getAbsolutePath());
} else if (actions == EditDialogFragment.Actions.NewFolder && !TextUtils.isEmpty(inputText)) {
} else if (actions == EditTextDialog.Actions.NewFolder && !TextUtils.isEmpty(inputText)) {
File file = new File(currentFolder, inputText);
file.mkdirs();
new UpdateList().execute(currentFolder);
@ -275,7 +285,7 @@ public class SelectFileActivity extends Activity implements SearchView.OnQueryTe
super.onPreExecute();
if (mSearchView != null) {
mSearchView.setIconified(true);
mSearchViewMenuItem.collapseActionView();
MenuItemCompat.collapseActionView(mSearchViewMenuItem);
mSearchView.setQuery("", false);
}
@ -329,8 +339,8 @@ public class SelectFileActivity extends Activity implements SearchView.OnQueryTe
getString(R.string.folder),
""));
} else if (f.isFile()
&& !FilenameUtils.isExtension(f.getName().toLowerCase(), unopenableExtensions)
&& FileUtils.sizeOf(f) <= Constants.MAX_FILE_SIZE * FileUtils.ONE_KB) {
&& !FilenameUtils.isExtension(f.getName().toLowerCase(), unopenableExtensions)
&& FileUtils.sizeOf(f) <= Build.MAX_FILE_SIZE * FileUtils.ONE_KB) {
final long fileSize = f.length();
SimpleDateFormat format = new SimpleDateFormat("MMM dd, yyyy hh:mm a");
String date = format.format(f.lastModified());
@ -357,6 +367,7 @@ public class SelectFileActivity extends Activity implements SearchView.OnQueryTe
boolean isRoot = currentFolder.equals("/");
AdapterDetailedList mAdapter = new AdapterDetailedList(getBaseContext(), names, isRoot);
listView.setAdapter(mAdapter);
filter = mAdapter.getFilter();
} else if (exceptionMessage != null) {
Toast.makeText(SelectFileActivity.this, exceptionMessage, Toast.LENGTH_SHORT).show();
}

View File

@ -29,14 +29,14 @@ import android.widget.Filter;
import android.widget.ImageView;
import android.widget.TextView;
import sharedcode.turboeditor.R;
import sharedcode.turboeditor.util.MimeTypes;
import org.apache.commons.io.FilenameUtils;
import java.util.Arrays;
import java.util.LinkedList;
import sharedcode.turboeditor.R;
import sharedcode.turboeditor.util.MimeTypes;
public class AdapterDetailedList extends
ArrayAdapter<AdapterDetailedList.FileDetail> {

View File

@ -29,10 +29,10 @@ import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import sharedcode.turboeditor.R;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import sharedcode.turboeditor.R;
public class AdapterDrawer extends
ArrayAdapter<File> {
@ -41,11 +41,11 @@ public class AdapterDrawer extends
// Layout Inflater
private final LayoutInflater inflater;
// List of file details
private final ArrayList<File> files;
private final List<File> files;
private String selectedPath = "";
public AdapterDrawer(Context context,
ArrayList<File> files,
List<File> files,
Callbacks callbacks) {
super(context, R.layout.item_file_list, files);
this.files = files;
@ -78,10 +78,13 @@ public class AdapterDrawer extends
}
});
if (TextUtils.equals(selectedPath, files.get(position).getAbsolutePath()))
hold.nameLabel.setTypeface(hold.nameLabel.getTypeface(), Typeface.BOLD);
else
hold.nameLabel.setTypeface(hold.nameLabel.getTypeface(), Typeface.NORMAL);
if (TextUtils.equals(selectedPath, files.get(position).getAbsolutePath())) {
hold.nameLabel.setTypeface(null, Typeface.BOLD);
} else {
hold.nameLabel.setTypeface(null, Typeface.NORMAL);
}
} else {
final ViewHolder hold = ((ViewHolder) convertView.getTag());
final String fileName = files.get(position).getName();
@ -95,23 +98,26 @@ public class AdapterDrawer extends
selectedPath = "";
}
});
if (TextUtils.equals(selectedPath, files.get(position).getAbsolutePath()))
hold.nameLabel.setTypeface(hold.nameLabel.getTypeface(), Typeface.BOLD);
else
hold.nameLabel.setTypeface(hold.nameLabel.getTypeface(), Typeface.NORMAL);
if (TextUtils.equals(selectedPath, files.get(position).getAbsolutePath())) {
hold.nameLabel.setTypeface(null, Typeface.BOLD);
} else {
hold.nameLabel.setTypeface(null, Typeface.NORMAL);
}
}
return convertView;
}
public void selectView(String selectedPath) {
callbacks.ItemSelected(selectedPath);
//callbacks.ItemSelected(selectedPath);
this.selectedPath = selectedPath;
notifyDataSetChanged();
}
public interface Callbacks {
void CancelItem(int position, boolean andCloseOpenedFile);
void ItemSelected(String path);
//void ItemSelected(String path);
}
public static class ViewHolder {

View File

@ -0,0 +1,75 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package sharedcode.turboeditor.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import sharedcode.turboeditor.R;
public class AdapterTwoItem extends
ArrayAdapter<String> {
private final LayoutInflater inflater;
private final String[] lines1;
private final String[] lines2;
public AdapterTwoItem(Context context,
String[] lines1,
String[] lines2) {
super(context, R.layout.item_two_lines, lines1);
this.lines1 = lines1;
this.lines2 = lines2;
this.inflater = LayoutInflater.from(context);
}
@Override
public View getView(final int position,
View convertView, final ViewGroup parent) {
if (convertView == null) {
convertView = this.inflater
.inflate(R.layout.item_two_lines,
parent, false);
final ViewHolder hold = new ViewHolder();
hold.line1 = (TextView) convertView.findViewById(android.R.id.text1);
hold.line2 = (TextView) convertView.findViewById(android.R.id.text2);
convertView.setTag(hold);
hold.line1.setText(lines1[position]);
hold.line2.setText(lines2[position]);
} else {
final ViewHolder hold = ((ViewHolder) convertView.getTag());
hold.line1.setText(lines1[position]);
hold.line2.setText(lines2[position]);
}
return convertView;
}
public static class ViewHolder {
public TextView line1;
public TextView line2;
}
}

View File

@ -0,0 +1,90 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package sharedcode.turboeditor.fragment;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.os.Bundle;
import android.text.Html;
import android.view.View;
import android.widget.Toast;
import sharedcode.turboeditor.R;
import sharedcode.turboeditor.views.DialogHelper;
/**
* Dialog fragment that shows some info about this application.
*
* @author Artem Chepurnoy
*/
public class AboutDialog extends DialogFragment {
private static final String VERSION_UNAVAILABLE = "N/A";
/**
* Merges app name and version name into one.
*/
public static CharSequence getVersionName(Context context) {
PackageManager pm = context.getPackageManager();
String packageName = context.getPackageName();
String versionName;
try {
PackageInfo info = pm.getPackageInfo(packageName, 0);
versionName = info.versionName;
// Make the info part of version name a bit smaller.
if (versionName.indexOf('-') >= 0) {
versionName = versionName.replaceFirst("\\-", "<small>-") + "</small>";
}
} catch (PackageManager.NameNotFoundException e) {
versionName = VERSION_UNAVAILABLE;
}
Resources res = context.getResources();
return Html.fromHtml(
res.getString(R.string.about_title,
res.getString(R.string.nome_app_turbo_editor), versionName)
);
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Context context = getActivity();
assert context != null;
CharSequence message = Html.fromHtml(getString(
R.string.about_message));
View view = new DialogHelper.Builder(context)
.setIcon(getResources().getDrawable(R.drawable.ic_launcher))
.setTitle(getVersionName(context))
.setMessage(message)
.createCommonView();
return new AlertDialog.Builder(context)
.setView(view)
.setNeutralButton(R.string.close, null)
.create();
}
}

View File

@ -31,22 +31,21 @@ import android.net.Uri;
import android.os.Bundle;
import android.view.LayoutInflater;
import sharedcode.turboeditor.R;
import it.gmariotti.changelibs.library.view.ChangeLogListView;
import sharedcode.turboeditor.util.Constants;
import sharedcode.turboeditor.R;
import sharedcode.turboeditor.util.Build;
public class ChangelogDialogFragment extends DialogFragment {
public class ChangelogDialog extends DialogFragment {
public static void showChangeLogDialog(FragmentManager fragmentManager) {
ChangelogDialogFragment changelogDialogFragment = new ChangelogDialogFragment();
ChangelogDialog changelogDialog = new ChangelogDialog();
FragmentTransaction ft = fragmentManager.beginTransaction();
Fragment prev = fragmentManager.findFragmentByTag("changelogdemo_dialog");
if (prev != null) {
ft.remove(prev);
}
ft.addToBackStack(null);
changelogDialogFragment.show(ft, "changelogdemo_dialog");
changelogDialog.show(ft, "changelogdemo_dialog");
}
@ -73,7 +72,7 @@ public class ChangelogDialogFragment extends DialogFragment {
@Override
public void onClick(final DialogInterface dialog, final int which) {
try {
if (Constants.FOR_AMAZON) {
if (Build.FOR_AMAZON) {
String url = "amzn://apps/android?p=com.maskyn.fileeditor";
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url))
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));

View File

@ -32,18 +32,19 @@ import android.widget.EditText;
import android.widget.TextView;
import sharedcode.turboeditor.R;
import sharedcode.turboeditor.views.DialogHelper;
// ...
public class EditDialogFragment extends DialogFragment implements TextView.OnEditorActionListener {
public class EditTextDialog extends DialogFragment implements TextView.OnEditorActionListener {
private EditText mEditText;
public static EditDialogFragment newInstance(final Actions action) {
return EditDialogFragment.newInstance(action, "");
public static EditTextDialog newInstance(final Actions action) {
return EditTextDialog.newInstance(action, "");
}
public static EditDialogFragment newInstance(final Actions action, final String hint) {
final EditDialogFragment f = new EditDialogFragment();
public static EditTextDialog newInstance(final Actions action, final String hint) {
final EditTextDialog f = new EditTextDialog();
final Bundle args = new Bundle();
args.putSerializable("action", action);
args.putString("hint", hint);
@ -55,22 +56,25 @@ public class EditDialogFragment extends DialogFragment implements TextView.OnEdi
public Dialog onCreateDialog(Bundle savedInstanceState) {
final Actions action = (Actions) getArguments().getSerializable("action");
final String hint;
final String title;
switch (action) {
case NewFile:
hint = getString(R.string.file);
title = getString(R.string.file);
break;
case NewFolder:
hint = getString(R.string.folder);
title = getString(R.string.folder);
break;
default:
hint = null;
title = null;
break;
}
final View view = getActivity().getLayoutInflater().inflate(R.layout.dialog_fragment_edittext, null);
View view = new DialogHelper.Builder(getActivity())
.setTitle(title)
.setView(R.layout.dialog_fragment_edittext)
.createSkeletonView();
this.mEditText = (EditText) view.findViewById(android.R.id.edit);
this.mEditText.setHint(hint);
this.mEditText.setHint(R.string.name);
// Show soft keyboard automatically
this.mEditText.setText(getArguments().getString("hint"));

View File

@ -22,25 +22,20 @@ package sharedcode.turboeditor.fragment;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.support.v7.widget.SwitchCompat;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.CompoundButton;
import android.widget.ListView;
import android.widget.Switch;
import sharedcode.turboeditor.R;
import sharedcode.turboeditor.preferences.PreferenceHelper;
import sharedcode.turboeditor.preferences.SettingsFragment;
import sharedcode.turboeditor.util.SaveFileTask;
import org.mozilla.universalchardet.Constants;
public class EncodingDialogFragment extends DialogFragment implements AdapterView.OnItemClickListener {
import sharedcode.turboeditor.R;
import sharedcode.turboeditor.preferences.PreferenceHelper;
public class EncodingDialog extends DialogFragment implements AdapterView.OnItemClickListener {
private final String[] encodings = new String[]{
Constants.CHARSET_BIG5,
@ -72,8 +67,8 @@ public class EncodingDialogFragment extends DialogFragment implements AdapterVie
};
private ListView list;
public static EncodingDialogFragment newInstance() {
final EncodingDialogFragment f = new EncodingDialogFragment();
public static EncodingDialog newInstance() {
final EncodingDialog f = new EncodingDialog();
return f;
}
@ -82,7 +77,7 @@ public class EncodingDialogFragment extends DialogFragment implements AdapterVie
final View view = getActivity().getLayoutInflater().inflate(R.layout.dialog_encoding_list, null);
list = (ListView) view.findViewById(android.R.id.list);
Switch autoencoding = (Switch) view.findViewById(android.R.id.checkbox);
SwitchCompat autoencoding = (SwitchCompat) view.findViewById(android.R.id.checkbox);
autoencoding.setChecked(PreferenceHelper.getAutoEncoding(getActivity()));
autoencoding.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {

View File

@ -0,0 +1,97 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package sharedcode.turboeditor.fragment;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.View;
import android.widget.ListView;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.util.Date;
import sharedcode.turboeditor.R;
import sharedcode.turboeditor.adapter.AdapterTwoItem;
import sharedcode.turboeditor.views.DialogHelper;
// ...
public class FileInfoDialog extends DialogFragment {
public static FileInfoDialog newInstance(String filePath) {
final FileInfoDialog f = new FileInfoDialog();
final Bundle args = new Bundle();
args.putString("filePath", filePath);
f.setArguments(args);
return f;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
View view = new DialogHelper.Builder(getActivity())
.setTitle(R.string.info)
.setView(R.layout.dialog_fragment_file_info)
.createSkeletonView();
//final View view = getActivity().getLayoutInflater().inflate(R.layout.dialog_fragment_file_info, null);
ListView list = (ListView) view.findViewById(android.R.id.list);
File file = new File(getArguments().getString("filePath"));
// Get the last modification information.
Long lastModified = file.lastModified();
// Create a new date object and pass last modified information
// to the date object.
Date date = new Date(lastModified);
String[] lines1 = {
getString(R.string.name),
getString(R.string.folder),
getString(R.string.size),
getString(R.string.modification_date)
};
String[] lines2 = {
file.getName(),
file.getParent(),
FileUtils.byteCountToDisplaySize(file.length()),
date.toString()
};
list.setAdapter(new AdapterTwoItem(getActivity(), lines1, lines2));
return new AlertDialog.Builder(getActivity())
.setView(view)
.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
}
)
.create();
}
}

View File

@ -32,22 +32,22 @@ import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.Toast;
import sharedcode.turboeditor.R;
import sharedcode.turboeditor.util.SearchResult;
import java.util.LinkedList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import sharedcode.turboeditor.R;
import sharedcode.turboeditor.texteditor.SearchResult;
import sharedcode.turboeditor.views.DialogHelper;
// ...
public class FindTextDialogFragment extends DialogFragment {
public class FindTextDialog extends DialogFragment {
private EditText textToFind, textToReplace;
private CheckBox regexCheck, replaceCheck, matchCaseCheck;
public static FindTextDialogFragment newInstance(String allText) {
final FindTextDialogFragment f = new FindTextDialogFragment();
public static FindTextDialog newInstance(String allText) {
final FindTextDialog f = new FindTextDialog();
final Bundle args = new Bundle();
args.putString("allText", allText);
f.setArguments(args);
@ -57,7 +57,13 @@ public class FindTextDialogFragment extends DialogFragment {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final View view = getActivity().getLayoutInflater().inflate(R.layout.dialog_fragment_find_text, null);
//final View view = getActivity().getLayoutInflater().inflate(R.layout.dialog_fragment_find_text, null);
View view = new DialogHelper.Builder(getActivity())
.setTitle(R.string.find)
.setView(R.layout.dialog_fragment_find_text)
.createSkeletonView();
this.textToFind = (EditText) view.findViewById(R.id.text_to_find);
this.textToReplace = (EditText) view.findViewById(R.id.text_to_replace);
this.regexCheck = (CheckBox) view.findViewById(R.id.regex_check);
@ -80,41 +86,29 @@ public class FindTextDialogFragment extends DialogFragment {
}
}
)
.setNegativeButton(android.R.string.cancel,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
}
)
.setNegativeButton(android.R.string.cancel, null)
.create();
}
@Override
public void onStart()
{
public void onStart() {
super.onStart(); //super.onStart() is where dialog.show() is actually called on the underlying dialog, so we have to do it after this point
AlertDialog d = (AlertDialog)getDialog();
if(d != null)
{
AlertDialog d = (AlertDialog) getDialog();
if (d != null) {
Button positiveButton = (Button) d.getButton(Dialog.BUTTON_POSITIVE);
positiveButton.setText(getString(R.string.find));
positiveButton.setOnClickListener(new View.OnClickListener()
{
positiveButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v)
{
public void onClick(View v) {
returnData();
}
});
Button negativeButton = (Button) d.getButton(Dialog.BUTTON_NEGATIVE);
negativeButton.setText(getString(android.R.string.cancel));
negativeButton.setOnClickListener(new View.OnClickListener()
{
negativeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v)
{
public void onClick(View v) {
dismiss();
}
});
@ -122,7 +116,7 @@ public class FindTextDialogFragment extends DialogFragment {
}
void returnData() {
if(textToFind.getText().toString().isEmpty()) {
if (textToFind.getText().toString().isEmpty()) {
this.dismiss();
} else {
// we disable the okButton while we search
@ -130,7 +124,11 @@ public class FindTextDialogFragment extends DialogFragment {
}
}
private class SearchTask extends AsyncTask<Void, Void, Void>{
public interface SearchDialogInterface {
void onSearchDone(SearchResult searchResult);
}
private class SearchTask extends AsyncTask<Void, Void, Void> {
LinkedList<Integer> foundIndex;
boolean foundSomething;
@ -145,9 +143,9 @@ public class FindTextDialogFragment extends DialogFragment {
Matcher matcher = null;
foundSomething = false;
if(isRegex) {
if (isRegex) {
try {
if(caseSensitive)
if (caseSensitive)
matcher = Pattern.compile(whatToSearch, Pattern.MULTILINE).matcher(allText);
else
matcher = Pattern.compile(whatToSearch, Pattern.CASE_INSENSITIVE | Pattern.MULTILINE).matcher(allText);
@ -156,14 +154,14 @@ public class FindTextDialogFragment extends DialogFragment {
}
}
if(isRegex) {
if (isRegex) {
while (matcher.find()) {
foundSomething = true;
foundIndex.add(matcher.start());
}
} else {
if(caseSensitive == false) { // by default is case sensitive
if (caseSensitive == false) { // by default is case sensitive
whatToSearch = whatToSearch.toLowerCase();
allText = allText.toLowerCase();
}
@ -183,15 +181,15 @@ public class FindTextDialogFragment extends DialogFragment {
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
if(foundSomething) {
if (foundSomething) {
// the class that called this Dialog should implement the SearchDialogIterface
SearchDialogInterface searchDialogInterface;
searchDialogInterface = ((SearchDialogInterface) getTargetFragment());
if(searchDialogInterface == null)
searchDialogInterface = ((SearchDialogInterface) getTargetFragment());
if (searchDialogInterface == null)
searchDialogInterface = ((SearchDialogInterface) getActivity());
// if who called this has not implemented the interface we return nothing
if(searchDialogInterface == null)
if (searchDialogInterface == null)
return;
// else we return positions and other things
else {
@ -203,11 +201,7 @@ public class FindTextDialogFragment extends DialogFragment {
}
Toast.makeText(getActivity(), String.format(getString(R.string.occurrences_found), foundIndex.size()), Toast.LENGTH_SHORT).show();
// dismiss the dialog
FindTextDialogFragment.this.dismiss();
FindTextDialog.this.dismiss();
}
}
public interface SearchDialogInterface {
void onSearchDone(SearchResult searchResult);
}
}

View File

@ -1,206 +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 <http://www.gnu.org/licenses/>.
*/
package sharedcode.turboeditor.fragment;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ListView;
import sharedcode.turboeditor.R;
import sharedcode.turboeditor.adapter.AdapterDrawer;
import sharedcode.turboeditor.util.EventBusEvents;
import sharedcode.turboeditor.preferences.PreferenceHelper;
import java.io.File;
import java.util.ArrayList;
import de.greenrobot.event.EventBus;
public class NavigationDrawerListFragment extends Fragment implements AdapterView.OnItemClickListener, AdapterDrawer.Callbacks {
private AdapterDrawer arrayAdapter;
private ArrayList<File> files;
private ListView listView;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Our custom layout
View rootView = inflater.inflate(R.layout.fragment_navigation_drawer, container, false);
listView = (ListView) rootView.findViewById(android.R.id.list);
listView.setEmptyView(rootView.findViewById(android.R.id.empty));
files = new ArrayList<>();
arrayAdapter = new AdapterDrawer(getActivity(), files, this);
listView.setAdapter(arrayAdapter);
return rootView;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
listView.setOnItemClickListener(this);
}
@Override
public void onResume() {
super.onResume();
// Register the Event Bus for events
EventBus.getDefault().registerSticky(this);
// Refresh the list view
refreshList();
}
@Override
public void onPause() {
super.onPause();
// Unregister the Event Bus
EventBus.getDefault().unregister(this);
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// File paths saved in preferences
String[] savedPaths = PreferenceHelper.getSavedPaths(getActivity());
// Path of the file selected
String filePath = savedPaths[position];
// Send the event that a file was selected
EventBus.getDefault().post(new EventBusEvents.NewFileToOpen(new File(filePath)));
arrayAdapter.selectView(filePath);
}
/**
* When a new file is opened
* Invoked by the main activity which receive the intent
*
* @param event The event called
*/
public void onEvent(EventBusEvents.NewFileToOpen event) {
// File paths saved in preferences
String[] savedPaths = PreferenceHelper.getSavedPaths(getActivity());
String selectedPath = event.getFile().getAbsolutePath();
for (String savedPath : savedPaths) {
// We don't need to save the file path twice
if (savedPath.equals(selectedPath)) {
arrayAdapter.selectView(selectedPath);
return;
}
}
// Add the path if it wasn't added before
addPath(selectedPath);
arrayAdapter.selectView(selectedPath);
EventBus.getDefault().removeStickyEvent(event);
}
public void onEvent(EventBusEvents.SavedAFile event) {
if (addPath(event.getPath())) {
arrayAdapter.selectView(event.getPath());
}
}
public void onEvent(EventBusEvents.ClosedAFile event) {
arrayAdapter.selectView("");
}
private boolean addPath(String path) {
// File paths saved in preferences
String[] savedPaths = PreferenceHelper.getSavedPaths(getActivity());
// StringBuilder
StringBuilder sb = new StringBuilder();
boolean pathAlreadyExist = false;
for (String savedPath : savedPaths) {
// Append the file path and a comma
sb.append(savedPath).append(",");
if (savedPath.equals(path))
pathAlreadyExist = true;
}
// Append new path
if (!pathAlreadyExist)
sb.append(path);
// Put the string and commit
PreferenceHelper.setSavedPaths(getActivity(), sb);
// Update list
refreshList();
return pathAlreadyExist == false;
}
private void removePath(String path) {
// File paths saved in preferences
String[] savedPaths = PreferenceHelper.getSavedPaths(getActivity());
// StringBuilder
StringBuilder sb = new StringBuilder();
// for cycle
for (String savedPath : savedPaths) {
if (path.equals(savedPath)) continue;
sb.append(savedPath).append(",");
}
// Put the string and commit
PreferenceHelper.setSavedPaths(getActivity(), sb);
// Update list
refreshList();
}
private void refreshList() {
// File paths saved in preferences
String[] savedPaths = PreferenceHelper.getSavedPaths(getActivity());
// File names for the list
files.clear();
// StringBuilder that will contain the file paths
StringBuilder sb = new StringBuilder();
// for cycle to convert paths to names
for (String path : savedPaths) {
File file = new File(path);
// Check that the file exist
if (file.exists()) {
files.add(file);
sb.append(path).append(",");
}
}
// save list without empty or non existed files
PreferenceHelper.setSavedPaths(getActivity(), sb);
// Set adapter
arrayAdapter.notifyDataSetChanged();
}
@Override
public void CancelItem(int position, boolean andCloseOpenedFile) {
String[] savedPaths = PreferenceHelper.getSavedPaths(getActivity());
removePath(savedPaths[position]);
if (andCloseOpenedFile)
EventBus.getDefault().post(new EventBusEvents.CannotOpenAFile());
}
@Override
public void ItemSelected(String path) {
EventBus.getDefault().post(new EventBusEvents.AFileIsSelected(path));
}
}

View File

@ -24,28 +24,25 @@ import android.app.Dialog;
import android.app.DialogFragment;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
import android.widget.TextView;
import java.io.File;
import sharedcode.turboeditor.R;
import sharedcode.turboeditor.activity.PreferenceAbout;
import sharedcode.turboeditor.preferences.PreferenceHelper;
import sharedcode.turboeditor.util.SaveFileTask;
import sharedcode.turboeditor.task.SaveFileTask;
import sharedcode.turboeditor.views.DialogHelper;
// ...
public class NewFileDetailsDialogFragment extends DialogFragment {
public class NewFileDetailsDialog extends DialogFragment {
private EditText mName;
private EditText mFolder;
public static NewFileDetailsDialogFragment newInstance(String fileText, String fileEncoding) {
final NewFileDetailsDialogFragment f = new NewFileDetailsDialogFragment();
public static NewFileDetailsDialog newInstance(String fileText, String fileEncoding) {
final NewFileDetailsDialog f = new NewFileDetailsDialog();
final Bundle args = new Bundle();
args.putString("fileText", fileText);
args.putString("fileEncoding", fileEncoding);
@ -56,7 +53,11 @@ public class NewFileDetailsDialogFragment extends DialogFragment {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final View view = getActivity().getLayoutInflater().inflate(R.layout.dialog_fragment_new_file_details, null);
View view = new DialogHelper.Builder(getActivity())
.setTitle(R.string.file)
.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);
@ -72,9 +73,10 @@ public class NewFileDetailsDialogFragment extends DialogFragment {
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if(!mName.getText().toString().isEmpty() && !mFolder.getText().toString().isEmpty()) {
if (!mName.getText().toString().isEmpty() && !mFolder.getText().toString().isEmpty()) {
File file = new File(mFolder.getText().toString(), mName.getText().toString());
new SaveFileTask(getActivity(), file.getPath(), getArguments().getString("fileText"), getArguments().getString("fileEncoding")).execute();
PreferenceHelper.setWorkingFolder(getActivity(), file.getParent());
}
}
}

View File

@ -24,60 +24,89 @@ import android.app.Dialog;
import android.app.DialogFragment;
import android.content.DialogInterface;
import android.os.Bundle;
import sharedcode.turboeditor.R;
import sharedcode.turboeditor.preferences.SettingsFragment;
import sharedcode.turboeditor.util.SaveFileTask;
import android.view.View;
import org.apache.commons.io.FilenameUtils;
import java.io.File;
public class SaveFileDialogFragment extends DialogFragment {
import sharedcode.turboeditor.R;
import sharedcode.turboeditor.task.SaveFileTask;
import sharedcode.turboeditor.views.DialogHelper;
public static SaveFileDialogFragment newInstance(String filePath, String text) {
SaveFileDialogFragment frag = new SaveFileDialogFragment();
public class SaveFileDialog extends DialogFragment {
public static SaveFileDialog newInstance(String filePath, String text, String encoding) {
return newInstance(filePath, text, encoding, false, "");
}
public static SaveFileDialog newInstance(String filePath, String text, String encoding, boolean openNewFileAfter, String pathOfNewFile) {
SaveFileDialog frag = new SaveFileDialog();
Bundle args = new Bundle();
args.putString("filePath", filePath);
args.putString("text", text);
args.putString("encoding", encoding);
args.putBoolean("openNewFileAfter", openNewFileAfter);
args.putString("pathOfNewFile", pathOfNewFile);
frag.setArguments(args);
return frag;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final String filePath = getArguments().getString("filePath");
final String text = getArguments().getString("text");
final String encoding = getArguments().getString("encoding");
final String fileName = FilenameUtils.getName(filePath);
final File file = new File(filePath);
return new AlertDialog.Builder(getActivity())
View view = new DialogHelper.Builder(getActivity())
.setIcon(getResources().getDrawable(R.drawable.ic_action_save))
.setTitle(R.string.salva)
.setMessage(String.format(getString(R.string.save_changes), fileName))
.setPositiveButton(android.R.string.yes,
.createCommonView();
return new AlertDialog.Builder(getActivity())
.setView(view)
.setPositiveButton(R.string.salva,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if(!fileName.isEmpty())
new SaveFileTask(getActivity(), filePath, text, SettingsFragment.sCurrentEncoding).execute();
if (!fileName.isEmpty())
new SaveFileTask(getActivity(), filePath, text,
encoding).execute();
else {
NewFileDetailsDialogFragment dialogFrag = NewFileDetailsDialogFragment.newInstance(text, SettingsFragment.sCurrentEncoding);
dialogFrag.show(getFragmentManager().beginTransaction(), "dialog");
NewFileDetailsDialog dialogFrag =
NewFileDetailsDialog.newInstance(text,
encoding);
dialogFrag.show(getFragmentManager().beginTransaction(),
"dialog");
}
}
}
)
.setNegativeButton(android.R.string.no,
.setNeutralButton(android.R.string.cancel, null)
.setNegativeButton(R.string.no,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ISaveDialog target = (ISaveDialog) getTargetFragment();
if (target == null) {
target = (ISaveDialog) getActivity();
}
target.userDoesntWantToSave(
getArguments().getBoolean("openNewFileAfter"),
getArguments().getString("pathOfNewFile")
);
}
}
)
.create();
}
public static enum Action {
SaveAFile
public interface ISaveDialog {
void userDoesntWantToSave(boolean openNewFile, String pathOfNewFile);
}
}

View File

@ -28,18 +28,19 @@ import android.view.View;
import android.widget.NumberPicker;
import sharedcode.turboeditor.R;
import sharedcode.turboeditor.views.DialogHelper;
// ...
public class SeekbarDialogFragment extends DialogFragment {
public class SeekbarDialog extends DialogFragment {
private NumberPicker mSeekBar;
public static SeekbarDialogFragment newInstance(final Actions action) {
return SeekbarDialogFragment.newInstance(action, 0, 50, 100);
public static SeekbarDialog newInstance(final Actions action) {
return SeekbarDialog.newInstance(action, 0, 50, 100);
}
public static SeekbarDialogFragment newInstance(final Actions action, final int min, final int current, final int max) {
final SeekbarDialogFragment f = new SeekbarDialogFragment();
public static SeekbarDialog newInstance(final Actions action, final int min, final int current, final int max) {
final SeekbarDialog f = new SeekbarDialog();
final Bundle args = new Bundle();
args.putSerializable("action", action);
args.putInt("min", min);
@ -52,9 +53,28 @@ public class SeekbarDialogFragment extends DialogFragment {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final Actions action = (Actions) getArguments().getSerializable("action");
Actions action = (Actions) getArguments().getSerializable("action");
int title;
switch (action){
case FontSize:
title = R.string.font_size;
break;
case SelectPage:
title = R.string.goto_page;
break;
case GoToLine:
title = R.string.goto_line;
break;
default:
title = R.string.nome_app_turbo_editor;
break;
}
View view = new DialogHelper.Builder(getActivity())
.setTitle(title)
.setView(R.layout.dialog_fragment_seekbar)
.createSkeletonView();
final View view = getActivity().getLayoutInflater().inflate(R.layout.dialog_fragment_seekbar, null);
this.mSeekBar = (NumberPicker) view.findViewById(android.R.id.input);
this.mSeekBar.setMaxValue(getArguments().getInt("max"));
this.mSeekBar.setMinValue(getArguments().getInt("min"));
@ -82,9 +102,9 @@ public class SeekbarDialogFragment extends DialogFragment {
}
void returnData() {
onSeekbarDialogDismissed target = (onSeekbarDialogDismissed) getTargetFragment();
ISeekbarDialog target = (ISeekbarDialog) getTargetFragment();
if (target == null) {
target = (onSeekbarDialogDismissed) getActivity();
target = (ISeekbarDialog) getActivity();
}
target.onSeekbarDialogDismissed(
(Actions) getArguments().getSerializable("action"),
@ -94,10 +114,10 @@ public class SeekbarDialogFragment extends DialogFragment {
}
public enum Actions {
FileSize, SelectPage, GoToLine
FontSize, SelectPage, GoToLine
}
public interface onSeekbarDialogDismissed {
public interface ISeekbarDialog {
void onSeekbarDialogDismissed(Actions action, int value);
}
}

View File

@ -0,0 +1,78 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
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();
}
}

View File

@ -0,0 +1,98 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
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<Donation> {
private final HashSet<String> mInventorySet;
private final LayoutInflater mInflater;
private final String mDonationAmountLabel;
private final int mColorNormal;
private final int mColorPurchased;
public DonationAdapter(Context context, Donation[] items, HashSet<String> 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;
}
}

View File

@ -0,0 +1,370 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
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<String> 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.<br/>
* 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;
}
}
/**
* <b>Make sure you call {@link #disposeBilling()}!</b>
*
* @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 shouldnt need to add just
// to cover for the deficiencies of the IAB API.
return true;
}
private void complain(String message) {
ToastUtils.showShort(getActivity(), message);
}
}

View File

@ -0,0 +1,53 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
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;
}
}

View File

@ -0,0 +1,582 @@
// 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:
* <p>
* 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
* <a href="http://iharder.net/xmlizable">http://iharder.net/xmlizable</a>
* periodically to check for updates or to contribute improvements.
* </p>
*
* @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.
* <p/>
* <p>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 <var>source</var>
* and writes the resulting four Base64 bytes to <var>destination</var>.
* The source and destination arrays can be manipulated
* anywhere along their length by specifying
* <var>srcOffset</var> and <var>destOffset</var>.
* This method does not check to make sure your arrays
* are large enough to accommodate <var>srcOffset</var> + 3 for
* the <var>source</var> array or <var>destOffset</var> + 4 for
* the <var>destination</var> array.
* The actual number of significant bytes in your array is
* given by <var>numSigBytes</var>.
*
* @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 <var>destination</var> 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 <var>source</var>
* and writes the resulting bytes (up to three of them)
* to <var>destination</var>.
* The source and destination arrays can be manipulated
* anywhere along their length by specifying
* <var>srcOffset</var> and <var>destOffset</var>.
* This method does not check to make sure your arrays
* are large enough to accommodate <var>srcOffset</var> + 4 for
* the <var>source</var> array or <var>destOffset</var> + 3 for
* the <var>destination</var> 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;
}
}

View File

@ -17,21 +17,21 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package sharedcode.turboeditor.fragment;
package sharedcode.turboeditor.iab.utils;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
/**
* Exception thrown when encountering an invalid Base64 input character.
*
* @author nelson
*/
public class Base64DecoderException extends Exception {
private static final long serialVersionUID = 1L;
import sharedcode.turboeditor.R;
public class NoFileOpenedFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_no_file_open, container, false);
public Base64DecoderException() {
super();
}
public Base64DecoderException(String s) {
super(s);
}
}

View File

@ -0,0 +1,54 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
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;
}
}

View File

@ -0,0 +1,966 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
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.
* <p/>
* 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.
* <p/>
* 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.
* <p/>
* 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.
* <p/>
* 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<ResolveInfo> 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<String> 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<String> moreItemSkus,
List<String> 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<String> 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<Purchase> 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<Purchase> 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<String> ownedSkus = ownedItems.getStringArrayList(
RESPONSE_INAPP_ITEM_LIST);
ArrayList<String> purchaseDataList = ownedItems.getStringArrayList(
RESPONSE_INAPP_PURCHASE_DATA_LIST);
ArrayList<String> 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<String> moreSkus)
throws RemoteException, JSONException {
logDebug("Querying SKU details.");
ArrayList<String> 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<String> 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<Purchase> purchases,
final OnConsumeFinishedListener singleListener,
final OnConsumeMultiFinishedListener multiListener) {
final Handler handler = new Handler();
flagStartAsync("consume");
(new Thread(new Runnable() {
public void run() {
final List<IabResult> 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<Purchase> purchases, List<IabResult> results);
}
}

View File

@ -0,0 +1,63 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
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();
}
}

View File

@ -0,0 +1,110 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
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<String, SkuDetails> mSkuMap = new HashMap<>();
Map<String, Purchase> 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<String> getAllOwnedSkus() {
return new ArrayList<>(mPurchaseMap.keySet());
}
/**
* Returns a list of all owned product IDs of a given type
*/
List<String> getAllOwnedSkus(String itemType) {
List<String> 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<Purchase> getAllPurchases() {
return new ArrayList<>(mPurchaseMap.values());
}
void addSkuDetails(SkuDetails d) {
mSkuMap.put(d.getSku(), d);
}
void addPurchase(Purchase p) {
mPurchaseMap.put(p.getSku(), p);
}
}

View File

@ -0,0 +1,98 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
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;
}
}

View File

@ -0,0 +1,124 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
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;
}
}

View File

@ -0,0 +1,76 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
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;
}
}

View File

@ -49,7 +49,7 @@ public final class PreferenceHelper {
return getPrefs(context).getBoolean("editor_line_numbers", true);
}
public static boolean getSyntaxHiglight(Context context) {
public static boolean getSyntaxHighlight(Context context) {
return getPrefs(context).getBoolean("editor_syntax_highlight", false);
}
@ -73,10 +73,6 @@ public final class PreferenceHelper {
return getPrefs(context).getBoolean("send_error_reports", true);
}
public static int getLastDayAdShowed(Context context) {
return getPrefs(context).getInt("last_day_ad_showed", 0);
}
public static String getEncoding(Context context) {
return getPrefs(context).getString("editor_encoding", "UTF-8");
}
@ -105,6 +101,17 @@ public final class PreferenceHelper {
return getPrefs(context).getBoolean("read_only", false);
}
public static boolean getIgnoreBackButton(Context context) {
return getPrefs(context).getBoolean("ignore_back_button", false);
}
public static boolean getSplitText(Context context) {
return getPrefs(context).getBoolean("page_system_active", true);
}
public static boolean hasDonated(Context context) {
return getPrefs(context).getBoolean("has_donated", false);
}
// Setter methods
public static void setUseMonospace(Context context, boolean value) {
@ -115,7 +122,7 @@ public final class PreferenceHelper {
getEditor(context).putBoolean("editor_line_numbers", value).commit();
}
public static void setSyntaxHiglight(Context context, boolean value) {
public static void setSyntaxHighlight(Context context, boolean value) {
getEditor(context).putBoolean("editor_syntax_highlight", value).commit();
}
@ -123,30 +130,10 @@ public final class PreferenceHelper {
getEditor(context).putBoolean("editor_wrap_content", value).commit();
}
public static void setLightTheme(Context context, boolean value) {
getEditor(context).putBoolean("light_theme", value).commit();
}
public static void setSuggestionActive(Context context, boolean value) {
getEditor(context).putBoolean("suggestion_active", value).commit();
}
public static void setAutoencoding(Context context, boolean value) {
getEditor(context).putBoolean("autoencoding", value).commit();
}
public static void setSendErrorReports(Context context, boolean value) {
getEditor(context).putBoolean("send_error_reports", value).commit();
}
public static void setLastDayAdShowed(Context context, int value) {
getEditor(context).putInt("last_day_ad_showed", value).commit();
}
public static void setEncoding(Context context, String value) {
getEditor(context).putString("editor_encoding", value).commit();
}
public static void setFontSize(Context context, int value) {
getEditor(context).putInt("font_size", value).commit();
}
@ -163,12 +150,39 @@ public final class PreferenceHelper {
getEditor(context).putBoolean("page_system_button_popup_shown", value).commit();
}
public static void setAutoSave(Context context, boolean value) {
getEditor(context).putBoolean("auto_save", value).commit();
}
public static void setReadOnly(Context context, boolean value) {
getEditor(context).putBoolean("read_only", value).commit();
}
public static void setHasDonated(Context context, boolean value) {
getEditor(context).putBoolean("has_donated", value);
}
public static void setLightTheme(Context context, boolean value) {
getEditor(context).putBoolean("light_theme", value).commit();
}
public static void setSuggestionsActive(Context context, boolean value) {
getEditor(context).putBoolean("suggestion_active", value).commit();
}
public static void setAutoSave(Context context, boolean value) {
getEditor(context).putBoolean("auto_save", value).commit();
}
public static void setIgnoreBackButton(Context context, boolean value) {
getEditor(context).putBoolean("ignore_back_button", value).commit();
}
public static void setSplitText(Context context, boolean value) {
getEditor(context).putBoolean("page_system_active", value).commit();
}
public static void setSendErrorReport(Context context, boolean value) {
getEditor(context).putBoolean("ignore_back_button", value).commit();
}
public static void setEncoding(Context context, String value) {
getEditor(context).putString("editor_encoding", value).commit();
}
}

View File

@ -20,27 +20,23 @@
package sharedcode.turboeditor.preferences;
import android.app.Fragment;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.widget.SwitchCompat;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.CheckedTextView;
import android.widget.CompoundButton;
import android.widget.Switch;
import android.widget.TextView;
import sharedcode.turboeditor.R;
import sharedcode.turboeditor.fragment.EncodingDialogFragment;
import sharedcode.turboeditor.fragment.SeekbarDialogFragment;
import de.greenrobot.event.EventBus;
import sharedcode.turboeditor.R;
import sharedcode.turboeditor.fragment.EncodingDialog;
import sharedcode.turboeditor.fragment.SeekbarDialog;
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.AUTO_SAVE;
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;
@ -51,97 +47,109 @@ import static sharedcode.turboeditor.util.EventBusEvents.APreferenceValueWasChan
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 EncodingDialogFragment.DialogListener, SeekbarDialogFragment.onSeekbarDialogDismissed {
public class SettingsFragment extends Fragment implements SeekbarDialog.ISeekbarDialog, EncodingDialog.DialogListener {
public static String sCurrentEncoding;
// Editor Variables
public static boolean sLineNumbers;
public static boolean sColorSyntax;
public static boolean sWrapContent;
public static int sFontSize;
public static boolean sUseMonospace;
public static boolean sLightTheme;
public static boolean sSuggestionsActive;
public static boolean sAutoSave;
public static boolean sReadOnly;
public static boolean sSendErrorReports;
private boolean sLineNumbers;
private boolean sColorSyntax;
private boolean sWrapContent;
private boolean sUseMonospace;
private boolean sReadOnly;
private boolean sLightTheme;
private boolean sSuggestions;
private boolean sAutoSave;
private boolean sIgnoreBackButton;
private boolean sSplitText;
private boolean sErrorReports;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SettingsFragment.sCurrentEncoding = PreferenceHelper.getEncoding(getActivity());
SettingsFragment.sUseMonospace = PreferenceHelper.getUseMonospace(getActivity());
SettingsFragment.sColorSyntax = PreferenceHelper.getSyntaxHiglight(getActivity());
SettingsFragment.sWrapContent = PreferenceHelper.getWrapContent(getActivity());
SettingsFragment.sLineNumbers = PreferenceHelper.getLineNumbers(getActivity());
SettingsFragment.sFontSize = PreferenceHelper.getFontSize(getActivity());
SettingsFragment.sSuggestionsActive = PreferenceHelper.getSuggestionActive(getActivity());
SettingsFragment.sLightTheme = PreferenceHelper.getLightTheme(getActivity());
SettingsFragment.sAutoSave = PreferenceHelper.getAutoSave(getActivity());
SettingsFragment.sReadOnly = PreferenceHelper.getReadOnly(getActivity());
SettingsFragment.sSendErrorReports = PreferenceHelper.getReadOnly(getActivity());
sUseMonospace = PreferenceHelper.getUseMonospace(getActivity());
sColorSyntax = PreferenceHelper.getSyntaxHighlight(getActivity());
sWrapContent = PreferenceHelper.getWrapContent(getActivity());
sLineNumbers = PreferenceHelper.getLineNumbers(getActivity());
sReadOnly = PreferenceHelper.getReadOnly(getActivity());
sLightTheme = PreferenceHelper.getLightTheme(getActivity());
sSuggestions = PreferenceHelper.getSuggestionActive(getActivity());
sAutoSave = PreferenceHelper.getAutoSave(getActivity());
sIgnoreBackButton = PreferenceHelper.getIgnoreBackButton(getActivity());
sSplitText = PreferenceHelper.getSplitText(getActivity());
sErrorReports = PreferenceHelper.getSendErrorReports(getActivity());
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Our custom layout
View rootView = inflater.inflate(R.layout.fragment_settings, container, false);
final CheckBox switchLineNumbers, switchSyntax, switchWrapContent, switchMonospace, switchLightTheme, switchSuggestionsActive, switchAutoSave, switchReadOnly, switchSendErrorReports;
switchLineNumbers = (CheckBox) rootView.findViewById(R.id.switch_line_numbers);
switchSyntax = (CheckBox) rootView.findViewById(R.id.switch_syntax);
switchWrapContent = (CheckBox) rootView.findViewById(R.id.switch_wrap_content);
switchMonospace = (CheckBox) rootView.findViewById(R.id.switch_monospace);
switchLightTheme = (CheckBox) rootView.findViewById(R.id.switch_light_theme);
switchSuggestionsActive = (CheckBox) rootView.findViewById(R.id.switch_suggestions_active);
switchAutoSave = (CheckBox) rootView.findViewById(R.id.switch_auto_save);
switchReadOnly = (CheckBox) rootView.findViewById(R.id.switch_read_only);
switchSendErrorReports = (CheckBox) rootView.findViewById(R.id.switch_send_error_reports);
final View rootView = inflater.inflate(R.layout.fragment_settings, container, false);
final SwitchCompat swLineNumbers, swSyntax, swWrapContent, swMonospace, swReadOnly;
final SwitchCompat swLightTheme, swSuggestions, swAutoSave, swIgnoreBackButton, swSplitText, swErrorReports;
switchLineNumbers.setChecked(sLineNumbers);
switchSyntax.setChecked(sColorSyntax);
switchWrapContent.setChecked(sWrapContent);
switchMonospace.setChecked(sUseMonospace);
switchLightTheme.setChecked(sLightTheme);
switchSuggestionsActive.setChecked(sSuggestionsActive);
switchAutoSave.setChecked(sAutoSave);
switchReadOnly.setChecked(sReadOnly);
swLineNumbers = (SwitchCompat) rootView.findViewById(R.id.switch_line_numbers);
swSyntax = (SwitchCompat) rootView.findViewById(R.id.switch_syntax);
swWrapContent = (SwitchCompat) rootView.findViewById(R.id.switch_wrap_content);
swMonospace = (SwitchCompat) rootView.findViewById(R.id.switch_monospace);
swReadOnly = (SwitchCompat) rootView.findViewById(R.id.switch_read_only);
swLightTheme = (SwitchCompat) rootView.findViewById(R.id.switch_light_theme);
swSuggestions = (SwitchCompat) rootView.findViewById(R.id.switch_suggestions_active);
swAutoSave = (SwitchCompat) rootView.findViewById(R.id.switch_auto_save);
swIgnoreBackButton = (SwitchCompat) rootView.findViewById(R.id.switch_ignore_backbutton);
swSplitText = (SwitchCompat) rootView.findViewById(R.id.switch_page_system);
swErrorReports = (SwitchCompat) rootView.findViewById(R.id.switch_send_error_reports);
TextView encodingView, fontSizeView, goProView;
encodingView = (TextView) rootView.findViewById(R.id.drawer_button_encoding);
swLineNumbers.setChecked(sLineNumbers);
swSyntax.setChecked(sColorSyntax);
swWrapContent.setChecked(sWrapContent);
swMonospace.setChecked(sUseMonospace);
swReadOnly.setChecked(sReadOnly);
swLightTheme.setChecked(sLightTheme);
swSuggestions.setChecked(sSuggestions);
swAutoSave.setChecked(sAutoSave);
swIgnoreBackButton.setChecked(sIgnoreBackButton);
swSplitText.setChecked(sSplitText);
swErrorReports.setChecked(sErrorReports);
TextView fontSizeView, encodingView, donateView, extraOptionsView;
fontSizeView = (TextView) rootView.findViewById(R.id.drawer_button_font_size);
goProView = (TextView) rootView.findViewById(R.id.drawer_button_go_pro);
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);
switchLineNumbers.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
if(ProCheckUtils.isPro(getActivity(), false))
ViewUtils.setVisible(donateView, false);
swLineNumbers.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
sLineNumbers = isChecked;
PreferenceHelper.setLineNumbers(getActivity(), isChecked);
EventBus.getDefault().post(new APreferenceValueWasChanged(LINE_NUMERS));
}
});
switchSyntax.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
swSyntax.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
sColorSyntax = isChecked;
PreferenceHelper.setSyntaxHiglight(getActivity(), isChecked);
PreferenceHelper.setSyntaxHighlight(getActivity(), isChecked);
EventBus.getDefault().post(new APreferenceValueWasChanged(SYNTAX));
}
});
switchWrapContent.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
swWrapContent.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
sWrapContent = isChecked;
PreferenceHelper.setWrapContent(getActivity(), isChecked);
EventBus.getDefault().post(new APreferenceValueWasChanged(WRAP_CONTENT));
}
});
switchMonospace.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
swMonospace.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
sUseMonospace = isChecked;
@ -151,59 +159,14 @@ public class SettingsFragment extends Fragment implements EncodingDialogFragment
}
});
switchLightTheme.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
swReadOnly.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
sLightTheme = isChecked;
PreferenceHelper.setLightTheme(getActivity(), isChecked);
EventBus.getDefault().post(new APreferenceValueWasChanged(THEME_CHANGE));
}
});
switchSuggestionsActive.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
sSuggestionsActive = isChecked;
PreferenceHelper.setSuggestionActive(getActivity(), isChecked);
EventBus.getDefault().post(new APreferenceValueWasChanged(TEXT_SUGGESTIONS));
}
});
switchAutoSave.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
sAutoSave = isChecked;
PreferenceHelper.setAutoSave(getActivity(), isChecked);
EventBus.getDefault().post(new APreferenceValueWasChanged(AUTO_SAVE));
}
});
switchReadOnly.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
sReadOnly = isChecked;
PreferenceHelper.setReadOnly(getActivity(), isChecked);
EventBus.getDefault().post(new APreferenceValueWasChanged(READ_ONLY));
}
});
switchSendErrorReports.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
sSendErrorReports = isChecked;
PreferenceHelper.setSendErrorReports(getActivity(), isChecked);
}
});
encodingView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
EncodingDialogFragment dialogFrag = EncodingDialogFragment.newInstance();
dialogFrag.setTargetFragment(SettingsFragment.this, 0);
dialogFrag.show(getFragmentManager().beginTransaction(), "dialog");
}
});
fontSizeView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
@ -211,54 +174,67 @@ public class SettingsFragment extends Fragment implements EncodingDialogFragment
int fontCurrent = //(int) (mEditor.getTextSize() / scaledDensity);
//fontMax / 2;
PreferenceHelper.getFontSize(getActivity());
SeekbarDialogFragment dialogFrag = SeekbarDialogFragment.newInstance(SeekbarDialogFragment.Actions.FileSize, 1, fontCurrent, fontMax);
SeekbarDialog dialogFrag = SeekbarDialog.newInstance(SeekbarDialog.Actions
.FontSize, 1, fontCurrent, fontMax);
dialogFrag.setTargetFragment(SettingsFragment.this, 0);
dialogFrag.show(getFragmentManager().beginTransaction(), "dialog");
}
});
goProView.setOnClickListener(new View.OnClickListener() {
encodingView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=com.maskyn.fileeditorpro"))
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
} catch (Exception e) {
}
EncodingDialog dialogFrag = EncodingDialog.newInstance();
dialogFrag.setTargetFragment(SettingsFragment.this, 0);
dialogFrag.show(getFragmentManager().beginTransaction(), "dialog");
}
});
extraOptionsView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
View otherOptions = rootView.findViewById(R.id.other_options);
boolean isVisible = otherOptions.getVisibility() == View.VISIBLE;
ViewUtils.setVisible(otherOptions, !isVisible);
}
});
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);
EventBus.getDefault().post(new APreferenceValueWasChanged(THEME_CHANGE));
}
});
swSuggestions.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
PreferenceHelper.setSuggestionsActive(getActivity(), isChecked);
EventBus.getDefault().post(new APreferenceValueWasChanged(TEXT_SUGGESTIONS));
}
});
goProView.setVisibility(ProCheckUtils.isPro(getActivity()) ? View.GONE : View.VISIBLE);
return rootView;
}
@Override
public void onEncodingSelected(String value) {
PreferenceHelper.setEncoding(getActivity(), value);
EventBus.getDefault().post(new APreferenceValueWasChanged(ENCODING));
}
@Override
public void onSeekbarDialogDismissed(SeekbarDialogFragment.Actions action, int value) {
sFontSize = value;
public void onSeekbarDialogDismissed(SeekbarDialog.Actions action, int value) {
PreferenceHelper.setFontSize(getActivity(), value);
EventBus.getDefault().post(new APreferenceValueWasChanged(FONT_SIZE));
}
/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
* <p/>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
public void onFragmentInteraction(Uri uri);
@Override
public void onEncodingSelected(String result) {
PreferenceHelper.setEncoding(getActivity(), result);
EventBus.getDefault().post(new APreferenceValueWasChanged(ENCODING));
}
}

View File

@ -0,0 +1,77 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
package sharedcode.turboeditor.root;
import android.util.Log;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class LinuxShell {
private static final String UNIX_ESCAPE_EXPRESSION = "(\\(|\\)|\\[|\\]|\\s|\'|\"|`|\\{|\\}|&|\\\\|\\?)";
public static String getCommandLineString(String input) {
return input.replaceAll(UNIX_ESCAPE_EXPRESSION, "\\\\$1");
}
public static BufferedReader execute(String cmd) {
BufferedReader reader = null;
try {
Process process = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(
process.getOutputStream());
os.writeBytes(cmd + "\n");
os.writeBytes("exit\n");
reader = new BufferedReader(new InputStreamReader(
process.getInputStream()));
String err = (new BufferedReader(new InputStreamReader(
process.getErrorStream()))).readLine();
os.flush();
if (process.waitFor() != 0 || (!"".equals(err) && null != err)
&& containsIllegals(err) != true) {
Log.e("Root Error, cmd: " + cmd, err);
return null;
}
return reader;
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static boolean containsIllegals(String toExamine) {
// checks for "+" sign so the program doesn't throw an error when its
// not erroring.
Pattern pattern = Pattern.compile("[+]");
Matcher matcher = pattern.matcher(toExamine);
return matcher.find();
}
}

View File

@ -32,7 +32,7 @@
* along with 920 Text Editor. If not, see <http://www.gnu.org/licenses/>.
*/
package sharedcode.turboeditor.util;
package sharedcode.turboeditor.root;
import android.content.Context;
@ -80,8 +80,7 @@ public class RootUtils {
} else {
BufferedReader reader = null; //errReader = null;
try {
reader = LinuxShell.execute("IFS='\n';CURDIR='" + LinuxShell.getCmdPath(path) + "';for i in `ls $CURDIR`; do if [ -d $CURDIR/$i ]; then echo \"d $CURDIR/$i\";else echo \"f $CURDIR/$i\"; fi; done");
LinuxShell.execute("ls -a " + LinuxShell.getCommandLineString(path));
if (reader == null)
return null;

View File

@ -17,14 +17,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package sharedcode.turboeditor.util;
package sharedcode.turboeditor.task;
import android.content.Context;
import android.os.AsyncTask;
import android.widget.Toast;
import sharedcode.turboeditor.R;
import org.sufficientlysecure.rootcommands.Shell;
import org.sufficientlysecure.rootcommands.Toolbox;
@ -33,6 +31,9 @@ import java.io.IOException;
import java.util.concurrent.TimeoutException;
import de.greenrobot.event.EventBus;
import sharedcode.turboeditor.R;
import sharedcode.turboeditor.root.RootUtils;
import sharedcode.turboeditor.util.EventBusEvents;
public class SaveFileTask extends AsyncTask<Void, Void, Void> {
@ -100,7 +101,7 @@ public class SaveFileTask extends AsyncTask<Void, Void, Void> {
protected void onPostExecute(final Void aVoid) {
super.onPostExecute(aVoid);
Toast.makeText(context, message, Toast.LENGTH_LONG).show();
if(message.equals(positiveMessage))
if (message.equals(positiveMessage))
EventBus.getDefault().post(new EventBusEvents.SavedAFile(filePath));
}
}

View File

@ -17,18 +17,20 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package sharedcode.turboeditor.util;
package sharedcode.turboeditor.texteditor;
import android.content.Context;
public class EdittextPadding {
import sharedcode.turboeditor.util.PixelDipConverter;
public class EditTextPadding {
public static int getPaddingWithoutLineNumbers(Context context) {
return (int) PixelDipConverter.convertDpToPixel(5, context);
}
public static int getPaddingWithLineNumbers(Context context, float fontSize) {
return (int) PixelDipConverter.convertDpToPixel(fontSize * 1.85f, context);
return (int) PixelDipConverter.convertDpToPixel(fontSize * 2f, context);
}
public static int getPaddingTop(Context context) {

View File

@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package sharedcode.turboeditor.util;
package sharedcode.turboeditor.texteditor;
import org.mozilla.universalchardet.UniversalDetector;

View File

@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package sharedcode.turboeditor.util;
package sharedcode.turboeditor.texteditor;
import android.text.Layout;
import android.widget.ScrollView;
@ -34,23 +34,18 @@ public class LineUtils {
return realLines;
}
public int getYAtLine(ScrollView scrollView, int lineCount, int line){
public int getYAtLine(ScrollView scrollView, int lineCount, int line) {
return scrollView.getChildAt(0).getHeight() / lineCount * line;
}
public int getFirstVisibleLine(ScrollView scrollView, int lineCount){
return getFirstVisibleLine(scrollView, scrollView.getChildAt(0).getHeight(), lineCount);
}
public int getFirstVisibleLine(ScrollView scrollView, int childHeight, int lineCount) throws ArithmeticException{
public int getFirstVisibleLine(ScrollView scrollView, int childHeight, int lineCount) throws ArithmeticException {
int line = (scrollView.getScrollY() * lineCount) / childHeight;
if (line < 0) line = 0;
return line;
}
public int getLastVisibleLine(int firstVisibleLine, int lineCount) {
int line;
line = firstVisibleLine + 150;
public int getLastVisibleLine(ScrollView scrollView, int childHeight, int lineCount, int deviceHeight) {
int line = ((scrollView.getScrollY() + deviceHeight) * lineCount) / childHeight;
if (line > lineCount) line = lineCount;
return line;
}
@ -90,6 +85,7 @@ public class LineUtils {
/**
* Gets the line from the index of the letter in the text
*
* @param index
* @param lineCount
* @param layout
@ -109,15 +105,19 @@ public class LineUtils {
return line;
}
public int firstReadLine() {
return realLines[0];
}
public int lastReadLine() {
return realLines[realLines.length-1];
return realLines[realLines.length - 1];
}
public int fakeLineFromRealLine(int realLine) {
int i;
int fakeLine = 0;
for(i = 0; i < realLines.length; i++) {
if (realLine == realLines[i]){
for (i = 0; i < realLines.length; i++) {
if (realLine == realLines[i]) {
fakeLine = i;
break;
}

View File

@ -17,26 +17,23 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package sharedcode.turboeditor.util;
package sharedcode.turboeditor.texteditor;
import android.content.Context;
import java.util.LinkedList;
import java.util.List;
import sharedcode.turboeditor.preferences.PreferenceHelper;
public class PageSystem {
public interface PageSystemInterface {
void onPageChanged(int page);
}
private List<String> pages;
private int[] startingLines;
private int currentPage = 0;
private PageSystemInterface pageSystemInterface;
public PageSystem(PageSystemInterface pageSystemInterface, String text) {
public PageSystem(Context context, PageSystemInterface pageSystemInterface, String text) {
this.pageSystemInterface = pageSystemInterface;
pages = new LinkedList<>();
@ -46,8 +43,9 @@ public class PageSystem {
int to;
int indexOfReturn;
int textLenght = text.length();
if(textLenght > maxLenghtInOnePage) {
while (i < textLenght) {
boolean pageSystemEnabled = PreferenceHelper.getSplitText(context);
if (pageSystemEnabled && textLenght > maxLenghtInOnePage) {
while (i < textLenght && pageSystemEnabled) {
to = i + charForPage;
indexOfReturn = text.indexOf("\n", to);
if (indexOfReturn > to) to = indexOfReturn;
@ -78,8 +76,8 @@ public class PageSystem {
public String getTextOfNextPages(boolean includeCurrent, int nOfPages) {
StringBuilder stringBuilder = new StringBuilder();
int i;
for(i = includeCurrent ? 0 : 1; i < nOfPages; i++){
if(pages.size() > (currentPage + i)) {
for (i = includeCurrent ? 0 : 1; i < nOfPages; i++) {
if (pages.size() > (currentPage + i)) {
stringBuilder.append(pages.get(currentPage + 1));
}
}
@ -92,25 +90,25 @@ public class PageSystem {
}
public void nextPage() {
if(!canReadNextPage()) return;
if (!canReadNextPage()) return;
goToPage(currentPage + 1);
}
public void prevPage() {
if(!canReadPrevPage()) return;
if (!canReadPrevPage()) return;
goToPage(currentPage - 1);
}
public void goToPage(int page) {
if(page >= pages.size()) page = pages.size() - 1;
if(page < 0) page = 0;
if (page >= pages.size()) page = pages.size() - 1;
if (page < 0) page = 0;
boolean shouldUpdateLines = page > currentPage && canReadNextPage();
if(shouldUpdateLines) {
if (shouldUpdateLines) {
String text = getCurrentPageText();
int nOfNewLineNow = (text.length() - text.replace("\n", "").length()) + 1; // normally the last line is not counted so we have to add 1
int nOfNewLineBefore = startingLines[currentPage+1] - startingLines[currentPage];
int difference = nOfNewLineNow - nOfNewLineBefore;
updateStartingLines(currentPage+1, difference);
int nOfNewLineBefore = startingLines[currentPage + 1] - startingLines[currentPage];
int difference = nOfNewLineNow - nOfNewLineBefore;
updateStartingLines(currentPage + 1, difference);
}
currentPage = page;
pageSystemInterface.onPageChanged(page);
@ -122,8 +120,8 @@ public class PageSystem {
int nOfNewLines;
String text;
startingLines[0] = 0;
for(i = 1; i < pages.size(); i++) {
text = pages.get(i-1);
for (i = 1; i < pages.size(); i++) {
text = pages.get(i - 1);
nOfNewLines = text.length() - text.replace("\n", "").length() + 1;
startingLine = startingLines[i - 1] + nOfNewLines;
startingLines[i] = startingLine;
@ -131,11 +129,11 @@ public class PageSystem {
}
public void updateStartingLines(int fromPage, int difference) {
if(difference == 0)
if (difference == 0)
return;
int i;
if(fromPage < 1) fromPage = 1;
for(i = fromPage; i < pages.size(); i++) {
if (fromPage < 1) fromPage = 1;
for (i = fromPage; i < pages.size(); i++) {
startingLines[i] += difference;
}
}
@ -144,13 +142,15 @@ public class PageSystem {
return pages.size() - 1;
}
public int getCurrentPage() { return currentPage; }
public int getCurrentPage() {
return currentPage;
}
public String getAllText(String currentPageText) {
pages.set(currentPage, currentPageText);
int i;
StringBuilder allText = new StringBuilder();
for(i = 0; i < pages.size(); i++) {
for (i = 0; i < pages.size(); i++) {
allText.append(pages.get(i)).append("\n");
}
return allText.toString();
@ -163,4 +163,8 @@ public class PageSystem {
public boolean canReadPrevPage() {
return currentPage >= 1;
}
public interface PageSystemInterface {
void onPageChanged(int page);
}
}

View File

@ -17,28 +17,27 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package sharedcode.turboeditor.util;
package sharedcode.turboeditor.texteditor;
import android.content.Context;
import android.os.Handler;
import android.view.View;
import com.faizmalkani.floatingactionbutton.FloatingActionButton;
import sharedcode.turboeditor.R;
public class PageSystemButtons {
private static final int TIME_TO_SHOW_FABS = 2000;
public interface PageButtonsInterface {
public void nextPageClicked();
public void prevPageClicked();
public void pageSystemButtonLongClicked();
public boolean canReadNextPage();
public boolean canReadPrevPage();
}
final Handler handler = new Handler();
final Runnable runnable = new Runnable() {
@Override
public void run() {
PageSystemButtons.this.next.setVisibility(View.GONE);
PageSystemButtons.this.prev.setVisibility(View.GONE);
}
};
FloatingActionButton prev, next;
PageButtonsInterface pageButtonsInterface;
@ -53,10 +52,10 @@ public class PageSystemButtons {
this.prev.setColor(context.getResources().getColor(R.color.fab_light));
this.prev.setDrawable(context.getResources().getDrawable(R.drawable.ic_keyboard_arrow_left));
if(pageButtonsInterface.canReadNextPage())
if (pageButtonsInterface.canReadNextPage())
next.setVisibility(View.VISIBLE);
if(pageButtonsInterface.canReadPrevPage())
if (pageButtonsInterface.canReadPrevPage())
prev.setVisibility(View.VISIBLE);
this.next.setOnClickListener(new View.OnClickListener() {
@ -90,23 +89,14 @@ public class PageSystemButtons {
});
}
final Handler handler = new Handler();
final Runnable runnable = new Runnable() {
@Override
public void run() {
PageSystemButtons.this.next.setVisibility(View.GONE);
PageSystemButtons.this.prev.setVisibility(View.GONE);
}
};
public void updateVisibility(boolean autoHide) {
if(pageButtonsInterface.canReadNextPage())
if (pageButtonsInterface.canReadNextPage())
PageSystemButtons.this.next.setVisibility(View.VISIBLE);
else
PageSystemButtons.this.next.setVisibility(View.GONE);
if(pageButtonsInterface.canReadPrevPage())
if (pageButtonsInterface.canReadPrevPage())
PageSystemButtons.this.prev.setVisibility(View.VISIBLE);
else
PageSystemButtons.this.prev.setVisibility(View.GONE);
@ -121,7 +111,7 @@ public class PageSystemButtons {
else
prev.hideFab();*/
if(autoHide) {
if (autoHide) {
handler.removeCallbacks(runnable);
handler.postDelayed(runnable, TIME_TO_SHOW_FABS);
} else {
@ -129,4 +119,16 @@ public class PageSystemButtons {
}
}
public interface PageButtonsInterface {
public void nextPageClicked();
public void prevPageClicked();
public void pageSystemButtonLongClicked();
public boolean canReadNextPage();
public boolean canReadPrevPage();
}
}

View File

@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package sharedcode.turboeditor.util;
package sharedcode.turboeditor.texteditor;
import java.util.regex.Pattern;
@ -69,9 +69,9 @@ public class Patterns {
"\\b(int|float|long|complex|str|unicode|list|tuple|bytearray|buffer|xrange|set|frozenset|dict|bool)|(True|False|None|self|NotImplemented|Ellipsis|__debug__|__file__)|(and|del|from|not|while|as|elif|global|or|with|assert|else|if|pass|yield|break|except|import|print|class|exec|in|raise|continue|finally|is|return|def|for|lambda|try)|(ArithmeticError|AssertionError|AttributeError|BaseException|DeprecationWarning|EnvironmentError|EOFError|Exception|FloatingPointError|FutureWarning|GeneratorExit|IOError|ImportError|ImportWarning|IndexError|KeyError|KeyboardInterrupt|LookupError|MemoryError|NameError|NotImplementedError|OSError|OverflowError|PendingDeprecationWarning|ReferenceError|RuntimeError|RuntimeWarning|StandardError|StopIteration|SyntaxError|SyntaxWarning|SystemError|SystemExit|TypeError|UnboundLocalError|UserWarning|UnicodeError|UnicodeWarning|UnicodeEncodeError|UnicodeDecodeError|UnicodeTranslateError|ValueError|Warning|WindowsError|ZeroDivisionError)\\b", Pattern.CASE_INSENSITIVE);
public static final Pattern LUA_KEYWORDS = Pattern.compile(
"@[A-Za-z0-9_\\.]*|\\b(local|global|boolean|number|userdata)\\b|\\b(true|false|nil)\\b|\\b(return|then|while|and|break|do|else|elseif|end|for|function|if|in|not|or|repeat|until|thread|table)\\b" +
"|(?i)\\b(editsetText|editText|inkey|touch|system.exit|system.expCall|system.getAppPath|system.getCardMnt|system.getSec|system.impCallActionSend|system.impCallActionView|system.setrun|system.setScreen|system.version|El_Psy_Congroo|canvas.drawCircle|canvas.drawCls|canvas.drawLine|canvas.drawRect|canvas.getBmpSize|canvas.getColor|canvas.getg|canvas.getviewSize|canvas.loadBmp|canvas.putCircle|canvas.putCls|canvas.putflush|canvas.putg|canvas.putLine|canvas.putRect|canvas.putrotg|canvas.putWork|canvas.saveBmp|canvas.setMainBmp|canvas.setWorkBmp|canvas.workCls|canvas.workflush|color|canvas.drawText|canvas.drawTextBox|canvas.drawTextCenter|canvas.drawTextRotate|canvas.putText|canvas.putTextBox|canvas.putTextRotate|http.addHeader|http.addParam|http.clrHeader|http.clrParam|http.get|http.post|http.setContentType|http.setPostFile|http.status|dialog|item.add|item.check|item.clear|item.list|item.radio|toast|sensor.getAccel|sensor.setdevAccel|sensor.setdevMagnet|sensor.setdevOrient|sensor.getGdirection|sensor.getMagnet|sensor.getOrient|sound.beep|sound.isPlay|sound.pause|sound.restart|sound.setSoundFile|sound.start|sound.stop|zip.addFile|zip.exec|zip.status|sock.close|sock.connectOpen|sock.getAddress|sock.listenOpen|sock.recv|sock.send|sprite.clear|sprite.define|sprite.init|sprite.move|sprite.put)\\b" +
"|(?i)\\b(assert|collectgarbage|coroutine.create|coroutine.resume|coroutine.running|coroutine.status|coroutine.wrap|coroutine.yield|debug.debug|debug.getfenv|debug.gethook|debug.getinfo|debug.getlocal|debug.getmetatable|debug.getregistry|debug.getupvalue|debug.setfenv|debug.sethook|debug.setlocal|debug.setmetatable|debug.setupvalue|debug.traceback|dofile|error|file:close|file:flush|file:lines|file:read|file:seek|file:setvbuf|file:write|getfenv|getmetatable|io.close|io.flush|io.input|io.lines|io.open|io.output|io.popen|io.read|io.tmpfile|io.type|io.write|ipairs|load|loadfile|loadstring|math.abs|math.acos|math.asin|math.atan2|math.atan|math.ceil|math.cosh|math.cos|math.deg|math.exp|math.floor|math.fmod|math.frexp|math.ldexp|math.log10|math.log|math.max|math.min|math.modf|math.pow|math.rad|math.random|math.randomseed|math.sinh|math.sin|math.sqrt|math.tanh|math.tan|module|next|os.clock|os.date|os.difftime|os.execute|os.exit|os.getenv|os.remove|os.rename|os.setlocale|os.time|os.tmpname|package.cpath|package.loaded|package.loadlib|package.path|package.preload|package.seeal|pairs|pcall|print|rawequal|rawget|rawset|require|select|setfenv|setmetatable|string.byte|string.char|string.dump|string.find|string.format|string.gmatch|string.gsub|string.len|string.lower|string.match|string.rep|string.reverse|string.sub|string.upper|table.concat|table.insert|table.maxn|table.remove|table.sort|tonumber|tostring|type|unpack|xpcall)\\b"
"@[A-Za-z0-9_\\.]*|\\b(local|global|boolean|number|userdata)\\b|\\b(true|false|nil)\\b|\\b(return|then|while|and|break|do|else|elseif|end|for|function|if|in|not|or|repeat|until|thread|table)\\b" +
"|(?i)\\b(editsetText|editText|inkey|touch|system.exit|system.expCall|system.getAppPath|system.getCardMnt|system.getSec|system.impCallActionSend|system.impCallActionView|system.setrun|system.setScreen|system.version|El_Psy_Congroo|canvas.drawCircle|canvas.drawCls|canvas.drawLine|canvas.drawRect|canvas.getBmpSize|canvas.getColor|canvas.getg|canvas.getviewSize|canvas.loadBmp|canvas.putCircle|canvas.putCls|canvas.putflush|canvas.putg|canvas.putLine|canvas.putRect|canvas.putrotg|canvas.putWork|canvas.saveBmp|canvas.setMainBmp|canvas.setWorkBmp|canvas.workCls|canvas.workflush|color|canvas.drawText|canvas.drawTextBox|canvas.drawTextCenter|canvas.drawTextRotate|canvas.putText|canvas.putTextBox|canvas.putTextRotate|http.addHeader|http.addParam|http.clrHeader|http.clrParam|http.get|http.post|http.setContentType|http.setPostFile|http.status|dialog|item.add|item.check|item.clear|item.list|item.radio|toast|sensor.getAccel|sensor.setdevAccel|sensor.setdevMagnet|sensor.setdevOrient|sensor.getGdirection|sensor.getMagnet|sensor.getOrient|sound.beep|sound.isPlay|sound.pause|sound.restart|sound.setSoundFile|sound.start|sound.stop|zip.addFile|zip.exec|zip.status|sock.close|sock.connectOpen|sock.getAddress|sock.listenOpen|sock.recv|sock.send|sprite.clear|sprite.define|sprite.init|sprite.move|sprite.put)\\b" +
"|(?i)\\b(assert|collectgarbage|coroutine.create|coroutine.resume|coroutine.running|coroutine.status|coroutine.wrap|coroutine.yield|debug.debug|debug.getfenv|debug.gethook|debug.getinfo|debug.getlocal|debug.getmetatable|debug.getregistry|debug.getupvalue|debug.setfenv|debug.sethook|debug.setlocal|debug.setmetatable|debug.setupvalue|debug.traceback|dofile|error|file:close|file:flush|file:lines|file:read|file:seek|file:setvbuf|file:write|getfenv|getmetatable|io.close|io.flush|io.input|io.lines|io.open|io.output|io.popen|io.read|io.tmpfile|io.type|io.write|ipairs|load|loadfile|loadstring|math.abs|math.acos|math.asin|math.atan2|math.atan|math.ceil|math.cosh|math.cos|math.deg|math.exp|math.floor|math.fmod|math.frexp|math.ldexp|math.log10|math.log|math.max|math.min|math.modf|math.pow|math.rad|math.random|math.randomseed|math.sinh|math.sin|math.sqrt|math.tanh|math.tan|module|next|os.clock|os.date|os.difftime|os.execute|os.exit|os.getenv|os.remove|os.rename|os.setlocale|os.time|os.tmpname|package.cpath|package.loaded|package.loadlib|package.path|package.preload|package.seeal|pairs|pcall|print|rawequal|rawget|rawset|require|select|setfenv|setmetatable|string.byte|string.char|string.dump|string.find|string.format|string.gmatch|string.gsub|string.len|string.lower|string.match|string.rep|string.reverse|string.sub|string.upper|table.concat|table.insert|table.maxn|table.remove|table.sort|tonumber|tostring|type|unpack|xpcall)\\b"
);
public static final Pattern PHP_VARIABLES = Pattern.compile("\\$\\s*(\\w+)");

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