Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exception while trying to access Google Fit API - The user must be signed in to make this API call

I am trying to set up a wearable app (for Huawei Watch 2) running on WearOS to provide a sort of continous feed of Heart Rate (BPM) into a Google Fit account, which is read into another smarphone application.

The issue comes when I am trying to set up the account and access the data as it follows:

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        if (ContextCompat.checkSelfPermission(this, Manifest.permission.BODY_SENSORS)
            != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.BODY_SENSORS),GOOGLE_FIT_PERMISSIONS_REQUEST_CODE)
        }

        fitnessOptions = FitnessOptions.builder()
            .addDataType(DataType.TYPE_HEART_RATE_BPM, FitnessOptions.ACCESS_READ)
            .addDataType(DataType.TYPE_HEART_RATE_BPM, FitnessOptions.ACCESS_WRITE)
            .build()

        account = GoogleSignIn.getAccountForExtension(this, fitnessOptions)
        if (!GoogleSignIn.hasPermissions(account, fitnessOptions)) {
                GoogleSignIn.requestPermissions(
                    this, // your activity
                    GOOGLE_FIT_PERMISSIONS_REQUEST_CODE, // e.g. 1
                    account,
                    fitnessOptions);
        } else {
            accessGoogleFit()
        }
        timer.scheduleAtFixedRate(
            object : TimerTask() {
                override fun run() {
                    Log.i("[TimerTask]", "Retrieving data..")
                    accessGoogleFit()
                    Log.i("[Account]", "" + account.email)

                }
            },0, 1000
        )
        // Enables Always-on
        setAmbientEnabled()
    }
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        when (resultCode) {
            Activity.RESULT_OK -> when (requestCode) {
                GOOGLE_FIT_PERMISSIONS_REQUEST_CODE -> accessGoogleFit()
                else -> {}
            }
            else -> {}
        }
    }

    private fun accessGoogleFit() {
        val cal: Calendar = Calendar.getInstance()
        val now = Date()
        cal.setTime(now)
        val endTime: Long = cal.getTimeInMillis()
        cal.add(Calendar.DAY_OF_MONTH, -1)
        val startTime: Long = cal.getTimeInMillis()

        val historyRequest = DataReadRequest.Builder()
                .read(DataType.TYPE_HEART_RATE_BPM)
                .enableServerQueries()
                .setTimeRange(startTime, endTime, TimeUnit.MILLISECONDS)
                .build()
        val sourceRequest = DataSourcesRequest.Builder()
            .setDataTypes(DataType.TYPE_HEART_RATE_BPM)
            .setDataSourceTypes(DataSource.TYPE_RAW, DataSource.TYPE_DERIVED)
            .build()

        Fitness.getHistoryClient(this,account)
                .readData(historyRequest)
                .addOnSuccessListener{
                        response-> txt_GoogleFit_FitData.setText(response.dataSets.get(0).toString())
                }
                .addOnFailureListener{ e ->
                    Log.e("[GoogleFIT]", "Find data sources request failed", e)
                }

        Fitness.getSensorsClient(this, account)
                .findDataSources(sourceRequest)
                .addOnSuccessListener { dataSources ->
                    dataSources.forEach {
                        Log.i("[GoogleFIT]", "Data source found: ${it.streamIdentifier}")
                        Log.i("[GoogleFIT]", "Data Source type: ${it.dataType.name}")

                        if (it.dataType == DataType.TYPE_HEART_RATE_BPM) {
                            Log.i("[GoogleFIT]", "Data source for LOCATION_SAMPLE found!")
                        }
            }
        }
        .addOnFailureListener { e ->
            Log.e("[GoogleFIT]", "Find data sources request failed", e)
        }
    }

Stack trace of exception:

2021-01-27 17:08:07.032 13743-13767/com.example.watch_bpmupdated2 I/[TimerTask]: Retrieving data..
2021-01-27 17:08:07.036 13743-13767/com.example.watch_bpmupdated2 I/[Account]: <<default account>>
2021-01-27 17:08:07.057 13743-13743/com.example.watch_bpmupdated2 E/[GoogleFIT]: Find data sources request failed
    com.google.android.gms.common.api.ApiException: 4: The user must be signed in to make this API call.
        at com.google.android.gms.common.internal.ApiExceptionUtil.fromStatus(com.google.android.gms:play-services-base@@17.1.0:4)
        at com.google.android.gms.common.internal.zai.zaf(com.google.android.gms:play-services-base@@17.1.0:2)
        at com.google.android.gms.common.internal.zak.onComplete(com.google.android.gms:play-services-base@@17.1.0:6)
        at com.google.android.gms.common.api.internal.BasePendingResult.zaa(com.google.android.gms:play-services-base@@17.1.0:176)
        at com.google.android.gms.common.api.internal.BasePendingResult.setResult(com.google.android.gms:play-services-base@@17.1.0:135)
        at com.google.android.gms.common.api.internal.BaseImplementation$ApiMethodImpl.setFailedResult(com.google.android.gms:play-services-base@@17.1.0:29)
        at com.google.android.gms.common.api.internal.zad.zaa(com.google.android.gms:play-services-base@@17.1.0:9)
        at com.google.android.gms.common.api.internal.GoogleApiManager$zaa.zac(com.google.android.gms:play-services-base@@17.1.0:175)
        at com.google.android.gms.common.api.internal.GoogleApiManager$zaa.onConnectionFailed(com.google.android.gms:play-services-base@@17.1.0:79)
        at com.google.android.gms.common.internal.zag.onConnectionFailed(com.google.android.gms:play-services-base@@17.1.0:2)
        at com.google.android.gms.common.internal.BaseGmsClient$zzg.zza(com.google.android.gms:play-services-basement@@17.1.1:6)
        at com.google.android.gms.common.internal.BaseGmsClient$zza.zza(com.google.android.gms:play-services-basement@@17.1.1:25)
        at com.google.android.gms.common.internal.BaseGmsClient$zzb.zzo(com.google.android.gms:play-services-basement@@17.1.1:11)
        at com.google.android.gms.common.internal.BaseGmsClient$zzc.handleMessage(com.google.android.gms:play-services-basement@@17.1.1:49)
        at android.os.Handler.dispatchMessage(Handler.java:105)
        at com.google.android.gms.internal.common.zzi.dispatchMessage(com.google.android.gms:play-services-basement@@17.1.1:8)
        at android.os.Looper.loop(Looper.java:164)
        at android.os.HandlerThread.run(HandlerThread.java:65)
2021-01-27 17:08:07.060 13743-13743/com.example.watch_bpmupdated2 E/[GoogleFIT]: Find data sources request failed
    com.google.android.gms.common.api.ApiException: 4: The user must be signed in to make this API call.
        at com.google.android.gms.common.internal.ApiExceptionUtil.fromStatus(com.google.android.gms:play-services-base@@17.1.0:4)
        at com.google.android.gms.common.internal.zai.zaf(com.google.android.gms:play-services-base@@17.1.0:2)
        at com.google.android.gms.common.internal.zak.onComplete(com.google.android.gms:play-services-base@@17.1.0:6)
        at com.google.android.gms.common.api.internal.BasePendingResult.zaa(com.google.android.gms:play-services-base@@17.1.0:176)
        at com.google.android.gms.common.api.internal.BasePendingResult.setResult(com.google.android.gms:play-services-base@@17.1.0:135)
        at com.google.android.gms.common.api.internal.BaseImplementation$ApiMethodImpl.setFailedResult(com.google.android.gms:play-services-base@@17.1.0:29)
        at com.google.android.gms.common.api.internal.zad.zaa(com.google.android.gms:play-services-base@@17.1.0:9)
        at com.google.android.gms.common.api.internal.GoogleApiManager$zaa.zac(com.google.android.gms:play-services-base@@17.1.0:175)
        at com.google.android.gms.common.api.internal.GoogleApiManager$zaa.onConnectionFailed(com.google.android.gms:play-services-base@@17.1.0:79)
        at com.google.android.gms.common.internal.zag.onConnectionFailed(com.google.android.gms:play-services-base@@17.1.0:2)
        at com.google.android.gms.common.internal.BaseGmsClient$zzg.zza(com.google.android.gms:play-services-basement@@17.1.1:6)
        at com.google.android.gms.common.internal.BaseGmsClient$zza.zza(com.google.android.gms:play-services-basement@@17.1.1:25)
        at com.google.android.gms.common.internal.BaseGmsClient$zzb.zzo(com.google.android.gms:play-services-basement@@17.1.1:11)
        at com.google.android.gms.common.internal.BaseGmsClient$zzc.handleMessage(com.google.android.gms:play-services-basement@@17.1.1:49)
        at android.os.Handler.dispatchMessage(Handler.java:105)
        at com.google.android.gms.internal.common.zzi.dispatchMessage(com.google.android.gms:play-services-basement@@17.1.1:8)
        at android.os.Looper.loop(Looper.java:164)
        at android.os.HandlerThread.run(HandlerThread.java:65)

My watch is paired to the smartphone I am using to read the data (I just need faster updates from google fit, and thought about forcing this. Code not available here for that). The same google fit account is present, logged into Google Fit app and synced on both devices. Everything runs smoothly on the smartphone (even with the same code), while on the Watch I get the "user must be signed in" exception when setting up the account.

Google services dependencies, application permissions are set the same way on both devices, as well as the required OAuth settings, SHA1 and credentials on the developer console.

Could this be an issue related to the watch->App->Google Fit account synchronization, or am I missing something?

like image 947
Raul Acu Avatar asked Jan 27 '21 15:01

Raul Acu


People also ask

How do I use Google fit REST API?

Go to the Google API Console. Select a project, or create a new one. Use the same project for the Android and REST versions of your app. Click Continue to enable the Fitness API.

How do I get data from Google Fit API?

Google Fit is available on Android devices with Google Play services 7.0 or higher. You should install the Google Play Service in your device, and then install the latest client library for Google Play services on your development host. Finally, get an OAuth 2.0 client ID for your Android applications.


1 Answers

Register the project in the Google Console and add your Google Account as a test user after adding the OAuth 2.0 Client ID for your project.

This should fix the login issue.

like image 60
Dimitri Williams Avatar answered Sep 22 '22 14:09

Dimitri Williams