From 947236a4c5fc19660d5b8ebb157cb6201bd8945f Mon Sep 17 00:00:00 2001 From: hyb1996 <946994919@qq.com> Date: Fri, 12 Oct 2018 10:38:53 +0800 Subject: [PATCH 1/3] fix: java.lang.IndexOutOfBoundsException Inconsistency detected. Invalid view holder adapter positionViewHolder{b7a986a position=1 id=-1, oldPos=0, pLpos:0 scrap [attachedScrap] tmpDetached no parent} com.stardust.autojs.core.ui.widget.JsGridView{99f615b VFED..CL. ......ID 0,120-1080,1554 #133a2c2}, adapter:com.stardust.autojs.core.ui.widget.JsListView$Adapter@fe85df8, layout:android.support.v7.widget.GridLayoutManager@861c2d1, context:com.stardust.autojs.execution.ScriptExecuteActivity@6cd9514 --- .../edit/keyboard/FunctionsKeyboardView.java | 8 ++-- .../autojs/ui/explorer/ExplorerView.java | 8 ++-- .../shortcut/ShortcutIconSelectActivity.java | 5 ++- .../WrapContentGridLayoutManger.java | 39 +++++++++++++++++++ .../autojs/core/ui/widget/JsGridView.java | 11 +++++- .../autojs/core/ui/widget/JsListView.java | 3 ++ 6 files changed, 66 insertions(+), 8 deletions(-) create mode 100644 app/src/main/java/org/autojs/autojs/workground/WrapContentGridLayoutManger.java diff --git a/app/src/main/java/org/autojs/autojs/ui/edit/keyboard/FunctionsKeyboardView.java b/app/src/main/java/org/autojs/autojs/ui/edit/keyboard/FunctionsKeyboardView.java index 14bf33ee..a1a9d70a 100644 --- a/app/src/main/java/org/autojs/autojs/ui/edit/keyboard/FunctionsKeyboardView.java +++ b/app/src/main/java/org/autojs/autojs/ui/edit/keyboard/FunctionsKeyboardView.java @@ -27,6 +27,7 @@ import org.autojs.autojs.model.indices.Module; import org.autojs.autojs.model.indices.Modules; import org.autojs.autojs.model.indices.Property; import org.autojs.autojs.ui.widget.GridDividerDecoration; +import org.autojs.autojs.workground.WrapContentGridLayoutManger; import java.util.ArrayList; import java.util.HashMap; @@ -98,10 +99,11 @@ public class FunctionsKeyboardView extends FrameLayout { } private void initPropertiesView() { - GridLayoutManager gridLayoutManager = new GridLayoutManager(getContext(), SPAN_COUNT); - mPropertiesView.setLayoutManager(gridLayoutManager); + WrapContentGridLayoutManger manager = new WrapContentGridLayoutManger(getContext(), 2); + manager.setDebugInfo("FunctionsKeyboardView"); + mPropertiesView.setLayoutManager(manager); mPropertiesView.setAdapter(new PropertiesAdapter()); - gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { + manager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { @Override public int getSpanSize(int position) { diff --git a/app/src/main/java/org/autojs/autojs/ui/explorer/ExplorerView.java b/app/src/main/java/org/autojs/autojs/ui/explorer/ExplorerView.java index a91384ff..900fefa6 100644 --- a/app/src/main/java/org/autojs/autojs/ui/explorer/ExplorerView.java +++ b/app/src/main/java/org/autojs/autojs/ui/explorer/ExplorerView.java @@ -42,6 +42,7 @@ import org.autojs.autojs.ui.viewmodel.ExplorerItemList; import org.autojs.autojs.ui.widget.BindableViewHolder; import org.autojs.autojs.theme.widget.ThemeColorSwipeRefreshLayout; +import org.autojs.autojs.workground.WrapContentGridLayoutManger; import org.greenrobot.eventbus.Subscribe; import java.util.Stack; @@ -194,7 +195,8 @@ public class ExplorerView extends ThemeColorSwipeRefreshLayout implements SwipeR private void initExplorerItemListView() { mExplorerItemListView.setAdapter(mExplorerAdapter); - GridLayoutManager manager = new GridLayoutManager(getContext(), 2); + WrapContentGridLayoutManger manager = new WrapContentGridLayoutManger(getContext(), 2); + manager.setDebugInfo("ExplorerView"); manager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { @Override public int getSpanSize(int position) { @@ -311,7 +313,7 @@ public class ExplorerView extends ThemeColorSwipeRefreshLayout implements SwipeR sort(ExplorerItemList.SORT_TYPE_SIZE, mDirSortMenuShowing); break; case R.id.reset: - // WorkspaceFileProvider.resetSample(mSelectedItem.toScriptFile()); + // WorkspaceFileProvider.resetSample(mSelectedItem.toScriptFile()); default: return false; } @@ -494,7 +496,7 @@ public class ExplorerView extends ThemeColorSwipeRefreshLayout implements SwipeR if (!mExplorerItem.canRename()) { menu.removeItem(R.id.rename); } - if(mExplorerItem instanceof ExplorerSampleItem){ + if (mExplorerItem instanceof ExplorerSampleItem) { } popupMenu.setOnMenuItemClickListener(ExplorerView.this); diff --git a/app/src/main/java/org/autojs/autojs/ui/shortcut/ShortcutIconSelectActivity.java b/app/src/main/java/org/autojs/autojs/ui/shortcut/ShortcutIconSelectActivity.java index fb0521ee..9bb35a9a 100644 --- a/app/src/main/java/org/autojs/autojs/ui/shortcut/ShortcutIconSelectActivity.java +++ b/app/src/main/java/org/autojs/autojs/ui/shortcut/ShortcutIconSelectActivity.java @@ -25,6 +25,7 @@ import org.autojs.autojs.ui.BaseActivity; import org.androidannotations.annotations.AfterViews; import org.androidannotations.annotations.EActivity; import org.androidannotations.annotations.ViewById; +import org.autojs.autojs.workground.WrapContentGridLayoutManger; import java.util.ArrayList; import java.util.List; @@ -57,7 +58,9 @@ public class ShortcutIconSelectActivity extends BaseActivity { private void setupApps() { mApps.setAdapter(new AppsAdapter()); - mApps.setLayoutManager(new GridLayoutManager(this, 5)); + WrapContentGridLayoutManger manager = new WrapContentGridLayoutManger(this, 2); + manager.setDebugInfo("IconSelectView"); + mApps.setLayoutManager(manager); loadApps(); } diff --git a/app/src/main/java/org/autojs/autojs/workground/WrapContentGridLayoutManger.java b/app/src/main/java/org/autojs/autojs/workground/WrapContentGridLayoutManger.java new file mode 100644 index 00000000..a8045f8d --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/workground/WrapContentGridLayoutManger.java @@ -0,0 +1,39 @@ +package org.autojs.autojs.workground; + +import android.content.Context; +import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.util.AttributeSet; +import android.util.Log; + +import com.tencent.bugly.crashreport.BuglyLog; + +public class WrapContentGridLayoutManger extends GridLayoutManager { + + private String mDebugInfo; + + public WrapContentGridLayoutManger(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + } + + public WrapContentGridLayoutManger(Context context, int spanCount) { + super(context, spanCount); + } + + public WrapContentGridLayoutManger(Context context, int spanCount, int orientation, boolean reverseLayout) { + super(context, spanCount, orientation, reverseLayout); + } + + public void setDebugInfo(String debugInfo) { + mDebugInfo = debugInfo; + } + + @Override + public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { + try { + super.onLayoutChildren(recycler, state); + } catch (IndexOutOfBoundsException e) { + BuglyLog.e("GridLayoutManager", "Android bug: debug info = " + mDebugInfo, e); + } + } +} diff --git a/autojs/src/main/java/com/stardust/autojs/core/ui/widget/JsGridView.java b/autojs/src/main/java/com/stardust/autojs/core/ui/widget/JsGridView.java index 7db08ec4..48162f06 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/ui/widget/JsGridView.java +++ b/autojs/src/main/java/com/stardust/autojs/core/ui/widget/JsGridView.java @@ -18,6 +18,15 @@ public class JsGridView extends JsListView { @Override protected void init() { super.init(); - setLayoutManager(new GridLayoutManager(getContext(), 1)); + setLayoutManager(new GridLayoutManager(getContext(), 1){ + @Override + public void onLayoutChildren(Recycler recycler, State state) { + try { + super.onLayoutChildren(recycler, state); + } catch (IndexOutOfBoundsException e) { + getScriptRuntime().console.error(e); + } + } + }); } } diff --git a/autojs/src/main/java/com/stardust/autojs/core/ui/widget/JsListView.java b/autojs/src/main/java/com/stardust/autojs/core/ui/widget/JsListView.java index 633a10e4..d4c73f5e 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/ui/widget/JsListView.java +++ b/autojs/src/main/java/com/stardust/autojs/core/ui/widget/JsListView.java @@ -54,6 +54,9 @@ public class JsListView extends RecyclerView { setLayoutManager(new WrapContentLinearLayoutManager(getContext())); } + protected ScriptRuntime getScriptRuntime() { + return mScriptRuntime; + } public void setOnItemTouchListener(OnItemTouchListener onItemTouchListener) { mOnItemTouchListener = onItemTouchListener; From 03f1379fd56e4e59b862383092d7d8a8bdb9af6f Mon Sep 17 00:00:00 2001 From: hyb1996 <946994919@qq.com> Date: Fri, 12 Oct 2018 14:21:59 +0800 Subject: [PATCH 2/3] fix: floating window cannot show --- .idea/caches/build_file_checksums.ser | Bin 733 -> 733 bytes app/build.gradle | 1 - app/src/main/java/org/autojs/autojs/App.java | 1 + .../ui/floating/CircularActionMenu.java | 287 ++++++++++++++++++ .../autojs/ui/floating/CircularMenu.java | 1 - .../ui/floating/CircularMenuFloaty.java | 1 - .../ui/floating/CircularMenuWindow.java | 136 +++++---- .../ui/floating/FullScreenFloatyWindow.java | 25 +- .../floating/gesture/BounceDragGesture.java | 60 ++++ .../ui/floating/gesture/DragGesture.java | 141 +++++++++ .../LayoutBoundsFloatyWindow.java | 10 +- .../LayoutHierarchyFloatyWindow.java | 8 +- .../main/res/layout/circular_action_menu.xml | 4 +- app/src/main/res/values/attrs.xml | 5 + autojs/build.gradle | 2 +- .../floaty/BaseResizableFloatyWindow.java | 113 ++----- .../autojs/core/floaty/RawWindow.java | 81 ++--- .../stardust/autojs/runtime/api/Floaty.java | 2 +- 18 files changed, 636 insertions(+), 242 deletions(-) create mode 100644 app/src/main/java/org/autojs/autojs/ui/floating/CircularActionMenu.java create mode 100644 app/src/main/java/org/autojs/autojs/ui/floating/gesture/BounceDragGesture.java create mode 100644 app/src/main/java/org/autojs/autojs/ui/floating/gesture/DragGesture.java diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser index 3d62b90f9716cee1284d9668941e3f1c1ef809e9..07bf5b2048739608925889e050ee4fd1627f541d 100644 GIT binary patch delta 57 zcmV-90LK5_1>FUZm;`3s7P66?cMz>a#&xaF@Vl{=rU}F?%1*N*0eb-uE%kSf_dbbB PnczzQoC(rqldb|UE1esr delta 57 zcmV-90LK5_1>FUZm;_#ue+iMCcMuO{AoqHi3y9F5YrViD)3UQ80eb-uk_ncK?J1HZ Po|y>j;PcAjldb|U)`A*V diff --git a/app/build.gradle b/app/build.gradle index 0f381340..96527d7a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -123,7 +123,6 @@ dependencies { implementation 'org.apache.commons:commons-lang3:3.6' //Expandable RecyclerView implementation 'com.thoughtbot:expandablerecyclerview:1.3' - implementation('com.github.hyb1996:FloatingCircularActionMenu:0.0.4') implementation 'com.github.hyb1996:Auto.js-ApkBuilder:1.0.1' // RxJava implementation "io.reactivex.rxjava2:rxjava:2.1.2" diff --git a/app/src/main/java/org/autojs/autojs/App.java b/app/src/main/java/org/autojs/autojs/App.java index b0c7c854..da2be8ae 100644 --- a/app/src/main/java/org/autojs/autojs/App.java +++ b/app/src/main/java/org/autojs/autojs/App.java @@ -78,6 +78,7 @@ public class App extends MultiDexApplication { } private void setUpDebugEnvironment() { + Bugly.isDev = false; CrashHandler crashHandler = new CrashHandler(ErrorReportActivity.class); CrashReport.UserStrategy strategy = new CrashReport.UserStrategy(getApplicationContext()); diff --git a/app/src/main/java/org/autojs/autojs/ui/floating/CircularActionMenu.java b/app/src/main/java/org/autojs/autojs/ui/floating/CircularActionMenu.java new file mode 100644 index 00000000..0128bad5 --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/ui/floating/CircularActionMenu.java @@ -0,0 +1,287 @@ +package org.autojs.autojs.ui.floating; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.PointF; +import android.support.annotation.AttrRes; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.view.animation.FastOutSlowInInterpolator; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.view.animation.Animation; +import android.view.animation.Interpolator; +import android.view.animation.ScaleAnimation; +import android.widget.FrameLayout; + +import org.autojs.autojs.R; + +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * Created by Stardust on 2017/9/25. + */ + +public class CircularActionMenu extends FrameLayout { + + public interface OnStateChangeListener { + void onExpanding(CircularActionMenu menu); + + void onExpanded(CircularActionMenu menu); + + void onCollapsing(CircularActionMenu menu); + + void onCollapsed(CircularActionMenu menu); + + void onMeasured(CircularActionMenu menu); + } + + public static class OnStateChangeListenerAdapter implements OnStateChangeListener { + + @Override + public void onExpanding(CircularActionMenu menu) { + + } + + @Override + public void onExpanded(CircularActionMenu menu) { + + } + + @Override + public void onCollapsing(CircularActionMenu menu) { + + } + + @Override + public void onCollapsed(CircularActionMenu menu) { + + } + + @Override + public void onMeasured(CircularActionMenu menu) { + + } + } + + private PointF[] mItemExpandedPositionOffsets; + private CopyOnWriteArrayList mOnStateChangeListeners = new CopyOnWriteArrayList<>(); + private boolean mExpanded; + private boolean mExpanding = false; + private boolean mCollapsing = false; + private float mRadius = 200; + private float mAngle = (float) Math.toRadians(90); + private long mDuration = 200; + private int mExpandedHeight = -1; + private int mExpandedWidth = -1; + private final Interpolator mInterpolator = new FastOutSlowInInterpolator(); + + + public CircularActionMenu(@NonNull Context context) { + super(context); + init(null); + } + + public CircularActionMenu(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + init(attrs); + } + + public CircularActionMenu(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(attrs); + } + + private void init(AttributeSet attrs) { + if (attrs == null) + return; + TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.CircularActionMenu); + mRadius = a.getDimensionPixelSize(R.styleable.CircularActionMenu_cam_radius, (int) mRadius); + int angleInDegree = a.getInt(R.styleable.CircularActionMenu_cam_angle, 0); + if (angleInDegree != 0) { + mAngle = (float) Math.toRadians(angleInDegree); + } + for (int i = 0; i < getItemCount(); i++) { + View v = getItemAt(i); + LayoutParams params = (LayoutParams) v.getLayoutParams(); + params.gravity = Gravity.START | Gravity.LEFT | Gravity.CENTER_VERTICAL; + // FIXME: 2017/10/17 Not working + updateViewLayout(v, params); + } + requestLayout(); + } + + public float getRadius() { + return mRadius; + } + + public void setRadius(float radius) { + mRadius = radius; + } + + public float getAngle() { + return mAngle; + } + + public void setAngle(float angle) { + mAngle = angle; + } + + public void expand(int direction) { + setVisibility(VISIBLE); + mExpanding = true; + Animator.AnimatorListener listener = new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mExpanding = false; + mExpanded = true; + for (OnStateChangeListener l : mOnStateChangeListeners) { + l.onExpanded(CircularActionMenu.this); + } + } + }; + ScaleAnimation scaleAnimation = createScaleAnimation(0, 1); + direction = (direction == Gravity.RIGHT ? 1 : -1); + for (int i = 0; i < getItemCount(); i++) { + View item = getItemAt(i); + item.animate() + .translationXBy(direction * mItemExpandedPositionOffsets[i].x) + .translationYBy(mItemExpandedPositionOffsets[i].y) + .setListener(listener) + .setDuration(mDuration) + .start(); + item.startAnimation(scaleAnimation); + } + for (OnStateChangeListener l : mOnStateChangeListeners) { + l.onExpanding(CircularActionMenu.this); + } + } + + private ScaleAnimation createScaleAnimation(float fromScale, float toScale) { + ScaleAnimation scaleAnimation = new ScaleAnimation(fromScale, toScale, fromScale, toScale, Animation.RELATIVE_TO_SELF, 0f, Animation.RELATIVE_TO_SELF, 0.5f); + scaleAnimation.setDuration(mDuration); + scaleAnimation.setFillAfter(true); + scaleAnimation.setInterpolator(mInterpolator); + return scaleAnimation; + } + + public View getItemAt(int i) { + return getChildAt(i); + } + + public void collapse() { + Animator.AnimatorListener listener = new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mCollapsing = false; + mExpanded = false; + setVisibility(GONE); + for (OnStateChangeListener l : mOnStateChangeListeners) { + l.onCollapsed(CircularActionMenu.this); + } + } + }; + mCollapsing = true; + ScaleAnimation scaleAnimation = createScaleAnimation(1, 0); + for (int i = 0; i < getItemCount(); i++) { + View item = getItemAt(i); + item.animate() + .translationX(0) + .translationY(0) + .setListener(listener) + .setDuration(mDuration) + .setInterpolator(mInterpolator) + .start(); + item.startAnimation(scaleAnimation); + } + for (OnStateChangeListener l : mOnStateChangeListeners) { + l.onCollapsing(CircularActionMenu.this); + } + } + + public void addOnStateChangeListener(OnStateChangeListener onStateChangeListener) { + mOnStateChangeListeners.add(onStateChangeListener); + } + + public boolean removeOnStateChangeListener(OnStateChangeListener listener) { + return mOnStateChangeListeners.remove(listener); + } + + public boolean isExpanded() { + return mExpanded; + } + + public boolean isExpanding() { + return mExpanding; + } + + public boolean isCollapsing() { + return mCollapsing; + } + + + public int getItemCount() { + return getChildCount(); + } + + private void calcExpandedPositions() { + mItemExpandedPositionOffsets = new PointF[getItemCount()]; + double averageAngle = mAngle / (getItemCount() - 1); + for (int i = 0; i < getItemCount(); i++) { + double angle = -mAngle / 2 + i * averageAngle; + mItemExpandedPositionOffsets[i] = new PointF((float) (mRadius * Math.cos(angle)), + (float) (mRadius * Math.sin(angle))); + } + } + + private void calcExpandedSize() { + int maxX = 0; + int maxY = 0; + int minY = Integer.MAX_VALUE; + int maxWidth = 0; + for (int i = 0; i < getItemCount(); i++) { + View item = getItemAt(i); + maxWidth = Math.max(item.getMeasuredWidth(), maxWidth); + maxX = Math.max((int) (mItemExpandedPositionOffsets[i].x + item.getMeasuredWidth()), maxX); + // FIXME: 2017/9/26 这样算出来的高度略大 + maxY = Math.max((int) (mItemExpandedPositionOffsets[i].y + item.getMeasuredHeight()), maxY); + minY = Math.min((int) (mItemExpandedPositionOffsets[i].y - item.getMeasuredHeight()), minY); + } + mExpandedWidth = maxX; + mExpandedHeight = maxY - minY; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + measureChildren(widthMeasureSpec, heightMeasureSpec); + calcExpandedPositions(); + if (mExpandedHeight == -1 || mExpandedWidth == -1) { + calcExpandedSize(); + } + setMeasuredDimension(2 * mExpandedWidth, mExpandedHeight); + for (OnStateChangeListener listener : mOnStateChangeListeners) { + listener.onMeasured(this); + } + } + + @Override + protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) { + for (int i = 0; i < getChildCount(); ++i) { + final View child = getChildAt(i); + measureChild(child, widthMeasureSpec, heightMeasureSpec); + } + } + + public int getExpandedHeight() { + return mExpandedHeight; + } + + public int getExpandedWidth() { + return mExpandedWidth; + } + +} diff --git a/app/src/main/java/org/autojs/autojs/ui/floating/CircularMenu.java b/app/src/main/java/org/autojs/autojs/ui/floating/CircularMenu.java index ffc5e0de..4fadb0a2 100644 --- a/app/src/main/java/org/autojs/autojs/ui/floating/CircularMenu.java +++ b/app/src/main/java/org/autojs/autojs/ui/floating/CircularMenu.java @@ -14,7 +14,6 @@ import com.stardust.app.OperationDialogBuilder; import com.stardust.autojs.core.record.Recorder; import com.stardust.enhancedfloaty.FloatyService; import com.stardust.enhancedfloaty.FloatyWindow; -import com.stardust.floatingcircularactionmenu.CircularActionMenu; import org.autojs.autojs.Pref; import org.autojs.autojs.R; diff --git a/app/src/main/java/org/autojs/autojs/ui/floating/CircularMenuFloaty.java b/app/src/main/java/org/autojs/autojs/ui/floating/CircularMenuFloaty.java index 5982aceb..e53c06c7 100644 --- a/app/src/main/java/org/autojs/autojs/ui/floating/CircularMenuFloaty.java +++ b/app/src/main/java/org/autojs/autojs/ui/floating/CircularMenuFloaty.java @@ -3,7 +3,6 @@ package org.autojs.autojs.ui.floating; import android.view.View; import com.stardust.enhancedfloaty.FloatyService; -import com.stardust.floatingcircularactionmenu.CircularActionMenu; public interface CircularMenuFloaty { diff --git a/app/src/main/java/org/autojs/autojs/ui/floating/CircularMenuWindow.java b/app/src/main/java/org/autojs/autojs/ui/floating/CircularMenuWindow.java index 12ef5e99..9dc42652 100644 --- a/app/src/main/java/org/autojs/autojs/ui/floating/CircularMenuWindow.java +++ b/app/src/main/java/org/autojs/autojs/ui/floating/CircularMenuWindow.java @@ -11,17 +11,16 @@ import android.view.WindowManager; import com.stardust.enhancedfloaty.FloatyService; import com.stardust.enhancedfloaty.FloatyWindow; import com.stardust.enhancedfloaty.WindowBridge; -import com.stardust.floatingcircularactionmenu.CircularActionMenu; -import com.stardust.floatingcircularactionmenu.gesture.BounceDragGesture; import com.stardust.util.ScreenMetrics; -public class CircularMenuWindow implements FloatyWindow { +import org.autojs.autojs.ui.floating.gesture.BounceDragGesture; + +public class CircularMenuWindow extends FloatyWindow { private static final String KEY_POSITION_X = CircularMenuWindow.class.getName() + ".position.x"; private static final String KEY_POSITION_Y = CircularMenuWindow.class.getName() + ".position.y"; protected CircularMenuFloaty mFloaty; - protected WindowManager mWindowManager; protected CircularActionMenu mCircularActionMenu; protected View mCircularActionView; protected BounceDragGesture mDragGesture; @@ -37,19 +36,19 @@ public class CircularMenuWindow implements FloatyWindow { private OrientationEventListener mOrientationEventListener; public CircularMenuWindow(Context context, CircularMenuFloaty floaty) { - this.mFloaty = floaty; + mFloaty = floaty; mContext = context; } - public void onCreate(FloatyService service, WindowManager manager) { - this.mWindowManager = manager; - this.mActionViewWindowLayoutParams = this.createWindowLayoutParams(); - this.mMenuWindowLayoutParams = this.createWindowLayoutParams(); - this.inflateWindowViews(service); - this.initWindowBridge(); - this.initGestures(); - this.setListeners(); - this.setInitialState(); + @Override + protected void onCreateWindow(FloatyService service, WindowManager manager) { + mActionViewWindowLayoutParams = createWindowLayoutParams(); + mMenuWindowLayoutParams = createWindowLayoutParams(); + inflateWindowViews(service); + initWindowBridge(); + initGestures(); + setListeners(); + setInitialState(); mOrientationEventListener = new OrientationEventListener(mContext) { @Override public void onOrientationChanged(int orientation) { @@ -63,6 +62,16 @@ public class CircularMenuWindow implements FloatyWindow { } } + @Override + protected View onCreateView(FloatyService floatyService) { + return null; + } + + @Override + protected WindowManager.LayoutParams onCreateWindowLayoutParams() { + return null; + } + private void keepToSide() { mDragGesture.keepToEdge(); } @@ -75,23 +84,22 @@ public class CircularMenuWindow implements FloatyWindow { } private void initGestures() { - this.mDragGesture = new BounceDragGesture(this.mActionViewWindowBridge, this.mCircularActionView); - this.mDragGesture.setKeepToSideHiddenWidthRadio(this.mKeepToSideHiddenWidthRadio); - this.mDragGesture.setPressedAlpha(this.mActiveAlpha); - this.mDragGesture.setUnpressedAlpha(this.mInactiveAlpha); + mDragGesture = new BounceDragGesture(mActionViewWindowBridge, mCircularActionView); + mDragGesture.setKeepToSideHiddenWidthRadio(mKeepToSideHiddenWidthRadio); + mDragGesture.setPressedAlpha(mActiveAlpha); + mDragGesture.setUnpressedAlpha(mInactiveAlpha); } private void initWindowBridge() { - this.mActionViewWindowBridge = new OrientationAwareWindowBridge(this.mActionViewWindowLayoutParams, this.mWindowManager, this.mCircularActionView, mContext); - this.mMenuWindowBridge = new WindowBridge.DefaultImpl(this.mMenuWindowLayoutParams, this.mWindowManager, this.mCircularActionMenu); + mActionViewWindowBridge = new OrientationAwareWindowBridge(mActionViewWindowLayoutParams, getWindowManager(), mCircularActionView, mContext); + mMenuWindowBridge = new WindowBridge.DefaultImpl(mMenuWindowLayoutParams, getWindowManager(), mCircularActionMenu); } public void setKeepToSideHiddenWidthRadio(float keepToSideHiddenWidthRadio) { - this.mKeepToSideHiddenWidthRadio = keepToSideHiddenWidthRadio; - if (this.mDragGesture != null) { - this.mDragGesture.setKeepToSideHiddenWidthRadio(this.mKeepToSideHiddenWidthRadio); + mKeepToSideHiddenWidthRadio = keepToSideHiddenWidthRadio; + if (mDragGesture != null) { + mDragGesture.setKeepToSideHiddenWidthRadio(mKeepToSideHiddenWidthRadio); } - } private WindowManager.LayoutParams createWindowLayoutParams() { @@ -103,7 +111,7 @@ public class CircularMenuWindow implements FloatyWindow { } private void setListeners() { - this.setOnActionViewClickListener(v -> { + setOnActionViewClickListener(v -> { if (isExpanded()) { collapse(); } else { @@ -111,11 +119,11 @@ public class CircularMenuWindow implements FloatyWindow { } }); - if (this.mActionViewOnClickListener != null) { - this.mDragGesture.setOnDraggedViewClickListener(this.mActionViewOnClickListener); + if (mActionViewOnClickListener != null) { + mDragGesture.setOnDraggedViewClickListener(mActionViewOnClickListener); } - this.mCircularActionMenu.addOnStateChangeListener(new CircularActionMenu.OnStateChangeListenerAdapter() { + mCircularActionMenu.addOnStateChangeListener(new CircularActionMenu.OnStateChangeListenerAdapter() { public void onCollapsed(CircularActionMenu menu) { mCircularActionView.setAlpha(mInactiveAlpha); } @@ -127,73 +135,73 @@ public class CircularMenuWindow implements FloatyWindow { } public void setOnActionViewClickListener(View.OnClickListener listener) { - if (this.mDragGesture == null) { - this.mActionViewOnClickListener = listener; + if (mDragGesture == null) { + mActionViewOnClickListener = listener; } else { - this.mDragGesture.setOnDraggedViewClickListener(listener); + mDragGesture.setOnDraggedViewClickListener(listener); } } public void expand() { - this.mDragGesture.setEnabled(false); - this.setMenuPositionAtActionView(); - if (this.mActionViewWindowBridge.getX() > this.mActionViewWindowBridge.getScreenWidth() / 2) { - this.mCircularActionMenu.expand(3); + mDragGesture.setEnabled(false); + setMenuPositionAtActionView(); + if (mActionViewWindowBridge.getX() > mActionViewWindowBridge.getScreenWidth() / 2) { + mCircularActionMenu.expand(3); } else { - this.mCircularActionMenu.expand(5); + mCircularActionMenu.expand(5); } } public void setActiveAlpha(float activeAlpha) { - this.mActiveAlpha = activeAlpha; - if (this.mDragGesture != null) { - this.mDragGesture.setPressedAlpha(activeAlpha); + mActiveAlpha = activeAlpha; + if (mDragGesture != null) { + mDragGesture.setPressedAlpha(activeAlpha); } } public void setInactiveAlpha(float inactiveAlpha) { - this.mInactiveAlpha = inactiveAlpha; - if (this.mDragGesture != null) { - this.mDragGesture.setUnpressedAlpha(this.mInactiveAlpha); + mInactiveAlpha = inactiveAlpha; + if (mDragGesture != null) { + mDragGesture.setUnpressedAlpha(mInactiveAlpha); } } public void collapse() { - this.mDragGesture.setEnabled(true); - this.setMenuPositionAtActionView(); - this.mCircularActionMenu.collapse(); - this.mCircularActionView.setAlpha(this.mDragGesture.getUnpressedAlpha()); + mDragGesture.setEnabled(true); + setMenuPositionAtActionView(); + mCircularActionMenu.collapse(); + mCircularActionView.setAlpha(mDragGesture.getUnpressedAlpha()); } public boolean isExpanded() { - return this.mCircularActionMenu.isExpanded(); + return mCircularActionMenu.isExpanded(); } private void setMenuPositionAtActionView() { - int y = this.mActionViewWindowBridge.getY() - this.mCircularActionMenu.getMeasuredHeight() / 2 + this.mCircularActionView.getMeasuredHeight() / 2; + int y = mActionViewWindowBridge.getY() - mCircularActionMenu.getMeasuredHeight() / 2 + mCircularActionView.getMeasuredHeight() / 2; int x; - if (this.mActionViewWindowBridge.getX() > this.mActionViewWindowBridge.getScreenWidth() / 2) { - x = this.mActionViewWindowBridge.getX() - this.mCircularActionMenu.getExpandedWidth() + this.mCircularActionView.getMeasuredWidth() / 2; + if (mActionViewWindowBridge.getX() > mActionViewWindowBridge.getScreenWidth() / 2) { + x = mActionViewWindowBridge.getX() - mCircularActionMenu.getExpandedWidth() + mCircularActionView.getMeasuredWidth() / 2; } else { - x = this.mActionViewWindowBridge.getX() - this.mCircularActionMenu.getExpandedWidth() + this.mCircularActionView.getMeasuredWidth(); + x = mActionViewWindowBridge.getX() - mCircularActionMenu.getExpandedWidth() + mCircularActionView.getMeasuredWidth(); } - this.mMenuWindowBridge.updatePosition(x, y); + mMenuWindowBridge.updatePosition(x, y); } private void inflateWindowViews(FloatyService service) { - this.mCircularActionMenu = this.mFloaty.inflateMenuItems(service, this); - this.mCircularActionView = this.mFloaty.inflateActionView(service, this); - this.mCircularActionMenu.setVisibility(View.GONE); - this.mWindowManager.addView(this.mCircularActionMenu, this.mActionViewWindowLayoutParams); - this.mWindowManager.addView(this.mCircularActionView, this.mMenuWindowLayoutParams); + mCircularActionMenu = mFloaty.inflateMenuItems(service, this); + mCircularActionView = mFloaty.inflateActionView(service, this); + mCircularActionMenu.setVisibility(View.GONE); + getWindowManager().addView(mCircularActionMenu, mActionViewWindowLayoutParams); + getWindowManager().addView(mCircularActionView, mMenuWindowLayoutParams); } public void onServiceDestroy(FloatyService floatyService) { - this.close(); + close(); } public void close() { @@ -202,10 +210,14 @@ public class CircularMenuWindow implements FloatyWindow { .putInt(KEY_POSITION_X, mActionViewWindowBridge.getX()) .putInt(KEY_POSITION_Y, mActionViewWindowBridge.getY()) .apply(); - mOrientationEventListener.disable(); - this.mWindowManager.removeView(this.mCircularActionMenu); - this.mWindowManager.removeView(this.mCircularActionView); - FloatyService.removeWindow(this); + try { + mOrientationEventListener.disable(); + getWindowManager().removeView(mCircularActionMenu); + getWindowManager().removeView(mCircularActionView); + FloatyService.removeWindow(this); + } catch (Exception e) { + e.printStackTrace(); + } } } diff --git a/app/src/main/java/org/autojs/autojs/ui/floating/FullScreenFloatyWindow.java b/app/src/main/java/org/autojs/autojs/ui/floating/FullScreenFloatyWindow.java index 82d79e4e..cab741df 100644 --- a/app/src/main/java/org/autojs/autojs/ui/floating/FullScreenFloatyWindow.java +++ b/app/src/main/java/org/autojs/autojs/ui/floating/FullScreenFloatyWindow.java @@ -11,35 +11,16 @@ import com.stardust.enhancedfloaty.FloatyWindow; * Created by Stardust on 2017/10/18. */ -public abstract class FullScreenFloatyWindow implements FloatyWindow { - - private WindowManager mWindowManager; - private WindowManager.LayoutParams mLayoutParams; - private View mView; +public abstract class FullScreenFloatyWindow extends FloatyWindow { @Override - public void onCreate(FloatyService floatyService, WindowManager windowManager) { - mWindowManager = windowManager; - mView = inflateView(floatyService); - mLayoutParams = new WindowManager.LayoutParams( + protected WindowManager.LayoutParams onCreateWindowLayoutParams() { + return new WindowManager.LayoutParams( WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT, FloatyWindowManger.getWindowType(), WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, PixelFormat.TRANSLUCENT); - mWindowManager.addView(mView, mLayoutParams); } - protected abstract View inflateView(FloatyService service); - - @Override - public void onServiceDestroy(FloatyService floatyService) { - close(); - } - - @Override - public void close() { - mWindowManager.removeView(mView); - FloatyService.removeWindow(this); - } } diff --git a/app/src/main/java/org/autojs/autojs/ui/floating/gesture/BounceDragGesture.java b/app/src/main/java/org/autojs/autojs/ui/floating/gesture/BounceDragGesture.java new file mode 100644 index 00000000..e67c31d8 --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/ui/floating/gesture/BounceDragGesture.java @@ -0,0 +1,60 @@ +package org.autojs.autojs.ui.floating.gesture; + +import android.animation.ValueAnimator; +import android.view.MotionEvent; +import android.view.View; +import android.view.animation.BounceInterpolator; + +import com.stardust.enhancedfloaty.WindowBridge; + +/** + * Created by Stardust on 2017/9/26. + */ + +public class BounceDragGesture extends DragGesture { + + private long mBounceDuration = 300; + private static final int MIN_DY_TO_SCREEN_BOTTOM = 100; + private static final int MIN_DY_TO_SCREEN_TOP = 0; + private BounceInterpolator mBounceInterpolator; + + public BounceDragGesture(WindowBridge windowBridge, View view) { + super(windowBridge, view); + setAutoKeepToEdge(true); + mBounceInterpolator = new BounceInterpolator(); + } + + public void setBounceDuration(long bounceDuration) { + mBounceDuration = bounceDuration; + } + + @Override + public boolean onDown(MotionEvent event) { + return super.onDown(event); + } + + @Override + public void keepToEdge() { + int y = Math.min(mWindowBridge.getScreenHeight() - mView.getHeight() - MIN_DY_TO_SCREEN_BOTTOM, Math.max(MIN_DY_TO_SCREEN_TOP, mWindowBridge.getY())); + int x = mWindowBridge.getX(); + int hiddenWidth = (int) (getKeepToSideHiddenWidthRadio() * (float) mView.getWidth()); + if (x > mWindowBridge.getScreenWidth() / 2) { + bounce(x, mWindowBridge.getScreenWidth() - mView.getWidth() + hiddenWidth, y); + } else { + bounce(x, -hiddenWidth, y); + } + } + + protected void bounce(final int fromX, final int toX, final int y) { + ValueAnimator animator = ValueAnimator.ofFloat(fromX, toX); + animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + mWindowBridge.updatePosition((int) ((float) animation.getAnimatedValue()), y); + } + }); + animator.setDuration(mBounceDuration); + animator.setInterpolator(mBounceInterpolator); + animator.start(); + } +} diff --git a/app/src/main/java/org/autojs/autojs/ui/floating/gesture/DragGesture.java b/app/src/main/java/org/autojs/autojs/ui/floating/gesture/DragGesture.java new file mode 100644 index 00000000..144e755d --- /dev/null +++ b/app/src/main/java/org/autojs/autojs/ui/floating/gesture/DragGesture.java @@ -0,0 +1,141 @@ +package org.autojs.autojs.ui.floating.gesture; + +import android.support.v4.view.GestureDetectorCompat; +import android.util.Log; +import android.view.GestureDetector; +import android.view.MotionEvent; +import android.view.View; + +import com.stardust.enhancedfloaty.WindowBridge; + +/** + * Created by Stardust on 2017/4/18. + */ + +public class DragGesture extends GestureDetector.SimpleOnGestureListener { + + protected WindowBridge mWindowBridge; + protected View mView; + + private float mKeepToSideHiddenWidthRadio = 0.5f; + private int mInitialX; + private int mInitialY; + private float mInitialTouchX; + private float mInitialTouchY; + private View.OnClickListener mOnClickListener; + private boolean mAutoKeepToEdge; + private float mPressedAlpha = 1.0f; + private float mUnpressedAlpha = 0.4f; + private boolean mEnabled = true; + + public DragGesture(WindowBridge windowBridge, View view) { + mWindowBridge = windowBridge; + mView = view; + setupView(); + } + + private void setupView() { + final GestureDetectorCompat gestureDetector = new GestureDetectorCompat(mView.getContext(), this); + mView.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + gestureDetector.onTouchEvent(event); + if (event.getAction() == MotionEvent.ACTION_UP) { + mView.setAlpha(mUnpressedAlpha); + if (!onTheEdge() && mAutoKeepToEdge) { + keepToEdge(); + } + } + return true; + } + }); + } + + public boolean isEnabled() { + return mEnabled; + } + + public void setEnabled(boolean enabled) { + mEnabled = enabled; + } + + protected boolean onTheEdge() { + int dX1 = Math.abs(mWindowBridge.getX()); + int dX2 = Math.abs(mWindowBridge.getX() - mWindowBridge.getScreenWidth()); + return Math.min(dX1, dX2) < 5; + } + + public float getPressedAlpha() { + return mPressedAlpha; + } + + public void setPressedAlpha(float pressedAlpha) { + mPressedAlpha = pressedAlpha; + } + + public float getUnpressedAlpha() { + return mUnpressedAlpha; + } + + public void setUnpressedAlpha(float unpressedAlpha) { + mUnpressedAlpha = unpressedAlpha; + } + + public void setAutoKeepToEdge(boolean autoKeepToEdge) { + mAutoKeepToEdge = autoKeepToEdge; + } + + public boolean isAutoKeepToEdge() { + return mAutoKeepToEdge; + } + + public void setKeepToSideHiddenWidthRadio(float keepToSideHiddenWidthRadio) { + mKeepToSideHiddenWidthRadio = keepToSideHiddenWidthRadio; + } + + public float getKeepToSideHiddenWidthRadio() { + return mKeepToSideHiddenWidthRadio; + } + + @Override + public boolean onDown(MotionEvent event) { + mInitialX = mWindowBridge.getX(); + mInitialY = mWindowBridge.getY(); + mInitialTouchX = event.getRawX(); + mInitialTouchY = event.getRawY(); + return false; + } + + @Override + public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { + if (!mEnabled) { + return false; + } + mWindowBridge.updatePosition(mInitialX + (int) ((e2.getRawX() - mInitialTouchX)), + mInitialY + (int) ((e2.getRawY() - mInitialTouchY))); + mView.setAlpha(mPressedAlpha); + Log.d("DragGesture", "onScroll"); + return false; + } + + + public void keepToEdge() { + int x = mWindowBridge.getX(); + int hiddenWidth = (int) (mKeepToSideHiddenWidthRadio * mView.getWidth()); + if (x > mWindowBridge.getScreenWidth() / 2) + mWindowBridge.updatePosition(mWindowBridge.getScreenWidth() - mView.getWidth() + hiddenWidth, mWindowBridge.getY()); + else + mWindowBridge.updatePosition(-hiddenWidth, mWindowBridge.getY()); + } + + @Override + public boolean onSingleTapConfirmed(MotionEvent e) { + if (mOnClickListener != null) + mOnClickListener.onClick(mView); + return super.onSingleTapConfirmed(e); + } + + public void setOnDraggedViewClickListener(View.OnClickListener onClickListener) { + mOnClickListener = onClickListener; + } +} diff --git a/app/src/main/java/org/autojs/autojs/ui/floating/layoutinspector/LayoutBoundsFloatyWindow.java b/app/src/main/java/org/autojs/autojs/ui/floating/layoutinspector/LayoutBoundsFloatyWindow.java index 60dee927..19519e89 100644 --- a/app/src/main/java/org/autojs/autojs/ui/floating/layoutinspector/LayoutBoundsFloatyWindow.java +++ b/app/src/main/java/org/autojs/autojs/ui/floating/layoutinspector/LayoutBoundsFloatyWindow.java @@ -11,11 +11,14 @@ import com.afollestad.materialdialogs.MaterialDialog; import com.afollestad.materialdialogs.Theme; import com.stardust.app.DialogUtils; import com.stardust.enhancedfloaty.FloatyService; + import org.autojs.autojs.R; import org.autojs.autojs.ui.codegeneration.CodeGenerateDialog; import org.autojs.autojs.ui.floating.FloatyWindowManger; import org.autojs.autojs.ui.floating.FullScreenFloatyWindow; + import com.stardust.view.accessibility.NodeInfo; + import org.autojs.autojs.ui.widget.BubblePopupMenu; import java.util.Arrays; @@ -39,8 +42,8 @@ public class LayoutBoundsFloatyWindow extends FullScreenFloatyWindow { } @Override - protected View inflateView(FloatyService service) { - mContext = new ContextThemeWrapper(service, R.style.AppTheme); + protected View onCreateView(FloatyService floatyService) { + mContext = new ContextThemeWrapper(floatyService, R.style.AppTheme); mLayoutBoundsView = new LayoutBoundsView(mContext) { @Override public boolean dispatchKeyEvent(KeyEvent event) { @@ -51,11 +54,10 @@ public class LayoutBoundsFloatyWindow extends FullScreenFloatyWindow { return super.dispatchKeyEvent(event); } }; - setupView(); return mLayoutBoundsView; } - private void setupView() { + protected void onViewCreated(View v) { mLayoutBoundsView.setOnNodeInfoSelectListener(info -> { mSelectedNode = info; ensureOperationPopMenu(); diff --git a/app/src/main/java/org/autojs/autojs/ui/floating/layoutinspector/LayoutHierarchyFloatyWindow.java b/app/src/main/java/org/autojs/autojs/ui/floating/layoutinspector/LayoutHierarchyFloatyWindow.java index 2c4f1848..2be24ba9 100644 --- a/app/src/main/java/org/autojs/autojs/ui/floating/layoutinspector/LayoutHierarchyFloatyWindow.java +++ b/app/src/main/java/org/autojs/autojs/ui/floating/layoutinspector/LayoutHierarchyFloatyWindow.java @@ -44,8 +44,8 @@ public class LayoutHierarchyFloatyWindow extends FullScreenFloatyWindow { @Override - protected View inflateView(FloatyService service) { - mContext = new ContextThemeWrapper(service, R.style.AppTheme); + protected View onCreateView(FloatyService floatyService) { + mContext = new ContextThemeWrapper(floatyService, R.style.AppTheme); mLayoutHierarchyView = new LayoutHierarchyView(mContext) { @Override public boolean dispatchKeyEvent(KeyEvent event) { @@ -56,11 +56,11 @@ public class LayoutHierarchyFloatyWindow extends FullScreenFloatyWindow { return super.dispatchKeyEvent(event); } }; - setupView(); return mLayoutHierarchyView; } - private void setupView() { + @Override + protected void onViewCreated(View v) { mLayoutHierarchyView.setBackgroundColor(COLOR_SHADOW); mLayoutHierarchyView.setShowClickedNodeBounds(true); mLayoutHierarchyView.getBoundsPaint().setStrokeWidth(3); diff --git a/app/src/main/res/layout/circular_action_menu.xml b/app/src/main/res/layout/circular_action_menu.xml index 95a7332a..69296a42 100644 --- a/app/src/main/res/layout/circular_action_menu.xml +++ b/app/src/main/res/layout/circular_action_menu.xml @@ -1,5 +1,5 @@ - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index 81bdd809..1e78fc7e 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -27,4 +27,9 @@ + + + + + \ No newline at end of file diff --git a/autojs/build.gradle b/autojs/build.gradle index d2f8af64..f2f46717 100644 --- a/autojs/build.gradle +++ b/autojs/build.gradle @@ -46,7 +46,7 @@ dependencies { exclude group: 'com.android.support' }) api 'com.android.support:design:28.0.0' - api 'com.github.hyb1996:EnhancedFloaty:0.21' + api 'com.github.hyb1996:EnhancedFloaty:0.31' api 'com.github.hyb1996:OpenCvLib:2.4.13.4-imgproc' api 'com.makeramen:roundedimageview:2.3.0' // OkHttp diff --git a/autojs/src/main/java/com/stardust/autojs/core/floaty/BaseResizableFloatyWindow.java b/autojs/src/main/java/com/stardust/autojs/core/floaty/BaseResizableFloatyWindow.java index 70c5de05..b0ef76ab 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/floaty/BaseResizableFloatyWindow.java +++ b/autojs/src/main/java/com/stardust/autojs/core/floaty/BaseResizableFloatyWindow.java @@ -37,15 +37,6 @@ public class BaseResizableFloatyWindow extends ResizableFloatyWindow { private VolatileDispose mInflateException = new VolatileDispose<>(); private View mCloseButton; - private static final String TAG = "ResizableFloatyWindow"; - private WindowManager mWindowManager; - private WindowManager.LayoutParams mWindowLayoutParams; - private ViewGroup mWindowView; - private View mRootView; - private View mResizer; - private View mMoveCursor; - private WindowBridge mWindowBridge; - private MyFloaty mFloaty; public BaseResizableFloatyWindow(Context context, ViewSupplier viewSupplier) { @@ -54,7 +45,6 @@ public class BaseResizableFloatyWindow extends ResizableFloatyWindow { private BaseResizableFloatyWindow(MyFloaty floaty) { super(floaty); - mFloaty = floaty; } public RuntimeException waitForCreation() { @@ -63,19 +53,11 @@ public class BaseResizableFloatyWindow extends ResizableFloatyWindow { @Override public void onCreate(FloatyService service, WindowManager manager) { - this.mWindowManager = manager; - this.mWindowLayoutParams = this.createWindowLayoutParams(); - if (this.mFloaty == null) { - throw new IllegalStateException("Must start this service by static method ResizableExpandableFloatyWindow.startService"); - } else { - try { - this.initWindowView(service); - } catch (RuntimeException e) { - mInflateException.setAndNotify(e); - return; - } - this.mWindowBridge = new WindowBridge.DefaultImpl(this.mWindowLayoutParams, this.mWindowManager, this.mWindowView); - this.initGesture(); + try { + super.onCreate(service, manager); + } catch (RuntimeException e) { + mInflateException.setAndNotify(e); + return; } mInflateException.setAndNotify(Exceptions.NO_EXCEPTION); } @@ -86,88 +68,37 @@ public class BaseResizableFloatyWindow extends ResizableFloatyWindow { public void setAdjustEnabled(boolean enabled) { if (!enabled) { - mMoveCursor.setVisibility(View.GONE); - mResizer.setVisibility(View.GONE); + getMoveCursor().setVisibility(View.GONE); + getResizer().setVisibility(View.GONE); mCloseButton.setVisibility(View.GONE); } else { - mMoveCursor.setVisibility(View.VISIBLE); - mResizer.setVisibility(View.VISIBLE); + getMoveCursor().setVisibility(View.VISIBLE); + getResizer().setVisibility(View.VISIBLE); mCloseButton.setVisibility(View.VISIBLE); } } public boolean isAdjustEnabled() { - return mMoveCursor.getVisibility() == View.VISIBLE; + return getMoveCursor().getVisibility() == View.VISIBLE; } - public View getRootView() { - return mRootView; - } - - private void initWindowView(FloatyService service) { - this.mWindowView = (ViewGroup) View.inflate(service, com.stardust.lib.R.layout.ef_floaty_container, (ViewGroup) null); - this.mRootView = this.mFloaty.inflateView(service, this); - this.mResizer = this.mFloaty.getResizerView(this.mRootView); - this.mMoveCursor = this.mFloaty.getMoveCursorView(this.mRootView); - this.mCloseButton = mRootView.findViewById(R.id.close); - android.view.ViewGroup.LayoutParams params = new android.view.ViewGroup.LayoutParams(-2, -2); - this.mWindowView.addView(this.mRootView, params); - this.mWindowView.setFocusableInTouchMode(true); - this.mWindowManager.addView(this.mWindowView, this.mWindowLayoutParams); - } - - private WindowManager.LayoutParams createWindowLayoutParams() { - int type; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; - } else { - type = WindowManager.LayoutParams.TYPE_PHONE; - } - WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams( - WindowManager.LayoutParams.WRAP_CONTENT, - WindowManager.LayoutParams.WRAP_CONTENT, - type, - WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, - PixelFormat.TRANSLUCENT); - layoutParams.gravity = Gravity.TOP | Gravity.START; - return layoutParams; + @Override + protected void onViewCreated(View view) { + super.onViewCreated(view); + mCloseButton = view.findViewById(R.id.close); } public void disableWindowFocus() { - mWindowLayoutParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; - mWindowManager.updateViewLayout(mWindowView, mWindowLayoutParams); + WindowManager.LayoutParams windowLayoutParams = getWindowLayoutParams(); + windowLayoutParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; + updateWindowLayoutParams(windowLayoutParams); } public void requestWindowFocus() { - mWindowLayoutParams.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; - mWindowManager.updateViewLayout(mWindowView, mWindowLayoutParams); - mWindowView.requestFocus(); - } - - - private void initGesture() { - if (this.mResizer != null) { - ResizeGesture.enableResize(this.mResizer, this.mRootView, this.mWindowBridge); - } - - if (this.mMoveCursor != null) { - DragGesture gesture = new DragGesture(this.mWindowBridge, this.mMoveCursor); - gesture.setPressedAlpha(1.0F); - } - } - - public WindowBridge getWindowBridge() { - return this.mWindowBridge; - } - - public void onServiceDestroy(FloatyService service) { - this.close(); - } - - public void close() { - if (mWindowView != null) - this.mWindowManager.removeView(this.mWindowView); - FloatyService.removeWindow(this); + WindowManager.LayoutParams windowLayoutParams = getWindowLayoutParams(); + windowLayoutParams.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; + updateWindowLayoutParams(windowLayoutParams); + getWindowView().requestLayout(); } private static class MyFloaty implements ResizableFloaty { @@ -185,7 +116,7 @@ public class BaseResizableFloatyWindow extends ResizableFloatyWindow { @Override public View inflateView(FloatyService floatyService, ResizableFloatyWindow resizableFloatyWindow) { mRootView = View.inflate(mContext, R.layout.floaty_window, null); - FrameLayout container = (FrameLayout) mRootView.findViewById(R.id.container); + FrameLayout container = mRootView.findViewById(R.id.container); View contentView = mContentViewSupplier.inflate(mContext, container); return mRootView; } diff --git a/autojs/src/main/java/com/stardust/autojs/core/floaty/RawWindow.java b/autojs/src/main/java/com/stardust/autojs/core/floaty/RawWindow.java index a2dbc401..250808a2 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/floaty/RawWindow.java +++ b/autojs/src/main/java/com/stardust/autojs/core/floaty/RawWindow.java @@ -15,8 +15,10 @@ import com.stardust.concurrent.VolatileDispose; import com.stardust.enhancedfloaty.FloatyService; import com.stardust.enhancedfloaty.FloatyWindow; import com.stardust.enhancedfloaty.WindowBridge; +import com.stardust.enhancedfloaty.util.WindowTypeCompat; + +public class RawWindow extends FloatyWindow { -public class RawWindow implements FloatyWindow { public interface RawFloaty { @@ -24,13 +26,9 @@ public class RawWindow implements FloatyWindow { View inflateWindowView(FloatyService service, ViewGroup parent); } - private WindowBridge mWindowBridge; private VolatileDispose mInflateException = new VolatileDispose<>(); - private WindowManager mWindowManager; - private ViewGroup mWindowView; - private View mWindowContent; private RawFloaty mRawFloaty; - private WindowManager.LayoutParams mWindowLayoutParams; + private View mContentView; public RawWindow(RawFloaty rawFloaty) { mRawFloaty = rawFloaty; @@ -38,26 +36,32 @@ public class RawWindow implements FloatyWindow { @Override public void onCreate(FloatyService floatyService, WindowManager windowManager) { - mWindowManager = windowManager; - mWindowView = (ViewGroup) View.inflate(floatyService, R.layout.raw_window, null); - mWindowLayoutParams = createWindowLayoutParams(); try { - mWindowContent = mRawFloaty.inflateWindowView(floatyService, mWindowView); - mWindowManager.addView(mWindowView, mWindowLayoutParams); + super.onCreate(floatyService, windowManager); } catch (RuntimeException e) { mInflateException.setAndNotify(e); return; } - mWindowBridge = new WindowBridge.DefaultImpl(mWindowLayoutParams, windowManager, mWindowView); mInflateException.setAndNotify(Exceptions.NO_EXCEPTION); } + @Override + protected View onCreateView(FloatyService floatyService) { + ViewGroup windowView = (ViewGroup) View.inflate(floatyService, R.layout.raw_window, null); + mContentView = mRawFloaty.inflateWindowView(floatyService, windowView); + return windowView; + } + public RuntimeException waitForCreation() { return mInflateException.blockedGetOrThrow(ScriptInterruptedException.class); } + public View getContentView() { + return mContentView; + } - protected WindowManager.LayoutParams createWindowLayoutParams() { + @Override + protected WindowManager.LayoutParams onCreateWindowLayoutParams() { int flags = WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL @@ -66,64 +70,37 @@ public class RawWindow implements FloatyWindow { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { flags |= WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS; } - int type; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; - } else { - type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; - } WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams( WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, - type, + WindowTypeCompat.getWindowType(), flags, PixelFormat.TRANSLUCENT); layoutParams.gravity = Gravity.TOP | Gravity.START; return layoutParams; } - public void disableWindowFocus() { - mWindowLayoutParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; - mWindowManager.updateViewLayout(mWindowView, mWindowLayoutParams); + WindowManager.LayoutParams windowLayoutParams = getWindowLayoutParams(); + windowLayoutParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; + updateWindowLayoutParams(windowLayoutParams); } public void requestWindowFocus() { - mWindowLayoutParams.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; - mWindowManager.updateViewLayout(mWindowView, mWindowLayoutParams); - mWindowView.requestFocus(); + WindowManager.LayoutParams windowLayoutParams = getWindowLayoutParams(); + windowLayoutParams.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; + updateWindowLayoutParams(windowLayoutParams); + getWindowView().requestLayout(); } public void setTouchable(boolean touchable) { + WindowManager.LayoutParams windowLayoutParams = getWindowLayoutParams(); if (touchable) { - mWindowLayoutParams.flags &= ~WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; + windowLayoutParams.flags &= ~WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; } else { - mWindowLayoutParams.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; + windowLayoutParams.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE; } - mWindowManager.updateViewLayout(mWindowView, mWindowLayoutParams); + updateWindowLayoutParams(windowLayoutParams); } - public WindowBridge getWindowBridge() { - return mWindowBridge; - } - - public ViewGroup getWindowView() { - return mWindowView; - } - - public View getWindowContent() { - return mWindowContent; - } - - @Override - public void onServiceDestroy(FloatyService floatyService) { - close(); - } - - @Override - public void close() { - if (mWindowView != null) - mWindowManager.removeView(mWindowView); - FloatyService.removeWindow(this); - } } diff --git a/autojs/src/main/java/com/stardust/autojs/runtime/api/Floaty.java b/autojs/src/main/java/com/stardust/autojs/runtime/api/Floaty.java index 841478ed..a01d2664 100644 --- a/autojs/src/main/java/com/stardust/autojs/runtime/api/Floaty.java +++ b/autojs/src/main/java/com/stardust/autojs/runtime/api/Floaty.java @@ -122,7 +122,7 @@ public class Floaty { } public View findView(String id) { - return JsViewHelper.findViewByStringId(mWindow.getWindowContent(), id); + return JsViewHelper.findViewByStringId(mWindow.getContentView(), id); } public int getX() { From 3a11d8dc6068295e0173e8103c64470229e346ee Mon Sep 17 00:00:00 2001 From: hyb1996 <946994919@qq.com> Date: Fri, 12 Oct 2018 14:48:43 +0800 Subject: [PATCH 3/3] save works --- .idea/caches/build_file_checksums.ser | Bin 733 -> 733 bytes .../autojs/core/ui/widget/NativeView.java | 230 +-------------- .../autojs/core/ui/xview/ViewAttributes.java | 261 ++++++++++++++++++ autojs/src/main/res/values/ids.xml | 4 + 4 files changed, 272 insertions(+), 223 deletions(-) create mode 100644 autojs/src/main/java/com/stardust/autojs/core/ui/xview/ViewAttributes.java create mode 100644 autojs/src/main/res/values/ids.xml diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser index 07bf5b2048739608925889e050ee4fd1627f541d..ecab1808f734b6c37175faf731e5b004890c1ed4 100644 GIT binary patch delta 35 tcmV+;0NnrG1>FUZnFH{!@v)o&0uWkzYRBHvwgY;k-|`&fggle30xvzp5pw_l delta 35 tcmV+;0NnrG1>FUZnFHMxvay^30uU|rcaHZyiA$N_O8=Y*(q@yc0xuyU5I6t; diff --git a/autojs/src/main/java/com/stardust/autojs/core/ui/widget/NativeView.java b/autojs/src/main/java/com/stardust/autojs/core/ui/widget/NativeView.java index 317849c4..53cf4302 100644 --- a/autojs/src/main/java/com/stardust/autojs/core/ui/widget/NativeView.java +++ b/autojs/src/main/java/com/stardust/autojs/core/ui/widget/NativeView.java @@ -1,98 +1,20 @@ package com.stardust.autojs.core.ui.widget; import android.annotation.SuppressLint; -import android.graphics.drawable.Drawable; import android.os.Build; -import android.support.annotation.CallSuper; -import android.view.KeyEvent; -import android.view.MotionEvent; import android.view.View; -import android.view.ViewGroup; -import android.view.ViewParent; -import android.widget.FrameLayout; -import android.widget.LinearLayout; import com.stardust.autojs.core.eventloop.EventEmitter; import com.stardust.autojs.core.ui.JsEvent; -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.xview.ViewAttributes; import com.stardust.autojs.rhino.NativeJavaObjectWithPrototype; import org.mozilla.javascript.NativeJavaObject; import org.mozilla.javascript.ScriptRuntime; import org.mozilla.javascript.Scriptable; -import org.mozilla.javascript.Undefined; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.Map; public class NativeView extends NativeJavaObjectWithPrototype { - protected interface Attribute { - String get(); - - void set(String value); - } - - - protected class BaseAttribute implements Attribute { - - private String mValue; - private final AttributeSetter mAttributeSetter; - - public BaseAttribute(AttributeSetter attributeSetter) { - mAttributeSetter = attributeSetter; - } - - @Override - public String get() { - return mValue; - } - - @Override - public void set(String value) { - mValue = value; - mAttributeSetter.set(value); - } - } - - protected interface AttributeGetter { - String get(); - } - - - protected interface AttributeSetter { - void set(String value); - } - - protected interface ValueConverter { - T convert(String value); - } - - protected interface ValueApplier { - void apply(T value); - } - - protected static class MappingAttributeSetter implements AttributeSetter { - - private final ValueConverter mValueConverter; - private final ValueApplier mValueApplier; - - public MappingAttributeSetter(ValueConverter valueConverter, ValueApplier valueApplier) { - mValueConverter = valueConverter; - mValueApplier = valueApplier; - } - - @Override - public void set(String value) { - mValueApplier.apply(mValueConverter.convert(value)); - } - } - public static class ScrollEvent { public int scrollX; public int scrollY; @@ -108,17 +30,14 @@ public class NativeView extends NativeJavaObjectWithPrototype { } - private Map mAttributes = new HashMap<>(); - private final com.stardust.autojs.runtime.ScriptRuntime mRuntime; - private final Drawables mDrawables; + private final ViewAttributes mViewAttributes; private final View mView; private final EventEmitter mEventEmitter; private final NativeJavaObject mNativeEventEmitter; public NativeView(Scriptable scope, View javaObject, Class staticType, com.stardust.autojs.runtime.ScriptRuntime runtime) { super(scope, javaObject, staticType); - mRuntime = runtime; - mDrawables = mRuntime.ui.getResourceParser().getDrawables(); + mViewAttributes = ViewAttributes.fromView(runtime.ui.getResourceParser(), javaObject); mEventEmitter = runtime.events.emitter(); mView = javaObject; mNativeEventEmitter = new NativeJavaObject(scope, mEventEmitter, mEventEmitter.getClass()); @@ -128,7 +47,6 @@ public class NativeView extends NativeJavaObjectWithPrototype { @SuppressLint("ClickableViewAccessibility") private void init() { - onRegisterAttrs(); mView.setOnTouchListener((v, event) -> { JsEvent e = new JsEvent(getParentScope(), event, event.getClass()); emit("touch", e, v); @@ -151,34 +69,10 @@ public class NativeView extends NativeJavaObjectWithPrototype { } } - @CallSuper - protected void onRegisterAttrs() { - registerAttr("id", Ids::parse, mView::setId); - registerAttr("gravity", Gravities::parse, this::setGravity); - registerAttrs(new String[]{"width", "layout_width", "w"}, this::parseDimension, this::setWidth); - registerAttrs(new String[]{"height", "layout_height", "h"}, this::parseDimension, this::setHeight); - registerDrawableAttrs(new String[]{"bg", "background"}, mView::setBackground); - registerAttr("layout_gravity", Gravities::parse, this::setLayoutGravity); - registerAttr("layout_weight", Float::parseFloat, this::setLayoutWeight); - } - - - private int parseDimension(String dim) { - switch (dim) { - case "wrap_content": - return ViewGroup.LayoutParams.WRAP_CONTENT; - case "fill_parent": - case "match_parent": - return ViewGroup.LayoutParams.MATCH_PARENT; - default: - return Dimensions.parseToPixel(dim, mView.getResources().getDisplayMetrics(), (ViewGroup) mView.getParent(), true); - } - } - @Override public boolean has(String name, Scriptable start) { - if (mAttributes.containsKey(name)) { + if (mViewAttributes.contains(name)) { return true; } return super.has(name, start) || mNativeEventEmitter.has(name, start); @@ -186,7 +80,7 @@ public class NativeView extends NativeJavaObjectWithPrototype { @Override public void put(String name, Scriptable start, Object value) { - Attribute attribute = mAttributes.get(name); + ViewAttributes.Attribute attribute = mViewAttributes.get(name); if (attribute != null) { attribute.set(ScriptRuntime.toString(value)); return; @@ -200,127 +94,17 @@ public class NativeView extends NativeJavaObjectWithPrototype { @Override public Object get(String name, Scriptable start) { - Attribute attribute = mAttributes.get(name); + ViewAttributes.Attribute attribute = mViewAttributes.get(name); if (attribute != null) { return attribute.get(); } Object o = mNativeEventEmitter.get(name, start); - if(o != Scriptable.NOT_FOUND){ + if (o != Scriptable.NOT_FOUND) { return o; } return super.get(name, start); } - protected void registerAttr(String name, Attribute attribute) { - mAttributes.put(name, attribute); - } - - protected void registerAttr(String name, AttributeGetter getter, AttributeSetter setter) { - mAttributes.put(name, new Attribute() { - @Override - public String get() { - return getter.get(); - } - - @Override - public void set(String value) { - setter.set(value); - } - }); - } - - protected void registerAttr(String name, AttributeSetter setter) { - mAttributes.put(name, new BaseAttribute(setter)); - } - - protected void registerAttr(String name, ValueConverter converter, ValueApplier applier) { - mAttributes.put(name, new BaseAttribute(new MappingAttributeSetter<>(converter, applier))); - } - - protected void registerAttrs(String[] names, ValueConverter converter, ValueApplier applier) { - registerAttrs(names, new MappingAttributeSetter<>(converter, applier)); - } - - protected void registerAttrs(String[] names, AttributeSetter setter) { - registerAttrs(names, new BaseAttribute(setter)); - } - - protected void registerAttrs(String[] names, Attribute attribute) { - for (String name : names) { - mAttributes.put(name, attribute); - } - } - - protected void registerDrawableAttr(String name, ValueApplier applier) { - mAttributes.put(name, new BaseAttribute(new MappingAttributeSetter<>( - this::parseDrawable, applier))); - } - - - private void registerDrawableAttrs(String[] names, ValueApplier applier) { - registerAttrs(names, new BaseAttribute(new MappingAttributeSetter<>( - this::parseDrawable, applier))); - } - - - protected Drawable parseDrawable(String value) { - return mDrawables.parse(mView, value); - } - - private boolean setGravity(int g) { - try { - Method setGravity = mView.getClass().getMethod("setGravity", int.class); - setGravity.invoke(mView, g); - return true; - } catch (Exception e) { - e.printStackTrace(); - return false; - } - } - - private void setLayoutGravity(int gravity) { - ViewParent parent = mView.getParent(); - ViewGroup.LayoutParams layoutParams = mView.getLayoutParams(); - if (parent instanceof LinearLayout) { - ((LinearLayout.LayoutParams) layoutParams).gravity = gravity; - mView.setLayoutParams(layoutParams); - } else if (parent instanceof FrameLayout) { - ((FrameLayout.LayoutParams) layoutParams).gravity = gravity; - mView.setLayoutParams(layoutParams); - } else { - try { - Field field = layoutParams.getClass().getField("gravity"); - field.set(layoutParams, gravity); - mView.setLayoutParams(layoutParams); - } catch (Exception e) { - e.printStackTrace(); - //TODO throw or ? - } - } - } - - private void setLayoutWeight(float weight) { - ViewParent parent = mView.getParent(); - ViewGroup.LayoutParams layoutParams = mView.getLayoutParams(); - if (parent instanceof LinearLayout) { - ((LinearLayout.LayoutParams) layoutParams).weight = weight; - mView.setLayoutParams(layoutParams); - } - } - - - private void setWidth(int width) { - ViewGroup.LayoutParams layoutParams = mView.getLayoutParams(); - layoutParams.width = width; - mView.setLayoutParams(layoutParams); - } - - - private void setHeight(int height) { - ViewGroup.LayoutParams layoutParams = mView.getLayoutParams(); - layoutParams.height = height; - mView.setLayoutParams(layoutParams); - } @Override public View unwrap() { diff --git a/autojs/src/main/java/com/stardust/autojs/core/ui/xview/ViewAttributes.java b/autojs/src/main/java/com/stardust/autojs/core/ui/xview/ViewAttributes.java new file mode 100644 index 00000000..b76ed3b9 --- /dev/null +++ b/autojs/src/main/java/com/stardust/autojs/core/ui/xview/ViewAttributes.java @@ -0,0 +1,261 @@ +package com.stardust.autojs.core.ui.xview; + +import android.annotation.SuppressLint; +import android.graphics.drawable.Drawable; +import android.support.annotation.CallSuper; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewParent; +import android.widget.FrameLayout; +import android.widget.LinearLayout; + +import com.stardust.autojs.R; +import com.stardust.autojs.core.ui.inflater.ResourceParser; +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.widget.NativeView; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +public class ViewAttributes { + + public interface Attribute { + String get(); + + void set(String value); + } + + + protected class BaseAttribute implements Attribute { + + private String mValue; + private final AttributeSetter mAttributeSetter; + + public BaseAttribute(AttributeSetter attributeSetter) { + mAttributeSetter = attributeSetter; + } + + @Override + public String get() { + return mValue; + } + + @Override + public void set(String value) { + mValue = value; + mAttributeSetter.set(value); + } + } + + protected interface AttributeGetter { + String get(); + } + + + protected interface AttributeSetter { + void set(String value); + } + + protected interface ValueConverter { + T convert(String value); + } + + protected interface ValueApplier { + void apply(T value); + } + + protected static class MappingAttributeSetter implements AttributeSetter { + + private final ValueConverter mValueConverter; + private final ValueApplier mValueApplier; + + public MappingAttributeSetter(ValueConverter valueConverter, ValueApplier valueApplier) { + mValueConverter = valueConverter; + mValueApplier = valueApplier; + } + + @Override + public void set(String value) { + mValueApplier.apply(mValueConverter.convert(value)); + } + } + + private Map mAttributes = new HashMap<>(); + private final Drawables mDrawables; + private final View mView; + + public ViewAttributes(Drawables drawables, View view) { + mDrawables = drawables; + mView = view; + init(); + } + + public static ViewAttributes fromView(ResourceParser parser, View view) { + ViewAttributes attributes; + Object tag = view.getTag(R.id.view_tag_view_attrs); + if (!(tag instanceof ViewAttributes)) { + attributes = new ViewAttributes(parser.getDrawables(), view); + view.setTag(R.id.view_tag_view_attrs, attributes); + } else { + attributes = (ViewAttributes) tag; + } + return attributes; + } + + + public boolean contains(String name) { + return mAttributes.containsKey(name); + } + + public Attribute get(String name) { + return mAttributes.get(name); + } + + + @SuppressLint("ClickableViewAccessibility") + private void init() { + onRegisterAttrs(); + } + + + @CallSuper + protected void onRegisterAttrs() { + registerAttr("id", Ids::parse, mView::setId); + registerAttr("gravity", Gravities::parse, this::setGravity); + registerAttrs(new String[]{"width", "layout_width", "w"}, this::parseDimension, this::setWidth); + registerAttrs(new String[]{"height", "layout_height", "h"}, this::parseDimension, this::setHeight); + registerDrawableAttrs(new String[]{"bg", "background"}, mView::setBackground); + registerAttr("layout_gravity", Gravities::parse, this::setLayoutGravity); + registerAttr("layout_weight", Float::parseFloat, this::setLayoutWeight); + } + + + private int parseDimension(String dim) { + switch (dim) { + case "wrap_content": + return ViewGroup.LayoutParams.WRAP_CONTENT; + case "fill_parent": + case "match_parent": + return ViewGroup.LayoutParams.MATCH_PARENT; + default: + return Dimensions.parseToPixel(dim, mView.getResources().getDisplayMetrics(), (ViewGroup) mView.getParent(), true); + } + } + + protected void registerAttr(String name, Attribute attribute) { + mAttributes.put(name, attribute); + } + + protected void registerAttr(String name, AttributeGetter getter, AttributeSetter setter) { + mAttributes.put(name, new Attribute() { + @Override + public String get() { + return getter.get(); + } + + @Override + public void set(String value) { + setter.set(value); + } + }); + } + + protected void registerAttr(String name, AttributeSetter setter) { + mAttributes.put(name, new BaseAttribute(setter)); + } + + protected void registerAttr(String name, ValueConverter converter, ValueApplier applier) { + mAttributes.put(name, new BaseAttribute(new MappingAttributeSetter<>(converter, applier))); + } + + protected void registerAttrs(String[] names, ValueConverter converter, ValueApplier applier) { + registerAttrs(names, new MappingAttributeSetter<>(converter, applier)); + } + + protected void registerAttrs(String[] names, AttributeSetter setter) { + registerAttrs(names, new BaseAttribute(setter)); + } + + protected void registerAttrs(String[] names, Attribute attribute) { + for (String name : names) { + mAttributes.put(name, attribute); + } + } + + protected void registerDrawableAttr(String name, ValueApplier applier) { + mAttributes.put(name, new BaseAttribute(new MappingAttributeSetter<>( + this::parseDrawable, applier))); + } + + + private void registerDrawableAttrs(String[] names, ValueApplier applier) { + registerAttrs(names, new BaseAttribute(new MappingAttributeSetter<>( + this::parseDrawable, applier))); + } + + + protected Drawable parseDrawable(String value) { + return mDrawables.parse(mView, value); + } + + private boolean setGravity(int g) { + try { + Method setGravity = mView.getClass().getMethod("setGravity", int.class); + setGravity.invoke(mView, g); + return true; + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + + private void setLayoutGravity(int gravity) { + ViewParent parent = mView.getParent(); + ViewGroup.LayoutParams layoutParams = mView.getLayoutParams(); + if (parent instanceof LinearLayout) { + ((LinearLayout.LayoutParams) layoutParams).gravity = gravity; + mView.setLayoutParams(layoutParams); + } else if (parent instanceof FrameLayout) { + ((FrameLayout.LayoutParams) layoutParams).gravity = gravity; + mView.setLayoutParams(layoutParams); + } else { + try { + Field field = layoutParams.getClass().getField("gravity"); + field.set(layoutParams, gravity); + mView.setLayoutParams(layoutParams); + } catch (Exception e) { + e.printStackTrace(); + //TODO throw or ? + } + } + } + + private void setLayoutWeight(float weight) { + ViewParent parent = mView.getParent(); + ViewGroup.LayoutParams layoutParams = mView.getLayoutParams(); + if (parent instanceof LinearLayout) { + ((LinearLayout.LayoutParams) layoutParams).weight = weight; + mView.setLayoutParams(layoutParams); + } + } + + + private void setWidth(int width) { + ViewGroup.LayoutParams layoutParams = mView.getLayoutParams(); + layoutParams.width = width; + mView.setLayoutParams(layoutParams); + } + + + private void setHeight(int height) { + ViewGroup.LayoutParams layoutParams = mView.getLayoutParams(); + layoutParams.height = height; + mView.setLayoutParams(layoutParams); + } + +} diff --git a/autojs/src/main/res/values/ids.xml b/autojs/src/main/res/values/ids.xml new file mode 100644 index 00000000..48da4307 --- /dev/null +++ b/autojs/src/main/res/values/ids.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file