diff --git a/qpython/build.gradle b/qpython/build.gradle
index 089b4f2d0277fcdf4233bdbe964aeae3ad2f1e82..69ad017b1db90cf9ed4e22ca89b3b5ac1242d345 100644
--- a/qpython/build.gradle
+++ b/qpython/build.gradle
@@ -15,8 +15,8 @@ android {
defaultConfig {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
- versionCode 316
- versionName "3.2.1"
+ versionCode 322
+ versionName "3.2.2"
multiDexEnabled true
vectorDrawables.useSupportLibrary = true
diff --git a/qpython/src/main/AndroidManifest.xml b/qpython/src/main/AndroidManifest.xml
index 9c022266b90693e50771b7a3c419ab15e214bf1a..ba73e87a66b9b9d3d20c8a8afdc694d4900377ae 100644
--- a/qpython/src/main/AndroidManifest.xml
+++ b/qpython/src/main/AndroidManifest.xml
@@ -49,6 +49,7 @@
+
@@ -141,6 +142,18 @@
+
+
+
+
+
+
buttons = FloatViewFacade.buttons;
+ //参数数组
+ static final ArrayList params = FloatViewFacade.params;
+ //时间数组
+ static final ArrayList times = FloatViewFacade.times;
+ //操作类型数组
+ static final ArrayList operations = FloatViewFacade.operations;
+ static WindowManager windowManager;
+ static DisplayMetrics displayMetrics;
+ //public static Handler handler;
+
+ @SuppressLint({"SimpleDateFormat", "HandlerLeak"})
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (Build.VERSION.SDK_INT < 26) {
+ Toast.makeText(this,
+ getString(R.string.float_view_android),
+ Toast.LENGTH_LONG).show();
+ finish();
+ return;
+ }
+ windowManager = (WindowManager) this.getSystemService(WINDOW_SERVICE);
+ FloatViewFacade.windowManager = windowManager;
+ displayMetrics = this.getResources().getDisplayMetrics();
+ FloatViewFacade.handler = new Handler(){
+ @Override
+ public void handleMessage(Message msg){
+ super.handleMessage(msg);
+ floatView((Intent) msg.obj);
+ }
+ };
+ floatView(getIntent());
+ }
+
+ @SuppressLint("ClickableViewAccessibility")
+ public void floatView(Intent intent){
+ //Intent intent = getIntent();
+ if (intent==null) intent = new Intent();
+ WindowManager.LayoutParams layoutParams = null;
+ int index;
+ //悬浮按钮
+ Button floatButton = null;
+ //悬浮窗文本
+ String text=intent.getStringExtra("text");
+ //是否彩色文本
+ boolean isHtml = false;
+ if (text == null) {
+ text = intent.getStringExtra("html");
+ if (text == null)
+ text = "drag move\nlong click close";
+ else isHtml = true;
+ }
+ //悬浮窗背景色 格式:aarrggbb或rrggbb
+ int backColor=colorToInt(intent.getStringExtra("backColor"),"7f7f7f7f");
+ //悬浮窗文字颜色 格式:aarrggbb或rrggbb
+ int textColor=colorToInt(intent.getStringExtra("textColor"),"ff000000");
+ //字体大小
+ int textSize=intent.getIntExtra("textSize",10);
+ //脚本路径
+ final String script=intent.getStringExtra("script");
+ //脚本参数
+ final String arg=intent.getStringExtra("arg");
+ final boolean clickRemove = intent.getBooleanExtra("clickRemove",true);
+ //moveTaskToBack(true);
+ //索引参数
+ index = intent.getIntExtra("index",-1);
+ if (index>=0) {
+ try {
+ floatButton = buttons.get(index);
+ layoutParams = params.get(index);
+ } catch (Exception e){
+ index=-1;
+ }
+ }
+ if(index<0){
+ floatButton = new Button(this);
+ layoutParams = new WindowManager.LayoutParams();
+ index = buttons.size();
+ }
+ WindowManager.LayoutParams finalLayoutParams = layoutParams;
+ floatButton.setOnTouchListener(new View.OnTouchListener() {
+ private int x;
+ private int y;
+
+ @SuppressLint("ClickableViewAccessibility")
+ @RequiresApi(api = Build.VERSION_CODES.N)
+ @Override
+ public boolean onTouch(View view, MotionEvent event) {
+ int index;
+ for(index =0; index < buttons.size(); index++){
+ if(view==buttons.get(index))
+ break;
+ }
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ x = (int) event.getRawX();
+ y = (int) event.getRawY();
+ break;
+ case MotionEvent.ACTION_MOVE:
+ int nowX = (int) event.getRawX();
+ int nowY = (int) event.getRawY();
+ boolean moved = nowX != x || nowY != y;
+ x = nowX;
+ y = nowY;
+ finalLayoutParams.x = nowX - displayMetrics.widthPixels/2;
+ finalLayoutParams.y = nowY - displayMetrics.heightPixels/2;
+ // 更新悬浮窗控件布局
+ if (moved) {
+ windowManager.updateViewLayout(view, finalLayoutParams);
+ operations.set(index, "move");
+ } else {
+ operations.set(index, "click");
+ }
+ times.set(index, getTime());
+ break;
+ case MotionEvent.ACTION_UP:
+ if (operations.get(index).equals("click")) {
+ if(script!=null)
+ ScriptExec.getInstance().playScript(FloatViewActivity.this,
+ script, arg,false);
+ if (clickRemove) FloatViewFacade.removeButton(index);
+ FloatViewActivity.this.finish();
+ }
+ default:
+ break;
+ }
+ return false;
+ }
+ });
+ if(isHtml)
+ floatButton.setText(HtmlUtil.textToHtml(text));
+ else
+ floatButton.setText(text);
+ floatButton.setBackgroundColor(backColor);
+ floatButton.setTextColor(textColor);
+ floatButton.setTextSize(textSize);
+ layoutParams.type=WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;//下拉通知栏不可见
+ // 设置Window flag,锁定悬浮窗 ,若不设置,悬浮窗会占用整个屏幕的点击事件,FLAG_NOT_FOCUSABLE不设置会导致菜单键和返回键失效
+ layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+ | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+ layoutParams.format = PixelFormat.RGBA_8888; // 设置图片格式,效果为背景透明
+ //悬浮窗宽度
+ int width = intent.getIntExtra("width",300);
+ if(width!=Integer.MIN_VALUE)
+ layoutParams.width = width;
+ //悬浮窗高度
+ int height = intent.getIntExtra("height",150);
+ if (height!=Integer.MIN_VALUE)
+ layoutParams.height = height;
+ //起始横坐标,原点为屏幕中心
+ int x = intent.getIntExtra("x",0);
+ if (x!=Integer.MIN_VALUE)
+ layoutParams.x=x;
+ //起始纵坐标,原点为屏幕中心
+ int y = intent.getIntExtra("y",0);
+ if (y!=Integer.MIN_VALUE)
+ layoutParams.y=y;
+ //记录结果
+ try {
+ if(index>=buttons.size()){
+ windowManager.addView(floatButton, layoutParams);
+ buttons.add(floatButton);
+ params.add(layoutParams);
+ times.add(getTime());
+ operations.add("initial");
+ } else {
+ params.set(index,layoutParams);
+ times.set(index,getTime());
+ windowManager.updateViewLayout(floatButton, layoutParams);
+ operations.set(index,"modify");
+ }
+ } catch (Exception e) {
+ Toast.makeText(this,getString(R.string.float_view_permission)+"\n"+ e,Toast.LENGTH_LONG).show();
+ return;
+ }
+ finish();
+ }
+
+ private int colorToInt(String color,String defaultColor){
+ if (color == null) {
+ color = defaultColor;
+ } else {
+ int len = color.length();
+ if (len <= 6) {
+ color = defaultColor.substring(0,2) + "000000".substring(len) + color;
+ }
+ }
+ long l;
+ try {
+ l = Long.valueOf(color,16);
+ return (int) l;
+ }
+ catch (Exception e) {
+ l = Long.valueOf(defaultColor,16);
+ return (int) l;
+ }
+ }
+
+ @SuppressLint({"SimpleDateFormat"})
+ private String getTime(){
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ return new SimpleDateFormat("yyyyMMdd-HHmmss-SSS").format(new Date(System.currentTimeMillis()));
+ } else return "Image_";
+ }
+}
diff --git a/qpython/src/main/res/values-zh-rCN/strings.xml b/qpython/src/main/res/values-zh-rCN/strings.xml
index 37f78e56f8dc6a1615c79c8990985413531bb580..f1b752af262202623ea02a4dc1c1f0cc6738d3ab 100644
--- a/qpython/src/main/res/values-zh-rCN/strings.xml
+++ b/qpython/src/main/res/values-zh-rCN/strings.xml
@@ -497,5 +497,8 @@
检查上次运行时日志
运行日志
QSL4A未来小程序
+ 悬浮窗仅支持 Android >= 8.0 .
+ 需要悬浮窗权限。
+ 悬浮窗
diff --git a/qpython/src/main/res/values/strings.xml b/qpython/src/main/res/values/strings.xml
index a0c344cbbcaed1e0209f48a74834aba8bb1bb904..20631d759714ceae7fd61acc53a264b4e5555018 100644
--- a/qpython/src/main/res/values/strings.xml
+++ b/qpython/src/main/res/values/strings.xml
@@ -767,5 +767,8 @@
https://gitee.com/buddygr/qpython-3c
" QSL4A FutureActivity"
https://gitee.com/buddygr/qpython-sl4a-gui
+ = 8.0 .]]>
+ Need Float View Permission .
+ Float View