需求
设备在进行入网认证的时候,实验室要求应用在使用特殊权限的时候,需要告知用户,要用户授权才能使用相应的权限;在高版本的安卓系统里,类似相机、位置这些权限都能自动申请,但是,像蓝牙、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