高级安卓开发必备——查看当前Activity

障碍辅助功能AccessibilityService

提到这个障碍功能,可能大家想想到的是前几年很火的自动抢红包功能,基本都是在亮屏时候模拟用户点击事件,市面上也出现不少的红包插件,但是息屏的抢红包软件还是比较少的,前段时间已经完成了一个,但是还没做兼容适配,存在不少bug,目前在我的7.0的华为mate8手机上是完美的。后面开一篇博客专门讲。大致就是用服务实现的。

查看当前应用的Activity

很多同学刚去新公司看别人的代码头疼,又不知道代码写在哪里,时间浪费了,老是去问又不好,我刚来现在的公司时候,就存在这个现象,现在没有那么忙了,就做点贡献。不废话

思路

大致思路,借助AccessibilityService这个服务,相当于是打了一个擦边球,获取当前event的然后通过发消息去刷新一个浮窗

具体实现

1、首先在MainActivity 中 检查权限:

private void checkOverlayPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (!Settings.canDrawOverlays(this)) {
                startActivityForResult(
                        new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()))
                                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
                        REQUEST_CODE
                );
                Toast.makeText(this, "请先授予 \"栈顶通\" 悬浮窗权限", Toast.LENGTH_LONG).show();
            }
        }
    }

2.在点击开启的界面处理点击事件:

public static boolean checkAccessibility(Context context) {
        // 判断辅助功能是否开启
        if (!AccessibilityUtil.isAccessibilitySettingsOn(context)) {
            // 引导至辅助功能设置页面
            context.startActivity(new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)
                    .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
            );
            Toast.makeText(context, "请先开启 \"Activity 栈\" 的辅助功能", Toast.LENGTH_LONG).show();
            return false;
        }
        return true;
    }

3.自定义一个弹窗布局

public class FloatingView extends LinearLayout {
    private final Context mContext;
    private final WindowManager mWindowManager;
    private TextView mTvPackageName;
    private TextView mTvClassName;
    private ImageView mIvClose;

    public FloatingView(Context context) {
        this(context,null);
    }

    public FloatingView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        mContext = context;
        mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
        LayoutInflater.from(context).inflate(R.layout.floating_layout,this);
        initView();
    }

    private void initView() {
        mTvPackageName = (TextView) findViewById(R.id.tv_package_name);
        mTvClassName = (TextView) findViewById(R.id.tv_class_name);
        mIvClose = (ImageView) findViewById(R.id.iv_close);
        mIvClose.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(mContext, "关闭悬浮框", Toast.LENGTH_SHORT).show();
                mContext.startService(
                        new Intent(mContext, TrackerService.class)
                                .putExtra(TrackerService.COMMAND, TrackerService.COMMAND_CLOSE)
                );
            }
        });
    }

    Point preP, curP;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                preP = new Point((int)event.getRawX(), (int)event.getRawY());
                break;

            case MotionEvent.ACTION_MOVE:
                curP = new Point((int)event.getRawX(), (int)event.getRawY());
                int dx = curP.x - preP.x,
                        dy = curP.y - preP.y;

                WindowManager.LayoutParams layoutParams = (WindowManager.LayoutParams) this.getLayoutParams();
                layoutParams.x += dx;
                layoutParams.y += dy;
                mWindowManager.updateViewLayout(this, layoutParams);

                preP = curP;
                break;
        }


        return false;
    }
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onEventMainThread(TrackerService.ActivityChangedEvent event){
        Log.d(TAG, "event:" + event.getPackageName() + ": " + event.getClassName());
        String packageName = event.getPackageName(),
                className = event.getClassName();

        mTvPackageName.setText(packageName);
        mTvClassName.setText(
                className.startsWith(packageName)?
                        className.substring(packageName.length()):
                        className
        );
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        EventBus.getDefault().register(this);
        Log.d(TAG, "event:      服务关闭" );
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        Log.d(TAG, "event:      服务关闭" );
        EventBus.getDefault().unregister(this);
    }
}

4.发送事件


 @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        Log.d(TAG, "event:" + event.getPackageName() + ": " + event.getClassName());
        if(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED == event.getEventType()){
//        if(AccessibilityEvent.TYPE_WINDOWS_CHANGED == event.getEventType()){  //这个坑B
            Log.d(TAG, "窗口改变发送方了一次请求" + event.getPackageName() + ": " + event.getClassName());
            EventBus.getDefault().post(new ActivityChangedEvent(event.getPackageName().toString(),event.getClassName().toString()));
        }
    }
这里有个比较坑的地方小心了

5.接受事件

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onEventMainThread(TrackerService.ActivityChangedEvent event){
        Log.d(TAG, "event:" + event.getPackageName() + ": " + event.getClassName());
        String packageName = event.getPackageName(),
                className = event.getClassName();

        mTvPackageName.setText(packageName);
        mTvClassName.setText(
                className.startsWith(packageName)?
                        className.substring(packageName.length()):
                        className
        );
    }

总结

在魅族小米手机上悬浮窗要在设置里面去开

你可能感兴趣的:(高级安卓开发必备——查看当前Activity)