android开发之代理Window.Callback

2023-11-06

Window.Callback是window类的一个内部接口。该接口包含了一系列类似于dispatchXXX和onXXX的接口。当window接收到外界状态改变的通知时,就会回调其中的相应方法。比如,当用户点击某个控件时,就会回调Window.Callback中的dispatchTouchEvent方法。

  • window.Callback的定义如下:
 public interface Callback {
        boolean dispatchKeyEvent(KeyEvent var1);

        boolean dispatchKeyShortcutEvent(KeyEvent var1);

        boolean dispatchTouchEvent(MotionEvent var1);

        boolean dispatchTrackballEvent(MotionEvent var1);

        boolean dispatchGenericMotionEvent(MotionEvent var1);

        boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent var1);

        @Nullable
        View onCreatePanelView(int var1);

        boolean onCreatePanelMenu(int var1, @NonNull Menu var2);

        boolean onPreparePanel(int var1, @Nullable View var2, @NonNull Menu var3);

        boolean onMenuOpened(int var1, @NonNull Menu var2);

        boolean onMenuItemSelected(int var1, @NonNull MenuItem var2);

        void onWindowAttributesChanged(LayoutParams var1);

        void onContentChanged();

        void onWindowFocusChanged(boolean var1);

        void onAttachedToWindow();

        void onDetachedFromWindow();

        void onPanelClosed(int var1, @NonNull Menu var2);

        boolean onSearchRequested();

        boolean onSearchRequested(SearchEvent var1);

        @Nullable
        ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback var1);

        @Nullable
        ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback var1, int var2);

        void onActionModeStarted(ActionMode var1);

        void onActionModeFinished(ActionMode var1);

        default void onProvideKeyboardShortcuts(List<KeyboardShortcutGroup> data, @Nullable Menu menu, int deviceId) {
            throw new RuntimeException("Stub!");
        }

        default void onPointerCaptureChanged(boolean hasCapture) {
            throw new RuntimeException("Stub!");
        }
    }
  • 这个方法可以用来实现全埋点,通过activity.getWindow方法拿到这个activity对应的window对象,再通过window.getCallback方法就可以拿到当前对应的Callback对象,然后我们在代理这个callback对象就可以找到被点击的view对象,并插入埋点代码。

  • 案例如下:

package com.mvp.myapplication

import android.annotation.TargetApi
import android.app.Activity
import android.graphics.Rect
import android.os.Bundle
import android.util.Log
import android.view.*
import android.view.Window.Callback
import android.view.accessibility.AccessibilityEvent
import android.widget.AdapterView
import android.widget.TextView
import androidx.annotation.Nullable
import androidx.appcompat.app.AppCompatActivity


class MainActivity : AppCompatActivity() {
    private lateinit var tv:TextView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        this.window.callback = WrapperWindowCallback(this, window.callback)

        tv = findViewById(R.id.tv)

        tv.setOnClickListener {
            Log.e("MainActivity","原始数据")
        }

    }
}

class WrapperWindowCallback : Window.Callback {
    private var callback: Window.Callback? = null
    private var activity: Activity? = null

    constructor() {}

    public constructor(activity: Activity, callback: Callback) : this() {
        this.callback = callback
        this.activity = activity
    }

    override fun dispatchKeyEvent(p0: KeyEvent?): Boolean {
        return this.callback!!.dispatchKeyEvent(p0)
    }

    override fun dispatchKeyShortcutEvent(p0: KeyEvent?): Boolean {
        return this.callback!!.dispatchKeyShortcutEvent(p0)
    }

    override fun dispatchTouchEvent(p0: MotionEvent?): Boolean {
        dispatchTouchEvent(activity!!, p0!!)
        return this.callback!!.dispatchTouchEvent(p0)
    }

    override fun dispatchTrackballEvent(p0: MotionEvent?): Boolean {
        return this.callback!!.dispatchTrackballEvent(p0)
    }

    override fun dispatchGenericMotionEvent(p0: MotionEvent?): Boolean {
        return this.callback!!.dispatchGenericMotionEvent(p0)
    }

    override fun dispatchPopulateAccessibilityEvent(p0: AccessibilityEvent?): Boolean {
        return this.callback!!.dispatchPopulateAccessibilityEvent(p0)
    }

    override fun onCreatePanelView(p0: Int): View? {
        return this.callback!!.onCreatePanelView(p0)
    }

    override fun onCreatePanelMenu(p0: Int, p1: Menu): Boolean {
        return this.callback!!.onCreatePanelMenu(p0, p1)
    }

    override fun onPreparePanel(p0: Int, p1: View?, p2: Menu): Boolean {
        return this.callback!!.onPreparePanel(p0, p1, p2)
    }

    override fun onMenuOpened(p0: Int, p1: Menu): Boolean {
        return this.callback!!.onMenuOpened(p0, p1)
    }

    override fun onMenuItemSelected(p0: Int, p1: MenuItem): Boolean {
        return this.callback!!.onMenuItemSelected(p0, p1)
    }

    override fun onWindowAttributesChanged(p0: WindowManager.LayoutParams?) {
        this.callback!!.onWindowAttributesChanged(p0)
    }

    override fun onContentChanged() {
        this.callback!!.onContentChanged()
    }

    override fun onWindowFocusChanged(p0: Boolean) {
        this.callback!!.onWindowFocusChanged(p0)
    }

    override fun onAttachedToWindow() {
        this.callback!!.onAttachedToWindow()
    }

    override fun onDetachedFromWindow() {
        this.callback!!.onDetachedFromWindow()
    }

    override fun onPanelClosed(p0: Int, p1: Menu) {
        this.callback!!.onPanelClosed(p0, p1)
    }

    override fun onSearchRequested(): Boolean {
        return this.callback!!.onSearchRequested()
    }

    @Nullable
    @TargetApi(23)
    override fun onSearchRequested(p0: SearchEvent?): Boolean {
        return this.callback!!.onSearchRequested(p0)
    }

    override fun onWindowStartingActionMode(p0: ActionMode.Callback?): ActionMode? {
        return this.callback!!.onWindowStartingActionMode(p0)
    }

    @Nullable
    @TargetApi(23)
    override fun onWindowStartingActionMode(p0: ActionMode.Callback?, p1: Int): ActionMode? {
        return this.callback!!.onWindowStartingActionMode(p0, p1)
    }

    override fun onActionModeStarted(p0: ActionMode?) {
        this.callback!!.onActionModeStarted(p0)
    }

    override fun onActionModeFinished(p0: ActionMode?) {
        this.callback!!.onActionModeFinished(p0)
    }

    private fun dispatchTouchEvent(activity: Activity, event: MotionEvent) {
        if (event.action == MotionEvent.ACTION_UP) {
            val rootView = activity.window.decorView as ViewGroup
            val targetVies = getTargetViews(rootView, event) ?: return
            for (view in targetVies) {
                if (view == null) {
                    continue
                }
                Log.e("MainActivity", "埋点数据")
            }
        }
    }

    private fun getTargetViewsInGroup(
        parent: ViewGroup,
        event: MotionEvent,
        hitViews: ArrayList<View>
    ) {
        try {
            val childCount = parent.childCount
            for (i in 0 until childCount) {
                val child = parent.getChildAt(i)
                val hitChildren: ArrayList<View> = getTargetViews(child, event)
                if (hitChildren.isNotEmpty()) {
                    hitViews.addAll(hitChildren)
                }
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    private fun getTargetViews(parent: View, event: MotionEvent): ArrayList<View> {
        val targetViews: ArrayList<View> = ArrayList()
        try {
            if (isVisible(parent) && isContainView(parent, event)) {
                if (parent is AdapterView<*>) {
                    targetViews.add(parent)
                    getTargetViewsInGroup((parent as ViewGroup), event, targetViews)
                } else if (parent.isClickable) {
                    targetViews.add(parent)
                } else if (parent is ViewGroup) {
                    getTargetViewsInGroup(parent, event, targetViews)
                }
            }
        } catch (e: java.lang.Exception) {
            e.printStackTrace()
        }
        return targetViews
    }

    private fun isVisible(view: View): Boolean {
        return view.visibility == View.VISIBLE
    }

    private fun isContainView(view: View, event: MotionEvent): Boolean {
        val x = event.rawX.toDouble()
        val y = event.rawY.toDouble()
        val outRect = Rect()
        view.getGlobalVisibleRect(outRect)
        return outRect.contains(x.toInt(), y.toInt())
    }

}
  • 缺点
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

android开发之代理Window.Callback 的相关文章

  • GCM 向主题发送消息:TOO_MANY_TOPICS 错误

    以前 GCM 每个应用程序有 100 万个主题订阅的限制 我发现他们现在已经取消了这一限制 基于发布 订阅模型 主题消息支持 每个应用程序无限订阅 https developers google com cloud messaging to
  • 从 Throwable 获取错误代码 - Android

    我怎样才能从错误代码可投掷 https developer android com reference java lang Throwable html public void onFailure Throwable exception 我
  • Android SoundPool 堆限制

    我正在使用 SoundPool 加载多个声音剪辑并播放它们 据我所知 它的功能 100 正确 但在 load 调用期间 我的日志中充斥着以下内容 06 09 11 30 26 110 ERROR AudioCache 23363 Heap
  • 如何将安卓手机从睡眠状态唤醒?

    如何以编程方式将 Android 手机从睡眠状态唤醒 挂起至内存 我不想获取任何唤醒锁 这意味着手机在禁用 CPU 的情况下进入 真正的 睡眠状态 我想我可以使用某种RTC 实时时钟 机制 有人有例子吗 Thanks 为了让Activity
  • Phonegap - 如何将.txt文件保存在Android手机的根目录中

    我正在尝试使用phonegap 将 txt 文件保存在Android 手机的根目录中 我已经安装了这些插件 cordova plugin file 和 cordova plugin file transfer 在 config xml 文件
  • 在意图过滤器中使用多个操作时的默认值

    尝试理解 Android 中的意图和操作并查看文档 http developer android com guide topics intents intents filters html 但我一直看到的一件事是定义了多个操作的意图过滤器
  • 如何查找 Android 设备中的所有文件并将它们放入列表中?

    我正在寻求帮助来列出 Android 外部存储设备中的所有文件 我想查找所有文件夹 包括主文件夹的子文件夹 有办法吗 我已经做了一个基本的工作 但我仍然没有得到想要的结果 这不起作用 这是我的代码 File files array file
  • TextView 之间有分隔线

    我正在尝试在 android studio 中创建以下布局 因为我对 android 东西还很陌生 所以我第一次尝试使用 LinearLayout 并认为这可能无法实现 现在我正在尝试使用RelativeLayout 我已经用颜色创建了这个
  • 在我的Android中,当其他应用程序想要录制音频时如何停止录音?

    在我的应用程序中 服务通过 AudioRecord 持续录制音频 当我的应用程序运行时 其他与音频记录相关的应用程序 例如 Google 搜索 无法工作 如何知道何时有其他应用想要录制音频 以便我可以停止录制以释放资源 答案是MediaRe
  • ROOM迁移过程中如何处理索引信息

    CODE Entity tableName UserRepo indices Index value id unique true public class GitHubRepo PrimaryKey autoGenerate true p
  • MediaCodec 创建输入表面

    我想使用 MediaCodec 将 Surface 编码为 H 264 使用 API 18 有一种方法可以通过调用 createInputSurface 然后在该表面上绘图来对表面中的内容进行编码 我在 createInputSurface
  • Android构建apk:控制MANIFEST.MF

    Android 构建 APK 假设一个 apk 包含一个库 jar 例如 foo jar 该库具有 META INF MANIFEST MF 这对于它的运行很重要 但在APK中有一个包含签名数据的MANIFEST MF 并且lib jar
  • 如何创建像谷歌位置历史记录一样的Android时间轴视图?

    我想设计像谷歌位置历史这样的用户界面 我必须为我正在使用的应用程序复制此 UIRecyclerView 每行都是水平的LinearLayout其中包含右侧的图标 线条和视图 该线是一个FrameLayout具有圆形背景和半透明圆圈Views
  • 将 JSON 参数从 java 发布到 sinatra 服务

    我有一个 Android 应用程序发布到我的 sinatra 服务 早些时候 我无法读取 sinatra 服务上的参数 但是 在我将内容类型设置为 x www form urlencoded 之后 我能够看到参数 但不完全是我想要的 我在
  • Android - 将 ImageView 保存到具有全分辨率图像的文件

    我将图像放入 ImageView 中 并实现了多点触控来调整 ImageView 中的图像大小和移动图像 现在我需要将调整大小的图像保存到图像文件中 我已经尝试过 getDrawingCache 但该图像具有 ImageView 的大小 我
  • 保护 APK 中的字符串

    我正在使用 Xamarin 的 Mono for Android 开发一个 Android 应用程序 我目前正在努力使用 Google Play API 添加应用内购买功能 为此 我需要从我的应用程序内向 Google 发送公共许可证密钥
  • Android 如何聚焦当前位置

    您好 我有一个 Android 应用程序 可以在谷歌地图上找到您的位置 但是当我启动该应用程序时 它从非洲开始 而不是在我当前的城市 国家 位置等 我已经在developer android com上检查了信息与位置问题有关 但问题仍然存在
  • 如何删除因 Google Fitness API 7.5.0 添加的权限

    将我的 play services fitness api 从 7 0 0 更新到 7 5 0 后 我注意到当我将新版本上传到 PlayStore 时 它 告诉我正在添加一个新权限和 2 个新功能 我没有这样做 有没有搞错 在做了一些研究来
  • 找到 Android 浏览器中使用的 webkit 版本?

    有没有办法知道某些特定手机上的 Android 浏览器使用的是哪个版本的 webkit 软件 如果有一个您可以浏览以获取该信息的 URL 那就太好了 但任何其他方式也很好 如果你知道 webkit 版本 你就知道 html5 支持多少 至少
  • 在 Google 地图上绘制线条/路径

    我很长一段时间都在忙于寻找如何在 HelloMapView 中的地图上的两个 GPS 点之间画一条线 但没有运气 谁能告诉我该怎么做 假设我使用扩展 MapView 的 HelloMapView 我需要使用叠加层吗 如果是这样 我是否必须重

随机推荐

  • 『数据结构』B树(B-Tree)及其变体 B+树,B*树

    原文地址 1 背景 当有大量数据储存在磁盘时 如数据库的查找 插入 删除等操作的实现 如果要读取或者写入 磁盘的寻道 旋转时间很长 远大于在 内存中的读取 写入时间 平时用的二叉排序树搜索元素的时间复杂度虽然是 O log2n O l o
  • BBR拥塞算法的简单解释

    TCP BBR的ACM论文中 开篇就引入了图1 以此来说明BBR算法的切入点 为何当前基于丢包探测的TCP拥塞控制算法还有优化空间 BBR算法的优化极限在哪儿 图1 为了理解这张图花了我整整一个晚上的时间 它使我重新审视了所有基础概念 而我
  • vue2.js初探

    今天学习了一下vue2 js 感觉很好用 一个是把相同的功能组件化了 把他定义一个标签 不用多次开发重复的代码 直接加标签就可以了 还有就是他把数据和标签的显示修改完全分开了 之前用jQuery开发 如果数据变动了 需要用jquery回调事
  • 计算机网络第八版——第一章课后题答案(超详细)

    第一章 该答案为博主在网络上整理 排版不易 希望大家多多点赞支持 后续将会持续更新 可以给博主点个关注 第二章 答案 1 01 计算机网络可以向用户提供哪些服务 解答 这道题没有现成的标准答案 因为可以从不同的角度来看 服务 首先要明确的是
  • ThreadX 内部系统时钟服务

    ThreadX中 有两个函数可以获取和设置内部系统时钟服务 tx time get 获取当前时间 tx time set 设置当前时间 tx time get 获取当前时间 原型 ULONG tx time get VOID 描述 这项服务
  • VUE安装问题

    启动应用 npm run serve 默认进入为 http localhost 8080 由于部署在虚拟化linux上 需远程访问 需将localhost修改为服务器IP 1 修改package json 新增host 0 0 0 0 2
  • 【Flutter 系列——1】Flutter环境搭建及配置这一篇就够了(Windows)

    最近正式入坑Flutter 首先从环境搭建开始 看了网上好多关于Windows环境搭建的资料 基本都是按官方文档写的 看完的感受是 还不如直接去看官方文档 官方英文文档传送门 Get Started Install on Windows 本
  • 数据要素流通视角下数据安全保障研究报告

    报告围绕数据要素流通视角下流通数据 流通活动 流通设施的安全需求 分析健全我国数据安全保障体系的推进思路 并从分类分级 流通环境 安全技术 协同共治等方面提出措施建议 为完善我国数据要素流通视角下数据安全保障提供有益参考与借鉴 关注公众号
  • WinCE5.0显卡驱动修改笔记

    WinCE5 0显卡驱动修改笔记公司前段时间让我在Geode上安装一个CE5 0 我把系统安装好之后发现显卡驱动不支持开发板的屏幕 我们的屏幕是800x480的 所以我只能自己动手写修改了一下驱动让它能够支持800x480 一下是我对驱动的
  • python报错code for hash md5 was not found解决方案

    因为开发机服务器不能上网 只能手动安装Python 但是装完后import hashlib出现异常 出现不支持sha256 sha512 md5等错误 现象如下 gt gt gt import hashlib ERROR root code
  • 排序算法之时间复杂度为O(N^2)的算法

    背景知识 排序算法算是比较基础的算法了 但是在面试过程中偶尔也会被问到 虽然很多语言都内置了排序函数 例如php的sort函数等等 但是还是有必要聊聊排序算法 这篇文章中将介绍时间复杂度为O N 2 的几个排序算法 本文基于从小到大排序讲解
  • react面试题(30个)

    1 React Native相对于原生的ios和Android有哪些优势 react native一套代码可以开发出跨平台app 减少了人力 节省了时间 避免了 iOS 与 Android 版本发布的时间差 开发新功能可以更迅速 等等 2
  • go语言后端调用以太坊rpc

    任务要求 使用golang作为后端语言 获取eth 私链 中的账户信息以及创建新的账号 1 启动geth geth identity aaron datadir data0 rpcport 8545 rpccorsdomain port 3
  • 分布式工程团队建设的十大教训

    转自 https www zybuluo com lsmn note 1059823 摘要 人才招聘 培养并促进分布式工程团队的发展并非一日之功 但是值得投资 Bruno提出了一些非常重要的见解 揭示了如何让团队全力以赴 而不管地理位置在哪
  • 初识springBoot

    springboot初学应该了解哪些 了解更多请看Spring Boot 初识 系列 会持续更新 Spring Boot 初识丨一 入门实战 Spring Boot 初识丨二 maven Spring Boot 初识丨三 starter S
  • springcloud搭建标配配置(参考)

    文章目录 架构图 shop parent 后端父项目 pom xml shop common 公共项目 pom xml CommonConstants UserInfo 用户对象 BusinessException 自定义异常 Common
  • SpringBoot+WebSocket+Netty实现消息推送

    实现思路 前端使用webSocket与服务端创建连接的时候 将用户ID传给服务端 服务端将用户ID与channel关联起来存储 同时将channel放入到channel组中 如果需要给所有用户发送消息 直接执行channel组的writeA
  • FusionSphere华为服务器虚拟化解决方案定位、架构、原理、应用场景

    目录 定位 应用场景 架构 原理 定位 华为fusion sphere虚拟化套件是业界领先的虚拟化解决方案 能够帮助客户解决数据中心基础设施的资源利用率低 业务上线周期时间长 数据中心能耗高等问题 应用场景 1 从应用侧来看 可应用于帮助客
  • 配置控制(自用)

    wd 123123 snh 123123
  • android开发之代理Window.Callback

    Window Callback是window类的一个内部接口 该接口包含了一系列类似于dispatchXXX和onXXX的接口 当window接收到外界状态改变的通知时 就会回调其中的相应方法 比如 当用户点击某个控件时 就会回调Windo