mirror of
https://github.com/TonyJiangWJ/Auto.js.git
synced 2026-06-24 21:33:16 +08:00
安卓12悬浮窗功能修改:RawWindow在有无障碍权限时挂载在无障碍WindowManager 避免setTouchable(false) 失效
This commit is contained in:
parent
b486d0cbff
commit
e1009c5003
@ -145,6 +145,7 @@ dependencies {
|
||||
implementation 'androidx.cardview:cardview:1.0.0'
|
||||
implementation 'com.google.android.material:material:1.4.0'
|
||||
implementation 'androidx.multidex:multidex:2.0.1'
|
||||
implementation 'androidx.activity:activity-ktx:1.4.0'
|
||||
// Personal libraries
|
||||
implementation 'com.github.hyb1996:MutableTheme:1.0.0'
|
||||
// Material Dialogs
|
||||
|
||||
@ -22,7 +22,6 @@ import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
import com.stardust.app.FragmentPagerAdapterBuilder;
|
||||
import com.stardust.app.OnActivityResultDelegate;
|
||||
import com.stardust.autojs.core.floaty.AccessibilityFloatyService;
|
||||
import com.stardust.autojs.core.permission.OnRequestPermissionsResultCallback;
|
||||
import com.stardust.autojs.core.permission.PermissionRequestProxyActivity;
|
||||
import com.stardust.autojs.core.permission.RequestPermissionCallbacks;
|
||||
@ -273,7 +272,6 @@ public class MainActivity extends BaseActivity implements OnActivityResultDelega
|
||||
FloatyWindowManger.hideCircularMenu();
|
||||
ForegroundService.stop(this);
|
||||
stopService(new Intent(this, FloatyService.class));
|
||||
stopService(new Intent(this, AccessibilityFloatyService.class));
|
||||
AutoJs.getInstance().getScriptEngineService().stopAll();
|
||||
}
|
||||
|
||||
|
||||
@ -53,7 +53,6 @@ dependencies {
|
||||
exclude group: 'com.android.support'
|
||||
})
|
||||
api 'com.google.android.material:material:1.4.0'
|
||||
api 'com.github.hyb1996:EnhancedFloaty:0.31'
|
||||
api 'com.makeramen:roundedimageview:2.3.0'
|
||||
// OpenCv
|
||||
api project(path: ':autojs-aar:opencv')
|
||||
|
||||
@ -50,11 +50,9 @@
|
||||
android:resource="@xml/accessibility_service_config"/>
|
||||
</service>
|
||||
|
||||
<service android:name="com.stardust.autojs.core.floaty.AccessibilityFloatyService"
|
||||
android:exported="false"/>
|
||||
|
||||
<service android:name="com.stardust.enhancedfloaty.FloatyService"
|
||||
android:exported="false" tools:node="merge"/>
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
||||
@ -2,11 +2,15 @@ package com.stardust.autojs.core.accessibility
|
||||
|
||||
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() {
|
||||
|
||||
private lateinit var windowManager: WindowManager
|
||||
|
||||
override fun onServiceConnected() {
|
||||
val serviceInfo = serviceInfo
|
||||
if (Pref.isStableModeEnabled) {
|
||||
@ -21,7 +25,16 @@ class AccessibilityService : AccessibilityService() {
|
||||
serviceInfo.flags = serviceInfo.flags and AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE.inv()
|
||||
}
|
||||
}
|
||||
windowManager = getSystemService(WINDOW_SERVICE) as WindowManager
|
||||
setServiceInfo(serviceInfo)
|
||||
super.onServiceConnected()
|
||||
}
|
||||
|
||||
override fun getWindowManager() : WindowManager {
|
||||
return windowManager
|
||||
}
|
||||
|
||||
override fun refreshFloatyService() {
|
||||
FloatyService.getInstance()?.refreshAccessWindowManager()
|
||||
}
|
||||
}
|
||||
@ -1,66 +0,0 @@
|
||||
package com.stardust.autojs.core.floaty;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.IBinder;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.stardust.enhancedfloaty.FloatyService;
|
||||
import com.stardust.enhancedfloaty.FloatyWindow;
|
||||
import com.taobao.idlefish.AccessibilityService;
|
||||
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
public class AccessibilityFloatyService extends FloatyService {
|
||||
|
||||
private static final CopyOnWriteArraySet<FloatyWindow> windows = new CopyOnWriteArraySet();
|
||||
private static AccessibilityFloatyService instance;
|
||||
private WindowManager mWindowManager;
|
||||
|
||||
public static void addWindow(FloatyWindow window) {
|
||||
if (windows.add(window) && instance != null) {
|
||||
window.onCreate(instance, instance.mWindowManager);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void removeWindow(FloatyWindow window) {
|
||||
windows.remove(window);
|
||||
}
|
||||
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
if (AccessibilityService.Companion.getInstance() != null) {
|
||||
this.mWindowManager = AccessibilityService.Companion.getInstance().getWindowManager();
|
||||
}
|
||||
if (this.mWindowManager == null) {
|
||||
this.mWindowManager = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE);
|
||||
}
|
||||
for (FloatyWindow delegate : windows) {
|
||||
delegate.onCreate(this, this.mWindowManager);
|
||||
}
|
||||
|
||||
instance = this;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
if (AccessibilityService.Companion.getInstance() == null) {
|
||||
return null;
|
||||
}
|
||||
return AccessibilityService.Companion.getInstance().onBind(intent);
|
||||
}
|
||||
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
instance = null;
|
||||
|
||||
for (FloatyWindow delegate : windows) {
|
||||
delegate.onServiceDestroy(this);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -84,7 +84,7 @@ public class RawWindow extends FloatyWindow {
|
||||
|
||||
private int getWindowType() {
|
||||
if (AccessibilityService.Companion.getInstance()!= null
|
||||
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
|
||||
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
return WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
|
||||
}
|
||||
return WindowTypeCompat.getWindowType();
|
||||
@ -116,6 +116,9 @@ public class RawWindow extends FloatyWindow {
|
||||
@Override
|
||||
public void close() {
|
||||
super.close();
|
||||
if (mContentView == null) {
|
||||
return;
|
||||
}
|
||||
ViewExtras.recycle(mContentView);
|
||||
ViewParent parent = mContentView.getParent();
|
||||
if (parent instanceof View) {
|
||||
|
||||
@ -7,7 +7,6 @@ import android.view.ContextThemeWrapper;
|
||||
import android.view.View;
|
||||
|
||||
import com.stardust.autojs.R;
|
||||
import com.stardust.autojs.core.floaty.AccessibilityFloatyService;
|
||||
import com.stardust.autojs.core.floaty.BaseResizableFloatyWindow;
|
||||
import com.stardust.autojs.core.floaty.RawWindow;
|
||||
import com.stardust.autojs.core.ui.JsViewHelper;
|
||||
@ -112,8 +111,8 @@ public class Floaty {
|
||||
public JsRawWindow(RawWindow.RawFloaty floaty) {
|
||||
mWindow = new RawWindow(floaty);
|
||||
mUiHandler.post(() -> {
|
||||
mUiHandler.getContext().startService(new Intent(mUiHandler.getContext(), AccessibilityFloatyService.class));
|
||||
AccessibilityFloatyService.addWindow(mWindow);
|
||||
mUiHandler.getContext().startService(new Intent(mUiHandler.getContext(), FloatyService.class));
|
||||
FloatyService.addWindow(mWindow);
|
||||
});
|
||||
RuntimeException exception = mWindow.waitForCreation();
|
||||
if (exception != Exceptions.NO_EXCEPTION && exception != null) {
|
||||
|
||||
@ -0,0 +1,95 @@
|
||||
package com.stardust.enhancedfloaty;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.stardust.autojs.core.floaty.RawWindow;
|
||||
import com.taobao.idlefish.AccessibilityService;
|
||||
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/5/1.
|
||||
*/
|
||||
public class FloatyService extends Service {
|
||||
|
||||
private static CopyOnWriteArraySet<FloatyWindow> windows = new CopyOnWriteArraySet<>();
|
||||
|
||||
private static FloatyService instance;
|
||||
private WindowManager mWindowManager;
|
||||
private WindowManager accessibilityWindowManager;
|
||||
|
||||
public static void addWindow(FloatyWindow window) {
|
||||
if (windows.add(window) && instance != null) {
|
||||
instance.appendWindow(window);
|
||||
}
|
||||
}
|
||||
|
||||
public static void removeWindow(FloatyWindow window) {
|
||||
windows.remove(window);
|
||||
}
|
||||
|
||||
public static FloatyService getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据无障碍链接情况刷新windowManager
|
||||
*/
|
||||
public void refreshAccessWindowManager() {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
|
||||
// 仅仅针对安卓12优化
|
||||
return;
|
||||
}
|
||||
if (AccessibilityService.Companion.getInstance() != null) {
|
||||
accessibilityWindowManager = AccessibilityService.Companion.getInstance().getWindowManager();
|
||||
} else {
|
||||
accessibilityWindowManager = null;
|
||||
}
|
||||
// TODO 目前设计当无障碍服务丢失后 RawWindow会自动移除 后续考虑将window重新添加 但是目前没有完美的方法
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
mWindowManager = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE);
|
||||
refreshAccessWindowManager();
|
||||
instance = this;
|
||||
for (FloatyWindow delegate : windows) {
|
||||
appendWindow(delegate);
|
||||
}
|
||||
}
|
||||
|
||||
private void appendWindow(FloatyWindow window) {
|
||||
if (instance == null) {
|
||||
return;
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S &&
|
||||
instance.accessibilityWindowManager != null && window instanceof RawWindow) {
|
||||
window.onCreate(instance, instance.accessibilityWindowManager);
|
||||
} else {
|
||||
window.onCreate(instance, instance.mWindowManager);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
instance = null;
|
||||
for (FloatyWindow delegate : windows) {
|
||||
delegate.onServiceDestroy(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,116 @@
|
||||
package com.stardust.enhancedfloaty;
|
||||
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import androidx.annotation.CallSuper;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/5/1.
|
||||
*/
|
||||
|
||||
public abstract class FloatyWindow {
|
||||
private WindowManager mWindowManager;
|
||||
private FloatyService mFloatyService;
|
||||
|
||||
private WindowBridge mWindowBridge;
|
||||
private WindowManager.LayoutParams mWindowLayoutParams;
|
||||
private View mWindowView;
|
||||
|
||||
@CallSuper
|
||||
public void onCreate(FloatyService service, WindowManager manager) {
|
||||
mFloatyService = service;
|
||||
mWindowManager = manager;
|
||||
onCreateWindow(service, manager);
|
||||
}
|
||||
|
||||
|
||||
protected void onCreateWindow(FloatyService service, WindowManager manager) {
|
||||
setWindowLayoutParams(onCreateWindowLayoutParams());
|
||||
setWindowView(onCreateView(service));
|
||||
setWindowBridge(onCreateWindowBridge(getWindowLayoutParams()));
|
||||
|
||||
onViewCreated(getWindowView());
|
||||
|
||||
//attach to window
|
||||
attachToWindow(getWindowView(), getWindowManager());
|
||||
}
|
||||
|
||||
protected void onViewCreated(View view) {
|
||||
|
||||
}
|
||||
|
||||
protected void attachToWindow(View view, WindowManager manager){
|
||||
getWindowManager().addView(view, getWindowLayoutParams());
|
||||
onAttachToWindow(view, manager);
|
||||
}
|
||||
|
||||
protected void onAttachToWindow(View view, WindowManager manager) {
|
||||
|
||||
}
|
||||
|
||||
protected abstract View onCreateView(FloatyService service);
|
||||
|
||||
protected WindowBridge onCreateWindowBridge(WindowManager.LayoutParams params) {
|
||||
return new WindowBridge.DefaultImpl(params, getWindowManager(), getWindowView());
|
||||
|
||||
}
|
||||
|
||||
protected abstract WindowManager.LayoutParams onCreateWindowLayoutParams();
|
||||
|
||||
public void updateWindowLayoutParams(WindowManager.LayoutParams params) {
|
||||
setWindowLayoutParams(params);
|
||||
mWindowManager.updateViewLayout(getWindowView(), getWindowLayoutParams());
|
||||
}
|
||||
|
||||
|
||||
protected void setWindowManager(WindowManager windowManager) {
|
||||
mWindowManager = windowManager;
|
||||
}
|
||||
|
||||
public WindowManager.LayoutParams getWindowLayoutParams() {
|
||||
return mWindowLayoutParams;
|
||||
}
|
||||
|
||||
protected void setWindowLayoutParams(WindowManager.LayoutParams windowLayoutParams) {
|
||||
mWindowLayoutParams = windowLayoutParams;
|
||||
}
|
||||
|
||||
public View getWindowView() {
|
||||
return mWindowView;
|
||||
}
|
||||
|
||||
protected void setWindowView(View windowView) {
|
||||
mWindowView = windowView;
|
||||
}
|
||||
|
||||
public FloatyService getFloatyService() {
|
||||
return mFloatyService;
|
||||
}
|
||||
|
||||
public WindowManager getWindowManager() {
|
||||
return mWindowManager;
|
||||
}
|
||||
|
||||
public WindowBridge getWindowBridge() {
|
||||
return mWindowBridge;
|
||||
}
|
||||
|
||||
protected void setWindowBridge(WindowBridge windowBridge) {
|
||||
mWindowBridge = windowBridge;
|
||||
}
|
||||
|
||||
public void onServiceDestroy(FloatyService service) {
|
||||
close();
|
||||
}
|
||||
|
||||
|
||||
public void close() {
|
||||
try {
|
||||
getWindowManager().removeView(getWindowView());
|
||||
FloatyService.removeWindow(this);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,141 @@
|
||||
package com.stardust.enhancedfloaty;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/4/19.
|
||||
*/
|
||||
|
||||
public interface ResizableExpandableFloaty {
|
||||
|
||||
|
||||
View inflateCollapsedView(FloatyService service, ResizableExpandableFloatyWindow window);
|
||||
|
||||
View inflateExpandedView(FloatyService service, ResizableExpandableFloatyWindow window);
|
||||
|
||||
@Nullable
|
||||
View getResizerView(View expandedView);
|
||||
|
||||
@Nullable
|
||||
View getMoveCursorView(View expandedView);
|
||||
|
||||
float getCollapsedHiddenWidthRadio();
|
||||
|
||||
float getCollapsedViewUnpressedAlpha();
|
||||
|
||||
float getCollapsedViewPressedAlpha();
|
||||
|
||||
|
||||
boolean shouldRequestFocusWhenExpand();
|
||||
|
||||
|
||||
int getInitialX();
|
||||
|
||||
|
||||
int getInitialY();
|
||||
|
||||
int getInitialHeight();
|
||||
|
||||
int getInitialWidth();
|
||||
|
||||
boolean isInitialExpanded();
|
||||
|
||||
abstract class AbstractResizableExpandableFloaty implements ResizableExpandableFloaty {
|
||||
private float mCollapsedHiddenWidthRadio = 0f;
|
||||
private float mCollapsedViewUnpressedAlpha = 0.7f;
|
||||
private float mCollapsedViewPressedAlpha = 1.0f;
|
||||
private boolean mShouldRequestFocusWhenExpand = true;
|
||||
private int mInitialX;
|
||||
private int mInitialY;
|
||||
private boolean mInitialExpanded = false;
|
||||
private int mInitialHeight;
|
||||
private int mInitialWidth;
|
||||
|
||||
@Nullable
|
||||
public View getResizerView(View expandedView) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public View getMoveCursorView(View expandedView) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public float getCollapsedHiddenWidthRadio() {
|
||||
return mCollapsedHiddenWidthRadio;
|
||||
}
|
||||
|
||||
public void setCollapsedHiddenWidthRadio(float collapsedHiddenWidthRadio) {
|
||||
this.mCollapsedHiddenWidthRadio = collapsedHiddenWidthRadio;
|
||||
}
|
||||
|
||||
public float getCollapsedViewUnpressedAlpha() {
|
||||
return mCollapsedViewUnpressedAlpha;
|
||||
}
|
||||
|
||||
public void setCollapsedViewUnpressedAlpha(float collapsedViewUnpressedAlpha) {
|
||||
mCollapsedViewUnpressedAlpha = collapsedViewUnpressedAlpha;
|
||||
}
|
||||
|
||||
public float getCollapsedViewPressedAlpha() {
|
||||
return mCollapsedViewPressedAlpha;
|
||||
}
|
||||
|
||||
public void setCollapsedViewPressedAlpha(float collapsedViewPressedAlpha) {
|
||||
mCollapsedViewPressedAlpha = collapsedViewPressedAlpha;
|
||||
}
|
||||
|
||||
public boolean shouldRequestFocusWhenExpand() {
|
||||
return mShouldRequestFocusWhenExpand;
|
||||
}
|
||||
|
||||
public void setShouldRequestFocusWhenExpand(boolean requestFocusWhenExpand) {
|
||||
mShouldRequestFocusWhenExpand = requestFocusWhenExpand;
|
||||
}
|
||||
|
||||
|
||||
public int getInitialX() {
|
||||
return mInitialX;
|
||||
}
|
||||
|
||||
public void setInitialX(int initialX) {
|
||||
mInitialX = initialX;
|
||||
}
|
||||
|
||||
public int getInitialY() {
|
||||
return mInitialY;
|
||||
}
|
||||
|
||||
public void setInitialY(int initialY) {
|
||||
mInitialY = initialY;
|
||||
}
|
||||
|
||||
public boolean isInitialExpanded() {
|
||||
return mInitialExpanded;
|
||||
}
|
||||
|
||||
public void setInitialExpanded(boolean initialExpanded) {
|
||||
mInitialExpanded = initialExpanded;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInitialHeight() {
|
||||
return mInitialHeight;
|
||||
}
|
||||
|
||||
public void setInitialHeight(int initialHeight) {
|
||||
mInitialHeight = initialHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInitialWidth() {
|
||||
return mInitialWidth;
|
||||
}
|
||||
|
||||
public void setInitialWidth(int initialWidth) {
|
||||
mInitialWidth = initialWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,302 @@
|
||||
package com.stardust.enhancedfloaty;
|
||||
|
||||
import android.graphics.PixelFormat;
|
||||
import android.view.Gravity;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.stardust.autojs.R;
|
||||
import com.stardust.enhancedfloaty.gesture.DragGesture;
|
||||
import com.stardust.enhancedfloaty.gesture.ResizeGesture;
|
||||
import com.stardust.enhancedfloaty.util.WindowTypeCompat;
|
||||
|
||||
import com.stardust.widget.ViewSwitcher;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/4/18.
|
||||
*/
|
||||
|
||||
public class ResizableExpandableFloatyWindow extends FloatyWindow {
|
||||
|
||||
private static final int INITIAL_WINDOW_PARAM_FLAG = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
|
||||
private static final String TAG = "ExpandableFloatyService";
|
||||
|
||||
|
||||
private ResizableExpandableFloaty mFloaty;
|
||||
private ViewSwitcher mCollapseExpandViewSwitcher;
|
||||
private View mCollapsedView;
|
||||
private View mExpandedView;
|
||||
private View mResizer;
|
||||
private View mMoveCursor;
|
||||
private DragGesture mDragGesture;
|
||||
private int mCollapsedViewX, mCollapsedViewY;
|
||||
private int mExpandedViewX, mExpandedViewY;
|
||||
|
||||
private ViewStack mViewStack = new ViewStack(new ViewStack.CurrentViewSetter() {
|
||||
@Override
|
||||
public void setCurrentView(View v) {
|
||||
mCollapseExpandViewSwitcher.setSecondView(v);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
public ResizableExpandableFloatyWindow(ResizableExpandableFloaty floaty) {
|
||||
if (floaty == null) {
|
||||
throw new NullPointerException("floaty == null");
|
||||
}
|
||||
mFloaty = floaty;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected View onCreateView(FloatyService service) {
|
||||
inflateWindowViews(service);
|
||||
View windowView = View.inflate(service, R.layout.ef_expandable_floaty_container, null);
|
||||
windowView.setFocusableInTouchMode(true);
|
||||
mCollapseExpandViewSwitcher = windowView.findViewById(R.id.container);
|
||||
mCollapseExpandViewSwitcher.setMeasureAllChildren(false);
|
||||
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
mCollapseExpandViewSwitcher.addView(mCollapsedView, params);
|
||||
mCollapseExpandViewSwitcher.addView(mExpandedView, params);
|
||||
mViewStack.setRootView(mExpandedView);
|
||||
return windowView;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachToWindow(View view, WindowManager manager) {
|
||||
super.onAttachToWindow(view, manager);
|
||||
initGesture();
|
||||
setKeyListener();
|
||||
setInitialState();
|
||||
}
|
||||
|
||||
public View getCollapsedView() {
|
||||
return mCollapsedView;
|
||||
}
|
||||
|
||||
public View getExpandedView() {
|
||||
return mExpandedView;
|
||||
}
|
||||
|
||||
public View getResizer() {
|
||||
return mResizer;
|
||||
}
|
||||
|
||||
public View getMoveCursor() {
|
||||
return mMoveCursor;
|
||||
}
|
||||
|
||||
protected ViewStack getViewStack() {
|
||||
return mViewStack;
|
||||
}
|
||||
|
||||
protected int getCollapsedViewX() {
|
||||
return mCollapsedViewX;
|
||||
}
|
||||
|
||||
protected void setCollapsedViewX(int collapsedViewX) {
|
||||
mCollapsedViewX = collapsedViewX;
|
||||
}
|
||||
|
||||
protected int getCollapsedViewY() {
|
||||
return mCollapsedViewY;
|
||||
}
|
||||
|
||||
protected void setCollapsedViewY(int collapsedViewY) {
|
||||
mCollapsedViewY = collapsedViewY;
|
||||
}
|
||||
|
||||
protected int getExpandedViewX() {
|
||||
return mExpandedViewX;
|
||||
}
|
||||
|
||||
protected void setExpandedViewX(int expandedViewX) {
|
||||
mExpandedViewX = expandedViewX;
|
||||
}
|
||||
|
||||
protected int getExpandedViewY() {
|
||||
return mExpandedViewY;
|
||||
}
|
||||
|
||||
protected void setExpandedViewY(int expandedViewY) {
|
||||
mExpandedViewY = expandedViewY;
|
||||
}
|
||||
|
||||
protected void setInitialState() {
|
||||
ResizableExpandableFloaty floaty = getFloaty();
|
||||
boolean expand = floaty.isInitialExpanded();
|
||||
if (expand) {
|
||||
setExpandedViewX(floaty.getInitialX());
|
||||
setExpandedViewY(floaty.getInitialY());
|
||||
expand();
|
||||
} else {
|
||||
setCollapsedViewX(floaty.getInitialX());
|
||||
setCollapsedViewX(floaty.getInitialY());
|
||||
getWindowBridge().updatePosition(getCollapsedViewX(), getCollapsedViewY());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected WindowBridge onCreateWindowBridge(WindowManager.LayoutParams params) {
|
||||
return new WindowBridge.DefaultImpl(params, getWindowManager(), getWindowView()) {
|
||||
@Override
|
||||
public void updatePosition(int x, int y) {
|
||||
super.updatePosition(x, y);
|
||||
if (getViewSwitcher().getCurrentView() == getExpandedView()) {
|
||||
setExpandedViewX(x);
|
||||
setExpandedViewY(y);
|
||||
} else {
|
||||
setCollapsedViewX(x);
|
||||
setCollapsedViewY(y);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
protected void inflateWindowViews(FloatyService service) {
|
||||
ResizableExpandableFloaty floaty = getFloaty();
|
||||
mExpandedView = floaty.inflateExpandedView(service, this);
|
||||
mCollapsedView = floaty.inflateCollapsedView(service, this);
|
||||
mResizer = floaty.getResizerView(getExpandedView());
|
||||
mMoveCursor = floaty.getMoveCursorView(getExpandedView());
|
||||
}
|
||||
|
||||
protected WindowManager.LayoutParams onCreateWindowLayoutParams() {
|
||||
WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
|
||||
WindowManager.LayoutParams.WRAP_CONTENT,
|
||||
WindowManager.LayoutParams.WRAP_CONTENT,
|
||||
WindowTypeCompat.getPhoneWindowType(),
|
||||
INITIAL_WINDOW_PARAM_FLAG,
|
||||
PixelFormat.TRANSLUCENT);
|
||||
layoutParams.gravity = Gravity.TOP | Gravity.START;
|
||||
return layoutParams;
|
||||
}
|
||||
|
||||
protected void initGesture() {
|
||||
enableResize();
|
||||
enableMove();
|
||||
}
|
||||
|
||||
protected void enableResize() {
|
||||
if (getResizer() != null) {
|
||||
ResizeGesture.enableResize(getResizer(), getExpandedView(), getWindowBridge());
|
||||
}
|
||||
}
|
||||
|
||||
public ResizableExpandableFloaty getFloaty() {
|
||||
return mFloaty;
|
||||
}
|
||||
|
||||
protected void enableMove() {
|
||||
if (getMoveCursor() != null) {
|
||||
DragGesture gesture = new DragGesture(getWindowBridge(), getMoveCursor());
|
||||
gesture.setPressedAlpha(1.0f);
|
||||
}
|
||||
DragGesture dragGesture = new DragGesture(getWindowBridge(), getCollapsedView());
|
||||
dragGesture.setUnpressedAlpha(getFloaty().getCollapsedViewUnpressedAlpha());
|
||||
dragGesture.setPressedAlpha(getFloaty().getCollapsedViewPressedAlpha());
|
||||
dragGesture.setKeepToSide(true);
|
||||
dragGesture.setKeepToSideHiddenWidthRadio(getFloaty().getCollapsedHiddenWidthRadio());
|
||||
dragGesture.setOnDraggedViewClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
expand();
|
||||
}
|
||||
});
|
||||
setDragGesture(dragGesture);
|
||||
}
|
||||
|
||||
protected void setDragGesture(DragGesture dragGesture) {
|
||||
mDragGesture = dragGesture;
|
||||
}
|
||||
|
||||
protected DragGesture getDragGesture() {
|
||||
return mDragGesture;
|
||||
}
|
||||
|
||||
public void expand() {
|
||||
getViewSwitcher().showSecond();
|
||||
//enableWindowLimit();
|
||||
if (getFloaty().shouldRequestFocusWhenExpand()) {
|
||||
requestWindowFocus();
|
||||
}
|
||||
getDragGesture().setKeepToSide(false);
|
||||
getWindowBridge().updatePosition(getExpandedViewX(), getExpandedViewY());
|
||||
}
|
||||
|
||||
protected ViewSwitcher getViewSwitcher() {
|
||||
return mCollapseExpandViewSwitcher;
|
||||
}
|
||||
|
||||
public void collapse() {
|
||||
getViewSwitcher().showFirst();
|
||||
disableWindowFocus();
|
||||
setWindowLayoutNoLimit();
|
||||
getDragGesture().setKeepToSide(true);
|
||||
getWindowBridge().updatePosition(getCollapsedViewX(), getCollapsedViewY());
|
||||
}
|
||||
|
||||
protected void setKeyListener() {
|
||||
getWindowView().setOnKeyListener(new View.OnKeyListener() {
|
||||
@Override
|
||||
public boolean onKey(View v, int keyCode, KeyEvent event) {
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
|
||||
onBackPressed();
|
||||
return true;
|
||||
}
|
||||
if (keyCode == KeyEvent.KEYCODE_HOME) {
|
||||
onHomePressed();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
private void onBackPressed() {
|
||||
ViewStack viewStack = getViewStack();
|
||||
if (viewStack.canGoBack()) {
|
||||
viewStack.goBack();
|
||||
} else {
|
||||
collapse();
|
||||
}
|
||||
}
|
||||
|
||||
private void onHomePressed() {
|
||||
getViewStack().goBackToFirst();
|
||||
collapse();
|
||||
}
|
||||
|
||||
|
||||
public void disableWindowFocus() {
|
||||
WindowManager.LayoutParams windowLayoutParams = getWindowLayoutParams();
|
||||
windowLayoutParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
|
||||
updateWindowLayoutParams(windowLayoutParams);
|
||||
}
|
||||
|
||||
public void setWindowLayoutInScreen() {
|
||||
WindowManager.LayoutParams windowLayoutParams = getWindowLayoutParams();
|
||||
windowLayoutParams.flags |= WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
|
||||
updateWindowLayoutParams(windowLayoutParams);
|
||||
}
|
||||
|
||||
public void requestWindowFocus() {
|
||||
WindowManager.LayoutParams windowLayoutParams = getWindowLayoutParams();
|
||||
windowLayoutParams.flags &= ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
|
||||
updateWindowLayoutParams(windowLayoutParams);
|
||||
getWindowView().requestFocus();
|
||||
}
|
||||
|
||||
public void setWindowLayoutNoLimit() {
|
||||
WindowManager.LayoutParams windowLayoutParams = getWindowLayoutParams();
|
||||
windowLayoutParams.flags |= WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
|
||||
updateWindowLayoutParams(windowLayoutParams);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,34 @@
|
||||
package com.stardust.enhancedfloaty;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/4/30.
|
||||
*/
|
||||
|
||||
public interface ResizableFloaty {
|
||||
|
||||
|
||||
View inflateView(FloatyService floatyService, ResizableFloatyWindow service);
|
||||
|
||||
@Nullable
|
||||
View getResizerView(View view);
|
||||
|
||||
@Nullable
|
||||
View getMoveCursorView(View view);
|
||||
|
||||
abstract class AbstractResizableFloaty implements ResizableFloaty {
|
||||
@Nullable
|
||||
public View getResizerView(View view) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public View getMoveCursorView(View view) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,92 @@
|
||||
package com.stardust.enhancedfloaty;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.stardust.autojs.R;
|
||||
import com.stardust.enhancedfloaty.gesture.DragGesture;
|
||||
import com.stardust.enhancedfloaty.gesture.ResizeGesture;
|
||||
import com.stardust.enhancedfloaty.util.WindowTypeCompat;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/4/30.
|
||||
*/
|
||||
|
||||
public class ResizableFloatyWindow extends FloatyWindow {
|
||||
|
||||
private static final String TAG = "ResizableFloatyWindow";
|
||||
|
||||
private View mView;
|
||||
private View mResizer;
|
||||
private View mMoveCursor;
|
||||
private ResizableFloaty mFloaty;
|
||||
|
||||
public ResizableFloatyWindow(ResizableFloaty floaty) {
|
||||
if (floaty == null) {
|
||||
throw new NullPointerException("floaty == null");
|
||||
}
|
||||
mFloaty = floaty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(FloatyService service, WindowManager manager) {
|
||||
super.onCreate(service, manager);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected View onCreateView(FloatyService service) {
|
||||
Context context = service.getApplicationContext();
|
||||
ViewGroup windowView = (ViewGroup) View.inflate(context, R.layout.ef_floaty_container, null);
|
||||
mView = mFloaty.inflateView(service, this);
|
||||
mResizer = mFloaty.getResizerView(mView);
|
||||
mMoveCursor = mFloaty.getMoveCursorView(mView);
|
||||
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
windowView.addView(mView, params);
|
||||
windowView.setFocusableInTouchMode(true);
|
||||
return windowView;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onViewCreated(View view) {
|
||||
super.onViewCreated(view);
|
||||
initGesture();
|
||||
}
|
||||
|
||||
protected WindowManager.LayoutParams onCreateWindowLayoutParams() {
|
||||
WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
|
||||
WindowManager.LayoutParams.WRAP_CONTENT,
|
||||
WindowManager.LayoutParams.WRAP_CONTENT,
|
||||
WindowTypeCompat.getPhoneWindowType(),
|
||||
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
|
||||
PixelFormat.TRANSLUCENT);
|
||||
layoutParams.gravity = Gravity.TOP | Gravity.START;
|
||||
return layoutParams;
|
||||
}
|
||||
|
||||
public View getRootView() {
|
||||
return mView;
|
||||
}
|
||||
|
||||
public View getResizer() {
|
||||
return mResizer;
|
||||
}
|
||||
|
||||
public View getMoveCursor() {
|
||||
return mMoveCursor;
|
||||
}
|
||||
|
||||
private void initGesture() {
|
||||
if (mResizer != null) {
|
||||
ResizeGesture.enableResize(mResizer, mView, getWindowBridge());
|
||||
}
|
||||
if (mMoveCursor != null) {
|
||||
DragGesture gesture = new DragGesture(getWindowBridge(), mMoveCursor);
|
||||
gesture.setPressedAlpha(1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,54 @@
|
||||
package com.stardust.enhancedfloaty;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/11.
|
||||
*/
|
||||
|
||||
public class ViewStack {
|
||||
|
||||
public interface CurrentViewSetter {
|
||||
void setCurrentView(View v);
|
||||
}
|
||||
|
||||
public interface NavigableView {
|
||||
void goBack();
|
||||
}
|
||||
|
||||
private Stack<View> 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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
20
autojs/src/main/java/com/stardust/widget/ViewSupplier.java
Normal file
20
autojs/src/main/java/com/stardust/widget/ViewSupplier.java
Normal file
@ -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.
|
||||
* <p>
|
||||
* 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);
|
||||
}
|
||||
63
autojs/src/main/java/com/stardust/widget/ViewSwitcher.java
Normal file
63
autojs/src/main/java/com/stardust/widget/ViewSwitcher.java
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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()
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.stardust.widget.ViewSwitcher xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/container"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
7
autojs/src/main/res/layout/ef_floaty_container.xml
Normal file
7
autojs/src/main/res/layout/ef_floaty_container.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/container"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
</RelativeLayout>
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user