diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..51f1a321 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,4 @@ +# These are supported funding model platforms + +patreon: riverfor +custom: ["https://paypal.me/qpyriver"] diff --git a/.gitignore b/.gitignore index f3579da9..1c454d72 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,29 @@ *.iml .gradle build +__MACOSX .idea -gradle +keystore .DS_Store -*.pyc +local.properties +*.apk +qbaselib.iml +.* +!/.gitignore +gradle-wrapper.properties +Android.mk +qpython/src/main/jni/python/libpython2.7.b +qpysdk/src/main/obj +values-fr +values-tr +build.gradle.new +captures +old.git +qpython/qpython.key +qpython/cn/release/output.json +qpython/od/release/* +qpython/cn +qpython/google +qpython/os +qpython/ol +qpython/op diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..441d4c0b --- /dev/null +++ b/.gitmodules @@ -0,0 +1,12 @@ +[submodule "qbaselib"] + path = qbaselib + url = git@github.com:qpython-android/qbaselib.git +[submodule "qftplib"] + path = qftplib + url = git@github.com:qpython-android/qftplib.git +[submodule "qpysdk/src/main/jni"] + path = qpysdk/src/main/jni + url = git@github.com:qpython-android/pygamesdl2-jni.git +[submodule "qpysl4a"] + path = qpysl4a + url = git@github.com:qpython-android/qpysl4a.git diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 33396733..00000000 --- a/LICENSE +++ /dev/null @@ -1,13 +0,0 @@ -Copyright [2017] [YAN HECUN ] - -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. diff --git a/README.md b/README.md index 87b21d5f..9912213e 100644 --- a/README.md +++ b/README.md @@ -1,58 +1,79 @@ -# QPython Project -

+# About -Welcome to read the QPython guide! -QPython is a script engine that runs Python on android devices. It lets your android device run Python scripts and projects. It contains the Python interpreter, console, editor, and the SL4A Library for Android. It’s Python on Android! +

+Welcome to the QPython project! -QPython has several millions users in the world already, it's a great project for programming users, welcome to join us for contributing to this project NOW. +QPython is the Python engine for android. It contains some amazing features such as Python interpreter, runtime environment, editor and QPYI and integrated SL4A. It makes it easy for you to use Python on Android. And it's FREE. +Compared with other Python apps, QPython mainly solves how to use Python to drive your Android device work. Good SL4A support is our main goal, such as android's camera, sensor, sms media APIs etc. -What's NEW ------------------------- -QPython project include the QPython https://play.google.com/store/apps/details?id=org.qpython.qpy and QPython3 https://play.google.com/store/apps/details?id=org.qpython.qpy3 applications. +QPython already has millions of users worldwide and it is also an open source project. -QPython application is using the **Python 2.7.2** , and QPython3 application is using the **Python 3.2.2** . +For different usage scenarios, QPython has two branches, namely QPython Ox and 3x. +QPython Ox is mainly aimed at programming learners, and it provides more friendly features for beginners. +QPython 3x is mainly for experienced Python users, and it provides some advanced technical features. -QPython's newest version is 1.3.0 (Released on 2017/3/20) , QPython3's newest version is 1.0.2 (Released on 2017/3/29), New versions include many amazing features, please upgrade to the newest version as soon from google play, amazon appstore etc. +## Quick start +This repository is the QPython Ox project repository, you can follow the below steps to run it. -Thanks these guys who are contributing ----------------------------------------- -They are pushing on the QPython project moving forward. +- Macos + Android studio, (Ubuntu may work too) +- git clone git@github.com:qpython-android/qpython.git +- git submodule init +- git submodule sync +- git submodule update +- build it... -River, Mae, Zoom.Quiet, MathiasLuo, liyuanrui, Kyle kersey ... +Get more information from [wiki](https://github.com/qpython-android/qpython/wiki) for developing QPython +## Related -Do you want to join the great QPython team ? You could Ask qustions on twitter https://twitter.com/qpython or email us mailto:support@qpython.org. -And you could fork us on github https://github.com/qpython-android/qpython and send pull request. +- [QPython 3x features](https://github.com/qpython-android/qpython.org/blob/master/qpython-docs/source/en/qpython_3x_featues.rst), [QPython Ox features](https://github.com/qpython-android/qpython.org/blob/master/qpython-docs/source/en/qpython_ox_featues.rst) +- [QPySL4A APIs](https://github.com/qpython-android/qpysl4a/blob/master/doc/en/APIs.rst) and [test scripts](https://github.com/qpython-android/qpysl4a/issues/1) +- QPYPI Packages +## How to ask QPython related questions +In order to benefit those guys who have the same issue with QPython, we suggest that you should ask the issue which is related with QPython within public techical communities. -QPython Communities ----------------------- -**There are many active QPython communities where you could meet the QPython users like you** -* Join Facebook community https://www.facebook.com/groups/qpython -* Join Google group https://groups.google.com/forum/#!forum/qpython -* Join Gitter chat https://gitter.im/qpython-android/qpython -* Join G+ community https://plus.google.com/communities/111759148772865961493 -* QPython on Stackoverflow http://stackoverflow.com/questions/tagged/qpython +### English QPythonista Community -**And you could talk to us through social network** +- [Ask in stackoverflow](https://stackoverflow.com/questions/tagged/qpython) +- [Discuss QPython Programming in QPython Group](https://www.facebook.com/groups/qpython/) -* Like us on facebook https://www.facebook.com/QPython -* Follow us on twitter https://twitter.com/qpython +### Chinese QPythonista Community -* Report issue https://github.com/qpython-android/qpython/issues -* Email us mailto:support@qpython.org +- [在segmentfault提问 - Chinese](https://segmentfault.com/t/qpython) +- [在贴吧讨论 - Chinese](https://tieba.baidu.com/f?ie=utf-8&kw=qpython) +### Report issues -Support -------------- -We are happy to hear feedback from you, but sometimes some bugs or features demand may not be implemented soon for we lack resources. +Please tell us your phone's informatioin, android os information, QPython branch, and your code, where did you install it and the detailed stituation you have encountered. -So if you have any issue need the core developer team to solve with higher priority, you could try the https://www.bountysource.com . +- [Report an app's issue](https://github.com/qpython-android/qpython/issues) +- [Report an non-app's issue](https://github.com/qpython-android/qpython.org/issues) +- [Request to support a package](https://github.com/qpython-android/qpypi/issues) -**It's the official QPython Users & Contributors' Guide, please follow http://www.qpython.org for more information.** +## Donation + +- harford (Wechat) +- 晨晖 (Wechat) + +THANK YOU VERY MUCH FOR DONATION! + + +## How to contribute +WE NEED YOUR HELP AND CONTRIBUTE, WE WILL BE VERY GRATEFUL IF YOU CAN TELL US YOUR IDEA OR SUGGESTION. + +IF YOU WANT TO PARTICIPATE THIS PROJECT, PLEASE SEND YOUR EMAIL TO US, WE WILL INVITE YOU INTO QPYTHON SLACK GROUP WHERE WE WILL DISCUSS HOW TO PUSH ON QPYTHON. + +- Email: support@qpython.org +- Twitter: @qpython +- Facebook: https://www.facebook.com/qpython + +Or you can join [qpython slack](https://join.slack.com/t/qpython/shared_invite/enQtOTI1MDY1NzM4NjU2LTljZDI3MjI0ZmZmNzIwNzAwMTU2ZDIyNGRjMTJiOTQ4MzgzY2Y3NDU5YzJjNTQ5MmM4Nzk2MGI4YWZmY2VhOTU) + +THANK YOU. diff --git a/build.gradle b/build.gradle index 9d8df85a..d576ffd4 100644 --- a/build.gradle +++ b/build.gradle @@ -1,33 +1,52 @@ -// Top-level build file where you can add configuration options common to all sub-projects/modules. +def supportVersion = "28.0.0" // equals to line60 +def retrofitVersion = "2.1.0" +def rxVersion = "1.2.1" + +def okhttpVersion = '3.10.0' -//task wrapper(type: Wrapper) { -// ersion = '2.2.1' -// gradleV -// distributionUrl = 'https://services.gradle.org/distributions/gradle-2.2.1-all.zip' -//} +def butterknifeVersion = '9.0.0' //eqals to line 26 buildscript { repositories { jcenter() - mavenCentral() google() + mavenCentral() + + maven { url "https://plugins.gradle.org/m2/" } + maven { url "https://maven.google.com" } } + dependencies { - classpath 'com.android.tools.build:gradle:3.0.1' - classpath 'me.tatarka:gradle-retrolambda:3.2.5' - classpath 'com.jakewharton.sdkmanager:gradle-plugin:0.12.0' - classpath "io.realm:realm-gradle-plugin:1.1.1" - classpath 'com.jakewharton:butterknife-gradle-plugin:8.5.1' - classpath "io.realm:realm-gradle-plugin:3.0.0" + classpath 'com.android.tools.build:gradle:3.5.3' + + // A gradle plugin for getting java lambda support in java 6, 7 and android + // https://github.com/evant/gradle-retrolambda + classpath 'me.tatarka:gradle-retrolambda:3.7.0' + + // Gradle plugin which downloads and manages your Android SDK. + //classpath 'com.jakewharton.sdkmanager:gradle-plugin:0.12.0' + + // Field and method binding for Android views which uses annotation processing to generate boilerplate code for you. + // https://github.com/JakeWharton/butterknife + classpath "com.jakewharton:butterknife-gradle-plugin:9.0.0-rc2" + + // Realm is a mobile database: a replacement for SQLite & ORMs + // https://github.com/realm/realm-java + classpath "io.realm:realm-gradle-plugin:3.5.0" + + classpath 'com.google.gms:google-services:4.0.2' } } allprojects { repositories { jcenter() + google() + + mavenCentral() maven { url "https://jitpack.io" } maven { url 'https://dl.bintray.com/azeesoft/maven' } - google() + //maven { url "http://mvn.leancloud.cn/nexus/content/repositories/public" } } } @@ -35,37 +54,65 @@ task clean(type: Delete) { delete rootProject.buildDir } - subprojects { def androidHome - if ((androidHome = System.env.'ANDROID_HOME') && (androidHome = androidHome as File).exists() - && androidHome.canWrite()) - apply plugin: 'android-sdk-manager' -} + && androidHome.canWrite()) { + //apply plugin: 'android-sdk-manager' + } + project.configurations.all { + resolutionStrategy.eachDependency { details -> + if (details.requested.group == 'com.android.support' + && !details.requested.name.contains('multidex')) { + details.useVersion "${supportVersion}" + } + } -def supportVersion = "26.0.2" -def rxVersion = "1.2.1" + } +} ext { - minSdkVersion = 15 - targetSdkVersion = 26 - compileSdkVersion = 26 - buildToolsVersion = '26.0.2' + libOkHttp3 = "com.squareup.okhttp3:okhttp:${okhttpVersion}" + + libRxJava = "io.reactivex:rxandroid:${rxVersion}" + libRxAndroid = "io.reactivex:rxjava:${rxVersion}" + libFileDownloaderLib = 'com.liulishuo.filedownloader:library:0.3.5' - libSupportV7 = "com.android.support:appcompat-v7:${supportVersion}" libSupportV4 = "com.android.support:support-v4:${supportVersion}" - libSupportAnnotation = "com.android.support:support-annotations:${supportVersion}" + libSupportV4Design = 'com.android.support:design:${supportVersion}' + + libSupportV7 = "com.android.support:appcompat-v7:${supportVersion}" libSupportCardView = "com.android.support:cardview-v7:${supportVersion}" + libSupportPreference = "com.android.support:preference-v14:${supportVersion}" + libSupportAnnotation = "com.android.support:support-annotations:${supportVersion}" libSupportDesign = "com.android.support:design:${supportVersion}" - libGuava = "com.google.guava:guava:18.0" - libOkHttp3 = "com.squareup.okhttp3:okhttp:3.4.0" + libOkHttp3Log = "com.squareup.okhttp3:logging-interceptor:${okhttpVersion}" - libRxJava = "io.reactivex:rxandroid:${rxVersion}" - libRxAndroid = "io.reactivex:rxjava:${rxVersion}" + minSdkVersion = 14 + targetSdkVersion = 28 + compileSdkVersion = 28 + buildToolsVersion = '28.0.3' + // firebase related https://firebase.google.com/docs/android/setup + firebaseCore = "com.google.firebase:firebase-core:16.0.6" + firebaseMsg = "com.google.firebase:firebase-messaging:17.3.4" + firebaseAuth = "com.google.firebase:firebase-auth:16.1.0" + firebaseDatabase = "com.google.firebase:firebase-database:16.0.5" -} + // https://developers.google.com/android/guides/setup + googlePlayServiceAuth = "com.google.android.gms:play-services-auth:16.0.1" + + leakcanaryDebug = 'com.squareup.leakcanary:leakcanary-android:1.5.4' + leakcanaryRelease = 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4' + libGoogleGuava = 'com.google.guava:guava:18.0' + + retrofit = "com.squareup.retrofit2:retrofit:${retrofitVersion}" + retrofitCoverterGson = "com.squareup.retrofit2:converter-gson:${retrofitVersion}" + retrofitAdapterRxjava = "com.squareup.retrofit2:adapter-rxjava:${retrofitVersion}" + + libButterknife = "com.jakewharton:butterknife:${butterknifeVersion}" + libButterknifeCompiler ="com.jakewharton:butterknife-compiler:${butterknifeVersion}" +} \ No newline at end of file diff --git a/debug.keystore b/debug.keystore new file mode 100644 index 00000000..70dc936c Binary files /dev/null and b/debug.keystore differ diff --git a/docs/QPython_3x_featues.md b/docs/QPython_3x_featues.md new file mode 100644 index 00000000..491234b5 --- /dev/null +++ b/docs/QPython_3x_featues.md @@ -0,0 +1,36 @@ +# QPython 3x featues + +Because google play and some appstores have strict requirements on the permissions of the app, we use different strategies in different appstores, which is why the branch name will be different. For example, L means Limited, and S means it contains Sensitive permissions. + +## Python +- Python3.6.6 +- QRCode Reader +- Editor +- QPYPI +- Ftp + +## Android Permissions + +### Both QPython 3S and 3L + +- android.permission.INTERNET +- android.permission.ACCESS_SUPERUSER +- android.permission.WAKE_LOCK +- android.permission.ACCESS_NETWORK_STATE +- android.permission.ACCESS_WIFI_STATE +- android.permission.RECEIVE_BOOT_COMPLETED +- android.permission.CAMERA +- android.permission.FLASHLIGHT +- android.permission.VIBRATE +- android.permission.RECEIVE_USER_PRESENT +- com.android.vending.BILLING +- com.android.browser.permission.READ_HISTORY_BOOKMARKS +- com.android.browser.permission.WRITE_HISTORY_BOOKMARKS +- com.android.launcher.permission.INSTALL_SHORTCUT +- com.android.launcher.permission.UNINSTALL_SHORTCUT +- android.permission.READ_EXTERNAL_STORAGE +- android.permission.WRITE_EXTERNAL_STORAGE +- android.permission.ACCESS_COARSE_LOCATION +- android.permission.ACCESS_FINE_LOCATION + +### QPython 3S diff --git a/docs/QPython_Ox_featues.md b/docs/QPython_Ox_featues.md new file mode 100644 index 00000000..fdfb8c09 --- /dev/null +++ b/docs/QPython_Ox_featues.md @@ -0,0 +1,40 @@ +# QPython Ox featues + +Because google play and some appstores have strict requirements on the permissions of the app, we use different strategies in different appstores, which is why the branch name will be different. For example, L means Limited, and S means it contains Sensitive permissions. + +## Python +- Python3 + Python2 basis +- QRCode Reader +- Editor +- QPYPI +- Ftp +- Course + +## Permissions +### Both QPython OL and OS +- android.permission.INTERNET +- android.permission.ACCESS_SUPERUSER +- android.permission.WAKE_LOCK +- android.permission.ACCESS_NETWORK_STATE +- android.permission.ACCESS_WIFI_STATE +- android.permission.RECEIVE_BOOT_COMPLETED +- android.permission.CAMERA +- android.permission.FLASHLIGHT +- android.permission.VIBRATE +- android.permission.RECEIVE_USER_PRESENT +- com.android.vending.BILLING +- com.android.browser.permission.READ_HISTORY_BOOKMARKS +- com.android.browser.permission.WRITE_HISTORY_BOOKMARKS +- com.android.launcher.permission.INSTALL_SHORTCUT +- com.android.launcher.permission.UNINSTALL_SHORTCUT +- android.permission.READ_EXTERNAL_STORAGE +- android.permission.WRITE_EXTERNAL_STORAGE +- android.permission.ACCESS_COARSE_LOCATION +- android.permission.ACCESS_FINE_LOCATION + +### QPython OS +- android.permission.FOREGROUND_SERVICE +- android.permission.BLUETOOTH +- android.permission.BLUETOOTH_ADMIN +- android.permission.NFC +- android.permission.RECORD_AUDIO diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000..42a966ab --- /dev/null +++ b/docs/README.md @@ -0,0 +1,2 @@ +# About +QPython documentation diff --git a/git-console-kotlin/GitTestProject/src/GitTest.kt b/git-console-kotlin/GitTestProject/src/GitTest.kt deleted file mode 100644 index defda7ff..00000000 --- a/git-console-kotlin/GitTestProject/src/GitTest.kt +++ /dev/null @@ -1,62 +0,0 @@ -import org.eclipse.jgit.api.Git -import org.eclipse.jgit.api.errors.GitAPIException -import org.eclipse.jgit.api.errors.JGitInternalException -import org.eclipse.jgit.internal.storage.file.FileRepository -import org.eclipse.jgit.storage.file.FileRepositoryBuilder -import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider -import org.junit.Test -import java.io.File -import java.io.IOException -// Modified UsernamePasswordCredentialsProvider Constructors string to apply git function is work. -class GitTest { - var remotePath: String? = null - var localPath: String? = null - var initPath: String? = null - @Test - @Throws(IOException::class, GitAPIException::class) - fun TestClone() { - val usernamePasswordCredentialsProvider = UsernamePasswordCredentialsProvider("username", "password") - val cloneCommand = Git.cloneRepository() - val git = cloneCommand.setURI(remotePath).setBranch("master").setDirectory(File(localPath!!)).setCredentialsProvider(usernamePasswordCredentialsProvider).call() - print(git.tag()) - } - - @Test - @Throws(IOException::class) - fun TestCreate() { - val newRepo = FileRepositoryBuilder.create(File(initPath!! + "/.git")) - newRepo.create() - } - - @Test - @Throws(IOException::class, GitAPIException::class) - fun TestAdd() { - val myFile = File(localPath!! + "/myfile.txt") - myFile.createNewFile() - val git = Git(FileRepository(localPath!! + "/.git")) - git.add().addFilepattern("myFile").call() - } - - @Test - @Throws(IOException::class, GitAPIException::class, JGitInternalException::class) - fun TestCommit() { - val git = Git(FileRepository(localPath!! + "/.git")) - git.commit().setMessage("Test Kotlin version").call() - } - - @Test - @Throws(IOException::class, GitAPIException::class) - fun TestPull() { - val usernamePasswordCredentialsProvider = UsernamePasswordCredentialsProvider("username", "password") - val git = Git(FileRepository(localPath!! + "/.git")) - git.pull().setRemoteBranchName("master").setCredentialsProvider(usernamePasswordCredentialsProvider).call() - } - - @Test - @Throws(IOException::class, GitAPIException::class, JGitInternalException::class) - fun TestPush() { - val usernamePasswordCredentialsProvider = UsernamePasswordCredentialsProvider("username", "password") - val git = Git(FileRepository(localPath!! + "/.git")) - git.push().setRemote("origin").setCredentialsProvider(usernamePasswordCredentialsProvider).call() - } -} diff --git a/git-console-kotlin/GitTestProject/src/Main.kt b/git-console-kotlin/GitTestProject/src/Main.kt deleted file mode 100644 index 8927091f..00000000 --- a/git-console-kotlin/GitTestProject/src/Main.kt +++ /dev/null @@ -1,24 +0,0 @@ -import java.util.Scanner -object Main { - @JvmStatic - fun main(args: Array) { - val test = GitTest() - val scanner = Scanner(System.`in`) - println("Please input the Git repository url: ") - test.remotePath = scanner.next() - println("Please input the local path: ") - test.localPath = scanner.next() - println("Please input the init path: ") - test.initPath = scanner.next() - try { - test.TestClone() - test.TestCreate() - test.TestAdd() - test.TestCommit() - test.TestPush() - test.TestPull() - } catch (e: Exception) { - e.printStackTrace() - } - } -} diff --git a/git-console-kotlin/README.md b/git-console-kotlin/README.md deleted file mode 100644 index 50153956..00000000 --- a/git-console-kotlin/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Git Module -这是用Kotlin语言写的控制台版的Git工具,如果需要应用到QPython工程中,需要将此API测试类进行重写 -## Modified By c4dr01d \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 6e9a9fd2..12d6a46b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,6 +14,6 @@ # org.gradle.parallel=true #Sun May 29 21:58:12 CST 2016 org.gradle.jvmargs=-Xmx2048m -#android.useDeprecatedNdk=true org.gradle.daemon=true -android.enableAapt2=false \ No newline at end of file +android.debug.obsoleteApi=true +#android.useDeprecatedNdk=true diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..f6b961fd Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 index 9d82f789..cccdd3d5 --- a/gradlew +++ b/gradlew @@ -1,4 +1,4 @@ -#!/usr/bin/env bash +#!/usr/bin/env sh ############################################################################## ## @@ -6,20 +6,38 @@ ## ############################################################################## -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" -warn ( ) { +warn () { echo "$*" } -die ( ) { +die () { echo echo "$*" echo @@ -30,6 +48,7 @@ die ( ) { cygwin=false msys=false darwin=false +nonstop=false case "`uname`" in CYGWIN* ) cygwin=true @@ -40,26 +59,11 @@ case "`uname`" in MINGW* ) msys=true ;; + NONSTOP* ) + nonstop=true + ;; esac -# Attempt to set APP_HOME -# Resolve links: $0 may be a link -PRG="$0" -# Need this for relative symlinks. -while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -85,7 +89,7 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then @@ -150,11 +154,19 @@ if $cygwin ; then esac fi -# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules -function splitJvmOpts() { - JVM_OPTS=("$@") +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " } -eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS -JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi -exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index aec99730..e95643d6 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -8,14 +8,14 @@ @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome @@ -46,10 +46,9 @@ echo location of your Java installation. goto fail :init -@rem Get command-line arguments, handling Windowz variants +@rem Get command-line arguments, handling Windows variants if not "%OS%" == "Windows_NT" goto win9xME_args -if "%@eval[2+2]" == "4" goto 4NT_args :win9xME_args @rem Slurp the command line arguments. @@ -60,11 +59,6 @@ set _SKIP=2 if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* -goto execute - -:4NT_args -@rem Get arguments from the 4NT Shell from JP Software -set CMD_LINE_ARGS=%$ :execute @rem Setup the command line diff --git a/local.properties b/local.properties index 463527d2..4929a5a2 100644 --- a/local.properties +++ b/local.properties @@ -1,12 +1,9 @@ -## This file is automatically generated by Android Studio. -# Do not modify this file -- YOUR CHANGES WILL BE ERASED! -# -# This file must *NOT* be checked into Version Control Systems, +## This file must *NOT* be checked into Version Control Systems, # as it contains information specific to your local configuration. # # Location of the SDK. This is only used by Gradle. # For customization when using a Version Control System, please read the # header note. -#Tue Jan 23 17:37:56 CST 2018 +#Thu Aug 02 10:23:49 CST 2018 ndk.dir=/Users/yanhecun/Library/Android/sdk/ndk-bundle sdk.dir=/Users/yanhecun/Library/Android/sdk diff --git a/qbaselib b/qbaselib new file mode 160000 index 00000000..d379973c --- /dev/null +++ b/qbaselib @@ -0,0 +1 @@ +Subproject commit d379973cb724f65f342a1fbfc7b426b185b7ce32 diff --git a/qftplib b/qftplib new file mode 160000 index 00000000..c1ab9384 --- /dev/null +++ b/qftplib @@ -0,0 +1 @@ +Subproject commit c1ab93848ec77ba6670332acff1e712a3c00301b diff --git a/qpypluginman/.gitignore b/qpypluginman/.gitignore deleted file mode 100644 index 3543521e..00000000 --- a/qpypluginman/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build diff --git a/qpypluginman/build.gradle b/qpypluginman/build.gradle index 14449ce0..3d455a43 100644 --- a/qpypluginman/build.gradle +++ b/qpypluginman/build.gradle @@ -1,34 +1,31 @@ -apply plugin: 'com.android.library' - -android { - compileSdkVersion rootProject.ext.compileSdkVersion - buildToolsVersion rootProject.ext.buildToolsVersion - - defaultConfig { - minSdkVersion rootProject.ext.minSdkVersion - targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 1 - versionName "1.0" - } - - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' - } - } -} - -dependencies { - compile fileTree(include: ['*.jar'], dir: 'libs') - testCompile 'junit:junit:4.12' - compile rootProject.ext.libRxJava - compile rootProject.ext.libRxAndroid - - compile 'com.liulishuo.filedownloader:library:0.3.5' - compile rootProject.ext.libSupportV4 - compile rootProject.ext.libOkHttp3 - - -} +apply plugin: 'com.android.library' + +android { + compileSdkVersion rootProject.ext.compileSdkVersion + + defaultConfig { + minSdkVersion rootProject.ext.minSdkVersion + targetSdkVersion rootProject.ext.targetSdkVersion + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + lintOptions { + abortOnError false + } +} + +dependencies { +// api fileTree(include: ['*.jar'], dir: 'libs') + //testApi 'junit:junit:4.12' + api rootProject.ext.libOkHttp3 + api rootProject.ext.libRxJava + api rootProject.ext.libRxAndroid + api rootProject.ext.libFileDownloaderLib + api rootProject.ext.libSupportV4 +} diff --git a/qpypluginman/proguard-rules.pro b/qpypluginman/proguard-rules.pro index ce612161..36693fa1 100644 --- a/qpypluginman/proguard-rules.pro +++ b/qpypluginman/proguard-rules.pro @@ -1,17 +1,17 @@ -# Add project specific ProGuard rules here. -# By default, the flags in this file are appended to flags specified -# in C:\Users\Jay\AppData\Local\Android\Sdk/tools/proguard/proguard-android.txt -# You can edit the include mPath 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 *; -#} +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in C:\Users\Jay\AppData\Local\Android\Sdk/tools/proguard/proguard-android.txt +# You can edit the include mPath 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 *; +#} diff --git a/qpypluginman/src/main/AndroidManifest.xml b/qpypluginman/src/main/AndroidManifest.xml index d010ff2f..3592f067 100644 --- a/qpypluginman/src/main/AndroidManifest.xml +++ b/qpypluginman/src/main/AndroidManifest.xml @@ -1,8 +1,8 @@ - - - - - - - + + + + + + + diff --git a/qpypluginman/src/main/java/com/quseit/common/updater/Updater.java b/qpypluginman/src/main/java/com/quseit/common/updater/Updater.java index eb08c609..08de8c45 100644 --- a/qpypluginman/src/main/java/com/quseit/common/updater/Updater.java +++ b/qpypluginman/src/main/java/com/quseit/common/updater/Updater.java @@ -1,149 +1,178 @@ -package com.quseit.common.updater; - - -import android.app.Application; -import android.content.Context; - -import com.quseit.common.updater.convertor.Convertor; -import com.quseit.common.updater.downloader.DefaultDownloader; -import com.quseit.common.updater.downloader.Downloader; -import com.quseit.common.updater.service.DefaultService; -import com.quseit.common.updater.service.Service; -import com.quseit.common.updater.updatepkg.UpdatePackage; - -import java.io.File; -import java.io.IOException; -import java.util.List; - -import rx.Observable; -import rx.Subscriber; -import rx.android.schedulers.AndroidSchedulers; -import rx.functions.Action1; -import rx.functions.Func1; -import rx.schedulers.Schedulers; - -public class Updater { - public static final String TAG = "Updater"; - private static List pkgs; - - private static Service service; - private static Convertor convertor; - private static Downloader downloader; - - private static String url; - private static Context context; - - public static synchronized void init(Application app, String url, Convertor convertor) { - Updater.context = app.getApplicationContext(); - Updater.url = url; - Updater.convertor = convertor; - - Updater.service = new DefaultService(); - Updater.downloader = new DefaultDownloader(app.getApplicationContext()); - } - - public static void checkUpdate(final CheckUpdateCallback callback) { - Observable - .create(new Observable.OnSubscribe() { - @Override - public void call(Subscriber subscriber) { - try { - String response = service.request(url); - subscriber.onNext(response); - } catch (IOException e) { - subscriber.onError(e); - } finally { - subscriber.onCompleted(); - } - } - }) - .subscribeOn(Schedulers.io()) - .observeOn(Schedulers.computation()) - .map(new Func1>() { - @Override - public List call(String response) { - return convertor.transform(response); - } - }) - .flatMap(new Func1, Observable>() { - @Override - public Observable call(List updatePkgs) { - return Observable.from(updatePkgs); - } - }) - .filter(new Func1() { - @Override - public Boolean call(UpdatePackage updatePackage) { - return updatePackage.checkVersion(); - } - }) - .toList() - .doOnNext(new Action1>() { - @Override - public void call(List pkgs) { - // 保存最新的获取的更新包 - Updater.pkgs = pkgs; - } - }) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe( - new Action1>() { - @Override - public void call(List updatePackages) { - if (!updatePackages.isEmpty()) { - callback.hasUpdate(updatePackages); - } else { - callback.noneUpdate(); - } - } - }, - new Action1() { - @Override - public void call(Throwable throwable) { - throwable.printStackTrace(); - callback.error(throwable); - } - }); - } - - public static void update(UpdatePackage pkg) { - downloadAndInstall(pkg); - } - - public static void update() { - // 检查是否调用过 checkUpdate - if (Updater.pkgs == null) { - return; - } - - downloadAndInstall(pkgs); - } - - private static void downloadAndInstall(final UpdatePackage pkg) { - downloader.download(pkg.getName(), pkg.getDownloadUrl(), - new Downloader.Callback() { - @Override - public void complete(String name, File installer) { - pkg.install(installer); - } - }); - } - - private static void downloadAndInstall(List pkgs) { - for (UpdatePackage pkg : pkgs) { - downloadAndInstall(pkg); - } - } - - public static Context getContext() { - return context; - } - - public interface CheckUpdateCallback { - void hasUpdate(List pkgs); - - void noneUpdate(); - - void error(Throwable e); - } -} +package com.quseit.common.updater; + + +import android.app.Application; +import android.content.Context; + +import com.quseit.common.updater.convertor.Convertor; +import com.quseit.common.updater.downloader.DefaultDownloader; +import com.quseit.common.updater.downloader.Downloader; +import com.quseit.common.updater.service.DefaultService; +import com.quseit.common.updater.service.Service; +import com.quseit.common.updater.updatepkg.UpdatePackage; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +import rx.Observable; +import rx.Subscriber; +import rx.android.schedulers.AndroidSchedulers; +import rx.functions.Action1; +import rx.functions.Func1; +import rx.schedulers.Schedulers; + +public class Updater { + public static final String TAG = "Updater"; + private static List pkgs; + + private static Service service; + private static Convertor convertor; + private static Downloader downloader; + + private static String url; + private static Context context; + + public static synchronized void init(Application app, String url, Convertor convertor) { + Updater.context = app.getApplicationContext(); + Updater.url = url; + Updater.convertor = convertor; + + Updater.service = new DefaultService(); + Updater.downloader = new DefaultDownloader(app.getApplicationContext()); + } + + // download service + public static void downloadAs(String file, String url, String savePath) { + Updater.downloader.download(file, url, savePath, new Downloader.Callback() { + @Override + public void pending(String name) { + + } + + @Override + public void complete(String name, File installer) { + } + + @Override + public void error(String err) { + + } + }); + } + // update servivce + public static void checkUpdate(final CheckUpdateCallback callback) { + Observable + .create(new Observable.OnSubscribe() { + @Override + public void call(Subscriber subscriber) { + try { + String response = service.request(url); + subscriber.onNext(response); + } catch (IOException e) { + subscriber.onError(e); + } finally { + subscriber.onCompleted(); + } + } + }) + .subscribeOn(Schedulers.io()) + .observeOn(Schedulers.computation()) + .map(new Func1>() { + @Override + public List call(String response) { + return convertor.transform(response); + } + }) + .flatMap(new Func1, Observable>() { + @Override + public Observable call(List updatePkgs) { + return Observable.from(updatePkgs); + } + }) + .filter(new Func1() { + @Override + public Boolean call(UpdatePackage updatePackage) { + return updatePackage.checkVersion(); + } + }) + .toList() + .doOnNext(new Action1>() { + @Override + public void call(List pkgs) { + // 保存最新的获取的更新包 + Updater.pkgs = pkgs; + } + }) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + new Action1>() { + @Override + public void call(List updatePackages) { + if (!updatePackages.isEmpty()) { + callback.hasUpdate(updatePackages); + } else { + callback.noneUpdate(); + } + } + }, + new Action1() { + @Override + public void call(Throwable throwable) { + throwable.printStackTrace(); + callback.error(throwable); + } + }); + } + + public static void update(UpdatePackage pkg) { + downloadAndInstall(pkg); + } + + public static void update() { + // 检查是否调用过 checkUpdate + if (Updater.pkgs == null) { + return; + } + + downloadAndInstall(pkgs); + } + + private static void downloadAndInstall(final UpdatePackage pkg) { + downloader.download(pkg.getName(), pkg.getDownloadUrl(), + new Downloader.Callback() { + @Override + public void pending(String name) { + + } + + @Override + public void complete(String name, File installer) { + pkg.install(installer); + } + + @Override + public void error(String err) { + + } + }); + } + + private static void downloadAndInstall(List pkgs) { + for (UpdatePackage pkg : pkgs) { + downloadAndInstall(pkg); + } + } + + public static Context getContext() { + return context; + } + + public interface CheckUpdateCallback { + void hasUpdate(List pkgs); + + void noneUpdate(); + + void error(Throwable e); + } +} diff --git a/qpypluginman/src/main/java/com/quseit/common/updater/callback/DialogCallback.java b/qpypluginman/src/main/java/com/quseit/common/updater/callback/DialogCallback.java index a13454cb..53f7b155 100644 --- a/qpypluginman/src/main/java/com/quseit/common/updater/callback/DialogCallback.java +++ b/qpypluginman/src/main/java/com/quseit/common/updater/callback/DialogCallback.java @@ -1,138 +1,138 @@ -package com.quseit.common.updater.callback; - -import android.app.AlertDialog; -import android.app.Dialog; -import android.content.DialogInterface; -import android.os.Bundle; -import android.support.v4.app.DialogFragment; -import android.support.v4.app.FragmentActivity; -import android.widget.Toast; - -import com.quseit.common.updater.R; -import com.quseit.common.updater.Updater; -import com.quseit.common.updater.updatepkg.UpdatePackage; - -import java.util.List; - -public class DialogCallback implements Updater.CheckUpdateCallback { - private FragmentActivity mActivity; - private boolean mIsSilence; - - public DialogCallback(FragmentActivity activity, boolean isSilence) { - mActivity = activity; - mIsSilence = isSilence; - } - - @Override - public void hasUpdate(List pkgs) { - StringBuilder description = new StringBuilder(); - for (UpdatePackage pkg : pkgs) { - description - .append(pkg.getName()) - .append(":") - .append("\n") - .append(pkg.getVersionDescription()) - .append("\n\n"); - } - description.delete(description.length() - 2, description.length()); - - DialogFragment dialog = SimpleReminderDialogFragment.newInstance(description.toString()); - try { - dialog.show(mActivity.getSupportFragmentManager(), SimpleReminderDialogFragment.TAG); - } catch (Exception e) { - // mActivity 不可用时忽略 - } - } - - @Override - public void noneUpdate() { - try { - if (!mIsSilence) { - Toast.makeText(mActivity, R.string.latest_version, Toast.LENGTH_SHORT).show(); - } - } catch (Exception e) { - // mActivity 不可用时忽略 - } - } - - @Override - public void error(Throwable e) { - try { - if (!mIsSilence) { - Toast.makeText(mActivity, R.string.check_update_error, Toast.LENGTH_SHORT).show(); - } - } catch (Exception e1) { - // mActivity 不可用时忽略 - } - } - - public static class SimpleReminderDialogFragment extends DialogFragment { - public static final String TAG = "SimpleReminderDialogFragment"; - private static final String DESCRIPTION = "description"; - - public static SimpleReminderDialogFragment newInstance(String description) { - Bundle args = new Bundle(); - args.putString(DESCRIPTION, description); - SimpleReminderDialogFragment fragment = new SimpleReminderDialogFragment(); - fragment.setArguments(args); - return fragment; - } - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - return new AlertDialog.Builder(getActivity()) - .setTitle(R.string.has_update) - .setPositiveButton(R.string.update, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - Updater.update(); - dismiss(); - } - }) - .setNegativeButton(R.string.show_detail, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - String description = getArguments().getString(DESCRIPTION); - DialogFragment dialog = DetailReminderDialogFragment.newInstance(description); - dialog.show(getFragmentManager(), DetailReminderDialogFragment.TAG); - dismiss(); - } - }) - .create(); - } - } - - public static class DetailReminderDialogFragment extends DialogFragment { - public static final String TAG = "DetailReminderDialogFragment"; - private static final String DESCRIPTION = "description"; - - public static DetailReminderDialogFragment newInstance(String description) { - Bundle args = new Bundle(); - args.putString(DESCRIPTION, description); - DetailReminderDialogFragment fragment = new DetailReminderDialogFragment(); - fragment.setArguments(args); - return fragment; - } - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - return new AlertDialog.Builder(getActivity()) - .setTitle(R.string.has_update) - .setMessage(getArguments().getString(DESCRIPTION)) - .setPositiveButton(R.string.update, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - Updater.update(); - dismiss(); - } - }) - .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - dismiss(); - } - }) - .create(); - } - } -} +package com.quseit.common.updater.callback; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.DialogInterface; +import android.os.Bundle; +import android.support.v4.app.DialogFragment; +import android.support.v4.app.FragmentActivity; +import android.widget.Toast; + +import com.quseit.common.updater.R; +import com.quseit.common.updater.Updater; +import com.quseit.common.updater.updatepkg.UpdatePackage; + +import java.util.List; + +public class DialogCallback implements Updater.CheckUpdateCallback { + private FragmentActivity mActivity; + private boolean mIsSilence; + + public DialogCallback(FragmentActivity activity, boolean isSilence) { + mActivity = activity; + mIsSilence = isSilence; + } + + @Override + public void hasUpdate(List pkgs) { + StringBuilder description = new StringBuilder(); + for (UpdatePackage pkg : pkgs) { + description + .append(pkg.getName()) + .append(":") + .append("\n") + .append(pkg.getVersionDescription()) + .append("\n\n"); + } + description.delete(description.length() - 2, description.length()); + + DialogFragment dialog = SimpleReminderDialogFragment.newInstance(description.toString()); + try { + dialog.show(mActivity.getSupportFragmentManager(), SimpleReminderDialogFragment.TAG); + } catch (Exception e) { + // mActivity 不可用时忽略 + } + } + + @Override + public void noneUpdate() { + try { + if (!mIsSilence) { + Toast.makeText(mActivity, R.string.latest_version, Toast.LENGTH_SHORT).show(); + } + } catch (Exception e) { + // mActivity 不可用时忽略 + } + } + + @Override + public void error(Throwable e) { + try { + if (!mIsSilence) { + Toast.makeText(mActivity, R.string.check_update_error, Toast.LENGTH_SHORT).show(); + } + } catch (Exception e1) { + // mActivity 不可用时忽略 + } + } + + public static class SimpleReminderDialogFragment extends DialogFragment { + public static final String TAG = "SimpleReminderDialogFragment"; + private static final String DESCRIPTION = "description"; + + public static SimpleReminderDialogFragment newInstance(String description) { + Bundle args = new Bundle(); + args.putString(DESCRIPTION, description); + SimpleReminderDialogFragment fragment = new SimpleReminderDialogFragment(); + fragment.setArguments(args); + return fragment; + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + return new AlertDialog.Builder(getActivity()) + .setTitle(R.string.has_update) + .setPositiveButton(R.string.update, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + Updater.update(); + dismiss(); + } + }) + .setNegativeButton(R.string.show_detail, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + String description = getArguments().getString(DESCRIPTION); + DialogFragment dialog = DetailReminderDialogFragment.newInstance(description); + dialog.show(getFragmentManager(), DetailReminderDialogFragment.TAG); + dismiss(); + } + }) + .create(); + } + } + + public static class DetailReminderDialogFragment extends DialogFragment { + public static final String TAG = "DetailReminderDialogFragment"; + private static final String DESCRIPTION = "description"; + + public static DetailReminderDialogFragment newInstance(String description) { + Bundle args = new Bundle(); + args.putString(DESCRIPTION, description); + DetailReminderDialogFragment fragment = new DetailReminderDialogFragment(); + fragment.setArguments(args); + return fragment; + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + return new AlertDialog.Builder(getActivity()) + .setTitle(R.string.has_update) + .setMessage(getArguments().getString(DESCRIPTION)) + .setPositiveButton(R.string.update, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + Updater.update(); + dismiss(); + } + }) + .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + dismiss(); + } + }) + .create(); + } + } +} diff --git a/qpypluginman/src/main/java/com/quseit/common/updater/convertor/Convertor.java b/qpypluginman/src/main/java/com/quseit/common/updater/convertor/Convertor.java index 9bdda98c..972d93da 100644 --- a/qpypluginman/src/main/java/com/quseit/common/updater/convertor/Convertor.java +++ b/qpypluginman/src/main/java/com/quseit/common/updater/convertor/Convertor.java @@ -1,10 +1,10 @@ -package com.quseit.common.updater.convertor; - - -import com.quseit.common.updater.updatepkg.UpdatePackage; - -import java.util.List; - -public interface Convertor { - List transform(String response); -} +package com.quseit.common.updater.convertor; + + +import com.quseit.common.updater.updatepkg.UpdatePackage; + +import java.util.List; + +public interface Convertor { + List transform(String response); +} diff --git a/qpypluginman/src/main/java/com/quseit/common/updater/downloader/DefaultDownloader.java b/qpypluginman/src/main/java/com/quseit/common/updater/downloader/DefaultDownloader.java index adb67fbc..3cd3182e 100644 --- a/qpypluginman/src/main/java/com/quseit/common/updater/downloader/DefaultDownloader.java +++ b/qpypluginman/src/main/java/com/quseit/common/updater/downloader/DefaultDownloader.java @@ -1,80 +1,104 @@ -package com.quseit.common.updater.downloader; - -import android.app.Notification; -import android.app.NotificationManager; -import android.content.Context; -import android.os.Environment; -import android.support.v4.app.NotificationCompat; - -import com.liulishuo.filedownloader.BaseDownloadTask; -import com.liulishuo.filedownloader.FileDownloadListener; -import com.liulishuo.filedownloader.FileDownloader; -import com.quseit.common.updater.R; - -import java.io.File; - -import static android.os.Environment.getExternalStoragePublicDirectory; - -public class DefaultDownloader implements Downloader { - public static final String TAG = "DefaultDownloader"; - public final String DEFAULT_PATH; - private final Context context; - private final NotificationManager notificationManager; - - - public DefaultDownloader(Context context) { - this.context = context; - FileDownloader.init(context); - notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); - DEFAULT_PATH = getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath(); - } - - @Override - public void download(final String name, String url, final Callback callback) { - String path = DEFAULT_PATH + "/" + name; - FileDownloader.getImpl() - .create(url) - .setPath(path, false) - .setCallbackProgressTimes(300) - .setListener(new FileDownloadListener() { - @Override - protected void pending(BaseDownloadTask task, int soFarBytes, int totalBytes) { - - } - - @Override - protected void progress(BaseDownloadTask task, int soFarBytes, int totalBytes) { - Notification notification = new NotificationCompat.Builder(context) - .setSmallIcon(R.drawable.ic_cloud_download_black_24dp) - .setContentTitle(context.getText(R.string.downloading)) - .setContentText(name) - .setProgress(totalBytes, soFarBytes, false) - .build(); - notificationManager.notify(name.hashCode(), notification); - } - - @Override - protected void completed(BaseDownloadTask task) { - notificationManager.cancel(name.hashCode()); - File file = new File(task.getTargetFilePath()); - callback.complete(name, file); - } - - @Override - protected void paused(BaseDownloadTask task, int soFarBytes, int totalBytes) { - - } - - @Override - protected void error(BaseDownloadTask task, Throwable e) { - - } - - @Override - protected void warn(BaseDownloadTask task) { - - } - }) - .start(); - } +package com.quseit.common.updater.downloader; + +import android.app.Notification; +import android.app.NotificationManager; +import android.content.Context; +import android.os.Environment; +import android.support.v4.app.NotificationCompat; +import android.util.Log; + +import com.liulishuo.filedownloader.BaseDownloadTask; +import com.liulishuo.filedownloader.FileDownloadListener; +import com.liulishuo.filedownloader.FileDownloader; +import com.quseit.common.updater.R; + +import java.io.File; + +import static android.os.Environment.getExternalStoragePublicDirectory; + +public class DefaultDownloader implements Downloader { + public static final String TAG = "DefaultDownloader"; + public final String DEFAULT_PATH; + private final Context context; + private final NotificationManager notificationManager; + + public DefaultDownloader(Context context) { + this.context = context; + FileDownloader.init(context); + notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + DEFAULT_PATH = getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath(); + } + + @Override + public void download(final String name, String url, final Callback callback) { + String path = DEFAULT_PATH + "/" + name; + download(name, url, path, callback); + } + + @Override + public void download(final String name, String url, final String path, final Callback callback) { + Log.d(TAG, "download:"+name+":"+url+"["+path+"]"); + FileDownloader.getImpl() + .create(url) + .setPath(path, false) + .setCallbackProgressTimes(2000) + .setListener(new FileDownloadListener() { + @Override + protected void pending(BaseDownloadTask task, int soFarBytes, int totalBytes) { + Log.d(TAG, "download:pending:"); + callback.pending(name); + } + + @Override + protected void progress(BaseDownloadTask task, int soFarBytes, int totalBytes) { + Log.d(TAG, "download:progress:"); + + Notification notification = new NotificationCompat.Builder(context) + .setSmallIcon(R.drawable.ic_cloud_download_black_24dp) + .setContentTitle(context.getText(R.string.downloading)) + .setContentText(name) + .setProgress(totalBytes, soFarBytes, false) + .build(); + notificationManager.notify(name.hashCode(), notification); + } + + @Override + protected void completed(BaseDownloadTask task) { + Log.d(TAG, "download:completed:"); + + //notificationManager.cancel(name.hashCode()); + Notification notification = new NotificationCompat.Builder(context) + .setSmallIcon(R.drawable.ic_cloud_download_black_24dp) + .setContentTitle(context.getText(R.string.downloaded)) + .setContentText(name) + .setProgress(100, 100, false) + .build(); + + notificationManager.notify(name.hashCode(),notification); + File file = new File(task.getTargetFilePath()); + callback.complete(name, file); + } + + @Override + protected void paused(BaseDownloadTask task, int soFarBytes, int totalBytes) { + Log.d(TAG, "download:paused:"); + + } + + @Override + protected void error(BaseDownloadTask task, Throwable e) { + Log.d(TAG, "download:error:"+e.getLocalizedMessage()); + callback.error(e.getLocalizedMessage()); + + } + + @Override + protected void warn(BaseDownloadTask task) { + Log.d(TAG, "download:warn:"); + + } + }) + .start(); + + } } \ No newline at end of file diff --git a/qpypluginman/src/main/java/com/quseit/common/updater/downloader/Downloader.java b/qpypluginman/src/main/java/com/quseit/common/updater/downloader/Downloader.java index 0d863326..260db300 100644 --- a/qpypluginman/src/main/java/com/quseit/common/updater/downloader/Downloader.java +++ b/qpypluginman/src/main/java/com/quseit/common/updater/downloader/Downloader.java @@ -1,11 +1,15 @@ -package com.quseit.common.updater.downloader; - -import java.io.File; - -public interface Downloader { - void download(String name, String url, Callback callback); - - interface Callback { - void complete(String name, File installer); - } -} +package com.quseit.common.updater.downloader; + +import java.io.File; + +public interface Downloader { + void download(String name, String url, Callback callback); + + void download(String name, String url, String savePath, Callback callback); + + interface Callback { + void pending(String name); + void complete(String name, File installer); + void error(String err); + } +} diff --git a/qpypluginman/src/main/java/com/quseit/common/updater/service/DefaultService.java b/qpypluginman/src/main/java/com/quseit/common/updater/service/DefaultService.java index 48cab3b4..3fde70af 100644 --- a/qpypluginman/src/main/java/com/quseit/common/updater/service/DefaultService.java +++ b/qpypluginman/src/main/java/com/quseit/common/updater/service/DefaultService.java @@ -1,22 +1,22 @@ -package com.quseit.common.updater.service; - -import java.io.IOException; - -import okhttp3.OkHttpClient; -import okhttp3.Request; - -public class DefaultService implements Service { - private final OkHttpClient client; - - public DefaultService() { - client = new OkHttpClient(); - } - - @Override - public String request(String url) throws IOException { - Request request = new Request.Builder() - .url(url) - .build(); - return client.newCall(request).execute().body().string(); - } -} +package com.quseit.common.updater.service; + +import java.io.IOException; + +import okhttp3.OkHttpClient; +import okhttp3.Request; + +public class DefaultService implements Service { + private final OkHttpClient client; + + public DefaultService() { + client = new OkHttpClient(); + } + + @Override + public String request(String url) throws IOException { + Request request = new Request.Builder() + .url(url) + .build(); + return client.newCall(request).execute().body().string(); + } +} diff --git a/qpypluginman/src/main/java/com/quseit/common/updater/service/Service.java b/qpypluginman/src/main/java/com/quseit/common/updater/service/Service.java index 39e6ba85..6690791c 100644 --- a/qpypluginman/src/main/java/com/quseit/common/updater/service/Service.java +++ b/qpypluginman/src/main/java/com/quseit/common/updater/service/Service.java @@ -1,7 +1,7 @@ -package com.quseit.common.updater.service; - -import java.io.IOException; - -public interface Service { - String request(String url) throws IOException; -} +package com.quseit.common.updater.service; + +import java.io.IOException; + +public interface Service { + String request(String url) throws IOException; +} diff --git a/qpypluginman/src/main/java/com/quseit/common/updater/updatepkg/Apk.java b/qpypluginman/src/main/java/com/quseit/common/updater/updatepkg/Apk.java index 7a9d47cc..55c3a465 100644 --- a/qpypluginman/src/main/java/com/quseit/common/updater/updatepkg/Apk.java +++ b/qpypluginman/src/main/java/com/quseit/common/updater/updatepkg/Apk.java @@ -1,70 +1,70 @@ -package com.quseit.common.updater.updatepkg; - -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.net.Uri; - -import com.quseit.common.updater.Updater; - -import java.io.File; - -public class Apk implements UpdatePackage { - private String name; - private String version; - private int versionCode; - private String description; - private String url; - - public Apk(String name, String version, int versionCode, String description, String url) { - this.name = name; - this.version = version; - this.versionCode = versionCode; - this.description = description; - this.url = url; - } - - @Override - public String getName() { - return this.name; - } - - @Override - public String getVersion() { - return String.valueOf(this.version); - } - - public String getVersionDescription() { - return this.description; - } - - @Override - public String getDownloadUrl() { - return this.url; - } - - @Override - public boolean checkVersion() { - Context context = Updater.getContext(); - PackageManager packageManager = context.getPackageManager(); - PackageInfo packageInfo = null; - try { - packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0); - - } catch (PackageManager.NameNotFoundException e) { - e.printStackTrace(); - } - int localVersion = packageInfo.versionCode; - return this.versionCode > localVersion; - } - - @Override - public void install(File installFile) { - Uri uri = Uri.fromFile(installFile); - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setDataAndType(uri, "application/vnd.android.package-archive"); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - Updater.getContext().startActivity(intent); - } -} +package com.quseit.common.updater.updatepkg; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.net.Uri; + +import com.quseit.common.updater.Updater; + +import java.io.File; + +public class Apk implements UpdatePackage { + private String name; + private String version; + private int versionCode; + private String description; + private String url; + + public Apk(String name, String version, int versionCode, String description, String url) { + this.name = name; + this.version = version; + this.versionCode = versionCode; + this.description = description; + this.url = url; + } + + @Override + public String getName() { + return this.name; + } + + @Override + public String getVersion() { + return String.valueOf(this.version); + } + + public String getVersionDescription() { + return this.description; + } + + @Override + public String getDownloadUrl() { + return this.url; + } + + @Override + public boolean checkVersion() { + Context context = Updater.getContext(); + PackageManager packageManager = context.getPackageManager(); + PackageInfo packageInfo = null; + try { + packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0); + + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } + int localVersion = packageInfo.versionCode; + return this.versionCode > localVersion; + } + + @Override + public void install(File installFile) { + Uri uri = Uri.fromFile(installFile); + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setDataAndType(uri, "application/vnd.android.package-archive"); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + Updater.getContext().startActivity(intent); + } +} diff --git a/qpypluginman/src/main/java/com/quseit/common/updater/updatepkg/UpdatePackage.java b/qpypluginman/src/main/java/com/quseit/common/updater/updatepkg/UpdatePackage.java index cf5d1d49..e274e6fe 100644 --- a/qpypluginman/src/main/java/com/quseit/common/updater/updatepkg/UpdatePackage.java +++ b/qpypluginman/src/main/java/com/quseit/common/updater/updatepkg/UpdatePackage.java @@ -1,18 +1,18 @@ -package com.quseit.common.updater.updatepkg; - -import java.io.File; - -public interface UpdatePackage { - - String getName(); - - String getVersion(); - - String getVersionDescription(); - - String getDownloadUrl(); - - boolean checkVersion(); - - void install(File file); -} +package com.quseit.common.updater.updatepkg; + +import java.io.File; + +public interface UpdatePackage { + + String getName(); + + String getVersion(); + + String getVersionDescription(); + + String getDownloadUrl(); + + boolean checkVersion(); + + void install(File file); +} diff --git a/qpypluginman/src/main/res/values-zh-rCn/strings.xml b/qpypluginman/src/main/res/values-zh-rCn/strings.xml index 45c4ec6c..a2154f42 100644 --- a/qpypluginman/src/main/res/values-zh-rCn/strings.xml +++ b/qpypluginman/src/main/res/values-zh-rCn/strings.xml @@ -1,11 +1,11 @@ - - 检查更新失败 - 您的应用已经是最新版本 - 提示 - 应用有更新 - 更新 - 显示详情 - 取消 - 正在下载 - 下载完成 - + + 检查更新失败 + 您的应用已经是最新版本 + 应用有更新 + 更新 + 显示详情 + 取消 + 正在下载 + 下载完成 + + diff --git a/qpypluginman/src/main/res/values-zh-rTW/strings.xml b/qpypluginman/src/main/res/values-zh-rTW/strings.xml new file mode 100644 index 00000000..bc9f6cf0 --- /dev/null +++ b/qpypluginman/src/main/res/values-zh-rTW/strings.xml @@ -0,0 +1,11 @@ + + 檢查更新失敗 + 已經更新 + 提示 + 有可使用的新版本 + 更新 + 顯示詳細內容 + 取消 + 正在下載 + 已下載 + diff --git a/qpypluginman/src/main/res/values/strings.xml b/qpypluginman/src/main/res/values/strings.xml index 53689eaf..f700bcae 100644 --- a/qpypluginman/src/main/res/values/strings.xml +++ b/qpypluginman/src/main/res/values/strings.xml @@ -1,11 +1,11 @@ - - Check update fail - Already update - Hint - New version available - Update - Show detail - Cancel - Downloading - Downloaded - + + Check update fail + Already update + New version available + Update + Show detail + Cancel + Downloading + Completed + + diff --git a/qpysdk/.gitignore b/qpysdk/.gitignore deleted file mode 100644 index f0a3a345..00000000 --- a/qpysdk/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -*.iml -.gradle -build -.idea -gradle -.DS_Store diff --git a/qpysdk/README.md b/qpysdk/README.md deleted file mode 100644 index 0763f3f1..00000000 --- a/qpysdk/README.md +++ /dev/null @@ -1 +0,0 @@ -#qpysdk diff --git a/qpysdk/build.gradle b/qpysdk/build.gradle index 44c6b438..deab3e87 100644 --- a/qpysdk/build.gradle +++ b/qpysdk/build.gradle @@ -11,7 +11,7 @@ android { versionName "1.0" ndk { - abiFilters 'armeabi' + abiFilters 'armeabi-v7a',"arm64-v8a" } } buildTypes { @@ -24,12 +24,22 @@ android { ndkBuild { path 'src/main/jni/Android.mk' } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + lintOptions { + abortOnError false } } + dependencies { - //compile fileTree(dir: 'libs', include: ['*.jar']) - compile files('libs/locale_platform.jar') - compile rootProject.ext.libGuava +// api fileTree(dir: 'libs', include: ['*.jar']) +// api files('libs/locale_platform.jar') + api rootProject.ext.libGoogleGuava + api project(':qbaselib') + api project(':qpysl4a') } diff --git a/qpysdk/libs/armeabi/libpython2.7.so b/qpysdk/libs/armeabi/libpython2.7.so deleted file mode 100755 index 74238437..00000000 Binary files a/qpysdk/libs/armeabi/libpython2.7.so and /dev/null differ diff --git a/qpysdk/src/main/AndroidManifest.xml b/qpysdk/src/main/AndroidManifest.xml index f50fef40..7ec0ded8 100644 --- a/qpysdk/src/main/AndroidManifest.xml +++ b/qpysdk/src/main/AndroidManifest.xml @@ -1,11 +1,11 @@ - + + + + - + diff --git a/qpysdk/src/main/assets/QPy_WebApp b/qpysdk/src/main/assets/QPy_WebApp deleted file mode 100644 index 682d292c..00000000 --- a/qpysdk/src/main/assets/QPy_WebApp +++ /dev/null @@ -1,70 +0,0 @@ -#-*-coding:utf-8-*- -#qpy:webapp:WebAppSample -#qpy://127.0.0.1:8080/ -""" -This is a sample of WebApp - -@Author river -""" - -from bottle import Bottle, ServerAdapter -from bottle import run, debug, route, error, static_file, template, redirect - -import urllib2 -import os -import json -#### 常量定义 ######### -ASSETS = "/assets/" -ROOT = os.path.dirname(os.path.abspath(__file__)) - - -######### QPYTHON WEB SERVER ############### - -class MyWSGIRefServer(ServerAdapter): - server = None - - def run(self, handler): - from wsgiref.simple_server import make_server, WSGIRequestHandler - if self.quiet: - class QuietHandler(WSGIRequestHandler): - def log_request(*args, **kw): pass - self.options['handler_class'] = QuietHandler - self.server = make_server(self.host, self.port, handler, **self.options) - self.server.serve_forever() - - def stop(self): - #sys.stderr.close() - import threading - threading.Thread(target=self.server.shutdown).start() - #self.server.shutdown() - self.server.server_close() - print "# QWEBAPPEND" - - -######### BUILT-IN ROUTERS ############### -def __exit(): - global server - server.stop() - -def __ping(): - return "ok" - -def server_static(filepath): - return static_file(filepath, root=ROOT+'/assets') - -def home(): - return "This is a QPython's WebApp" - - -######### WEBAPP ROUTERS ############### -app = Bottle() -app.route('/', method='GET')(home) -app.route('/__exit', method=['GET','HEAD'])(__exit) -app.route('/__ping', method=['GET','HEAD'])(__ping) -app.route('/assets/:filepath', method='GET')(server_static) - -try: - server = MyWSGIRefServer(host="127.0.0.1", port="8080") - app.run(server=server,reloader=False) -except Exception,ex: - print "Exception: %s" % repr(ex) diff --git a/qpysdk/src/main/assets/html/index.html b/qpysdk/src/main/assets/html/index.html index 2283e77a..aee35474 100644 --- a/qpysdk/src/main/assets/html/index.html +++ b/qpysdk/src/main/assets/html/index.html @@ -4,7 +4,7 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/qpython/.gitignore b/qpython/.gitignore deleted file mode 100644 index 796b96d1..00000000 --- a/qpython/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build diff --git a/qpython/build.gradle b/qpython/build.gradle index d883fdbe..738e1a9e 100644 --- a/qpython/build.gradle +++ b/qpython/build.gradle @@ -1,98 +1,218 @@ -apply plugin: 'com.android.application' -//apply plugin: 'me.tatarka.retrolambda' -apply plugin: 'com.jakewharton.butterknife' -apply plugin: 'realm-android' - -android { - compileSdkVersion rootProject.ext.compileSdkVersion - buildToolsVersion rootProject.ext.buildToolsVersion - - defaultConfig { - minSdkVersion rootProject.ext.minSdkVersion - targetSdkVersion rootProject.ext.targetSdkVersion - - applicationId "org.qpython.qpy.community" - versionCode 1 - versionName "1.0" - - ndk { - abiFilters 'armeabi' - } - - multiDexEnabled true - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' - } - } - externalNativeBuild { - ndkBuild { - path '../qpython/src/main/jni/Android.mk' - } - - } - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - - dataBinding { - enabled = true - } - - sourceSets { - main { - jniLibs.srcDirs = ['libs'] - } - } -} - - -configurations { - all*.exclude group: 'commons-logging', module: 'commons-logging' -} - - -dependencies { - compile fileTree(include: ['*.jar'], dir: 'libs') - compile project(':termemulator') - compile project(':termexec') - compile project(':qpypluginman') - compile project(':qpysdk') - compile project(':qpysl4a') - - //debugCompile project(path: ':qpysl4a', configuration: 'libraryDebug') - //releaseCompile project(path: ':qpysl4a', configuration: 'libraryRelease') - - compile 'com.umeng.analytics:analytics:latest.integration' - compile 'com.jakewharton:butterknife:8.5.1' - annotationProcessor 'com.jakewharton:butterknife-compiler:8.5.1' - - compile rootProject.ext.libSupportDesign - compile rootProject.ext.libSupportV7 - compile rootProject.ext.libSupportAnnotation - compile rootProject.ext.libSupportCardView - - - compile 'de.hdodenhof:circleimageview:2.0.0' - compile 'com.thefinestartist:finestwebview:1.2.7' - compile 'me.zhanghai.android.materialprogressbar:library:1.1.4' - compile 'org.apmem.tools:layouts:1.9@aar' - compile 'com.azeesoft.lib.colorpicker:colorpicker:1.0.8@aar' - compile 'com.googlecode.juniversalchardet:juniversalchardet:1.0.3' - compile('com.github.afollestad.material-dialogs:commons:0.8.5.6') { transitive = true } - compile 'com.daimajia.numberprogressbar:library:1.2@aar' - compile rootProject.ext.libRxJava - compile rootProject.ext.libRxAndroid - - compile 'com.google.code.gson:gson:2.6.2' - compile 'org.litepal.android:core:1.3.1' - compile 'org.greenrobot:eventbus:3.0.0' - compile 'me.dm7.barcodescanner:zxing:1.9' - //compile 'com.android.support:multidex:1.0.1' - //compile 'com.squareup.okhttp3:okhttp:3.4.1' - compile 'com.loopj.android:android-async-http:1.4.9' -} \ No newline at end of file +apply plugin: 'com.android.application' +apply plugin: 'com.jakewharton.butterknife' +apply plugin: 'realm-android' + +//获取系统时间 +def releaseTime() { + return new Date().format("yyyy-MM-dd", TimeZone.getTimeZone("UTC")) +} + +android { + compileSdkVersion rootProject.ext.compileSdkVersion + buildToolsVersion rootProject.ext.buildToolsVersion + flavorDimensions "default" + defaultConfig { + minSdkVersion rootProject.ext.minSdkVersion + targetSdkVersion rootProject.ext.targetSdkVersion + versionCode 304 + versionName "3.0.0" + multiDexEnabled true + vectorDrawables.useSupportLibrary = true + + ndk { + abiFilters 'armeabi-v7a',"arm64-v8a" + + } + + sourceSets { + main { + jniLibs.srcDirs = ['libs'] + + } + } + } + + signingConfigs { + release { + keyAlias 'zuowuxuxi' + keyPassword 'myxiake1q' + storeFile file('qpython.key') + storePassword 'myxiake1q' + v1SigningEnabled true + v2SigningEnabled false + } + + debug { + storeFile file("../debug.keystore") + } + } + + buildTypes { + release { + minifyEnabled false + shrinkResources false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + + signingConfig signingConfigs.release + + //修改生成的包名 + applicationVariants.all { variant -> + variant.outputs.each { output -> + def outputFile = output.outputFile + if (outputFile != null && outputFile.name.endsWith('.apk')) { + def fileName = "qpython_os_${releaseTime()}_${variant.productFlavors[0].name}.apk" + output.outputFileName = fileName + } + } + } + } + + debug { + signingConfig signingConfigs.release + } + + } + + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + dataBinding { + enabled = true + } + lintOptions { + disable 'MissingTranslation' + abortOnError false + } + + //为了解决部分第三方库重复打包了META-INF的问题 + packagingOptions { + exclude 'META-INF/LICENSE.txt' + exclude 'META-INF/NOTICE.txt' + } + + //设置渠道 + productFlavors { + + ol { +// resValue "string", "app_name", "Qpython" + applicationId "org.qpython.qpy" + } + os { +// resValue "string", "app_name", "Qpython" + applicationId "org.qpython.qpy" + } + od { +// resValue "string", "app_name", "Qpython" + applicationId "org.qpython.qpy" + } + op { +// resValue "string", "app_name", "QpythonL" + applicationId "com.hipipal.qpyplus" + } + oh { +// resValue "string", "app_name", "QpythonL" + applicationId "com.hipipal.qpyplus" + } + + } + + repositories { + flatDir { + dirs 'libs' + } + } + + +// dexOptions { +// incremental =true +// } + +} + +configurations { + all*.exclude group: 'commons-logging', module: 'commons-logging' +} + +dependencies { + //api rootProject.ext.libButterknife + //annotationProcessor rootProject.ext.libButterknifeCompiler + + api fileTree(include: ['*.jar'], dir: 'libs') + api fileTree(include: ['*.so'], dir: 'libs') + + api project(':termemulator') + api project(':termexec') + api project(':qpypluginman') + api project(':qpysdk') + + api files('libs/markdown4j.jar') + //api files('libs/android-async-http-1.4.8.aar') + //api 'com.loopj.android:android-async-http:1.4.8' + + api('com.github.afollestad.material-dialogs:commons:0.8.5.6') { transitive = true } + + api 'me.zhanghai.android.materialprogressbar:library:1.1.4' + api 'org.apmem.tools:layouts:1.9@aar' + api 'com.azeesoft.lib.colorpicker:colorpicker:1.0.8@aar' + api 'com.googlecode.juniversalchardet:juniversalchardet:1.0.3' + api 'com.daimajia.numberprogressbar:library:1.2@aar' + api 'org.litepal.android:core:1.3.1' + api 'me.dm7.barcodescanner:zxing:1.9' + api 'com.android.support:multidex:1.0.1' + + api rootProject.ext.libOkHttp3 + api rootProject.ext.libOkHttp3Log + + api 'com.squareup.okio:okio:1.9.0' + api 'com.google.code.gson:gson:2.7' + api 'com.yanzhenjie:recyclerview-swipe:1.1.3' + + api rootProject.ext.libRxAndroid + api rootProject.ext.libRxJava + + api rootProject.ext.libSupportCardView + api rootProject.ext.libSupportPreference + + osApi rootProject.ext.firebaseCore + osApi rootProject.ext.firebaseMsg + osApi rootProject.ext.firebaseAuth + osApi rootProject.ext.firebaseDatabase + osApi rootProject.ext.googlePlayServiceAuth + + olApi rootProject.ext.firebaseCore + olApi rootProject.ext.firebaseMsg + olApi rootProject.ext.firebaseAuth + olApi rootProject.ext.firebaseDatabase + olApi rootProject.ext.googlePlayServiceAuth + + api rootProject.ext.retrofit + api rootProject.ext.retrofitCoverterGson + api rootProject.ext.retrofitAdapterRxjava + + api 'com.android.support.constraint:constraint-layout:1.0.2' + + // 微信 + opApi('com.tencent.mm.opensdk:wechat-sdk-android-with-mta:1.4.0') { + exclude group: 'com.android.support:support-v4' + } + // 友盟统计 + opApi('com.umeng.analytics:analytics:6.1.2') { + exclude group: 'com.android.support:support-v4' + } + + ohApi('com.tencent.mm.opensdk:wechat-sdk-android-with-mta:1.4.0') { + exclude group: 'com.android.support:support-v4' + } + // 友盟统计 + ohApi('com.umeng.analytics:analytics:6.1.2') { + exclude group: 'com.android.support:support-v4' + } + + + api 'com.youth.banner:banner:1.4.10' +} + +apply plugin: 'com.google.gms.google-services' \ No newline at end of file diff --git a/qpython/google-services.json b/qpython/google-services.json new file mode 100644 index 00000000..dcb69ca8 --- /dev/null +++ b/qpython/google-services.json @@ -0,0 +1,68 @@ +{ + "project_info": { + "project_number": "955258715976", + "firebase_url": "https://qpython-316a3.firebaseio.com", + "project_id": "qpython-316a3", + "storage_bucket": "qpython-316a3.appspot.com" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:955258715976:android:4fd6edc2d9a8f5a8", + "android_client_info": { + "package_name": "org.qpython.qpy" + } + }, + "oauth_client": [ + { + "client_id": "955258715976-griocs2ml4pm168gggtrrvqv8m6aftvs.apps.googleusercontent.com", + "client_type": 1, + "android_info": { + "package_name": "org.qpython.qpy", + "certificate_hash": "45fd6098019a37d98403063602f6852ca21fb867" + } + }, + { + "client_id": "955258715976-i6t5usa0tjg8favq17lsfaj885l4lilv.apps.googleusercontent.com", + "client_type": 3 + } + ], + "api_key": [ + { + "current_key": "AIzaSyB7W6_FKMJO13hQ2HKhMopGQvemjjuDv4c" + } + ], + "services": { + "analytics_service": { + "status": 1 + }, + "appinvite_service": { + "status": 2, + "other_platform_oauth_client": [ + { + "client_id": "955258715976-i6t5usa0tjg8favq17lsfaj885l4lilv.apps.googleusercontent.com", + "client_type": 3 + } + ] + }, + "ads_service": { + "status": 2 + } + } + }, + { + "client_info": { + "mobilesdk_app_id": "1:955258715976:android:4fd6edc2d9a8f5a8", + "android_client_info": { + "package_name": "com.hipipal.qpyplus" + } + }, + "api_key": [ + { + "current_key": "AIzaSyB7W6_FKMJO13hQ2HKhMopGQvemjjuDv4c" + } + ] + } + ], + "configuration_version": "1" +} \ No newline at end of file diff --git a/qpython/gradle/wrapper/gradle-wrapper.jar b/qpython/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..13372aef Binary files /dev/null and b/qpython/gradle/wrapper/gradle-wrapper.jar differ diff --git a/qpython/gradlew b/qpython/gradlew new file mode 100644 index 00000000..9d82f789 --- /dev/null +++ b/qpython/gradlew @@ -0,0 +1,160 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/qpython/gradlew.bat b/qpython/gradlew.bat new file mode 100644 index 00000000..8a0b282a --- /dev/null +++ b/qpython/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/qpython/libs/android-async-http-1.4.8.aar b/qpython/libs/android-async-http-1.4.8.aar new file mode 100644 index 00000000..41776363 Binary files /dev/null and b/qpython/libs/android-async-http-1.4.8.aar differ diff --git a/qpython/libs/armeabi/libapplication.so b/qpython/libs/armeabi/libapplication.so deleted file mode 100755 index 2c0b1cc9..00000000 Binary files a/qpython/libs/armeabi/libapplication.so and /dev/null differ diff --git a/qpython/libs/armeabi/libjpush217.so b/qpython/libs/armeabi/libjpush217.so deleted file mode 100644 index 34d56e71..00000000 Binary files a/qpython/libs/armeabi/libjpush217.so and /dev/null differ diff --git a/qpython/libs/armeabi/libpymodules.so b/qpython/libs/armeabi/libpymodules.so deleted file mode 100755 index 31d27ea0..00000000 Binary files a/qpython/libs/armeabi/libpymodules.so and /dev/null differ diff --git a/qpython/libs/armeabi/libpython2.7.so b/qpython/libs/armeabi/libpython2.7.so deleted file mode 100755 index 74238437..00000000 Binary files a/qpython/libs/armeabi/libpython2.7.so and /dev/null differ diff --git a/qpython/libs/armeabi/libsdl.so b/qpython/libs/armeabi/libsdl.so deleted file mode 100755 index 1a3e9f09..00000000 Binary files a/qpython/libs/armeabi/libsdl.so and /dev/null differ diff --git a/qpython/libs/armeabi/libsdl_image.so b/qpython/libs/armeabi/libsdl_image.so deleted file mode 100755 index 2f929d3a..00000000 Binary files a/qpython/libs/armeabi/libsdl_image.so and /dev/null differ diff --git a/qpython/libs/armeabi/libsdl_main.so b/qpython/libs/armeabi/libsdl_main.so deleted file mode 100755 index ba3f186f..00000000 Binary files a/qpython/libs/armeabi/libsdl_main.so and /dev/null differ diff --git a/qpython/libs/armeabi/libsdl_mixer.so b/qpython/libs/armeabi/libsdl_mixer.so deleted file mode 100755 index 0bafee72..00000000 Binary files a/qpython/libs/armeabi/libsdl_mixer.so and /dev/null differ diff --git a/qpython/libs/armeabi/libsdl_ttf.so b/qpython/libs/armeabi/libsdl_ttf.so deleted file mode 100755 index 1cceb593..00000000 Binary files a/qpython/libs/armeabi/libsdl_ttf.so and /dev/null differ diff --git a/qpython/libs/armeabi/libsqlite3.so b/qpython/libs/armeabi/libsqlite3.so deleted file mode 100755 index e4113195..00000000 Binary files a/qpython/libs/armeabi/libsqlite3.so and /dev/null differ diff --git a/qpython/libs/markdown4j.jar b/qpython/libs/markdown4j.jar new file mode 100644 index 00000000..65030fa0 Binary files /dev/null and b/qpython/libs/markdown4j.jar differ diff --git a/qpython/proguard-rules.pro b/qpython/proguard-rules.pro index bce53e2e..0a213a26 100644 --- a/qpython/proguard-rules.pro +++ b/qpython/proguard-rules.pro @@ -13,5 +13,233 @@ # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; +# public org.qpython.qpy.main.event.Bean #} +-keepattributes SourceFile,LineNumberTable +-renamesourcefileattribute SourceFile + +# Platform calls Class.forName on types which do not exist on Android to determine platform. +-dontnote retrofit2.Platform +# Platform used when running on Java 8 VMs. Will not be used at runtime. +-dontwarn retrofit2.Platform$Java8 +# Retain generic type information for use by reflection by converters and adapters. +-keepattributes Signature +# Retain declared checked exceptions for use by a Proxy instance. +-keepattributes Exceptions +-dontwarn rx.** +-dontwarn okio.** +-keep class org.apache.http.** { *; } +-dontwarn org.apache.http.** +-dontwarn java.lang.invoke.** +-keep class com.google.** +-dontwarn com.google.** +# EventBus 3.0 +-keep class de.greenrobot.event.** { *; } +-keep class * { + @de.greenrobot.event.* ; +} +-keepattributes *Annotation* +-keepclassmembers class ** { + @org.greenrobot.eventbus.Subscribe ; +} +-keep enum org.greenrobot.eventbus.ThreadMode { *; } + +-dontpreverify + +#-keep class * extends junit.framework.TestCase +#-keepclassmembers class * extends junit.framework.TestCase { *; } + +# android +-repackageclasses '' +-allowaccessmodification +-optimizations !code/simplification/arithmetic +# +## retrace +#-renamesourcefileattribute SourceFile +#-keepattributes SourceFile,LineNumberTable +# +#-keep public class * extends android.app.Activity +#-keep public class * extends android.app.Application +#-keep public class * extends android.app.Service +#-keep public class * extends android.content.BroadcastReceiver +#-keep public class * extends android.content.ContentProvider +# +#-keep public class * extends android.view.View { +# public (android.content.Context); +# public (android.content.Context, android.util.AttributeSet); +# public (android.content.Context, android.util.AttributeSet, int); +# public void set*(...); +#} +# +#-keepclasseswithmembers class * { +# public (android.content.Context, android.util.AttributeSet); +#} +# +#-keepclasseswithmembers class * { +# public (android.content.Context, android.util.AttributeSet, int); +#} +# +#-keepclassmembers class * extends android.content.Context { +# public void *(android.view.View); +# public void *(android.view.MenuItem); +#} +# +#-keepclassmembers class * implements android.os.Parcelable { +# static ** CREATOR; +#} +# +#-keepclassmembers class **.R$* { +# public static ; +#} +# +#-keepclassmembers class * { +# @android.webkit.JavascriptInterface ; +#} + + +# gms +-keep public class com.google.android.gms.** +-dontwarn com.google.android.gms.** + +# OkHttp +-dontwarn okio.** + +# rx +-dontwarn sun.misc.Unsafe +-keep class rx.schedulers.Schedulers { + public static ; +} +-keep class rx.schedulers.ImmediateScheduler { + public ; +} +-keep class rx.schedulers.TestScheduler { + public ; +} +-keep class rx.schedulers.Schedulers { + public static ** test(); +} +-keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* { + long producerIndex; + long consumerIndex; +} +-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef { + long producerNode; + long consumerNode; +} + + +## databinding +-keep class android.databinding.** { *; } +-keepnames class * implements java.io.Serializable +-keepclassmembers class * implements java.io.Serializable { + static final long serialVersionUID; + private static final java.io.ObjectStreamField[] serialPersistentFields; + !static !transient ; + private void writeObject(java.io.ObjectOutputStream); + private void readObject(java.io.ObjectInputStream); + java.lang.Object writeReplace(); + java.lang.Object readResolve(); +} +-keepattributes *Annotation* +-keepattributes javax.xml.bind.annotation.* +-keepattributes javax.annotation.processing.* +-keepclassmembers class * extends java.lang.Enum { *; } +-keepclasseswithmembernames class android.** +-keepclasseswithmembernames interface android.** +-libraryjars /lib/rt.jar +-libraryjars /lib/jce.jar + +##---------------Begin: proguard configuration for Gson ---------- +# Gson uses generic type information stored in a class file when working with fields. Proguard +# removes such information by default, so configure it to keep all of it. +#-keepattributes Signature + +# For using GSON @Expose annotation +#-keepattributes *Annotation* + +# Gson specific classes +-keep class sun.misc.Unsafe { *; } +#-keep class com.google.gson.stream.** { *; } + +# Application classes that will be serialized/deserialized over Gson +-keep class com.google.gson.examples.android.model.** { *; } + +# Prevent proguard from stripping interface information from TypeAdapterFactory, +# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter) +-keep class * implements com.google.gson.TypeAdapterFactory +-keep class * implements com.google.gson.JsonSerializer +-keep class * implements com.google.gson.JsonDeserializer +-keep class org.qpython.qpy.main.server.model.** {*;} +##---------------End: proguard configuration for Gson ---------- + +##---------------Begin: proguard configuration for SL4A ---------- +-keep class org.qpython.sl4a.** {*;} +##---------------End: proguard configuration for SL4A ---------- + +# leancloud +-keepattributes Signature +-dontwarn com.jcraft.jzlib.** +-keep class com.jcraft.jzlib.** { *;} + +-dontwarn sun.misc.** +-keep class sun.misc.** { *;} + +-dontwarn com.alibaba.fastjson.** +-keep class com.alibaba.fastjson.** { *;} + +-dontwarn sun.security.** +-keep class sun.security.** { *; } + +-dontwarn com.google.** +-keep class com.google.** { *;} + +-dontwarn com.avos.** +-keep class com.avos.** { *;} + +-keep public class android.net.http.SslError +-keep public class android.webkit.WebViewClient + +-dontwarn android.webkit.WebView +-dontwarn android.net.http.SslError +-dontwarn android.webkit.WebViewClient + +-dontwarn android.support.** + +-dontwarn org.apache.** +-keep class org.apache.** { *;} + +-dontwarn org.jivesoftware.smack.** +-keep class org.jivesoftware.smack.** { *;} + +-dontwarn com.loopj.** +-keep class com.loopj.** { *;} + +-dontwarn com.squareup.okhttp.** +-keep class com.squareup.okhttp.** { *;} +-keep interface com.squareup.okhttp.** { *; } + +-dontwarn okio.** + +-dontwarn org.xbill.** +-keep class org.xbill.** { *;} + +-keepattributes *Annotation* + +#wx +-keep class com.tencent.mm.sdk.** { + *; +} + +#umeng +-keepclassmembers class * { + public (org.json.JSONObject); +} + +-keep public class org.qpython.qpy.R$*{ +public static final int *; +} + +-keepclassmembers enum * { + public static **[] values(); + public static ** valueOf(java.lang.String); +} \ No newline at end of file diff --git a/qpython/release/cn/release/output.json b/qpython/release/cn/release/output.json new file mode 100644 index 00000000..47944358 --- /dev/null +++ b/qpython/release/cn/release/output.json @@ -0,0 +1 @@ +[{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":241},"path":"Qpython_2018-02-28_cn.apk","properties":{"packageId":"com.hipipal.qpyplus","split":"","minSdkVersion":"14"}}] \ No newline at end of file diff --git a/qpython/release/output.json b/qpython/release/output.json new file mode 100644 index 00000000..bd56657f --- /dev/null +++ b/qpython/release/output.json @@ -0,0 +1 @@ +[{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":229},"path":"qpython-release.apk","properties":{"packageId":"org.qpython.qpy","split":"","minSdkVersion":"14"}}] \ No newline at end of file diff --git a/qpython/src/main/AndroidManifest.xml b/qpython/src/main/AndroidManifest.xml index c3869efd..db2647f9 100644 --- a/qpython/src/main/AndroidManifest.xml +++ b/qpython/src/main/AndroidManifest.xml @@ -1,223 +1,376 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/qpython/src/main/aidl/com/android/vending/billing/IInAppBillingService.aidl b/qpython/src/main/aidl/com/android/vending/billing/IInAppBillingService.aidl new file mode 100644 index 00000000..0f2bcae3 --- /dev/null +++ b/qpython/src/main/aidl/com/android/vending/billing/IInAppBillingService.aidl @@ -0,0 +1,281 @@ +/* + * 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_SERVICE_UNAVAILABLE = 2 - The network connection is down + * 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 billing API version that 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 subscriptions) + * @return RESULT_OK(0) on success and appropriate response 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 app is using + * @param packageName the package name of the calling app + * @param type of the in-app items ("inapp" for one-time purchases + * and "subs" for subscriptions) + * @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, appropriate response codes + * on failures. + * "DETAILS_LIST" with a StringArrayList containing purchase information + * in JSON format similar to: + * '{ "productId" : "exampleSku", + * "type" : "inapp", + * "price" : "$5.00", + * "price_currency": "USD", + * "price_amount_micros": 5000000, + * "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 of the in-app item being purchased ("inapp" for one-time purchases + * and "subs" for subscriptions) + * @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, appropriate response codes + * on failures. + * "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, appropriate response + * codes on failures. + * "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 + */ + 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 of the in-app items being requested ("inapp" for one-time purchases + * and "subs" for subscriptions) + * @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, appropriate response codes + on failures. + * "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 RESULT_OK(0) if consumption succeeded, appropriate response codes on failures. + */ + int consumePurchase(int apiVersion, String packageName, String purchaseToken); + + /** + * This API is currently under development. + */ + int stub(int apiVersion, String packageName, String type); + + /** + * Returns a pending intent to launch the purchase flow for upgrading or downgrading a + * subscription. The existing owned SKU(s) should be provided along with the new SKU that + * the user is upgrading or downgrading to. + * @param apiVersion billing API version that the app is using, must be 5 or later + * @param packageName package name of the calling app + * @param oldSkus the SKU(s) that the user is upgrading or downgrading from, + * if null or empty this method will behave like {@link #getBuyIntent} + * @param newSku the SKU that the user is upgrading or downgrading to + * @param type of the item being purchased, currently must be "subs" + * @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, appropriate response codes + * on failures. + * "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, appropriate response + * codes on failures. + * "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 + */ + Bundle getBuyIntentToReplaceSkus(int apiVersion, String packageName, + in List oldSkus, String newSku, String type, String developerPayload); + + /** + * Returns a pending intent to launch the purchase flow for an in-app item. This method is + * a variant of the {@link #getBuyIntent} method and takes an additional {@code extraParams} + * parameter. This parameter is a Bundle of optional keys and values that affect the + * operation of the method. + * @param apiVersion billing API version that the app is using, must be 6 or later + * @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 of the in-app item being purchased ("inapp" for one-time purchases + * and "subs" for subscriptions) + * @param developerPayload optional argument to be sent back with the purchase information + * @extraParams a Bundle with the following optional keys: + * "skusToReplace" - List - an optional list of SKUs that the user is + * upgrading or downgrading from. + * Pass this field if the purchase is upgrading or downgrading + * existing subscriptions. + * The specified SKUs are replaced with the SKUs that the user is + * purchasing. Google Play replaces the specified SKUs at the start of + * the next billing cycle. + * "replaceSkusProration" - Boolean - whether the user should be credited for any unused + * subscription time on the SKUs they are upgrading or downgrading. + * If you set this field to true, Google Play swaps out the old SKUs + * and credits the user with the unused value of their subscription + * time on a pro-rated basis. + * Google Play applies this credit to the new subscription, and does + * not begin billing the user for the new subscription until after + * the credit is used up. + * If you set this field to false, the user does not receive credit for + * any unused subscription time and the recurrence date does not + * change. + * Default value is true. Ignored if you do not pass skusToReplace. + * "accountId" - String - an optional obfuscated string that is uniquely + * associated with the user's account in your app. + * If you pass this value, Google Play can use it to detect irregular + * activity, such as many devices making purchases on the same + * account in a short period of time. + * Do not use the developer ID or the user's Google ID for this field. + * In addition, this field should not contain the user's ID in + * cleartext. + * We recommend that you use a one-way hash to generate a string from + * the user's ID, and store the hashed string in this field. + * "vr" - Boolean - an optional flag indicating whether the returned intent + * should start a VR purchase flow. The apiVersion must also be 7 or + * later to use this flag. + */ + Bundle getBuyIntentExtraParams(int apiVersion, String packageName, String sku, + String type, String developerPayload, in Bundle extraParams); + + /** + * Returns the most recent purchase made by the user for each SKU, even if that purchase is + * expired, canceled, or consumed. + * @param apiVersion billing API version that the app is using, must be 6 or later + * @param packageName package name of the calling app + * @param type of the in-app items being requested ("inapp" for one-time purchases + * and "subs" for subscriptions) + * @param continuationToken to be set as null for the first call, if the number of owned + * skus is too large, 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. + * @param extraParams a Bundle with extra params that would be appended into http request + * query string. Not used at this moment. Reserved for future functionality. + * @return Bundle containing the following key-value pairs + * "RESPONSE_CODE" with int value: RESULT_OK(0) if success, + * {@link IabHelper#BILLING_RESPONSE_RESULT_*} response codes on failures. + * + * "INAPP_PURCHASE_ITEM_LIST" - ArrayList containing the list of SKUs + * "INAPP_PURCHASE_DATA_LIST" - ArrayList containing the purchase information + * "INAPP_DATA_SIGNATURE_LIST"- ArrayList 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 getPurchaseHistory(int apiVersion, String packageName, String type, + String continuationToken, in Bundle extraParams); + + /** + * This method is a variant of {@link #isBillingSupported}} that takes an additional + * {@code extraParams} parameter. + * @param apiVersion billing API version that the app is using, must be 7 or later + * @param packageName package name of the calling app + * @param type of the in-app item being purchased ("inapp" for one-time purchases and "subs" + * for subscriptions) + * @param extraParams a Bundle with the following optional keys: + * "vr" - Boolean - an optional flag to indicate whether {link #getBuyIntentExtraParams} + * supports returning a VR purchase flow. + * @return RESULT_OK(0) on success and appropriate response code on failures. + */ + int isBillingSupportedExtraParams(int apiVersion, String packageName, String type, + in Bundle extraParams); +} diff --git a/qpython/src/main/assets/Apache_License b/qpython/src/main/assets/Apache_License new file mode 100644 index 00000000..8e911f15 --- /dev/null +++ b/qpython/src/main/assets/Apache_License @@ -0,0 +1,15 @@ +""" +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +""" \ No newline at end of file diff --git a/qpysdk/src/main/assets/QPy_ConsoleApp b/qpython/src/main/assets/QPy_ConsoleApp similarity index 90% rename from qpysdk/src/main/assets/QPy_ConsoleApp rename to qpython/src/main/assets/QPy_ConsoleApp index a56f28b6..d878d640 100644 --- a/qpysdk/src/main/assets/QPy_ConsoleApp +++ b/qpython/src/main/assets/QPy_ConsoleApp @@ -1,5 +1,4 @@ #-*-coding:utf8;-*- -#qpy:2 #qpy:console print "This is console module" diff --git a/qpython/src/main/assets/QPy_PygameApp b/qpython/src/main/assets/QPy_PygameApp new file mode 100644 index 00000000..8e6ef873 --- /dev/null +++ b/qpython/src/main/assets/QPy_PygameApp @@ -0,0 +1,24 @@ +#-*-coding:utf8;-*- +#qpy:pygame + +import sys +import pygame +from pygame.locals import * + +pygame.init() +# Resolution is ignored on Android +surface = pygame.display.set_mode((640, 480)) +# Only one built in font is available on Android +myfont = pygame.font.SysFont("DejaVuSans", 64) +label = myfont.render("Hello, QPython!", 1, (255, 255, 255)) +clock = pygame.time.Clock() + +while True: + for ev in pygame.event.get(): + if ev.type == QUIT: + pygame.quit() + # Framelimiter + clock.tick(60) + surface.fill((0, 0, 0)) + surface.blit(label, (0, 0)) + pygame.display.flip() diff --git a/qpython/src/main/assets/QPy_SL4AApp b/qpython/src/main/assets/QPy_SL4AApp new file mode 100644 index 00000000..e6b595d0 --- /dev/null +++ b/qpython/src/main/assets/QPy_SL4AApp @@ -0,0 +1,109 @@ +#qpy:quiet +#-*-coding:utf8;-*- +""" +This is a sample project which use SL4A UI Framework, +There is another Sample project: https://github.com/qpython-android/qpy-calcount +""" +import qpy +import androidhelper +try: + import urllib.request as ur +except: + import urllib as ur +from qsl4ahelper.fullscreenwrapper2 import * + +droid = androidhelper.Android() + +class MainScreen(Layout): + def __init__(self): + super(MainScreen,self).__init__(str(""" + + + + + + + + + + +