From 9580d80ae7fd2c56d5de9a04b2747b26f631954d Mon Sep 17 00:00:00 2001 From: Runt <qingingrunt2010@qq.com> Date: Thu, 05 Jun 2025 13:15:21 +0000 Subject: [PATCH] 权限说明优化 --- libmvi/src/main/java/com/runt/open/mvi/base/BaseActivity.kt | 299 ++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 files changed, 253 insertions(+), 46 deletions(-) diff --git a/libmvi/src/main/java/com/runt/open/mvi/base/BaseActivity.kt b/libmvi/src/main/java/com/runt/open/mvi/base/BaseActivity.kt index 71b3ecf..bf326ac 100644 --- a/libmvi/src/main/java/com/runt/open/mvi/base/BaseActivity.kt +++ b/libmvi/src/main/java/com/runt/open/mvi/base/BaseActivity.kt @@ -1,18 +1,24 @@ package com.runt.open.mvi.base import android.Manifest +import android.app.ActivityManager +import android.content.ContentResolver import android.content.Context import android.content.Intent -import android.content.pm.ActivityInfo import android.content.pm.PackageManager +import android.net.Uri import android.os.Build import android.os.Bundle import android.os.Environment +import android.provider.MediaStore +import android.provider.Settings +import android.text.TextUtils import android.util.Log import android.view.MotionEvent import android.view.View import android.view.WindowManager import android.view.inputmethod.InputMethodManager +import android.webkit.MimeTypeMap import android.widget.EditText import android.widget.Toast import androidx.activity.ComponentActivity @@ -23,6 +29,7 @@ import androidx.activity.result.contract.ActivityResultContracts import androidx.annotation.ColorRes import androidx.annotation.StringRes +import androidx.collection.ArraySet import androidx.core.content.ContextCompat import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProvider @@ -53,6 +60,11 @@ val PARAMS_TITLE = "title" + private var requestFileResult:Observer<List<String>>? = null; + + private var fileLauncher : ActivityResultLauncher<Intent>? = null //选择文件 + private var filePermissionLauncher : ActivityResultLauncher<Intent>? = null //文件权限 + private val fileUriList = mutableListOf<Uri>() override fun onCreate(savedInstanceState : Bundle?) { super.onCreate(savedInstanceState) // get genericity "B" @@ -77,30 +89,28 @@ init(); //setContentView(mLayout) setContent { - mLayout!!.layout() + mLayout!!.layoutFrame() } mContext = this - try { //设置坚屏 一定要放到try catch里面,否则会崩溃 - setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) - } catch (e : Exception) { - } TAG = this.javaClass.simpleName initViews() //初始化UI mViewModel!!.onCreate(this as BaseActivity<LayoutView<BaseViewModel> , BaseViewModel>) loadData() //加载数据 } + abstract fun init() abstract fun initViews() abstract fun loadData() - fun registerPermissionResult(){ + protected fun registerPermissionResult(){ permissionsLauncher = this.registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { result -> if (result == null || result.size === 0) { permissionObserver !!.onChanged("") return@registerForActivityResult } + mViewModel!!.hidePopupWindow() Log.d(TAG , "result:" + result + " size:" + result.size) var allGranted = true for (key in result.keys) { @@ -116,6 +126,115 @@ permissionObserver !!.onChanged(com.google.gson.Gson().toJson(result.keys).replace("[" , "").replace("]" , "").replace("\"" , "")) } } + } + + protected fun registerFileResult(){ + + filePermissionLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> + Log.i(TAG,"filePermission ${result}") + onRequestFileResult(); + } + //选择文件 + fileLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult() , object : ActivityResultCallback<ActivityResult?> { + override fun onActivityResult(result : ActivityResult?) { + Log.i(TAG,"fileLauncher ${result!!.data?.data}") + Log.i(TAG,"fileLauncher clipData= ${result!!.data?.clipData}") + fileUriList.clear(); + result!!.data?.data?.let{ + fileUriList.add(it); + } + result!!.data?.clipData?.let{ + val count = it.itemCount + for (i in 0 until count) { + fileUriList.add(it.getItemAt(i).uri) + } + } + if(fileUriList.size == 0){ + requestFileResult?.onChanged(ArrayList()) + }else{ + onRequestFileResult(); + } + } + }) + } + + private fun onRequestFileResult(){ + + val cR : ContentResolver = getContentResolver() + val mime = MimeTypeMap.getSingleton() + var filePath = mViewModel!!.getFilePathFromUri(fileUriList.get(0)!!); + //文件不存在或读写权限受限 + if(filePath == null){ + //android 11需要申请权限 //是否有所有问读写权限 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && ! Environment.isExternalStorageManager()) { + //跳转到打开权限页面 + var intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION); + + intent.setData(Uri.parse("package:" + mContext!!.getPackageName())); + filePermissionLauncher!!.launch(intent) + return; + } + requestFileResult?.onChanged(ArrayList()) + }else{ + var filePathes = ArrayList<String>() + for (i in 0 until fileUriList.size) { + var filePath = mViewModel!!.getFilePathFromUri(fileUriList.get(i)!!); + filePathes.add(filePath!!) + } + requestFileResult?.onChanged(filePathes) + } + } + + fun requestFile(fileType :String,maxCount:Int = 1,fileResult:Observer<List<String>>){ + requestFileResult = fileResult; + var permissions = ""; + //android 13 权限申请细化类型 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + permissions = fileType ; + //android 14 选择文件授权 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { + permissions+=","+ Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED; + } + }else{ + //读取权限 + permissions = Manifest.permission.READ_EXTERNAL_STORAGE ; + } + //申请权限 + requestPermissions(permissions , object :Observer<String>{ + override fun onChanged(value : String) { + if(!value.isEmpty()){ + var intent = Intent() + // intent.action = Intent.ACTION_PICK + // intent.action = Intent.ACTION_GET_CONTENT + + //intent.setType("image/*") + when(fileType){ + Manifest.permission.READ_MEDIA_VIDEO ->{ + intent.action = MediaStore.ACTION_PICK_IMAGES + intent.setType("video/*") // 设置文件类型,可以更具体如"application/pdf" + } + Manifest.permission.READ_MEDIA_AUDIO ->{ + intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI) + intent.setType("audio/*") // 设置文件类型,可以更具体如"application/pdf" + } + Manifest.permission.READ_MEDIA_IMAGES ->{ + intent.action = MediaStore.ACTION_PICK_IMAGES + intent.setType("image/*") // 设置文件类型,可以更具体如"application/pdf" + } + else -> {} + } + // 设置可多选 + intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, maxCount > 1); + if(maxCount > 1){ + //设置最大数量 + intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, maxCount); + } + fileLauncher!!.launch(intent) + }else{ + requestFileResult?.onChanged(ArrayList()) + } + } + }) } fun registerForActivityResult(callback : ActivityResultCallback<ActivityResult>):ActivityResultLauncher<Intent>{ @@ -245,6 +364,16 @@ return result } + @Suppress("DEPRECATION") + protected fun isMyServiceRunning(serviceClass: Class<*>): Boolean { + val manager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager + for (service in manager.getRunningServices(Integer.MAX_VALUE)) { + if (serviceClass.name == service.service.className) { + return true + } + } + return false + } /** * 检查权限 @@ -265,7 +394,37 @@ allGranted = false if (showPop) { // TODO: - //showPermissionPopu(permission) + var title = "" + var message = ""; + if(permissions.contains(Manifest.permission.READ_EXTERNAL_STORAGE)){ + title = "申请文件读取权限"; + message = " 通过文件读取权限后,可无障碍使用图片类、音乐类、视频类文件,并将读取的文件数据添加到直播中的音视频流中。" + }else if(permissions.contains(Manifest.permission.CAMERA)){ + title = "申请相机权限"; + message = " 通过相机权限后,可无障碍使用相机及USB采集设备,并将设备采集的画面添加到直播中的视频流中。" + }else if(permissions.contains(Manifest.permission.RECORD_AUDIO)){ + title = "申请话筒权限"; + message = " 通过话筒权限后,可无障碍使用话筒设备,并将话筒采集的音频数据添加到直播中的音频流中" + }else if(permissions.contains(Manifest.permission.READ_MEDIA_IMAGES) || + permissions.contains(Manifest.permission.READ_MEDIA_VIDEO)){ + title = "申请图片和视频文件权限"; + message = " 通过图片类和视频类文件权限后,可将读取的图片和视频数据添加到直播中的音视频流中。" + }/*else if(permissions.contains(Manifest.permission.READ_MEDIA_IMAGES)){ + title = "申请图片文件权限"; + message = "通过图片类文件权限后,可将读取的图片数据添加到直播中的视频流中。" + }else if(permissions.contains(Manifest.permission.READ_MEDIA_VIDEO)){ + title = "申请视频文件权限"; + message = "通过视频类文件权限后,可将读取的视频数据添加到直播中的音视频流中。" + }*/else if(permissions.contains(Manifest.permission.READ_MEDIA_AUDIO)){ + title = "申请音频文件权限"; + message = " 通过音频文件权限后,可将音频文件的声音添加到直播中的音频流中" + }/*else if(permissions.contains(Manifest.permission.POST_NOTIFICATIONS)){ + title = "申请通知栏权限"; + message = "通过通知栏权限后,可开启后台服务,保证相机、话筒、截屏、扬声器等功能不被系统终止" + }*/ + if(!TextUtils.isEmpty(title)){ + mViewModel!!.showPopupWindow(title = title, message = message) + } } break } @@ -275,6 +434,7 @@ var permissionsLauncher : ActivityResultLauncher<Array<String>>? = null //权限 var permissionObserver : Observer<String>? = null //权限和文件请求回调 + /** * 统一权限申请 */ @@ -329,109 +489,156 @@ //=========================================== //以下为preferences操作 - fun getBooleanUserPrefrence(key : String?) : Boolean { - return PreferencesUtils.getBoolean(this , key , false , PreferencesUtils.USER) + fun getBooleanUserPrefrence(key : String) : Boolean { + return getBooleanUserPrefrence(key,false) } - fun getBooleanProjectPrefrence(key : String?) : Boolean { - return PreferencesUtils.getBoolean(this , key , false , PreferencesUtils.PROJECT) + fun getBooleanUserPrefrence(key : String,value : Boolean) : Boolean { + return PreferencesUtils.getBoolean(this , key , value , PreferencesUtils.USER) } - fun getStringUserPrefrence(key : String?) : String { - return PreferencesUtils.getString(this , key , "" , PreferencesUtils.USER) + fun getBooleanProjectPrefrence(key : String) : Boolean { + return getBooleanProjectPrefrence(key,false) } - fun getStringProjectPrefrence(key : String?) : String { - return PreferencesUtils.getString(this , key , "" , PreferencesUtils.PROJECT) + fun getBooleanProjectPrefrence(key : String,value : Boolean) : Boolean { + return PreferencesUtils.getBoolean(this , key , value , PreferencesUtils.PROJECT) } - fun getIntProjectPrefrence(key : String?) : Int { - return PreferencesUtils.getInt(this , key , 0 , PreferencesUtils.PROJECT) + fun getStringUserPrefrence(key : String) : String { + return getStringUserPrefrence(key,""); } - fun getLongProjectPrefrence(key : String?) : Long { - return PreferencesUtils.getLong(this , key , 0 , PreferencesUtils.PROJECT) + fun getStringUserPrefrence(key : String,value : String?) : String { + return PreferencesUtils.getString(this , key , value, PreferencesUtils.USER) } - fun getFloatProjectPrefrence(key : String?) : Float { - return PreferencesUtils.getFloat(this , key , 0f , PreferencesUtils.PROJECT) + fun getStringProjectPrefrence(key : String) : String { + return getStringProjectPrefrence(key,""); } - fun getStringSetProjectPrefrence(key : String?) : Set<*> { - return PreferencesUtils.getStringSet(this , key , PreferencesUtils.PROJECT) + fun getStringProjectPrefrence(key : String,value : String?) : String { + return PreferencesUtils.getString(this , key , value, PreferencesUtils.PROJECT) } - fun getIntUserPrefrence(key : String?) : Int { - return PreferencesUtils.getInt(this , key , 0 , PreferencesUtils.USER) + fun getIntProjectPrefrence(key : String) : Int { + return getIntProjectPrefrence(key,0); } - fun getLongUserPrefrence(key : String?) : Long { - return PreferencesUtils.getLong(this , key , 0 , PreferencesUtils.USER) + fun getIntProjectPrefrence(key : String,value : Int) : Int { + return PreferencesUtils.getInt(this , key , value , PreferencesUtils.PROJECT) } - fun getFloatUserPrefrence(key : String?) : Float { - return PreferencesUtils.getFloat(this , key , 0f , PreferencesUtils.USER) + fun getLongProjectPrefrence(key : String) : Long { + return getLongProjectPrefrence(key,0); } - fun getStringSetUserPrefrence(key : String?) : Set<*> { - return PreferencesUtils.getStringSet(this , key , PreferencesUtils.USER) + fun getLongProjectPrefrence(key : String,value : Long) : Long { + return PreferencesUtils.getLong(this , key , value , PreferencesUtils.PROJECT) } + fun getFloatProjectPrefrence(key : String) : Float { + return getFloatProjectPrefrence(key,0f); + } - fun putBooleanUserPrefrence(key : String? , value : Boolean) { + fun getFloatProjectPrefrence(key : String,value : Float) : Float { + return PreferencesUtils.getFloat(this , key , value , PreferencesUtils.PROJECT) + } + + fun getStringSetProjectPrefrence(key : String) : Set<*> { + return getStringSetProjectPrefrence(key, ArraySet<Any?>() ) + } + + fun getStringSetProjectPrefrence(key : String,value : Set<*>?) : Set<*> { + return PreferencesUtils.getStringSet(this , key ,value, PreferencesUtils.PROJECT) + } + + fun getIntUserPrefrence(key : String) : Int { + return getIntUserPrefrence(key,0) + } + + fun getIntUserPrefrence(key : String,value : Int) : Int { + return PreferencesUtils.getInt(this , key , value , PreferencesUtils.USER) + } + + fun getLongUserPrefrence(key : String) : Long { + return getLongUserPrefrence(key,0) + } + + fun getLongUserPrefrence(key : String,value : Long) : Long { + return PreferencesUtils.getLong(this , key , value , PreferencesUtils.USER) + } + + fun getFloatUserPrefrence(key : String) : Float { + return getFloatUserPrefrence(key,0f) + } + + fun getFloatUserPrefrence(key : String,value : Float) : Float { + return PreferencesUtils.getFloat(this , key , value , PreferencesUtils.USER) + } + + fun getStringSetUserPrefrence(key : String) : Set<*> { + return getStringSetUserPrefrence(key,ArraySet<Any?>()) + } + + fun getStringSetUserPrefrence(key : String,value : Set<*>) : Set<*> { + return PreferencesUtils.getStringSet(this , key ,value, PreferencesUtils.USER) + } + + fun putBooleanUserPrefrence(key : String , value : Boolean) { PreferencesUtils.putBoolean(this , key , value , PreferencesUtils.USER) } - fun putBooleanProjectPrefrence(key : String? , value : Boolean) { + fun putBooleanProjectPrefrence(key : String , value : Boolean) { PreferencesUtils.putBoolean(this , key , value , PreferencesUtils.PROJECT) } - fun putStringUserPrefrence(key : String? , value : String?) { + fun putStringUserPrefrence(key : String , value : String?) { PreferencesUtils.putString(this , key , value , PreferencesUtils.USER) } - fun putStringProjectPrefrence(key : String? , value : String?) { + fun putStringProjectPrefrence(key : String , value : String?) { PreferencesUtils.putString(this , key , value , PreferencesUtils.PROJECT) } - fun putIntProjectPrefrence(key : String? , value : Int) { + fun putIntProjectPrefrence(key : String , value : Int) { PreferencesUtils.putInt(this , key , value , PreferencesUtils.PROJECT) } - fun putLongProjectPrefrence(key : String? , value : Long) { + fun putLongProjectPrefrence(key : String , value : Long) { PreferencesUtils.putLong(this , key , value , PreferencesUtils.PROJECT) } - fun putFloatProjectPrefrence(key : String? , value : Float) { + fun putFloatProjectPrefrence(key : String , value : Float) { PreferencesUtils.putFloat(this , key , value , PreferencesUtils.PROJECT) } - fun putStringSetProjectPrefrence(key : String? , value : Set<*>?) { + fun putStringSetProjectPrefrence(key : String , value : Set<*>?) { PreferencesUtils.putStringSet(this , key , value , PreferencesUtils.PROJECT) } - fun putIntUserPrefrence(key : String? , value : Int) { + fun putIntUserPrefrence(key : String , value : Int) { PreferencesUtils.putInt(this , key , value , PreferencesUtils.USER) } - fun putLongUserPrefrence(key : String? , value : Long) { + fun putLongUserPrefrence(key : String , value : Long) { PreferencesUtils.putLong(this , key , value , PreferencesUtils.USER) } - fun putFloatUserPrefrence(key : String? , value : Float) { + fun putFloatUserPrefrence(key : String , value : Float) { PreferencesUtils.putFloat(this , key , value , PreferencesUtils.USER) } - fun putStringSetUserPrefrence(key : String? , value : Set<*>?) { + fun putStringSetUserPrefrence(key : String , value : Set<*>?) { PreferencesUtils.putStringSet(this , key , value , PreferencesUtils.USER) } - fun removeUserKey(key : String?) { + fun removeUserKey(key : String) { PreferencesUtils.removeKey(this , key , PreferencesUtils.USER) } - fun removeProjectKey(key : String?) { + fun removeProjectKey(key : String) { PreferencesUtils.removeKey(this , key , PreferencesUtils.PROJECT) } -- Gitblit v1.9.1