diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..acfb8bb
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,13 @@
+# https://editorconfig.org/
+root = true
+
+[*]
+charset = utf-8
+end_of_line = lf
+indent_size = 2
+indent_style = space
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[*.md]
+trim_trailing_whitespace = false
diff --git a/.github/workflows/ci_cd.yml b/.github/workflows/ci_cd.yml
index 9be5041..2d2a625 100644
--- a/.github/workflows/ci_cd.yml
+++ b/.github/workflows/ci_cd.yml
@@ -4,14 +4,14 @@ on:
# Push on main and release tags
push:
branches:
- - 'main'
+ - "main"
tags:
- - '[0-9]+.[0-9]+.[0-9]+'
+ - "[0-9]+.[0-9]+.[0-9]+"
# PR
pull_request:
branches:
- - 'main'
+ - "main"
# Manual trigger
workflow_dispatch:
@@ -21,7 +21,6 @@ concurrency:
cancel-in-progress: true
jobs:
-
build:
name: CI/CD
runs-on: ubuntu-latest
@@ -34,9 +33,9 @@ jobs:
id: java
uses: actions/setup-java@03ad4de0992f5dab5e18fcb136590ce7c4a0ac95 # v5.6.0
with:
- distribution: 'temurin'
- java-version: '17'
- cache: 'gradle'
+ distribution: "temurin"
+ java-version: "17"
+ cache: "gradle"
- name: Check if main repo
id: is_main_repo
@@ -45,6 +44,9 @@ jobs:
echo "value=true" >> $GITHUB_OUTPUT
fi
+ - name: Run Spotless check
+ run: ./gradlew spotlessCheck
+
- name: Run assemble
if: ${{ !steps.is_main_repo.outputs.value || github.event_name == 'pull_request' }}
run: |
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 4afe8ad..0fcb4b1 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -5,7 +5,7 @@ on:
workflow_dispatch:
inputs:
VERSION_INCREMENT:
- description: 'The version number part to increment (major.minor.patch)'
+ description: "The version number part to increment (major.minor.patch)"
default: Minor
type: choice
options:
@@ -14,32 +14,32 @@ on:
- Patch
required: false
VERSION_OVERRIDE:
- description: 'Version override (when not incrementing the previous version)'
+ description: "Version override (when not incrementing the previous version)"
type: string
required: false
-
permissions:
actions: write
contents: write
jobs:
-
build:
name: Release
runs-on: ubuntu-latest
steps:
-
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Set up JDK 17 and gradle cache
uses: actions/setup-java@03ad4de0992f5dab5e18fcb136590ce7c4a0ac95 # v5.6.0
with:
- distribution: 'temurin'
- java-version: '17'
- cache: 'gradle'
+ distribution: "temurin"
+ java-version: "17"
+ cache: "gradle"
+
+ - name: Run Spotless check
+ run: ./gradlew spotlessCheck
- name: Run release
id: release
diff --git a/GenericApp/app/build.gradle b/GenericApp/app/build.gradle
index 3057a48..768d91e 100644
--- a/GenericApp/app/build.gradle
+++ b/GenericApp/app/build.gradle
@@ -1,155 +1,155 @@
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
plugins {
- alias(libs.plugins.android.application)
- alias(libs.plugins.google.services)
- id 'maven-publish'
- id 'signing'
+ alias(libs.plugins.android.application)
+ alias(libs.plugins.google.services)
+ id 'maven-publish'
+ id 'signing'
}
android {
- defaultConfig {
- applicationId = "io.openremote.app"
- minSdk = 25
- compileSdk = 37
- targetSdk = 37
- versionCode = 47
- versionName = version
-
- testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
-
- resValue "string", "NOTIFICATION_CHANNEL_ID", applicationId + ".ORAppMessage"
- }
-
- if (project.hasProperty("keystoreFile")) {
- signingConfigs {
- release {
- keyAlias keystoreKeyAlias
- keyPassword keystoreKeyPassword
- storeFile file(keystoreFile)
- storePassword keystorePassword
- }
- }
+ defaultConfig {
+ applicationId = "io.openremote.app"
+ minSdk = 25
+ compileSdk = 37
+ targetSdk = 37
+ versionCode = 47
+ versionName = version
+
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+
+ resValue "string", "NOTIFICATION_CHANNEL_ID", applicationId + ".ORAppMessage"
+ }
+
+ if (project.hasProperty("keystoreFile")) {
+ signingConfigs {
+ release {
+ keyAlias keystoreKeyAlias
+ keyPassword keystoreKeyPassword
+ storeFile file(keystoreFile)
+ storePassword keystorePassword
+ }
}
-
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
- if (project.hasProperty("keystoreFile")) {
- signingConfig signingConfigs.release
- }
- }
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ if (project.hasProperty("keystoreFile")) {
+ signingConfig signingConfigs.release
+ }
}
+ }
- buildFeatures {
- viewBinding = true
- resValues = true
- }
+ buildFeatures {
+ viewBinding = true
+ resValues = true
+ }
- compileOptions {
- sourceCompatibility = JavaVersion.VERSION_17
- targetCompatibility = JavaVersion.VERSION_17
- }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+ }
- namespace = 'io.openremote.app'
+ namespace = 'io.openremote.app'
- publishing {
- singleVariant('release') {
- }
+ publishing {
+ singleVariant('release') {
}
+ }
}
kotlin {
- compilerOptions {
- jvmTarget.set(JvmTarget.JVM_17)
- }
+ compilerOptions {
+ jvmTarget.set(JvmTarget.JVM_17)
+ }
}
dependencies {
- implementation fileTree(dir: "libs", include: ["*.jar"])
- implementation libs.androidx.core.ktx
- implementation libs.androidx.appcompat
- implementation libs.androidx.constraintlayout
- implementation libs.androidx.preference.ktx
- implementation libs.play.services.location
- implementation libs.jackson.module.kotlin
- implementation platform(libs.firebase.bom)
- implementation libs.firebase.messaging
- implementation libs.material
- implementation project(':ORLib')
-
- // Unit testing framework
- testImplementation libs.junit
+ implementation fileTree(dir: "libs", include: ["*.jar"])
+ implementation libs.androidx.core.ktx
+ implementation libs.androidx.appcompat
+ implementation libs.androidx.constraintlayout
+ implementation libs.androidx.preference.ktx
+ implementation libs.play.services.location
+ implementation libs.jackson.module.kotlin
+ implementation platform(libs.firebase.bom)
+ implementation libs.firebase.messaging
+ implementation libs.material
+ implementation project(':ORLib')
+
+ // Unit testing framework
+ testImplementation libs.junit
}
tasks.register('sourcesJar', Jar) {
- from android.sourceSets.main.java.srcDirs
- archiveClassifier = 'sources'
+ from android.sourceSets.main.java.srcDirs
+ archiveClassifier = 'sources'
}
afterEvaluate {
- publishing {
- publications {
- release(MavenPublication) {
- from components.release
-
- artifact source: file('build/outputs/apk/release/app-release.apk')
- artifact sourcesJar
-
- group = "io.openremote"
- artifactId = "app"
-
- pom {
- name = 'OpenRemote Android Console'
- description = 'Provides the Android OpenRemote Console Application'
- url = 'https://github.com/openremote/console-android'
- licenses {
- license {
- name = 'GNU Affero General Public License v3.0'
- url = 'https://www.gnu.org/licenses/agpl-3.0.en.html'
- }
- }
- developers {
- developer {
- id = 'developers'
- name = 'Developers'
- email = 'developers@openremote.io'
- organization = 'OpenRemote'
- organizationUrl = 'https://openremote.io'
- }
- }
- scm {
- connection = 'scm:git:git://github.com/openremote/console-android.git'
- developerConnection = 'scm:git:ssh://github.com:openremote/console-android.git'
- url = 'https://github.com/openremote/console-android/tree/main'
- }
- }
+ publishing {
+ publications {
+ release(MavenPublication) {
+ from components.release
+
+ artifact source: file('build/outputs/apk/release/app-release.apk')
+ artifact sourcesJar
+
+ group = "io.openremote"
+ artifactId = "app"
+
+ pom {
+ name = 'OpenRemote Android Console'
+ description = 'Provides the Android OpenRemote Console Application'
+ url = 'https://github.com/openremote/console-android'
+ licenses {
+ license {
+ name = 'GNU Affero General Public License v3.0'
+ url = 'https://www.gnu.org/licenses/agpl-3.0.en.html'
}
- }
-
- repositories {
- maven {
- if (!version.endsWith('-LOCAL')) {
- credentials {
- username = findProperty("publishUsername")
- password = findProperty("publishPassword")
- }
- }
- url = version.endsWith('-LOCAL') ? layout.buildDirectory.dir('repo') : version.endsWith('-SNAPSHOT') ? findProperty("snapshotsRepoUrl") : findProperty("releasesRepoUrl")
+ }
+ developers {
+ developer {
+ id = 'developers'
+ name = 'Developers'
+ email = 'developers@openremote.io'
+ organization = 'OpenRemote'
+ organizationUrl = 'https://openremote.io'
}
+ }
+ scm {
+ connection = 'scm:git:git://github.com/openremote/console-android.git'
+ developerConnection = 'scm:git:ssh://github.com:openremote/console-android.git'
+ url = 'https://github.com/openremote/console-android/tree/main'
+ }
}
+ }
}
- signing {
- def signingKey = findProperty("signingKey")
- def signingPassword = findProperty("signingPassword")
- if (signingKey && signingPassword) {
- useInMemoryPgpKeys(signingKey, signingPassword)
- sign publishing.publications
- signReleasePublication.dependsOn(packageRelease)
+ repositories {
+ maven {
+ if (!version.endsWith('-LOCAL')) {
+ credentials {
+ username = findProperty("publishUsername")
+ password = findProperty("publishPassword")
+ }
}
+ url = version.endsWith('-LOCAL') ? layout.buildDirectory.dir('repo') : version.endsWith('-SNAPSHOT') ? findProperty("snapshotsRepoUrl") : findProperty("releasesRepoUrl")
+ }
+ }
+ }
+
+ signing {
+ def signingKey = findProperty("signingKey")
+ def signingPassword = findProperty("signingPassword")
+ if (signingKey && signingPassword) {
+ useInMemoryPgpKeys(signingKey, signingPassword)
+ sign publishing.publications
+ signReleasePublication.dependsOn(packageRelease)
}
+ }
- publishReleasePublicationToMavenLocal.dependsOn(packageRelease)
+ publishReleasePublicationToMavenLocal.dependsOn(packageRelease)
}
diff --git a/GenericApp/app/google-services.json b/GenericApp/app/google-services.json
index 75b2bc9..28a71ed 100644
--- a/GenericApp/app/google-services.json
+++ b/GenericApp/app/google-services.json
@@ -27,4 +27,4 @@
}
],
"configuration_version": "1"
-}
\ No newline at end of file
+}
diff --git a/GenericApp/app/proguard-rules.pro b/GenericApp/app/proguard-rules.pro
index 481bb43..f1b4245 100644
--- a/GenericApp/app/proguard-rules.pro
+++ b/GenericApp/app/proguard-rules.pro
@@ -18,4 +18,4 @@
# If you keep the line number information, uncomment this to
# hide the original source file name.
-#-renamesourcefileattribute SourceFile
\ No newline at end of file
+#-renamesourcefileattribute SourceFile
diff --git a/GenericApp/app/src/main/AndroidManifest.xml b/GenericApp/app/src/main/AndroidManifest.xml
index 34f5bd1..d96a605 100644
--- a/GenericApp/app/src/main/AndroidManifest.xml
+++ b/GenericApp/app/src/main/AndroidManifest.xml
@@ -1,88 +1,59 @@
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
diff --git a/GenericApp/app/src/main/java/io/openremote/app/model/ORAppInfo.kt b/GenericApp/app/src/main/java/io/openremote/app/model/ORAppInfo.kt
index 9737138..9cfd286 100644
--- a/GenericApp/app/src/main/java/io/openremote/app/model/ORAppInfo.kt
+++ b/GenericApp/app/src/main/java/io/openremote/app/model/ORAppInfo.kt
@@ -1,8 +1,26 @@
+/*
+ * Copyright 2026, OpenRemote Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ *
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
package io.openremote.app.model
data class ORAppInfo(
- val consoleAppIncompatible: Boolean,
- val realms: List,
- val providers: List,
- val description: String
+ val consoleAppIncompatible: Boolean,
+ val realms: List,
+ val providers: List,
+ val description: String,
)
diff --git a/GenericApp/app/src/main/java/io/openremote/app/model/ORConsoleConfig.kt b/GenericApp/app/src/main/java/io/openremote/app/model/ORConsoleConfig.kt
index ec320a9..be40cdc 100644
--- a/GenericApp/app/src/main/java/io/openremote/app/model/ORConsoleConfig.kt
+++ b/GenericApp/app/src/main/java/io/openremote/app/model/ORConsoleConfig.kt
@@ -1,9 +1,27 @@
+/*
+ * Copyright 2026, OpenRemote Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ *
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
package io.openremote.app.model
-data class ORConsoleConfig (
- val showAppTextInput: Boolean,
- val showRealmTextInput: Boolean,
- val app: String?,
- val allowedApps: List?,
- val apps: Map?
+data class ORConsoleConfig(
+ val showAppTextInput: Boolean,
+ val showRealmTextInput: Boolean,
+ val app: String?,
+ val allowedApps: List?,
+ val apps: Map?,
)
diff --git a/GenericApp/app/src/main/java/io/openremote/app/model/ProjectItem.kt b/GenericApp/app/src/main/java/io/openremote/app/model/ProjectItem.kt
index 943fe24..bce670f 100644
--- a/GenericApp/app/src/main/java/io/openremote/app/model/ProjectItem.kt
+++ b/GenericApp/app/src/main/java/io/openremote/app/model/ProjectItem.kt
@@ -1,8 +1,26 @@
+/*
+ * Copyright 2026, OpenRemote Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ *
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
package io.openremote.app.model
-data class ProjectItem (
- val host: String,
- val app: String,
- val realm: String?,
- val url: String
+data class ProjectItem(
+ val host: String,
+ val app: String,
+ val realm: String?,
+ val url: String,
)
diff --git a/GenericApp/app/src/main/java/io/openremote/app/network/ApiManager.kt b/GenericApp/app/src/main/java/io/openremote/app/network/ApiManager.kt
index 2032150..cc4460a 100644
--- a/GenericApp/app/src/main/java/io/openremote/app/network/ApiManager.kt
+++ b/GenericApp/app/src/main/java/io/openremote/app/network/ApiManager.kt
@@ -1,3 +1,21 @@
+/*
+ * Copyright 2026, OpenRemote Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ *
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
package io.openremote.app.network
import android.net.Uri
@@ -8,137 +26,141 @@ import io.openremote.app.model.ORAppInfo
import io.openremote.app.model.ORConsoleConfig
import java.net.HttpURLConnection
import java.net.URL
-import javax.net.ssl.HttpsURLConnection
import kotlin.concurrent.thread
-
typealias ResponseBlock = (statusCode: Int, model: T?, error: Throwable?) -> Unit
class ApiManager(private val baseUrl: String) {
- val mapper = jacksonObjectMapper()
-
- enum class HttpMethod {
- GET,
- POST,
- PUT,
+ val mapper = jacksonObjectMapper()
+
+ enum class HttpMethod {
+ GET,
+ POST,
+ PUT,
+ }
+
+ fun getApps(callback: ResponseBlock>?) {
+ get(arrayOf("apps"), callback)
+ }
+
+ fun getAppInfos(callback: ResponseBlock