* refactor: move library dynamic layout inflater to autojs module
* fix: ScriptExecuteActivity memory leak * fix: InterruptedException on script exit event
This commit is contained in:
@@ -40,7 +40,6 @@ dependencies {
|
||||
})
|
||||
testCompile 'junit:junit:4.12'
|
||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||
compile('com.github.hyb1996:DynamicLayoutInflator:0.26')
|
||||
compile 'org.greenrobot:eventbus:3.0.0'
|
||||
compile 'net.lingala.zip4j:zip4j:1.3.2'
|
||||
compile('com.afollestad.material-dialogs:core:0.9.2.3', {
|
||||
|
||||
@@ -73,14 +73,11 @@ public class ScreenCapturer {
|
||||
setImageListener(mHandler);
|
||||
return;
|
||||
}
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Looper.prepare();
|
||||
mImageAcquireLooper = Looper.myLooper();
|
||||
setImageListener(new Handler());
|
||||
Looper.loop();
|
||||
}
|
||||
new Thread(() -> {
|
||||
Looper.prepare();
|
||||
mImageAcquireLooper = Looper.myLooper();
|
||||
setImageListener(new Handler());
|
||||
Looper.loop();
|
||||
}).start();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.stardust.autojs.core.looper;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.MessageQueue;
|
||||
|
||||
import com.stardust.autojs.runtime.ScriptRuntime;
|
||||
import com.stardust.autojs.runtime.api.Threads;
|
||||
@@ -13,7 +14,7 @@ import com.stardust.lang.ThreadCompat;
|
||||
* Created by Stardust on 2017/7/29.
|
||||
*/
|
||||
|
||||
public class Loopers {
|
||||
public class Loopers implements MessageQueue.IdleHandler {
|
||||
|
||||
public interface LooperQuitHandler {
|
||||
boolean shouldQuit();
|
||||
@@ -30,6 +31,7 @@ public class Loopers {
|
||||
private Handler mMainHandler;
|
||||
private Looper mMainLooper;
|
||||
private Threads mThreads;
|
||||
private MessageQueue mMainMessageQueue;
|
||||
|
||||
public Loopers(ScriptRuntime runtime) {
|
||||
mTimers = runtime.timers;
|
||||
@@ -38,6 +40,7 @@ public class Loopers {
|
||||
prepare();
|
||||
mMainLooper = Looper.myLooper();
|
||||
mMainHandler = new Handler();
|
||||
mMainMessageQueue = Looper.myQueue();
|
||||
}
|
||||
|
||||
|
||||
@@ -92,33 +95,37 @@ public class Loopers {
|
||||
waitWhenIdle.set(b);
|
||||
}
|
||||
|
||||
public void quitAll() {
|
||||
public void recycle() {
|
||||
quitServantLooper();
|
||||
mMainMessageQueue.removeIdleHandler(this);
|
||||
}
|
||||
|
||||
public void setMainLooperQuitHandler(LooperQuitHandler mainLooperQuitHandler) {
|
||||
mMainLooperQuitHandler = mainLooperQuitHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean queueIdle() {
|
||||
Looper l = Looper.myLooper();
|
||||
if (l == null)
|
||||
return true;
|
||||
if (l == mMainLooper) {
|
||||
if (shouldQuitLooper() && !mThreads.hasRunningThreads() &&
|
||||
mMainLooperQuitHandler != null && mMainLooperQuitHandler.shouldQuit()) {
|
||||
l.quit();
|
||||
}
|
||||
} else {
|
||||
if (shouldQuitLooper()) {
|
||||
l.quit();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void prepare() {
|
||||
if (Looper.myLooper() == null)
|
||||
Looper.prepare();
|
||||
Looper.myQueue().addIdleHandler(() -> {
|
||||
Looper l = Looper.myLooper();
|
||||
if (l == null)
|
||||
return true;
|
||||
if (l == mMainLooper) {
|
||||
if (shouldQuitLooper() && !mThreads.hasRunningThreads() &&
|
||||
mMainLooperQuitHandler != null && mMainLooperQuitHandler.shouldQuit()) {
|
||||
l.quit();
|
||||
}
|
||||
} else {
|
||||
if (shouldQuitLooper()) {
|
||||
l.quit();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
Looper.myQueue().addIdleHandler(this);
|
||||
waitWhenIdle.set(Looper.myLooper() == Looper.getMainLooper());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,23 +1,14 @@
|
||||
package com.stardust.autojs.core.ui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.InputType;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.stardust.autojs.core.ui.inflater.DynamicLayoutInflater;
|
||||
import com.stardust.autojs.core.ui.widget.JsFrameLayout;
|
||||
import com.stardust.autojs.core.ui.widget.JsImageView;
|
||||
import com.stardust.autojs.core.ui.xml.JsImageViewAttrSetter;
|
||||
import com.stardust.autojs.core.ui.inflater.attrsetter.JsImageViewAttrSetter;
|
||||
import com.stardust.autojs.core.ui.xml.XmlConverter;
|
||||
import com.stardust.util.MapEntries;
|
||||
|
||||
import org.autojs.dynamiclayoutinflater.DynamicLayoutInflater;
|
||||
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/5/14.
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
package com.stardust.autojs.core.ui;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.TypedValue;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import org.autojs.dynamiclayoutinflater.util.Ids;
|
||||
import com.stardust.autojs.core.ui.inflater.util.Ids;
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,236 @@
|
||||
package com.stardust.autojs.core.ui.inflater;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.InflateException;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.DatePicker;
|
||||
import android.widget.EditText;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.RadioGroup;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
import android.widget.TimePicker;
|
||||
|
||||
import com.stardust.autojs.core.ui.inflater.attrsetter.BaseViewAttrSetter;
|
||||
import com.stardust.autojs.core.ui.inflater.attrsetter.DatePickerAttrSetter;
|
||||
import com.stardust.autojs.core.ui.inflater.attrsetter.FrameLayoutAttrSetter;
|
||||
import com.stardust.autojs.core.ui.inflater.attrsetter.ImageViewAttrSetter;
|
||||
import com.stardust.autojs.core.ui.inflater.attrsetter.LinearLayoutAttrSetter;
|
||||
import com.stardust.autojs.core.ui.inflater.attrsetter.ProgressBarAttrSetter;
|
||||
import com.stardust.autojs.core.ui.inflater.attrsetter.RadioGroupAttrSetter;
|
||||
import com.stardust.autojs.core.ui.inflater.attrsetter.SpinnerAttrSetter;
|
||||
import com.stardust.autojs.core.ui.inflater.attrsetter.TextViewAttrSetter;
|
||||
import com.stardust.autojs.core.ui.inflater.attrsetter.TimePickerAttrSetter;
|
||||
import com.stardust.autojs.core.ui.inflater.attrsetter.ToolbarAttrSetter;
|
||||
import com.stardust.autojs.core.ui.inflater.attrsetter.ViewGroupAttrSetter;
|
||||
import com.stardust.autojs.core.ui.inflater.util.Res;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.NamedNodeMap;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
|
||||
/**
|
||||
* Copyright Nicholas White 2015.
|
||||
* Source: https://github.com/nickwah/DynamicLayoutInflator
|
||||
* <p>
|
||||
* Licensed under the MIT License:
|
||||
* <p>
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
* <p>
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
* <p>
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
public class DynamicLayoutInflater {
|
||||
private static final String LOG_TAG = "DynamicLayoutInflater";
|
||||
|
||||
private Map<String, ViewAttrSetter<?>> mViewAttrSetters = new HashMap<>();
|
||||
private Map<String, com.stardust.autojs.core.ui.inflater.ViewCreator<?>> mViewCreators = new HashMap<>();
|
||||
private Context mContext;
|
||||
|
||||
public DynamicLayoutInflater(Context context) {
|
||||
mContext = context;
|
||||
registerViewAttrSetter(TextView.class.getName(), new TextViewAttrSetter<>());
|
||||
registerViewAttrSetter(EditText.class.getName(), new TextViewAttrSetter<>());
|
||||
registerViewAttrSetter(ImageView.class.getName(), new ImageViewAttrSetter<>());
|
||||
registerViewAttrSetter(LinearLayout.class.getName(), new LinearLayoutAttrSetter<>());
|
||||
registerViewAttrSetter(FrameLayout.class.getName(), new FrameLayoutAttrSetter<>());
|
||||
registerViewAttrSetter(View.class.getName(), new BaseViewAttrSetter<>());
|
||||
registerViewAttrSetter(Toolbar.class.getName(), new ToolbarAttrSetter<>());
|
||||
registerViewAttrSetter(DatePicker.class.getName(), new DatePickerAttrSetter());
|
||||
registerViewAttrSetter(RadioGroup.class.getName(), new RadioGroupAttrSetter<>());
|
||||
registerViewAttrSetter(ProgressBar.class.getName(), new ProgressBarAttrSetter<>());
|
||||
registerViewAttrSetter(Spinner.class.getName(), new SpinnerAttrSetter());
|
||||
registerViewAttrSetter(TimePicker.class.getName(), new TimePickerAttrSetter());
|
||||
|
||||
}
|
||||
|
||||
public void registerViewAttrSetter(String fullName, ViewAttrSetter<?> setter) {
|
||||
mViewAttrSetters.put(fullName, setter);
|
||||
com.stardust.autojs.core.ui.inflater.ViewCreator<?> creator = setter.getCreator();
|
||||
if (creator != null) {
|
||||
mViewCreators.put(fullName, creator);
|
||||
}
|
||||
}
|
||||
|
||||
public View inflate(String xml) {
|
||||
InputStream inputStream = new ByteArrayInputStream(xml.getBytes());
|
||||
return inflate(inputStream);
|
||||
}
|
||||
|
||||
public View inflate(String xml, ViewGroup parent) {
|
||||
InputStream inputStream = new ByteArrayInputStream(xml.getBytes());
|
||||
return inflate(inputStream, parent);
|
||||
}
|
||||
|
||||
public View inflate(InputStream inputStream) {
|
||||
return inflate(inputStream, null);
|
||||
}
|
||||
|
||||
public View inflate(InputStream inputStream, ViewGroup parent) {
|
||||
try {
|
||||
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||
dbf.setNamespaceAware(true);
|
||||
DocumentBuilder db = dbf.newDocumentBuilder();
|
||||
Document document = db.parse(inputStream);
|
||||
return inflate(document.getDocumentElement(), parent);
|
||||
} catch (Exception e) {
|
||||
throw new InflateException(e);
|
||||
} finally {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private View inflate(Node node, ViewGroup parent) {
|
||||
HashMap<String, String> attrs = getAttributesMap(node);
|
||||
View view = createViewForName(node.getNodeName(), attrs);
|
||||
if (parent != null) {
|
||||
parent.addView(view); // have to add to parent to enable certain layout attrs
|
||||
}
|
||||
ViewAttrSetter<View> setter = (ViewAttrSetter<View>) getViewAttrSetter(view);
|
||||
applyAttributes(view, setter, attrs, parent);
|
||||
if (view instanceof ViewGroup && node.hasChildNodes()) {
|
||||
inflateChildren(node, (ViewGroup) view);
|
||||
if (setter instanceof ViewGroupAttrSetter) {
|
||||
((ViewGroupAttrSetter) setter).applyPendingAttributesAboutChildren((ViewGroup) view);
|
||||
}
|
||||
}
|
||||
return view;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ViewAttrSetter<?> getViewAttrSetter(View view) {
|
||||
ViewAttrSetter<?> setter = mViewAttrSetters.get(view.getClass().getName());
|
||||
Class c = view.getClass();
|
||||
while (setter == null && c != View.class) {
|
||||
c = c.getSuperclass();
|
||||
setter = mViewAttrSetters.get(c.getName());
|
||||
}
|
||||
return setter;
|
||||
}
|
||||
|
||||
private void inflateChildren(Node node, ViewGroup parent) {
|
||||
NodeList nodeList = node.getChildNodes();
|
||||
for (int i = 0; i < nodeList.getLength(); i++) {
|
||||
Node currentNode = nodeList.item(i);
|
||||
if (currentNode.getNodeType() != Node.ELEMENT_NODE) continue;
|
||||
inflate(currentNode, parent); // this recursively can call inflateChildren
|
||||
}
|
||||
}
|
||||
|
||||
private View createViewForName(String name, HashMap<String, String> attrs) {
|
||||
try {
|
||||
if (name.equals("View")) {
|
||||
return new View(mContext);
|
||||
}
|
||||
if (!name.contains(".")) {
|
||||
name = "android.widget." + name;
|
||||
}
|
||||
ViewCreator<?> creator = mViewCreators.get(name);
|
||||
if (creator != null) {
|
||||
return creator.create(mContext, attrs);
|
||||
}
|
||||
Class<?> clazz = Class.forName(name);
|
||||
String style = attrs.get("style");
|
||||
if (style == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
return (View) clazz.getConstructor(Context.class).newInstance(mContext);
|
||||
} else {
|
||||
int styleRes = Res.parseStyle(mContext, style);
|
||||
return (View) clazz.getConstructor(Context.class, AttributeSet.class, int.class, int.class)
|
||||
.newInstance(mContext, null, 0, styleRes);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new InflateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private HashMap<String, String> getAttributesMap(Node currentNode) {
|
||||
NamedNodeMap attributeMap = currentNode.getAttributes();
|
||||
int attributeCount = attributeMap.getLength();
|
||||
HashMap<String, String> attributes = new HashMap<>(attributeCount);
|
||||
for (int j = 0; j < attributeCount; j++) {
|
||||
Node attr = attributeMap.item(j);
|
||||
String nodeName = attr.getNodeName();
|
||||
attributes.put(nodeName, attr.getNodeValue());
|
||||
}
|
||||
return attributes;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void applyAttributes(View view, ViewAttrSetter<View> setter, Map<String, String> attrs, ViewGroup parent) {
|
||||
if (setter != null) {
|
||||
for (Map.Entry<String, String> entry : attrs.entrySet()) {
|
||||
String[] attr = entry.getKey().split(":");
|
||||
if (attr.length == 1) {
|
||||
setter.setAttr(view, attr[0], entry.getValue(), parent, attrs);
|
||||
} else if (attr.length == 2) {
|
||||
setter.setAttr(view, attr[0], attr[1], entry.getValue(), parent, attrs);
|
||||
} else {
|
||||
throw new InflateException("illegal attr name: " + entry.getKey());
|
||||
}
|
||||
}
|
||||
setter.applyPendingAttributes(view, parent);
|
||||
} else {
|
||||
Log.e(LOG_TAG, "cannot set attributes for view: " + view.getClass());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.stardust.autojs.core.ui.inflater;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/11/3.
|
||||
*/
|
||||
|
||||
public interface ImageLoader {
|
||||
|
||||
interface BitmapCallback {
|
||||
void onLoaded(Bitmap bitmap);
|
||||
}
|
||||
|
||||
interface DrawableCallback {
|
||||
void onLoaded(Drawable drawable);
|
||||
}
|
||||
|
||||
void loadInto(ImageView view, Uri uri);
|
||||
|
||||
void loadIntoBackground(View view, Uri uri);
|
||||
|
||||
Drawable load(View view, Uri uri);
|
||||
|
||||
void load(View view, Uri uri, DrawableCallback callback);
|
||||
|
||||
void load(View view, Uri uri, BitmapCallback callback);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.stardust.autojs.core.ui.inflater;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/11/3.
|
||||
*/
|
||||
|
||||
|
||||
public interface ViewAttrSetter<V extends View> {
|
||||
|
||||
boolean setAttr(V view, String attrName, String value, ViewGroup parent, Map<String, String> attrs);
|
||||
|
||||
boolean setAttr(V view, String ns, String attrName, String value, ViewGroup parent, Map<String, String> attrs);
|
||||
|
||||
void applyPendingAttributes(V view, ViewGroup parent);
|
||||
|
||||
@Nullable
|
||||
ViewCreator<V> getCreator();
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.stardust.autojs.core.ui.inflater;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/11/29.
|
||||
*/
|
||||
|
||||
public interface ViewCreator<V extends View> {
|
||||
|
||||
V create(Context context, Map<String, String> attrs);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,602 @@
|
||||
package com.stardust.autojs.core.ui.inflater.attrsetter;
|
||||
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.os.Build;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
|
||||
import com.stardust.autojs.core.ui.inflater.ViewAttrSetter;
|
||||
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.Drawables;
|
||||
import com.stardust.autojs.core.ui.inflater.util.Gravities;
|
||||
import com.stardust.autojs.core.ui.inflater.util.Ids;
|
||||
import com.stardust.autojs.core.ui.inflater.util.Strings;
|
||||
import com.stardust.autojs.core.ui.inflater.util.ValueMapper;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/11/3.
|
||||
*/
|
||||
|
||||
public class BaseViewAttrSetter<V extends View> implements ViewAttrSetter<V> {
|
||||
|
||||
|
||||
protected static final ValueMapper<PorterDuff.Mode> TINT_MODES = new ValueMapper<PorterDuff.Mode>("tintMode")
|
||||
.map("add", PorterDuff.Mode.ADD)
|
||||
.map("multiply", PorterDuff.Mode.MULTIPLY)
|
||||
.map("screen", PorterDuff.Mode.SCREEN)
|
||||
.map("src_atop", PorterDuff.Mode.SRC_ATOP)
|
||||
.map("src_in", PorterDuff.Mode.SRC_IN)
|
||||
.map("src_over", PorterDuff.Mode.SRC_OVER);
|
||||
|
||||
private static final ValueMapper<Integer> DRAWABLE_CACHE_QUALITIES = new ValueMapper<Integer>("drawingCacheQuality")
|
||||
.map("auto", View.DRAWING_CACHE_QUALITY_AUTO)
|
||||
.map("high", View.DRAWING_CACHE_QUALITY_HIGH)
|
||||
.map("low", View.DRAWING_CACHE_QUALITY_LOW);
|
||||
|
||||
private static final ValueMapper<Integer> IMPORTANT_FOR_ACCESSIBILITY = new ValueMapper<Integer>("importantForAccessibility")
|
||||
.map("auto", 0) //View.IMPORTANT_FOR_ACCESSIBILITY_AUTO)
|
||||
.map("no", 2) //View.IMPORTANT_FOR_ACCESSIBILITY_NO)
|
||||
.map("noHideDescendants", 4) //View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS)
|
||||
.map("yes", 1); //View.IMPORTANT_FOR_ACCESSIBILITY_YES);
|
||||
private static final ValueMapper<Integer> LAYOUT_DIRECTIONS = new ValueMapper<Integer>("layoutDirection")
|
||||
.map("inherit", 2)
|
||||
.map("locale", 3)
|
||||
.map("ltr", 0)
|
||||
.map("rtl", 1);
|
||||
private static final ValueMapper<Integer> SCROLLBARS_STYLES = new ValueMapper<Integer>("scrollbarStyle")
|
||||
.map("insideInset", View.SCROLLBARS_INSIDE_INSET)
|
||||
.map("insideOverlay", View.SCROLLBARS_INSIDE_OVERLAY)
|
||||
.map("outsideInset", View.SCROLLBARS_OUTSIDE_INSET)
|
||||
.map("outsideOverlay", View.SCROLLBARS_OUTSIDE_OVERLAY);
|
||||
private static final ValueMapper<Integer> SCROLL_INDICATORS = new ValueMapper<Integer>("scrollIndicators")
|
||||
.map("bottom", 2) //View.SCROLL_INDICATOR_BOTTOM)
|
||||
.map("end", 20) //View.SCROLL_INDICATOR_END)
|
||||
.map("left", 4) //View.SCROLL_INDICATOR_LEFT)
|
||||
.map("none", 0)
|
||||
.map("right", 8) //View.SCROLL_INDICATOR_RIGHT)
|
||||
.map("start", 10) //View.SCROLL_INDICATOR_START)
|
||||
.map("top", 1); //View.SCROLL_INDICATOR_TOP)
|
||||
private static final ValueMapper<Integer> VISIBILITY = new ValueMapper<Integer>("visibility")
|
||||
.map("visible", View.VISIBLE)
|
||||
.map("invisible", View.INVISIBLE)
|
||||
.map("gone", View.GONE);
|
||||
private static final ValueMapper<Integer> TEXT_DIRECTIONS = new ValueMapper<Integer>("textDirection")
|
||||
.map("anyRtl", 2)
|
||||
.map("firstStrong", 1)
|
||||
.map("firstStrongLtr", 6)
|
||||
.map("firstStrongRtl", 7)
|
||||
.map("inherit", 0)
|
||||
.map("locale", 5)
|
||||
.map("ltr", 3)
|
||||
.map("rtl", 4);
|
||||
private static final ValueMapper<Integer> TEXT_ALIGNMENTS = new ValueMapper<Integer>("textAlignment")
|
||||
.map("center", 4)
|
||||
.map("gravity", 1)
|
||||
.map("inherit", 0)
|
||||
.map("textEnd", 3)
|
||||
.map("textStart", 2)
|
||||
.map("viewEnd", 6)
|
||||
.map("viewStart", 5);
|
||||
|
||||
@Override
|
||||
public boolean setAttr(V view, String attr, String value, ViewGroup parent, Map<String, String> attrs) {
|
||||
Integer layoutRule = null;
|
||||
boolean layoutTarget = false;
|
||||
ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
|
||||
switch (attr) {
|
||||
case "id":
|
||||
view.setId(Ids.parse(value));
|
||||
break;
|
||||
case "gravity":
|
||||
return setGravity(view, value);
|
||||
case "width":
|
||||
case "layout_width":
|
||||
switch (value) {
|
||||
case "wrap_content":
|
||||
layoutParams.width = ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||
break;
|
||||
case "fill_parent":
|
||||
case "match_parent":
|
||||
layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
break;
|
||||
default:
|
||||
layoutParams.width = Dimensions.parseToPixel(value, view.getResources().getDisplayMetrics(), parent, true);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case "height":
|
||||
case "layout_height":
|
||||
switch (value) {
|
||||
case "wrap_content":
|
||||
layoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||
break;
|
||||
case "fill_parent":
|
||||
case "match_parent":
|
||||
layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
break;
|
||||
default:
|
||||
layoutParams.height = Dimensions.parseToPixel(value, view.getResources().getDisplayMetrics(), parent, false);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case "layout_gravity":
|
||||
if (parent != null && parent instanceof LinearLayout) {
|
||||
((LinearLayout.LayoutParams) layoutParams).gravity = Gravities.parse(value);
|
||||
} else if (parent != null && parent instanceof FrameLayout) {
|
||||
((FrameLayout.LayoutParams) layoutParams).gravity = Gravities.parse(value);
|
||||
}
|
||||
break;
|
||||
case "layout_weight":
|
||||
if (parent != null && parent instanceof LinearLayout) {
|
||||
((LinearLayout.LayoutParams) layoutParams).weight = Float.parseFloat(value);
|
||||
}
|
||||
break;
|
||||
case "layout_below":
|
||||
layoutRule = RelativeLayout.BELOW;
|
||||
layoutTarget = true;
|
||||
break;
|
||||
case "layout_above":
|
||||
layoutRule = RelativeLayout.ABOVE;
|
||||
layoutTarget = true;
|
||||
break;
|
||||
case "layout_toLeftOf":
|
||||
layoutRule = RelativeLayout.LEFT_OF;
|
||||
layoutTarget = true;
|
||||
break;
|
||||
case "layout_toRightOf":
|
||||
layoutRule = RelativeLayout.RIGHT_OF;
|
||||
layoutTarget = true;
|
||||
break;
|
||||
case "layout_alignBottom":
|
||||
layoutRule = RelativeLayout.ALIGN_BOTTOM;
|
||||
layoutTarget = true;
|
||||
break;
|
||||
case "layout_alignTop":
|
||||
layoutRule = RelativeLayout.ALIGN_TOP;
|
||||
layoutTarget = true;
|
||||
break;
|
||||
case "layout_alignLeft":
|
||||
case "layout_alignStart":
|
||||
layoutRule = RelativeLayout.ALIGN_LEFT;
|
||||
layoutTarget = true;
|
||||
break;
|
||||
case "layout_alignRight":
|
||||
case "layout_alignEnd":
|
||||
layoutRule = RelativeLayout.ALIGN_RIGHT;
|
||||
layoutTarget = true;
|
||||
break;
|
||||
case "layout_alignParentBottom":
|
||||
layoutRule = RelativeLayout.ALIGN_PARENT_BOTTOM;
|
||||
break;
|
||||
case "layout_alignParentTop":
|
||||
layoutRule = RelativeLayout.ALIGN_PARENT_TOP;
|
||||
break;
|
||||
case "layout_alignParentLeft":
|
||||
case "layout_alignParentStart":
|
||||
layoutRule = RelativeLayout.ALIGN_PARENT_LEFT;
|
||||
break;
|
||||
case "layout_alignParentRight":
|
||||
case "layout_alignParentEnd":
|
||||
layoutRule = RelativeLayout.ALIGN_PARENT_RIGHT;
|
||||
break;
|
||||
case "layout_centerHorizontal":
|
||||
layoutRule = RelativeLayout.CENTER_HORIZONTAL;
|
||||
break;
|
||||
case "layout_centerVertical":
|
||||
layoutRule = RelativeLayout.CENTER_VERTICAL;
|
||||
break;
|
||||
case "layout_centerInParent":
|
||||
layoutRule = RelativeLayout.CENTER_IN_PARENT;
|
||||
break;
|
||||
case "layout_margin":
|
||||
if (view.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
|
||||
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
|
||||
int margin = Dimensions.parseToIntPixel(value, view);
|
||||
params.bottomMargin = params.leftMargin = params.topMargin = params.rightMargin = margin;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
params.setMarginStart(margin);
|
||||
params.setMarginEnd(margin);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "layout_marginLeft":
|
||||
if (view.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
|
||||
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
|
||||
params.leftMargin = Dimensions.parseToIntPixel(value, view);
|
||||
}
|
||||
break;
|
||||
case "layout_marginTop":
|
||||
if (view.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
|
||||
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
|
||||
params.topMargin = Dimensions.parseToIntPixel(value, view);
|
||||
}
|
||||
break;
|
||||
case "layout_marginRight":
|
||||
if (view.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
|
||||
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
|
||||
params.rightMargin = Dimensions.parseToIntPixel(value, view);
|
||||
}
|
||||
break;
|
||||
case "layout_marginBottom":
|
||||
if (view.getLayoutParams() instanceof ViewGroup.MarginLayoutParams) {
|
||||
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
|
||||
params.bottomMargin = Dimensions.parseToIntPixel(value, view);
|
||||
}
|
||||
break;
|
||||
case "padding":
|
||||
int p = Dimensions.parseToIntPixel(value, view);
|
||||
view.setPadding(p, p, p, p);
|
||||
break;
|
||||
case "paddingLeft":
|
||||
view.setPadding(Dimensions.parseToIntPixel(value, view), view.getPaddingTop(), view.getPaddingRight(), view.getPaddingBottom());
|
||||
break;
|
||||
case "paddingTop":
|
||||
view.setPadding(view.getPaddingLeft(), Dimensions.parseToIntPixel(value, view), view.getPaddingRight(), view.getPaddingBottom());
|
||||
break;
|
||||
case "paddingRight":
|
||||
view.setPadding(view.getPaddingLeft(), view.getPaddingTop(), Dimensions.parseToIntPixel(value, view), view.getPaddingBottom());
|
||||
break;
|
||||
case "paddingBottom":
|
||||
view.setPadding(view.getPaddingLeft(), view.getPaddingTop(), view.getPaddingRight(), Dimensions.parseToIntPixel(value, view));
|
||||
break;
|
||||
case "background":
|
||||
Drawables.setupWithViewBackground(view, value);
|
||||
break;
|
||||
case "accessibilityLiveRegion":
|
||||
case "accessibilityTraversalAfter":
|
||||
case "accessibilityTraversalBefore":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
case "alpha":
|
||||
view.setAlpha(Float.valueOf(value));
|
||||
break;
|
||||
case "autofillHints":
|
||||
case "autofilledHighlight":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
break;
|
||||
case "backgroundTint":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
view.setBackgroundTintList(ColorStateList.valueOf(Colors.parse(view, value)));
|
||||
}
|
||||
break;
|
||||
case "backgroundTintMode":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
view.setBackgroundTintMode(TINT_MODES.get(value));
|
||||
}
|
||||
break;
|
||||
case "checked":
|
||||
if (view instanceof CompoundButton) {
|
||||
((CompoundButton) view).setChecked(Boolean.parseBoolean(value));
|
||||
}
|
||||
break;
|
||||
case "clickable":
|
||||
view.setClickable(Boolean.valueOf(value));
|
||||
break;
|
||||
case "contentDescription":
|
||||
view.setContentDescription(Strings.parse(view, value));
|
||||
break;
|
||||
case "contextClickable":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
view.setContextClickable(Boolean.valueOf(value));
|
||||
}
|
||||
break;
|
||||
case "defaultFocusHighlightEnabled":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
break;
|
||||
case "drawingCacheQuality":
|
||||
view.setDrawingCacheQuality(DRAWABLE_CACHE_QUALITIES.get(value));
|
||||
break;
|
||||
case "duplicateParentState":
|
||||
view.setDuplicateParentStateEnabled(Boolean.valueOf(value));
|
||||
break;
|
||||
case "elevation":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
view.setElevation(Dimensions.parseToIntPixel(value, view));
|
||||
}
|
||||
break;
|
||||
case "fadeScrollbars":
|
||||
view.setScrollbarFadingEnabled(Boolean.valueOf(value));
|
||||
break;
|
||||
case "fadingEdgeLength":
|
||||
view.setFadingEdgeLength(Dimensions.parseToIntPixel(value, view));
|
||||
break;
|
||||
case "filterTouchesWhenObscured":
|
||||
view.setFilterTouchesWhenObscured(Boolean.valueOf(value));
|
||||
break;
|
||||
case "fitsSystemWindows":
|
||||
view.setFitsSystemWindows(Boolean.valueOf(value));
|
||||
break;
|
||||
case "focusable":
|
||||
view.setFocusable(Boolean.valueOf(value));
|
||||
break;
|
||||
case "focusableInTouchMode":
|
||||
view.setFocusableInTouchMode(Boolean.valueOf(value));
|
||||
break;
|
||||
case "focusedByDefault":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
break;
|
||||
case "forceHasOverlappingRendering":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
view.forceHasOverlappingRendering(Boolean.valueOf(value));
|
||||
}
|
||||
break;
|
||||
case "foreground":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
view.setForeground(Drawables.parse(view, value));
|
||||
}
|
||||
break;
|
||||
case "foregroundGravity":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
view.setForegroundGravity(Gravities.parse(value));
|
||||
}
|
||||
break;
|
||||
case "foregroundTint":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
view.setForegroundTintList(ColorStateList.valueOf(Colors.parse(view, value)));
|
||||
}
|
||||
break;
|
||||
case "foregroundTintMode":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
view.setForegroundTintMode(TINT_MODES.get(value));
|
||||
}
|
||||
break;
|
||||
case "hapticFeedbackEnabled":
|
||||
view.setHapticFeedbackEnabled(Boolean.valueOf(value));
|
||||
break;
|
||||
case "importantForAccessibility":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
view.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY.get(value));
|
||||
}
|
||||
break;
|
||||
case "importantForAutofill":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
break;
|
||||
case "isScrollContainer":
|
||||
view.setScrollContainer(Boolean.valueOf(value));
|
||||
break;
|
||||
case "keepScreenOn":
|
||||
view.setKeepScreenOn(Boolean.valueOf(value));
|
||||
break;
|
||||
case "keyboardNavigationCluster":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
break;
|
||||
case "layerType":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
break;
|
||||
case "layoutDirection":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
view.setLayoutDirection(LAYOUT_DIRECTIONS.get(value));
|
||||
}
|
||||
break;
|
||||
case "longClickable":
|
||||
view.setLongClickable(Boolean.valueOf(value));
|
||||
break;
|
||||
case "minHeight":
|
||||
view.setMinimumHeight(Dimensions.parseToIntPixel(value, view));
|
||||
break;
|
||||
case "minWidth":
|
||||
view.setMinimumWidth(Dimensions.parseToIntPixel(value, view));
|
||||
break;
|
||||
case "nextClusterForward":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
break;
|
||||
case "nextFocusDown":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
break;
|
||||
case "nextFocusForward":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
break;
|
||||
case "nextFocusLeft":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
break;
|
||||
case "nextFocusRight":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
break;
|
||||
case "nextFocusUp":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
break;
|
||||
case "onClick":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
break;
|
||||
case "paddingEnd":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
view.setPaddingRelative(view.getPaddingStart(), view.getPaddingTop(),
|
||||
Dimensions.parseToIntPixel(value, view), view.getPaddingBottom());
|
||||
} else {
|
||||
view.setPadding(view.getPaddingLeft(), view.getPaddingTop(),
|
||||
Dimensions.parseToIntPixel(value, view), view.getPaddingBottom());
|
||||
}
|
||||
break;
|
||||
case "paddingHorizontal":
|
||||
case "paddingVertical":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
break;
|
||||
case "paddingStart":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
view.setPaddingRelative(Dimensions.parseToIntPixel(value, view), view.getPaddingTop(),
|
||||
view.getPaddingEnd(), view.getPaddingBottom());
|
||||
} else {
|
||||
view.setPadding(Dimensions.parseToIntPixel(value, view), view.getPaddingTop(),
|
||||
view.getPaddingRight(), view.getPaddingBottom());
|
||||
}
|
||||
break;
|
||||
case "requiresFadingEdge":
|
||||
for (String str : value.split("|")) {
|
||||
if (str.equals("horizontal")) {
|
||||
view.setHorizontalFadingEdgeEnabled(true);
|
||||
} else if (str.equals("vertical")) {
|
||||
view.setVerticalFadingEdgeEnabled(true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "rotation":
|
||||
view.setRotation(Float.parseFloat(value));
|
||||
break;
|
||||
case "rotationX":
|
||||
view.setRotationX(Float.parseFloat(value));
|
||||
break;
|
||||
case "rotationY":
|
||||
view.setRotationY(Float.parseFloat(value));
|
||||
break;
|
||||
case "saveEnabled":
|
||||
view.setSaveEnabled(Boolean.valueOf(value));
|
||||
break;
|
||||
case "scaleX":
|
||||
view.setScaleX(Dimensions.parseToPixel(value, view));
|
||||
break;
|
||||
case "scaleY":
|
||||
view.setScaleY(Dimensions.parseToPixel(value, view));
|
||||
break;
|
||||
case "scrollIndicators":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
view.setScrollIndicators(SCROLL_INDICATORS.get(value));
|
||||
}
|
||||
break;
|
||||
case "scrollX":
|
||||
view.setScrollX(Dimensions.parseToIntPixel(value, view));
|
||||
break;
|
||||
case "scrollY":
|
||||
view.setScrollY(Dimensions.parseToIntPixel(value, view));
|
||||
break;
|
||||
case "scrollbarAlwaysDrawHorizontalTrack":
|
||||
case "scrollbarAlwaysDrawVerticalTrack":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
break;
|
||||
case "scrollbarDefaultDelayBeforeFade":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
view.setScrollBarDefaultDelayBeforeFade(Integer.valueOf(value));
|
||||
}
|
||||
break;
|
||||
case "scrollbarFadeDuration":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
view.setScrollBarFadeDuration(Integer.valueOf(value));
|
||||
}
|
||||
break;
|
||||
case "scrollbarSize":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
view.setScrollBarSize(Dimensions.parseToIntPixel(value, view));
|
||||
}
|
||||
break;
|
||||
case "scrollbarStyle":
|
||||
view.setScrollBarStyle(SCROLLBARS_STYLES.get(value));
|
||||
break;
|
||||
case "scrollbarThumbHorizontal":
|
||||
case "scrollbarThumbVertical":
|
||||
case "scrollbarTrackHorizontal":
|
||||
case "scrollbarTrackVertical":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
case "scrollbars":
|
||||
for (String str : value.split("|")) {
|
||||
if (str.equals("horizontal")) {
|
||||
view.setHorizontalScrollBarEnabled(true);
|
||||
} else if (str.equals("vertical")) {
|
||||
view.setVerticalScrollBarEnabled(true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "soundEffectsEnabled":
|
||||
view.setSoundEffectsEnabled(Boolean.valueOf(value));
|
||||
break;
|
||||
case "stateListAnimator":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
case "tag":
|
||||
view.setTag(Strings.parse(view, value));
|
||||
break;
|
||||
case "textAlignment":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
view.setTextAlignment(TEXT_ALIGNMENTS.get(value));
|
||||
}
|
||||
break;
|
||||
case "textDirection":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
view.setTextDirection(TEXT_DIRECTIONS.get(value));
|
||||
}
|
||||
break;
|
||||
case "theme":
|
||||
//Exceptions.unsupports(view, attr, value);
|
||||
|
||||
break;
|
||||
case "tooltipText":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
break;
|
||||
case "transformPivotX":
|
||||
view.setPivotX(Dimensions.parseToPixel(value, view));
|
||||
break;
|
||||
case "transformPivotY":
|
||||
view.setPivotY(Dimensions.parseToPixel(value, view));
|
||||
break;
|
||||
case "transitionName":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
view.setTransitionName(Strings.parse(view, value));
|
||||
}
|
||||
break;
|
||||
case "translationX":
|
||||
view.setTranslationX(Dimensions.parseToPixel(value, view));
|
||||
break;
|
||||
case "translationY":
|
||||
view.setTranslationY(Dimensions.parseToPixel(value, view));
|
||||
break;
|
||||
case "translationZ":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
view.setTranslationZ(Dimensions.parseToPixel(value, view));
|
||||
}
|
||||
break;
|
||||
case "visibility":
|
||||
view.setVisibility(VISIBILITY.get(value));
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
|
||||
}
|
||||
if (layoutRule != null && parent instanceof RelativeLayout) {
|
||||
if (layoutTarget) {
|
||||
int anchor = Ids.parse(value);
|
||||
((RelativeLayout.LayoutParams) layoutParams).addRule(layoutRule, anchor);
|
||||
} else if (value.equals("true")) {
|
||||
((RelativeLayout.LayoutParams) layoutParams).addRule(layoutRule);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setAttr(V view, String ns, String attrName, String value, ViewGroup parent, Map<String, String> attrs) {
|
||||
if (ns.equals("android")) {
|
||||
return setAttr(view, attrName, value, parent, attrs);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean setGravity(V view, String g) {
|
||||
try {
|
||||
Method setGravity = view.getClass().getMethod("setGravity", int.class);
|
||||
setGravity.invoke(view, Gravities.parse(g));
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyPendingAttributes(V view, ViewGroup parent) {
|
||||
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ViewCreator<V> getCreator() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package com.stardust.autojs.core.ui.inflater.attrsetter;
|
||||
|
||||
import android.os.Build;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.InflateException;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.DatePicker;
|
||||
|
||||
|
||||
import com.stardust.autojs.R;
|
||||
import com.stardust.autojs.core.ui.inflater.ViewCreator;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/11/29.
|
||||
*/
|
||||
|
||||
public class DatePickerAttrSetter extends BaseViewAttrSetter<DatePicker> {
|
||||
|
||||
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("mm/dd/yyyy", Locale.getDefault());
|
||||
|
||||
@Override
|
||||
public boolean setAttr(DatePicker view, String attr, String value, ViewGroup parent, Map<String, String> attrs) {
|
||||
switch (attr) {
|
||||
case "calendarTextColor":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
break;
|
||||
case "calendarViewShown":
|
||||
view.setCalendarViewShown(Boolean.parseBoolean(attr));
|
||||
break;
|
||||
case "dayOfWeekBackground":
|
||||
case "dayOfWeekTextAppearance":
|
||||
case "endYear":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
break;
|
||||
case "firstDayOfWeek":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
view.setFirstDayOfWeek(Integer.parseInt(value));
|
||||
}
|
||||
break;
|
||||
case "headerBackground":
|
||||
case "headerDayOfMonthTextAppearance":
|
||||
case "headerMonthTextAppearance":
|
||||
case "headerYearTextAppearance":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
break;
|
||||
case "maxDate":
|
||||
try {
|
||||
view.setMaxDate(DATE_FORMAT.parse(value).getTime());
|
||||
} catch (ParseException e) {
|
||||
throw new InflateException(e);
|
||||
}
|
||||
break;
|
||||
case "minDate":
|
||||
try {
|
||||
view.setMinDate(DATE_FORMAT.parse(value).getTime());
|
||||
} catch (ParseException e) {
|
||||
throw new InflateException(e);
|
||||
}
|
||||
break;
|
||||
case "spinnersShown":
|
||||
view.setSpinnersShown(Boolean.parseBoolean(value));
|
||||
break;
|
||||
case "startYear":
|
||||
case "yearListItemTextAppearance":
|
||||
case "yearListSelectorColor":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
break;
|
||||
default:
|
||||
return super.setAttr(view, attr, value, parent, attrs);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ViewCreator<DatePicker> getCreator() {
|
||||
return (context, attrs) -> {
|
||||
String datePickerMode = attrs.remove("android:datePickerMode");
|
||||
if (datePickerMode == null || !datePickerMode.equals("spinner")) {
|
||||
return new DatePicker(context);
|
||||
}
|
||||
DatePicker datePicker = (DatePicker) View.inflate(context, R.layout.date_picker_spinner, null);
|
||||
datePicker.setCalendarViewShown(false);
|
||||
return datePicker;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.stardust.autojs.core.ui.inflater.attrsetter;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/11/4.
|
||||
*/
|
||||
|
||||
public class Exceptions {
|
||||
|
||||
public interface ExceptionHandler {
|
||||
boolean handleUnsupportedException(UnsupportedOperationException e, View v, String attrName, String value);
|
||||
}
|
||||
|
||||
private static ExceptionHandler sExceptionHandler;
|
||||
|
||||
public static void unsupports(View v, String name, String value) {
|
||||
UnsupportedOperationException e = new UnsupportedOperationException(String.format("Attr %s:%s=\"%s\" is not supported",
|
||||
v.getClass().getSimpleName(), name, value));
|
||||
if (sExceptionHandler == null || !sExceptionHandler.handleUnsupportedException(e, v, name, value)) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static ExceptionHandler getExceptionHandler() {
|
||||
return sExceptionHandler;
|
||||
}
|
||||
|
||||
public static void setExceptionHandler(ExceptionHandler exceptionHandler) {
|
||||
sExceptionHandler = exceptionHandler;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.stardust.autojs.core.ui.inflater.attrsetter;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import com.stardust.autojs.core.ui.inflater.util.Gravities;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/11/29.
|
||||
*/
|
||||
|
||||
public class FrameLayoutAttrSetter<V extends FrameLayout> extends ViewGroupAttrSetter<V> {
|
||||
|
||||
private Integer mGravity;
|
||||
|
||||
@Override
|
||||
public boolean setAttr(V view, String attr, String value, ViewGroup parent, Map<String, String> attrs) {
|
||||
if (attr.equals("gravity")) {
|
||||
mGravity = Gravities.parse(value);
|
||||
return true;
|
||||
}
|
||||
return super.setAttr(view, attr, value, parent, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyPendingAttributesAboutChildren(V view) {
|
||||
if (mGravity == null)
|
||||
return;
|
||||
for (int i = 0; i < view.getChildCount(); i++) {
|
||||
View child = view.getChildAt(i);
|
||||
FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) child.getLayoutParams();
|
||||
params.gravity = mGravity;
|
||||
child.setLayoutParams(params);
|
||||
}
|
||||
mGravity = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package com.stardust.autojs.core.ui.inflater.attrsetter;
|
||||
|
||||
import android.os.Build;
|
||||
import android.view.InflateException;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
|
||||
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.Drawables;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/11/3.
|
||||
*/
|
||||
|
||||
public class ImageViewAttrSetter<V extends ImageView> extends BaseViewAttrSetter<V> {
|
||||
|
||||
@Override
|
||||
public boolean setAttr(V view, String attr, String value, ViewGroup parent, Map<String, String> attrs) {
|
||||
if (super.setAttr(view, attr, value, parent, attrs)) {
|
||||
return true;
|
||||
}
|
||||
switch (attr) {
|
||||
case "adjustViewBounds":
|
||||
view.setAdjustViewBounds(Boolean.valueOf(value));
|
||||
break;
|
||||
case "baseline":
|
||||
view.setBaseline(Dimensions.parseToIntPixel(value, view));
|
||||
break;
|
||||
case "baselineAlignBottom":
|
||||
view.setBaselineAlignBottom(Boolean.valueOf(value));
|
||||
break;
|
||||
case "cropToPadding":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
view.setCropToPadding(Boolean.valueOf(value));
|
||||
}
|
||||
break;
|
||||
case "maxHeight":
|
||||
view.setMaxHeight(Dimensions.parseToIntPixel(value, view));
|
||||
break;
|
||||
case "maxWidth":
|
||||
view.setMaxWidth(Dimensions.parseToIntPixel(value, view));
|
||||
break;
|
||||
case "path":
|
||||
Drawables.setupWithImage(view, wrapAsPath(value));
|
||||
break;
|
||||
case "scaleType":
|
||||
view.setScaleType(parseScaleType(value));
|
||||
break;
|
||||
case "src":
|
||||
Drawables.setupWithImage(view, value);
|
||||
break;
|
||||
case "tint":
|
||||
view.setColorFilter(Colors.parse(view, value));
|
||||
break;
|
||||
case "tintMode":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
view.setImageTintMode(TINT_MODES.get(value));
|
||||
}
|
||||
break;
|
||||
case "url":
|
||||
Drawables.setupWithImage(view, wrapAsUrl(value));
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
private String wrapAsPath(String value) {
|
||||
if (!value.startsWith("file://")) {
|
||||
return "file://" + value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private String wrapAsUrl(String value) {
|
||||
if (!value.startsWith("http://") && !value.startsWith("https://")) {
|
||||
return "http://" + value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private ImageView.ScaleType parseScaleType(String value) {
|
||||
switch (value.toLowerCase()) {
|
||||
case "center":
|
||||
return ImageView.ScaleType.CENTER;
|
||||
case "center_crop":
|
||||
return ImageView.ScaleType.CENTER_CROP;
|
||||
case "center_inside":
|
||||
return ImageView.ScaleType.CENTER_INSIDE;
|
||||
case "fit_center":
|
||||
return ImageView.ScaleType.FIT_CENTER;
|
||||
case "fit_end":
|
||||
return ImageView.ScaleType.FIT_END;
|
||||
case "fit_start":
|
||||
return ImageView.ScaleType.FIT_START;
|
||||
case "fit_xy":
|
||||
return ImageView.ScaleType.FIT_XY;
|
||||
case "matrix":
|
||||
return ImageView.ScaleType.MATRIX;
|
||||
}
|
||||
throw new InflateException("unknown scale type: " + value);
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,14 @@
|
||||
package com.stardust.autojs.core.ui.xml;
|
||||
package com.stardust.autojs.core.ui.inflater.attrsetter;
|
||||
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ImageView.ScaleType;
|
||||
|
||||
import com.makeramen.roundedimageview.Corner;
|
||||
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.ValueMapper;
|
||||
import com.stardust.autojs.core.ui.widget.JsImageView;
|
||||
|
||||
import org.autojs.dynamiclayoutinflater.attrsetter.BaseViewAttrSetter;
|
||||
import org.autojs.dynamiclayoutinflater.attrsetter.ImageViewAttrSetter;
|
||||
import org.autojs.dynamiclayoutinflater.util.Colors;
|
||||
import org.autojs.dynamiclayoutinflater.util.Dimensions;
|
||||
import org.autojs.dynamiclayoutinflater.util.ValueMapper;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -37,6 +35,18 @@ public class JsImageViewAttrSetter<V extends JsImageView> extends ImageViewAttrS
|
||||
case "radius":
|
||||
view.setCornerRadius(Dimensions.parseToPixel(value, view));
|
||||
break;
|
||||
case "radiusTopLeft":
|
||||
view.setCornerRadius(Dimensions.parseToPixel(value, view), view.getCornerRadius(Corner.TOP_RIGHT), view.getCornerRadius(Corner.BOTTOM_LEFT), view.getCornerRadius(Corner.BOTTOM_RIGHT));
|
||||
break;
|
||||
case "radiusTopRight":
|
||||
view.setCornerRadius(view.getCornerRadius(Corner.TOP_LEFT), Dimensions.parseToPixel(value, view), view.getCornerRadius(Corner.BOTTOM_LEFT), view.getCornerRadius(Corner.BOTTOM_RIGHT));
|
||||
break;
|
||||
case "radiusBottomLeft":
|
||||
view.setCornerRadius(view.getCornerRadius(Corner.TOP_LEFT), view.getCornerRadius(Corner.TOP_RIGHT), Dimensions.parseToPixel(value, view), view.getCornerRadius(Corner.BOTTOM_RIGHT));
|
||||
break;
|
||||
case "radiusBottomRight":
|
||||
view.setCornerRadius(view.getCornerRadius(Corner.TOP_LEFT), view.getCornerRadius(Corner.TOP_RIGHT), view.getCornerRadius(Corner.BOTTOM_LEFT), Dimensions.parseToPixel(value, view));
|
||||
break;
|
||||
case "borderWidth":
|
||||
view.setBorderWidth(Dimensions.parseToPixel(value, view));
|
||||
break;
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.stardust.autojs.core.ui.inflater.attrsetter;
|
||||
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.stardust.autojs.core.ui.inflater.util.Drawables;
|
||||
import com.stardust.autojs.core.ui.inflater.util.Gravities;
|
||||
import com.stardust.autojs.core.ui.inflater.util.ValueMapper;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/11/4.
|
||||
*/
|
||||
|
||||
public class LinearLayoutAttrSetter<V extends LinearLayout> extends ViewGroupAttrSetter<V> {
|
||||
|
||||
private static final ValueMapper<Integer> ORIENTATIONS = new ValueMapper<Integer>("orientation")
|
||||
.map("vertical", LinearLayout.VERTICAL)
|
||||
.map("horizontal", LinearLayout.HORIZONTAL);
|
||||
|
||||
@Override
|
||||
public boolean setAttr(V view, String attr, String value, ViewGroup parent, Map<String, String> attrs) {
|
||||
switch (attr) {
|
||||
case "baselineAligned":
|
||||
view.setBaselineAligned(Boolean.valueOf(value));
|
||||
break;
|
||||
case "baselineAlignedChildIndex":
|
||||
view.setBaselineAlignedChildIndex(Integer.valueOf(value));
|
||||
break;
|
||||
case "divider":
|
||||
view.setDividerDrawable(Drawables.parse(view, value));
|
||||
break;
|
||||
case "gravity":
|
||||
view.setGravity(Gravities.parse(value));
|
||||
break;
|
||||
case "measureWithLargestChild":
|
||||
view.setMeasureWithLargestChildEnabled(Boolean.valueOf(value));
|
||||
break;
|
||||
case "orientation":
|
||||
view.setOrientation(ORIENTATIONS.get(value));
|
||||
break;
|
||||
case "weightSum":
|
||||
view.setWeightSum(Float.valueOf(value));
|
||||
break;
|
||||
default:
|
||||
return super.setAttr(view, attr, value, parent, attrs);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
package com.stardust.autojs.core.ui.inflater.attrsetter;
|
||||
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/11/5.
|
||||
*/
|
||||
|
||||
public class MapAttrbuteSet implements AttributeSet {
|
||||
private Map<String, String> mMap;
|
||||
private ArrayList<String> mKeys;
|
||||
private ArrayList<String> mValues;
|
||||
|
||||
public MapAttrbuteSet(Map<String, String> map) {
|
||||
mMap = map;
|
||||
mKeys = new ArrayList<>(map.size());
|
||||
mValues = new ArrayList<>(map.size());
|
||||
for (Map.Entry<String, String> entry : map.entrySet()) {
|
||||
mKeys.add(entry.getKey());
|
||||
mValues.add(entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAttributeCount() {
|
||||
return mKeys.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAttributeName(int index) {
|
||||
return mKeys.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAttributeValue(int index) {
|
||||
return mValues.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAttributeValue(String namespace, String name) {
|
||||
return mMap.get(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPositionDescription() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAttributeNameResource(int index) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAttributeListValue(String namespace, String attribute, String[] options, int defaultValue) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getAttributeBooleanValue(String namespace, String attribute, boolean defaultValue) {
|
||||
String v = mMap.get(attribute);
|
||||
return v == null ? defaultValue : Boolean.valueOf(v);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAttributeResourceValue(String namespace, String attribute, int defaultValue) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAttributeIntValue(String namespace, String attribute, int defaultValue) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAttributeUnsignedIntValue(String namespace, String attribute, int defaultValue) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getAttributeFloatValue(String namespace, String attribute, float defaultValue) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAttributeListValue(int index, String[] options, int defaultValue) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getAttributeBooleanValue(int index, boolean defaultValue) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAttributeResourceValue(int index, int defaultValue) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAttributeIntValue(int index, int defaultValue) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAttributeUnsignedIntValue(int index, int defaultValue) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getAttributeFloatValue(int index, float defaultValue) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIdAttribute() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClassAttribute() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIdAttributeResourceValue(int defaultValue) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStyleAttribute() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
package com.stardust.autojs.core.ui.inflater.attrsetter;
|
||||
|
||||
import android.content.res.ColorStateList;
|
||||
import android.os.Build;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ProgressBar;
|
||||
|
||||
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.Drawables;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/11/29.
|
||||
*/
|
||||
|
||||
public class ProgressBarAttrSetter<V extends ProgressBar> extends BaseViewAttrSetter<V> {
|
||||
|
||||
@Override
|
||||
public boolean setAttr(V view, String attr, String value, ViewGroup parent, Map<String, String> attrs) {
|
||||
switch (attr) {
|
||||
case "animationResolution":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
break;
|
||||
case "indeterminate":
|
||||
view.setIndeterminate(Boolean.parseBoolean(value));
|
||||
break;
|
||||
case "indeterminateBehavior":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
break;
|
||||
case "indeterminateDrawable":
|
||||
view.setIndeterminateDrawable(Drawables.parse(view, value));
|
||||
break;
|
||||
case "indeterminateDuration":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
break;
|
||||
case "indeterminateOnly":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
break;
|
||||
case "indeterminateTint":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
view.setIndeterminateTintList(ColorStateList.valueOf(Colors.parse(view, value)));
|
||||
}
|
||||
break;
|
||||
case "indeterminateTintMode":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
view.setIndeterminateTintMode(TINT_MODES.get(value));
|
||||
}
|
||||
break;
|
||||
case "interpolato":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
break;
|
||||
case "max":
|
||||
view.setMax(Integer.parseInt(value));
|
||||
break;
|
||||
case "maxHeight":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
break;
|
||||
case "maxWidth":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
break;
|
||||
case "min":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
break;
|
||||
case "minHeigh":
|
||||
view.setMinimumHeight(Dimensions.parseToIntPixel(value, view));
|
||||
break;
|
||||
case "minWidth":
|
||||
view.setMinimumWidth(Dimensions.parseToIntPixel(value, view));
|
||||
break;
|
||||
case "mirrorForRtl":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
break;
|
||||
case "progress":
|
||||
view.setProgress(Integer.parseInt(value));
|
||||
break;
|
||||
case "progressBackgroundTint":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
view.setProgressBackgroundTintList(ColorStateList.valueOf(Colors.parse(view, value)));
|
||||
}
|
||||
break;
|
||||
case "progressBackgroundTintMode":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
view.setProgressBackgroundTintMode(TINT_MODES.get(value));
|
||||
}
|
||||
break;
|
||||
case "progressDrawable":
|
||||
view.setProgressDrawable(Drawables.parse(view, value));
|
||||
break;
|
||||
case "progressTint":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
view.setProgressTintList(ColorStateList.valueOf(Colors.parse(view, value)));
|
||||
}
|
||||
break;
|
||||
case "progressTintMode":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
view.setProgressTintMode(TINT_MODES.get(value));
|
||||
}
|
||||
break;
|
||||
case "secondaryProgress":
|
||||
view.setSecondaryProgress(Integer.parseInt(value));
|
||||
break;
|
||||
case "secondaryProgressTint":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
view.setSecondaryProgressTintList(ColorStateList.valueOf(Colors.parse(view, value)));
|
||||
}
|
||||
break;
|
||||
case "secondaryProgressTintMode":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
view.setSecondaryProgressTintMode(TINT_MODES.get(value));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return super.setAttr(view, attr, value, parent, attrs);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.stardust.autojs.core.ui.inflater.attrsetter;
|
||||
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.RadioGroup;
|
||||
|
||||
import com.stardust.autojs.core.ui.inflater.util.Ids;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/11/29.
|
||||
*/
|
||||
|
||||
public class RadioGroupAttrSetter<V extends RadioGroup> extends LinearLayoutAttrSetter<V> {
|
||||
|
||||
private Integer mCheckedButton;
|
||||
|
||||
@Override
|
||||
public boolean setAttr(V view, String attr, String value, ViewGroup parent, Map<String, String> attrs) {
|
||||
if (attr.equals("checkedButton")) {
|
||||
mCheckedButton = Ids.parse(value);
|
||||
return true;
|
||||
} else {
|
||||
return super.setAttr(view, attr, value, parent, attrs);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyPendingAttributesAboutChildren(V view) {
|
||||
if (mCheckedButton != null) {
|
||||
view.check(mCheckedButton);
|
||||
mCheckedButton = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package com.stardust.autojs.core.ui.inflater.attrsetter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.SimpleAdapter;
|
||||
import android.widget.Spinner;
|
||||
|
||||
import com.stardust.autojs.core.ui.inflater.ViewCreator;
|
||||
import com.stardust.autojs.core.ui.inflater.util.Dimensions;
|
||||
import com.stardust.autojs.core.ui.inflater.util.Drawables;
|
||||
import com.stardust.autojs.core.ui.inflater.util.Strings;
|
||||
import com.stardust.autojs.core.ui.inflater.util.ValueMapper;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/11/29.
|
||||
*/
|
||||
|
||||
public class SpinnerAttrSetter extends BaseViewAttrSetter<Spinner> {
|
||||
|
||||
protected static final ValueMapper<Integer> SPINNER_MODES = new ValueMapper<Integer>("spinnerMode")
|
||||
.map("dialog", Spinner.MODE_DIALOG)
|
||||
.map("dropdown", Spinner.MODE_DROPDOWN);
|
||||
|
||||
@Override
|
||||
public boolean setAttr(Spinner view, String attr, String value, ViewGroup parent, Map<String, String> attrs) {
|
||||
switch (attr) {
|
||||
case "dropDownHorizontalOffset":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
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));
|
||||
}
|
||||
break;
|
||||
case "dropDownWidth":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
view.setDropDownWidth(Dimensions.parseToIntPixel(value, view));
|
||||
}
|
||||
break;
|
||||
case "popupBackground":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
view.setPopupBackgroundDrawable(Drawables.parse(view, value));
|
||||
}
|
||||
break;
|
||||
case "prompt":
|
||||
view.setPrompt(Strings.parse(view, value));
|
||||
break;
|
||||
case "entries":
|
||||
view.setAdapter(new ArrayAdapter<>(view.getContext(),
|
||||
android.R.layout.simple_spinner_dropdown_item, value.split("[|]")));
|
||||
break;
|
||||
default:
|
||||
return super.setAttr(view, attr, value, parent, attrs);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ViewCreator<Spinner> getCreator() {
|
||||
return new ViewCreator<Spinner>() {
|
||||
@Override
|
||||
public Spinner create(Context context, Map<String, String> attrs) {
|
||||
String mode = attrs.remove("android:spinnerMode");
|
||||
if (mode == null) {
|
||||
return new Spinner(context);
|
||||
}
|
||||
return new Spinner(context, SPINNER_MODES.get(mode));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static class EntryAdapter extends SimpleAdapter {
|
||||
|
||||
public EntryAdapter(Context context, List<? extends Map<String, ?>> data, int resource, String[] from, int[] to) {
|
||||
super(context, data, resource, from, to);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,420 @@
|
||||
package com.stardust.autojs.core.ui.inflater.attrsetter;
|
||||
|
||||
import android.graphics.Typeface;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.text.InputFilter;
|
||||
import android.text.InputType;
|
||||
import android.text.TextUtils;
|
||||
import android.text.method.DigitsKeyListener;
|
||||
import android.text.method.TextKeyListener;
|
||||
import android.text.util.Linkify;
|
||||
import android.util.TypedValue;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.inputmethod.EditorInfo;
|
||||
import android.widget.TextView;
|
||||
|
||||
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.Drawables;
|
||||
import com.stardust.autojs.core.ui.inflater.util.Gravities;
|
||||
import com.stardust.autojs.core.ui.inflater.util.Res;
|
||||
import com.stardust.autojs.core.ui.inflater.util.Strings;
|
||||
import com.stardust.autojs.core.ui.inflater.util.ValueMapper;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/11/3.
|
||||
*/
|
||||
|
||||
public class TextViewAttrSetter<V extends TextView> extends BaseViewAttrSetter<V> {
|
||||
|
||||
private static final ValueMapper<Integer> AUTO_LINK_MASKS = new ValueMapper<Integer>("autoLink")
|
||||
.map("all", Linkify.ALL)
|
||||
.map("email", Linkify.EMAIL_ADDRESSES)
|
||||
.map("map", Linkify.MAP_ADDRESSES)
|
||||
.map("none", 0)
|
||||
.map("phone", Linkify.PHONE_NUMBERS)
|
||||
.map("web", Linkify.WEB_URLS);
|
||||
private static final ValueMapper<TextUtils.TruncateAt> ELLIPSIZE = new ValueMapper<TextUtils.TruncateAt>("ellipsize")
|
||||
.map("end", TextUtils.TruncateAt.END)
|
||||
.map("marquee", TextUtils.TruncateAt.MIDDLE)
|
||||
.map("none", null)
|
||||
.map("start", TextUtils.TruncateAt.START)
|
||||
.map("middle", TextUtils.TruncateAt.MIDDLE);
|
||||
private static final ValueMapper<Integer> HYPHENATION_FREQUENCY = new ValueMapper<Integer>("hyphenationFrequency")
|
||||
.map("full", 2)
|
||||
.map("none", 0)
|
||||
.map("normal", 1);
|
||||
|
||||
// TODO: 2017/11/4 IME FLAG
|
||||
private static final ValueMapper<Integer> IME_OPTIONS = new ValueMapper<Integer>("imeOptions")
|
||||
.map("actionDone", EditorInfo.IME_ACTION_DONE)
|
||||
.map("actionGo", EditorInfo.IME_ACTION_DONE)
|
||||
.map("actionNext", EditorInfo.IME_ACTION_DONE)
|
||||
.map("actionNone", EditorInfo.IME_ACTION_DONE)
|
||||
.map("actionPrevious", EditorInfo.IME_ACTION_DONE)
|
||||
.map("actionSearch", EditorInfo.IME_ACTION_DONE)
|
||||
.map("actionSend", EditorInfo.IME_ACTION_DONE)
|
||||
.map("actionUnspecified", EditorInfo.IME_ACTION_DONE);
|
||||
|
||||
private static final ValueMapper<Integer> INPUT_TYPES = new ValueMapper<Integer>("inputType")
|
||||
.map("date", 0x14)
|
||||
.map("datetime", 0x4)
|
||||
.map("none", 0x0)
|
||||
.map("number", 0x2)
|
||||
.map("numberDecimal", 0x2002)
|
||||
.map("numberPassword", 0x12)
|
||||
.map("numberSigned", 0x1002)
|
||||
.map("phone", 0x3)
|
||||
.map("text", 0x1)
|
||||
.map("textAutoComplete", 0x10001)
|
||||
.map("textAutoCorrect", 0x8001)
|
||||
.map("textCapCharacters", 0x1001)
|
||||
.map("textCapSentences", 0x4001)
|
||||
.map("textCapWords", 0x2001)
|
||||
.map("textEmailAddress", 0x21)
|
||||
.map("textEmailSubject", 0x31)
|
||||
.map("textFilter", 0xb1)
|
||||
.map("textImeMultiLine", 0x40001)
|
||||
.map("textLongMessage", 0x51)
|
||||
.map("textMultiLine", 0x20001)
|
||||
.map("textNoSuggestions", 0x80001)
|
||||
.map("textPassword", 0x81)
|
||||
.map("textPersonName", 0x61)
|
||||
.map("textPhonetic", 0xc1)
|
||||
.map("textPostalAddress", 0x71)
|
||||
.map("textShortMessage", 0x41)
|
||||
.map("textUri", 0x11)
|
||||
.map("textVisiblePassword", 0x91)
|
||||
.map("textWebEditText", 0xa1)
|
||||
.map("textWebEmailAddress", 0xd1)
|
||||
.map("textWebPassword", 0xe1)
|
||||
.map("time", 0x24);
|
||||
|
||||
private static final ValueMapper<Integer> INPUT_TYPE_NUMERIC = new ValueMapper<Integer>("numeric")
|
||||
.map("decimal", InputType.TYPE_NUMBER_FLAG_DECIMAL)
|
||||
.map("number", InputType.TYPE_CLASS_NUMBER)
|
||||
.map("signed", InputType.TYPE_NUMBER_FLAG_SIGNED);
|
||||
|
||||
private static final ValueMapper<Integer> TEXT_STYLES = new ValueMapper<Integer>("textStyle")
|
||||
.map("bold", Typeface.BOLD)
|
||||
.map("italic", Typeface.ITALIC)
|
||||
.map("normal", Typeface.NORMAL);
|
||||
|
||||
private static final ValueMapper<TextKeyListener.Capitalize> CAPITALIZE = new ValueMapper<TextKeyListener.Capitalize>("capitalize")
|
||||
.map("characters", TextKeyListener.Capitalize.CHARACTERS)
|
||||
.map("none", TextKeyListener.Capitalize.NONE)
|
||||
.map("sentences", TextKeyListener.Capitalize.SENTENCES)
|
||||
.map("words", TextKeyListener.Capitalize.WORDS);
|
||||
|
||||
|
||||
private boolean mAutoText;
|
||||
private TextKeyListener.Capitalize mCapitalize;
|
||||
private Drawable mDrawableBottom;
|
||||
private Drawable mDrawableRight;
|
||||
private Drawable mDrawableTop;
|
||||
private Drawable mDrawableLeft;
|
||||
private Integer mLineSpacingExtra;
|
||||
private Integer mLineSpacingMultiplier;
|
||||
private String mFontFamily;
|
||||
private Integer mTextStyle;
|
||||
private String mTypeface;
|
||||
|
||||
@Override
|
||||
public boolean setAttr(V view, String attrName, String value, ViewGroup parent, Map<String, String> attrs) {
|
||||
if (super.setAttr(view, attrName, value, parent, attrs)) {
|
||||
return true;
|
||||
}
|
||||
switch (attrName) {
|
||||
case "autoLink":
|
||||
view.setAutoLinkMask(AUTO_LINK_MASKS.get(value));
|
||||
break;
|
||||
case "autoText":
|
||||
mAutoText = Boolean.valueOf(value);
|
||||
break;
|
||||
case "capitalize":
|
||||
mCapitalize = CAPITALIZE.get(value);
|
||||
break;
|
||||
case "cursorVisible":
|
||||
view.setCursorVisible(Boolean.valueOf(value));
|
||||
break;
|
||||
case "digit":
|
||||
if (value.equals("true")) {
|
||||
view.setKeyListener(DigitsKeyListener.getInstance());
|
||||
} else if (!value.equals("false")) {
|
||||
view.setKeyListener(DigitsKeyListener.getInstance(value));
|
||||
}
|
||||
break;
|
||||
case "drawableBottom":
|
||||
mDrawableBottom = Drawables.parse(view, value);
|
||||
break;
|
||||
case "drawableTop":
|
||||
mDrawableTop = Drawables.parse(view, value);
|
||||
break;
|
||||
case "drawableLeft":
|
||||
mDrawableLeft = Drawables.parse(view, value);
|
||||
break;
|
||||
case "drawableRight":
|
||||
mDrawableRight = Drawables.parse(view, value);
|
||||
break;
|
||||
case "drawablePadding":
|
||||
view.setCompoundDrawablePadding(Dimensions.parseToIntPixel(value, view));
|
||||
break;
|
||||
case "drawableStart":
|
||||
case "drawableEnd":
|
||||
case "editable":
|
||||
case "editorExtras":
|
||||
Exceptions.unsupports(view, attrName, value);
|
||||
case "elegantTextHeight":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
view.setElegantTextHeight(Boolean.valueOf(value));
|
||||
}
|
||||
break;
|
||||
case "ellipsize":
|
||||
TextUtils.TruncateAt e = ELLIPSIZE.get(value);
|
||||
if (e != null) {
|
||||
view.setEllipsize(e);
|
||||
}
|
||||
break;
|
||||
case "ems":
|
||||
view.setEms(Integer.valueOf(value));
|
||||
break;
|
||||
case "fontFamily":
|
||||
mFontFamily = value;
|
||||
break;
|
||||
case "fontFeatureSettings":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
view.setFontFeatureSettings(value);
|
||||
}
|
||||
break;
|
||||
case "freezesText":
|
||||
view.setFreezesText(Boolean.valueOf(value));
|
||||
break;
|
||||
case "gravity":
|
||||
view.setGravity(Gravities.parse(value));
|
||||
break;
|
||||
case "hint":
|
||||
view.setHint(Strings.parse(view, value));
|
||||
break;
|
||||
case "hyphenationFrequency":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
view.setHyphenationFrequency(HYPHENATION_FREQUENCY.get(value));
|
||||
}
|
||||
break;
|
||||
case "imeActionId":
|
||||
view.setImeActionLabel(view.getImeActionLabel(), Integer.valueOf(value));
|
||||
break;
|
||||
case "imeActionLabel":
|
||||
view.setImeActionLabel(value, view.getImeActionId());
|
||||
break;
|
||||
case "imeOptions":
|
||||
view.setImeOptions(IME_OPTIONS.split(value));
|
||||
break;
|
||||
case "includeFontPadding":
|
||||
view.setIncludeFontPadding(Boolean.valueOf(value));
|
||||
break;
|
||||
case "inputMethod":
|
||||
Exceptions.unsupports(view, attrName, value);
|
||||
case "inputType":
|
||||
view.setInputType(INPUT_TYPES.split(value));
|
||||
break;
|
||||
case "letterSpacing":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
view.setLetterSpacing(Float.valueOf(value));
|
||||
}
|
||||
break;
|
||||
case "lineSpacingExtra":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
view.setLineSpacing(Dimensions.parseToIntPixel(value, view), view.getLineSpacingMultiplier());
|
||||
} else {
|
||||
mLineSpacingExtra = Dimensions.parseToIntPixel(value, view);
|
||||
}
|
||||
break;
|
||||
case "lineSpacingMultiplier":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
view.setLineSpacing(view.getLineSpacingExtra(), Dimensions.parseToIntPixel(value, view));
|
||||
} else {
|
||||
mLineSpacingMultiplier = Dimensions.parseToIntPixel(value, view);
|
||||
}
|
||||
break;
|
||||
case "lines":
|
||||
view.setLines(Integer.valueOf(value));
|
||||
break;
|
||||
case "linksClickable":
|
||||
view.setLinksClickable(Boolean.valueOf(value));
|
||||
break;
|
||||
case "marqueeRepeatLimit":
|
||||
view.setMarqueeRepeatLimit(value.equals("marquee_forever") ? Integer.MAX_VALUE : Integer.valueOf(value));
|
||||
break;
|
||||
case "maxEms":
|
||||
view.setMaxEms(Integer.valueOf(value));
|
||||
break;
|
||||
case "maxHeight":
|
||||
view.setMaxHeight(Integer.valueOf(value));
|
||||
break;
|
||||
case "maxLength":
|
||||
view.setFilters(new InputFilter[]{new InputFilter.LengthFilter(Integer.valueOf(value))});
|
||||
break;
|
||||
case "maxLines":
|
||||
view.setMaxLines(Integer.valueOf(value));
|
||||
break;
|
||||
case "maxWidth":
|
||||
view.setMaxWidth(Integer.valueOf(value));
|
||||
break;
|
||||
case "minEms":
|
||||
view.setMinEms(Integer.valueOf(value));
|
||||
break;
|
||||
case "minHeight":
|
||||
view.setMinHeight(Dimensions.parseToIntPixel(value, view));
|
||||
break;
|
||||
case "minLines":
|
||||
view.setMinLines(Integer.valueOf(value));
|
||||
break;
|
||||
case "minWidth":
|
||||
view.setMinWidth(Dimensions.parseToIntPixel(value, view));
|
||||
break;
|
||||
case "numeric":
|
||||
view.setInputType(INPUT_TYPE_NUMERIC.split(value) | InputType.TYPE_CLASS_NUMBER);
|
||||
break;
|
||||
case "password":
|
||||
if (value.equals("true")) {
|
||||
view.setInputType(view.getInputType() | InputType.TYPE_TEXT_VARIATION_PASSWORD);
|
||||
}
|
||||
break;
|
||||
case "phoneNumber":
|
||||
if (value.equals("true")) {
|
||||
view.setInputType(view.getInputType() | InputType.TYPE_TEXT_VARIATION_PHONETIC);
|
||||
}
|
||||
break;
|
||||
case "privateImeOptions":
|
||||
view.setPrivateImeOptions(Strings.parse(view, value));
|
||||
break;
|
||||
case "scrollHorizontally":
|
||||
view.setHorizontallyScrolling(Boolean.valueOf(value));
|
||||
break;
|
||||
case "selectAllOnFocus":
|
||||
view.setSelectAllOnFocus(Boolean.valueOf(value));
|
||||
break;
|
||||
case "shadowColor":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
view.setShadowLayer(view.getShadowRadius(), view.getShadowDx(), view.getShadowDy(), Colors.parse(view, value));
|
||||
}
|
||||
break;
|
||||
case "shadowDx":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
view.setShadowLayer(view.getShadowRadius(), Dimensions.parseToPixel(value, view), view.getShadowDy(), view.getShadowColor());
|
||||
}
|
||||
break;
|
||||
case "shadowDy":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
view.setShadowLayer(view.getShadowRadius(), view.getShadowDx(), Dimensions.parseToPixel(value, view), view.getShadowColor());
|
||||
}
|
||||
break;
|
||||
case "shadowRadius":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
view.setShadowLayer(Dimensions.parseToPixel(value, view), view.getShadowDx(), view.getShadowDy(), view.getShadowColor());
|
||||
}
|
||||
break;
|
||||
case "singleLine":
|
||||
view.setSingleLine(Boolean.valueOf(value));
|
||||
break;
|
||||
case "textAllCaps":
|
||||
view.setAllCaps(Boolean.valueOf(value));
|
||||
break;
|
||||
case "textAppearance":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
view.setTextAppearance(Res.parseStyle(view, value));
|
||||
}
|
||||
break;
|
||||
case "textColorHighlight":
|
||||
view.setHighlightColor(Colors.parse(view, value));
|
||||
break;
|
||||
case "textColorHint":
|
||||
view.setHintTextColor(Colors.parse(view, value));
|
||||
break;
|
||||
case "textColorLink":
|
||||
view.setLinkTextColor(Colors.parse(view, value));
|
||||
break;
|
||||
case "textIsSelectable":
|
||||
view.setTextIsSelectable(Boolean.valueOf(value));
|
||||
break;
|
||||
case "textScaleX":
|
||||
view.setTextScaleX(Dimensions.parseToPixel(value, view));
|
||||
break;
|
||||
case "textStyle":
|
||||
mTextStyle = TEXT_STYLES.get(value);
|
||||
break;
|
||||
case "typeface":
|
||||
mTypeface = value;
|
||||
break;
|
||||
case "text":
|
||||
view.setText(Strings.parse(view, value));
|
||||
break;
|
||||
case "textColor":
|
||||
view.setTextColor(Colors.parse(view.getContext(), value));
|
||||
break;
|
||||
case "textSize":
|
||||
view.setTextSize(TypedValue.COMPLEX_UNIT_PX, Dimensions.parseToPixel(value, view));
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyPendingAttributes(V view, ViewGroup parent) {
|
||||
setTypeface(view);
|
||||
setLineSpacing(view);
|
||||
setDrawables(view);
|
||||
setKeyListener(view);
|
||||
}
|
||||
|
||||
private void setKeyListener(V view) {
|
||||
if (mCapitalize != null) {
|
||||
view.setKeyListener(TextKeyListener.getInstance(mAutoText, mCapitalize));
|
||||
}
|
||||
mCapitalize = null;
|
||||
mAutoText = false;
|
||||
}
|
||||
|
||||
private void setDrawables(V view) {
|
||||
Drawable[] drawables = view.getCompoundDrawables();
|
||||
view.setCompoundDrawables(
|
||||
mDrawableLeft != null ? mDrawableLeft : drawables[0],
|
||||
mDrawableTop != null ? mDrawableTop : drawables[1],
|
||||
mDrawableRight != null ? mDrawableRight : drawables[2],
|
||||
mDrawableBottom != null ? mDrawableBottom : drawables[3]
|
||||
);
|
||||
mDrawableLeft = mDrawableBottom = mDrawableRight = mDrawableTop = null;
|
||||
}
|
||||
|
||||
private void setLineSpacing(V view) {
|
||||
if (mLineSpacingExtra != null) {
|
||||
view.setLineSpacing(mLineSpacingExtra, mLineSpacingMultiplier == null ? 1 : mLineSpacingMultiplier);
|
||||
} else if (mLineSpacingMultiplier != null) {
|
||||
view.setLineSpacing(0, mLineSpacingMultiplier);
|
||||
}
|
||||
mLineSpacingMultiplier = mLineSpacingExtra = null;
|
||||
}
|
||||
|
||||
private void setTypeface(V view) {
|
||||
if (mFontFamily != null) {
|
||||
//ignore typeface as android does
|
||||
mTypeface = mFontFamily;
|
||||
}
|
||||
if (mTypeface != null) {
|
||||
if (mTextStyle != null) {
|
||||
view.setTypeface(Typeface.create(mTypeface, mTextStyle));
|
||||
} else {
|
||||
view.setTypeface(Typeface.create(mTypeface, view.getTypeface().getStyle()));
|
||||
}
|
||||
} else if (mTextStyle != null) {
|
||||
view.setTypeface(view.getTypeface(), mTextStyle);
|
||||
}
|
||||
mTypeface = mFontFamily = null;
|
||||
mTextStyle = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.stardust.autojs.core.ui.inflater.attrsetter;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
import android.view.View;
|
||||
import android.widget.TimePicker;
|
||||
|
||||
import com.stardust.autojs.R;
|
||||
import com.stardust.autojs.core.ui.inflater.ViewCreator;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/11/29.
|
||||
*/
|
||||
|
||||
public class TimePickerAttrSetter extends BaseViewAttrSetter<TimePicker> {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ViewCreator<TimePicker> getCreator() {
|
||||
return (context, attrs) -> {
|
||||
String datePickerMode = attrs.remove("android:timePickerMode");
|
||||
if (datePickerMode == null || !datePickerMode.equals("spinner")) {
|
||||
return new TimePicker(context);
|
||||
}
|
||||
return (TimePicker) View.inflate(context, R.layout.time_picker_spinner, null);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.stardust.autojs.core.ui.inflater.attrsetter;
|
||||
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.stardust.autojs.core.ui.inflater.util.Strings;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/11/5.
|
||||
*/
|
||||
|
||||
public class ToolbarAttrSetter<V extends Toolbar> extends BaseViewAttrSetter<V> {
|
||||
|
||||
|
||||
@Override
|
||||
public boolean setAttr(V view, String attr, String value, ViewGroup parent, Map<String, String> attrs) {
|
||||
return super.setAttr(view, attr, value, parent, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setAttr(V view, String ns, String attrName, String value, ViewGroup parent, Map<String, String> attrs) {
|
||||
if (super.setAttr(view, ns, attrName, value, parent, attrs)) {
|
||||
return true;
|
||||
}
|
||||
if (!ns.equals("app")) {
|
||||
return false;
|
||||
}
|
||||
switch (attrName) {
|
||||
case "title":
|
||||
view.setTitle(Strings.parse(view, value));
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package com.stardust.autojs.core.ui.inflater.attrsetter;
|
||||
|
||||
import android.animation.LayoutTransition;
|
||||
import android.os.Build;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.stardust.autojs.core.ui.inflater.util.ValueMapper;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/11/4.
|
||||
*/
|
||||
|
||||
public class ViewGroupAttrSetter<V extends ViewGroup> extends BaseViewAttrSetter<V> {
|
||||
|
||||
private static final ValueMapper<Integer> PERSISTENT_DRAWING_CACHE = new ValueMapper<Integer>("persistentDrawingCache")
|
||||
.map("all", ViewGroup.PERSISTENT_ALL_CACHES)
|
||||
.map("animation", ViewGroup.PERSISTENT_ANIMATION_CACHE)
|
||||
.map("none", 0)
|
||||
.map("scrolling", ViewGroup.PERSISTENT_SCROLLING_CACHE);
|
||||
|
||||
private static final ValueMapper<Integer> LAYOUT_MODES = new ValueMapper<Integer>("layoutMode")
|
||||
.map("clipBounds", 0) //ViewGroup.LAYOUT_MODE_CLIP_BOUNDS)
|
||||
.map("opticalBounds", 1); //ViewGroup.LAYOUT_MODE_OPTICAL_BOUNDS);
|
||||
|
||||
private static final ValueMapper<Integer> DESCENDANT_FOCUSABILITY = new ValueMapper<Integer>("descendantFocusability")
|
||||
.map("afterDescendants", ViewGroup.FOCUS_AFTER_DESCENDANTS)
|
||||
.map("beforeDescendants", ViewGroup.FOCUS_BEFORE_DESCENDANTS)
|
||||
.map("blocksDescendants", ViewGroup.FOCUS_BLOCK_DESCENDANTS);
|
||||
|
||||
|
||||
@Override
|
||||
public boolean setAttr(V view, String attr, String value, ViewGroup parent, Map<String, String> attrs) {
|
||||
switch (attr) {
|
||||
case "addStatesFromChildren":
|
||||
view.setAddStatesFromChildren(Boolean.valueOf(value));
|
||||
break;
|
||||
case "alwaysDrawnWithCache":
|
||||
view.setAlwaysDrawnWithCacheEnabled(Boolean.valueOf(value));
|
||||
break;
|
||||
case "animateLayoutChanges":
|
||||
view.setLayoutTransition(new LayoutTransition());
|
||||
break;
|
||||
case "animationCache":
|
||||
view.setAnimationCacheEnabled(Boolean.valueOf(value));
|
||||
break;
|
||||
case "clipChildren":
|
||||
view.setClipChildren(Boolean.valueOf(value));
|
||||
break;
|
||||
case "clipToPadding":
|
||||
view.setClipToPadding(Boolean.valueOf(value));
|
||||
break;
|
||||
case "descendantFocusability":
|
||||
view.setDescendantFocusability(DESCENDANT_FOCUSABILITY.get(value));
|
||||
break;
|
||||
case "layoutAnimation":
|
||||
Exceptions.unsupports(view, attr, value);
|
||||
break;
|
||||
case "layoutMode":
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
||||
view.setLayoutMode(LAYOUT_MODES.get(value));
|
||||
}
|
||||
break;
|
||||
case "persistentDrawingCache":
|
||||
view.setPersistentDrawingCache(PERSISTENT_DRAWING_CACHE.get(value));
|
||||
break;
|
||||
case "splitMotionEvents":
|
||||
view.setMotionEventSplittingEnabled(Boolean.valueOf(value));
|
||||
break;
|
||||
default:
|
||||
return super.setAttr(view, attr, value, parent, attrs);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void applyPendingAttributesAboutChildren(V view) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.stardust.autojs.core.ui.inflater.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Color;
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/11/3.
|
||||
*/
|
||||
|
||||
public class Colors {
|
||||
|
||||
public static int parse(Context context, String color) {
|
||||
Resources resources = context.getResources();
|
||||
if (color.startsWith("@color/")) {
|
||||
return resources.getColor(resources.getIdentifier(color.substring("@color/".length()), "color", context.getPackageName()));
|
||||
}
|
||||
if (color.startsWith("@android:color/")) {
|
||||
return Color.parseColor(color.substring(15));
|
||||
}
|
||||
return Color.parseColor(color);
|
||||
}
|
||||
|
||||
public static int parse(View view, String color){
|
||||
return parse(view.getContext(), color);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.stardust.autojs.core.ui.inflater.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.TypedValue;
|
||||
import android.view.InflateException;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Created by nick on 8/10/15.
|
||||
* <p>
|
||||
* Taken from http://stackoverflow.com/questions/8343971/how-to-parse-a-dimension-string-and-convert-it-to-a-dimension-value
|
||||
*/
|
||||
public class Dimensions {
|
||||
|
||||
private static final ValueMapper<Integer> UNITS = new ValueMapper<Integer>("unit")
|
||||
.map("px", TypedValue.COMPLEX_UNIT_PX)
|
||||
.map("dip", TypedValue.COMPLEX_UNIT_DIP)
|
||||
.map("dp", TypedValue.COMPLEX_UNIT_DIP)
|
||||
.map("sp", TypedValue.COMPLEX_UNIT_SP)
|
||||
.map("pt", TypedValue.COMPLEX_UNIT_PT)
|
||||
.map("in", TypedValue.COMPLEX_UNIT_IN)
|
||||
.map("mm", TypedValue.COMPLEX_UNIT_MM);
|
||||
|
||||
|
||||
private static final Pattern DIMENSION_PATTERN = Pattern.compile("([+-]?[0-9.]+)([a-zA-Z]*)");
|
||||
|
||||
public static int parseToPixel(String dimension, DisplayMetrics metrics, ViewGroup parent, boolean horizontal) {
|
||||
if (dimension.endsWith("%")) {
|
||||
float pct = Float.parseFloat(dimension.substring(0, dimension.length() - 1)) / 100.0f;
|
||||
return (int) (pct * (horizontal ? parent.getMeasuredWidth() : parent.getMeasuredHeight()));
|
||||
}
|
||||
return parseToIntPixel(dimension, parent.getContext());
|
||||
}
|
||||
|
||||
public static float parseToPixel(String dimension, View view) {
|
||||
return parseToPixel(dimension, view.getContext());
|
||||
}
|
||||
|
||||
public static float parseToPixel(String dimension, Context context) {
|
||||
if (dimension.startsWith("?")) {
|
||||
int[] attr = {context.getResources().getIdentifier(dimension.substring(1), "attr",
|
||||
context.getPackageName())};
|
||||
TypedArray ta = context.obtainStyledAttributes(attr);
|
||||
float d = ta.getDimension(0, 0);
|
||||
ta.recycle();
|
||||
return d;
|
||||
}
|
||||
Matcher m = DIMENSION_PATTERN.matcher(dimension);
|
||||
if (!m.matches()) {
|
||||
throw new InflateException("dimension cannot be resolved: " + dimension);
|
||||
}
|
||||
int unit = m.groupCount() == 2 ? UNITS.get(m.group(2)) : TypedValue.COMPLEX_UNIT_PX;
|
||||
float value = Integer.valueOf(m.group(1));
|
||||
return TypedValue.applyDimension(unit, value, context.getResources().getDisplayMetrics());
|
||||
}
|
||||
|
||||
public static int parseToIntPixel(String value, View view) {
|
||||
return Math.round(parseToPixel(value, view));
|
||||
}
|
||||
|
||||
public static int parseToIntPixel(String value, Context context) {
|
||||
return Math.round(parseToPixel(value, context));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
package com.stardust.autojs.core.ui.inflater.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.util.Base64;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import com.stardust.autojs.core.ui.inflater.ImageLoader;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/11/3.
|
||||
*/
|
||||
|
||||
public class Drawables {
|
||||
|
||||
private static final Pattern DATA_PATTERN = Pattern.compile("data:(\\w+/\\w+);base64,(.+)");
|
||||
private static ImageLoader sImageLoader = new ImageLoader() {
|
||||
@Override
|
||||
public void loadInto(final ImageView view, Uri uri) {
|
||||
load(view, uri, view::setImageDrawable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadIntoBackground(final View view, Uri uri) {
|
||||
load(view, uri, view::setBackground);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Drawable load(View view, Uri uri) {
|
||||
try {
|
||||
URL url = new URL(uri.toString());
|
||||
Bitmap bmp = BitmapFactory.decodeStream(url.openConnection().getInputStream());
|
||||
return new BitmapDrawable(view.getResources(), bmp);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(View view, Uri uri, final DrawableCallback callback) {
|
||||
load(view, uri, (BitmapCallback) bitmap -> callback.onLoaded(new BitmapDrawable(view.getResources(), bitmap)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(final View view, final Uri uri, final BitmapCallback callback) {
|
||||
new Thread(() -> {
|
||||
try {
|
||||
URL url = new URL(uri.toString());
|
||||
final Bitmap bmp = BitmapFactory.decodeStream(url.openConnection().getInputStream());
|
||||
view.post(() -> callback.onLoaded(bmp));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
};
|
||||
|
||||
public static Drawable parse(Context context, String value) {
|
||||
Resources resources = context.getResources();
|
||||
if (value.startsWith("@color/") || value.startsWith("@android:color/") || value.startsWith("#")) {
|
||||
return new ColorDrawable(Colors.parse(context, value));
|
||||
}
|
||||
if (value.startsWith("?")) {
|
||||
int[] attr = {resources.getIdentifier(value.substring(1), "attr",
|
||||
context.getPackageName())};
|
||||
TypedArray ta = context.obtainStyledAttributes(attr);
|
||||
Drawable drawable = ta.getDrawable(0 /* index */);
|
||||
ta.recycle();
|
||||
return drawable;
|
||||
}
|
||||
if (value.startsWith("file://")) {
|
||||
return decodeImage(value.substring(7));
|
||||
}
|
||||
return resources.getDrawable(resources.getIdentifier(value, "drawable",
|
||||
context.getPackageName()));
|
||||
}
|
||||
|
||||
private static Drawable decodeImage(String path) {
|
||||
return new BitmapDrawable(BitmapFactory.decodeFile(path));
|
||||
}
|
||||
|
||||
public static Drawable parse(View view, String name) {
|
||||
return parse(view.getContext(), name);
|
||||
}
|
||||
|
||||
public static void loadInto(ImageView view, Uri uri) {
|
||||
sImageLoader.loadInto(view, uri);
|
||||
}
|
||||
|
||||
public static void loadIntoBackground(View view, Uri uri) {
|
||||
sImageLoader.loadIntoBackground(view, uri);
|
||||
}
|
||||
|
||||
public static <V extends ImageView> void setupWithImage(V view, String value) {
|
||||
if (value.startsWith("http://") || value.startsWith("https://")) {
|
||||
loadInto(view, Uri.parse(value));
|
||||
} else if(value.startsWith("data:")) {
|
||||
loadDataInto(view, value);
|
||||
}else {
|
||||
view.setImageDrawable(com.stardust.autojs.core.ui.inflater.util.Drawables.parse(view, value));
|
||||
}
|
||||
}
|
||||
|
||||
private static void loadDataInto(ImageView view, String data) {
|
||||
Bitmap bitmap = loadData(data);
|
||||
view.setImageBitmap(bitmap);
|
||||
}
|
||||
|
||||
public static Bitmap loadData(String data){
|
||||
Matcher matcher = DATA_PATTERN.matcher(data);
|
||||
if(!matcher.matches() || matcher.groupCount() != 2){
|
||||
return null;
|
||||
}
|
||||
String mimeType = matcher.group(1);
|
||||
String base64 = matcher.group(2);
|
||||
byte[] bytes = Base64.decode(base64, Base64.DEFAULT);
|
||||
return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
|
||||
}
|
||||
|
||||
public static void setupWithViewBackground(View view, String value) {
|
||||
if (value.startsWith("http://") || value.startsWith("https://")) {
|
||||
loadIntoBackground(view, Uri.parse(value));
|
||||
} else {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
|
||||
view.setBackground(com.stardust.autojs.core.ui.inflater.util.Drawables.parse(view, value));
|
||||
} else {
|
||||
view.setBackgroundDrawable(com.stardust.autojs.core.ui.inflater.util.Drawables.parse(view, value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void setImageLoader(ImageLoader imageLoader) {
|
||||
sImageLoader = imageLoader;
|
||||
}
|
||||
|
||||
public static ImageLoader getImageLoader() {
|
||||
return sImageLoader;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.stardust.autojs.core.ui.inflater.util;
|
||||
|
||||
import android.view.Gravity;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/11/3.
|
||||
*/
|
||||
|
||||
public class Gravities {
|
||||
|
||||
public static int parse(String g) {
|
||||
int gravity = Gravity.NO_GRAVITY;
|
||||
String[] parts = g.toLowerCase().split("[|]");
|
||||
for (String part : parts) {
|
||||
switch (part) {
|
||||
case "center":
|
||||
gravity = gravity | Gravity.CENTER;
|
||||
break;
|
||||
case "left":
|
||||
case "textStart":
|
||||
gravity = gravity | Gravity.LEFT;
|
||||
break;
|
||||
case "right":
|
||||
case "textEnd":
|
||||
gravity = gravity | Gravity.RIGHT;
|
||||
break;
|
||||
case "top":
|
||||
gravity = gravity | Gravity.TOP;
|
||||
break;
|
||||
case "bottom":
|
||||
gravity = gravity | Gravity.BOTTOM;
|
||||
break;
|
||||
case "center_horizontal":
|
||||
gravity = gravity | Gravity.CENTER_HORIZONTAL;
|
||||
break;
|
||||
case "center_vertical":
|
||||
gravity = gravity | Gravity.CENTER_VERTICAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return gravity;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.stardust.autojs.core.ui.inflater.util;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/11/3.
|
||||
*/
|
||||
|
||||
public class Ids {
|
||||
|
||||
private static AtomicInteger maxId = new AtomicInteger(20161209);
|
||||
private static HashMap<String, Integer> ids = new HashMap<>();
|
||||
|
||||
public static String parseIdName(String idName) {
|
||||
if (idName.startsWith("@+id/")) {
|
||||
return idName.substring(5);
|
||||
} else if (idName.startsWith("@id/")) {
|
||||
return idName.substring(4);
|
||||
}
|
||||
return idName;
|
||||
}
|
||||
|
||||
public static int parse(String name) {
|
||||
name = parseIdName(name);
|
||||
Integer id = ids.get(name);
|
||||
if (id == null) {
|
||||
id = maxId.incrementAndGet();
|
||||
ids.put(name, id);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.stardust.autojs.core.ui.inflater.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/11/5.
|
||||
*/
|
||||
|
||||
public class Res {
|
||||
public static int parseStyle(View view, String value) {
|
||||
return parseStyle(view.getContext(), value);
|
||||
}
|
||||
|
||||
public static int parseStyle(Context context, String value) {
|
||||
// FIXME: 2017/11/5 Can or should it retrieve android.R.style or styleable?
|
||||
if (value.startsWith("@style/")) {
|
||||
value = value.substring(7);
|
||||
}
|
||||
return context.getResources().getIdentifier(value, "style", context.getPackageName());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.stardust.autojs.core.ui.inflater.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/11/4.
|
||||
*/
|
||||
|
||||
public class Strings {
|
||||
|
||||
|
||||
public static String parse(Context context, String str) {
|
||||
if (str.startsWith("@string/")) {
|
||||
Resources resources = context.getResources();
|
||||
return resources.getString(resources.getIdentifier(str, "string",
|
||||
context.getPackageName()));
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
public static String parse(View view, String str) {
|
||||
return parse(view.getContext(), str);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.stardust.autojs.core.ui.inflater.util;
|
||||
|
||||
import android.view.InflateException;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/11/3.
|
||||
*/
|
||||
|
||||
public class ValueMapper<V> {
|
||||
|
||||
private HashMap<String, V> mHashMap = new HashMap<>();
|
||||
private String mAttrName;
|
||||
|
||||
public ValueMapper(String attrName) {
|
||||
mAttrName = attrName;
|
||||
}
|
||||
|
||||
public ValueMapper<V> map(String key, V value) {
|
||||
mHashMap.put(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public V get(String key) {
|
||||
V v = mHashMap.get(key);
|
||||
if (v == null) {
|
||||
throw new InflateException(String.format("unknown value for %s: %s", mAttrName, key));
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
public int split(String str){
|
||||
int r = 0;
|
||||
for(String s : str.split("\\|")){
|
||||
r |= (Integer) get(s);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,13 +1,11 @@
|
||||
package com.stardust.autojs.core.ui.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import com.makeramen.roundedimageview.RoundedImageView;
|
||||
|
||||
import org.autojs.dynamiclayoutinflater.util.Drawables;
|
||||
import com.stardust.autojs.core.ui.inflater.util.Drawables;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/11/30.
|
||||
@@ -41,14 +39,15 @@ public class JsImageView extends RoundedImageView {
|
||||
}
|
||||
|
||||
public void setSource(String uri) {
|
||||
Drawables.loadInto(this, Uri.parse(uri));
|
||||
Drawables.setupWithImage(this, uri);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
setMeasuredDimension(getMeasuredWidth(), getMeasuredWidth());
|
||||
if (mCircle) {
|
||||
setCornerRadius(Math.min(getWidth(), getHeight()) / 2);
|
||||
setCornerRadius(getMeasuredWidth() / 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import com.stardust.autojs.runtime.exception.ScriptInterruptedException;
|
||||
import com.stardust.autojs.core.accessibility.SimpleActionAutomator;
|
||||
import com.stardust.autojs.runtime.api.UI;
|
||||
import com.stardust.concurrent.VolatileDispose;
|
||||
import com.stardust.lang.ThreadCompat;
|
||||
import com.stardust.pio.UncheckedIOException;
|
||||
import com.stardust.util.ClipboardUtil;
|
||||
import com.stardust.autojs.core.util.ProcessShell;
|
||||
@@ -324,7 +325,7 @@ public class ScriptRuntime {
|
||||
|
||||
public void onExit() {
|
||||
//清除interrupt状态
|
||||
Thread.interrupted();
|
||||
ThreadCompat.interrupted();
|
||||
//悬浮窗需要第一时间关闭以免出现恶意脚本全屏悬浮窗屏蔽屏幕并且在exit中写死循环的问题
|
||||
ignoresException(floaty::closeAll);
|
||||
try {
|
||||
@@ -334,7 +335,7 @@ public class ScriptRuntime {
|
||||
}
|
||||
ignoresException(threads::shutDownAll);
|
||||
ignoresException(events::recycle);
|
||||
ignoresException(loopers::quitAll);
|
||||
ignoresException(loopers::recycle);
|
||||
ignoresException(() -> {
|
||||
if (mRootShell != null) mRootShell.exitAndWaitFor();
|
||||
mRootShell = null;
|
||||
|
||||
7
autojs/src/main/res/layout/date_picker_spinner.xml
Normal file
7
autojs/src/main/res/layout/date_picker_spinner.xml
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<DatePicker xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:datePickerMode="spinner">
|
||||
|
||||
</DatePicker>
|
||||
7
autojs/src/main/res/layout/time_picker_spinner.xml
Normal file
7
autojs/src/main/res/layout/time_picker_spinner.xml
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TimePicker xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:timePickerMode="spinner">
|
||||
|
||||
</TimePicker>
|
||||
Reference in New Issue
Block a user