Архив за день: 15.06.2022



Android Studio: Создание простого шагомера (Step Counter) на Kotlin (часть 1)

В 2019 году Google объявила, что предпочтительным для программирования под Андроид языком теперь является не java, а Kotlin, поэтому продолжим создавать Шагомер именно на нём. Плюс ко всему, код из старой заметки уже не работает на новых версиях Android…

Подготовка проекта

1. Запускаем Android Studio и выбираем «Create New Project»:

2. На вкладке Phone and Tablet выбираем Empty Activity:

3. В окошке конфигурации проекта заполняем необходимые поля (на этот раз выбираем язык Kotlin):

Обратите внимание, на этот раз здесь мы выбрали API 29: Android 10.0 (Q)

 

Дизайн и код

В связи с требованиями к API level 29 и выше, если нашему приложению потребуются разрешения на доступ к сенсорам, то мы обязаны об этом сообщить в файле AndroidManifest.xml. Однако это только первая часть, т.к. потом мы дополнительно в коде запросим у пользователя подтвердить (или отклонить) эти разрешения.

 

4. В файл AndroidManifest.xml добавим разрешение на ACTIVITY_RECOGNITION (приведу полный код файла):

AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.simplestepcounter_kotlin">

    <uses-permission android:name="android.permission.ACTIVITY_RECOGNITION"/>

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.SimpleStepcounter_Kotlin"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

5. В build.gradle (:app) включим использование View Binding

build.gradle (:app)
    buildFeatures {
        viewBinding true
    }
Хотя данный шаг не является обязательным для работы с сенсорами.

 

6. Удалим старый виджет TextView и, как и в предыдущий раз, добавим два новых виджета TextView:

7. В редакторе кода (либо в окошке Attributes) присвоим им другие id:

android:id="@+id/textView_Info"

и

android:id="@+id/textView_Steps"

8. Для виджета textView_Steps установим выравнивание по горизонтали и вертикали (Horizontally in Parent и Vertically in Parent):

9. Для виджета textView_Info мы сделаем привязку к созданному ранее виджету textView_Steps:

10. Перетаскиваем правый ограничитель на правую часть, а левый на левую часть виджета textView_Info для создания привязки по горизонтали к виджету textView_Steps:

11. В редакторе выделим строковый ресурс для этого виджета:

12. Увеличиваем его размер до 48sp.
13. Полный код с дизайном теперь такой:

activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/textView_Info"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/steps_count"
        app:layout_constraintBottom_toTopOf="@+id/textView_Steps"
        app:layout_constraintEnd_toEndOf="@+id/textView_Steps"
        app:layout_constraintStart_toStartOf="@+id/textView_Steps" />

    <TextView
        android:id="@+id/textView_Steps"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/tv_StepsCount"
        android:textSize="48sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
Размер шрифта и прочую «красоту» можно настроить потом. Сейчас нам главное заставить шагомер работать.

 

14. Проверка разрешений на доступ к датчику активности (шагомеру):

Фрагмент файла MainActivity.kt
  override fun onCreate(savedInstanceState: Bundle?)
  {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    val binding = ActivityMainBinding.inflate(layoutInflater)
    setContentView(binding.root)

    binding.buttonAskForPermissions.setOnClickListener {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACTIVITY_RECOGNITION) == PackageManager.PERMISSION_GRANTED)
        {
            OnStepCounterPermissionGranted()
        } else
        {
            ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.ACTIVITY_RECOGNITION), RQ_PERMISSION_FOR_STEPCOUNTER_CODE)
        }
    }

    sensorManager = getSystemService(SENSOR_SERVICE) as SensorManager
}

Промежуточный результат

При запуске приложения мы проверяем текущие разрешения на доступ к датчику физической активности (шагомеру). Если их нет, то с помощью функции ActivityCompat.requestPermissions выводим запрос, с просьбой разрешить или отклонить эти разрешения:

Если же изначально разрешения не предоставлены (заблокированы перманентно), то выводится уведомление. В данном уведомлении мы сообщаем пользователю о том, что разрешений нет и он может открыть настройки, чтобы выставить необходимые разрешения самостоятельно. Проверку и отображение необходимой информации мы делаем в функции askUserForOpeningUpSettings():

private fun askUserForOpeningUpSettings()
{
    val sppSettingsIntent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.fromParts("package", packageName, null))
    if (packageManager.resolveActivity(sppSettingsIntent, PackageManager.MATCH_DEFAULT_ONLY) == null)
    {
        Toast.makeText(this, "Permissions are denied forever", Toast.LENGTH_SHORT).show()
    } else
    {
        AlertDialog.Builder(this)
            .setTitle("Permission denied")
            .setMessage(
                "You have denied permissions forever. " +
                        "You can change it in app settings.\n\n" +
                        "Would you like to open app settings?"
            )
            .setPositiveButton("Open") { _, _ ->
                startActivity(sppSettingsIntent)
            }
            .create()
            .show()
    }
}


Нажав на кнопочку Open, откроются системные настройки приложения, где можно открыть раздел Права:

Здесь можно нажать на пункт Физическая активность, чтобы изменить доступ:

Выбираем пункт Разрешить для сенсора «Физическая активность»:

Продолжение в части 2.