Repo Created

This commit is contained in:
Fr4nz D13trich 2025-11-15 17:44:12 +01:00
parent eb305e2886
commit a8c22c65db
4784 changed files with 329907 additions and 2 deletions

View file

@ -0,0 +1,43 @@
/*
* SPDX-FileCopyrightText: 2022 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
apply plugin: 'com.android.library'
apply plugin: 'maven-publish'
apply plugin: 'signing'
android {
namespace "com.google.android.gms.maps"
compileSdkVersion androidCompileSdk
buildToolsVersion "$androidBuildVersionTools"
buildFeatures {
aidl = true
}
defaultConfig {
versionName version
minSdkVersion androidMinSdk
targetSdkVersion androidTargetSdk
}
compileOptions {
sourceCompatibility = 1.8
targetCompatibility = 1.8
}
}
apply from: '../gradle/publish-android.gradle'
description = 'microG implementation of play-services-maps'
dependencies {
// Dependencies from play-services-maps:18.1.0
api "androidx.fragment:fragment:1.0.0"
api project(":play-services-base")
api project(":play-services-basement")
annotationProcessor project(":safe-parcel-processor")
}

View file

@ -0,0 +1,61 @@
/*
* SPDX-FileCopyrightText: 2023 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
dependencies {
implementation project(':play-services-base-core')
implementation project(':play-services-maps')
implementation 'com.huawei.hms:maps:6.9.0.300'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"
}
android {
namespace "org.microg.gms.maps.hms"
compileSdkVersion androidCompileSdk
buildToolsVersion "$androidBuildVersionTools"
defaultConfig {
versionName version
minSdkVersion androidMinSdk
targetSdkVersion androidTargetSdk
buildConfigField "String", "HMSMAP_KEY", "\"${localProperties.getProperty("hmsmap.key", "")}\""
ndk {
abiFilters "armeabi", "armeabi-v7a", "arm64-v8a"
}
}
buildFeatures {
buildConfig = true
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
lintOptions {
disable 'GradleCompatible'
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = 1.8
}
}

View file

@ -0,0 +1,9 @@
-ignorewarnings
-keepattributes *Annotation*
-keepattributes Exceptions
-keepattributes InnerClasses
-keepattributes Signature
-keepattributes SourceFile,LineNumberTable
-keep class com.huawei.hianalytics.**{*;}
-keep class com.huawei.updatesdk.**{*;}
-keep class com.huawei.hms.**{*;}

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-sdk tools:overrideLibrary="com.huawei.hms.maps,com.huawei.android.hms.base,com.huawei.hms.feature.dynamic,com.huawei.hms.base.availableupdate,com.huawei.hms.stats,com.huawei.hms.base.ui,com.huawei.hms.base.device,com.huawei.hms.log,com.huawei.hmf.tasks,com.huawei.hms.framework.network.grs,com.huawei.hms.hatool,com.huawei.hms.framework.network.frameworkcompat,com.huawei.hms.framework.common" />
<application />
</manifest>

View file

@ -0,0 +1 @@
agconnect-services.json

View file

@ -0,0 +1,14 @@
/*
* SPDX-FileCopyrightText: 2023 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.dynamite.descriptors.com.google.android.gms.maps_dynamite;
import androidx.annotation.Keep;
@Keep
public class ModuleDescriptor {
public static final String MODULE_ID = "com.google.android.gms.maps_dynamite";
public static final int MODULE_VERSION = 1;
}

View file

@ -0,0 +1,92 @@
/*
* SPDX-FileCopyrightText: 2023 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.maps.internal;
import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.os.Parcel;
import android.os.RemoteException;
import androidx.annotation.Keep;
import android.util.Log;
import com.google.android.gms.dynamic.IObjectWrapper;
import com.google.android.gms.dynamic.ObjectWrapper;
import com.google.android.gms.maps.GoogleMapOptions;
import com.google.android.gms.maps.StreetViewPanoramaOptions;
import com.google.android.gms.maps.model.internal.IBitmapDescriptorFactoryDelegate;
import com.huawei.hms.maps.MapsInitializer;
import org.microg.gms.maps.hms.CameraUpdateFactoryImpl;
import org.microg.gms.maps.hms.MapFragmentImpl;
import org.microg.gms.maps.hms.MapViewImpl;
import org.microg.gms.maps.hms.StreetViewPanoramaFragmentImpl;
import org.microg.gms.maps.hms.StreetViewPanoramaViewImpl;
import org.microg.gms.maps.hms.model.BitmapDescriptorFactoryImpl;
@Keep
public class CreatorImpl extends ICreator.Stub {
private static final String TAG = "GmsMapCreator";
@Override
public void init(IObjectWrapper resources) {
initV2(resources, 0);
}
@Override
public IMapFragmentDelegate newMapFragmentDelegate(IObjectWrapper activity) {
return new MapFragmentImpl(ObjectWrapper.unwrapTyped(activity, Activity.class));
}
@Override
public IMapViewDelegate newMapViewDelegate(IObjectWrapper context, GoogleMapOptions options) {
return new MapViewImpl(ObjectWrapper.unwrapTyped(context, Context.class), options);
}
@Override
public ICameraUpdateFactoryDelegate newCameraUpdateFactoryDelegate() {
return new CameraUpdateFactoryImpl();
}
@Override
public IBitmapDescriptorFactoryDelegate newBitmapDescriptorFactoryDelegate() {
return BitmapDescriptorFactoryImpl.INSTANCE;
}
@Override
public void initV2(IObjectWrapper resources, int flags) {
BitmapDescriptorFactoryImpl.INSTANCE.initialize(ObjectWrapper.unwrapTyped(resources, Resources.class));
//ResourcesContainer.set((Resources) ObjectWrapper.unwrap(resources));
Log.d(TAG, "initV2 " + flags);
}
@Override
public IStreetViewPanoramaViewDelegate newStreetViewPanoramaViewDelegate(IObjectWrapper context, StreetViewPanoramaOptions options) {
return new StreetViewPanoramaViewImpl(ObjectWrapper.unwrapTyped(context, Context.class));
}
@Override
public IStreetViewPanoramaFragmentDelegate newStreetViewPanoramaFragmentDelegate(IObjectWrapper activity) {
return new StreetViewPanoramaFragmentImpl(ObjectWrapper.unwrapTyped(activity, Activity.class));
}
@Override
public int getRendererType() throws RemoteException {
return 2;
}
@Override
public void logInitialization(IObjectWrapper context, int preferredRenderer) throws RemoteException {
Log.d(TAG, "HMS-based Map initialized (preferred renderer was " + preferredRenderer + ")");
}
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
if (super.onTransact(code, data, reply, flags)) return true;
Log.d(TAG, "onTransact [unknown]: " + code + ", " + data + ", " + flags);
return false;
}
}

View file

@ -0,0 +1,71 @@
/*
* SPDX-FileCopyrightText: 2023 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package org.microg.gms.maps.hms
import android.graphics.Point
import android.os.Parcel
import android.util.Log
import com.google.android.gms.dynamic.IObjectWrapper
import com.google.android.gms.dynamic.ObjectWrapper
import com.google.android.gms.maps.internal.ICameraUpdateFactoryDelegate
import com.google.android.gms.maps.model.CameraPosition
import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.LatLngBounds
import com.huawei.hms.maps.CameraUpdateFactory
import org.microg.gms.maps.hms.utils.toHms
import org.microg.gms.maps.hms.utils.toHmsZoom
class CameraUpdateFactoryImpl : ICameraUpdateFactoryDelegate.Stub() {
override fun zoomIn(): IObjectWrapper = ObjectWrapper.wrap(CameraUpdateFactory.zoomIn())
override fun zoomOut(): IObjectWrapper = ObjectWrapper.wrap(CameraUpdateFactory.zoomOut())
override fun zoomTo(zoom: Float): IObjectWrapper =
ObjectWrapper.wrap(CameraUpdateFactory.zoomTo(toHmsZoom(zoom)))
override fun zoomBy(zoomDelta: Float): IObjectWrapper =
ObjectWrapper.wrap(CameraUpdateFactory.zoomBy(zoomDelta))
override fun zoomByWithFocus(zoomDelta: Float, x: Int, y: Int): IObjectWrapper =
ObjectWrapper.wrap(CameraUpdateFactory.zoomBy(zoomDelta, Point(x, y)))
override fun newCameraPosition(cameraPosition: CameraPosition): IObjectWrapper =
ObjectWrapper.wrap(CameraUpdateFactory.newCameraPosition(cameraPosition.toHms()))
override fun newLatLng(latLng: LatLng): IObjectWrapper =
ObjectWrapper.wrap(CameraUpdateFactory.newLatLng(latLng.toHms()))
override fun newLatLngZoom(latLng: LatLng, zoom: Float): IObjectWrapper =
ObjectWrapper.wrap(CameraUpdateFactory.newLatLngZoom(latLng.toHms(),
toHmsZoom(zoom)
))
override fun newLatLngBounds(bounds: LatLngBounds, padding: Int): IObjectWrapper =
ObjectWrapper.wrap(CameraUpdateFactory.newLatLngBounds(bounds.toHms(), padding))
override fun scrollBy(x: Float, y: Float): IObjectWrapper {
Log.d(TAG, "scrollBy: $x, $y")
// gms map: A positive value moves the camera downwards
// hms map: A positive value moves the camera upwards
return ObjectWrapper.wrap(CameraUpdateFactory.scrollBy(x, -y))
}
override fun newLatLngBoundsWithSize(bounds: LatLngBounds, width: Int, height: Int, padding: Int): IObjectWrapper =
ObjectWrapper.wrap(CameraUpdateFactory.newLatLngBounds(bounds.toHms(), width, height, padding))
override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =
if (super.onTransact(code, data, reply, flags)) {
true
} else {
Log.d(TAG, "onTransact [unknown]: $code, $data, $flags"); false
}
companion object {
private val TAG = "GmsCameraUpdate"
}
}

View file

@ -0,0 +1,984 @@
/*
* SPDX-FileCopyrightText: 2023 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package org.microg.gms.maps.hms
import android.content.Context
import android.graphics.Bitmap
import android.location.Location
import android.os.*
import android.os.Build.VERSION.SDK_INT
import android.util.DisplayMetrics
import android.util.Log
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.RelativeLayout
import androidx.annotation.IdRes
import androidx.annotation.Keep
import androidx.collection.LongSparseArray
import com.google.android.gms.dynamic.IObjectWrapper
import com.google.android.gms.dynamic.unwrap
import com.google.android.gms.maps.GoogleMap.MAP_TYPE_TERRAIN
import com.google.android.gms.maps.GoogleMapOptions
import com.google.android.gms.maps.internal.*
import com.google.android.gms.maps.model.*
import com.google.android.gms.maps.model.internal.*
import com.huawei.hms.maps.CameraUpdate
import com.huawei.hms.maps.HuaweiMap
import com.huawei.hms.maps.MapView
import com.huawei.hms.maps.MapsInitializer
import com.huawei.hms.maps.OnMapReadyCallback
import com.huawei.hms.maps.TextureMapView
import com.huawei.hms.maps.internal.IOnIndoorStateChangeListener
import com.huawei.hms.maps.internal.IOnInfoWindowCloseListener
import com.huawei.hms.maps.internal.IOnInfoWindowLongClickListener
import com.huawei.hms.maps.internal.IOnPoiClickListener
import com.huawei.hms.maps.model.Marker
import org.microg.gms.maps.hms.model.*
import org.microg.gms.maps.hms.utils.*
import java.util.concurrent.CopyOnWriteArrayList
import java.util.concurrent.atomic.AtomicBoolean
private fun <T : Any> LongSparseArray<T>.values() = (0 until size()).mapNotNull { valueAt(it) }
fun runOnMainLooper(forceQueue: Boolean = false, method: () -> Unit) {
if (!forceQueue && Looper.myLooper() == Looper.getMainLooper()) {
method()
} else {
Handler(Looper.getMainLooper()).post {
method()
}
}
}
class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions) : IGoogleMapDelegate.Stub() {
internal val mapContext = MapContext(context)
val view: FrameLayout
var map: HuaweiMap? = null
private set
val dpiFactor: Float
get() = context.resources.displayMetrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT
private var mapView: MapView? = null
private var created = false
private var initialized = false
private var loaded = false
private val mapLock = Object()
private var latLngBounds: LatLngBounds? = null
private val internalOnInitializedCallbackList = CopyOnWriteArrayList<OnMapReadyCallback>()
private val initializedCallbackList = CopyOnWriteArrayList<IOnMapReadyCallback>()
private var loadedCallback: IOnMapLoadedCallback? = null
private var cameraChangeListener: IOnCameraChangeListener? = null
private var cameraMoveListener: IOnCameraMoveListener? = null
private var cameraMoveCanceledListener: IOnCameraMoveCanceledListener? = null
private var cameraMoveStartedListener: IOnCameraMoveStartedListener? = null
private var cameraIdleListener: IOnCameraIdleListener? = null
private var mapClickListener: IOnMapClickListener? = null
private var mapLongClickListener: IOnMapLongClickListener? = null
private val groundOverlays = mutableMapOf<String, GroundOverlayImpl>()
private val polylines = mutableMapOf<String, PolylineImpl>()
private val polygons = mutableMapOf<String, PolygonImpl>()
private val circles = mutableMapOf<String, CircleImpl>()
private val tileOverlays = mutableMapOf<String, TileOverlayImpl>()
private var storedMapType: Int = options.mapType
val waitingCameraUpdates = mutableListOf<CameraUpdate>()
private var markerId = 0L
val markers = mutableMapOf<String, MarkerImpl>()
private var projectionImpl: ProjectionImpl? = null
private var inDeveloperAnimation = false
init {
BitmapDescriptorFactoryImpl.initialize(context.resources)
runOnMainLooper {
MapsInitializer.setApiKey(BuildConfig.HMSMAP_KEY)
}
this.view = object : FrameLayout(mapContext) {
private val fakeWatermark = ImageView(mapContext).apply {
tag = "GoogleWatermark"
visibility = GONE
}
private val fakeCompass = View(mapContext).apply {
tag = "GoogleMapCompass"
visibility = GONE
}
private val fakeZoomInButton = View(mapContext).apply {
tag = "GoogleMapZoomInButton"
visibility = GONE
}
private val fakeZoomOutButton = View(mapContext).apply {
tag = "GoogleMapZoomOutButton"
visibility = GONE
}
private val fakeMyLocationButton = View(mapContext).apply {
tag = "GoogleMapMyLocationButton"
visibility = GONE
}
private val fakeZoomButtonRoot = LinearLayout(mapContext).apply {
addView(fakeZoomInButton)
addView(fakeZoomOutButton)
visibility = GONE
}
private val mapButtonRoot = RelativeLayout(mapContext).apply {
addView(fakeZoomButtonRoot)
addView(fakeMyLocationButton)
addView(fakeCompass)
addView(fakeWatermark)
visibility = GONE
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
addView(mapButtonRoot)
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
removeView(mapButtonRoot)
}
@Keep
fun <T : View> findViewTraversal(@IdRes id: Int): T? {
if (1 == id) {
return try {
@Suppress("UNCHECKED_CAST")
mapButtonRoot as T
} catch (e: ClassCastException) {
null
}
}
if (2 == id) {
return try {
@Suppress("UNCHECKED_CAST")
fakeMyLocationButton as T
} catch (e: ClassCastException) {
null
}
}
return null
}
@Keep
fun <T : View> findViewWithTagTraversal(tag: Any): T? {
if ("GoogleWatermark" == tag) {
return try {
@Suppress("UNCHECKED_CAST")
fakeWatermark as T
} catch (e: ClassCastException) {
null
}
}
if ("GoogleMapCompass" == tag) {
return try {
@Suppress("UNCHECKED_CAST")
fakeCompass as T
} catch (e: ClassCastException) {
null
}
}
if ("GoogleMapZoomInButton" == tag) {
return try {
@Suppress("UNCHECKED_CAST")
fakeZoomInButton as T
} catch (e: ClassCastException) {
null
}
}
if ("GoogleMapZoomOutButton" == tag) {
return try {
@Suppress("UNCHECKED_CAST")
fakeZoomOutButton as T
} catch (e: ClassCastException) {
null
}
}
if ("GoogleMapMyLocationButton" == tag) {
return try {
@Suppress("UNCHECKED_CAST")
fakeMyLocationButton as T
} catch (e: ClassCastException) {
null
}
}
return null
}
}
}
override fun getCameraPosition(): CameraPosition {
return map?.cameraPosition?.toGms() ?: CameraPosition(LatLng(0.0, 0.0), 0f, 0f, 0f)
}
override fun getMaxZoomLevel(): Float = toHmsZoom(map?.maxZoomLevel ?: 18.toFloat())
override fun getMinZoomLevel(): Float = toHmsZoom(map?.minZoomLevel ?: 3.toFloat())
override fun moveCamera(cameraUpdate: IObjectWrapper?) {
val update = cameraUpdate.unwrap<CameraUpdate>() ?: return
synchronized(mapLock) {
if (initialized) {
this.map?.moveCamera(update)
} else {
waitingCameraUpdates.add(update)
}
}
}
override fun animateCamera(cameraUpdate: IObjectWrapper?) {
val update = cameraUpdate.unwrap<CameraUpdate>() ?: return
synchronized(mapLock) {
if (initialized) {
this.map?.animateCamera(update)
} else {
waitingCameraUpdates.add(update)
}
}
}
override fun animateCameraWithCallback(cameraUpdate: IObjectWrapper?, callback: ICancelableCallback?) {
val update = cameraUpdate.unwrap<CameraUpdate>() ?: return
synchronized(mapLock) {
if (initialized) {
Log.d(TAG, "animateCameraWithCallback start ")
inDeveloperAnimation = true
this.map?.animateCamera(update, object : HuaweiMap.CancelableCallback {
override fun onFinish() {
Log.d(TAG, "animateCameraWithCallback onFinish: ")
inDeveloperAnimation = false
callback?.onFinish()
}
override fun onCancel() {
Log.d(TAG, "animateCameraWithCallback onCancel: ")
inDeveloperAnimation = false
callback?.onCancel()
}
})
} else {
waitingCameraUpdates.add(update)
afterInitialize { callback?.onFinish() }
}
}
}
override fun animateCameraWithDurationAndCallback(
cameraUpdate: IObjectWrapper?,
duration: Int,
callback: ICancelableCallback?
) {
val update = cameraUpdate.unwrap<CameraUpdate>() ?: return
synchronized(mapLock) {
if (initialized) {
Log.d(TAG, "animateCameraWithDurationAndCallback")
this.map?.animateCamera(update, duration, callback?.toHms())
} else {
waitingCameraUpdates.add(update)
afterInitialize { callback?.onFinish() }
}
}
}
override fun stopAnimation() = map?.stopAnimation() ?: Unit
override fun setMapStyle(options: MapStyleOptions?): Boolean {
Log.d(TAG, "setMapStyle: ")
val bool = options?.toHms(mapContext).let {
map?.setMapStyle(it)
}
Log.d(TAG, "setMapStyle: bool: $bool")
return true == bool
}
override fun setMinZoomPreference(minZoom: Float) = afterInitialize {
it.setMinZoomPreference(toHmsZoom(minZoom))
}
override fun setMaxZoomPreference(maxZoom: Float) = afterInitialize {
it.setMaxZoomPreference(toHmsZoom(maxZoom))
}
override fun resetMinMaxZoomPreference() = afterInitialize {
it.setMinZoomPreference(3.toFloat())
it.setMaxZoomPreference(18.toFloat())
}
override fun setLatLngBoundsForCameraTarget(bounds: LatLngBounds?) = afterInitialize {
if (latLngBounds == null || bounds == null || latLngBounds!! != bounds) {
latLngBounds = bounds
it.setLatLngBoundsForCameraTarget(bounds?.toHms())
}
}
override fun addPolyline(options: PolylineOptions): IPolylineDelegate? {
val polyline = map?.addPolyline(options.toHms()) ?: return null
val polylineImpl = PolylineImpl(polyline, options)
polylines[polylineImpl.id] = polylineImpl
return polylineImpl
}
override fun addPolygon(options: PolygonOptions): IPolygonDelegate? {
val polygon = map?.addPolygon(options.toHms()) ?: return null
val polygonImpl = PolygonImpl(polygon)
polygons[polygonImpl.id] = polygonImpl
return polygonImpl
}
override fun addMarker(options: MarkerOptions): IMarkerDelegate {
val marker = MarkerImpl(this, "m${markerId++}", options)
if (map != null) {
marker.update()
} else {
markers[marker.id] = marker
}
return marker
}
override fun addGroundOverlay(options: GroundOverlayOptions): IGroundOverlayDelegate? {
Log.d(TAG, "Method: addGroundOverlay")
if (options.width <= 0 && options.height <= 0 && options.bounds == null) {
Log.w(TAG, "addGroundOverlay options Parameters do not meet requirements")
return null
}
val groundOverlay = map?.addGroundOverlay(options.toHms()) ?: return null
val groundOverlayImpl = GroundOverlayImpl(groundOverlay)
groundOverlays[groundOverlayImpl.id] = groundOverlayImpl
return groundOverlayImpl
}
override fun addTileOverlay(options: TileOverlayOptions): ITileOverlayDelegate? {
Log.d(TAG, "Method: addTileOverlay")
val tileOverlay = map?.addTileOverlay(options.toHms()) ?: return null
val tileOverlayImpl = TileOverlayImpl(tileOverlay)
tileOverlays[tileOverlayImpl.id] = tileOverlayImpl
return tileOverlayImpl
}
override fun addCircle(options: CircleOptions): ICircleDelegate? {
val circle = map?.addCircle(options.toHms()) ?: return null
val circleImpl = CircleImpl(circle)
circles[circleImpl.id] = circleImpl
return circleImpl
}
override fun clear() {
map?.clear()
}
override fun getMapType(): Int {
return map?.mapType ?: storedMapType
}
override fun setMapType(type: Int) {
storedMapType = type
applyMapType()
}
fun applyMapType() {
// TODO: Serve map styles locally
Log.d(TAG, "Method: applyMapType -> $storedMapType")
when (storedMapType) {
MAP_TYPE_TERRAIN -> map?.mapType = HuaweiMap.MAP_TYPE_TERRAIN
// MAP_TYPE_SATELLITE, MAP_TYPE_HYBRID, MAP_TYPE_NONE, MAP_TYPE_NORMAL,
else -> map?.mapType = HuaweiMap.MAP_TYPE_NORMAL
}
// map?.let { BitmapDescriptorFactoryImpl.registerMap(it) }
}
override fun isTrafficEnabled(): Boolean {
return map?.isTrafficEnabled ?: false
}
override fun setTrafficEnabled(traffic: Boolean) = afterInitialize {
Log.d(TAG, "setTrafficEnabled")
it.isTrafficEnabled = traffic
}
override fun isIndoorEnabled(): Boolean {
Log.d(TAG, "isIndoorEnabled")
return map?.isIndoorEnabled ?: false
}
override fun setIndoorEnabled(indoor: Boolean) = afterInitialize {
Log.d(TAG, "setIndoorEnabled")
it.isIndoorEnabled = indoor
}
override fun isMyLocationEnabled(): Boolean {
return map?.isMyLocationEnabled ?: false
}
override fun setMyLocationEnabled(myLocation: Boolean) = afterInitialize {
Log.d(TAG, "setMyLocationEnabled $myLocation")
it.isMyLocationEnabled = myLocation
}
override fun getMyLocation(): Location? {
Log.d(TAG, "deprecated Method: getMyLocation")
return null
}
override fun setLocationSource(locationSource: ILocationSourceDelegate?) = afterInitialize {
Log.d(TAG, "unimplemented Method: setLocationSource")
}
override fun setContentDescription(desc: String?) = afterInitialize {
Log.d(TAG, "setContentDescription desc -> $desc")
it.setContentDescription(desc)
}
override fun getUiSettings(): IUiSettingsDelegate =
map?.uiSettings?.let { UiSettingsImpl(it, view) } ?: UiSettingsCache().also {
internalOnInitializedCallbackList.add(it.getMapReadyCallback())
}
override fun getProjection(): IProjectionDelegate {
return projectionImpl ?: map?.projection?.let {
val experiment = try {
map?.cameraPosition?.tilt == 0.0f && map?.cameraPosition?.bearing == 0.0f
} catch (e: Exception) {
Log.w(TAG, e);false
}
ProjectionImpl(it, experiment)
}?.also { projectionImpl = it } ?: DummyProjection()
}
override fun setOnCameraChangeListener(listener: IOnCameraChangeListener?) = afterInitialize {
Log.d(TAG, "setOnCameraChangeListener");
cameraChangeListener = listener
}
override fun setOnCircleClickListener(listener: IOnCircleClickListener?) = afterInitialize { hmap ->
Log.d(TAG, "setOnCircleClickListener")
hmap.setOnCircleClickListener { listener?.onCircleClick(circles[it.id]) }
}
override fun setOnGroundOverlayClickListener(listener: IOnGroundOverlayClickListener?) =
afterInitialize { hmap ->
Log.d(TAG, "Method: setOnGroundOverlayClickListener")
hmap.setOnGroundOverlayClickListener { listener?.onGroundOverlayClick(groundOverlays[it.id]) }
}
override fun setOnInfoWindowLongClickListener(listener: com.google.android.gms.maps.internal.IOnInfoWindowLongClickListener?) =
afterInitialize {
Log.d(TAG, "Not yet implemented setInfoWindowLongClickListener")
}
fun setOnIndoorStateChangeListener(listener: IOnIndoorStateChangeListener?) {
Log.d(TAG, "unimplemented Method: setOnIndoorStateChangeListener")
}
override fun setOnMapClickListener(listener: IOnMapClickListener?) = afterInitialize {
mapClickListener = listener
it.setOnMapClickListener { latlng ->
try {
mapClickListener?.onMapClick(latlng.toGms())
} catch (e: Exception) {
Log.w(TAG, e)
}
}
}
override fun setOnMapLongClickListener(listener: IOnMapLongClickListener?) = afterInitialize {
mapLongClickListener = listener
it.setOnMapLongClickListener { latlng ->
try {
mapLongClickListener?.onMapLongClick(latlng.toGms())
} catch (e: Exception) {
Log.w(TAG, e)
}
}
}
override fun setOnMarkerClickListener(listener: IOnMarkerClickListener?) = afterInitialize { hmap ->
hmap.setOnMarkerClickListener {
Log.d("GmsGoogleMap", "setOnMarkerClickListener marker id -> ${it.id}")
listener?.onMarkerClick(markers[it.id]) ?: false
}
}
override fun setOnMarkerDragListener(listener: IOnMarkerDragListener?) = afterInitialize {
it.setOnMarkerDragListener(object : HuaweiMap.OnMarkerDragListener {
override fun onMarkerDragStart(p0: Marker?) {
listener?.onMarkerDragStart(markers[p0?.id])
}
override fun onMarkerDrag(p0: Marker?) {
listener?.onMarkerDrag(markers[p0?.id])
}
override fun onMarkerDragEnd(p0: Marker?) {
listener?.onMarkerDragEnd(markers[p0?.id])
}
})
}
override fun setOnInfoWindowClickListener(listener: IOnInfoWindowClickListener?) = afterInitialize { hmap ->
Log.d(TAG, "setOnInfoWindowClickListener")
hmap.setOnInfoWindowClickListener { listener?.onInfoWindowClick(markers[it.id]) }
}
fun setOnInfoWindowCloseListener(listener: IOnInfoWindowCloseListener?) {
Log.d(TAG, "unimplemented Method: setOnInfoWindowCloseListener")
}
fun setOnInfoWindowLongClickListener(listener: IOnInfoWindowLongClickListener?) {
Log.d(TAG, "unimplemented Method: setOnInfoWindowLongClickListener")
}
override fun setInfoWindowAdapter(adapter: IInfoWindowAdapter?) = afterInitialize {
Log.d(TAG, "setInfoWindowAdapter")
it.setInfoWindowAdapter(object : HuaweiMap.InfoWindowAdapter {
override fun getInfoContents(p0: Marker?): View? {
return adapter?.getInfoContents(markers[p0?.id]).unwrap<View>()
}
override fun getInfoWindow(p0: Marker?): View? {
return adapter?.getInfoWindow(markers[p0?.id]).unwrap<View>()
}
})
}
override fun setOnMyLocationChangeListener(listener: IOnMyLocationChangeListener?) = afterInitialize {
Log.d(TAG, "deprecated Method: setOnMyLocationChangeListener")
}
override fun setOnMyLocationButtonClickListener(listener: IOnMyLocationButtonClickListener?) = afterInitialize {
Log.d(TAG, "setOnMyLocationButtonClickListener")
it.setOnMyLocationButtonClickListener { listener?.onMyLocationButtonClick() ?: false }
}
override fun setOnMyLocationClickListener(listener: IOnMyLocationClickListener?) = afterInitialize { hmap ->
Log.d(TAG, "setOnMyLocationClickListener")
hmap.setOnMyLocationClickListener { listener?.onMyLocationClick(it) }
}
fun setOnPoiClickListener(listener: IOnPoiClickListener?) {
Log.d(TAG, "unimplemented Method: setOnPoiClickListener")
}
override fun setOnPolygonClickListener(listener: IOnPolygonClickListener?) = afterInitialize { hmap ->
Log.d(TAG, "setOnPolygonClickListener")
hmap.setOnPolygonClickListener { listener?.onPolygonClick(polygons[it.id]) }
}
override fun setOnInfoWindowCloseListener(listener: com.google.android.gms.maps.internal.IOnInfoWindowCloseListener?) =
afterInitialize {
Log.d(TAG, "Not yet implemented setInfoWindowCloseListener")
}
override fun setOnPolylineClickListener(listener: IOnPolylineClickListener?) = afterInitialize { hmap ->
Log.d(TAG, "unimplemented Method: setOnPolylineClickListener")
hmap.setOnPolylineClickListener { listener?.onPolylineClick(polylines[it.id]) }
}
override fun snapshot(callback: ISnapshotReadyCallback, bitmap: IObjectWrapper?) = afterInitialize {
Log.d(TAG, "snapshot")
val hmsBitmap = bitmap.unwrap<Bitmap>() ?: return@afterInitialize
val hmsCallback = HuaweiMap.SnapshotReadyCallback { p0 -> callback.onBitmapReady(p0) }
it.snapshot(hmsCallback, hmsBitmap)
}
override fun snapshotForTest(callback: ISnapshotReadyCallback) = afterInitialize {
Log.d(TAG, "snapshotForTest")
val hmsCallback = HuaweiMap.SnapshotReadyCallback { p0 -> callback.onBitmapReady(p0) }
it.snapshot(hmsCallback)
}
override fun setPadding(left: Int, top: Int, right: Int, bottom: Int) = afterInitialize {
Log.d(TAG, "setPadding: $left $top $right $bottom")
it.setPadding(left, top, right, bottom)
}
override fun isBuildingsEnabled(): Boolean {
Log.d(TAG, "isBuildingsEnabled")
return map?.isBuildingsEnabled ?: true
}
override fun setBuildingsEnabled(buildings: Boolean) = afterInitialize {
Log.d(TAG, "setBuildingsEnabled: $buildings")
it.isBuildingsEnabled = buildings
}
override fun setOnMapLoadedCallback(callback: IOnMapLoadedCallback?) {
if (callback != null) {
synchronized(mapLock) {
if (loaded) {
Log.d(TAG, "Invoking callback instantly, as map is loaded")
try {
callback.onMapLoaded()
} catch (e: Exception) {
Log.w(TAG, e)
}
} else {
Log.d(TAG, "Delay callback invocation, as map is not yet loaded")
loadedCallback = callback
}
}
} else {
loadedCallback = null
}
}
override fun setCameraMoveStartedListener(listener: IOnCameraMoveStartedListener?) = afterInitialize { hmap ->
Log.d(TAG, "setCameraMoveStartedListener")
cameraMoveStartedListener = listener
hmap.setOnCameraMoveStartedListener {
if (it == HuaweiMap.OnCameraMoveStartedListener.REASON_DEVELOPER_ANIMATION && inDeveloperAnimation) {
Log.d(TAG, "onCameraMoveStarted <inDeveloperAnimation> skipped: 1st ")
return@setOnCameraMoveStartedListener
}
try {
Log.d(TAG, "Listener: onCameraMoveStarted: ")
cameraMoveStartedListener?.onCameraMoveStarted(it)
} catch (e: Exception) {
Log.w(TAG, e)
}
}
}
override fun setCameraMoveListener(listener: IOnCameraMoveListener?) = afterInitialize {
Log.d(TAG, "setCameraMoveListener")
cameraMoveListener = listener
it.setOnCameraMoveListener {
try {
Log.d(TAG, "Listener: onCameraMove: ")
if (SDK_INT >= 26) {
mapView?.let { it.parent?.onDescendantInvalidated(it, it) }
}
map?.let {
val cameraPosition = it.cameraPosition
val tilt = cameraPosition.tilt
val bearing = cameraPosition.bearing
val useFast = tilt < 1f && (bearing % 360f < 1f || bearing % 360f > 359f)
projectionImpl?.updateProjectionState(it.projection, useFast)
}
cameraMoveListener?.onCameraMove()
cameraChangeListener?.onCameraChange(map?.cameraPosition?.toGms())
} catch (e: Exception) {
Log.w(TAG, e)
}
}
}
override fun setCameraMoveCanceledListener(listener: IOnCameraMoveCanceledListener?) = afterInitialize {
Log.d(TAG, "setCameraMoveCanceledListener")
cameraMoveCanceledListener = listener
it.setOnCameraMoveCanceledListener {
try {
Log.d(TAG, "setOnCameraMoveCanceledListener: ")
cameraMoveCanceledListener?.onCameraMoveCanceled()
} catch (e: Exception) {
Log.w(TAG, e)
}
}
}
override fun setCameraIdleListener(listener: IOnCameraIdleListener?) = afterInitialize {
Log.d(TAG, "setCameraIdleListener")
cameraIdleListener = listener
}
override fun getTestingHelper(): IObjectWrapper? {
Log.d(TAG, "unimplemented Method: getTestingHelper")
return null
}
override fun setWatermarkEnabled(watermark: Boolean) {
Log.d(TAG, "unimplemented Method: setWatermarkEnabled")
}
override fun useViewLifecycleWhenInFragment(): Boolean {
Log.d(TAG, "unimplemented Method: useViewLifecycleWhenInFragment")
return false
}
override fun onCreate(savedInstanceState: Bundle?) {
if (!created) {
Log.d(TAG_LOGO, "create: ${context.packageName},\n$options")
MapsInitializer.initialize(mapContext)
val mapView = runCatching {
TextureMapView(mapContext, options.toHms())
}.onFailure {
Log.w(TAG, "onCreate: init TextureMapView error ", it)
}.getOrDefault(MapView(mapContext, options.toHms())).apply { visibility = View.INVISIBLE }
this.mapView = mapView
view.addView(mapView)
mapView.onCreate(savedInstanceState?.toHms())
mapView.getMapAsync(this::initMap)
created = true
runOnMainLooper(forceQueue = true) { tryRunUserInitializedCallbacks("onCreate") }
}
}
private fun fakeWatermark(method: () -> Unit) {
Log.d(TAG_LOGO, "start -> $view")
val view1 = view.getChildAt(0) as? ViewGroup
val view2 = view1?.getChildAt(0) as? ViewGroup
val view4 = view2?.getChildAt(1)
Log.d(TAG_LOGO, view4?.toString() ?: "view4 is null")
if (view4 is LinearLayout) {
view4.visibility = View.GONE
method()
} else {
Log.d(TAG_LOGO, "LinearLayout not found")
}
}
private fun getAllChildViews(view: View, index: Int): List<View>? {
Log.d(TAG_LOGO, "getAllChildViews: $index, $view")
if (view is LinearLayout) {
Log.d(TAG_LOGO, "legal: $index")
view.visibility = View.GONE
}
val allChildren: MutableList<View> = ArrayList()
if (view is ViewGroup) {
val vp = view
for (i in 0 until vp.childCount) {
val viewChild = vp.getChildAt(i)
Log.d(TAG_LOGO, "child:$index, $i, $viewChild")
allChildren.add(viewChild)
allChildren.addAll(getAllChildViews(viewChild, index + 1)!!)
}
}
return allChildren
}
private fun initMap(map: HuaweiMap) {
if (this.map != null && initialized) return
loaded = true
this.map = map
map.setOnCameraIdleListener {
Log.d(TAG, "initMap: onCameraIdle: ")
try {
cameraChangeListener?.onCameraChange(map.cameraPosition.toGms())
} catch (e: Exception) {
Log.w(TAG, e)
}
try {
cameraIdleListener?.onCameraIdle()
} catch (e: Exception) {
Log.w(TAG, e)
}
}
map.setOnCameraMoveListener {
Log.d(TAG, "initMap: onCameraMove: ")
try {
cameraMoveListener?.onCameraMove()
} catch (e: Exception) {
Log.w(TAG, e)
}
}
map.setOnCameraMoveStartedListener {
Log.d(TAG, "initMap: onCameraMoveStarted: $it")
try {
cameraMoveStartedListener?.onCameraMoveStarted(it)
} catch (e: Exception) {
Log.w(TAG, e)
}
}
map.setOnCameraMoveCanceledListener {
Log.d(TAG, "initMap: onCameraMoveCanceled: ")
try {
cameraMoveCanceledListener?.onCameraMoveCanceled()
} catch (e: Exception) {
Log.w(TAG, e)
}
}
map.setOnMapClickListener { latlng ->
try {
if (options.liteMode) {
val parentView = view.parent?.parent
// TODO hms not support disable click listener when liteMode, this just fix for teams
if (parentView != null && parentView::class.qualifiedName.equals("com.microsoft.teams.location.ui.map.MapViewLite")) {
val clickView = parentView as ViewGroup
clickView.performClick()
return@setOnMapClickListener
}
}
mapClickListener?.onMapClick(latlng.toGms())
} catch (e: Exception) {
Log.w(TAG, e)
}
}
map.setOnMapLongClickListener { latlng ->
try {
if (options.liteMode) {
val parentView = view.parent?.parent
// TODO hms not support disable click listener when liteMode, this just fix for teams
if (parentView != null && parentView::class.qualifiedName.equals("com.microsoft.teams.location.ui.map.MapViewLite")) {
val clickView = parentView as ViewGroup
clickView.performLongClick()
return@setOnMapLongClickListener
}
}
mapLongClickListener?.onMapLongClick(latlng.toGms())
} catch (e: Exception) {
Log.w(TAG, e)
}
}
synchronized(mapLock) {
initialized = true
markers.filter { it.key.startsWith("m") }.forEach { it.value.update() }
waitingCameraUpdates.forEach { map.moveCamera(it) }
val initializedCallbacks = ArrayList(internalOnInitializedCallbackList)
Log.d(TAG, "Invoking ${initializedCallbacks.size} internal callbacks now that the true map is initialized")
for (callback in initializedCallbacks) {
callback.onMapReady(map)
}
internalOnInitializedCallbackList.clear()
fakeWatermark { Log.d(TAG_LOGO, "fakeWatermark success") }
mapView?.visibility = View.VISIBLE
}
tryRunUserInitializedCallbacks(tag = "initMap")
}
override fun onResume() {
mapView?.visibility = View.VISIBLE
mapView?.onResume()
}
override fun onPause() = mapView?.onPause() ?: Unit
override fun onDestroy() {
Log.d(TAG, "onDestroy")
initializedCallbackList.clear()
internalOnInitializedCallbackList.clear()
circles.map { it.value.remove() }
circles.clear()
polylines.map { it.value.remove() }
polylines.clear()
polygons.map { it.value.remove() }
polygons.clear()
markers.map { it.value.remove() }
markers.clear()
// BitmapDescriptorFactoryImpl.unregisterMap(map)
view.removeView(mapView)
// TODO can crash?
mapView?.onDestroy()
mapView = null
// Don't make it null; this object is not deleted immediately, and it may want to access map.* stuff
//map = null
created = false
initialized = false
loaded = false
}
override fun onStart() {
mapView?.onStart()
}
override fun onStop() {
mapView?.visibility = View.INVISIBLE
mapView?.onStop()
}
override fun onEnterAmbient(bundle: Bundle?) {
Log.d(TAG, "unimplemented Method: onEnterAmbient")
}
override fun onExitAmbient() {
Log.d(TAG, "unimplemented Method: onExitAmbient")
}
override fun onLowMemory() = mapView?.onLowMemory() ?: Unit
override fun onSaveInstanceState(outState: Bundle) {
val newBundle = Bundle()
mapView?.onSaveInstanceState(newBundle)
outState.putAll(newBundle.toGms())
}
fun getMapAsync(callback: IOnMapReadyCallback) {
synchronized(mapLock) {
initializedCallbackList.add(callback)
}
tryRunUserInitializedCallbacks("getMapAsync")
}
private fun afterInitialize(runnable: (HuaweiMap) -> Unit) {
synchronized(mapLock) {
if (initialized) {
runnable(map!!)
} else {
internalOnInitializedCallbackList.add(OnMapReadyCallback {
runnable(it)
})
}
}
}
private var isInvokingInitializedCallbacks = AtomicBoolean(false)
private fun tryRunUserInitializedCallbacks(tag: String = "") {
synchronized(mapLock) {
if (initializedCallbackList.isEmpty()) return
}
val runCallbacks = {
val callbacks = synchronized(mapLock) {
ArrayList(initializedCallbackList)
.also { initializedCallbackList.clear() }
}
callbacks.forEach {
try {
it.onMapReady(this)
} catch (e: Exception) {
Log.w(TAG, e)
}
}
}
if (initialized && map != null) {
Log.d("$TAG:$tag", "Invoking callback now, as map is initialized")
val wasCallbackActive = isInvokingInitializedCallbacks.getAndSet(true)
runOnMainLooper(forceQueue = wasCallbackActive) {
runCallbacks()
}
if (!wasCallbackActive) isInvokingInitializedCallbacks.set(false)
} else {
Log.d(
"$TAG:$tag",
"Initialized callbacks could not be run at this point, as the map view has not been created yet."
)
}
}
override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =
if (super.onTransact(code, data, reply, flags)) {
Log.d(TAG, "onTransact: $code, $data, $flags")
true
} else {
Log.w(TAG, "onTransact [unknown]: $code, $data, $flags"); false
}
companion object {
private const val TAG = "GmsGoogleMap"
private const val TAG_LOGO = "fakeWatermark"
private const val MAX_TIMES = 300
}
}

View file

@ -0,0 +1,115 @@
/*
* SPDX-FileCopyrightText: 2023 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package org.microg.gms.maps.hms
import android.app.Activity
import android.os.Bundle
import android.os.Parcel
import android.util.Log
import android.view.ViewGroup
import com.google.android.gms.dynamic.IObjectWrapper
import com.google.android.gms.dynamic.ObjectWrapper
import com.google.android.gms.maps.GoogleMapOptions
import com.google.android.gms.maps.internal.IGoogleMapDelegate
import com.google.android.gms.maps.internal.IMapFragmentDelegate
import com.google.android.gms.maps.internal.IOnMapReadyCallback
class MapFragmentImpl(private val activity: Activity) : IMapFragmentDelegate.Stub() {
private var map: GoogleMapImpl? = null
private var options: GoogleMapOptions? = null
private var readyCallbackList: MutableList<IOnMapReadyCallback> = mutableListOf()
override fun onInflate(activity: IObjectWrapper, options: GoogleMapOptions, savedInstanceState: Bundle?) {
Log.d(TAG, "onInflate: $options")
this.options = options
map?.options = options
}
override fun onCreate(savedInstanceState: Bundle?) {
if (options == null) {
options = savedInstanceState?.getParcelable("MapOptions")
}
if (options == null) {
options = GoogleMapOptions()
}
Log.d(TAG, "onCreate $this : $options ")
if (map == null) {
map = GoogleMapImpl(activity, options ?: GoogleMapOptions())
}
}
override fun onCreateView(layoutInflater: IObjectWrapper, container: IObjectWrapper, savedInstanceState: Bundle?): IObjectWrapper {
if (options == null) {
options = savedInstanceState?.getParcelable("MapOptions")
}
Log.d(TAG, "onCreateView: ${options?.camera?.target}")
if (map == null) {
map = GoogleMapImpl(activity, options ?: GoogleMapOptions())
}
Log.d(TAG, "onCreateView $this : $options")
map!!.onCreate(savedInstanceState)
readyCallbackList.forEach { map!!.getMapAsync(it) }
readyCallbackList.clear()
val view = map!!.view
val parent = view.parent as ViewGroup?
parent?.removeView(view)
return ObjectWrapper.wrap(view)
}
override fun getMap(): IGoogleMapDelegate? = map
override fun onEnterAmbient(bundle: Bundle?) = map?.onEnterAmbient(bundle) ?: Unit
override fun onExitAmbient() = map?.onExitAmbient() ?: Unit
override fun onStart() = map?.onStart() ?: Unit
override fun onStop() = map?.onStop() ?: Unit
override fun onResume() = map?.onResume() ?: Unit
override fun onPause() = map?.onPause() ?: Unit
override fun onLowMemory() = map?.onLowMemory() ?: Unit
override fun isReady(): Boolean = this.map != null
override fun getMapAsync(callback: IOnMapReadyCallback) {
Log.d(TAG, "getMapAsync: map: $map")
if (map == null) {
readyCallbackList.add(callback)
return
}
map?.getMapAsync(callback)
}
override fun onDestroyView() {
Log.d(TAG, "onDestroyView: $this : $options")
if (options?.useViewLifecycleInFragment == true) {
map?.onDestroy()
map = null
}
}
override fun onDestroy() {
Log.d(TAG, "onDestroy: $this")
map?.onDestroy()
map = null
options = null
}
override fun onSaveInstanceState(outState: Bundle) {
if (options != null) {
outState.putParcelable("MapOptions", options)
}
map?.onSaveInstanceState(outState)
}
override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean {
if (super.onTransact(code, data, reply, flags)) {
return true
} else {
Log.d(TAG, "onTransact [unknown]: $code, $data, $flags")
return false
}
}
companion object {
private val TAG = "GmsMapFragment"
}
}

View file

@ -0,0 +1,69 @@
/*
* SPDX-FileCopyrightText: 2023 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package org.microg.gms.maps.hms
import android.content.Context
import android.os.Bundle
import android.os.Parcel
import android.util.Log
import com.google.android.gms.dynamic.IObjectWrapper
import com.google.android.gms.dynamic.ObjectWrapper
import com.google.android.gms.maps.GoogleMapOptions
import com.google.android.gms.maps.internal.IGoogleMapDelegate
import com.google.android.gms.maps.internal.IMapViewDelegate
import com.google.android.gms.maps.internal.IOnMapReadyCallback
class MapViewImpl(private val context: Context, options: GoogleMapOptions?) : IMapViewDelegate.Stub() {
private var options: GoogleMapOptions = options ?: GoogleMapOptions()
private var map: GoogleMapImpl? = null
private var readyCallbackList: MutableList<IOnMapReadyCallback> = mutableListOf()
override fun onCreate(savedInstanceState: Bundle?) {
Log.d(TAG, "onCreate: $options")
if (map == null) {
map = GoogleMapImpl(context, options)
}
map!!.onCreate(savedInstanceState)
readyCallbackList.forEach { map!!.getMapAsync(it) }
readyCallbackList.clear()
}
override fun getMap(): IGoogleMapDelegate? = map
override fun onEnterAmbient(bundle: Bundle?) = map?.onEnterAmbient(bundle) ?: Unit
override fun onExitAmbient() = map?.onExitAmbient() ?: Unit
override fun onStart() = map?.onStart() ?: Unit
override fun onStop() = map?.onStop() ?: Unit
override fun onResume() = map?.onResume() ?: Unit
override fun onPause() = map?.onPause() ?: Unit
override fun onDestroy() {
map?.onDestroy()
map = null
}
override fun onLowMemory() = map?.onLowMemory() ?: Unit
override fun onSaveInstanceState(outState: Bundle) = map?.onSaveInstanceState(outState) ?: Unit
override fun getView(): IObjectWrapper = ObjectWrapper.wrap(map?.view)
override fun getMapAsync(callback: IOnMapReadyCallback) {
Log.d(TAG, "getMapAsync: map: $map")
if (map == null) {
readyCallbackList.add(callback)
return
}
map?.getMapAsync(callback)
}
override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =
if (super.onTransact(code, data, reply, flags)) {
true
} else {
Log.d(TAG, "onTransact [unknown]: $code, $data, $flags"); false
}
companion object {
private val TAG = "GmsMapView"
}
}

View file

@ -0,0 +1,142 @@
/*
* SPDX-FileCopyrightText: 2023 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package org.microg.gms.maps.hms
import android.graphics.Point
import android.util.Log
import com.google.android.gms.dynamic.IObjectWrapper
import com.google.android.gms.dynamic.ObjectWrapper
import com.google.android.gms.dynamic.unwrap
import com.google.android.gms.maps.internal.IProjectionDelegate
import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.LatLngBounds
import com.google.android.gms.maps.model.VisibleRegion
import com.huawei.hms.maps.Projection
import org.microg.gms.maps.hms.utils.toGms
import org.microg.gms.maps.hms.utils.toHms
import kotlin.math.roundToInt
private const val TAG = "GmsProjectionImpl"
class ProjectionImpl(private var projection: Projection, private var withoutTiltOrBearing: Boolean) : IProjectionDelegate.Stub() {
private var lastVisibleRegion: VisibleRegion? = null
private var visibleRegion = projection.visibleRegion
private var farLeft: Point? = visibleRegion.farLeft?.let { projection.toScreenLocation(it) }
private var farRight: Point? = visibleRegion.farRight?.let { projection.toScreenLocation(it) }
private var nearLeft: Point? = visibleRegion.nearLeft?.let { projection.toScreenLocation(it) }
private var farLeftLat = visibleRegion.farLeft?.latitude ?: 0.0
private var nearLeftLat = visibleRegion.nearLeft?.latitude ?: 0.0
private var farLeftLng = visibleRegion.farLeft?.longitude ?: 0.0
private var farRightLng = visibleRegion.farRight?.longitude ?: 0.0
private var farLeftX = farLeft?.x ?: 0
private var farLeftY = farLeft?.y ?: 0
private var farRightX = farRight?.x ?: (farLeftX + 1)
private var nearLeftY = nearLeft?.y ?: (farLeftY + 1)
fun updateProjectionState(newProjection: Projection, useFastMode: Boolean) {
Log.d(TAG, "updateProjectionState: useFastMode: $useFastMode")
projection = newProjection
visibleRegion = newProjection.visibleRegion
withoutTiltOrBearing = useFastMode
farLeft = visibleRegion.farLeft?.let { projection.toScreenLocation(it) }
farRight = visibleRegion.farRight?.let { projection.toScreenLocation(it) }
nearLeft = visibleRegion.nearLeft?.let { projection.toScreenLocation(it) }
farLeftLat = visibleRegion.farLeft?.latitude ?: 0.0
nearLeftLat = visibleRegion.nearLeft?.latitude ?: 0.0
farLeftLng = visibleRegion.farLeft?.longitude ?: 0.0
farRightLng = visibleRegion.farRight?.longitude ?: 0.0
farLeftX = farLeft?.x ?: 0
farLeftY = farLeft?.y ?: 0
farRightX = farRight?.x ?: (farLeftX + 1)
nearLeftY = nearLeft?.y ?: (farLeftY + 1)
}
private fun isInvalid(): Boolean {
return farLeftX == farRightX || farLeftY == nearLeftY || (farRightX == 1 && farLeftX == 0) || (nearLeftY == 1 && farLeftY == 0)
}
override fun fromScreenLocation(obj: IObjectWrapper?): LatLng? = try {
obj.unwrap<Point>()?.let {
if (withoutTiltOrBearing && farLeft != null && farRight != null && nearLeft != null) {
if (isInvalid()) {
Log.w(TAG, "Invalid projection layout, fallback to SDK")
projection.fromScreenLocation(Point(it)).toGms()
} else {
val xPercent = (it.x.toFloat() - farLeftX) / (farRightX - farLeftX)
val yPercent = (it.y.toFloat() - farLeftY) / (nearLeftY - farLeftY)
val lon = farLeftLng + xPercent * (farRightLng - farLeftLng)
val lat = farLeftLat + yPercent * (nearLeftLat - farLeftLat)
Log.d(TAG, "fromScreenLocation: $it -> lat: $lat lon: $lon")
LatLng(lat, lon)
}
} else {
projection.fromScreenLocation(Point(it)).toGms()
}
}
} catch (e: Exception) {
Log.d(TAG, "fromScreenLocation() error", e)
LatLng(0.0, 0.0)
}
override fun toScreenLocation(latLng: LatLng?): IObjectWrapper = try {
ObjectWrapper.wrap(latLng?.toHms()?.let {
if (withoutTiltOrBearing && farLeft != null && farRight != null && nearLeft != null) {
if (isInvalid()) {
Log.w(TAG, "Invalid projection layout, fallback to SDK")
projection.toScreenLocation(it).let { p -> Point(p.x, p.y) }
} else {
val xPercent = (it.longitude - farLeftLng) / (farRightLng - farLeftLng)
val yPercent = (it.latitude - farLeftLat) / (nearLeftLat - farLeftLat)
val x = farLeftX + xPercent * (farRightX - farLeftX)
val y = farLeftY + yPercent * (nearLeftY - farLeftY)
Log.d(TAG, "toScreenLocation: $latLng -> x: $x y: $y")
Point(x.roundToInt(), y.roundToInt())
}
} else {
projection.toScreenLocation(it).let { p -> Point(p.x, p.y) }
}
})
} catch (e: Exception) {
Log.d(TAG, "toScreenLocation() error", e)
ObjectWrapper.wrap(Point(0, 0))
}
override fun getVisibleRegion(): VisibleRegion? {
if (visibleRegion.farLeft.latitude.isNaN() || visibleRegion.farLeft.longitude.isNaN()) {
return lastVisibleRegion
}
lastVisibleRegion = visibleRegion.toGms()
Log.d(TAG, "getVisibleRegion: $visibleRegion")
return lastVisibleRegion
}
}
class DummyProjection : IProjectionDelegate.Stub() {
override fun fromScreenLocation(obj: IObjectWrapper?): LatLng {
Log.d(TAG, "Map not initialized when calling getProjection(). Cannot calculate fromScreenLocation")
return LatLng(0.0, 0.0)
}
override fun toScreenLocation(latLng: LatLng?): IObjectWrapper {
Log.d(TAG, "Map not initialized when calling getProjection(). Cannot calculate toScreenLocation")
return ObjectWrapper.wrap(Point(0, 0))
}
override fun getVisibleRegion(): VisibleRegion {
Log.d(TAG, "Map not initialized when calling getProjection(). Cannot calculate getVisibleRegion")
return VisibleRegion(LatLngBounds(LatLng(0.0, 0.0), LatLng(0.0, 0.0)))
}
}

View file

@ -0,0 +1,63 @@
/*
* SPDX-FileCopyrightText: 2023 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package org.microg.gms.maps.hms
import android.app.Activity
import android.os.Bundle
import android.widget.TextView
import com.google.android.gms.dynamic.IObjectWrapper
import com.google.android.gms.dynamic.ObjectWrapper
import com.google.android.gms.maps.StreetViewPanoramaOptions
import com.google.android.gms.maps.internal.IOnStreetViewPanoramaReadyCallback
import com.google.android.gms.maps.internal.IStreetViewPanoramaDelegate
import com.google.android.gms.maps.internal.IStreetViewPanoramaFragmentDelegate
class StreetViewPanoramaFragmentImpl(private val activity: Activity) : IStreetViewPanoramaFragmentDelegate.Stub() {
override fun getStreetViewPanorama(): IStreetViewPanoramaDelegate? {
return null
}
override fun onInflate(activity: IObjectWrapper?, options: StreetViewPanoramaOptions?, savedInstanceState: Bundle?) {
}
override fun onCreate(savedInstanceState: Bundle?) {
}
override fun onCreateView(layoutInflater: IObjectWrapper?, container: IObjectWrapper?, savedInstanceState: Bundle?): IObjectWrapper {
return ObjectWrapper.wrap(TextView(activity))
}
override fun onResume() {
}
override fun onPause() {
}
override fun onDestroyView() {
}
override fun onDestroy() {
}
override fun onLowMemory() {
}
override fun onSaveInstanceState(outState: Bundle?) {
}
override fun isReady(): Boolean = true
override fun getStreetViewPanoramaAsync(callback: IOnStreetViewPanoramaReadyCallback?) {
}
override fun onStart() {
}
override fun onStop() {
}
}

View file

@ -0,0 +1,54 @@
/*
* SPDX-FileCopyrightText: 2023 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package org.microg.gms.maps.hms
import android.content.Context
import android.os.Bundle
import android.widget.TextView
import com.google.android.gms.dynamic.IObjectWrapper
import com.google.android.gms.dynamic.ObjectWrapper
import com.google.android.gms.maps.internal.IOnStreetViewPanoramaReadyCallback
import com.google.android.gms.maps.internal.IStreetViewPanoramaDelegate
import com.google.android.gms.maps.internal.IStreetViewPanoramaViewDelegate
class StreetViewPanoramaViewImpl(private val context: Context) : IStreetViewPanoramaViewDelegate.Stub() {
override fun getStreetViewPanorama(): IStreetViewPanoramaDelegate? {
return null
}
override fun onCreate(savedInstanceState: Bundle?) {
}
override fun onResume() {
}
override fun onPause() {
}
override fun onDestroy() {
}
override fun onLowMemory() {
}
override fun onSaveInstanceState(outState: Bundle?) {
}
override fun getView(): IObjectWrapper? {
return ObjectWrapper.wrap(TextView(context))
}
override fun getStreetViewPanoramaAsync(callback: IOnStreetViewPanoramaReadyCallback?) {
}
override fun onStart() {
}
override fun onStop() {
}
}

View file

@ -0,0 +1,316 @@
/*
* SPDX-FileCopyrightText: 2023 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package org.microg.gms.maps.hms
import android.os.Parcel
import android.util.Log
import android.view.ViewGroup
import com.google.android.gms.maps.internal.IUiSettingsDelegate
import com.huawei.hms.maps.OnMapReadyCallback
import com.huawei.hms.maps.UiSettings
import org.microg.gms.maps.hms.utils.MapUiController
import org.microg.gms.maps.hms.utils.MapUiElement
private const val TAG = "GmsMapsUiSettings"
/**
* This class "implements" unimplemented methods to avoid duplication in subclasses
*/
abstract class AbstractUiSettings : IUiSettingsDelegate.Stub() {
override fun setZoomControlsEnabled(zoom: Boolean) {
Log.d(TAG, "unimplemented Method: setZoomControlsEnabled")
}
override fun setMyLocationButtonEnabled(locationButton: Boolean) {
Log.d(TAG, "unimplemented Method: setMyLocationButtonEnabled")
}
override fun isZoomControlsEnabled(): Boolean {
Log.d(TAG, "unimplemented Method: isZoomControlsEnabled")
return false
}
override fun isMyLocationButtonEnabled(): Boolean {
Log.d(TAG, "unimplemented Method: isMyLocationButtonEnabled")
return false
}
override fun setIndoorLevelPickerEnabled(indoorLevelPicker: Boolean) {
Log.d(TAG, "unimplemented Method: setIndoorLevelPickerEnabled")
}
override fun isIndoorLevelPickerEnabled(): Boolean {
Log.d(TAG, "unimplemented Method: isIndoorLevelPickerEnabled")
return false
}
override fun setMapToolbarEnabled(mapToolbar: Boolean) {
Log.d(TAG, "unimplemented Method: setMapToolbarEnabled")
}
override fun isMapToolbarEnabled(): Boolean {
Log.d(TAG, "unimplemented Method: isMapToolbarEnabled")
return false
}
override fun setScrollGesturesEnabledDuringRotateOrZoom(scrollDuringZoom: Boolean) {
Log.d(TAG, "unimplemented Method: setScrollGesturesEnabledDuringRotateOrZoom")
}
override fun isScrollGesturesEnabledDuringRotateOrZoom(): Boolean {
Log.d(TAG, "unimplemented Method: isScrollGesturesEnabledDuringRotateOrZoom")
return true
}
}
class UiSettingsImpl(private val uiSettings: UiSettings, rootView: ViewGroup) : IUiSettingsDelegate.Stub() {
private val mapUiController = MapUiController(rootView)
init {
uiSettings.isZoomControlsEnabled = false
uiSettings.isCompassEnabled = false
uiSettings.isMapToolbarEnabled = false
uiSettings.isMyLocationButtonEnabled = false
mapUiController.initUiStates(
mapOf(
MapUiElement.MyLocationButton to false,
MapUiElement.ZoomView to false,
MapUiElement.CompassView to false
)
)
}
override fun setZoomControlsEnabled(zoom: Boolean) {
Log.d(TAG, "setZoomControlsEnabled: $zoom")
uiSettings.isZoomControlsEnabled = zoom
mapUiController.setUiEnabled(MapUiElement.ZoomView, zoom)
}
override fun setCompassEnabled(compass: Boolean) {
Log.d(TAG, "setCompassEnabled: $compass")
uiSettings.isCompassEnabled = compass
mapUiController.setUiEnabled(MapUiElement.CompassView, compass)
}
override fun setMyLocationButtonEnabled(locationButton: Boolean) {
Log.d(TAG, "setMyLocationButtonEnabled: $locationButton")
uiSettings.isMyLocationButtonEnabled = locationButton
mapUiController.setUiEnabled(MapUiElement.MyLocationButton, locationButton)
}
override fun setScrollGesturesEnabled(scrollGestures: Boolean) {
uiSettings.isScrollGesturesEnabled = scrollGestures
}
override fun setZoomGesturesEnabled(zoomGestures: Boolean) {
uiSettings.isZoomGesturesEnabled = zoomGestures
}
override fun setTiltGesturesEnabled(tiltGestures: Boolean) {
uiSettings.isTiltGesturesEnabled = tiltGestures
}
override fun setRotateGesturesEnabled(rotateGestures: Boolean) {
uiSettings.isRotateGesturesEnabled = rotateGestures
}
override fun setAllGesturesEnabled(gestures: Boolean) {
uiSettings.setAllGesturesEnabled(gestures)
}
override fun isZoomControlsEnabled(): Boolean {
Log.d(TAG, "isZoomControlsEnabled")
return uiSettings.isZoomControlsEnabled
}
override fun isCompassEnabled(): Boolean = uiSettings.isCompassEnabled
override fun isMyLocationButtonEnabled(): Boolean {
Log.d(TAG, "isMyLocationButtonEnabled")
return uiSettings.isMyLocationButtonEnabled
}
override fun isScrollGesturesEnabled(): Boolean = uiSettings.isScrollGesturesEnabled
override fun isZoomGesturesEnabled(): Boolean = uiSettings.isZoomGesturesEnabled
override fun isTiltGesturesEnabled(): Boolean = uiSettings.isTiltGesturesEnabled
override fun isRotateGesturesEnabled(): Boolean = uiSettings.isRotateGesturesEnabled
override fun setIndoorLevelPickerEnabled(indoorLevelPicker: Boolean) {
Log.d(TAG, "setIndoorLevelPickerEnabled: $indoorLevelPicker")
uiSettings.isIndoorLevelPickerEnabled = indoorLevelPicker
}
override fun isIndoorLevelPickerEnabled(): Boolean {
Log.d(TAG, "isIndoorLevelPickerEnabled")
return uiSettings.isIndoorLevelPickerEnabled
}
override fun setMapToolbarEnabled(mapToolbar: Boolean) {
Log.d(TAG, "setMapToolbarEnabled: $mapToolbar")
uiSettings.isMapToolbarEnabled = mapToolbar
}
override fun isMapToolbarEnabled(): Boolean {
Log.d(TAG, "isMapToolbarEnabled")
return uiSettings.isMapToolbarEnabled
}
override fun setScrollGesturesEnabledDuringRotateOrZoom(scrollDuringZoom: Boolean) {
Log.d(TAG, "setScrollGesturesEnabledDuringRotateOrZoom: $scrollDuringZoom")
uiSettings.isScrollGesturesEnabledDuringRotateOrZoom = scrollDuringZoom
}
override fun isScrollGesturesEnabledDuringRotateOrZoom(): Boolean {
Log.d(TAG, "isScrollGesturesEnabledDuringRotateOrZoom")
return uiSettings.isScrollGesturesEnabledDuringRotateOrZoom
}
override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =
if (super.onTransact(code, data, reply, flags)) {
true
} else {
Log.d(TAG, "onTransact [unknown]: $code, $data, $flags"); false
}
}
class UiSettingsCache : AbstractUiSettings() {
private var compass: Boolean? = null
private var scrollGestures: Boolean? = null
private var zoomGestures: Boolean? = null
private var tiltGestures: Boolean? = null
private var rotateGestures: Boolean? = null
private var otherGestures: Boolean? = null
private var isZoomControlsEnabled: Boolean? = null
private var isMyLocationButtonEnabled: Boolean? = null
private var isAllGesturesEnabled: Boolean? = null
private var isIndoorLevelPickerEnabled: Boolean? = null
private var isMapToolbarEnabled: Boolean? = null
private var isScrollGesturesEnabledDuringRotateOrZoom: Boolean? = null
override fun setMapToolbarEnabled(mapToolbar: Boolean) {
Log.d(TAG, "setMapToolbarEnabled: $mapToolbar")
this.isMapToolbarEnabled = mapToolbar
}
override fun isMapToolbarEnabled(): Boolean {
Log.d(TAG, "isMapToolbarEnabled")
return isMapToolbarEnabled ?: true
}
override fun setScrollGesturesEnabledDuringRotateOrZoom(scrollDuringZoom: Boolean) {
Log.d(TAG, "setScrollGesturesEnabledDuringRotateOrZoom: $scrollDuringZoom")
this.isScrollGesturesEnabledDuringRotateOrZoom = scrollDuringZoom
}
override fun isScrollGesturesEnabledDuringRotateOrZoom(): Boolean {
Log.d(TAG, "isScrollGesturesEnabledDuringRotateOrZoom")
return isScrollGesturesEnabledDuringRotateOrZoom ?: true
}
override fun setIndoorLevelPickerEnabled(indoorLevelPicker: Boolean) {
Log.d(TAG, "setIndoorLevelPickerEnabled: $indoorLevelPicker")
this.isIndoorLevelPickerEnabled = indoorLevelPicker
}
override fun isIndoorLevelPickerEnabled(): Boolean {
Log.d(TAG, "isIndoorLevelPickerEnabled")
return isIndoorLevelPickerEnabled ?: true
}
override fun setMyLocationButtonEnabled(locationButton: Boolean) {
Log.d(TAG, "setMyLocationButtonEnabled: $locationButton")
this.isMyLocationButtonEnabled = locationButton
}
override fun isMyLocationButtonEnabled(): Boolean {
Log.d(TAG, "isMyLocationButtonEnabled")
return isMyLocationButtonEnabled ?: true
}
override fun setZoomControlsEnabled(zoom: Boolean) {
Log.d(TAG, "setZoomControlsEnabled: $zoom")
this.isZoomControlsEnabled = zoom
}
override fun isZoomControlsEnabled(): Boolean {
Log.d(TAG, "isZoomControlsEnabled")
return isZoomControlsEnabled ?: true
}
override fun setCompassEnabled(compass: Boolean) {
this.compass = compass
}
override fun setScrollGesturesEnabled(scrollGestures: Boolean) {
this.scrollGestures = scrollGestures
}
override fun setZoomGesturesEnabled(zoomGestures: Boolean) {
this.zoomGestures = zoomGestures
}
override fun setTiltGesturesEnabled(tiltGestures: Boolean) {
this.tiltGestures = tiltGestures
}
override fun setRotateGesturesEnabled(rotateGestures: Boolean) {
this.rotateGestures = rotateGestures
}
override fun setAllGesturesEnabled(gestures: Boolean) {
isAllGesturesEnabled = gestures
// Simulate MapLibre's UiSettings behavior
isScrollGesturesEnabled = gestures
isRotateGesturesEnabled = gestures
isTiltGesturesEnabled = gestures
isZoomGesturesEnabled = gestures
// Other gestures toggles double tap and quick zoom gestures
otherGestures = gestures
}
override fun isCompassEnabled(): Boolean {
return compass ?: true
}
override fun isScrollGesturesEnabled(): Boolean {
return scrollGestures ?: true
}
override fun isZoomGesturesEnabled(): Boolean {
return zoomGestures ?: true
}
override fun isTiltGesturesEnabled(): Boolean {
return tiltGestures ?: true
}
override fun isRotateGesturesEnabled(): Boolean {
return rotateGestures ?: true
}
fun getMapReadyCallback(): OnMapReadyCallback = OnMapReadyCallback { map ->
val uiSettings = map.uiSettings
compass?.let { uiSettings.isCompassEnabled = it }
scrollGestures?.let { uiSettings.isScrollGesturesEnabled = it }
zoomGestures?.let { uiSettings.isZoomGesturesEnabled = it }
tiltGestures?.let { uiSettings.isTiltGesturesEnabled = it }
rotateGestures?.let { uiSettings.isRotateGesturesEnabled = it }
isAllGesturesEnabled?.let { uiSettings.setAllGesturesEnabled(it) }
isZoomControlsEnabled?.let { uiSettings.isZoomControlsEnabled = it }
isMyLocationButtonEnabled?.let { uiSettings.isMyLocationButtonEnabled = it }
isIndoorLevelPickerEnabled?.let { uiSettings.isIndoorLevelPickerEnabled = it }
isMapToolbarEnabled?.let { uiSettings.isMapToolbarEnabled = it }
isScrollGesturesEnabledDuringRotateOrZoom?.let { uiSettings.isScrollGesturesEnabledDuringRotateOrZoom = it }
}
}

View file

@ -0,0 +1,68 @@
/*
* SPDX-FileCopyrightText: 2023 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package org.microg.gms.maps.hms.model
import android.content.res.Resources
import android.graphics.*
import android.os.Parcel
import android.util.Log
import com.google.android.gms.dynamic.IObjectWrapper
import com.google.android.gms.dynamic.ObjectWrapper
import com.google.android.gms.maps.model.internal.IBitmapDescriptorFactoryDelegate
import com.huawei.hms.maps.HuaweiMap
import com.huawei.hms.maps.model.BitmapDescriptorFactory
object BitmapDescriptorFactoryImpl : IBitmapDescriptorFactoryDelegate.Stub() {
private val TAG = "GmsMapBitmap"
private var resources: Resources? = null
fun initialize(resources: Resources?) {
BitmapDescriptorFactoryImpl.resources = resources ?: BitmapDescriptorFactoryImpl.resources
}
override fun fromResource(resourceId: Int): IObjectWrapper? {
return BitmapFactory.decodeResource(resources, resourceId)?.let {
ObjectWrapper.wrap(BitmapDescriptorFactory.fromBitmap(it))
}
}
override fun fromAsset(assetName: String): IObjectWrapper? {
return resources?.assets?.open(assetName)?.let {
BitmapFactory.decodeStream(it)
?.let { ObjectWrapper.wrap(BitmapDescriptorFactory.fromBitmap(it)) }
}
}
override fun fromFile(fileName: String): IObjectWrapper? {
return BitmapFactory.decodeFile(fileName)
?.let { ObjectWrapper.wrap(BitmapDescriptorFactory.fromBitmap(it)) }
}
override fun defaultMarker(): IObjectWrapper? {
return ObjectWrapper.wrap(BitmapDescriptorFactory.defaultMarker())
}
override fun defaultMarkerWithHue(hue: Float): IObjectWrapper? {
return ObjectWrapper.wrap(BitmapDescriptorFactory.defaultMarker(hue))
}
override fun fromBitmap(bitmap: Bitmap): IObjectWrapper? {
return ObjectWrapper.wrap(BitmapDescriptorFactory.fromBitmap(bitmap))
}
override fun fromPath(absolutePath: String): IObjectWrapper? {
return BitmapFactory.decodeFile(absolutePath)
?.let { ObjectWrapper.wrap(BitmapDescriptorFactory.fromBitmap(it)) }
}
override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =
if (super.onTransact(code, data, reply, flags)) {
true
} else {
Log.d(TAG, "onTransact [unknown]: $code, $data, $flags"); false
}
}

View file

@ -0,0 +1,124 @@
/*
* SPDX-FileCopyrightText: 2023 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package org.microg.gms.maps.hms.model
import android.os.Parcel
import android.util.Log
import com.google.android.gms.dynamic.IObjectWrapper
import com.google.android.gms.dynamic.ObjectWrapper
import com.google.android.gms.dynamic.unwrap
import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.PatternItem
import com.google.android.gms.maps.model.internal.ICircleDelegate
import com.huawei.hms.maps.model.Circle
import org.microg.gms.maps.hms.utils.toGms
import org.microg.gms.maps.hms.utils.toHms
class CircleImpl(private val circle: Circle) : ICircleDelegate.Stub() {
private var tag: Any? = null
override fun remove() {
circle.remove()
}
override fun getId(): String = circle.id
override fun setCenter(center: LatLng) {
circle.center = center.toHms()
}
override fun getCenter(): LatLng = circle.center.toGms()
override fun setRadius(radius: Double) {
circle.radius = radius
}
override fun getRadius(): Double = circle.radius
override fun setStrokeWidth(width: Float) {
circle.strokeWidth = width
}
override fun getStrokeWidth(): Float = circle.strokeWidth
override fun setStrokeColor(color: Int) {
circle.strokeColor = color
}
override fun getStrokeColor(): Int = circle.strokeColor
override fun setTag(tag: IObjectWrapper) {
this.tag = tag.unwrap()
}
override fun getTag(): IObjectWrapper? {
return ObjectWrapper.wrap(this.tag)
}
override fun setStrokePattern(pattern: List<PatternItem>?) {
circle.strokePattern = pattern?.map { it.toHms() }
}
override fun getStrokePattern(): List<PatternItem>? {
return circle.strokePattern?.map { it.toGms() }
}
override fun setFillColor(color: Int) {
circle.fillColor = color
}
override fun getFillColor(): Int = circle.fillColor
override fun setZIndex(zIndex: Float) {
circle.zIndex = zIndex
}
override fun getZIndex(): Float = circle.zIndex
override fun setVisible(visible: Boolean) {
circle.isVisible = visible
}
override fun isVisible(): Boolean = circle.isVisible
override fun setClickable(clickable: Boolean) {
circle.isClickable = clickable
}
override fun isClickable(): Boolean {
return circle.isClickable
}
override fun equalsRemote(other: ICircleDelegate?): Boolean = equals(other)
override fun hashCodeRemote(): Int = hashCode()
override fun hashCode(): Int {
return id.hashCode()
}
override fun toString(): String {
return id
}
override fun equals(other: Any?): Boolean {
if (other is CircleImpl) {
return other.id == id
}
return false
}
override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =
if (super.onTransact(code, data, reply, flags)) {
true
} else {
Log.d(TAG, "onTransact [unknown]: $code, $data, $flags"); false
}
companion object {
val TAG = "GmsMapCircle"
}
}

View file

@ -0,0 +1,144 @@
/*
* SPDX-FileCopyrightText: 2023 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package org.microg.gms.maps.hms.model
import android.os.Parcel
import android.util.Log
import com.google.android.gms.dynamic.IObjectWrapper
import com.google.android.gms.dynamic.ObjectWrapper
import com.google.android.gms.dynamic.unwrap
import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.LatLngBounds
import com.google.android.gms.maps.model.internal.IGroundOverlayDelegate
import com.huawei.hms.maps.model.GroundOverlay
import org.microg.gms.maps.hms.utils.toGms
import org.microg.gms.maps.hms.utils.toHms
class GroundOverlayImpl(private val groundOverlay: GroundOverlay) : IGroundOverlayDelegate.Stub() {
private var tag: Any? = null
override fun getId(): String {
return groundOverlay.id
}
override fun getPosition(): LatLng? {
return groundOverlay.position?.toGms()
}
override fun setPosition(pos: LatLng?) {
pos?.let { groundOverlay.position = it.toHms() }
}
override fun getWidth(): Float {
return groundOverlay.width
}
override fun getHeight(): Float {
return groundOverlay.height
}
override fun setDimensions(width: Float, height: Float) {
groundOverlay.setDimensions(width, height)
}
override fun getBounds(): LatLngBounds? {
return groundOverlay.bounds?.toGms()
}
override fun getBearing(): Float {
return groundOverlay.bearing
}
override fun setBearing(bearing: Float) {
groundOverlay.bearing = bearing
}
override fun setZIndex(zIndex: Float) {
groundOverlay.zIndex = zIndex
}
override fun getZIndex(): Float {
return groundOverlay.zIndex
}
override fun isVisible(): Boolean {
return groundOverlay.isVisible
}
override fun setVisible(visible: Boolean) {
groundOverlay.isVisible = visible
}
override fun getTransparency(): Float {
return groundOverlay.transparency
}
override fun setTransparency(transparency: Float) {
groundOverlay.transparency = transparency
}
override fun setDimension(dimension: Float) {
groundOverlay.setDimensions(dimension)
}
override fun setPositionFromBounds(bounds: LatLngBounds?) {
bounds?.let { groundOverlay.setPositionFromBounds(it.toHms()) }
}
override fun getTag(): IObjectWrapper? {
return ObjectWrapper.wrap(this.tag)
}
override fun isClickable(): Boolean = groundOverlay.isClickable
override fun setClickable(clickable: Boolean) {
groundOverlay.isClickable = clickable
}
override fun setImage(obj: IObjectWrapper?) {
groundOverlay.setImage(obj.unwrap())
}
override fun setTag(tag: IObjectWrapper) {
this.tag = tag.unwrap()
}
override fun equalsRemote(other: IGroundOverlayDelegate?): Boolean {
return this == other
}
override fun hashCode(): Int {
return groundOverlay.hashCode()
}
override fun hashCodeRemote(): Int {
return hashCode()
}
// override fun todo(obj: IObjectWrapper?) {
// Log.d(TAG, "Not yet implemented")
// }
override fun equals(other: Any?): Boolean {
return groundOverlay == other
}
override fun remove() {
Log.d(TAG, "Method: remove")
groundOverlay.remove()
}
override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =
if (super.onTransact(code, data, reply, flags)) {
true
} else {
Log.d(TAG, "onTransact [unknown]: $code, $data, $flags"); false
}
companion object {
private val TAG = "GmsMapGroundOverlay"
}
}

View file

@ -0,0 +1,154 @@
/*
* SPDX-FileCopyrightText: 2023 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package org.microg.gms.maps.hms.model
import android.os.Parcel
import android.util.Log
import com.google.android.gms.dynamic.IObjectWrapper
import com.google.android.gms.dynamic.ObjectWrapper
import com.google.android.gms.dynamic.unwrap
import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.MarkerOptions
import com.google.android.gms.maps.model.internal.IMarkerDelegate
import com.huawei.hms.maps.model.Marker
import org.microg.gms.maps.hms.GoogleMapImpl
import org.microg.gms.maps.hms.utils.toGms
import org.microg.gms.maps.hms.utils.toHms
class MarkerImpl(private val mapImpl: GoogleMapImpl, private val id: String, private val options: MarkerOptions) : IMarkerDelegate.Stub() {
private var marker: Marker? = null
private var tag: Any? = null
@Synchronized
fun update() {
marker = mapImpl.map?.addMarker(options.toHms())?.also {
mapImpl.markers[it.id] = this
}
}
override fun remove() {
marker?.remove()
}
override fun getId(): String = marker?.id ?: id
override fun setPosition(position: LatLng?) {
marker?.position = position?.toHms()
}
override fun getPosition(): LatLng? {
return marker?.position?.toGms()
}
override fun setTitle(title: String?) {
marker?.title = title
}
override fun getTitle(): String? = marker?.title
override fun setSnippet(snippet: String?) {
marker?.snippet = snippet
}
override fun getSnippet(): String? = marker?.snippet
override fun setDraggable(draggable: Boolean) {
marker?.isDraggable = draggable
}
override fun isDraggable(): Boolean = marker?.isDraggable ?: false
override fun showInfoWindow() {
marker?.showInfoWindow()
}
override fun hideInfoWindow() {
marker?.hideInfoWindow()
}
override fun isInfoWindowShown(): Boolean {
return marker?.isInfoWindowShown ?: false
}
override fun setVisible(visible: Boolean) {
marker?.isVisible = visible
}
override fun isVisible(): Boolean = marker?.isVisible ?: false
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other is IMarkerDelegate) return other.id == id
return false
}
override fun equalsRemote(other: IMarkerDelegate?): Boolean = equals(other)
override fun hashCode(): Int {
return id.hashCode()
}
override fun toString(): String {
return "$id ($title)"
}
override fun hashCodeRemote(): Int = hashCode()
override fun setIcon(obj: IObjectWrapper?) {
marker?.setIcon(obj.unwrap())
}
override fun setAnchor(x: Float, y: Float) {
marker?.setMarkerAnchor(x, y)
}
override fun setFlat(flat: Boolean) {
marker?.isFlat = flat
}
override fun isFlat(): Boolean {
return marker?.isFlat ?: false
}
override fun setRotation(rotation: Float) {
marker?.rotation = rotation
}
override fun getRotation(): Float = marker?.rotation ?: 0f
override fun setInfoWindowAnchor(x: Float, y: Float) {
marker?.setInfoWindowAnchor(x, y)
}
override fun setAlpha(alpha: Float) {
marker?.alpha = alpha
}
override fun getAlpha(): Float = marker?.alpha ?: 0f
override fun setZIndex(zIndex: Float) {
marker?.zIndex = zIndex
}
override fun getZIndex(): Float = marker?.zIndex ?: 0f
override fun setTag(obj: IObjectWrapper?) {
this.tag = obj.unwrap()
}
override fun getTag(): IObjectWrapper = ObjectWrapper.wrap(this.tag)
override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =
if (super.onTransact(code, data, reply, flags)) {
true
} else {
Log.d(TAG, "onTransact [unknown]: $code, $data, $flags"); false
}
companion object {
private val TAG = "GmsMapMarker"
}
}

View file

@ -0,0 +1,172 @@
/*
* SPDX-FileCopyrightText: 2023 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package org.microg.gms.maps.hms.model
import android.os.Parcel
import android.util.Log
import com.google.android.gms.dynamic.IObjectWrapper
import com.google.android.gms.dynamic.ObjectWrapper
import com.google.android.gms.dynamic.unwrap
import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.PatternItem
import com.google.android.gms.maps.model.internal.IPolygonDelegate
import com.huawei.hms.maps.model.Polygon
import org.microg.gms.maps.hms.utils.toGms
import org.microg.gms.maps.hms.utils.toHms
import org.microg.gms.utils.warnOnTransactionIssues
class PolygonImpl(private val polygon: Polygon) : IPolygonDelegate.Stub() {
private var tag: Any? = null
override fun remove() {
polygon.remove()
}
override fun getId(): String = polygon.id
override fun setPoints(points: List<LatLng>) {
polygon.points = points.map { it.toHms() }
}
override fun getPoints(): List<LatLng> = polygon.points.map { it.toGms() }
override fun setHoles(holes: List<Any?>?) {
if (holes == null) {
polygon.holes = emptyList()
} else {
val outHmsHoles: MutableList<MutableList<com.huawei.hms.maps.model.LatLng>> =
ArrayList()
for (out in holes) {
if (out is List<*>) {
val inHmsHoles: MutableList<com.huawei.hms.maps.model.LatLng> = ArrayList()
for (inn in out) {
if (inn is LatLng) {
inHmsHoles.add(inn.toHms())
}
}
outHmsHoles.add(inHmsHoles)
}
}
polygon.holes = outHmsHoles
}
}
override fun getHoles(): List<Any?> {
val outHoles = polygon.holes ?: return emptyList()
val outGmsHoles: MutableList<MutableList<LatLng>> = ArrayList()
for (inHoles in outHoles) {
if (inHoles != null) {
val inGmsHoles: MutableList<LatLng> = ArrayList()
for (inHole in inHoles) {
inGmsHoles.add(inHole.toGms())
}
outGmsHoles.add(inGmsHoles)
}
}
return outGmsHoles
}
override fun setStrokeWidth(width: Float) {
polygon.strokeWidth = width
}
override fun getStrokeWidth(): Float = polygon.strokeWidth
override fun setStrokeColor(color: Int) {
polygon.strokeColor = color
}
override fun getStrokeColor(): Int = polygon.strokeColor
override fun setFillColor(color: Int) {
polygon.fillColor = color
}
override fun getFillColor(): Int {
return polygon.fillColor
}
override fun setZIndex(zIndex: Float) {
polygon.zIndex = zIndex
}
override fun getZIndex(): Float {
return polygon.zIndex
}
override fun setVisible(visible: Boolean) {
polygon.isVisible = visible
}
override fun isVisible(): Boolean {
return polygon.isVisible
}
override fun setGeodesic(geod: Boolean) {
polygon.isGeodesic = geod
}
override fun isGeodesic(): Boolean {
return polygon.isGeodesic
}
override fun getStrokeJointType(): Int {
return polygon.strokeJointType
}
override fun getStrokePattern(): List<PatternItem>? {
return polygon.strokePattern?.map { it.toGms() }
}
override fun getTag(): IObjectWrapper {
return ObjectWrapper.wrap(this.tag)
}
override fun isClickable(): Boolean {
return polygon.isClickable
}
override fun setClickable(clickable: Boolean) {
polygon.isClickable = clickable
}
override fun setStrokeJointType(jointType: Int) {
polygon.strokeJointType = jointType
}
override fun setStrokePattern(pattern: List<PatternItem>?) {
polygon.strokePattern = pattern?.map { it.toHms() }
}
override fun setTag(tag: IObjectWrapper?) {
this.tag = tag.unwrap()
}
override fun equalsRemote(other: IPolygonDelegate?): Boolean = equals(other)
override fun hashCodeRemote(): Int = hashCode()
override fun hashCode(): Int {
return id.hashCode()
}
override fun toString(): String {
return id
}
override fun equals(other: Any?): Boolean {
if (other is PolygonImpl) {
return other.id == id
}
return false
}
override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean = warnOnTransactionIssues(code, reply, flags) { super.onTransact(code, data, reply, flags) }
companion object {
private val TAG = "GmsMapPolygon"
}
}

View file

@ -0,0 +1,220 @@
/*
* SPDX-FileCopyrightText: 2023 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package org.microg.gms.maps.hms.model
import android.os.Parcel
import android.util.Log
import com.google.android.gms.dynamic.IObjectWrapper
import com.google.android.gms.dynamic.ObjectWrapper
import com.google.android.gms.dynamic.unwrap
import com.google.android.gms.maps.model.*
import com.google.android.gms.maps.model.BitmapDescriptor
import com.google.android.gms.maps.model.CustomCap
import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.PatternItem
import com.google.android.gms.maps.model.PolylineOptions
import com.google.android.gms.maps.model.internal.IPolylineDelegate
import com.huawei.hms.maps.model.*
import com.huawei.hms.maps.model.ButtCap as HmsButtCap
import com.huawei.hms.maps.model.Cap as HmsCap
import com.huawei.hms.maps.model.CustomCap as HmsCustomCap
import com.huawei.hms.maps.model.RoundCap as HmsRoundCap
import com.huawei.hms.maps.model.SquareCap as HmsSquareCap
import com.huawei.hms.maps.model.LatLng as HmsLatLng
import org.microg.gms.maps.hms.utils.toGms
import org.microg.gms.maps.hms.utils.toGmsPolylineWidth
import org.microg.gms.maps.hms.utils.toHms
import org.microg.gms.maps.hms.utils.toHmsPolylineWidth
class PolylineImpl(private val polyline: Polyline, polylineOptions: PolylineOptions) : IPolylineDelegate.Stub() {
private var tag: Any? = null
private val linePoints = arrayListOf<LatLng>()
private var lastPointsHash: Int = 0
private val toHmsCache = mutableMapOf<LatLng, HmsLatLng>()
private fun List<LatLng>.toHmsList(): List<HmsLatLng> {
return this.map { latLng ->
toHmsCache.getOrPut(latLng) { latLng.toHms() }
}
}
override fun remove() {
linePoints.clear()
toHmsCache.clear()
polyline.remove()
}
override fun getId(): String = polyline.id
override fun setPoints(points: List<LatLng>) {
if (linePoints.size == points.size && linePoints == points) {
Log.d(TAG, "setPoints skipped: identical points")
return
}
val newHash = points.hashCode()
if (newHash == lastPointsHash) {
Log.d(TAG, "setPoints skipped: hash unchanged")
return
}
lastPointsHash = newHash
linePoints.clear()
linePoints.addAll(points)
polyline.points = linePoints.toHmsList()
Log.d(TAG, "setPoints updated, size=${linePoints.size}")
}
override fun getPoints(): List<LatLng> {
return linePoints
}
override fun setWidth(width: Float) {
polyline.width = toHmsPolylineWidth(width)
}
override fun getWidth(): Float {
return toGmsPolylineWidth(polyline.width)
}
override fun setColor(color: Int) {
polyline.color = color
}
override fun getColor(): Int {
return polyline.color
}
override fun setZIndex(zIndex: Float) {
Log.d(TAG, "setZIndex: $zIndex")
polyline.zIndex = zIndex
}
override fun getZIndex(): Float {
Log.d(TAG, "getZIndex")
return polyline.zIndex
}
override fun setVisible(visible: Boolean) {
polyline.isVisible = visible
}
override fun isVisible(): Boolean {
return polyline.isVisible
}
override fun setGeodesic(geod: Boolean) {
Log.d(TAG, "setGeodesic: $geod")
polyline.isGeodesic = geod
}
override fun isGeodesic(): Boolean {
Log.d(TAG, "isGeodesic")
return polyline.isGeodesic
}
override fun setClickable(clickable: Boolean) {
Log.d(TAG, "setClickable: $clickable")
polyline.isClickable = clickable
}
override fun isClickable(): Boolean {
Log.d(TAG, "isClickable")
return polyline.isClickable
}
override fun equalsRemote(other: IPolylineDelegate?): Boolean = equals(other)
override fun hashCodeRemote(): Int = hashCode()
override fun hashCode(): Int {
return id.hashCode()
}
override fun toString(): String {
return id
}
override fun equals(other: Any?): Boolean {
if (other is PolylineImpl) {
return other.id == id
}
return false
}
override fun getPattern(): List<PatternItem>? {
Log.d(TAG, "Method: getStrokePattern")
return polyline.pattern?.map { it.toGms() }
}
override fun getTag(): IObjectWrapper {
return ObjectWrapper.wrap(this.tag)
}
override fun setJointType(jointType: Int) {
polyline.jointType = jointType
}
override fun getJointType(): Int {
return polyline.jointType
}
override fun setPattern(pattern: List<PatternItem>?) {
Log.d(TAG, "Method: setStrokePattern")
polyline.pattern = pattern?.map { it.toHms() }
}
override fun setTag(tag: IObjectWrapper?) {
this.tag = tag.unwrap()
}
override fun setEndCap(endCap: Cap) {
polyline.endCap = endCap.toHms()
}
override fun getEndCap(): Cap {
return polyline.endCap.toGms()
}
override fun setStartCap(startCap: Cap) {
polyline.startCap = startCap.toHms()
}
override fun getStartCap(): Cap {
return polyline.startCap.toGms()
}
private fun Cap.toHms(): HmsCap {
return when (this) {
is ButtCap -> HmsButtCap()
is SquareCap -> HmsSquareCap()
is RoundCap -> HmsRoundCap()
is CustomCap -> HmsCustomCap(bitmapDescriptor.remoteObject.unwrap(), refWidth)
else -> HmsButtCap()
}
}
private fun com.huawei.hms.maps.model.Cap.toGms(): Cap {
return when (this) {
is HmsButtCap -> ButtCap()
is HmsSquareCap -> SquareCap()
is HmsRoundCap -> RoundCap()
is HmsCustomCap -> CustomCap(BitmapDescriptor(ObjectWrapper.wrap(bitmapDescriptor)), refWidth)
else -> ButtCap()
}
}
override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =
if (super.onTransact(code, data, reply, flags)) {
true
} else {
Log.d(TAG, "onTransact [unknown]: $code, $data, $flags"); false
}
companion object {
private val TAG = "GmsMapPolyline"
}
}

View file

@ -0,0 +1,81 @@
/*
* SPDX-FileCopyrightText: 2023 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package org.microg.gms.maps.hms.model
import android.os.Parcel
import android.util.Log
import com.google.android.gms.maps.model.internal.ITileOverlayDelegate
import com.huawei.hms.maps.model.TileOverlay
class TileOverlayImpl(private val tileOverlay: TileOverlay) : ITileOverlayDelegate.Stub() {
override fun clearTileCache() {
tileOverlay.clearTileCache()
}
override fun equals(other: Any?): Boolean {
return tileOverlay == other
}
override fun getFadeIn(): Boolean {
return tileOverlay.fadeIn
}
override fun getId(): String {
return tileOverlay.id
}
override fun getTransparency(): Float {
return tileOverlay.transparency
}
override fun getZIndex(): Float {
return tileOverlay.zIndex
}
override fun hashCode(): Int {
return tileOverlay.hashCode()
}
override fun isVisible(): Boolean {
return tileOverlay.isVisible
}
override fun remove() {
return tileOverlay.remove()
}
override fun setFadeIn(fadeIn: Boolean) {
tileOverlay.fadeIn = fadeIn
}
override fun setTransparency(transparency: Float) {
tileOverlay.transparency = transparency
}
override fun setVisible(visible: Boolean) {
tileOverlay.isVisible = visible
}
override fun setZIndex(zIndex: Float) {
tileOverlay.zIndex = zIndex
}
override fun equalsRemote(other: ITileOverlayDelegate): Boolean = tileOverlay == (other as? TileOverlayImpl)?.tileOverlay
override fun hashCodeRemote(): Int = tileOverlay.hashCode()
override fun onTransact(code: Int, data: Parcel, reply: Parcel?, flags: Int): Boolean =
if (super.onTransact(code, data, reply, flags)) {
Log.e(TAG, "onTransact [known]: $code, $data, $flags")
true
} else {
Log.d(TAG, "onTransact [unknown]: $code, $data, $flags"); false
}
companion object {
private val TAG = "GmsMapTileOverlay"
}
}

View file

@ -0,0 +1,80 @@
/*
* SPDX-FileCopyrightText: 2023 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package org.microg.gms.maps.hms.utils
import android.content.Context
import android.content.ContextWrapper
import android.content.Intent
import android.content.SharedPreferences
import android.view.LayoutInflater
import androidx.annotation.RequiresApi
import com.huawei.hms.maps.MapClientIdentify
import com.huawei.hms.maps.utils.MapClientUtil
import org.microg.gms.common.Constants
import java.io.File
class MapContext(private val context: Context) : ContextWrapper(context.createPackageContext(Constants.GMS_PACKAGE_NAME, Context.CONTEXT_INCLUDE_CODE or Context.CONTEXT_IGNORE_SECURITY)) {
private var layoutInflater: LayoutInflater? = null
private val appContext: Context
get() = context.applicationContext ?: context
override fun getApplicationContext(): Context {
return this
}
override fun getCacheDir(): File {
val cacheDir = File(appContext.cacheDir, "com.google.android.gms")
cacheDir.mkdirs()
return cacheDir
}
override fun getFilesDir(): File {
val filesDir = File(appContext.filesDir, "com.google.android.gms")
filesDir.mkdirs()
return filesDir
}
override fun getClassLoader(): ClassLoader {
return MapContext::class.java.classLoader!!
}
override fun getPackageName(): String {
// Use original package name for requests not from HMS MapClientIdentify
val stackTrace = Thread.currentThread().stackTrace
if (stackTrace.any { it.className == MapClientUtil::class.java.name || it.className == MapClientIdentify::class.java.name }) return Constants.GMS_PACKAGE_NAME
return appContext.packageName
}
override fun getSharedPreferences(name: String?, mode: Int): SharedPreferences {
return appContext.getSharedPreferences("com.google.android.gms_$name", mode)
}
override fun getSystemService(name: String): Any? {
if (name == Context.LAYOUT_INFLATER_SERVICE) {
if (layoutInflater == null) {
layoutInflater = super.getSystemService(name) as LayoutInflater
layoutInflater?.cloneInContext(this)?.let { layoutInflater = it }
}
if (layoutInflater != null) {
return layoutInflater
}
}
return context.getSystemService(name)
}
override fun startActivity(intent: Intent?) {
context.startActivity(intent)
}
@RequiresApi(24)
override fun createDeviceProtectedStorageContext(): Context {
return appContext.createDeviceProtectedStorageContext()
}
companion object {
val TAG = "GmsMapContext"
}
}

View file

@ -0,0 +1,71 @@
/**
* SPDX-FileCopyrightText: 2025 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package org.microg.gms.maps.hms.utils
import android.view.View
import android.view.ViewGroup
enum class MapUiElement(val classType: String) {
MyLocationButton("MyLocationButton"),
ZoomView("ZoomView"),
CompassView("CompassView")
}
class MapUiController(private val rootView: ViewGroup) {
private val uiViews = mutableMapOf<MapUiElement, View>()
private val uiStates = mutableMapOf<MapUiElement, Boolean>()
init {
MapUiElement.entries.forEach { element ->
rootView.waitForChild(element.classType) { view ->
uiViews[element] = view
val uiEnabled = isUiEnabled(element)
view.isEnabled = uiEnabled
view.alpha = if (uiEnabled) 1f else 0f
}
}
}
fun setUiEnabled(element: MapUiElement, enabled: Boolean) {
uiStates[element] = enabled
uiViews[element]?.alpha = if (enabled) 1f else 0f
uiViews[element]?.isEnabled = enabled
}
fun isUiEnabled(element: MapUiElement): Boolean {
return uiStates[element] ?: true
}
fun initUiStates(states: Map<MapUiElement, Boolean>) {
states.forEach { (element, enabled) ->
setUiEnabled(element, enabled)
}
}
}
private fun ViewGroup.waitForChild(classType: String, onReady: (View) -> Unit) {
for (i in 0 until childCount) {
val child = getChildAt(i)
if (child.javaClass.name.contains(classType)) {
onReady(child)
return
}
if (child is ViewGroup) {
child.waitForChild(classType, onReady)
}
}
setOnHierarchyChangeListener(object : ViewGroup.OnHierarchyChangeListener {
override fun onChildViewAdded(parent: View?, child: View?) {
if (child?.javaClass?.name?.contains(classType) == true) {
onReady(child)
}
}
override fun onChildViewRemoved(parent: View?, child: View?) {}
})
}

View file

@ -0,0 +1,239 @@
/*
* SPDX-FileCopyrightText: 2023 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package org.microg.gms.maps.hms.utils
import android.content.res.Configuration
import android.os.Bundle
import com.google.android.gms.dynamic.unwrap
import com.google.android.gms.maps.GoogleMapOptions
import com.google.android.gms.maps.internal.ICancelableCallback
import com.huawei.hms.maps.HuaweiMap
import com.huawei.hms.maps.HuaweiMapOptions
import com.huawei.hms.maps.model.*
import org.microg.gms.maps.hms.R
import com.google.android.gms.maps.model.CameraPosition as GmsCameraPosition
import com.google.android.gms.maps.model.CircleOptions as GmsCircleOptions
import com.google.android.gms.maps.model.Dash as GmsDash
import com.google.android.gms.maps.model.Dot as GmsDot
import com.google.android.gms.maps.model.Gap as GmsGap
import com.google.android.gms.maps.model.GroundOverlayOptions as GmsGroundOverlayOptions
import com.google.android.gms.maps.model.LatLng as GmsLatLng
import com.google.android.gms.maps.model.LatLngBounds as GmsLatLngBounds
import com.google.android.gms.maps.model.MapStyleOptions as GmsMapStyleOptions
import com.google.android.gms.maps.model.MarkerOptions as GmsMarkerOptions
import com.google.android.gms.maps.model.PatternItem as GmsPatternItem
import com.google.android.gms.maps.model.PolygonOptions as GmsPolygonOptions
import com.google.android.gms.maps.model.PolylineOptions as GmsPolylineOptions
import com.google.android.gms.maps.model.Tile as GmsTile
import com.google.android.gms.maps.model.TileOverlayOptions as GmsTileOverlayOptions
import com.google.android.gms.maps.model.VisibleRegion as GmsVisibleRegion
fun GmsCameraPosition.toHms(): CameraPosition {
return CameraPosition.Builder().target(target.toHms()).zoom(toHmsZoom(zoom)).tilt(tilt)
.bearing(toHmsBearing(bearing)).build()
}
fun GmsCircleOptions.toHms(): CircleOptions =
CircleOptions().center(center.toHms()).clickable(isClickable).fillColor(fillColor)
.radius(radius).strokeColor(strokeColor).strokeWidth(strokeWidth).visible(isVisible)
.zIndex(zIndex)
fun GmsPatternItem.toHms(): PatternItem {
return when (this) {
is GmsDash -> Dash(length)
is GmsDot -> Dot()
is GmsGap -> Gap(length)
else -> PatternItem(0,0f)
}
}
fun GoogleMapOptions.toHms(): HuaweiMapOptions {
val huaweiMapOptions = HuaweiMapOptions()
camera?.let { huaweiMapOptions.camera(camera?.toHms()) }
if (maxZoomPreference != 0f) {
huaweiMapOptions.maxZoomPreference(toHmsZoom(maxZoomPreference))
}
if (minZoomPreference != 0f) {
huaweiMapOptions.minZoomPreference(toHmsZoom(minZoomPreference))
}
latLngBoundsForCameraTarget?.let {
huaweiMapOptions.latLngBoundsForCameraTarget(
latLngBoundsForCameraTarget?.toHms()
)
}
return huaweiMapOptions
.compassEnabled(isCompassEnabled)
.liteMode(liteMode)
// .mapType(mapType)
.rotateGesturesEnabled(rotateGesturesEnabled == true)
.scrollGesturesEnabled(scrollGesturesEnabled == true)
.tiltGesturesEnabled(tiltGesturesEnabled == true)
.useViewLifecycleInFragment(useViewLifecycleInFragment == true)
.zOrderOnTop(zOrderOnTop == true)
.zoomControlsEnabled(zoomControlsEnabled == true)
.zoomGesturesEnabled(zoomGesturesEnabled == true)
}
fun GmsLatLng.toHms(): LatLng =
LatLng(latitude, longitude)
fun GmsLatLngBounds.toHms(): LatLngBounds =
LatLngBounds(
LatLng(if(southwest.latitude.isNaN()) 0.0 else southwest.latitude, if(southwest.longitude.isNaN()) 0.0 else southwest.longitude),
LatLng(if(northeast.latitude.isNaN()) 0.0 else northeast.latitude, if(northeast.longitude.isNaN()) 0.0 else northeast.longitude)
)
fun ICancelableCallback.toHms(): HuaweiMap.CancelableCallback =
object : HuaweiMap.CancelableCallback {
override fun onFinish() = this@toHms.onFinish()
override fun onCancel() = this@toHms.onCancel()
}
fun GmsMarkerOptions.toHms(): MarkerOptions {
val markerOptions = MarkerOptions()
icon?.let { markerOptions.icon(it.remoteObject.unwrap()) }
return markerOptions.alpha(alpha).anchorMarker(anchorU, anchorV).draggable(isDraggable)
.flat(isFlat).infoWindowAnchor(infoWindowAnchorU, infoWindowAnchorV)
.position(position.toHms()).rotation(rotation).snippet(snippet).title(title)
.visible(isVisible).zIndex(zIndex)
}
fun GmsGroundOverlayOptions.toHms(): GroundOverlayOptions {
val groundOverlayOptions = GroundOverlayOptions()
groundOverlayOptions.anchor(anchorU, anchorV).bearing(bearing)
.clickable(isClickable)
.image(image.remoteObject.unwrap())
.visible(isVisible)
.zIndex(zIndex)
location?.let {
if (height > 0) {
groundOverlayOptions.position(it.toHms(), width, height)
} else {
groundOverlayOptions.position(it.toHms(), width)
}
}
bounds?.let { groundOverlayOptions.positionFromBounds(it.toHms()) }
return groundOverlayOptions
}
fun GmsTileOverlayOptions.toHms(): TileOverlayOptions {
return TileOverlayOptions().tileProvider(tileProvider?.let { TileProvider { x, y, zoom -> it.getTile(x, y, zoom)?.toHms() } })
.fadeIn(fadeIn)
.visible(isVisible)
.transparency(transparency)
.zIndex(zIndex)
}
fun GmsTile.toHms(): Tile = Tile(width, height, data)
fun GmsPolygonOptions.toHms(): PolygonOptions {
val polygonOptions = PolygonOptions()
holes?.map {
val hole = it?.map { it?.toHms() }
polygonOptions.addHole(hole)
}
return polygonOptions.addAll(points.map { it.toHms() })
.clickable(isClickable)
.fillColor(fillColor)
.geodesic(isGeodesic)
.strokeColor(strokeColor).strokeJointType(strokeJointType).strokeWidth(strokeWidth)
.visible(isVisible)
.zIndex(zIndex)
}
fun GmsPolylineOptions.toHms(): PolylineOptions {
val polylineOptions = PolylineOptions()
polylineOptions.addAll(points.map { it.toHms() })
return polylineOptions.clickable(isClickable).color(color).geodesic(isGeodesic)
.jointType(jointType).visible(isVisible).width(toHmsPolylineWidth(width)).zIndex(zIndex)
}
fun toHmsPolylineWidth(gmsWidth: Float): Float = gmsWidth / 3
fun toHmsZoom(gmsZoom: Float?): Float {
if (gmsZoom == null) {
return 3f
}
if (gmsZoom < 3) {
return 3f
} else if (gmsZoom > 18) {
return 18f
}
return gmsZoom
}
fun toHmsBearing(gmsBearing: Float): Float {
return 360 - gmsBearing
}
fun Bundle.toHms(): Bundle {
val newBundle = Bundle(this)
val oldLoader = newBundle.classLoader
newBundle.classLoader = GmsLatLng::class.java.classLoader
for (key in newBundle.keySet()) {
when (val value = newBundle.get(key)) {
is GmsCameraPosition -> newBundle.putParcelable(key, value.toHms())
is GmsLatLng -> newBundle.putParcelable(key, value.toHms())
is GmsLatLngBounds -> newBundle.putParcelable(key, value.toHms())
is Bundle -> newBundle.putBundle(key, value.toHms())
}
}
newBundle.classLoader = oldLoader
return newBundle
}
fun CameraPosition.toGms(): GmsCameraPosition =
GmsCameraPosition(target.toGms(), zoom, tilt, bearing)
fun PatternItem.toGms(): GmsPatternItem = when (this) {
is Dot -> GmsDot()
is Dash -> GmsDash(length)
is Gap -> GmsGap(length)
else -> GmsGap(0f)
}
fun LatLng.toGms(): GmsLatLng = GmsLatLng(latitude, longitude)
fun LatLngBounds.toGms(): GmsLatLngBounds = GmsLatLngBounds(
GmsLatLng(southwest.latitude, southwest.longitude),
GmsLatLng(northeast.latitude, northeast.longitude)
)
fun VisibleRegion.toGms(): GmsVisibleRegion =
GmsVisibleRegion(
nearLeft.toGms(),
nearRight.toGms(),
farLeft.toGms(),
farRight.toGms(),
latLngBounds.toGms()
)
fun toGmsPolylineWidth(hmsWidth: Float): Float = hmsWidth * 3
fun Bundle.toGms(): Bundle {
val newBundle = Bundle(this)
val oldLoader = newBundle.classLoader
newBundle.classLoader = LatLng::class.java.classLoader
for (key in newBundle.keySet()) {
when (val value = newBundle.get(key)) {
is CameraPosition -> newBundle.putParcelable(key, value.toGms())
is LatLng -> newBundle.putParcelable(key, value.toGms())
is LatLngBounds -> newBundle.putParcelable(key, value.toGms())
is Bundle -> newBundle.putBundle(key, value.toGms())
}
}
newBundle.classLoader = oldLoader
return newBundle
}
fun GmsMapStyleOptions.toHms(context: MapContext): MapStyleOptions {
val nightMode = context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
if (nightMode == Configuration.UI_MODE_NIGHT_YES) {
return MapStyleOptions.loadRawResourceStyle(context, R.raw.mapstyle_night_hms)
}
return MapStyleOptions.loadRawResourceStyle(context, R.raw.mapstyle_grayscale_hms)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 946 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

View file

@ -0,0 +1,101 @@
[
{
"featureType": "all",
"elementType": "geometry",
"stylers": [
{
"color": "#f5f5f5"
}
]
},
{
"featureType": "all",
"elementType": "labels.icon",
"stylers": [
{
"saturation": -100
}
]
},
{
"featureType": "all",
"elementType": "labels.text",
"stylers": [
{
"saturation": -100
}
]
},
{
"featureType": "poi",
"elementType": "geometry",
"stylers": [
{
"color": "#eeeeee"
}
]
},
{
"featureType": "poi.park",
"elementType": "geometry",
"stylers": [
{
"color": "#e5e5e5"
}
]
},
{
"featureType": "road",
"elementType": "geometry",
"stylers": [
{
"color": "#ffffff"
}
]
},
{
"featureType": "road.highway",
"elementType": "geometry",
"stylers": [
{
"color": "#dadada"
}
]
},
{
"featureType": "road.highway",
"elementType": "labels.icon",
"stylers": [
{
"lightness": 30
}
]
},
{
"featureType": "transit.line",
"elementType": "geometry",
"stylers": [
{
"color": "#e5e5e5"
}
]
},
{
"featureType": "transit.station",
"elementType": "geometry",
"stylers": [
{
"color": "#eeeeee"
}
]
},
{
"featureType": "water",
"elementType": "geometry",
"stylers": [
{
"color": "#c9c9c9"
}
]
}
]

View file

@ -0,0 +1,376 @@
[
{
"mapFeature": "all",
"options": "geometry",
"paint": {
"color": "#25292B"
}
},
{
"mapFeature": "all",
"options": "labels.text.stroke",
"paint": {
"color": "#25292B"
}
},
{
"mapFeature": "all",
"options": "labels.icon",
"paint": {
"icon-type": "night"
}
},
{
"mapFeature": "administrative",
"options": "labels.text.fill",
"paint": {
"color": "#E0D5C7"
}
},
{
"mapFeature": "administrative.country",
"options": "geometry",
"paint": {
"color": "#787272"
}
},
{
"mapFeature": "administrative.province",
"options": "geometry",
"paint": {
"color": "#666262"
}
},
{
"mapFeature": "administrative.province",
"options": "labels.text.fill",
"paint": {
"color": "#928C82"
}
},
{
"mapFeature": "administrative.district",
"options": "labels.text.fill",
"paint": {
"color": "#AAA59E"
}
},
{
"mapFeature": "administrative.locality",
"options": "labels.text.fill",
"paint": {
"color": "#928C82"
}
},
{
"mapFeature": "landcover.parkland.natural",
"visibility": false,
"options": "geometry",
"paint": {
"color": "#25292B"
}
},
{
"mapFeature": "landcover.parkland.public-garden",
"options": "geometry",
"paint": {
"color": "#283631"
}
},
{
"mapFeature": "landcover.parkland.human-made",
"visibility": false,
"options": "geometry",
"paint": {
"color": "#25292B"
}
},
{
"mapFeature": "landcover.parkland.public-garden",
"options": "labels.text.fill",
"paint": {
"color": "#8BAA7F"
}
},
{
"mapFeature": "landcover.hospital",
"options": "geometry",
"paint": {
"color": "#382B2B"
}
},
{
"mapFeature": "landcover",
"options": "labels.text.fill",
"paint": {
"color": "#928C82"
}
},
{
"mapFeature": "poi.shopping",
"options": "labels.text.fill",
"paint": {
"color": "#9C8C5F"
}
},
{
"mapFeature": "landcover.human-made.building",
"visibility": false,
"options": "labels.text.fill",
"paint": {
"color": "#000000"
}
},
{
"mapFeature": "poi.tourism",
"options": "labels.text.fill",
"paint": {
"color": "#578C8C"
}
},
{
"mapFeature": "poi.beauty",
"options": "labels.text.fill",
"paint": {
"color": "#9E7885"
}
},
{
"mapFeature": "poi.leisure",
"options": "labels.text.fill",
"paint": {
"color": "#916A91"
}
},
{
"mapFeature": "poi.eating&drinking",
"options": "labels.text.fill",
"paint": {
"color": "#996E50"
}
},
{
"mapFeature": "poi.lodging",
"options": "labels.text.fill",
"paint": {
"color": "#A3678F"
}
},
{
"mapFeature": "poi.health-care",
"options": "labels.text.fill",
"paint": {
"color": "#B07373"
}
},
{
"mapFeature": "poi.public-service",
"options": "labels.text.fill",
"paint": {
"color": "#5F7299"
}
},
{
"mapFeature": "poi.business",
"options": "labels.text.fill",
"paint": {
"color": "#6B6B9D"
}
},
{
"mapFeature": "poi.automotive",
"options": "labels.text.fill",
"paint": {
"color": "#6B6B9D"
}
},
{
"mapFeature": "poi.sports.outdoor",
"options": "labels.text.fill",
"paint": {
"color": "#597A52"
}
},
{
"mapFeature": "poi.sports.other",
"options": "labels.text.fill",
"paint": {
"color": "#3E90AB"
}
},
{
"mapFeature": "poi.natural",
"options": "labels.text.fill",
"paint": {
"color": "#597A52"
}
},
{
"mapFeature": "poi.miscellaneous",
"options": "labels.text.fill",
"paint": {
"color": "#A7ADB0"
}
},
{
"mapFeature": "road.highway",
"options": "labels.text.fill",
"paint": {
"color": "#E3CAA2"
}
},
{
"mapFeature": "road.national",
"options": "labels.text.fill",
"paint": {
"color": "#A7ADB0"
}
},
{
"mapFeature": "road.province",
"options": "labels.text.fill",
"paint": {
"color": "#A7ADB0"
}
},
{
"mapFeature": "road.city-arterial",
"options": "labels.text.fill",
"paint": {
"color": "#808689"
}
},
{
"mapFeature": "road.minor-road",
"options": "labels.text.fill",
"paint": {
"color": "#808689"
}
},
{
"mapFeature": "road.sidewalk",
"options": "labels.text.fill",
"paint": {
"color": "#808689"
}
},
{
"mapFeature": "road.highway.country",
"options": "geometry.fill",
"paint": {
"color": "#8C7248"
}
},
{
"mapFeature": "road.highway.city",
"options": "geometry.fill",
"paint": {
"color": "#706148"
}
},
{
"mapFeature": "road.national",
"options": "geometry.fill",
"paint": {
"color": "#444A4D"
}
},
{
"mapFeature": "road.province",
"options": "geometry.fill",
"paint": {
"color": "#444A4D"
}
},
{
"mapFeature": "road.city-arterial",
"options": "geometry.fill",
"paint": {
"color": "#434B4F"
}
},
{
"mapFeature": "road.minor-road",
"options": "geometry.fill",
"paint": {
"color": "#434B4F"
}
},
{
"mapFeature": "road.sidewalk",
"options": "geometry.fill",
"paint": {
"color": "#434B4F"
}
},
{
"mapFeature": "transit",
"options": "labels.text.fill",
"paint": {
"color": "#4F81B3"
}
},
{
"mapFeature": "transit.railway",
"options": "geometry",
"paint": {
"color": "#5B2E57"
}
},
{
"mapFeature": "transit.ferry-line",
"options": "geometry",
"paint": {
"color": "#364D67"
}
},
{
"mapFeature": "transit.airport",
"options": "geometry",
"paint": {
"color": "#2C3235"
}
},
{
"mapFeature": "water",
"options": "geometry",
"paint": {
"color": "#243850"
}
},
{
"mapFeature": "water",
"options": "labels.text.fill",
"paint": {
"color": "#4C6481"
}
},
{
"mapFeature": "trafficInfo.smooth",
"options": "geometry",
"paint": {
"color": "#348734"
}
},
{
"mapFeature": "trafficInfo.amble",
"options": "geometry",
"paint": {
"color": "#947000"
}
},
{
"mapFeature": "trafficInfo.congestion",
"options": "geometry",
"paint": {
"color": "#A4281E"
}
},
{
"mapFeature": "trafficInfo.extremelycongestion",
"options": "geometry",
"paint": {
"color": "#7A120B"
}
}
]

View file

@ -0,0 +1 @@
<resources></resources>

View file

@ -0,0 +1,84 @@
/*
* Copyright 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.
*/
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
dependencies {
implementation project(':play-services-maps')
implementation project(':play-services-base-core')
implementation project(':play-services-location')
implementation("org.maplibre.gl:android-sdk:10.2.0")
implementation("org.maplibre.gl:android-plugin-annotation-v9:2.0.1") {
exclude group: 'com.google.android.gms'
}
implementation 'org.maplibre.gl:android-sdk-turf:5.9.0'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"
}
def execResult(...args) {
def stdout = new ByteArrayOutputStream()
exec {
commandLine args
standardOutput = stdout
}
return stdout.toString().trim()
}
android {
namespace "org.microg.gms.maps.mapbox"
compileSdkVersion androidCompileSdk
buildToolsVersion "$androidBuildVersionTools"
buildFeatures {
buildConfig = true
}
defaultConfig {
versionName version
minSdkVersion androidMinSdk
targetSdkVersion androidTargetSdk
buildConfigField "String", "MAPBOX_KEY", "\"${localProperties.getProperty("mapbox.key", System.getenv('MAPBOX_VECTOR_TILES_KEY') ?: "")}\""
buildConfigField "String", "STADIA_KEY", "\"${localProperties.getProperty("stadia.key", System.getenv('STADIA_API_KEY') ?: "")}\""
ndk {
abiFilters "armeabi", "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
}
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
lintOptions {
disable 'GradleCompatible'
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = 1.8
}
}
if (file('user.gradle').exists()) {
apply from: 'user.gradle'
}

View file

@ -0,0 +1,35 @@
<?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">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-sdk tools:overrideLibrary="com.mapbox.mapboxsdk, com.mapbox.mapboxsdk.plugins.annotation" />
<application />
</manifest>

View file

@ -0,0 +1,3 @@

Roboto Bold 10240-10495

View file

@ -0,0 +1,3 @@

Roboto Bold 10496-10751

View file

@ -0,0 +1,3 @@

Roboto Bold 10752-11007

View file

@ -0,0 +1,3 @@

Roboto Bold 11008-11263

View file

@ -0,0 +1,3 @@

Roboto Bold 11264-11519

View file

@ -0,0 +1,3 @@

Roboto Bold 11520-11775

View file

@ -0,0 +1,3 @@

Roboto Bold 11776-12031

View file

@ -0,0 +1,3 @@

Roboto Bold 12032-12287

View file

@ -0,0 +1,3 @@

Roboto Bold 12288-12543

View file

@ -0,0 +1,3 @@

Roboto Bold 12544-12799

View file

@ -0,0 +1,3 @@

Roboto Bold 12800-13055

View file

@ -0,0 +1,3 @@

Roboto Bold 13056-13311

View file

@ -0,0 +1,3 @@

Roboto Bold 13312-13567

View file

@ -0,0 +1,3 @@

Roboto Bold 13568-13823

View file

@ -0,0 +1,3 @@

Roboto Bold 13824-14079

View file

@ -0,0 +1,3 @@

Roboto Bold 14080-14335

View file

@ -0,0 +1,3 @@

Roboto Bold 14336-14591

View file

@ -0,0 +1,3 @@

Roboto Bold 14592-14847

View file

@ -0,0 +1,3 @@

Roboto Bold 14848-15103

View file

@ -0,0 +1,3 @@

Roboto Bold 15104-15359

View file

@ -0,0 +1,3 @@

Roboto Bold 1536-1791

View file

@ -0,0 +1,3 @@

Roboto Bold 15360-15615

View file

@ -0,0 +1,3 @@

Roboto Bold 15616-15871

View file

@ -0,0 +1,3 @@

Roboto Bold 15872-16127

View file

@ -0,0 +1,3 @@

Roboto Bold 16128-16383

View file

@ -0,0 +1,3 @@

Roboto Bold 16384-16639

View file

@ -0,0 +1,3 @@

Roboto Bold 16640-16895

View file

@ -0,0 +1,3 @@

Roboto Bold 16896-17151

View file

@ -0,0 +1,3 @@

Roboto Bold 17152-17407

View file

@ -0,0 +1,3 @@

Roboto Bold 17408-17663

View file

@ -0,0 +1,3 @@

Roboto Bold 17664-17919

View file

@ -0,0 +1,3 @@

Roboto Bold 1792-2047

View file

@ -0,0 +1,3 @@

Roboto Bold 17920-18175

View file

@ -0,0 +1,3 @@

Roboto Bold 18176-18431

View file

@ -0,0 +1,3 @@

Roboto Bold 18432-18687

View file

@ -0,0 +1,3 @@

Roboto Bold 18688-18943

View file

@ -0,0 +1,3 @@

Roboto Bold 18944-19199

View file

@ -0,0 +1,3 @@

Roboto Bold 19200-19455

View file

@ -0,0 +1,3 @@

Roboto Bold 19456-19711

View file

@ -0,0 +1,3 @@

Roboto Bold 19712-19967

View file

@ -0,0 +1,3 @@

Roboto Bold 19968-20223

View file

@ -0,0 +1,3 @@

Roboto Bold 20224-20479

View file

@ -0,0 +1,3 @@

Roboto Bold 2048-2303

View file

@ -0,0 +1,3 @@

Roboto Bold 20480-20735

View file

@ -0,0 +1,3 @@

Roboto Bold 20736-20991

View file

@ -0,0 +1,3 @@

Roboto Bold 20992-21247

View file

@ -0,0 +1,3 @@

Roboto Bold 21248-21503

View file

@ -0,0 +1,3 @@

Roboto Bold 21504-21759

View file

@ -0,0 +1,3 @@

Roboto Bold 21760-22015

View file

@ -0,0 +1,3 @@

Roboto Bold 22016-22271

View file

@ -0,0 +1,3 @@

Roboto Bold 22272-22527

View file

@ -0,0 +1,3 @@

Roboto Bold 22528-22783

View file

@ -0,0 +1,3 @@

Roboto Bold 22784-23039

View file

@ -0,0 +1,3 @@

Roboto Bold 2304-2559

View file

@ -0,0 +1,3 @@

Roboto Bold 23040-23295

View file

@ -0,0 +1,3 @@

Roboto Bold 23296-23551

View file

@ -0,0 +1,3 @@

Roboto Bold 23552-23807

View file

@ -0,0 +1,3 @@

Roboto Bold 23808-24063

View file

@ -0,0 +1,3 @@

Roboto Bold 24064-24319

View file

@ -0,0 +1,3 @@

Roboto Bold 24320-24575

Some files were not shown because too many files have changed in this diff Show more