api(autojs): supports ui label toolbar, appbar, tabs, viewpager, drawer

This commit is contained in:
hyb1996 2018-05-31 01:38:36 +08:00
parent 22185346e8
commit debcb1d7b8
21 changed files with 354 additions and 13 deletions

View File

@ -2,6 +2,7 @@
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/Auto.js.iml" filepath="$PROJECT_DIR$/Auto.js.iml" />
<module fileurl="file://$PROJECT_DIR$/NoRootScriptDroid.iml" filepath="$PROJECT_DIR$/NoRootScriptDroid.iml" />
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
<module fileurl="file://$PROJECT_DIR$/autojs/autojs.iml" filepath="$PROJECT_DIR$/autojs/autojs.iml" />

View File

@ -20,6 +20,7 @@ import android.view.View;
import com.stardust.app.FragmentPagerAdapterBuilder;
import com.stardust.app.OnActivityResultDelegate;
import com.stardust.autojs.core.image.OpenCVHelper;
import com.stardust.autojs.core.permission.OnRequestPermissionsResultCallback;
import com.stardust.autojs.core.permission.PermissionRequestProxyActivity;
import com.stardust.autojs.core.permission.RequestPermissionCallbacks;
@ -61,6 +62,7 @@ import org.androidannotations.annotations.EActivity;
import org.androidannotations.annotations.ViewById;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.opencv.core.Core;
import java.util.Arrays;

View File

@ -44,6 +44,8 @@ module.exports = function(__runtime__, scope){
images.read = rtImages.read.bind(rtImages);
images.copy = rtImages.copy.bind(rtImages);
images.load = rtImages.load.bind(rtImages);
images.clip = rtImages.clip.bind(rtImages);

View File

@ -154,7 +154,6 @@ module.exports = function (runtime, global) {
return false;
},
beforeApplyAttribute: function (inflater, view, ns, attrName, value, parent, attrs) {
log("beforeApplyAttribute:", view, attrName, value);
var isDynamic = layoutInflater.isDynamicValue(value);
if ((isDynamic && layoutInflater.getInflateFlags() == layoutInflater.FLAG_IGNORES_DYNAMIC_ATTRS)
|| (!isDynamic && layoutInflater.getInflateFlags() == layoutInflater.FLAG_JUST_DYNAMIC_ATTRS)) {
@ -197,9 +196,9 @@ module.exports = function (runtime, global) {
}
function decorate(view) {
var androidView = view;
var javaObject = view;
var view = global.events.__asEmitter__(Object.create(view));
view.__androidView__ = androidView;
view.__javaObject__ = javaObject;
if (view.getClass().getName() == "com.stardust.autojs.core.ui.widget.JsListView"
|| view.getClass().getName() == "com.stardust.autojs.core.ui.widget.JsGridView") {
view = decorateList(view);

View File

@ -41,6 +41,8 @@ public class ImageWrapper {
public ImageWrapper(Bitmap bitmap, Mat mat) {
mBitmap = bitmap;
mMat = mat;
mWidth = bitmap.getWidth();
mHeight = bitmap.getHeight();
}
public ImageWrapper(int width, int height) {

View File

@ -4,6 +4,8 @@ import android.content.Context;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.AppBarLayout;
import android.support.design.widget.TabLayout;
import android.support.v7.widget.Toolbar;
import android.util.AttributeSet;
import android.util.Log;
@ -21,6 +23,7 @@ import android.widget.Spinner;
import android.widget.TextView;
import android.widget.TimePicker;
import com.stardust.autojs.core.ui.inflater.inflaters.AppBarInflater;
import com.stardust.autojs.core.ui.inflater.inflaters.BaseViewInflater;
import com.stardust.autojs.core.ui.inflater.inflaters.DatePickerInflater;
import com.stardust.autojs.core.ui.inflater.inflaters.FrameLayoutInflater;
@ -29,11 +32,13 @@ import com.stardust.autojs.core.ui.inflater.inflaters.LinearLayoutInflater;
import com.stardust.autojs.core.ui.inflater.inflaters.ProgressBarInflater;
import com.stardust.autojs.core.ui.inflater.inflaters.RadioGroupInflater;
import com.stardust.autojs.core.ui.inflater.inflaters.SpinnerInflater;
import com.stardust.autojs.core.ui.inflater.inflaters.TabLayoutInflater;
import com.stardust.autojs.core.ui.inflater.inflaters.TextViewInflater;
import com.stardust.autojs.core.ui.inflater.inflaters.TimePickerInflater;
import com.stardust.autojs.core.ui.inflater.inflaters.ToolbarInflater;
import com.stardust.autojs.core.ui.inflater.inflaters.ViewGroupInflater;
import com.stardust.autojs.core.ui.inflater.util.Res;
import com.stardust.autojs.core.ui.widget.JsToolbar;
import com.stardust.autojs.core.ui.xml.XmlConverter;
import org.w3c.dom.Document;
@ -116,12 +121,14 @@ public class DynamicLayoutInflater {
registerViewAttrSetter(LinearLayout.class.getName(), new LinearLayoutInflater<>(mResourceParser));
registerViewAttrSetter(FrameLayout.class.getName(), new FrameLayoutInflater<>(mResourceParser));
registerViewAttrSetter(View.class.getName(), new BaseViewInflater<>(mResourceParser));
registerViewAttrSetter(Toolbar.class.getName(), new ToolbarInflater<>(mResourceParser));
registerViewAttrSetter(JsToolbar.class.getName(), new ToolbarInflater<>(mResourceParser));
registerViewAttrSetter(DatePicker.class.getName(), new DatePickerInflater(mResourceParser));
registerViewAttrSetter(RadioGroup.class.getName(), new RadioGroupInflater<>(mResourceParser));
registerViewAttrSetter(ProgressBar.class.getName(), new ProgressBarInflater<>(mResourceParser));
registerViewAttrSetter(Spinner.class.getName(), new SpinnerInflater(mResourceParser));
registerViewAttrSetter(TimePicker.class.getName(), new TimePickerInflater(mResourceParser));
registerViewAttrSetter(AppBarLayout.class.getName(), new AppBarInflater<>(mResourceParser));
registerViewAttrSetter(TabLayout.class.getName(), new TabLayoutInflater<>(mResourceParser));
}
public void registerViewAttrSetter(String fullName, ViewInflater<?> inflater) {
@ -169,6 +176,14 @@ public class DynamicLayoutInflater {
@SuppressWarnings("unchecked")
public View inflate(Node node, @Nullable ViewGroup parent, boolean attachToParent) {
View view = doInflation(node, parent, attachToParent);
if (view != null && view instanceof ShouldCallOnFinishInflate) {
((ShouldCallOnFinishInflate) view).onFinishDynamicInflate();
}
return view;
}
protected View doInflation(Node node, @Nullable ViewGroup parent, boolean attachToParent) {
View view = mLayoutInflaterDelegate.beforeInflateView(node, parent, attachToParent);
if (view != null)
return view;

View File

@ -0,0 +1,6 @@
package com.stardust.autojs.core.ui.inflater;
public interface ShouldCallOnFinishInflate {
void onFinishDynamicInflate();
}

View File

@ -0,0 +1,43 @@
package com.stardust.autojs.core.ui.inflater.inflaters;
import android.content.Context;
import android.support.annotation.Nullable;
import android.support.design.widget.AppBarLayout;
import android.view.View;
import android.view.ViewGroup;
import com.stardust.autojs.R;
import com.stardust.autojs.core.ui.inflater.ResourceParser;
import com.stardust.autojs.core.ui.inflater.ViewCreator;
import com.stardust.autojs.core.ui.inflater.util.Dimensions;
import java.util.Map;
public class AppBarInflater<V extends AppBarLayout> extends BaseViewInflater<V> {
public AppBarInflater(ResourceParser resourceParser) {
super(resourceParser);
}
@Override
public boolean setAttr(V view, String attr, String value, ViewGroup parent, Map<String, String> attrs) {
switch (attr) {
case "elevation":
view.setTargetElevation(Dimensions.parseToPixel(value, view));
break;
case "expanded":
view.setExpanded(Boolean.parseBoolean(value));
break;
default:
return super.setAttr(view, attr, value, parent, attrs);
}
return true;
}
@Nullable
@Override
@SuppressWarnings("unchecked")
public ViewCreator<? super V> getCreator() {
return (ViewCreator<V>) (context, attrs) -> (V) View.inflate(context, R.layout.js_appbar, null);
}
}

View File

@ -0,0 +1,63 @@
package com.stardust.autojs.core.ui.inflater.inflaters;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Color;
import android.support.annotation.Nullable;
import android.support.design.widget.TabLayout;
import android.view.ViewGroup;
import com.stardust.autojs.core.ui.inflater.ResourceParser;
import com.stardust.autojs.core.ui.inflater.ViewCreator;
import com.stardust.autojs.core.ui.inflater.util.Colors;
import com.stardust.autojs.core.ui.inflater.util.Dimensions;
import com.stardust.autojs.core.ui.inflater.util.Gravities;
import com.stardust.autojs.core.ui.inflater.util.ValueMapper;
import com.stardust.autojs.core.ui.widget.JsTabLayout;
import java.util.Map;
public class TabLayoutInflater<V extends TabLayout> extends BaseViewInflater<V> {
private static final ValueMapper<Integer> TAB_MODES = new ValueMapper<Integer>("tabMode")
.map("fixed", TabLayout.MODE_FIXED)
.map("scrollable", TabLayout.MODE_SCROLLABLE);
public TabLayoutInflater(ResourceParser resourceParser) {
super(resourceParser);
}
@Override
public boolean setAttr(V view, String attr, String value, ViewGroup parent, Map<String, String> attrs) {
switch (attr) {
case "tabGravity":
view.setTabGravity(Gravities.parse(value));
break;
case "tabIndicatorColor":
view.setSelectedTabIndicatorColor(Colors.parse(view, value));
break;
case "tabIndicatorHeight":
view.setSelectedTabIndicatorHeight(Dimensions.parseToIntPixel(value, view));
break;
case "tabMode":
view.setTabMode(TAB_MODES.get(value));
break;
case "tabSelectedTextColor":
ColorStateList colors = view.getTabTextColors();
view.setTabTextColors(colors == null ? Color.WHITE : colors.getDefaultColor(),
Colors.parse(view, value));
break;
case "tabTextColor":
colors = view.getTabTextColors();
view.setTabTextColors(Colors.parse(view, value),
colors == null ? Color.WHITE : colors.getDefaultColor());
break;
default:
return super.setAttr(view, attr, value, parent, attrs);
}
return true;
}
}

View File

@ -9,7 +9,10 @@ import android.view.ViewGroup;
import com.stardust.autojs.R;
import com.stardust.autojs.core.ui.inflater.ResourceParser;
import com.stardust.autojs.core.ui.inflater.ViewCreator;
import com.stardust.autojs.core.ui.inflater.util.Colors;
import com.stardust.autojs.core.ui.inflater.util.Dimensions;
import com.stardust.autojs.core.ui.inflater.util.Strings;
import com.stardust.autojs.core.ui.inflater.util.ValueMapper;
import java.util.Map;
@ -20,6 +23,10 @@ import java.util.Map;
public class ToolbarInflater<V extends Toolbar> extends BaseViewInflater<V> {
private static final ValueMapper<Integer> POP_UP_THEMES = new ValueMapper<Integer>("popupTheme")
.map("dark", R.style.ThemeOverlay_AppCompat_Dark_ActionBar)
.map("light", R.style.ThemeOverlay_AppCompat_ActionBar);
public ToolbarInflater(ResourceParser resourceParser) {
super(resourceParser);
}
@ -27,9 +34,47 @@ public class ToolbarInflater<V extends Toolbar> extends BaseViewInflater<V> {
@Override
public boolean setAttr(V view, String attr, String value, ViewGroup parent, Map<String, String> attrs) {
switch (attr) {
case "logo":
view.setLogo(getDrawables().parse(view, value));
break;
case "logoDescription":
view.setLogoDescription(Strings.parse(view, value));
break;
case "navigationIcon":
view.setNavigationContentDescription(Strings.parse(view, value));
break;
case "popupTheme":
view.setPopupTheme(POP_UP_THEMES.get(value));
break;
case "subtitle":
view.setSubtitle(Strings.parse(view, value));
break;
case "subtitleTextColor":
view.setSubtitleTextColor(Colors.parse(view, value));
break;
case "titleTextColor":
view.setTitleTextColor(Colors.parse(view, value));
break;
case "title":
view.setTitle(Strings.parse(view, value));
break;
case "titleMargin":
int margin = Dimensions.parseToIntPixel(value, view);
view.setTitleMargin(margin, margin, margin, margin);
break;
case "titleMarginBottom":
view.setTitleMarginBottom(Dimensions.parseToIntPixel(value, view));
break;
case "titleMarginTop":
view.setTitleMarginTop(Dimensions.parseToIntPixel(value, view));
break;
case "titleMarginStart":
view.setTitleMarginStart(Dimensions.parseToIntPixel(value, view));
break;
case "titleMarginEnd":
view.setTitleMarginEnd(Dimensions.parseToIntPixel(value, view));
break;
default:
return super.setAttr(view, attr, value, parent, attrs);
}

View File

@ -0,0 +1,30 @@
package com.stardust.autojs.core.ui.widget;
import android.content.Context;
import android.support.annotation.Nullable;
import android.support.design.widget.TabLayout;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import com.stardust.autojs.runtime.api.UI;
import org.mozilla.javascript.NativeObject;
public class JsTabLayout extends TabLayout {
public JsTabLayout(Context context) {
super(context);
}
public JsTabLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public JsTabLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void setupWithViewPager(NativeObject viewPager) {
setupWithViewPager(UI.unwrapJsViewObject(viewPager, ViewPager.class));
}
}

View File

@ -2,6 +2,7 @@ package com.stardust.autojs.core.ui.widget;
import android.app.Activity;
import android.content.Context;
import android.content.ContextWrapper;
import android.support.annotation.Nullable;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
@ -10,6 +11,7 @@ import android.util.AttributeSet;
import android.util.Log;
import com.stardust.autojs.R;
import com.stardust.autojs.runtime.api.UI;
import org.mozilla.javascript.NativeObject;
@ -28,18 +30,26 @@ public class JsToolbar extends Toolbar {
}
public void setupWithDrawer(DrawerLayout drawerLayout) {
ActionBarDrawerToggle drawerToggle = new ActionBarDrawerToggle((Activity) getContext(), drawerLayout, this, R.string.text_drawer_open,
ActionBarDrawerToggle drawerToggle = new ActionBarDrawerToggle(getActivity(), drawerLayout, this, R.string.text_drawer_open,
R.string.text_drawer_close);
drawerToggle.syncState();
drawerLayout.addDrawerListener(drawerToggle);
}
public void setupWithDrawer(NativeObject object) {
if (object.containsKey("__androidView__")) {
setupWithDrawer((DrawerLayout) object.get("__androidView__"));
} else {
throw new ClassCastException("cannot cast object to DrawerLayout");
private Activity getActivity() {
Context context = getContext();
while (!(context instanceof Activity)) {
if (context instanceof ContextWrapper) {
context = ((ContextWrapper) context).getBaseContext();
} else {
return null;
}
}
return (Activity) context;
}
public void setupWithDrawer(NativeObject object) {
setupWithDrawer(UI.unwrapJsViewObject(object, DrawerLayout.class));
}
}

View File

@ -0,0 +1,68 @@
package com.stardust.autojs.core.ui.widget;
import android.content.Context;
import android.graphics.Bitmap;
import android.support.design.widget.TabLayout;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import com.stardust.autojs.core.ui.inflater.ShouldCallOnFinishInflate;
public class JsViewPager extends ViewPager implements ShouldCallOnFinishInflate {
private String[] mTitles;
public JsViewPager(Context context) {
super(context);
}
public JsViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void onFinishDynamicInflate() {
setAdapter();
}
public void setTitles(String[] titles) {
mTitles = titles;
}
private void setAdapter() {
setOffscreenPageLimit(getChildCount());
setAdapter(new PagerAdapter() {
@Override
public Object instantiateItem(ViewGroup container, int position) {
return getChildAt(position);
}
@Override
public CharSequence getPageTitle(int position) {
return mTitles != null && position < mTitles.length ?
mTitles[position] :
super.getPageTitle(position);
}
@Override
public int getCount() {
return getChildCount();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
}
});
}
}

View File

@ -25,8 +25,10 @@ import com.stardust.autojs.core.ui.widget.JsImageView;
import com.stardust.autojs.core.ui.widget.JsLinearLayout;
import com.stardust.autojs.core.ui.widget.JsListView;
import com.stardust.autojs.core.ui.widget.JsRelativeLayout;
import com.stardust.autojs.core.ui.widget.JsTabLayout;
import com.stardust.autojs.core.ui.widget.JsTextView;
import com.stardust.autojs.core.ui.widget.JsToolbar;
import com.stardust.autojs.core.ui.widget.JsViewPager;
import com.stardust.autojs.core.ui.widget.JsWebView;
import org.w3c.dom.Document;
@ -77,7 +79,8 @@ public class XmlConverter {
.map("grid", JsGridView.class.getName())
.map("drawer", DrawerLayout.class.getName())
.map("appbar", AppBarLayout.class.getName())
.map("tabs", TabLayout.class.getName())
.map("tabs", JsTabLayout.class.getName())
.map("viewpager", JsViewPager.class.getName())
);
private static final AttributeHandler ATTRIBUTE_HANDLER = new AttributeHandler.AttrNameRouter()

View File

@ -7,6 +7,9 @@ import android.os.Bundle;
import android.os.PersistableBundle;
import android.support.v7.app.AppCompatActivity;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import com.stardust.autojs.core.eventloop.EventEmitter;
import com.stardust.autojs.core.eventloop.SimpleEvent;
@ -63,6 +66,10 @@ public class ScriptExecuteActivity extends AppCompatActivity {
runScript();
}
public EventEmitter getEventEmitter() {
return mEventEmitter;
}
private IntentExtras readIntentExtras(Bundle savedInstanceState) {
IntentExtras extras = IntentExtras.fromIntentAndRelease(getIntent());
if (extras == null && savedInstanceState != null) {
@ -189,12 +196,31 @@ public class ScriptExecuteActivity extends AppCompatActivity {
}
@Override
public boolean onGenericMotionEvent(MotionEvent event) {
SimpleEvent e = new SimpleEvent();
mEventEmitter.emit("generic_motion_event", event, e);
return super.onGenericMotionEvent(event);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
mEventEmitter.emit("activity_result", requestCode, resultCode, data);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
mEventEmitter.emit("create_options_menu", menu);
return menu.size() > 0;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
SimpleEvent e = new SimpleEvent();
mEventEmitter.emit("options_item_selected", e, item);
return e.consumed || super.onOptionsItemSelected(item);
}
private static class ActivityScriptExecution extends ScriptExecution.AbstractScriptExecution {

View File

@ -146,7 +146,7 @@ public class Images {
if (compressFormat == null)
throw new IllegalArgumentException("unknown format " + format);
Bitmap bitmap = image.getBitmap();
FileOutputStream outputStream = new FileOutputStream(path);
FileOutputStream outputStream = new FileOutputStream(mScriptRuntime.files.path(path));
return bitmap.compress(compressFormat, quality, outputStream);
}

View File

@ -2,6 +2,7 @@ package com.stardust.autojs.runtime.api;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.View;
import com.stardust.autojs.core.graphics.ScriptCanvasView;
import com.stardust.autojs.core.ui.inflater.DynamicLayoutInflater;
@ -16,6 +17,7 @@ import com.stardust.autojs.core.ui.widget.JsListView;
import com.stardust.autojs.rhino.ProxyObject;
import com.stardust.autojs.runtime.ScriptRuntime;
import org.mozilla.javascript.NativeObject;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.UniqueTag;
@ -52,6 +54,19 @@ public class UI extends ProxyObject {
mProperties.put("layoutInflater", this.mDynamicLayoutInflater);
}
@SuppressWarnings("unchecked")
public static <V extends View> V unwrapJsViewObject(NativeObject object, Class<V> c) {
if (!object.containsKey("__javaObject__")) {
throw new ClassCastException("object " + object + " cannot be cast to " + c.getName());
}
Object view = object.get("__javaObject__");
if (!c.isInstance(view)) {
throw new ClassCastException("object " + object + " cannot be cast to " + c.getName());
}
return (V) view;
}
public Object getBindingContext() {
return mProperties.get("bindingContext");
}

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.AppBarLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay"
app:popupTheme="@style/AppTheme.PopupOverlay">
</android.support.design.widget.AppBarLayout>

View File

@ -3,6 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:popupTheme="@style/AppTheme.PopupOverlay">
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
</com.stardust.autojs.core.ui.widget.JsToolbar>

View File

@ -14,6 +14,7 @@
</style>
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar"/>
<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar"/>