diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser index 398f8f7d..bf0552a3 100644 Binary files a/.idea/caches/build_file_checksums.ser and b/.idea/caches/build_file_checksums.ser differ diff --git a/app/build.gradle b/app/build.gradle index 9ae3d14d..ea809434 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -8,8 +8,8 @@ android { applicationId "org.autojs.autojs" minSdkVersion 17 targetSdkVersion 23 - versionCode 403 - versionName "4.0.2 Alpha" + versionCode 406 + versionName "4.0.2 Alpha2" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" multiDexEnabled true ndk { diff --git a/app/src/main/java/org/autojs/autojs/ui/floating/FloatyWindowManger.java b/app/src/main/java/org/autojs/autojs/ui/floating/FloatyWindowManger.java index f2be6c8c..54dec712 100644 --- a/app/src/main/java/org/autojs/autojs/ui/floating/FloatyWindowManger.java +++ b/app/src/main/java/org/autojs/autojs/ui/floating/FloatyWindowManger.java @@ -54,7 +54,7 @@ public class FloatyWindowManger { } public static boolean showCircularMenu() { - if (!SettingsCompat.canDrawOverlays(GlobalAppContext.get())) { + if (!FloatingPermission.canDrawOverlays(GlobalAppContext.get())) { Toast.makeText(GlobalAppContext.get(), R.string.text_no_floating_window_permission, Toast.LENGTH_SHORT).show(); manageDrawOverlays(GlobalAppContext.get()); return false; diff --git a/autojs/src/main/assets/.vscode/launch.json b/autojs/src/main/assets/.vscode/launch.json deleted file mode 100644 index 897fbc7a..00000000 --- a/autojs/src/main/assets/.vscode/launch.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - // 使用 IntelliSense 了解相关属性。 - // 悬停以查看现有属性的描述。 - // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "type": "node", - "request": "launch", - "name": "启动程序", - "program": "${file}" - } - ] -} \ No newline at end of file diff --git a/autojs/src/main/assets/init.js b/autojs/src/main/assets/init.js index 1fa0fe37..3734cf50 100644 --- a/autojs/src/main/assets/init.js +++ b/autojs/src/main/assets/init.js @@ -72,21 +72,12 @@ runtime.init(); Image = com.stardust.autojs.core.image.ImageWrapper; //重定向require以便支持相对路径 + (function(){ - var __require__ = require; - var builtInModules = ["lodash.js"]; - global.require = function(path){ - if(!path.endsWith(".js")){ - path = path + ".js"; - } - if(builtInModules.indexOf(path) >= 0 && !files.exists(path)){ - return __require__(path); - } - if(path.startsWith("http://") || path.startsWith("https://")){ - return __require__(path); - } - return __require__(files.path(path)); - }; + var loadAssets = function(path){ + eval(files.readAssets(path)); + } + loadAssets("jvm-npm.js"); })(); diff --git a/autojs/src/main/assets/jvm-npm.js b/autojs/src/main/assets/jvm-npm.js new file mode 100644 index 00000000..25de71e6 --- /dev/null +++ b/autojs/src/main/assets/jvm-npm.js @@ -0,0 +1,294 @@ +/** + * Copyright 2014-2016 Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License") + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +// Since we intend to use the Function constructor. +/* jshint evil: true */ + +module = (typeof module === 'undefined') ? {} : module; + +(function () { + var builtInModules = ["lodash.js"]; + + var System = java.lang.System; + var Scanner = java.util.Scanner; + var File = java.io.File; + + NativeRequire = (typeof NativeRequire === 'undefined') ? {} : NativeRequire; + if (typeof require === 'function' && !NativeRequire.require) { + NativeRequire.require = require; + } + + function Module (id, parent, core) { + this.id = id; + this.core = core; + this.parent = parent; + this.children = []; + this.filename = id; + this.loaded = false; + + Object.defineProperty(this, 'exports', { + get: function () { + return this._exports; + }.bind(this), + set: function (val) { + Require.cache[this.filename] = val; + this._exports = val; + }.bind(this) + }); + this.exports = {}; + + if (parent && parent.children) parent.children.push(this); + + this.require = function (id) { + return Require(id, this); + }.bind(this); + } + + Module._load = function _load (file, parent, core, main) { + var module = new Module(file, parent, core); + var body = readFile(module.filename, module.core); + var dir = new File(module.filename).getParent(); + var func = new Function('exports', 'module', 'require', '__filename', '__dirname', body); + func.apply(module, + [module.exports, module, module.require, module.filename, dir]); + module.loaded = true; + module.main = main; + return module.exports; + }; + + Module.runMain = function runMain (main) { + var file = Require.resolve(main); + Module._load(file, undefined, false, true); + }; + + function Require (id, parent) { + var normalizePath = normalizeName(id); + if(builtInModules.indexOf(normalizePath) >= 0 && !files.exists(normalizePath)){ + return NativeRequire.require(normalizePath); + } + if(id.startsWith("http://") || id.startsWith("https://")){ + return NativeRequire.require(id); + } + + var core; + var native_; + var file = Require.resolve(id, parent); + + if (!file) { + if (typeof NativeRequire.require === 'function') { + if (Require.debug) { + System.out.println(['Cannot resolve', id, 'defaulting to native'].join(' ')); + } + native_ = NativeRequire.require(id); + if (native_) return native_; + } + System.err.println('Cannot find module ' + id); + throw new ModuleError('Cannot find module ' + id, 'MODULE_NOT_FOUND'); + } + + if (file.core) { + file = file.path; + core = true; + } + try { + if (Require.cache[file]) { + return Require.cache[file]; + } else if (file.endsWith('.js')) { + return Module._load(file, parent, core); + } else if (file.endsWith('.json')) { + return loadJSON(file); + } + } catch (ex) { + if (ex instanceof java.lang.Exception) { + throw new ModuleError('Cannot load module ' + id, 'LOAD_ERROR', ex); + } else { + System.out.println('Cannot load module ' + id + ' LOAD_ERROR'); + throw ex; + } + } + } + + Require.resolve = function (id, parent) { + var roots = findRoots(parent); + for (var i = 0; i < roots.length; ++i) { + var root = roots[i]; + var result = resolveCoreModule(id, root) || + resolveAsFile(id, root, '.js') || + resolveAsFile(id, root, '.json') || + resolveAsDirectory(id, root) || + resolveAsNodeModule(id, root); + if (result) { + return result; + } + } + return false; + }; + + Require.root = files.cwd();//System.getProperty('user.dir'); + Require.NODE_PATH = undefined; + + function findRoots (parent) { + var r = []; + r.push(findRoot(parent)); + return r.concat(Require.paths()); + } + + function parsePaths (paths) { + if (!paths) { + return []; + } + if (paths === '') { + return []; + } + var osName = java.lang.System.getProperty('os.name').toLowerCase(); + var separator; + + if (osName.indexOf('win') >= 0) { + separator = ';'; + } else { + separator = ':'; + } + + return paths.split(separator); + } + + Require.paths = function () { + var r = []; + r.push(java.lang.System.getProperty('user.home') + '/.node_modules'); + r.push(java.lang.System.getProperty('user.home') + '/.node_libraries'); + + if (Require.NODE_PATH) { + r = r.concat(parsePaths(Require.NODE_PATH)); + } else { + var NODE_PATH = java.lang.System.getenv().NODE_PATH; + if (NODE_PATH) { + r = r.concat(parsePaths(NODE_PATH)); + } + } + // r.push( $PREFIX + "/node/library" ) + return r; + }; + + function findRoot (parent) { + if (!parent || !parent.id) { return Require.root; } + var pathParts = parent.id.split(/[\/|\\,]+/g); + pathParts.pop(); + return pathParts.join('/'); + } + + Require.debug = true; + Require.cache = {}; + Require.extensions = {}; + require = Require; + + module.exports = Module; + + function loadJSON (file) { + var json = JSON.parse(readFile(file)); + Require.cache[file] = json; + return json; + } + + function resolveAsNodeModule (id, root) { + var base = [root, 'node_modules'].join('/'); + return resolveAsFile(id, base) || + resolveAsDirectory(id, base) || + (root ? resolveAsNodeModule(id, new File(root).getParent()) : false); + } + + function resolveAsDirectory (id, root) { + var base = [root, id].join('/'); + var file = new File([base, 'package.json'].join('/')); + if (file.exists()) { + try { + var body = readFile(file.getCanonicalPath()); + var package_ = JSON.parse(body); + if (package_.main) { + return (resolveAsFile(package_.main, base) || + resolveAsDirectory(package_.main, base)); + } + // if no package.main exists, look for index.js + return resolveAsFile('index.js', base); + } catch (ex) { + throw new ModuleError('Cannot load JSON file', 'PARSE_ERROR', ex); + } + } + return resolveAsFile('index.js', base); + } + + function resolveAsFile (id, root, ext) { + var file; + if (id.length > 0 && id[0] === '/') { + file = new File(normalizeName(id, ext)); + if (!file.exists()) { + return resolveAsDirectory(id); + } + } else { + file = new File([root, normalizeName(id, ext)].join('/')); + } + if (file.exists()) { + return file.getCanonicalPath(); + } + } + + function resolveCoreModule (id, root) { + var name = normalizeName(id); + var classloader = java.lang.Thread.currentThread().getContextClassLoader(); + if (classloader.getResource(name)) { + return { path: name, core: true }; + } + } + + function normalizeName (fileName, ext) { + var extension = ext || '.js'; + if (fileName.endsWith(extension)) { + return fileName; + } + return fileName + extension; + } + + function readFile (filename, core) { + var input; + try { + if (core) { + var classloader = java.lang.Thread.currentThread().getContextClassLoader(); + input = classloader.getResourceAsStream(filename); + } else { + input = new File(filename); + } + // TODO: I think this is not very efficient + return new Scanner(input).useDelimiter('\\A').next(); + } catch (e) { + throw new ModuleError('Cannot read file [' + input + ']: ', 'IO_ERROR', e); + } + } + + function ModuleError (message, code, cause) { + this.code = code || 'UNDEFINED'; + this.message = message || 'Error loading module'; + this.cause = cause; + } + + // Helper function until ECMAScript 6 is complete + if (typeof String.prototype.endsWith !== 'function') { + String.prototype.endsWith = function (suffix) { + if (!suffix) return false; + return this.indexOf(suffix, this.length - suffix.length) !== -1; + }; + } + + ModuleError.prototype = new Error(); + ModuleError.prototype.constructor = ModuleError; +}()); \ No newline at end of file diff --git a/autojs/src/main/java/com/stardust/autojs/core/console/StardustConsole.java b/autojs/src/main/java/com/stardust/autojs/core/console/StardustConsole.java index 28c1512c..0ed26141 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/console/StardustConsole.java +++ b/autojs/src/main/java/com/stardust/autojs/core/console/StardustConsole.java @@ -10,6 +10,7 @@ import com.stardust.autojs.annotation.ScriptInterface; import com.stardust.autojs.runtime.api.AbstractConsole; import com.stardust.autojs.runtime.api.Console; import com.stardust.autojs.runtime.exception.ScriptInterruptedException; +import com.stardust.autojs.util.FloatingPermission; import com.stardust.concurrent.ConcurrentArrayList; import com.stardust.enhancedfloaty.FloatyService; import com.stardust.enhancedfloaty.ResizableExpandableFloatyWindow; @@ -151,8 +152,8 @@ public class StardustConsole extends AbstractConsole { if (mShown) { return; } - if (!SettingsCompat.canDrawOverlays(mUiHandler.getContext())) { - SettingsCompat.manageDrawOverlays(mUiHandler.getContext()); + if (!FloatingPermission.canDrawOverlays(mUiHandler.getContext())) { + FloatingPermission.manageDrawOverlays(mUiHandler.getContext()); mUiHandler.toast(R.string.text_no_floating_window_permission); return; } diff --git a/autojs/src/main/java/com/stardust/autojs/core/ui/inflater/DynamicLayoutInflater.java b/autojs/src/main/java/com/stardust/autojs/core/ui/inflater/DynamicLayoutInflater.java index f43ff511..6d1f1e17 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/ui/inflater/DynamicLayoutInflater.java +++ b/autojs/src/main/java/com/stardust/autojs/core/ui/inflater/DynamicLayoutInflater.java @@ -38,6 +38,7 @@ import com.stardust.autojs.core.ui.inflater.inflaters.TimePickerInflater; import com.stardust.autojs.core.ui.inflater.inflaters.ToolbarInflater; import com.stardust.autojs.core.ui.inflater.inflaters.ViewGroupInflater; import com.stardust.autojs.core.ui.inflater.util.Res; +import com.stardust.autojs.core.ui.widget.JsSpinner; import com.stardust.autojs.core.ui.widget.JsTabLayout; import com.stardust.autojs.core.ui.widget.JsToolbar; import com.stardust.autojs.core.ui.xml.XmlConverter; @@ -126,7 +127,7 @@ public class DynamicLayoutInflater { registerViewAttrSetter(DatePicker.class.getName(), new DatePickerInflater(mResourceParser)); registerViewAttrSetter(RadioGroup.class.getName(), new RadioGroupInflater<>(mResourceParser)); registerViewAttrSetter(ProgressBar.class.getName(), new ProgressBarInflater<>(mResourceParser)); - registerViewAttrSetter(Spinner.class.getName(), new SpinnerInflater(mResourceParser)); + registerViewAttrSetter(JsSpinner.class.getName(), new SpinnerInflater(mResourceParser)); registerViewAttrSetter(TimePicker.class.getName(), new TimePickerInflater(mResourceParser)); registerViewAttrSetter(AppBarLayout.class.getName(), new AppBarInflater<>(mResourceParser)); registerViewAttrSetter(JsTabLayout.class.getName(), new TabLayoutInflater<>(mResourceParser)); diff --git a/autojs/src/main/java/com/stardust/autojs/core/ui/inflater/inflaters/SpinnerInflater.java b/autojs/src/main/java/com/stardust/autojs/core/ui/inflater/inflaters/SpinnerInflater.java index 7c6335ac..8c3a2a4a 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/ui/inflater/inflaters/SpinnerInflater.java +++ b/autojs/src/main/java/com/stardust/autojs/core/ui/inflater/inflaters/SpinnerInflater.java @@ -2,17 +2,22 @@ package com.stardust.autojs.core.ui.inflater.inflaters; import android.content.Context; import android.os.Build; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.util.TypedValue; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.SimpleAdapter; import android.widget.Spinner; +import com.stardust.autojs.R; import com.stardust.autojs.core.ui.inflater.ResourceParser; import com.stardust.autojs.core.ui.inflater.ViewCreator; +import com.stardust.autojs.core.ui.inflater.util.Colors; import com.stardust.autojs.core.ui.inflater.util.Dimensions; import com.stardust.autojs.core.ui.inflater.util.Strings; import com.stardust.autojs.core.ui.inflater.util.ValueMapper; +import com.stardust.autojs.core.ui.widget.JsSpinner; import java.util.List; import java.util.Map; @@ -21,7 +26,7 @@ import java.util.Map; * Created by Stardust on 2017/11/29. */ -public class SpinnerInflater extends BaseViewInflater { +public class SpinnerInflater extends BaseViewInflater { protected static final ValueMapper SPINNER_MODES = new ValueMapper("spinnerMode") .map("dialog", Spinner.MODE_DIALOG) @@ -32,38 +37,48 @@ public class SpinnerInflater extends BaseViewInflater { } @Override - public boolean setAttr(Spinner view, String attr, String value, ViewGroup parent, Map attrs) { + public boolean setAttr(JsSpinner view, String attr, String value, ViewGroup parent, Map attrs) { switch (attr) { case "dropDownHorizontalOffset": - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - view.setDropDownHorizontalOffset(Dimensions.parseToIntPixel(value, view)); - } + view.setDropDownHorizontalOffset(Dimensions.parseToIntPixel(value, view)); break; case "dropDownSelector": Exceptions.unsupports(view, attr, value); break; case "dropDownVerticalOffset": - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - view.setDropDownVerticalOffset(Dimensions.parseToIntPixel(value, view)); - } + view.setDropDownVerticalOffset(Dimensions.parseToIntPixel(value, view)); break; case "dropDownWidth": - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - view.setDropDownWidth(Dimensions.parseToIntPixel(value, view)); - } + view.setDropDownWidth(Dimensions.parseToIntPixel(value, view)); break; case "popupBackground": - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - view.setPopupBackgroundDrawable(getDrawables().parse(view, value)); - } + view.setPopupBackgroundDrawable(getDrawables().parse(view, value)); break; case "prompt": view.setPrompt(Strings.parse(view, value)); break; case "entries": - view.setAdapter(new ArrayAdapter<>(view.getContext(), + view.setAdapter(view.new Adapter(view.getContext(), android.R.layout.simple_spinner_dropdown_item, value.split("[|]"))); break; + case "textStyle": + view.setTextStyle(TextViewInflater.TEXT_STYLES.split(value)); + break; + case "textColor": + view.setTextColor(Colors.parse(view.getContext(), value)); + break; + case "textSize": + view.setTextSize(Dimensions.parseToPixel(value, view)); + break; + case "entryTextStyle": + view.setEntryTextStyle(TextViewInflater.TEXT_STYLES.split(value)); + break; + case "entryTextColor": + view.setEntryTextColor(Colors.parse(view.getContext(), value)); + break; + case "entryTextSize": + view.setEntryTextSize(Dimensions.parseToPixel(value, view)); + break; default: return super.setAttr(view, attr, value, parent, attrs); } @@ -76,16 +91,11 @@ public class SpinnerInflater extends BaseViewInflater { return (context, attrs) -> { String mode = attrs.remove("android:spinnerMode"); if (mode == null) { - return new Spinner(context); + return new JsSpinner(context); } - return new Spinner(context, SPINNER_MODES.get(mode)); + return new JsSpinner(context, SPINNER_MODES.get(mode)); }; } - private static class EntryAdapter extends SimpleAdapter { - public EntryAdapter(Context context, List> data, int resource, String[] from, int[] to) { - super(context, data, resource, from, to); - } - } } diff --git a/autojs/src/main/java/com/stardust/autojs/core/ui/inflater/inflaters/TabLayoutInflater.java b/autojs/src/main/java/com/stardust/autojs/core/ui/inflater/inflaters/TabLayoutInflater.java index 164a8093..cbb3d309 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/ui/inflater/inflaters/TabLayoutInflater.java +++ b/autojs/src/main/java/com/stardust/autojs/core/ui/inflater/inflaters/TabLayoutInflater.java @@ -1,6 +1,5 @@ package com.stardust.autojs.core.ui.inflater.inflaters; -import android.content.Context; import android.content.res.ColorStateList; import android.graphics.Color; import android.support.annotation.Nullable; @@ -15,7 +14,6 @@ import com.stardust.autojs.core.ui.inflater.util.Colors; import com.stardust.autojs.core.ui.inflater.util.Dimensions; import com.stardust.autojs.core.ui.inflater.util.Gravities; import com.stardust.autojs.core.ui.inflater.util.ValueMapper; -import com.stardust.autojs.core.ui.widget.JsTabLayout; import java.util.Map; diff --git a/autojs/src/main/java/com/stardust/autojs/core/ui/inflater/inflaters/TextViewInflater.java b/autojs/src/main/java/com/stardust/autojs/core/ui/inflater/inflaters/TextViewInflater.java index f92ae9d9..0bd1709a 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/ui/inflater/inflaters/TextViewInflater.java +++ b/autojs/src/main/java/com/stardust/autojs/core/ui/inflater/inflaters/TextViewInflater.java @@ -98,7 +98,7 @@ public class TextViewInflater extends BaseViewInflater { .map("number", InputType.TYPE_CLASS_NUMBER) .map("signed", InputType.TYPE_NUMBER_FLAG_SIGNED); - private static final ValueMapper TEXT_STYLES = new ValueMapper("textStyle") + static final ValueMapper TEXT_STYLES = new ValueMapper("textStyle") .map("bold", Typeface.BOLD) .map("italic", Typeface.ITALIC) .map("normal", Typeface.NORMAL); diff --git a/autojs/src/main/java/com/stardust/autojs/core/ui/widget/JsSpinner.java b/autojs/src/main/java/com/stardust/autojs/core/ui/widget/JsSpinner.java new file mode 100644 index 00000000..8649d7f4 --- /dev/null +++ b/autojs/src/main/java/com/stardust/autojs/core/ui/widget/JsSpinner.java @@ -0,0 +1,163 @@ +package com.stardust.autojs.core.ui.widget; + +import android.content.Context; +import android.content.res.Resources; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.Spinner; +import android.widget.TextView; + +public class JsSpinner extends android.support.v7.widget.AppCompatSpinner { + + private float mTextSize = -1; + private int mTextStyle = -1; + private int mTextColor = 0; + + private float mEntryTextSize = -1; + private int mEntryTextStyle = -1; + private int mEntryTextColor = 0; + + public JsSpinner(Context context) { + super(context); + } + + public JsSpinner(Context context, int mode) { + super(context, mode); + } + + public JsSpinner(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public JsSpinner(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + public JsSpinner(Context context, AttributeSet attrs, int defStyleAttr, int mode) { + super(context, attrs, defStyleAttr, mode); + } + + public JsSpinner(Context context, AttributeSet attrs, int defStyleAttr, int mode, Resources.Theme popupTheme) { + super(context, attrs, defStyleAttr, mode, popupTheme); + } + + + public float getTextSize() { + return mTextSize; + } + + public float getEntryTextSize() { + return mEntryTextSize; + } + + public void setEntryTextSize(float entryTextSize) { + mEntryTextSize = entryTextSize; + } + + public int getEntryTextStyle() { + return mEntryTextStyle; + } + + public void setEntryTextStyle(int entryTextStyle) { + mEntryTextStyle = entryTextStyle; + } + + public int getEntryTextColor() { + return mEntryTextColor; + } + + public void setEntryTextColor(int entryTextColor) { + mEntryTextColor = entryTextColor; + } + + public void setTextSize(float textSize) { + mTextSize = textSize; + for (int i = 0; i < getChildCount(); i++) { + View child = getChildAt(i); + if (child instanceof TextView) { + ((TextView) child).setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize); + } + } + } + + + public int getTextStyle() { + return mTextStyle; + } + + public void setTextStyle(int textStyle) { + mTextStyle = textStyle; + for (int i = 0; i < getChildCount(); i++) { + View child = getChildAt(i); + if (child instanceof TextView) { + ((TextView) child).setTypeface(((TextView) child).getTypeface(), mTextStyle); + } + } + } + + public int getTextColor() { + return mTextColor; + } + + public void setTextColor(int textColor) { + mTextColor = textColor; + for (int i = 0; i < getChildCount(); i++) { + View child = getChildAt(i); + if (child instanceof TextView) { + ((TextView) child).setTextColor(mTextColor); + } + } + } + + + public class Adapter extends ArrayAdapter { + + public Adapter(@NonNull Context context, int resource, @NonNull String[] objects) { + super(context, resource, objects); + } + + @NonNull + @Override + public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { + View view = super.getView(position, convertView, parent); + if (!(view instanceof TextView)) { + return view; + } + TextView textView = (TextView) view; + if (mTextColor != 0) { + textView.setTextColor(mTextColor); + } + if (mTextSize != -1) { + textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize); + } + if (mTextStyle != -1) { + textView.setTypeface(textView.getTypeface(), mTextStyle); + } + return textView; + } + + @Override + public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { + View view = super.getDropDownView(position, convertView, parent); + if (!(view instanceof TextView)) { + return view; + } + TextView textView = (TextView) view; + if (mEntryTextColor != 0) { + textView.setTextColor(mEntryTextColor); + } + if (mEntryTextSize != -1) { + textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mEntryTextSize); + } + if (mEntryTextStyle != -1) { + textView.setTypeface(textView.getTypeface(), mEntryTextStyle); + } + return textView; + } + } +} diff --git a/autojs/src/main/java/com/stardust/autojs/core/ui/xml/XmlConverter.java b/autojs/src/main/java/com/stardust/autojs/core/ui/xml/XmlConverter.java index a264b8d3..f2e27cad 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/ui/xml/XmlConverter.java +++ b/autojs/src/main/java/com/stardust/autojs/core/ui/xml/XmlConverter.java @@ -25,6 +25,7 @@ import com.stardust.autojs.core.ui.widget.JsImageView; import com.stardust.autojs.core.ui.widget.JsLinearLayout; import com.stardust.autojs.core.ui.widget.JsListView; import com.stardust.autojs.core.ui.widget.JsRelativeLayout; +import com.stardust.autojs.core.ui.widget.JsSpinner; import com.stardust.autojs.core.ui.widget.JsTabLayout; import com.stardust.autojs.core.ui.widget.JsTextView; import com.stardust.autojs.core.ui.widget.JsToolbar; @@ -68,7 +69,7 @@ public class XmlConverter { .map("webview", JsWebView.class.getName()) .map("progressbar", ProgressBar.class.getName()) .map("seekbar", SeekBar.class.getName()) - .map("spinner", Spinner.class.getName()) + .map("spinner", JsSpinner.class.getName()) .map("radio", RadioButton.class.getName()) .map("radiogroup", RadioGroup.class.getName()) .map("checkbox", CheckBox.class.getName()) diff --git a/autojs/src/main/java/com/stardust/autojs/runtime/api/Files.java b/autojs/src/main/java/com/stardust/autojs/runtime/api/Files.java index 0cf659d5..15635ad4 100644 --- a/autojs/src/main/java/com/stardust/autojs/runtime/api/Files.java +++ b/autojs/src/main/java/com/stardust/autojs/runtime/api/Files.java @@ -4,9 +4,11 @@ import com.stardust.autojs.engine.ScriptEngine; import com.stardust.autojs.runtime.ScriptRuntime; import com.stardust.pio.PFileInterface; import com.stardust.pio.PFiles; +import com.stardust.pio.UncheckedIOException; import com.stardust.util.Func1; import java.io.File; +import java.io.IOException; /** * Created by Stardust on 2018/1/23. @@ -82,10 +84,23 @@ public class Files { return PFiles.read(path(path), encoding); } + public String read(String path) { return PFiles.read(path(path)); } + public String readAssets(String path, String encoding){ + try { + return PFiles.read(mRuntime.getUiHandler().getContext().getAssets().open(path), encoding); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + public String readAssets(String path){ + return readAssets(path, "UTF-8"); + } + public byte[] readBytes(String path){ return PFiles.readBytes(path(path)); } @@ -185,4 +200,5 @@ public class Files { public String getSimplifiedPath(String path) { return PFiles.getSimplifiedPath(path); } + } diff --git a/autojs/src/main/java/com/stardust/autojs/util/FloatingPermission.java b/autojs/src/main/java/com/stardust/autojs/util/FloatingPermission.java index 7b5abcda..c8e59d1b 100644 --- a/autojs/src/main/java/com/stardust/autojs/util/FloatingPermission.java +++ b/autojs/src/main/java/com/stardust/autojs/util/FloatingPermission.java @@ -1,8 +1,14 @@ package com.stardust.autojs.util; import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.Build; import android.os.Handler; import android.os.Looper; +import android.provider.Settings; +import android.support.annotation.RequiresApi; +import android.text.TextUtils; import android.widget.Toast; import com.stardust.R; @@ -10,6 +16,11 @@ import com.stardust.autojs.runtime.exception.ScriptInterruptedException; import com.stardust.enhancedfloaty.util.FloatingWindowPermissionUtil; import com.stardust.lang.ThreadCompat; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Set; + +import ezy.assist.compat.RomUtil; import ezy.assist.compat.SettingsCompat; /** @@ -19,8 +30,20 @@ import ezy.assist.compat.SettingsCompat; public class FloatingPermission { + private static final int OP_SYSTEM_ALERT_WINDOW = 24; + private static Method sCheckOp; + + static { + try { + sCheckOp = SettingsCompat.class.getDeclaredMethod("checkOp", Context.class, int.class); + sCheckOp.setAccessible(true); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } + } + public static void ensurePermissionGranted(Context context) { - if (!SettingsCompat.canDrawOverlays(context)) { + if (!canDrawOverlays(context)) { Toast.makeText(context, R.string.text_no_floating_window_permission, Toast.LENGTH_SHORT).show(); manageDrawOverlays(context); return; @@ -28,7 +51,7 @@ public class FloatingPermission { } public static void waitForPermissionGranted(Context context) throws InterruptedException { - if (SettingsCompat.canDrawOverlays(context)) { + if (canDrawOverlays(context)) { return; } Runnable r = () -> { @@ -41,7 +64,7 @@ public class FloatingPermission { r.run(); } while (true) { - if (SettingsCompat.canDrawOverlays(context)) + if (canDrawOverlays(context)) return; Thread.sleep(200); } @@ -51,11 +74,42 @@ public class FloatingPermission { public static void manageDrawOverlays(Context context) { try { - SettingsCompat.manageDrawOverlays(context); + if (RomUtil.isMiui() && TextUtils.equals("V10", RomUtil.getVersion()) + && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + manageDrawOverlaysForAndroidM(context); + } else { + SettingsCompat.manageDrawOverlays(context); + } } catch (Exception ex) { - FloatingWindowPermissionUtil.goToAppDetailSettings(context, context.getPackageName()); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + manageDrawOverlaysForAndroidM(context); + } else { + FloatingWindowPermissionUtil.goToAppDetailSettings(context, context.getPackageName()); + + } } } + @RequiresApi(api = Build.VERSION_CODES.M) + public static void manageDrawOverlaysForAndroidM(Context context) { + Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION); + intent.setData(Uri.parse("package:" + context.getPackageName())); + context.startActivity(intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); + } + public static boolean canDrawOverlays(Context context) { + return SettingsCompat.canDrawOverlays(context); + } + + private static boolean checkOp(Context context, int op) { + if (sCheckOp == null) { + return SettingsCompat.canDrawOverlays(context); + } + try { + return (boolean) sCheckOp.invoke(null, context, op); + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } } diff --git a/common/src/main/java/com/stardust/util/IntentUtil.java b/common/src/main/java/com/stardust/util/IntentUtil.java index 3b595b84..93efdea4 100644 --- a/common/src/main/java/com/stardust/util/IntentUtil.java +++ b/common/src/main/java/com/stardust/util/IntentUtil.java @@ -84,6 +84,7 @@ public class IntentUtil { return goToAppDetailSettings(context, context.getPackageName()); } + // FIXME: 2018/7/11 Permission denial public static void installApk(Context context, String path) { Intent intent = new Intent(Intent.ACTION_VIEW);