完善摄像头信息

This commit is contained in:
xsean 2025-12-23 15:44:19 +08:00
parent 25b5d7b977
commit b8f046ec87
3 changed files with 1304 additions and 11 deletions

View File

@ -2,39 +2,517 @@ package com.xyzshell.andinfo.libs
import android.Manifest
import android.annotation.SuppressLint
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothManager
import android.bluetooth.le.BluetoothLeScanner
import android.bluetooth.le.ScanCallback
import android.bluetooth.le.ScanResult
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageManager
import android.os.Build
import androidx.core.app.ActivityCompat
/**
* 蓝牙信息工具类
* 提供蓝牙适配器信息已配对设备附近设备扫描蓝牙特性检测等功能
*/
class BluetoothInfo(private val context: Context) {
/**
* 蓝牙管理器
*/
private val bluetoothManager: BluetoothManager? = context.getSystemService(
BluetoothManager::class.java
)
/**
* 蓝牙适配器
*/
@get:SuppressLint("MissingPermission")
val bluetoothAdapter by lazy { bluetoothManager?.adapter }
/**
* 蓝牙设备信息数据类
*/
data class DeviceInfo(
val name: String?, // 设备名称
val address: String, // MAC地址
val bondState: Int, // 配对状态
val bondStateText: String, // 配对状态文本
val deviceClass: Int?, // 设备类型
val deviceType: Int?, // 设备类型LE/Classic/Dual
val rssi: Int? = null, // 信号强度(仅扫描设备)
val uuids: List<String>? = null // 支持的服务UUID
)
/**
* 蓝牙特性信息数据类
*/
data class BluetoothFeatures(
val version: String, // 蓝牙版本
val bluetoothLe: Boolean, // 是否支持BLE
val bluetooth: Boolean, // 是否支持经典蓝牙
// Bluetooth 4.x 特性
val le2MbPhy: Boolean, // 2Mbps PHY
val leCodedPhy: Boolean, // Coded PHY
val leExtendedAdvertising: Boolean, // 扩展广播
val lePeriodicAdvertising: Boolean, // 周期性广播
// Bluetooth 5.x 特性
val bluetooth5Support: Boolean, // Bluetooth 5支持
val leAudioSupport: Boolean, // LE Audio支持
val leAudioBroadcast: Boolean, // LE Audio广播
val leAudioUnicast: Boolean, // LE Audio单播
// 其他特性
val offloadedFiltering: Boolean, // 硬件过滤
val offloadedScanBatching: Boolean, // 批量扫描
val multipleAdvertisement: Boolean, // 多广播
val lowEnergyExtended: Boolean // 扩展LE
)
// ==================== 基本信息 ====================
/**
* 获取蓝牙适配器名称
* 需要权限: BLUETOOTH_CONNECT (Android 12+)
*/
@get:SuppressLint("MissingPermission")
val adapterName: String?
get() = bluetoothAdapter?.name
get() = if (checkBluetoothConnectPermission()) {
bluetoothAdapter?.name
} else null
/**
* 获取蓝牙适配器MAC地址
* 需要权限: BLUETOOTH_CONNECT (Android 12+)
* 注意: Android 6.0+ 返回固定地址 02:00:00:00:00:00
*/
@get:SuppressLint("HardwareIds", "MissingPermission")
val adapterMacAddress: String?
get() = bluetoothAdapter?.address
get() = if (checkBluetoothConnectPermission()) {
bluetoothAdapter?.address
} else null
@get:SuppressLint("MissingPermission")
val bondedDevices: List<Pair<String?, String>>
get() = bluetoothAdapter?.bondedDevices?.map {
Pair(it.name, it.address)
} ?: emptyList()
/**
* 蓝牙是否已启用
*/
val isEnabled: Boolean
get() = bluetoothAdapter?.isEnabled == true
/**
* 蓝牙适配器状态
*/
val state: Int
get() = bluetoothAdapter?.state ?: BluetoothAdapter.STATE_OFF
/**
* 蓝牙适配器状态文本
*/
val stateText: String
get() = when (state) {
BluetoothAdapter.STATE_OFF -> "关闭"
BluetoothAdapter.STATE_TURNING_ON -> "正在开启"
BluetoothAdapter.STATE_ON -> "已开启"
BluetoothAdapter.STATE_TURNING_OFF -> "正在关闭"
else -> "未知"
}
/**
* 是否支持低功耗蓝牙BLE
*/
val isBluetoothLeSupported: Boolean
get() = context.packageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)
/**
* 是否正在扫描设备
*/
@get:SuppressLint("MissingPermission")
val isDiscovering: Boolean
get() = if (checkBluetoothScanPermission()) {
bluetoothAdapter?.isDiscovering == true
} else false
// ==================== 已配对设备 ====================
/**
* 获取已配对设备列表简化版本兼容旧代码
* 需要权限: BLUETOOTH_CONNECT (Android 12+)
*/
@get:SuppressLint("MissingPermission")
val bondedDevices: List<Pair<String?, String>>
get() = if (checkBluetoothConnectPermission()) {
bluetoothAdapter?.bondedDevices?.map {
Pair(it.name, it.address)
} ?: emptyList()
} else emptyList()
/**
* 获取已配对设备详细信息列表
* 需要权限: BLUETOOTH_CONNECT (Android 12+)
*/
@SuppressLint("MissingPermission")
fun getBondedDevicesInfo(): List<DeviceInfo> {
if (!checkBluetoothConnectPermission()) return emptyList()
return try {
bluetoothAdapter?.bondedDevices?.map { device ->
DeviceInfo(
name = device.name,
address = device.address,
bondState = device.bondState,
bondStateText = getBondStateText(device.bondState),
deviceClass = device.bluetoothClass?.deviceClass,
deviceType = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
device.type
} else null,
uuids = device.uuids?.map { it.toString() }
)
} ?: emptyList()
} catch (e: SecurityException) {
emptyList()
}
}
// ==================== 附近设备扫描 ====================
/**
* 扫描附近的经典蓝牙设备
* 需要权限: BLUETOOTH_SCAN, ACCESS_FINE_LOCATION (Android 12+)
* @param onDeviceFound 发现设备回调
* @param onScanFinished 扫描完成回调
*/
@SuppressLint("MissingPermission")
fun scanNearbyDevices(
onDeviceFound: (DeviceInfo) -> Unit,
onScanFinished: () -> Unit
) {
if (!checkBluetoothScanPermission() || !checkLocationPermission()) {
onScanFinished()
return
}
val receiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
when (intent.action) {
BluetoothDevice.ACTION_FOUND -> {
val device: BluetoothDevice? = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE, BluetoothDevice::class.java)
} else {
@Suppress("DEPRECATION")
intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)
}
val rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI, Short.MIN_VALUE).toInt()
device?.let {
onDeviceFound(
DeviceInfo(
name = it.name,
address = it.address,
bondState = it.bondState,
bondStateText = getBondStateText(it.bondState),
deviceClass = it.bluetoothClass?.deviceClass,
deviceType = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
it.type
} else null,
rssi = rssi,
uuids = it.uuids?.map { uuid -> uuid.toString() }
)
)
}
}
BluetoothAdapter.ACTION_DISCOVERY_FINISHED -> {
context.unregisterReceiver(this)
onScanFinished()
}
}
}
}
val filter = IntentFilter().apply {
addAction(BluetoothDevice.ACTION_FOUND)
addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)
}
context.registerReceiver(receiver, filter)
bluetoothAdapter?.startDiscovery()
}
/**
* 扫描附近的BLE设备
* 需要权限: BLUETOOTH_SCAN, ACCESS_FINE_LOCATION (Android 12+)
* @param onDeviceFound 发现设备回调
* @param durationMillis 扫描时长毫秒
*/
@SuppressLint("MissingPermission")
fun scanLeDevices(
onDeviceFound: (DeviceInfo) -> Unit,
durationMillis: Long = 10000
) {
if (!checkBluetoothScanPermission() || !checkLocationPermission()) {
return
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return
val leScanner: BluetoothLeScanner? = bluetoothAdapter?.bluetoothLeScanner
val scanCallback = object : ScanCallback() {
override fun onScanResult(callbackType: Int, result: ScanResult) {
val device = result.device
onDeviceFound(
DeviceInfo(
name = device.name,
address = device.address,
bondState = device.bondState,
bondStateText = getBondStateText(device.bondState),
deviceClass = device.bluetoothClass?.deviceClass,
deviceType = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
device.type
} else null,
rssi = result.rssi,
uuids = result.scanRecord?.serviceUuids?.map { it.toString() }
)
)
}
}
leScanner?.startScan(scanCallback)
// 定时停止扫描
android.os.Handler(android.os.Looper.getMainLooper()).postDelayed({
leScanner?.stopScan(scanCallback)
}, durationMillis)
}
/**
* 停止设备扫描
*/
@SuppressLint("MissingPermission")
fun stopScan() {
if (checkBluetoothScanPermission()) {
bluetoothAdapter?.cancelDiscovery()
}
}
// ==================== 蓝牙特性检测 ====================
/**
* 获取蓝牙特性信息
*/
fun getBluetoothFeatures(): BluetoothFeatures {
val adapter = bluetoothAdapter
return BluetoothFeatures(
version = getBluetoothVersion(),
bluetoothLe = isBluetoothLeSupported,
bluetooth = context.packageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH),
// Bluetooth 4.x 特性
le2MbPhy = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
adapter?.isLe2MPhySupported == true
} else false,
leCodedPhy = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
adapter?.isLeCodedPhySupported == true
} else false,
leExtendedAdvertising = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
adapter?.isLeExtendedAdvertisingSupported == true
} else false,
lePeriodicAdvertising = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
adapter?.isLePeriodicAdvertisingSupported == true
} else false,
// Bluetooth 5.x 特性
bluetooth5Support = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
adapter?.isLe2MPhySupported == true ||
adapter?.isLeCodedPhySupported == true ||
adapter?.isLeExtendedAdvertisingSupported == true
} else false,
leAudioSupport = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
context.packageManager.hasSystemFeature("android.hardware.bluetooth.le.audio")
} else false,
leAudioBroadcast = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
context.packageManager.hasSystemFeature("android.hardware.bluetooth.le.audio.broadcast_source")
} else false,
leAudioUnicast = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
context.packageManager.hasSystemFeature("android.hardware.bluetooth.le.audio.unicast_client")
} else false,
// 其他特性
offloadedFiltering = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
adapter?.isOffloadedFilteringSupported == true
} else false,
offloadedScanBatching = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
adapter?.isOffloadedScanBatchingSupported == true
} else false,
multipleAdvertisement = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
adapter?.isMultipleAdvertisementSupported == true
} else false,
lowEnergyExtended = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
adapter?.isLeExtendedAdvertisingSupported == true
} else false
)
}
/**
* 获取蓝牙版本根据支持的特性推断
*/
private fun getBluetoothVersion(): String {
val adapter = bluetoothAdapter ?: return "未知"
return when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU &&
context.packageManager.hasSystemFeature("android.hardware.bluetooth.le.audio") ->
"Bluetooth 5.2+"
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O &&
(adapter.isLe2MPhySupported || adapter.isLeCodedPhySupported) ->
"Bluetooth 5.0"
Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && isBluetoothLeSupported ->
"Bluetooth 4.2"
isBluetoothLeSupported ->
"Bluetooth 4.0"
else ->
"Bluetooth 3.0 或更低"
}
}
// ==================== 权限检查 ====================
/**
* 所需权限列表
*/
val requiredPermissions: Array<String>
get() = buildList {
add(Manifest.permission.BLUETOOTH_CONNECT)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
add(Manifest.permission.BLUETOOTH_CONNECT)
add(Manifest.permission.BLUETOOTH_SCAN)
} else {
add(Manifest.permission.BLUETOOTH)
add(Manifest.permission.BLUETOOTH_ADMIN)
}
add(Manifest.permission.ACCESS_FINE_LOCATION)
}.toTypedArray()
/**
* 检查蓝牙连接权限
*/
private fun checkBluetoothConnectPermission(): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
ActivityCompat.checkSelfPermission(
context,
Manifest.permission.BLUETOOTH_CONNECT
) == PackageManager.PERMISSION_GRANTED
} else {
ActivityCompat.checkSelfPermission(
context,
Manifest.permission.BLUETOOTH
) == PackageManager.PERMISSION_GRANTED
}
}
/**
* 检查蓝牙扫描权限
*/
private fun checkBluetoothScanPermission(): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
ActivityCompat.checkSelfPermission(
context,
Manifest.permission.BLUETOOTH_SCAN
) == PackageManager.PERMISSION_GRANTED
} else {
ActivityCompat.checkSelfPermission(
context,
Manifest.permission.BLUETOOTH_ADMIN
) == PackageManager.PERMISSION_GRANTED
}
}
/**
* 检查位置权限
*/
private fun checkLocationPermission(): Boolean {
return ActivityCompat.checkSelfPermission(
context,
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
}
// ==================== 辅助方法 ====================
/**
* 获取配对状态文本
*/
private fun getBondStateText(state: Int): String = when (state) {
BluetoothDevice.BOND_NONE -> "未配对"
BluetoothDevice.BOND_BONDING -> "正在配对"
BluetoothDevice.BOND_BONDED -> "已配对"
else -> "未知"
}
/**
* 获取设备类型文本
*/
fun getDeviceTypeText(type: Int?): String = when (type) {
BluetoothDevice.DEVICE_TYPE_CLASSIC -> "经典蓝牙"
BluetoothDevice.DEVICE_TYPE_LE -> "低功耗蓝牙"
BluetoothDevice.DEVICE_TYPE_DUAL -> "双模蓝牙"
else -> "未知"
}
/**
* 获取文本格式的蓝牙信息摘要
*/
fun text(): String {
val sb = StringBuilder()
// 基本信息
sb.append("=== 蓝牙基本信息 ===\n")
sb.append("适配器名称: ${adapterName ?: "未知"}\n")
sb.append("MAC地址: ${adapterMacAddress ?: "未知"}\n")
sb.append("状态: $stateText\n")
sb.append("是否启用: ${if (isEnabled) "是" else "否"}\n")
// 蓝牙特性
val features = getBluetoothFeatures()
sb.append("\n=== 蓝牙特性 ===\n")
sb.append("蓝牙版本: ${features.version}\n")
sb.append("经典蓝牙: ${if (features.bluetooth) "支持" else "不支持"}\n")
sb.append("低功耗蓝牙: ${if (features.bluetoothLe) "支持" else "不支持"}\n")
sb.append("Bluetooth 5: ${if (features.bluetooth5Support) "支持" else "不支持"}\n")
sb.append("LE Audio: ${if (features.leAudioSupport) "支持" else "不支持"}\n")
sb.append("2Mbps PHY: ${if (features.le2MbPhy) "支持" else "不支持"}\n")
sb.append("Coded PHY: ${if (features.leCodedPhy) "支持" else "不支持"}\n")
sb.append("扩展广播: ${if (features.leExtendedAdvertising) "支持" else "不支持"}\n")
sb.append("周期性广播: ${if (features.lePeriodicAdvertising) "支持" else "不支持"}\n")
// 已配对设备
val bonded = getBondedDevicesInfo()
sb.append("\n=== 已配对设备 (${bonded.size}) ===\n")
bonded.forEach { device ->
sb.append("设备: ${device.name ?: "未知"}\n")
sb.append(" 地址: ${device.address}\n")
sb.append(" 状态: ${device.bondStateText}\n")
device.deviceType?.let {
sb.append(" 类型: ${getDeviceTypeText(it)}\n")
}
}
return sb.toString()
}
}

View File

@ -5,101 +5,257 @@ import android.os.Build
// import androidx.security.state.SecurityStateManagerCompat
import java.util.Date
/**
* 系统构建信息工具类
* 提供 Android 系统构建版本编译信息安全补丁JVM 信息等
*/
class BuildInfo(private val context: Context) {
// private val securityStateManager = SecurityStateManagerCompat(context)
// private val globalSecurityState = securityStateManager.getGlobalSecurityState()
// ==================== 构建基本信息 ====================
/**
* 系统构建指纹
* 格式: brand/product/device:version/id/incremental:type/tags
* 示例: google/redfin/redfin:13/TP1A.220905.004/9012412:user/release-keys
*/
val fingerprint: String
get() = Build.FINGERPRINT
/**
* 构建标签
* 通常为 "release-keys" (正式版) "test-keys" (测试版)
*/
val tags: String
get() = Build.TAGS
/**
* 构建类型
* 通常为 "user" (用户版)"userdebug" (调试版) "eng" (工程版)
*/
val type: String
get() = Build.TYPE
/**
* 系统构建日期
* 返回构建时的时间戳
*/
val buildDate: Date
get() = Date(Build.TIME)
/**
* 构建主机名
* 编译系统的主机名
*/
val host: String
get() = Build.HOST
/**
* 构建用户
* 执行编译的用户名
*/
val user: String
get() = Build.USER
/**
* 构建 ID
* 构建的唯一标识符通常是版本号
* 示例: TP1A.220905.004
*/
val id: String
get() = Build.ID
/**
* 显示 ID
* 用于向用户显示的构建标识符
*/
val display: String
get() = Build.DISPLAY
// ==================== Android 版本信息 ====================
/**
* Android 版本号
* 示例: "13", "12", "11"
*/
val versionRelease: String
get() = Build.VERSION.RELEASE
/**
* 版本代号
* 开发阶段的代号正式版通常为 "REL"
*/
val versionCodename: String
get() = Build.VERSION.CODENAME
/**
* SDK 版本号API Level
* 示例: 33 (Android 13), 31 (Android 12), 30 (Android 11)
*/
val versionSdkInt: Int
get() = Build.VERSION.SDK_INT
/**
* 预览版 SDK 版本号
* 如果是预览版返回非 0 正式版返回 0
*/
val versionPreviewSdkInt: Int
get() = Build.VERSION.PREVIEW_SDK_INT
/**
* 安全补丁级别
* 格式: YYYY-MM-DD
* 示例: "2023-12-05"
*/
val securityPatch: String
get() = Build.VERSION.SECURITY_PATCH
/**
* 基础操作系统
* 通常为空除非是基于其他版本构建
*/
val baseOs: String
get() = Build.VERSION.BASE_OS
/**
* 增量版本
* 表示在同一版本号下的递增更新
*/
val incremental: String
get() = Build.VERSION.INCREMENTAL
/**
* 版本号或代号
* Android 11+ 可用
* 如果是正式版返回版本号预览版返回代号
*/
val releaseOrCodename: String?
get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) Build.VERSION.RELEASE_OR_CODENAME else null
/**
* 媒体性能等级
* Android 12+ 可用
* 返回设备的媒体性能等级0 表示未定义
* 示例: 31 (Android 12), 33 (Android 13)
*/
val mediaPerformanceClass: Int
get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) Build.VERSION.MEDIA_PERFORMANCE_CLASS else 0
/**
* 版本显示字符串
* Android 13+ 可用
* 用于显示的完整版本号包括预览版
*/
val releaseOrPreviewDisplay: String?
get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) Build.VERSION.RELEASE_OR_PREVIEW_DISPLAY else null
// ==================== JVM 信息 ====================
/**
* JVM 名称
* 示例: "Dalvik" (Android) "Java HotSpot(TM) 64-Bit Server VM"
*/
val jvmName: String?
get() = System.getProperty("java.vm.name")
/**
* JVM 供应商
* 示例: "The Android Project" "Oracle Corporation"
*/
val jvmVendor: String?
get() = System.getProperty("java.vm.vendor")
/**
* JVM 版本
* 示例: "2.1.0"
*/
val jvmVersion: String?
get() = System.getProperty("java.vm.version")
/**
* Java 类版本
* 示例: "50.0" (Java 6), "52.0" (Java 8)
*/
val jvmClassVersion: String?
get() = System.getProperty("java.class.version")
/**
* Java 规范名称
* 示例: "Dalvik Core Library"
*/
val jvmSpecificationName: String?
get() = System.getProperty("java.specification.name")
/**
* Java 规范供应商
* 示例: "The Android Project"
*/
val jvmSpecificationVendor: String?
get() = System.getProperty("java.specification.vendor")
/**
* Java 规范版本
* 示例: "0.9"
*/
val jvmSpecificationVersion: String?
get() = System.getProperty("java.specification.version")
// ==================== 安全与内核信息 ====================
/**
* 厂商安全补丁级别
* 需要 SecurityStateManagerCompat 支持
* 某些设备可能有额外的厂商安全补丁
*/
val vendorSecurityPatchLevel: String?
get() = null // globalSecurityState.getString(SecurityStateManagerCompat.KEY_VENDOR_SPL)
/**
* 内核版本
* 需要 SecurityStateManagerCompat 支持
* 示例: "5.10.157"
*/
val kernelVersion: String?
get() = null // globalSecurityState.getString(SecurityStateManagerCompat.KEY_KERNEL_VERSION)
/**
* 完整内核版本
* 包含内核版本和编译信息
* 示例: "5.10.157-android13-4-00001-gf0123456789a-ab9876543"
*/
val kernelCompleteVersion: String?
get() = System.getProperty("os.version")
/**
* Bootloader 版本
* 设备的引导加载程序版本
*/
val bootloaderVersion: String
get() = Build.BOOTLOADER
/**
* 基带版本无线电版本
* 移动网络基带固件版本
*/
val radioVersion: String?
get() = Build.getRadioVersion()
// ==================== 分区信息 ====================
/**
* 指纹分区信息列表
* Android 10+ 可用
* 包含系统各分区的名称和指纹信息
*
* 常见分区
* - system: 系统分区
* - vendor: 厂商分区
* - product: 产品分区
* - odm: ODM原始设计制造商分区
* - system_ext: 系统扩展分区
*/
val fingerprintedPartitions: List<PartitionInfo>
get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
Build.getFingerprintedPartitions().map { PartitionInfo(it.name, it.fingerprint) }
@ -107,5 +263,72 @@ class BuildInfo(private val context: Context) {
emptyList()
}
/**
* 分区信息数据类
* @property name 分区名称
* @property fingerprint 分区指纹构建标识
*/
data class PartitionInfo(val name: String, val fingerprint: String)
// ==================== 辅助方法 ====================
/**
* 获取文本格式的构建信息摘要
* @return 格式化的文本信息
*/
fun text(): String {
val sb = StringBuilder()
// 基本构建信息
sb.append("=== 系统构建信息 ===\n")
sb.append("指纹: $fingerprint\n")
sb.append("显示ID: $display\n")
sb.append("构建ID: $id\n")
sb.append("类型: $type\n")
sb.append("标签: $tags\n")
sb.append("构建日期: $buildDate\n")
sb.append("构建用户: $user\n")
sb.append("构建主机: $host\n")
// Android 版本信息
sb.append("\n=== Android 版本 ===\n")
sb.append("版本号: $versionRelease\n")
sb.append("SDK版本: $versionSdkInt\n")
sb.append("代号: $versionCodename\n")
sb.append("增量版本: $incremental\n")
sb.append("安全补丁: $securityPatch\n")
releaseOrCodename?.let { sb.append("版本/代号: $it\n") }
if (mediaPerformanceClass > 0) {
sb.append("媒体性能等级: $mediaPerformanceClass\n")
}
releaseOrPreviewDisplay?.let { sb.append("版本显示: $it\n") }
if (baseOs.isNotEmpty()) {
sb.append("基础OS: $baseOs\n")
}
// JVM 信息
sb.append("\n=== JVM 信息 ===\n")
jvmName?.let { sb.append("JVM名称: $it\n") }
jvmVendor?.let { sb.append("JVM供应商: $it\n") }
jvmVersion?.let { sb.append("JVM版本: $it\n") }
jvmClassVersion?.let { sb.append("类版本: $it\n") }
jvmSpecificationName?.let { sb.append("规范名称: $it\n") }
jvmSpecificationVersion?.let { sb.append("规范版本: $it\n") }
// 硬件信息
sb.append("\n=== 硬件信息 ===\n")
sb.append("Bootloader: $bootloaderVersion\n")
radioVersion?.let { sb.append("基带版本: $it\n") }
kernelCompleteVersion?.let { sb.append("内核版本: $it\n") }
// 分区信息
if (fingerprintedPartitions.isNotEmpty()) {
sb.append("\n=== 分区指纹 ===\n")
fingerprintedPartitions.forEach { partition ->
sb.append("${partition.name}: ${partition.fingerprint}\n")
}
}
return sb.toString()
}
}

View File

@ -8,25 +8,111 @@ import android.hardware.camera2.CameraMetadata
import android.os.Build
import android.os.Handler
import android.os.Looper
import android.util.Range
import android.util.SizeF
import com.xyzshell.andinfo.R
import com.xyzshell.andinfo.libs.camera.models.CameraCapability
import com.xyzshell.andinfo.libs.camera.models.CameraFacing
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.callbackFlow
import kotlin.math.sqrt
/**
* 摄像头信息工具类
* 提供摄像头硬件参数特性功能列表等详细信息
* 需要权限: CAMERA
*/
class CameraInfo(private val context: Context) {
/**
* 摄像头管理器
*/
private val cameraManager: CameraManager? = context.getSystemService(
CameraManager::class.java
)
/**
* 摄像头详细信息数据类
*/
data class CameraDetails(
val cameraId: String, // 摄像头ID
val facing: CameraFacing?, // 前置/后置/外置
val facingText: String, // 方向文本
// 传感器信息
val megaPixels: Double?, // 有效百万像素
val resolution: String?, // 分辨率宽x高
val sensorSize: String?, // 传感器尺寸mm
val sensorSizeInch: Double?, // 传感器英寸
val pixelSize: Double?, // 单像素尺寸μm
val colorFilterArrangement: String?, // 滤镜颜色排列Bayer等
// 光学参数
val focalLength: FloatArray?, // 焦距mm
val apertures: FloatArray?, // 光圈值
val fieldOfView: String?, // 视野角度
val focal35mmEquivalent: Double?, // 35mm等效焦距
val cropFactor: Double?, // 裁切系数
// 曝光参数
val isoRange: Range<Int>?, // ISO感光范围
val exposureTimeRange: Range<Long>?, // 曝光时间范围(纳秒)
val shutterSpeedRange: String?, // 快门速度范围
val exposureCompensationRange: String?, // 曝光补偿范围
val exposureCompensationStep: Double?, // 曝光补偿步长
// 对焦参数
val minimumFocusDistance: Float?, // 最小对焦距离(屈光度)
val minimumFocusDistanceCm: Double?, // 最小对焦距离(厘米)
val hyperFocalDistance: Float?, // 超焦距
// 功能特性
val hasFlash: Boolean?, // 是否有闪光灯
val hasOpticalStabilization: Boolean?, // 光学防抖OIS
val hasVideoStabilization: Boolean?, // 视频防抖
val hasAutoFocus: Boolean?, // 自动对焦
val camera2ApiSupport: String?, // Camera2 API支持级别
// 面部检测
val maxFaceCount: Int?, // 最大面部检测数量
val faceDetectionModes: List<String>?, // 面部检测模式列表
// 功能列表
val capabilities: List<CameraCapability>, // 摄像头能力
val supportedFeatures: List<String>, // 支持的功能HDR、RAW等
// 模式列表
val autoExposureModes: List<String>?, // 自动曝光模式
val autoFocusModes: List<String>?, // 自动对焦模式
val whiteBalanceModes: List<String>?, // 白平衡模式
val sceneModes: List<String>?, // 场景模式
val colorEffects: List<String>?, // 色彩效果
// 视频能力
val maxFrameRate: Int?, // 最大帧率
val supportsHighSpeedVideo: Boolean, // 是否支持高速视频
val supports4K: Boolean, // 是否支持4K录制
val supports8K: Boolean // 是否支持8K录制
)
/**
* 获取所有摄像头ID列表
*/
val cameraIds: List<String>
get() = cameraManager?.cameraIdList?.toList() ?: emptyList()
/**
* 获取指定摄像头的特性对象
* @param cameraId 摄像头ID
* @return CameraCharacteristics 对象
*/
fun getCameraCharacteristics(cameraId: String): CameraCharacteristics? {
return cameraManager?.getCameraCharacteristics(cameraId)
}
/**
* 监听摄像头可用性变化的 Flow
*/
fun cameraIdsFlow() = cameraManager?.let { manager ->
callbackFlow {
val onCameraIdUpdated = {
@ -55,6 +141,12 @@ class CameraInfo(private val context: Context) {
}
}
// ==================== 基本信息 ====================
/**
* 获取摄像头朝向
* @return 前置/后置/外置
*/
fun getCameraFacing(characteristics: CameraCharacteristics): CameraFacing? {
return characteristics.get(CameraCharacteristics.LENS_FACING)?.let {
when (it) {
@ -66,22 +158,291 @@ class CameraInfo(private val context: Context) {
}
}
/**
* 获取摄像头朝向文本
*/
fun getCameraFacingText(characteristics: CameraCharacteristics): String {
return when (getCameraFacing(characteristics)) {
CameraFacing.BACK -> "后置"
CameraFacing.FRONT -> "前置"
CameraFacing.EXTERNAL -> "外置"
else -> "未知"
}
}
// ==================== 传感器信息 ====================
/**
* 获取像素阵列尺寸分辨率
* @return 格式: "宽x高"
*/
fun getPixelArraySize(characteristics: CameraCharacteristics): String? {
return characteristics.get(CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE)?.toString()
}
/**
* 获取有效百万像素
*/
fun getMegaPixels(characteristics: CameraCharacteristics): Double? {
val size = characteristics.get(CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE)
return size?.let { (it.width * it.height) / 1_000_000.0 }
}
/**
* 获取传感器物理尺寸
* @return 格式: "宽x高 mm"
*/
fun getSensorPhysicalSize(characteristics: CameraCharacteristics): String? {
return characteristics.get(CameraCharacteristics.SENSOR_INFO_PHYSICAL_SIZE)?.toString()
return characteristics.get(CameraCharacteristics.SENSOR_INFO_PHYSICAL_SIZE)?.let {
String.format("%.2f x %.2f mm", it.width, it.height)
}
}
fun hasFlashUnit(characteristics: CameraCharacteristics): Boolean? {
return characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE)
/**
* 获取传感器尺寸英寸对角线
*/
fun getSensorSizeInch(characteristics: CameraCharacteristics): Double? {
return characteristics.get(CameraCharacteristics.SENSOR_INFO_PHYSICAL_SIZE)?.let {
val diagonal = sqrt((it.width * it.width + it.height * it.height).toDouble())
diagonal / 25.4 // 转换为英寸
}
}
/**
* 获取单像素尺寸微米
*/
fun getPixelSize(characteristics: CameraCharacteristics): Double? {
val physicalSize = characteristics.get(CameraCharacteristics.SENSOR_INFO_PHYSICAL_SIZE)
val pixelArray = characteristics.get(CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE)
return if (physicalSize != null && pixelArray != null) {
val pixelWidth = (physicalSize.width * 1000) / pixelArray.width
val pixelHeight = (physicalSize.height * 1000) / pixelArray.height
(pixelWidth + pixelHeight) / 2.0
} else null
}
/**
* 获取滤镜颜色排列
*/
fun getColorFilterArrangement(characteristics: CameraCharacteristics): String? {
return characteristics.get(CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT)?.let {
when (it) {
CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGGB -> "RGGB (Bayer)"
CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GRBG -> "GRBG (Bayer)"
CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_GBRG -> "GBRG (Bayer)"
CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_BGGR -> "BGGR (Bayer)"
CameraCharacteristics.SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_RGB -> "RGB"
5 -> "Mono/NIR (单色/近红外)" // MONO/NIR
else -> "未知"
}
}
}
// ==================== 光学参数 ====================
/**
* 获取焦距数组
*/
fun getFocalLength(characteristics: CameraCharacteristics): FloatArray? {
return characteristics.get(CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS)
}
/**
* 获取光圈值数组
*/
fun getAvailableApertures(characteristics: CameraCharacteristics): FloatArray? {
return characteristics.get(CameraCharacteristics.LENS_INFO_AVAILABLE_APERTURES)
}
/**
* 获取35mm等效焦距
*/
fun getFocal35mmEquivalent(characteristics: CameraCharacteristics): Double? {
val focalLength = getFocalLength(characteristics)?.firstOrNull()
val cropFactor = getCropFactor(characteristics)
return if (focalLength != null && cropFactor != null) {
focalLength * cropFactor
} else null
}
/**
* 获取裁切系数相对于全画幅
*/
fun getCropFactor(characteristics: CameraCharacteristics): Double? {
val sensorSize = characteristics.get(CameraCharacteristics.SENSOR_INFO_PHYSICAL_SIZE)
return sensorSize?.let {
val diagonal = sqrt((it.width * it.width + it.height * it.height).toDouble())
43.27 / diagonal // 全画幅对角线约43.27mm
}
}
/**
* 获取视野角度
*/
fun getFieldOfView(characteristics: CameraCharacteristics): String? {
val focalLength = getFocalLength(characteristics)?.firstOrNull()
val sensorSize = characteristics.get(CameraCharacteristics.SENSOR_INFO_PHYSICAL_SIZE)
return if (focalLength != null && sensorSize != null) {
val hFov = 2 * Math.toDegrees(Math.atan((sensorSize.width / 2.0 / focalLength).toDouble()))
val vFov = 2 * Math.toDegrees(Math.atan((sensorSize.height / 2.0 / focalLength).toDouble()))
String.format("H: %.1f°, V: %.1f°", hFov, vFov)
} else null
}
// ==================== 曝光参数 ====================
/**
* 获取ISO感光度范围
*/
fun getIsoRange(characteristics: CameraCharacteristics): Range<Int>? {
return characteristics.get(CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE)
}
/**
* 获取曝光时间范围纳秒
*/
fun getExposureTimeRange(characteristics: CameraCharacteristics): Range<Long>? {
return characteristics.get(CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE)
}
/**
* 获取快门速度范围格式化字符串
*/
fun getShutterSpeedRange(characteristics: CameraCharacteristics): String? {
val exposureRange = getExposureTimeRange(characteristics)
return exposureRange?.let {
val minSeconds = it.lower / 1_000_000_000.0
val maxSeconds = it.upper / 1_000_000_000.0
String.format("1/%.0f - %.2fs", 1.0 / minSeconds, maxSeconds)
}
}
/**
* 获取曝光补偿范围
*/
fun getExposureCompensationRange(characteristics: CameraCharacteristics): String? {
val range = characteristics.get(CameraCharacteristics.CONTROL_AE_COMPENSATION_RANGE)
val step = characteristics.get(CameraCharacteristics.CONTROL_AE_COMPENSATION_STEP)
return if (range != null && step != null) {
val minEv = range.lower * step.toDouble()
val maxEv = range.upper * step.toDouble()
String.format("%.1f ~ %.1f EV", minEv, maxEv)
} else null
}
/**
* 获取曝光补偿步长
*/
fun getExposureCompensationStep(characteristics: CameraCharacteristics): Double? {
return characteristics.get(CameraCharacteristics.CONTROL_AE_COMPENSATION_STEP)?.toDouble()
}
// ==================== 对焦参数 ====================
/**
* 获取最小对焦距离屈光度
*/
fun getMinimumFocusDistance(characteristics: CameraCharacteristics): Float? {
return characteristics.get(CameraCharacteristics.LENS_INFO_MINIMUM_FOCUS_DISTANCE)
}
/**
* 获取最小对焦距离厘米
*/
fun getMinimumFocusDistanceCm(characteristics: CameraCharacteristics): Double? {
val diopters = getMinimumFocusDistance(characteristics)
return diopters?.let {
if (it > 0) 100.0 / it else null
}
}
/**
* 获取超焦距
*/
fun getHyperFocalDistance(characteristics: CameraCharacteristics): Float? {
return characteristics.get(CameraCharacteristics.LENS_INFO_HYPERFOCAL_DISTANCE)
}
// ==================== 功能特性 ====================
/**
* 是否有闪光灯
*/
fun hasFlashUnit(characteristics: CameraCharacteristics): Boolean? {
return characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE)
}
/**
* 是否支持光学防抖OIS
*/
fun hasOpticalStabilization(characteristics: CameraCharacteristics): Boolean {
val modes = characteristics.get(CameraCharacteristics.LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION)
return modes?.contains(CameraCharacteristics.LENS_OPTICAL_STABILIZATION_MODE_ON) == true
}
/**
* 是否支持视频防抖
*/
fun hasVideoStabilization(characteristics: CameraCharacteristics): Boolean {
val modes = characteristics.get(CameraCharacteristics.CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES)
return modes?.contains(CameraCharacteristics.CONTROL_VIDEO_STABILIZATION_MODE_ON) == true
}
/**
* 是否支持自动对焦
*/
fun hasAutoFocus(characteristics: CameraCharacteristics): Boolean {
val minDistance = getMinimumFocusDistance(characteristics)
return minDistance != null && minDistance > 0
}
/**
* 获取Camera2 API支持级别
*/
fun getCamera2ApiSupport(characteristics: CameraCharacteristics): String? {
return characteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL)?.let {
when (it) {
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED -> "LIMITED"
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_FULL -> "FULL"
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY -> "LEGACY"
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_3 -> "LEVEL_3"
CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) "EXTERNAL" else "未知"
else -> "未知"
}
}
}
// ==================== 面部检测 ====================
/**
* 获取最大面部检测数量
*/
fun getMaxFaceCount(characteristics: CameraCharacteristics): Int? {
return characteristics.get(CameraCharacteristics.STATISTICS_INFO_MAX_FACE_COUNT)
}
/**
* 获取面部检测模式列表
*/
fun getFaceDetectionModes(characteristics: CameraCharacteristics): List<String>? {
return characteristics.get(CameraCharacteristics.STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES)?.map {
when (it) {
CameraCharacteristics.STATISTICS_FACE_DETECT_MODE_OFF -> "关闭"
CameraCharacteristics.STATISTICS_FACE_DETECT_MODE_SIMPLE -> "简单"
CameraCharacteristics.STATISTICS_FACE_DETECT_MODE_FULL -> "完整"
else -> "未知"
}
}
}
// ==================== 能力列表 ====================
/**
* 获取摄像头能力列表
*/
fun getAvailableCapabilities(characteristics: CameraCharacteristics): List<CameraCapability> {
val capabilities = characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES)
return capabilities?.toList()?.mapNotNull { capability ->
@ -111,4 +472,235 @@ class CameraInfo(private val context: Context) {
}
} ?: emptyList()
}
/**
* 获取支持的功能列表人类可读
*/
fun getSupportedFeatures(characteristics: CameraCharacteristics): List<String> {
val features = mutableListOf<String>()
val capabilities = getAvailableCapabilities(characteristics)
if (capabilities.contains(CameraCapability.RAW)) features.add("RAW拍摄")
if (capabilities.contains(CameraCapability.BURST_CAPTURE)) features.add("连拍")
if (capabilities.contains(CameraCapability.DEPTH_OUTPUT)) features.add("景深输出")
if (capabilities.contains(CameraCapability.CONSTRAINED_HIGH_SPEED_VIDEO)) features.add("高速视频")
if (capabilities.contains(CameraCapability.MANUAL_SENSOR)) features.add("手动模式")
if (capabilities.contains(CameraCapability.MONOCHROME)) features.add("黑白模式")
if (capabilities.contains(CameraCapability.ULTRA_HIGH_RESOLUTION_SENSOR)) features.add("超高分辨率")
if (capabilities.contains(CameraCapability.DYNAMIC_RANGE_TEN_BIT)) features.add("10-bit HDR")
if (hasOpticalStabilization(characteristics)) features.add("光学防抖")
if (hasVideoStabilization(characteristics)) features.add("视频防抖")
return features
}
// ==================== 模式列表 ====================
/**
* 获取自动曝光模式列表
*/
fun getAutoExposureModes(characteristics: CameraCharacteristics): List<String>? {
return characteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_MODES)?.map {
when (it) {
CameraCharacteristics.CONTROL_AE_MODE_OFF -> "关闭"
CameraCharacteristics.CONTROL_AE_MODE_ON -> "自动"
CameraCharacteristics.CONTROL_AE_MODE_ON_AUTO_FLASH -> "自动闪光"
CameraCharacteristics.CONTROL_AE_MODE_ON_ALWAYS_FLASH -> "强制闪光"
CameraCharacteristics.CONTROL_AE_MODE_ON_AUTO_FLASH_REDEYE -> "防红眼"
CameraCharacteristics.CONTROL_AE_MODE_ON_EXTERNAL_FLASH -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) "外置闪光" else "未知"
else -> "未知"
}
}
}
/**
* 获取自动对焦模式列表
*/
fun getAutoFocusModes(characteristics: CameraCharacteristics): List<String>? {
return characteristics.get(CameraCharacteristics.CONTROL_AF_AVAILABLE_MODES)?.map {
when (it) {
CameraCharacteristics.CONTROL_AF_MODE_OFF -> "关闭"
CameraCharacteristics.CONTROL_AF_MODE_AUTO -> "自动"
CameraCharacteristics.CONTROL_AF_MODE_MACRO -> "微距"
CameraCharacteristics.CONTROL_AF_MODE_CONTINUOUS_VIDEO -> "连续视频"
CameraCharacteristics.CONTROL_AF_MODE_CONTINUOUS_PICTURE -> "连续拍照"
CameraCharacteristics.CONTROL_AF_MODE_EDOF -> "EDOF"
else -> "未知"
}
}
}
/**
* 获取白平衡模式列表
*/
fun getWhiteBalanceModes(characteristics: CameraCharacteristics): List<String>? {
return characteristics.get(CameraCharacteristics.CONTROL_AWB_AVAILABLE_MODES)?.map {
when (it) {
CameraCharacteristics.CONTROL_AWB_MODE_OFF -> "关闭"
CameraCharacteristics.CONTROL_AWB_MODE_AUTO -> "自动"
CameraCharacteristics.CONTROL_AWB_MODE_INCANDESCENT -> "白炽灯"
CameraCharacteristics.CONTROL_AWB_MODE_FLUORESCENT -> "荧光灯"
CameraCharacteristics.CONTROL_AWB_MODE_WARM_FLUORESCENT -> "暖荧光"
CameraCharacteristics.CONTROL_AWB_MODE_DAYLIGHT -> "日光"
CameraCharacteristics.CONTROL_AWB_MODE_CLOUDY_DAYLIGHT -> "阴天"
CameraCharacteristics.CONTROL_AWB_MODE_TWILIGHT -> "黄昏"
CameraCharacteristics.CONTROL_AWB_MODE_SHADE -> "阴影"
else -> "未知"
}
}
}
/**
* 获取场景模式列表
*/
fun getSceneModes(characteristics: CameraCharacteristics): List<String>? {
return characteristics.get(CameraCharacteristics.CONTROL_AVAILABLE_SCENE_MODES)?.map {
when (it) {
CameraCharacteristics.CONTROL_SCENE_MODE_DISABLED -> "禁用"
CameraCharacteristics.CONTROL_SCENE_MODE_FACE_PRIORITY -> "人像优先"
CameraCharacteristics.CONTROL_SCENE_MODE_ACTION -> "运动"
CameraCharacteristics.CONTROL_SCENE_MODE_PORTRAIT -> "人像"
CameraCharacteristics.CONTROL_SCENE_MODE_LANDSCAPE -> "风景"
CameraCharacteristics.CONTROL_SCENE_MODE_NIGHT -> "夜景"
CameraCharacteristics.CONTROL_SCENE_MODE_NIGHT_PORTRAIT -> "夜景人像"
CameraCharacteristics.CONTROL_SCENE_MODE_THEATRE -> "剧院"
CameraCharacteristics.CONTROL_SCENE_MODE_BEACH -> "海滩"
CameraCharacteristics.CONTROL_SCENE_MODE_SNOW -> "雪景"
CameraCharacteristics.CONTROL_SCENE_MODE_SUNSET -> "日落"
CameraCharacteristics.CONTROL_SCENE_MODE_STEADYPHOTO -> "防抖"
CameraCharacteristics.CONTROL_SCENE_MODE_FIREWORKS -> "烟火"
CameraCharacteristics.CONTROL_SCENE_MODE_SPORTS -> "体育"
CameraCharacteristics.CONTROL_SCENE_MODE_PARTY -> "派对"
CameraCharacteristics.CONTROL_SCENE_MODE_CANDLELIGHT -> "烛光"
CameraCharacteristics.CONTROL_SCENE_MODE_BARCODE -> "条形码"
CameraCharacteristics.CONTROL_SCENE_MODE_HIGH_SPEED_VIDEO -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) "高速视频" else "未知"
CameraCharacteristics.CONTROL_SCENE_MODE_HDR -> "HDR"
else -> "未知"
}
}
}
/**
* 获取色彩效果列表
*/
fun getColorEffects(characteristics: CameraCharacteristics): List<String>? {
return characteristics.get(CameraCharacteristics.CONTROL_AVAILABLE_EFFECTS)?.map {
when (it) {
CameraCharacteristics.CONTROL_EFFECT_MODE_OFF -> "关闭"
CameraCharacteristics.CONTROL_EFFECT_MODE_MONO -> "黑白"
CameraCharacteristics.CONTROL_EFFECT_MODE_NEGATIVE -> "负片"
CameraCharacteristics.CONTROL_EFFECT_MODE_SOLARIZE -> "曝光"
CameraCharacteristics.CONTROL_EFFECT_MODE_SEPIA -> "棕褐色"
CameraCharacteristics.CONTROL_EFFECT_MODE_POSTERIZE -> "海报化"
CameraCharacteristics.CONTROL_EFFECT_MODE_WHITEBOARD -> "白板"
CameraCharacteristics.CONTROL_EFFECT_MODE_BLACKBOARD -> "黑板"
CameraCharacteristics.CONTROL_EFFECT_MODE_AQUA -> "水蓝"
else -> "未知"
}
}
}
// ==================== 视频能力 ====================
/**
* 获取最大帧率
*/
fun getMaxFrameRate(characteristics: CameraCharacteristics): Int? {
val ranges = characteristics.get(CameraCharacteristics.CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES)
return ranges?.maxOfOrNull { it.upper }
}
/**
* 是否支持高速视频
*/
fun supportsHighSpeedVideo(characteristics: CameraCharacteristics): Boolean {
return getAvailableCapabilities(characteristics)
.contains(CameraCapability.CONSTRAINED_HIGH_SPEED_VIDEO)
}
/**
* 是否支持4K录制
*/
fun supports4K(characteristics: CameraCharacteristics): Boolean {
// 简化判断,实际需要检查 StreamConfigurationMap
val resolution = getPixelArraySize(characteristics)
return resolution?.contains("3840") == true || resolution?.contains("4096") == true
}
/**
* 是否支持8K录制
*/
fun supports8K(characteristics: CameraCharacteristics): Boolean {
val resolution = getPixelArraySize(characteristics)
return resolution?.contains("7680") == true
}
// ==================== 综合信息 ====================
/**
* 获取摄像头详细信息
*/
fun getCameraDetails(cameraId: String): CameraDetails? {
val characteristics = getCameraCharacteristics(cameraId) ?: return null
return CameraDetails(
cameraId = cameraId,
facing = getCameraFacing(characteristics),
facingText = getCameraFacingText(characteristics),
megaPixels = getMegaPixels(characteristics),
resolution = getPixelArraySize(characteristics),
sensorSize = getSensorPhysicalSize(characteristics),
sensorSizeInch = getSensorSizeInch(characteristics),
pixelSize = getPixelSize(characteristics),
colorFilterArrangement = getColorFilterArrangement(characteristics),
focalLength = getFocalLength(characteristics),
apertures = getAvailableApertures(characteristics),
fieldOfView = getFieldOfView(characteristics),
focal35mmEquivalent = getFocal35mmEquivalent(characteristics),
cropFactor = getCropFactor(characteristics),
isoRange = getIsoRange(characteristics),
exposureTimeRange = getExposureTimeRange(characteristics),
shutterSpeedRange = getShutterSpeedRange(characteristics),
exposureCompensationRange = getExposureCompensationRange(characteristics),
exposureCompensationStep = getExposureCompensationStep(characteristics),
minimumFocusDistance = getMinimumFocusDistance(characteristics),
minimumFocusDistanceCm = getMinimumFocusDistanceCm(characteristics),
hyperFocalDistance = getHyperFocalDistance(characteristics),
hasFlash = hasFlashUnit(characteristics),
hasOpticalStabilization = hasOpticalStabilization(characteristics),
hasVideoStabilization = hasVideoStabilization(characteristics),
hasAutoFocus = hasAutoFocus(characteristics),
camera2ApiSupport = getCamera2ApiSupport(characteristics),
maxFaceCount = getMaxFaceCount(characteristics),
faceDetectionModes = getFaceDetectionModes(characteristics),
capabilities = getAvailableCapabilities(characteristics),
supportedFeatures = getSupportedFeatures(characteristics),
autoExposureModes = getAutoExposureModes(characteristics),
autoFocusModes = getAutoFocusModes(characteristics),
whiteBalanceModes = getWhiteBalanceModes(characteristics),
sceneModes = getSceneModes(characteristics),
colorEffects = getColorEffects(characteristics),
maxFrameRate = getMaxFrameRate(characteristics),
supportsHighSpeedVideo = supportsHighSpeedVideo(characteristics),
supports4K = supports4K(characteristics),
supports8K = supports8K(characteristics)
)
}
/**
* 获取所有摄像头的详细信息列表
*/
fun getAllCameraDetails(): List<CameraDetails> {
return cameraIds.mapNotNull { getCameraDetails(it) }
}
}