Skip to content

Commit

Permalink
Merge branch 'main' into tbedford-patch-1
Browse files Browse the repository at this point in the history
  • Loading branch information
tbedford authored Sep 12, 2022
2 parents ffd1c6c + b0a526e commit 7c4510b
Show file tree
Hide file tree
Showing 10 changed files with 126 additions and 9 deletions.
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,27 @@
# Change log

## [1.3.0](https://github.com/ably/ably-asset-tracking-android/tree/1.3.0)

[Full Changelog](https://github.com/ably/ably-asset-tracking-android/compare/v1.2.0...1.3.0)

**Implemented enhancements:**

- Upgrade Mapbox Nav SDK to the GA 2.7.0 version [\#742](https://github.com/ably/ably-asset-tracking-android/issues/742)

**Fixed bugs:**

- CoreLocationAnimator progress may be bigger than 100% [\#751](https://github.com/ably/ably-asset-tracking-android/issues/751)
- Fix the waitForChannelReconnection\(\) method implementation [\#744](https://github.com/ably/ably-asset-tracking-android/issues/744)

**Merged pull requests:**

- Expose publisher presence flow from the subscriber SDK [\#754](https://github.com/ably/ably-asset-tracking-android/pull/754) ([KacperKluka](https://github.com/KacperKluka))
- Fix location animator progress exceeding 100% [\#752](https://github.com/ably/ably-asset-tracking-android/pull/752) ([KacperKluka](https://github.com/KacperKluka))
- Update builder examples for publisher and subscriber in the README [\#750](https://github.com/ably/ably-asset-tracking-android/pull/750) ([KacperKluka](https://github.com/KacperKluka))
- Fix the waitForChannelReconnection\(\) method implementation [\#749](https://github.com/ably/ably-asset-tracking-android/pull/749) ([KacperKluka](https://github.com/KacperKluka))
- Upgrade Mapbox to 2.7.0 [\#748](https://github.com/ably/ably-asset-tracking-android/pull/748) ([KacperKluka](https://github.com/KacperKluka))
- Add known limitations section to the README [\#747](https://github.com/ably/ably-asset-tracking-android/pull/747) ([KacperKluka](https://github.com/KacperKluka))

## [1.2.0](https://github.com/ably/ably-asset-tracking-android/tree/v1.2.0)

[Full Changelog](https://github.com/ably/ably-asset-tracking-android/compare/v1.1.1...v1.2.0)
Expand Down
33 changes: 29 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,13 +127,13 @@ you can then add the Ably Asset Tracking dependency that you require in your Gra
```groovy
dependencies {
// Publishers, developing in Kotlin, will need the Publishing SDK
implementation 'com.ably.tracking:publishing-sdk:1.2.0'
implementation 'com.ably.tracking:publishing-sdk:1.3.0'
// Subscribers, developing in Kotlin, will need the Subscribing SDK
implementation 'com.ably.tracking:subscribing-sdk:1.2.0'
implementation 'com.ably.tracking:subscribing-sdk:1.3.0'
// Subscribers, developing in Kotlin, can optionally use the UI utilities
implementation 'com.ably.tracking:ui-sdk:1.2.0'
implementation 'com.ably.tracking:ui-sdk:1.3.0'
}
```

Expand Down Expand Up @@ -251,6 +251,31 @@ try {
}
```

### Publisher presence

Publisher presence is provided as an experimental API for subscribers which you can use to get information about
whether the publisher is online or offline. This API is not yet stable and may change in the future.

To use the API you must explicitly opt in to it by adding the following to your `build.gradle` file:

```groovy
android {
kotlinOptions {
freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn"
}
}
```

Then you can annotate your element of the desired scope with ``@OptIn(Experimental::class)`` annotation.

An example usage of the API is shown below:

```kotlin
subscriber.publisherPresence
.onEach { isOnline -> print(isOnline) } // provide a function to be called when the asset's presnec is changed
.launchIn(scope) // coroutines scope on which the statuses are received
```

### UI utilities

#### Location Animator
Expand Down Expand Up @@ -331,7 +356,7 @@ Firstly, you have to exclude the notification module from Mapbox Navigation SDK

```groovy
// The Ably Asset Tracking Publisher SDK for Android.
implementation ('com.ably.tracking:publishing-sdk:1.2.0')
implementation ('com.ably.tracking:publishing-sdk:1.3.0')
// The Mapbox Navigation SDK.
implementation ('com.mapbox.navigation:android:2.7.0') {
Expand Down
5 changes: 3 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ allprojects {

// version MUST conform to the Semantic Versioning Specification (https://semver.org/) version 2.0.0
// on incrementing this value, ensure to also increment versionCode in android defaultConfig (also in this file)
version = '1.2.0'
version = '1.3.0'

// Values used to publish the SDK to maven repositories.
ext {
Expand Down Expand Up @@ -111,7 +111,7 @@ subprojects {
// projects in this repository. Therefore, this same version number is used for SDK and
// example app projects alike.
// - versionCode MUST be incremented by 1 for each release from the main branch
versionCode 28
versionCode 29
versionName version

testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
Expand All @@ -130,6 +130,7 @@ subprojects {
kotlinOptions {
jvmTarget = '1.8'
allWarningsAsErrors = true
freeCompilerArgs += '-Xopt-in=kotlin.RequiresOptIn'
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.ably.tracking.annotations

@RequiresOptIn(message = "This is an experimental API. It may change in the future.")
@Retention(AnnotationRetention.BINARY)
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY)
annotation class Experimental // Opt-in requirement annotation
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.ably.tracking.example.subscriber
import com.ably.tracking.Accuracy
import com.ably.tracking.connection.Authentication
import com.ably.tracking.Resolution
import com.ably.tracking.annotations.Experimental
import com.ably.tracking.connection.ConnectionConfiguration
import com.ably.tracking.subscriber.Subscriber
import kotlinx.coroutines.CoroutineScope
Expand All @@ -20,6 +21,7 @@ val ABLY_API_KEY = ""
// The client ID for the Ably SDK instance.
val CLIENT_ID = ""

@OptIn(Experimental::class)
fun exampleUsage(trackingId: String) {
val scope = CoroutineScope(Dispatchers.Main)
// EXAMPLE SNIPPET FROM HERE, WITH EXCESS INDENT REMOVED:
Expand Down Expand Up @@ -54,7 +56,11 @@ fun exampleUsage(trackingId: String) {
// provide a function to be called when the asset changes online/offline status
}
.launchIn(scope)

subscriber.publisherPresence
.onEach {
// TODO provide a function to be called when the publisher changes online/offline status
}
.launchIn(scope)
// Request a different resolution when needed.
scope.launch {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import kotlinx.android.synthetic.main.activity_main.mapFragmentContainerView
import kotlinx.android.synthetic.main.activity_main.rootContainer
import kotlinx.android.synthetic.main.asset_information_view.animationSettingsImageView
import kotlinx.android.synthetic.main.asset_information_view.assetStateTextView
import kotlinx.android.synthetic.main.asset_information_view.assetPresenceStateTextView
import kotlinx.android.synthetic.main.asset_information_view.publisherResolutionAccuracyTextView
import kotlinx.android.synthetic.main.asset_information_view.publisherResolutionDisplacementTextView
import kotlinx.android.synthetic.main.asset_information_view.publisherResolutionIntervalTextView
Expand All @@ -53,6 +54,7 @@ import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import timber.log.Timber
import com.ably.tracking.annotations.Experimental

// The client ID for the Ably SDK instance.
private const val CLIENT_ID = "<INSERT_CLIENT_ID_HERE>"
Expand Down Expand Up @@ -169,6 +171,7 @@ class MainActivity : AppCompatActivity() {
}
}

@OptIn(Experimental::class)
private suspend fun createAndStartAssetSubscriber(trackableId: String) {
subscriber = Subscriber.subscribers()
.connection(ConnectionConfiguration(Authentication.basic(CLIENT_ID, ABLY_API_KEY)))
Expand Down Expand Up @@ -196,6 +199,9 @@ class MainActivity : AppCompatActivity() {
trackableStates
.onEach { updateAssetState(it) }
.launchIn(scope)
publisherPresence
.onEach { updatePresenceState(it) }
.launchIn(scope)
resolutions
.onEach {
updatePublisherResolutionInfo(it)
Expand Down Expand Up @@ -297,6 +303,16 @@ class MainActivity : AppCompatActivity() {
assetStateTextView.backgroundTintList = ColorStateList.valueOf(ContextCompat.getColor(this, backgroundColorId))
}

private fun updatePresenceState(isPresent: Boolean) {
val textColorId = if (isPresent) R.color.black else R.color.mid_grey
val backgroundColorId = if (isPresent) R.color.asset_online else R.color.asset_offline

assetPresenceStateTextView.text = if (isPresent) "Presence: Online" else "Presence: Offline"
assetPresenceStateTextView.setTextColor(ContextCompat.getColor(this, textColorId))
assetPresenceStateTextView.backgroundTintList =
ColorStateList.valueOf(ContextCompat.getColor(this, backgroundColorId))
}

private fun stopSubscribing() {
showLoading()
scope.launch {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,21 @@
app:layout_constraintTop_toTopOf="@id/assetStateLabelTextView"
tools:ignore="SmallSp" />

<TextView
android:id="@+id/assetPresenceStateTextView"
android:layout_width="52dp"
android:layout_height="20dp"
android:layout_marginStart="16dp"
android:background="@drawable/round_rectangle"
android:backgroundTint="@color/asset_offline"
android:gravity="center"
android:text="@string/asset_status_offline"
android:textColor="@color/mid_grey"
android:textSize="8sp"
app:layout_constraintStart_toEndOf="@+id/assetStateTextView"
app:layout_constraintTop_toTopOf="@+id/assetStateTextView"
tools:ignore="SmallSp" />

<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/animationSettingsImageView"
android:layout_width="25dp"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ internal interface CoreSubscriber {
val enhancedLocations: SharedFlow<LocationUpdate>
val rawLocations: SharedFlow<LocationUpdate>
val trackableStates: StateFlow<TrackableState>
val publisherPresence: StateFlow<Boolean>
val resolutions: SharedFlow<Resolution>
val nextLocationUpdateIntervals: SharedFlow<Long>
}
Expand All @@ -57,6 +58,7 @@ private class DefaultCoreSubscriber(
private val scope = CoroutineScope(singleThreadDispatcher + SupervisorJob())
private val sendEventChannel: SendChannel<Event>
private val _trackableStates: MutableStateFlow<TrackableState> = MutableStateFlow(TrackableState.Offline())
private val _publisherPresence: MutableStateFlow<Boolean> = MutableStateFlow(false)
private val _enhancedLocations: MutableSharedFlow<LocationUpdate> = MutableSharedFlow(replay = 1)
private val _rawLocations: MutableSharedFlow<LocationUpdate> = MutableSharedFlow(replay = 1)
private val _resolutions: MutableSharedFlow<Resolution> = MutableSharedFlow(replay = 1)
Expand All @@ -71,6 +73,9 @@ private class DefaultCoreSubscriber(
override val trackableStates: StateFlow<TrackableState>
get() = _trackableStates.asStateFlow()

override val publisherPresence: StateFlow<Boolean>
get() = _publisherPresence

override val resolutions: SharedFlow<Resolution>
get() = _resolutions.asSharedFlow()

Expand Down Expand Up @@ -152,14 +157,14 @@ private class DefaultCoreSubscriber(
when (event.presenceMessage.action) {
PresenceAction.PRESENT_OR_ENTER -> {
if (event.presenceMessage.data.type == ClientTypes.PUBLISHER) {
properties.isPublisherOnline = true
updatePublisherPresence(properties, true)
updateTrackableState(properties)
updatePublisherResolutionInformation(event.presenceMessage.data)
}
}
PresenceAction.LEAVE_OR_ABSENT -> {
if (event.presenceMessage.data.type == ClientTypes.PUBLISHER) {
properties.isPublisherOnline = false
updatePublisherPresence(properties, false)
updateTrackableState(properties)
}
}
Expand Down Expand Up @@ -199,6 +204,13 @@ private class DefaultCoreSubscriber(
}
}

private fun updatePublisherPresence(properties: Properties, isPublisherPresent: Boolean) {
if (isPublisherPresent != properties.isPublisherOnline) {
properties.isPublisherOnline = isPublisherPresent
scope.launch { _publisherPresence.emit(isPublisherPresent) }
}
}

private fun updateTrackableState(properties: Properties) {
val newTrackableState = when (properties.lastConnectionStateChange.state) {
ConnectionState.ONLINE -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.ably.tracking.subscriber
import com.ably.tracking.LocationUpdate
import com.ably.tracking.Resolution
import com.ably.tracking.TrackableState
import com.ably.tracking.annotations.Experimental
import com.ably.tracking.common.Ably
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
Expand All @@ -26,6 +27,10 @@ internal class DefaultSubscriber(
override val trackableStates: StateFlow<TrackableState>
get() = core.trackableStates

@Experimental
override val publisherPresence: StateFlow<Boolean>
get() = core.publisherPresence

override val resolutions: SharedFlow<Resolution>
get() = core.resolutions

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.ably.tracking.ConnectionException
import com.ably.tracking.LocationUpdate
import com.ably.tracking.Resolution
import com.ably.tracking.TrackableState
import com.ably.tracking.annotations.Experimental
import com.ably.tracking.connection.ConnectionConfiguration
import com.ably.tracking.logging.LogHandler
import kotlinx.coroutines.flow.SharedFlow
Expand Down Expand Up @@ -63,6 +64,14 @@ interface Subscriber {
val trackableStates: StateFlow<TrackableState>
@JvmSynthetic get

/**
* The shared flow emitting values when the presence of the publisher changes.
* The publisher is present when the value is "true". If the value is "false" the publisher is not present.
*/
@Experimental
val publisherPresence: StateFlow<Boolean>
@JvmSynthetic get

/**
* The shared flow emitting resolution values when they become available.
*/
Expand Down

0 comments on commit 7c4510b

Please sign in to comment.