diff --git a/build.gradle b/build.gradle index d576ffd4..db07eaa1 100644 --- a/build.gradle +++ b/build.gradle @@ -8,16 +8,19 @@ def butterknifeVersion = '9.0.0' //eqals to line 26 buildscript { repositories { - jcenter() - google() - mavenCentral() - + // 配置HMS Core SDK的Maven仓地址。 + maven {url 'https://developer.huawei.com/repo/'} + maven {url 'https://maven.aliyun.com/repository/jcenter'} + maven {url 'https://maven.aliyun.com/repository/google'} + maven { url 'https://maven.aliyun.com/nexus/content/groups/public/' } maven { url "https://plugins.gradle.org/m2/" } maven { url "https://maven.google.com" } + google() + mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:3.5.3' + classpath 'com.android.tools.build:gradle:3.5.4' // A gradle plugin for getting java lambda support in java 6, 7 and android // https://github.com/evant/gradle-retrolambda @@ -35,18 +38,25 @@ buildscript { classpath "io.realm:realm-gradle-plugin:3.5.0" classpath 'com.google.gms:google-services:4.0.2' + + // 添加agcp插件配置。 + classpath 'com.huawei.agconnect:agcp:1.6.0.300' } } allprojects { repositories { - jcenter() + // 配置HMS Core SDK的Maven仓地址。 + maven {url 'https://developer.huawei.com/repo/'} + maven {url 'https://maven.aliyun.com/repository/jcenter'} + maven {url 'https://maven.aliyun.com/repository/google'} + maven { url 'https://maven.aliyun.com/nexus/content/groups/public/' } + maven { url "https://jitpack.io" } +// maven { url 'https://dl.bintray.com/azeesoft/maven' } + //maven { url "http://mvn.leancloud.cn/nexus/content/repositories/public" } google() mavenCentral() - maven { url "https://jitpack.io" } - maven { url 'https://dl.bintray.com/azeesoft/maven' } - //maven { url "http://mvn.leancloud.cn/nexus/content/repositories/public" } } } @@ -74,11 +84,16 @@ subprojects { } ext { + minSdkVersion = 18 + targetSdkVersion = 28 + compileSdkVersion = 28 + buildToolsVersion = '28.0.2'//30.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' + libFileDownloaderLib = 'com.liulishuo.filedownloader:library:1.7.4' libSupportV4 = "com.android.support:support-v4:${supportVersion}" libSupportV4Design = 'com.android.support:design:${supportVersion}' @@ -91,16 +106,12 @@ ext { libSupportDesign = "com.android.support:design:${supportVersion}" libOkHttp3Log = "com.squareup.okhttp3:logging-interceptor:${okhttpVersion}" - 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" + firebaseCore = "com.google.firebase:firebase-core:16.0.7" + firebaseMsg = "com.google.firebase:firebase-messaging:18.0.0" + firebaseIid = "com.google.firebase:firebase-iid:17.0.4" firebaseAuth = "com.google.firebase:firebase-auth:16.1.0" - firebaseDatabase = "com.google.firebase:firebase-database:16.0.5" + firebaseDatabase = "com.google.firebase:firebase-database:16.0.6" // https://developers.google.com/android/guides/setup googlePlayServiceAuth = "com.google.android.gms:play-services-auth:16.0.1" @@ -115,4 +126,8 @@ ext { libButterknife = "com.jakewharton:butterknife:${butterknifeVersion}" libButterknifeCompiler ="com.jakewharton:butterknife-compiler:${butterknifeVersion}" + + //https://developer.huawei.com/consumer/cn/doc/development/HMSCore-Guides/android-app-quickstart-0000001071490422 + huaweiPush = "com.huawei.hms:push:6.1.0.300" + huaweiAnlytics = "com.huawei.hms:hianalytics:6.3.2.300" } \ No newline at end of file diff --git a/local.properties b/local.properties index 4929a5a2..b8cc166d 100644 --- a/local.properties +++ b/local.properties @@ -4,6 +4,8 @@ # Location of the SDK. This is only used by Gradle. # For customization when using a Version Control System, please read the # header note. -#Thu Aug 02 10:23:49 CST 2018 -ndk.dir=/Users/yanhecun/Library/Android/sdk/ndk-bundle -sdk.dir=/Users/yanhecun/Library/Android/sdk +#Mon Apr 13 14:53:44 CST 2020 +#ndk.dir=/Users/yanhecun/Library/Android/sdk/ndk-bundle +ndk.dir=D\:\\android-sdk-windows\\ndk\\20.1.5948944 +sdk.dir=D\:\\android-sdk-windows + diff --git a/qbaselib b/qbaselib index d379973c..7cf3672c 160000 --- a/qbaselib +++ b/qbaselib @@ -1 +1 @@ -Subproject commit d379973cb724f65f342a1fbfc7b426b185b7ce32 +Subproject commit 7cf3672cd25bcd0f935ef0124144cb080dd6308d diff --git a/qpysdk/build.gradle b/qpysdk/build.gradle index deab3e87..9e50b479 100644 --- a/qpysdk/build.gradle +++ b/qpysdk/build.gradle @@ -20,11 +20,18 @@ android { proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } - externalNativeBuild { - ndkBuild { - path 'src/main/jni/Android.mk' + sourceSets { + main { + jniLibs.srcDirs = ['src/main/libs'] + } } + +// externalNativeBuild { +// ndkBuild { +// path 'src/main/jni/Android.mk' +// } +// } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 diff --git a/qpysdk/src/main/java/org/qpython/qpysdk/QPyConstants.java b/qpysdk/src/main/java/org/qpython/qpysdk/QPyConstants.java index bf9ebd1d..f6cc077e 100644 --- a/qpysdk/src/main/java/org/qpython/qpysdk/QPyConstants.java +++ b/qpysdk/src/main/java/org/qpython/qpysdk/QPyConstants.java @@ -3,6 +3,7 @@ import android.os.Environment; import com.quseit.config.BASE_CONF; +import com.quseit.util.FileUtils; public interface QPyConstants extends BASE_CONF { @@ -34,8 +35,9 @@ public interface QPyConstants extends BASE_CONF { String ABSOLUTE_PATH = Environment.getExternalStorageDirectory().getPath() + "/" + BASE_PATH; - String PY_CACHE_PATH = ABSOLUTE_PATH+"/"+PY_CACHE; - String ABSOLUTE_LOG = ABSOLUTE_PATH + "/log/last.log"; +// String ABSOLUTE_PATH = FileUtils.getPath().getPath() + "/" + BASE_PATH; +// String PY_CACHE_PATH = ABSOLUTE_PATH+"/"+PY_CACHE; +// String ABSOLUTE_LOG = ABSOLUTE_PATH + "/log/last.log"; String PYTHON_2 = "2.x"; diff --git a/qpysdk/src/main/java/org/qpython/qpysdk/QPySDK.java b/qpysdk/src/main/java/org/qpython/qpysdk/QPySDK.java index 516f523e..9d1973a6 100644 --- a/qpysdk/src/main/java/org/qpython/qpysdk/QPySDK.java +++ b/qpysdk/src/main/java/org/qpython/qpysdk/QPySDK.java @@ -94,10 +94,10 @@ public void playQScript(final String script) { mArguments.add(script); String[] argumentsArray = mArguments.toArray(new String[mArguments.size()]); - final File mLog = new File(String.format("%s", QPyConstants.ABSOLUTE_LOG)); + final File mLog = new File(String.format("%s", com.quseit.util.FileUtils.getAbsoluteLogPath(context.getApplicationContext()))); File logDir = mLog.getParentFile(); - mFd = Exec.createSubprocess(binaryPath, argumentsArray, getEnvironmentArray(f.getParentFile() + ""), Environment.getExternalStorageDirectory() + "/", pid); + mFd = Exec.createSubprocess(binaryPath, argumentsArray, getEnvironmentArray(f.getParentFile() + ""), com.quseit.util.FileUtils.getPath(context.getApplicationContext()) + "/", pid); final AtomicInteger mPid = new AtomicInteger(PID_INIT_VALUE); mPid.set(pid[0]); @@ -106,34 +106,32 @@ public void playQScript(final String script) { long mStartTime = System.currentTimeMillis(); - new Thread(new Runnable() { - public void run() { - int returnValue = Exec.waitFor(mPid.get()); - //long mEndTime = System.currentTimeMillis(); - int pid = mPid.getAndSet(PID_INIT_VALUE); - Log.d("", "out:" + mFd.out.toString()); + new Thread(() -> { + int returnValue = Exec.waitFor(mPid.get()); + //long mEndTime = System.currentTimeMillis(); + int pid1 = mPid.getAndSet(PID_INIT_VALUE); + Log.d("", "out:" + mFd.out.toString()); - Message msg = new Message(); - msg.what = returnValue; - msg.obj = mArguments.get(0); + Message msg = new Message(); + msg.what = returnValue; + msg.obj = mArguments.get(0); - Log.d(TAG, "Process " + pid + " exited with result code " + returnValue + "."); + Log.d(TAG, "Process " + pid1 + " exited with result code " + returnValue + "."); - try { - mIn.close(); - } catch (IOException e) { - Log.e(TAG, e.getMessage()); - } + try { + mIn.close(); + } catch (IOException e) { + Log.e(TAG, e.getMessage()); + } - try { - mOut.close(); - } catch (IOException e) { - Log.e(TAG, e.getMessage()); - } + try { + mOut.close(); + } catch (IOException e) { + Log.e(TAG, e.getMessage()); + } - //context.updateNotify(msg); + //context.updateNotify(msg); - } }).start(); } @@ -149,7 +147,7 @@ private String[] getEnvironmentArray(String pyPath) { environmentVariables.add("PYTHONHOME=" + filesDir); environmentVariables.add("ANDROID_PRIVATE=" + filesDir); - File externalStorage = new File(Environment.getExternalStorageDirectory(), "org.qpython.qpy"); + File externalStorage = new File(com.quseit.util.FileUtils.getPath(context.getApplicationContext()), "org.qpython.qpy"); environmentVariables.add("PYTHONPATH=" + externalStorage + "/lib/python2.7/site-packages/:" + filesDir + "/lib/python2.7/site-packages/:" 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 90ffe237..90f8b721 100644 --- a/qpysdk/src/main/java/org/qpython/qpysdk/utils/FileHelper.java +++ b/qpysdk/src/main/java/org/qpython/qpysdk/utils/FileHelper.java @@ -6,6 +6,8 @@ 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,29 +25,29 @@ /** * 对SD卡文件的管理 - * + * * @author ch.linghu - * */ public class FileHelper { - @SuppressWarnings("unused") - private static final String TAG = "FileHelper"; - - public static final void createDirIfNExists(String dirname) { - File yy = new File(dirname); - if (!yy.exists()) { - yy.mkdirs(); - } - } - - public static final void createFileFromAssetsIfNExists(Context con, String filename, String dst) { - File yy = new File(dst); - if (!yy.exists()) { - String content = FileHelper.LoadDataFromAssets(con, filename); - FileHelper.writeToFile(dst, content, false); - } - } - public static void openFile(Context context, String filePath, String fileExtension) { + @SuppressWarnings("unused") + private static final String TAG = "FileHelper"; + + public static final void createDirIfNExists(String dirname) { + File yy = new File(dirname); + if (!yy.exists()) { + yy.mkdirs(); + } + } + + public static final void createFileFromAssetsIfNExists(Context con, String filename, String dst) { + File yy = new File(dst); + if (!yy.exists()) { + String content = FileHelper.LoadDataFromAssets(con, filename); + FileHelper.writeToFile(dst, content, false); + } + } + + public static void openFile(Context context, String filePath, String fileExtension) { Intent intent = new Intent(); intent.setAction(android.content.Intent.ACTION_VIEW); File file = new File(filePath); @@ -57,328 +59,331 @@ public static void openFile(Context context, String filePath, String fileExtensi context.startActivity(intent); } catch (android.content.ActivityNotFoundException e) { } -} + } + + public static String getFileNameFromUrl(String urlFile) { + try { + URL url = new URL(urlFile); + File f = new File(url.getPath()); + return f.getName(); + + } catch (MalformedURLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + + return "unname.dat"; + } + } + + public static String getTypeByMimeType(String mType) { + if (mType.equals("application/vnd.android.package-archive")) { + return "apk"; + } else { + String[] xx = mType.split("/"); + if (xx.length > 1) { + return xx[0]; + } + } + return "other"; + } + + public static String LoadDataFromAssets(Context context, String inFile) { + String tContents = ""; + + try { + InputStream stream = context.getAssets().open(inFile); + int size = stream.available(); + byte[] buffer = new byte[size]; + stream.read(buffer); + stream.close(); + tContents = new String(buffer); + } catch (IOException e) { + } + return tContents; + } - public static String getFileNameFromUrl(String urlFile) { - try { - URL url = new URL(urlFile); - File f = new File(url.getPath()); - return f.getName(); - - } catch (MalformedURLException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - - return "unname.dat"; - } - } - public static String getTypeByMimeType(String mType) { - if (mType.equals("application/vnd.android.package-archive")) { - return "apk"; - } else { - String[] xx = mType.split("/"); - if (xx.length>1) { - return xx[0]; - } - } - return "other"; - } - - public static String LoadDataFromAssets(Context context, String inFile) { - String tContents = ""; - - try { - InputStream stream = context.getAssets().open(inFile); - int size = stream.available(); - byte[] buffer = new byte[size]; - stream.read(buffer); - stream.close(); - tContents = new String(buffer); - } catch (IOException e) { - } - return tContents; - } - - public static void putFileContents(Context context, String filename, String content) { - try { - File fileCache = new File(filename); - byte[] data = content.getBytes(); - FileOutputStream outStream; - outStream = new FileOutputStream(fileCache); - outStream.write(data); - outStream.close(); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - - } - } - - public static void writeToFile(String filePath, String data, boolean append) { - try { - FileOutputStream fOut = new FileOutputStream(filePath, append); + public static void putFileContents(Context context, String filename, String content) { + try { + File fileCache = new File(filename); + byte[] data = content.getBytes(); + FileOutputStream outStream; + outStream = new FileOutputStream(fileCache); + outStream.write(data); + outStream.close(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + + } + } + + public static void writeToFile(String filePath, String data, boolean append) { + try { + FileOutputStream fOut = new FileOutputStream(filePath, append); fOut.write(data.getBytes()); fOut.flush(); fOut.close(); - } catch (IOException iox) { - iox.printStackTrace(); - } - - } - - - public static String getFileContentsFromAssets(Context context, String filename) { - String content=""; //结果字符串 - try{ - java.io.InputStream is= context.getResources().getAssets().open(filename); //打开文件 - int ch=0; - ByteArrayOutputStream baos = new ByteArrayOutputStream(); //实现了一个输出流 - while((ch=is.read())!=-1){ - baos.write(ch); //将指定的字节写入此 byte 数组输出流 - } - byte[] buff=baos.toByteArray();//以byte 数组的形式返回此输出流的当前内容 - baos.close(); //关闭流 - is.close(); //关闭流 - content=new String(buff,"UTF-8"); //设置字符串编码 - - } catch(Exception e) { - e.printStackTrace(); - //LogUtil.d(TAG, "getFileContentsFromAssets:"+e.getMessage()); - } - return content; - } - public static String getFileContents(String filename) { - - File scriptFile = new File( filename ); + } catch (IOException iox) { + iox.printStackTrace(); + } + + } + + + public static String getFileContentsFromAssets(Context context, String filename) { + String content = ""; //结果字符串 + try { + java.io.InputStream is = context.getResources().getAssets().open(filename); //打开文件 + int ch = 0; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); //实现了一个输出流 + while ((ch = is.read()) != -1) { + baos.write(ch); //将指定的字节写入此 byte 数组输出流 + } + byte[] buff = baos.toByteArray();//以byte 数组的形式返回此输出流的当前内容 + baos.close(); //关闭流 + is.close(); //关闭流 + content = new String(buff, "UTF-8"); //设置字符串编码 + + } catch (Exception e) { + e.printStackTrace(); + //LogUtil.d(TAG, "getFileContentsFromAssets:"+e.getMessage()); + } + return content; + } + + public static String getFileContents(String filename) { + + File scriptFile = new File(filename); + String tContent = ""; + if (scriptFile.exists()) { + BufferedReader in; + try { + in = new BufferedReader(new FileReader(scriptFile)); + String line; + + while ((line = in.readLine()) != null) { + tContent += line + "\n"; + } + in.close(); + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + return tContent; + } + + public static String getFileContents(String filename, int pos) { + + File scriptFile = new File(filename); String tContent = ""; if (scriptFile.exists()) { - BufferedReader in; - try { - in = new BufferedReader(new FileReader(scriptFile)); - String line; - - while ((line = in.readLine())!=null) { - tContent += line+"\n"; - } - in.close(); - } catch (FileNotFoundException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } + BufferedReader in; + try { + in = new BufferedReader(new FileReader(scriptFile)); + String line; + + while ((line = in.readLine()) != null) { + tContent += line + "\n"; + if (tContent.length() >= pos) { + in.close(); + return tContent; + } + } + in.close(); + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } + return tContent; + } + + public static void clearDir(String dir, int level, boolean deleteS) { + //LogUtil.d(TAG, "clearDir:"+dir); + File basePath = new File(dir); + if (basePath.exists() && basePath.isDirectory()) { + for (File item : basePath.listFiles()) { + if (item.isFile()) { + //LogUtil.d(TAG, "deleteItem:"+item.getAbsolutePath()); + item.delete(); + + } else if (item.isDirectory()) { + clearDir(item.getAbsolutePath(), level + 1, deleteS); + } + } + if (level > 0 || deleteS) { + basePath.delete(); + } + } + } + + public static File getBasePath(Context context, String parDir, String subdir) throws IOException { + try { + File basePath = new File(FileUtils.getPath(context), + parDir); + + if (!basePath.exists()) { + if (!basePath.mkdirs()) { + throw new IOException(String.format("%s cannot be created!", + basePath.toString())); + } + } + File subPath = null; + if (!subdir.equals("")) { + subPath = new File(FileUtils.getPath(context.getApplicationContext()), + parDir + "/" + subdir); + if (!subPath.exists()) { + if (!subPath.mkdirs()) { + throw new IOException(String.format("%s cannot be created!", + subPath.toString())); + } + } + } + + if (!basePath.isDirectory()) { + throw new IOException(String.format("%s is not a directory!", + basePath.toString())); + } + if (subdir.equals("")) { + return basePath; + } else { + return subPath; + } + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /*public static File getBasePath(String subdir) throws IOException { + File basePath = new File(Environment.getExternalStorageDirectory(), + BASE_CONF.BASE_PATH); + + if (!basePath.exists()) { + if (!basePath.mkdirs()) { + throw new IOException(String.format("%s cannot be created!", + basePath.toString())); + } + } + File subPath = null; + if (!subdir.equals("")) { + subPath = new File(Environment.getExternalStorageDirectory(), + BASE_CONF.BASE_PATH+"/"+subdir); + if (!subPath.exists()) { + if (!subPath.mkdirs()) { + throw new IOException(String.format("%s cannot be created!", + subPath.toString())); + } + } + } + + if (!basePath.isDirectory()) { + throw new IOException(String.format("%s is not a directory!", + basePath.toString())); + } + if (subdir.equals("")) + return basePath; + else + return subPath; + } + */ + public static File getABSPath(String subdir) throws IOException { + File basePath = new File(subdir); + + if (!basePath.exists()) { + if (!basePath.mkdirs()) { + throw new IOException(String.format("%s cannot be created!", + basePath.toString())); + } + } + File subPath = null; + if (!subdir.equals("")) { + subPath = new File(subdir); + if (!subPath.exists()) { + if (!subPath.mkdirs()) { + throw new IOException(String.format("%s cannot be created!", + subPath.toString())); + } + } + } + if (!basePath.isDirectory()) { + throw new IOException(String.format("%s is not a directory!", + basePath.toString())); } - return tContent; - } - - public static String getFileContents(String filename, int pos) { - - File scriptFile = new File( filename ); - String tContent = ""; - if (scriptFile.exists()) { - BufferedReader in; - try { - in = new BufferedReader(new FileReader(scriptFile)); - String line; - - while ((line = in.readLine())!=null) { - tContent += line+"\n"; - if (tContent.length()>=pos) { - in.close(); - return tContent; - } - } - in.close(); - } catch (FileNotFoundException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - } - return tContent; - } - - public static void clearDir(String dir, int level, boolean deleteS) { - //LogUtil.d(TAG, "clearDir:"+dir); - File basePath = new File(dir); - if (basePath.exists() && basePath.isDirectory()) { - for (File item : basePath.listFiles()) { - if (item.isFile()) { - //LogUtil.d(TAG, "deleteItem:"+item.getAbsolutePath()); - item.delete(); - - } else if (item.isDirectory()){ - clearDir(item.getAbsolutePath(), level+1, deleteS); - } - } - if (level>0 || deleteS) { - basePath.delete(); - } - } - } - - public static File getBasePath(String parDir, String subdir) throws IOException { - try { - File basePath = new File(Environment.getExternalStorageDirectory(), - parDir); - - if (!basePath.exists()) { - if (!basePath.mkdirs()) { - throw new IOException(String.format("%s cannot be created!", - basePath.toString())); - } - } - File subPath = null; - if (!subdir.equals("")) { - subPath = new File(Environment.getExternalStorageDirectory(), - parDir+"/"+subdir); - if (!subPath.exists()) { - if (!subPath.mkdirs()) { - throw new IOException(String.format("%s cannot be created!", - subPath.toString())); - } - } - } - - if (!basePath.isDirectory()) { - throw new IOException(String.format("%s is not a directory!", - basePath.toString())); - } - if (subdir.equals("")) - return basePath; - else - return subPath; - } catch (Exception e) { - e.printStackTrace(); - return null; - } - } - - /*public static File getBasePath(String subdir) throws IOException { - File basePath = new File(Environment.getExternalStorageDirectory(), - BASE_CONF.BASE_PATH); - - if (!basePath.exists()) { - if (!basePath.mkdirs()) { - throw new IOException(String.format("%s cannot be created!", - basePath.toString())); - } - } - File subPath = null; - if (!subdir.equals("")) { - subPath = new File(Environment.getExternalStorageDirectory(), - BASE_CONF.BASE_PATH+"/"+subdir); - if (!subPath.exists()) { - if (!subPath.mkdirs()) { - throw new IOException(String.format("%s cannot be created!", - subPath.toString())); - } - } - } - - if (!basePath.isDirectory()) { - throw new IOException(String.format("%s is not a directory!", - basePath.toString())); - } - if (subdir.equals("")) - return basePath; - else - return subPath; - } - */ - public static File getABSPath(String subdir) throws IOException { - File basePath = new File(subdir); - - if (!basePath.exists()) { - if (!basePath.mkdirs()) { - throw new IOException(String.format("%s cannot be created!", - basePath.toString())); - } - } - File subPath = null; - if (!subdir.equals("")) { - subPath = new File(subdir); - if (!subPath.exists()) { - if (!subPath.mkdirs()) { - throw new IOException(String.format("%s cannot be created!", - subPath.toString())); - } - } - } - - if (!basePath.isDirectory()) { - throw new IOException(String.format("%s is not a directory!", - basePath.toString())); - } - if (subdir.equals("")) - return basePath; - else - return subPath; - } - - public static String getFileName(String filename) { - File f = new File(filename); - return f.getName(); - } - + if (subdir.equals("")) + {return basePath;} + else + {return subPath;} + } + + public static String getFileName(String filename) { + File f = new File(filename); + return f.getName(); + } + public static String getExt(String filename, String def) { - String[] yy = filename.split("\\?"); + String[] yy = filename.split("\\?"); String[] xx = yy[0].split("\\."); //LogUtil.d(TAG, "filename:"+filename+"-size:"+xx.length); - - if (xx.length<2) { - return def; + + if (xx.length < 2) { + return def; } else { - String ext = xx[xx.length-1]; + String ext = xx[xx.length - 1]; //LogUtil.d(TAG, "ext:"+ext); return ext; - } - } - + } + } + public static boolean getUrlAsFile(String link, String fileName) { - try { - // get URL content - URL url = new URL(link); - URLConnection conn = url.openConnection(); - - // open the stream and put it into BufferedReader - BufferedReader br = new BufferedReader( - new InputStreamReader(conn.getInputStream())); - - String inputLine; - - //save to this filename - File file = new File(fileName); - - if (!file.exists()) { - file.createNewFile(); - } - - //use FileWriter to write file - FileWriter fw = new FileWriter(file.getAbsoluteFile()); - BufferedWriter bw = new BufferedWriter(fw); - - while ((inputLine = br.readLine()) != null) { - bw.write(inputLine+"\n"); - } - - bw.close(); - br.close(); - - //System.out.println("Done"); - return true; - } catch (MalformedURLException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } - return false; - - } + try { + // get URL content + URL url = new URL(link); + URLConnection conn = url.openConnection(); + + // open the stream and put it into BufferedReader + BufferedReader br = new BufferedReader( + new InputStreamReader(conn.getInputStream())); + + String inputLine; + + //save to this filename + File file = new File(fileName); + + if (!file.exists()) { + file.createNewFile(); + } + + //use FileWriter to write file + FileWriter fw = new FileWriter(file.getAbsoluteFile()); + BufferedWriter bw = new BufferedWriter(fw); + + while ((inputLine = br.readLine()) != null) { + bw.write(inputLine + "\n"); + } + + bw.close(); + br.close(); + + //System.out.println("Done"); + return true; + } catch (MalformedURLException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + return false; + + } } diff --git a/qpysdk/src/main/java/org/renpy/android/PythonSDLActivity.java b/qpysdk/src/main/java/org/renpy/android/PythonSDLActivity.java index e727399e..33817663 100644 --- a/qpysdk/src/main/java/org/renpy/android/PythonSDLActivity.java +++ b/qpysdk/src/main/java/org/renpy/android/PythonSDLActivity.java @@ -28,6 +28,7 @@ import android.widget.Toast; +import com.quseit.util.FileUtils; import com.quseit.util.NAction; import com.quseit.util.NUtil; @@ -69,6 +70,7 @@ public class PythonSDLActivity extends SDLActivity { ResourceManager resourceManager; + @Override protected String[] getLibraries() { return new String[] { "png16", @@ -243,11 +245,7 @@ public void toastError(final String msg) { final Activity thisActivity = this; - runOnUiThread(new Runnable () { - public void run() { - Toast.makeText(thisActivity, msg, Toast.LENGTH_LONG).show(); - } - }); + runOnUiThread(() -> Toast.makeText(thisActivity, msg, Toast.LENGTH_LONG).show()); // Wait to show the error. synchronized (this) { @@ -276,7 +274,7 @@ public void initEnviron() { nativeSetEnv("ANDROID_ARGUMENT", path.getAbsolutePath()); } else { - nativeSetEnv("ANDROID_ARGUMENT", QPyConstants.ABSOLUTE_PATH); + nativeSetEnv("ANDROID_ARGUMENT", FileUtils.getAbsolutePath(getApplicationContext())); } @@ -299,7 +297,7 @@ public void preparePython() { resourceManager = new ResourceManager(this); - File oldExternalStorage = new File(Environment.getExternalStorageDirectory(), getPackageName()); + File oldExternalStorage = new File(FileUtils.getPath(getApplicationContext()), getPackageName()); File externalStorage = getExternalFilesDir(null); File path; @@ -323,7 +321,7 @@ public void preparePython() { path = getFilesDir(); } - nativeSetEnv("ANDROID_LOG", QPyConstants.ABSOLUTE_LOG); + nativeSetEnv("ANDROID_LOG",FileUtils.getAbsoluteLogPath(getApplicationContext())); File filesDir = getFilesDir(); //unpackData("private", getFilesDir()); @@ -331,7 +329,7 @@ public void preparePython() { nativeSetEnv("ANDROID_ARGUMENT", path.getAbsolutePath()); nativeSetEnv("ANDROID_PRIVATE", getFilesDir().getAbsolutePath()); - nativeSetEnv("ANDROID_PUBLIC", QPyConstants.ABSOLUTE_PATH); + nativeSetEnv("ANDROID_PUBLIC", FileUtils.getAbsolutePath(getApplicationContext())); nativeSetEnv("ANDROID_OLD_PUBLIC", oldExternalStorage.getAbsolutePath()); nativeSetEnv("LD_LIBRARY_PATH", ".:"+filesDir+"/lib/"+":"+filesDir+"/:"+filesDir.getParentFile()+"/lib/"); @@ -403,6 +401,7 @@ protected void onDestroy() { super.onDestroy(); } + @Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) { super.onActivityResult(requestCode, resultCode, intent); } @@ -433,18 +432,18 @@ public int getDPI() { public PowerManager.WakeLock wakeLock = null; - public void setWakeLock(boolean active) { - if (wakeLock == null) { - PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); - wakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "Screen On"); - wakeLock.setReferenceCounted(false); - } - - if (active) { - wakeLock.acquire(); - } else { - wakeLock.release(); - } - } +// public void setWakeLock(boolean active) { +// if (wakeLock == null) { +// PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); +// wakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "Screen On"); +// wakeLock.setReferenceCounted(false); +// } +// +// if (active) { +// wakeLock.acquire(); +// } else { +// wakeLock.release(); +// } +// } } diff --git a/qpysdk/src/main/jni b/qpysdk/src/main/jni index 3ee8b209..13b2bb1b 160000 --- a/qpysdk/src/main/jni +++ b/qpysdk/src/main/jni @@ -1 +1 @@ -Subproject commit 3ee8b209df6481a585826a44bfa94eeecd621e4e +Subproject commit 13b2bb1b99c208f41c8f0c83eb284bc29493587e diff --git a/qpysdk/src/main/libs/arm64-v8a/libSDL2.so b/qpysdk/src/main/libs/arm64-v8a/libSDL2.so new file mode 100755 index 00000000..479428c8 Binary files /dev/null and b/qpysdk/src/main/libs/arm64-v8a/libSDL2.so differ diff --git a/qpysdk/src/main/libs/arm64-v8a/libSDL2_gfx.so b/qpysdk/src/main/libs/arm64-v8a/libSDL2_gfx.so new file mode 100755 index 00000000..04a7d33e Binary files /dev/null and b/qpysdk/src/main/libs/arm64-v8a/libSDL2_gfx.so differ diff --git a/qpysdk/src/main/libs/arm64-v8a/libSDL2_image.so b/qpysdk/src/main/libs/arm64-v8a/libSDL2_image.so new file mode 100755 index 00000000..d7c20bbb Binary files /dev/null and b/qpysdk/src/main/libs/arm64-v8a/libSDL2_image.so differ diff --git a/qpysdk/src/main/libs/arm64-v8a/libSDL2_mixer.so b/qpysdk/src/main/libs/arm64-v8a/libSDL2_mixer.so new file mode 100755 index 00000000..72742e96 Binary files /dev/null and b/qpysdk/src/main/libs/arm64-v8a/libSDL2_mixer.so differ diff --git a/qpysdk/src/main/libs/arm64-v8a/libSDL2_ttf.so b/qpysdk/src/main/libs/arm64-v8a/libSDL2_ttf.so new file mode 100755 index 00000000..1b1ac8e0 Binary files /dev/null and b/qpysdk/src/main/libs/arm64-v8a/libSDL2_ttf.so differ diff --git a/qpysdk/src/main/libs/arm64-v8a/libandroid-support.so b/qpysdk/src/main/libs/arm64-v8a/libandroid-support.so new file mode 100644 index 00000000..aee30ce6 Binary files /dev/null and b/qpysdk/src/main/libs/arm64-v8a/libandroid-support.so differ diff --git a/qpysdk/src/main/libs/arm64-v8a/libmain.so b/qpysdk/src/main/libs/arm64-v8a/libmain.so new file mode 100755 index 00000000..c635de54 Binary files /dev/null and b/qpysdk/src/main/libs/arm64-v8a/libmain.so differ diff --git a/qpysdk/src/main/libs/arm64-v8a/libpng16.so b/qpysdk/src/main/libs/arm64-v8a/libpng16.so new file mode 100755 index 00000000..76a0ef33 Binary files /dev/null and b/qpysdk/src/main/libs/arm64-v8a/libpng16.so differ diff --git a/qpysdk/src/main/libs/arm64-v8a/libpython2.7.so b/qpysdk/src/main/libs/arm64-v8a/libpython2.7.so new file mode 100644 index 00000000..4af0affd Binary files /dev/null and b/qpysdk/src/main/libs/arm64-v8a/libpython2.7.so differ diff --git a/qpysdk/src/main/libs/arm64-v8a/libqpysdk.so b/qpysdk/src/main/libs/arm64-v8a/libqpysdk.so new file mode 100755 index 00000000..259563f3 Binary files /dev/null and b/qpysdk/src/main/libs/arm64-v8a/libqpysdk.so differ diff --git a/qpysl4a b/qpysl4a index fc9d4745..2d03143d 160000 --- a/qpysl4a +++ b/qpysl4a @@ -1 +1 @@ -Subproject commit fc9d47452c2cdd99b1314c2d5f913dfea33698ad +Subproject commit 2d03143d1160884c22e5769f92b33492aad3d983 diff --git a/qpython/agconnect-services.json b/qpython/agconnect-services.json new file mode 100644 index 00000000..af056f75 --- /dev/null +++ b/qpython/agconnect-services.json @@ -0,0 +1,74 @@ +{ + "agcgw":{ + "backurl":"connect-drcn.hispace.hicloud.com", + "url":"connect-drcn.dbankcloud.cn", + "websocketbackurl":"connect-ws-drcn.hispace.dbankcloud.com", + "websocketurl":"connect-ws-drcn.hispace.dbankcloud.cn" + }, + "agcgw_all":{ + "CN":"connect-drcn.dbankcloud.cn", + "CN_back":"connect-drcn.hispace.hicloud.com", + "DE":"connect-dre.dbankcloud.cn", + "DE_back":"connect-dre.hispace.hicloud.com", + "RU":"connect-drru.dbankcloud.cn", + "RU_back":"connect-drru.hispace.hicloud.com", + "SG":"connect-dra.dbankcloud.cn", + "SG_back":"connect-dra.hispace.hicloud.com" + }, + "client":{ + "cp_id":"900086000022705692", + "product_id":"9105163812218458309", + "client_id":"804293314852440512", + "client_secret":"864AE81B4347F373978F6B15A6E7CA19F7E93A2DF037B25FD18FCA18BA4E4DF6", + "project_id":"9105163812218458309", + "app_id":"100120703", + "api_key":"DAEDABuPtw45yeckkFzuqDKBBpuQAwXZb1BnJMz59lT+GpdaX6f6udSEPYvnZvEXpAbbe3mh5a8L6PFvAEXvkmkTVaTRBdH51SiCeg==", + "package_name":"org.qpython.qpy" + }, + "oauth_client":{ + "client_id":"100120703", + "client_type":1 + }, + "app_info":{ + "app_id":"100120703", + "package_name":"org.qpython.qpy" + }, + "service":{ + "analytics":{ + "collector_url":"datacollector-drcn.dt.hicloud.com,datacollector-drcn.dt.dbankcloud.cn", + "collector_url_ru":"datacollector-drru.dt.hicloud.com,datacollector-drru.dt.dbankcloud.cn", + "collector_url_sg":"datacollector-dra.dt.hicloud.com,datacollector-dra.dt.dbankcloud.cn", + "collector_url_de":"datacollector-dre.dt.hicloud.com,datacollector-dre.dt.dbankcloud.cn", + "collector_url_cn":"datacollector-drcn.dt.hicloud.com,datacollector-drcn.dt.dbankcloud.cn", + "resource_id":"p1", + "channel_id":"" + }, + "search":{ + "url":"https://search-drcn.cloud.huawei.com" + }, + "cloudstorage":{ + "storage_url":"https://agc-storage-drcn.platform.dbankcloud.cn" + }, + "ml":{ + "mlservice_url":"ml-api-drcn.ai.dbankcloud.com,ml-api-drcn.ai.dbankcloud.cn" + } + }, + "region":"CN", + "configuration_version":"3.0", + "appInfos":[ + { + "package_name":"org.qpython.qpy", + "client":{ + "app_id":"100120703" + }, + "app_info":{ + "package_name":"org.qpython.qpy", + "app_id":"100120703" + }, + "oauth_client":{ + "client_type":1, + "client_id":"100120703" + } + } + ] +} \ No newline at end of file diff --git a/qpython/build.gradle b/qpython/build.gradle index 738e1a9e..e07ee819 100644 --- a/qpython/build.gradle +++ b/qpython/build.gradle @@ -1,6 +1,7 @@ apply plugin: 'com.android.application' apply plugin: 'com.jakewharton.butterknife' apply plugin: 'realm-android' +apply plugin: 'com.huawei.agconnect' //获取系统时间 def releaseTime() { @@ -14,8 +15,8 @@ android { defaultConfig { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 304 - versionName "3.0.0" + versionCode 313 + versionName "3.1.8" multiDexEnabled true vectorDrawables.useSupportLibrary = true @@ -68,7 +69,12 @@ android { } debug { - signingConfig signingConfigs.release + signingConfig signingConfigs.debug + debuggable true + minifyEnabled false + jniDebuggable true +// signingConfig signingConfigs.debug + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } @@ -149,6 +155,8 @@ 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' @@ -162,6 +170,9 @@ dependencies { api 'org.litepal.android:core:1.3.1' api 'me.dm7.barcodescanner:zxing:1.9' api 'com.android.support:multidex:1.0.1' + implementation ('com.gyf.cactus:cactus-support:1.1.3-beta09'){ + exclude group: 'com.google.guava' + } api rootProject.ext.libOkHttp3 api rootProject.ext.libOkHttp3Log @@ -176,43 +187,60 @@ dependencies { 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 +// 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:1.0.2' + api 'com.android.support.constraint:constraint-layout:1.1.3' // 微信 - 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' - } +// 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' + implementation rootProject.ext.huaweiPush + implementation rootProject.ext.huaweiAnlytics } -apply plugin: 'com.google.gms.google-services' \ No newline at end of file +//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 deleted file mode 100644 index dcb69ca8..00000000 --- a/qpython/google-services.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "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/libs/MiPush_SDK_Client_4_9_1.jar b/qpython/libs/MiPush_SDK_Client_4_9_1.jar new file mode 100644 index 00000000..ec8357d4 Binary files /dev/null and b/qpython/libs/MiPush_SDK_Client_4_9_1.jar differ diff --git a/qpython/proguard-rules.pro b/qpython/proguard-rules.pro index 0a213a26..88417e59 100644 --- a/qpython/proguard-rules.pro +++ b/qpython/proguard-rules.pro @@ -242,4 +242,12 @@ public static final int *; -keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); -} \ No newline at end of file +} + +#华为通知 +-ignorewarnings +-keepattributes InnerClasses +-keepattributes Signature +-keep class com.huawei.hianalytics.**{*;} +-keep class com.huawei.updatesdk.**{*;} +-keep class com.huawei.hms.**{*;} \ No newline at end of file diff --git a/qpython/src/main/AndroidManifest.xml b/qpython/src/main/AndroidManifest.xml index db2647f9..814bda67 100644 --- a/qpython/src/main/AndroidManifest.xml +++ b/qpython/src/main/AndroidManifest.xml @@ -6,6 +6,7 @@ + @@ -19,8 +20,6 @@ - - @@ -35,6 +34,27 @@ + + + + + + + + + + + + + + + + + + + + @@ -68,6 +88,8 @@ + + @@ -367,10 +389,84 @@ android:configChanges="keyboardHidden|orientation|screenSize"/> - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/qpython/src/main/java/org/qpython/qpy/codeshare/CONSTANT.java b/qpython/src/main/java/org/qpython/qpy/codeshare/CONSTANT.java index e878b621..a9c39b81 100644 --- a/qpython/src/main/java/org/qpython/qpy/codeshare/CONSTANT.java +++ b/qpython/src/main/java/org/qpython/qpy/codeshare/CONSTANT.java @@ -6,4 +6,7 @@ public class CONSTANT { public static final String CLOUDED_MAP = "clouded_map";// 云端文件名路径MAP public static final String DOT_REPLACE = "_%"; // Firebase Database中"." & "/" 等为非法字符无法上传, 需转义 public static final String SLASH_REPLACE = "-%"; + + public static final String MI_PUSH_APP_ID = "2882303761517632253";//小米推送appid + public static final String MI_PUSH_APP_KEY = "5761763248253";//小米推送appkey } 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 9a23d02d..4aa17d1e 100644 --- a/qpython/src/main/java/org/qpython/qpy/console/ScriptExec.java +++ b/qpython/src/main/java/org/qpython/qpy/console/ScriptExec.java @@ -20,6 +20,7 @@ import android.text.TextUtils; import android.util.Log; +import org.qpython.qpy.main.app.App; import org.qpython.qpysdk.Exec; import com.quseit.util.FileUtils; import com.quseit.util.NAction; @@ -129,7 +130,7 @@ public void playProject(Context context, String project, String args, boolean no public String getLastLog() { - File logFile = new File(QPyConstants.ABSOLUTE_LOG); + File logFile = new File(FileUtils.getAbsoluteLogPath(App.getContext())); if (!logFile.getAbsoluteFile().getParentFile().exists()) { logFile.getAbsoluteFile().getParentFile().mkdirs(); @@ -146,7 +147,7 @@ public String[] getPyEnv(Context context, String path, String term, String pyPat boolean isQPy3 = NAction.isQPy3(context); File filesDir = context.getFilesDir(); - File externalStorage = new File(QPyConstants.ABSOLUTE_PATH); + File externalStorage = new File(FileUtils.getAbsolutePath(context)); String[] env = new String[24]; @@ -332,7 +333,7 @@ public void playKScript(Context context, final String script, String argv, boole if (Utils.isOpenGL2supported(context)) { File scriptParent = new File(script).getParentFile(); String proj, log; - log = QPyConstants.ABSOLUTE_LOG; + log = FileUtils.getAbsoluteLogPath(App.getContext()); if (scriptParent.getName().startsWith("scripts")) { proj = new File(script).getName(); @@ -413,9 +414,9 @@ public int playQScript(Context context, final String script, String argv, boolea String[] argumentsArray = mArguments.toArray(new String[mArguments.size()]); - final File mLog = new File(QPyConstants.ABSOLUTE_LOG); + final File mLog = new File(FileUtils.getAbsoluteLogPath(App.getContext())); - mFd = Exec.createSubprocess(binaryPath, argumentsArray, getPyEnv(context, System.getenv("PATH"), System.getenv("TERM"),f.getParentFile() + ""), Environment.getExternalStorageDirectory() + "/", pid); + mFd = Exec.createSubprocess(binaryPath, argumentsArray, getPyEnv(context, System.getenv("PATH"), System.getenv("TERM"),f.getParentFile() + ""), FileUtils.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/TermActivity.java b/qpython/src/main/java/org/qpython/qpy/console/TermActivity.java index bf2f1f01..c91dbe21 100644 --- a/qpython/src/main/java/org/qpython/qpy/console/TermActivity.java +++ b/qpython/src/main/java/org/qpython/qpy/console/TermActivity.java @@ -158,6 +158,7 @@ public class TermActivity extends AppCompatActivity implements UpdateCallback, S * Intercepts keys before the view/terminal gets it. */ private View.OnKeyListener mKeyListener = new View.OnKeyListener() { + @Override public boolean onKey(View v, int keyCode, KeyEvent event) { return backkeyInterceptor(keyCode, event) || keyboardShortcuts(keyCode, event); } @@ -232,6 +233,7 @@ public void onReceive(Context context, Intent intent) { } }; private ServiceConnection mTSConnection = new ServiceConnection() { + @Override public void onServiceConnected(ComponentName className, IBinder service) { Log.i(TermDebug.LOG_TAG, "Bound to TermService"); TermService.TSBinder binder = (TermService.TSBinder) service; @@ -246,6 +248,7 @@ public void onServiceConnected(ComponentName className, IBinder service) { } } + @Override public void onServiceDisconnected(ComponentName arg0) { mTermService = null; } @@ -293,7 +296,7 @@ public void onCreate(Bundle icicle) { initView(); mPrivateAlias = new ComponentName(this, RemoteInterface.PRIVACT_ACTIVITY_ALIAS); if (icicle == null) - onNewIntent(getIntent()); + {onNewIntent(getIntent());} Intent broadcast = new Intent(ACTION_PATH_BROADCAST); @@ -944,6 +947,7 @@ private void closeActivity() { } // Called when the list of sessions changes + @Override public void onUpdate() { SessionList sessions = mTermSessions; if (sessions == null) { @@ -1154,7 +1158,7 @@ private void execURL(String link) { PackageManager pm = getPackageManager(); List handlers = pm.queryIntentActivities(openLink, 0); if (handlers.size() > 0) - startActivity(openLink); + {startActivity(openLink);} } private TermSession createPyTermSession(String[] mArgs) throws IOException { @@ -1181,7 +1185,7 @@ private TermSession createPyTermSession(String[] mArgs) throws IOException { } else { StringBuilder cm = new StringBuilder(); for (int i = 0; i < mArgs.length; i++) { - if (i == 1 && mArgs[0].contains(mArgs[i])) continue; + if (i == 1 && mArgs[0].contains(mArgs[i])) {continue;} cm.append(" ").append(mArgs[i]).append(" "); } session = createTermSession(this, settings, scmd + " " + cm + " && exit", mArgs[1]); @@ -1238,14 +1242,14 @@ private class EmulatorViewGestureListener extends SimpleOnGestureListener { @Override public boolean onSingleTapUp(MotionEvent e) { // Let the EmulatorView handle taps if mouse tracking is active - if (view.isMouseTrackingActive()) return false; + if (view.isMouseTrackingActive()) {return false;} //Check for link at tap location String link = view.getURLat(e.getX(), e.getY()); if (link != null) - execURL(link); + {execURL(link);} else - doUIToggle((int) e.getX(), (int) e.getY(), view.getVisibleWidth(), view.getVisibleHeight()); + {doUIToggle((int) e.getX(), (int) e.getY(), view.getVisibleWidth(), view.getVisibleHeight());} return true; } 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 566eaaa5..3e4cad77 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 @@ -18,6 +18,8 @@ import android.widget.ScrollView; import android.widget.TextView; +import com.quseit.util.FileUtils; + import org.qpython.qpy.R; import org.qpython.qpy.console.RemoteInterface; @@ -26,6 +28,7 @@ import org.qpython.qpy.console.compont.AlertDialogCompat; import org.qpython.qpy.console.compont.PRNGFixes; import org.qpython.qpy.console.util.ShortcutEncryption; +import org.qpython.qpy.main.app.App; import java.io.File; import java.security.GeneralSecurityException; @@ -82,7 +85,7 @@ void makeShortcut() { btn_path.setOnClickListener(p1 -> { String lastPath = SP.getString("lastPath", null); File get = (lastPath == null) - ? Environment.getExternalStorageDirectory() + ? FileUtils.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 3a95584c..a20893ea 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,7 +19,10 @@ 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; import java.io.File; @@ -57,7 +60,7 @@ public void onCreate(android.os.Bundle savedInstanceState) { getWindow().setSoftInputMode(android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN); Intent intent = getIntent(); - extSdCardFile = Environment.getExternalStorageDirectory(); + extSdCardFile = FileUtils.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/console/shortcuts/ShortcutReceiver.java b/qpython/src/main/java/org/qpython/qpy/console/shortcuts/ShortcutReceiver.java new file mode 100644 index 00000000..848230e7 --- /dev/null +++ b/qpython/src/main/java/org/qpython/qpy/console/shortcuts/ShortcutReceiver.java @@ -0,0 +1,16 @@ +package org.qpython.qpy.console.shortcuts; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +import org.qpython.qsl4a.qsl4a.LogUtil; + +public class ShortcutReceiver extends BroadcastReceiver { + + + @Override + public void onReceive(Context context, Intent intent) { + LogUtil.e("111111111" + intent); + } +} diff --git a/qpython/src/main/java/org/qpython/qpy/main/activity/AboutActivity.java b/qpython/src/main/java/org/qpython/qpy/main/activity/AboutActivity.java index ad5a7853..0dd7d95a 100644 --- a/qpython/src/main/java/org/qpython/qpy/main/activity/AboutActivity.java +++ b/qpython/src/main/java/org/qpython/qpy/main/activity/AboutActivity.java @@ -68,7 +68,7 @@ private void initListener() { }); binding.tvPrivacy.setOnClickListener(v -> { - Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.privacy_html))); + Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.url_user_private))); startActivity(browserIntent); }); 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 e964f622..a1252ea5 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 @@ -1,20 +1,35 @@ package org.qpython.qpy.main.activity; -import android.app.Activity; +import android.Manifest; +import android.app.ActivityManager; import android.app.AlertDialog; import android.app.LoaderManager; +import android.app.PendingIntent; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.content.Loader; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.pm.ShortcutInfo; +import android.content.pm.ShortcutManager; +import android.graphics.drawable.Icon; +import android.os.Build; import android.os.Bundle; +import android.os.Handler; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.support.v7.app.AppCompatActivity; +import android.support.annotation.RequiresApi; +import android.support.v4.app.ActivityCompat; +import android.support.v4.content.ContextCompat; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; 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; @@ -23,12 +38,15 @@ import org.greenrobot.eventbus.ThreadMode; 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.event.AppsLoader; import org.qpython.qpy.main.model.AppModel; import org.qpython.qpy.main.model.QPyScriptModel; +import org.qpython.qpy.utils.ShortcutUtil; import org.qpython.qpysdk.QPyConstants; import org.qpython.qpysdk.utils.Utils; +import org.qpython.qsl4a.qsl4a.LogUtil; import java.io.File; import java.io.IOException; @@ -36,6 +54,8 @@ import java.util.Arrays; import java.util.List; +import static org.qpython.qpy.R2.string.show; + /** * Local App list * Created by Hmei on 2017-05-22. @@ -43,10 +63,13 @@ public class AppListActivity extends BaseActivity implements LoaderManager.LoaderCallbacks> { public static final String TYPE_SCRIPT = "script"; + private static final int REQUEST_INSTALL_SHORTCUT = 0; private List dataList; private AppListAdapter adapter; + ShortcutReceiver receiver; + public static void start(Context context, String type) { Intent starter = new Intent(context, AppListActivity.class); starter.putExtra("type", type); @@ -56,12 +79,25 @@ public static void start(Context context, String type) { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); + initShortcutReceiver(); runShortcut(); setContentView(R.layout.activity_local_app); initView(); EventBus.getDefault().register(this); } + private void initShortcutReceiver() { + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_CREATE_SHORTCUT); + filter.addAction("com.android.launcher.action.INSTALL_SHORTCUT"); + filter.addAction("android.content.pm.action.CONFIRM_PIN_SHORTCUT"); + filter.addAction(Intent.ACTION_VIEW); + + receiver = new ShortcutReceiver(); + registerReceiver(receiver,filter); + + } + @Override protected void onResume() { super.onResume(); @@ -74,6 +110,9 @@ protected void onResume() { @Override protected void onDestroy() { super.onDestroy(); + if (receiver != null){ + unregisterReceiver(receiver); + } EventBus.getDefault().unregister(this); } @@ -90,6 +129,7 @@ private void runShortcut() { } } + QPyScriptModel mBean; private void initView() { dataList = new ArrayList<>(); adapter = new AppListAdapter(dataList, getIntent().getStringExtra("type"), this); @@ -104,6 +144,16 @@ public void runProject(QPyScriptModel item) { ScriptExec.getInstance().playProject(AppListActivity.this, item.getPath(), false); } + @Override + public void createShortcut(QPyScriptModel item) { + mBean = item; +// if (!checkPermission()){ +// return; +// } + createShortcutOnThis(); +// test(); + } + @Override public void exit() { AppListActivity.this.finish(); @@ -116,14 +166,117 @@ public void exit() { appsView.setAdapter(adapter); ((TextView) findViewById(R.id.tv_folder_name)).setText(R.string.qpy_app); + findViewById(R.id.iv_back).setOnClickListener(view -> AppListActivity.this.finish()); + getScriptList(); } +// 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; +// } +// } + +// @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(); +// } +// } +// } + + @RequiresApi(api = Build.VERSION_CODES.N_MR1) + private void test(){ + judgeShortcutNameV2("org.qpython.qpy"); + } + + private void createShortcutOnThis(){ + if (mBean == null){ + return; + } + + Intent intent = new Intent(); + intent.setClass(this, AppListActivity.class); + intent.setAction(Intent.ACTION_VIEW); + intent.putExtra("type", "script"); + intent.putExtra("path", mBean.getPath()); + intent.putExtra("isProj", mBean.isProj()); + + if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + ShortcutManager mShortcutManager = getSystemService(ShortcutManager.class); + if (mShortcutManager.isRequestPinShortcutSupported()) { + ShortcutInfo pinShortcutInfo = + new ShortcutInfo.Builder(this, mBean.getLabel()) + .setShortLabel(mBean.getLabel()) + .setLongLabel(mBean.getLabel()) + .setIcon(Icon.createWithResource(this, mBean.getIconRes())) + .setIntent(intent) + .build(); + Intent pinnedShortcutCallbackIntent = + mShortcutManager.createShortcutResultIntent(pinShortcutInfo); + PendingIntent successCallback = PendingIntent.getBroadcast(this, 0, + pinnedShortcutCallbackIntent, 0); + LogUtil.e("createShortcut: " + "111111111111"); + mShortcutManager.requestPinShortcut(pinShortcutInfo, + successCallback.getIntentSender()); + LogUtil.e("createShortcut: " + mBean.getLabel()); + new Handler().postDelayed(() -> { + judgeShortcutNameV2("org.qpython.qpy"); +// judgeShortcutName(mBean.getLabel()); + },200); + } + } else { + //Adding shortcut for MainActivity + //on Home screen + Intent addIntent = new Intent(); + addIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, intent); + addIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, mBean.getLabel()); + addIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, + Intent.ShortcutIconResource.fromContext(getApplicationContext(), + mBean.getIconRes())); + addIntent.setAction("com.android.launcher.action.INSTALL_SHORTCUT"); + getApplicationContext().sendBroadcast(addIntent); + Toast.makeText(this, getString(R.string.shortcut_create_suc, mBean.getLabel()), Toast.LENGTH_SHORT).show(); + } + } + +// private void judgeShortcutName(String name) { +// int shortcutNum = 0; +// for (String packageName : ShortcutUtil.getAllTheLauncher(getApplicationContext())) { +// LogUtil.e("packageName111111: " + packageName); +// if (name.equals(packageName)) { +// shortcutNum ++; +// } +// } +// LogUtil.e("packageName222222: " + shortcutNum); +// } + + @RequiresApi(api = Build.VERSION_CODES.N_MR1) + private void judgeShortcutNameV2(String name) { + if (!ShortcutUtil.getShortcutInfo(getApplicationContext()).isEmpty()){ + return; + } + Toast.makeText(this, getString(R.string.shortcut_create_fail), Toast.LENGTH_SHORT).show(); + } + private void getScriptList() { try { String projectPath = NAction.isQPy3(this.getApplicationContext())? QPyConstants.DFROM_PRJ3:QPyConstants.DFROM_PRJ2; - File[] projectFiles = FileHelper.getABSPath(QPyConstants.ABSOLUTE_PATH + "/" + projectPath).listFiles(); + File[] projectFiles = FileHelper.getABSPath(FileUtils.getAbsolutePath(getApplicationContext()) + "/" + projectPath).listFiles(); if (projectFiles != null) { Arrays.sort(projectFiles, FolderUtils.sortByName); dataList.clear(); @@ -135,7 +288,7 @@ private void getScriptList() { } String scriptPath = NAction.isQPy3(this.getApplicationContext())?QPyConstants.DFROM_QPY3:QPyConstants.DFROM_QPY2; - File[] files = FileHelper.getFilesByType(FileHelper.getABSPath(QPyConstants.ABSOLUTE_PATH + "/" + scriptPath)); + File[] files = FileHelper.getFilesByType(FileHelper.getABSPath(FileUtils.getAbsolutePath(getApplicationContext()) + "/" + scriptPath)); if (files!=null && files.length > 0) { Arrays.sort(files, FolderUtils.sortByName); for (File file : files) { diff --git a/qpython/src/main/java/org/qpython/qpy/main/activity/HomeMainActivity.java b/qpython/src/main/java/org/qpython/qpy/main/activity/HomeMainActivity.java index c058e0cd..685ed384 100644 --- a/qpython/src/main/java/org/qpython/qpy/main/activity/HomeMainActivity.java +++ b/qpython/src/main/java/org/qpython/qpy/main/activity/HomeMainActivity.java @@ -10,17 +10,21 @@ import android.databinding.DataBindingUtil; import android.net.Uri; import android.os.Bundle; -import android.os.Environment; import android.preference.PreferenceManager; import android.support.v4.app.ActivityCompat; import android.support.v7.app.AlertDialog; import android.text.Html; +import android.text.TextUtils; import android.util.Log; import android.view.View; import android.widget.Toast; +import com.gyf.cactus.Cactus; +import com.quseit.util.FileUtils; import com.quseit.util.NAction; import com.quseit.util.Utils; +import com.xiaomi.mipush.sdk.MiPushMessage; +import com.xiaomi.mipush.sdk.PushMessageHelper; import org.greenrobot.eventbus.Subscribe; import org.json.JSONException; @@ -30,34 +34,35 @@ import org.qpython.qpy.databinding.ActivityMainBinding; import org.qpython.qpy.main.app.App; import org.qpython.qpy.main.app.CONF; -import org.qpython.qpy.main.server.MySubscriber; -import org.qpython.qpy.main.server.model.CourseAdModel; import org.qpython.qpy.main.utils.Bus; import org.qpython.qpy.texteditor.EditorActivity; import org.qpython.qpy.texteditor.TedLocalActivity; +import org.qpython.qpy.utils.BrandUtil; +import org.qpython.qpy.utils.JumpToUtils; import org.qpython.qpy.utils.UpdateHelper; import org.qpython.qpysdk.QPyConstants; import org.qpython.qpysdk.QPySDK; import org.qpython.qpysdk.utils.FileHelper; -import org.qpython.qsl4a.QPyScriptService; import java.io.File; import java.io.InputStream; - -import rx.android.schedulers.AndroidSchedulers; -import rx.schedulers.Schedulers; +import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; import static org.qpython.qpysdk.QPyConstants.PYTHON_2; +/*** + * Qpython主页 + */ public class HomeMainActivity extends BaseActivity { - private static final String URL_COMMUNITY = "https://www.qpython.org/community.html"; - private static final String URL_COURSE = "https://edu.qpython.org/?from=qpy2"; private static final String USER_NAME = "username"; - private static final String TAG = "HomeMainActivity"; + private static final String TAG = "HomeMainActivity"; private static final int LOGIN_REQUEST_CODE = 136; private ActivityMainBinding binding; + private SharedPreferences preferences; public static void start(Context context) { Intent starter = new Intent(context, HomeMainActivity.class); @@ -73,11 +78,60 @@ public static void start(Context context, String userName) { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + preferences = PreferenceManager.getDefaultSharedPreferences(this); binding = DataBindingUtil.setContentView(this, R.layout.activity_main); //App.setActivity(this); startMain(); handlePython3(getIntent()); handleNotification(savedInstanceState); + getIntentData(getIntent()); + } + + /** + * 获取Intent数据,用于通知跳转 + * @param intent + */ + private void getIntentData(Intent intent) { + if (null != intent) { + // 获取data里的值 + Bundle bundle = intent.getExtras(); + if (bundle != null) { + String action = null; + String value = null; + if(BrandUtil.isBrandHuawei()) { + //华为通知 + action = bundle.getString(JumpToUtils.EXTRA_ACTION); + value = bundle.getString(JumpToUtils.EXTRA_VALUE); + } else if(BrandUtil.isBrandXiaoMi()) { + if (bundle.getSerializable(PushMessageHelper.KEY_MESSAGE) != null) { + //小米通知 + MiPushMessage message = (MiPushMessage) bundle.getSerializable(PushMessageHelper.KEY_MESSAGE); + Map extra = message.getExtra(); + action = extra.get(JumpToUtils.EXTRA_ACTION); + value = extra.get(JumpToUtils.EXTRA_VALUE); + } + } + + if(!TextUtils.isEmpty(action) && + !TextUtils.isEmpty(value)) { + delayNotifyJumpTo(action, value); + } + } + } + } + + /** + * 延迟跳转页面 + * @param action + * @param value + */ + private void delayNotifyJumpTo(String action, String value) { + new Timer().schedule(new TimerTask() { + @Override + public void run() { + JumpToUtils.jumpTo(HomeMainActivity.this, action, value); + } + }, 1000); } private void initIcon() { @@ -88,6 +142,8 @@ private void initIcon() { case "2.x": binding.icon.setImageResource(R.drawable.img_home_logo); break; + default: + break; } } @@ -101,7 +157,7 @@ private void initUser() { private void startMain() { initListener(); - startPyService(); +// startPyService(); Bus.getDefault().register(this); init(); if (ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { @@ -121,6 +177,7 @@ protected void onResume() { protected void onNewIntent(Intent intent) { super.onNewIntent(intent); handlePython3(intent); + getIntentData(intent); } private void initListener() { @@ -136,8 +193,10 @@ private void initListener() { }); binding.llTerminal.setOnClickListener(v -> { - TermActivity.startActivity(HomeMainActivity.this); - sendEvent(getString(R.string.event_term)); + openQpySDK(view -> { + TermActivity.startActivity(HomeMainActivity.this); + sendEvent(getString(R.string.event_term)); + }); }); binding.llTerminal.setOnLongClickListener(v -> { @@ -146,6 +205,8 @@ private void initListener() { .setTitle(R.string.choose_action) .setItems(chars, (dialog, which) -> { switch (which) { + default: + break; case 0: // Create Shortcut TermActivity.startActivity(HomeMainActivity.this); break; @@ -190,19 +251,22 @@ public void onClick(DialogInterface dialogInterface, int i) { sendEvent(getString(R.string.event_file)); }); binding.llQpyApp.setOnClickListener(v -> { - AppListActivity.start(this, AppListActivity.TYPE_SCRIPT); - overridePendingTransition(R.anim.fade_in, R.anim.fade_out); - sendEvent(getString(R.string.event_top)); + openQpySDK(view -> { + AppListActivity.start(HomeMainActivity.this, AppListActivity.TYPE_SCRIPT); + overridePendingTransition(R.anim.fade_in, R.anim.fade_out); + sendEvent(getString(R.string.event_top)); + }); }); - binding.llCourse.setOnClickListener(v -> { - CourseActivity.start(HomeMainActivity.this); - sendEvent(getString(R.string.event_course)); - }); -/* binding.llCourse.setOnClickListener(v -> - QWebViewActivity.start(HomeMainActivity.this, getString(R.string.course), URL_COURSE)); +// binding.llCourse.setOnClickListener(v -> { +// CourseActivity.start(HomeMainActivity.this); +// sendEvent(getString(R.string.event_course)); +// }); + String courseUrl = getString(R.string.url_course); + binding.llCourse.setOnClickListener(v -> + QWebViewActivity.start(HomeMainActivity.this, getString(R.string.course), courseUrl)); - initCourseListener();*/ +// initCourseListener(); } @@ -210,6 +274,11 @@ public void onClick(DialogInterface dialogInterface, int i) { protected void onDestroy() { super.onDestroy(); Bus.getDefault().unregister(this); + boolean isKeepAlive = preferences.getBoolean(getString(R.string.key_alive), false); + if (!isKeepAlive){ + return; + } + Cactus.getInstance().unregister(this); } private void handlePython3(Intent intent) { @@ -227,7 +296,7 @@ private void handlePython3(Intent intent) { } private void handleNotification(Bundle bundle) { - if (bundle == null) return; + if (bundle == null) {return;} if (!bundle.getBoolean("force") && !PreferenceManager.getDefaultSharedPreferences(this).getBoolean(getString(R.string.key_hide_push), true)) { return; } @@ -244,6 +313,7 @@ private void handleNotification(Bundle bundle) { Intent starter = new Intent(Intent.ACTION_VIEW, Uri.parse(link)); startActivity(starter); break; + default:break; } } } @@ -270,6 +340,7 @@ private void handleNotification() { Intent starter = new Intent(Intent.ACTION_VIEW, Uri.parse(link)); startActivity(starter); break; + default:break; } sharedPreferences.edit().clear().apply(); } catch (JSONException e) { @@ -310,28 +381,35 @@ protected void onPause() { super.onPause(); } - private void startPyService() { - Log.d(TAG, "startPyService"); - Intent intent = new Intent(this, QPyScriptService.class); - startService(intent); - } +// private void startPyService() { +// Log.d(TAG, "startPyService"); +// Intent intent = new Intent(this, QPyScriptService.class); +// startService(intent); +// } - private void openQpySDK() { + private void openQpySDK(View.OnClickListener clickListener) { Log.d("HomeMainActivity", "openQpySDK"); String[] permssions = {Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}; checkPermissionDo(permssions, new BaseActivity.PermissionAction() { @Override public void onGrant() { //这里只执行一次做为初始化 - if (!NAction.isQPyInterpreterSet(HomeMainActivity.this)) { new AlertDialog.Builder(HomeMainActivity.this, R.style.MyDialog) .setTitle(R.string.notice) .setMessage(R.string.py2_or_3) - .setPositiveButton(R.string.use_py3, (dialog1, which) -> initQpySDK3()) - .setNegativeButton(R.string.use_py2, (dialog1, which) -> initQpySDK()) + .setPositiveButton(R.string.use_py3, (dialog1, which) + -> { + initQpySDK3(clickListener); + }) + .setNegativeButton(R.string.use_py2, (dialog1, which) + -> { + initQpySDK(clickListener); + }) .create() .show(); + } else { + clickListener.onClick(null); } } @@ -345,20 +423,20 @@ public void onDeny() { /** * 在工作线程中作初始化 */ - private void initQpySDK3() { + private void initQpySDK3(View.OnClickListener clickListener) { Log.d(TAG, "initQpySDK3"); NAction.setQPyInterpreter(HomeMainActivity.this, "3.x"); - initQPy(true); + initQPy(true, clickListener); initIcon(); } - private void initQpySDK() { + private void initQpySDK(View.OnClickListener clickListener) { Log.d(TAG, "initQpySDK"); - initQPy(false); + initQPy(false, clickListener); NAction.setQPyInterpreter(HomeMainActivity.this, "2.x"); initIcon(); } - private void initQPy(boolean py3) { + private void initQPy(boolean py3, View.OnClickListener clickListener) { new Thread(() -> { QPySDK qpysdk = new QPySDK(HomeMainActivity.this, HomeMainActivity.this); //这里会在切换qpy3的时候再次释放相关资源 @@ -368,7 +446,7 @@ private void initQPy(boolean py3) { if (py3) { qpysdk.extractRes("notebook3", HomeMainActivity.this.getFilesDir()); } - File externalStorage = new File(Environment.getExternalStorageDirectory(), "qpython"); + File externalStorage = new File(FileUtils.getPath(App.getContext()), "qpython"); FileHelper.createDirIfNExists(externalStorage + "/cache"); FileHelper.createDirIfNExists(externalStorage + "/log"); FileHelper.createDirIfNExists(externalStorage + "/notebooks"); @@ -378,6 +456,7 @@ private void initQPy(boolean py3) { qpysdk.extractRes("ipynb", new File(externalStorage + "/notebooks")); extractRes(); + clickListener.onClick(null); }).start(); } @@ -386,7 +465,7 @@ private void initQPy(boolean py3) { * 初始化内置python项目 */ public void extractRes() { - File externalStorage = new File(QPyConstants.ABSOLUTE_PATH); + File externalStorage = new File(FileUtils.getAbsolutePath(getApplicationContext())); if (checkExpired("public", new File(externalStorage + "/lib").getAbsolutePath(), "programs"+NAction.getPyVer(this))) { String name, sFileName; InputStream content; @@ -403,23 +482,23 @@ public void extractRes() { content.reset(); if (sFileName.equals("projects2.zip")) { - Utils.createDirectoryOnExternalStorage("qpython/projects/"); - Utils.unzip(content, Environment.getExternalStorageDirectory().getAbsolutePath() + "/qpython/projects/", false); + Utils.createDirectoryOnExternalStorage(App.getContext(),"qpython/projects/"); + Utils.unzip(content, FileUtils.getQyPath(App.getContext()) + "/qpython/projects/", false); } else if (sFileName.equals("scripts2.zip")) { - Utils.unzip(content, Environment.getExternalStorageDirectory().getAbsolutePath() + "/qpython/scripts/", false); + Utils.unzip(content, FileUtils.getQyPath(App.getContext()) + "/qpython/scripts/", false); } else if (sFileName.equals("projects3.zip")) { - Utils.createDirectoryOnExternalStorage("qpython/projects3/"); - Utils.unzip(content, Environment.getExternalStorageDirectory().getAbsolutePath() + "/qpython/projects3/", false); + Utils.createDirectoryOnExternalStorage(App.getContext(),"qpython/projects3/"); + Utils.unzip(content, FileUtils.getQyPath(App.getContext()) + "/qpython/projects3/", false); } else if (sFileName.equals("scripts3.zip")) { - Utils.createDirectoryOnExternalStorage("qpython/scripts3/"); - Utils.unzip(content, Environment.getExternalStorageDirectory().getAbsolutePath() + "/qpython/scripts3/", false); + Utils.createDirectoryOnExternalStorage(App.getContext(),"qpython/scripts3/"); + Utils.unzip(content, FileUtils.getQyPath(App.getContext()) + "/qpython/scripts3/", false); } if (sFileName.equals("ipynb.zip")) { - Utils.createDirectoryOnExternalStorage("qpython/notebooks/"); - Utils.unzip(content, Environment.getExternalStorageDirectory().getAbsolutePath() + "/qpython/notebooks/", false); + Utils.createDirectoryOnExternalStorage(App.getContext(),"qpython/notebooks/"); + Utils.unzip(content, FileUtils.getQyPath(App.getContext()) + "/qpython/notebooks/", false); } } catch (Exception e) { @@ -431,7 +510,8 @@ public void extractRes() { } private void init() { - openQpySDK(); + //点击时再申请权限,加载资源方法 +// openQpySDK(null); } @Override @@ -470,4 +550,5 @@ public static class StartQrCodeActivityEvent { private void sendEvent(String evenName) { } + } diff --git a/qpython/src/main/java/org/qpython/qpy/main/activity/NotebookActivity.java b/qpython/src/main/java/org/qpython/qpy/main/activity/NotebookActivity.java index 38dbfe29..88f6b2b0 100644 --- a/qpython/src/main/java/org/qpython/qpy/main/activity/NotebookActivity.java +++ b/qpython/src/main/java/org/qpython/qpy/main/activity/NotebookActivity.java @@ -436,6 +436,7 @@ public boolean OnClickListener(String name) { } } + @Override public void toast(String msg) { Toast.makeText(this, msg, Toast.LENGTH_SHORT).show(); } diff --git a/qpython/src/main/java/org/qpython/qpy/main/activity/NotebookListActivity.java b/qpython/src/main/java/org/qpython/qpy/main/activity/NotebookListActivity.java index 7e7bb75f..28f2ec2b 100644 --- a/qpython/src/main/java/org/qpython/qpy/main/activity/NotebookListActivity.java +++ b/qpython/src/main/java/org/qpython/qpy/main/activity/NotebookListActivity.java @@ -9,9 +9,12 @@ import android.support.annotation.Nullable; import android.support.v7.widget.LinearLayoutManager; +import com.quseit.util.FileUtils; + import org.qpython.qpy.R; import org.qpython.qpy.databinding.ActivityNotebooklistBinding; import org.qpython.qpy.main.adapter.NotebookAdapter; +import org.qpython.qpy.main.app.App; import org.qpython.qpysdk.QPyConstants; import java.io.File; @@ -29,7 +32,7 @@ public class NotebookListActivity extends BaseActivity { private ActivityNotebooklistBinding mBinding; private NotebookAdapter mNotebookAdapter; private File mRootFile; - private static final String sdcard = Environment.getExternalStorageDirectory().getAbsolutePath(); + private static final String sdcard = FileUtils.getQyPath(App.getContext()); public static void start(Context context){ Intent intent = new Intent(context,NotebookListActivity.class); @@ -47,7 +50,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { } private void initRootDir() { - mRootFile = new File(QPyConstants.ABSOLUTE_PATH+"/notebooks"); + mRootFile = new File(FileUtils.getAbsolutePath(getApplicationContext()) +"/notebooks"); if (!mRootFile.exists()) { mRootFile.mkdirs(); } diff --git a/qpython/src/main/java/org/qpython/qpy/main/activity/QWebViewActivity.java b/qpython/src/main/java/org/qpython/qpy/main/activity/QWebViewActivity.java index e901c85f..eb3aa03f 100644 --- a/qpython/src/main/java/org/qpython/qpy/main/activity/QWebViewActivity.java +++ b/qpython/src/main/java/org/qpython/qpy/main/activity/QWebViewActivity.java @@ -32,6 +32,7 @@ import com.loopj.android.http.AsyncHttpResponseHandler; import com.quseit.base.QBaseApp; +import com.quseit.util.FileUtils; import com.quseit.util.NAction; import com.quseit.util.NUtil; @@ -224,16 +225,17 @@ public boolean onOptionsItemSelected(MenuItem item) { if (launchScript.contains("/scripts")) { String proj = new File(launchScript).getName(); - resultIntent.putExtra(LogActivity.LOG_PATH, QPyConstants.ABSOLUTE_LOG); + resultIntent.putExtra(LogActivity.LOG_PATH, FileUtils.getAbsoluteLogPath(App.getContext())); resultIntent.putExtra(LogActivity.LOG_TITLE, proj); } else { String proj = new File(launchScript).getParentFile().getName(); - resultIntent.putExtra(LogActivity.LOG_PATH, QPyConstants.ABSOLUTE_LOG); + resultIntent.putExtra(LogActivity.LOG_PATH, FileUtils.getAbsoluteLogPath(App.getContext())); resultIntent.putExtra(LogActivity.LOG_TITLE, proj); } startActivity(resultIntent); break; + default:break; } return true; } @@ -295,7 +297,7 @@ public void accessUrl() { } private void writeWebLog(String data) { - FileHelper.writeToFile(QPyConstants.ABSOLUTE_LOG,data+"\n", true); + FileHelper.writeToFile(FileUtils.getAbsoluteLogPath(App.getContext()),data+"\n", true); } // diff --git a/qpython/src/main/java/org/qpython/qpy/main/activity/SplashActivity.java b/qpython/src/main/java/org/qpython/qpy/main/activity/SplashActivity.java index 4d9fdfd6..09620f30 100644 --- a/qpython/src/main/java/org/qpython/qpy/main/activity/SplashActivity.java +++ b/qpython/src/main/java/org/qpython/qpy/main/activity/SplashActivity.java @@ -1,30 +1,164 @@ package org.qpython.qpy.main.activity; import android.content.Intent; +import android.databinding.DataBindingUtil; +import android.graphics.Color; +import android.net.Uri; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v7.app.AppCompatActivity; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.TextUtils; +import android.text.method.LinkMovementMethod; +import android.view.View; +import android.widget.Toast; + +import com.huawei.hms.analytics.HiAnalytics; +import com.huawei.hms.analytics.HiAnalyticsInstance; +import com.quseit.util.Log; +import com.xiaomi.mipush.sdk.MiPushMessage; +import com.xiaomi.mipush.sdk.PushMessageHelper; import org.qpython.qpy.R; +import org.qpython.qpy.databinding.ActivitySplashBinding; +import org.qpython.qpy.main.app.App; +import org.qpython.qpy.main.widget.MyCheckTextView; +import org.qpython.qpy.utils.BrandUtil; +import org.qpython.qpy.utils.JumpToUtils; +import java.util.Map; import java.util.Timer; import java.util.TimerTask; -public class SplashActivity extends AppCompatActivity { +public class SplashActivity extends AppCompatActivity implements View.OnClickListener, MyCheckTextView.ClickListener { + private final static String TAG = "SplashActivity"; + ActivitySplashBinding binding; + @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.activity_splash); + binding = DataBindingUtil.setContentView(this, R.layout.activity_splash); +// setContentView(R.layout.activity_splash); + initClick(); + initData(); + } + + private void initClick() { + binding.tvPositive.setOnClickListener(this); + binding.tvNegative.setOnClickListener(this); + } + + private void initData() { + setContent(); + setAgreeContent(); + judgeAgreementStatus(); + } + + private void setAgreeContent() { + String one = getString(R.string.user_agreement_bottom_split1); + String two = getString(R.string.user_agreement_bottom_split2); + String three = getString(R.string.user_agreement_bottom_split3); + String four = getString(R.string.user_agreement_bottom_split4); + + String content = one + two + three + four; + SpannableString str = new SpannableString(content); + str.setSpan(new MyCheckTextView(getApplicationContext(), 0, R.color.color_498fdd, this), one.length(), one.length() + two.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + str.setSpan(new MyCheckTextView(getApplicationContext(), 1, R.color.color_498fdd, this), one.length() + two.length() + three.length(), one.length() + two.length() + three.length() + four.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + + binding.tvAgreeContent.setText(str); + + //不设置 没有点击事件 + binding.tvAgreeContent.setMovementMethod(LinkMovementMethod.getInstance()); + //设置点击后的颜色为透明 + binding.tvAgreeContent.setHighlightColor(Color.TRANSPARENT); + + } + + private void setContent() { + binding.tvContent.setText(R.string.user_agreement_text); + } + + private void judgeAgreementStatus() { + if (App.getAgreementStatus()){ + delayJumpToMain(); + initHuaweiAnalytics(); + }else{ + binding.clAgreeLayout.setVisibility(View.VISIBLE); + } + } + + private void delayJumpToMain() { new Timer().schedule(new TimerTask() { @Override public void run() { - Intent intent = new Intent(SplashActivity.this,HomeMainActivity.class); - intent.setAction(getIntent().getAction()); - startActivity(intent); - finish(); + jumpToMain(); } - },1000); + }, 1000); } + private void jumpToMain(){ + Intent intent = new Intent(SplashActivity.this, HomeMainActivity.class); + intent.setAction(getIntent().getAction()); + + if(getIntent() != null) { + Bundle bundle = getIntent().getExtras(); + if (bundle != null) { + intent.putExtras(bundle); + } + } + + startActivity(intent); + finish(); + } + + /** + * 初始化华为分析 + */ + private void initHuaweiAnalytics() { + if(BrandUtil.isBrandHuawei()) { + //判断华为设备,初始化分析实例 + HiAnalyticsInstance instance = HiAnalytics.getInstance(this); + } + } + + @Override + public void onClick(View v) { + int id = v.getId(); + if (id == R.id.tv_positive) { + if(binding.cbxAgreeContent.isChecked()) { + App.setAgreementStatus(true); + App.initLibs(App.appInstance); + initHuaweiAnalytics(); + jumpToMain(); + } else { + Toast.makeText(this, R.string.user_aggreement_toast, + Toast.LENGTH_SHORT).show(); + } + } else if (id == R.id.tv_negative){ + finish(); + } + } + + @Override + public void click(int mark) { + if (mark == 0) { + goServiceAgreement(); + }else{ + goPrivacyAgreement(); + } + } + + private void goPrivacyAgreement() { +// QWebViewActivity.start(this, getString(R.string.privacy_agreement), getString(R.string.url_user_private)); + Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.url_user_private))); + startActivity(browserIntent); + } + + private void goServiceAgreement() { +// QWebViewActivity.start(this, getString(R.string.service_agreement), getString(R.string.url_user_agreement)); + Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.url_user_agreement))); + startActivity(browserIntent); + } } \ No newline at end of file diff --git a/qpython/src/main/java/org/qpython/qpy/main/adapter/AppListAdapter.java b/qpython/src/main/java/org/qpython/qpy/main/adapter/AppListAdapter.java index 920a5d19..a5cb6aa3 100644 --- a/qpython/src/main/java/org/qpython/qpy/main/adapter/AppListAdapter.java +++ b/qpython/src/main/java/org/qpython/qpy/main/adapter/AppListAdapter.java @@ -28,6 +28,8 @@ import org.qpython.qpy.main.model.QPyScriptModel; import org.qpython.qpy.texteditor.EditorActivity; import org.qpython.qpy.texteditor.ui.view.EnterDialog; +import org.qpython.qsl4a.qsl4a.LogUtil; + import android.support.v7.app.AlertDialog; @@ -114,6 +116,8 @@ public void onBindViewHolder(MyViewHolder holder, int positi case 2: openToEdit(position); dialog.dismiss(); + default: + break; } }).setNegativeButton("CLOSE", new DialogInterface.OnClickListener() { @@ -146,6 +150,8 @@ public interface Callback { void runProject(QPyScriptModel item); + void createShortcut(QPyScriptModel item); + void exit(); } @@ -156,43 +162,46 @@ private boolean createShortCut(int position) { } // Create shortcut QPyScriptModel qPyScriptModel = (QPyScriptModel) dataList.get(position); - Intent intent = new Intent(); - intent.setClass(context, AppListActivity.class); - intent.setAction(Intent.ACTION_VIEW); - intent.putExtra("type", "script"); - intent.putExtra("path", qPyScriptModel.getPath()); - intent.putExtra("isProj", qPyScriptModel.isProj()); - - if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - ShortcutManager mShortcutManager = context.getSystemService(ShortcutManager.class); - if (mShortcutManager.isRequestPinShortcutSupported()) { - ShortcutInfo pinShortcutInfo = - new ShortcutInfo.Builder(context, dataList.get(position).getLabel()) - .setShortLabel(dataList.get(position).getLabel()) - .setLongLabel(dataList.get(position).getLabel()) - .setIcon(Icon.createWithResource(context, dataList.get(position).getIconRes())) - .setIntent(intent) - .build(); - Intent pinnedShortcutCallbackIntent = - mShortcutManager.createShortcutResultIntent(pinShortcutInfo); - PendingIntent successCallback = PendingIntent.getBroadcast(context, 0, - pinnedShortcutCallbackIntent, 0); - mShortcutManager.requestPinShortcut(pinShortcutInfo, - successCallback.getIntentSender()); - } - } else { - //Adding shortcut for MainActivity - //on Home screen - Intent addIntent = new Intent(); - addIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, intent); - addIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, dataList.get(position).getLabel()); - addIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, - Intent.ShortcutIconResource.fromContext(context.getApplicationContext(), - dataList.get(position).getIconRes())); - addIntent.setAction("com.android.launcher.action.INSTALL_SHORTCUT"); - context.getApplicationContext().sendBroadcast(addIntent); - Toast.makeText(context, context.getString(R.string.shortcut_create_suc, dataList.get(position).getLabel()), Toast.LENGTH_SHORT).show(); - } +// Intent intent = new Intent(); +// intent.setClass(context, AppListActivity.class); +// intent.setAction(Intent.ACTION_VIEW); +// intent.putExtra("type", "script"); +// intent.putExtra("path", qPyScriptModel.getPath()); +// intent.putExtra("isProj", qPyScriptModel.isProj()); +// +// if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { +// ShortcutManager mShortcutManager = context.getSystemService(ShortcutManager.class); +// if (mShortcutManager.isRequestPinShortcutSupported()) { +// ShortcutInfo pinShortcutInfo = +// new ShortcutInfo.Builder(context, dataList.get(position).getLabel()) +// .setShortLabel(dataList.get(position).getLabel()) +// .setLongLabel(dataList.get(position).getLabel()) +// .setIcon(Icon.createWithResource(context, dataList.get(position).getIconRes())) +// .setIntent(intent) +// .build(); +// Intent pinnedShortcutCallbackIntent = +// mShortcutManager.createShortcutResultIntent(pinShortcutInfo); +// PendingIntent successCallback = PendingIntent.getBroadcast(context, 0, +// pinnedShortcutCallbackIntent, 0); +// +// boolean aaa = mShortcutManager.requestPinShortcut(pinShortcutInfo, +// successCallback.getIntentSender()); +// LogUtil.e("11111111111" + aaa); +// } +// } else { +// //Adding shortcut for MainActivity +// //on Home screen +// Intent addIntent = new Intent(); +// addIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, intent); +// addIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, dataList.get(position).getLabel()); +// addIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, +// Intent.ShortcutIconResource.fromContext(context.getApplicationContext(), +// dataList.get(position).getIconRes())); +// addIntent.setAction("com.android.launcher.action.INSTALL_SHORTCUT"); +// context.getApplicationContext().sendBroadcast(addIntent); +// Toast.makeText(context, context.getString(R.string.shortcut_create_suc, dataList.get(position).getLabel()), Toast.LENGTH_SHORT).show(); +// } + callback.createShortcut(qPyScriptModel); return true; } diff --git a/qpython/src/main/java/org/qpython/qpy/main/adapter/CloudScriptAdapter.java b/qpython/src/main/java/org/qpython/qpy/main/adapter/CloudScriptAdapter.java index 7df33aca..4efc8958 100644 --- a/qpython/src/main/java/org/qpython/qpy/main/adapter/CloudScriptAdapter.java +++ b/qpython/src/main/java/org/qpython/qpy/main/adapter/CloudScriptAdapter.java @@ -6,6 +6,8 @@ import android.view.ViewGroup; +import com.quseit.util.FileUtils; + import org.qpython.qpy.R; import org.qpython.qpy.codeshare.pojo.CloudFile; import org.qpython.qpy.databinding.ItemFolderBinding; @@ -50,7 +52,7 @@ public void onBindViewHolder(MyViewHolder holder, int positio } else { binding.uploading.setVisibility(View.GONE); } - if (new File(QPyConstants.ABSOLUTE_PATH + cloudFile.getPath()).exists()) { + if (new File(FileUtils.getAbsolutePath(binding.uploaded.getContext().getApplicationContext()) + cloudFile.getPath()).exists()) { binding.uploaded.setImageResource(R.drawable.ic_check_circle); binding.uploaded.setVisibility(View.VISIBLE); } else { diff --git a/qpython/src/main/java/org/qpython/qpy/main/app/App.java b/qpython/src/main/java/org/qpython/qpy/main/app/App.java index 95ea64e2..54d5f786 100644 --- a/qpython/src/main/java/org/qpython/qpy/main/app/App.java +++ b/qpython/src/main/java/org/qpython/qpy/main/app/App.java @@ -1,26 +1,50 @@ package org.qpython.qpy.main.app; +import android.app.ActivityManager; import android.content.Context; +import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Configuration; import android.content.res.Resources; import android.os.Build; +import android.os.Process; +import android.preference.PreferenceManager; import android.support.multidex.MultiDex; import android.support.v7.app.AppCompatActivity; +import android.util.Log; import com.google.gson.Gson; +import com.gyf.cactus.Cactus; +import com.gyf.cactus.callback.CactusCallback; +import com.huawei.agconnect.common.network.AccessNetworkManager; +import com.huawei.hmf.tasks.OnCompleteListener; +import com.huawei.hmf.tasks.Task; +import com.huawei.hms.aaid.HmsInstanceId; +import com.huawei.hms.common.ApiException; +import com.huawei.hms.push.HmsMessaging; import com.quseit.common.CrashHandler; import com.quseit.common.updater.downloader.DefaultDownloader; +import com.quseit.util.FileUtils; import com.squareup.leakcanary.LeakCanary; +import com.xiaomi.channel.commonutils.logger.LoggerInterface; +import com.xiaomi.mipush.sdk.Logger; +import com.xiaomi.mipush.sdk.MiPushClient; +import org.qpython.qpy.R; +import org.qpython.qpy.codeshare.CONSTANT; +import org.qpython.qpy.main.activity.HomeMainActivity; import org.qpython.qpy.main.server.Service; import org.qpython.qpy.main.server.gist.Api; import org.qpython.qpy.main.server.gist.TokenManager; import org.qpython.qpy.main.server.gist.response.GistBean; import org.qpython.qpy.main.server.http.Retrofitor; +import org.qpython.qpy.utils.BrandUtil; +import org.qpython.qpy.utils.JumpToUtils; import org.qpython.qpy.utils.NotebookUtil; import org.qpython.qpysdk.QPyConstants; +import org.qpython.qsl4a.QPyScriptService; import org.qpython.qsl4a.QSL4APP; +import org.qpython.qsl4a.qsl4a.LogUtil; import java.util.ArrayList; import java.util.HashMap; @@ -35,21 +59,23 @@ import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory; import retrofit2.converter.gson.GsonConverterFactory; -public class App extends QSL4APP { +public class App extends QSL4APP implements CactusCallback{ + private static final String TAG = "MyApplication"; + public static App appInstance; private static Context sContext; - private static String sScriptPath; - private static String sProjectPath; + private static String sScriptPath; + private static String sProjectPath; //private static AppCompatActivity sActivity; - private static OkHttpClient okHttpClient; + private static OkHttpClient okHttpClient; private static HttpLoggingInterceptor interceptor; - private static Gson gson; + private static Gson gson; private static DefaultDownloader downloader; //保存user信息 - private static SharedPreferences mPreferences; + private static SharedPreferences mPreferences; private static Retrofit.Builder retrofitBuilder; @@ -87,7 +113,7 @@ public static Context getContext() { return sContext; } -// public static AppCompatActivity getActivity() { + // public static AppCompatActivity getActivity() { // return sActivity; // } // @@ -107,6 +133,18 @@ public static User getUser() { return user; } + public static boolean getAgreementStatus(){ + return mPreferences.getBoolean("user_agree_status",false); + } + + public static void setAgreementStatus(boolean status){ + SharedPreferences.Editor editor = mPreferences.edit(); + editor.putBoolean("user_agree_status",status); + if (!editor.commit()) { + editor.apply(); + } + } + public static DefaultDownloader getDownloader() { return downloader; } @@ -151,17 +189,16 @@ protected void attachBaseContext(Context base) { MultiDex.install(this); } - @Override - public void onCreate() { - super.onCreate(); - if (LeakCanary.isInAnalyzerProcess(this)) { + public static void initLibs(App app) { + app.initConfiguration(); + if (LeakCanary.isInAnalyzerProcess(app)) { // This process is dedicated to LeakCanary for heap analysis. // You should not init your app in this process. return; } - LeakCanary.install(this); + LeakCanary.install(app); - sContext = getApplicationContext(); + sContext = app.getApplicationContext(); downloader = new DefaultDownloader(sContext); // init retrofit relate gson = new Gson(); @@ -178,17 +215,16 @@ public void onCreate() { .addCallAdapterFactory(RxJavaCallAdapterFactory.create()); mService = new Service(); - String basePath = QPyConstants.ABSOLUTE_PATH; + String basePath = FileUtils.getAbsolutePath(app.getApplicationContext()); sProjectPath = String.format("%s/%s", basePath, "projects"); sScriptPath = String.format("%s/%s", basePath, "scripts"); - initLayoutDir(); - mPreferences = this.getSharedPreferences("user", 0); - CrashHandler.getInstance().init(this); - AppInit.init(this); + app.initLayoutDir(); + CrashHandler.getInstance().init(app); + AppInit.init(app); Map header = new HashMap<>(); - TokenManager.init(this); + TokenManager.init(app); header.put("Content-Type", "application/json"); // if (!TextUtils.isEmpty(TokenManager.getToken())) { // header.put("HTTP_TOKEN", TokenManager.getToken()); @@ -197,7 +233,7 @@ public void onCreate() { .getInstance() .setTimeOut(Retrofitor.DEFAULT_TIMEOUT) // .openDebug(BuildConfig.DEBUG) - // .supportSSL(!BuildConfig.DEBUG) + // .supportSSL(!BuildConfig.DEBUG) .addHeaders(header) .init(Api.BASE_URL); @@ -208,13 +244,126 @@ public void onCreate() { // } // restart Notebook - if (NotebookUtil.isNBSrvSet(this)) { + if (NotebookUtil.isNBSrvSet(app)) { - NotebookUtil.killNBSrv(this); - NotebookUtil.startNotebookService2(this); + NotebookUtil.killNBSrv(app); + NotebookUtil.startNotebookService2(app); + } + + app.initCactus(); + + initPush(app); + initAnalytics(app); + } + + /** + * 初始化分析服务 + * @param context + */ + private static void initAnalytics(Context context) { + // todo 暂时注释起来,不启动华为分析服务,因与下载器冲突导致问题 +// AccessNetworkManager.getInstance().setAccessNetwork(true); + } + + /** + * 初始化推送 + */ + private static void initPush(Context context) { + if(BrandUtil.isBrandHuawei()) { + // 华为通道设置自动初始化 + HmsMessaging.getInstance(context).setAutoInitEnabled(true); + Log.d(TAG, "Init Push:Huawei"); + + try { + // 主题订阅 + HmsMessaging.getInstance(context).subscribe(JumpToUtils.EXTRA_TOPIC) + .addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(Task task) { + // 获取主题订阅的结果 + if (task.isSuccessful()) { + Log.i(TAG, "subscribe topic successfully"); + } else { + Log.e(TAG, "subscribe topic failed, return value is " + task.getException().getMessage()); + } + } + }); + } catch (Exception e) { + Log.e(TAG, "subscribe failed, catch exception : " + e.getMessage()); + } + } else if(BrandUtil.isBrandXiaoMi()) { + //初始化小米push推送服务 + if(shouldInit(context)) { + MiPushClient.registerPush(context, CONSTANT.MI_PUSH_APP_ID, CONSTANT.MI_PUSH_APP_KEY); + } + //打开Log + LoggerInterface newLogger = new LoggerInterface() { + @Override + public void setTag(String tag) { + // ignore + } + + @Override + public void log(String content, Throwable t) { + Log.d(TAG, content, t); + } + + @Override + public void log(String content) { + Log.d(TAG, content); + } + }; + Logger.setLogger(context, newLogger); } } + /** + * 小米通知,判断是否需要初始化 + * @return + */ + private static boolean shouldInit(Context context) { + ActivityManager am = ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)); + List processInfos = am.getRunningAppProcesses(); + String mainProcessName = context.getApplicationInfo().processName; + int myPid = Process.myPid(); + for (ActivityManager.RunningAppProcessInfo info : processInfos) { + if (info.pid == myPid && mainProcessName.equals(info.processName)) { + return true; + } + } + return false; + } + + @Override + public void onCreate() { + super.onCreate(); + appInstance = this; + mPreferences = getSharedPreferences("user", 0); + if (App.getAgreementStatus()) { + initLibs(this); + } + } + + private void initCactus() { + boolean isKeepAlive = PreferenceManager.getDefaultSharedPreferences(this).getBoolean(getString(R.string.key_alive), false); + LogUtil.e("isKeepAlive:" + isKeepAlive); + if (!isKeepAlive){ + LogUtil.e("doWork0000000"); + if (!isRunService( "org.qpython.qsl4a.QPyScriptService")) { + startPyService(); + } + return; + } + Cactus.getInstance() + .isDebug(true) + .setTitle("QPython") + .setContent("QPython service is alive") + .setLargeIcon(R.drawable.ic_launcher) + .setSmallIcon(R.drawable.ic_launcher) + .hideNotificationAfterO(false) + .addCallback(this) + .register(this); + } private void initLayoutDir() { if (Build.VERSION.SDK_INT >= 17) { @@ -225,4 +374,45 @@ private void initLayoutDir() { resources.updateConfiguration(config, resources.getDisplayMetrics()); } } + + /** + * 保活的回调接口 + * @param i + */ + @Override + public void doWork(int i) { + LogUtil.e("doWork1111111"); + if (!isRunService( "org.qpython.qsl4a.QPyScriptService")) { + startPyService(); + } + } + + /** + * 保活的回调接口 + */ + @Override + public void onStop() {} + + private void startPyService() { + LogUtil.e("doWork22222"); + Log.d(TAG, "startPyService"); + Intent intent = new Intent(this, QPyScriptService.class); + startService(intent); + } + + /** + * 判断服务是否在运行 + * + * @param serviceName + * @return 服务名称为全路径 例如com.ghost.WidgetUpdateService + */ + public boolean isRunService(String serviceName) { + ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE); + for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) { + if (serviceName.equals(service.service.getClassName())) { + return true; + } + } + return false; + } } diff --git a/qpython/src/main/java/org/qpython/qpy/main/app/CONF.java b/qpython/src/main/java/org/qpython/qpy/main/app/CONF.java index 6a37732c..898dc60a 100644 --- a/qpython/src/main/java/org/qpython/qpy/main/app/CONF.java +++ b/qpython/src/main/java/org/qpython/qpy/main/app/CONF.java @@ -6,18 +6,18 @@ public class CONF implements QPyConstants { - public static final String LIB_DOWNLOAD_TEMP = QPyConstants.ABSOLUTE_PATH + "/cache"; - public static final String QPYPI_URL = "https://pypi.org/simple/"; +// public static final String LIB_DOWNLOAD_TEMP = QPyConstants.ABSOLUTE_PATH + "/cache"; +// public static final String QPYPI_URL = "https://pypi.org/simple/"; public static final String NOTIFICATION_SP_NAME = "NOTIFICATION_EXTRA"; - public static final String NOTIFICATION_SP_OBJ = "NOTIFICATION_OBJ"; + public static final String NOTIFICATION_SP_OBJ = "NOTIFICATION_OBJ"; public static final String IAP_NUM_REQUEST_URL = "http://apu.quseit.com/conf/iaplognum/org.qpython.qpy/"; - public static final String GOOGLE_ID_TOKEN = "955258715976-i6t5usa0tjg8favq17lsfaj885l4lilv.apps.googleusercontent.com"; + public static final String GOOGLE_ID_TOKEN = "955258715976-i6t5usa0tjg8favq17lsfaj885l4lilv.apps.googleusercontent.com"; - public static final String CLOUD_MAP_CACHE_PATH = QPyConstants.ABSOLUTE_PATH + "/lib/.cloud_cache"; +// public static final String CLOUD_MAP_CACHE_PATH = QPyConstants.ABSOLUTE_PATH + "/lib/.cloud_cache"; public static String qpypiPath() { - return App.getContext().getFilesDir().getAbsolutePath() + "/lib/python"+(NAction.isQPy3(App.getContext())?"3.6":"2.7")+"/site-packages/"; + return App.getContext().getFilesDir().getAbsolutePath() + "/lib/python" + (NAction.isQPy3(App.getContext()) ? "3.6" : "2.7") + "/site-packages/"; } } diff --git a/qpython/src/main/java/org/qpython/qpy/main/event/Bean.java b/qpython/src/main/java/org/qpython/qpy/main/event/Bean.java index 12076c31..0d0dacb5 100644 --- a/qpython/src/main/java/org/qpython/qpy/main/event/Bean.java +++ b/qpython/src/main/java/org/qpython/qpy/main/event/Bean.java @@ -16,12 +16,16 @@ import org.qpython.qpy.main.activity.PurchaseActivity; import org.qpython.qpy.main.activity.QWebViewActivity; import org.qpython.qpy.main.activity.SettingActivity; +import org.qpython.qpy.main.app.App; import org.qpython.qpy.main.app.CONF; import org.qpython.qpy.main.utils.Utils; import org.qpython.qpy.texteditor.EditorActivity; +import com.quseit.common.updater.downloader.DefaultDownloader; import com.quseit.util.FileHelper; +import com.quseit.util.FileUtils; +import org.qpython.qpy.utils.DownloadUtil; import org.qpython.qpy.utils.NotebookUtil; import org.qpython.qpysdk.QPyConstants; @@ -160,7 +164,7 @@ public String isNetworkOk(Context context) { public String returnTmpScript(String xcode, String flag, String param) { try { // - File root = new File(QPyConstants.ABSOLUTE_PATH + "/cache"); + File root = new File(FileUtils.getLibDownloadTempPath(App.getContext())); if (root != null) { FileHelper.clearDir(root.toString(), 0, false); } @@ -182,7 +186,7 @@ public String returnTmpScript(String xcode, String flag, String param) { } } else { - py = QPyConstants.ABSOLUTE_PATH + "/cache/main.py"; + py = FileUtils.getAbsolutePath(App.getContext()) + "/cache/main.py"; if (xcode.contains("#{HEADER}")) { code = xcode.replace("#{HEADER}", "PARAM = '" + param + "'"); @@ -217,6 +221,19 @@ public void qeditor(String content) { EditorActivity.start(context, uri); } + @JavascriptInterface + public void download(String url, String mimeType, String title, String description) { + DownloadUtil.startDownloader(App.getContext(), url, System.nanoTime() + "", mimeType, + title, description); + } + + @JavascriptInterface + public void download(String url, String mimeType) { + DownloadUtil.startDownloader(App.getContext(), url, System.nanoTime() + "", mimeType, + "download", "download"); + } + + @JavascriptInterface public String qpyChecklibinstall(String cat, String smodule) { final File libFile = getLibFile(smodule, cat); @@ -239,13 +256,13 @@ public File getLibFile(String smodule, String cat) { File libFile; if (cat.equals("script")) { - libFile = new File(Environment.getExternalStorageDirectory(), "qpython/" + ubase + "/" + smodule); + libFile = new File(FileUtils.getPath(App.getContext()), "qpython/" + ubase + "/" + smodule); } else if (cat.equals("user")) { - libFile = new File(Environment.getExternalStorageDirectory(), "qpython/" + pbase + "/" + smodule); + libFile = new File(FileUtils.getPath(App.getContext()), "qpython/" + pbase + "/" + smodule); } else if (cat.equals("component")) { - libFile = new File(Environment.getExternalStorageDirectory(), "qpython/lib/" + smodule); + libFile = new File(FileUtils.getPath(App.getContext()), "qpython/lib/" + smodule); } else { libFile = new File(context.getFilesDir(), "/lib/" + sbase + "/site-packages/" + smodule); diff --git a/qpython/src/main/java/org/qpython/qpy/main/fragment/FileFragment.java b/qpython/src/main/java/org/qpython/qpy/main/fragment/FileFragment.java index 2e14b019..a967b92e 100644 --- a/qpython/src/main/java/org/qpython/qpy/main/fragment/FileFragment.java +++ b/qpython/src/main/java/org/qpython/qpy/main/fragment/FileFragment.java @@ -13,6 +13,7 @@ import android.widget.Toast; import com.quseit.util.FileHelper; +import com.quseit.util.FileUtils; import com.quseit.util.ImageUtil; import com.quseit.util.NAction; import com.yanzhenjie.recyclerview.swipe.SwipeMenuCreator; @@ -20,6 +21,7 @@ import org.qpython.qpy.R; import org.qpython.qpy.databinding.FragmentRefreshRvBinding; +import org.qpython.qpy.main.app.App; import org.qpython.qpy.texteditor.TedLocalActivity; import org.qpython.qpy.texteditor.ui.adapter.FolderAdapter; import org.qpython.qpy.texteditor.ui.adapter.bean.FolderBean; @@ -43,11 +45,11 @@ public class FileFragment extends Fragment { public static final String PROJECT3 = "projects3"; public static final String SCRIPT3 = "scripts3"; - private static final String PROJECT_PATH = QPyConstants.ABSOLUTE_PATH + "/" + PROJECT; - private static final String SCRIPT_PATH = QPyConstants.ABSOLUTE_PATH + "/" + SCRIPT; + private static final String PROJECT_PATH = FileUtils.getAbsolutePath(App.getContext()) + "/" + PROJECT; + private static final String SCRIPT_PATH = FileUtils.getAbsolutePath(App.getContext()) + "/" + SCRIPT; - private static final String PROJECT_PATH3 = QPyConstants.ABSOLUTE_PATH + "/" + PROJECT3; - private static final String SCRIPT_PATH3 = QPyConstants.ABSOLUTE_PATH + "/" + SCRIPT3; + private static final String PROJECT_PATH3 = FileUtils.getAbsolutePath(App.getContext()) + "/" + PROJECT3; + private static final String SCRIPT_PATH3 = FileUtils.getAbsolutePath(App.getContext()) + "/" + SCRIPT3; private FolderAdapter adapter; private List dataList; diff --git a/qpython/src/main/java/org/qpython/qpy/main/fragment/LibProjectFragment.java b/qpython/src/main/java/org/qpython/qpy/main/fragment/LibProjectFragment.java index d83dc827..5c7cdf94 100644 --- a/qpython/src/main/java/org/qpython/qpy/main/fragment/LibProjectFragment.java +++ b/qpython/src/main/java/org/qpython/qpy/main/fragment/LibProjectFragment.java @@ -17,6 +17,7 @@ import com.quseit.common.updater.downloader.Downloader; import com.quseit.util.ACache; +import com.quseit.util.FileUtils; import com.quseit.util.ImageUtil; import com.quseit.util.NAction; import com.quseit.util.NetStateUtil; @@ -49,14 +50,14 @@ */ public class LibProjectFragment extends RefreshFragment { - private static final int SCRIPT_CONSOLE_CODE = 1237; - private static String SCRIPT_DIR; // = QPyConstants.ABSOLUTE_PATH + "/" + QPyConstants.DFROM_QPY2 + "/"; - private static String PROJECT_DIR; // = QPyConstants.ABSOLUTE_PATH + "/" + QPyConstants.DFROM_PRJ2 + "/"; + private static final int SCRIPT_CONSOLE_CODE = 1237; + private static String SCRIPT_DIR; // = QPyConstants.ABSOLUTE_PATH + "/" + QPyConstants.DFROM_QPY2 + "/"; + private static String PROJECT_DIR; // = QPyConstants.ABSOLUTE_PATH + "/" + QPyConstants.DFROM_PRJ2 + "/"; - private List dataList; + private List dataList; private LibListAdapter adapter; private FragmentRefreshRvBinding binding; - private TextView header; + private TextView header; private int WIDTH = (int) ImageUtil.dp2px(60); @@ -77,8 +78,8 @@ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); binding = DataBindingUtil.bind(view); - SCRIPT_DIR = QPyConstants.ABSOLUTE_PATH + "/" + (NAction.isQPy3(getActivity())?QPyConstants.DFROM_QPY3:QPyConstants.DFROM_QPY2) +"/"; - PROJECT_DIR = QPyConstants.ABSOLUTE_PATH + "/" + (NAction.isQPy3(getActivity())?QPyConstants.DFROM_PRJ3:QPyConstants.DFROM_PRJ2) +"/"; + SCRIPT_DIR = FileUtils.getPath(App.getContext()) + "/qpython/" + (NAction.isQPy3(getActivity()) ? QPyConstants.DFROM_QPY3 : QPyConstants.DFROM_QPY2) + "/"; + PROJECT_DIR = FileUtils.getAbsolutePath(App.getContext()) + "/" + (NAction.isQPy3(getActivity()) ? QPyConstants.DFROM_PRJ3 : QPyConstants.DFROM_PRJ2) + "/"; initDataList(); initView(); @@ -161,6 +162,7 @@ private void openPip() { startActivity(intent); } } + private SwipeMenuCreator getMenu() { SwipeMenuItem detail = new SwipeMenuItem(getContext()) .setBackgroundColor(Color.parseColor("#FF4A4A4A")) @@ -201,33 +203,32 @@ private SwipeMenuCreator getMenu() { } - private void installTool(LibModel item) { String downloadDir = null; if (item.getCat().equals("script")) { - downloadDir = "qpython/"+(NAction.isQPy3(getActivity())?QPyConstants.DFROM_QPY3:QPyConstants.DFROM_QPY2); + downloadDir = "qpython/" + (NAction.isQPy3(getActivity()) ? QPyConstants.DFROM_QPY3 : QPyConstants.DFROM_QPY2); } else if (item.getCat().equals("user")) { - downloadDir = "qpython/"+(NAction.isQPy3(getActivity())?QPyConstants.DFROM_QPY3:QPyConstants.DFROM_QPY2); + downloadDir = "qpython/" + (NAction.isQPy3(getActivity()) ? QPyConstants.DFROM_QPY3 : QPyConstants.DFROM_QPY2); } // Download - App.getDownloader().download(item.getTitle(), item.getLink(), Environment.getExternalStorageDirectory()+"/"+downloadDir+"/"+item.getSmodule(), - new Downloader.Callback() { - @Override - public void pending(String name) { + App.getDownloader().download(item.getTitle(), item.getLink(), FileUtils.getPath(App.getContext()) + "/" + downloadDir + "/" + item.getSmodule(), + new Downloader.Callback() { + @Override + public void pending(String name) { - } + } - @Override - public void complete(String name, File installer) { - refresh(true); - } + @Override + public void complete(String name, File installer) { + refresh(true); + } - @Override - public void error(String err) { + @Override + public void error(String err) { - } - }); + } + }); } private void initListener() { diff --git a/qpython/src/main/java/org/qpython/qpy/main/fragment/SettingFragment.java b/qpython/src/main/java/org/qpython/qpy/main/fragment/SettingFragment.java index f5624c51..cd2a3e60 100644 --- a/qpython/src/main/java/org/qpython/qpy/main/fragment/SettingFragment.java +++ b/qpython/src/main/java/org/qpython/qpy/main/fragment/SettingFragment.java @@ -12,6 +12,7 @@ import android.os.Build; import android.os.Bundle; import android.os.Environment; +import android.os.Handler; import android.preference.CheckBoxPreference; import android.preference.Preference; import android.preference.PreferenceFragment; @@ -30,6 +31,7 @@ import com.loopj.android.http.JsonHttpResponseHandler; import com.quseit.base.QBaseApp; import com.quseit.common.updater.downloader.Downloader; +import com.quseit.util.FileUtils; import com.quseit.util.NAction; import com.quseit.util.NStorage; @@ -69,12 +71,12 @@ public class SettingFragment extends PreferenceFragment { private LoadingDialog mLoadingDialog; private SharedPreferences settings; - private Resources resources; - private Preference mPassWordPref, username_pref, portnum_pref, chroot_pref, lastlog; - private CheckBoxPreference sl4a, running_state, root, display_pwd, notebook_run; + private Resources resources; + private Preference mPassWordPref, username_pref, portnum_pref, chroot_pref, lastlog; + private CheckBoxPreference sl4a, running_state, root, display_pwd, notebook_run, keepAliveBox; - private PreferenceScreen py_inter,notebook_page; - private Preference py3,py2; //notebook_res, py2compatible + private PreferenceScreen py_inter, notebook_page; + private Preference py3, py2; //notebook_res, py2compatible //private Preference update_qpy3,update_qpy2compatible; private SwitchPreference log, app; @@ -99,7 +101,7 @@ public void onReceive(Context context, Intent intent) { static private String transformPassword(String password) { StringBuilder sb = new StringBuilder(password.length()); for (int i = 0; i < password.length(); ++i) - sb.append('*'); + {sb.append('*');} return sb.toString(); } @@ -140,7 +142,7 @@ private void initSettings() { ip = null; } - if (ip!=null) { + if (ip != null) { ipaddress.setSummary(ip.getHostAddress()); } else { ipaddress.setSummary(R.string.ip_address_need_wifi); @@ -153,7 +155,7 @@ private void initSettings() { notebook_page.setSummary(NotebookUtil.isNotebookLibInstall(getActivity()) ? R.string.notebook_installed : R.string.notebook_not_started); } else { - notebook_page.setSummary( R.string.notebook_py3_support); + notebook_page.setSummary(R.string.notebook_py3_support); } @@ -169,6 +171,7 @@ private void initSettings() { root = (CheckBoxPreference) findPreference(resources.getString(R.string.key_root)); + keepAliveBox = (CheckBoxPreference) findPreference(resources.getString(R.string.key_alive)); sl4a = (CheckBoxPreference) findPreference(resources.getString(R.string.key_sl4a)); app = (SwitchPreference) findPreference(getString(R.string.key_hide_push)); log = (SwitchPreference) findPreference(resources.getString(R.string.key_hide_noti)); @@ -185,6 +188,11 @@ private void initSettings() { root.setChecked(isRoot); root.setSummary(isRoot ? R.string.enable_root : R.string.disable_root); + boolean isKeepAlive; + isKeepAlive = settings.getBoolean(getString(R.string.key_alive), false); + keepAliveBox.setChecked(isKeepAlive); + keepAliveBox.setSummary(isKeepAlive ? R.string.enable_keep_alive : R.string.disable_keep_alive); + isRunning = isMyServiceRunning(QPyScriptService.class); sl4a.setChecked(isRunning); sl4a.setSummary(isRunning ? R.string.sl4a_running : R.string.sl4a_un_running); @@ -204,13 +212,14 @@ private void initSettings() { portnum_pref.setSummary(settings.getString(resources.getString(R.string.key_port_num), resources.getString(org.swiftp.R.string.portnumber_default))); chroot_pref.setSummary(settings.getString(resources.getString(R.string.key_root_dir), - Environment.getExternalStorageDirectory().getPath())); + FileUtils.getPath(App.getContext()).getPath())); py_inter.setSummary(NAction.isQPy3(getActivity()) ? R.string.py3_now : R.string.py2_now); //setNotebookCheckbox(); SharedPreferences.Editor editor = settings.edit(); editor.putBoolean(getString(R.string.key_root), root.isChecked()); + editor.putBoolean(getString(R.string.key_alive), keepAliveBox.isChecked()); //editor.putString(getString(R.string.key_qpypi), qpypi.getSummary().toString()); editor.putString(getString(R.string.key_username), username_pref.getSummary().toString()); editor.putString(getString(R.string.key_ftp_pwd), settings.getString(mPassWordPref.getKey(), "ftp")); @@ -249,7 +258,7 @@ private boolean isMyServiceRunning(Class serviceClass) { private void initListener() { lastlog.setOnPreferenceClickListener(preference -> { - Utils.checkRunTimeLog(getActivity(), getString(R.string.last_log), QPyConstants.ABSOLUTE_LOG); + Utils.checkRunTimeLog(getActivity(), getString(R.string.last_log), FileUtils.getAbsoluteLogPath(App.getContext())); return false; }); @@ -262,13 +271,13 @@ private void initListener() { notebook_run.setChecked(NotebookUtil.isNBSrvSet(getActivity())); notebook_run.setOnPreferenceChangeListener((preference, newValue) -> { - if ((boolean)newValue) { + if ((boolean) newValue) { NotebookUtil.startNotebookService2(getActivity()); } else { NotebookUtil.killNBSrv(getActivity()); } - notebook_page.setSummary(NotebookUtil.isNotebookEnable(getActivity())?R.string.notebook_installed : R.string.notebook_not_started); + notebook_page.setSummary(NotebookUtil.isNotebookEnable(getActivity()) ? R.string.notebook_installed : R.string.notebook_not_started); return true; }); @@ -305,6 +314,20 @@ private void initListener() { } }); + keepAliveBox.setOnPreferenceChangeListener((preference, newValue) -> + { + boolean isCheck = (boolean) newValue; + settings.edit().putBoolean(getString(R.string.key_alive), isCheck).apply(); + Toast.makeText(getActivity(), R.string.keep_alive_tips, Toast.LENGTH_SHORT).show(); + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + restartAppV2(); + } + },2000); + return true; + }); + sl4a.setOnPreferenceChangeListener((preference, newValue) -> { @@ -333,32 +356,32 @@ private void initListener() { }); findPreference(resources.getString(R.string.key_reset)). - setOnPreferenceClickListener(preference -> - { - NAction.startInstalledAppDetailsActivity(getActivity()); - return false; - }); + setOnPreferenceClickListener(preference -> + { + NAction.startInstalledAppDetailsActivity(getActivity()); + return false; + }); findPreference(resources.getString(R.string.key_about)). - setOnPreferenceClickListener(preference -> - { - AboutActivity.start(getActivity()); - return true; - }); + setOnPreferenceClickListener(preference -> + { + AboutActivity.start(getActivity()); + return true; + }); - findPreference("course"). - setOnPreferenceClickListener(preference -> - { - CourseActivity.start(getActivity()); - return true; - }); +// findPreference("course"). +// setOnPreferenceClickListener(preference -> +// { +// CourseActivity.start(getActivity()); +// return true; +// }); findPreference("community"). - setOnPreferenceClickListener(preference -> - { - startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(URL_COMMUNITY+"?from="+NAction.getCode(this.getActivity())))); - return true; - }); + setOnPreferenceClickListener(preference -> + { + startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(URL_COMMUNITY + "?from=" + NAction.getCode(this.getActivity())))); + return true; + }); /* ====================FTP==================== */ running_state.setOnPreferenceChangeListener((preference, newValue) -> { @@ -475,6 +498,14 @@ private void initListener() { }); } + private void restartAppV2() { + Intent intent = getActivity().getPackageManager().getLaunchIntentForPackage(getActivity().getPackageName()); + PendingIntent restartIntent = PendingIntent.getActivity(getActivity().getApplicationContext(), 0, intent, PendingIntent.FLAG_ONE_SHOT); + AlarmManager mgr = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE); + mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 1000, restartIntent); // 1秒钟后重启应用 + System.exit(0); + } + private void releaseNotebook(Preference preference) { Observable.create((Observable.OnSubscribe) subscriber -> { try { @@ -493,32 +524,32 @@ private void releaseNotebook(Preference preference) { } }) - .subscribeOn(Schedulers.io()) - .doOnSubscribe(() -> mLoadingDialog.show()) - .subscribeOn(AndroidSchedulers.mainThread()) - .observeOn(AndroidSchedulers.mainThread()) - .doOnTerminate(() -> mLoadingDialog.dismiss()) - .subscribe(new Observer() { - @Override - public void onCompleted() { + .subscribeOn(Schedulers.io()) + .doOnSubscribe(() -> mLoadingDialog.show()) + .subscribeOn(AndroidSchedulers.mainThread()) + .observeOn(AndroidSchedulers.mainThread()) + .doOnTerminate(() -> mLoadingDialog.dismiss()) + .subscribe(new Observer() { + @Override + public void onCompleted() { - } + } - @Override - public void onError(Throwable e) { + @Override + public void onError(Throwable e) { - } + } - @Override - public void onNext(Boolean aBoolean) { - Log.d(TAG, "onNext"); + @Override + public void onNext(Boolean aBoolean) { + Log.d(TAG, "onNext"); - NotebookUtil.startNotebookService2(getActivity()); - notebook_page.setSummary(NotebookUtil.isNotebookLibInstall(getActivity())?R.string.notebook_installed : R.string.notebook_not_started); + NotebookUtil.startNotebookService2(getActivity()); + notebook_page.setSummary(NotebookUtil.isNotebookLibInstall(getActivity()) ? R.string.notebook_installed : R.string.notebook_not_started); - } - }); + } + }); } private void installNotebook() { @@ -539,7 +570,7 @@ private void installNotebook() { private void extractNotebookRes(String path) { final String extarget = NotebookUtil.RELEASE_PATH; - if (path!=null && !path.equals("")) { + if (path != null && !path.equals("")) { File resf = new File(path); if (resf.exists()) { QPySDK qpySDK = new QPySDK(App.getContext(), getActivity()); @@ -550,9 +581,9 @@ private void extractNotebookRes(String path) { private void releaseQPycRes(String path) { - final String extarget = QPyConstants.PY_CACHE_PATH; + final String extarget = FileUtils.getPyCachePath(App.getContext()); - if (path!=null && !path.equals("")) { + if (path != null && !path.equals("")) { File res = new File(path); if (res.exists()) { @@ -569,7 +600,7 @@ private void releasePython2Standard(Preference preference) { QPySDK qpysdk = new QPySDK(getActivity(), getActivity()); qpysdk.extractRes("private1", getActivity().getFilesDir(), true); qpysdk.extractRes("private2", getActivity().getFilesDir(), true); - qpysdk.extractRes("private3", getActivity().getFilesDir(),true); + qpysdk.extractRes("private3", getActivity().getFilesDir(), true); subscriber.onNext(true); subscriber.onCompleted(); @@ -578,30 +609,30 @@ private void releasePython2Standard(Preference preference) { subscriber.onError(new Throwable("Failed to release Py2 resources")); } }) - .subscribeOn(Schedulers.io()) - .doOnSubscribe(() -> mLoadingDialog.show()) - .subscribeOn(AndroidSchedulers.mainThread()) - .observeOn(AndroidSchedulers.mainThread()) - .doOnTerminate(() -> mLoadingDialog.dismiss()) - .subscribe(new Observer() { - @Override - public void onCompleted() { + .subscribeOn(Schedulers.io()) + .doOnSubscribe(() -> mLoadingDialog.show()) + .subscribeOn(AndroidSchedulers.mainThread()) + .observeOn(AndroidSchedulers.mainThread()) + .doOnTerminate(() -> mLoadingDialog.dismiss()) + .subscribe(new Observer() { + @Override + public void onCompleted() { - } + } - @Override - public void onError(Throwable e) { - Toast.makeText(getActivity(), "Faild to extract Py2 resource", Toast.LENGTH_SHORT).show(); - } + @Override + public void onError(Throwable e) { + Toast.makeText(getActivity(), "Faild to extract Py2 resource", Toast.LENGTH_SHORT).show(); + } - @Override - public void onNext(Boolean aBoolean) { - NAction.setQPyInterpreter(getActivity(), "2.x"); - py_inter.setSummary(R.string.py2_now); + @Override + public void onNext(Boolean aBoolean) { + NAction.setQPyInterpreter(getActivity(), "2.x"); + py_inter.setSummary(R.string.py2_now); - getActivity().recreate(); - } - }); + getActivity().recreate(); + } + }); } private void releasePython2Compatable(Preference preference) { @@ -619,30 +650,30 @@ private void releasePython2Compatable(Preference preference) { subscriber.onError(new Throwable("Failed to release Py2 resources")); } }) - .subscribeOn(Schedulers.io()) - .doOnSubscribe(() -> mLoadingDialog.show()) - .subscribeOn(AndroidSchedulers.mainThread()) - .observeOn(AndroidSchedulers.mainThread()) - .doOnTerminate(() -> mLoadingDialog.dismiss()) - .subscribe(new Observer() { - @Override - public void onCompleted() { + .subscribeOn(Schedulers.io()) + .doOnSubscribe(() -> mLoadingDialog.show()) + .subscribeOn(AndroidSchedulers.mainThread()) + .observeOn(AndroidSchedulers.mainThread()) + .doOnTerminate(() -> mLoadingDialog.dismiss()) + .subscribe(new Observer() { + @Override + public void onCompleted() { - } + } - @Override - public void onError(Throwable e) { - Toast.makeText(getActivity(), "Faild to extract Py2 resource", Toast.LENGTH_SHORT).show(); - } + @Override + public void onError(Throwable e) { + Toast.makeText(getActivity(), "Faild to extract Py2 resource", Toast.LENGTH_SHORT).show(); + } - @Override - public void onNext(Boolean aBoolean) { - NAction.setQPyInterpreter(getActivity(), "2.x"); - py_inter.setSummary(R.string.py2_now); + @Override + public void onNext(Boolean aBoolean) { + NAction.setQPyInterpreter(getActivity(), "2.x"); + py_inter.setSummary(R.string.py2_now); - getActivity().recreate(); - } - }); + getActivity().recreate(); + } + }); } @@ -650,15 +681,15 @@ private void releasePython3(Preference preference) { QPySDK qpysdk = new QPySDK(this.getActivity(), this.getActivity()); Observable.create((Observable.OnSubscribe) subscriber -> { try { - releaseQPycRes(NStorage.getSP(App.getContext(),QPyConstants.KEY_PY3_RES)); + releaseQPycRes(NStorage.getSP(App.getContext(), QPyConstants.KEY_PY3_RES)); //extractQPyCore(false); qpysdk.extractRes("private31", getActivity().getFilesDir(), true); qpysdk.extractRes("private32", getActivity().getFilesDir(), true); - qpysdk.extractRes("private33", getActivity().getFilesDir(),true); + qpysdk.extractRes("private33", getActivity().getFilesDir(), true); qpysdk.extractRes("notebook3", getActivity().getFilesDir(), true); - File externalStorage = new File(Environment.getExternalStorageDirectory(), "qpython"); + File externalStorage = new File(FileUtils.getPath(App.getContext()), "qpython"); qpysdk.extractRes("publi3c", new File(externalStorage + "/lib")); @@ -669,30 +700,30 @@ private void releasePython3(Preference preference) { subscriber.onError(new Throwable("Failed to release Py3 resources")); } }) - .subscribeOn(Schedulers.io()) - .doOnSubscribe(() -> mLoadingDialog.show()) - .subscribeOn(AndroidSchedulers.mainThread()) - .observeOn(AndroidSchedulers.mainThread()) - .doOnTerminate(() -> mLoadingDialog.dismiss()) - .subscribe(new Observer() { - @Override - public void onCompleted() { + .subscribeOn(Schedulers.io()) + .doOnSubscribe(() -> mLoadingDialog.show()) + .subscribeOn(AndroidSchedulers.mainThread()) + .observeOn(AndroidSchedulers.mainThread()) + .doOnTerminate(() -> mLoadingDialog.dismiss()) + .subscribe(new Observer() { + @Override + public void onCompleted() { - } + } - @Override - public void onError(Throwable e) { - Toast.makeText(getActivity(), "Faild to extract Py3 resource", Toast.LENGTH_SHORT).show(); - } + @Override + public void onError(Throwable e) { + Toast.makeText(getActivity(), "Faild to extract Py3 resource", Toast.LENGTH_SHORT).show(); + } - @Override - public void onNext(Boolean aBoolean) { - NAction.setQPyInterpreter(getActivity(), "3.x"); - py_inter.setSummary(R.string.py3_now); + @Override + public void onNext(Boolean aBoolean) { + NAction.setQPyInterpreter(getActivity(), "3.x"); + py_inter.setSummary(R.string.py3_now); - getActivity().recreate(); - } - }); + getActivity().recreate(); + } + }); } @@ -757,206 +788,209 @@ private void getNotebook() { mLoadingDialog.show(); QBaseApp.getInstance().getAsyncHttpClient().get(getActivity(), NotebookUtil.getNBLink(getActivity()), - null, new JsonHttpResponseHandler() { - @Override - public void onSuccess(int statusCode, Header[] headers, JSONObject result) { - final String KEY_RES = "setting.notebookresource.ver"; - - try { - - final String notebook_resource_ver = NStorage.getSP(getActivity(), KEY_RES); - final String url = result.getString("link"); - final String target = result.getString("target"); - final String vercode = result.getString("vercode"); - final String title = result.getString("title"); - final String vername = result.getString("vername"); - final String path = NotebookUtil.RELEASE_PATH+"/"+target; - - NStorage.setSP(App.getContext(), NotebookUtil.getNbResFk(getActivity()), path); - - Log.d(TAG, "getNotebook:onSuccess:"+notebook_resource_ver+"["+vercode+"]"); + null, new JsonHttpResponseHandler() { + @Override + public void onSuccess(int statusCode, Header[] headers, JSONObject result) { + final String KEY_RES = "setting.notebookresource.ver"; - if (notebook_resource_ver.equals(vercode) && new File(path).exists()) { - mLoadingDialog.dismiss(); + try { - new AlertDialog.Builder(getActivity(), R.style.MyDialog) - .setTitle(title) - .setMessage(R.string.newest_resource) - .setPositiveButton(R.string.ok, (dialog1, which) -> { - try { - extractNotebookRes(path); - } catch (Exception e) { + final String notebook_resource_ver = NStorage.getSP(getActivity(), KEY_RES); + final String url = result.getString("link"); + final String target = result.getString("target"); + final String vercode = result.getString("vercode"); + final String title = result.getString("title"); + final String vername = result.getString("vername"); + final String path = NotebookUtil.RELEASE_PATH + "/" + target; - } - dialog1.dismiss(); - }) - .create() - .show(); + NStorage.setSP(App.getContext(), NotebookUtil.getNbResFk(getActivity()), path); - } else { - App.getDownloader().download(getString(R.string.download_notebook), url, path, new Downloader.Callback() { + Log.d(TAG, "getNotebook:onSuccess:" + notebook_resource_ver + "[" + vercode + "]"); - @Override - public void pending(String name) { - mLoadingDialog.cancel(); + if (notebook_resource_ver.equals(vercode) && new File(path).exists()) { + mLoadingDialog.dismiss(); new AlertDialog.Builder(getActivity(), R.style.MyDialog) - .setTitle(R.string.notice) - .setMessage(R.string.download_progress_need_sometime) - .setPositiveButton(R.string.ok, (dialog1, which) -> { - }) - .create() - .show(); - } + .setTitle(title) + .setMessage(R.string.newest_resource) + .setPositiveButton(R.string.ok, (dialog1, which) -> { + try { + extractNotebookRes(path); + } catch (Exception e) { + + } + dialog1.dismiss(); + }) + .create() + .show(); + + } else { + App.getDownloader().download(getString(R.string.download_notebook), url, path, new Downloader.Callback() { + + @Override + public void pending(String name) { + mLoadingDialog.cancel(); + + new AlertDialog.Builder(getActivity(), R.style.MyDialog) + .setTitle(R.string.notice) + .setMessage(R.string.download_progress_need_sometime) + .setPositiveButton(R.string.ok, (dialog1, which) -> { + }) + .create() + .show(); + } - @Override - public void complete(String name, File installer) { + @Override + public void complete(String name, File installer) { - Log.d(TAG, "getNotebook:complete:" + name + "[" + installer.getAbsolutePath() + "]"); - mLoadingDialog.dismiss(); + Log.d(TAG, "getNotebook:complete:" + name + "[" + installer.getAbsolutePath() + "]"); + mLoadingDialog.dismiss(); - NStorage.setSP(App.getContext(),KEY_RES, vercode); + NStorage.setSP(App.getContext(), KEY_RES, vercode); - // UNZIP resources && install - try { - extractNotebookRes(installer.getAbsolutePath()); - Toast.makeText(App.getContext(), R.string.file_downloaded, Toast.LENGTH_SHORT).show(); + // UNZIP resources && install + try { + extractNotebookRes(installer.getAbsolutePath()); + Toast.makeText(App.getContext(), R.string.file_downloaded, Toast.LENGTH_SHORT).show(); - } catch (Exception e) { + } catch (Exception e) { - } - } + } + } - @Override - public void error(String err) { - mLoadingDialog.cancel(); - try { - Toast.makeText(getActivity(), err, Toast.LENGTH_SHORT).show(); - } catch (Exception e) { + @Override + public void error(String err) { + mLoadingDialog.cancel(); + try { + Toast.makeText(getActivity(), err, Toast.LENGTH_SHORT).show(); + } catch (Exception e) { - } + } + } + }); } - }); + } catch (JSONException e) { + e.printStackTrace(); + } } - } catch (JSONException e) { - e.printStackTrace(); - } - } - @Override - public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { - // waitingWindow.dismiss(); - Log.d(TAG, "Error in checkConfUpdate:" + throwable.getMessage()); - } - }); + + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + // waitingWindow.dismiss(); + Log.d(TAG, "Error in checkConfUpdate:" + throwable.getMessage()); + } + }); } + private void getQPYC(boolean ispy2compatible) { mLoadingDialog.show(); - String conf_url = (ispy2compatible?QPyConstants.QPYC2COMPATIBLE:QPyConstants.QPYC3)+"?"+NAction.getUserUrl(getActivity()); + String conf_url = (ispy2compatible ? QPyConstants.QPYC2COMPATIBLE : QPyConstants.QPYC3) + "?" + NAction.getUserUrl(getActivity()); QBaseApp.getInstance().getAsyncHttpClient().get(getActivity(), conf_url, - null, new JsonHttpResponseHandler() { - @Override - public void onSuccess(int statusCode, Header[] headers, JSONObject result) { - final String KEY_RES = ispy2compatible?QPyConstants.QPYC2COMPATIBLE_VER_KEY:QPyConstants.QPYC3_VER_KEY; - - try { + null, new JsonHttpResponseHandler() { + @Override + public void onSuccess(int statusCode, Header[] headers, JSONObject result) { + final String KEY_RES = ispy2compatible ? QPyConstants.QPYC2COMPATIBLE_VER_KEY : QPyConstants.QPYC3_VER_KEY; - final String py_resource_ver = NStorage.getSP(getActivity(), KEY_RES); + try { - final String url = result.getString("link"); - final String target = result.getString("target"); - final String vercode = result.getString("vercode"); - final String title = result.getString("title"); - final String vername = result.getString("vername"); - final String path = QPyConstants.PY_CACHE_PATH + "/" + target; + final String py_resource_ver = NStorage.getSP(getActivity(), KEY_RES); - NStorage.setSP(App.getContext(), QPyConstants.KEY_PY3_RES, path); + final String url = result.getString("link"); + final String target = result.getString("target"); + final String vercode = result.getString("vercode"); + final String title = result.getString("title"); + final String vername = result.getString("vername"); + final String path = FileUtils.getPyCachePath(App.getContext()) + "/" + target; - Log.d(TAG, "getQPYC:onSuccess:"+py_resource_ver+"["+vercode+"]"); + NStorage.setSP(App.getContext(), QPyConstants.KEY_PY3_RES, path); - if (py_resource_ver.equals(vercode) && new File(path).exists()) { - mLoadingDialog.dismiss(); + Log.d(TAG, "getQPYC:onSuccess:" + py_resource_ver + "[" + vercode + "]"); - new AlertDialog.Builder(getActivity(), R.style.MyDialog) - .setTitle(title) - .setMessage(R.string.newest_resource) - .setPositiveButton(R.string.ok, (dialog1, which) -> { - try { - releaseQPycRes(path); - } catch (Exception e) { + if (py_resource_ver.equals(vercode) && new File(path).exists()) { + mLoadingDialog.dismiss(); + new AlertDialog.Builder(getActivity(), R.style.MyDialog) + .setTitle(title) + .setMessage(R.string.newest_resource) + .setPositiveButton(R.string.ok, (dialog1, which) -> { + try { + releaseQPycRes(path); + } catch (Exception e) { + + } + + dialog1.dismiss(); + }) + .create() + .show(); + + } else { + + App.getDownloader().download(getString(R.string.download_py), url, path, new Downloader.Callback() { + + @Override + public void pending(String name) { + mLoadingDialog.cancel(); + + new AlertDialog.Builder(getActivity(), R.style.MyDialog) + .setTitle(R.string.notice) + .setMessage(R.string.download_progress_need_sometime) + //.setNegativeButton(R.string.cancel, (dialog1, which) -> dialog1.dismiss()) + .setPositiveButton(R.string.ok, (dialog1, which) -> { + }) + .create() + .show(); } - dialog1.dismiss(); - }) - .create() - .show(); - - } else { - - App.getDownloader().download(getString(R.string.download_py), url, path, new Downloader.Callback() { - - @Override - public void pending(String name) { - mLoadingDialog.cancel(); + @Override + public void complete(String name, File installer) { - new AlertDialog.Builder(getActivity(), R.style.MyDialog) - .setTitle(R.string.notice) - .setMessage(R.string.download_progress_need_sometime) - //.setNegativeButton(R.string.cancel, (dialog1, which) -> dialog1.dismiss()) - .setPositiveButton(R.string.ok, (dialog1, which) -> { - }) - .create() - .show(); - } + Log.d(TAG, "getQPYC:complete:" + name + "[" + installer.getAbsolutePath() + "]"); + mLoadingDialog.dismiss(); - @Override - public void complete(String name, File installer) { + NStorage.setSP(App.getContext(), KEY_RES, vercode); + // UNZIP resources && install + try { + releaseQPycRes(installer.getAbsolutePath()); - Log.d(TAG, "getQPYC:complete:" + name + "[" + installer.getAbsolutePath() + "]"); - mLoadingDialog.dismiss(); - - NStorage.setSP(App.getContext(),KEY_RES, vercode); - // UNZIP resources && install - try { - releaseQPycRes(installer.getAbsolutePath()); - - } catch (Exception e) { + } catch (Exception e) { + } } - } - @Override - public void error(String err) { - mLoadingDialog.cancel(); - try { - Toast.makeText(getActivity(), err, Toast.LENGTH_SHORT).show(); - } catch (Exception e) { + @Override + public void error(String err) { + mLoadingDialog.cancel(); + try { + Toast.makeText(getActivity(), err, Toast.LENGTH_SHORT).show(); + } catch (Exception e) { + } } - } - }); + }); + } + } catch (JSONException e) { + e.printStackTrace(); } - } catch (JSONException e) { - e.printStackTrace(); - } - } - @Override - public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { - // waitingWindow.dismiss(); - Log.d(TAG, "Error in getQPYC:" + throwable.getMessage()); - } - }); + } + + @Override + public void onFailure(int statusCode, Header[] headers, String responseString, Throwable throwable) { + // waitingWindow.dismiss(); + Log.d(TAG, "Error in getQPYC:" + throwable.getMessage()); + } + }); } private boolean isQPycRelease(boolean ispy2compatible) { boolean isRelease = true; - String[] py3Mp3File = getActivity().getResources().getStringArray(ispy2compatible?R.array.qpy2compatible_zip:R.array.qpy3_zip); + String[] py3Mp3File = getActivity().getResources().getStringArray(ispy2compatible ? R.array.qpy2compatible_zip : R.array.qpy3_zip); for (String s : py3Mp3File) { - isRelease = isRelease && new File(QPyConstants.PY_CACHE_PATH + "/" + s).exists(); + isRelease = isRelease && new File(FileUtils.getPyCachePath(App.getContext()) + "/" + s).exists(); } return isRelease; } @@ -964,8 +998,8 @@ private boolean isQPycRelease(boolean ispy2compatible) { private void removeQPyc2Core() { Log.d(TAG, "removeQPyc2Core"); String files = getActivity().getFilesDir().getAbsolutePath(); - String[] files2del = {files+"/lib/notebook.zip", files+"/lib/python27.zip", files+"/lib/python2.7"}; - for (int i=0;i arguments = message.getCommandArguments(); + String cmdArg1 = ((arguments != null && arguments.size() > 0) ? arguments.get(0) : null); + String cmdArg2 = ((arguments != null && arguments.size() > 1) ? arguments.get(1) : null); + if (MiPushClient.COMMAND_REGISTER.equals(command)) { + if (message.getResultCode() == ErrorCode.SUCCESS) { + mRegId = cmdArg1; + + Log.d(TAG, "RegId:" + mRegId); + } + } + } + @Override + public void onReceiveRegisterResult(Context context, MiPushCommandMessage message) { + String command = message.getCommand(); + List arguments = message.getCommandArguments(); + String cmdArg1 = ((arguments != null && arguments.size() > 0) ? arguments.get(0) : null); + String cmdArg2 = ((arguments != null && arguments.size() > 1) ? arguments.get(1) : null); + if (MiPushClient.COMMAND_REGISTER.equals(command)) { + if (message.getResultCode() == ErrorCode.SUCCESS) { + mRegId = cmdArg1; + } + } + } +} \ No newline at end of file diff --git a/qpython/src/main/java/org/qpython/qpy/texteditor/EditorActivity.java b/qpython/src/main/java/org/qpython/qpy/texteditor/EditorActivity.java index db16f157..4430d905 100644 --- a/qpython/src/main/java/org/qpython/qpy/texteditor/EditorActivity.java +++ b/qpython/src/main/java/org/qpython/qpy/texteditor/EditorActivity.java @@ -31,6 +31,7 @@ import android.view.inputmethod.InputMethodManager; import com.quseit.util.FileHelper; +import com.quseit.util.FileUtils; import com.quseit.util.NAction; import com.quseit.util.NStorage; @@ -43,6 +44,7 @@ import org.qpython.qpy.main.activity.BaseActivity; import org.qpython.qpy.main.activity.GistEditActivity; import org.qpython.qpy.main.adapter.EditorFileTreeAdapter; +import org.qpython.qpy.main.app.App; import org.qpython.qpy.texteditor.common.RecentFiles; import org.qpython.qpy.texteditor.common.Settings; import org.qpython.qpy.texteditor.common.TextFileUtils; @@ -374,7 +376,7 @@ private void initFiles() { //String code = NAction.getCode(this); boolean isQpy3 = NAction.isQPy3(getApplication()); - String baseDir = QPyConstants.ABSOLUTE_PATH; + String baseDir = FileUtils.getAbsolutePath(App.getContext()); File root = new File(baseDir); if (!(root.exists() && root.isDirectory())) { root.mkdir(); @@ -889,7 +891,7 @@ protected void newScript() { .setTitle(getString(R.string.new_script)) .setExt(".py") .setConfirmListener(name -> { - File file = new File(QPyConstants.ABSOLUTE_PATH + "/" + (isQpy3? QPyConstants.DFROM_QPY3:QPyConstants.DFROM_QPY2) + "/" + name); + File file = new File(FileUtils.getAbsolutePath(App.getContext()) + "/" + (isQpy3? QPyConstants.DFROM_QPY3:QPyConstants.DFROM_QPY2) + "/" + name); if (file.exists()) { Crouton.showText(this, R.string.file_exists, Style.ALERT); @@ -924,7 +926,7 @@ protected void newProject(final String type) { Stack curArtistDir = new Stack<>(); final boolean isQpy3 = NAction.isQPy3(getApplicationContext()); - curArtistDir.push(QPyConstants.ABSOLUTE_PATH + curArtistDir.push(FileUtils.getAbsolutePath(App.getContext()) + "/" + (isQpy3 ? QPyConstants.DFROM_PRJ3 : QPyConstants.DFROM_PRJ2) + "/" + name); File fileN = new File(curArtistDir.peek()); diff --git a/qpython/src/main/java/org/qpython/qpy/texteditor/MFTPSettingActivity.java b/qpython/src/main/java/org/qpython/qpy/texteditor/MFTPSettingActivity.java index b3b45626..b77b1ea9 100644 --- a/qpython/src/main/java/org/qpython/qpy/texteditor/MFTPSettingActivity.java +++ b/qpython/src/main/java/org/qpython/qpy/texteditor/MFTPSettingActivity.java @@ -17,10 +17,12 @@ import android.widget.Toast; import com.quseit.base.QBaseDialog; +import com.quseit.util.FileUtils; import com.quseit.util.NAction; import com.quseit.util.NUtil; import org.qpython.qpy.R; +import org.qpython.qpy.main.app.App; import org.qpython.qpysdk.QPyConstants; import org.swiftp.Defaults; @@ -80,7 +82,7 @@ protected void onCreate(Bundle savedInstanceState) { //initWidgetTabItem(4); - String externalStorage = new File(Environment.getExternalStorageDirectory(), QPyConstants.BASE_PATH).getAbsolutePath(); + String externalStorage = new File(FileUtils.getPath(App.getContext()), QPyConstants.BASE_PATH).getAbsolutePath(); String frv = MessageFormat.format(getString(R.string.ftp_root), externalStorage); TextView fr = (TextView)findViewById(R.id.ftp_root_value); fr.setText(frv); @@ -125,7 +127,8 @@ public void onFTPOp(View v) { private void startServer() { Context context = getApplicationContext(); - NAction.setFtpRoot(context, Environment.getExternalStorageDirectory()+"/"+ QPyConstants.BASE_PATH); + NAction.setFtpRoot(context, FileUtils.getPath(App.getContext())+"/"+ QPyConstants.BASE_PATH); + Intent serverService = new Intent(context, FTPServerService.class); if (!org.swiftp.FTPServerService.isRunning()) { startService(serverService); diff --git a/qpython/src/main/java/org/qpython/qpy/texteditor/TedFragment.java b/qpython/src/main/java/org/qpython/qpy/texteditor/TedFragment.java index 7b1ee0ce..5437225d 100644 --- a/qpython/src/main/java/org/qpython/qpy/texteditor/TedFragment.java +++ b/qpython/src/main/java/org/qpython/qpy/texteditor/TedFragment.java @@ -25,6 +25,7 @@ import android.view.ViewGroup; import android.widget.Toast; +import com.quseit.util.FileUtils; import com.quseit.util.NAction; import com.quseit.util.NStorage; @@ -330,7 +331,7 @@ private void initSearchBarListener() { public void SnippetsList() { boolean isQpy3 = NAction.isQPy3(getContext()); List listItems = new ArrayList<>(); - String baseDir = Environment.getExternalStorageDirectory().getAbsolutePath() + String baseDir = FileUtils.getQyPath(App.getContext()) + "/" + QPyConstants.BASE_PATH; String path = baseDir + (isQpy3 ? "/snippets3/" : "/snippets/"); String files; @@ -367,7 +368,7 @@ public void SnippetsList() { */ public void insertSnippet(String snippetName) throws IOException { boolean isQPy3 = NAction.isQPy3(getContext()); - String baseDir = Environment.getExternalStorageDirectory().getAbsolutePath() + String baseDir = FileUtils.getQyPath(App.getContext()) + "/" + QPyConstants.BASE_PATH; String path = baseDir + (isQPy3 ? "/snippets3/" : "/snippets/"); String s; @@ -401,7 +402,7 @@ public void insertSnippet(String snippetName) throws IOException { public void saveCodeSnippet(String selectText) { boolean isQPy3 = NAction.isQPy3(getContext()); - String baseDir = Environment.getExternalStorageDirectory().getAbsolutePath() + String baseDir = FileUtils.getQyPath(App.getContext()) + "/" + QPyConstants.BASE_PATH; String path = baseDir + (isQPy3 ? "/snippets3/" : "/snippets/"); diff --git a/qpython/src/main/java/org/qpython/qpy/texteditor/androidlib/data/FileUtils.java b/qpython/src/main/java/org/qpython/qpy/texteditor/androidlib/data/FileUtils.java index 58b343f4..7846df31 100644 --- a/qpython/src/main/java/org/qpython/qpy/texteditor/androidlib/data/FileUtils.java +++ b/qpython/src/main/java/org/qpython/qpy/texteditor/androidlib/data/FileUtils.java @@ -18,14 +18,13 @@ @SuppressLint("DefaultLocale") public class FileUtils { /** File of the external storage data */ - public static final File STORAGE = Environment - .getExternalStorageDirectory(); - /** Path to the external storage data */ - public static final String STORAGE_PATH = STORAGE.getAbsolutePath(); - - /** default android Download folder */ - public static final String DOWNLOAD_FOLDER = (STORAGE.getAbsolutePath() - + File.separator + "Download"); +// public static final File STORAGE = Environment.getExternalStorageDirectory(); +// /** Path to the external storage data */ +// public static final String STORAGE_PATH = STORAGE.getAbsolutePath(); +// +// /** default android Download folder */ +// public static final String DOWNLOAD_FOLDER = (STORAGE.getAbsolutePath() +// + File.separator + "Download"); /** * Copy all files in the given asset folder to the destination folder (must diff --git a/qpython/src/main/java/org/qpython/qpy/texteditor/androidlib/ui/activity/BrowsingActivity.java b/qpython/src/main/java/org/qpython/qpy/texteditor/androidlib/ui/activity/BrowsingActivity.java index c1058cc9..640dd347 100644 --- a/qpython/src/main/java/org/qpython/qpy/texteditor/androidlib/ui/activity/BrowsingActivity.java +++ b/qpython/src/main/java/org/qpython/qpy/texteditor/androidlib/ui/activity/BrowsingActivity.java @@ -27,238 +27,243 @@ import java.util.List; /** - * + * */ public abstract class BrowsingActivity extends Activity implements - OnItemClickListener { - - /** The list of files to display */ - protected ArrayList mList; - /** the dialog's list view */ - protected ListView mFilesList; - /** The list adapter */ - protected FileListAdapter mListAdapter; - - /** the current folder */ - protected File mCurrentFolder; - - /** the current file sort */ - protected Comparator mComparator; - - protected boolean mShowFoldersOnly = false; - protected boolean mShowHiddenFiles = true; - protected boolean mHideNonWriteableFiles = false; - protected List mExtensionsWhiteList; - protected List mExtensionsBlackList; - - /** - * @see android.app.Activity#onCreate(android.os.Bundle) - */ - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - mExtensionsWhiteList = new ArrayList<>(); - mExtensionsBlackList = new ArrayList<>(); - mComparator = new ComparatorFilesAlpha(); - mListAdapter = new FileListAdapter(this, new LinkedList<>(), null); - } - - /** - * @see android.app.Activity#onResume() - */ - protected void onResume() { - super.onResume(); - - // Setup the widget - mFilesList = findViewById(android.R.id.list); - mFilesList.setOnItemClickListener(this); - - // set adapter - mFilesList.setAdapter(mListAdapter); - - // initial folder - File folder; - if (mCurrentFolder != null) { - folder = mCurrentFolder; - } else if ((FileUtils.STORAGE.exists()) - && (FileUtils.STORAGE.canRead())) { - folder = FileUtils.STORAGE; - } else { - folder = new File("/"); - } - - fillFolderView(folder); - } - - /** - * @see android.widget.AdapterView.OnItemClickListener#onItemClick(android.widget.AdapterView, - * android.view.View, int, long) - */ - public void onItemClick(AdapterView parent, View view, int position, - long id) { - File file, canon; - - file = mList.get(position); - canon = new File(FileUtils.getCanonizePath(file)); - - // safe check : file exists - if (file.exists()) { - if (file.isDirectory()) { - if (onFolderClick(file)) { - fillFolderView(canon); - } - } else { - onFileClick(canon); - } - } - } - - /** - * @param folder - * the folder being clicked - * @return if the folder should be opened in the browsing list view - */ - protected abstract boolean onFolderClick(File folder); - - /** - * @param file - * the file being clicked (it is not a folder) - */ - protected abstract void onFileClick(File file); - - /** - * Folder view has been filled - */ - protected abstract void onFolderViewFilled(); - - /** - * Fills the files list with the specified folder - * - * @param file - * the file of the folder to display - */ - @TargetApi(Build.VERSION_CODES.HONEYCOMB) - protected void fillFolderView(File file) { - file = new File(FileUtils.getCanonizePath(file)); - - if (!file.exists()) { - Crouton.makeText(this, R.string.toast_folder_doesnt_exist, - Style.ALERT).show(); - return; - } - - if (!file.isDirectory()) { - Crouton.makeText(this, R.string.toast_folder_not_folder, - Style.ALERT).show(); - return; - } - - if (!file.canRead()) { - Crouton.makeText(this, R.string.toast_folder_cant_read, Style.ALERT) - .show(); - return; - } - - listFiles(file); - - // create string list adapter - // mListAdapter = new FileListAdapter(this, mList, file); - mListAdapter.clear(); - mListAdapter.setCurrentFolder(file); - mListAdapter.addAll(mList); - mFilesList.scrollTo(0, 0); - - // update path - mCurrentFolder = file; - setTitle(file.getName()); - - onFolderViewFilled(); - } - - /** - * List the files in the given folder and store them in the list of files to - * display - * - * @param folder - * the folder to analyze - */ - protected void listFiles(File folder) { - File file; - - // get files list as array list - if ((folder == null) || (!folder.isDirectory())) { - mList = new ArrayList<>(); - return; - } - - mList = new ArrayList<>(Arrays.asList(folder.listFiles())); - - // filter files - for (int i = (mList.size() - 1); i >= 0; i--) { - file = mList.get(i); - - // remove - if (!(isFileVisible(file) && isFileTypeAllowed(file))) { - mList.remove(i); - } - } - - // Sort list - if (mComparator != null) { - Collections.sort(mList, mComparator); - } - - // Add parent folder - if (!folder.getPath().equals("/")) { - mList.add(0, folder.getParentFile()); - } - } - - protected boolean isFileVisible(File file) { - - boolean visible = true; - - // filter hidden files - if ((!mShowHiddenFiles) && (file.getName().startsWith("."))) { - visible = false; - } - - // filter non folders - if (mShowFoldersOnly && (!file.isDirectory())) { - visible = false; - } - - return visible; - } - - /** - * Filters files based on their extensions and white list / black list - * - * @param file - * the file to test - * @return if the file can be shown (either appear in white list or doesn't - * appear on blacklist) - */ - protected boolean isFileTypeAllowed(File file) { - boolean allow = true; - String ext; - - if (file.isFile()) { - ext = FileUtils.getFileExtension(file); - if ((mExtensionsWhiteList != null) - && (mExtensionsWhiteList.size() > 0) - && (!mExtensionsWhiteList.contains(ext))) { - allow = false; - } - - if ((mExtensionsBlackList != null) - && (mExtensionsBlackList.size() > 0) - && (mExtensionsBlackList.contains(ext))) { - allow = false; - } - } - - return allow; - } + OnItemClickListener { + + /** + * The list of files to display + */ + protected ArrayList mList; + /** + * the dialog's list view + */ + protected ListView mFilesList; + /** + * The list adapter + */ + protected FileListAdapter mListAdapter; + + /** + * the current folder + */ + protected File mCurrentFolder; + + /** + * the current file sort + */ + protected Comparator mComparator; + + protected boolean mShowFoldersOnly = false; + protected boolean mShowHiddenFiles = true; + protected boolean mHideNonWriteableFiles = false; + protected List mExtensionsWhiteList; + protected List mExtensionsBlackList; + + /** + * @see android.app.Activity#onCreate(android.os.Bundle) + */ + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + mExtensionsWhiteList = new ArrayList<>(); + mExtensionsBlackList = new ArrayList<>(); + mComparator = new ComparatorFilesAlpha(); + mListAdapter = new FileListAdapter(this, new LinkedList<>(), null); + } + + /** + * @see android.app.Activity#onResume() + */ + protected void onResume() { + super.onResume(); + + // Setup the widget + mFilesList = findViewById(android.R.id.list); + mFilesList.setOnItemClickListener(this); + + // set adapter + mFilesList.setAdapter(mListAdapter); + + // initial folder + File folder; + if (mCurrentFolder != null) { + folder = mCurrentFolder; + } else if ((com.quseit.util.FileUtils.getPath(getApplicationContext()).exists()) + && (com.quseit.util.FileUtils.getPath(getApplicationContext()).canRead())) { + folder = com.quseit.util.FileUtils.getPath(getApplicationContext()); + } else { + folder = new File("/"); + } + + fillFolderView(folder); + } + + /** + * @see android.widget.AdapterView.OnItemClickListener#onItemClick(android.widget.AdapterView, + * android.view.View, int, long) + */ + public void onItemClick(AdapterView parent, View view, int position, + long id) { + File file, canon; + + file = mList.get(position); + canon = new File(FileUtils.getCanonizePath(file)); + + // safe check : file exists + if (file.exists()) { + if (file.isDirectory()) { + if (onFolderClick(file)) { + fillFolderView(canon); + } + } else { + onFileClick(canon); + } + } + } + + /** + * @param folder the folder being clicked + * @return if the folder should be opened in the browsing list view + */ + protected abstract boolean onFolderClick(File folder); + + /** + * @param file the file being clicked (it is not a folder) + */ + protected abstract void onFileClick(File file); + + /** + * Folder view has been filled + */ + protected abstract void onFolderViewFilled(); + + /** + * Fills the files list with the specified folder + * + * @param file the file of the folder to display + */ + @TargetApi(Build.VERSION_CODES.HONEYCOMB) + protected void fillFolderView(File file) { + file = new File(FileUtils.getCanonizePath(file)); + + if (!file.exists()) { + Crouton.makeText(this, R.string.toast_folder_doesnt_exist, + Style.ALERT).show(); + return; + } + + if (!file.isDirectory()) { + Crouton.makeText(this, R.string.toast_folder_not_folder, + Style.ALERT).show(); + return; + } + + if (!file.canRead()) { + Crouton.makeText(this, R.string.toast_folder_cant_read, Style.ALERT) + .show(); + return; + } + + listFiles(file); + + // create string list adapter + // mListAdapter = new FileListAdapter(this, mList, file); + mListAdapter.clear(); + mListAdapter.setCurrentFolder(file); + mListAdapter.addAll(mList); + mFilesList.scrollTo(0, 0); + + // update path + mCurrentFolder = file; + setTitle(file.getName()); + + onFolderViewFilled(); + } + + /** + * List the files in the given folder and store them in the list of files to + * display + * + * @param folder the folder to analyze + */ + protected void listFiles(File folder) { + File file; + + // get files list as array list + if ((folder == null) || (!folder.isDirectory())) { + mList = new ArrayList<>(); + return; + } + + mList = new ArrayList<>(Arrays.asList(folder.listFiles())); + + // filter files + for (int i = (mList.size() - 1); i >= 0; i--) { + file = mList.get(i); + + // remove + if (!(isFileVisible(file) && isFileTypeAllowed(file))) { + mList.remove(i); + } + } + + // Sort list + if (mComparator != null) { + Collections.sort(mList, mComparator); + } + + // Add parent folder + if (!folder.getPath().equals("/")) { + mList.add(0, folder.getParentFile()); + } + } + + protected boolean isFileVisible(File file) { + + boolean visible = true; + + // filter hidden files + if ((!mShowHiddenFiles) && (file.getName().startsWith("."))) { + visible = false; + } + + // filter non folders + if (mShowFoldersOnly && (!file.isDirectory())) { + visible = false; + } + + return visible; + } + + /** + * Filters files based on their extensions and white list / black list + * + * @param file the file to test + * @return if the file can be shown (either appear in white list or doesn't + * appear on blacklist) + */ + protected boolean isFileTypeAllowed(File file) { + boolean allow = true; + String ext; + + if (file.isFile()) { + ext = FileUtils.getFileExtension(file); + if ((mExtensionsWhiteList != null) + && (mExtensionsWhiteList.size() > 0) + && (!mExtensionsWhiteList.contains(ext))) { + allow = false; + } + + if ((mExtensionsBlackList != null) + && (mExtensionsBlackList.size() > 0) + && (mExtensionsBlackList.contains(ext))) { + allow = false; + } + } + + return allow; + } } diff --git a/qpython/src/main/java/org/qpython/qpy/texteditor/androidlib/ui/adapter/FileListAdapter.java b/qpython/src/main/java/org/qpython/qpy/texteditor/androidlib/ui/adapter/FileListAdapter.java index 9c7de160..d7c44508 100644 --- a/qpython/src/main/java/org/qpython/qpy/texteditor/androidlib/ui/adapter/FileListAdapter.java +++ b/qpython/src/main/java/org/qpython/qpy/texteditor/androidlib/ui/adapter/FileListAdapter.java @@ -14,6 +14,7 @@ import android.widget.TextView; import org.qpython.qpy.R; +import org.qpython.qpy.main.app.App; import org.qpython.qpy.texteditor.androidlib.common.UIUtils; import org.qpython.qpy.texteditor.androidlib.data.FileUtils; @@ -100,7 +101,7 @@ public View getView(int position, View convertView, ViewGroup parent) { // } else { if (FileUtils.isSymLink(file)) { File target = FileUtils.getSymLinkTarget(file); - if (target.equals(FileUtils.STORAGE)) { + if (target.equals(com.quseit.util.FileUtils.getPath(App.getContext()))) { icon = R.drawable.prev; } else if (target.isDirectory()) { icon = R.drawable.ic_editor_folder_little; diff --git a/qpython/src/main/java/org/qpython/qpy/texteditor/common/Constants.java b/qpython/src/main/java/org/qpython/qpy/texteditor/common/Constants.java index 19581089..e2194b71 100644 --- a/qpython/src/main/java/org/qpython/qpy/texteditor/common/Constants.java +++ b/qpython/src/main/java/org/qpython/qpy/texteditor/common/Constants.java @@ -72,15 +72,14 @@ public interface Constants { */ int MENU_ID_QUIT = 666; - /** - * File of the external storage data - */ - File STORAGE = Environment - .getExternalStorageDirectory(); - /** - * Path to the external storage data - */ - String STORAGE_PATH = STORAGE.getAbsolutePath(); +// /** +// * File of the external storage data +// */ +// File STORAGE = Environment.getExternalStorageDirectory(); +// /** +// * Path to the external storage data +// */ +// String STORAGE_PATH = STORAGE.getAbsolutePath(); /** * name of the backup file */ diff --git a/qpython/src/main/java/org/qpython/qpy/utils/BrandUtil.java b/qpython/src/main/java/org/qpython/qpy/utils/BrandUtil.java new file mode 100644 index 00000000..0f670686 --- /dev/null +++ b/qpython/src/main/java/org/qpython/qpy/utils/BrandUtil.java @@ -0,0 +1,53 @@ +package org.qpython.qpy.utils; + +import android.os.Build; + +/** + * 用于判断设备类型 + */ +public class BrandUtil { + /** + * 判断是否为小米设备 + */ + public static boolean isBrandXiaoMi() { + return "xiaomi".equalsIgnoreCase(Build.BRAND) + || "xiaomi".equalsIgnoreCase(Build.MANUFACTURER); + } + + /** + * 判断是否为华为设备 + */ + public static boolean isBrandHuawei() { + return "huawei".equalsIgnoreCase(Build.BRAND) + || "huawei".equalsIgnoreCase(Build.MANUFACTURER); + } + + /** + * 判断是否为魅族设备 + */ + public static boolean isBrandMeizu() { + return "meizu".equalsIgnoreCase(Build.BRAND) + || "meizu".equalsIgnoreCase(Build.MANUFACTURER) + || "22c4185e".equalsIgnoreCase(Build.BRAND); + } + + /** + * 判断是否是oppo设备 + * + * @return + */ + public static boolean isBrandOppo() { + return "oppo".equalsIgnoreCase(Build.BRAND) + || "oppo".equalsIgnoreCase(Build.MANUFACTURER); + } + + /** + * 判断是否是vivo设备 + * + * @return + */ + public static boolean isBrandVivo() { + return "vivo".equalsIgnoreCase(Build.BRAND) + || "vivo".equalsIgnoreCase(Build.MANUFACTURER); + } +} diff --git a/qpython/src/main/java/org/qpython/qpy/utils/DownloadUtil.java b/qpython/src/main/java/org/qpython/qpy/utils/DownloadUtil.java new file mode 100644 index 00000000..fa912331 --- /dev/null +++ b/qpython/src/main/java/org/qpython/qpy/utils/DownloadUtil.java @@ -0,0 +1,66 @@ +package org.qpython.qpy.utils; + +import android.app.DownloadManager; +import android.content.Context; +import android.net.Uri; +import android.os.Environment; +import android.text.TextUtils; +import android.widget.Toast; + +import org.qpython.qpy.R; + +import java.io.File; + +/** + * @ProjectName: qpython + * @Package: org.qpython.qpy.utils + * @ClassName: DownloadUtil + * @Description: 下载应用类 + * @Author: wjx + * @CreateDate: 2022/1/11 16:39 + * @Version: 1.0 + */ +public class DownloadUtil { + public static void startDownloader(Context context, String url, String fileName, String mimeType, + String title, String description) { + if (TextUtils.isEmpty(url)) { + return; + } + try { + Uri uri = Uri.parse(url); + DownloadManager downloadManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); + DownloadManager.Request request = new DownloadManager.Request(uri); + // 在通知栏中显示 + request.setVisibleInDownloadsUi(true); + if(!TextUtils.isEmpty(title)) { + request.setTitle(title); + } else { + request.setTitle("download"); + } + if(!TextUtils.isEmpty(description)) { + request.setDescription(description); + } else { + request.setTitle("download"); + } + request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); + request.setMimeType(mimeType); + + String filePath = null; + if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {//SD卡是否正常挂载 + filePath = FileUtils.getAbsolutePath(context) + File.separator + "download"; + } else { + return; + } + + String downloadFilePath = filePath + File.separator + fileName; + // 若存在,则删除 +// deleteFile(downloadUpdateApkFilePath); + Uri fileUri = Uri.parse("file://" + downloadFilePath); + request.setDestinationUri(fileUri); + long downloadId = downloadManager.enqueue(request); + Toast.makeText(context, R.string.start_download, Toast.LENGTH_SHORT).show(); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/qpython/src/main/java/org/qpython/qpy/utils/FileUtils.java b/qpython/src/main/java/org/qpython/qpy/utils/FileUtils.java index d5d1b718..5c455977 100644 --- a/qpython/src/main/java/org/qpython/qpy/utils/FileUtils.java +++ b/qpython/src/main/java/org/qpython/qpy/utils/FileUtils.java @@ -15,6 +15,11 @@ import java.io.OutputStream; public class FileUtils { + + public static String getAbsolutePath(Context context){ + return context.getExternalFilesDir(null).getPath() + "/qpython"; + } + public static boolean copyToFile(InputStream inputStream, File destFile) { try { if (destFile.exists()) { diff --git a/qpython/src/main/java/org/qpython/qpy/utils/JumpToUtils.java b/qpython/src/main/java/org/qpython/qpy/utils/JumpToUtils.java new file mode 100644 index 00000000..54cba2af --- /dev/null +++ b/qpython/src/main/java/org/qpython/qpy/utils/JumpToUtils.java @@ -0,0 +1,31 @@ +package org.qpython.qpy.utils; + +import android.content.Context; + +import org.qpython.qpy.R; +import org.qpython.qpy.main.activity.QWebViewActivity; + +/** + * @ProjectName: qpython + * @Package: org.qpython.qpy.utils + * @ClassName: JumpToUtils + * @Description: 通知逻辑跳转相关 + * @Author: wjx + * @CreateDate: 2022/1/18 12:03 + * @Version: 1.0 + */ +public class JumpToUtils { + public final static String EXTRA_ACTION = "action"; + public final static String EXTRA_VALUE = "value"; + + public final static String EXTRA_TOPIC = "QPython"; + + private final static String JUMP_ACTION_WEB_PAGE = "jump_web_page"; + + public static void jumpTo(Context context, String action, String value) { + if(JUMP_ACTION_WEB_PAGE.equals(action)) { + QWebViewActivity.start(context, + context.getString(R.string.text_noti), value); + } + } +} diff --git a/qpython/src/main/java/org/qpython/qpy/utils/NotebookUtil.java b/qpython/src/main/java/org/qpython/qpy/utils/NotebookUtil.java index 1717f9e5..97c74fa9 100644 --- a/qpython/src/main/java/org/qpython/qpy/utils/NotebookUtil.java +++ b/qpython/src/main/java/org/qpython/qpy/utils/NotebookUtil.java @@ -8,6 +8,7 @@ import com.loopj.android.http.AsyncHttpResponseHandler; import com.quseit.base.QBaseApp; +import com.quseit.util.FileUtils; import com.quseit.util.NAction; import com.quseit.util.NStorage; import com.quseit.util.NUtil; @@ -41,12 +42,12 @@ public class NotebookUtil { private static final String TAG = "NotebookUtil"; - public static final String RELEASE_PATH = QPyConstants.ABSOLUTE_PATH + "/.notebook"; + public static final String RELEASE_PATH = FileUtils.getAbsolutePath(App.getContext()) + "/.notebook"; public static final String NB_SERVER = "http://127.0.0.1:13000"; public static final String KILL_SERVER = NB_SERVER + "/__exit"; public static final String NOTEBOOK_SERVER = NB_SERVER + "/notebooks/"; - public static final String NOTEBOOK_DIR = QPyConstants.ABSOLUTE_PATH+"/"; + public static final String NOTEBOOK_DIR = FileUtils.getAbsolutePath(App.getContext())+"/"; public static final String ext = ".ipynb"; public static final String Untitled = "Untitled"; @@ -226,7 +227,7 @@ public void onResponse(Call call, Response response) throws IOException { private static String getTempFilePath(String url) { //LogUtil.d("NotebookUtil", "getTempFilePath:"+url); - File dir = new File(QPyConstants.ABSOLUTE_PATH, "notebooks"); + File dir = new File(FileUtils.getAbsolutePath(App.getContext()), "notebooks"); if (!dir.exists()) { dir.mkdirs(); } diff --git a/qpython/src/main/java/org/qpython/qpy/utils/ShortcutUtil.java b/qpython/src/main/java/org/qpython/qpy/utils/ShortcutUtil.java new file mode 100644 index 00000000..d8fbd50c --- /dev/null +++ b/qpython/src/main/java/org/qpython/qpy/utils/ShortcutUtil.java @@ -0,0 +1,55 @@ +package org.qpython.qpy.utils; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.pm.ShortcutInfo; +import android.content.pm.ShortcutManager; +import android.os.Build; +import android.support.annotation.RequiresApi; + +import java.util.ArrayList; +import java.util.List; + +public class ShortcutUtil { + + public static List getAllTheLauncher(Context context) { + List names = new ArrayList<>(); + List packs = context.getPackageManager().getInstalledPackages(0); + for (int i = 0; i < packs.size(); i++) { + PackageInfo p = packs.get(i); + + + if (p.versionName == null) { + continue; + } + names.add(p.packageName); +// newInfo.appname = p.applicationInfo.loadLabel(context.getPackageManager()).toString(); +// newInfo.pname = p.packageName; +// newInfo.classname = p.applicationInfo.className; +// newInfo.versionCode = p.versionCode; +// newInfo.icon = p.applicationInfo.loadIcon(context.getPackageManager()); +// List names = null; +// PackageManager pkgMgt = context.getPackageManager(); +// Intent it = new Intent(Intent.ACTION_MAIN); +// it.addCategory(Intent.CATEGORY_LAUNCHER); +// List ra = pkgMgt.queryIntentActivities(it, 0); +// if (ra.size() != 0) { +// names = new ArrayList(); +// } +// for (int i = 0; i < ra.size(); i++) { +// String packageName = ra.get(i).activityInfo.packageName; +// names.add(packageName); +// } + } + return names; + } + + @RequiresApi(api = Build.VERSION_CODES.N_MR1) + public static List getShortcutInfo(Context context){ + ShortcutManager mShortcutManager = context.getSystemService(ShortcutManager.class); + return mShortcutManager.getPinnedShortcuts(); + } +} diff --git a/qpython/src/main/java/org/qpython/qpy/utils/UpdateHelper.java b/qpython/src/main/java/org/qpython/qpy/utils/UpdateHelper.java index 8b221d3b..b6a22862 100644 --- a/qpython/src/main/java/org/qpython/qpy/utils/UpdateHelper.java +++ b/qpython/src/main/java/org/qpython/qpy/utils/UpdateHelper.java @@ -24,6 +24,7 @@ import com.quseit.common.db.UserLog; import com.quseit.util.DateTimeHelper; import com.quseit.util.FileHelper; +import com.quseit.util.FileUtils; import com.quseit.util.NAction; import com.quseit.util.NUtil; import com.quseit.util.VeDate; @@ -169,7 +170,7 @@ public static void checkConfUpdate(Context context, String root) { checkConfUpdate(context.getApplicationContext()); // 清空图片目录的缓存 - String cacheDir = Environment.getExternalStorageDirectory() + "/" + root + "/" + BASE_CONF.DCACHE + "/"; + String cacheDir = FileUtils.getPath(context.getApplicationContext()) + "/" + root + "/" + BASE_CONF.DCACHE + "/"; FileHelper.clearDir(cacheDir, 0, false); } diff --git a/qpython/src/main/java/org/qpython/qpylib/MPyApi.java b/qpython/src/main/java/org/qpython/qpylib/MPyApi.java index c814676e..daa779fe 100644 --- a/qpython/src/main/java/org/qpython/qpylib/MPyApi.java +++ b/qpython/src/main/java/org/qpython/qpylib/MPyApi.java @@ -23,10 +23,12 @@ import org.qpython.qpy.console.ScriptExec; import com.quseit.util.FileHelper; +import com.quseit.util.FileUtils; import com.quseit.util.NAction; import com.quseit.util.NUtil; import org.qpython.qpy.main.activity.BaseActivity; +import org.qpython.qpy.main.app.App; import org.qpython.qpysdk.QPyConstants; import java.io.File; @@ -47,7 +49,7 @@ public void handleMessage(Message msg) { } }; private boolean live = false; - private String logF = QPyConstants.ABSOLUTE_LOG; + private String logF = FileUtils.getAbsoluteLogPath(App.getContext()); private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { @@ -139,7 +141,7 @@ private void process() { } else { runMode = 1; } - String script = QPyConstants.ABSOLUTE_PATH + "/cache/last.py"; + String script = FileUtils.getAbsolutePath(App.getContext()) + "/cache/last.py"; FileHelper.putFileContents(this, script, pycode); ScriptExec.getInstance().playScript(this,script, null, false); } @@ -226,7 +228,7 @@ protected void onAPIEnd() { } else { try { - String root = QBaseApp.getInstance().getOrCreateRoot(QPyConstants.DFROM_RUN); + String root = QBaseApp.getInstance().getOrCreateRoot(App.getContext(),QPyConstants.DFROM_RUN); File f = new File(root, ".last_tmp.py"); param = f.getAbsolutePath().toString(); } catch (Exception e) { @@ -242,7 +244,7 @@ protected void onAPIEnd() { rBundle.putString("result", result); rBundle.putString("param", param); rBundle.putString("flag", flag); - rBundle.putString("log", QPyConstants.ABSOLUTE_LOG); + rBundle.putString("log", FileUtils.getAbsoluteLogPath(App.getContext())); rIntent.putExtras(rBundle); diff --git a/qpython/src/main/java/org/qpython/qpylib/MPyService.java b/qpython/src/main/java/org/qpython/qpylib/MPyService.java index d0b6dc58..f64633ab 100644 --- a/qpython/src/main/java/org/qpython/qpylib/MPyService.java +++ b/qpython/src/main/java/org/qpython/qpylib/MPyService.java @@ -8,6 +8,7 @@ import android.support.annotation.Nullable; import com.quseit.util.FileHelper; +import com.quseit.util.FileUtils; import com.quseit.util.NAction; import com.quseit.util.NUtil; @@ -79,7 +80,7 @@ private void process(Intent intent) { } else { runMode = 1; } - String script = QPyConstants.ABSOLUTE_PATH + "/cache/last.py"; + String script = FileUtils.getAbsolutePath(App.getContext()) + "/cache/last.py"; FileHelper.putFileContents(this, script, pycode); ScriptExec.getInstance().playScript(MPyService.this, script, null, false); } diff --git a/qpython/src/main/res/drawable/agree_confirm_btn.xml b/qpython/src/main/res/drawable/agree_confirm_btn.xml new file mode 100644 index 00000000..c61413a4 --- /dev/null +++ b/qpython/src/main/res/drawable/agree_confirm_btn.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/qpython/src/main/res/drawable/top_white_r10.xml b/qpython/src/main/res/drawable/top_white_r10.xml new file mode 100644 index 00000000..01a09b4b --- /dev/null +++ b/qpython/src/main/res/drawable/top_white_r10.xml @@ -0,0 +1,10 @@ + + + + + + + + \ No newline at end of file diff --git a/qpython/src/main/res/layout-land/activity_main.xml b/qpython/src/main/res/layout-land/activity_main.xml index daeca16c..08481d5e 100644 --- a/qpython/src/main/res/layout-land/activity_main.xml +++ b/qpython/src/main/res/layout-land/activity_main.xml @@ -202,7 +202,7 @@ android:id="@+id/ll_course" style="@style/row_ll"> - + android:textColor="#FFF"/> + android:text="@string/check_update" /> - - + + + + + + + + android:background="@null" /> \ No newline at end of file diff --git a/qpython/src/main/res/layout/activity_main.xml b/qpython/src/main/res/layout/activity_main.xml index 265907b4..c1a8801b 100644 --- a/qpython/src/main/res/layout/activity_main.xml +++ b/qpython/src/main/res/layout/activity_main.xml @@ -150,22 +150,25 @@ - + android:text="@string/course" + android:textColor="#FFF"/> + @@ -211,21 +214,20 @@ android:textColor="#FFF"/> - diff --git a/qpython/src/main/res/layout/activity_splash.xml b/qpython/src/main/res/layout/activity_splash.xml index ce6f6cd4..bd000639 100644 --- a/qpython/src/main/res/layout/activity_splash.xml +++ b/qpython/src/main/res/layout/activity_splash.xml @@ -1,16 +1,125 @@ - + - - - + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/qpython/src/main/res/values-ja/strings.xml b/qpython/src/main/res/values-ja/strings.xml index 18a6d9fb..06df6638 100644 --- a/qpython/src/main/res/values-ja/strings.xml +++ b/qpython/src/main/res/values-ja/strings.xml @@ -412,6 +412,7 @@ ログアウトしますか? ログ通知 アプリの通知 + Notification ローカルのファイルを上書きしますか? ファイルがダウンロードされました。 ログイン中にエラーが発生しました。 @@ -430,6 +431,7 @@ 新規ファイル ツール 依存しているパッケージをインストールしてからAIPYをインストールしてください。]]> + Welcome to Use QPython @@ -486,4 +488,8 @@ 現在Python2を使用中です。Python3に切り替えますか? 設定に移動 ネットワークにラグが発生しています。しばらくお待ちください。 + You can run QPython script even it\'s in background if this mode is enabled. + Disable + QPython will restart to apply changes. + "Please grant the creat shortcut permission. " diff --git a/qpython/src/main/res/values-ru/strings.xml b/qpython/src/main/res/values-ru/strings.xml index 33a26d74..9162ff56 100644 --- a/qpython/src/main/res/values-ru/strings.xml +++ b/qpython/src/main/res/values-ru/strings.xml @@ -430,4 +430,9 @@ w Подтвердить Я Необходимо получить разрешение для доступа к хранилищу. Не могу подключиться к серверу Google. Пожалуйста, проверьте ваше соединение. + You can run QPython script even it\'s in background if this mode is enabled. + Disable + QPython will restart to apply changes. + "Please grant the creat shortcut permission. " + Welcome to Use QPython \ No newline at end of file diff --git a/qpython/src/main/res/values-v11/strings.xml b/qpython/src/main/res/values-v11/strings.xml new file mode 100644 index 00000000..55344e51 --- /dev/null +++ b/qpython/src/main/res/values-v11/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/qpython/src/main/res/values-v21/strings.xml b/qpython/src/main/res/values-v21/strings.xml new file mode 100644 index 00000000..55344e51 --- /dev/null +++ b/qpython/src/main/res/values-v21/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/qpython/src/main/res/values-w820dp/strings.xml b/qpython/src/main/res/values-w820dp/strings.xml new file mode 100644 index 00000000..55344e51 --- /dev/null +++ b/qpython/src/main/res/values-w820dp/strings.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/qpython/src/main/res/values-zh-rCN/strings.xml b/qpython/src/main/res/values-zh-rCN/strings.xml index aeff98b2..ea8ed7b4 100644 --- a/qpython/src/main/res/values-zh-rCN/strings.xml +++ b/qpython/src/main/res/values-zh-rCN/strings.xml @@ -114,12 +114,13 @@ 确定 + 同意 + 不同意 关闭 没有任何改变 意见反馈 关于 文件不存在 - m 启用Root权限 发送 没有发现可用的摄像头,请查看是否开启摄像头权限 @@ -140,6 +141,7 @@ 警告 将重置所有设置并删除已下载的库,确定重置吗? 库文件 + 开始下载 保存 另存为 打开 @@ -255,10 +257,12 @@ 当前状态将被重置 在后台运行 保存当前修改吗? - 运行日誌 : %s - 运行日誌 + 运行日志 : %s + 运行日志 二维码 + 扩展 + 扩展 从二维码中读取代码 屏幕 @@ -329,6 +333,7 @@ 文件已下载 覆写本地文件? 应用消息推送 + 消息通知 Log消息推送 退出吗? 删除文件成功 @@ -450,5 +455,38 @@ 运行 请先从QPYPI中安装kivy库 获得帮助 + You can run QPython script even it\'s in background if this mode is enabled. + Disable + QPython will restart to apply changes. + "Please grant the creat shortcut permission. " + 隐私政策 + 服务协议 + + + + 北京优趣天下信息技术有限公司(以下称“QPYTHON”或“我们”)尊重并保护所有使用QPYTHON服务用户的隐私权,在您使用我们提供的服务时,我们可能会收集和使用您的相关信息,我们希望通过本《隐私政策》向您说明,我们如何收集、存储、保护及使用您的个人信息,以及清楚地向您介绍我们对您个人信息的处理方式。本《隐私政策》与您使用QPYTHON的服务相关,因此我们建议您完整地阅读,以帮助您更好地保护您的隐私。\n\n + + 权限说明:\n +要使用Android的某些功能进行编程,QPython/QPython需要以下权限:摄像头、麦克风、存储、账号、蓝牙、GPS和其他等,如果您不需要这些特性,可以从系统设置中禁用它们。\n\n + +为了能使用扫描二维码的便捷功能和让您使用手机的拍照特性进行编程,QPython可能会使用您申请摄像头权限;\n +为了让您能用手机的麦克风、存储进行编程,QPython可能会使用您申请麦克风权限、读写存储等权限;\n +为了让您使用手机的地理位置用于编程,QPython可能会向您申请位置权限;\n +为了让您使用手机的账号信息用于编程,QPython可能会向您申请系统设备权限收集设备信息、日志信息;\n +我们会努力采取各种安全技术保护您的个人信息。未经您同意,我们不会从第三方获取、共享或对外提供您的信息;\n +如果不是你主动在系统设置->Apps->QPython权限中管理上述权限,QPython不会自动使用它们\n\n + + + https://www.qpython.org/agreement-cn.html + https://www.qpython.org/privacy-cn.html + https://edu.qpython.org/courses-cn.html + + + 请阅读并接受《服务协议》和《隐私政策》 + 已阅读并接受 + 《服务协议》 + + 《隐私政策》 + 欢迎使用QPython diff --git a/qpython/src/main/res/values-zh-rTW/strings.xml b/qpython/src/main/res/values-zh-rTW/strings.xml index 6677a532..ce5c4fa4 100644 --- a/qpython/src/main/res/values-zh-rTW/strings.xml +++ b/qpython/src/main/res/values-zh-rTW/strings.xml @@ -291,5 +291,10 @@ 衆籌 衆籌中 獲得幫助 + You can run QPython script even it\'s in background if this mode is enabled. + Disable + QPython will restart to apply changes. + "Please grant the creat shortcut permission. " + Welcome to Use QPython \ No newline at end of file diff --git a/qpython/src/main/res/values/colors.xml b/qpython/src/main/res/values/colors.xml index 2516e6f8..08747454 100644 --- a/qpython/src/main/res/values/colors.xml +++ b/qpython/src/main/res/values/colors.xml @@ -13,6 +13,7 @@ #CACCCB #333333 + #87AADC #40000000 @@ -29,8 +30,10 @@ #fbfbfb #e8e8e8 - \ #ffffff #000000 + #498fdd + #103606 + #999999 diff --git a/qpython/src/main/res/values/strings.xml b/qpython/src/main/res/values/strings.xml index 1c38275b..d0305a7d 100644 --- a/qpython/src/main/res/values/strings.xml +++ b/qpython/src/main/res/values/strings.xml @@ -10,11 +10,10 @@ 20200206.1205 20200207.1205 - https://www.qpython.org/privacy.html https://www.qpython.org/contributors.html projects - QPYPI - QPYPI + QPYPI + QPYPI α R @@ -58,6 +57,23 @@ FTP Server + 1. In order to allow you to use the hardware features of your mobile phone for programming, QPython may apply for camera permission, microphone permission, read-write storage and other permissions;\n\n + 2. In order to allow you to use the geographical location of your mobile phone for programming, QPython may apply to you for location permission;\n\n + 3. In order to allow you to use the account information of your mobile phone for programming, QPython may apply for system device permission to collect device information and log information;\n\n + 4. We will strive to adopt various security technologies to protect your personal information. Without your consent, we will not obtain, share or provide your information from a third party;\n\n + 5. If you do not actively manage the above permissions in system settings - > Apps - > qpython permissions, QPython will not automatically use them.\n\n + + + Please read and accept the "Service Agreement" and "Privacy Policy" + https://www.qpython.org/agreement.html + https://www.qpython.org/privacy.html + https://edu.qpython.org/courses.html + + You can read the full + <<service agreement>> + and + <<privacy policy>> + Terminal Preference @@ -218,6 +234,8 @@ Yes No OK + Ok + Cancel close No change Feedback @@ -246,6 +264,7 @@ Reset storage will lost all setting and downloaded libs, are you sure you want to reset? Library Location + Start download @@ -392,8 +411,9 @@ Run on background Scan Read code from QRCode + Welcome to Use QPython - QPython Courses + Courses Lose Connect Courses Programs @@ -467,6 +487,7 @@ Do you want to sign out? Log Notification App Notifications + Notification Override local file? File downloaded Login error @@ -720,6 +741,7 @@ Project\'s main.py does not exit root + keep alive sl4a qpypi update_py3 @@ -734,5 +756,12 @@ Do you want to override? + You can run QPython script even it\'s in background if this mode is enabled. + Disable + Keep Alive Mode + QPython will restart to apply changes. + "Please grant the creat shortcut permission. " + Privacy Policy + Service Agreement diff --git a/qpython/src/main/res/values/styles.xml b/qpython/src/main/res/values/styles.xml index 0f3672b1..02a200f7 100644 --- a/qpython/src/main/res/values/styles.xml +++ b/qpython/src/main/res/values/styles.xml @@ -47,6 +47,12 @@ + + +