পদক্ষেপগুলি ট্র্যাক করুন

হেলথ কানেক্ট, StepsRecord ব্যবহার করে পদক্ষেপের সংখ্যা রেকর্ড করার জন্য একটি স্টেপস ডেটা টাইপ প্রদান করে। স্বাস্থ্য ও ফিটনেস ট্র্যাকিংয়ের ক্ষেত্রে পদক্ষেপ একটি মৌলিক পরিমাপ।

মোবাইলের ধাপগুলো পড়ুন

অ্যান্ড্রয়েড ১৪ (এপিআই লেভেল ৩৪) এবং এসডিকে এক্সটেনশন ভার্সন ২০ বা তার উচ্চতর সংস্করণের সাথে, হেলথ কানেক্ট ডিভাইসেই পদক্ষেপ গণনার সুবিধা প্রদান করে। যদি কোনো অ্যাপকে READ_STEPS পারমিশন দেওয়া থাকে, তাহলে হেলথ কানেক্ট অ্যান্ড্রয়েড-চালিত ডিভাইস থেকে পদক্ষেপ গণনা শুরু করে এবং ব্যবহারকারীরা হেলথ কানেক্ট স্টেপস এন্ট্রিতে পদক্ষেপের ডেটা স্বয়ংক্রিয়ভাবে যুক্ত হতে দেখেন।

ডিভাইসে স্টেপ কাউন্টিং উপলব্ধ আছে কিনা তা পরীক্ষা করতে, যাচাই করুন যে ডিভাইসটিতে অ্যান্ড্রয়েড ১৪ (এপিআই লেভেল ৩৪) চলছে এবং এতে অন্তত এসডিকে এক্সটেনশন ভার্সন ২০ রয়েছে:

val isStepTrackingAvailable =
    Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE &&
        SdkExtensions.getExtensionVersion(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) >= 20

যদি আপনার অ্যাপ aggregate ব্যবহার করে মোট পদক্ষেপের সংখ্যা পড়ে এবং DataOrigin দ্বারা ফিল্টার না করে, তাহলে ডিভাইসে থাকা পদক্ষেপগুলো স্বয়ংক্রিয়ভাবে মোট সংখ্যার মধ্যে অন্তর্ভুক্ত হয়ে যাবে, এবং জুন ২০২৬ আপডেটের জন্য কোনো পরিবর্তনের প্রয়োজন নেই।

ডিভাইসে থাকা ধাপগুলির জন্য অ্যাট্রিবিউশন পরিবর্তন

জুন ২০২৬-এর আপডেট থেকে শুরু করে, হেলথ কানেক্ট দ্বারা স্বাভাবিকভাবে ট্র্যাক করা পদক্ষেপগুলো একটি সিন্থেটিক প্যাকেজ নেম (SPN)- এর অধীনে যুক্ত করা হবে, যেমন com.android.healthconnect.phone.jd5bdd37e1a8d3667a05d0abebfc4a89e

পূর্বে, অন্তর্নির্মিত পদক্ষেপগুলো android প্যাকেজ নামের অধীনে ছিল। জুন ২০২৬-এর আগে রেকর্ড করা ঐতিহাসিক পদক্ষেপের ডেটাতেও android প্যাকেজ নামটিই বজায় থাকে।

ব্যবহারকারীর গোপনীয়তা রক্ষার জন্য এসপিএন (SPN) ডিভাইস-ভিত্তিক এবং অ্যাপ্লিকেশন-প্রতি এর পরিধি নির্ধারণ করা হয়:

  • স্থিতিশীল: বর্তমান ডিভাইসটির SPN আপনার অ্যাপ্লিকেশনের জন্য স্থিতিশীল।
  • অ্যাপ্লিকেশন-ভিত্তিক: একই ডিভাইসের বিভিন্ন অ্যাপ্লিকেশন অন-ডিভাইস স্টেপ ডেটার জন্য ভিন্ন ভিন্ন SPN দেখতে পায়।

ডিভাইসের ধাপগুলির জন্য অনুসন্ধান করুন

যেহেতু SPN-গুলো নির্দিষ্ট পরিসরের এবং ডিভাইস-ভিত্তিক, তাই SPN-এর মান হার্ডকোড করা উচিত নয় । এর পরিবর্তে, বর্তমান ডিভাইসের SPN পাওয়ার জন্য getCurrentDeviceDataSource() API ব্যবহার করুন।

ডিভাইসে স্টেপ কাউন্টিংয়ের জন্য এসডিকে এক্সটেনশন ভার্সন ২০ বা তার বেশি প্রয়োজন হলেও, getCurrentDeviceDataSource() এপিআইটি অ্যান্ড্রয়েড ১৪ (এপিআই লেভেল ৩৪)-এ এসডিকে এক্সটেনশন ভার্সন ১১ বা তার বেশির সাথেই পাওয়া যায়।

হেলথ কানেক্ট জেটপ্যাক লাইব্রেরিতে getCurrentDeviceDataSource() API-টি এখনও উপলব্ধ নয়। এর পরিবর্তে, নিম্নলিখিত উদাহরণগুলিতে অ্যান্ড্রয়েড ফ্রেমওয়ার্ক API ব্যবহার করা হয়েছে:

import android.content.Context
import android.health.connect.HealthConnectManager

val healthConnectManager = context.getSystemService(HealthConnectManager::class.java)
val deviceDataSource = healthConnectManager?.getCurrentDeviceDataSource()
val currentDeviceSpn = deviceDataSource?.deviceDataOrigin?.packageName

আপনার অ্যাপকে যদি ডিভাইসের স্টেপ সংখ্যা পড়তে হয়, অথবা যদি এটি উৎস অ্যাপ্লিকেশন বা ডিভাইস অনুযায়ী স্টেপ ডেটা ভাগ করে দেখায়, তাহলে আপনাকে অবশ্যই সেই রেকর্ডগুলো কোয়েরি করতে হবে যেখানে DataOrigin হলো android অথবা যা ডিভাইসের SPN-এর সাথে মেলে। আপনার অ্যাপ যদি স্টেপ ডেটার জন্য অ্যাট্রিবিউশন দেখায়, তাহলে প্রতিটি রেকর্ডের জন্য উৎস ডিভাইস শনাক্ত করতে metadata.device ব্যবহার করুন। একত্রিত ডেটাতে SPN দ্বারা শনাক্ত করা ডিভাইসের স্টেপ সংখ্যার জন্য, আপনি অ্যাট্রিবিউশনের জন্য DeviceDataSource থেকে model বা manufacturer মতো ডিভাইসের মেটাডেটা ব্যবহার করতে পারেন, অথবা ডিভাইসের স্টেপ সংখ্যার জন্য "আপনার ফোন"-এর মতো একটি সাধারণ লেবেল ব্যবহার করতে পারেন।

নিম্নলিখিত উদাহরণটি দেখায় কিভাবে android এবং বর্তমান ডিভাইসের SPN উভয়কে ফিল্টার করে ডিভাইসের একত্রিত পদক্ষেপ গণনার ডেটা পড়তে হয়:

import android.content.Context
import android.health.connect.HealthConnectManager
import android.os.Build
import android.os.ext.SdkExtensions
import androidx.health.connect.client.HealthConnectClient
import androidx.health.connect.client.records.StepsRecord
import androidx.health.connect.client.records.metadata.DataOrigin
import androidx.health.connect.client.request.AggregateRequest
import androidx.health.connect.client.time.TimeRangeFilter
import java.time.Instant

suspend fun readDeviceStepsByTimeRange(
    healthConnectClient: HealthConnectClient,
    context: Context,
    startTime: Instant,
    endTime: Instant
) {
    // 1. Check if SDK Extension 11+ is available for getCurrentDeviceDataSource()
    val isDataSourceApiAvailable = Build.VERSION.SDK_INT >= Build.VERSION_CODES.U &&
            SdkExtensions.getExtensionVersion(Build.VERSION_CODES.U) >= 11

    try {
        val healthConnectManager = context.getSystemService(HealthConnectManager::class.java)

        // 2. Safely fetch the package name only if API is available and data exists
        val currentDeviceSpn = if (isDataSourceApiAvailable) {
            healthConnectManager?.getCurrentDeviceDataSource()?.deviceDataOrigin?.packageName
        } else {
            null
        }

        val dataOriginFilters = mutableSetOf(DataOrigin("android"))

        // 3. Explicit null-safety check using .let
        currentDeviceSpn?.let {
            dataOriginFilters.add(DataOrigin(it))
        }

        val response = healthConnectClient.aggregate(
            AggregateRequest(
                metrics = setOf(StepsRecord.COUNT_TOTAL),
                timeRangeFilter = TimeRangeFilter.between(startTime, endTime),
                dataOriginFilter = dataOriginFilters
            )
        )

        val stepCount = response[StepsRecord.COUNT_TOTAL]

    } catch (e: Exception) {
        // Now this catch block only handles actual runtime exceptions, 
        // rather than Errors from missing methods.
    }
}

ডিভাইসে পদক্ষেপ গণনা

  • সেন্সরের ব্যবহার : হেলথ কানেক্ট, SensorManager থেকে TYPE_STEP_COUNTER সেন্সরটি ব্যবহার করে। এই সেন্সরটি কম বিদ্যুৎ খরচের জন্য অপ্টিমাইজ করা হয়েছে, যা এটিকে অবিচ্ছিন্ন ব্যাকগ্রাউন্ড স্টেপ ট্র্যাকিংয়ের জন্য আদর্শ করে তোলে।
  • ডেটার সূক্ষ্মতা : ব্যাটারির আয়ু বাঁচাতে, পদক্ষেপের ডেটা সাধারণত ব্যাচ করে প্রতি মিনিটে একবারের বেশি হেলথ কানেক্ট ডেটাবেসে লেখা হয় না।
  • অ্যাট্রিবিউশন : জুন ২০২৬-এর আগে এই ফিচার দ্বারা রেকর্ড করা স্টেপগুলো DataOriginandroid প্যাকেজ নামের অধীনে অ্যাট্রিবিউট করা হয়। এই তারিখের পরে, এগুলো একটি ডিভাইস-নির্দিষ্ট SPN-এর অধীনে অ্যাট্রিবিউট করা হয়। অন-ডিভাইস স্টেপগুলোর জন্য অ্যাট্রিবিউশন পরিবর্তন দেখুন।
  • সক্রিয়করণ : ডিভাইসের স্টেপ গণনার প্রক্রিয়াটি তখনই সক্রিয় হয়, যখন হেলথ কানেক্ট-এর মধ্যে ডিভাইসের অন্তত একটি অ্যাপ্লিকেশনকে READ_STEPS পারমিশন দেওয়া হয়।

হেলথ কানেক্ট-এর প্রাপ্যতা যাচাই করুন

হেলথ কানেক্ট ব্যবহার করার চেষ্টা করার আগে, আপনার অ্যাপের যাচাই করে নেওয়া উচিত যে ব্যবহারকারীর ডিভাইসে হেলথ কানেক্ট উপলব্ধ আছে কিনা। সব ডিভাইসে হেলথ কানেক্ট আগে থেকে ইনস্টল করা নাও থাকতে পারে বা এটি নিষ্ক্রিয় করা থাকতে পারে। আপনি HealthConnectClient.getSdkStatus() মেথড ব্যবহার করে এর উপলব্ধতা পরীক্ষা করতে পারেন।

হেলথ কানেক্ট-এর প্রাপ্যতা কীভাবে পরীক্ষা করবেন

fun checkHealthConnectAvailability(context: Context) {
    val providerPackageName = "com.google.android.apps.healthdata" // Or get from HealthConnectClient.DEFAULT_PROVIDER_PACKAGE_NAME
    val availabilityStatus = HealthConnectClient.getSdkStatus(context, providerPackageName)

    if (availabilityStatus == HealthConnectClient.SDK_UNAVAILABLE) {
      // Health Connect is not available. Guide the user to install/enable it.
      // For example, show a dialog.
      return // early return as there is no viable integration
    }
    if (availabilityStatus == HealthConnectClient.SDK_UNAVAILABLE_PROVIDER_UPDATE_REQUIRED) {
      // Health Connect is available but requires an update.
      // Optionally redirect to package installer to find a provider, for example:
      val uriString = "market://details?id=$providerPackageName&url=healthconnect%3A%2F%2Fonboarding"
      context.startActivity(
        Intent(Intent.ACTION_VIEW).apply {
          setPackage("com.android.vending")
          data = Uri.parse(uriString)
          putExtra("overlay", true)
          putExtra("callerId", context.packageName)
        }
      )
      return
    }
    // Health Connect is available, obtain a HealthConnectClient instance
    val healthConnectClient = HealthConnectClient.getOrCreate(context)
    // Issue operations with healthConnectClient
}

getSdkStatus() থেকে প্রাপ্ত স্ট্যাটাসের উপর নির্ভর করে, প্রয়োজনে আপনি ব্যবহারকারীকে গুগল প্লে স্টোর থেকে হেলথ কানেক্ট ইনস্টল বা আপডেট করার জন্য নির্দেশনা দিতে পারেন।

প্রয়োজনীয় অনুমতি

সিঁড়িতে প্রবেশ নিম্নলিখিত অনুমতি দ্বারা সুরক্ষিত:

  • android.permission.health.READ_STEPS
  • android.permission.health.WRITE_STEPS

আপনার অ্যাপে স্টেপস সক্ষমতা যোগ করতে, প্রথমে Steps ডেটা টাইপের জন্য অনুমতির অনুরোধ করুন।

ধাপগুলো লেখার জন্য আপনাকে যে অনুমতিটি ঘোষণা করতে হবে তা এখানে দেওয়া হলো:

<application>
  <uses-permission
android:name="android.permission.health.WRITE_STEPS" />
...
</application>

ধাপগুলো পড়ার জন্য, আপনাকে নিম্নলিখিত অনুমতিগুলোর জন্য অনুরোধ করতে হবে:

<application>
  <uses-permission
android:name="android.permission.health.READ_STEPS" />
...
</application>

ব্যবহারকারীর কাছ থেকে অনুমতি অনুরোধ করুন

একটি ক্লায়েন্ট ইনস্ট্যান্স তৈরি করার পর, আপনার অ্যাপকে ব্যবহারকারীর কাছ থেকে অনুমতির জন্য অনুরোধ করতে হবে। ব্যবহারকারীদের যেকোনো সময় অনুমতি প্রদান বা প্রত্যাখ্যান করার ক্ষমতা থাকতে হবে।

এটি করার জন্য, প্রয়োজনীয় ডেটা টাইপগুলোর জন্য এক সেট পারমিশন তৈরি করুন। প্রথমে নিশ্চিত করুন যে, সেটের অন্তর্ভুক্ত পারমিশনগুলো আপনার অ্যান্ড্রয়েড ম্যানিফেস্টে ঘোষিত হয়েছে।

// Create a set of permissions for required data types
val PERMISSIONS =
    setOf(
  HealthPermission.getReadPermission(StepsRecord::class),
  HealthPermission.getWritePermission(StepsRecord::class)
)

আপনার অ্যাপে প্রয়োজনীয় অনুমতিগুলো আগে থেকেই দেওয়া আছে কিনা তা দেখতে getGrantedPermissions ব্যবহার করুন। যদি না থাকে, তাহলে সেই অনুমতিগুলোর জন্য অনুরোধ করতে createRequestPermissionResultContract ব্যবহার করুন। এটি হেলথ কানেক্ট পারমিশন স্ক্রিনটি প্রদর্শন করবে।

// Create the permissions launcher
val requestPermissionActivityContract = PermissionController.createRequestPermissionResultContract()

val requestPermissions = registerForActivityResult(requestPermissionActivityContract) { granted ->
  if (granted.containsAll(PERMISSIONS)) {
    // Permissions successfully granted
  } else {
    // Lack of required permissions
  }
}

suspend fun checkPermissionsAndRun(healthConnectClient: HealthConnectClient) {
  val granted = healthConnectClient.permissionController.getGrantedPermissions()
  if (granted.containsAll(PERMISSIONS)) {
    // Permissions already granted; proceed with inserting or reading data
  } else {
    requestPermissions.launch(PERMISSIONS)
  }
}

যেহেতু ব্যবহারকারীরা যেকোনো সময় অনুমতি দিতে বা প্রত্যাহার করতে পারেন, তাই আপনার অ্যাপকে প্রতিবার ব্যবহারের আগে অনুমতি যাচাই করতে হবে এবং অনুমতি হারিয়ে গেলে তার মোকাবিলা করতে হবে।

স্টেপস রেকর্ডে অন্তর্ভুক্ত তথ্য

প্রতিটি StepsRecord নিম্নলিখিত তথ্য থাকে:

  • count : নির্দিষ্ট সময় ব্যবধানে নেওয়া পদক্ষেপের সংখ্যা, একটি Long হিসেবে।
  • startTime : পরিমাপ ব্যবধানের শুরুর সময়।
  • endTime : পরিমাপ ব্যবধানের শেষ সময়।
  • startZoneOffset : শুরুর সময়ের জন্য জোন অফসেট।
  • endZoneOffset : শেষ সময়ের জন্য জোন অফসেট।

সমর্থিত সমষ্টি

StepsRecord জন্য নিম্নলিখিত সমষ্টিগত মানগুলি উপলব্ধ রয়েছে:

StepsCadenceRecord জন্য নিম্নলিখিত সমষ্টিগত মানগুলি উপলব্ধ রয়েছে:

উদাহরণ ব্যবহার

নিম্নলিখিত বিভাগগুলিতে StepsRecord ডেটা কীভাবে পড়তে এবং লিখতে হয় তা দেখানো হয়েছে।

ধাপ ডেটা লিখুন

আপনার অ্যাপ StepsRecord ইনস্ট্যান্স সন্নিবেশ করার মাধ্যমে পদক্ষেপ গণনার ডেটা লিখতে পারে। নিম্নলিখিত উদাহরণটি দেখায় কিভাবে একজন ব্যবহারকারীর নেওয়া ১০০০ পদক্ষেপ রেকর্ড করতে হয়:

val zoneOffset = ZoneOffset.systemDefault().rules.getOffset(startTime)
val stepsRecord = StepsRecord(
    count = 120,
    startTime = startTime,
    endTime = endTime,
    startZoneOffset = zoneOffset,
    endZoneOffset = zoneOffset,
    metadata = Metadata(
        device = Device(type = Device.TYPE_WATCH),
        recordingMethod = Metadata.RECORDING_METHOD_AUTOMATICALLY_RECORDED
    )
)
healthConnectClient.insertRecords(listOf(stepsRecord))

সমষ্টিগত ডেটা পড়ুন

স্টেপ ডেটা পড়ার সবচেয়ে প্রচলিত উপায় হলো একটি নির্দিষ্ট সময়কালের মোট স্টেপ সংখ্যাকে একত্রিত করা। নিচের উদাহরণটিতে দেখানো হয়েছে, কীভাবে একটি নির্দিষ্ট সময়সীমার মধ্যে একজন ব্যবহারকারীর মোট স্টেপ সংখ্যা পড়তে হয়:

suspend fun readStepsAggregate(startTime: Instant, endTime: Instant): Long {
    val response = healthConnectClient.aggregate(
        AggregateRequest(
            metrics = setOf(StepsRecord.COUNT_TOTAL),
            timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
        )
    )
    return response[StepsRecord.COUNT_TOTAL] ?: 0L
}

কাঁচা ডেটা পড়ুন

নিম্নলিখিত উদাহরণটি দেখায় কিভাবে একটি শুরু এবং শেষ সময়ের মধ্যে StepsRecord কাঁচা ডেটা পড়তে হয়:

val response = healthConnectClient.readRecords(
    ReadRecordsRequest(
        StepsRecord::class,
        timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
    )
)
response.records.forEach { record ->
    /* Process records */
}