mStack = new Stack<>();
+ private CurrentViewSetter mCurrentViewSetter;
+
+ public ViewStack(CurrentViewSetter currentViewSetter) {
+ mCurrentViewSetter = currentViewSetter;
+ }
+
+ public void navigateTo(View v) {
+ mStack.push(v);
+ mCurrentViewSetter.setCurrentView(v);
+ }
+
+ public boolean canGoBack() {
+ return mStack.size() > 1;
+ }
+
+ public void goBack() {
+ mCurrentViewSetter.setCurrentView(mStack.pop());
+ }
+
+ public void goBackToFirst() {
+ while (mStack.size() > 1) {
+ mStack.pop();
+ }
+ mCurrentViewSetter.setCurrentView(mStack.peek());
+ }
+
+ public void setRootView(View view) {
+ mStack.clear();
+ mStack.push(view);
+ }
+
+
+}
diff --git a/autojs/src/main/java/com/stardust/enhancedfloaty/WindowBridge.java b/autojs/src/main/java/com/stardust/enhancedfloaty/WindowBridge.java
new file mode 100644
index 00000000..2c0deda1
--- /dev/null
+++ b/autojs/src/main/java/com/stardust/enhancedfloaty/WindowBridge.java
@@ -0,0 +1,94 @@
+package com.stardust.enhancedfloaty;
+
+import android.util.DisplayMetrics;
+import android.view.View;
+import android.view.WindowManager;
+
+/**
+ * Created by Stardust on 2017/4/18.
+ */
+
+public interface WindowBridge {
+ int getX();
+
+ int getY();
+
+ void updatePosition(int x, int y);
+
+ int getWidth();
+
+ int getHeight();
+
+ void updateMeasure(int width, int height);
+
+ int getScreenWidth();
+
+ int getScreenHeight();
+
+ class DefaultImpl implements WindowBridge {
+
+ DisplayMetrics mDisplayMetrics;
+ private WindowManager.LayoutParams mWindowLayoutParams;
+ private WindowManager mWindowManager;
+ private View mWindowView;
+
+ public DefaultImpl(WindowManager.LayoutParams windowLayoutParams, WindowManager windowManager, View windowView) {
+ mWindowLayoutParams = windowLayoutParams;
+ mWindowManager = windowManager;
+ mWindowView = windowView;
+ }
+
+ @Override
+ public int getX() {
+ return mWindowLayoutParams.x;
+ }
+
+ @Override
+ public int getY() {
+ return mWindowLayoutParams.y;
+ }
+
+ @Override
+ public void updatePosition(int x, int y) {
+ mWindowLayoutParams.x = x;
+ mWindowLayoutParams.y = y;
+ mWindowManager.updateViewLayout(mWindowView, mWindowLayoutParams);
+ }
+
+ @Override
+ public int getWidth() {
+ return mWindowView.getWidth();
+ }
+
+ @Override
+ public int getHeight() {
+ return mWindowView.getHeight();
+ }
+
+ @Override
+ public void updateMeasure(int width, int height) {
+ mWindowLayoutParams.width = width;
+ mWindowLayoutParams.height = height;
+ mWindowManager.updateViewLayout(mWindowView, mWindowLayoutParams);
+ }
+
+ @Override
+ public int getScreenWidth() {
+ ensureDisplayMetrics();
+ return mDisplayMetrics.widthPixels;
+ }
+
+ @Override
+ public int getScreenHeight() {
+ ensureDisplayMetrics();
+ return mDisplayMetrics.heightPixels;
+ }
+
+ private void ensureDisplayMetrics() {
+ if (mDisplayMetrics == null) {
+ mDisplayMetrics = new DisplayMetrics();
+ mWindowManager.getDefaultDisplay().getMetrics(mDisplayMetrics);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/autojs/src/main/java/com/stardust/enhancedfloaty/gesture/DragGesture.java b/autojs/src/main/java/com/stardust/enhancedfloaty/gesture/DragGesture.java
new file mode 100644
index 00000000..99feaf80
--- /dev/null
+++ b/autojs/src/main/java/com/stardust/enhancedfloaty/gesture/DragGesture.java
@@ -0,0 +1,132 @@
+package com.stardust.enhancedfloaty.gesture;
+
+
+import android.view.GestureDetector;
+import android.view.MotionEvent;
+import android.view.View;
+
+import androidx.core.view.GestureDetectorCompat;
+
+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 mFlung = false;
+ private boolean mKeepToSide;
+ private float mPressedAlpha = 0.7f;
+ private float mUnpressedAlpha = 1.0f;
+
+ 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 (!mFlung && isKeepToSide()) {
+ keepToSide();
+ }
+ }
+ return true;
+ }
+ });
+ }
+
+ 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 setKeepToSide(boolean keepToSide) {
+ mKeepToSide = keepToSide;
+ }
+
+ public boolean isKeepToSide() {
+ return mKeepToSide;
+ }
+
+ 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();
+ mFlung = false;
+ return false;
+ }
+
+ @Override
+ public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
+ mWindowBridge.updatePosition(mInitialX + (int) ((e2.getRawX() - mInitialTouchX)),
+ mInitialY + (int) ((e2.getRawY() - mInitialTouchY)));
+ mView.setAlpha(mPressedAlpha);
+ return false;
+ }
+
+ @Override
+ public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
+ mFlung = true;
+ if (mKeepToSide)
+ keepToSide();
+ return false;
+ }
+
+ public void keepToSide() {
+ 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/autojs/src/main/java/com/stardust/enhancedfloaty/gesture/ResizeGesture.java b/autojs/src/main/java/com/stardust/enhancedfloaty/gesture/ResizeGesture.java
new file mode 100644
index 00000000..efc58bca
--- /dev/null
+++ b/autojs/src/main/java/com/stardust/enhancedfloaty/gesture/ResizeGesture.java
@@ -0,0 +1,109 @@
+package com.stardust.enhancedfloaty.gesture;
+
+import android.content.Context;
+import android.view.GestureDetector;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.annotation.Nullable;
+
+import com.stardust.enhancedfloaty.WindowBridge;
+
+/**
+ * Created by Stardust on 2017/4/18.
+ */
+
+public class ResizeGesture extends GestureDetector.SimpleOnGestureListener {
+
+ public static ResizeGesture enableResize(View resizer, @Nullable View resizableView, WindowBridge windowBridge) {
+ ResizeGesture resizeGesture = new ResizeGesture(windowBridge, resizer, resizableView);
+ final GestureDetector detector = new GestureDetector(resizer.getContext(), resizeGesture);
+ resizer.setOnTouchListener(new View.OnTouchListener() {
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ detector.onTouchEvent(event);
+ return true;
+ }
+ });
+ return resizeGesture;
+ }
+
+ public static ResizeGesture enableResize(View resizer, WindowBridge windowBridge) {
+ return enableResize(resizer, null, windowBridge);
+ }
+
+ private WindowBridge mWindowBridge;
+ private float initialTouchX;
+ private float initialTouchY;
+ private int mInitialWidth, mInitialHeight;
+ private View mResizerView;
+ private int mMinHeight = 200, mMinWidth = 200;
+ private final int mStatusBarHeight;
+ private View mResizableView;
+
+
+ public ResizeGesture(WindowBridge windowBridge, View resizerView, @Nullable View resizableView) {
+ mWindowBridge = windowBridge;
+ mResizerView = resizerView;
+ mResizableView = resizableView;
+ mStatusBarHeight = getStatusBarHeight(resizerView.getContext());
+ }
+
+ private int getStatusBarHeight(Context context) {
+ int result = 0;
+ int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
+ if (resourceId > 0) {
+ result = context.getResources().getDimensionPixelSize(resourceId);
+ }
+ return result;
+ }
+
+ public void setMinHeight(int minHeight) {
+ mMinHeight = minHeight;
+ }
+
+ public void setMinWidth(int minWidth) {
+ mMinWidth = minWidth;
+ }
+
+ @Override
+ public boolean onDown(MotionEvent event) {
+ initialTouchX = event.getRawX();
+ initialTouchY = event.getRawY();
+ mInitialWidth = mResizableView != null ? mResizableView.getWidth() : mWindowBridge.getWidth();
+ mInitialHeight = mResizableView != null ? mResizableView.getHeight() : mWindowBridge.getHeight();
+ return false;
+ }
+
+ @Override
+ public boolean onScroll(MotionEvent e1, final MotionEvent e2, float distanceX, float distanceY) {
+ int newWidth = mInitialWidth + (int) ((e2.getRawX() - initialTouchX));
+ int newHeight = mInitialHeight + (int) ((e2.getRawY() - initialTouchY));
+ newWidth = Math.max(mMinWidth, newWidth);
+ newHeight = Math.max(mMinHeight, newHeight);
+ newWidth = Math.min(mWindowBridge.getScreenWidth() - getX() - mResizerView.getWidth(), newWidth);
+ newHeight = Math.min(mWindowBridge.getScreenHeight() - getY() - mResizerView.getHeight() - mStatusBarHeight, newHeight);
+ updateMeasure(newWidth, newHeight);
+ return true;
+ }
+
+ private void updateMeasure(int newWidth, int newHeight) {
+ if (mResizableView == null) {
+ mWindowBridge.updateMeasure(newWidth, newHeight);
+ } else {
+ ViewGroup.LayoutParams params = mResizableView.getLayoutParams();
+ params.width = newWidth;
+ params.height = newHeight;
+ mResizableView.setLayoutParams(params);
+ }
+ }
+
+ private int getY() {
+ return mResizableView != null ? (int) mResizableView.getY() : mWindowBridge.getY();
+ }
+
+ private int getX() {
+ return mResizableView != null ? (int) mResizableView.getX() : mWindowBridge.getX();
+ }
+}
\ No newline at end of file
diff --git a/autojs/src/main/java/com/stardust/enhancedfloaty/util/FloatingWindowPermissionUtil.java b/autojs/src/main/java/com/stardust/enhancedfloaty/util/FloatingWindowPermissionUtil.java
new file mode 100644
index 00000000..f4f2f245
--- /dev/null
+++ b/autojs/src/main/java/com/stardust/enhancedfloaty/util/FloatingWindowPermissionUtil.java
@@ -0,0 +1,57 @@
+package com.stardust.enhancedfloaty.util;
+
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Build;
+import android.provider.Settings;
+
+/**
+ * Created by Stardust on 2017/3/10.
+ */
+
+public class FloatingWindowPermissionUtil {
+
+ public static void goToFloatingWindowPermissionSettingIfNeeded(Context context) {
+ if (!hasFloatingWindowPermission(context)) {
+ goToFloatingWindowPermissionSetting(context);
+ }
+ }
+
+ public static void goToFloatingWindowPermissionSetting(Context context) {
+ String packageName = context.getPackageName();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ try {
+ context.startActivity(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
+ Uri.parse("package:" + packageName))
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+ } catch (Exception e) {
+ goToAppDetailSettings(context, packageName);
+ }
+ } else {
+ goToAppDetailSettings(context, packageName);
+ }
+ }
+
+ public static boolean hasFloatingWindowPermission(Context context) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ return Settings.canDrawOverlays(context);
+ }
+ return true;
+ }
+
+ public static boolean goToAppDetailSettings(Context context, String packageName) {
+ try {
+ Intent i = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+ i.addCategory(Intent.CATEGORY_DEFAULT);
+ i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ i.setData(Uri.parse("package:" + packageName));
+ context.startActivity(i);
+ return true;
+ } catch (ActivityNotFoundException ignored) {
+ return false;
+ }
+ }
+
+}
diff --git a/autojs/src/main/java/com/stardust/enhancedfloaty/util/WindowTypeCompat.java b/autojs/src/main/java/com/stardust/enhancedfloaty/util/WindowTypeCompat.java
new file mode 100644
index 00000000..c8e3eadf
--- /dev/null
+++ b/autojs/src/main/java/com/stardust/enhancedfloaty/util/WindowTypeCompat.java
@@ -0,0 +1,25 @@
+package com.stardust.enhancedfloaty.util;
+
+import android.os.Build;
+import android.view.WindowManager;
+
+public class WindowTypeCompat {
+
+
+ public static int getWindowType() {
+ return getWindowType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+ }
+
+ public static int getPhoneWindowType() {
+ return getWindowType(WindowManager.LayoutParams.TYPE_PHONE);
+ }
+
+ public static int getWindowType(int type) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ return WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+ } else {
+ return type;
+ }
+ }
+
+}
diff --git a/autojs/src/main/java/com/stardust/widget/ViewSupplier.java b/autojs/src/main/java/com/stardust/widget/ViewSupplier.java
new file mode 100644
index 00000000..6074e29c
--- /dev/null
+++ b/autojs/src/main/java/com/stardust/widget/ViewSupplier.java
@@ -0,0 +1,20 @@
+package com.stardust.widget;
+
+import android.content.Context;
+import android.view.View;
+
+import java.io.Serializable;
+
+/**
+ * Created by Stardust on 2017/4/18.
+ *
+ * The interface and its implementations must be serializable.
+ * Only in this way it can be set to intent extra and be used as service argument.
+ * So, implementations should not has any non-serializable fields.
+ */
+
+
+public interface ViewSupplier extends Serializable {
+
+ View inflateView(Context context);
+}
diff --git a/autojs/src/main/java/com/stardust/widget/ViewSwitcher.java b/autojs/src/main/java/com/stardust/widget/ViewSwitcher.java
new file mode 100644
index 00000000..aa99e07d
--- /dev/null
+++ b/autojs/src/main/java/com/stardust/widget/ViewSwitcher.java
@@ -0,0 +1,63 @@
+package com.stardust.widget;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+
+/**
+ * Created by Stardust on 2017/3/11.
+ */
+
+public class ViewSwitcher extends android.widget.ViewSwitcher {
+
+ private View mCurrentView;
+
+ public ViewSwitcher(Context context) {
+ super(context);
+ }
+
+ public ViewSwitcher(Context context, View first, View second) {
+ super(context);
+ addView(first);
+ addView(second);
+ }
+
+ public ViewSwitcher(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public View getCurrentView() {
+ return mCurrentView;
+ }
+
+ public int getCurrentViewIndex() {
+ return mCurrentView == getChildAt(0) ? 0 : 1;
+ }
+
+ public void showFirst() {
+ ensureCurrentView();
+ if (mCurrentView != getChildAt(0)) {
+ showPrevious();
+ mCurrentView = getChildAt(0);
+ }
+ }
+
+ private void ensureCurrentView() {
+ if (mCurrentView == null) {
+ mCurrentView = getChildAt(0);
+ }
+ }
+
+ public void showSecond() {
+ ensureCurrentView();
+ if (mCurrentView != getChildAt(1)) {
+ showNext();
+ mCurrentView = getChildAt(1);
+ }
+ }
+
+ public void setSecondView(View v) {
+ removeViewAt(1);
+ addView(v);
+ }
+}
diff --git a/autojs/src/main/java/com/taobao/idlefish/AccessibilityService.kt b/autojs/src/main/java/com/taobao/idlefish/AccessibilityService.kt
index d60b7a52..c7687e14 100644
--- a/autojs/src/main/java/com/taobao/idlefish/AccessibilityService.kt
+++ b/autojs/src/main/java/com/taobao/idlefish/AccessibilityService.kt
@@ -4,6 +4,7 @@ import android.accessibilityservice.AccessibilityServiceInfo
import android.os.Build
import android.view.WindowManager
import com.stardust.autojs.core.pref.Pref
+import com.stardust.enhancedfloaty.FloatyService
import com.stardust.view.accessibility.AccessibilityService
class AccessibilityService: AccessibilityService() {
@@ -30,6 +31,10 @@ class AccessibilityService: AccessibilityService() {
}
override fun getWindowManager() : WindowManager {
- return windowManager;
+ return windowManager
+ }
+
+ override fun refreshFloatyService() {
+ FloatyService.getInstance()?.refreshAccessWindowManager()
}
}
\ No newline at end of file
diff --git a/autojs/src/main/res/layout/ef_expandable_floaty_container.xml b/autojs/src/main/res/layout/ef_expandable_floaty_container.xml
new file mode 100644
index 00000000..e2910040
--- /dev/null
+++ b/autojs/src/main/res/layout/ef_expandable_floaty_container.xml
@@ -0,0 +1,6 @@
+
+
+
diff --git a/autojs/src/main/res/layout/ef_floaty_container.xml b/autojs/src/main/res/layout/ef_floaty_container.xml
new file mode 100644
index 00000000..de41fd84
--- /dev/null
+++ b/autojs/src/main/res/layout/ef_floaty_container.xml
@@ -0,0 +1,7 @@
+
+
+
+
\ No newline at end of file
diff --git a/automator/src/main/java/com/stardust/view/accessibility/AccessibilityService.kt b/automator/src/main/java/com/stardust/view/accessibility/AccessibilityService.kt
index 1dd42252..bc88bf67 100644
--- a/automator/src/main/java/com/stardust/view/accessibility/AccessibilityService.kt
+++ b/automator/src/main/java/com/stardust/view/accessibility/AccessibilityService.kt
@@ -100,6 +100,7 @@ open class AccessibilityService : android.accessibilityservice.AccessibilityServ
Log.v(TAG, "onDestroy: $instance")
instance = null
mEventExecutor?.shutdownNow()
+ refreshFloatyService()
super.onDestroy()
}
@@ -107,6 +108,7 @@ open class AccessibilityService : android.accessibilityservice.AccessibilityServ
override fun onServiceConnected() {
Log.v(TAG, "onServiceConnected: " + serviceInfo.toString())
instance = this
+ refreshFloatyService()
super.onServiceConnected()
LOCK.lock()
ENABLED.signalAll()
@@ -119,6 +121,13 @@ open class AccessibilityService : android.accessibilityservice.AccessibilityServ
return mFastRootInActiveWindow
}
+ /**
+ * 刷新悬浮窗的windowManager
+ */
+ open fun refreshFloatyService() {
+ // do refresh on sub class
+ }
+
open fun getWindowManager() : WindowManager? {
return null;
}
diff --git a/automator/src/main/java/com/stardust/view/accessibility/AccessibilityServiceUtils.kt b/automator/src/main/java/com/stardust/view/accessibility/AccessibilityServiceUtils.kt
index aa3685b6..6231e897 100644
--- a/automator/src/main/java/com/stardust/view/accessibility/AccessibilityServiceUtils.kt
+++ b/automator/src/main/java/com/stardust/view/accessibility/AccessibilityServiceUtils.kt
@@ -7,8 +7,6 @@ import android.content.Intent
import android.provider.Settings
import android.text.TextUtils
-import java.util.Locale
-
/**
* Created by Stardust on 2017/1/26.