diff --git a/play-services-droidguard-api/build.gradle b/play-services-droidguard-api/build.gradle
new file mode 100644
index 00000000..41829087
--- /dev/null
+++ b/play-services-droidguard-api/build.gradle
@@ -0,0 +1,35 @@
+/*
+ * SPDX-FileCopyrightText: 2020, microG Project Team
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+apply plugin: 'com.android.library'
+apply plugin: 'maven-publish'
+apply plugin: 'signing'
+
+android {
+ compileSdkVersion androidCompileSdk
+ buildToolsVersion "$androidBuildVersionTools"
+
+ defaultConfig {
+ versionName version
+ minSdkVersion androidMinSdk
+ targetSdkVersion androidTargetSdk
+ }
+
+ compileOptions {
+ sourceCompatibility = 1.8
+ targetCompatibility = 1.8
+ }
+}
+
+apply from: '../gradle/publish-android.gradle'
+
+description = 'microG API for play-services-droidguard'
+
+dependencies {
+ api project(':play-services-basement')
+ api project(':play-services-base-api')
+
+ implementation "androidx.annotation:annotation:$annotationVersion"
+}
diff --git a/play-services-droidguard-api/src/main/AndroidManifest.xml b/play-services-droidguard-api/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..30563293
--- /dev/null
+++ b/play-services-droidguard-api/src/main/AndroidManifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/play-services-droidguard-api/src/main/aidl/com/google/android/gms/droidguard/internal/DroidGuardInitReply.aidl b/play-services-droidguard-api/src/main/aidl/com/google/android/gms/droidguard/internal/DroidGuardInitReply.aidl
new file mode 100644
index 00000000..48cd159f
--- /dev/null
+++ b/play-services-droidguard-api/src/main/aidl/com/google/android/gms/droidguard/internal/DroidGuardInitReply.aidl
@@ -0,0 +1,3 @@
+package com.google.android.gms.droidguard.internal;
+
+parcelable DroidGuardInitReply;
diff --git a/play-services-droidguard-api/src/main/aidl/com/google/android/gms/droidguard/internal/DroidGuardResultsRequest.aidl b/play-services-droidguard-api/src/main/aidl/com/google/android/gms/droidguard/internal/DroidGuardResultsRequest.aidl
new file mode 100644
index 00000000..9fff3a8d
--- /dev/null
+++ b/play-services-droidguard-api/src/main/aidl/com/google/android/gms/droidguard/internal/DroidGuardResultsRequest.aidl
@@ -0,0 +1,3 @@
+package com.google.android.gms.droidguard.internal;
+
+parcelable DroidGuardResultsRequest;
diff --git a/play-services-droidguard-api/src/main/aidl/com/google/android/gms/droidguard/internal/IDroidGuardCallbacks.aidl b/play-services-droidguard-api/src/main/aidl/com/google/android/gms/droidguard/internal/IDroidGuardCallbacks.aidl
new file mode 100644
index 00000000..7e4aa680
--- /dev/null
+++ b/play-services-droidguard-api/src/main/aidl/com/google/android/gms/droidguard/internal/IDroidGuardCallbacks.aidl
@@ -0,0 +1,5 @@
+package com.google.android.gms.droidguard.internal;
+
+interface IDroidGuardCallbacks {
+ void onResult(in byte[] res);
+}
diff --git a/play-services-droidguard-api/src/main/aidl/com/google/android/gms/droidguard/internal/IDroidGuardHandle.aidl b/play-services-droidguard-api/src/main/aidl/com/google/android/gms/droidguard/internal/IDroidGuardHandle.aidl
new file mode 100644
index 00000000..649f2fd8
--- /dev/null
+++ b/play-services-droidguard-api/src/main/aidl/com/google/android/gms/droidguard/internal/IDroidGuardHandle.aidl
@@ -0,0 +1,13 @@
+package com.google.android.gms.droidguard.internal;
+
+import com.google.android.gms.droidguard.internal.DroidGuardInitReply;
+import com.google.android.gms.droidguard.internal.DroidGuardResultsRequest;
+
+interface IDroidGuardHandle {
+ void init(String flow) = 0;
+ DroidGuardInitReply initWithRequest(String flow, in DroidGuardResultsRequest request) = 4;
+
+ byte[] guard(in Map map) = 1;
+
+ void close() = 2;
+}
diff --git a/play-services-droidguard-api/src/main/aidl/com/google/android/gms/droidguard/internal/IDroidGuardService.aidl b/play-services-droidguard-api/src/main/aidl/com/google/android/gms/droidguard/internal/IDroidGuardService.aidl
new file mode 100644
index 00000000..2e604453
--- /dev/null
+++ b/play-services-droidguard-api/src/main/aidl/com/google/android/gms/droidguard/internal/IDroidGuardService.aidl
@@ -0,0 +1,14 @@
+package com.google.android.gms.droidguard.internal;
+
+import com.google.android.gms.droidguard.internal.IDroidGuardCallbacks;
+import com.google.android.gms.droidguard.internal.IDroidGuardHandle;
+import com.google.android.gms.droidguard.internal.DroidGuardResultsRequest;
+
+interface IDroidGuardService {
+ void guard(IDroidGuardCallbacks callbacks, String flow, in Map map) = 0;
+ void guardWithRequest(IDroidGuardCallbacks callbacks, String flow, in Map map, in DroidGuardResultsRequest request) = 3;
+
+ IDroidGuardHandle getHandle() = 1;
+
+ int getClientTimeoutMillis() = 2;
+}
diff --git a/play-services-droidguard-api/src/main/java/com/google/android/gms/droidguard/internal/DroidGuardInitReply.java b/play-services-droidguard-api/src/main/java/com/google/android/gms/droidguard/internal/DroidGuardInitReply.java
new file mode 100644
index 00000000..02b93b0d
--- /dev/null
+++ b/play-services-droidguard-api/src/main/java/com/google/android/gms/droidguard/internal/DroidGuardInitReply.java
@@ -0,0 +1,48 @@
+/*
+ * SPDX-FileCopyrightText: 2020, microG Project Team
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package com.google.android.gms.droidguard.internal;
+
+import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
+import android.os.Parcelable;
+
+public class DroidGuardInitReply implements Parcelable {
+ public ParcelFileDescriptor pfd;
+ public Parcelable object;
+
+ public DroidGuardInitReply(ParcelFileDescriptor pfd, Parcelable object) {
+ this.pfd = pfd;
+ this.object = object;
+ }
+
+ @Override
+ public int describeContents() {
+ return (pfd != null ? Parcelable.CONTENTS_FILE_DESCRIPTOR : 0) | (object != null ? object.describeContents() : 0);
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelable(pfd, flags);
+ dest.writeParcelable(object, flags);
+ }
+
+ public final static Creator CREATOR = new Creator() {
+ @Override
+ public DroidGuardInitReply createFromParcel(Parcel source) {
+ ParcelFileDescriptor pfd = source.readParcelable(ParcelFileDescriptor.class.getClassLoader());
+ Parcelable object = source.readParcelable(getClass().getClassLoader());
+ if (pfd != null && object != null) {
+ return new DroidGuardInitReply(pfd, object);
+ }
+ return null;
+ }
+
+ @Override
+ public DroidGuardInitReply[] newArray(int size) {
+ return new DroidGuardInitReply[size];
+ }
+ };
+}
diff --git a/play-services-droidguard-api/src/main/java/com/google/android/gms/droidguard/internal/DroidGuardResultsRequest.java b/play-services-droidguard-api/src/main/java/com/google/android/gms/droidguard/internal/DroidGuardResultsRequest.java
new file mode 100644
index 00000000..162a6bfc
--- /dev/null
+++ b/play-services-droidguard-api/src/main/java/com/google/android/gms/droidguard/internal/DroidGuardResultsRequest.java
@@ -0,0 +1,93 @@
+/*
+ * SPDX-FileCopyrightText: 2020, microG Project Team
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package com.google.android.gms.droidguard.internal;
+
+import android.net.Network;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+
+import androidx.annotation.RequiresApi;
+
+import org.microg.gms.common.Constants;
+import org.microg.safeparcel.AutoSafeParcelable;
+
+public class DroidGuardResultsRequest extends AutoSafeParcelable {
+ private static final String KEY_APP_ARCHITECTURE = "appArchitecture";
+ private static final String KEY_CLIENT_VERSION = "clientVersion";
+ private static final String KEY_FD = "fd";
+ private static final String KEY_NETWORK_TO_USE = "networkToUse";
+ private static final String KEY_TIMEOUT_MS = "timeoutMs";
+ public static final String KEY_OPEN_HANDLES = "openHandles";
+
+ @Field(2)
+ public Bundle bundle;
+
+ public DroidGuardResultsRequest() {
+ bundle = new Bundle();
+ String arch;
+ try {
+ arch = System.getProperty("os.arch");
+ } catch (Exception ignored) {
+ arch = "?";
+ }
+ bundle.putString(KEY_APP_ARCHITECTURE, arch);
+ setClientVersion(Constants.GMS_VERSION_CODE);
+ }
+
+ public String getAppArchitecture() {
+ return bundle.getString(KEY_APP_ARCHITECTURE);
+ }
+
+ public int getTimeoutMillis() {
+ return bundle.getInt(KEY_TIMEOUT_MS, 60000);
+ }
+
+ public DroidGuardResultsRequest setTimeoutMillis(int millis) {
+ bundle.putInt(KEY_TIMEOUT_MS, millis);
+ return this;
+ }
+
+ public int getClientVersion() {
+ return bundle.getInt(KEY_CLIENT_VERSION);
+ }
+
+ public DroidGuardResultsRequest setClientVersion(int clientVersion) {
+ bundle.putInt(KEY_CLIENT_VERSION, clientVersion);
+ return this;
+ }
+
+ public ParcelFileDescriptor getFd() {
+ return bundle.getParcelable(KEY_FD);
+ }
+
+ public DroidGuardResultsRequest setFd(ParcelFileDescriptor fd) {
+ bundle.putParcelable(KEY_FD, fd);
+ return this;
+ }
+
+ public int getOpenHandles() {
+ return bundle.getInt(KEY_OPEN_HANDLES);
+ }
+
+ public DroidGuardResultsRequest setOpenHandles(int openHandles) {
+ bundle.putInt(KEY_OPEN_HANDLES, openHandles);
+ return this;
+ }
+
+ @RequiresApi(api = 21)
+ public Network getNetworkToUse() {
+ return bundle.getParcelable(KEY_NETWORK_TO_USE);
+ }
+
+ @RequiresApi(api = 21)
+ public DroidGuardResultsRequest setNetworkToUse(Network networkToUse) {
+ bundle.putParcelable(KEY_NETWORK_TO_USE, networkToUse);
+ return this;
+ }
+
+ public static final Creator CREATOR = new AutoCreator<>(DroidGuardResultsRequest.class);
+}
diff --git a/play-services-droidguard/build.gradle b/play-services-droidguard/build.gradle
new file mode 100644
index 00000000..a473f2d5
--- /dev/null
+++ b/play-services-droidguard/build.gradle
@@ -0,0 +1,42 @@
+/*
+ * SPDX-FileCopyrightText: 2020, microG Project Team
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+apply plugin: 'com.android.library'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-android-extensions'
+apply plugin: 'maven-publish'
+apply plugin: 'signing'
+
+android {
+ compileSdkVersion androidCompileSdk
+ buildToolsVersion "$androidBuildVersionTools"
+
+ defaultConfig {
+ versionName version
+ minSdkVersion androidMinSdk
+ targetSdkVersion androidTargetSdk
+ }
+
+ sourceSets {
+ main.java.srcDirs += 'src/main/kotlin'
+ }
+
+ compileOptions {
+ sourceCompatibility = 1.8
+ targetCompatibility = 1.8
+ }
+}
+
+apply from: '../gradle/publish-android.gradle'
+
+description = 'microG implementation of play-services-droidguard'
+
+dependencies {
+ api project(':play-services-base')
+ api project(':play-services-droidguard-api')
+
+ implementation "androidx.annotation:annotation:$annotationVersion"
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"
+}
diff --git a/play-services-droidguard/src/main/AndroidManifest.xml b/play-services-droidguard/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..4d4b7873
--- /dev/null
+++ b/play-services-droidguard/src/main/AndroidManifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/play-services-droidguard/src/main/kotlin/org/microg/gms/droidguard/DroidGuardApiClient.kt b/play-services-droidguard/src/main/kotlin/org/microg/gms/droidguard/DroidGuardApiClient.kt
new file mode 100644
index 00000000..a9aa7a85
--- /dev/null
+++ b/play-services-droidguard/src/main/kotlin/org/microg/gms/droidguard/DroidGuardApiClient.kt
@@ -0,0 +1,25 @@
+/*
+ * SPDX-FileCopyrightText: 2020, microG Project Team
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.microg.gms.droidguard
+
+import android.content.Context
+import android.os.IBinder
+import com.google.android.gms.droidguard.internal.IDroidGuardHandle
+import com.google.android.gms.droidguard.internal.IDroidGuardService
+import org.microg.gms.common.GmsClient
+import org.microg.gms.common.GmsService
+import org.microg.gms.common.api.ConnectionCallbacks
+import org.microg.gms.common.api.OnConnectionFailedListener
+
+class DroidGuardApiClient(context: Context, connectionCallbacks: ConnectionCallbacks, onConnectionFailedListener: OnConnectionFailedListener) : GmsClient(context, connectionCallbacks, onConnectionFailedListener, GmsService.DROIDGUARD.ACTION) {
+ init {
+ serviceId = GmsService.DROIDGUARD.SERVICE_ID
+ }
+
+ override fun interfaceFromBinder(binder: IBinder): IDroidGuardService = IDroidGuardService.Stub.asInterface(binder)
+
+ fun getHandle() = serviceInterface.handle
+}
diff --git a/play-services-droidguard/src/main/kotlin/org/microg/gms/droidguard/DroidGuardClient.kt b/play-services-droidguard/src/main/kotlin/org/microg/gms/droidguard/DroidGuardClient.kt
new file mode 100644
index 00000000..adcaa45b
--- /dev/null
+++ b/play-services-droidguard/src/main/kotlin/org/microg/gms/droidguard/DroidGuardClient.kt
@@ -0,0 +1,13 @@
+/*
+ * SPDX-FileCopyrightText: 2020, microG Project Team
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.microg.gms.droidguard
+
+import com.google.android.gms.droidguard.internal.IDroidGuardHandle
+import com.google.android.gms.tasks.Task
+
+interface DroidGuardClient {
+ fun getHandle(): Task
+}
diff --git a/play-services-droidguard/src/main/kotlin/org/microg/gms/droidguard/DroidGuardClientImpl.kt b/play-services-droidguard/src/main/kotlin/org/microg/gms/droidguard/DroidGuardClientImpl.kt
new file mode 100644
index 00000000..49f3fc63
--- /dev/null
+++ b/play-services-droidguard/src/main/kotlin/org/microg/gms/droidguard/DroidGuardClientImpl.kt
@@ -0,0 +1,33 @@
+/*
+ * SPDX-FileCopyrightText: 2020, microG Project Team
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.microg.gms.droidguard
+
+import android.content.Context
+import android.os.Looper
+import com.google.android.gms.common.api.Api
+import com.google.android.gms.common.api.Api.ApiOptions.NoOptions
+import com.google.android.gms.common.api.GoogleApi
+import com.google.android.gms.tasks.Task
+import org.microg.gms.common.api.ApiClientBuilder
+import org.microg.gms.common.api.ApiClientSettings
+import org.microg.gms.common.api.ConnectionCallbacks
+import org.microg.gms.common.api.OnConnectionFailedListener
+
+class DroidGuardClientImpl(context: Context) : GoogleApi(context, API), DroidGuardClient {
+ companion object {
+ private val API = Api(ApiClientBuilder { _: NoOptions?, context: Context, _: Looper?, _: ApiClientSettings?, callbacks: ConnectionCallbacks, connectionFailedListener: OnConnectionFailedListener -> DroidGuardApiClient(context, callbacks, connectionFailedListener) })
+ }
+
+ override fun getHandle(): Task {
+ return scheduleTask { client: DroidGuardApiClient, completionSource ->
+ try {
+ completionSource.setResult(DroidGuardHandle(client.getHandle()))
+ } catch (e: Exception) {
+ completionSource.setException(e)
+ }
+ }
+ }
+}
diff --git a/play-services-droidguard/src/main/kotlin/org/microg/gms/droidguard/DroidGuardHandle.kt b/play-services-droidguard/src/main/kotlin/org/microg/gms/droidguard/DroidGuardHandle.kt
new file mode 100644
index 00000000..07e4fd39
--- /dev/null
+++ b/play-services-droidguard/src/main/kotlin/org/microg/gms/droidguard/DroidGuardHandle.kt
@@ -0,0 +1,54 @@
+/*
+ * SPDX-FileCopyrightText: 2020, microG Project Team
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package org.microg.gms.droidguard
+
+import com.google.android.gms.droidguard.internal.DroidGuardResultsRequest
+import com.google.android.gms.droidguard.internal.IDroidGuardHandle
+
+class DroidGuardHandle(private val handle: IDroidGuardHandle) {
+ private var state = 0
+
+ fun init(flow: String) {
+ if (state != 0) throw IllegalStateException("init() already called")
+ try {
+ handle.initWithRequest(flow, DroidGuardResultsRequest().setOpenHandles(openHandles++))
+ state = 1
+ } catch (e: Exception) {
+ state = -1
+ throw e
+ }
+ }
+
+ fun guard(map: Map): ByteArray {
+ if (state != 1) throw IllegalStateException("init() must be called before guard()")
+ try {
+ return handle.guard(map)
+ } catch (e: Exception) {
+ state = -1
+ throw e
+ }
+ }
+
+ fun close() {
+ if (state != 1) throw IllegalStateException("init() must be called before close()")
+ try {
+ handle.close()
+ openHandles--
+ state = 2
+ } catch (e: Exception) {
+ state = -1
+ throw e
+ }
+ }
+
+ fun finalize() {
+ if (state == 1) close()
+ }
+
+ companion object {
+ private var openHandles = 0
+ }
+}
diff --git a/settings.gradle b/settings.gradle
index 1ed21081..cdbee860 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -6,6 +6,7 @@ include ':play-services-appinvite-api'
include ':play-services-base-api'
include ':play-services-cast-api'
include ':play-services-cast-framework-api'
+include ':play-services-droidguard-api'
include ':play-services-iid-api'
include ':play-services-location-api'
include ':play-services-nearby-api'
@@ -41,6 +42,7 @@ include ':play-services-core'
include ':play-services-base'
include ':play-services-cast'
+include ':play-services-droidguard'
include ':play-services-gcm'
include ':play-services-iid'
include ':play-services-location'