Skip to content

Commit

Permalink
Update to the latest version of up-java (v2.0.x) (#10)
Browse files Browse the repository at this point in the history
Co-authored-by: Mikhail Petrov <[email protected]>
  • Loading branch information
mishap4 and Mikhail Petrov authored Oct 2, 2024
1 parent 17571d2 commit 836444a
Show file tree
Hide file tree
Showing 43 changed files with 1,364 additions and 3,990 deletions.
111 changes: 33 additions & 78 deletions README.adoc
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
= uProtocol Client Android Java Library
= uProtocol Transport Android Java Library
:toc:
:toclevels: 4
:sectnums:
:source-highlighter: coderay

== Overview
The following is the uProtocol client library that implements uTransport, RpcClient and RpcService defined in https://github.com/eclipse-uprotocol/up-java[uProtocol Java Library] using Android Binder. It also includes some commonly used utilities for error handling.
The following is the uProtocol library that implements uTransport defined in https://github.com/eclipse-uprotocol/up-java[uProtocol Java Library] using Android Binder. It also includes some commonly used utilities for error handling.

== Getting Started
=== Importing the Library
Expand All @@ -15,13 +15,13 @@ If you are using Gradle, add the following to your _build.gradle_ file's depende
----
android {
dependencies {
implementation 'org.eclipse.uprotocol:up-client-android-java::1.5.+'
implementation 'org.eclipse.uprotocol:up-transport-android-java::0.1.+'
}
}
----

=== Configuring the Library
`UPClient`, by default, establishes a connection to uBus service that is integrated into the system as part of `"org.eclipse.uprotocol.core"` package.
`UTransprtAndroid`, by default, establishes a connection to uBus service that is integrated into the system as part of `"org.eclipse.uprotocol.core"` package.

If a service that implements `IUBus.aidl` interface is integrated in a different package, you should configure the library by specifying that component or just that package.

Expand All @@ -35,26 +35,25 @@ If a service that implements `IUBus.aidl` interface is integrated in a different

=== Using the Library
==== Connecting to uTransport
Before using the `UPClient` APIs, a uE must create an instance and connect to uBus.
Before using the `UTransportAndroid` APIs, a uE must create an instance and open connection to uBus.

First create an instance with one of static factory methods:

[,java]
----
static UPClient create(Context context, Handler handler, ServiceLifecycleListener listener)
static UPClient create(Context context, Executor executor, ServiceLifecycleListener listener)
static UPClient create(Context context, UEntity entity, Handler handler, ServiceLifecycleListener listener)
static UPClient create(Context context, UEntity entity, Executor executor, ServiceLifecycleListener listener)
static UTransportAndroid create(Context context, Handler handler)
static UTransportAndroid create(Context context, Executor executor)
static UTransportAndroid create(Context context, UUri source, Handler handler)
static UTransportAndroid create(Context context, UUri source, Executor executor)
----

[%hardbreaks]
`context` is an application context.
`entity` is information about uE containing its name and major version (MUST match the meta data in the manifest).
`source` is an address of uE containing its name and major version (MUST match the meta data in the manifest).
`handler` is a handler on which callbacks should execute, or null to execute on the application's main thread.
`executor` is an executor on which callbacks should execute, or null to execute on the application's main thread executor.
`listener` is a listener for monitoring uBus lifecycle.

NOTE: Every Android uE MUST declare its name and major version in the manifest.
NOTE: Every Android uE MUST declare its id and major version in the manifest.

For the example below you may use any `create(...)` factory method.

Expand All @@ -66,8 +65,8 @@ For the example below you may use any `create(...)` factory method.
...
<application android:label="@string/app_name" ...>
<meta-data
android:name="uprotocol.entity.name"
android:value="example.client" />
android:name="uprotocol.entity.id"
android:value="100" />
<meta-data
android:name="uprotocol.entity.version"
android:value="1" />
Expand All @@ -79,7 +78,7 @@ For the example below you may use any `create(...)` factory method.
</manifest>
----

For the next example you should create a separate instance of `UPClient` for each uE using `create(..., UEntity entity,...)` factory method.
For the next example you should create a separate instance of `UTransportAndroid` for each uE using `create(..., UUri source,...)` factory method.

.Example 2: Several Android uEs bundled together in APK
[,xml]
Expand All @@ -92,8 +91,8 @@ For the next example you should create a separate instance of `UPClient` for eac
android:name=".ExteriorLightingService"
... >
<meta-data
android:name="uprotocol.entity.name"
android:value="body.lighting.exterior" />
android:name="uprotocol.entity.id"
android:value="100" />
<meta-data
android:name="uprotocol.entity.version"
android:value="1" />
Expand All @@ -103,8 +102,8 @@ For the next example you should create a separate instance of `UPClient` for eac
android:name=".InteriorLightingService"
... >
<meta-data
android:name="uprotocol.entity.name"
android:value="body.lighting.interior" />
android:name="uprotocol.entity.id"
android:value="101" />
<meta-data
android:name="uprotocol.entity.version"
android:value="1" />
Expand All @@ -113,95 +112,51 @@ For the next example you should create a separate instance of `UPClient` for eac
</manifest>
----

Then connect to uBus using a reactive API below:
Then open connection to uBus using a reactive API below:

[,java]
----
CompletionStage<UStatus> connect()
CompletionStage<UStatus> open()
----

When you are done with the `UPClient` you should disconnect from uBus:
When you are done with the `UTransportAndroid` you should close the connection:

[,java]
----
CompletionStage<UStatus> disconnect()
void close()
----

You cannot use other methods until the `UPClient` is connected. When this happens the `CompletionStage<UStatus>` returned by connect() will be completed and you also will receive the `onLifecycleChanged(..., true)` callback on your service lifecycle listener. You may query the connected status using these methods:
You cannot use other methods until the `UTransportAndroid` is connected. When this happens the `CompletionStage<UStatus>` returned by open() will be completed. You may query the connection status using this method:

[,java]
----
boolean isDisconnected()
boolean isConnecting()
boolean isConnected()
boolean isOpened()
----

==== Sending a UMessage
For both, publisher/subscriber or observer (notification) design patterns, a uE should use the `UPClient` to send messages to consumers using any method below:
The method below is used to send messages to consumers:

[,java]
----
UStatus send(UUri source, UPayload payload, UAttributes attributes)
UStatus send(UMessage message)
CompletionStage<UStatus> send(UMessage message)
----

==== Registering a UListener
In order to start receiving messages, a consumer should register a listener for a topic:
In order to start receiving messages, a consumer should register a listener:

[,java]
----
UStatus registerListener(UUri topic, UListener listener)
CompletionStage<UStatus> registerListener(UUri sourceFilter, UListener listener)
CompletionStage<UStatus> registerListener(UUri sourceFilter, UUri sinkFilter, UListener listener)
----
*For the publisher/subscriber design pattern*, the precondition for a callback is that the uE needs to subscribe to the topic AND register the listener.
A consumer can use the same listener for multiple filters, or register different listeners with the same filters.

Given the precondition, the callback will be triggered in any of the following cases:

. As soon as listener is registered if there is already a sent message for that topic that is in cache, OR
. Whenever the producer sends a new message for that topic

*For the notification design pattern*, the only precondition is that uE needs to register the listener.
Once the listener is registered the callback will be triggered whenever the notification message is sent by the producer.

A consumer can use the same listener for multiple topics, or register different listeners to the same topic.

To unregister a listener from receiving topic messages:

[,java]
----
UStatus unregisterListener(UUri topic, UListener listener)
----

To unregister a listener from all topics:

[,java]
----
UStatus unregisterListener(UListener listener)
----

==== Registering a URpcListener
A uE with a service role should register a listener for a particular method URI to be notified when request messages are sent against said method.

NOTE: Only one listener is allowed to be registered per a method URI.

[,java]
----
UStatus registerRpcListener(UUri methodUri, URpcListener listener)
----

To stop processing request messages for a specific method URI or all of the, a service uE should unregister the listener:

[,java]
----
UStatus unregisterRpcListener(UUri methodUri, URpcListener listener)
UStatus unregisterRpcListener(URpcListener listener)
----

==== Invoking an RPC Method
Code generators for uProtocol services defined in proto files primarily utilize the following method. However, clients also have the option to directly use it for invoking RPC methods.
To unregister a listener from receiving messages:

[,java]
----
CompletionStage<UPayload> invokeMethod(UUri methodUri, UPayload requestPayload, CallOptions options)
CompletionStage<UStatus> unregisterListener(UUri sourceFilter, UListener listener)
CompletionStage<UStatus> unregisterListener(UUri sourceFilter, UUri sinkFilter, UListener listener)
----

=== Building the Library
Expand Down
16 changes: 11 additions & 5 deletions gradle/config.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,17 @@
ext {
config = [
toolsVersion : '34.0.0',
sdkVersion : 31,
minSdkVersion : 31,
namespace : 'org.eclipse.uprotocol.client',
sdkVersion : 34,
minSdkVersion : 34,
namespace : 'org.eclipse.uprotocol.transport',
group : 'org.eclipse.uprotocol',
artifact : 'up-client-android-java',
version : '0.1.2',
artifact : 'up-transport-android-java',
version : '1.0.0',
jvm : [
version : [
java : JavaVersion.VERSION_17,
kotlin : "17",
]
],
]
}
19 changes: 13 additions & 6 deletions gradle/jacoco.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,19 @@ tasks.register('jacocoTestReport', JacocoReport) {
html.getRequired().set(true)
}
def buildDir = layout.buildDirectory.get()
executionData.from = ["${buildDir}/jacoco/testDebugUnitTest.exec"]
sourceDirectories.from = ["${projectDir}/src/main/java"]
classDirectories.from = fileTree(
dir: "${buildDir}/intermediates/javac/debug/classes/",
excludes: ['**/IU*', '**/BuildConfig.class']
)
def excludeClasses = [
'**/BuildConfig.class',
'**/IU*',
]
def javaClasses = fileTree(dir: "${buildDir}/intermediates/javac/debug/compileDebugJavaWithJavac/classes/", excludes: excludeClasses)
def kotlinClasses = fileTree(dir: "${buildDir}/tmp/kotlin-classes/debug/", excludes: excludeClasses)
getClassDirectories().setFrom(files([javaClasses, kotlinClasses]))
getSourceDirectories().setFrom(files([
"${projectDir}/src/main/java",
"${buildDir}/generated/source/kapt/debug/",
]))
getExecutionData().setFrom(files("${buildDir}/jacoco/testDebugUnitTest.exec"))

doLast {
println "Unit-test coverage report generated at folder: ${buildDir}/reports/jacoco/jacocoTestReport/"
}
Expand Down
17 changes: 9 additions & 8 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,15 @@
# SPDX-License-Identifier: Apache-2.0
#
[versions]
android = "8.2.+"
androidx-appcompat = "1.4.2"
androidx-espresso = "3.5.1"
androidx-junit = "1.1.5"
android = "8.5.+"
androidx-appcompat = "1.7.0"
androidx-espresso = "3.6.1"
androidx-junit = "1.2.1"
junit = "4.13.2"
mockito = "4.6.1"
robolectric = "4.7.3"
up-java = "0.1.9"
mockito = "5.5.0"
mockito-inline = "5.2.0"
robolectric = "4.12.1"
up-java = "2.0.0"

[libraries]
androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "androidx-appcompat" }
Expand All @@ -26,7 +27,7 @@ androidx-junit = { module = "androidx.test.ext:junit", version.ref = "androidx-j
junit = { module = "junit:junit", version.ref = "junit"}
mockito-android = { module = "org.mockito:mockito-android", version.ref = "mockito"}
mockito-core = { module = "org.mockito:mockito-core", version.ref = "mockito"}
mockito-inline = { module = "org.mockito:mockito-inline", version.ref = "mockito"}
mockito-inline = { module = "org.mockito:mockito-inline", version.ref = "mockito-inline"}
robolectric = { module = "org.robolectric:robolectric", version.ref = "robolectric"}
up-java = { module = "org.eclipse.uprotocol:up-java", version.ref = "up-java" }

Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
Expand Down
16 changes: 13 additions & 3 deletions library/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,23 @@ android {
consumerProguardFiles 'consumer-rules.pro'
}

signingConfigs {
platform {
storeFile file('certs/platform.keystore')
storePassword 'android'
keyAlias 'platform'
keyPassword 'android'
}
}

buildTypes {
debug {
signingConfig signingConfigs.platform
debuggable true
minifyEnabled false
}
release {
signingConfig signingConfigs.platform
minifyEnabled true
proguardFiles 'proguard-rules.pro'
}
Expand All @@ -48,8 +59,8 @@ android {
}

compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
sourceCompatibility config.jvm.version.java
targetCompatibility config.jvm.version.java
}

testNamespace "${config.namespace}.test"
Expand All @@ -75,7 +86,6 @@ android {

publishing {
singleVariant('release') {
withJavadocJar()
withSourcesJar()
}
}
Expand Down
Binary file added library/certs/platform.keystore
Binary file not shown.
4 changes: 2 additions & 2 deletions library/consumer-rules.pro
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@
-keep class * extends com.google.protobuf.** {*;}
-keep class * extends com.google.protobuf.**$** {*;}

-keep public class com.ultifi.core.** {
-keep public class org.eclipse.uprotocol.** {
public protected *;
<init>();
}

-keep public interface com.ultifi.core.** {
-keep public interface org.eclipse.uprotocol.** {
*;
}
3 changes: 3 additions & 0 deletions library/proguard-rules.pro
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@
RuntimeVisibleTypeAnnotations,
Signature

-keepclasseswithmembers class * {
@androidx.annotation.VisibleForTesting *;
}

# The support libraries contains references to newer platform versions.
# Don't warn about those in case this app is linking against an older
Expand Down
7 changes: 5 additions & 2 deletions library/src/androidTest/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,14 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<uses-permission android:name="uprotocol.permission.ACCESS_UBUS" />
<queries>
<package android:name="org.eclipse.uprotocol.example.service" />
</queries>

<application>
<meta-data
android:name="uprotocol.entity.name"
android:value="client.test" />
android:name="uprotocol.entity.id"
android:value="0x50" />
<meta-data
android:name="uprotocol.entity.version"
android:value="1" />
Expand Down
Loading

0 comments on commit 836444a

Please sign in to comment.