Skip to content

Commit 373cb73

Browse files
Client integration
Signed-off-by: tobiasKaminsky <[email protected]>
1 parent 6e8260c commit 373cb73

File tree

23 files changed

+714
-2
lines changed

23 files changed

+714
-2
lines changed

.idea/codeStyles/Project.xml

Lines changed: 35 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

library/src/androidTest/java/com/owncloud/android/AbstractIT.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,8 +263,8 @@ public static File extractAsset(String fileName, Context context) throws IOExcep
263263

264264
@After
265265
public void after() {
266-
removeOnClient(client);
267-
removeOnClient(client2);
266+
// removeOnClient(client);
267+
// removeOnClient(client2);
268268
}
269269

270270
private void removeOnClient(OwnCloudClient client) {

library/src/androidTest/java/com/owncloud/android/GetCapabilitiesRemoteOperationIT.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import com.owncloud.android.lib.resources.status.NextcloudVersion;
2424
import com.owncloud.android.lib.resources.status.OCCapability;
2525
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
26+
import com.owncloud.android.lib.resources.status.Type;
2627

2728
import org.junit.Test;
2829

@@ -163,4 +164,17 @@ private void checkCapability(OCCapability capability, String userId) {
163164
assertTrue(capability.isWCFEnabled().isFalse());
164165
}
165166
}
167+
168+
@Test
169+
public void testClientIntegration() {
170+
// get capabilities
171+
RemoteOperationResult result = new GetCapabilitiesRemoteOperation().execute(nextcloudClient);
172+
assertTrue(result.isSuccess());
173+
assertNotNull(result.getSingleData());
174+
175+
OCCapability capability = (OCCapability) result.getSingleData();
176+
177+
assertEquals(5, capability.getClientIntegrationEndpoints(Type.CONTEXT_MENU, "").size());
178+
assertEquals(2, capability.getClientIntegrationEndpoints(Type.CREATE_NEW, "").size());
179+
}
166180
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
* Nextcloud Android Library
3+
*
4+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
5+
* SPDX-FileCopyrightText: 2025 Tobias Kaminsky <[email protected]>
6+
* SPDX-License-Identifier: MIT
7+
*/
8+
9+
package com.nextcloud.android.lib.resources.clientintegration
10+
11+
import com.google.gson.annotations.SerializedName
12+
13+
data class App(
14+
val version: Double,
15+
@SerializedName("context-menu")
16+
val contextMenu: List<Endpoint>,
17+
@SerializedName("create-new")
18+
val createNew: List<Endpoint>
19+
)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
* Nextcloud Android Library
3+
*
4+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
5+
* SPDX-FileCopyrightText: 2025 Tobias Kaminsky <[email protected]>
6+
* SPDX-License-Identifier: MIT
7+
*/
8+
9+
package com.nextcloud.android.lib.resources.clientintegration
10+
11+
import android.os.Parcelable
12+
import kotlinx.parcelize.Parcelize
13+
14+
@Parcelize
15+
data class Button(
16+
val label: String,
17+
val type: String
18+
) : Element,
19+
Parcelable
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*
2+
* Nextcloud Android Library
3+
*
4+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
5+
* SPDX-FileCopyrightText: 2025 Tobias Kaminsky <[email protected]>
6+
* SPDX-License-Identifier: MIT
7+
*/
8+
9+
package com.nextcloud.android.lib.resources.clientintegration
10+
11+
import android.os.Parcelable
12+
import kotlinx.parcelize.Parcelize
13+
14+
@Parcelize
15+
data class ClientIntegrationUI(
16+
val version: Double,
17+
val root: Layout
18+
) : Parcelable
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/*
2+
* Nextcloud Android Library
3+
*
4+
* SPDX-FileCopyrightText: 2025 Your Name <[email protected]>
5+
* SPDX-License-Identifier: MIT
6+
*/
7+
8+
package com.nextcloud.android.lib.resources.clientintegration
9+
10+
import android.os.Parcelable
11+
12+
interface Element : Parcelable
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Nextcloud Android Library
3+
*
4+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
5+
* SPDX-FileCopyrightText: 2025 Tobias Kaminsky <[email protected]>
6+
* SPDX-License-Identifier: MIT
7+
*/
8+
9+
package com.nextcloud.android.lib.resources.clientintegration
10+
11+
import com.google.gson.Gson
12+
import com.google.gson.JsonDeserializationContext
13+
import com.google.gson.JsonDeserializer
14+
import com.google.gson.JsonElement
15+
import com.google.gson.JsonParseException
16+
import com.google.gson.JsonSerializationContext
17+
import com.google.gson.JsonSerializer
18+
import java.lang.reflect.Type
19+
20+
class ElementTypeAdapter :
21+
JsonSerializer<Element>,
22+
JsonDeserializer<Element> {
23+
override fun serialize(
24+
src: Element,
25+
type: Type,
26+
context: JsonSerializationContext
27+
): JsonElement {
28+
// needs to be a new Gson instance, otherwise we end up in a loop
29+
val element = Gson().toJsonTree(src)
30+
element.asJsonObject.addProperty("element", src.javaClass.name)
31+
32+
return element
33+
}
34+
35+
@Throws(JsonParseException::class, ClassNotFoundException::class, Throwable::class)
36+
override fun deserialize(
37+
json: JsonElement,
38+
type: Type,
39+
context: JsonDeserializationContext
40+
): Element? {
41+
val jsonObject = json.asJsonObject
42+
val typeName = jsonObject.get("element").asString
43+
44+
try {
45+
val cls: Class<out Element> =
46+
when (typeName) {
47+
"Button" ->
48+
Class.forName("com.nextcloud.android.lib.resources.clientintegration.Button")
49+
as Class<out Element>
50+
51+
"Text" ->
52+
Class.forName("com.nextcloud.android.lib.resources.clientintegration.Text")
53+
as Class<out Element>
54+
55+
"Image" ->
56+
Class.forName("com.nextcloud.android.lib.resources.clientintegration.Image")
57+
as Class<out Element>
58+
59+
"URL" ->
60+
Class.forName("com.nextcloud.android.lib.resources.clientintegration.URL")
61+
as Class<out Element>
62+
63+
else -> return null
64+
}
65+
66+
return Gson().fromJson(json, cls)
67+
} catch (e: ClassNotFoundException) {
68+
throw JsonParseException(e)
69+
}
70+
}
71+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Nextcloud Android Library
3+
*
4+
* SPDX-FileCopyrightText: 2025 Your Name <[email protected]>
5+
* SPDX-License-Identifier: MIT
6+
*/
7+
8+
package com.nextcloud.android.lib.resources.clientintegration
9+
10+
import android.os.Parcelable
11+
import com.google.gson.annotations.SerializedName
12+
import com.owncloud.android.lib.resources.status.Method
13+
import kotlinx.parcelize.Parcelize
14+
15+
@Parcelize
16+
data class Endpoint(
17+
val name: String,
18+
val url: String,
19+
var method: Method?,
20+
@SerializedName("mimetype_filters")
21+
val mimetypeFilter: String?,
22+
val params: Map<String, String>?,
23+
val icon: String?,
24+
val filter: String?
25+
) : Parcelable
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* Nextcloud Android Library
3+
*
4+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
5+
* SPDX-FileCopyrightText: 2025 Tobias Kaminsky <[email protected]>
6+
* SPDX-License-Identifier: MIT
7+
*/
8+
package com.nextcloud.android.lib.resources.clientintegration
9+
10+
import com.google.gson.GsonBuilder
11+
import com.google.gson.JsonArray
12+
import com.google.gson.reflect.TypeToken
13+
import com.nextcloud.common.NextcloudClient
14+
import com.nextcloud.operations.GetMethod
15+
import com.owncloud.android.lib.common.operations.RemoteOperationResult
16+
import com.owncloud.android.lib.common.utils.Log_OC
17+
import com.owncloud.android.lib.ocs.ServerResponse
18+
import com.owncloud.android.lib.resources.OCSRemoteOperation
19+
import org.apache.commons.httpclient.HttpStatus
20+
21+
/**
22+
* Get client integration
23+
*/
24+
class GetClientIntegrationJsonOperation(
25+
val url: String
26+
) : OCSRemoteOperation<JsonArray>() {
27+
@Suppress("TooGenericExceptionCaught")
28+
override fun run(client: NextcloudClient): RemoteOperationResult<JsonArray> {
29+
var result: RemoteOperationResult<JsonArray>
30+
var getMethod: GetMethod? = null
31+
try {
32+
getMethod =
33+
GetMethod(
34+
client.baseUri.toString() + url + JSON_FORMAT,
35+
true
36+
)
37+
val status = client.execute(getMethod)
38+
if (status == HttpStatus.SC_OK) {
39+
val terms =
40+
getServerResponse(
41+
getMethod,
42+
object : TypeToken<ServerResponse<JsonArray>>() {}
43+
)?.ocs?.data
44+
45+
val json = parseResult(getMethod.getResponseBodyAsString())
46+
47+
if (terms != null) {
48+
result = RemoteOperationResult(true, getMethod)
49+
result.resultData = terms
50+
} else {
51+
result = RemoteOperationResult(false, getMethod)
52+
}
53+
} else {
54+
result = RemoteOperationResult(false, getMethod)
55+
}
56+
} catch (e: Exception) {
57+
result = RemoteOperationResult(e)
58+
Log_OC.e(
59+
TAG,
60+
"Get client integration failed: " + result.logMessage,
61+
result.exception
62+
)
63+
} finally {
64+
getMethod?.releaseConnection()
65+
}
66+
return result
67+
}
68+
69+
fun parseResult(response: String): ClientIntegrationUI {
70+
val gson =
71+
GsonBuilder()
72+
.registerTypeHierarchyAdapter(Element::class.java, ElementTypeAdapter())
73+
.create()
74+
75+
return gson.fromJson(response, ClientIntegrationUI::class.java)
76+
}
77+
78+
companion object {
79+
private val TAG = GetClientIntegrationJsonOperation::class.java.simpleName
80+
}
81+
}

0 commit comments

Comments
 (0)