add googleServicesFrameworkId

This commit is contained in:
xsean 2026-01-13 16:16:21 +08:00
parent aa06fc263f
commit cd26dc8016
3 changed files with 122 additions and 5 deletions

View File

@ -13,8 +13,11 @@ import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageManager
import android.media.MediaCodecInfo
import android.media.MediaCodecList
import android.os.Build
import androidx.core.app.ActivityCompat
import kotlin.text.compareTo
/**
* 蓝牙信息工具类
@ -73,7 +76,11 @@ class BluetoothInfo(private val context: Context) {
val offloadedFiltering: Boolean, // 硬件过滤
val offloadedScanBatching: Boolean, // 批量扫描
val multipleAdvertisement: Boolean, // 多广播
val lowEnergyExtended: Boolean // 扩展LE
val lowEnergyExtended: Boolean, // 扩展LE
val lowLatencyAudio: Boolean, // 低延迟音频
val proAudio: Boolean, // 专业音频
val midiSupport: Boolean, // MIDI支持
val supportedCodecs: List<String> // 支持的编解码器
)
// ==================== 基本信息 ====================
@ -305,6 +312,7 @@ class BluetoothInfo(private val context: Context) {
*/
fun getBluetoothFeatures(): BluetoothFeatures {
val adapter = bluetoothAdapter
val pm = context.packageManager
return BluetoothFeatures(
version = getBluetoothVersion(),
@ -336,15 +344,15 @@ class BluetoothInfo(private val context: Context) {
} else false,
leAudioSupport = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
context.packageManager.hasSystemFeature("android.hardware.bluetooth.le.audio")
pm.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")
pm.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")
pm.hasSystemFeature("android.hardware.bluetooth.le.audio.unicast_client")
} else false,
// 其他特性
@ -362,10 +370,40 @@ class BluetoothInfo(private val context: Context) {
lowEnergyExtended = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
adapter?.isLeExtendedAdvertisingSupported == true
} else false
} else false,
// 音频和MIDI特性
lowLatencyAudio = pm.hasSystemFeature(PackageManager.FEATURE_AUDIO_LOW_LATENCY),
proAudio = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
pm.hasSystemFeature(PackageManager.FEATURE_AUDIO_PRO)
} else false,
midiSupport = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
pm.hasSystemFeature(PackageManager.FEATURE_MIDI)
} else false,
// 支持的编解码器
supportedCodecs = getSupportedCodecs()
)
}
private fun getSupportedAudioCodecs(): List<MediaCodecInfo> {
val codecList = MediaCodecList(MediaCodecList.ALL_CODECS)
return codecList.codecInfos.filter { codecInfo ->
!codecInfo.isEncoder && // 解码器(如果你要编码器,改成 true
codecInfo.supportedTypes.any { it.startsWith("audio/") }
}
}
/**
* 获取支持的蓝牙音频编解码器
*/
@SuppressLint("MissingPermission")
private fun getSupportedCodecs(): List<String> {
return getSupportedAudioCodecs().flatMap { codecInfo ->
codecInfo.supportedTypes.map { it }
}.distinct().sorted()
}
/**
* 获取蓝牙版本根据支持的特性推断

View File

@ -2,6 +2,7 @@ package com.xyzshell.andinfo.libs
import android.content.Context
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.provider.Settings
// import androidx.security.state.SecurityStateManagerCompat
@ -548,6 +549,29 @@ class BuildInfo(private val context: Context) {
val googleServicesFrameworkVersion: String?
get() = getPackageVersion("com.google.android.gsf")
/**
* GSF IDGoogle Services Framework ID
* 设备的唯一标识符
*/
val googleServicesFrameworkId: String?
get() = getGSFId(context)
private fun getGSFId(context: Context): String? {
return try {
val uri = Uri.parse("content://com.google.android.gsf.gservices")
val params = arrayOf("android_id")
context.contentResolver.query(uri, null, null, params, null)?.use { cursor ->
if (cursor.moveToFirst() && cursor.columnCount >= 2) {
cursor.getString(1)
} else {
null
}
}
} catch (e: Exception) {
null
}
}
/**
* 获取包版本名称
*/

View File

@ -2,6 +2,7 @@ package com.xyzshell.andinfo.libs
import android.Manifest
import android.content.Context
import android.graphics.ImageFormat
import android.hardware.camera2.CameraCharacteristics
import android.hardware.camera2.CameraManager
import android.hardware.camera2.CameraMetadata
@ -9,12 +10,14 @@ import android.os.Build
import android.os.Handler
import android.os.Looper
import android.util.Range
import android.util.Size
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.roundToInt
import kotlin.math.sqrt
/**
@ -92,6 +95,7 @@ class CameraInfo(private val context: Context) {
val maxFrameRate: Int?, // 最大帧率
val supportsHighSpeedVideo: Boolean, // 是否支持高速视频
val supports4K: Boolean, // 是否支持4K录制
val streamConfigurations: List<String>?, // 视频-型材 ; 视频采集流配置列表 (格式: 宽x高 @ 帧率 Hz, 格式)
val supports8K: Boolean // 是否支持8K录制
)
@ -636,6 +640,56 @@ class CameraInfo(private val context: Context) {
return resolution?.contains("7680") == true
}
// ==================== 视频能力 ====================
/**
* 获取支持的视频流配置 (分辨率@帧率)
*/
fun getStreamConfigurations(characteristics: CameraCharacteristics): List<String>? {
val map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP) ?: return null
val configs = mutableMapOf<Size, MutableSet<Int>>()
// 遍历所有支持的尺寸
val outputSizes = map.getOutputSizes(ImageFormat.YUV_420_888) ?: map.getOutputSizes(ImageFormat.PRIVATE)
outputSizes?.forEach { size ->
// 获取该尺寸下的最小帧间隔(纳秒),从而计算出最大帧率
val minFrameDuration = map.getOutputMinFrameDuration(ImageFormat.YUV_420_888, size)
if (minFrameDuration > 0) {
val maxFps = (1_000_000_000.0 / minFrameDuration).roundToInt()
if (!configs.containsKey(size)) {
configs[size] = mutableSetOf()
}
configs[size]?.add(maxFps)
}
}
// 检查高速视频配置
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
map.highSpeedVideoSizes.forEach { size ->
map.getHighSpeedVideoFpsRangesFor(size).forEach { range ->
if (!configs.containsKey(size)) {
configs[size] = mutableSetOf()
}
// 通常高速视频会使用固定的高帧率
configs[size]?.add(range.upper)
}
}
}
// 格式化输出
return configs.map { (size, fpsSet) ->
val resolutionName = when {
size.width == 7680 && size.height == 4320 -> "8K UHD"
size.width == 3840 && size.height == 2160 -> "4K UHD"
size.width == 1920 && size.height == 1080 -> "1080p"
size.width == 1280 && size.height == 720 -> "720p"
else -> "${size.width}x${size.height}"
}
val fpsString = fpsSet.sortedDescending().joinToString("/")
"$resolutionName @ $fpsString Hz"
}.sortedDescending() // 按分辨率排序
}
// ==================== 综合信息 ====================
/**
@ -693,6 +747,7 @@ class CameraInfo(private val context: Context) {
maxFrameRate = getMaxFrameRate(characteristics),
supportsHighSpeedVideo = supportsHighSpeedVideo(characteristics),
supports4K = supports4K(characteristics),
streamConfigurations = getStreamConfigurations(characteristics),
supports8K = supports8K(characteristics)
)
}