首页 > 解决方案 > 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:”。

在此处输入图像描述

在此处输入图像描述

标签: androidapikotlingoogle-playgoogle-play-services

解决方案


推荐阅读