【CTA认证】Android8开关wifi或蓝牙时弹出授权选择框

为了满足CTA入网认证要求,Android 8系统中需在开启或关闭蓝牙、WiFi时弹出用户授权提示。本文介绍了如何利用AppOps管理normal权限,如BLUETOOTH_ADMIN,通过BluetoothManagerService调用AppOps的noteOp接口检查权限状态,并展示中文授权提示。当授权选择窗口出现超时时,原本会自动拒绝,但这里移除了超时功能,并在拒绝后结束设置应用进程。
摘要由CSDN通过智能技术生成

需求

设备在进行入网认证的时候,实验室要求应用在使用特殊权限的时候,需要告知用户,要用户授权才能使用相应的权限;在高版本的安卓系统里,类似相机、位置这些权限都能自动申请,但是,像蓝牙、wifi的使用,是没有弹框提示用户授权的,实验室要求,蓝牙、wifi同样需要弹框提示用户授权。

参照

https://www.javatt.com/p/71538
https://cdmana.com/2022/04/202204090914104656.html
https://blog.csdn.net/Hebin320320/article/details/124053531
https://www.796t.com/content/1550533519.html

方法简介

系统:安卓8
对于Runtime permission,在应用需要对应的权限的时候,会给用户一个提示。
CTA 要求对于BT、WLAN、NFC 等也需要给出相应的提示,所以这些permission也需要单独的控制。

蓝牙权限permission android:name=“android.permission.BLUETOOTH_ADMIN”

如果需要打开/关闭蓝牙的控制,必须申请这个权限,但是这个权限level 是normal的,并不是runtime permission,不能通过PMS 中的grantRuntimePermission 或者是invokeRuntimePermission 来管理。对于这种normal permission,我们可以利用AppOps 来管理。

BluetoothManagerService类中,在enable,disable蓝牙时,调用AppOps请求权限

AppOpsManager mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
String packages = mContext.getPackageManager().getNameForUid(Binder.getCallingUid());
if ((Binder.getCallingUid() >= Process.FIRST_APPLICATION_UID)
         && (packages.indexOf("android.uid.systemui") != 0)
         && (packages.indexOf("android.uid.system") != 0)) {
   
    int result = mAppOpsManager.noteOp(AppOpsManager.OP_BLUETOOTH_ADMIN,
          Binder.getCallingUid(), packages);
    if (result == AppOpsManager.MODE_IGNORED) {
   
        return false;
    }
}

通过AppOps 的noteOp 接口确认当前permission 是否是允许或者禁止状态,返回值分别是AppOpsManager.MODE_ALLOWED 和AppOpsManager.MODE_IGNORED。
对于返回值MODE_ERRORED 是否进行exception 提醒进行了区分。但是最终调用的都是AppOpsService 中的noteOperation 接口, 最终会通过AppOpsManager调用AppOpsService中的PermissionDialog弹窗功能。
注意:弹窗提示文本必须是中文,不能是英文,不然实验室不让过。

代码

diff --git a/base/core/java/android/app/AppOpsManager.java b/base/core/java/android/app/AppOpsManager.java
index 1b8e199e..1eaa2ef5 100644
--- a/base/core/java/android/app/AppOpsManager.java
+++ b/base/core/java/android/app/AppOpsManager.java
@@ -252,10 +252,14 @@ public class AppOpsManager {
   
     public static final int OP_INSTANT_APP_START_FOREGROUND = 68;
     /** @hide Answer incoming phone calls */
     public static final int OP_ANSWER_PHONE_CALLS = 69;
+    /** @hide */
+    public static final int OP_BLUETOOTH_ADMIN = 70;
+    /** @hide */
+    public static final int OP_CHANGE_WIFI_STATE = 71;
     /** @hide SPRD: disable 3rd app auto run*/
-    public static final int OP_POST_AUTORUN = 70;
+    public static final int OP_POST_AUTORUN = 72;
     /** @hide */
-    public static final int _NUM_OP = 71;
+    public static final int _NUM_OP = 73;
 
     /** Access to coarse location information. */
     public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -497,7 +501,10 @@ public class AppOpsManager {
   
             OP_REQUEST_INSTALL_PACKAGES,
             OP_PICTURE_IN_PICTURE,
             OP_INSTANT_APP_START_FOREGROUND,
-            OP_ANSWER_PHONE_CALLS
+            OP_ANSWER_PHONE_CALLS,
+            // cta
+            OP_BLUETOOTH_ADMIN,
+            OP_CHANGE_WIFI_STATE,
     };
 
     /**
@@ -575,6 +582,9 @@ public class AppOpsManager {
             OPSTR_PICTURE_IN_PICTURE,
             OPSTR_INSTANT_APP_START_FOREGROUND,
             OPSTR_ANSWER_PHONE_CALLS,
+            // cta
+            null, //OP_BLUETOOTH_ADMIN,
+            null, //OP_CHANGE_WIFI_STATE,
     };
 
     /**
@@ -652,6 +662,8 @@ public class AppOpsManager {
             "PICTURE_IN_PICTURE",
             "INSTANT_APP_START_FOREGROUND",
             "ANSWER_PHONE_CALLS",
+            "BLUETOOTH_ADMIN",
+            "CHANGE_WIFI_STATE",
     };
 
     /**
@@ -729,6 +741,8 @@ public class AppOpsManager {
             null, // no permission for entering picture-in-picture on hide
             Manifest.permission.INSTANT_APP_FOREGROUND_SERVICE,
             Manifest.permission.ANSWER_PHONE_CALLS,
+            null, //OP_BLUETOOTH_ADMIN,
+            null, //OP_CHANGE_WIFI_STATE,
     };
 
     /**
@@ -807,6 +821,8 @@ public class AppOpsManager {
             null, // ENTER_PICTURE_IN_PICTURE_ON_HIDE
             null, // INSTANT_APP_START_FOREGROUND
             null, // ANSWER_PHONE_CALLS
+            null, //OP_BLUETOOTH_ADMIN,
+            null, //OP_CHANGE_WIFI_STATE,
     };
 
     /**
@@ -884,6 +900,8 @@ public class AppOpsManager {
             false, // ENTER_PICTURE_IN_PICTURE_ON_HIDE
             false, // INSTANT_APP_START_FOREGROUND
             false, // ANSWER_PHONE_CALLS
+            true, //OP_BLUETOOTH_ADMIN,
+            true, //OP_CHANGE_WIFI_STATE,
     };
 
     /**
@@ -960,6 +978,8 @@ public class AppOpsManager {
             AppOpsManager.MODE_ALLOWED,  // OP_PICTURE_IN_PICTURE
             AppOpsManager.MODE_DEFAULT,  // OP_INSTANT_APP_START_FOREGROUND
             AppOpsManager.MODE_ALLOWED, // ANSWER_PHONE_CALLS
+            AppOpsManager.MODE_ERRORED, //OP_BLUETOOTH_ADMIN,
+            AppOpsManager.MODE_ERRORED, //OP_CHANGE_WIFI_STATE,
     };
 
     /**
@@ -1040,6 +1060,8 @@ public class AppOpsManager {
             false, // OP_PICTURE_IN_PICTURE
             false,
             false, // ANSWER_PHONE_CALLS
+            false, //OP_BLUETOOTH_ADMIN,
+            false, //OP_CHANGE_WIFI_STATE,
     };
 
     /**
@@ -1107,7 +1129,7 @@ public class AppOpsManager {
         }
     }
 
-    /**
+    /**        
      * Retrieve the op switch that controls the given operation.
      * @hide
      */
diff --git a/base/core/res/res/layout/permission_confirmation_dialog.xml b/base/core/res/res/layout/permission_confirmation_dialog.xml
new file mode 100755
index 00000000..472602b2
--- /dev/null
+++ b/base/core/res/res/layout/permission_confirmation_dialog.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (c) 2015, The Linux Foundation. All rights reserved.
+
+     Redistribution and use in source and binary forms, with or without
+     modification, are permitted provided that the following conditions are
+     met:
+         * Redistributions of source code must retain the above copyright
+           notice, this list of conditions and the following disclaimer.
+         * Redistributions in binary form must reproduce the above
+           copyright notice, this list of conditions and the following
+           disclaimer in the documentation and/or other materials provided
+           with the distribution.
+         * Neither the name of The Linux Foundation nor the names of its
+           contributors may be used to endorse or promote products derived
+           from this software without specific prior written permission.
+
+     THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+     WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+     ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+     BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+     CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+     SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+     BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+     WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+     OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+     IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/parentPanel"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:layout_marginLeft="8dip"
+    android:layout_marginRight="8dip"
+    android:orientation="vertical">
+
+    <TextView android:id="@+id/permission_text"
+        style="?android:attr/textAppearanceMedium"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingLeft="20dip"
+        android:paddingRight="20dip"
+        android:paddingTop="16dip"
+        android:paddingBottom="16dip" />
+
+    <TableLayout android:id="@+id/permission_remember_layout"
+        android:shrinkColumns="1"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:paddingLeft="16dip"
+        android:paddingRight="16dip">
+
+        <TableRow
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content" >
+            <RelativeLayout android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:paddingTop="12dip"
+                android:paddingLeft="8dip" >
+            <CheckBox android:id="@+id/permission_remember_choice_checkbox"
+                android:paddingTop="11dip"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content" />
+            </RelativeLayout>
+            <TextView android:id="@+id/permission_remember_choice_text"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:paddingTop="18dip"
+                android:text="@string/permission_remember_choice" />
+        </TableRow>
+
+    </TableLayout>
+
+</LinearLayout>
diff --git a/base/core/res/res/values-zh-rCN/strings.xml b/base/core/res/res/values-zh-rCN/strings.xml
index a02441d9..1e2fcebb 100644
--- a/base/core/res/res/values-zh-rCN/strings.xml
+++ b/base/core/res/res/values-zh-rCN/strings.xml
@@ -1774,4 +1774,5 @@
     <string name="mmcc_illegal_ms" msgid="2769452751852211112">"不受允许的 SIM 卡"</string>
     <string name="mmcc_illegal_me" msgid="4438696681169345015">"不受允许的手机"</string>
     <string name="popup_window_default_title" msgid="4874318849712115433">"弹出式窗口"</string>
+    <string name="permission_remember_choice">"永远记住"</string>
 </resources>
diff --git a/base/core/res/res/values/arrays.xml b/base/core/res/res/values/arrays.xml
index dda4e748..39276a8a 100644
--- a/base/core/res/res/values/arrays.xml
+++ b/base/core/res/res/values/arrays.xml
@@ -184,6 +184,11 @@
         <item>@string/pin_target</item>
         <item>@string/app_info</item>
     </string-array>
+   
+    <string-array name="app_ops_labels">
+        <item>请求开/关网络</item>
+        <item>请求开/关蓝牙</item>
+    </string-array>
 
     <string-array name="resolver_target_actions_unpin">
         <item>@string/unpin_target</item>
diff --git a/base/core/res/res/values/strings.xml b/base/core/res/res/values/strings.xml
index df03c119..8d8079cd 100644
--- a/base/core/res/res/values/strings.xml
+++ b/base/core/res/res/values/strings.xml
@@ -4673,4 +4673,11 @@
 
     <!-- Popup window default title to be read by a screen reader-->
     <string name="popup_window_default_title">Popup Window</string>
+
+    <!--cta for wifi, bt-->
+    <string name="permission_remember_choice">Remember</string>
+    <string name="other_permissions">other permissions</string>
+    <string name="permission_title">Permission</string>
+    <string name="allow_button">Allow</string>
+    <string name
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值