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