diff --git a/build.gradle b/build.gradle index 111770191003264044295948916ec5fbf66661cd..c0c6900ecbe1fa2e6b2845de6d35a7d7c0c4a95a 100644 --- a/build.gradle +++ b/build.gradle @@ -85,9 +85,9 @@ subprojects { ext { minSdkVersion = 24 - targetSdkVersion = 30 + targetSdkVersion = 33 compileSdkVersion = 34 - buildToolsVersion = '30.0.3'//30.0.3正常 + buildToolsVersion = '33.0.0'//30.0.3正常 libOkHttp3 = "com.squareup.okhttp3:okhttp:${okhttpVersion}" diff --git a/qpypluginman/build.gradle b/qpypluginman/build.gradle index 3d455a43e8c711f4e67774f815705d5a03c7cfc8..44d7c9d339c54702abfe816266ab851797a4d388 100644 --- a/qpypluginman/build.gradle +++ b/qpypluginman/build.gradle @@ -6,8 +6,6 @@ android { defaultConfig { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 1 - versionName "1.0" } buildTypes { release { @@ -18,6 +16,10 @@ android { lintOptions { abortOnError false } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_7 + targetCompatibility JavaVersion.VERSION_1_7 + } } dependencies { diff --git a/qpysdk/build.gradle b/qpysdk/build.gradle index a69a9615bace73eabe7c96f14732a099b90a3cbb..0c1ec3a6e481132d2044808372f0742dded1d80e 100644 --- a/qpysdk/build.gradle +++ b/qpysdk/build.gradle @@ -7,8 +7,6 @@ android { defaultConfig { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 1 - versionName "1.0" ndk { abiFilters "arm64-v8a"//,'armeabi-v7a' diff --git a/qpysdk/src/main/java/com/android/vending/billing/IInAppBillingService.aidl b/qpysdk/src/main/java/com/android/vending/billing/IInAppBillingService.aidl deleted file mode 100644 index 2a492f784545221cab9710ccd85350057a9a228c..0000000000000000000000000000000000000000 --- a/qpysdk/src/main/java/com/android/vending/billing/IInAppBillingService.aidl +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.vending.billing; - -import android.os.Bundle; - -/** - * InAppBillingService is the service that provides in-app billing version 3 and beyond. - * This service provides the following features: - * 1. Provides a new API to get details of in-app items published for the app including - * price, type, title and description. - * 2. The purchase flow is synchronous and purchase information is available immediately - * after it completes. - * 3. Purchase information of in-app purchases is maintained within the Google Play system - * till the purchase is consumed. - * 4. An API to consume a purchase of an inapp item. All purchases of one-time - * in-app items are consumable and thereafter can be purchased again. - * 5. An API to get current purchases of the user immediately. This will not contain any - * consumed purchases. - * - * All calls will give a response code with the following possible values - * RESULT_OK = 0 - success - * RESULT_USER_CANCELED = 1 - user pressed back or canceled a dialog - * RESULT_BILLING_UNAVAILABLE = 3 - this billing API version is not supported for the type requested - * RESULT_ITEM_UNAVAILABLE = 4 - requested SKU is not available for purchase - * RESULT_DEVELOPER_ERROR = 5 - invalid arguments provided to the API - * RESULT_ERROR = 6 - Fatal error during the API action - * RESULT_ITEM_ALREADY_OWNED = 7 - Failure to purchase since item is already owned - * RESULT_ITEM_NOT_OWNED = 8 - Failure to consume since item is not owned - */ -interface IInAppBillingService { - /** - * Checks support for the requested billing API version, package and in-app type. - * Minimum API version supported by this interface is 3. - * @param apiVersion the billing version which the app is using - * @param packageName the package name of the calling app - * @param type type of the in-app item being purchased "inapp" for one-time purchases - * and "subs" for subscription. - * @return RESULT_OK(0) on success, corresponding result code on failures - */ - int isBillingSupported(int apiVersion, String packageName, String type); - - /** - * Provides details of a list of SKUs - * Given a list of SKUs of a valid type in the skusBundle, this returns a bundle - * with a list JSON strings containing the productId, price, title and description. - * This API can be called with a maximum of 20 SKUs. - * @param apiVersion billing API version that the Third-party is using - * @param packageName the package name of the calling app - * @param skusBundle bundle containing a StringArrayList of SKUs with key "ITEM_ID_LIST" - * @return Bundle containing the following key-value pairs - * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on - * failure as listed above. - * "DETAILS_LIST" with a StringArrayList containing purchase information - * in JSON format similar to: - * '{ "productId" : "exampleSku", "type" : "inapp", "price" : "$5.00", - * "title : "Example Title", "description" : "This is an example description" }' - */ - Bundle getSkuDetails(int apiVersion, String packageName, String type, in Bundle skusBundle); - - /** - * Returns a pending intent to launch the purchase flow for an in-app item by providing a SKU, - * the type, a unique purchase token and an optional developer payload. - * @param apiVersion billing API version that the app is using - * @param packageName package name of the calling app - * @param sku the SKU of the in-app item as published in the developer console - * @param type the type of the in-app item ("inapp" for one-time purchases - * and "subs" for subscription). - * @param developerPayload optional argument to be sent back with the purchase information - * @return Bundle containing the following key-value pairs - * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on - * failure as listed above. - * "BUY_INTENT" - PendingIntent to start the purchase flow - * - * The Pending intent should be launched with startIntentSenderForResult. When purchase flow - * has completed, the onActivityResult() will give a resultCode of OK or CANCELED. - * If the purchase is successful, the result data will contain the following key-value pairs - * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on - * failure as listed above. - * "INAPP_PURCHASE_DATA" - String in JSON format similar to - * '{"orderId":"12999763169054705758.1371079406387615", - * "packageName":"com.example.app", - * "productId":"exampleSku", - * "purchaseTime":1345678900000, - * "purchaseToken" : "122333444455555", - * "developerPayload":"example developer payload" }' - * "INAPP_DATA_SIGNATURE" - String containing the signature of the purchase data that - * was signed with the private key of the developer - * TODO: change this to app-specific keys. - */ - Bundle getBuyIntent(int apiVersion, String packageName, String sku, String type, - String developerPayload); - - /** - * Returns the current SKUs owned by the user of the type and package name specified along with - * purchase information and a signature of the data to be validated. - * This will return all SKUs that have been purchased in V3 and managed items purchased using - * V1 and V2 that have not been consumed. - * @param apiVersion billing API version that the app is using - * @param packageName package name of the calling app - * @param type the type of the in-app items being requested - * ("inapp" for one-time purchases and "subs" for subscription). - * @param continuationToken to be set as null for the first call, if the number of owned - * skus are too many, a continuationToken is returned in the response bundle. - * This method can be called again with the continuation token to get the next set of - * owned skus. - * @return Bundle containing the following key-value pairs - * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on - * failure as listed above. - * "INAPP_PURCHASE_ITEM_LIST" - StringArrayList containing the list of SKUs - * "INAPP_PURCHASE_DATA_LIST" - StringArrayList containing the purchase information - * "INAPP_DATA_SIGNATURE_LIST"- StringArrayList containing the signatures - * of the purchase information - * "INAPP_CONTINUATION_TOKEN" - String containing a continuation token for the - * next set of in-app purchases. Only set if the - * user has more owned skus than the current list. - */ - Bundle getPurchases(int apiVersion, String packageName, String type, String continuationToken); - - /** - * Consume the last purchase of the given SKU. This will result in this item being removed - * from all subsequent responses to getPurchases() and allow re-purchase of this item. - * @param apiVersion billing API version that the app is using - * @param packageName package name of the calling app - * @param purchaseToken token in the purchase information JSON that identifies the purchase - * to be consumed - * @return 0 if consumption succeeded. Appropriate error values for failures. - */ - int consumePurchase(int apiVersion, String packageName, String purchaseToken); -} diff --git a/qpysdk/src/main/java/org/qpython/qpysdk/QPyConstants.java b/qpysdk/src/main/java/org/qpython/qpysdk/QPyConstants.java index 9e0af9b92175ca24b50c4d853817cda45852c79c..34d22d385f0e48e814ca0e40f64faf9735c21700 100644 --- a/qpysdk/src/main/java/org/qpython/qpysdk/QPyConstants.java +++ b/qpysdk/src/main/java/org/qpython/qpysdk/QPyConstants.java @@ -21,10 +21,11 @@ public interface QPyConstants extends BASE_CONF { String DFROM_RUN = ".runtime"; String PY_CACHE = ".qpyc"; - String DFROM_QPY2 = "scripts"; - String DFROM_QPY3 = "scripts3"; - String DFROM_PRJ2 = "projects"; + //String DFROM_QPY2 = "scripts"; + String DFROM_SCR3 = "scripts3"; + //String DFROM_PRJ2 = "projects"; String DFROM_PRJ3 = "projects3"; + String DFROM_NOTE = "notebooks"; String KEY_PY3_RES = "setting.py3resource.path"; String KEY_NOTEBOOK_RES = "setting.notebook3sresource.path"; diff --git a/qpysdk/src/main/java/org/qpython/qpysdk/QPySDK.java b/qpysdk/src/main/java/org/qpython/qpysdk/QPySDK.java index 887fd9f01e0d656431a43608b9a482c0efbbba91..1163b4fab7ae7ad236fd29da6fcd3686ebb17af5 100644 --- a/qpysdk/src/main/java/org/qpython/qpysdk/QPySDK.java +++ b/qpysdk/src/main/java/org/qpython/qpysdk/QPySDK.java @@ -27,6 +27,8 @@ import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; +import util.FileUtil; + /** * Created by yhc on 16/2/22. */ @@ -94,10 +96,10 @@ public class QPySDK { mArguments.add(script); String[] argumentsArray = mArguments.toArray(new String[mArguments.size()]); - final File mLog = new File(String.format("%s", com.quseit.util.FileUtils.getAbsoluteLogPath(context.getApplicationContext()))); + final File mLog = new File(String.format("%s", FileUtil.getAbsoluteLogPath(context.getApplicationContext()))); File logDir = mLog.getParentFile(); - mFd = Exec.createSubprocess(binaryPath, argumentsArray, getEnvironmentArray(f.getParentFile() + ""), com.quseit.util.FileUtils.getPath(context.getApplicationContext()) + "/", pid); + mFd = Exec.createSubprocess(binaryPath, argumentsArray, getEnvironmentArray(f.getParentFile() + ""), FileUtil.getPath(context.getApplicationContext()) + "/", pid); final AtomicInteger mPid = new AtomicInteger(PID_INIT_VALUE); mPid.set(pid[0]); @@ -147,7 +149,7 @@ public class QPySDK { environmentVariables.add("PYTHONHOME=" + filesDir); environmentVariables.add("ANDROID_PRIVATE=" + filesDir); - File externalStorage = new File(com.quseit.util.FileUtils.getPath(context.getApplicationContext()), "org.qpython.qpy"); + File externalStorage = new File(FileUtil.getPath(context.getApplicationContext()), "org.qpython.qpy"); environmentVariables.add("PYTHONPATH=" + externalStorage + "/lib/python2.7/site-packages/:" + filesDir + "/lib/python2.7/site-packages/:" @@ -348,7 +350,7 @@ public class QPySDK { try { //LogUtil.d(TAG, "chmod:"+bin.getAbsolutePath()); - FileUtils.chmod(bin, 0755); + FileUtil.chmod(bin, 0755); } catch (Exception e1) { e1.printStackTrace(); } diff --git a/qpysdk/src/main/java/org/qpython/qpysdk/utils/FileHelper.java b/qpysdk/src/main/java/org/qpython/qpysdk/utils/FileHelper.java index 90f8b721a699626de125eff3d7e9c5a690d8a742..4c94f0752e98a1f2bcb4f23efce10f418bc97515 100644 --- a/qpysdk/src/main/java/org/qpython/qpysdk/utils/FileHelper.java +++ b/qpysdk/src/main/java/org/qpython/qpysdk/utils/FileHelper.java @@ -3,11 +3,8 @@ package org.qpython.qpysdk.utils; import android.content.Context; import android.content.Intent; import android.net.Uri; -import android.os.Environment; import android.webkit.MimeTypeMap; -import com.quseit.util.FileUtils; - import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.ByteArrayOutputStream; @@ -23,6 +20,8 @@ import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; +import util.FileUtil; + /** * 对SD卡文件的管理 * @@ -229,7 +228,7 @@ public class FileHelper { public static File getBasePath(Context context, String parDir, String subdir) throws IOException { try { - File basePath = new File(FileUtils.getPath(context), + File basePath = new File(FileUtil.getPath(context), parDir); if (!basePath.exists()) { @@ -240,7 +239,7 @@ public class FileHelper { } File subPath = null; if (!subdir.equals("")) { - subPath = new File(FileUtils.getPath(context.getApplicationContext()), + subPath = new File(FileUtil.getPath(context.getApplicationContext()), parDir + "/" + subdir); if (!subPath.exists()) { if (!subPath.mkdirs()) { diff --git a/qpysdk/src/main/java/org/renpy/android/PythonSDLActivity.java b/qpysdk/src/main/java/org/renpy/android/PythonSDLActivity.java index 3381766379599c03a4bae67668639a5ce318fb63..3c34318cc78815b0340670c39c1036b3590db42c 100644 --- a/qpysdk/src/main/java/org/renpy/android/PythonSDLActivity.java +++ b/qpysdk/src/main/java/org/renpy/android/PythonSDLActivity.java @@ -1,22 +1,18 @@ package org.renpy.android; import org.libsdl.app.SDLActivity; -import org.qpython.qpysdk.QPyConstants; -import org.qpython.qpysdk.utils.FileHelper; import org.qpython.qpysdk.utils.Utils; import android.annotation.SuppressLint; import android.app.Activity; import android.content.Context; import android.content.Intent; -import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.net.Uri; import android.os.Build; import android.os.Bundle; -import android.os.Environment; import android.os.PowerManager; import android.os.Vibrator; import android.util.DisplayMetrics; @@ -28,15 +24,13 @@ import android.widget.LinearLayout; import android.widget.Toast; -import com.quseit.util.FileUtils; -import com.quseit.util.NAction; -import com.quseit.util.NUtil; - import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; +import util.FileUtil; + public class PythonSDLActivity extends SDLActivity { public final static int PY_NOTI_FLAG = 123400; @@ -274,7 +268,7 @@ public class PythonSDLActivity extends SDLActivity { nativeSetEnv("ANDROID_ARGUMENT", path.getAbsolutePath()); } else { - nativeSetEnv("ANDROID_ARGUMENT", FileUtils.getAbsolutePath(getApplicationContext())); + nativeSetEnv("ANDROID_ARGUMENT", FileUtil.getAbsolutePath(getApplicationContext())); } @@ -297,7 +291,7 @@ public class PythonSDLActivity extends SDLActivity { resourceManager = new ResourceManager(this); - File oldExternalStorage = new File(FileUtils.getPath(getApplicationContext()), getPackageName()); + File oldExternalStorage = new File(FileUtil.getPath(getApplicationContext()), getPackageName()); File externalStorage = getExternalFilesDir(null); File path; @@ -321,7 +315,7 @@ public class PythonSDLActivity extends SDLActivity { path = getFilesDir(); } - nativeSetEnv("ANDROID_LOG",FileUtils.getAbsoluteLogPath(getApplicationContext())); + nativeSetEnv("ANDROID_LOG", FileUtil.getAbsoluteLogPath(getApplicationContext())); File filesDir = getFilesDir(); //unpackData("private", getFilesDir()); @@ -329,7 +323,7 @@ public class PythonSDLActivity extends SDLActivity { nativeSetEnv("ANDROID_ARGUMENT", path.getAbsolutePath()); nativeSetEnv("ANDROID_PRIVATE", getFilesDir().getAbsolutePath()); - nativeSetEnv("ANDROID_PUBLIC", FileUtils.getAbsolutePath(getApplicationContext())); + nativeSetEnv("ANDROID_PUBLIC", FileUtil.getAbsolutePath(getApplicationContext())); nativeSetEnv("ANDROID_OLD_PUBLIC", oldExternalStorage.getAbsolutePath()); nativeSetEnv("LD_LIBRARY_PATH", ".:"+filesDir+"/lib/"+":"+filesDir+"/:"+filesDir.getParentFile()+"/lib/"); diff --git a/qpython/build.gradle b/qpython/build.gradle index 224141859ee3b60fa53e962b386597c544ea9a33..5c34d450a5c2012e10465f01287ffc5ac72adf35 100644 --- a/qpython/build.gradle +++ b/qpython/build.gradle @@ -1,11 +1,11 @@ apply plugin: 'com.android.application' apply plugin: 'com.jakewharton.butterknife' apply plugin: 'realm-android' -apply plugin: 'com.huawei.agconnect' +//apply plugin: 'com.huawei.agconnect' //获取系统时间 -def releaseTime() { - return new Date().format("yyyy-MM-dd", TimeZone.getTimeZone("UTC")) +static def releaseTime() { + return new Date().format("yyyyMMdd~HHmmss") } android { @@ -15,8 +15,8 @@ android { defaultConfig { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 325 - versionName "3.2.5" + versionCode 328 + versionName "3.2.8" multiDexEnabled true vectorDrawables.useSupportLibrary = true @@ -61,7 +61,7 @@ android { 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" + def fileName = "qpython_${variant.productFlavors[0].name}_${releaseTime()}.apk" output.outputFileName = fileName } } @@ -142,10 +142,6 @@ dependencies { api project(':qpysdk') api files('libs/markdown4j.jar') - //https://dev.mi.com/console/doc/detail?pId=41 - implementation files('libs/MiPush_SDK_Client_4_9_1.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 } @@ -157,9 +153,9 @@ dependencies { api 'org.litepal.android:core:1.3.1' api 'me.dm7.barcodescanner:zxing:1.9' api 'com.android.support:multidex:1.0.3' - implementation ('com.gyf.cactus:cactus-support:1.1.3-beta09'){ + /*implementation ('com.gyf.cactus:cactus-support:1.1.3-beta09'){ exclude group: 'com.google.guava' - } + }*/ api rootProject.ext.libOkHttp3 api rootProject.ext.libOkHttp3Log @@ -174,63 +170,19 @@ dependencies { api rootProject.ext.libSupportCardView api rootProject.ext.libSupportPreference -// odApi rootProject.ext.firebaseCore -// implementation ("com.google.firebase:firebase-messaging:17.3.4"){ -// exclude group: 'com.google.firebase', module: 'firebase-iid' -// } -// odApi rootProject.ext.firebaseIid -// odApi rootProject.ext.firebaseAuth -// odApi rootProject.ext.firebaseDatabase -// odApi rootProject.ext.googlePlayServiceAuth - -// osApi rootProject.ext.firebaseCore -// osApi rootProject.ext.firebaseMsg -// osApi rootProject.ext.firebaseAuth -// osApi rootProject.ext.firebaseDatabase -// implementation platform('com.google.firebase:firebase-bom:29.0.0') -// osApi rootProject.ext.firebaseAnalytics -// osApi rootProject.ext.firebaseMsg -// osApi rootProject.ext.googlePlayServiceAuth - -// olApi rootProject.ext.firebaseCore -// olApi rootProject.ext.firebaseMsg -// olApi rootProject.ext.firebaseAuth -// olApi rootProject.ext.firebaseDatabase -// implementation platform('com.google.firebase:firebase-bom:29.0.0') -// olApi rootProject.ext.firebaseAnalytics -// olApi rootProject.ext.firebaseMsg -// olApi rootProject.ext.googlePlayServiceAuth - api rootProject.ext.retrofit api rootProject.ext.retrofitCoverterGson api rootProject.ext.retrofitAdapterRxjava api 'com.android.support.constraint:constraint-layout:2.0.4' - // 微信 -// 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' -// } - // 友盟统计SDK implementation 'com.umeng.umsdk:common:9.6.3'// 必选 implementation 'com.umeng.umsdk:asms:1.8.0'// 必选 api 'com.youth.banner:banner:1.4.10' - implementation rootProject.ext.huaweiPush - implementation rootProject.ext.huaweiAnlytics + //implementation rootProject.ext.huaweiPush + //implementation rootProject.ext.huaweiAnlytics } //apply plugin: 'com.google.gms.google-services' diff --git a/qpython/libs/arm64-v8a/lib-qpython3-setup.so b/qpython/libs/arm64-v8a/lib-qpython3-setup.so index ebcbb3b28006817abf3923edd39c3bc3f5c3691b..6008910c79e5fb98f2f76c7cfdaade354469ec2a 100644 --- a/qpython/libs/arm64-v8a/lib-qpython3-setup.so +++ b/qpython/libs/arm64-v8a/lib-qpython3-setup.so @@ -32,7 +32,7 @@ j="$LNK $j" p7z 7za -for i in 1 2 +for i in 1 2 3 do i=$HOME/private$i.7z $j x $i -aoa -o$HOME diff --git a/qpython/src/main/AndroidManifest.xml b/qpython/src/main/AndroidManifest.xml index f43df68fc8b218718dc628d5605cedd75fab2154..f502edb9aa74db25e5fd70d2f1e2452eab464c9f 100644 --- a/qpython/src/main/AndroidManifest.xml +++ b/qpython/src/main/AndroidManifest.xml @@ -19,7 +19,7 @@ - + @@ -51,6 +51,7 @@ + + diff --git a/qpython/src/main/aidl/com/android/vending/billing/IInAppBillingService.aidl b/qpython/src/main/aidl/com/android/vending/billing/IInAppBillingService.aidl deleted file mode 100644 index 0f2bcae3382e9b6bd9f27bd8521f3f92dc121919..0000000000000000000000000000000000000000 --- a/qpython/src/main/aidl/com/android/vending/billing/IInAppBillingService.aidl +++ /dev/null @@ -1,281 +0,0 @@ -/* - * 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/resource3.mp3 b/qpython/src/main/assets/resource3.mp3 index c92e563aa64782d272c35abb240271c4fa7c93f3..a1acb126ab5b195813025fc9336d1c98f79103fa 100644 Binary files a/qpython/src/main/assets/resource3.mp3 and b/qpython/src/main/assets/resource3.mp3 differ diff --git a/qpython/src/main/java/org/qpython/qpy/console/ScriptExec.java b/qpython/src/main/java/org/qpython/qpy/console/ScriptExec.java index c8fe5ca9e64c0b474381df1a08fdcfca954257f2..f0bf279e6cc7622ddd00c3f8634c6a0ea61e7f8b 100644 --- a/qpython/src/main/java/org/qpython/qpy/console/ScriptExec.java +++ b/qpython/src/main/java/org/qpython/qpy/console/ScriptExec.java @@ -15,11 +15,12 @@ import android.support.v4.util.ArrayMap; import android.support.v7.app.AlertDialog; import android.text.TextUtils; import android.util.Log; +import android.widget.Toast; import org.qpython.qpy.main.app.App; import org.qpython.qpy.main.app.CONF; import org.qpython.qpysdk.Exec; -import com.quseit.util.FileUtils; + import com.quseit.util.NAction; import org.greenrobot.eventbus.EventBus; @@ -30,6 +31,7 @@ import org.qpython.qpy.main.utils.Utils; import org.qpython.qpysdk.utils.FileHelper; import org.qpython.qpysdk.utils.StreamGobbler; import org.qpython.qsl4a.QPyScriptService; +import org.qpython.qsl4a.qsl4a.jsonrpc.JsonRpcServer; import org.qpython.qsl4a.qsl4a.util.SPFUtils; import org.renpy.android.PythonSDLActivity; @@ -42,10 +44,14 @@ import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; import java.util.concurrent.atomic.AtomicInteger; import java.util.regex.Matcher; import java.util.regex.Pattern; +import util.FileUtil; + public class ScriptExec { private static final String TAG = "ScriptExec"; @@ -65,44 +71,56 @@ public class ScriptExec { public void playScript(Context context, String script, String arg) { // confirm the SL4A Service is started - context.startService(new Intent(context, QPyScriptService.class)); + if(JsonRpcServer.isServiceRunning()) { String header_512 = FileHelper.getFileContents(script,512); boolean isWeb = header_512.contains("#qpy:webapp"); boolean isQApp = header_512.contains("#qpy:quiet"); - boolean isKivy = header_512.contains("#qpy:kivy"); - boolean isGame = header_512.contains("#qpy:pygame"); + //boolean isKivy = header_512.contains("#qpy:kivy"); + //boolean isGame = header_512.contains("#qpy:pygame"); boolean isDaemon = header_512.contains("#qpy:daemon"); - Log.d(TAG, "playScript:" + script+"|isWeb:"+isWeb+"|isQapp:"+isQApp+"|isKivy:"+isKivy+"|isGame:"+isGame+"|isDaemon:"+isDaemon); + //Log.d(TAG, "playScript:" + script+"|isWeb:"+isWeb+"|isQapp:"+isQApp+"|isKivy:"+isKivy+"|isGame:"+isGame+"|isDaemon:"+isDaemon); if (isWeb) { playWebApp(context, script, arg); - } else if (isKivy) { - playKScript(context, script, arg); + //} else if (isKivy) { + // playKScript(context, script, arg); } else if (isQApp) { playQScript(context, script, arg); - } else if (isGame) { - playGScript(context, script, arg); + //} else if (isGame) { + // playGScript(context, script, arg); } else if (isDaemon) { playDScript(context, script, arg); } else { playCScript(context, script, arg); } + }else { + + context.startService(new Intent(context, QPyScriptService.class)); + Toast.makeText(context, R.string.sl4a_start, Toast.LENGTH_SHORT).show(); + new Timer().schedule(new TimerTask() { + @Override + public void run() { + playScript(context, script, arg); + } + },512); + + } } /* Play project Without args */ - public void playProject(Context context, String project, boolean notify) { - playProject(context, project, null, notify); + public void playProject(Context context, String project) { + playProject(context, project, null); } /* Play project with args */ - public void playProject(Context context, String project, String args, boolean notify) { + public void playProject(Context context, String project, String args) { Log.d(TAG, "playProject:" + project); String script = project + "/main.py"; @@ -125,7 +143,7 @@ public class ScriptExec { public String getLastLog() { - File logFile = new File(FileUtils.getAbsoluteLogPath(App.getContext())); + File logFile = new File(FileUtil.getAbsoluteLogPath(App.getContext())); if (!logFile.getAbsoluteFile().getParentFile().exists()) { logFile.getAbsoluteFile().getParentFile().mkdirs(); @@ -142,7 +160,7 @@ public class ScriptExec { //boolean isQPy3 = NAction.isQPy3(context); File filesDir = context.getFilesDir(); - File externalStorage = new File(FileUtils.getAbsolutePath(context)); + File externalStorage = new File(FileUtil.getAbsolutePath(context)); String[] env = new String[24]; @@ -300,7 +318,7 @@ public class ScriptExec { if (Utils.isOpenGL2supported(context)) { File scriptParent = new File(script).getParentFile(); String proj, log; - log = FileUtils.getAbsoluteLogPath(App.getContext()); + log = FileUtil.getAbsoluteLogPath(App.getContext()); if (scriptParent.getName().startsWith("scripts")) { proj = new File(script).getName(); @@ -381,9 +399,9 @@ public class ScriptExec { String[] argumentsArray = mArguments.toArray(new String[mArguments.size()]); - final File mLog = new File(FileUtils.getAbsoluteLogPath(App.getContext())); + final File mLog = new File(FileUtil.getAbsoluteLogPath(App.getContext())); - mFd = Exec.createSubprocess(binaryPath, argumentsArray, getPyEnv(context, System.getenv("PATH"), System.getenv("TERM"),f.getParentFile() + ""), FileUtils.getPath(App.getContext()) + "/", pid); + mFd = Exec.createSubprocess(binaryPath, argumentsArray, getPyEnv(context, System.getenv("PATH"), System.getenv("TERM"),f.getParentFile() + ""), FileUtil.getPath(App.getContext()) + "/", pid); final AtomicInteger mPid = new AtomicInteger(PID_INIT_VALUE); mPid.set(pid[0]); diff --git a/qpython/src/main/java/org/qpython/qpy/console/ShellTermSession.java b/qpython/src/main/java/org/qpython/qpy/console/ShellTermSession.java index 0d5ba05b36864e79b441c3da45f4ba994f5ecb42..0df7cf88076e4dbc013813224a1e82e0e0a854d8 100644 --- a/qpython/src/main/java/org/qpython/qpy/console/ShellTermSession.java +++ b/qpython/src/main/java/org/qpython/qpy/console/ShellTermSession.java @@ -23,7 +23,6 @@ import android.preference.PreferenceManager; import android.util.Log; import com.quseit.util.FileHelper; -import com.quseit.util.FileUtils; import org.qpython.qpy.R; import org.qpython.qpy.console.compont.FileCompat; @@ -35,6 +34,7 @@ import java.io.IOException; import java.util.ArrayList; import jackpal.androidterm.TermExec; +import util.FileUtil; /** * A terminal session, controlling the process attached to the session (usually @@ -121,9 +121,9 @@ public class ShellTermSession extends GenericTermSession { for (String s : env) { content.append("\nexport ").append(s); } - FileHelper.putFileContents(context, enf.getAbsolutePath(), content.toString().trim()); + FileUtil.writeToFile(enf.getAbsolutePath(), content.toString().trim()); try { - FileUtils.chmod(enf, 0755); + FileUtil.chmod(enf, 0755); } catch (Exception e) { e.printStackTrace(); diff --git a/qpython/src/main/java/org/qpython/qpy/console/TermActivity.java b/qpython/src/main/java/org/qpython/qpy/console/TermActivity.java index f548b75319825e9c51a9038bc349a8385d377d94..8e0cec8f86b2fe210db27cacc8d704e548153cc7 100644 --- a/qpython/src/main/java/org/qpython/qpy/console/TermActivity.java +++ b/qpython/src/main/java/org/qpython/qpy/console/TermActivity.java @@ -77,7 +77,9 @@ import org.qpython.qpy.main.app.App; import org.qpython.qpy.texteditor.ui.adapter.bean.PopupItemBean; import org.qpython.qpy.texteditor.ui.view.EditorPopUp; import org.qpython.qpysdk.utils.AndroidCompat; +import org.qpython.qsl4a.QPyScriptService; import org.qpython.qsl4a.qsl4a.StringUtils; +import org.qpython.qsl4a.qsl4a.jsonrpc.JsonRpcServer; import java.io.File; import java.io.IOException; @@ -86,6 +88,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Locale; +import java.util.Timer; +import java.util.TimerTask; import jackpal.androidterm.emulatorview.EmulatorView; import jackpal.androidterm.emulatorview.TermSession; @@ -260,10 +264,25 @@ public class TermActivity extends AppCompatActivity implements UpdateCallback, S context.startActivity(intent); } + private static void startActivity(Context context,Intent intent){ + if(JsonRpcServer.isServiceRunning()) { + context.startActivity(intent); + } else { + context.startService(new Intent(context, QPyScriptService.class)); + Toast.makeText(context, R.string.sl4a_start, Toast.LENGTH_SHORT).show(); + new Timer().schedule(new TimerTask() { + @Override + public void run() { + context.startActivity(intent); + } + },512); + } + } + public static void startShell(Context context,String shellType) { Intent intent = new Intent(context, TermActivity.class); intent.putExtra(TYPE,shellType); - context.startActivity(intent); + startActivity(context,intent); } protected static TermSession createTermSession(Context context, TermSettings settings, String initialCommand, String path) throws IOException { @@ -371,7 +390,7 @@ public class TermActivity extends AppCompatActivity implements UpdateCallback, S } private void openNotebook() { - startActivity(new Intent(this, NotebookActivity.class)); + startActivity(this,new Intent(this, NotebookActivity.class)); } @Override @@ -1153,7 +1172,7 @@ public class TermActivity extends AppCompatActivity implements UpdateCallback, S } private TermSession createPyTermSession(String[] mArgs) throws IOException { - Log.d("TermActivity", "createPyTermSession:" + mArgs); + //Log.d("TermActivity", "createPyTermSession:" + mArgs); TermSettings settings = mSettings; TermSession session = null; Intent intent = this.getIntent(); diff --git a/qpython/src/main/java/org/qpython/qpy/console/shortcuts/AddShortcut.java b/qpython/src/main/java/org/qpython/qpy/console/shortcuts/AddShortcut.java index 3e4cad77981c4b4e52e9e06cc1d56ca0e73e8d73..385d0fb9f8872d2946e016495f235e72eb32b5b0 100644 --- a/qpython/src/main/java/org/qpython/qpy/console/shortcuts/AddShortcut.java +++ b/qpython/src/main/java/org/qpython/qpy/console/shortcuts/AddShortcut.java @@ -6,7 +6,6 @@ import android.content.SharedPreferences; import android.graphics.Typeface; import android.net.Uri; import android.os.Bundle; -import android.os.Environment; import android.preference.PreferenceManager; import android.util.Log; import android.view.Gravity; @@ -18,8 +17,6 @@ import android.widget.LinearLayout; import android.widget.ScrollView; import android.widget.TextView; -import com.quseit.util.FileUtils; - import org.qpython.qpy.R; import org.qpython.qpy.console.RemoteInterface; @@ -33,6 +30,8 @@ import org.qpython.qpy.main.app.App; import java.io.File; import java.security.GeneralSecurityException; +import util.FileUtil; + public class AddShortcut extends android.app.Activity { private final int OP_MAKE_SHORTCUT = 1; @@ -85,7 +84,7 @@ public class AddShortcut extends android.app.Activity { btn_path.setOnClickListener(p1 -> { String lastPath = SP.getString("lastPath", null); File get = (lastPath == null) - ? FileUtils.getPath(App.getContext()) + ? FileUtil.getPath(App.getContext()) : new File(lastPath).getParentFile(); Intent pickerIntent = new Intent(); if (SP.getBoolean("useInternalScriptFinder", false)) { diff --git a/qpython/src/main/java/org/qpython/qpy/console/shortcuts/FSNavigator.java b/qpython/src/main/java/org/qpython/qpy/console/shortcuts/FSNavigator.java index a20893eacc05247a89fc613a6c14578a514e5111..9641a02c511acd414443417c7df10f1b7d3afc9a 100644 --- a/qpython/src/main/java/org/qpython/qpy/console/shortcuts/FSNavigator.java +++ b/qpython/src/main/java/org/qpython/qpy/console/shortcuts/FSNavigator.java @@ -19,8 +19,6 @@ import android.widget.ScrollView; import android.widget.TextView; import android.widget.Toast; -import com.quseit.util.FileUtils; - import org.qpython.qpy.R; import org.qpython.qpy.main.app.App; @@ -29,6 +27,8 @@ import java.io.File; import java.io.IOException; import java.util.HashMap; +import util.FileUtil; + public class FSNavigator extends android.app.Activity { private final int ACTION_THEME_SWAP = 0x00000100; @@ -60,7 +60,7 @@ public class FSNavigator extends android.app.Activity { getWindow().setSoftInputMode(android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN); Intent intent = getIntent(); - extSdCardFile = FileUtils.getPath(App.getContext()); + extSdCardFile = FileUtil.getPath(App.getContext()); extSdCard = getCanonicalPath(extSdCardFile); Uri uri = intent.getData(); String path = uri == null ? null : uri.getPath(); diff --git a/qpython/src/main/java/org/qpython/qpy/main/activity/AppListActivity.java b/qpython/src/main/java/org/qpython/qpy/main/activity/AppListActivity.java index 7cb36555e9f41572a814dbb15d8425a0fcac8132..3de7f6f29e6ee93410ae036a2406e466238a0fc5 100644 --- a/qpython/src/main/java/org/qpython/qpy/main/activity/AppListActivity.java +++ b/qpython/src/main/java/org/qpython/qpy/main/activity/AppListActivity.java @@ -10,6 +10,7 @@ import android.content.Loader; import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutManager; import android.graphics.drawable.Icon; +import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Handler; @@ -22,9 +23,7 @@ import android.widget.TextView; import android.widget.Toast; import com.quseit.util.FileHelper; -import com.quseit.util.FileUtils; import com.quseit.util.FolderUtils; -import com.quseit.util.NAction; import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.Subscribe; @@ -33,21 +32,23 @@ import org.qpython.qpy.R; import org.qpython.qpy.console.ScriptExec; import org.qpython.qpy.console.shortcuts.ShortcutReceiver; import org.qpython.qpy.main.adapter.AppListAdapter; +import org.qpython.qpy.main.app.CONF; import org.qpython.qpy.main.event.AppsLoader; import org.qpython.qpy.main.model.AppModel; import org.qpython.qpy.main.model.QPyScriptModel; +import org.qpython.qpy.texteditor.EditorActivity; import org.qpython.qpy.utils.ShortcutUtil; import org.qpython.qpysdk.QPyConstants; import org.qpython.qpysdk.utils.Utils; -import org.qpython.qsl4a.qsl4a.LogUtil; +import org.qpython.qsl4a.QPyScriptService; +import org.qpython.qsl4a.qsl4a.jsonrpc.JsonRpcServer; import java.io.File; -import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; - -import static org.qpython.qpy.R2.string.show; +import java.util.Timer; +import java.util.TimerTask; /** * Local App list @@ -114,9 +115,12 @@ public class AppListActivity extends BaseActivity implements LoaderManager.Loade String path = getIntent().getStringExtra("path"); boolean isProj = getIntent().getBooleanExtra("isProj", false); if (isProj) { - ScriptExec.getInstance().playProject(this, path, false); + ScriptExec.getInstance().playProject(this, path); } else { - ScriptExec.getInstance().playScript(this, path, null); + if(path.endsWith(".ipynb")) + AppListActivity.openNotebook(this ,path); + else + ScriptExec.getInstance().playScript(this, path, null); } finish(); } @@ -134,7 +138,12 @@ public class AppListActivity extends BaseActivity implements LoaderManager.Loade @Override public void runProject(QPyScriptModel item) { - ScriptExec.getInstance().playProject(AppListActivity.this, item.getPath(), false); + ScriptExec.getInstance().playProject(AppListActivity.this, item.getPath()); + } + + @Override + public void runNotebook(QPyScriptModel item) { + openNotebook(AppListActivity.this,item.getFile()); } @Override @@ -161,35 +170,31 @@ public class AppListActivity extends BaseActivity implements LoaderManager.Loade ((TextView) findViewById(R.id.tv_folder_name)).setText(R.string.qpy_app); findViewById(R.id.iv_back).setOnClickListener(view -> AppListActivity.this.finish()); - getScriptList(); + getProjectScriptList(); } -// private boolean checkPermission() { -// if (Build.VERSION.SDK_INT >= 23) { -// int checkPermission = ContextCompat.checkSelfPermission(this, Manifest.permission.INSTALL_SHORTCUT); -// LogUtil.e("checkPermission" + checkPermission); -// LogUtil.e("checkPermission" + PackageManager.PERMISSION_GRANTED); -// if (checkPermission != PackageManager.PERMISSION_GRANTED) { -// ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.INSTALL_SHORTCUT}, REQUEST_INSTALL_SHORTCUT); -// return false; -// } else { -// return true; -// } -// } else { -// return true; -// } -// } + public static void openNotebook(Context context,String file){ + openNotebook(context,new File(file)); + } -// @Override -// public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { -// if (requestCode == REQUEST_INSTALL_SHORTCUT) { -// if (grantResults[0] != PackageManager.PERMISSION_GRANTED) { -// Toast.makeText(this, R.string.toast_read_permission_deny, Toast.LENGTH_SHORT).show(); -// } else { -// createShortcutOnThis(); -// } -// } -// } + public static void openNotebook(Context context,File file){ + if(JsonRpcServer.isServiceRunning()) { + File qcnb = new File(context.getFilesDir(),"bin/quick_notebook.py"); + boolean notebookInstall = qcnb.exists(); + if(notebookInstall) + ScriptExec.getInstance().playQScript(context,qcnb.getAbsolutePath(),file.getAbsolutePath()); + else + EditorActivity.start(context, Uri.fromFile(file)); + } else { + context.startService(new Intent(context, QPyScriptService.class)); + Toast.makeText(context, R.string.sl4a_start, Toast.LENGTH_SHORT).show(); + new Timer().schedule(new TimerTask() { + @Override + public void run() { + openNotebook(context,file); + } + },512); + }} @RequiresApi(api = Build.VERSION_CODES.N_MR1) private void test(){ @@ -266,22 +271,49 @@ public class AppListActivity extends BaseActivity implements LoaderManager.Loade } - private void getScriptList() { - try { - String projectPath = NAction.isQPy3(this.getApplicationContext())? QPyConstants.DFROM_PRJ3:QPyConstants.DFROM_PRJ2; - File[] projectFiles = FileHelper.getABSPath(FileUtils.getAbsolutePath(getApplicationContext()) + "/" + projectPath).listFiles(); - if (projectFiles != null) { - Arrays.sort(projectFiles, FolderUtils.sortByName); - dataList.clear(); - for (File file : projectFiles) { - if (file.isDirectory()) { + private void getProjectList(File projectFile) { + File[] projectFiles = projectFile.listFiles(); + if (projectFiles != null) { + Arrays.sort(projectFiles, FolderUtils.sortByName); + for (File file : projectFiles) { + if (file.isDirectory()) { + if ((new File(file, "main.py")).exists()) dataList.add(new QPyScriptModel(file)); + else { + getProjectList(file); } } } - String scriptPath = NAction.isQPy3(this.getApplicationContext())?QPyConstants.DFROM_QPY3:QPyConstants.DFROM_QPY2; + } + } + + private void getProjectScriptList() { + String path = CONF.ABSOLUTE_PATH; + File projectFile = new File(path,QPyConstants.DFROM_PRJ3); + getProjectList(projectFile); + getScriptList(path); + getNotebookList(path); + + } + + private void getScriptList(String path) { + try { + File[] files = FileHelper.getPyFiles(new File(path + "/" + QPyConstants.DFROM_SCR3)); + if (files!=null && files.length > 0) { + Arrays.sort(files, FolderUtils.sortByName); + for (File file : files) { + dataList.add(new QPyScriptModel(file)); + } + } + adapter.notifyDataSetChanged(); + } catch (Exception e) { + e.printStackTrace(); + } + } - File[] files = FileHelper.getFilesByType(FileHelper.getABSPath(FileUtils.getAbsolutePath(getApplicationContext()) + "/" + scriptPath)); + private void getNotebookList(String path) { + try { + File[] files = FileHelper.getPyFiles(new File(path + "/notebooks")); if (files!=null && files.length > 0) { Arrays.sort(files, FolderUtils.sortByName); for (File file : files) { @@ -289,7 +321,7 @@ public class AppListActivity extends BaseActivity implements LoaderManager.Loade } } adapter.notifyDataSetChanged(); - } catch (IOException e) { + } catch (Exception e) { e.printStackTrace(); } } diff --git a/qpython/src/main/java/org/qpython/qpy/main/activity/CourseIndexFundingActivity.java b/qpython/src/main/java/org/qpython/qpy/main/activity/CourseIndexFundingActivity.java deleted file mode 100644 index 6d1b4b6ee977db49f65a5c9ce76d489936b46e2e..0000000000000000000000000000000000000000 --- a/qpython/src/main/java/org/qpython/qpy/main/activity/CourseIndexFundingActivity.java +++ /dev/null @@ -1,266 +0,0 @@ -package org.qpython.qpy.main.activity; - -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.databinding.DataBindingUtil; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.annotation.RequiresApi; -import android.support.v4.app.ActivityOptionsCompat; -import android.support.v4.util.Pair; -import android.support.v7.app.AppCompatActivity; -import android.text.TextUtils; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.widget.ArrayAdapter; - -import com.quseit.util.ImageDownLoader; -import com.quseit.util.VeDate; -import com.quseit.util.NAction; - -import org.greenrobot.eventbus.EventBus; -import org.json.JSONException; -import org.json.JSONObject; -import org.qpython.qpy.R; -import org.qpython.qpy.databinding.ActivityCourseCrowdfundingBinding; -import org.qpython.qpy.main.app.App; -import org.qpython.qpy.main.server.MySubscriber; -import org.qpython.qpy.main.server.model.CourseModel; -import org.qpython.qpy.main.server.model.PayStatusModel; -import org.qpython.qpy.main.widget.scheduleview.DotObj; -import org.qpython.qpy.utils.UpdateHelper; - -import java.util.Map; - - -public class CourseIndexFundingActivity extends AppCompatActivity { - private static final int SUPPORT_LOGIN_REQUEST_CODE = 2053; - private static final int COURSE_LOGIN_REQUEST_CODE = 2030; - - private static final String START_TO_LEARN_TYPE = "course_free"; - private static final String COMMENT_HTML = "http://edu.qpython.org/comments/%s.html?from=app"; - private static final String STATUS = "status"; - private static final String COURSE = "COURSE"; - - private ActivityCourseCrowdfundingBinding binding; - - private CourseModel course; - - @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN) - public static void start(Activity context, Pair[] pairs, CourseModel courseModel, int status) { - Intent starter = new Intent(context, CourseIndexFundingActivity.class); - starter.putExtra(COURSE, courseModel); - starter.putExtra(STATUS, status); - ActivityOptionsCompat options = ActivityOptionsCompat. - makeSceneTransitionAnimation(context, pairs); - context.startActivity(starter, options.toBundle()); - } - - public static void start(Context context, CourseModel courseModel, int status) { - Intent starter = new Intent(context, CourseIndexFundingActivity.class); - starter.putExtra(COURSE, courseModel); - starter.putExtra(STATUS, status); - context.startActivity(starter); - } - - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - binding = DataBindingUtil.setContentView(this, R.layout.activity_course_crowdfunding); - course = (CourseModel) getIntent().getSerializableExtra(COURSE); - binding.setCourse(course); - initToolbar(); - initViewContent(); - initListener(); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.comment_menu, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.menu_comment: - startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(String.format(COMMENT_HTML, course.getSmodule())))); - break; - } - return true; - } - - @Override - protected void onDestroy() { - super.onDestroy(); - } - - private void initToolbar() { - setSupportActionBar(binding.tl.toolbar); - setTitle(course.getTitle()); - binding.tl.toolbar.setNavigationIcon(R.drawable.ic_back); - binding.tl.toolbar.setNavigationOnClickListener(v -> { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - finishAfterTransition(); - } else { - finish(); - } - }); - } - - private void initViewContent() { - binding.tvLevel.setText(getString(R.string.level, course.getLevel() + "")); - binding.supportBtn.setText(binding.schedule.getVisibility() == View.VISIBLE ? R.string.support : R.string.buy_course); - ImageDownLoader.setImageFromUrl(this, binding.authorAvatar, course.getAuth_avatar()); - ImageDownLoader.setImageFromUrl(this, binding.ivTheme, course.getLogo()); - - ArrayAdapter adapter = new ArrayAdapter<>(this, R.layout.item_course_funding_index, course.getCourses()); - binding.rvIndex.setAdapter(adapter); - - if (getIntent().getIntExtra(STATUS, 0) == 0 || getIntent().getIntExtra(STATUS, 0) == 4) { - //[0,不进行众筹/1,初级课程众筹/2, 中级课程众筹/3,高级课程众筹/4, 众筹完毕] - binding.schedule.setVisibility(View.GONE); - binding.explanation.setVisibility(View.GONE); - binding.more.setVisibility(View.GONE); - binding.supportBtn.setVisibility(View.GONE); - - binding.thumbBtn.setVisibility(View.VISIBLE); - binding.supportPercent.setText(R.string.support_explanation); - binding.rvIndex.setOnItemClickListener((parent, view, position, id) -> - QWebViewActivity.start(this, course.getCourses().get(position).getTitle(), course.getCourses().get(position).getLink())); - } else { - binding.thumbBtn.setVisibility(View.GONE); - binding.schedule.setDotObj(DotObj.getDefaultList(this)); - binding.schedule.setPercent(course.getFunding_process()); - - String[] fundingPrice = getResources().getStringArray(R.array.funding_price); - binding.moreText.setText(getString(R.string.explanation_more, fundingPrice[0], - fundingPrice[1], - fundingPrice[2], - fundingPrice[3])); - initSupportCount(); - } - } - - private void initSupportCount() { - App.getService().getArticleSupportNum(course.getSmodule(), new MySubscriber() { - @Override - public void onNext(Object o) { - String num = ((Double) ((Map) o).get("number")).intValue() + ""; - if (TextUtils.isEmpty(num)) { - binding.supportPercent.setVisibility(View.GONE); - } else { - binding.supportPercent.setVisibility(View.VISIBLE); - binding.supportPercent.setText(getString(R.string.support_count, num)); - } - } - }); - } - - View.OnClickListener recordNIndex = (v -> { - if (App.getUser() != null) { - uploadMyCourse(); - QWebViewActivity.start(this, course.getTitle(), course.getLink()); - } else { - startActivityForResult(new Intent(this, SignInActivity.class), COURSE_LOGIN_REQUEST_CODE); - } - }); - - View.OnClickListener backThisProjectUnlogin = (v -> { - - startActivityForResult(new Intent(this, SignInActivity.class), SUPPORT_LOGIN_REQUEST_CODE); - }); - - private void initListener() { - binding.more.setOnClickListener(v -> { - binding.explanationMore.toggle(); - binding.more.setText(binding.explanationMore.isExpanded() ? R.string.more : R.string.hide); - }); - - //binding.ivTheme.setOnClickListener(v -> QWebViewActivity.start(this, course.getTitle(), course.getLink())); - - binding.supportBtn.setOnClickListener(v -> { - if (App.getUser() != null) { - FundingPurchaseActivity.startSupport(this, course.getSmodule(), course.getFunding_process()); - } else { - startActivityForResult(new Intent(this, SignInActivity.class), SUPPORT_LOGIN_REQUEST_CODE); - } - }); - - binding.thumbBtn.setOnClickListener(v -> PurchaseActivity.start(this, course.getSmodule())); - - switch (getIntent().getIntExtra(STATUS, 0)) { - //[0,不进行众筹/1,初级课程众筹/2, 中级课程众筹/3,高级课程众筹/4, 众筹完毕] - case 0: - binding.btnStartLearn.setOnClickListener(recordNIndex); - break; - case 1: - case 2: - case 3: - case 4: - checkIsPayed(); - break; - } - } - - private void checkIsPayed() { - if (App.getUser() != null) { - App.getService().getPayStatus(App.getUser().getEmail(), course.getSmodule(), new - MySubscriber() { - @Override - public void onNext(PayStatusModel o) { - if (o.getPayed() > 0) { - binding.btnStartLearn.setText(R.string.start_learn); - binding.btnStartLearn.setOnClickListener(recordNIndex); - } else { - binding.btnStartLearn.setText(R.string.back_course); - binding.btnStartLearn.setOnClickListener(v -> FundingPurchaseActivity - .startSupport(CourseIndexFundingActivity.this, course - .getSmodule(), course - .getFunding_process())); - } - } - }); - } else { - binding.btnStartLearn.setText(R.string.back_course); - binding.btnStartLearn.setOnClickListener(backThisProjectUnlogin); - - - //startActivityForResult(new Intent(this, SignInActivity.class), SUPPORT_LOGIN_REQUEST_CODE); - } - } - - private void uploadMyCourse() { - JSONObject jsonObject = new JSONObject(); - try { - jsonObject.put("type", START_TO_LEARN_TYPE); - jsonObject.put("time", VeDate.getStringDateHourAsInt()); - jsonObject.put("crowdfunding", 0);//0 非众筹/ 1: 0-100 /2: 100-500/3 500-2000 - jsonObject.put("articleId", course.getSmodule()); - jsonObject.put("account", App.getUser().getEmail()); - } catch (JSONException e) { - e.printStackTrace(); - } - UpdateHelper.submitIAPLog(CourseIndexFundingActivity.this, NAction.getUserNoId(this), - App.getGson().toJson(jsonObject)); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - switch (requestCode) { - case SUPPORT_LOGIN_REQUEST_CODE: - if (resultCode == Activity.RESULT_OK) { - FundingPurchaseActivity.startSupport(this, course.getSmodule(), course.getFunding_process()); - } - break; - case COURSE_LOGIN_REQUEST_CODE: - // do nothing - break; - } - } -} diff --git a/qpython/src/main/java/org/qpython/qpy/main/activity/FloatViewActivity.java b/qpython/src/main/java/org/qpython/qpy/main/activity/FloatViewActivity.java index 6f675912a5752bdb1e6228edee42124fdb26f40e..90506c60f5bfe5ae079c2f013fbf96309ec29f30 100644 --- a/qpython/src/main/java/org/qpython/qpy/main/activity/FloatViewActivity.java +++ b/qpython/src/main/java/org/qpython/qpy/main/activity/FloatViewActivity.java @@ -1,286 +1,293 @@ -package org.qpython.qpy.main.activity; - -import android.annotation.SuppressLint; -import android.app.Activity; -import android.graphics.PixelFormat; -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.support.annotation.RequiresApi; -import android.util.DisplayMetrics; -import android.view.MotionEvent; -import android.view.View; -import android.view.WindowManager; -import android.widget.Button; -import android.widget.Toast; - -import org.json.JSONException; -import org.json.JSONObject; -import org.qpython.qpy.R; -import org.qpython.qpy.console.ScriptExec; -import org.qpython.qsl4a.qsl4a.facade.FloatViewFacade; -import org.qpython.qsl4a.qsl4a.util.HtmlUtil; - -import java.util.ArrayList; - -public class FloatViewActivity extends Activity - { - //按钮数组 - static final ArrayList