android - Android 睡眠 API 异常:com.google.android.gms.common.api.ApiException:16:
问题描述
我正在尝试运行 android 团队提供的 Sleep Sample 应用程序来展示新的 Sleep API 的使用。该应用程序在某些设备(OnePlus、Pixel、诺基亚)上运行良好,但在某些设备(三星)上显示错误“com.google.android.gms.common.api.ApiException: 16:”。我认为这与 Google Play 服务有关,所以我已经对其进行了更新。我的手机运行的是搭载 Android 11 的 Samsung Color OS。它具有最新版本的 GooglePlay 和 Google Play 服务。这个问题往往只发生在三星设备上(在我测试过的设备中)
package com.android.example.sleepcodelab
import android.Manifest.permission
import android.annotation.SuppressLint
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Bundle
import android.provider.Settings
import android.util.Log
import android.view.View
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import com.android.example.sleepcodelab.databinding.ActivityMainBinding
import com.android.example.sleepcodelab.receiver.SleepReceiver
import com.google.android.gms.location.ActivityRecognition
import com.google.android.gms.location.SleepSegmentRequest
import com.google.android.material.snackbar.Snackbar
import java.util.Calendar
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private val mainViewModel: MainViewModel by lazy {
MainViewModel((application as MainApplication).repository)
}
private var sleepSegmentOutput: String = ""
private var sleepClassifyOutput: String = ""
private var subscribedToSleepData = false
set(newSubscribedToSleepData) {
field = newSubscribedToSleepData
if (newSubscribedToSleepData) {
binding.button.text = getString(R.string.sleep_button_unsubscribe_text)
} else {
binding.button.text = getString(R.string.sleep_button_subscribe_text)
}
updateOutput()
}
private lateinit var sleepPendingIntent: PendingIntent
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
mainViewModel.subscribedToSleepDataLiveData.observe(this) { newSubscribedToSleepData ->
if (subscribedToSleepData != newSubscribedToSleepData) {
subscribedToSleepData = newSubscribedToSleepData
}
}
mainViewModel.allSleepSegments.observe(this) { sleepSegmentEventEntities ->
Log.d(TAG, "sleepSegmentEventEntities: $sleepSegmentEventEntities")
if (sleepSegmentEventEntities.isNotEmpty()) {
sleepSegmentOutput = sleepSegmentEventEntities.joinToString {
"\t$it\n"
}
updateOutput()
}
}
mainViewModel.allSleepClassifyEventEntities.observe(this) {
sleepClassifyEventEntities ->
Log.d(TAG, "sleepClassifyEventEntities: $sleepClassifyEventEntities")
if (sleepClassifyEventEntities.isNotEmpty()) {
sleepClassifyOutput = sleepClassifyEventEntities.joinToString {
"\t$it\n"
}
updateOutput()
}
}
sleepPendingIntent =
SleepReceiver.createSleepReceiverPendingIntent(context = applicationContext)
}
fun onClickRequestSleepData(view: View) {
if (activityRecognitionPermissionApproved()) {
if (subscribedToSleepData) {
unsubscribeToSleepSegmentUpdates(applicationContext, sleepPendingIntent)
} else {
subscribeToSleepSegmentUpdates(applicationContext, sleepPendingIntent)
}
} else {
requestPermissionLauncher.launch(permission.ACTIVITY_RECOGNITION)
}
}
@SuppressLint("MissingPermission")
private fun subscribeToSleepSegmentUpdates(context: Context, pendingIntent: PendingIntent) {
Log.d(TAG, "requestSleepSegmentUpdates()")
val task = ActivityRecognition.getClient(context).requestSleepSegmentUpdates(
pendingIntent,
SleepSegmentRequest.getDefaultSleepSegmentRequest()
)
task.addOnSuccessListener {
mainViewModel.updateSubscribedToSleepData(true)
Log.d(TAG, "Successfully subscribed to sleep data.")
}
task.addOnFailureListener { exception ->
Log.d(TAG, "Exception when subscribing to sleep data: $exception")
}
}
private fun unsubscribeToSleepSegmentUpdates(context: Context, pendingIntent: PendingIntent) {
Log.d(TAG, "unsubscribeToSleepSegmentUpdates()")
val task = ActivityRecognition.getClient(context).removeSleepSegmentUpdates(pendingIntent)
task.addOnSuccessListener {
mainViewModel.updateSubscribedToSleepData(false)
Log.d(TAG, "Successfully unsubscribed to sleep data.")
}
task.addOnFailureListener { exception ->
Log.d(TAG, "Exception when unsubscribing to sleep data: $exception")
}
}
private fun activityRecognitionPermissionApproved(): Boolean {
return PackageManager.PERMISSION_GRANTED == ContextCompat.checkSelfPermission(
this,
permission.ACTIVITY_RECOGNITION
)
}
private val requestPermissionLauncher: ActivityResultLauncher<String> =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
if (!isGranted) {
displayPermissionSettingsSnackBar()
} else {
binding.outputTextView.text = getString(R.string.permission_approved)
}
}
private fun displayPermissionSettingsSnackBar() {
Snackbar.make(
binding.mainActivity,
R.string.permission_rational,
Snackbar.LENGTH_LONG
)
.setAction(R.string.action_settings) {
val intent = Intent()
intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
val uri = Uri.fromParts(
"package",
BuildConfig.APPLICATION_ID,
null
)
intent.data = uri
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(intent)
}
.show()
}
private fun updateOutput() {
Log.d(TAG, "updateOutput()")
val header = if (subscribedToSleepData) {
val timestamp = Calendar.getInstance().time.toString()
getString(R.string.main_output_header1_subscribed_sleep_data, timestamp)
} else {
getString(R.string.main_output_header1_unsubscribed_sleep_data)
}
val sleepData = getString(
R.string.main_output_header2_and_sleep_data,
sleepSegmentOutput,
sleepClassifyOutput
)
val newOutput = header + sleepData
binding.outputTextView.text = newOutput
}
companion object {
private const val TAG = "MainActivity"
}
}
每当我单击订阅睡眠数据按钮时,它都会在 logcat 中显示“订阅睡眠数据时出现异常:com.google.android.gms.common.api.ApiException: 16:”。
解决方案
推荐阅读
- scala - 什么时候在 Scala 中使用 SBT 和 Ivy 模糊地选择了具有相同定义和类路径的两个类?
- c# - .Net Framework Web API FormsAuthentication.SetAuthCookie 不工作
- java - 提交后非法尝试将集合与两个打开的会话相关联
- reactjs - 如何组合来自父组件和子组件的 makeStyle 类?
- linux - “松散”的进程间通信
- c++ - 为什么这些类型不兼容?
- testing - 即使清除了 cookie,所有迭代的响应数据也相同
- android - Firebase Catch 异常 + Firebase 异常列表 Kotlin
- python - 是否有来自 win32api 的 GetLogicalDriveStrings() 的 mac 和 linux 版本?
- javascript - 做出反应。无法访问本地 5000 上的 API 数据。来自 CSV 文件的数据库。承诺未定义的响应