pref: 优化权限申请

This commit is contained in:
HuanCheng65 2022-12-31 18:21:58 +08:00
parent 7b2a1836c1
commit 1c517de556
No known key found for this signature in database
GPG Key ID: E9031EF91A805148
9 changed files with 324 additions and 111 deletions

View File

@ -19,7 +19,7 @@ import com.huanchengfly.tieba.post.models.PhotoInfoBean
import com.huanchengfly.tieba.post.utils.PermissionUtils import com.huanchengfly.tieba.post.utils.PermissionUtils
import com.huanchengfly.tieba.post.utils.PickMediasRequest import com.huanchengfly.tieba.post.utils.PickMediasRequest
import com.huanchengfly.tieba.post.utils.isPhotoPickerAvailable import com.huanchengfly.tieba.post.utils.isPhotoPickerAvailable
import java.util.* import java.util.Collections
class InsertPhotoAdapter(private val mContext: Context) : RecyclerView.Adapter<MyViewHolder>() { class InsertPhotoAdapter(private val mContext: Context) : RecyclerView.Adapter<MyViewHolder>() {
private var fileList: MutableList<PhotoInfoBean> = ArrayList<PhotoInfoBean>() private var fileList: MutableList<PhotoInfoBean> = ArrayList<PhotoInfoBean>()
@ -90,7 +90,7 @@ class InsertPhotoAdapter(private val mContext: Context) : RecyclerView.Adapter<M
} }
PermissionUtils.askPermission( PermissionUtils.askPermission(
mContext, mContext,
PermissionUtils.Permission( PermissionUtils.PermissionData(
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
listOf( listOf(
PermissionUtils.READ_EXTERNAL_STORAGE, PermissionUtils.READ_EXTERNAL_STORAGE,

View File

@ -12,7 +12,7 @@ import com.huanchengfly.tieba.post.dpToPx
import com.huanchengfly.tieba.post.utils.PermissionUtils import com.huanchengfly.tieba.post.utils.PermissionUtils
class RequestPermissionTipDialog(context: Context, permission: PermissionUtils.Permission) : class RequestPermissionTipDialog(context: Context, permission: PermissionUtils.PermissionData) :
AlertDialog(context, R.style.Dialog_RequestPermissionTip) { AlertDialog(context, R.style.Dialog_RequestPermissionTip) {
val title: TextView val title: TextView
val message: TextView val message: TextView

View File

@ -391,12 +391,12 @@ public class WebViewFragment extends BaseFragment implements DownloadListener, B
new PermissionDialog(getAttachContext(), new PermissionDialog(getAttachContext(),
new PermissionBean(PermissionDialog.CustomPermission.PERMISSION_LOCATION, new PermissionBean(PermissionDialog.CustomPermission.PERMISSION_LOCATION,
uri.getHost(), uri.getHost(),
getAttachContext().getString(R.string.title_ask_permission, uri.getHost(), getAttachContext().getString(R.string.permission_name_location)), getAttachContext().getString(R.string.title_ask_permission, uri.getHost(), getAttachContext().getString(R.string.common_permission_location)),
R.drawable.ic_round_location_on)) R.drawable.ic_round_location_on))
.setOnGrantedCallback(isForever -> { .setOnGrantedCallback(isForever -> {
PermissionUtils.INSTANCE.askPermission( PermissionUtils.INSTANCE.askPermission(
getAttachContext(), getAttachContext(),
new PermissionUtils.Permission( new PermissionUtils.PermissionData(
Arrays.asList(Permission.ACCESS_COARSE_LOCATION, Permission.ACCESS_FINE_LOCATION), Arrays.asList(Permission.ACCESS_COARSE_LOCATION, Permission.ACCESS_FINE_LOCATION),
getAttachContext().getString(R.string.usage_webview_location_permission) getAttachContext().getString(R.string.usage_webview_location_permission)
), ),

View File

@ -32,7 +32,7 @@ class PermissionFragment : BaseIntroFragment() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
PermissionUtils.askPermission( PermissionUtils.askPermission(
attachContext, attachContext,
PermissionUtils.Permission( PermissionUtils.PermissionData(
listOf(PermissionUtils.READ_PHONE_STATE), listOf(PermissionUtils.READ_PHONE_STATE),
getString(R.string.tip_permission_phone) getString(R.string.tip_permission_phone)
) )

View File

@ -199,7 +199,7 @@ public class FileUtil {
} }
PermissionUtils.INSTANCE.askPermission( PermissionUtils.INSTANCE.askPermission(
context, context,
new PermissionUtils.Permission( new PermissionUtils.PermissionData(
Arrays.asList(PermissionUtils.READ_EXTERNAL_STORAGE, PermissionUtils.WRITE_EXTERNAL_STORAGE), Arrays.asList(PermissionUtils.READ_EXTERNAL_STORAGE, PermissionUtils.WRITE_EXTERNAL_STORAGE),
context.getString(R.string.tip_permission_storage_download) context.getString(R.string.tip_permission_storage_download)
), ),

View File

@ -282,7 +282,7 @@ public class ImageUtil {
} }
PermissionUtils.INSTANCE.askPermission( PermissionUtils.INSTANCE.askPermission(
context, context,
new PermissionUtils.Permission( new PermissionUtils.PermissionData(
Arrays.asList(PermissionUtils.READ_EXTERNAL_STORAGE, PermissionUtils.WRITE_EXTERNAL_STORAGE), Arrays.asList(PermissionUtils.READ_EXTERNAL_STORAGE, PermissionUtils.WRITE_EXTERNAL_STORAGE),
context.getString(R.string.tip_permission_storage) context.getString(R.string.tip_permission_storage)
), ),

View File

@ -3,8 +3,11 @@ package com.huanchengfly.tieba.post.utils
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context
import android.os.Build import android.os.Build
import androidx.core.app.ActivityCompat import android.os.Handler
import android.os.Looper
import com.hjq.permissions.IPermissionInterceptor
import com.hjq.permissions.OnPermissionCallback import com.hjq.permissions.OnPermissionCallback
import com.hjq.permissions.Permission
import com.hjq.permissions.XXPermissions import com.hjq.permissions.XXPermissions
import com.huanchengfly.tieba.post.R import com.huanchengfly.tieba.post.R
import com.huanchengfly.tieba.post.components.dialogs.RequestPermissionTipDialog import com.huanchengfly.tieba.post.components.dialogs.RequestPermissionTipDialog
@ -57,131 +60,293 @@ object PermissionUtils {
* Turn permissions into text. * Turn permissions into text.
*/ */
fun transformText(context: Context, permissions: List<String>): List<String> { fun transformText(context: Context, permissions: List<String>): List<String> {
val textList: MutableList<String> = ArrayList() val permissionNames: MutableList<String> = mutableListOf()
if (context == null) {
return permissionNames
}
if (permissions == null) {
return permissionNames
}
for (permission in permissions) { for (permission in permissions) {
when (permission) { when (permission) {
READ_CALENDAR, WRITE_CALENDAR -> { Permission.READ_EXTERNAL_STORAGE, Permission.WRITE_EXTERNAL_STORAGE -> {
val message = context.getString(R.string.permission_name_calendar) val hint = context.getString(R.string.common_permission_storage)
if (!textList.contains(message)) { if (!permissionNames.contains(hint)) {
textList.add(message) permissionNames.add(hint)
} }
} }
CAMERA -> {
val message = context.getString(R.string.permission_name_camera)
if (!textList.contains(message)) {
textList.add(message)
}
}
GET_ACCOUNTS, READ_CONTACTS, WRITE_CONTACTS -> {
val message = context.getString(R.string.permission_name_contacts)
if (!textList.contains(message)) {
textList.add(message)
}
}
ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION -> {
val message = context.getString(R.string.permission_name_location)
if (!textList.contains(message)) {
textList.add(message)
}
}
RECORD_AUDIO -> {
val message = context.getString(R.string.permission_name_microphone)
if (!textList.contains(message)) {
textList.add(message)
}
}
READ_PHONE_STATE, CALL_PHONE, ADD_VOICEMAIL, USE_SIP, READ_PHONE_NUMBERS, ANSWER_PHONE_CALLS -> {
val message = context.getString(R.string.permission_name_phone)
if (!textList.contains(message)) {
textList.add(message)
}
}
READ_CALL_LOG, WRITE_CALL_LOG, PROCESS_OUTGOING_CALLS -> {
val messageId: Int =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) R.string.permission_name_call_log else R.string.permission_name_phone
val message = context.getString(messageId)
if (!textList.contains(message)) {
textList.add(message)
}
}
BODY_SENSORS -> {
val message = context.getString(R.string.permission_name_sensors)
if (!textList.contains(message)) {
textList.add(message)
}
}
ACTIVITY_RECOGNITION -> {
val message = context.getString(R.string.permission_name_activity_recognition)
if (!textList.contains(message)) {
textList.add(message)
}
}
SEND_SMS, RECEIVE_SMS, READ_SMS, RECEIVE_WAP_PUSH, RECEIVE_MMS -> {
val message = context.getString(R.string.permission_name_sms)
if (!textList.contains(message)) {
textList.add(message)
}
}
READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE -> {
val message = context.getString(R.string.permission_name_storage)
if (!textList.contains(message)) {
textList.add(message)
}
}
READ_MEDIA_IMAGES -> {
val message = context.getString(R.string.permission_name_images)
if (!textList.contains(message)) {
textList.add(message)
}
}
POST_NOTIFICATIONS -> {
val message = context.getString(R.string.permission_name_post_notifications)
if (!textList.contains(message)) {
textList.add(message)
}
}
}
}
return textList
}
fun askPermission(context: Context, permission: Permission, onGranted: () -> Unit) { Permission.READ_MEDIA_IMAGES, Permission.READ_MEDIA_VIDEO -> {
askPermission(context, permission, R.string.tip_no_permission, onGranted) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
val hint = context.getString(R.string.common_permission_image_and_video)
if (!permissionNames.contains(hint)) {
permissionNames.add(hint)
}
}
}
Permission.READ_MEDIA_AUDIO -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
val hint = context.getString(R.string.common_permission_music_and_audio)
if (!permissionNames.contains(hint)) {
permissionNames.add(hint)
}
}
}
Permission.CAMERA -> {
val hint = context.getString(R.string.common_permission_camera)
if (!permissionNames.contains(hint)) {
permissionNames.add(hint)
}
}
Permission.RECORD_AUDIO -> {
val hint = context.getString(R.string.common_permission_microphone)
if (!permissionNames.contains(hint)) {
permissionNames.add(hint)
}
}
Permission.ACCESS_FINE_LOCATION, Permission.ACCESS_COARSE_LOCATION, Permission.ACCESS_BACKGROUND_LOCATION -> {
val hint: String = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q &&
!permissions.contains(Permission.ACCESS_FINE_LOCATION) &&
!permissions.contains(Permission.ACCESS_COARSE_LOCATION)
) {
context.getString(R.string.common_permission_location_background)
} else {
context.getString(R.string.common_permission_location)
}
if (!permissionNames.contains(hint)) {
permissionNames.add(hint)
}
}
Permission.BODY_SENSORS, Permission.BODY_SENSORS_BACKGROUND -> {
val hint: String = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU &&
!permissions.contains(Permission.BODY_SENSORS)
) {
context.getString(R.string.common_permission_body_sensors_background)
} else {
context.getString(R.string.common_permission_body_sensors)
}
if (!permissionNames.contains(hint)) {
permissionNames.add(hint)
}
}
Permission.BLUETOOTH_SCAN, Permission.BLUETOOTH_CONNECT, Permission.BLUETOOTH_ADVERTISE -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
val hint = context.getString(R.string.common_permission_nearby_devices)
if (!permissionNames.contains(hint)) {
permissionNames.add(hint)
}
}
}
Permission.NEARBY_WIFI_DEVICES -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
val hint = context.getString(R.string.common_permission_nearby_devices)
if (!permissionNames.contains(hint)) {
permissionNames.add(hint)
}
}
}
Permission.READ_PHONE_STATE, Permission.CALL_PHONE, Permission.ADD_VOICEMAIL, Permission.USE_SIP, Permission.READ_PHONE_NUMBERS, Permission.ANSWER_PHONE_CALLS -> {
val hint = context.getString(R.string.common_permission_phone)
if (!permissionNames.contains(hint)) {
permissionNames.add(hint)
}
}
Permission.GET_ACCOUNTS, Permission.READ_CONTACTS, Permission.WRITE_CONTACTS -> {
val hint = context.getString(R.string.common_permission_contacts)
if (!permissionNames.contains(hint)) {
permissionNames.add(hint)
}
}
Permission.READ_CALENDAR, Permission.WRITE_CALENDAR -> {
val hint = context.getString(R.string.common_permission_calendar)
if (!permissionNames.contains(hint)) {
permissionNames.add(hint)
}
}
Permission.READ_CALL_LOG, Permission.WRITE_CALL_LOG, Permission.PROCESS_OUTGOING_CALLS -> {
val hint =
context.getString(if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) R.string.common_permission_call_logs else R.string.common_permission_phone)
if (!permissionNames.contains(hint)) {
permissionNames.add(hint)
}
}
Permission.ACTIVITY_RECOGNITION -> {
val hint =
context.getString(if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) R.string.common_permission_activity_recognition_api30 else R.string.common_permission_activity_recognition_api29)
if (!permissionNames.contains(hint)) {
permissionNames.add(hint)
}
}
Permission.ACCESS_MEDIA_LOCATION -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val hint =
context.getString(R.string.common_permission_access_media_location)
if (!permissionNames.contains(hint)) {
permissionNames.add(hint)
}
}
}
Permission.SEND_SMS, Permission.RECEIVE_SMS, Permission.READ_SMS, Permission.RECEIVE_WAP_PUSH, Permission.RECEIVE_MMS -> {
val hint = context.getString(R.string.common_permission_sms)
if (!permissionNames.contains(hint)) {
permissionNames.add(hint)
}
}
Permission.MANAGE_EXTERNAL_STORAGE -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val hint = context.getString(R.string.common_permission_all_file_access)
if (!permissionNames.contains(hint)) {
permissionNames.add(hint)
}
}
}
Permission.REQUEST_INSTALL_PACKAGES -> {
val hint = context.getString(R.string.common_permission_install_unknown_apps)
if (!permissionNames.contains(hint)) {
permissionNames.add(hint)
}
}
Permission.SYSTEM_ALERT_WINDOW -> {
val hint = context.getString(R.string.common_permission_display_over_other_apps)
if (!permissionNames.contains(hint)) {
permissionNames.add(hint)
}
}
Permission.WRITE_SETTINGS -> {
val hint = context.getString(R.string.common_permission_modify_system_settings)
if (!permissionNames.contains(hint)) {
permissionNames.add(hint)
}
}
Permission.NOTIFICATION_SERVICE -> {
val hint = context.getString(R.string.common_permission_allow_notifications)
if (!permissionNames.contains(hint)) {
permissionNames.add(hint)
}
}
Permission.POST_NOTIFICATIONS -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
val hint = context.getString(R.string.common_permission_post_notifications)
if (!permissionNames.contains(hint)) {
permissionNames.add(hint)
}
}
}
Permission.BIND_NOTIFICATION_LISTENER_SERVICE -> {
val hint =
context.getString(R.string.common_permission_allow_notifications_access)
if (!permissionNames.contains(hint)) {
permissionNames.add(hint)
}
}
Permission.PACKAGE_USAGE_STATS -> {
val hint = context.getString(R.string.common_permission_apps_with_usage_access)
if (!permissionNames.contains(hint)) {
permissionNames.add(hint)
}
}
Permission.SCHEDULE_EXACT_ALARM -> {
val hint = context.getString(R.string.common_permission_alarms_reminders)
if (!permissionNames.contains(hint)) {
permissionNames.add(hint)
}
}
Permission.ACCESS_NOTIFICATION_POLICY -> {
val hint = context.getString(R.string.common_permission_do_not_disturb_access)
if (!permissionNames.contains(hint)) {
permissionNames.add(hint)
}
}
Permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS -> {
val hint = context.getString(R.string.common_permission_ignore_battery_optimize)
if (!permissionNames.contains(hint)) {
permissionNames.add(hint)
}
}
Permission.BIND_VPN_SERVICE -> {
val hint = context.getString(R.string.common_permission_vpn)
if (!permissionNames.contains(hint)) {
permissionNames.add(hint)
}
}
Permission.PICTURE_IN_PICTURE -> {
val hint = context.getString(R.string.common_permission_picture_in_picture)
if (!permissionNames.contains(hint)) {
permissionNames.add(hint)
}
}
else -> {}
}
}
return permissionNames
}
fun askPermission(context: Context, permissionData: PermissionData, onGranted: () -> Unit) {
askPermission(context, permissionData, R.string.tip_no_permission, onGranted)
} }
fun askPermission( fun askPermission(
context: Context, context: Context,
permission: Permission, permissionData: PermissionData,
deniedToast: Int, deniedToast: Int,
onGranted: () -> Unit onGranted: () -> Unit
) { ) {
askPermission(context, permission, context.getString(deniedToast), onGranted, null) askPermission(context, permissionData, context.getString(deniedToast), onGranted, null)
} }
fun askPermission( fun askPermission(
context: Context, context: Context,
permission: Permission, permissionData: PermissionData,
deniedToast: Int, deniedToast: Int,
onGranted: () -> Unit, onGranted: () -> Unit,
onDenied: (() -> Unit)? onDenied: (() -> Unit)?
) { ) {
askPermission(context, permission, context.getString(deniedToast), onGranted, onDenied) askPermission(context, permissionData, context.getString(deniedToast), onGranted, onDenied)
} }
@JvmOverloads @JvmOverloads
fun askPermission( fun askPermission(
context: Context, context: Context,
permission: Permission, permissionData: PermissionData,
deniedToast: String, deniedToast: String,
onGranted: () -> Unit, onGranted: () -> Unit,
onDenied: (() -> Unit)? = null onDenied: (() -> Unit)? = null
) { ) {
if (XXPermissions.isGranted(context, permission.permissions)) { if (XXPermissions.isGranted(context, permissionData.permissions)) {
onGranted() onGranted()
} else { } else {
val dialog = RequestPermissionTipDialog(context, permission)
XXPermissions.with(context) XXPermissions.with(context)
.permission(permission.permissions) .permission(permissionData.permissions)
.interceptor(ShowPermissionTipInterceptor(permissionData))
.request(object : OnPermissionCallback { .request(object : OnPermissionCallback {
override fun onGranted(permissions: List<String>, all: Boolean) { override fun onGranted(permissions: List<String>, all: Boolean) {
if (all) { if (all) {
@ -190,20 +355,66 @@ object PermissionUtils {
context.toastShort(deniedToast) context.toastShort(deniedToast)
onDenied?.invoke() onDenied?.invoke()
} }
dialog.dismiss()
} }
override fun onDenied(permissions: List<String>, never: Boolean) { override fun onDenied(permissions: List<String>, never: Boolean) {
context.toastShort(deniedToast) context.toastShort(deniedToast)
onDenied?.invoke() onDenied?.invoke()
dialog.dismiss()
} }
}) })
dialog.show()
} }
} }
data class Permission(val permissions: List<String>, val desc: String) data class PermissionData(val permissions: List<String>, val desc: String)
}
class ShowPermissionTipInterceptor(val permissions: List<String>, val description: String) :
IPermissionInterceptor {
companion object {
@JvmStatic
val HANDLER: Handler = Handler(Looper.getMainLooper())
}
constructor(permissionData: PermissionUtils.PermissionData) : this(
permissionData.permissions,
permissionData.desc
)
private var mRequestFlag = false
private var tipDialog: RequestPermissionTipDialog? = null
override fun launchPermissionRequest(
activity: Activity,
allPermissions: MutableList<String>,
callback: OnPermissionCallback?
) {
mRequestFlag = true
super.launchPermissionRequest(activity, allPermissions, callback)
HANDLER.postDelayed({
if (!mRequestFlag) {
return@postDelayed
}
if (activity.isFinishing || activity.isDestroyed) {
return@postDelayed
}
tipDialog = RequestPermissionTipDialog(
activity,
PermissionUtils.PermissionData(permissions, description)
).apply { show() }
tipDialog?.show()
}, 300)
}
override fun finishPermissionRequest(
activity: Activity,
allPermissions: MutableList<String>,
skipRequest: Boolean,
callback: OnPermissionCallback?
) {
mRequestFlag = false
tipDialog?.dismiss()
}
} }
class PermissionRequester(val context: Context) { class PermissionRequester(val context: Context) {
@ -217,23 +428,9 @@ class PermissionRequester(val context: Context) {
if (XXPermissions.isGranted(context, permissions)) { if (XXPermissions.isGranted(context, permissions)) {
onGranted?.invoke() onGranted?.invoke()
} else { } else {
val isFirstRequest = permissions.any {
!SharedPreferencesUtil.get(SharedPreferencesUtil.SP_PERMISSION)
.getBoolean("tried_request_${it}", false)
}
val showRationale = (context !is Activity) || permissions.any {
ActivityCompat.shouldShowRequestPermissionRationale(
context,
it
)
}
val showDialog = isFirstRequest || showRationale
val dialog = RequestPermissionTipDialog(
context,
PermissionUtils.Permission(permissions, description)
)
XXPermissions.with(context) XXPermissions.with(context)
.permission(permissions) .permission(permissions)
.interceptor(ShowPermissionTipInterceptor(permissions, description))
.apply { .apply {
if (unchecked) { if (unchecked) {
unchecked() unchecked()
@ -246,15 +443,12 @@ class PermissionRequester(val context: Context) {
} else { } else {
onDenied?.invoke() onDenied?.invoke()
} }
if (showDialog) dialog.dismiss()
} }
override fun onDenied(permissions: List<String>, never: Boolean) { override fun onDenied(permissions: List<String>, never: Boolean) {
onDenied?.invoke() onDenied?.invoke()
if (showDialog) dialog.dismiss()
} }
}) })
if (showDialog) dialog.show()
} }
} }
} }

View File

@ -32,7 +32,7 @@
android:layout_marginStart="16dp" android:layout_marginStart="16dp"
android:layout_marginBottom="4dp" android:layout_marginBottom="4dp"
android:layout_toEndOf="@+id/permission_icon_storage" android:layout_toEndOf="@+id/permission_icon_storage"
android:text="@string/permission_name_storage" android:text="@string/common_permission_storage"
android:textColor="@color/default_color_text" android:textColor="@color/default_color_text"
android:textSize="15sp" android:textSize="15sp"
android:textStyle="bold" /> android:textStyle="bold" />
@ -78,7 +78,7 @@
android:layout_marginStart="16dp" android:layout_marginStart="16dp"
android:layout_marginBottom="4dp" android:layout_marginBottom="4dp"
android:layout_toEndOf="@+id/permission_icon_phone" android:layout_toEndOf="@+id/permission_icon_phone"
android:text="@string/permission_name_phone" android:text="@string/common_permission_phone"
android:textColor="@color/default_color_text" android:textColor="@color/default_color_text"
android:textSize="15sp" android:textSize="15sp"
android:textStyle="bold" /> android:textStyle="bold" />

View File

@ -509,18 +509,37 @@
<string name="toast_ignore_battery_optimization_already">已忽略电池优化</string> <string name="toast_ignore_battery_optimization_already">已忽略电池优化</string>
<string name="button_copy_crash">复制崩溃报告</string> <string name="button_copy_crash">复制崩溃报告</string>
<string name="button_redo">重做</string> <string name="button_redo">重做</string>
<string name="permission_name_calendar">日历</string> <string name="common_permission_calendar">日历</string>
<string name="permission_name_camera">相机</string> <string name="common_permission_camera">相机</string>
<string name="permission_name_contacts">手机账号 / 通讯录</string> <string name="common_permission_contacts">通讯录</string>
<string name="permission_name_location">位置信息</string> <string name="common_permission_location">定位</string>
<string name="permission_name_microphone">麦克风</string> <string name="common_permission_location_background">后台定位</string>
<string name="permission_name_phone">电话</string> <string name="common_permission_nearby_devices">附近的设备</string>
<string name="permission_name_call_log">通话记录</string> <string name="common_permission_microphone">麦克风</string>
<string name="permission_name_sensors">身体传感器</string> <string name="common_permission_phone">电话</string>
<string name="permission_name_activity_recognition">健身运动</string> <string name="common_permission_call_logs">通话记录</string>
<string name="permission_name_sms">短信</string> <string name="common_permission_body_sensors">身体传感器</string>
<string name="permission_name_storage">存储空间</string> <string name="common_permission_body_sensors_background">后台身体传感器</string>
<string name="permission_name_images">媒体图片</string> <string name="common_permission_activity_recognition_api29">健身运动</string>
<string name="common_permission_activity_recognition_api30">身体活动</string>
<string name="common_permission_access_media_location">读取媒体文件位置</string>
<string name="common_permission_sms">短信</string>
<string name="common_permission_storage">存储</string>
<string name="common_permission_post_notifications">发送通知</string>
<string name="common_permission_image_and_video">照片和视频</string>
<string name="common_permission_music_and_audio">音乐和音频</string>
<string name="common_permission_all_file_access">所有文件访问</string>
<string name="common_permission_install_unknown_apps">安装应用</string>
<string name="common_permission_display_over_other_apps">悬浮窗</string>
<string name="common_permission_modify_system_settings">修改系统设置</string>
<string name="common_permission_allow_notifications">通知</string>
<string name="common_permission_allow_notifications_access">通知栏监听</string>
<string name="common_permission_apps_with_usage_access">查看使用情况</string>
<string name="common_permission_alarms_reminders">查看闹钟提醒</string>
<string name="common_permission_do_not_disturb_access">勿扰</string>
<string name="common_permission_ignore_battery_optimize">忽略电池优化</string>
<string name="common_permission_picture_in_picture">画中画</string>
<string name="common_permission_vpn">\tVPN\t</string>
<string name="title_request_permission_tip_dialog">贴吧 Lite 正在请求“%1$s”权限</string> <string name="title_request_permission_tip_dialog">贴吧 Lite 正在请求“%1$s”权限</string>
<string name="message_request_permission_tip_dialog">授权后,将%1$s</string> <string name="message_request_permission_tip_dialog">授权后,将%1$s</string>
<string name="usage_webview_location_permission">用于向当前访问的网页提供你的位置信息,以便该网页向你提供相关服务。</string> <string name="usage_webview_location_permission">用于向当前访问的网页提供你的位置信息,以便该网页向你提供相关服务。</string>