微信自动回复功能实现

参考:http://www.jianshu.com/p/f67e950d84f7
源码: itsMelo https://github.com/itsMelo/WcAutoReply#fork-destination-box
扩展-自动抢红包http://blog.csdn.net/qq_15796477/article/details/52130416

思路
实现AccessibilityService,重写onAccessibilityEvent(final AccessibilityEvent event),判断event对象是TYPE_NOTIFICATION_STATE_CHANGED(通知栏事件)还是TYPE_WINDOW_STATE_CHANGED(窗体状态改变事件)。
若是TYPE_NOTIFICATION_STATE_CHANGED(通知栏事件)
1.判断是否处于锁屏状态。若是,则唤醒屏幕解锁。
2.判断app是否处于前台。若是,拉起微信。1s后,设置回复文本,模拟点击发送按钮发送。若处于后台,则拉起微信。重复1,2。
相关api
1.判断是否处于锁屏状态是通过KeyguardManager的实例inKeyguardRestrictedInputMode()方法实现。

 /**
     * 系统是否在锁屏状态
     *
     * @return
     */
    private boolean isScreenLocked() {
        KeyguardManager keyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
        return keyguardManager.inKeyguardRestrictedInputMode();
    }

2.唤醒屏幕并解锁
通过PowerManager.WakeLock对象实例acquire()方法唤醒屏幕,KeyguardManager.KeyguardLock对象实例的disableKeyguard()实现解锁。

private void wakeAndUnlock() {
        //获取电源管理器对象
        PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);

        //获取PowerManager.WakeLock对象,后面的参数|表示同时传入两个值,最后的是调试用的Tag
        PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "bright");

        //点亮屏幕
        wl.acquire(1000);

        //得到键盘锁管理器对象
        KeyguardManager km = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
        kl = km.newKeyguardLock("unLock");

        //解锁
        kl.disableKeyguard();

    }


3.判断app是否处于前台
原理是通过ActivityManager实例的getRunningTasks(1).get(0).topActivity()获取顶部的activity即ComponentName 对象,若ComponentName实例包名一致则在前台。

/**
 * 判断指定的应用是否在前台运行
 *
 * @param packageName
 * @return
 */
private boolean isAppForeground(String packageName) {
    ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
    ComponentName cn = am.getRunningTasks(1).get(0).topActivity;
    String currentPackageName = cn.getPackageName();
    if (!TextUtils.isEmpty(currentPackageName) && currentPackageName.equals(packageName)) {
        return true;
    }

    return false;
}

4.调起微信

 Notification notification = (Notification) event.getParcelableData();
                     PendingIntent pendingIntent = notification.contentIntent;

                pendingIntent.send();

5.设置自动回复的文本

getRootInActiveWindow获取活动窗口根节点,遍历子节点,通过nodeInfo.getContentDescription()获取微信对应的节点。获取EditText节点,通过ClipboardManager 对象设置ClipData,即设置给剪贴板对象。并执行粘贴操作。

  AccessibilityNodeInfo rootNode = getRootInActiveWindow();
  for (int i = 0; i < rootNode .getChildCount(); i++) {
            AccessibilityNodeInfo nodeInfo = rootNode.getChild(i);
            if (nodeInfo == null) {
                android.util.Log.d("maptrix", "nodeinfo = null");
                continue;
            }

            if(nodeInfo.getContentDescription() != null){
                int nindex = nodeInfo.getContentDescription().toString().indexOf(name);
                int cindex = nodeInfo.getContentDescription().toString().indexOf(scontent);

                if(nindex != -1){
                    itemNodeinfo = nodeInfo;
                }
            }

            if ("android.widget.EditText".equals(nodeInfo.getClassName())) {

                Bundle arguments = new Bundle();
                arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT,
                        AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD);
                arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN,
                        true);
                nodeInfo.performAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY,
                        arguments);
                nodeInfo.performAction(AccessibilityNodeInfo.ACTION_FOCUS);
                ClipData clip = ClipData.newPlainText("label", content);
                ClipboardManager clipboardManager = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
                clipboardManager.setPrimaryClip(clip);
                nodeInfo.performAction(AccessibilityNodeInfo.ACTION_PASTE);
                return true;
            }

        }

6.发送
nodeInfo.findAccessibilityNodeInfosByText(“发送”)获取发送按钮节点,performAction(AccessibilityNodeInfo.ACTION_CLICK)执行点击事件。

 /**
     * 寻找窗体中的“发送”按钮,并且点击。
     */
    @SuppressLint("NewApi")
    private void send() {
        AccessibilityNodeInfo nodeInfo = getRootInActiveWindow();
        if (nodeInfo != null) {
            List<AccessibilityNodeInfo> list = nodeInfo.findAccessibilityNodeInfosByText("发送");
            if (list != null && list.size() > 0) {
                for (AccessibilityNodeInfo n : list) {
                    if(n.getClassName().equals("android.widget.Button") && n.isEnabled()){
                        n.performAction(AccessibilityNodeInfo.ACTION_CLICK);
                    }
                }

            } else {
                List<AccessibilityNodeInfo> liste = nodeInfo
                        .findAccessibilityNodeInfosByText("Send");
                if (liste != null && liste.size() > 0) {
                    for (AccessibilityNodeInfo n : liste) {
                        if(n.getClassName().equals("android.widget.Button") && n.isEnabled()){
                            n.performAction(AccessibilityNodeInfo.ACTION_CLICK);
                        }
                    }
                }
            }
            pressBackButton();
        }
    }

若是TYPE_WINDOW_STATE_CHANGED(窗体状态变化事件)

1.判断event类名是否是微信的LaunchUI(即event.getClassName().toString()
Equals(“com.tencent.mm.ui.LauncherUI”))若是,则设置回复文本。
2.判断设置回复文本是否成功,成功则发送。失败,则模拟点击事件,重新设置回复文本。设置成功后发送。
3.返回系统桌面,释放键盘键对象。

  case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:
                android.util.Log.d("maptrix", "get type window down event");
                if (!hasAction) break;
                itemNodeinfo = null;
                String className = event.getClassName().toString();
                if (className.equals("com.tencent.mm.ui.LauncherUI")) {
                    if (fill()) {
                        send();
                    }else {
                        if(itemNodeinfo != null){
                            itemNodeinfo.performAction(AccessibilityNodeInfo.ACTION_CLICK);
                            handler.postDelayed(new Runnable() {
                                @Override
                                public void run() {
                                    if (fill()) {
                                        send();
                                    }
                                    back2Home();
                                    release();
                                    hasAction = false;
                                }
                            }, 1000);
                            break;
                        }
                    }
                }
                //bring2Front();
                back2Home();
                release();
                hasAction = false;
                break;

流程图:
这里写图片描述

©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页