Android12(S)授权弹窗被悬浮窗遮挡导致无法点击问题分析

这篇具有很好参考价值的文章主要介绍了Android12(S)授权弹窗被悬浮窗遮挡导致无法点击问题分析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

概述

在测试过程中发现,部分情况下当应用请求权限时,权限授予弹窗中的选项无法点击,有时候又可以。点击其他区域发现是可以正常响应,获取按键事件,发现触摸是有正常上报事件的,所以可以排除是触摸失灵导致。

问题分析

既然是权限授予弹窗无法点击,那么我们就去找权限管理代码看看弹窗点击的逻辑。
弹窗的布局文件如下:

//path:packages/modules/Permission/PermissionController/res/layout/grant_permissions.xml
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2015 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->

<!-- In (hopefully very rare) case dialog is too high: allow scrolling -->
<ScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    style="@style/PermissionGrantScrollView">

    <LinearLayout
        android:id="@+id/grant_singleton"
        android:importantForAccessibility="no"
        style="@style/PermissionGrantSingleton">

        <!-- The dialog -->
        <LinearLayout
            android:id="@+id/grant_dialog"
            android:theme="@style/Theme.PermissionGrantDialog"
            android:importantForAccessibility="no"
            style="@style/PermissionGrantDialog">

            <LinearLayout
                android:id="@+id/content_container"
                style="@style/PermissionGrantContent">

                <LinearLayout
                    style="@style/PermissionGrantDescription">

                    <ImageView
                        android:id="@+id/permission_icon"
                        style="@style/PermissionGrantTitleIcon" />

                    <TextView
                        android:id="@+id/permission_message"
                        style="@style/PermissionGrantTitleMessage" />

                </LinearLayout>

                <TextView
                    android:id="@+id/detail_message"
                    style="@style/PermissionGrantDetailMessage" />

            </LinearLayout>

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:id="@+id/permission_location_accuracy">

                <RadioGroup
                    android:id="@+id/permission_location_accuracy_radio_group"
                    style="@style/PermissionLocationAccuracyRadioGroup">

                    <RadioButton
                        android:id="@+id/permission_location_accuracy_radio_fine"
                        android:text="@string/permgrouprequest_finelocation_imagetext"
                        style="@style/PermissionLocationAccuracyRadioFine"/>

                    <RadioButton
                        android:id="@+id/permission_location_accuracy_radio_coarse"
                        android:text="@string/permgrouprequest_coarselocation_imagetext"
                        style="@style/PermissionLocationAccuracyRadioCoarse" />
                </RadioGroup>

                <ImageView
                    android:id="@+id/permission_location_accuracy_fine_only"
                    android:contentDescription="@string/precise_image_description"
                    style="@style/PermissionLocationAccuracyFineImageView" />

                <ImageView
                    android:id="@+id/permission_location_accuracy_coarse_only"
                    android:contentDescription="@string/approximate_image_description"
                    style="@style/PermissionLocationAccuracyCoarseImageView" />

            </LinearLayout>

            <!-- Buttons on bottom of dialog -->
            <LinearLayout
                style="@style/PermissionGrantButtonList">

                <Space
                    style="@style/PermissionGrantButtonBarSpace"/>

                <com.android.permissioncontroller.permission.ui.widget.SecureButton
                    android:id="@+id/permission_allow_button"
                    android:text="@string/grant_dialog_button_allow"
                    style="@style/PermissionGrantButtonAllow" />

                <com.android.permissioncontroller.permission.ui.widget.SecureButton
                    android:id="@+id/permission_allow_foreground_only_button"
                    android:text="@string/grant_dialog_button_allow_foreground"
                    style="@style/PermissionGrantButtonAllowForeground" />

                <com.android.permissioncontroller.permission.ui.widget.SecureButton
                    android:id="@+id/permission_allow_one_time_button"
                    android:text="@string/grant_dialog_button_allow_one_time"
                    style="@style/PermissionGrantButtonAllowOneTime" />

                <com.android.permissioncontroller.permission.ui.widget.SecureButton
                    android:id="@+id/permission_deny_button"
                    android:text="@string/grant_dialog_button_deny"
                    style="@style/PermissionGrantButtonDeny" />

                <com.android.permissioncontroller.permission.ui.widget.SecureButton
                    android:id="@+id/permission_deny_and_dont_ask_again_button"
                    android:text="@string/grant_dialog_button_deny"
                    style="@style/PermissionGrantButtonDeny" />

                <com.android.permissioncontroller.permission.ui.widget.SecureButton
                    android:id="@+id/permission_no_upgrade_button"
                    android:text="@string/grant_dialog_button_no_upgrade"
                    style="@style/PermissionGrantButtonNoUpgrade" />

                <com.android.permissioncontroller.permission.ui.widget.SecureButton
                    android:id="@+id/permission_no_upgrade_and_dont_ask_again_button"
                    android:text="@string/grant_dialog_button_no_upgrade"
                    style="@style/PermissionGrantButtonNoUpgrade" />

                <com.android.permissioncontroller.permission.ui.widget.SecureButton
                    android:id="@+id/permission_no_upgrade_one_time_button"
                    android:text="@string/grant_dialog_button_no_upgrade_one_time"
                    style="@style/PermissionGrantButtonNoUpgrade" />

                <com.android.permissioncontroller.permission.ui.widget.SecureButton
                    android:id="@+id/permission_no_upgrade_one_time_and_dont_ask_again_button"
                    android:text="@string/grant_dialog_button_no_upgrade_one_time"
                    style="@style/PermissionGrantButtonNoUpgrade" />
            </LinearLayout>

        </LinearLayout>
    </LinearLayout>
</ScrollView>

发现点击按钮是自定义了一个com.android.permissioncontroller.permission.ui.widget.SecureButton,继续查看

package com.android.permissioncontroller.permission.ui.widget;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.Button;

import com.android.modules.utils.build.SdkLevel;

/**
 * A button which doesn't allow clicking when any part of the window is obscured
 */
public class SecureButton extends Button {

    private static final int FLAGS_WINDOW_IS_OBSCURED =
            MotionEvent.FLAG_WINDOW_IS_OBSCURED | MotionEvent.FLAG_WINDOW_IS_PARTIALLY_OBSCURED;

    public SecureButton(Context context) {
        super(context);
    }

    public SecureButton(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public SecureButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public SecureButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    public boolean onFilterTouchEventForSecurity(MotionEvent event) {
        if (SdkLevel.isAtLeastS()) {
            return (event.getFlags() & FLAGS_WINDOW_IS_OBSCURED) == 0
                    && super.onFilterTouchEventForSecurity(event);
        }

        return super.onFilterTouchEventForSecurity(event);
    }
}

这个SecureButton 只是继承了Button,添加了onFilterTouchEventForSecurity 方法,对MotionEvent.FLAG_WINDOW_IS_OBSCURED | MotionEvent.FLAG_WINDOW_IS_PARTIALLY_OBSCURED这两个flag进行了判断。

查询资料可知,这是Android12新特性:
不信任的触摸事件被阻止
为了保持系统安全性和良好的用户体验,Android 12会阻止应用程序在覆盖层以不安全的方式遮盖应用程序时使用触摸事件。换句话说,系统会阻止通过某些窗口的触摸
侵害的应用
此更改会影响选择让触摸通过其窗口(例如通过使用 FLAG_NOT_TOUCHABLE 标志)的应用。几个示例包括但不限于以下示例:

  • 需要SYSTEM_ALERT_WINDOW 权限的叠加层
    ,例如使用TYPE_APPLICATION_OVERLAY,使用FLAG_NOT_TOUCHABLE标志的窗口 。

  • 使用该FLAG_NOT_TOUCHABLE标志的活动窗口。

  • Toast messages.

例外情况
在以下情况下,允许“通过”触摸:

  • 您的应用内的互动。您的应用会显示叠加层,并且叠加层仅在用户与您的应用进行交互时才会显示。
  • 受信任的窗口。这些窗口包括(但不限于)以下内容:
    辅助功能窗口
    输入法编辑器(IME)窗口
    助手窗口

注意:Windows类型 不受信任。TYPE_APPLICATION_OVERLAY

  • 隐形窗户。窗口的根视图为 GONE或 INVISIBLE。

  • 完全透明的窗口。该alpha窗口的 属性为0.0。

  • 足够透明的系统警报窗口。当组合的不透明度小于或等于系统对触摸的最大遮盖不透明度时,系统认为一组系统警报窗口是足够透明的。在Developer
    Preview 1中,最大不透明度为0.8,但是此值稍后可能在Developer Preview中更改。

在InputDispatcher 中可以找到触摸不被阻止的条件

//path:frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp

/**
 * Indicate whether one window handle should be considered as obscuring
 * another window handle. We only check a few preconditions. Actually
 * checking the bounds is left to the caller.
 */
static bool canBeObscuredBy(const sp<WindowInfoHandle>& windowHandle,
                            const sp<WindowInfoHandle>& otherHandle) {
    // Compare by token so cloned layers aren't counted
    if (haveSameToken(windowHandle, otherHandle)) {//两个窗口拥有相同的windowhandle 不被阻止
        return false;
    }
    auto info = windowHandle->getInfo();
    auto otherInfo = otherHandle->getInfo();
    if (!otherInfo->visible) {//另一个窗口不可见 触摸不被阻止
        return false;
    } else if (otherInfo->alpha == 0 && otherInfo->flags.test(WindowInfo::Flag::NOT_TOUCHABLE)) {//另一个窗口透明并且不可touch 触摸就不会被阻止
        // Those act as if they were invisible, so we don't need to flag them.
        // We do want to potentially flag touchable windows even if they have 0
        // opacity, since they can consume touches and alter the effects of the
        // user interaction (eg. apps that rely on
        // FLAG_WINDOW_IS_PARTIALLY_OBSCURED should still be told about those
        // windows), hence we also check for FLAG_NOT_TOUCHABLE.
        return false;
    } else if (info->ownerUid == otherInfo->ownerUid) {//两个窗口拥有相同的UID 触摸不被阻止
        // If ownerUid is the same we don't generate occlusion events as there
        // is no security boundary within an uid.
        return false;
    } else if (otherInfo->trustedOverlay) {//另一个窗口拥有trustedOverlay flag 触摸不被阻止
        return false;
    } else if (otherInfo->displayId != info->displayId) {//另一个窗口在其他屏幕上显示 触摸不被阻止
        return false;
    }
    return true;
}

以上可以分析出想要授权窗口的触摸事件不被阻止,那么只能让悬浮窗拥有trustedOverlay flag

解决方案

由上分析知,想要悬浮窗不影响授权框的点击,只能给悬浮窗设置不可点击,透明,或者拥有trustedOverlay flag。前面的不可点击,透明这些会改变悬浮窗的设计,不可取,那么久只能设置flag。
在windowmanager中有setTrustedOverlay 方法,可以给弹窗设置PRIVATE_FLAG_TRUSTED_OVERLAY flag 但是它是hide方法,并且需要INTERNAL_SYSTEM_WINDOW 权限,该方法只能系统应用使用。我们的应用本身是系统应用所以可以使用,问题能够解决。

 /**
         * Specifies that the window should be considered a trusted system overlay. Trusted system
         * overlays are ignored when considering whether windows are obscured during input
         * dispatch. Requires the {@link android.Manifest.permission#INTERNAL_SYSTEM_WINDOW}
         * permission.
         *
         * {@see android.view.MotionEvent#FLAG_WINDOW_IS_OBSCURED}
         * {@see android.view.MotionEvent#FLAG_WINDOW_IS_PARTIALLY_OBSCURED}
         * @hide
         */
        public void setTrustedOverlay() {
            privateFlags |= PRIVATE_FLAG_TRUSTED_OVERLAY;
        }

其实对于非系统应用,本身不会存在这个问题,授权弹窗其实在启动时会设置flag:getWindow().addSystemFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS 会主动去隐藏掉非系统的悬浮窗,这样本身也就没有遮挡的问题了。
但是我们应用是系统应用,这个方法就不起效果,所以需要特殊处理。文章来源地址https://www.toymoban.com/news/detail-500744.html

到了这里,关于Android12(S)授权弹窗被悬浮窗遮挡导致无法点击问题分析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android 12.0Launcher3 去掉workspace长按弹出壁纸弹窗

    在12.0的系统开发中,在Launcher3开发中,在长按屏幕的时候,会弹出窗口,修改主屏幕配置,壁纸,等信息,由于要默认设置一些配置 不想让用户修改相关配置,这时候就需要去掉长按弹窗功能了,禁止修改相关配置 下面来分析下workspace相关长按事件的功能实现 先看workspac

    2024年02月07日
    浏览(47)
  • android 12.0去掉usb授权提示框 默认给予权限

    在12.0的系统rom产品开发中,在进行iot开发过程中,在插入usb设备时会弹出usb授权提示框,也带来一些不便,这个需要默认授予USB权限,插拔usb都不弹出usb弹窗所以这要从usb授权相关管理页默认给与usb权限 在进行开发的过程中,发现在插入usb后,通过adb shell命令adb shell dumpsys

    2024年02月15日
    浏览(38)
  • 【uniapp】 video视频层级、遮挡其他弹窗或顶部导航 使用nvue覆盖

    uniapp 顶部导航和弹窗被video遮挡解决办法 全部代码 请前往dcloud 视频播放器 解决video视频遮挡顶部导航、 遮挡分享弹窗 组件层级 下载 话不多说 直接来干货 示例图片: 第一步:配置 subNVues 第二步:分别在index文件夹下建立三个文件分别为:index.vue 、drawer.nvue、subnvue.nvue文件

    2024年02月12日
    浏览(36)
  • python selenium 定位鼠标悬浮后的新弹窗数据

            最近需要获取网页上的标签数据,但是标签大于3个以后是隐藏的,需要鼠标hover上去才显示。如下图,图一是刚进来界面展示的,需要知道额外的7个标签则需要将鼠标移动到目标上面去。            但是比较尴尬的一个点是,当游览器打开F12后,使用鼠标去选中关

    2024年02月06日
    浏览(28)
  • 关于微信小程序--授权弹窗

    1.进入微信文档官网,找到button组件 添加链接描述 2.阅读文档,发现只需设置一个opentype类型和bindgetuserinfo 3.在js页面编写GetuserinfoHide函数的实现 4.以上操作完成后,在模拟器上进行调试,怎么也出不来效果,log可以打印出res,但是获取用户信息失败。通过百度,查看官网。最

    2024年02月11日
    浏览(41)
  • 浏览器F12定位悬浮下拉框元素

     解决办法 1. 鼠标悬浮于 设置 2. 点击鼠标右键显示 3. 鼠标移动到F12窗口,按N,成功定位到下拉框元素 

    2024年02月12日
    浏览(44)
  • uniapp授权小程序隐私弹窗效果demo(整理)

    官方“小程序隐私协议开发指南”文档 1、开通调用微信接口-比如获取当前位置 2、更新隐私说明

    2024年02月09日
    浏览(30)
  • 小程序隐私保护授权处理方式之弹窗组件

    欢迎点击领取 -《前端开发面试题进阶秘籍》:前端登顶之巅-最全面的前端知识点梳理总结 *分享一个使用比较久的🪜 小程序隐私保护授权弹窗组件 调用wx.getUserProfile进行授权时,返回错误信息:{errMsg: “getUserProfile:fail api scope is not declared in the privacy agreement”, errno: 112} 是因

    2024年02月10日
    浏览(29)
  • Win解答 | 解决键盘中 字母+空格 导致的输入法弹窗导致的一系列问题

    近三个月来,一直都有一个键盘组合键的问题影响我的电脑使用,不管是打字还是打游戏,都会出现按键盘的 字母+空格 弹出一个特殊符号的候选框,如下图所示 图片中为 S+空格 所出现的弹窗 一个看似方便,实则难受的功能 其实打字写代码的时候还好,只是速度快的时候关

    2024年02月10日
    浏览(24)
  • uniApp微信小程序唤出授权头像昵称(微信授权登录)弹窗,及服务端用户信息解密注意事项

    头像昵称弹窗弹出条件:button授权按钮 + uni.getUserProfile API请求 1.H5部分 2.JS部分 注意事项: 不能嵌入其他API内调用,一定要在调用的方法中第一层执行(优先执行 uni.getUserProfile ) 正确做法 :必须第一步用户点击按钮,第二步调取 uni.getUserProfile API(调取 uni.getUserProfile 操作

    2024年02月11日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包