From cab2517b1c523a9ca8fd282c92b1015e37c8bf0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=91=A3=E5=AE=8F=E5=AE=87?= Date: Tue, 29 Dec 2020 18:44:01 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E6=8D=A2=E8=82=A4=E6=A1=86?= =?UTF-8?q?=E6=9E=B6=E4=B8=8E=E9=AB=98=E5=BE=B7=E5=9C=B0=E5=9B=BE=E7=9A=84?= =?UTF-8?q?=E5=86=B2=E7=AA=81=20=E7=9B=B4=E6=8E=A5=E9=80=9A=E8=BF=87?= =?UTF-8?q?=E5=86=85=E5=AD=98=E5=9C=B0=E5=9D=80=E6=9B=BF=E6=8D=A2=E6=95=B4?= =?UTF-8?q?=E4=B8=AA=20ArtMethod=20=EF=BC=8C=E5=AE=8C=E6=88=90=E4=BA=86?= =?UTF-8?q?=E9=AB=98=E5=BE=B7=E5=9C=B0=E5=9B=BE=E6=96=B9=E6=B3=95=E7=9A=84?= =?UTF-8?q?=E6=9B=BF=E6=8D=A2=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/gradle.xml | 1 - .idea/misc.xml | 6 +- modules/mogo-module-common/CMakeLists.txt | 44 +++++ modules/mogo-module-common/build.gradle | 12 +- .../src/main/cpp/method-hook-lib.cpp | 87 ++++++++ .../mogo/module/common/hook/HookManager.java | 67 +++++++ .../mogo/module/common/hook/MethodHook.java | 64 ++++++ .../src/main/AndroidManifest.xml | 6 +- .../main/java/com/amap/api/col/n3/le2.java | 186 ++++++++++++++++++ .../main/java/com/amap/api/col/n3/lg2.java | 40 ++++ .../policy/MyPhoneLayoutInflater.java | 60 ++++++ .../module/small/map/SmallVisionProvider.java | 70 ++++++- 12 files changed, 628 insertions(+), 15 deletions(-) create mode 100644 modules/mogo-module-common/CMakeLists.txt create mode 100644 modules/mogo-module-common/src/main/cpp/method-hook-lib.cpp create mode 100644 modules/mogo-module-common/src/main/java/com/mogo/module/common/hook/HookManager.java create mode 100644 modules/mogo-module-common/src/main/java/com/mogo/module/common/hook/MethodHook.java create mode 100644 modules/mogo-module-smp/src/main/java/com/amap/api/col/n3/le2.java create mode 100644 modules/mogo-module-smp/src/main/java/com/amap/api/col/n3/lg2.java create mode 100644 modules/mogo-module-smp/src/main/java/com/android/internal/policy/MyPhoneLayoutInflater.java diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 8efbfa420e..426ff6b360 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -85,7 +85,6 @@ diff --git a/.idea/misc.xml b/.idea/misc.xml index e082ea7475..733acb1920 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,10 +1,14 @@ + + + + - + \ No newline at end of file diff --git a/modules/mogo-module-common/CMakeLists.txt b/modules/mogo-module-common/CMakeLists.txt new file mode 100644 index 0000000000..e66e013af7 --- /dev/null +++ b/modules/mogo-module-common/CMakeLists.txt @@ -0,0 +1,44 @@ +# For more information about using CMake with Android Studio, read the +# documentation: https://d.android.com/studio/projects/add-native-code.html + +# Sets the minimum version of CMake required to build the native library. + +cmake_minimum_required(VERSION 3.4.1) + +# Creates and names a library, sets it as either STATIC +# or SHARED, and provides the relative paths to its source code. +# You can define multiple libraries, and CMake builds them for you. +# Gradle automatically packages shared libraries with your APK. + +add_library( # Sets the name of the library. + method-hook-lib + + # Sets the library as a shared library. + SHARED + + # Provides a relative path to your source file(s). + src/main/cpp/method-hook-lib.cpp ) + +# Searches for a specified prebuilt library and stores the path as a +# variable. Because CMake includes system libraries in the search path by +# default, you only need to specify the name of the public NDK library +# you want to add. CMake verifies that the library exists before +# completing its build. + +find_library( # Sets the name of the path variable. + log-lib + + # Specifies the name of the NDK library that + # you want CMake to locate. + log ) + +# Specifies libraries CMake should link to your target library. You +# can link multiple libraries, such as libraries you define in this +# build script, prebuilt third-party libraries, or system libraries. + +target_link_libraries( # Specifies the target library. + method-hook-lib + + # Links the target library to the log library + # included in the NDK. + ${log-lib} ) \ No newline at end of file diff --git a/modules/mogo-module-common/build.gradle b/modules/mogo-module-common/build.gradle index 99e827b866..783a180702 100644 --- a/modules/mogo-module-common/build.gradle +++ b/modules/mogo-module-common/build.gradle @@ -11,8 +11,18 @@ android { testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles 'consumer-rules.pro' - } + externalNativeBuild { + cmake { + cppFlags "-std=c++11 -frtti -fexceptions" + } + } + } + externalNativeBuild { + cmake { + path "CMakeLists.txt" + } + } buildTypes { release { minifyEnabled false diff --git a/modules/mogo-module-common/src/main/cpp/method-hook-lib.cpp b/modules/mogo-module-common/src/main/cpp/method-hook-lib.cpp new file mode 100644 index 0000000000..046981c7f2 --- /dev/null +++ b/modules/mogo-module-common/src/main/cpp/method-hook-lib.cpp @@ -0,0 +1,87 @@ +#include +#include + +// +// Created by donghongyu on 12/10/20 1:34 PM. +// 源码地址 https://github.com/pqpo/methodhook +// 方法hook jni类 +static const char *kClassMethodHookChar = "com/mogo/module/common/hook/MethodHook"; + +static struct { + jmethodID m1; + jmethodID m2; + size_t methodSize; +} methodHookClassInfo; + + +/** + * 替换指定类中的方法 + * @param env + * @param type 要替换方法的目标 class + * @param srcMethodObj 目标方法对象 + * @param destMethodObj 替换的方法对象 + * @return + */ +static jlong methodHook(JNIEnv *env, jclass type, jobject srcMethodObj, jobject destMethodObj) { + void *srcMethod = reinterpret_cast(env->FromReflectedMethod(srcMethodObj)); + void *destMethod = reinterpret_cast(env->FromReflectedMethod(destMethodObj)); + int *backupMethod = new int[methodHookClassInfo.methodSize]; + memcpy(backupMethod, srcMethod, methodHookClassInfo.methodSize); + memcpy(srcMethod, destMethod, methodHookClassInfo.methodSize); + return reinterpret_cast(backupMethod); +} + +/** + * 恢复指定类中的方法 + * @param env + * @param type 要恢复方法的目标 class + * @param srcMethod 目标方法对象 + * @param methodPtr + * @return + */ +static jobject methodRestore(JNIEnv *env, jclass type, jobject srcMethod, jlong methodPtr) { + int *backupMethod = reinterpret_cast(methodPtr); + void *artMethodSrc = reinterpret_cast(env->FromReflectedMethod(srcMethod)); + memcpy(artMethodSrc, backupMethod, methodHookClassInfo.methodSize); + delete[]backupMethod; + return srcMethod; +} + + +static JNINativeMethod gMethods[] = { + { + "hook_native", + "(Ljava/lang/reflect/Method;Ljava/lang/reflect/Method;)J", + (void *) methodHook + }, + { + "restore_native", + "(Ljava/lang/reflect/Method;J)Ljava/lang/reflect/Method;", + (void *) methodRestore + } +}; + +extern "C" +JNIEXPORT jint JNICALL +/** + * 在jni加载的时候进行方法参数获取 + * @param vm + * @param reserved + * @return + */ +JNI_OnLoad(JavaVM *vm, void *reserved) { + JNIEnv *env = nullptr; + if (vm->GetEnv((void **) &env, JNI_VERSION_1_4) != JNI_OK) { + return JNI_FALSE; + } + jclass classEvaluateUtil = env->FindClass(kClassMethodHookChar); + if (env->RegisterNatives(classEvaluateUtil, gMethods, sizeof(gMethods) / sizeof(gMethods[0])) < + 0) { + return JNI_FALSE; + } + methodHookClassInfo.m1 = env->GetStaticMethodID(classEvaluateUtil, "m1", "()V"); + methodHookClassInfo.m2 = env->GetStaticMethodID(classEvaluateUtil, "m2", "()V"); + methodHookClassInfo.methodSize = reinterpret_cast(methodHookClassInfo.m2) - + reinterpret_cast(methodHookClassInfo.m1); + return JNI_VERSION_1_4; +} diff --git a/modules/mogo-module-common/src/main/java/com/mogo/module/common/hook/HookManager.java b/modules/mogo-module-common/src/main/java/com/mogo/module/common/hook/HookManager.java new file mode 100644 index 0000000000..6dc15753b1 --- /dev/null +++ b/modules/mogo-module-common/src/main/java/com/mogo/module/common/hook/HookManager.java @@ -0,0 +1,67 @@ +package com.mogo.module.common.hook; + + +import android.util.Pair; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 替换管理 + * Created by donghongyu on 12/29/20 1:34 PM + */ +public final class HookManager { + + private HookManager() { + } + + public static HookManager get() { + return InstanceHolder.sInstance; + } + + private static class InstanceHolder { + private static HookManager sInstance = new HookManager(); + } + + private Map, MethodHook> methodHookMap = new ConcurrentHashMap<>(); + + /** + * 替换方法 + * + * @param originMethod 原始方法 + * @param hookMethod 替换方法 + */ + public void hookMethod(Method originMethod, Method hookMethod) { + if (originMethod == null || hookMethod == null) { + throw new IllegalArgumentException("argument cannot be null"); + } + + Pair key = Pair.create(hookMethod.getDeclaringClass().getName(), hookMethod.getName()); + if (methodHookMap.containsKey(key)) { + MethodHook methodHook = methodHookMap.get(key); + methodHook.restore(); + } + MethodHook methodHook = new MethodHook(originMethod, hookMethod); + methodHookMap.put(key, methodHook); + methodHook.hook(); + } + + public void callOrigin(Object receiver, Object... args) { + StackTraceElement stackTrace = Thread.currentThread().getStackTrace()[3]; + String className = stackTrace.getClassName(); + String methodName = stackTrace.getMethodName(); + MethodHook methodHook = methodHookMap.get(Pair.create(className, methodName)); + if (methodHook != null) { + try { + methodHook.callOrigin(receiver, args); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + } + +} diff --git a/modules/mogo-module-common/src/main/java/com/mogo/module/common/hook/MethodHook.java b/modules/mogo-module-common/src/main/java/com/mogo/module/common/hook/MethodHook.java new file mode 100644 index 0000000000..e63cf11392 --- /dev/null +++ b/modules/mogo-module-common/src/main/java/com/mogo/module/common/hook/MethodHook.java @@ -0,0 +1,64 @@ +package com.mogo.module.common.hook; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * 替换类与c++代码对应 + * Created by donghongyu on 12/29/20 1:34 PM + */ +public class MethodHook { + + public static void m1() { + } + + public static void m2() { + } + + // 目标方法 + private Method srcMethod; + // 要替换的方法 + private Method hookMethod; + + // 备份目标替换方法ID + private long backupMethodPtr; + + public MethodHook(Method src, Method dest) { + srcMethod = src; + hookMethod = dest; + srcMethod.setAccessible(true); + hookMethod.setAccessible(true); + } + + public void hook() { + if (backupMethodPtr == 0) { + backupMethodPtr = hook_native(srcMethod, hookMethod); + } + } + + public void restore() { + if (backupMethodPtr != 0) { + restore_native(srcMethod, backupMethodPtr); + backupMethodPtr = 0; + } + } + + public void callOrigin(Object receiver, Object... args) throws InvocationTargetException, IllegalAccessException { + if (backupMethodPtr != 0) { + restore(); + srcMethod.invoke(receiver, args); + hook(); + } else { + srcMethod.invoke(receiver, args); + } + } + + private static native long hook_native(Method src, Method dest); + + private static native Method restore_native(Method src, long methodPtr); + + static { + System.loadLibrary("method-hook-lib"); + } + +} diff --git a/modules/mogo-module-smp/src/main/AndroidManifest.xml b/modules/mogo-module-smp/src/main/AndroidManifest.xml index 32b078729c..33c6adff88 100644 --- a/modules/mogo-module-smp/src/main/AndroidManifest.xml +++ b/modules/mogo-module-smp/src/main/AndroidManifest.xml @@ -2,10 +2,10 @@ - + \ No newline at end of file diff --git a/modules/mogo-module-smp/src/main/java/com/amap/api/col/n3/le2.java b/modules/mogo-module-smp/src/main/java/com/amap/api/col/n3/le2.java new file mode 100644 index 0000000000..cd406be8a7 --- /dev/null +++ b/modules/mogo-module-smp/src/main/java/com/amap/api/col/n3/le2.java @@ -0,0 +1,186 @@ +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// + +package com.amap.api.col.n3; + +import android.content.Context; +import android.content.res.Resources; +import android.content.res.Resources.Theme; +import android.util.AttributeSet; +import android.util.Log; +import android.view.ContextThemeWrapper; +import android.view.LayoutInflater; +import android.view.LayoutInflater.Factory; +import android.view.View; +import android.view.ViewStub; + +import com.android.internal.policy.MyPhoneLayoutInflater; + +import java.lang.reflect.Constructor; +import java.util.HashMap; +import java.util.HashSet; + +public final class le2 extends ContextThemeWrapper { + private Resources a = lg.a(); + private Theme b; + private LayoutInflater c; + private ClassLoader d; + private int e; + private static final String[] f = new String[]{"android.widget", "android.webkit", "android.app"}; + private le2.a g = new le2.a(); + private Factory h = new Factory() { + public final View onCreateView(String var1, Context var2, AttributeSet var3) { + return le2.this.a(var1, var2, var3); + } + }; + + public le2(Context var1, int var2, ClassLoader var3) { + super(var1, var2); + this.d = var3; + this.b = lg.b(); + this.e = var2; + super.onApplyThemeResource(this.b, this.e, true); + (new StringBuilder("classloader:")).append(this.d); + } + + public final Resources getResources() { + return this.a != null ? this.a : super.getResources(); + } + + public final void a(int var1) { + if (var1 != this.e) { + this.e = var1; + super.onApplyThemeResource(this.b, this.e, true); + } + + } + + public final Theme getTheme() { + return this.b != null ? this.b : super.getTheme(); + } + + public final Object getSystemService(String var1) { + if ("layout_inflater".equals(var1)) { + if (this.c == null) { + // 这里构建一个自己对的布局填充器 + // 与已经被修改的context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) + // 隔离从而保证高德地图SDK能正常初始化 + LayoutInflater var2 = new MyPhoneLayoutInflater(getBaseContext()); + this.c = var2.cloneInContext(this); + this.c.setFactory(this.h); + this.c = this.c.cloneInContext(this); + } + + return this.c; + } else { + return super.getSystemService(var1); + } + } + + private final View a(String var1, Context var2, AttributeSet var3) { + if (this.g.a.contains(var1)) { + return null; + } else { + Constructor var4; + if ((var4 = (Constructor) this.g.b.get(var1)) == null) { + Class var5 = null; + boolean var6 = false; + String var7 = "api.navi"; + + label71: + { + label70: + { + Throwable var10000; + label79: + { + boolean var10001; + try { + if (var1.contains(var7)) { + var5 = this.d.loadClass(var1); + } else { + String[] var17; + int var8 = (var17 = f).length; + int var9 = 0; + + while (var9 < var8) { + String var10 = var17[var9]; + + try { + var5 = this.d.loadClass(var10 + "." + var1); + break; + } catch (Throwable var13) { + ++var9; + } + } + } + + if (var5 == null) { + break label71; + } + } catch (Throwable var15) { + var10000 = var15; + var10001 = false; + break label79; + } + + if (var5 == ViewStub.class) { + break label71; + } + + try { + if (var5.getClassLoader() != this.d) { + break label71; + } + break label70; + } catch (Throwable var14) { + var10000 = var14; + var10001 = false; + } + } + + Throwable var18 = var10000; + (new StringBuilder("load view err:")).append(Log.getStackTraceString(var18)); + break label71; + } + + var6 = true; + } + + if (!var6) { + this.g.a.add(var1); + return null; + } + + try { + var4 = var5.getConstructor(Context.class, AttributeSet.class); + this.g.b.put(var1, var4); + } catch (Throwable var12) { + (new StringBuilder("create view err:")).append(Log.getStackTraceString(var12)); + } + } + + try { + View var16 = null; + if (var4 != null) { + var16 = (View) var4.newInstance(var2, var3); + } + + return var16; + } catch (Throwable var11) { + (new StringBuilder("create view err:")).append(Log.getStackTraceString(var11)); + return null; + } + } + } + + public static class a { + public HashSet a = new HashSet(); + public HashMap> b = new HashMap(); + + public a() { + } + } +} diff --git a/modules/mogo-module-smp/src/main/java/com/amap/api/col/n3/lg2.java b/modules/mogo-module-smp/src/main/java/com/amap/api/col/n3/lg2.java new file mode 100644 index 0000000000..347f98ddc6 --- /dev/null +++ b/modules/mogo-module-smp/src/main/java/com/amap/api/col/n3/lg2.java @@ -0,0 +1,40 @@ +package com.amap.api.col.n3; + +import android.content.Context; +import android.content.res.XmlResourceParser; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +/** + * 这里是为了解决 使用换肤框架后,高德地图初始化有问题加入的 + * 问题原因是: + * skin 框架会替换 LayoutInflater 中的 setFactory2 从而导致高德 le 中的 setFactory 失效。 + * 解决方案为: + * 直接通过内存地址替换整个 ArtMethod,来将需要修改的高德SDK中的方法指向我们修改过后的方法。 + */ +public class lg2 extends lg { + static le2 b; + + public static View a(Context var0, int var1, ViewGroup var2) { + XmlResourceParser var9 = a().getXml(var1); + if (!a) { + return LayoutInflater.from(var0).inflate(var9, var2); + } else { + try { + if (b == null) { + b = new le2(var0, c == -1 ? 0 : c, lg.class.getClassLoader()); + } + b.a(c == -1 ? 0 : c); + View var3 = LayoutInflater.from(b).inflate(var9, var2); + return var3; + } catch (Throwable var7) { + var7.printStackTrace(); + np.c(var7, "ResourcesUtil", "selfInflate(Activity activity, int resource, ViewGroup root)"); + } finally { + var9.close(); + } + return null; + } + } +} diff --git a/modules/mogo-module-smp/src/main/java/com/android/internal/policy/MyPhoneLayoutInflater.java b/modules/mogo-module-smp/src/main/java/com/android/internal/policy/MyPhoneLayoutInflater.java new file mode 100644 index 0000000000..4a2d262764 --- /dev/null +++ b/modules/mogo-module-smp/src/main/java/com/android/internal/policy/MyPhoneLayoutInflater.java @@ -0,0 +1,60 @@ +package com.android.internal.policy; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; + +/** + * @author donghongyu + * @date 12/25/20 5:12 PM + */ +public class MyPhoneLayoutInflater extends LayoutInflater { + private static final String[] sClassPrefixList = { + "android.widget.", + "android.webkit.", + "android.app." + }; + + /** + * Instead of instantiating directly, you should retrieve an instance + * through {@link Context#getSystemService} + * + * @param context The Context in which in which to find resources and other + * application-specific things. + * @see Context#getSystemService + */ + public MyPhoneLayoutInflater(Context context) { + super(context); + } + + protected MyPhoneLayoutInflater(LayoutInflater original, Context newContext) { + super(original, newContext); + } + + /** + * Override onCreateView to instantiate names that correspond to the + * widgets known to the Widget factory. If we don't find a match, + * call through to our super class. + */ + @Override + protected View onCreateView(String name, AttributeSet attrs) throws ClassNotFoundException { + for (String prefix : sClassPrefixList) { + try { + View view = createView(name, prefix, attrs); + if (view != null) { + return view; + } + } catch (ClassNotFoundException e) { + // In this case we want to let the base class take a crack + // at it. + } + } + + return super.onCreateView(name, attrs); + } + + public LayoutInflater cloneInContext(Context newContext) { + return new MyPhoneLayoutInflater(this, newContext); + } +} \ No newline at end of file diff --git a/modules/mogo-module-smp/src/main/java/com/mogo/module/small/map/SmallVisionProvider.java b/modules/mogo-module-smp/src/main/java/com/mogo/module/small/map/SmallVisionProvider.java index 10fb9139b9..258bce4688 100644 --- a/modules/mogo-module-smp/src/main/java/com/mogo/module/small/map/SmallVisionProvider.java +++ b/modules/mogo-module-smp/src/main/java/com/mogo/module/small/map/SmallVisionProvider.java @@ -1,22 +1,30 @@ package com.mogo.module.small.map; import android.content.Context; -import android.content.Intent; import android.os.Bundle; import android.util.Log; +import android.view.Gravity; import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; import com.alibaba.android.arouter.facade.annotation.Route; -import com.mogo.commons.AbsMogoApplication; +import com.amap.api.col.n3.lg; +import com.amap.api.col.n3.lg2; import com.mogo.module.common.MogoApisHandler; +import com.mogo.module.common.hook.HookManager; +import com.mogo.module.common.wm.WindowManagerView; import com.mogo.service.MogoServicePaths; import com.mogo.service.map.IMogoSmallMapProvider; import com.mogo.service.module.ModuleType; import com.mogo.service.statusmanager.IMogoStatusChangedListener; import com.mogo.service.statusmanager.StatusDescriptor; +import com.mogo.utils.logger.Logger; + +import java.lang.reflect.Method; /** * @author donghongyu @@ -26,9 +34,11 @@ import com.mogo.service.statusmanager.StatusDescriptor; public class SmallVisionProvider implements IMogoSmallMapProvider, IMogoStatusChangedListener { private final String TAG = "SmallVisionProvider"; - private Intent mSmallMapServiceIntent; private Context mContext; + private WindowManagerView mWindowManagerView; + private SmallMapDirectionView mSmallMapDirectionView; + @Override public Fragment createFragment(Context context, Bundle data) { return null; @@ -55,6 +65,19 @@ public class SmallVisionProvider implements IMogoSmallMapProvider, IMogoStatusCh Log.d(TAG, "小地图模块初始化……"); mContext = context; + try { + try { + // 替换高德地图的方法,解决因为加入换肤框架导致地图初始化失败 + Method srcMethod = lg.class.getDeclaredMethod("a", Context.class, int.class, ViewGroup.class); + Method destMethod = lg2.class.getDeclaredMethod("a", Context.class, int.class, ViewGroup.class); + HookManager.get().hookMethod(srcMethod, destMethod); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } + } catch (Exception e) { + e.printStackTrace(); + } + MogoApisHandler.getInstance() .getApis() .getStatusManagerApi() @@ -76,22 +99,22 @@ public class SmallVisionProvider implements IMogoSmallMapProvider, IMogoStatusCh public void onDestroy() { Log.d(TAG, "小地图模块销毁……"); hidePanel(); + // 释放组件内存 + mSmallMapDirectionView = null; + mWindowManagerView = null; } @Override public void showPanel() { Log.d(TAG, "小地图模块触发展示……"); - if (MogoApisHandler.getInstance().getApis().getStatusManagerApi().isVrMode()) { - mSmallMapServiceIntent = new Intent(mContext, SmallMapService.class); - mContext.startService(mSmallMapServiceIntent); - } + addSmallMapView(); } @Override public void hidePanel() { Log.d(TAG, "小地图模块触发隐藏……"); - if (mSmallMapServiceIntent != null) { - AbsMogoApplication.getApp().stopService(mSmallMapServiceIntent); + if (mWindowManagerView != null && mWindowManagerView.isShowing()) { + mWindowManagerView.dismiss(); } } @@ -122,4 +145,33 @@ public class SmallVisionProvider implements IMogoSmallMapProvider, IMogoStatusCh } } } + + + /** + * 添加小地图View + */ + private void addSmallMapView() { + Logger.d(TAG, "addSmallMapView"); + // 初始化小地图控件 + if (mSmallMapDirectionView == null) { + mSmallMapDirectionView = new SmallMapDirectionView(mContext); + } + + if (mWindowManagerView == null) { + mWindowManagerView = new WindowManagerView.Builder(mContext) + .contentView(mSmallMapDirectionView) + .size( + WindowManager.LayoutParams.WRAP_CONTENT, + WindowManager.LayoutParams.WRAP_CONTENT + ) + .position( + mContext.getResources().getDimensionPixelOffset(R.dimen.module_small_map_view_x), + mContext.getResources().getDimensionPixelOffset(R.dimen.module_small_map_view_y) + ) + .gravity(Gravity.TOP | Gravity.LEFT) + .showInWindowManager(); + } + mWindowManagerView.show(); + } + }