diff --git a/build.gradle b/build.gradle
index d576ffd4..2e0c3ccb 100644
--- a/build.gradle
+++ b/build.gradle
@@ -11,7 +11,6 @@ buildscript {
jcenter()
google()
mavenCentral()
-
maven { url "https://plugins.gradle.org/m2/" }
maven { url "https://maven.google.com" }
}
@@ -92,15 +91,16 @@ ext {
libOkHttp3Log = "com.squareup.okhttp3:logging-interceptor:${okhttpVersion}"
minSdkVersion = 14
- targetSdkVersion = 28
- compileSdkVersion = 28
- buildToolsVersion = '28.0.3'
+ targetSdkVersion = 29
+ compileSdkVersion = 29
+ buildToolsVersion = '29.0.2'
// 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"
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..62eac93e 100644
--- a/qpysdk/build.gradle
+++ b/qpysdk/build.gradle
@@ -20,11 +20,11 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
- externalNativeBuild {
- ndkBuild {
- path 'src/main/jni/Android.mk'
- }
- }
+// 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..29203212 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 {
@@ -33,9 +34,10 @@ public interface QPyConstants extends BASE_CONF {
final String KEY_NOTEBOOK2_RES = "setting.notebook2resource.path";
- 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 = Environment.getExternalStorageDirectory().getPath() + "/" + BASE_PATH;
+// 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/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/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/build.gradle b/qpython/build.gradle
index 738e1a9e..b9e36ca6 100644
--- a/qpython/build.gradle
+++ b/qpython/build.gradle
@@ -68,7 +68,12 @@ android {
}
debug {
- signingConfig signingConfigs.release
+// signingConfig signingConfigs.release
+ debuggable true
+ minifyEnabled false
+ jniDebuggable true
+ signingConfig signingConfigs.debug
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
@@ -162,6 +167,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,23 +184,38 @@ 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') {
diff --git a/qpython/src/main/AndroidManifest.xml b/qpython/src/main/AndroidManifest.xml
index db2647f9..1418caa5 100644
--- a/qpython/src/main/AndroidManifest.xml
+++ b/qpython/src/main/AndroidManifest.xml
@@ -19,8 +19,6 @@
-
-
@@ -35,6 +33,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -57,6 +71,7 @@
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:largeHeap="true"
+ android:requestLegacyExternalStorage="true"
android:supportsRtl="true"
android:theme="@style/AppTheme">
@@ -68,6 +83,8 @@
+
+
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/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..21fc01f5 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
@@ -19,6 +19,8 @@
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;
@@ -58,6 +60,7 @@ public class HomeMainActivity extends BaseActivity {
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,6 +76,7 @@ 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();
@@ -88,6 +92,8 @@ private void initIcon() {
case "2.x":
binding.icon.setImageResource(R.drawable.img_home_logo);
break;
+ default:
+ break;
}
}
@@ -101,7 +107,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) {
@@ -146,6 +152,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;
@@ -210,6 +218,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 +240,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 +257,7 @@ private void handleNotification(Bundle bundle) {
Intent starter = new Intent(Intent.ACTION_VIEW, Uri.parse(link));
startActivity(starter);
break;
+ default:break;
}
}
}
@@ -270,6 +284,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,11 +325,11 @@ 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() {
Log.d("HomeMainActivity", "openQpySDK");
@@ -368,7 +383,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");
@@ -386,7 +401,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 +418,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) {
@@ -470,4 +485,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..ab213da0 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,132 @@
package org.qpython.qpy.main.activity;
import android.content.Intent;
+import android.databinding.DataBindingUtil;
+import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.Nullable;
+import android.support.constraint.ConstraintLayout;
import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.AppCompatTextView;
+import android.text.SpannableString;
+import android.text.Spanned;
+import android.text.method.LinkMovementMethod;
+import android.util.Log;
+import android.view.View;
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 java.util.Timer;
import java.util.TimerTask;
-public class SplashActivity extends AppCompatActivity {
+public class SplashActivity extends AppCompatActivity implements View.OnClickListener, MyCheckTextView.ClickListener {
+
+ 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 = "您可以阅读完整版";
+ String two = "《服务协议》";
+ String three = "和";
+ String four = "《隐私政策》";
+
+ 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() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.append("1.为了给您提供发布服务,我们可能会向您申请摄像头权限、麦克风权限、收集存储权限;\n");
+ buffer.append("2.为了向您推荐您附近的村庄,我们会向您申请位置权限;\n");
+ buffer.append("3.为了账号安全,我们会向您申请系统设备权限收集设备信息、日志信息;\n");
+ buffer.append("4.我们会努力采取各种安全技术保护您的个人信息。未经您同意,我们不会从第三方获取、共享或对外提供您的信息;\n");
+ buffer.append("5.您还可以访问、更正、删除您的个人信息,我们为您提供了注销、投诉等多种不同方式。");
+ binding.tvContent.setText(buffer.toString());
+ }
+
+ private void judgeAgreementStatus() {
+ if (App.getAgreementStatus()){
+ delayJumpToMain();
+ }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());
+ startActivity(intent);
+ finish();
+ }
+
+ @Override
+ public void onClick(View v) {
+ int id = v.getId();
+ if (id == R.id.tv_positive){
+ App.setAgreementStatus(true);
+ jumpToMain();
+ return;
+ }
+ 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), "https://www.qpython.org/privacy-cn.html");
+ }
+
+ private void goServiceAgreement() {
+ QWebViewActivity.start(this, getString(R.string.service_agreement), "https://www.qpython.org/agreement-cn.html");
+ }
}
\ 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..445d0411 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,18 +1,26 @@
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.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.quseit.common.CrashHandler;
import com.quseit.common.updater.downloader.DefaultDownloader;
+import com.quseit.util.FileUtils;
import com.squareup.leakcanary.LeakCanary;
+import org.qpython.qpy.R;
import org.qpython.qpy.main.server.Service;
import org.qpython.qpy.main.server.gist.Api;
import org.qpython.qpy.main.server.gist.TokenManager;
@@ -20,7 +28,9 @@
import org.qpython.qpy.main.server.http.Retrofitor;
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 +45,22 @@
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 = "APP";
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 +98,7 @@ public static Context getContext() {
return sContext;
}
-// public static AppCompatActivity getActivity() {
+ // public static AppCompatActivity getActivity() {
// return sActivity;
// }
//
@@ -107,6 +118,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;
}
@@ -178,7 +201,7 @@ public void onCreate() {
.addCallAdapterFactory(RxJavaCallAdapterFactory.create());
mService = new Service();
- String basePath = QPyConstants.ABSOLUTE_PATH;
+ String basePath = FileUtils.getAbsolutePath(getApplicationContext());
sProjectPath = String.format("%s/%s", basePath, "projects");
sScriptPath = String.format("%s/%s", basePath, "scripts");
@@ -197,7 +220,7 @@ public void onCreate() {
.getInstance()
.setTimeOut(Retrofitor.DEFAULT_TIMEOUT)
// .openDebug(BuildConfig.DEBUG)
- // .supportSSL(!BuildConfig.DEBUG)
+ // .supportSSL(!BuildConfig.DEBUG)
.addHeaders(header)
.init(Api.BASE_URL);
@@ -213,8 +236,30 @@ public void onCreate() {
NotebookUtil.killNBSrv(this);
NotebookUtil.startNotebookService2(this);
}
+
+ initCactus();
}
+ 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 +270,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..9b7628d4 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,11 +16,13 @@
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.util.FileHelper;
+import com.quseit.util.FileUtils;
import org.qpython.qpy.utils.NotebookUtil;
import org.qpython.qpysdk.QPyConstants;
@@ -160,7 +162,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 +184,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 + "'");
@@ -239,13 +241,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..9aecb41b 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.getAbsolutePath(App.getContext()) + "/" + (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..a7da8f2f 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;
- });
+ 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 {
- 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/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/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/activity_local_app.xml b/qpython/src/main/res/layout/activity_local_app.xml
index ef51f7e5..754f8318 100644
--- a/qpython/src/main/res/layout/activity_local_app.xml
+++ b/qpython/src/main/res/layout/activity_local_app.xml
@@ -1,8 +1,8 @@
-
-
+
+
+
+
+
+
+
+ android:background="@null" />
\ No newline at end of file
diff --git a/qpython/src/main/res/layout/activity_splash.xml b/qpython/src/main/res/layout/activity_splash.xml
index ce6f6cd4..2ef88d58 100644
--- a/qpython/src/main/res/layout/activity_splash.xml
+++ b/qpython/src/main/res/layout/activity_splash.xml
@@ -1,16 +1,109 @@
-
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ 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..4e3b1e22 100644
--- a/qpython/src/main/res/values-ja/strings.xml
+++ b/qpython/src/main/res/values-ja/strings.xml
@@ -486,4 +486,10 @@
現在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..cc23b367 100644
--- a/qpython/src/main/res/values-ru/strings.xml
+++ b/qpython/src/main/res/values-ru/strings.xml
@@ -430,4 +430,10 @@ 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. "
+ 服务协议
+ 隐私政策
\ 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..c3a06cfb 100644
--- a/qpython/src/main/res/values-zh-rCN/strings.xml
+++ b/qpython/src/main/res/values-zh-rCN/strings.xml
@@ -450,5 +450,11 @@
运行
请先从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. "
+ 服务协议
+ 隐私政策
diff --git a/qpython/src/main/res/values-zh-rTW/strings.xml b/qpython/src/main/res/values-zh-rTW/strings.xml
index 6677a532..8049cb06 100644
--- a/qpython/src/main/res/values-zh-rTW/strings.xml
+++ b/qpython/src/main/res/values-zh-rTW/strings.xml
@@ -291,5 +291,11 @@
衆籌
衆籌中
獲得幫助
+ 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. "
+ 服务协议
+ 隐私政策
\ 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..0ff89cbd 100644
--- a/qpython/src/main/res/values/colors.xml
+++ b/qpython/src/main/res/values/colors.xml
@@ -33,4 +33,5 @@
#ffffff
#000000
+ #498fdd
diff --git a/qpython/src/main/res/values/strings.xml b/qpython/src/main/res/values/strings.xml
index 1c38275b..97c44fd1 100644
--- a/qpython/src/main/res/values/strings.xml
+++ b/qpython/src/main/res/values/strings.xml
@@ -720,6 +720,7 @@
Project\'s main.py does not exit
root
+ keep alive
sl4a
qpypi
update_py3
@@ -734,5 +735,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. "
+ 隐私政策
+ 服务协议
diff --git a/qpython/src/main/res/xml/qpython_setting.xml b/qpython/src/main/res/xml/qpython_setting.xml
index 245731f7..777fdbc4 100644
--- a/qpython/src/main/res/xml/qpython_setting.xml
+++ b/qpython/src/main/res/xml/qpython_setting.xml
@@ -109,6 +109,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/qpython/src/od/java/org/qpython/qpy/codeshare/ShareCodeUtil.java b/qpython/src/od/java/org/qpython/qpy/codeshare/ShareCodeUtil.java
new file mode 100644
index 00000000..2837ad82
--- /dev/null
+++ b/qpython/src/od/java/org/qpython/qpy/codeshare/ShareCodeUtil.java
@@ -0,0 +1,749 @@
+package org.qpython.qpy.codeshare;
+
+import android.app.Activity;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+import android.support.annotation.NonNull;
+import android.util.Log;
+import android.widget.Toast;
+
+import com.google.common.reflect.TypeToken;
+import com.google.firebase.database.DataSnapshot;
+import com.google.firebase.database.DatabaseError;
+import com.google.firebase.database.DatabaseReference;
+import com.google.firebase.database.FirebaseDatabase;
+import com.google.firebase.database.ValueEventListener;
+import com.quseit.util.ACache;
+import com.quseit.util.FileHelper;
+import com.quseit.util.FileUtils;
+import com.quseit.util.NetStateUtil;
+
+import org.json.JSONObject;
+import org.qpython.qpy.R;
+import org.qpython.qpy.codeshare.pojo.BookmarkerList;
+import org.qpython.qpy.codeshare.pojo.CloudFile;
+import org.qpython.qpy.codeshare.pojo.Gist;
+import org.qpython.qpy.codeshare.pojo.GistBase;
+import org.qpython.qpy.main.app.App;
+import org.qpython.qpy.texteditor.common.TextFileUtils;
+import org.qpython.qpysdk.utils.DateTimeHelper;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import rx.Observable;
+import rx.functions.Action1;
+
+import static org.qpython.qpy.codeshare.CONSTANT.DOT_REPLACE;
+import static org.qpython.qpy.codeshare.CONSTANT.SLASH_REPLACE;
+import static org.qpython.qpy.main.server.CacheKey.CLOUD_FILE;
+
+/**
+ * FireBase database util
+ * Created by Hmei on 2017-08-10.
+ */
+
+public class ShareCodeUtil {
+ private static final boolean CLEAR = false;
+
+ private static final String CLOUD = "cloud";
+ private static final String GIST = "gist";
+ private static final String USER = "user";
+ private static final String BASE = "base";
+ private static final String GIST_LIST = "gist_list";
+ private static final String HISTORY = "history";
+ private static final String COMMENT = "comment";
+ private static final String BOOKMARK = "bookmark";
+ private static final String COMMIT = "commit";
+ private static final String INDEX = "index";
+ private static final String USAGE = "usage";
+ private static final String PROJECT = "project";
+ private static final String SCRIPT = "script";
+ private static final String OTHER = "other";
+ private static final String PROJECT_PATH = "/projects/";
+ private static final String SCRIPTS_PATH = "/scripts/";
+
+ private static final int MAX_FILE = 100;
+
+ private DatabaseReference reference;
+ private String email;
+ private String userName;
+ private String avatarUrl;
+
+ private SharedPreferences sharedPreferences;
+ private int currentFileCount = -1;
+
+ private ShareCodeUtil() {
+ reference = FirebaseDatabase.getInstance().getReference();
+ if (App.getUser() != null) {
+ email = App.getUser().getEmail().replace(".", "_");
+ userName = App.getUser().getUserName();
+ avatarUrl = App.getUser().getAvatarUrl();
+ sharedPreferences = PreferenceManager.getDefaultSharedPreferences(App.getContext());
+ initUsage(null);
+ } else {
+ email = "";
+ userName = "";
+ avatarUrl = "";
+ }
+ //LogUtil.d("ShareCodeUtil", "ShareCodeUtil:"+App.getUser().getEmail());
+
+ Log.d("ShareCodeUtil", "ShareCodeUtil:"+email);
+ }
+
+ public static ShareCodeUtil getInstance() {
+ return ShareCodeHolder.INSTANCE;
+ }
+
+ @SuppressWarnings({"DEBUG_ONLY"})
+ public void clearAll() {
+ if (CLEAR) {
+ reference.child(CLOUD).child(email).removeValue(
+ (databaseError, databaseReference) ->
+ Toast.makeText(App.getContext(), "Clear", Toast.LENGTH_SHORT).show());
+ }
+ }
+
+ public void createScriptGist(String title, String desc, String msg, String content, DatabaseReference.CompletionListener listener) {
+ String date = DateTimeHelper.getDate();
+ // Add to all gist repo
+ Gist gist = new Gist();
+ gist.setTitle(title);
+ gist.setAuthor(userName);
+ gist.setAvatar(avatarUrl);
+ gist.setDescribe(desc);
+ gist.setDate(date);
+ DatabaseReference path = reference.child(GIST).child(SCRIPT).push();// gist/script/
+ String gistId = path.getKey();
+ path.setValue(gist, listener);
+ commitGist(gistId, msg, content, null, null);
+
+ // Add to user repo
+ GistBase baseGist = new GistBase();
+ baseGist.setAuthor(userName);
+ baseGist.setAvatar(avatarUrl);
+ baseGist.setDate(date);
+ baseGist.setTitle(title);
+ reference.child(USER).child(email).child(GIST_LIST).child(SCRIPT).child(gistId).setValue(baseGist);// user//gist_list/script/
+
+ // Add to base repo
+ reference.child(BASE).child(SCRIPT).child(gistId).setValue(baseGist); // base/script/
+ }
+
+ public void createProjectGist(String projectName, String desc, String msg, List paths, DatabaseReference.CompletionListener completionListener) {
+ for (String path : paths) {
+ File file = new File(path);
+ String code = TextFileUtils.readTextFile(file);
+ String fileName = file.getName().replace(".", DOT_REPLACE);
+
+ String date = DateTimeHelper.getDate();
+ // Add to all gist repo
+ Gist gist = new Gist();
+ gist.setTitle(fileName);
+ gist.setAuthor(userName);
+ gist.setAvatar(avatarUrl);
+ gist.setDescribe(desc);
+ gist.setDate(date);
+ DatabaseReference subReference = reference.child(GIST).child(PROJECT);// gist/script/
+ String gistId = subReference.getKey();
+ subReference.child(gistId).child(projectName).child(fileName).setValue(gist, completionListener);// gist/project///
+ commitGist(gistId, msg, code, projectName, fileName);
+
+ // Add to user repo
+ GistBase baseGist = new GistBase();
+ baseGist.setAuthor(userName);
+ baseGist.setAuthor(avatarUrl);
+ baseGist.setDate(date);
+ baseGist.setTitle(fileName);
+ // user//gist_list/project///
+ reference.child(USER).child(email).child(GIST_LIST).child(PROJECT).child(gistId).child(projectName).child(fileName).setValue(baseGist);
+
+ // Add to base repo
+ // base/project///
+ reference.child(BASE).child(PROJECT).child(gistId).child(projectName).child(fileName).setValue(baseGist);
+ }
+ }
+
+ public void commitGist(String gistId, String msg, String content, String projName, String fileName) {
+ Gist.HistoryBean historyBean = new Gist.HistoryBean();
+ historyBean.setData(DateTimeHelper.getDate());
+ historyBean.setMassage(msg);
+ historyBean.setContent(content);
+ if (projName != null) {
+ DatabaseReference subRe = reference.child(GIST).child(PROJECT).child(gistId).child(projName).child(fileName).child(HISTORY).push();
+ String historyId = subRe.getKey();
+ subRe.child(historyId).setValue(historyBean); // gist//history/}
+ } else {
+ DatabaseReference subRe = reference.child(GIST).child(SCRIPT).child(gistId).child(HISTORY).push();
+ String historyId = subRe.getKey();
+ subRe.child(historyId).setValue(historyBean); // gist//history/}
+ reference.child(GIST).child(SCRIPT).child(gistId).child("lastCommitCode").setValue(content);
+ }
+ }
+
+ public void sendComment(String gistId, String comment, boolean isProj, CommentCallback callback) {
+ sendComment(gistId, "", comment, "", isProj, callback);
+ }
+
+ /**
+ * @param comment 评论
+ * @param reComment 被回复的评论
+ */
+ public void sendComment(String gistId, String to, String comment, String reComment, boolean isProj, CommentCallback callback) {
+ Gist.CommentBean commentBean = new Gist.CommentBean();
+ commentBean.setFrom_content(comment);
+ commentBean.setData(DateTimeHelper.getDate());
+ commentBean.setFrom(userName);
+ commentBean.setAvatar(avatarUrl);
+ commentBean.setRe(to);
+ commentBean.setRe_content(reComment);
+ callback.commentBean(commentBean);
+ DatabaseReference subRe = reference.child(GIST).child(isProj ? PROJECT : SCRIPT).child(gistId).child(COMMENT).push();
+ String commentId = subRe.getKey();
+ subRe.child(commentId).setValue(commentBean);
+ }
+
+ public void bookmark(String gistId) {
+ reference.child(GIST).child(gistId).child(BOOKMARK).child(email).setValue(userName);
+ reference.child(USER).child(email).child(BOOKMARK).child(gistId).setValue(true);
+ }
+
+ public void cancelBookmark(String gistId) {
+ reference.child(GIST).child(gistId).child(BOOKMARK).child(email).removeValue();
+ reference.child(USER).child(email).child(BOOKMARK).child(gistId).removeValue();
+ }
+
+ public void getBaseScriptGistList(Action1> callback) {
+ reference.child(BASE).child(SCRIPT).addListenerForSingleValueEvent(new SimpleValueEventListener() {
+ @Override
+ public void onDataGet(HashMap value) {
+ handleKey(value,callback);
+ }
+ });
+ }
+
+ private void handleKey(HashMap value,Action1> callback){
+ List dataList = new ArrayList<>();
+ for (Object key : value.keySet()) {
+ GistBase gistBase = App.getGson().fromJson(new JSONObject((Map) value.get(key)).toString(), GistBase.class);
+ gistBase.setId((String) key);
+ dataList.add(gistBase);
+ }
+ Observable.just(dataList)
+ .subscribe(callback);
+ }
+
+ public void getBaseProjectGistList(Action1> callback) {
+ reference.child(BASE).child(PROJECT).addListenerForSingleValueEvent(new SimpleValueEventListener() {
+ @Override
+ public void onDataGet(HashMap value) {
+// List dataList = new ArrayList<>();
+// for (Object key : value.keySet()) {
+// GistBase gistBase = App.getGson().fromJson(new JSONObject((Map) value.get(key)).toString(), GistBase.class);
+// gistBase.setId((String) key);
+// dataList.add(gistBase);
+// }
+// Observable.just(dataList)
+// .subscribe(callback);
+ handleKey(value,callback);
+ }
+ });
+ }
+
+ public void getGistDetail(String gistId, boolean isProj, Action1 callback) {
+ reference.child(GIST).child(isProj ? PROJECT : SCRIPT).child(gistId).addListenerForSingleValueEvent(new SimpleValueEventListener() {
+ @Override
+ public void onDataGet(HashMap value) {
+ JSONObject jsonObject = new JSONObject(value);
+ Gist gist = App.getGson().fromJson(String.valueOf(jsonObject), Gist.class);
+
+ HashMap historyMap = (HashMap) value.get(HISTORY);
+ if (historyMap != null) {
+ List historyList = new ArrayList<>();
+ for (Object historyKey : historyMap.keySet()) {
+ Gist.HistoryBean historyBean = App.getGson().fromJson(String.valueOf(new JSONObject((Map) historyMap.get(historyKey))), Gist.HistoryBean.class);
+ historyBean.setHistoryId((String) historyKey);
+ historyList.add(historyBean);
+ }
+ gist.setHistory(historyList);
+ }
+
+ HashMap commentMap = (HashMap) value.get(COMMENT);
+ if (commentMap != null) {
+ List commentList = new ArrayList<>();
+ for (Object commentKey : commentMap.keySet()) {
+ Gist.CommentBean commentBean = App.getGson().fromJson(String.valueOf(new JSONObject((Map) commentMap.get(commentKey))), Gist.CommentBean.class);
+ commentBean.setId((String) commentKey);
+ commentList.add(commentBean);
+ }
+ gist.setComment(commentList);
+ }
+
+ HashMap bookmarkMap = (HashMap) value.get(BOOKMARK);
+ if (bookmarkMap != null) {
+ List bookmarkerList = new ArrayList<>();
+ for (Object bookmarkKey : bookmarkMap.keySet()) {
+ Gist.BookmarkerBean bookmarkerBean = App.getGson().fromJson(String.valueOf(new JSONObject((Map) bookmarkMap.get(bookmarkKey))), Gist.BookmarkerBean.class);
+ bookmarkerBean.setId((String) bookmarkKey);
+ bookmarkerList.add(bookmarkerBean);
+ }
+ gist.setBookmarker(bookmarkerList);
+ }
+ Observable.just(gist)
+ .subscribe(callback);
+ }
+ });
+ }
+
+ // TODO: 2017-08-14 Need to fix
+ public void getMyGistList(Action1> callback) {
+ reference.child(USER).child(GIST_LIST).addListenerForSingleValueEvent(new ValueEventListener() {
+ @Override
+ public void onDataChange(DataSnapshot dataSnapshot) {
+ HashMap object = (HashMap) dataSnapshot.getValue();
+ List userGist = new ArrayList<>();
+ if (object == null) {
+ return;
+ }
+ for (Object key : object.keySet()) {
+ userGist.add(App.getGson().fromJson(new JSONObject((Map) object.get(key)).toString(), GistBase.class));
+ }
+ Observable.just(userGist)
+ .subscribe(callback);
+ }
+
+ @Override
+ public void onCancelled(DatabaseError databaseError) {
+
+ }
+ });
+ }
+
+ public void getMyBookmarkList(Action1> callback) {
+ reference.child(USER).child(BOOKMARK).addListenerForSingleValueEvent(new ValueEventListener() {
+ @Override
+ public void onDataChange(DataSnapshot dataSnapshot) {
+ HashMap object = (HashMap) dataSnapshot.getValue();
+ List userGist = new ArrayList<>();
+ if (object == null) {
+ return;
+ }
+ for (Object key : object.keySet()) {
+ userGist.add(App.getGson().fromJson(new JSONObject((Map) object.get(key)).toString(), BookmarkerList.class));
+ }
+ Observable.just(userGist)
+ .subscribe(callback);
+ }
+
+ @Override
+ public void onCancelled(DatabaseError databaseError) {
+
+ }
+ });
+ }
+
+ public void getGistCommentList(String gistId, Action1> callback) {
+ reference.child(GIST).child(gistId).child(COMMENT).addListenerForSingleValueEvent(new ValueEventListener() {
+ @Override
+ public void onDataChange(DataSnapshot dataSnapshot) {
+ HashMap object = (HashMap) dataSnapshot.getValue();
+ List commentList = new ArrayList<>();
+ if (object == null) {
+ return;
+ }
+ for (Object key : object.keySet()) {
+ commentList.add(App.getGson().fromJson(new JSONObject((Map) object.get(key)).toString(), Gist.CommentBean.class));
+ }
+ Observable.just(commentList)
+ .subscribe(callback);
+ }
+
+ @Override
+ public void onCancelled(DatabaseError databaseError) {
+
+ }
+ });
+ }
+
+ public boolean uploadFolder(String path, DatabaseReference.CompletionListener completionListener, int[] size) {
+ File folder = new File(path);
+ // 获取该文件夹下符合后缀文件及非隐藏文件
+
+ if (!folder.isDirectory()) {
+ return false;
+ }
+ List files = FileHelper.filterExt(folder, App.getContext().getResources().getStringArray(R.array.support_file_ext), size[0]);
+ if (files.size() == 0) {
+ Toast.makeText(App.getContext(), R.string.no_file, Toast.LENGTH_SHORT).show();
+ return false;
+ }
+
+ if (!hasSpace(files.size())) {
+ return false;
+ }
+
+ for (File file : files) {
+ uploadFile(file.getAbsolutePath(), completionListener);
+ }
+
+// // 如果在project目录下
+// if ("projects".equals(folder.getName())) {
+// DatabaseReference projNode = reference.child(CLOUD).child(email).child(PROJECT).child(folder.getName().replace(".", DOT_REPLACE));
+// for (int i = 0; i < files.size(); i++) {
+// String date = DateTimeHelper.AGO_FULL_DATE_FORMATTER.format(new Date(files.get(i).lastModified()));
+// String subPath = files.get(i).getAbsolutePath();
+// String subKey = subPath.substring(subPath.indexOf(folder.getName()) + folder.getName().length(), subPath.length()).replace(".", DOT_REPLACE).replace("/", SLASH_REPLACE);
+// if (i == files.size() - 1) {
+// projNode.child(subKey)
+// .child(date)
+// .setValue(TextFileUtils.readTextFile(files.get(i)), completionListener);
+// } else {
+// projNode.child(subKey)
+// .child(date)
+// .setValue(TextFileUtils.readTextFile(files.get(i)));
+// }
+// reference.child(CLOUD)
+// .child(email)
+// .child(INDEX)
+// .child(PROJECT)
+// .child(folder.getName().replace(".", DOT_REPLACE) + subKey)
+// .setValue(date);
+// }
+// } else if ("scripts".equals(folder.getName())) {
+// // 上传整个scripts文件夹
+// for (int i = 0; i < files.size(); i++) {
+// String abs_path = files.get(i).getAbsolutePath();
+// String key = abs_path
+// .substring(abs_path.indexOf(SCRIPTS_PATH) + SCRIPTS_PATH.length())
+// .replace(".", DOT_REPLACE)
+// .replace("/", SLASH_REPLACE);
+// DatabaseReference content = reference.child(CLOUD)
+// .child(email)
+// .child(SCRIPT)
+// .child(key)
+// .child(DateTimeHelper.AGO_FULL_DATE_FORMATTER.format(new Date(files.get(i).lastModified())));
+// if (i == files.size() - 1) {
+// content.setValue(TextFileUtils.readTextFile(files.get(i)), completionListener);
+// } else {
+// content.setValue(TextFileUtils.readTextFile(files.get(i)));
+// }
+//
+// reference.child(CLOUD)
+// .child(email)
+// .child(INDEX)
+// .child(SCRIPT)
+// .child(key)
+// .setValue(DateTimeHelper.AGO_FULL_DATE_FORMATTER.format(new Date(files.get(i).lastModified())));
+// }
+// } else {
+// // 普通文件夹
+// int fileListSize = files.size();
+// for (File file : files) {
+// fileListSize--;
+// final String rootNode = "/qpython/";
+// String node = file.getAbsolutePath().substring(path.indexOf(rootNode) + rootNode.length());
+// DatabaseReference child =
+// reference
+// .child(CLOUD)
+// .child(email)/*.child(folder.getName().replace(".", DOT_REPLACE))*/
+// .child(OTHER)
+// .child(node.replace(".", DOT_REPLACE).replace("/", SLASH_REPLACE))
+// .child(DateTimeHelper.getDate());
+// if (fileListSize == 0) {
+// child.setValue(TextFileUtils.readTextFile(file), completionListener);
+// } else {
+// child.setValue(TextFileUtils.readTextFile(file));
+// }
+//
+// reference.child(CLOUD)
+// .child(email)
+// .child(INDEX)
+// .child(OTHER)
+// .child(node.replace(".", DOT_REPLACE).replace("/", SLASH_REPLACE))
+// .setValue(DateTimeHelper.getDate());
+// }
+// }
+ return true;
+ }
+
+ public boolean uploadFile(String path, DatabaseReference.CompletionListener completionListener) {
+ File file = new File(path);
+
+ if (!hasSpace(1)) {
+ return false;
+ }
+
+ if (path.contains(PROJECT_PATH)) {
+ String subPath = path.substring(path.indexOf(PROJECT_PATH) + PROJECT_PATH.length());
+ String projName = subPath.split("/")[0];
+ reference.child(CLOUD)
+ .child(email)
+ .child(PROJECT)
+ .child(projName)
+ .child(subPath.replace(".", DOT_REPLACE).replace("/", SLASH_REPLACE).replace(projName, ""))
+ .child(DateTimeHelper.AGO_FULL_DATE_FORMATTER.format(new Date(file.lastModified())))
+ .setValue(TextFileUtils.readTextFile(file), completionListener);
+
+ reference.child(CLOUD)
+ .child(email)
+ .child(INDEX)
+ .child(PROJECT)
+ .child(subPath.replace(".", DOT_REPLACE).replace("/", SLASH_REPLACE))
+ .setValue(DateTimeHelper.AGO_FULL_DATE_FORMATTER.format(new Date(file.lastModified())));
+ } else if (path.contains(SCRIPTS_PATH)) {
+ reference.child(CLOUD)
+ .child(email)
+ .child(SCRIPT)
+ .child(file.getName().replace(".", DOT_REPLACE))
+ .child(DateTimeHelper.AGO_FULL_DATE_FORMATTER.format(new Date(file.lastModified())))
+ .setValue(TextFileUtils.readTextFile(file), completionListener);
+
+ reference.child(CLOUD)
+ .child(email)
+ .child(INDEX)
+ .child(SCRIPT)
+ .child(file.getName().replace(".", DOT_REPLACE))
+ .setValue(DateTimeHelper.AGO_FULL_DATE_FORMATTER.format(new Date(file.lastModified())));
+ } else {
+ final String rootNode = "/qpython/";
+ String uploadKey = path.substring(path.indexOf(rootNode) + rootNode.length());
+ reference.child(CLOUD)
+ .child(email)
+ .child(OTHER)
+ .child(uploadKey.replace(".", DOT_REPLACE).replace("/", SLASH_REPLACE))
+ .child(DateTimeHelper.getDate())
+ .setValue(TextFileUtils.readTextFile(file), completionListener);
+
+ reference.child(CLOUD)
+ .child(email)
+ .child(INDEX)
+ .child(OTHER)
+ .child(uploadKey.replace(".", DOT_REPLACE).replace("/", SLASH_REPLACE))
+ .setValue(DateTimeHelper.getDate());
+ }
+ return true;
+ }
+
+ public void getUploadedScripts(boolean forceRefresh, Activity context, Action1> callback) {
+ if (CLEAR) {
+ return;
+ }
+ String content = FileHelper.getFileContents(FileUtils.getCloudMapCachePath(context.getApplicationContext()));
+ List cloudFiles = content == null ? null : App.getGson().fromJson(content, new TypeToken>() {
+ }.getType());
+ if (cloudFiles != null && !forceRefresh) {
+ Observable.just(cloudFiles)
+ .subscribe(callback);
+ } else {
+ email = App.getUser()!=null?App.getUser().getEmail().replace(".","_"):"";
+ if (email.equals("")) {
+ Toast.makeText(context, "Waiting the firebase to initializ...",Toast.LENGTH_SHORT).show();
+
+ } else {
+ reference.child(CLOUD).child(email).child(INDEX).addListenerForSingleValueEvent(new ValueEventListener() {
+ @Override
+ public void onDataChange(DataSnapshot dataSnapshot) {
+ HashMap value = (HashMap) dataSnapshot.getValue();
+ if (value == null) {
+ resetUsage(0);
+ Observable.just(new ArrayList())
+ .subscribe(callback);
+ return;
+ }
+ List cloudFiles = new ArrayList<>();
+ for (String node : value.keySet()) {
+ switch (node) {
+ case SCRIPT:
+ HashMap script;
+ script = (HashMap) value.get(SCRIPT);
+ for (String o : script.keySet()) {
+ CloudFile cloudFile = new CloudFile();
+ cloudFile.setName(o);
+ cloudFile.setKey(SCRIPT + "/" + o);
+ cloudFile.setPath(SCRIPTS_PATH);
+ cloudFile.setUploadTime((String) script.get(o));
+ cloudFiles.add(cloudFile);
+ }
+ break;
+ case PROJECT:
+ HashMap project = (HashMap) value.get(PROJECT);
+ for (String s : project.keySet()) {
+ CloudFile cloudFile = new CloudFile();
+ cloudFile.setKey(PROJECT + "/" + s);
+ String[] nodes = s.split(SLASH_REPLACE);
+ cloudFile.setName(nodes[nodes.length - 1]);
+ cloudFile.setProjectName(nodes[0]);
+ cloudFile.setPath(s.replace(nodes[0], ""));
+ cloudFile.setUploadTime((String) project.get(s));
+ cloudFiles.add(cloudFile);
+ }
+ break;
+ default:
+ HashMap other = (HashMap) value.get(OTHER);
+ for (String s : other.keySet()) {
+ CloudFile cloudFile = new CloudFile();
+ cloudFile.setPath(s);
+ cloudFile.setKey(OTHER + "/" + s);
+ String[] nodes = s.split(SLASH_REPLACE);
+ boolean index = false;
+ for (String node1 : nodes) {
+ if (index) {
+ cloudFile.setProjectName(node1);
+ break;
+ } else if (node1.equals("projects3")) {
+ index = true;
+ }
+ }
+ cloudFile.setName(nodes[nodes.length - 1]);
+ cloudFile.setUploadTime((String) other.get(s));
+ cloudFiles.add(cloudFile);
+ }
+ break;
+ }
+ }
+ resetUsage(cloudFiles.size());
+ Observable.just(cloudFiles)
+ .subscribe(callback);
+ ACache.get(context).put(CLOUD_FILE, App.getGson().toJson(cloudFiles));
+
+ }
+
+ @Override
+ public void onCancelled(DatabaseError databaseError) {
+
+ }
+ });
+ }
+ }
+ }
+
+ public void getFileContent(String path, Action1 callback) {
+ reference.child(CLOUD)
+ .child(email)
+ .child(path)
+ .addListenerForSingleValueEvent(new ValueEventListener() {
+ @Override
+ public void onDataChange(DataSnapshot dataSnapshot) {
+ HashMap dateContent = (HashMap) dataSnapshot.getValue();
+ String latest = "";
+ for (String s : dateContent.keySet()) {
+ latest = DateTimeHelper.isLater(s, latest) ? s : latest;
+ }
+
+ Observable.just(dateContent.get(latest))
+ .subscribe(callback);
+ }
+
+ @Override
+ public void onCancelled(DatabaseError databaseError) {
+
+ }
+ });
+ }
+
+ public void deleteUploadScript(CloudFile cloudFile, DatabaseReference.CompletionListener listener) {
+ reference.child(CLOUD)
+ .child(email)
+ .child(cloudFile.getKey())
+ .removeValue(listener);
+ reference.child(CLOUD)
+ .child(email)
+ .child(INDEX)
+ .child(cloudFile.getKey())
+ .removeValue();
+ changeUsage(-1);
+ }
+
+ public void initUsage(Action1 callback) {
+ if (CLEAR) {
+ return;
+ }
+ if (currentFileCount == -1) {
+ if (NetStateUtil.isConnected(App.getContext())) {
+ reference.child(CLOUD)
+ .child(email)
+ .child(USAGE)
+ .addListenerForSingleValueEvent(new ValueEventListener() {
+ @Override
+ public void onDataChange(DataSnapshot dataSnapshot) {
+ if (dataSnapshot.getValue() != null) {
+ currentFileCount = ((Long) dataSnapshot.getValue()).intValue();
+ } else {
+ currentFileCount = 0;
+ }
+ if (callback != null) {
+ Observable.just(currentFileCount)
+ .subscribe(callback);
+ }
+ }
+
+ @Override
+ public void onCancelled(DatabaseError databaseError) {
+
+ }
+ });
+ }
+ } else {
+ callback.call(currentFileCount);
+ }
+ }
+
+ public int changeUsage(int change) {
+ currentFileCount += change;
+ reference.child(CLOUD)
+ .child(email)
+ .child(USAGE)
+ .setValue(currentFileCount);
+ return currentFileCount;
+ }
+
+ public void resetUsage(int value) {
+ currentFileCount = value;
+ reference.child(CLOUD)
+ .child(email)
+ .child(USAGE)
+ .setValue(currentFileCount);
+ }
+
+ private boolean hasSpace(int waiting) {
+ if (currentFileCount < 0) {
+ Toast.makeText(App.getContext(), R.string.usage_not_init, Toast.LENGTH_SHORT).show();
+ return false;
+ } else if (currentFileCount + waiting > MAX_FILE) {
+ Toast.makeText(App.getContext(), R.string.no_space, Toast.LENGTH_SHORT).show();
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ public interface CommentCallback {
+ void commentBean(Gist.CommentBean comment);
+ }
+
+ private static class ShareCodeHolder {
+ private static final ShareCodeUtil INSTANCE = new ShareCodeUtil();
+ }
+
+ abstract class SimpleValueEventListener implements ValueEventListener {
+ @Override
+ public void onDataChange(DataSnapshot dataSnapshot) {
+ HashMap object = (HashMap) dataSnapshot.getValue();
+ if (object == null) {
+ return;
+ }
+ onDataGet(object);
+ }
+
+ @Override
+ public void onCancelled(DatabaseError databaseError) {
+
+ }
+
+ public abstract void onDataGet(HashMap value);
+ }
+}
\ No newline at end of file
diff --git a/qpython/src/od/java/org/qpython/qpy/codeshare/pojo/CloudFile.java b/qpython/src/od/java/org/qpython/qpy/codeshare/pojo/CloudFile.java
new file mode 100644
index 00000000..1231486b
--- /dev/null
+++ b/qpython/src/od/java/org/qpython/qpy/codeshare/pojo/CloudFile.java
@@ -0,0 +1,100 @@
+package org.qpython.qpy.codeshare.pojo;
+
+
+import com.quseit.util.FileUtils;
+
+import org.qpython.qpy.codeshare.CONSTANT;
+import org.qpython.qpy.main.app.App;
+import org.qpython.qpysdk.QPyConstants;
+
+import java.io.Serializable;
+
+public class CloudFile implements Serializable {
+ private String projectName;
+ private String path;
+ private String uploadTime;
+ private String name;
+ private String content;
+ private String key;
+ private boolean uploading;
+
+ public String getPath() {
+ if (projectName == null) {
+ if (path.contains("scripts3")) {
+ return "/" + path.replace(CONSTANT.SLASH_REPLACE, "/").replace(CONSTANT.DOT_REPLACE, ".");
+ } else if (path.contains("scripts")) {
+ return path.replace(CONSTANT.SLASH_REPLACE, "/") + getName();
+ } else {
+ return "/" + path.replace(CONSTANT.SLASH_REPLACE, "/").replace(CONSTANT.DOT_REPLACE, ".");
+ }
+ } else {
+ String projNode = path.contains("projects3") ? "projects3/" : "projects/";
+ return "/" + projNode + getProjectName() + path
+ .replace(CONSTANT.SLASH_REPLACE, "/")
+ .replace(CONSTANT.DOT_REPLACE, ".")
+ .replace(projNode, "")
+ .replace(getProjectName(), "");
+ }
+ }
+
+ public void setPath(String path) {
+ this.path = path;
+ }
+
+ public String getUploadTime() {
+ return uploadTime;
+ }
+
+ public void setUploadTime(String uploadTime) {
+ this.uploadTime = uploadTime;
+ }
+
+ public String getName() {
+ return name.replace(CONSTANT.DOT_REPLACE, ".");
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getContent() {
+ return content;
+ }
+
+ public void setContent(String content) {
+ this.content = content;
+ }
+
+ public long getContentSize() {
+ return content == null ? 0 : content.length();
+ }
+
+ public String getProjectName() {
+ return projectName == null ? null : projectName.
+ replace(CONSTANT.SLASH_REPLACE, "/").replace(CONSTANT.DOT_REPLACE, ".");
+ }
+
+ public void setProjectName(String projectName) {
+ this.projectName = projectName;
+ }
+
+ public boolean isUploading() {
+ return uploading;
+ }
+
+ public void setUploading(boolean uploading) {
+ this.uploading = uploading;
+ }
+
+ public String getKey() {
+ return key == null ? getName().replace(".", CONSTANT.DOT_REPLACE) : key;
+ }
+
+ public void setKey(String key) {
+ this.key = key;
+ }
+
+ public String getAbsolutePath() {
+ return FileUtils.getAbsolutePath(App.getContext()) + getPath();
+ }
+}
diff --git a/qpython/src/od/java/org/qpython/qpy/main/PayActivity.java b/qpython/src/od/java/org/qpython/qpy/main/PayActivity.java
new file mode 100644
index 00000000..c1a7b8d2
--- /dev/null
+++ b/qpython/src/od/java/org/qpython/qpy/main/PayActivity.java
@@ -0,0 +1,188 @@
+package org.qpython.qpy.main;
+
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.support.annotation.Nullable;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.GridLayoutManager;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.Toast;
+
+import com.android.vending.billing.IInAppBillingService;
+import com.quseit.util.ImageUtil;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.qpython.qpy.R;
+import org.qpython.qpy.main.activity.PurchaseActivity;
+import org.qpython.qpy.main.server.MySubscriber;
+import org.qpython.qpy.main.widget.GridSpace;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import rx.Observable;
+import rx.android.schedulers.AndroidSchedulers;
+import rx.schedulers.Schedulers;
+
+/**
+ * Created by Hmei
+ * 1/30/18.
+ */
+
+public class PayActivity extends AppCompatActivity {
+ public static final int BUY_REQUEST_CODE = 2333;
+ private IInAppBillingService mService;
+ private ServiceConnection mServiceConn;
+ private ArrayList skuList;
+ private MySubscriber callback;
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ }
+
+ void initIAB(ArrayList skuList, MySubscriber callback) {
+ this.skuList = skuList;
+ this.callback = callback;
+ mServiceConn = new ServiceConnection() {
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ mService = null;
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName name,
+ IBinder service) {
+ mService = IInAppBillingService.Stub.asInterface(service);
+ getPrices(skuList, callback);
+ }
+ };
+
+ Intent serviceIntent = new Intent("com.android.vending.billing.InAppBillingService.BIND");
+ serviceIntent.setPackage("com.android.vending");
+ bindService(serviceIntent, mServiceConn, Context.BIND_AUTO_CREATE);
+ }
+
+ /**
+ * 从Google服务器获取不同国家价格表并显示
+ */
+ private void getPrices(ArrayList skuList, MySubscriber callback) {
+ if (mService == null) {
+ Toast.makeText(this, R.string.lose_google_server, Toast.LENGTH_SHORT).show();
+ if (findViewById(R.id.pb) != null) findViewById(R.id.pb).setVisibility(View.GONE);
+ return;
+ }
+// ArrayList skuList;
+// if (!isCrowdFunding) {
+// skuList = new ArrayList<>(Arrays.asList(getResources().getStringArray(R.array.sku)));
+// } else {
+// skuList = new ArrayList<>(Arrays.asList(getResources().getStringArray(R.array.crowdfunding)));
+// int index = (int) (getIntent().getIntExtra(PERCENT, 0) / 100.00 * 4);
+// String sku = skuList.get(index);
+// skuList.clear();
+// skuList.add(sku);
+// }
+ Bundle querySkus = new Bundle();
+ querySkus.putStringArrayList("ITEM_ID_LIST", skuList);
+ try {
+ Observable.just(mService.getSkuDetails(3, getPackageName(), "inapp", querySkus))
+ .map(bundle -> {
+ ArrayList responseList = bundle.getStringArrayList("DETAILS_LIST");
+ if (responseList == null) {
+ return null;
+ }
+ String[] prices = new String[responseList.size()];
+ for (int i = 0; i < responseList.size(); i++) {
+ JSONObject object;
+ try {
+ object = new JSONObject(responseList.get(i));
+ String price = object.getString("price");
+ prices[i] = price;
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+ Arrays.sort(prices, (o1, o2) -> Integer.parseInt(o1.replaceAll("[^0-9]", "")) - Integer.parseInt(o2.replaceAll("[^0-9]", "")));
+ return prices;
+ }
+ )
+ .subscribeOn(Schedulers.newThread())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(callback
+// new MySubscriber() {
+// @Override
+// public void onNext(String[] o) {
+// super.onNext(o);
+// if (o == null) {
+// return;
+// }
+// invalidateData();
+// GridSpace gridSpace = new GridSpace(2, (int) ImageUtil.dp2px(16), false);
+// binding.list.setLayoutManager(new GridLayoutManager(PurchaseActivity.this, 2));
+// binding.list.addItemDecoration(gridSpace);
+// binding.list.setAdapter(new PurchaseActivity.ListAdapter(o));
+// }
+// }
+ );
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void purchase(String sku) {
+// String[] skus;
+// if (isCrowdFunding) {
+// skus = getResources().getStringArray(R.array.crowdfunding);
+// } else {
+// skus = getResources().getStringArray(R.array.sku);
+// }
+ try {
+ if (mService == null) {
+ Toast.makeText(this, R.string.lose_google_server, Toast.LENGTH_SHORT).show();
+ return;
+ }
+ Bundle buyIntentBundle = mService.getBuyIntent(3, getPackageName(),
+ sku, "inapp", "bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ");
+ switch (buyIntentBundle.getInt("RESPONSE_CODE")) {
+ case 0:
+ //BILLING_RESPONSE_RESULT_OK
+ PendingIntent pendingIntent = buyIntentBundle.getParcelable("BUY_INTENT");
+ startIntentSenderForResult(pendingIntent.getIntentSender(),
+ BUY_REQUEST_CODE, new Intent(), 0, 0, 0);
+ break;
+
+ }
+ } catch (RemoteException | IntentSender.SendIntentException | NullPointerException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == R.id.refresh_menu) {
+ if (findViewById(R.id.pb) != null) findViewById(R.id.pb).setVisibility(View.VISIBLE);
+ getPrices(skuList, callback);
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ if (mService != null) {
+ unbindService(mServiceConn);
+ }
+ }
+
+}
diff --git a/qpython/src/od/java/org/qpython/qpy/main/activity/BaseActivity.java b/qpython/src/od/java/org/qpython/qpy/main/activity/BaseActivity.java
new file mode 100644
index 00000000..20c1e0e5
--- /dev/null
+++ b/qpython/src/od/java/org/qpython/qpy/main/activity/BaseActivity.java
@@ -0,0 +1,302 @@
+package org.qpython.qpy.main.activity;
+
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Configuration;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Environment;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.app.ActivityCompat;
+import android.support.v4.content.ContextCompat;
+import android.support.v4.util.ArrayMap;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.app.AppCompatActivity;
+import android.widget.ArrayAdapter;
+import android.widget.Toast;
+import android.text.TextUtils;
+
+import com.quseit.util.FileUtils;
+import com.quseit.util.NAction;
+import com.quseit.util.NUtil;
+
+import org.qpython.qpy.R;
+import org.qpython.qpy.console.ShellTermSession;
+import org.qpython.qpy.console.util.TermSettings;
+import org.renpy.android.ResourceManager;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.qpython.qpy.main.server.gist.TokenManager;
+
+public class BaseActivity extends AppCompatActivity {
+ // QPython interfaces
+ private static final int SCRIPT_CONSOLE_CODE = 1237;
+ private static final int PID_INIT_VALUE = -1;
+ private static final int DEFAULT_BUFFER_SIZE = 8192;
+ private static final int LOG_NOTIFICATION_ID = (int) System.currentTimeMillis();
+
+
+ //private FirebaseAnalytics mFirebaseAnalytics;
+ private ArrayList mArguments = new ArrayList<>();
+ private InputStream mIn;
+ private OutputStream mOut;
+ private Map mActionMap = new ArrayMap<>();
+ private TermSettings mSettings;
+ private ShellTermSession session;
+
+ private boolean permissionGrant = true;
+
+ protected static ShellTermSession createTermSession(Context context, TermSettings settings, String initialCommand, String path) {
+ ShellTermSession session = null;
+ try {
+ session = new ShellTermSession(context, settings, initialCommand, path);
+ session.setProcessExitMessage(context.getString(R.string.process_exit_message));
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ return session;
+ }
+
+ protected void toast(String content) {
+ Toast.makeText(this, content, Toast.LENGTH_SHORT).show();
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ }
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ //mFirebaseAnalytics = FirebaseAnalytics.getInstance(this);
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
+ PermissionAction action = mActionMap.get(requestCode);
+ if (action != null) {
+ if (grantResults.length > 0 && (grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
+ action.onGrant();
+ } else {
+ action.onDeny();
+ }
+
+ }
+ mActionMap.remove(action);
+ }
+
+ public final void checkPermissionDo(String[] permissions, PermissionAction action) {
+ if (Build.VERSION.SDK_INT >= 23) {
+ boolean granted = true;
+ for (String permission : permissions) {
+ int checkPermission = ContextCompat.checkSelfPermission(this, permission);
+ granted = checkPermission == PackageManager.PERMISSION_GRANTED;
+ }
+ if (!granted) {
+ int code = permissions.hashCode() & 0xffff;
+ mActionMap.put(code, action);
+ ActivityCompat.requestPermissions(this, permissions, code);
+ } else {
+ action.onGrant();
+ }
+ } else {
+ action.onGrant();
+ }
+ }
+
+
+ // feedback
+ public void onFeedback(String feedback) {
+ String app = getString(R.string.app_name);
+ int ver = NUtil.getVersinoCode(getApplicationContext());
+ String subject = MessageFormat.format(getString(com.quseit.android.R.string.feeback_email_title), app, ver, Build.PRODUCT);
+
+ String lastError = "";
+ String code = NAction.getCode(getApplicationContext());
+ File log = new File(FileUtils.getPath(getApplicationContext()) + "/" + code + "_last_err.log");
+ if (log.exists()) {
+ lastError = com.quseit.util.FileHelper.getFileContents(log.getAbsolutePath());
+ }
+
+ String body = feedback.isEmpty() ? feedback : MessageFormat.format(getString(R.string.feedback_email_body), Build.PRODUCT,
+ Build.VERSION.RELEASE, Build.VERSION.SDK, lastError, feedback);
+
+
+ Intent twitterIntent = getPackageManager().getLaunchIntentForPackage("com.twitter.android");
+ if (twitterIntent != null) {
+ List list = new ArrayList<>();
+ list.add("Feedback with Twitter");
+ list.add("Feedback with Email");
+ new AlertDialog.Builder(this)
+ .setTitle(R.string.feedback)
+ .setNegativeButton(R.string.close, (dialog, which) -> dialog.dismiss())
+ .setAdapter(new ArrayAdapter<>(this, R.layout.dialog_feedback, list), (dialog, which) -> {
+ if (which == 0) {
+ twitter(body);
+ } else {
+ email(subject, body);
+ }
+ })
+ .show();
+ } else {
+ email(subject, body);
+ }
+ }
+
+ private void email(String subject, String body) {
+ Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.parse("mailto:" + getString(R.string.ui_feedback_mail)));
+
+ intent.putExtra(Intent.EXTRA_SUBJECT, subject);
+ intent.putExtra(Intent.EXTRA_TEXT, session == null ? body : session.getTranscriptText().trim());
+ try {
+ startActivity(Intent.createChooser(intent,
+ getString(R.string.email_transcript_chooser_title)));
+ } catch (ActivityNotFoundException e) {
+ Toast.makeText(this,
+ R.string.email_transcript_no_email_activity_found,
+ Toast.LENGTH_LONG)
+ .show();
+ }
+ }
+
+ private void twitter(String message) {
+ Intent tweetIntent = new Intent(Intent.ACTION_SEND);
+ if (message.isEmpty()){
+ tweetIntent.putExtra(Intent.EXTRA_TEXT, "@qpython,");
+ }else {
+ tweetIntent.putExtra(Intent.EXTRA_TEXT, "@qpython\n" + message);
+ }
+ tweetIntent.setType("text/plain");
+
+ PackageManager packManager = getPackageManager();
+ List resolvedInfoList = packManager.queryIntentActivities(tweetIntent, PackageManager.MATCH_DEFAULT_ONLY);
+
+ boolean resolved = false;
+ for (ResolveInfo resolveInfo : resolvedInfoList) {
+ if (resolveInfo.activityInfo.packageName.startsWith("com.twitter.android")) {
+ tweetIntent.setClassName(
+ resolveInfo.activityInfo.packageName,
+ resolveInfo.activityInfo.name);
+ resolved = true;
+ break;
+ }
+ }
+ if (resolved) {
+ startActivity(tweetIntent);
+ } else {
+ Intent i = new Intent();
+ i.putExtra(Intent.EXTRA_TEXT, message);
+ i.setAction(Intent.ACTION_VIEW);
+ i.setData(Uri.parse("https://twitter.com/intent/tweet?text=" + urlEncode(message)));
+ startActivity(i);
+ Toast.makeText(this, "Twitter app isn't found", Toast.LENGTH_LONG).show();
+ }
+ }
+
+ private String urlEncode(String s) {
+ try {
+ return URLEncoder.encode(s, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ return "";
+ }
+ }
+
+ protected boolean checkExpired(final String resource, String filesDir, String tag) {
+ ResourceManager resourceManager = new ResourceManager(this);
+
+ String data_version = resourceManager.getString(resource + "_version");
+ String disk_version = "0";
+
+ // If no version, no unpacking is necessary.
+ if (data_version == null) {
+ return false;
+ }
+
+ // Check the current disk version, if any.
+ String disk_version_fn = filesDir + "/" + tag + "_" + resource + ".version";
+
+ try {
+ byte buf[] = new byte[64];
+ InputStream is = new FileInputStream(disk_version_fn);
+ int len = is.read(buf);
+ disk_version = new String(buf, 0, len);
+ is.close();
+ } catch (Exception e) {
+
+ disk_version = "0";
+
+ }
+
+ if (!NUtil.isNumeric(disk_version)) {
+ disk_version = "0";
+
+ }
+
+ if ((int) (Double.parseDouble(data_version) - Double.parseDouble(disk_version)) > 0 || disk_version.equals("0")) {
+ try {
+ FileOutputStream os = new FileOutputStream(disk_version_fn);
+ try {
+ os.write(data_version.getBytes());
+ os.close();
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ //Mint.logException(e);
+
+ }
+
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ //Mint.logException(e);
+
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public interface PermissionAction {
+ void onGrant();
+
+ void onDeny();
+ }
+
+ public void ifLogin(Login afterLogin) {
+ if (!TextUtils.isEmpty(TokenManager.getToken())) {
+ afterLogin.process();
+ } else {
+ Toast.makeText(this, R.string.login_first, Toast.LENGTH_SHORT).show();
+ }
+ }
+ public interface Login {
+ void process();
+ }
+}
\ No newline at end of file
diff --git a/qpython/src/od/java/org/qpython/qpy/main/activity/FundingPurchaseActivity.java b/qpython/src/od/java/org/qpython/qpy/main/activity/FundingPurchaseActivity.java
new file mode 100644
index 00000000..6e6cf10a
--- /dev/null
+++ b/qpython/src/od/java/org/qpython/qpy/main/activity/FundingPurchaseActivity.java
@@ -0,0 +1,143 @@
+package org.qpython.qpy.main.activity;
+
+import android.content.Context;
+import android.content.Intent;
+import android.databinding.DataBindingUtil;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.view.Menu;
+import android.view.View;
+import android.widget.Toast;
+
+import com.quseit.util.VeDate;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.qpython.qpy.R;
+import org.qpython.qpy.databinding.ActivityFundingPurchaseBinding;
+import org.qpython.qpy.main.app.App;
+import org.qpython.qpy.main.server.MySubscriber;
+import org.qpython.qpy.main.server.model.GooglePurchaseModel;
+import org.qpython.qpy.utils.UpdateHelper;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * Created by Hmei
+ * 1/30/18.
+ */
+
+public class FundingPurchaseActivity extends PayActivity {
+ private static final String ARTICLE_ID = "article_id";
+ private static final String FUNDING_COUNT = "fundingCount";
+ // private final String[] prices = get
+ private ActivityFundingPurchaseBinding binding;
+ private String sku;
+
+ public static void startSupport(Context context, String articleId, int fundingPercent) {
+ Intent starter = new Intent(context, FundingPurchaseActivity.class);
+ starter.putExtra(ARTICLE_ID, articleId);
+ starter.putExtra(FUNDING_COUNT, fundingPercent);
+ context.startActivity(starter);
+ }
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ binding = DataBindingUtil.setContentView(this, R.layout.activity_funding_purchase);
+ binding.pb.setVisibility(View.VISIBLE);
+ initView();
+ initPrice();
+ initListener();
+ }
+
+ private void initView() {
+ setSupportActionBar(binding.lt.toolbar);
+ binding.lt.toolbar.setNavigationIcon(R.drawable.ic_back);
+ binding.lt.toolbar.setNavigationOnClickListener(v -> finish());
+ setTitle(R.string.reward);
+ }
+
+ private void initPrice() {
+ String[] skus = getResources().getStringArray(R.array.crowdfunding);
+ int fundingCount = getIntent().getIntExtra(FUNDING_COUNT, 0);
+ if (fundingCount < 100) {
+ sku = skus[0];
+ } else if (fundingCount < 500) {
+ sku = skus[1];
+ } else if (fundingCount < 2000) {
+ sku = skus[2];
+ } else {
+ sku = skus[3];
+ }
+ ArrayList skuList = new ArrayList<>();
+ skuList.add(sku);
+ initIAB(skuList, new MySubscriber() {
+ @Override
+ public void onNext(String[] o) {
+ super.onNext(o);
+ if (o == null) {
+ return;
+ }
+ invalidateData(true);
+ binding.price.setText(o[0]);
+ }
+ });
+ }
+
+ private void initListener() {
+ binding.price.setOnClickListener(v -> payUtil.purchase(sku));
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.refresh_menu, menu);
+ return true;
+ }
+
+ private void invalidateData(boolean showData) {
+ binding.price.setVisibility(showData ? View.VISIBLE : View.GONE);
+ binding.tvThanks.setVisibility(showData ? View.VISIBLE : View.GONE);
+ binding.noData.llRoot.setVisibility(showData ? View.GONE : View.VISIBLE);
+ binding.pb.setVisibility(View.GONE);
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ if (requestCode == BUY_REQUEST_CODE) {
+ if (resultCode == RESULT_OK) {
+ GooglePurchaseModel model = App.getGson().fromJson(data.getStringExtra("INAPP_PURCHASE_DATA"), GooglePurchaseModel.class);
+ if (model == null) {
+ return;
+ }
+ switch (model.getProductId()) {
+ default:
+ Toast.makeText(this, R.string.thanks_your_support, Toast.LENGTH_SHORT).show();
+ break;
+ }
+ // 统计赞赏数据
+ JSONObject jsonObject = new JSONObject();
+ try {
+ jsonObject.put("type", model.getProductId());
+ jsonObject.put("time", VeDate.getStringDateHourAsInt());
+ int percent = getIntent().getIntExtra(FUNDING_COUNT, 0);
+ String[] fundingCount = getResources().getStringArray(R.array.funding_count_divider);
+ jsonObject.put("crowdfunding",
+ percent > (Integer.parseInt(fundingCount[1]) / Integer.parseInt(fundingCount[2])) ? 3 :
+ percent > (Integer.parseInt(fundingCount[0]) / Integer.parseInt(fundingCount[1])) ? 2 : 1);//0 非众筹/ 1: 0-100 /2: 100-500/3 500-2000
+ jsonObject.put("articleId", getIntent().getStringExtra(ARTICLE_ID));
+ if (App.getUser() != null) {
+ jsonObject.put("account", App.getUser().getEmail());
+ }
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ UpdateHelper.submitIAPLog(this, model.getOrderId(), App.getGson().toJson(jsonObject));
+ payUtil.digestPurchase(model.getPurchaseToken());
+ finish();
+ }
+ }
+ }
+}
diff --git a/qpython/src/od/java/org/qpython/qpy/main/activity/PayActivity.java b/qpython/src/od/java/org/qpython/qpy/main/activity/PayActivity.java
new file mode 100644
index 00000000..c637254e
--- /dev/null
+++ b/qpython/src/od/java/org/qpython/qpy/main/activity/PayActivity.java
@@ -0,0 +1,54 @@
+package org.qpython.qpy.main.activity;
+
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v7.app.AppCompatActivity;
+import android.view.MenuItem;
+import android.view.View;
+
+import org.qpython.qpy.R;
+import org.qpython.qpy.main.server.MySubscriber;
+import org.qpython.qpy.main.service.PayUtil;
+
+import java.util.ArrayList;
+
+/**
+ * Created by Hmei
+ * 1/30/18.
+ */
+
+public class PayActivity extends AppCompatActivity {
+ public static final int BUY_REQUEST_CODE = 2333;
+ private ArrayList skuList;
+ private MySubscriber callback;
+ protected PayUtil payUtil;
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ payUtil = new PayUtil(this);
+ }
+
+ protected void initIAB(ArrayList skuList, MySubscriber callback) {
+ this.skuList = skuList;
+ this.callback = callback;
+ payUtil.initIAP(() -> payUtil.getPrices(skuList,callback));
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == R.id.refresh_menu) {
+ if (findViewById(R.id.pb) != null) findViewById(R.id.pb).setVisibility(View.VISIBLE);
+ payUtil.getPrices(skuList, callback);
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ payUtil.unbindPayService();
+ }
+
+}
diff --git a/qpython/src/od/java/org/qpython/qpy/main/activity/PurchaseActivity.java b/qpython/src/od/java/org/qpython/qpy/main/activity/PurchaseActivity.java
new file mode 100644
index 00000000..74335cc2
--- /dev/null
+++ b/qpython/src/od/java/org/qpython/qpy/main/activity/PurchaseActivity.java
@@ -0,0 +1,158 @@
+package org.qpython.qpy.main.activity;
+
+import android.content.Context;
+import android.content.Intent;
+import android.databinding.DataBindingUtil;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Toast;
+
+import com.quseit.util.ImageUtil;
+import com.quseit.util.VeDate;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.qpython.qpy.R;
+import org.qpython.qpy.databinding.ActivityPurchaseBinding;
+import org.qpython.qpy.databinding.ItemPriceBinding;
+import org.qpython.qpy.main.adapter.MyViewHolder;
+import org.qpython.qpy.main.app.App;
+import org.qpython.qpy.main.server.MySubscriber;
+import org.qpython.qpy.main.server.model.GooglePurchaseModel;
+import org.qpython.qpy.main.widget.GridSpace;
+import org.qpython.qpy.utils.UpdateHelper;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * Google purchase activity
+ * Created by Hmei on 2017-07-19.
+ */
+
+public class PurchaseActivity extends PayActivity {
+
+ private static final String ARTICLE_ID = "article_id";
+
+ private ActivityPurchaseBinding binding;
+ private ArrayList skus;
+
+ public static void start(Context context, String articleId) {
+ Intent starter = new Intent(context, PurchaseActivity.class);
+ starter.putExtra(ARTICLE_ID, articleId);
+ context.startActivity(starter);
+ }
+
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ binding = DataBindingUtil.setContentView(this, R.layout.activity_purchase);
+ skus = new ArrayList<>(Arrays.asList(getResources().getStringArray(R.array.sku)));
+
+ initIAB(skus, new MySubscriber() {
+ @Override
+ public void onNext(String[] o) {
+ super.onNext(o);
+ if (o == null) {
+ return;
+ }
+ invalidateData();
+ GridSpace gridSpace = new GridSpace(2, (int) ImageUtil.dp2px(16), false);
+ binding.list.setLayoutManager(new GridLayoutManager(PurchaseActivity.this, 2));
+ binding.list.addItemDecoration(gridSpace);
+ binding.list.setAdapter(new PurchaseActivity.ListAdapter(o));
+ }
+ });
+
+ initView();
+ }
+
+ private void initView() {
+ setSupportActionBar(binding.lt.toolbar);
+ binding.lt.toolbar.setNavigationIcon(R.drawable.ic_back);
+ binding.lt.toolbar.setNavigationOnClickListener(v -> finish());
+ setTitle(R.string.reward);
+ }
+
+ private void invalidateData() {
+ binding.tvThanks.setVisibility(View.VISIBLE);
+ binding.list.setVisibility(View.VISIBLE);
+ binding.noData.llRoot.setVisibility(View.GONE);
+ }
+
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.refresh_menu, menu);
+ return true;
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ if (requestCode == BUY_REQUEST_CODE) {
+ if (resultCode == RESULT_OK) {
+ GooglePurchaseModel model = App.getGson().fromJson(data.getStringExtra("INAPP_PURCHASE_DATA"), GooglePurchaseModel.class);
+ if (model == null) {
+ return;
+ }
+ switch (model.getProductId()) {
+ default:
+ Toast.makeText(this, R.string.thanks_your_support, Toast.LENGTH_SHORT).show();
+ break;
+ }
+ // 统计赞赏数据
+ JSONObject jsonObject = new JSONObject();
+ try {
+ jsonObject.put("type", model.getProductId());
+ jsonObject.put("time", VeDate.getStringDateHourAsInt());
+ jsonObject.put("crowdfunding", 0);//0 非众筹/ 1: 0-100 /2: 100-500/3 500-2000
+ jsonObject.put("articleId", getIntent().getStringExtra(ARTICLE_ID));
+ if (App.getUser() != null) {
+ jsonObject.put("account", App.getUser().getEmail());
+ }
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ UpdateHelper.submitIAPLog(this, model.getOrderId(), App.getGson().toJson(jsonObject));
+ payUtil.digestPurchase(model.getPurchaseToken());
+ finish();
+ }
+ }
+ }
+
+ private class ListAdapter extends RecyclerView.Adapter> {
+ String[] dataList;
+
+ ListAdapter(String[] dataList) {
+ this.dataList = dataList;
+ }
+
+ @Override
+ public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ ItemPriceBinding binding = DataBindingUtil.inflate(LayoutInflater.from(PurchaseActivity.this), R.layout.item_price, parent, false);
+ MyViewHolder holder = new MyViewHolder<>(binding.getRoot());
+ holder.setBinding(binding);
+ return holder;
+ }
+
+ @Override
+ public void onBindViewHolder(MyViewHolder holder, int position) {
+ ItemPriceBinding binding = holder.getBinding();
+ binding.tvPrices.setText(dataList[position]);
+ binding.tvPrices.setOnClickListener(v -> payUtil.purchase(skus.get(position)));
+ }
+
+ @Override
+ public int getItemCount() {
+ return dataList.length;
+ }
+ }
+}
diff --git a/qpython/src/od/java/org/qpython/qpy/main/activity/SignInActivity.java b/qpython/src/od/java/org/qpython/qpy/main/activity/SignInActivity.java
new file mode 100644
index 00000000..b5fc5d2c
--- /dev/null
+++ b/qpython/src/od/java/org/qpython/qpy/main/activity/SignInActivity.java
@@ -0,0 +1,184 @@
+package org.qpython.qpy.main.activity;
+
+import android.content.Intent;
+import android.databinding.DataBindingUtil;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v7.app.AppCompatActivity;
+import android.text.Html;
+import android.util.Log;
+import android.view.View;
+import android.widget.Toast;
+
+import com.google.android.gms.auth.api.Auth;
+import com.google.android.gms.auth.api.signin.GoogleSignInAccount;
+import com.google.android.gms.auth.api.signin.GoogleSignInOptions;
+import com.google.android.gms.auth.api.signin.GoogleSignInResult;
+import com.google.android.gms.common.ConnectionResult;
+import com.google.android.gms.common.api.GoogleApiClient;
+import com.google.firebase.auth.AuthCredential;
+import com.google.firebase.auth.FirebaseAuth;
+import com.google.firebase.auth.FirebaseUser;
+import com.google.firebase.auth.GoogleAuthProvider;
+
+import org.qpython.qpy.R;
+import org.qpython.qpy.databinding.ActivitySignInBinding;
+import org.qpython.qpy.main.app.App;
+import org.qpython.qpy.main.app.CONF;
+import org.qpython.qpy.main.app.User;
+import org.qpython.qpy.main.server.gist.loginScreen.LoginControler;
+import org.qpython.qpy.main.server.gist.loginScreen.LoginView;
+
+/**
+ * SignIn
+ * Created by Hmei on 2017-08-04.
+ */
+
+public class SignInActivity extends AppCompatActivity implements GoogleApiClient.OnConnectionFailedListener ,LoginView{
+ private static final int RC_SIGN_IN = 54503;
+
+ private GoogleApiClient mGoogleApiClient;
+ private ActivitySignInBinding binding;
+ private FirebaseAuth mAuth;
+
+ private LoginControler mLoginControler;
+
+ {
+ mAuth = FirebaseAuth.getInstance();
+ FirebaseUser currentUser = mAuth.getCurrentUser();
+ initUserInfo(currentUser);
+ }
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ binding = DataBindingUtil.setContentView(this, R.layout.activity_sign_in);
+ binding.textView3.setText(Html.fromHtml(getString(R.string.by_signing_in_you_agree_to_out_privacy_policy_term_of_service)));
+ GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
+ .requestIdToken(CONF.GOOGLE_ID_TOKEN)
+ .requestEmail()
+ .build();
+
+ mGoogleApiClient = new GoogleApiClient.Builder(this)
+ .enableAutoManage(this, this)
+ .addApi(Auth.GOOGLE_SIGN_IN_API, gso)
+ .addOnConnectionFailedListener(connectionResult -> showToast(getString(R.string.lost_google_hint)))
+ .build();
+ initListener();
+
+ mLoginControler = new LoginControler(this);
+ }
+
+ private void initListener() {
+ binding.textView3.setOnClickListener(v -> startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.privacy_html)))));
+ binding.button2.setOnClickListener(v -> signIn());
+ binding.button3.setOnClickListener(v -> finish());
+ }
+
+ private void signIn() {
+ Intent signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient);
+ startActivityForResult(signInIntent, RC_SIGN_IN);
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ // Result returned from launching the Intent from GoogleSignInApi.getSignInIntent(...);
+ if (requestCode == RC_SIGN_IN) {
+ GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
+ if (result.isSuccess()) {
+ GoogleSignInAccount account = result.getSignInAccount();
+ firebaseAuthWithGoogle(account);
+ } else {
+ Log.e("LOGIN", result.getStatus().toString());
+ try {
+ String msg = result.getStatus().getStatusMessage().trim();
+ showToast(getString(R.string.login_error) + (msg.equals("") ? "" : ": ") + msg);
+ initUserInfo(null);
+ } catch (NullPointerException ignore) {
+ showToast(getString(R.string.no_google));
+ }
+ }
+ }
+ }
+
+ private void firebaseAuthWithGoogle(GoogleSignInAccount acct) {
+ showLoading();
+ AuthCredential credential = GoogleAuthProvider.getCredential(acct.getIdToken(), "45:FD:60:98:01:9A:37:D9:84:03:06:36:02:F6:85:2C:A2:1F:B8:67");
+ mAuth.signInWithCredential(credential)
+ .addOnCompleteListener(this, task -> {
+ if (task.isSuccessful()) {
+ FirebaseUser user = mAuth.getCurrentUser();
+ initUserInfo(user);
+ } else {
+ showToast(getString(R.string.auth_failed));
+ initUserInfo(null);
+ hideLoading();
+ }
+ });
+ }
+
+ private void initUserInfo(FirebaseUser currentUser) {
+ if (currentUser == null) {
+ App.setUser(null);
+ return;
+ }
+ Log.d("SingInActivity", "NICK:"+currentUser.getDisplayName()+"-UN:"+currentUser.getEmail());
+ User user = new User();
+ user.setUserId(currentUser.getUid());
+ user.setAvatarUrl(currentUser.getPhotoUrl() == null ? "" : currentUser.getPhotoUrl().toString());
+ user.setEmail(currentUser.getEmail());
+ user.setUserName(currentUser.getEmail());
+ user.setNick(currentUser.getDisplayName());
+ App.setUser(user);
+ if (mLoginControler!=null) {
+ mLoginControler.login(user);
+ } else {
+ Toast.makeText(this, R.string.signin_error, Toast.LENGTH_SHORT).show();
+ }
+ }
+
+ @Override
+ public void onConnectionFailed(@NonNull ConnectionResult connectionResult) {
+ initUserInfo(null);
+ }
+
+ @Override
+ public void showLoading() {
+ binding.progressBar2.setVisibility(View.VISIBLE);
+ }
+
+ @Override
+ public void hideLoading() {
+ binding.progressBar2.setVisibility(View.GONE);
+ }
+
+ @Override
+ public void showToast(String msg) {
+ Toast.makeText(SignInActivity.this, msg, Toast.LENGTH_SHORT)
+ .show();
+ }
+
+ @Override
+ public void loginSuccess() {
+ Log.d("SignInActivity", "loginSuccess");
+// setResult(RESULT_OK);
+// this.finish();
+
+ setResult(RESULT_OK);
+ binding.progressBar2.setVisibility(View.GONE);
+ showToast("login successfully");
+ finish();
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ if (mLoginControler!=null) {
+
+ mLoginControler.onDestroy();
+ }
+ }
+}
\ No newline at end of file
diff --git a/qpython/src/od/java/org/qpython/qpy/main/activity/UserActivity.java b/qpython/src/od/java/org/qpython/qpy/main/activity/UserActivity.java
new file mode 100644
index 00000000..09607c79
--- /dev/null
+++ b/qpython/src/od/java/org/qpython/qpy/main/activity/UserActivity.java
@@ -0,0 +1,77 @@
+package org.qpython.qpy.main.activity;
+
+import android.content.Context;
+import android.content.Intent;
+import android.databinding.DataBindingUtil;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.app.AppCompatActivity;
+import android.view.View;
+
+import com.google.firebase.auth.FirebaseAuth;
+import com.quseit.util.FileUtils;
+import com.quseit.util.ImageDownLoader;
+
+import org.qpython.qpy.R;
+import org.qpython.qpy.codeshare.CONSTANT;
+import org.qpython.qpy.codeshare.ShareCodeUtil;
+import org.qpython.qpy.databinding.ActivityUserBinding;
+import org.qpython.qpy.main.app.App;
+import org.qpython.qpy.main.app.CONF;
+
+import java.io.File;
+
+public class UserActivity extends AppCompatActivity {
+ ActivityUserBinding binding;
+
+ public static void start(Context context) {
+ Intent starter = new Intent(context, UserActivity.class);
+ context.startActivity(starter);
+ }
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ binding = DataBindingUtil.setContentView(this, R.layout.activity_user);
+ setSupportActionBar(binding.toolbar);
+ setTitle(getString(R.string.me));
+ binding.toolbar.setNavigationIcon(R.drawable.ic_back);
+ binding.toolbar.setNavigationOnClickListener(v -> finish());
+
+ ImageDownLoader.setImageFromUrl(this, binding.avatar, App.getUser().getAvatarUrl());
+ binding.name.setText(App.getUser().getNick());
+ //binding.email.setText(App.getUser().getEmail());
+
+ binding.usage.setText(R.string.my_space_empty);
+ binding.logout.setOnClickListener(v -> logout());
+ binding.myShareLayout.setOnClickListener(v -> MyGistActivity.startMyShare(UserActivity.this));
+ setUsage();
+ }
+
+ private void setUsage() {
+ ShareCodeUtil.getInstance().initUsage(integer ->
+ binding.usage.setText(getString(R.string.my_space, integer == null ? 0 : integer)));
+ }
+
+ private void logout() {
+ new AlertDialog.Builder(this, R.style.MyDialog)
+ .setTitle(R.string.lout)
+ .setPositiveButton(R.string.yes, (dialog, which) -> {
+ FirebaseAuth.getInstance().signOut();
+ App.setUser(null);
+ getPreferences(MODE_PRIVATE).edit().putBoolean(CONSTANT.IS_UPLOAD_INIT, false)
+ .putString(CONSTANT.CLOUDED_MAP, "")
+ .apply();
+ File cloud_cache = new File(FileUtils.getCloudMapCachePath(getApplicationContext()));
+ if (cloud_cache.exists()) {
+ cloud_cache.delete();
+ }
+ finish();
+ })
+ .setNegativeButton(R.string.no, null)
+ .create()
+ .show();
+
+ }
+}
\ No newline at end of file
diff --git a/qpython/src/od/java/org/qpython/qpy/main/app/AppInit.java b/qpython/src/od/java/org/qpython/qpy/main/app/AppInit.java
new file mode 100644
index 00000000..76cc52ab
--- /dev/null
+++ b/qpython/src/od/java/org/qpython/qpy/main/app/AppInit.java
@@ -0,0 +1,37 @@
+package org.qpython.qpy.main.app;
+
+import android.content.Context;
+import android.util.Log;
+
+import com.google.firebase.FirebaseApp;
+import com.google.firebase.iid.FirebaseInstanceId;
+import com.quseit.config.BASE_CONF;
+
+import org.qpython.qpy.codeshare.ShareCodeUtil;
+
+/**
+ * 文 件 名: AppInit
+ * 创 建 人: ZhangRonghua
+ * 创建日期: 2018/3/8 15:13
+ * 修改时间:
+ * 修改备注:
+ */
+
+public class AppInit {
+
+ public static void init(Context context){
+
+ FirebaseApp.initializeApp(context);
+ if (BASE_CONF.DEBUG) {
+ try {
+ FirebaseInstanceId xx = FirebaseInstanceId.getInstance();
+ if (xx != null) {
+ Log.e("Firebase", xx.getToken());
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ ShareCodeUtil.getInstance();
+ }
+}
diff --git a/qpython/src/od/java/org/qpython/qpy/main/fragment/ExplorerFragment.java b/qpython/src/od/java/org/qpython/qpy/main/fragment/ExplorerFragment.java
new file mode 100644
index 00000000..5713b1ec
--- /dev/null
+++ b/qpython/src/od/java/org/qpython/qpy/main/fragment/ExplorerFragment.java
@@ -0,0 +1,505 @@
+package org.qpython.qpy.main.fragment;
+
+import android.content.Intent;
+import android.databinding.DataBindingUtil;
+import android.graphics.Color;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Environment;
+import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.widget.LinearLayoutManager;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Toast;
+
+import com.google.firebase.database.DatabaseReference;
+import com.quseit.util.FileHelper;
+import com.quseit.util.ImageUtil;
+import com.yanzhenjie.recyclerview.swipe.SwipeMenuCreator;
+import com.yanzhenjie.recyclerview.swipe.SwipeMenuItem;
+
+import org.qpython.qpy.R;
+import org.qpython.qpy.codeshare.ShareCodeUtil;
+import org.qpython.qpy.codeshare.pojo.CloudFile;
+import org.qpython.qpy.databinding.FragmentExplorerBinding;
+import org.qpython.qpy.main.activity.NotebookActivity;
+import org.qpython.qpy.main.activity.SettingActivity;
+import org.qpython.qpy.main.activity.SignInActivity;
+import org.qpython.qpy.main.app.App;
+import org.qpython.qpy.main.app.CONF;
+import org.qpython.qpy.texteditor.EditorActivity;
+import org.qpython.qpy.texteditor.TedLocalActivity;
+import org.qpython.qpy.texteditor.common.CommonEnums;
+import org.qpython.qpy.texteditor.common.RecentFiles;
+import org.qpython.qpy.texteditor.ui.adapter.FolderAdapter;
+import org.qpython.qpy.texteditor.ui.adapter.bean.FolderBean;
+import org.qpython.qpy.texteditor.ui.view.EnterDialog;
+import org.qpython.qpy.texteditor.widget.crouton.Crouton;
+import org.qpython.qpy.texteditor.widget.crouton.Style;
+import org.qpython.qpy.utils.FileUtils;
+import org.qpython.qpy.utils.NotebookUtil;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static com.quseit.util.FolderUtils.sortTypeByName;
+
+public class ExplorerFragment extends Fragment {
+ private static final int REQUEST_SAVE_AS = 107;
+ private static final int REQUEST_HOME_PAGE = 109;
+ private static final int REQUEST_RECENT = 111;
+ private static final int LOGIN_REQUEST = 2741;
+
+ private static final String TYPE = "type";
+
+ private int WIDTH = (int) ImageUtil.dp2px(60);
+
+ private FragmentExplorerBinding binding;
+ private List folderList;
+ private FolderAdapter adapter;
+ private Map cloudedMap = new HashMap<>();
+
+ private boolean openable = true; // 是否可打开文件
+ private boolean uploadable;
+
+ private int type;
+ private String curPath;
+
+ public static ExplorerFragment newInstance(int type) {
+ ExplorerFragment myFragment = new ExplorerFragment();
+
+ Bundle args = new Bundle();
+ args.putInt(TYPE, type);
+ myFragment.setArguments(args);
+
+ return myFragment;
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.fragment_explorer, null);
+ }
+
+ @Override
+ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ binding = DataBindingUtil.bind(view);
+ type = getArguments().getInt(TYPE);
+ initView();
+ initListener();
+ initCloud();
+ switch (type) {
+ case REQUEST_RECENT:
+ binding.rlPath.setVisibility(View.GONE);
+ uploadable = false;
+ break;
+ case REQUEST_SAVE_AS:
+ binding.ivNewFolder.setVisibility(View.VISIBLE);
+ uploadable = false;
+ break;
+ case REQUEST_HOME_PAGE:
+ binding.ivNewFolder.setVisibility(View.VISIBLE);
+ uploadable = true;
+ break;
+ }
+ }
+
+ private void initView() {
+ SwipeMenuCreator swipeMenuCreator = (leftMenu, rightMenu, viewType) -> {
+// SwipeMenuItem uploadItem = new SwipeMenuItem(getContext())
+// .setBackgroundColor(Color.parseColor("#FF4798F3"))
+// .setImage(R.drawable.ic_cloud_upload)
+// .setHeight(ViewGroup.LayoutParams.MATCH_PARENT)
+// .setWidth(WIDTH);
+
+ SwipeMenuItem renameItem = new SwipeMenuItem(getContext())
+ .setBackgroundColor(Color.parseColor("#FF4BAC07"))
+ .setImage(R.drawable.ic_file_rename)
+ .setHeight(ViewGroup.LayoutParams.MATCH_PARENT)
+ .setWidth(WIDTH);
+
+ SwipeMenuItem deleteItem = new SwipeMenuItem(getContext())
+ .setBackgroundColor(Color.parseColor("#FFD14136"))
+ .setImage(R.drawable.ic_editor_filetree_close)
+ .setHeight(ViewGroup.LayoutParams.MATCH_PARENT)
+ .setWidth(WIDTH);
+
+ switch (type) {
+ case REQUEST_RECENT:
+ rightMenu.addMenuItem(deleteItem);
+ break;
+ case REQUEST_SAVE_AS:
+ rightMenu.addMenuItem(deleteItem);
+ break;
+ case REQUEST_HOME_PAGE:
+ //rightMenu.addMenuItem(uploadItem);
+ rightMenu.addMenuItem(renameItem);
+ rightMenu.addMenuItem(deleteItem);
+ break;
+ }
+ };
+
+ folderList = new ArrayList<>();
+ adapter = new FolderAdapter(folderList, getArguments().getInt(TYPE) == REQUEST_RECENT);
+ adapter.setCloudMap(cloudedMap);
+ binding.swipeList.setLayoutManager(new LinearLayoutManager(getContext()));
+ binding.swipeList.setSwipeMenuCreator(swipeMenuCreator);
+ openDir(FileUtils.getAbsolutePath(App.getContext()));
+ }
+
+ private void initListener() {
+ binding.ivNewFolder.setOnClickListener(v -> doNewDir());
+ binding.prevFolder.setOnClickListener(v -> {
+ try {
+ //采用Environment来获取sdcard路径
+ String parentPath = new File(curPath).getParent();
+
+ if (parentPath.length() >= com.quseit.util.FileUtils.getQyPath(App.getContext()).length()) {
+ openDir(parentPath);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ });
+ binding.swipeList.setSwipeMenuItemClickListener(menuBridge -> {
+ binding.swipeList.smoothCloseMenu();
+ switch (menuBridge.getPosition()) {
+ case 0:
+// if (uploadable) {
+// uploadFile(menuBridge.getAdapterPosition());
+// } else {
+// deleteFile(menuBridge.getAdapterPosition());
+// }
+// break;
+// case 1:
+ renameFile(menuBridge.getAdapterPosition());
+ break;
+ case 1:
+ deleteFile(menuBridge.getAdapterPosition());
+ break;
+ default:break;
+ }
+ });
+ adapter.setClickListener(new FolderAdapter.Click() {
+ @Override
+ public void onItemClick(int position) {
+ FolderBean item = folderList.get(position);
+ if (item.getType().equals(CommonEnums.FileType.FILE)) {
+ if (!openable) {
+ Toast.makeText(getActivity(), R.string.cant_open, Toast.LENGTH_SHORT).show();
+ return;
+ }
+ //判断文件类型
+ int lastDot = item.getName().lastIndexOf(".");
+ if (lastDot != -1) {
+ String ext = item.getName().substring(lastDot + 1);
+ openFile(item.getFile(), ext);
+ }
+ } else {
+ openDir(item.getPath());
+ }
+ }
+
+ @Override
+ public void onLongClick(int position) {
+ binding.swipeList.smoothOpenRightMenu(position);
+ }
+ });
+
+ binding.swipeList.setAdapter(adapter);
+ }
+
+ private void gotoSetting() {
+ SettingActivity.startActivity(getActivity());
+ }
+
+ private void openFile(File file, String ext) {
+ List textExts = Arrays.asList(getContext().getResources().getStringArray(R.array.text_ext));
+ if (textExts.contains(ext)) {
+ EditorActivity.start(getContext(), Uri.fromFile(file));
+ } else if (ext.equals("ipynb")) {
+ boolean notebookenable = NotebookUtil.isNotebookEnable(getActivity());
+ if (notebookenable) {
+ NotebookActivity.start(getActivity(), file.getAbsolutePath(), false);
+ } else {
+
+ new AlertDialog.Builder(getActivity(), R.style.MyDialog)
+ .setTitle(R.string.dialog_alert)
+ .setMessage(getString(R.string.ennable_notebook_first))
+ .setNegativeButton(R.string.cancel, (dialog1, which) -> dialog1.dismiss())
+ .setPositiveButton(R.string.ok, (dialog1, which) -> gotoSetting())
+ .create()
+ .show();
+
+ //Toast.makeText(getActivity(), R.string.ennable_notebook_first, Toast.LENGTH_SHORT).show();
+ }
+ } else {
+ FileUtils.openFile(getContext(), file);
+ }
+ }
+
+ private void uploadFile(int adapterPosition) {
+ File file = folderList.get(adapterPosition).getFile();
+
+ // only support type in
+ String ext = "";
+ if (file.getName().lastIndexOf(".") > 0) {
+ ext = file.getName().substring(file.getName().lastIndexOf(".") + 1);
+ }
+ boolean isSupport = false;
+ if (!file.isDirectory()) {
+ for (String s : getResources().getStringArray(R.array.support_file_ext)) {
+ if (s.equals(ext)) {
+ isSupport = true;
+ break;
+ }
+ }
+ } else {
+ isSupport = true;
+ }
+
+ if (!isSupport) {
+ Toast.makeText(getContext(), R.string.not_support_type_hint, Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ // only available for already login user
+ if (App.getUser() == null) {
+ new AlertDialog.Builder(getActivity(), R.style.MyDialog)
+ .setTitle(R.string.need_login)
+ .setMessage(R.string.upload_login_hint)
+ .setNegativeButton(R.string.no, null)
+ .setPositiveButton(getString(R.string.login_now), (dialog, which) ->
+ startActivityForResult(new Intent(getActivity(), SignInActivity.class), LOGIN_REQUEST)
+ )
+ .create()
+ .show();
+ return;
+ }
+
+ // upload
+ folderList.get(adapterPosition).setUploading(true);
+ adapter.notifyItemChanged(adapterPosition);
+ int[] size = {1};
+ DatabaseReference.CompletionListener listener = ((databaseError, databaseReference) -> {
+ if (databaseError == null) {
+// updateClouded(folderList.get(adapterPosition).getFile());
+// adapter.setUploadFile(adapterPosition);
+// ((TedLocalActivity) getActivity()).setNewUpload();
+// Toast.makeText(getActivity(), R.string.upload_suc, Toast.LENGTH_SHORT).show();
+// ShareCodeUtil.getInstance().changeUsage(size[0]);
+ } else {
+ Toast.makeText(getActivity(), databaseError.getMessage(), Toast.LENGTH_SHORT).show();
+ }
+ folderList.get(adapterPosition).setUploading(false);
+ adapter.notifyDataSetChanged();
+ });
+ if (folderList.get(adapterPosition).getFile().isDirectory()) {
+ // 如果上传整个projects目录,则将该目录下项目分开上传
+ if (folderList.get(adapterPosition).getName().contains("projects")) {
+ File[] files = folderList.get(adapterPosition).getFile().listFiles();
+ for (int i = 0; i < files.length; i++) {
+ if (!ShareCodeUtil.getInstance().uploadFolder(files[i].getPath(), i == 0 ? null : listener, size)) {
+ folderList.get(adapterPosition).setUploading(false);
+ adapter.notifyDataSetChanged();
+ }
+ }
+ } else {
+ if (!ShareCodeUtil.getInstance().uploadFolder(folderList.get(adapterPosition).getPath(), listener, size)) {
+ folderList.get(adapterPosition).setUploading(false);
+ adapter.notifyDataSetChanged();
+ }
+ }
+ } else {
+ if (!ShareCodeUtil.getInstance().uploadFile(folderList.get(adapterPosition).getPath(), listener)) {
+ folderList.get(adapterPosition).setUploading(false);
+ adapter.notifyDataSetChanged();
+ }
+ }
+ }
+
+ private void renameFile(int adapterPosition) {
+ new EnterDialog(getContext())
+ .setTitle(getString(R.string.rename))
+ .setConfirmListener(name -> {
+ File oldFile = folderList.get(adapterPosition).getFile();
+ File newFile = new File(oldFile.getParent(), name);
+ boolean renameSuc = oldFile.renameTo(newFile);
+ if (renameSuc) {
+ folderList.set(adapterPosition, new FolderBean(newFile));
+ adapter.notifyItemChanged(adapterPosition);
+ return true;
+ } else {
+ Toast.makeText(getActivity(), R.string.rename_fail, Toast.LENGTH_SHORT).show();
+ return false;
+ }
+ })
+ .setText(folderList.get(adapterPosition).getName())
+ .show();
+ }
+
+ private void deleteFile(int adapterPosition) {
+ switch (type) {
+ case REQUEST_RECENT:
+ RecentFiles.removePath(folderList.get(adapterPosition).getPath());
+ folderList.remove(adapterPosition);
+ adapter.notifyDataSetChanged();
+ break;
+ case REQUEST_HOME_PAGE:
+ case REQUEST_SAVE_AS:
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), R.style.MyDialog);
+ builder.setTitle(R.string.warning)
+ .setMessage(R.string.delete_file_hint)
+ .setNegativeButton(R.string.no, null)
+ .setPositiveButton(R.string.yes, (dialog, which) -> {
+ String dir = folderList.get(adapterPosition).getFile().getParent();
+ FileHelper.clearDir(folderList.get(adapterPosition).getFile().getAbsolutePath(), 0, true);
+ openDir(dir);
+
+// folderList.remove(adapterPosition);
+// adapter.notifyItemRemoved(adapterPosition);
+ })
+ .show();
+ break;
+ }
+ }
+
+ private void openDir(String dirPath) {
+ if (type == REQUEST_RECENT) {
+ folderList.clear();
+ for (String path : RecentFiles.getRecentFiles()) {
+ folderList.add(new FolderBean(new File(path)));
+ }
+
+ if (folderList.size() == 0) {
+ binding.emptyHint.setVisibility(View.VISIBLE);
+ } else {
+ binding.emptyHint.setVisibility(View.GONE);
+ adapter.notifyDataSetChanged();
+ }
+ } else {
+ binding.tvPath.setText(dirPath);
+ curPath = dirPath;
+ File dir = new File(dirPath);
+ if (dir.exists()) {
+ File[] files = dir.listFiles();
+ if (files != null) {
+ Arrays.sort(files, sortTypeByName);
+ folderList.clear();
+ adapter.notifyDataSetChanged();
+ for (File file : files) {
+ if (!dir.getName().equals(CONF.BASE_PATH)) {
+ if (!file.getName().startsWith(".")) {
+ folderList.add(new FolderBean(file));
+ }
+
+ } else {
+ folderList.add(new FolderBean(file));
+
+ }
+
+ }
+ adapter.notifyDataSetChanged();
+ }
+ } else {
+ Toast.makeText(getContext(), R.string.file_not_exists, Toast.LENGTH_SHORT).show();
+ }
+ }
+ }
+
+ private void doNewDir() {
+ new EnterDialog(getContext())
+ .setTitle(getString(R.string.new_folder))
+ .setHint(getString(R.string.folder_name))
+ .setConfirmListener(name -> {
+ File dirN = new File(curPath, name.equals("") ? getString(R.string.untitled_folder) : name);
+ if (dirN.exists()) {
+ Crouton.makeText(getActivity(), getString(R.string.toast_folder_exist), Style.ALERT).show();
+ return false;
+ } else {
+ if (dirN.mkdirs()) {
+ openDir(curPath + "/" + name);
+ } else {
+ Toast.makeText(getContext(), R.string.mkdir_fail, Toast.LENGTH_SHORT).show();
+ }
+ return true;
+ }
+ })
+ .show();
+ }
+
+ public void backToPrev() {
+ Log.d("ExplorerFragment", "backToPrev:" + curPath);
+ String qpyDir = com.quseit.util.FileUtils.getQyPath(App.getContext()) + "/qpython";
+ if (curPath == null || qpyDir.equals(curPath) || com.quseit.util.FileUtils.getQyPath(App.getContext()).equals(curPath)) {
+ getActivity().finish();
+ } else {
+ String parentPath = new File(curPath).getParent();
+ if (!TextUtils.isEmpty(parentPath)) openDir(parentPath);
+ }
+ }
+
+ private void updateClouded(File file) {
+ if (file.getParent().contains("projects")) {
+ String parent = file.getParent() + "/";
+ String subPath = file.getPath().substring(file.getPath().indexOf(parent) + parent.length());
+ String projName = subPath.contains("/") ? subPath.substring(0, subPath.indexOf("/")) : "/" + subPath;
+ cloudedMap.put(FileUtils.getAbsolutePath(App.getContext()) + projName, true);
+ }
+ if (file.isDirectory()) {
+ for (File file1 : FileHelper.filterExt(file, getResources().getStringArray(R.array.support_file_ext))) {
+ cloudedMap.put(file1.getPath(), true);
+ }
+ } else {
+ cloudedMap.put(file.getPath(), true);
+ }
+ }
+
+ public String getCurPath() {
+ return curPath;
+ }
+
+ private void initCloud() {
+ if (App.getUser() == null) {
+ return;
+ }
+ ShareCodeUtil.getInstance().getUploadedScripts(false, getActivity(), cloudFiles -> {
+ if (cloudFiles == null || cloudFiles.size() == 0) {
+ return;
+ }
+ for (CloudFile cloudFile : cloudFiles) {
+ if (cloudFile.getPath().contains("/projects")) {
+ String projNode = cloudFile.getPath().contains("/projects3/") ? "/projects3/" : "/projects/";
+ cloudedMap.put(FileUtils.getAbsolutePath(App.getContext()) + projNode + cloudFile.getProjectName(), true);
+ }
+ cloudedMap.put(FileUtils.getAbsolutePath(App.getContext()) + cloudFile.getPath(), true);
+ }
+ adapter.setCloudMap(cloudedMap);
+ adapter.notifyDataSetChanged();
+ });
+ }
+
+ public void deleteCloudedMap(String absolutePath) {
+ if (cloudedMap.containsKey(absolutePath)) {
+ cloudedMap.remove(absolutePath);
+ adapter.notifyDataSetChanged();
+ }
+ }
+
+ public void updateCloudedFiles(Map map) {
+ if (map != null) {
+ cloudedMap.putAll(map);
+ }
+ adapter.notifyDataSetChanged();
+ }
+}
diff --git a/qpython/src/od/java/org/qpython/qpy/main/fragment/MyProjectFragment.java b/qpython/src/od/java/org/qpython/qpy/main/fragment/MyProjectFragment.java
new file mode 100644
index 00000000..5d250ec0
--- /dev/null
+++ b/qpython/src/od/java/org/qpython/qpy/main/fragment/MyProjectFragment.java
@@ -0,0 +1,259 @@
+package org.qpython.qpy.main.fragment;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.databinding.DataBindingUtil;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.widget.LinearLayoutManager;
+import android.text.Html;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Toast;
+
+import com.quseit.util.DateTimeHelper;
+import com.quseit.util.ImageUtil;
+import com.yanzhenjie.recyclerview.swipe.SwipeMenuCreator;
+import com.yanzhenjie.recyclerview.swipe.SwipeMenuItem;
+
+import org.qpython.qpy.R;
+import org.qpython.qpy.codeshare.CONSTANT;
+import org.qpython.qpy.codeshare.ShareCodeUtil;
+import org.qpython.qpy.codeshare.pojo.CloudFile;
+import org.qpython.qpy.databinding.FragmentRefreshRvBinding;
+import org.qpython.qpy.main.adapter.CloudScriptAdapter;
+import org.qpython.qpy.main.app.App;
+import org.qpython.qpy.texteditor.TedLocalActivity;
+import org.qpython.qpy.utils.FileUtils;
+import org.qpython.qpysdk.QPyConstants;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import rx.Observable;
+import rx.android.schedulers.AndroidSchedulers;
+
+public class MyProjectFragment extends Fragment {
+ private int WIDTH = (int) ImageUtil.dp2px(60);
+ private FragmentRefreshRvBinding binding;
+ private CloudScriptAdapter adapter;
+ private List scriptList = new ArrayList<>();
+ private TedLocalActivity activity;
+
+ public boolean isLoading;
+
+ @Nullable
+ @Override
+ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
+ binding = DataBindingUtil.bind(LayoutInflater.from(getContext()).inflate(R.layout.fragment_refresh_rv, null));
+ return binding.getRoot();
+ }
+
+ @Override
+ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ scriptList = new ArrayList<>();
+ adapter = new CloudScriptAdapter(scriptList);
+ ShareCodeUtil.getInstance().clearAll();
+ initView();
+ initListener();
+ retry(true);
+ }
+
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ activity = (TedLocalActivity) context;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ if (adapter != null) {
+ adapter.notifyDataSetChanged();
+ }
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+// activity.locatedCloud(scriptList);
+ }
+
+ public void retry(boolean forceRefresh) {
+ if (scriptList != null && adapter != null) {
+ scriptList.clear();
+ adapter.notifyDataSetChanged();
+ }
+ startProgressBar();
+ isLoading = true;
+ ShareCodeUtil.getInstance().getUploadedScripts(forceRefresh, getActivity(), cloudFiles -> {
+ isLoading = false;
+ if (cloudFiles == null || cloudFiles.size() == 0) {
+ showEmpty();
+ return;
+ }
+// ((TedLocalActivity) getActivity()).updateCloudFiles(cloudFiles);
+ scriptList.clear();
+ scriptList.addAll(cloudFiles);
+ adapter.notifyDataSetChanged();
+ binding.progressBar.setVisibility(View.GONE);
+ binding.netError.setVisibility(View.GONE);
+ });
+ }
+
+ public void notifyDataSetChange() {
+ if (adapter != null) adapter.notifyDataSetChanged();
+ }
+
+ private void startProgressBar() {
+ binding.progressBar.setVisibility(View.VISIBLE);
+ binding.netError.setVisibility(View.GONE);
+ Observable.just(null)
+ .delay(5, TimeUnit.SECONDS)
+ .observeOn(AndroidSchedulers.mainThread())
+ .doOnNext(o -> showNetErrorText())
+ .subscribe();
+ }
+
+ private void showEmpty() {
+ if (binding.progressBar.getVisibility() == View.VISIBLE) {
+ binding.progressBar.setVisibility(View.GONE);
+ binding.netError.setText(R.string.cloud_empty_hint);
+ binding.netError.setVisibility(View.VISIBLE);
+ }
+ }
+
+ private void showNetErrorText() {
+ if (binding.progressBar.getVisibility() == View.VISIBLE) {
+ binding.progressBar.setVisibility(View.GONE);
+ binding.netError.setText(R.string.net_lagging);
+ binding.netError.setVisibility(View.VISIBLE);
+ }
+ }
+
+ private void initView() {
+ SwipeMenuCreator swipeMenuCreator = (leftMenu, rightMenu, viewType) -> {
+ SwipeMenuItem deleteItem = new SwipeMenuItem(getContext())
+ .setBackgroundColor(Color.parseColor("#FFD14136"))
+ .setImage(R.drawable.ic_editor_filetree_close)
+ .setHeight(ViewGroup.LayoutParams.MATCH_PARENT)
+ .setWidth(WIDTH);
+
+ SwipeMenuItem downloadItem = new SwipeMenuItem(getContext())
+ .setBackgroundColor(Color.parseColor("#FF4798F3"))
+ .setImage(R.drawable.ic_cloud_download)
+ .setHeight(ViewGroup.LayoutParams.MATCH_PARENT)
+ .setWidth(WIDTH);
+ rightMenu.addMenuItem(downloadItem);
+ rightMenu.addMenuItem(deleteItem);
+ };
+ binding.swipeList.setLayoutManager(new LinearLayoutManager(getContext()));
+ binding.swipeList.setSwipeMenuCreator(swipeMenuCreator);
+ }
+
+ @SuppressLint("StringFormatMatches")
+ private void initListener() {
+ binding.netError.setOnClickListener(v -> retry(true));
+ binding.swipeList.setSwipeMenuItemClickListener(menuBridge -> {
+ menuBridge.closeMenu();
+ switch (menuBridge.getPosition()) {
+ default:break;
+ case 0:
+ // download
+ CloudFile cloudFile = scriptList.get(menuBridge.getAdapterPosition());
+ cloudFile.setUploading(true);
+ adapter.notifyItemChanged(menuBridge.getAdapterPosition());
+ String path;
+ path = FileUtils.getAbsolutePath(App.getContext()) + cloudFile.getPath();
+ File file = new File(path);
+ if (file.exists()) {
+ new AlertDialog.Builder(getContext(), R.style.MyDialog)
+ .setTitle(R.string.override_hint)
+ .setMessage(Html.fromHtml(getString(R.string.conflict_hint,
+ cloudFile.getUploadTime(),
+ DateTimeHelper.AGO_FULL_DATE_FORMATTER.format(new Date(file.lastModified())))))
+ .setNegativeButton(R.string.no, (dialog, which) ->{
+ cloudFile.setUploading(false);
+ adapter.notifyItemChanged(menuBridge.getAdapterPosition());
+ })
+ .setPositiveButton(R.string.yes,
+ (dialog, which) ->
+ getRemoteContentNWrite(cloudFile, path, menuBridge.getAdapterPosition()))
+ .create()
+ .show();
+ } else {
+ getRemoteContentNWrite(cloudFile, path, menuBridge.getAdapterPosition());
+ }
+ break;
+ case 1:
+ // delete
+ scriptList.get(menuBridge.getAdapterPosition()).setUploading(true);
+ adapter.notifyItemChanged(menuBridge.getAdapterPosition());
+ ShareCodeUtil.getInstance().deleteUploadScript(scriptList.get(menuBridge.getAdapterPosition()), (databaseError, databaseReference) -> {
+// if (databaseError == null && getContext() != null) {
+// Toast.makeText(getContext(), R.string.delete_remote_suc, Toast.LENGTH_SHORT).show();
+// adapter.notifyItemRemoved(menuBridge.getAdapterPosition());
+// ((TedLocalActivity) getActivity()).deleteCloudFile(scriptList.get(menuBridge.getAdapterPosition()).getAbsolutePath());
+// scriptList.remove(menuBridge.getAdapterPosition());
+// if (scriptList.size() == 0) {
+// binding.netError.setText(R.string.cloud_empty_hint);
+// binding.netError.setVisibility(View.VISIBLE);
+// } else {
+// binding.netError.setVisibility(View.INVISIBLE);
+// }
+// } else {
+// Toast.makeText(getContext(), databaseError.getMessage(), Toast.LENGTH_SHORT).show();
+// }
+ });
+ break;
+ }
+ });
+ adapter.setCallback((position) -> binding.swipeList.smoothOpenRightMenu(position));
+ binding.swipeList.setAdapter(adapter);
+ }
+
+ private void getRemoteContentNWrite(CloudFile cloudFile, String path, int position) {
+ String key = cloudFile.getKey();
+ if (cloudFile.getProjectName() != null && !cloudFile.getKey().contains("projects3")) {
+ key = key.replace(cloudFile.getProjectName() + CONSTANT.SLASH_REPLACE, cloudFile.getProjectName() + "/" + CONSTANT.SLASH_REPLACE);
+ }
+ ShareCodeUtil.getInstance().getFileContent(key, content -> {
+ writeFile(path, content, position);
+ scriptList.get(position).setUploading(false);
+ adapter.notifyItemChanged(position);
+ });
+ }
+
+ private void writeFile(String path, String content, int adapterPosition) {
+ try {
+ FileWriter writer = new FileWriter(new File(path), false);
+ writer.write(content);
+ writer.close();
+ Toast.makeText(getContext(), R.string.file_downloaded, Toast.LENGTH_SHORT).show();
+ adapter.notifyItemChanged(adapterPosition);
+ } catch (IOException e) {
+ e.printStackTrace();
+ Toast.makeText(getContext(), R.string.override_fail_hint, Toast.LENGTH_SHORT).show();
+ }
+ }
+
+ public void needRefresh(boolean isNewUpload) {
+ if (binding == null) {
+ // not init yet
+ return;
+ }
+ if (isNewUpload) {
+ retry(true);
+ }
+ }
+}
diff --git a/qpython/src/od/java/org/qpython/qpy/main/receiver/LeancloudReceiver.java b/qpython/src/od/java/org/qpython/qpy/main/receiver/LeancloudReceiver.java
new file mode 100644
index 00000000..6f12375e
--- /dev/null
+++ b/qpython/src/od/java/org/qpython/qpy/main/receiver/LeancloudReceiver.java
@@ -0,0 +1,18 @@
+package org.qpython.qpy.main.receiver;
+
+import android.annotation.SuppressLint;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+/**
+ * 处理leancloud的消息推送
+ */
+public class LeancloudReceiver extends BroadcastReceiver {
+
+ @SuppressLint("UnsafeProtectedBroadcastReceiver")
+ @Override
+ public void onReceive(Context context, Intent intent) {
+
+ }
+}
\ No newline at end of file
diff --git a/qpython/src/od/java/org/qpython/qpy/main/service/MyFirebaseInstanceIDService.java b/qpython/src/od/java/org/qpython/qpy/main/service/MyFirebaseInstanceIDService.java
new file mode 100644
index 00000000..362c2336
--- /dev/null
+++ b/qpython/src/od/java/org/qpython/qpy/main/service/MyFirebaseInstanceIDService.java
@@ -0,0 +1,15 @@
+package org.qpython.qpy.main.service;
+
+import com.google.firebase.iid.FirebaseInstanceId;
+import com.google.firebase.iid.FirebaseInstanceIdService;
+
+/**
+ * Created by Hmei on 2017-06-29.
+ */
+
+public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService {
+ @Override
+ public void onTokenRefresh() {
+ String refreshedToken = FirebaseInstanceId.getInstance().getToken();
+ }
+}
diff --git a/qpython/src/od/java/org/qpython/qpy/main/service/MyFirebaseMessagingService.java b/qpython/src/od/java/org/qpython/qpy/main/service/MyFirebaseMessagingService.java
new file mode 100644
index 00000000..9f333943
--- /dev/null
+++ b/qpython/src/od/java/org/qpython/qpy/main/service/MyFirebaseMessagingService.java
@@ -0,0 +1,88 @@
+package org.qpython.qpy.main.service;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.net.Uri;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+
+import com.google.firebase.messaging.FirebaseMessagingService;
+import com.google.firebase.messaging.RemoteMessage;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.qpython.qpy.R;
+import org.qpython.qpy.main.activity.QWebViewActivity;
+import org.qpython.qpy.main.app.App;
+import org.qpython.qpy.main.app.CONF;
+import org.qpython.qpy.main.receiver.NotificationBean;
+
+import java.util.Map;
+
+
+public class MyFirebaseMessagingService extends FirebaseMessagingService {
+ private static final int LOG_NOTIFICATION_ID = (int) System.currentTimeMillis();
+
+ private boolean handled = false;
+
+ @Override
+ public void onMessageReceived(RemoteMessage remoteMessage) {
+ super.onMessageReceived(remoteMessage);
+ Map data = remoteMessage.getData();
+ String json = App.getGson().toJson(data);
+ NotificationBean bean = App.getGson().fromJson(json, NotificationBean.class);
+ if (!bean.isForce()&&!PreferenceManager.getDefaultSharedPreferences(this).getBoolean(getString(R.string.key_hide_push), true)) {
+ return;
+ }
+ Intent intent;
+ if (bean.getType().equals("ext")) {
+ intent = new Intent(Intent.ACTION_VIEW, Uri.parse(bean.getLink()));
+ } else {
+ intent = new Intent(App.getContext(), QWebViewActivity.class);
+ intent.putExtra(QWebViewActivity.TITLE, bean.getTitle());
+ intent.putExtra("url", bean.getLink());
+ }
+
+ PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
+
+ Notification.Builder builder = new Notification.Builder(this)
+ .setSmallIcon(R.drawable.img_home_logo)
+ .setContentTitle(getString(R.string.app_name))
+ .setContentText(bean.getMsg())
+ .setContentIntent(pendingIntent)
+ .setAutoCancel(true);
+
+ Notification notification;
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
+ notification = builder.build();
+ } else {
+ notification = builder.getNotification();
+ }
+ NotificationManager mNotifyMgr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
+ mNotifyMgr.notify(LOG_NOTIFICATION_ID, notification);
+ handled = true;
+ }
+
+ /* @Override
+ public void handleIntent(Intent intent) {
+ super.handleIntent(intent);
+ if (handled) {
+ return;
+ }
+ Bundle bundle = intent.getExtras();
+ JSONObject extras = new JSONObject();
+ try {
+ for (String s : bundle.keySet()) {
+ extras.put(s, bundle.get(s));
+ }
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ SharedPreferences.Editor editor = getSharedPreferences(CONF.NOTIFICATION_SP_NAME, MODE_PRIVATE).edit();
+ editor.putString(CONF.NOTIFICATION_SP_OBJ, extras.toString());
+ editor.apply();
+ }*/
+}
\ No newline at end of file
diff --git a/qpython/src/od/java/org/qpython/qpy/main/service/PayUtil.java b/qpython/src/od/java/org/qpython/qpy/main/service/PayUtil.java
new file mode 100644
index 00000000..8b88e8cc
--- /dev/null
+++ b/qpython/src/od/java/org/qpython/qpy/main/service/PayUtil.java
@@ -0,0 +1,150 @@
+package org.qpython.qpy.main.service;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentSender;
+import android.content.ServiceConnection;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.view.View;
+import android.widget.Toast;
+
+import com.android.vending.billing.IInAppBillingService;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.qpython.qpy.R;
+import org.qpython.qpy.main.server.MySubscriber;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import rx.Observable;
+import rx.android.schedulers.AndroidSchedulers;
+import rx.schedulers.Schedulers;
+
+/**
+ * Created by Hmei
+ * 1/31/18.
+ */
+
+public class PayUtil {
+ private static final int BUY_REQUEST_CODE = 2333;
+ private IInAppBillingService mService;
+ private ServiceConnection mServiceConn;
+ private Activity context;
+
+ public PayUtil(Activity context) {
+ this.context = context;
+ }
+
+ public void initIAP(PayCallback callback) {
+ mServiceConn = new ServiceConnection() {
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ mService = null;
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName name,
+ IBinder service) {
+ mService = IInAppBillingService.Stub.asInterface(service);
+ if (callback != null) callback.doAfterConn();
+ }
+ };
+ Intent serviceIntent = new Intent("com.android.vending.billing.InAppBillingService.BIND");
+ serviceIntent.setPackage("com.android.vending");
+ context.bindService(serviceIntent, mServiceConn, Context.BIND_AUTO_CREATE);
+ }
+
+ /**
+ * 从Google服务器获取不同国家价格表并显示
+ */
+ public void getPrices(ArrayList skuList, MySubscriber callback) {
+ if (mService == null) {
+ Toast.makeText(context, R.string.lose_google_server, Toast.LENGTH_SHORT).show();
+ if (context.findViewById(R.id.pb) != null)
+ context.findViewById(R.id.pb).setVisibility(View.GONE);
+ return;
+ }
+ Bundle querySkus = new Bundle();
+ querySkus.putStringArrayList("ITEM_ID_LIST", skuList);
+ try {
+ Observable.just(mService.getSkuDetails(3, context.getPackageName(), "inapp", querySkus))
+ .map(bundle -> {
+ ArrayList responseList = bundle.getStringArrayList("DETAILS_LIST");
+ if (responseList == null) {
+ return null;
+ }
+ String[] prices = new String[responseList.size()];
+ for (int i = 0; i < responseList.size(); i++) {
+ JSONObject object;
+ try {
+ object = new JSONObject(responseList.get(i));
+ String price = object.getString("price");
+ prices[i] = price;
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+ Arrays.sort(prices, (o1, o2) -> Integer.parseInt(o1.replaceAll("[^0-9]", "")) - Integer.parseInt(o2.replaceAll("[^0-9]", "")));
+ return prices;
+ }
+ )
+ .subscribeOn(Schedulers.newThread())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(callback);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void digestPurchase(String purchaseToken) {
+ // 消耗购买,使能重复赞赏同一金额
+ try {
+ Observable.just(mService.consumePurchase(3, context.getPackageName(), purchaseToken))
+ .subscribeOn(Schedulers.newThread())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe();
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void purchase(String sku) {
+ try {
+ if (mService == null) {
+ Toast.makeText(context, R.string.lose_google_server, Toast.LENGTH_SHORT).show();
+ return;
+ }
+ Bundle buyIntentBundle = mService.getBuyIntent(3, context.getPackageName(),
+ sku, "inapp", "bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ");
+ switch (buyIntentBundle.getInt("RESPONSE_CODE")) {
+ case 0:
+ //BILLING_RESPONSE_RESULT_OK
+ PendingIntent pendingIntent = buyIntentBundle.getParcelable("BUY_INTENT");
+ context.startIntentSenderForResult(pendingIntent.getIntentSender(),
+ BUY_REQUEST_CODE, new Intent(), 0, 0, 0);
+ break;
+
+ }
+ } catch (RemoteException | IntentSender.SendIntentException | NullPointerException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void unbindPayService() {
+ if (mService != null) {
+ context.unbindService(mServiceConn);
+ }
+ }
+
+ public interface PayCallback {
+ void doAfterConn();
+ }
+
+}
diff --git a/qpython/src/od/java/org/qpython/qpy/texteditor/TedLocalActivity.java b/qpython/src/od/java/org/qpython/qpy/texteditor/TedLocalActivity.java
new file mode 100644
index 00000000..466f0c8a
--- /dev/null
+++ b/qpython/src/od/java/org/qpython/qpy/texteditor/TedLocalActivity.java
@@ -0,0 +1,308 @@
+package org.qpython.qpy.texteditor;
+
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.databinding.DataBindingUtil;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.support.v7.app.AppCompatActivity;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.EditText;
+import android.widget.Toast;
+
+import com.google.gson.reflect.TypeToken;
+import com.quseit.util.FileHelper;
+import com.quseit.util.NAction;
+
+import org.qpython.qpy.R;
+import org.qpython.qpy.codeshare.pojo.CloudFile;
+import org.qpython.qpy.databinding.ActivityLocalBinding;
+import org.qpython.qpy.main.activity.SignInActivity;
+import org.qpython.qpy.main.app.App;
+import org.qpython.qpy.main.app.CONF;
+import org.qpython.qpy.main.fragment.ExplorerFragment;
+import org.qpython.qpy.main.fragment.LocalFragment;
+import org.qpython.qpy.main.fragment.MyProjectFragment;
+import org.qpython.qpy.utils.NotebookUtil;
+import org.qpython.qpysdk.QPyConstants;
+
+import java.io.File;
+import java.lang.reflect.Type;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class TedLocalActivity extends AppCompatActivity {
+ public static final int REQUEST_SAVE_AS = 107;
+ public static final int REQUEST_OPEN = 108;
+ public static final int REQUEST_HOME_PAGE = 109;
+ public static final int REQUEST_RECENT = 111;
+ private static final int LOGIN_REQUEST_CODE = 4806;
+
+ private static final String EXTRA_REQUEST_CODE = "request_code";
+ private static final String EXTRA_REQUEST_FN = "request_fn";
+
+ private static final String FRAGMENT_EXPLORER = "explorer";
+ private static final String FRAGMENT_CLOUD = "cloud";
+
+ private ActivityLocalBinding binding;
+
+ private Fragment firstPageFragment;
+ private MyProjectFragment myProjectFragment;
+
+ private boolean isExplorer = true;
+ private boolean isNewUpload = false;
+ //private String defaultFileName = "";
+
+ public static void start(Context context, int type) {
+ Intent starter = new Intent(context, TedLocalActivity.class);
+ starter.putExtra(EXTRA_REQUEST_CODE, type);
+ context.startActivity(starter);
+ }
+
+ public static void start(Activity context, int type, int requestCode, String filename) {
+ Intent starter = new Intent(context, TedLocalActivity.class);
+ starter.putExtra(EXTRA_REQUEST_CODE, type);
+ starter.putExtra(EXTRA_REQUEST_FN, filename);
+
+ context.startActivityForResult(starter, requestCode);
+ }
+
+ public void finishForGetPath(String path) {
+ Intent intent = new Intent();
+ intent.putExtra("path", path);
+ setResult(Activity.RESULT_OK, intent);
+ finish();
+ }
+
+ public void finishForOpen(String path, boolean isProj) {
+ Intent intent = new Intent();
+ intent.putExtra("path", path);
+ intent.putExtra("isProj", isProj);
+ setResult(Activity.RESULT_OK, intent);
+ finish();
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ binding = DataBindingUtil.setContentView(this, R.layout.activity_local);
+ setSupportActionBar(binding.toolbar);
+ int type = getIntent().getIntExtra(EXTRA_REQUEST_CODE, REQUEST_HOME_PAGE);
+
+ initView();
+ initListener();
+ switch (type) {
+ case REQUEST_RECENT:
+ setTitle(R.string.recent);
+ binding.switchBtn.setVisibility(View.GONE);
+ firstPageFragment = ExplorerFragment.newInstance(type);
+ break;
+ case REQUEST_OPEN:
+ setTitle(R.string.open);
+ binding.switchBtn.setVisibility(View.GONE);
+ binding.explore.setVisibility(View.VISIBLE);
+ firstPageFragment = new LocalFragment();
+ break;
+ case REQUEST_SAVE_AS:
+ setTitle(R.string.save_as);
+ binding.vsSave.getRoot().setVisibility(View.VISIBLE);
+ initSaveListener();
+
+ String fn = getIntent().getStringExtra(EXTRA_REQUEST_FN);
+ if (fn!=null) {
+ binding.vsSave.etName.setText(fn);
+ }
+ binding.switchBtn.setVisibility(View.GONE);
+ firstPageFragment = ExplorerFragment.newInstance(type);
+ break;
+ case REQUEST_HOME_PAGE:
+ setTitle(R.string.explorer);
+ firstPageFragment = ExplorerFragment.newInstance(type);
+ break;
+ }
+
+ getSupportFragmentManager().beginTransaction()
+ .add(R.id.container, firstPageFragment, FRAGMENT_EXPLORER)
+ .commit();
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ }
+
+ private void initView() {
+ binding.toolbar.setNavigationIcon(R.drawable.ic_back);
+ binding.toolbar.setNavigationOnClickListener(v -> finish());
+ if (binding.switchBtn.getVisibility() == View.VISIBLE) {
+ myProjectFragment = new MyProjectFragment();
+ }
+ }
+
+ private void initListener() {
+ binding.switchBtn.setOnClickListener(v -> {
+ if (isExplorer) {
+ if (App.getUser() == null) {
+ startActivityForResult(new Intent(this, SignInActivity.class), LOGIN_REQUEST_CODE);
+ return;
+ }
+ binding.switchBtn.setImageResource(R.drawable.ic_folder_open);
+ binding.refresh.setVisibility(View.VISIBLE);
+ if (getSupportFragmentManager().findFragmentByTag(FRAGMENT_CLOUD) == null) {
+ getSupportFragmentManager().beginTransaction().add(R.id.container, myProjectFragment, FRAGMENT_CLOUD).commit();
+ getSupportFragmentManager().beginTransaction().hide(firstPageFragment).commit();
+ } else {
+ getSupportFragmentManager().beginTransaction()
+ .hide(firstPageFragment)
+ .show(myProjectFragment)
+ .commit();
+ }
+ myProjectFragment.needRefresh(isNewUpload);
+ isNewUpload = false;
+ if (!myProjectFragment.isLoading) {
+ myProjectFragment.notifyDataSetChange();
+ }
+ } else {
+ binding.switchBtn.setImageResource(R.drawable.ic_cloud_list);
+ binding.refresh.setVisibility(View.GONE);
+ getSupportFragmentManager().beginTransaction()
+ .hide(myProjectFragment)
+ .show(firstPageFragment)
+ .commit();
+ }
+ isExplorer = !isExplorer;
+ });
+
+ binding.refresh.setOnClickListener(v -> myProjectFragment.retry(true));
+
+ binding.explore.setOnClickListener(v -> {
+ start(this, REQUEST_HOME_PAGE);
+ finish();
+ });
+ }
+
+ public void doSave(String fn) {
+ if (fn.length() == 0) {
+ Toast.makeText(getApplicationContext(), R.string.toast_filename_empty, Toast.LENGTH_SHORT).show();
+ } else {
+ String filename = ((ExplorerFragment) firstPageFragment).getCurPath() + "/" + fn;
+ final File f = new File(filename);
+ if (f.exists()) {
+ Toast.makeText(this, R.string.file_exist_hint, Toast.LENGTH_SHORT).show();
+ } else {
+ setSaveResult(f.getAbsolutePath());
+ }
+ }
+ }
+
+ protected boolean setSaveResult(String filepath) {
+ File f = new File(filepath);
+ if (f.getParentFile().canWrite()) {
+ finishForGetPath(filepath);
+ } else {
+ Toast.makeText(getApplicationContext(), R.string.toast_folder_cant_write, Toast.LENGTH_SHORT).show();
+ }
+ return true;
+ }
+
+ private void initSaveListener() {
+ binding.vsSave.btnSave.setOnClickListener(v -> doSave(binding.vsSave.etName.getText().toString()));
+ binding.vsSave.etName.setOnTouchListener((v, event) -> {
+ final int DRAWABLE_RIGHT = 2;
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ Drawable deleteText = ((EditText) v).getCompoundDrawables()[DRAWABLE_RIGHT];
+ if (deleteText != null) {
+ if (event.getRawX() >= (v.getRight() - deleteText.getBounds().width())) {
+ ((EditText) v).setText("");
+ return true;
+ }
+ }
+ break;
+ case MotionEvent.ACTION_UP:
+ v.performClick();
+ break;
+ default:
+ break;
+ }
+ return false;
+ });
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ if (resultCode == RESULT_OK) {
+ switch (requestCode) {
+ case LOGIN_REQUEST_CODE:
+ binding.switchBtn.setImageResource(R.drawable.ic_folder_open);
+ if (getSupportFragmentManager().findFragmentByTag(FRAGMENT_CLOUD) == null) {
+ getSupportFragmentManager().beginTransaction().add(R.id.container, myProjectFragment, FRAGMENT_CLOUD).commit();
+ getSupportFragmentManager().beginTransaction().hide(firstPageFragment).commit();
+ } else {
+ getSupportFragmentManager().beginTransaction()
+ .hide(firstPageFragment)
+ .show(myProjectFragment)
+ .commit();
+ }
+ isExplorer = !isExplorer;
+ break;
+ }
+ }
+ }
+
+ @Override
+ public void onBackPressed() {
+ if (firstPageFragment.isVisible() && firstPageFragment instanceof ExplorerFragment) {
+ ((ExplorerFragment) firstPageFragment).backToPrev();
+ } else {
+ super.onBackPressed();
+ }
+ }
+
+// public void deleteCloudFile(String path) {
+// if (firstPageFragment instanceof ExplorerFragment) {
+// ((ExplorerFragment) firstPageFragment).deleteCloudedMap(path);
+// }
+// }
+//
+// public void updateCloudFiles(List cloudFiles) {
+// Map map = new HashMap<>();
+// boolean isQPy3 = NAction.isQPy3(getBaseContext());
+// String tag = isQPy3?"/projects3/":"/projects/";
+// for (CloudFile cloudFile : cloudFiles) {
+// if (cloudFile.getPath().contains(tag)) {
+// map.put(QPyConstants.ABSOLUTE_PATH + tag + cloudFile.getProjectName(), true);
+// }
+// map.put(QPyConstants.ABSOLUTE_PATH + cloudFile.getPath(), true);
+// }
+// ((ExplorerFragment) firstPageFragment).updateCloudedFiles(map);
+// }
+//
+// public void setNewUpload() {
+// isNewUpload = true;
+// }
+
+ /**
+ * 保存云端文件目录到本地
+ */
+// public void locatedCloud(List cloudFiles) {
+// if (cloudFiles.size() > 0) {
+// Type type = new TypeToken>() {
+// }.getType();
+// FileHelper.writeToFile(CONF.CLOUD_MAP_CACHE_PATH, App.getGson().toJson(cloudFiles, type));
+// }
+// }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ NotebookUtil.killServer();
+ }
+}
diff --git a/qpython/src/od/res/layout/activity_local.xml b/qpython/src/od/res/layout/activity_local.xml
new file mode 100644
index 00000000..abdcb0aa
--- /dev/null
+++ b/qpython/src/od/res/layout/activity_local.xml
@@ -0,0 +1,86 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/qpython/src/od/res/values-zh-rCN/strings.xml b/qpython/src/od/res/values-zh-rCN/strings.xml
new file mode 100644
index 00000000..a900de8f
--- /dev/null
+++ b/qpython/src/od/res/values-zh-rCN/strings.xml
@@ -0,0 +1,5 @@
+
+
+ 使用谷歌登录
+ QPython OS
+
diff --git a/qpython/src/od/res/values/strings.xml b/qpython/src/od/res/values/strings.xml
new file mode 100644
index 00000000..49b3ca29
--- /dev/null
+++ b/qpython/src/od/res/values/strings.xml
@@ -0,0 +1,4 @@
+
+ Sign in with Google
+ QPython OS
+
diff --git a/qpython/src/oh/java/org/qpython/qpy/main/activity/BaseActivity.java b/qpython/src/oh/java/org/qpython/qpy/main/activity/BaseActivity.java
index 9c3765d4..997b151b 100644
--- a/qpython/src/oh/java/org/qpython/qpy/main/activity/BaseActivity.java
+++ b/qpython/src/oh/java/org/qpython/qpy/main/activity/BaseActivity.java
@@ -137,7 +137,7 @@ public void onFeedback(String feedback) {
String lastError = "";
String code = NAction.getCode(getApplicationContext());
- File log = new File(Environment.getExternalStorageDirectory() + "/" + code + "_last_err.log");
+ File log = new File(FileUtils.getPath(App.getContext()) + "/" + code + "_last_err.log");
if (log.exists()) {
lastError = com.quseit.util.FileHelper.getFileContents(log.getAbsolutePath());
}
diff --git a/qpython/src/oh/java/org/qpython/qpy/main/fragment/ExplorerFragment.java b/qpython/src/oh/java/org/qpython/qpy/main/fragment/ExplorerFragment.java
index a5836685..64179188 100644
--- a/qpython/src/oh/java/org/qpython/qpy/main/fragment/ExplorerFragment.java
+++ b/qpython/src/oh/java/org/qpython/qpy/main/fragment/ExplorerFragment.java
@@ -157,7 +157,7 @@ private void initListener() {
binding.prevFolder.setOnClickListener(v -> {
String parentPath = new File(curPath).getParent();
- if (parentPath.length()>=Environment.getExternalStorageDirectory().getAbsolutePath().length()) {
+ if (parentPath.length()>=FileUtils.getQyPath(App.getContext()).length()) {
openDir(parentPath);
}
});
@@ -384,9 +384,9 @@ private void doNewDir() {
public void backToPrev() {
- String qpyDir = Environment.getExternalStorageDirectory().getAbsolutePath()+"/qpython";
+ String qpyDir = FileUtils.getQyPath(App.getContext())+"/qpython";
- if (curPath == null || qpyDir.equals(curPath) || Environment.getExternalStorageDirectory().getAbsolutePath().equals(curPath)) {
+ if (curPath == null || qpyDir.equals(curPath) || FileUtils.getQyPath(App.getContext()).equals(curPath)) {
getActivity().finish();
} else {
String parentPath = new File(curPath).getParent();
diff --git a/qpython/src/ol/java/org/qpython/qpy/main/activity/BaseActivity.java b/qpython/src/ol/java/org/qpython/qpy/main/activity/BaseActivity.java
index d3e259f8..4b1b9634 100644
--- a/qpython/src/ol/java/org/qpython/qpy/main/activity/BaseActivity.java
+++ b/qpython/src/ol/java/org/qpython/qpy/main/activity/BaseActivity.java
@@ -138,7 +138,7 @@ public void onFeedback(String feedback) {
String lastError = "";
String code = NAction.getCode(getApplicationContext());
- File log = new File(Environment.getExternalStorageDirectory() + "/" + code + "_last_err.log");
+ File log = new File(FileUtils.getPath(App.getContext()) + "/" + code + "_last_err.log");
if (log.exists()) {
lastError = com.quseit.util.FileHelper.getFileContents(log.getAbsolutePath());
}
diff --git a/qpython/src/ol/java/org/qpython/qpy/main/fragment/ExplorerFragment.java b/qpython/src/ol/java/org/qpython/qpy/main/fragment/ExplorerFragment.java
index 6705c248..a422cd25 100644
--- a/qpython/src/ol/java/org/qpython/qpy/main/fragment/ExplorerFragment.java
+++ b/qpython/src/ol/java/org/qpython/qpy/main/fragment/ExplorerFragment.java
@@ -164,7 +164,7 @@ private void initListener() {
//采用Environment来获取sdcard路径
String parentPath = new File(curPath).getParent();
- if (parentPath.length()>=Environment.getExternalStorageDirectory().getAbsolutePath().length()) {
+ if (parentPath.length()>=FileUtils.getQyPath(App.getContext()).length()) {
openDir(parentPath);
}
} catch (Exception e) {
@@ -438,8 +438,8 @@ private void doNewDir() {
public void backToPrev() {
Log.d("ExplorerFragment", "backToPrev:"+curPath);
- String qpyDir = Environment.getExternalStorageDirectory().getAbsolutePath()+"/qpython";
- if (curPath == null || qpyDir.equals(curPath) || Environment.getExternalStorageDirectory().getAbsolutePath().equals(curPath)) {
+ String qpyDir = FileUtils.getQyPath(App.getContext())+"/qpython";
+ if (curPath == null || qpyDir.equals(curPath) || FileUtils.getQyPath(App.getContext()).equals(curPath)) {
getActivity().finish();
} else {
String parentPath = new File(curPath).getParent();
diff --git a/qpython/src/op/java/org/qpython/qpy/main/activity/BaseActivity.java b/qpython/src/op/java/org/qpython/qpy/main/activity/BaseActivity.java
index 9c3765d4..997b151b 100644
--- a/qpython/src/op/java/org/qpython/qpy/main/activity/BaseActivity.java
+++ b/qpython/src/op/java/org/qpython/qpy/main/activity/BaseActivity.java
@@ -137,7 +137,7 @@ public void onFeedback(String feedback) {
String lastError = "";
String code = NAction.getCode(getApplicationContext());
- File log = new File(Environment.getExternalStorageDirectory() + "/" + code + "_last_err.log");
+ File log = new File(FileUtils.getPath(App.getContext()) + "/" + code + "_last_err.log");
if (log.exists()) {
lastError = com.quseit.util.FileHelper.getFileContents(log.getAbsolutePath());
}
diff --git a/qpython/src/op/java/org/qpython/qpy/main/fragment/ExplorerFragment.java b/qpython/src/op/java/org/qpython/qpy/main/fragment/ExplorerFragment.java
index a5836685..64179188 100644
--- a/qpython/src/op/java/org/qpython/qpy/main/fragment/ExplorerFragment.java
+++ b/qpython/src/op/java/org/qpython/qpy/main/fragment/ExplorerFragment.java
@@ -157,7 +157,7 @@ private void initListener() {
binding.prevFolder.setOnClickListener(v -> {
String parentPath = new File(curPath).getParent();
- if (parentPath.length()>=Environment.getExternalStorageDirectory().getAbsolutePath().length()) {
+ if (parentPath.length()>=FileUtils.getQyPath(App.getContext()).length()) {
openDir(parentPath);
}
});
@@ -384,9 +384,9 @@ private void doNewDir() {
public void backToPrev() {
- String qpyDir = Environment.getExternalStorageDirectory().getAbsolutePath()+"/qpython";
+ String qpyDir = FileUtils.getQyPath(App.getContext())+"/qpython";
- if (curPath == null || qpyDir.equals(curPath) || Environment.getExternalStorageDirectory().getAbsolutePath().equals(curPath)) {
+ if (curPath == null || qpyDir.equals(curPath) || FileUtils.getQyPath(App.getContext()).equals(curPath)) {
getActivity().finish();
} else {
String parentPath = new File(curPath).getParent();
diff --git a/qpython/src/os/java/org/qpython/qpy/main/activity/BaseActivity.java b/qpython/src/os/java/org/qpython/qpy/main/activity/BaseActivity.java
index d3e259f8..4b1b9634 100644
--- a/qpython/src/os/java/org/qpython/qpy/main/activity/BaseActivity.java
+++ b/qpython/src/os/java/org/qpython/qpy/main/activity/BaseActivity.java
@@ -138,7 +138,7 @@ public void onFeedback(String feedback) {
String lastError = "";
String code = NAction.getCode(getApplicationContext());
- File log = new File(Environment.getExternalStorageDirectory() + "/" + code + "_last_err.log");
+ File log = new File(FileUtils.getPath(App.getContext()) + "/" + code + "_last_err.log");
if (log.exists()) {
lastError = com.quseit.util.FileHelper.getFileContents(log.getAbsolutePath());
}
diff --git a/qpython/src/os/java/org/qpython/qpy/main/fragment/ExplorerFragment.java b/qpython/src/os/java/org/qpython/qpy/main/fragment/ExplorerFragment.java
index 6705c248..dcb9a018 100644
--- a/qpython/src/os/java/org/qpython/qpy/main/fragment/ExplorerFragment.java
+++ b/qpython/src/os/java/org/qpython/qpy/main/fragment/ExplorerFragment.java
@@ -54,24 +54,24 @@
import static com.quseit.util.FolderUtils.sortTypeByName;
public class ExplorerFragment extends Fragment {
- private static final int REQUEST_SAVE_AS = 107;
+ private static final int REQUEST_SAVE_AS = 107;
private static final int REQUEST_HOME_PAGE = 109;
- private static final int REQUEST_RECENT = 111;
- private static final int LOGIN_REQUEST = 2741;
+ private static final int REQUEST_RECENT = 111;
+ private static final int LOGIN_REQUEST = 2741;
private static final String TYPE = "type";
private int WIDTH = (int) ImageUtil.dp2px(60);
private FragmentExplorerBinding binding;
- private List folderList;
- private FolderAdapter adapter;
+ private List folderList;
+ private FolderAdapter adapter;
private Map cloudedMap = new HashMap<>();
private boolean openable = true; // 是否可打开文件
private boolean uploadable;
- private int type;
+ private int type;
private String curPath;
public static ExplorerFragment newInstance(int type) {
@@ -164,7 +164,7 @@ private void initListener() {
//采用Environment来获取sdcard路径
String parentPath = new File(curPath).getParent();
- if (parentPath.length()>=Environment.getExternalStorageDirectory().getAbsolutePath().length()) {
+ if (parentPath.length() >= context.getExternalFilesDir(null).getAbsolutePath().length()) {
openDir(parentPath);
}
} catch (Exception e) {
@@ -221,6 +221,7 @@ public void onLongClick(int position) {
private void gotoSetting() {
SettingActivity.startActivity(getActivity());
}
+
private void openFile(File file, String ext) {
List textExts = Arrays.asList(getContext().getResources().getStringArray(R.array.text_ext));
if (textExts.contains(ext)) {
@@ -231,7 +232,7 @@ private void openFile(File file, String ext) {
NotebookActivity.start(getActivity(), file.getAbsolutePath(), false);
} else {
- new AlertDialog.Builder(getActivity(),R.style.MyDialog)
+ new AlertDialog.Builder(getActivity(), R.style.MyDialog)
.setTitle(R.string.dialog_alert)
.setMessage(getString(R.string.ennable_notebook_first))
.setNegativeButton(R.string.cancel, (dialog1, which) -> dialog1.dismiss())
@@ -437,9 +438,9 @@ private void doNewDir() {
}
public void backToPrev() {
- Log.d("ExplorerFragment", "backToPrev:"+curPath);
- String qpyDir = Environment.getExternalStorageDirectory().getAbsolutePath()+"/qpython";
- if (curPath == null || qpyDir.equals(curPath) || Environment.getExternalStorageDirectory().getAbsolutePath().equals(curPath)) {
+ Log.d("ExplorerFragment", "backToPrev:" + curPath);
+ String qpyDir = context.getExternalFilesDir(null).getAbsolutePath() + "/qpython";
+ if (curPath == null || qpyDir.equals(curPath) || context.getExternalFilesDir(null).getAbsolutePath().equals(curPath)) {
getActivity().finish();
} else {
String parentPath = new File(curPath).getParent();