Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Verified Commit aff82ab9 authored by Marvin W.'s avatar Marvin W. 🐿️
Browse files

Add service

parent 75d87e1d
Loading
Loading
Loading
Loading

service/build.gradle

0 → 100644
+73 −0
Original line number Diff line number Diff line
/*
 * SPDX-FileCopyrightText: 2019, 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'

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
    }
}

dependencies {
    implementation project(':api')
    implementation project(':client')
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"
}

afterEvaluate {
    publishing {
        publications {
            release(MavenPublication) {
                pom {
                    name = 'UnifiedNlp Service'
                    description = 'UnifiedNlp service library'
                    url = 'https://github.com/microg/UnifiedNlp'
                    licenses {
                        license {
                            name = 'The Apache Software License, Version 2.0'
                            url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
                        }
                    }
                    developers {
                        developer {
                            id = 'microg'
                            name = 'microG Team'
                        }
                        developer {
                            id = 'mar-v-in'
                            name = 'Marvin W.'
                        }
                    }
                    scm {
                        url = 'https://github.com/microg/UnifiedNlp'
                        connection = 'scm:git:https://github.com/microg/UnifiedNlp.git'
                        developerConnection = 'scm:git:ssh://github.com/microg/UnifiedNlp.git'
                    }
                }

                from components.release
            }
        }
    }
}
+45 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?><!--
  ~ Copyright (C) 2013-2019 microG Project Team
  ~
  ~ Licensed under the Apache License, Version 2.0 (the "License");
  ~ you may not use this file except in compliance with the License.
  ~ You may obtain a copy of the License at
  ~
  ~     http://www.apache.org/licenses/LICENSE-2.0
  ~
  ~ Unless required by applicable law or agreed to in writing, software
  ~ distributed under the License is distributed on an "AS IS" BASIS,
  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  ~ See the License for the specific language governing permissions and
  ~ limitations under the License.
  -->

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="org.microg.nlp.service">

    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

    <application>
        <service
            android:name=".UnifiedLocationServiceEntryPoint"
            android:exported="true"
            android:process=":ulocservice"
            tools:ignore="ExportedService">
            <intent-filter>
                <action android:name="org.microg.nlp.service.UnifiedLocationService" />
            </intent-filter>
        </service>

        <receiver android:name=".PackageChangedReceiver">
            <intent-filter>
                <action android:name="android.intent.action.PACKAGE_CHANGED" />
                <action android:name="android.intent.action.PACKAGE_REMOVED" />
                <action android:name="android.intent.action.PACKAGE_REPLACED" />
                <action android:name="android.intent.action.PACKAGE_RESTARTED" />

                <data android:scheme="package" />
            </intent-filter>
        </receiver>
    </application>
</manifest>
+124 −0
Original line number Diff line number Diff line
/*
 * SPDX-FileCopyrightText: 2014, microG Project Team
 * SPDX-License-Identifier: Apache-2.0
 */

package org.microg.nlp.service

import android.annotation.SuppressLint
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.content.pm.Signature
import android.os.IBinder
import android.os.RemoteException
import android.util.Log

import java.security.MessageDigest
import java.security.NoSuchAlgorithmException

fun <T> Array<out T>?.isNotNullOrEmpty(): Boolean {
    return this != null && this.isNotEmpty()
}

abstract class AbstractBackendHelper(private val TAG: String, private val context: Context, val serviceIntent: Intent, val signatureDigest: String?) : ServiceConnection {
    private var bound: Boolean = false

    protected abstract fun close()

    protected abstract fun hasBackend(): Boolean

    override fun onServiceConnected(name: ComponentName, service: IBinder) {
        bound = true
        Log.d(TAG, "Bound to: $name")
    }

    override fun onServiceDisconnected(name: ComponentName) {
        bound = false
        Log.d(TAG, "Unbound from: $name")
    }

    fun unbind() {
        if (bound) {
            if (hasBackend()) {
                try {
                    close()
                } catch (e: Exception) {
                    Log.w(TAG, e)
                }

            }
            try {
                Log.d(TAG, "Unbinding from: $serviceIntent")
                context.unbindService(this)
            } catch (e: Exception) {
                Log.w(TAG, e)
            }

            bound = false
        }
    }

    fun bind() {
        if (!bound) {
            Log.d(TAG, "Binding to: $serviceIntent sig: $signatureDigest")
            if (signatureDigest == null) {
                Log.w(TAG, "No signature digest provided. Aborting.")
                return
            }
            if (serviceIntent.getPackage() == null) {
                Log.w(TAG, "Intent is not properly resolved, can't verify signature. Aborting.")
                return
            }
            if (signatureDigest != firstSignatureDigest(context, serviceIntent.getPackage())) {
                Log.w(TAG, "Target signature does not match selected package (" + signatureDigest + " = " + firstSignatureDigest(context, serviceIntent.getPackage()) + "). Aborting.")
                return
            }
            try {
                context.bindService(serviceIntent, this, Context.BIND_AUTO_CREATE)
            } catch (e: Exception) {
                Log.w(TAG, e)
            }

        }
    }

    companion object {
        @Suppress("DEPRECATION")
        @SuppressLint("PackageManagerGetSignatures")
        fun firstSignatureDigest(context: Context, packageName: String?): String? {
            val packageManager = context.packageManager
            val info: PackageInfo?
            try {
                info = packageManager.getPackageInfo(packageName!!, PackageManager.GET_SIGNATURES)
            } catch (e: PackageManager.NameNotFoundException) {
                return null
            }

            if (info?.signatures.isNotNullOrEmpty()) {
                for (sig in info.signatures) {
                    sha256sum(sig.toByteArray())?.let { return it }
                }
            }
            return null
        }

        private fun sha256sum(bytes: ByteArray): String? {
            try {
                val md = MessageDigest.getInstance("SHA-256")
                val digest = md.digest(bytes)
                val sb = StringBuilder(2 * digest.size)
                for (b in digest) {
                    sb.append(String.format("%02x", b))
                }
                return sb.toString()
            } catch (e: NoSuchAlgorithmException) {
                return null
            }
        }
    }

}
+86 −0
Original line number Diff line number Diff line
/*
 * SPDX-FileCopyrightText: 2014, microG Project Team
 * SPDX-License-Identifier: Apache-2.0
 */

package org.microg.nlp.service

import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.location.Address
import android.os.IBinder
import android.os.RemoteException
import android.util.Log
import org.microg.nlp.api.GeocoderBackend

class GeocodeBackendHelper(context: Context, serviceIntent: Intent, signatureDigest: String?) : AbstractBackendHelper(TAG, context, serviceIntent, signatureDigest) {
    private var backend: GeocoderBackend? = null

    fun getFromLocation(latitude: Double, longitude: Double, maxResults: Int,
                        locale: String): List<Address> {
        if (backend == null) {
            Log.d(TAG, "Not (yet) bound.")
            return emptyList()
        }
        try {
            return backend!!.getFromLocation(latitude, longitude, maxResults, locale) ?: emptyList()
        } catch (e: Exception) {
            Log.w(TAG, e)
            unbind()
            return emptyList()
        }

    }

    fun getFromLocationName(locationName: String, maxResults: Int,
                            lowerLeftLatitude: Double, lowerLeftLongitude: Double,
                            upperRightLatitude: Double, upperRightLongitude: Double,
                            locale: String): List<Address> {
        if (backend == null) {
            Log.d(TAG, "Not (yet) bound.")
            return emptyList()
        }
        try {
            return backend!!.getFromLocationName(locationName, maxResults, lowerLeftLatitude,
                    lowerLeftLongitude, upperRightLatitude, upperRightLongitude, locale) ?: emptyList()
        } catch (e: Exception) {
            Log.w(TAG, e)
            unbind()
            return emptyList()
        }

    }

    override fun onServiceConnected(name: ComponentName, service: IBinder) {
        super.onServiceConnected(name, service)
        backend = GeocoderBackend.Stub.asInterface(service)
        if (backend != null) {
            try {
                backend!!.open()
            } catch (e: Exception) {
                Log.w(TAG, e)
                unbind()
            }

        }
    }

    override fun onServiceDisconnected(name: ComponentName) {
        super.onServiceDisconnected(name)
        backend = null
    }

    @Throws(RemoteException::class)
    public override fun close() {
        backend!!.close()
    }

    public override fun hasBackend(): Boolean {
        return backend != null
    }

    companion object {
        private val TAG = "UnifiedGeocoder"
    }
}
 No newline at end of file
+73 −0
Original line number Diff line number Diff line
/*
 * SPDX-FileCopyrightText: 2014, microG Project Team
 * SPDX-License-Identifier: Apache-2.0
 */

package org.microg.nlp.service

import android.content.Context
import android.content.Intent
import android.location.Address
import org.microg.nlp.api.Constants.ACTION_GEOCODER_BACKEND
import java.util.ArrayList

class GeocodeFuser(private val context: Context) {
    private val backendHelpers = ArrayList<GeocodeBackendHelper>()

    init {
        reset()
    }

    fun reset() {
        unbind()
        backendHelpers.clear()
        for (backend in Preferences(context).geocoderBackends) {
            val parts = backend.split("/".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
            if (parts.size >= 2) {
                val intent = Intent(ACTION_GEOCODER_BACKEND)
                intent.setPackage(parts[0])
                intent.setClassName(parts[0], parts[1])
                backendHelpers.add(GeocodeBackendHelper(context, intent, if (parts.size >= 3) parts[2] else null))
            }
        }
    }

    fun bind() {
        for (backendHelper in backendHelpers) {
            backendHelper.bind()
        }
    }

    fun unbind() {
        for (backendHelper in backendHelpers) {
            backendHelper.unbind()
        }
    }

    fun destroy() {
        unbind()
        backendHelpers.clear()
    }

    fun getFromLocation(latitude: Double, longitude: Double, maxResults: Int, locale: String): List<Address>? {
        if (backendHelpers.isEmpty())
            return null
        val result = ArrayList<Address>()
        for (backendHelper in backendHelpers) {
            val backendResult = backendHelper.getFromLocation(latitude, longitude, maxResults, locale)
            result.addAll(backendResult)
        }
        return result
    }

    fun getFromLocationName(locationName: String, maxResults: Int, lowerLeftLatitude: Double, lowerLeftLongitude: Double, upperRightLatitude: Double, upperRightLongitude: Double, locale: String): List<Address>? {
        if (backendHelpers.isEmpty())
            return null
        val result = ArrayList<Address>()
        for (backendHelper in backendHelpers) {
            val backendResult = backendHelper.getFromLocationName(locationName, maxResults, lowerLeftLatitude, lowerLeftLongitude, upperRightLatitude, upperRightLongitude, locale)
            result.addAll(backendResult)
        }
        return result
    }
}
Loading