diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml deleted file mode 100644 index 797acea..0000000 --- a/.idea/runConfigurations.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index fcf977e..675afed 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -4,13 +4,13 @@ plugins { } android { - compileSdkVersion 30 + compileSdkVersion 31 buildToolsVersion "30.0.3" defaultConfig { applicationId "fr.oupson.taotoolbox" minSdkVersion 21 - targetSdkVersion 30 + targetSdkVersion 31 versionCode 1 versionName "0.0.3" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -43,19 +43,17 @@ android { } dependencies { - - implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" - implementation 'androidx.core:core-ktx:1.3.2' - implementation 'androidx.appcompat:appcompat:1.2.0' - implementation 'com.google.android.material:material:1.3.0' - implementation 'androidx.constraintlayout:constraintlayout:2.0.4' + implementation 'androidx.core:core-ktx:1.7.0' + implementation 'androidx.appcompat:appcompat:1.4.0' + implementation 'com.google.android.material:material:1.4.0' + implementation 'androidx.constraintlayout:constraintlayout:2.1.2' implementation 'androidx.preference:preference-ktx:1.1.1' testImplementation 'junit:junit:4.13.2' - androidTestImplementation 'androidx.test.ext:junit:1.1.2' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' + androidTestImplementation 'androidx.test.ext:junit:1.1.3' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.3' - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.3' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.0' implementation project(":common") implementation 'org.osmdroid:osmdroid-android:6.1.10' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 011a8d6..dce8fb7 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,9 +2,10 @@ - + + - + - + - + @@ -31,7 +36,9 @@ android:resource="@xml/widget_tao_info" /> - + diff --git a/app/src/main/java/fr/oupson/taotoolbox/activities/MainActivity.kt b/app/src/main/java/fr/oupson/taotoolbox/activities/MainActivity.kt index ad65b91..5d32188 100644 --- a/app/src/main/java/fr/oupson/taotoolbox/activities/MainActivity.kt +++ b/app/src/main/java/fr/oupson/taotoolbox/activities/MainActivity.kt @@ -12,6 +12,7 @@ import android.view.WindowManager import androidx.appcompat.app.AppCompatActivity import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat +import androidx.lifecycle.lifecycleScope import androidx.preference.PreferenceManager import fr.oupson.common.api.TaoRestApi import fr.oupson.common.db.TaoDatabaseHelper @@ -20,6 +21,7 @@ import fr.oupson.common.db.TaoDatabaseHelper.TaoDatabase.StopEntry import fr.oupson.taotoolbox.BuildConfig import fr.oupson.taotoolbox.R import fr.oupson.taotoolbox.databinding.ActivityMainBinding +import fr.oupson.taotoolbox.utils.PolylineDecoder import fr.oupson.taotoolbox.windows.StopInfoWindow import kotlinx.coroutines.* import org.json.JSONArray @@ -98,7 +100,7 @@ class MainActivity : AppCompatActivity() { requestPermissionsIfNecessary() - GlobalScope.launch(scope) { + lifecycleScope.launch(scope) { val helper = TaoDatabaseHelper(this@MainActivity).apply { try { this.checkUpdate() @@ -241,12 +243,7 @@ class MainActivity : AppCompatActivity() { ) } - val geo = route.getJSONArray("geojson") // TODO DECODE ENCODED ? - - for (i in 0 until geo.length()) { - val value = geo.getJSONArray(i) - routeLine.addPoint(GeoPoint(value.getDouble(1), value.getDouble(0))) - } + PolylineDecoder.decodeInto(routeLine, route.getString("geojsonEncoded"), 1) binding.map.overlays.add(routeLine) } diff --git a/app/src/main/java/fr/oupson/taotoolbox/activities/TaoWidgetConfigurationActivity.kt b/app/src/main/java/fr/oupson/taotoolbox/activities/TaoWidgetConfigurationActivity.kt index d7ba606..4af17a2 100644 --- a/app/src/main/java/fr/oupson/taotoolbox/activities/TaoWidgetConfigurationActivity.kt +++ b/app/src/main/java/fr/oupson/taotoolbox/activities/TaoWidgetConfigurationActivity.kt @@ -12,6 +12,7 @@ import android.view.MenuItem import android.view.View import android.widget.AutoCompleteTextView import androidx.appcompat.app.AppCompatActivity +import androidx.lifecycle.lifecycleScope import fr.oupson.common.api.TaoRestApi import fr.oupson.common.db.TaoDatabaseHelper import fr.oupson.common.db.TaoDatabaseHelper.TaoDatabase.* @@ -69,7 +70,7 @@ class TaoWidgetConfigurationActivity : AppCompatActivity() { val appWidgetManager: AppWidgetManager = AppWidgetManager.getInstance(this) val ids = appWidgetManager.getAppWidgetIds(ComponentName(this, TaoWidget::class.java)) - GlobalScope.launch(Dispatchers.IO) { + lifecycleScope.launch(Dispatchers.IO) { for (id in ids) { TaoWidget.updateAppWidget( this@TaoWidgetConfigurationActivity, @@ -88,7 +89,7 @@ class TaoWidgetConfigurationActivity : AppCompatActivity() { (binding.configSelectLine.editText as? AutoCompleteTextView)?.also { autoCompleteTextView -> autoCompleteTextView.setAdapter(lineAdapter) autoCompleteTextView.setOnItemClickListener { _, _, position, _ -> - GlobalScope.launch(Dispatchers.IO) { + lifecycleScope.launch(Dispatchers.IO) { linePosition = position directionPosition = -1 loadDirectionList(position) @@ -99,7 +100,7 @@ class TaoWidgetConfigurationActivity : AppCompatActivity() { (binding.configSelectDirection.editText as? AutoCompleteTextView)?.also { directionAutoComplete -> directionAutoComplete.setAdapter(directionAdapter) directionAutoComplete.setOnItemClickListener { _, _, position, _ -> - GlobalScope.launch(Dispatchers.IO) { + lifecycleScope.launch(Dispatchers.IO) { directionPosition = position stopPosition = -1 @@ -120,7 +121,7 @@ class TaoWidgetConfigurationActivity : AppCompatActivity() { save() } - GlobalScope.launch(Dispatchers.IO) { + lifecycleScope.launch(Dispatchers.IO) { db = TaoDatabaseHelper(this@TaoWidgetConfigurationActivity).apply { checkUpdate() withContext(Dispatchers.Main) { diff --git a/app/src/main/java/fr/oupson/taotoolbox/adapters/ScheduleAdapter.kt b/app/src/main/java/fr/oupson/taotoolbox/adapters/RealTimeAdapter.kt similarity index 73% rename from app/src/main/java/fr/oupson/taotoolbox/adapters/ScheduleAdapter.kt rename to app/src/main/java/fr/oupson/taotoolbox/adapters/RealTimeAdapter.kt index 8707d19..c5b7af8 100644 --- a/app/src/main/java/fr/oupson/taotoolbox/adapters/ScheduleAdapter.kt +++ b/app/src/main/java/fr/oupson/taotoolbox/adapters/RealTimeAdapter.kt @@ -7,18 +7,19 @@ import android.view.ViewGroup import android.widget.ImageView import android.widget.TextView import androidx.recyclerview.widget.RecyclerView -import fr.oupson.taotoolbox.R import fr.oupson.common.api.LineColors -import fr.oupson.common.api.Schedule +import fr.oupson.common.api.RealtimeStopArea +import fr.oupson.taotoolbox.R import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -class ScheduleAdapter( - private val scheduleList: SimplePtr> +// TODO ADAPT +class RealTimeAdapter( + private val realTimeList: SimplePtr> ) : - RecyclerView.Adapter() { + RecyclerView.Adapter() { class SimplePtr(private var value: T? = null) { fun get(): T? = value fun set(value: T?) { @@ -26,21 +27,23 @@ class ScheduleAdapter( } } - class ScheduleViewHolder( + class RealTimeViewHolder( private val view: View ) : RecyclerView.ViewHolder(view) { private val scheduleDirectionTextView = view.findViewById(R.id.item_schedule_direction_text_view) - private val scheduleImageView = view.findViewById(R.id.item_schedule_line_image_view) - private val scheduleNextTextView = view.findViewById(R.id.item_schedule_next_text_view) + private val scheduleImageView = + view.findViewById(R.id.item_schedule_line_image_view) + private val scheduleNextTextView = + view.findViewById(R.id.item_schedule_next_text_view) private val scheduleAfterTextView = view.findViewById(R.id.item_schedule_after_text_view) - fun bind(schedule: Schedule) { + fun bind(schedule: RealtimeStopArea) { scheduleDirectionTextView.text = view.context.getString( R.string.line_and_direction_name, schedule.lineColors.lineCode, - schedule.lineDirectionName + schedule.routeName ) scheduleNextTextView.text = @@ -50,7 +53,6 @@ class ScheduleAdapter( schedule.timeRemainingAfter() ?: "∅" ) - GlobalScope.launch(Dispatchers.Default) { val btm = LineColors.getLineBtm( view.context, @@ -67,16 +69,16 @@ class ScheduleAdapter( } } - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ScheduleViewHolder { + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RealTimeViewHolder { val inflater = LayoutInflater.from(parent.context) - return ScheduleViewHolder(inflater.inflate(R.layout.item_schedule, parent, false)) + return RealTimeViewHolder(inflater.inflate(R.layout.item_schedule, parent, false)) } - override fun onBindViewHolder(holder: ScheduleViewHolder, position: Int) { - val ref = scheduleList.get() + override fun onBindViewHolder(holder: RealTimeViewHolder, position: Int) { + val ref = realTimeList.get() if (ref != null) holder.bind(ref[position]) } - override fun getItemCount(): Int = scheduleList.get()?.size ?: 0 + override fun getItemCount(): Int = realTimeList.get()?.size ?: 0 } \ No newline at end of file diff --git a/app/src/main/java/fr/oupson/taotoolbox/receivers/TaoWidget.kt b/app/src/main/java/fr/oupson/taotoolbox/receivers/TaoWidget.kt index a72a0ce..2c4bb29 100644 --- a/app/src/main/java/fr/oupson/taotoolbox/receivers/TaoWidget.kt +++ b/app/src/main/java/fr/oupson/taotoolbox/receivers/TaoWidget.kt @@ -7,6 +7,7 @@ import android.content.Context import android.content.Intent import android.graphics.* import android.net.Uri +import android.os.Build import android.util.Log import android.widget.RemoteViews import fr.oupson.common.api.LineColors @@ -37,12 +38,18 @@ class TaoWidget : AppWidgetProvider() { serviceIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, intArrayOf(appWidgetId)) serviceIntent.data = Uri.parse(serviceIntent.toUri(Intent.URI_INTENT_SCHEME)) - val pending = PendingIntent.getBroadcast( - context, - appWidgetId, - serviceIntent, - PendingIntent.FLAG_UPDATE_CURRENT - ) + val pending = + PendingIntent.getBroadcast( + context, + appWidgetId, + serviceIntent, + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE + } else { + PendingIntent.FLAG_UPDATE_CURRENT + } + ) + views.setOnClickPendingIntent(R.id.tao_widget_root, pending) try { diff --git a/app/src/main/java/fr/oupson/taotoolbox/utils/PolylineDecoder.java b/app/src/main/java/fr/oupson/taotoolbox/utils/PolylineDecoder.java new file mode 100644 index 0000000..c685e3a --- /dev/null +++ b/app/src/main/java/fr/oupson/taotoolbox/utils/PolylineDecoder.java @@ -0,0 +1,37 @@ +package fr.oupson.taotoolbox.utils; + + +import org.osmdroid.util.GeoPoint; +import org.osmdroid.views.overlay.Polyline; + +public class PolylineDecoder { + public static void decodeInto(Polyline line, String encodedString, int precision) { + int index = 0; + int len = encodedString.length(); + int lat = 0, lng = 0; + + while (index < len) { + int b, shift, result; + shift = result = 0; + do { + b = encodedString.charAt(index++) - 63; + result |= (b & 0x1f) << shift; + shift += 5; + } while (b >= 0x20); + int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1)); + lat += dlat; + + shift = result = 0; + do { + b = encodedString.charAt(index++) - 63; + result |= (b & 0x1f) << shift; + shift += 5; + } while (b >= 0x20); + int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1)); + lng += dlng; + + GeoPoint p = new GeoPoint(((double) (lng * precision)) / 1.0e6, ((double) (lat * precision)) / 1.0e6, 0); + line.addPoint(p); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/fr/oupson/taotoolbox/windows/StopInfoWindow.kt b/app/src/main/java/fr/oupson/taotoolbox/windows/StopInfoWindow.kt index f917793..b6f3d07 100644 --- a/app/src/main/java/fr/oupson/taotoolbox/windows/StopInfoWindow.kt +++ b/app/src/main/java/fr/oupson/taotoolbox/windows/StopInfoWindow.kt @@ -3,10 +3,10 @@ package fr.oupson.taotoolbox.windows import android.widget.TextView import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView -import fr.oupson.taotoolbox.R -import fr.oupson.taotoolbox.adapters.ScheduleAdapter -import fr.oupson.common.api.Schedule +import fr.oupson.common.api.RealtimeStopArea import fr.oupson.common.api.TaoRestApi +import fr.oupson.taotoolbox.R +import fr.oupson.taotoolbox.adapters.RealTimeAdapter import kotlinx.coroutines.* import org.osmdroid.views.MapView import org.osmdroid.views.overlay.Marker @@ -21,13 +21,13 @@ class StopInfoWindow( private val titleTextView: TextView by lazy { view.findViewById(R.id.window_stop_info_title_text_view) } - private val scheduleList: ScheduleAdapter.SimplePtr> by lazy { - ScheduleAdapter.SimplePtr( + private val realtimeList: RealTimeAdapter.SimplePtr> by lazy { + RealTimeAdapter.SimplePtr( null ) } - private val adapter: ScheduleAdapter by lazy { ScheduleAdapter(scheduleList) } + private val adapter: RealTimeAdapter by lazy { RealTimeAdapter(realtimeList) } private val recyclerView: RecyclerView by lazy { view.findViewById(R.id.window_stop_info_schedule_recycler_view).also { it.adapter = adapter @@ -36,7 +36,7 @@ class StopInfoWindow( } override fun onOpen(item: Any?) { - scheduleList.set(null) + realtimeList.set(null) recyclerView.adapter?.notifyDataSetChanged() if (item is Marker) { @@ -44,10 +44,10 @@ class StopInfoWindow( titleTextView.text = item.title GlobalScope.launch(windowsContext) { - val schedule = taoRestApi.getSchedule(id) + val realtime = taoRestApi.getRealtimeByStopArea(id) withContext(Dispatchers.Main) { - scheduleList.set(schedule) + realtimeList.set(realtime) adapter.notifyDataSetChanged() } } diff --git a/build.gradle b/build.gradle index 2160468..cf98189 100644 --- a/build.gradle +++ b/build.gradle @@ -1,13 +1,13 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = "1.5.0" - ext.ktor_version = "1.5.3" + ext.kotlin_version = "1.6.10" + ext.ktor_version = "1.6.3" repositories { google() mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:4.2.0' + classpath 'com.android.tools.build:gradle:7.0.4' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong diff --git a/common/build.gradle b/common/build.gradle index 068b431..183be4a 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -1,18 +1,16 @@ plugins { id 'com.android.library' id 'kotlin-android' - id 'org.jetbrains.kotlin.plugin.serialization' version '1.4.30' + id 'org.jetbrains.kotlin.plugin.serialization' version '1.5.30' } android { - compileSdkVersion 30 + compileSdkVersion 31 buildToolsVersion "30.0.3" defaultConfig { minSdkVersion 21 - targetSdkVersion 30 - versionCode 1 - versionName "1.0" + targetSdkVersion 31 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles "consumer-rules.pro" @@ -34,14 +32,13 @@ android { } dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" - implementation 'androidx.core:core-ktx:1.3.2' - implementation 'androidx.appcompat:appcompat:1.2.0' - implementation 'com.google.android.material:material:1.3.0' + implementation 'androidx.core:core-ktx:1.7.0' + implementation 'androidx.appcompat:appcompat:1.4.0' + implementation 'com.google.android.material:material:1.4.0' testImplementation 'junit:junit:4.13.2' - androidTestImplementation 'androidx.test.ext:junit:1.1.2' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' - implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.1.0" + androidTestImplementation 'androidx.test.ext:junit:1.1.3' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' + implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2" implementation "io.ktor:ktor-client-serialization:$ktor_version" implementation "io.ktor:ktor-client-core:$ktor_version" diff --git a/common/src/main/java/fr/oupson/common/api/Stop.kt b/common/src/main/java/fr/oupson/common/api/Stop.kt index aef30b0..84e8238 100644 --- a/common/src/main/java/fr/oupson/common/api/Stop.kt +++ b/common/src/main/java/fr/oupson/common/api/Stop.kt @@ -130,7 +130,10 @@ object DateAsStringSerializer : KSerializer { SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX", Locale.getDefault()).parse(string)!! } else { // Z format is not supported :/ val newDateStr = if (string.endsWith("Z")) { - string.substring(0, string.length - 1) + "+0000" // Little trick to get time in correct time zone + string.substring( + 0, + string.length - 1 + ) + "+0000" // Little trick to get time in correct time zone } else { throw Exception("$string is not supported") // TODO ? } @@ -164,4 +167,65 @@ data class Schedule( nextScheduleAfter?.let { (it.time - Date().time) / (1000 * 60) } -} \ No newline at end of file +} + +@Serializable +data class RealtimeStopArea( + val lineId: String, + val lineCode: String, + val lineColors: LineColors, + val routeId: String, + val routeName: String, + val lineIsTAD: Boolean, + val nextPassages: Array, + val summaryStatus: String? +) { + fun timeRemaining(): Long? = + nextPassages.getOrNull(0)?.let { + (it.date!!.time - Date().time) / (1000 * 60) + } + + fun timeRemainingAfter(): Long? = + nextPassages.getOrNull(1)?.let { + (it.date!!.time - Date().time) / (1000 * 60) + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as RealtimeStopArea + + if (lineId != other.lineId) return false + if (lineCode != other.lineCode) return false + if (lineColors != other.lineColors) return false + if (routeId != other.routeId) return false + if (routeName != other.routeName) return false + if (lineIsTAD != other.lineIsTAD) return false + if (!nextPassages.contentEquals(other.nextPassages)) return false + if (summaryStatus != other.summaryStatus) return false + + return true + } + + override fun hashCode(): Int { + var result = lineId.hashCode() + result = 31 * result + lineCode.hashCode() + result = 31 * result + lineColors.hashCode() + result = 31 * result + routeId.hashCode() + result = 31 * result + routeName.hashCode() + result = 31 * result + lineIsTAD.hashCode() + result = 31 * result + nextPassages.contentHashCode() + result = 31 * result + (summaryStatus?.hashCode() ?: 0) + return result + } +} + +@Serializable +data class NextPassage( + @Serializable(with = DateAsStringSerializer::class) + val date: Date?, + val vehicleId: String, + val loadPrediction: String?, // TODO + val isLiveData: Boolean +) diff --git a/common/src/main/java/fr/oupson/common/api/TaoRestApi.kt b/common/src/main/java/fr/oupson/common/api/TaoRestApi.kt index b850a06..29511fc 100644 --- a/common/src/main/java/fr/oupson/common/api/TaoRestApi.kt +++ b/common/src/main/java/fr/oupson/common/api/TaoRestApi.kt @@ -3,6 +3,7 @@ package fr.oupson.common.api import io.ktor.client.* import io.ktor.client.engine.android.* import io.ktor.client.features.json.* +import io.ktor.client.features.json.serializer.* import io.ktor.client.request.* import io.ktor.client.request.forms.* import io.ktor.http.* @@ -12,7 +13,9 @@ import kotlin.coroutines.CoroutineContext class TaoRestApi(private val httpClient: HttpClient) { constructor() : this(HttpClient(Android) { - install(JsonFeature) + install(JsonFeature) { + serializer = KotlinxSerializer(kotlinx.serialization.json.Json { ignoreUnknownKeys = true }) + } engine { connectTimeout = 10_1000 socketTimeout = 10_000 @@ -69,9 +72,24 @@ class TaoRestApi(private val httpClient: HttpClient) { }, true) {} } + suspend fun getRealtimeByStopArea(stopAreaId: String, limit: Int? = null, includeLoadPrediction: Boolean? = null) : Array = withContext(Dispatchers.IO) { + httpClient.submitForm("https://navigorleans.c-t.io/api/3.0/realtime/byStopArea", Parameters.build { + append( + "stopAreaId", stopAreaId + ) + if (limit != null) { + append("limit", limit.toString()) + } + + if (includeLoadPrediction != null) { + append("includeLoadPrediction", includeLoadPrediction.toString()) + } + }, true) {} + } + suspend fun getTaoGeoJson( lineId: String ): String = withContext(requestContext) { - httpClient.get("$baseUrl/2.0/lines/$lineId/geojson") + httpClient.get("$baseUrl/2.0/lines/$lineId/geojson/encoded") } } \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 98619f1..c198239 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip diff --git a/wear_tao/build.gradle b/wear_tao/build.gradle index 4c13c09..900d121 100644 --- a/wear_tao/build.gradle +++ b/wear_tao/build.gradle @@ -33,16 +33,15 @@ android { } dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" - implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.3' + implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.0' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-guava:1.4.2' - implementation 'androidx.core:core-ktx:1.3.2' - implementation 'androidx.appcompat:appcompat:1.2.0' - implementation 'com.google.android.material:material:1.3.0' - implementation 'androidx.constraintlayout:constraintlayout:2.0.4' + implementation 'androidx.core:core-ktx:1.6.0' + implementation 'androidx.appcompat:appcompat:1.3.1' + implementation 'com.google.android.material:material:1.4.0' + implementation 'androidx.constraintlayout:constraintlayout:2.1.0' testImplementation 'junit:junit:4.13.2' - androidTestImplementation 'androidx.test.ext:junit:1.1.2' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' + androidTestImplementation 'androidx.test.ext:junit:1.1.3' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' implementation 'androidx.wear:wear:1.1.0' implementation "androidx.wear:wear-tiles:1.0.0-alpha01" debugImplementation "androidx.wear:wear-tiles-renderer:1.0.0-alpha01"