Skip to content

Commit

Permalink
Maps: Add HMS-based implementation
Browse files Browse the repository at this point in the history
This is disabled by default, as it currently relies on a non-free library. It
can be enabled by setting modules.hms=true in local.properties. You also need
to place your agconnect-services.json and set hmsmap.key in local.properties.
  • Loading branch information
mar-v-in committed Sep 19, 2023
1 parent 49f739f commit b192f35
Show file tree
Hide file tree
Showing 32 changed files with 2,602 additions and 7 deletions.
9 changes: 8 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,17 @@ buildscript {
ext.localProperties = new Properties()

try {
ext.localProperties.load(rootProject.file('local.properties').newDataInputStream())
var stream = rootProject.file('local.properties').newDataInputStream()
ext.localProperties.load(stream)
stream.close()
} catch (ignored) {
// Ignore
}

ext.hasModule = (String name, boolean enabledByDefault) -> {
return ext.localProperties.getProperty("modules." + name, enabledByDefault.toString()).toBoolean()
}

repositories {
mavenCentral()
google()
Expand Down Expand Up @@ -111,6 +117,7 @@ subprojects {
repositories {
mavenCentral()
google()
if (hasModule("hms", false)) maven {url 'https://developer.huawei.com/repo/'}
}
}

9 changes: 5 additions & 4 deletions play-services-core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,10 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'

def hasModule(String name, boolean enabledByDefault) {
return localProperties.getProperty("modules." + name, enabledByDefault.toString()).toBoolean()
}

configurations {
mapboxRuntimeOnly
vtmRuntimeOnly
if (hasModule("hms", true)) hmsRuntimeOnly
defaultRuntimeOnly
}

Expand Down Expand Up @@ -69,6 +66,7 @@ dependencies {
defaultRuntimeOnly project(':play-services-location-core-provider')

if (hasModule("nearby", true)) runtimeOnly project(':play-services-nearby-core-package')
if (hasModule("hms", false)) hmsRuntimeOnly project(':play-services-maps-core-hms')

// AndroidX UI
implementation "androidx.multidex:multidex:$multidexVersion"
Expand Down Expand Up @@ -149,6 +147,9 @@ android {
dimension 'target'
versionNameSuffix "-hw"
}
"hms" {
dimension 'maps'
}
"mapbox" {
dimension 'maps'
}
Expand Down
61 changes: 61 additions & 0 deletions play-services-maps/core/hms/build.gradle
Original file line number Diff line number Diff line change
@@ -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
}
}
9 changes: 9 additions & 0 deletions play-services-maps/core/hms/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -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.**{*;}
20 changes: 20 additions & 0 deletions play-services-maps/core/hms/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -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>
1 change: 1 addition & 0 deletions play-services-maps/core/hms/src/main/assets/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
agconnect-services.json
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* 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.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.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 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;
}
}
Original file line number Diff line number Diff line change
@@ -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"
}
}


Loading

0 comments on commit b192f35

Please sign in to comment.