diff --git a/.idea/misc.xml b/.idea/misc.xml index 707ee6e613..2dc54c489f 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 1c0e75aa78..ad5fcc5f39 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -20,12 +20,12 @@ android { } multiDexEnabled true - externalNativeBuild { - ndk { - // 设置支持的SO库架构 - abiFilters 'armeabi-v7a' - } - } +// externalNativeBuild { +// ndk { +// // 设置支持的SO库架构 +// abiFilters 'armeabi-v7a' +// } +// } } signingConfigs { release { diff --git a/app/src/main/java/com/mogo/launcher/MogoApplication.java b/app/src/main/java/com/mogo/launcher/MogoApplication.java index 81ffef0cdb..2864bdbd21 100644 --- a/app/src/main/java/com/mogo/launcher/MogoApplication.java +++ b/app/src/main/java/com/mogo/launcher/MogoApplication.java @@ -46,12 +46,13 @@ public class MogoApplication extends AbsMogoApplication { //运营位卡片,需要默认显示,放在第一个加载 MogoModulePaths.addModule(new MogoModule(AdCardConstants.TAG, AdCardConstants.MODULE_NAME)); - MogoModulePaths.addModule(new MogoModule(OnLineCarConstants.TAG, OnLineCarConstants.MODULE_NAME)); - MogoModulePaths.addModule(new MogoModule(V2XConst.PATH_V2X_UI, V2XConst.PATH_V2X_UI)); - MogoModulePaths.addModule(new MogoModule(TanluConstants.TAG, TanluConstants.MODEL_NAME)); - MogoModulePaths.addModule(new MogoModule(CallChatConstant.PROVIDER, CallChatConstant.MODULE_NAME)); MogoModulePaths.addModule(new MogoModule(MediaConstants.TAG, MediaConstants.MODULE_TYPE)); + MogoModulePaths.addModule(new MogoModule(CallChatConstant.PROVIDER, CallChatConstant.MODULE_NAME)); + MogoModulePaths.addModule(new MogoModule(TanluConstants.TAG, TanluConstants.MODEL_NAME)); + MogoModulePaths.addModule(new MogoModule(OnLineCarConstants.TAG, OnLineCarConstants.MODULE_NAME)); MogoModulePaths.addModule(new MogoModule( FreshNewsConstants.TAG, FreshNewsConstants.MODULE_NAME)); + + MogoModulePaths.addModule(new MogoModule(V2XConst.PATH_V2X_UI, V2XConst.PATH_V2X_UI)); MogoModulePaths.addModule(new MogoModule(PushUIConstants.TAG, PushUIConstants.TAG)); MogoModulePaths.addModule(new MogoModule( BackToLauncherConst.MODULE_PATH, BackToLauncherConst.MODULE_NAME)); Log.i("timer", "cost " + (System.currentTimeMillis() - start) + "ms"); diff --git a/build.gradle b/build.gradle index fe76aac9ed..0b6d343d97 100644 --- a/build.gradle +++ b/build.gradle @@ -21,6 +21,8 @@ buildscript { classpath 'com.android.tools.build:gradle:3.5.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "com.alibaba:arouter-register:1.0.2" + classpath 'com.novoda:bintray-release:0.8.0' + // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } diff --git a/config.gradle b/config.gradle index 5cdac9cd7e..996479e8ca 100644 --- a/config.gradle +++ b/config.gradle @@ -89,7 +89,8 @@ ext { modulecommon : "com.mogo.module:module-common:${MOGO_MODULE_COMMON_VERSION}", modulemain : "com.mogo.module:module-main:${MOGO_MODULE_MAIN_VERSION}", modulemap : "com.mogo.module:module-map:${MOGO_MODULE_MAP_VERSION}", - moduleservice : "com.mogo.module:module-service:${MOGO_MODULE_SERVICE_VERSION}", + moduleservice : "com.mogo.module:module-service:${CARD_LIBRARY_VERSION}", + uicard : "com.mogo.ui:card-libaray:${MOGO_MODULE_SERVICE_VERSION}", mogoservice : "com.mogo.service:mogo-service:${MOGO_SERVICE_VERSION}", mogoserviceapi : "com.mogo.service:mogo-service-api:${MOGO_SERVICE_API_VERSION}", moduleapps : "com.mogo.module:module-apps:${MOGO_MODULE_APPS_VERSION}", diff --git a/foudations/mogo-connection/src/main/java/com/mogo/connection/socket/SocketManager.java b/foudations/mogo-connection/src/main/java/com/mogo/connection/socket/SocketManager.java index 5ceced9c21..2faf7b6bed 100644 --- a/foudations/mogo-connection/src/main/java/com/mogo/connection/socket/SocketManager.java +++ b/foudations/mogo-connection/src/main/java/com/mogo/connection/socket/SocketManager.java @@ -107,7 +107,7 @@ public class SocketManager implements IMogoSocketManager, OnSocketReceiveCallbac object = GsonUtil.objectFromJson( payload.getPayload().toStringUtf8(), listener.target() ); } if ( listener != null ) { - Logger.d( TAG, "received msgId = %s", msgId ); + Logger.d( TAG, "received msgId = %s, content = %s", msgId, payload.getPayload().toStringUtf8() ); listener.onMsgReceived( object ); } } diff --git a/foudations/mogo-utils/src/main/java/com/mogo/utils/ThreadPoolService.java b/foudations/mogo-utils/src/main/java/com/mogo/utils/ThreadPoolService.java index b94b28b555..53315efd95 100644 --- a/foudations/mogo-utils/src/main/java/com/mogo/utils/ThreadPoolService.java +++ b/foudations/mogo-utils/src/main/java/com/mogo/utils/ThreadPoolService.java @@ -5,7 +5,7 @@ import java.util.concurrent.Executors; public class ThreadPoolService { - private static final ExecutorService SERVICE = Executors.newScheduledThreadPool( 3 ); + private static final ExecutorService SERVICE = Executors.newFixedThreadPool( 3 ); private ThreadPoolService() { } diff --git a/gradle.properties b/gradle.properties index c9ce7e6ae6..44d36a4351 100644 --- a/gradle.properties +++ b/gradle.properties @@ -66,3 +66,5 @@ MOGO_MODULE_AD_CARD_VERSION=1.0.0-SNAPSHOT # 新鲜水 MOGO_MODULE_FRESH_NEWS_VERSION=1.0.0-SNAPSHOT +# 卡片效果 +CARD_LIBRARY_VERSION=1.0.0-SNAPSHOT \ No newline at end of file diff --git a/libraries/card-library/.gitignore b/libraries/card-library/.gitignore new file mode 100644 index 0000000000..796b96d1c4 --- /dev/null +++ b/libraries/card-library/.gitignore @@ -0,0 +1 @@ +/build diff --git a/libraries/card-library/build.gradle b/libraries/card-library/build.gradle new file mode 100644 index 0000000000..de2e3eddb9 --- /dev/null +++ b/libraries/card-library/build.gradle @@ -0,0 +1,36 @@ +apply plugin: 'com.android.library' +apply plugin: 'com.novoda.bintray-release' + +android { + compileSdkVersion rootProject.ext.android.compileSdkVersion + + defaultConfig { + targetSdkVersion rootProject.ext.android.targetSdkVersion + minSdkVersion rootProject.ext.android.minSdkVersion + versionCode Integer.valueOf(VERSION_CODE) + versionName getValueFromRootProperties("${project.name.replace("-", "_").toUpperCase()}_VERSION") + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } +} + +dependencies { + implementation rootProject.ext.dependencies.androidxappcompat + implementation rootProject.ext.dependencies.androidxrecyclerview + testImplementation 'org.robolectric:robolectric:3.0' + testImplementation 'junit:junit:4.12' + testImplementation 'org.mockito:mockito-core:2.13.0' + testImplementation 'org.hamcrest:hamcrest-library:1.3' + androidTestImplementation 'org.hamcrest:hamcrest-library:1.3' +} +apply from: new File(rootProject.rootDir, "gradle/upload.gradle").toString() + +//publish { +// artifactId = 'discrete-scrollview' +// userOrg = rootProject.userOrg +// groupId = rootProject.groupId +// uploadName = rootProject.uploadName +// publishVersion = rootProject.publishVersion +// description = rootProject.description +// licences = rootProject.licences +//} \ No newline at end of file diff --git a/libraries/card-library/gradle.properties b/libraries/card-library/gradle.properties new file mode 100644 index 0000000000..1d49d2e63f --- /dev/null +++ b/libraries/card-library/gradle.properties @@ -0,0 +1,3 @@ +GROUP=com.mogo.ui +POM_ARTIFACT_ID=card-libaray +VERSION_CODE=1 \ No newline at end of file diff --git a/libraries/card-library/proguard-rules.pro b/libraries/card-library/proguard-rules.pro new file mode 100644 index 0000000000..2309852b8f --- /dev/null +++ b/libraries/card-library/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in C:\Users\yarolegovich\AppData\Local\Android\Sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/libraries/card-library/src/main/AndroidManifest.xml b/libraries/card-library/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..f4432f4932 --- /dev/null +++ b/libraries/card-library/src/main/AndroidManifest.xml @@ -0,0 +1 @@ + diff --git a/libraries/card-library/src/main/java/com/yarolegovich/discretescrollview/DSVOrientation.java b/libraries/card-library/src/main/java/com/yarolegovich/discretescrollview/DSVOrientation.java new file mode 100644 index 0000000000..d00779e027 --- /dev/null +++ b/libraries/card-library/src/main/java/com/yarolegovich/discretescrollview/DSVOrientation.java @@ -0,0 +1,219 @@ +package com.yarolegovich.discretescrollview; + +import android.graphics.Point; +import android.view.View; + +/** + * Created by yarolegovich on 16.03.2017. + */ +public enum DSVOrientation { + + HORIZONTAL { + @Override + Helper createHelper() { + return new HorizontalHelper(); + } + }, + VERTICAL { + @Override + Helper createHelper() { + return new VerticalHelper(); + } + }; + + //Package private + abstract Helper createHelper(); + + interface Helper { + + int getViewEnd(int recyclerWidth, int recyclerHeight); + + int getDistanceToChangeCurrent(int childWidth, int childHeight); + + void setCurrentViewCenter(Point recyclerCenter, int scrolled, Point outPoint); + + void shiftViewCenter(Direction direction, int shiftAmount, Point outCenter); + + int getFlingVelocity(int velocityX, int velocityY); + + int getPendingDx(int pendingScroll); + + int getPendingDy(int pendingScroll); + + void offsetChildren(int amount, RecyclerViewProxy lm); + + float getDistanceFromCenter(Point center, int viewCenterX, int viewCenterY); + + boolean isViewVisible(Point center, int halfWidth, int halfHeight, int endBound, int extraSpace); + + boolean hasNewBecomeVisible(DiscreteScrollLayoutManager lm); + + boolean canScrollVertically(); + + boolean canScrollHorizontally(); + } + + protected static class HorizontalHelper implements Helper { + + @Override + public int getViewEnd(int recyclerWidth, int recyclerHeight) { + return recyclerWidth; + } + + @Override + public int getDistanceToChangeCurrent(int childWidth, int childHeight) { + return childWidth; + } + + @Override + public void setCurrentViewCenter(Point recyclerCenter, int scrolled, Point outPoint) { + int newX = recyclerCenter.x - scrolled; + outPoint.set(newX, recyclerCenter.y); + } + + @Override + public void shiftViewCenter(Direction direction, int shiftAmount, Point outCenter) { + int newX = outCenter.x + direction.applyTo(shiftAmount); + outCenter.set(newX, outCenter.y); + } + + @Override + public boolean isViewVisible( + Point viewCenter, int halfWidth, int halfHeight, int endBound, + int extraSpace) { + int viewLeft = viewCenter.x - halfWidth; + int viewRight = viewCenter.x + halfWidth; + return viewLeft < (endBound + extraSpace) && viewRight > -extraSpace; + } + + @Override + public boolean hasNewBecomeVisible(DiscreteScrollLayoutManager lm) { + View firstChild = lm.getFirstChild(), lastChild = lm.getLastChild(); + int leftBound = -lm.getExtraLayoutSpace(); + int rightBound = lm.getWidth() + lm.getExtraLayoutSpace(); + boolean isNewVisibleFromLeft = lm.getDecoratedLeft(firstChild) > leftBound + && lm.getPosition(firstChild) > 0; + boolean isNewVisibleFromRight = lm.getDecoratedRight(lastChild) < rightBound + && lm.getPosition(lastChild) < lm.getItemCount() - 1; + return isNewVisibleFromLeft || isNewVisibleFromRight; + } + + @Override + public void offsetChildren(int amount, RecyclerViewProxy helper) { + helper.offsetChildrenHorizontal(amount); + } + + @Override + public float getDistanceFromCenter(Point center, int viewCenterX, int viewCenterY) { + return viewCenterX - center.x; + } + + @Override + public int getFlingVelocity(int velocityX, int velocityY) { + return velocityX; + } + + @Override + public boolean canScrollHorizontally() { + return true; + } + + @Override + public boolean canScrollVertically() { + return false; + } + + @Override + public int getPendingDx(int pendingScroll) { + return pendingScroll; + } + + @Override + public int getPendingDy(int pendingScroll) { + return 0; + } + } + + + protected static class VerticalHelper implements Helper { + + @Override + public int getViewEnd(int recyclerWidth, int recyclerHeight) { + return recyclerHeight; + } + + @Override + public int getDistanceToChangeCurrent(int childWidth, int childHeight) { + return childHeight; + } + + @Override + public void setCurrentViewCenter(Point recyclerCenter, int scrolled, Point outPoint) { + int newY = recyclerCenter.y - scrolled; + outPoint.set(recyclerCenter.x, newY); + } + + @Override + public void shiftViewCenter(Direction direction, int shiftAmount, Point outCenter) { + int newY = outCenter.y + direction.applyTo(shiftAmount); + outCenter.set(outCenter.x, newY); + } + + @Override + public void offsetChildren(int amount, RecyclerViewProxy helper) { + helper.offsetChildrenVertical(amount); + } + + @Override + public float getDistanceFromCenter(Point center, int viewCenterX, int viewCenterY) { + return viewCenterY - center.y; + } + + @Override + public boolean isViewVisible( + Point viewCenter, int halfWidth, int halfHeight, int endBound, + int extraSpace) { + int viewTop = viewCenter.y - halfHeight; + int viewBottom = viewCenter.y + halfHeight; + return viewTop < (endBound + extraSpace) && viewBottom > -extraSpace; + } + + @Override + public boolean hasNewBecomeVisible(DiscreteScrollLayoutManager lm) { + View firstChild = lm.getFirstChild(), lastChild = lm.getLastChild(); + int topBound = -lm.getExtraLayoutSpace(); + int bottomBound = lm.getHeight() + lm.getExtraLayoutSpace(); + boolean isNewVisibleFromTop = lm.getDecoratedTop(firstChild) > topBound + && lm.getPosition(firstChild) > 0; + boolean isNewVisibleFromBottom = lm.getDecoratedBottom(lastChild) < bottomBound + && lm.getPosition(lastChild) < lm.getItemCount() - 1; + return isNewVisibleFromTop || isNewVisibleFromBottom; + } + + @Override + public int getFlingVelocity(int velocityX, int velocityY) { + return velocityY; + } + + @Override + public boolean canScrollHorizontally() { + return false; + } + + @Override + public boolean canScrollVertically() { + return true; + } + + @Override + public int getPendingDx(int pendingScroll) { + return 0; + } + + @Override + public int getPendingDy(int pendingScroll) { + return pendingScroll; + } + } + +} diff --git a/libraries/card-library/src/main/java/com/yarolegovich/discretescrollview/Direction.java b/libraries/card-library/src/main/java/com/yarolegovich/discretescrollview/Direction.java new file mode 100644 index 0000000000..e4d1c386ce --- /dev/null +++ b/libraries/card-library/src/main/java/com/yarolegovich/discretescrollview/Direction.java @@ -0,0 +1,38 @@ +package com.yarolegovich.discretescrollview; + +/** + * Created by yarolegovich on 16.03.2017. + */ +enum Direction { + + START { + @Override + public int applyTo(int delta) { + return delta * -1; + } + + @Override + public boolean sameAs(int direction) { + return direction < 0; + } + }, + END { + @Override + public int applyTo(int delta) { + return delta; + } + + @Override + public boolean sameAs(int direction) { + return direction > 0; + } + }; + + public abstract int applyTo(int delta); + + public abstract boolean sameAs(int direction); + + public static Direction fromDelta(int delta) { + return delta > 0 ? END : START; + } +} diff --git a/libraries/card-library/src/main/java/com/yarolegovich/discretescrollview/DiscreteScrollLayoutManager.java b/libraries/card-library/src/main/java/com/yarolegovich/discretescrollview/DiscreteScrollLayoutManager.java new file mode 100644 index 0000000000..3cc41b2db5 --- /dev/null +++ b/libraries/card-library/src/main/java/com/yarolegovich/discretescrollview/DiscreteScrollLayoutManager.java @@ -0,0 +1,786 @@ +package com.yarolegovich.discretescrollview; + +import android.content.Context; +import android.graphics.Point; +import android.graphics.PointF; +import android.os.Bundle; +import android.os.Parcelable; +import android.util.SparseArray; +import android.view.View; +import android.view.ViewGroup; +import android.view.accessibility.AccessibilityEvent; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.view.accessibility.AccessibilityEventCompat; +import androidx.core.view.accessibility.AccessibilityRecordCompat; +import androidx.recyclerview.widget.LinearSmoothScroller; +import androidx.recyclerview.widget.RecyclerView; +import com.yarolegovich.discretescrollview.transform.DiscreteScrollItemTransformer; + +import java.util.Locale; + +/** + * Created by yarolegovich on 17.02.2017. + */ +class DiscreteScrollLayoutManager extends RecyclerView.LayoutManager { + + static final int NO_POSITION = -1; + + private static final String EXTRA_POSITION = "extra_position"; + private static final int DEFAULT_TIME_FOR_ITEM_SETTLE = 300; + private static final int DEFAULT_FLING_THRESHOLD = 2100; //Decrease to increase sensitivity. + private static final int DEFAULT_TRANSFORM_CLAMP_ITEM_COUNT = 1; + + protected static final float SCROLL_TO_SNAP_TO_ANOTHER_ITEM = 0.6f; + + //This field will take value of all visible view's center points during the fill phase + protected Point viewCenterIterator; + protected Point recyclerCenter; + protected Point currentViewCenter; + protected int childHalfWidth, childHalfHeight; + protected int extraLayoutSpace; + + //Max possible distance a view can travel during one scroll phase + protected int scrollToChangeCurrent; + protected int currentScrollState; + + protected int scrolled; + protected int pendingScroll; + protected int currentPosition; + protected int pendingPosition; + + protected SparseArray detachedCache; + + private DSVOrientation.Helper orientationHelper; + + protected boolean isFirstOrEmptyLayout; + + private Context context; + + private int timeForItemSettle; + private int offscreenItems; + private int transformClampItemCount; + + private boolean dataSetChangeShiftedPosition; + + private int flingThreshold; + private boolean shouldSlideOnFling; + + private int viewWidth, viewHeight; + + @NonNull + private final ScrollStateListener scrollStateListener; + private DiscreteScrollItemTransformer itemTransformer; + + private RecyclerViewProxy recyclerViewProxy; + + public DiscreteScrollLayoutManager( + @NonNull Context c, + @NonNull ScrollStateListener scrollStateListener, + @NonNull DSVOrientation orientation) { + this.context = c; + this.timeForItemSettle = DEFAULT_TIME_FOR_ITEM_SETTLE; + this.pendingPosition = NO_POSITION; + this.currentPosition = NO_POSITION; + this.flingThreshold = DEFAULT_FLING_THRESHOLD; + this.shouldSlideOnFling = false; + this.recyclerCenter = new Point(); + this.currentViewCenter = new Point(); + this.viewCenterIterator = new Point(); + this.detachedCache = new SparseArray<>(); + this.scrollStateListener = scrollStateListener; + this.orientationHelper = orientation.createHelper(); + this.recyclerViewProxy = new RecyclerViewProxy(this); + this.transformClampItemCount = DEFAULT_TRANSFORM_CLAMP_ITEM_COUNT; + } + + @Override + public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { + if (state.getItemCount() == 0) { + recyclerViewProxy.removeAndRecycleAllViews(recycler); + currentPosition = pendingPosition = NO_POSITION; + scrolled = pendingScroll = 0; + return; + } + + ensureValidPosition(state); + + updateRecyclerDimensions(state); + + //onLayoutChildren may be called multiple times and this check is required so that the flag + //won't be cleared until onLayoutCompleted + if (!isFirstOrEmptyLayout) { + isFirstOrEmptyLayout = recyclerViewProxy.getChildCount() == 0; + if (isFirstOrEmptyLayout) { + initChildDimensions(recycler); + } + } + + recyclerViewProxy.detachAndScrapAttachedViews(recycler); + + fill(recycler); + + applyItemTransformToChildren(); + } + + private void ensureValidPosition(RecyclerView.State state) { + if (currentPosition == NO_POSITION || currentPosition >= state.getItemCount()) { + //currentPosition might have been assigned in onRestoreInstanceState() + //which can lead to a crash (position out of bounds) when data set + //is not persisted across rotations + currentPosition = 0; + } + } + + @Override + public void onLayoutCompleted(RecyclerView.State state) { + if (isFirstOrEmptyLayout) { + scrollStateListener.onCurrentViewFirstLayout(); + isFirstOrEmptyLayout = false; + } else if (dataSetChangeShiftedPosition) { + scrollStateListener.onDataSetChangeChangedPosition(); + dataSetChangeShiftedPosition = false; + } + } + + protected void initChildDimensions(RecyclerView.Recycler recycler) { + View viewToMeasure = recyclerViewProxy.getMeasuredChildForAdapterPosition(0, recycler); + + int childViewWidth = recyclerViewProxy.getMeasuredWidthWithMargin(viewToMeasure); + int childViewHeight = recyclerViewProxy.getMeasuredHeightWithMargin(viewToMeasure); + + childHalfWidth = childViewWidth / 2; + childHalfHeight = childViewHeight / 2; + + scrollToChangeCurrent = orientationHelper.getDistanceToChangeCurrent( + childViewWidth, + childViewHeight); + + extraLayoutSpace = scrollToChangeCurrent * offscreenItems; + + recyclerViewProxy.detachAndScrapView(viewToMeasure, recycler); + } + + protected void updateRecyclerDimensions(RecyclerView.State state) { + boolean dimensionsChanged = !state.isMeasuring() + && (recyclerViewProxy.getWidth() != viewWidth + || recyclerViewProxy.getHeight() != viewHeight); + if (dimensionsChanged) { + viewWidth = recyclerViewProxy.getWidth(); + viewHeight = recyclerViewProxy.getHeight(); + recyclerViewProxy.removeAllViews(); + } + recyclerCenter.set( + recyclerViewProxy.getWidth() / 523*330, + recyclerViewProxy.getHeight() / 2); + } + + protected void fill(RecyclerView.Recycler recycler) { + cacheAndDetachAttachedViews(); + + orientationHelper.setCurrentViewCenter(recyclerCenter, scrolled, currentViewCenter); + + final int endBound = orientationHelper.getViewEnd( + recyclerViewProxy.getWidth(), + recyclerViewProxy.getHeight()); + + //Layout current + if (isViewVisible(currentViewCenter, endBound)) { + layoutView(recycler, currentPosition, currentViewCenter); + } + + //Layout items before the current item + layoutViews(recycler, Direction.START, endBound); + + //Layout items after the current item + layoutViews(recycler, Direction.END, endBound); + + recycleDetachedViewsAndClearCache(recycler); + } + + private void layoutViews(RecyclerView.Recycler recycler, Direction direction, int endBound) { + final int positionStep = direction.applyTo(1); + + //Predictive layout is required when we are doing smooth fast scroll towards pendingPosition + boolean noPredictiveLayoutRequired = pendingPosition == NO_POSITION + || !direction.sameAs(pendingPosition - currentPosition); + + viewCenterIterator.set(currentViewCenter.x, currentViewCenter.y); + for (int pos = currentPosition + positionStep; isInBounds(pos); pos += positionStep) { + if (pos == pendingPosition) { + noPredictiveLayoutRequired = true; + } + orientationHelper.shiftViewCenter(direction, scrollToChangeCurrent, viewCenterIterator); + if (isViewVisible(viewCenterIterator, endBound)) { + layoutView(recycler, pos, viewCenterIterator); + } else if (noPredictiveLayoutRequired) { + break; + } + } + } + + protected void layoutView(RecyclerView.Recycler recycler, int position, Point viewCenter) { + if (position < 0) return; + View v = detachedCache.get(position); + if (v == null) { + v = recyclerViewProxy.getMeasuredChildForAdapterPosition(position, recycler); + recyclerViewProxy.layoutDecoratedWithMargins(v, + viewCenter.x - childHalfWidth, viewCenter.y - childHalfHeight, + viewCenter.x + childHalfWidth, viewCenter.y + childHalfHeight); + } else { + recyclerViewProxy.attachView(v); + detachedCache.remove(position); + } + } + + protected void cacheAndDetachAttachedViews() { + detachedCache.clear(); + for (int i = 0; i < recyclerViewProxy.getChildCount(); i++) { + View child = recyclerViewProxy.getChildAt(i); + detachedCache.put(recyclerViewProxy.getPosition(child), child); + } + + for (int i = 0; i < detachedCache.size(); i++) { + recyclerViewProxy.detachView(detachedCache.valueAt(i)); + } + } + + protected void recycleDetachedViewsAndClearCache(RecyclerView.Recycler recycler) { + for (int i = 0; i < detachedCache.size(); i++) { + View viewToRemove = detachedCache.valueAt(i); + recyclerViewProxy.recycleView(viewToRemove, recycler); + } + detachedCache.clear(); + } + + @Override + public void onItemsAdded(RecyclerView recyclerView, int positionStart, int itemCount) { + int newPosition = currentPosition; + if (currentPosition == NO_POSITION) { + newPosition = 0; + } else if (currentPosition >= positionStart) { + newPosition = Math.min(currentPosition + itemCount, recyclerViewProxy.getItemCount() - 1); + } + onNewPosition(newPosition); + } + + @Override + public void onItemsRemoved(RecyclerView recyclerView, int positionStart, int itemCount) { + int newPosition = currentPosition; + if (recyclerViewProxy.getItemCount() == 0) { + newPosition = NO_POSITION; + } else if (currentPosition >= positionStart) { + if (currentPosition < positionStart + itemCount) { + //If currentPosition is in the removed items, then the new item became current + currentPosition = NO_POSITION; + } + newPosition = Math.max(0, currentPosition - itemCount); + } + onNewPosition(newPosition); + } + + @Override + public void onItemsChanged(RecyclerView recyclerView) { + //notifyDataSetChanged() was called. We need to ensure that currentPosition is not out of bounds + currentPosition = Math.min(Math.max(0, currentPosition), recyclerViewProxy.getItemCount() - 1); + dataSetChangeShiftedPosition = true; + } + + private void onNewPosition(int position) { + if (currentPosition != position) { + currentPosition = position; + dataSetChangeShiftedPosition = true; + } + } + + @Override + public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) { + return scrollBy(dx, recycler); + } + + @Override + public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) { + return scrollBy(dy, recycler); + } + + protected int scrollBy(int amount, RecyclerView.Recycler recycler) { + if (recyclerViewProxy.getChildCount() == 0) { + return 0; + } + + Direction direction = Direction.fromDelta(amount); + int leftToScroll = calculateAllowedScrollIn(direction); + if (leftToScroll <= 0) { + return 0; + } + + int delta = direction.applyTo(Math.min(leftToScroll, Math.abs(amount))); + scrolled += delta; + if (pendingScroll != 0) { + pendingScroll -= delta; + } + + orientationHelper.offsetChildren(-delta, recyclerViewProxy); + + if (orientationHelper.hasNewBecomeVisible(this)) { + fill(recycler); + } + + notifyScroll(); + + applyItemTransformToChildren(); + + return delta; + } + + protected void applyItemTransformToChildren() { + if (itemTransformer != null) { + int clampAfterDistance = scrollToChangeCurrent * transformClampItemCount; + for (int i = 0; i < recyclerViewProxy.getChildCount(); i++) { + View child = recyclerViewProxy.getChildAt(i); + float position = getCenterRelativePositionOf(child, clampAfterDistance); + itemTransformer.transformItem(child, position); + } + } + } + + @Override + public void scrollToPosition(int position) { + if (currentPosition == position) { + return; + } + + currentPosition = position; + recyclerViewProxy.requestLayout(); + } + + @Override + public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) { + if (currentPosition == position || pendingPosition != NO_POSITION) { + return; + } + checkTargetPosition(state, position); + if (currentPosition == NO_POSITION) { + //Layout not happened yet + currentPosition = position; + } else { + startSmoothPendingScroll(position); + } + } + + @Override + public boolean canScrollHorizontally() { + return orientationHelper.canScrollHorizontally(); + } + + @Override + public boolean canScrollVertically() { + return orientationHelper.canScrollVertically(); + } + + @Override + public void onScrollStateChanged(int state) { + if (currentScrollState == RecyclerView.SCROLL_STATE_IDLE && currentScrollState != state) { + scrollStateListener.onScrollStart(); + } + + if (state == RecyclerView.SCROLL_STATE_IDLE) { + //Scroll is not finished until current view is centered + boolean isScrollEnded = onScrollEnd(); + if (isScrollEnded) { + scrollStateListener.onScrollEnd(); + } else { + //Scroll continues and we don't want to set currentScrollState to STATE_IDLE, + //because this will then trigger .scrollStateListener.onScrollStart() + return; + } + } else if (state == RecyclerView.SCROLL_STATE_DRAGGING) { + onDragStart(); + } + currentScrollState = state; + } + + /** + * @return true if scroll is ended and we don't need to settle items + */ + private boolean onScrollEnd() { + if (pendingPosition != NO_POSITION) { + currentPosition = pendingPosition; + pendingPosition = NO_POSITION; + scrolled = 0; + } + + Direction scrollDirection = Direction.fromDelta(scrolled); + if (Math.abs(scrolled) == scrollToChangeCurrent) { + currentPosition += scrollDirection.applyTo(1); + scrolled = 0; + } + + if (isAnotherItemCloserThanCurrent()) { + pendingScroll = getHowMuchIsLeftToScroll(scrolled); + } else { + pendingScroll = -scrolled; + } + + if (pendingScroll == 0) { + return true; + } else { + startSmoothPendingScroll(); + return false; + } + } + + private void onDragStart() { + //Here we need to: + //1. Stop any pending scroll + //2. Set currentPosition to position of the item that is closest to the center + boolean isScrollingThroughMultiplePositions = Math.abs(scrolled) > scrollToChangeCurrent; + if (isScrollingThroughMultiplePositions) { + int scrolledPositions = scrolled / scrollToChangeCurrent; + currentPosition += scrolledPositions; + scrolled -= scrolledPositions * scrollToChangeCurrent; + } + if (isAnotherItemCloserThanCurrent()) { + Direction direction = Direction.fromDelta(scrolled); + currentPosition += direction.applyTo(1); + scrolled = -getHowMuchIsLeftToScroll(scrolled); + } + pendingPosition = NO_POSITION; + pendingScroll = 0; + } + + public void onFling(int velocityX, int velocityY) { + int velocity = orientationHelper.getFlingVelocity(velocityX, velocityY); + int throttleValue = shouldSlideOnFling ? Math.abs(velocity / flingThreshold) : 1; + int newPosition = currentPosition + Direction.fromDelta(velocity).applyTo(throttleValue); + newPosition = checkNewOnFlingPositionIsInBounds(newPosition); + boolean isInScrollDirection = velocity * scrolled >= 0; + boolean canFling = isInScrollDirection && isInBounds(newPosition); + if (canFling) { + startSmoothPendingScroll(newPosition); + } else { + returnToCurrentPosition(); + } + } + + public void returnToCurrentPosition() { + pendingScroll = -scrolled; + if (pendingScroll != 0) { + startSmoothPendingScroll(); + } + } + + protected int calculateAllowedScrollIn(Direction direction) { + if (pendingScroll != 0) { + return Math.abs(pendingScroll); + } + int allowedScroll; + boolean isBoundReached; + boolean isScrollDirectionAsBefore = direction.applyTo(scrolled) > 0; + if (direction == Direction.START && currentPosition == 0) { + //We can scroll to the left when currentPosition == 0 only if we scrolled to the right before + isBoundReached = scrolled == 0; + allowedScroll = isBoundReached ? 0 : Math.abs(scrolled); + } else if (direction == Direction.END && currentPosition == recyclerViewProxy.getItemCount() - 1) { + //We can scroll to the right when currentPosition == last only if we scrolled to the left before + isBoundReached = scrolled == 0; + allowedScroll = isBoundReached ? 0 : Math.abs(scrolled); + } else { + isBoundReached = false; + allowedScroll = isScrollDirectionAsBefore ? + scrollToChangeCurrent - Math.abs(scrolled) : + scrollToChangeCurrent + Math.abs(scrolled); + } + scrollStateListener.onIsBoundReachedFlagChange(isBoundReached); + return allowedScroll; + } + + private void startSmoothPendingScroll() { + LinearSmoothScroller scroller = new DiscreteLinearSmoothScroller(context); + scroller.setTargetPosition(currentPosition); + recyclerViewProxy.startSmoothScroll(scroller); + } + + private void startSmoothPendingScroll(int position) { + if (currentPosition == position) return; + pendingScroll = -scrolled; + Direction direction = Direction.fromDelta(position - currentPosition); + int distanceToScroll = Math.abs(position - currentPosition) * scrollToChangeCurrent; + pendingScroll += direction.applyTo(distanceToScroll); + pendingPosition = position; + startSmoothPendingScroll(); + } + + @Override + public boolean isAutoMeasureEnabled() { + return true; + } + + @Override + public int computeVerticalScrollRange(RecyclerView.State state) { + return computeScrollRange(state); + } + + @Override + public int computeVerticalScrollOffset(RecyclerView.State state) { + return computeScrollOffset(state); + } + + @Override + public int computeVerticalScrollExtent(RecyclerView.State state) { + return computeScrollExtent(state); + } + + @Override + public int computeHorizontalScrollRange(RecyclerView.State state) { + return computeScrollRange(state); + } + + @Override + public int computeHorizontalScrollOffset(RecyclerView.State state) { + return computeScrollOffset(state); + } + + @Override + public int computeHorizontalScrollExtent(RecyclerView.State state) { + return computeScrollExtent(state); + } + + private int computeScrollOffset(RecyclerView.State state) { + int scrollbarSize = computeScrollExtent(state); + int offset = (int) ((scrolled / (float) scrollToChangeCurrent) * scrollbarSize); + return (currentPosition * scrollbarSize) + offset; + } + + private int computeScrollExtent(RecyclerView.State state) { + if (getItemCount() == 0) { + return 0; + } else { + return (int) (computeScrollRange(state) / (float) getItemCount()); + } + } + + private int computeScrollRange(RecyclerView.State state) { + if (getItemCount() == 0) { + return 0; + } else { + return scrollToChangeCurrent * (getItemCount() - 1); + } + } + + @Override + public void onAdapterChanged(RecyclerView.Adapter oldAdapter, RecyclerView.Adapter newAdapter) { + pendingPosition = NO_POSITION; + scrolled = pendingScroll = 0; + if (newAdapter instanceof InitialPositionProvider) { + currentPosition = ((InitialPositionProvider) newAdapter).getInitialPosition(); + } else { + currentPosition = 0; + } + recyclerViewProxy.removeAllViews(); + } + + @Override + public Parcelable onSaveInstanceState() { + Bundle bundle = new Bundle(); + if (pendingPosition != NO_POSITION) { + currentPosition = pendingPosition; + } + bundle.putInt(EXTRA_POSITION, currentPosition); + return bundle; + } + + @Override + public void onRestoreInstanceState(Parcelable state) { + Bundle bundle = (Bundle) state; + currentPosition = bundle.getInt(EXTRA_POSITION); + } + + @Override + public RecyclerView.LayoutParams generateDefaultLayoutParams() { + return new RecyclerView.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT); + } + + public int getNextPosition() { + if (scrolled == 0) { + return currentPosition; + } else if (pendingPosition != NO_POSITION) { + return pendingPosition; + } else { + return currentPosition + Direction.fromDelta(scrolled).applyTo(1); + } + } + + public void setItemTransformer(DiscreteScrollItemTransformer itemTransformer) { + this.itemTransformer = itemTransformer; + } + + public void setTimeForItemSettle(int timeForItemSettle) { + this.timeForItemSettle = timeForItemSettle; + } + + public void setOffscreenItems(int offscreenItems) { + this.offscreenItems = offscreenItems; + extraLayoutSpace = scrollToChangeCurrent * offscreenItems; + recyclerViewProxy.requestLayout(); + } + + public void setTransformClampItemCount(int transformClampItemCount) { + this.transformClampItemCount = transformClampItemCount; + applyItemTransformToChildren(); + } + + public void setOrientation(DSVOrientation orientation) { + orientationHelper = orientation.createHelper(); + recyclerViewProxy.removeAllViews(); + recyclerViewProxy.requestLayout(); + } + + public void setShouldSlideOnFling(boolean result) { + shouldSlideOnFling = result; + } + + public void setSlideOnFlingThreshold(int threshold) { + flingThreshold = threshold; + } + + public int getCurrentPosition() { + return currentPosition; + } + + @Override + public void onInitializeAccessibilityEvent(AccessibilityEvent event) { + super.onInitializeAccessibilityEvent(event); + if (recyclerViewProxy.getChildCount() > 0) { + final AccessibilityRecordCompat record = AccessibilityEventCompat.asRecord(event); + record.setFromIndex(getPosition(getFirstChild())); + record.setToIndex(getPosition(getLastChild())); + } + } + + private float getCenterRelativePositionOf(View v, int maxDistance) { + float distanceFromCenter = orientationHelper.getDistanceFromCenter(recyclerCenter, + getDecoratedLeft(v) + childHalfWidth, + getDecoratedTop(v) + childHalfHeight); + return Math.min(Math.max(-1f, distanceFromCenter / maxDistance), 1f); + } + + private int checkNewOnFlingPositionIsInBounds(int position) { + final int itemCount = recyclerViewProxy.getItemCount(); + //The check is required in case slide through multiple items is turned on + if (currentPosition != 0 && position < 0) { + //If currentPosition == 0 && position < 0 we forbid scroll to the left, + //but if currentPosition != 0 we can slide to the first item + return 0; + } else if (currentPosition != itemCount - 1 && position >= itemCount) { + return itemCount - 1; + } + return position; + } + + private int getHowMuchIsLeftToScroll(int dx) { + return Direction.fromDelta(dx).applyTo(scrollToChangeCurrent - Math.abs(scrolled)); + } + + private boolean isAnotherItemCloserThanCurrent() { + return Math.abs(scrolled) >= scrollToChangeCurrent * SCROLL_TO_SNAP_TO_ANOTHER_ITEM; + } + + public View getFirstChild() { + return recyclerViewProxy.getChildAt(0); + } + + public View getLastChild() { + return recyclerViewProxy.getChildAt(recyclerViewProxy.getChildCount() - 1); + } + + public int getExtraLayoutSpace() { + return extraLayoutSpace; + } + + private void notifyScroll() { + float amountToScroll = pendingPosition != NO_POSITION ? + Math.abs(scrolled + pendingScroll) : + scrollToChangeCurrent; + float position = -Math.min(Math.max(-1f, scrolled / amountToScroll), 1f); + scrollStateListener.onScroll(position); + } + + private boolean isInBounds(int itemPosition) { + return itemPosition >= 0 && itemPosition < recyclerViewProxy.getItemCount(); + } + + private boolean isViewVisible(Point viewCenter, int endBound) { + return orientationHelper.isViewVisible( + viewCenter, childHalfWidth, childHalfHeight, + endBound, extraLayoutSpace); + } + + private void checkTargetPosition(RecyclerView.State state, int targetPosition) { + if (targetPosition < 0 || targetPosition >= state.getItemCount()) { + throw new IllegalArgumentException(String.format(Locale.US, + "target position out of bounds: position=%d, itemCount=%d", + targetPosition, state.getItemCount())); + } + } + + protected void setRecyclerViewProxy(RecyclerViewProxy recyclerViewProxy) { + this.recyclerViewProxy = recyclerViewProxy; + } + + protected void setOrientationHelper(DSVOrientation.Helper orientationHelper) { + this.orientationHelper = orientationHelper; + } + + private class DiscreteLinearSmoothScroller extends LinearSmoothScroller { + + public DiscreteLinearSmoothScroller(Context context) { + super(context); + } + + @Override + public int calculateDxToMakeVisible(View view, int snapPreference) { + return orientationHelper.getPendingDx(-pendingScroll); + } + + @Override + public int calculateDyToMakeVisible(View view, int snapPreference) { + return orientationHelper.getPendingDy(-pendingScroll); + } + + @Override + protected int calculateTimeForScrolling(int dx) { + float dist = Math.min(Math.abs(dx), scrollToChangeCurrent); + return (int) (Math.max(0.01f, dist / scrollToChangeCurrent) * timeForItemSettle); + } + + @Nullable + @Override + public PointF computeScrollVectorForPosition(int targetPosition) { + return new PointF( + orientationHelper.getPendingDx(pendingScroll), + orientationHelper.getPendingDy(pendingScroll)); + } + } + + public interface ScrollStateListener { + void onIsBoundReachedFlagChange(boolean isBoundReached); + + void onScrollStart(); + + void onScrollEnd(); + + void onScroll(float currentViewPosition); + + void onCurrentViewFirstLayout(); + + void onDataSetChangeChangedPosition(); + } + + public interface InitialPositionProvider { + int getInitialPosition(); + } +} diff --git a/libraries/card-library/src/main/java/com/yarolegovich/discretescrollview/DiscreteScrollView.java b/libraries/card-library/src/main/java/com/yarolegovich/discretescrollview/DiscreteScrollView.java new file mode 100644 index 0000000000..27973063b8 --- /dev/null +++ b/libraries/card-library/src/main/java/com/yarolegovich/discretescrollview/DiscreteScrollView.java @@ -0,0 +1,293 @@ +package com.yarolegovich.discretescrollview; + +import android.content.Context; +import android.content.res.TypedArray; +import android.util.AttributeSet; +import android.view.View; + +import androidx.annotation.IntRange; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.RecyclerView; +import com.yarolegovich.discretescrollview.transform.DiscreteScrollItemTransformer; +import com.yarolegovich.discretescrollview.util.ScrollListenerAdapter; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by yarolegovich on 18.02.2017. + */ +@SuppressWarnings("unchecked") +public class DiscreteScrollView extends RecyclerView { + + public static final int NO_POSITION = DiscreteScrollLayoutManager.NO_POSITION; + + private static final int DEFAULT_ORIENTATION = DSVOrientation.HORIZONTAL.ordinal(); + + private DiscreteScrollLayoutManager layoutManager; + + private List scrollStateChangeListeners; + private List onItemChangedListeners; + + private boolean isOverScrollEnabled; + + public DiscreteScrollView(Context context) { + super(context); + init(null); + } + + public DiscreteScrollView(Context context, AttributeSet attrs) { + super(context, attrs); + init(attrs); + } + + public DiscreteScrollView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(attrs); + } + + private void init(AttributeSet attrs) { + scrollStateChangeListeners = new ArrayList<>(); + onItemChangedListeners = new ArrayList<>(); + + int orientation = DEFAULT_ORIENTATION; + if (attrs != null) { + TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.DiscreteScrollView); + orientation = ta.getInt(R.styleable.DiscreteScrollView_dsv_orientation, DEFAULT_ORIENTATION); + ta.recycle(); + } + + isOverScrollEnabled = getOverScrollMode() != OVER_SCROLL_NEVER; + + layoutManager = new DiscreteScrollLayoutManager( + getContext(), new ScrollStateListener(), + DSVOrientation.values()[orientation]); + setLayoutManager(layoutManager); + } + + @Override + public void setLayoutManager(LayoutManager layout) { + if (layout instanceof DiscreteScrollLayoutManager) { + super.setLayoutManager(layout); + } else { + throw new IllegalArgumentException(getContext().getString(R.string.dsv_ex_msg_dont_set_lm)); + } + } + + + @Override + public boolean fling(int velocityX, int velocityY) { + boolean isFling = super.fling(velocityX, velocityY); + if (isFling) { + layoutManager.onFling(velocityX, velocityY); + } else { + layoutManager.returnToCurrentPosition(); + } + return isFling; + } + + @Nullable + public ViewHolder getViewHolder(int position) { + View view = layoutManager.findViewByPosition(position); + return view != null ? getChildViewHolder(view) : null; + } + + /** + * @return adapter position of the current item or -1 if nothing is selected + */ + public int getCurrentItem() { + return layoutManager.getCurrentPosition(); + } + + public void setItemTransformer(DiscreteScrollItemTransformer transformer) { + layoutManager.setItemTransformer(transformer); + } + + public void setItemTransitionTimeMillis(@IntRange(from = 10) int millis) { + layoutManager.setTimeForItemSettle(millis); + } + + public void setSlideOnFling(boolean result){ + layoutManager.setShouldSlideOnFling(result); + } + + public void setSlideOnFlingThreshold(int threshold){ + layoutManager.setSlideOnFlingThreshold(threshold); + } + + public void setOrientation(DSVOrientation orientation) { + layoutManager.setOrientation(orientation); + } + + public void setOffscreenItems(int items) { + layoutManager.setOffscreenItems(items); + } + + public void setClampTransformProgressAfter(@IntRange(from = 1) int itemCount) { + if (itemCount <= 1) { + throw new IllegalArgumentException("must be >= 1"); + } + layoutManager.setTransformClampItemCount(itemCount); + } + + public void setOverScrollEnabled(boolean overScrollEnabled) { + isOverScrollEnabled = overScrollEnabled; + setOverScrollMode(OVER_SCROLL_NEVER); + } + + public void addScrollStateChangeListener(@NonNull ScrollStateChangeListener scrollStateChangeListener) { + scrollStateChangeListeners.add(scrollStateChangeListener); + } + + public void addScrollListener(@NonNull ScrollListener scrollListener) { + addScrollStateChangeListener(new ScrollListenerAdapter(scrollListener)); + } + + public void addOnItemChangedListener(@NonNull OnItemChangedListener onItemChangedListener) { + onItemChangedListeners.add(onItemChangedListener); + } + + public void removeScrollStateChangeListener(@NonNull ScrollStateChangeListener scrollStateChangeListener) { + scrollStateChangeListeners.remove(scrollStateChangeListener); + } + + public void removeScrollListener(@NonNull ScrollListener scrollListener) { + removeScrollStateChangeListener(new ScrollListenerAdapter<>(scrollListener)); + } + + public void removeItemChangedListener(@NonNull OnItemChangedListener onItemChangedListener) { + onItemChangedListeners.remove(onItemChangedListener); + } + + private void notifyScrollStart(ViewHolder holder, int current) { + for (ScrollStateChangeListener listener : scrollStateChangeListeners) { + listener.onScrollStart(holder, current); + } + } + + private void notifyScrollEnd(ViewHolder holder, int current) { + for (ScrollStateChangeListener listener : scrollStateChangeListeners) { + listener.onScrollEnd(holder, current); + } + } + + private void notifyScroll(float position, + int currentIndex, int newIndex, + ViewHolder currentHolder, ViewHolder newHolder) { + for (ScrollStateChangeListener listener : scrollStateChangeListeners) { + listener.onScroll(position, currentIndex, newIndex, + currentHolder, + newHolder); + } + } + + private void notifyCurrentItemChanged(ViewHolder holder, int current) { + for (OnItemChangedListener listener : onItemChangedListeners) { + listener.onCurrentItemChanged(holder, current); + } + } + + private void notifyCurrentItemChanged() { + if (onItemChangedListeners.isEmpty()) { + return; + } + int current = layoutManager.getCurrentPosition(); + ViewHolder currentHolder = getViewHolder(current); + notifyCurrentItemChanged(currentHolder, current); + } + + private class ScrollStateListener implements DiscreteScrollLayoutManager.ScrollStateListener { + + @Override + public void onIsBoundReachedFlagChange(boolean isBoundReached) { + if (isOverScrollEnabled) { + setOverScrollMode(isBoundReached ? OVER_SCROLL_ALWAYS : OVER_SCROLL_NEVER); + } + } + + @Override + public void onScrollStart() { + if (scrollStateChangeListeners.isEmpty()) { + return; + } + int current = layoutManager.getCurrentPosition(); + ViewHolder holder = getViewHolder(current); + if (holder != null) { + notifyScrollStart(holder, current); + } + } + + @Override + public void onScrollEnd() { + if (onItemChangedListeners.isEmpty() && scrollStateChangeListeners.isEmpty()) { + return; + } + int current = layoutManager.getCurrentPosition(); + ViewHolder holder = getViewHolder(current); + if (holder != null) { + notifyScrollEnd(holder, current); + notifyCurrentItemChanged(holder, current); + } + } + + @Override + public void onScroll(float currentViewPosition) { + if (scrollStateChangeListeners.isEmpty()) { + return; + } + int currentIndex = getCurrentItem(); + int newIndex = layoutManager.getNextPosition(); + if (currentIndex != newIndex) { + notifyScroll(currentViewPosition, + currentIndex, newIndex, + getViewHolder(currentIndex), + getViewHolder(newIndex)); + } + } + + @Override + public void onCurrentViewFirstLayout() { + post(new Runnable() { + @Override + public void run() { + notifyCurrentItemChanged(); + } + }); + } + + @Override + public void onDataSetChangeChangedPosition() { + notifyCurrentItemChanged(); + } + } + + public interface ScrollStateChangeListener { + + void onScrollStart(@NonNull T currentItemHolder, int adapterPosition); + + void onScrollEnd(@NonNull T currentItemHolder, int adapterPosition); + + void onScroll(float scrollPosition, + int currentPosition, + int newPosition, + @Nullable T currentHolder, + @Nullable T newCurrent); + } + + public interface ScrollListener { + + void onScroll(float scrollPosition, + int currentPosition, int newPosition, + @Nullable T currentHolder, + @Nullable T newCurrent); + } + + public interface OnItemChangedListener { + /* + * This method will be also triggered when view appears on the screen for the first time. + * If data set is empty, viewHolder will be null and adapterPosition will be NO_POSITION + */ + void onCurrentItemChanged(@Nullable T viewHolder, int adapterPosition); + } +} diff --git a/libraries/card-library/src/main/java/com/yarolegovich/discretescrollview/InfiniteScrollAdapter.java b/libraries/card-library/src/main/java/com/yarolegovich/discretescrollview/InfiniteScrollAdapter.java new file mode 100644 index 0000000000..49cdb7ef45 --- /dev/null +++ b/libraries/card-library/src/main/java/com/yarolegovich/discretescrollview/InfiniteScrollAdapter.java @@ -0,0 +1,178 @@ +package com.yarolegovich.discretescrollview; + +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; +import java.util.Locale; + +/** + * Created by yarolegovich on 28-Apr-17. + */ + +public class InfiniteScrollAdapter extends RecyclerView.Adapter + implements DiscreteScrollLayoutManager.InitialPositionProvider { + + private static final int CENTER = Integer.MAX_VALUE / 2; + private static final int RESET_BOUND = 100; + + public static InfiniteScrollAdapter wrap( + @NonNull RecyclerView.Adapter adapter) { + return new InfiniteScrollAdapter<>(adapter); + } + + private RecyclerView.Adapter wrapped; + private DiscreteScrollLayoutManager layoutManager; + + public InfiniteScrollAdapter(@NonNull RecyclerView.Adapter wrapped) { + this.wrapped = wrapped; + this.wrapped.registerAdapterDataObserver(new DataSetChangeDelegate()); + } + + @Override + public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) { + wrapped.onAttachedToRecyclerView(recyclerView); + if (recyclerView instanceof DiscreteScrollView) { + layoutManager = (DiscreteScrollLayoutManager) recyclerView.getLayoutManager(); + } else { + String msg = recyclerView.getContext().getString(R.string.dsv_ex_msg_adapter_wrong_recycler); + throw new RuntimeException(msg); + } + } + + @Override + public void onDetachedFromRecyclerView(@NonNull RecyclerView recyclerView) { + wrapped.onDetachedFromRecyclerView(recyclerView); + layoutManager = null; + } + + @Override + public @NonNull T onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + return wrapped.onCreateViewHolder(parent, viewType); + } + + @Override + public void onBindViewHolder(@NonNull T holder, int position) { + if (isResetRequired(position)) { + int resetPosition = CENTER + mapPositionToReal(layoutManager.getCurrentPosition()); + setPosition(resetPosition); + return; + } + wrapped.onBindViewHolder(holder, mapPositionToReal(position)); + } + + @Override + public int getItemViewType(int position) { + return wrapped.getItemViewType(mapPositionToReal(position)); + } + + @Override + public int getItemCount() { + return isInfinite() ? Integer.MAX_VALUE : wrapped.getItemCount(); + } + + public int getRealItemCount() { + return wrapped.getItemCount(); + } + + public int getRealCurrentPosition() { + return getRealPosition(layoutManager.getCurrentPosition()); + } + + public int getRealPosition(int position) { + return mapPositionToReal(position); + } + + public int getClosestPosition(int position) { + ensureValidPosition(position); + int adapterCurrent = layoutManager.getCurrentPosition(); + int current = mapPositionToReal(adapterCurrent); + if (position == current) { + return adapterCurrent; + } + int delta = position - current; + int target = adapterCurrent + delta; + int wraparoundTarget = adapterCurrent + (position > current ? + delta - wrapped.getItemCount() : + wrapped.getItemCount() + delta); + int distance = Math.abs(adapterCurrent - target); + int wraparoundDistance = Math.abs(adapterCurrent - wraparoundTarget); + if (distance == wraparoundDistance) { + //Scroll to the right feels more natural, so prefer it + return target > adapterCurrent ? target : wraparoundTarget; + } else { + return distance < wraparoundDistance ? target : wraparoundTarget; + } + } + + private int mapPositionToReal(int position) { + if (position < CENTER) { + int rem = (CENTER - position) % wrapped.getItemCount(); + return rem == 0 ? 0 : wrapped.getItemCount() - rem; + } else { + return (position - CENTER) % wrapped.getItemCount(); + } + } + + private boolean isResetRequired(int requestedPosition) { + return isInfinite() + && (requestedPosition <= RESET_BOUND + || requestedPosition >= (Integer.MAX_VALUE - RESET_BOUND)); + } + + private void ensureValidPosition(int position) { + if (position >= wrapped.getItemCount()) { + throw new IndexOutOfBoundsException(String.format(Locale.US, + "requested position is outside adapter's bounds: position=%d, size=%d", + position, wrapped.getItemCount())); + } + } + + private boolean isInfinite() { + return wrapped.getItemCount() > 1; + } + + @Override + public int getInitialPosition() { + return isInfinite() ? CENTER : 0; + } + + private void setPosition(int position) { + layoutManager.scrollToPosition(position); + } + + //TODO: handle proper data set change notifications + private class DataSetChangeDelegate extends RecyclerView.AdapterDataObserver { + + @Override + public void onChanged() { + setPosition(getInitialPosition()); + notifyDataSetChanged(); + } + + @Override + public void onItemRangeRemoved(int positionStart, int itemCount) { + onChanged(); + } + + @Override + public void onItemRangeInserted(int positionStart, int itemCount) { + onChanged(); + } + + @Override + public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) { + onChanged(); + } + + @Override + public void onItemRangeChanged(int positionStart, int itemCount) { + notifyItemRangeChanged(0, getItemCount()); + } + + @Override + public void onItemRangeChanged(int positionStart, int itemCount, Object payload) { + notifyItemRangeChanged(0, getItemCount(), payload); + } + } +} \ No newline at end of file diff --git a/libraries/card-library/src/main/java/com/yarolegovich/discretescrollview/RecyclerViewProxy.java b/libraries/card-library/src/main/java/com/yarolegovich/discretescrollview/RecyclerViewProxy.java new file mode 100644 index 0000000000..cbafbf4f6b --- /dev/null +++ b/libraries/card-library/src/main/java/com/yarolegovich/discretescrollview/RecyclerViewProxy.java @@ -0,0 +1,107 @@ +package com.yarolegovich.discretescrollview; + +import android.view.View; +import android.view.ViewGroup; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +/** + * Created by yarolegovich on 10/25/17. + */ +public class RecyclerViewProxy { + + private RecyclerView.LayoutManager layoutManager; + + public RecyclerViewProxy(@NonNull RecyclerView.LayoutManager layoutManager) { + this.layoutManager = layoutManager; + } + + public void attachView(View view) { + layoutManager.attachView(view); + } + + public void detachView(View view) { + layoutManager.detachView(view); + } + + public void detachAndScrapView(View view, RecyclerView.Recycler recycler) { + layoutManager.detachAndScrapView(view, recycler); + } + + public void detachAndScrapAttachedViews(RecyclerView.Recycler recycler) { + layoutManager.detachAndScrapAttachedViews(recycler); + } + + public void recycleView(View view, RecyclerView.Recycler recycler) { + recycler.recycleView(view); + } + + public void removeAndRecycleAllViews(RecyclerView.Recycler recycler) { + layoutManager.removeAndRecycleAllViews(recycler); + } + + public int getChildCount() { + return layoutManager.getChildCount(); + } + + public int getItemCount() { + return layoutManager.getItemCount(); + } + + public View getMeasuredChildForAdapterPosition(int position, RecyclerView.Recycler recycler) { + View view = recycler.getViewForPosition(position); + layoutManager.addView(view); + layoutManager.measureChildWithMargins(view, 0, 0); + return view; + } + + public void layoutDecoratedWithMargins(View v, int left, int top, int right, int bottom) { + layoutManager.layoutDecoratedWithMargins(v, left, top, right, bottom); + } + + public View getChildAt(int index) { + return layoutManager.getChildAt(index); + } + + public int getPosition(View view) { + return layoutManager.getPosition(view); + } + + public int getMeasuredWidthWithMargin(View child) { + ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) child.getLayoutParams(); + return layoutManager.getDecoratedMeasuredWidth(child) + lp.leftMargin + lp.rightMargin; + } + + public int getMeasuredHeightWithMargin(View child) { + ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) child.getLayoutParams(); + return layoutManager.getDecoratedMeasuredHeight(child) + lp.topMargin + lp.bottomMargin; + } + + public int getWidth() { + return layoutManager.getWidth(); + } + + public int getHeight() { + return layoutManager.getHeight(); + } + + public void offsetChildrenHorizontal(int amount) { + layoutManager.offsetChildrenHorizontal(amount); + } + + public void offsetChildrenVertical(int amount) { + layoutManager.offsetChildrenVertical(amount); + } + + public void requestLayout() { + layoutManager.requestLayout(); + } + + public void startSmoothScroll(RecyclerView.SmoothScroller smoothScroller) { + layoutManager.startSmoothScroll(smoothScroller); + } + + public void removeAllViews() { + layoutManager.removeAllViews(); + } +} diff --git a/libraries/card-library/src/main/java/com/yarolegovich/discretescrollview/transform/DiscreteScrollItemTransformer.java b/libraries/card-library/src/main/java/com/yarolegovich/discretescrollview/transform/DiscreteScrollItemTransformer.java new file mode 100644 index 0000000000..957ae51f41 --- /dev/null +++ b/libraries/card-library/src/main/java/com/yarolegovich/discretescrollview/transform/DiscreteScrollItemTransformer.java @@ -0,0 +1,11 @@ +package com.yarolegovich.discretescrollview.transform; + +import android.view.View; + +/** + * Created by yarolegovich on 02.03.2017. + */ + +public interface DiscreteScrollItemTransformer { + void transformItem(View item, float position); +} diff --git a/libraries/card-library/src/main/java/com/yarolegovich/discretescrollview/transform/Pivot.java b/libraries/card-library/src/main/java/com/yarolegovich/discretescrollview/transform/Pivot.java new file mode 100644 index 0000000000..fc5fcd11d2 --- /dev/null +++ b/libraries/card-library/src/main/java/com/yarolegovich/discretescrollview/transform/Pivot.java @@ -0,0 +1,116 @@ +package com.yarolegovich.discretescrollview.transform; + +import android.view.View; + +import androidx.annotation.IntDef; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Created by yarolegovich on 03.03.2017. + */ + +public class Pivot { + + public static final int AXIS_X = 0; + public static final int AXIS_Y = 1; + + private static final int PIVOT_CENTER = -1; + private static final int PIVOT_MAX = -2; + + private int axis; + private int pivotPoint; + + public Pivot(@Axis int axis, int pivotPoint) { + this.axis = axis; + this.pivotPoint = pivotPoint; + } + + public void setOn(View view) { + if (axis == AXIS_X) { + switch (pivotPoint) { + case PIVOT_CENTER: + view.setPivotX(view.getWidth() * 0.5f); + break; + case PIVOT_MAX: + view.setPivotX(view.getWidth()); + break; + default: + view.setPivotX(pivotPoint); + break; + } + return; + } + + if (axis == AXIS_Y) { + switch (pivotPoint) { + case PIVOT_CENTER: + view.setPivotY(view.getHeight() * 0.5f); + break; + case PIVOT_MAX: + view.setPivotY(view.getHeight()); + break; + default: + view.setPivotY(pivotPoint); + break; + } + } + } + + @Axis + public int getAxis() { + return axis; + } + + public enum X { + LEFT { + @Override + public Pivot create() { + return new Pivot(AXIS_X, 0); + } + }, + CENTER { + @Override + public Pivot create() { + return new Pivot(AXIS_X, PIVOT_CENTER); + } + }, + RIGHT { + @Override + public Pivot create() { + return new Pivot(AXIS_X, PIVOT_MAX); + } + }; + + public abstract Pivot create(); + } + + public enum Y { + TOP { + @Override + public Pivot create() { + return new Pivot(AXIS_Y, 0); + } + }, + CENTER { + @Override + public Pivot create() { + return new Pivot(AXIS_Y, PIVOT_CENTER); + } + }, + BOTTOM { + @Override + public Pivot create() { + return new Pivot(AXIS_Y, PIVOT_MAX); + } + }; + + public abstract Pivot create(); + } + + @IntDef({AXIS_X, AXIS_Y}) + @Retention(RetentionPolicy.SOURCE) + public @interface Axis{ + } +} + diff --git a/libraries/card-library/src/main/java/com/yarolegovich/discretescrollview/transform/ScaleTransformer.java b/libraries/card-library/src/main/java/com/yarolegovich/discretescrollview/transform/ScaleTransformer.java new file mode 100644 index 0000000000..74a0d26087 --- /dev/null +++ b/libraries/card-library/src/main/java/com/yarolegovich/discretescrollview/transform/ScaleTransformer.java @@ -0,0 +1,84 @@ +package com.yarolegovich.discretescrollview.transform; + +import android.view.View; +import androidx.annotation.FloatRange; + +/** + * Created by yarolegovich on 03.03.2017. + */ +public class ScaleTransformer implements DiscreteScrollItemTransformer { + + private Pivot pivotX; + private Pivot pivotY; + private float minScale; + private float maxMinDiff; + + public ScaleTransformer() { + pivotX = Pivot.X.CENTER.create(); + pivotY = Pivot.Y.CENTER.create(); + minScale = 0.8f; + maxMinDiff = 0.2f; + } + + @Override + public void transformItem(View item, float position) { + pivotX.setOn(item); + pivotY.setOn(item); + float closenessToCenter = 1f - Math.abs(position); + float scale = minScale + maxMinDiff * closenessToCenter; + item.setScaleX(scale); + item.setScaleY(scale); + } + + public static class Builder { + + private ScaleTransformer transformer; + private float maxScale; + + public Builder() { + transformer = new ScaleTransformer(); + maxScale = 1f; + } + + public Builder setMinScale(@FloatRange(from = 0.01) float scale) { + transformer.minScale = scale; + return this; + } + + public Builder setMaxScale(@FloatRange(from = 0.01) float scale) { + maxScale = scale; + return this; + } + + public Builder setPivotX(Pivot.X pivotX) { + return setPivotX(pivotX.create()); + } + + public Builder setPivotX(Pivot pivot) { + assertAxis(pivot, Pivot.AXIS_X); + transformer.pivotX = pivot; + return this; + } + + public Builder setPivotY(Pivot.Y pivotY) { + return setPivotY(pivotY.create()); + } + + public Builder setPivotY(Pivot pivot) { + assertAxis(pivot, Pivot.AXIS_Y); + transformer.pivotY = pivot; + return this; + } + + public ScaleTransformer build() { + transformer.maxMinDiff = maxScale - transformer.minScale; + return transformer; + } + + private void assertAxis(Pivot pivot, @Pivot.Axis int axis) { + if (pivot.getAxis() != axis) { + throw new IllegalArgumentException("You passed a Pivot for wrong axis."); + } + } + } +} diff --git a/libraries/card-library/src/main/java/com/yarolegovich/discretescrollview/util/ScrollListenerAdapter.java b/libraries/card-library/src/main/java/com/yarolegovich/discretescrollview/util/ScrollListenerAdapter.java new file mode 100644 index 0000000000..265ab331f0 --- /dev/null +++ b/libraries/card-library/src/main/java/com/yarolegovich/discretescrollview/util/ScrollListenerAdapter.java @@ -0,0 +1,44 @@ +package com.yarolegovich.discretescrollview.util; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.RecyclerView; +import com.yarolegovich.discretescrollview.DiscreteScrollView; + +/** + * Created by yarolegovich on 16.03.2017. + */ +public class ScrollListenerAdapter implements DiscreteScrollView.ScrollStateChangeListener { + + private DiscreteScrollView.ScrollListener adaptee; + + public ScrollListenerAdapter(@NonNull DiscreteScrollView.ScrollListener adaptee) { + this.adaptee = adaptee; + } + + @Override + public void onScrollStart(@NonNull T currentItemHolder, int adapterPosition) { + + } + + @Override + public void onScrollEnd(@NonNull T currentItemHolder, int adapterPosition) { + + } + + @Override + public void onScroll(float scrollPosition, + int currentIndex, int newIndex, + @Nullable T currentHolder, @Nullable T newCurrentHolder) { + adaptee.onScroll(scrollPosition, currentIndex, newIndex, currentHolder, newCurrentHolder); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof ScrollListenerAdapter) { + return adaptee.equals(((ScrollListenerAdapter) obj).adaptee); + } else { + return super.equals(obj); + } + } +} diff --git a/libraries/card-library/src/main/res/values/attr.xml b/libraries/card-library/src/main/res/values/attr.xml new file mode 100644 index 0000000000..7310089318 --- /dev/null +++ b/libraries/card-library/src/main/res/values/attr.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/libraries/card-library/src/main/res/values/strings.xml b/libraries/card-library/src/main/res/values/strings.xml new file mode 100644 index 0000000000..4909bfbff7 --- /dev/null +++ b/libraries/card-library/src/main/res/values/strings.xml @@ -0,0 +1,4 @@ + + You should not set LayoutManager on DiscreteScrollView.class instance. Library uses a special one. Just don\'t call the method. + InfiniteScrollAdapter is supposed to work only with DiscreteScrollView + diff --git a/libraries/map-amap/src/main/java/com/mogo/map/impl/amap/AMapNaviViewWrapper.java b/libraries/map-amap/src/main/java/com/mogo/map/impl/amap/AMapNaviViewWrapper.java index bc39f455c6..65d62c8ff2 100644 --- a/libraries/map-amap/src/main/java/com/mogo/map/impl/amap/AMapNaviViewWrapper.java +++ b/libraries/map-amap/src/main/java/com/mogo/map/impl/amap/AMapNaviViewWrapper.java @@ -7,6 +7,7 @@ import android.graphics.Point; import android.graphics.Rect; import android.os.Bundle; import android.os.SystemClock; +import android.os.Trace; import android.view.MotionEvent; import android.view.View; import android.view.animation.Interpolator; @@ -319,7 +320,9 @@ public class AMapNaviViewWrapper implements IMogoMapView, @Override public void onLockMap( boolean isLock ) { Logger.d( TAG, "lock status = %s", isLock ); + Trace.beginSection( "timer.onCameraChangeFinish" ); MogoMapListenerHandler.getInstance().onLockMap( isLock ); + Trace.endSection(); } @Override @@ -418,7 +421,6 @@ public class AMapNaviViewWrapper implements IMogoMapView, } - private boolean checkAMapView() { if ( mMapView == null ) { Logger.e( TAG, "高德mapView实例为空,请检查" ); @@ -549,17 +551,19 @@ public class AMapNaviViewWrapper implements IMogoMapView, @Override public void onCameraChangeFinish( CameraPosition cameraPosition ) { if ( cameraPosition != null ) { - MogoMapListenerHandler.getInstance() - .onMapChanged( ObjectUtils.fromAMap( cameraPosition.target ), cameraPosition.zoom, - cameraPosition.tilt, cameraPosition.bearing ); + Trace.beginSection( "timer.onCameraChangeFinish" ); + MogoMapListenerHandler.getInstance().onMapChanged( ObjectUtils.fromAMap( cameraPosition.target ), + cameraPosition.zoom, + cameraPosition.tilt, + cameraPosition.bearing ); + Trace.endSection(); } } @Override public MogoLatLng getCameraNorthEastPosition() { try { - return ObjectUtils.fromAMap( - mMapView.getMap().getProjection().getVisibleRegion().latLngBounds.northeast ); + return ObjectUtils.fromAMap( mMapView.getMap().getProjection().getVisibleRegion().latLngBounds.northeast ); } catch ( Exception e ) { } @@ -569,8 +573,7 @@ public class AMapNaviViewWrapper implements IMogoMapView, @Override public MogoLatLng getCameraSouthWestPosition() { try { - return ObjectUtils.fromAMap( - mMapView.getMap().getProjection().getVisibleRegion().latLngBounds.southwest ); + return ObjectUtils.fromAMap( mMapView.getMap().getProjection().getVisibleRegion().latLngBounds.southwest ); } catch ( Exception e ) { } diff --git a/libraries/map-amap/src/main/java/com/mogo/map/impl/amap/AMapWrapper.java b/libraries/map-amap/src/main/java/com/mogo/map/impl/amap/AMapWrapper.java index 9b73bf10ab..6372fcd37f 100644 --- a/libraries/map-amap/src/main/java/com/mogo/map/impl/amap/AMapWrapper.java +++ b/libraries/map-amap/src/main/java/com/mogo/map/impl/amap/AMapWrapper.java @@ -6,16 +6,21 @@ import com.amap.api.maps.AMap; import com.amap.api.maps.CameraUpdateFactory; import com.amap.api.maps.model.Marker; import com.amap.api.maps.model.MarkerOptions; +import com.amap.api.maps.model.Polyline; +import com.amap.api.maps.model.PolylineOptions; import com.amap.api.navi.AMapNaviView; import com.mogo.map.IMogoMap; import com.mogo.map.IMogoUiSettings; import com.mogo.map.impl.amap.marker.AMapInfoWindowAdapter; import com.mogo.map.impl.amap.marker.AMapMarkerWrapper; +import com.mogo.map.impl.amap.overlay.AMapPolylineWrapper; import com.mogo.map.impl.amap.uicontroller.AMapUIController; import com.mogo.map.impl.amap.utils.ObjectUtils; import com.mogo.map.marker.IMogoMarker; import com.mogo.map.marker.MogoMarkerOptions; import com.mogo.map.marker.MogoMarkersHandler; +import com.mogo.map.overlay.IMogoPolyline; +import com.mogo.map.overlay.MogoPolylineOptions; import com.mogo.map.uicontroller.IMogoMapUIController; import com.mogo.utils.logger.Logger; @@ -219,6 +224,19 @@ public class AMapWrapper implements IMogoMap { return 0; } + @Override + public IMogoPolyline addPolyline( MogoPolylineOptions options ) { + if ( checkAMap() ) { + PolylineOptions polylineOptions = ObjectUtils.fromMogo( options ); + if ( polylineOptions == null ) { + return null; + } + Polyline polyline = mAMap.addPolyline( polylineOptions ); + return new AMapPolylineWrapper( polyline, options ); + } + return null; + } + private boolean checkAMap() { if ( mAMap == null ) { Logger.e( TAG, "高德map实例为空,请检查" ); diff --git a/libraries/map-amap/src/main/java/com/mogo/map/impl/amap/location/ALocationClient.java b/libraries/map-amap/src/main/java/com/mogo/map/impl/amap/location/ALocationClient.java index 8dc2020411..a551c302bc 100644 --- a/libraries/map-amap/src/main/java/com/mogo/map/impl/amap/location/ALocationClient.java +++ b/libraries/map-amap/src/main/java/com/mogo/map/impl/amap/location/ALocationClient.java @@ -1,6 +1,7 @@ package com.mogo.map.impl.amap.location; import android.content.Context; +import android.os.Trace; import com.amap.api.location.AMapLocation; import com.amap.api.location.AMapLocationClient; @@ -139,6 +140,7 @@ public class ALocationClient implements IMogoLocationClient { aMapLocation.getLongitude() == 0.0D ) { return; } + Trace.beginSection("timer.onLocationChanged"); mLastLocation = ObjectUtils.fromAMap( aMapLocation ); synchronized ( sListeners ) { Iterator< IMogoLocationListener > listenerIterator = sListeners.iterator(); @@ -146,6 +148,7 @@ public class ALocationClient implements IMogoLocationClient { listenerIterator.next().onLocationChanged( mLastLocation.clone() ); } } + Trace.endSection(); } } diff --git a/libraries/map-amap/src/main/java/com/mogo/map/impl/amap/marker/AMapMarkerWrapper.java b/libraries/map-amap/src/main/java/com/mogo/map/impl/amap/marker/AMapMarkerWrapper.java index e248076708..a98e791870 100644 --- a/libraries/map-amap/src/main/java/com/mogo/map/impl/amap/marker/AMapMarkerWrapper.java +++ b/libraries/map-amap/src/main/java/com/mogo/map/impl/amap/marker/AMapMarkerWrapper.java @@ -294,7 +294,13 @@ public class AMapMarkerWrapper implements IMogoMarker, Observer { @Override public String getOwner() { - return this.mOwner == null ? mMogoMarkerOptions.getOwner() : mOwner; + if ( mOwner != null ) { + return mOwner; + } + if ( mMogoMarkerOptions != null ) { + return mMogoMarkerOptions.getOwner(); + } + return null; } @Override diff --git a/libraries/map-amap/src/main/java/com/mogo/map/impl/amap/navi/NaviListenerAdapter.java b/libraries/map-amap/src/main/java/com/mogo/map/impl/amap/navi/NaviListenerAdapter.java index 92cd15011f..81259970c1 100644 --- a/libraries/map-amap/src/main/java/com/mogo/map/impl/amap/navi/NaviListenerAdapter.java +++ b/libraries/map-amap/src/main/java/com/mogo/map/impl/amap/navi/NaviListenerAdapter.java @@ -2,6 +2,7 @@ package com.mogo.map.impl.amap.navi; import android.content.Context; import android.graphics.Rect; +import android.os.Trace; import com.amap.api.maps.model.Polyline; import com.amap.api.navi.AMapNavi; @@ -178,8 +179,10 @@ public class NaviListenerAdapter extends AMapNaviListenerAdapter { @Override public void onNaviInfoUpdate( NaviInfo naviInfo ) { + Trace.beginSection( "NaviListenerAdapter.onNaviInfoUpdate" ); MogoNaviListenerHandler.getInstance().onNaviInfoUpdate( ObjectUtils.fromAMap( mContext, naviInfo ) ); mNaviOverlayHelper.handleNaviInfoUpdate( naviInfo ); + Trace.endSection(); } @Override @@ -201,8 +204,10 @@ public class NaviListenerAdapter extends AMapNaviListenerAdapter { @Override public void onLocationChange( AMapNaviLocation aMapNaviLocation ) { + Trace.beginSection( "NaviListenerAdapter.onLocationChange" ); super.onLocationChange( aMapNaviLocation ); mNaviOverlayHelper.handlePassedLocation( aMapNaviLocation ); + Trace.endSection(); } public void stopNavi() { diff --git a/libraries/map-amap/src/main/java/com/mogo/map/impl/amap/overlay/AMapPolylineWrapper.java b/libraries/map-amap/src/main/java/com/mogo/map/impl/amap/overlay/AMapPolylineWrapper.java new file mode 100644 index 0000000000..0c2766d842 --- /dev/null +++ b/libraries/map-amap/src/main/java/com/mogo/map/impl/amap/overlay/AMapPolylineWrapper.java @@ -0,0 +1,196 @@ +package com.mogo.map.impl.amap.overlay; + +import com.amap.api.maps.model.LatLng; +import com.amap.api.maps.model.Polyline; +import com.amap.api.maps.model.PolylineOptions; +import com.mogo.map.MogoLatLng; +import com.mogo.map.impl.amap.utils.ObjectUtils; +import com.mogo.map.overlay.IMogoPolyline; +import com.mogo.map.overlay.MogoPolylineOptions; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author congtaowang + * @since 2020-03-10 + *

+ * 描述 + */ +public class AMapPolylineWrapper implements IMogoPolyline { + + private Polyline mPolyline; + private MogoPolylineOptions mOptions; + private boolean mIsDestroyed = false; + + public AMapPolylineWrapper( Polyline mPolyline, + MogoPolylineOptions mOptions ) { + this.mPolyline = mPolyline; + this.mOptions = mOptions; + } + + @Override + public void destroy() { + remove(); + } + + @Override + public void remove() { + if ( mPolyline != null ) { + mPolyline.remove(); + } + mIsDestroyed = true; + } + + @Override + public String getId() { + if ( mPolyline != null ) { + return mPolyline.getId(); + } + return null; + } + + @Override + public void setPoints( List< MogoLatLng > lonLats ) { + if ( lonLats == null || lonLats.isEmpty() ) { + mPolyline.setPoints( new ArrayList< LatLng >() ); + return; + } + ArrayList< LatLng > points = new ArrayList<>(); + for ( MogoLatLng lonLat : lonLats ) { + LatLng latLng = ObjectUtils.fromMogo2( lonLat ); + if ( latLng == null ) { + continue; + } + points.add( latLng ); + } + mPolyline.setPoints( points ); + } + + @Override + public List< MogoLatLng > getPoints() { + if ( mPolyline == null ) { + return null; + } + ArrayList< MogoLatLng > lonLats = new ArrayList<>(); + List< LatLng > points = mPolyline.getPoints(); + if ( points != null ) { + for ( LatLng latLng : points ) { + MogoLatLng lonLat = ObjectUtils.fromAMap( latLng ); + if ( lonLat == null ) { + continue; + } + lonLats.add( lonLat ); + } + } + return lonLats; + } + + @Override + public void setGeodesic( boolean draw ) { + if ( mPolyline != null ) { + mPolyline.setGeodesic( draw ); + } + } + + @Override + public boolean isGeodesic() { + return mPolyline == null ? false : mPolyline.isGeodesic(); + } + + @Override + public void setDottedLine( boolean dottedLine ) { + if ( mPolyline != null ) { + mPolyline.setDottedLine( dottedLine ); + } + } + + @Override + public boolean isDottedLine() { + return mPolyline == null ? false : mPolyline.isDottedLine(); + } + + @Override + public void setWidth( float width ) { + if ( mPolyline != null ) { + mPolyline.setWidth( width ); + } + } + + @Override + public float getWidth() { + if ( mPolyline != null ) { + return mPolyline.getWidth(); + } + return 0; + } + + @Override + public void setColor( int color ) { + if ( mPolyline != null ) { + mPolyline.setColor( color ); + } + } + + @Override + public int getColor() { + if ( mPolyline != null ) { + return mPolyline.getColor(); + } + return 0; + } + + @Override + public void setZIndex( float zIndex ) { + if ( mPolyline != null ) { + mPolyline.setZIndex( zIndex ); + } + } + + @Override + public float getZIndex() { + if ( mPolyline != null ) { + return mPolyline.getZIndex(); + } + return 0; + } + + @Override + public void setVisible( boolean visible ) { + if ( mPolyline != null ) { + mPolyline.setVisible( visible ); + } + } + + @Override + public boolean isVisible() { + if ( mPolyline != null ) { + return mPolyline.isVisible(); + } + return false; + } + + @Override + public void setTransparency( float transparency ) { + if ( mPolyline != null ) { + mPolyline.setTransparency( transparency ); + } + } + + @Override + public void setOption( MogoPolylineOptions option ) { + PolylineOptions target = ObjectUtils.fromMogo( option ); + if ( target == null ) { + return; + } + mOptions = option; + if ( mPolyline != null ) { + mPolyline.setOptions( target ); + } + } + + @Override + public boolean isDestroyed() { + return false; + } +} diff --git a/libraries/map-amap/src/main/java/com/mogo/map/impl/amap/utils/ObjectUtils.java b/libraries/map-amap/src/main/java/com/mogo/map/impl/amap/utils/ObjectUtils.java index 415974d956..e2f3c11892 100644 --- a/libraries/map-amap/src/main/java/com/mogo/map/impl/amap/utils/ObjectUtils.java +++ b/libraries/map-amap/src/main/java/com/mogo/map/impl/amap/utils/ObjectUtils.java @@ -10,6 +10,7 @@ import com.amap.api.maps.model.BitmapDescriptorFactory; import com.amap.api.maps.model.LatLng; import com.amap.api.maps.model.MarkerOptions; import com.amap.api.maps.model.Poi; +import com.amap.api.maps.model.PolylineOptions; import com.amap.api.navi.model.AMapCongestionLink; import com.amap.api.navi.model.AMapNaviTrafficFacilityInfo; import com.amap.api.navi.model.AimLessModeCongestionInfo; @@ -46,6 +47,7 @@ import com.mogo.map.navi.MogoCongestionLink; import com.mogo.map.navi.MogoNaviInfo; import com.mogo.map.navi.MogoNaviListenerHandler; import com.mogo.map.navi.MogoTraffic; +import com.mogo.map.overlay.MogoPolylineOptions; import com.mogo.map.search.geo.MogoAoiItem; import com.mogo.map.search.geo.MogoBusinessArea; import com.mogo.map.search.geo.MogoCrossroad; @@ -704,4 +706,31 @@ public class ObjectUtils { } return null; } + + public static PolylineOptions fromMogo( MogoPolylineOptions options ) { + if ( options == null ) { + return null; + } + PolylineOptions target = new PolylineOptions(); + if ( options.getPoints() != null ) { + List< LatLng > points = new ArrayList<>(); + for ( MogoLatLng point : options.getPoints() ) { + points.add( fromMogo2( point ) ); + } + target.addAll( points ); + } + target.width( options.getWidth() ); + target.color( options.getColor() ); + target.zIndex( options.getWidth() ); + target.visible( options.isVisible() ); + target.geodesic( options.isGeodesic() ); + target.setDottedLine( options.isDottedLine() ); + target.useGradient( options.isGradient() ); + target.transparency( options.getTransparency() ); + target.aboveMaskLayer( options.isAboveMaskLayer() ); + target.lineCapType( PolylineOptions.LineCapType.LineCapRound ); + target.lineJoinType( PolylineOptions.LineJoinType.LineJoinRound ); + target.setDottedLineType( PolylineOptions.DOTTEDLINE_TYPE_CIRCLE ); + return target; + } } diff --git a/libraries/mogo-map-api/src/main/java/com/mogo/map/IMogoMap.java b/libraries/mogo-map-api/src/main/java/com/mogo/map/IMogoMap.java index f306f0f4cb..1c648028dd 100644 --- a/libraries/mogo-map-api/src/main/java/com/mogo/map/IMogoMap.java +++ b/libraries/mogo-map-api/src/main/java/com/mogo/map/IMogoMap.java @@ -2,6 +2,8 @@ package com.mogo.map; import com.mogo.map.marker.IMogoMarker; import com.mogo.map.marker.MogoMarkerOptions; +import com.mogo.map.overlay.IMogoPolyline; +import com.mogo.map.overlay.MogoPolylineOptions; import com.mogo.map.uicontroller.IMogoMapUIController; import java.util.ArrayList; @@ -127,4 +129,12 @@ public interface IMogoMap { * @return */ float getZoomLevel(); + + /** + * 添加线段 + * + * @param options + * @return + */ + IMogoPolyline addPolyline( MogoPolylineOptions options ); } diff --git a/libraries/mogo-map-api/src/main/java/com/mogo/map/listener/MogoMapListenerHandler.java b/libraries/mogo-map-api/src/main/java/com/mogo/map/listener/MogoMapListenerHandler.java index 5c90b7de00..186e614ee8 100644 --- a/libraries/mogo-map-api/src/main/java/com/mogo/map/listener/MogoMapListenerHandler.java +++ b/libraries/mogo-map-api/src/main/java/com/mogo/map/listener/MogoMapListenerHandler.java @@ -54,63 +54,49 @@ public class MogoMapListenerHandler implements IMogoMapListener, IMogoMapListene @Override public void onMapLoaded() { if ( mDelegateListener != null ) { - synchronized ( mDelegateListener ) { - mDelegateListener.onMapLoaded(); - } + mDelegateListener.onMapLoaded(); } } @Override public void onTouch( MotionEvent motionEvent ) { if ( mDelegateListener != null ) { - synchronized ( mDelegateListener ) { - mDelegateListener.onTouch( motionEvent ); - } + mDelegateListener.onTouch( motionEvent ); } } @Override public void onPOIClick( MogoPoi poi ) { if ( mDelegateListener != null ) { - synchronized ( mDelegateListener ) { - mDelegateListener.onPOIClick( poi ); - } + mDelegateListener.onPOIClick( poi ); } } @Override public void onMapClick( MogoLatLng latLng ) { if ( mDelegateListener != null ) { - synchronized ( mDelegateListener ) { - mDelegateListener.onMapClick( latLng ); - } + mDelegateListener.onMapClick( latLng ); } } @Override public void onLockMap( boolean isLock ) { if ( mDelegateListener != null ) { - synchronized ( mDelegateListener ) { - mDelegateListener.onLockMap( isLock ); - } + mDelegateListener.onLockMap( isLock ); } } @Override public void onMapModeChanged( EnumMapUI ui ) { if ( mDelegateListener != null ) { - synchronized ( mDelegateListener ) { - mDelegateListener.onMapModeChanged( ui ); - } + mDelegateListener.onMapModeChanged( ui ); } } @Override public void onMapChanged( MogoLatLng location, float zoom, float tilt, float bearing ) { if ( mDelegateListener != null ) { - synchronized ( mDelegateListener ) { - mDelegateListener.onMapChanged( location, zoom, tilt, bearing ); - } + mDelegateListener.onMapChanged( location, zoom, tilt, bearing ); } } } diff --git a/libraries/mogo-map-api/src/main/java/com/mogo/map/overlay/IMogoOverlayManager.java b/libraries/mogo-map-api/src/main/java/com/mogo/map/overlay/IMogoOverlayManager.java new file mode 100644 index 0000000000..f429797e1a --- /dev/null +++ b/libraries/mogo-map-api/src/main/java/com/mogo/map/overlay/IMogoOverlayManager.java @@ -0,0 +1,18 @@ +package com.mogo.map.overlay; + +/** + * @author congtaowang + * @since 2020-03-10 + *

+ * 覆盖物 + */ +public interface IMogoOverlayManager { + + /** + * 绘制线段 + * + * @param options + * @return + */ + IMogoPolyline addPolyline( MogoPolylineOptions options ); +} diff --git a/libraries/mogo-map-api/src/main/java/com/mogo/map/overlay/IMogoPolyline.java b/libraries/mogo-map-api/src/main/java/com/mogo/map/overlay/IMogoPolyline.java new file mode 100644 index 0000000000..f20e545720 --- /dev/null +++ b/libraries/mogo-map-api/src/main/java/com/mogo/map/overlay/IMogoPolyline.java @@ -0,0 +1,144 @@ +package com.mogo.map.overlay; + +import androidx.annotation.ColorInt; + +import com.mogo.map.IDestroyable; +import com.mogo.map.MogoLatLng; + +import java.util.List; + +/** + * @author congtaowang + * @since 2020-03-10 + *

+ * 线段 + */ +public interface IMogoPolyline extends IDestroyable { + + + /** + * 是否已经销毁 + * + * @return + */ + boolean isDestroyed(); + + /** + * 移除 + */ + void remove(); + + /** + * 获取ID + * + * @return + */ + String getId(); + + /** + * 设置绘制点数据 + * + * @param lonLats + */ + void setPoints( List< MogoLatLng > lonLats ); + + /** + * 获取点 + * + * @return + */ + List< MogoLatLng > getPoints(); + + /** + * 测地线 + * + * @param draw + */ + void setGeodesic( boolean draw ); + + /** + * 是否设置了测地线 + * + * @return + */ + boolean isGeodesic(); + + /** + * 虚线 + * + * @param dottedLine + */ + void setDottedLine( boolean dottedLine ); + + /** + * 是否是虚线 + * + * @return + */ + boolean isDottedLine(); + + /** + * 设置线宽 + * + * @param width + */ + void setWidth( float width ); + + /** + * 获取线宽 + * + * @return + */ + float getWidth(); + + /** + * 设置线条颜色 + * + * @param color + */ + void setColor( @ColorInt int color ); + + /** + * 获取线条颜色 + * + * @return + */ + @ColorInt + int getColor(); + + /** + * 设置Z轴 + */ + void setZIndex( float zIndex ); + + /** + * 获取Z轴 + * + * @return + */ + float getZIndex(); + + /** + * 设置显示/隐藏 + */ + void setVisible( boolean visible ); + + /** + * 是否可见 + * + * @return + */ + boolean isVisible(); + + /** + * 设置透明度 + * + * @param transparency + */ + void setTransparency( float transparency ); + + /** + * 设置配置项 + */ + void setOption( MogoPolylineOptions option ); +} diff --git a/libraries/mogo-map-api/src/main/java/com/mogo/map/overlay/MogoPolylineOptions.java b/libraries/mogo-map-api/src/main/java/com/mogo/map/overlay/MogoPolylineOptions.java new file mode 100644 index 0000000000..a9cd740f09 --- /dev/null +++ b/libraries/mogo-map-api/src/main/java/com/mogo/map/overlay/MogoPolylineOptions.java @@ -0,0 +1,214 @@ +package com.mogo.map.overlay; + +import android.graphics.Color; + +import androidx.annotation.ColorInt; + +import com.mogo.map.MogoLatLng; +import com.mogo.map.location.MogoLocation; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * @author congtaowang + * @since 2020-03-10 + *

+ * 线段属性 + */ +public class MogoPolylineOptions { + + private List< MogoLatLng > mPoints; + private float mWidth = 10.0F; + private int mColor = Color.BLACK; + private float mZIndex = 0.0F; + private boolean mIsVisible = true; + private boolean mIsGeodesic = false; + private boolean mIsDottedLine = false; + private boolean mIsGradient = false; + private float mTransparency = 1.0F; + private boolean mIsAboveMaskLayer = false; + private boolean mIsPointsUpdated = false; + + public MogoPolylineOptions() { + this.mPoints = new ArrayList<>(); + } + + /** + * 设置顶点 + * + * @param points + * @return + */ + public MogoPolylineOptions points( List< MogoLatLng > points ) { + this.mPoints.clear(); + this.mPoints.addAll( points ); + this.mIsPointsUpdated = true; + return this; + } + + /** + * 添加顶点到集合最后 + * + * @param points + * @return + */ + public MogoPolylineOptions add( MogoLatLng... points ) { + if ( points != null ) { + this.mPoints.addAll( Arrays.asList( points ) ); + this.mIsPointsUpdated = true; + } + return this; + } + + public MogoPolylineOptions add( double lon, double lat ) { + this.mPoints.add( new MogoLatLng( lat, lon ) ); + return this; + } + + public MogoPolylineOptions add( MogoLocation location ) { + if ( location != null ) { + this.mPoints.add( new MogoLatLng( location.getLatitude(), location.getLongitude() ) ); + } + return this; + } + + /** + * 设置线宽 + */ + public MogoPolylineOptions width( float width ) { + this.mWidth = width; + return this; + } + + /** + * 设置线的颜色 + * + * @param color + * @return + */ + public MogoPolylineOptions color( @ColorInt int color ) { + this.mColor = color; + return this; + } + + /** + * 设置Z轴的值 + * + * @param zIndex + * @return + */ + public MogoPolylineOptions zIndex( float zIndex ) { + this.mZIndex = zIndex; + return this; + } + + /** + * 设置是否可见 + * + * @param isVisible + * @return + */ + public MogoPolylineOptions visible( boolean isVisible ) { + this.mIsVisible = isVisible; + return this; + } + + /** + * 设置是否绘制测地线 + * + * @param isGeodesic + * @return + */ + public MogoPolylineOptions geodesic( boolean isGeodesic ) { + this.mIsGeodesic = isGeodesic; + return this; + } + + /** + * 是否是虚线 + * + * @param isDottedLine + * @return + */ + public MogoPolylineOptions dottedLine( boolean isDottedLine ) { + this.mIsDottedLine = isDottedLine; + return this; + } + + /** + * 是否使用渐变色 + * + * @param isGradient + * @return + */ + public MogoPolylineOptions useGradient( boolean isGradient ) { + this.mIsGradient = isGradient; + return this; + } + + /** + * 设置透明度 + * + * @param transparency + * @return + */ + public MogoPolylineOptions transparency( float transparency ) { + this.mTransparency = transparency; + return this; + } + + /** + * @param isAboveMaskLayer + * @return + */ + public MogoPolylineOptions aboveMaskLayer( boolean isAboveMaskLayer ) { + this.mIsAboveMaskLayer = isAboveMaskLayer; + return this; + } + + public List< MogoLatLng > getPoints() { + return mPoints; + } + + public float getWidth() { + return mWidth; + } + + public int getColor() { + return mColor; + } + + public float getZIndex() { + return mZIndex; + } + + public boolean isVisible() { + return mIsVisible; + } + + public boolean isGeodesic() { + return mIsGeodesic; + } + + public boolean isDottedLine() { + return mIsDottedLine; + } + + public boolean isGradient() { + return mIsGradient; + } + + public float getTransparency() { + return mTransparency; + } + + public boolean isAboveMaskLayer() { + return mIsAboveMaskLayer; + } + + public boolean isPointsUpdated() { + return mIsPointsUpdated; + } +} diff --git a/libraries/mogo-map/src/main/java/com/mogo/map/MogoOverlayManager.java b/libraries/mogo-map/src/main/java/com/mogo/map/MogoOverlayManager.java new file mode 100644 index 0000000000..6cde910cf3 --- /dev/null +++ b/libraries/mogo-map/src/main/java/com/mogo/map/MogoOverlayManager.java @@ -0,0 +1,40 @@ +package com.mogo.map; + +import com.mogo.map.overlay.IMogoOverlayManager; +import com.mogo.map.overlay.IMogoPolyline; +import com.mogo.map.overlay.MogoPolylineOptions; + +/** + * @author congtaowang + * @since 2020-03-10 + *

+ * 描述 + */ +public class MogoOverlayManager implements IMogoOverlayManager { + + private MogoOverlayManager() { + // private constructor + } + + private static final class InstanceHolder { + private static final MogoOverlayManager INSTANCE = new MogoOverlayManager(); + } + + public static MogoOverlayManager getInstance() { + return InstanceHolder.INSTANCE; + } + + private Object readResolve() { + // 阻止反序列化,必须实现 Serializable 接口 + return InstanceHolder.INSTANCE; + } + + @Override + public IMogoPolyline addPolyline( MogoPolylineOptions options ) { + try { + return MogoMap.getInstance().getMogoMap().addPolyline( options ); + } catch ( Exception e ) { + return null; + } + } +} diff --git a/modules/mogo-module-apps/build.gradle b/modules/mogo-module-apps/build.gradle index 8b87ab74eb..4ac0696a0d 100644 --- a/modules/mogo-module-apps/build.gradle +++ b/modules/mogo-module-apps/build.gradle @@ -43,10 +43,10 @@ dependencies { implementation rootProject.ext.dependencies.material annotationProcessor rootProject.ext.dependencies.aroutercompiler implementation rootProject.ext.dependencies.androidxrecyclerview - if (Boolean.valueOf(RELEASE)) { implementation rootProject.ext.dependencies.mogomap implementation rootProject.ext.dependencies.mogomapapi + implementation rootProject.ext.dependencies.mogomapapi implementation rootProject.ext.dependencies.mogoutils api rootProject.ext.dependencies.mogocommons api rootProject.ext.dependencies.mogoserviceapi @@ -58,6 +58,8 @@ dependencies { api project(":foudations:mogo-commons") api project(':services:mogo-service-api') implementation project(':modules:mogo-module-common') + implementation project(":libraries:card-library") + } } diff --git a/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/AppNavigatorFragment.java b/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/AppNavigatorFragment.java index 8caeabbe1b..6cf4635b34 100644 --- a/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/AppNavigatorFragment.java +++ b/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/AppNavigatorFragment.java @@ -3,12 +3,18 @@ package com.mogo.module.apps; import android.os.Bundle; import android.view.View; +import android.widget.HorizontalScrollView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.LinearSnapHelper; +import androidx.recyclerview.widget.RecyclerView; import com.alibaba.android.arouter.launcher.ARouter; import com.mogo.commons.mvp.MvpFragment; +import com.mogo.module.apps.adapter.AppIndicatorAdapter; +import com.mogo.module.apps.utils.CardScaleTransformer; import com.mogo.module.apps.utils.LaunchUtils; import com.mogo.module.common.MogoModulePaths; import com.mogo.service.MogoServicePaths; @@ -18,6 +24,9 @@ import com.mogo.service.fragmentmanager.IMogoFragmentManager; import com.mogo.service.module.IMogoModuleProvider; import com.mogo.utils.TipToast; +import com.yarolegovich.discretescrollview.DiscreteScrollView; +import com.yarolegovich.discretescrollview.transform.ScaleTransformer; +import java.util.ArrayList; import java.util.HashMap; import java.util.Map; @@ -27,11 +36,10 @@ import java.util.Map; *

* 描述 */ -public class AppNavigatorFragment extends MvpFragment< AppNavigatorView, AppNavigatorPresenter > implements AppNavigatorView { +public class AppNavigatorFragment extends MvpFragment + implements AppNavigatorView, DiscreteScrollView.OnItemChangedListener, + DiscreteScrollView.ScrollStateChangeListener { - private View mNavigation; - private View mMediaCenter; - private View mCarSettings; private View mApps; private IMogoFragmentManager mMogoFragmentManager; @@ -42,6 +50,7 @@ public class AppNavigatorFragment extends MvpFragment< AppNavigatorView, AppNavi private IMogoModuleProvider mSearchProvider; private IMogoAnalytics mMogoAnalytics; + private DiscreteScrollView scroller; @Override protected int getLayoutId() { @@ -51,66 +60,105 @@ public class AppNavigatorFragment extends MvpFragment< AppNavigatorView, AppNavi @Override protected void initViews() { - mMogoFragmentManager = ( IMogoFragmentManager ) ARouter.getInstance().build( MogoServicePaths.PATH_FRAGMENT_MANAGER ).navigation(); + mMogoFragmentManager = (IMogoFragmentManager) ARouter.getInstance() + .build(MogoServicePaths.PATH_FRAGMENT_MANAGER) + .navigation(); - mNavigation = findViewById( R.id.module_apps_id_navigation ); - mMediaCenter = findViewById( R.id.module_apps_ic_media_center ); - mCarSettings = findViewById( R.id.module_apps_ic_car_settings ); - mApps = findViewById( R.id.module_apps_id_apps ); - mNavigation.setOnClickListener( view -> { - openSearchPanel(); - trackNavigatorClickEvent( 1 ); - } ); - mMediaCenter.setOnClickListener( view -> { - try { - LaunchUtils.launchByPkg( getContext(), AppsConst.APP_PKG_MUSIC ); - trackNavigatorClickEvent( 2 ); - } catch ( Exception e ) { - TipToast.shortTip( R.string.module_apps_str_no_app ); - } - } ); - mCarSettings.setOnClickListener( view -> { - try { - LaunchUtils.launchByPkg( getContext(), AppsConst.APP_PKG_CAR_SETTINGS ); - trackNavigatorClickEvent( 3 ); - } catch ( Exception e ) { - TipToast.shortTip( R.string.module_apps_str_no_app ); - } - } ); - mApps.setOnClickListener( view -> { + mApps = findViewById(R.id.module_apps_id_apps); + + scroller = findViewById(R.id.module_apps_id_scroller); + scroller.setSlideOnFling(true); + scroller.addOnItemChangedListener(this); + scroller.addScrollStateChangeListener(this); + //scroller.setItemTransitionTimeMillis(DiscreteScrollViewOptions.getTransitionTime()); + scroller.setItemTransformer(new CardScaleTransformer.Builder() + .setMinScale(0.84f) + .build()); + // + // + //LinearLayoutManager linearLayoutManager = + // new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false); + // + //scroller.setLayoutManager(linearLayoutManager); + + ArrayList integers = new ArrayList<>(10); + + integers.add(R.drawable.module_apps_ic_interest); + integers.add(R.drawable.module_apps_ic_online_car); + integers.add(R.drawable.module_apps_ic_news); + integers.add(R.drawable.module_apps_ic_tanlu); + integers.add(R.drawable.module_apps_ic_media_center); + + AppIndicatorAdapter appIndicatorAdapter = new AppIndicatorAdapter(getContext(), integers); + scroller.setAdapter(appIndicatorAdapter); + scroller.scrollToPosition(Integer.MAX_VALUE / 2-1); + //mNavigation.setOnClickListener( view -> { + // openSearchPanel(); + // trackNavigatorClickEvent( 1 ); + //} ); + //mMediaCenter.setOnClickListener( view -> { + // try { + // LaunchUtils.launchByPkg( getContext(), AppsConst.APP_PKG_MUSIC ); + // trackNavigatorClickEvent( 2 ); + // } catch ( Exception e ) { + // TipToast.shortTip( R.string.module_apps_str_no_app ); + // } + //} ); + //mCarSettings.setOnClickListener( view -> { + // try { + // LaunchUtils.launchByPkg( getContext(), AppsConst.APP_PKG_CAR_SETTINGS ); + // trackNavigatorClickEvent( 3 ); + // } catch ( Exception e ) { + // TipToast.shortTip( R.string.module_apps_str_no_app ); + // } + //} ); + mApps.setOnClickListener(view -> { openAppsPanel(); - trackNavigatorClickEvent( 4 ); - } ); + trackNavigatorClickEvent(4); + }); + } + + private void scrollToCenter(int index) { + } @NonNull @Override protected AppNavigatorPresenter createPresenter() { - return new AppNavigatorPresenter( this ); + return new AppNavigatorPresenter(this); } private void openSearchPanel() { - mSearchProvider = ( IMogoModuleProvider ) ARouter.getInstance().build( MogoModulePaths.PATH_MODULE_SEARCH ).navigation(); - final Fragment fragment = mSearchProvider.createFragment( getContext(), null ); - mMogoFragmentManager.push( new FragmentDescriptor.Builder().fragment( fragment ).tag( MogoModulePaths.PATH_FRAGMENT_SEARCH ).notifyMainModule( true ).build() ); + mSearchProvider = (IMogoModuleProvider) ARouter.getInstance() + .build(MogoModulePaths.PATH_MODULE_SEARCH) + .navigation(); + final Fragment fragment = mSearchProvider.createFragment(getContext(), null); + mMogoFragmentManager.push(new FragmentDescriptor.Builder().fragment(fragment) + .tag(MogoModulePaths.PATH_FRAGMENT_SEARCH) + .notifyMainModule(true) + .build()); } @Override - public void onActivityCreated( @Nullable Bundle savedInstanceState ) { - super.onActivityCreated( savedInstanceState ); - mMogoFragmentManager = ( IMogoFragmentManager ) ARouter.getInstance().build( MogoServicePaths.PATH_FRAGMENT_MANAGER ).navigation( getContext() ); - mMogoAnalytics = ( IMogoAnalytics ) ARouter.getInstance().build( MogoServicePaths.PATH_UTILS_ANALYTICS ).navigation( getContext() ); + public void onActivityCreated(@Nullable Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + mMogoFragmentManager = (IMogoFragmentManager) ARouter.getInstance() + .build(MogoServicePaths.PATH_FRAGMENT_MANAGER) + .navigation(getContext()); + mMogoAnalytics = (IMogoAnalytics) ARouter.getInstance() + .build(MogoServicePaths.PATH_UTILS_ANALYTICS) + .navigation(getContext()); } @Override public void openAppsPanel() { - AppsListActivity.start( getActivity() ); + AppsListActivity.start(getActivity()); } - private void trackNavigatorClickEvent( int type ) { - final Map< String, Object > properties = new HashMap<>(); - properties.put( "type", type ); - mMogoAnalytics.track( "Launcher_APP_Icon", properties ); + private void trackNavigatorClickEvent(int type) { + final Map properties = new HashMap<>(); + properties.put("type", type); + mMogoAnalytics.track("Launcher_APP_Icon", properties); } @Override @@ -120,8 +168,27 @@ public class AppNavigatorFragment extends MvpFragment< AppNavigatorView, AppNavi @Override public void onDestroyView() { super.onDestroyView(); - if ( mPresenter != null ) { - mPresenter.onDestroy( getViewLifecycleOwner() ); + if (mPresenter != null) { + mPresenter.onDestroy(getViewLifecycleOwner()); } } + + @Override + public void onCurrentItemChanged(@Nullable RecyclerView.ViewHolder viewHolder, int i) { + + } + + @Override public void onScrollStart(@NonNull RecyclerView.ViewHolder viewHolder, int i) { + + } + + @Override public void onScrollEnd(@NonNull RecyclerView.ViewHolder viewHolder, int i) { + + } + + @Override + public void onScroll(float v, int i, int i1, @Nullable RecyclerView.ViewHolder viewHolder, + @Nullable RecyclerView.ViewHolder t1) { + + } } diff --git a/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/adapter/AppIndicatorAdapter.java b/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/adapter/AppIndicatorAdapter.java new file mode 100644 index 0000000000..f5003e91d1 --- /dev/null +++ b/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/adapter/AppIndicatorAdapter.java @@ -0,0 +1,34 @@ +package com.mogo.module.apps.adapter; + +import android.content.Context; +import android.view.View; +import android.widget.ImageView; +import com.mogo.module.apps.R; +import com.mogo.module.apps.adapter.base.RecycleBaseAdapter; +import com.mogo.module.apps.adapter.base.RecycleViewHolder; +import java.util.List; + +/** + * @author zyz + * 2020-03-09. + */ +public class AppIndicatorAdapter extends RecycleBaseAdapter { + /** + * + */ + public AppIndicatorAdapter(Context context, List list + ) { + super(context, list, R.layout.module_apps_item_app_indicator); + } + + @Override public int getItemCount() { + return Integer.MAX_VALUE; + } + + @Override public void onBindViewHolder(RecycleViewHolder holder, Integer integer) { + ImageView ivIndicator = holder.getView(R.id.module_apps_id_app_icon); + ivIndicator.setImageResource(integer); + holder.setText(R.id.module_apps_id_app_name,names[holder.getLayoutPosition()%5] ); + } + private String[] names=new String[]{"新鲜事","在线车辆","首页","探路","车聊聊"}; +} diff --git a/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/adapter/base/RecycleBaseAdapter.java b/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/adapter/base/RecycleBaseAdapter.java new file mode 100644 index 0000000000..2a8cc64079 --- /dev/null +++ b/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/adapter/base/RecycleBaseAdapter.java @@ -0,0 +1,122 @@ +package com.mogo.module.apps.adapter.base; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Toast; +import androidx.recyclerview.widget.RecyclerView; +import java.util.List; + +/** + *

+ * Title: adapter + *

+ *

+ * Description: + *

+ *

+ * Copyright: Copyright (c) 2015 + *

+ *

+ *

+ */ +public abstract class RecycleBaseAdapter extends + RecyclerView.Adapter +{ + + protected Context context; + protected List list; + private int resourceID; + private Toast toast; + + /** + * @param context + */ + public RecycleBaseAdapter(Context context, List list, int resourceID) + { + super(); + this.context = context; + this.list = list; + this.resourceID = resourceID; + } + + @Override + public RecycleViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) + { + View v = LayoutInflater.from(context).inflate(resourceID, viewGroup, + false); + + RecycleViewHolder holder = RecycleViewHolder + .get(v); + + initHolder(holder); + + return holder; + } + + @Override + public void onBindViewHolder( + RecycleViewHolder viewHolder, int position) + { + onBindViewHolder(viewHolder, list.get(position % list.size())); + } + + @Override + public int getItemCount() + { + return list == null ? 0 : list.size(); + } + + public abstract void onBindViewHolder( + RecycleViewHolder holder, T t); + + public void initHolder(RecycleViewHolder holder) + { + + } + public void setDatas(List list) + { + setDatas(list, false); + } + + public void setDatas(List list, boolean add) + { + if (add) + { + this.list.addAll(list); + } + else + { + this.list = list; + } + notifyDataSetChanged(); + } + public void clear(){ + if (list != null) { + list.clear(); + notifyDataSetChanged(); + } + } + public void messageShow(String mes) + { + if (toast==null){ + toast= Toast.makeText(context,mes, Toast.LENGTH_LONG); + } + else{ + toast.setText(mes); + } + toast.show(); + } + + public T getItem(int position){ + if (list==null||list.size()==0){ + return null; + } + return list.get(position); + } + + public List getList() { + return list; + } +} diff --git a/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/adapter/base/RecycleViewHolder.java b/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/adapter/base/RecycleViewHolder.java new file mode 100644 index 0000000000..58bbebbfce --- /dev/null +++ b/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/adapter/base/RecycleViewHolder.java @@ -0,0 +1,138 @@ +package com.mogo.module.apps.adapter.base; + +import android.graphics.Bitmap; +import android.text.SpannableString; +import android.util.SparseArray; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.ImageView; +import android.widget.TextView; +import androidx.recyclerview.widget.RecyclerView; + +public class RecycleViewHolder extends RecyclerView.ViewHolder { + + private SparseArray mViews; + + private View mConvertView; + + public RecycleViewHolder(View itemView) { + super(itemView); + this.mConvertView = itemView; + mViews = new SparseArray(); + // TODO Auto-generated constructor stub + } + + public static RecycleViewHolder get(View itemView) { + return new RecycleViewHolder(itemView); + } + + public View getConvertView() { + return mConvertView; + } + + public T getView(int viewId) { + View view = mViews.get(viewId); + if (view == null) { + view = mConvertView.findViewById(viewId); + mViews.put(viewId, view); + } + return (T) view; + } + + /** + * + * @param viewId + * @param text + * @return + */ + public RecycleViewHolder setText(int viewId, String text) { + TextView tv = getView(viewId); + if (tv==null)return this; + tv.setText(text); + return this; + } + + /** + * + * @param viewId + * @param text + * @return + */ + public RecycleViewHolder setText(int viewId, SpannableString text) { + TextView tv = getView(viewId); + tv.setText(text); + return this; + } + + /** + * + * @param viewId + * @param resId + * @return + */ + public RecycleViewHolder setImageResource(int viewId, int resId) { + ImageView view = getView(viewId); + view.setImageResource(resId); + return this; + } + + /** + * + * @param viewId + * @return + */ + public RecycleViewHolder setImageBitmap(int viewId, Bitmap bitmap) { + ImageView view = getView(viewId); + view.setImageBitmap(bitmap); + return this; + } + + + /** + * + * @param viewId + * @param resId + * @return + */ + // public ViewHolder setImageURI(int viewId, String url) { + // ImageView view = getView(viewId); + // // ImageLoader.getInstance.loadImg(view,url); + // return this; + // } + + /** + * + * @param viewId + * @param resId + * @return + */ + public RecycleViewHolder setBackgroundImage(int viewId, int resId) { + View view = getView(viewId); + view.setBackgroundResource(resId); + return this; + } + + /** + * + * @param viewId + * @param resId + * @return + */ + public RecycleViewHolder setTextColor(int viewId, int resId) { + TextView view = getView(viewId); + view.setTextColor(resId); + return this; + } + + /** + * + * @param viewId + * @return + */ + public RecycleViewHolder setOnClickListener(int viewId, + OnClickListener listener) { + getView(viewId).setOnClickListener(listener); + return this; + } + +} diff --git a/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/utils/CardScaleTransformer.java b/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/utils/CardScaleTransformer.java new file mode 100644 index 0000000000..1bc8021d5d --- /dev/null +++ b/modules/mogo-module-apps/src/main/java/com/mogo/module/apps/utils/CardScaleTransformer.java @@ -0,0 +1,91 @@ +package com.mogo.module.apps.utils; + +import android.view.View; +import androidx.annotation.FloatRange; +import com.mogo.module.apps.R; +import com.yarolegovich.discretescrollview.transform.DiscreteScrollItemTransformer; +import com.yarolegovich.discretescrollview.transform.Pivot; +import com.yarolegovich.discretescrollview.transform.ScaleTransformer; + +/** + * @author zyz + * 2020-03-11. + */ +public class CardScaleTransformer implements DiscreteScrollItemTransformer { + + private Pivot pivotX; + private Pivot pivotY; + private float minScale; + private float maxMinDiff; + + public CardScaleTransformer() { + pivotX = Pivot.X.CENTER.create(); + pivotY = Pivot.Y.BOTTOM.create(); + minScale = 0.8f; + maxMinDiff = 0.2f; + } + + @Override + public void transformItem(View item, float position) { + + item= item.findViewById(R.id.module_apps_id_app_icon); + pivotX.setOn(item); + pivotY.setOn(item); + float closenessToCenter = 1f - Math.abs(position); + float scale = minScale + maxMinDiff * closenessToCenter; + item.setScaleX(scale); + item.setScaleY(scale); + } + + public static class Builder { + + private CardScaleTransformer transformer; + private float maxScale; + + public Builder() { + transformer = new CardScaleTransformer(); + maxScale = 1f; + } + + public Builder setMinScale(@FloatRange(from = 0.01) float scale) { + transformer.minScale = scale; + return this; + } + + public Builder setMaxScale(@FloatRange(from = 0.01) float scale) { + maxScale = scale; + return this; + } + + public Builder setPivotX(Pivot.X pivotX) { + return setPivotX(pivotX.create()); + } + + public Builder setPivotX(Pivot pivot) { + assertAxis(pivot, Pivot.AXIS_X); + transformer.pivotX = pivot; + return this; + } + + public Builder setPivotY(Pivot.Y pivotY) { + return setPivotY(pivotY.create()); + } + + public Builder setPivotY(Pivot pivot) { + assertAxis(pivot, Pivot.AXIS_Y); + transformer.pivotY = pivot; + return this; + } + + public CardScaleTransformer build() { + transformer.maxMinDiff = maxScale - transformer.minScale; + return transformer; + } + + private void assertAxis(Pivot pivot, @Pivot.Axis int axis) { + if (pivot.getAxis() != axis) { + throw new IllegalArgumentException("You passed a Pivot for wrong axis."); + } + } + } +} diff --git a/modules/mogo-module-apps/src/main/res/drawable-ldpi/module_apps_ic_apps.png b/modules/mogo-module-apps/src/main/res/drawable-ldpi/module_apps_ic_apps.png deleted file mode 100755 index c564b8867f..0000000000 Binary files a/modules/mogo-module-apps/src/main/res/drawable-ldpi/module_apps_ic_apps.png and /dev/null differ diff --git a/modules/mogo-module-apps/src/main/res/drawable-xhdpi/module_apps_ic_apps.png b/modules/mogo-module-apps/src/main/res/drawable-xhdpi/module_apps_ic_apps.png index 80ecfda0bd..f1fc6671f2 100755 Binary files a/modules/mogo-module-apps/src/main/res/drawable-xhdpi/module_apps_ic_apps.png and b/modules/mogo-module-apps/src/main/res/drawable-xhdpi/module_apps_ic_apps.png differ diff --git a/modules/mogo-module-apps/src/main/res/drawable-xhdpi/module_apps_ic_chat_icon.png b/modules/mogo-module-apps/src/main/res/drawable-xhdpi/module_apps_ic_chat_icon.png new file mode 100755 index 0000000000..9d74b24ea8 Binary files /dev/null and b/modules/mogo-module-apps/src/main/res/drawable-xhdpi/module_apps_ic_chat_icon.png differ diff --git a/modules/mogo-module-apps/src/main/res/drawable-xhdpi/module_apps_ic_chat_unchecked.png b/modules/mogo-module-apps/src/main/res/drawable-xhdpi/module_apps_ic_chat_unchecked.png new file mode 100755 index 0000000000..9b4d5501dc Binary files /dev/null and b/modules/mogo-module-apps/src/main/res/drawable-xhdpi/module_apps_ic_chat_unchecked.png differ diff --git a/modules/mogo-module-apps/src/main/res/drawable-xhdpi/module_apps_ic_interest.png b/modules/mogo-module-apps/src/main/res/drawable-xhdpi/module_apps_ic_interest.png new file mode 100755 index 0000000000..5d0d4e1a6d Binary files /dev/null and b/modules/mogo-module-apps/src/main/res/drawable-xhdpi/module_apps_ic_interest.png differ diff --git a/modules/mogo-module-apps/src/main/res/drawable-xhdpi/module_apps_ic_interest_unchecked.png b/modules/mogo-module-apps/src/main/res/drawable-xhdpi/module_apps_ic_interest_unchecked.png new file mode 100755 index 0000000000..807d603b7b Binary files /dev/null and b/modules/mogo-module-apps/src/main/res/drawable-xhdpi/module_apps_ic_interest_unchecked.png differ diff --git a/modules/mogo-module-apps/src/main/res/drawable-xhdpi/module_apps_ic_media_center.png b/modules/mogo-module-apps/src/main/res/drawable-xhdpi/module_apps_ic_media_center.png old mode 100644 new mode 100755 index 13aa66438a..1e6247d47a Binary files a/modules/mogo-module-apps/src/main/res/drawable-xhdpi/module_apps_ic_media_center.png and b/modules/mogo-module-apps/src/main/res/drawable-xhdpi/module_apps_ic_media_center.png differ diff --git a/modules/mogo-module-apps/src/main/res/drawable-xhdpi/module_apps_ic_media_center_checked.png b/modules/mogo-module-apps/src/main/res/drawable-xhdpi/module_apps_ic_media_center_checked.png new file mode 100755 index 0000000000..ded21b6af2 Binary files /dev/null and b/modules/mogo-module-apps/src/main/res/drawable-xhdpi/module_apps_ic_media_center_checked.png differ diff --git a/modules/mogo-module-apps/src/main/res/drawable-xhdpi/module_apps_ic_news.png b/modules/mogo-module-apps/src/main/res/drawable-xhdpi/module_apps_ic_news.png new file mode 100755 index 0000000000..b3bc19464e Binary files /dev/null and b/modules/mogo-module-apps/src/main/res/drawable-xhdpi/module_apps_ic_news.png differ diff --git a/modules/mogo-module-apps/src/main/res/drawable-xhdpi/module_apps_ic_news_unchecked.png b/modules/mogo-module-apps/src/main/res/drawable-xhdpi/module_apps_ic_news_unchecked.png new file mode 100755 index 0000000000..5a64a68660 Binary files /dev/null and b/modules/mogo-module-apps/src/main/res/drawable-xhdpi/module_apps_ic_news_unchecked.png differ diff --git a/modules/mogo-module-apps/src/main/res/drawable-xhdpi/module_apps_ic_online_car.png b/modules/mogo-module-apps/src/main/res/drawable-xhdpi/module_apps_ic_online_car.png new file mode 100755 index 0000000000..761a11b72a Binary files /dev/null and b/modules/mogo-module-apps/src/main/res/drawable-xhdpi/module_apps_ic_online_car.png differ diff --git a/modules/mogo-module-apps/src/main/res/drawable-xhdpi/module_apps_ic_online_car_unchecked.png b/modules/mogo-module-apps/src/main/res/drawable-xhdpi/module_apps_ic_online_car_unchecked.png new file mode 100755 index 0000000000..b967fc7071 Binary files /dev/null and b/modules/mogo-module-apps/src/main/res/drawable-xhdpi/module_apps_ic_online_car_unchecked.png differ diff --git a/modules/mogo-module-apps/src/main/res/drawable-xhdpi/module_apps_ic_tanlu.png b/modules/mogo-module-apps/src/main/res/drawable-xhdpi/module_apps_ic_tanlu.png new file mode 100755 index 0000000000..edd6eaca26 Binary files /dev/null and b/modules/mogo-module-apps/src/main/res/drawable-xhdpi/module_apps_ic_tanlu.png differ diff --git a/modules/mogo-module-apps/src/main/res/drawable-xhdpi/module_apps_ic_tanlu_unchecked.png b/modules/mogo-module-apps/src/main/res/drawable-xhdpi/module_apps_ic_tanlu_unchecked.png new file mode 100755 index 0000000000..ac2a05136b Binary files /dev/null and b/modules/mogo-module-apps/src/main/res/drawable-xhdpi/module_apps_ic_tanlu_unchecked.png differ diff --git a/modules/mogo-module-apps/src/main/res/layout/module_apps_fragment_apps_navigator.xml b/modules/mogo-module-apps/src/main/res/layout/module_apps_fragment_apps_navigator.xml index 97cbe13f84..5c05b17a94 100644 --- a/modules/mogo-module-apps/src/main/res/layout/module_apps_fragment_apps_navigator.xml +++ b/modules/mogo-module-apps/src/main/res/layout/module_apps_fragment_apps_navigator.xml @@ -1,35 +1,46 @@ - + android:paddingBottom="@dimen/module_apps_navigation_icon_paddingBottom" + > - + + - - - - \ No newline at end of file + + + + + \ No newline at end of file diff --git a/modules/mogo-module-apps/src/main/res/layout/module_apps_item_app_indicator.xml b/modules/mogo-module-apps/src/main/res/layout/module_apps_item_app_indicator.xml new file mode 100644 index 0000000000..8e02e01c0e --- /dev/null +++ b/modules/mogo-module-apps/src/main/res/layout/module_apps_item_app_indicator.xml @@ -0,0 +1,24 @@ + + + + + + + \ No newline at end of file diff --git a/modules/mogo-module-apps/src/main/res/values-xhdpi/dimens.xml b/modules/mogo-module-apps/src/main/res/values-xhdpi/dimens.xml index ff19f10f5d..8981b061bc 100644 --- a/modules/mogo-module-apps/src/main/res/values-xhdpi/dimens.xml +++ b/modules/mogo-module-apps/src/main/res/values-xhdpi/dimens.xml @@ -5,9 +5,9 @@ 30px 4px 103px - 120px - 120px - 60px + 94px + 94px + 43px 60px 32px 32px diff --git a/modules/mogo-module-apps/src/main/res/values/dimens.xml b/modules/mogo-module-apps/src/main/res/values/dimens.xml index 604c52ddec..f3a1d89594 100644 --- a/modules/mogo-module-apps/src/main/res/values/dimens.xml +++ b/modules/mogo-module-apps/src/main/res/values/dimens.xml @@ -14,4 +14,5 @@ 220px 220px 154px + 174px \ No newline at end of file diff --git a/modules/mogo-module-back/build.gradle b/modules/mogo-module-back/build.gradle index 28579c4416..f0c93b2d40 100644 --- a/modules/mogo-module-back/build.gradle +++ b/modules/mogo-module-back/build.gradle @@ -47,13 +47,21 @@ dependencies { implementation rootProject.ext.dependencies.rxandroid if (Boolean.valueOf(RELEASE)) { + implementation rootProject.ext.dependencies.mogomap + implementation rootProject.ext.dependencies.mogomapapi implementation rootProject.ext.dependencies.mogoutils implementation rootProject.ext.dependencies.mogocommons + implementation rootProject.ext.dependencies.mogoserviceapi implementation rootProject.ext.dependencies.modulecommon + implementation rootProject.ext.dependencies.moduleshare } else { + implementation project(":libraries:mogo-map") + implementation project(":libraries:mogo-map-api") implementation project(":foudations:mogo-utils") - api project(":foudations:mogo-commons") + implementation project(":foudations:mogo-commons") + implementation project(':services:mogo-service-api') implementation project(':modules:mogo-module-common') + implementation project(':modules:mogo-module-share') } } diff --git a/modules/mogo-module-back/src/main/java/com/mogo/module/back/BackToLauncherModuleProvider.java b/modules/mogo-module-back/src/main/java/com/mogo/module/back/BackToLauncherModuleProvider.java index 5a1e46cb39..bb4d000185 100644 --- a/modules/mogo-module-back/src/main/java/com/mogo/module/back/BackToLauncherModuleProvider.java +++ b/modules/mogo-module-back/src/main/java/com/mogo/module/back/BackToLauncherModuleProvider.java @@ -1,33 +1,31 @@ package com.mogo.module.back; -import android.app.Activity; import android.content.Context; -import android.os.Build; +import android.content.Intent; import android.os.Bundle; -import android.text.TextUtils; -import android.util.ArrayMap; -import android.util.Log; import android.view.View; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentActivity; -import androidx.fragment.app.FragmentManager; import com.alibaba.android.arouter.facade.annotation.Route; +import com.alibaba.android.arouter.launcher.ARouter; +import com.alibaba.idst.nls.internal.utils.L; +import com.mogo.commons.AbsMogoApplication; import com.mogo.map.listener.IMogoMapListener; import com.mogo.map.location.IMogoLocationListener; import com.mogo.map.marker.IMogoMarkerClickListener; import com.mogo.map.navi.IMogoNaviListener; +import com.mogo.service.IMogoServiceApis; +import com.mogo.service.MogoServicePaths; +import com.mogo.service.fragmentmanager.IMogoFragmentManager; +import com.mogo.service.intent.IMogoIntentListener; +import com.mogo.service.intent.IMogoIntentManager; import com.mogo.service.module.IMogoModuleLifecycle; import com.mogo.service.module.IMogoModuleProvider; import com.mogo.service.module.ModuleType; import com.mogo.utils.logger.Logger; -import java.lang.reflect.Field; -import java.util.HashMap; -import java.util.Map; - /** * @author congtaowang * @since 2020-02-26 @@ -35,7 +33,12 @@ import java.util.Map; * 描述 */ @Route( path = BackToLauncherConst.MODULE_PATH ) -public class BackToLauncherModuleProvider implements IMogoModuleProvider { +public class BackToLauncherModuleProvider implements IMogoModuleProvider, IMogoIntentListener { + + private IMogoServiceApis mServiceApis; + private IMogoIntentManager mIntentManager; + + public static final String COMMAND_BACK = "com.ileja.launcher.back"; private static final String TAG = "BackToLauncherModuleProvider"; @@ -98,54 +101,17 @@ public class BackToLauncherModuleProvider implements IMogoModuleProvider { @Override public void init( Context context ) { BackToMainHomeManager.addMainHomeView(); -// final Activity activity = getTopActivity(context.getPackageName()); -// if ( activity instanceof FragmentActivity ) { -// Logger.d( TAG, "init." ); -// FragmentManager fragmentManager = ( ( FragmentActivity ) activity ).getSupportFragmentManager(); -// fragmentManager.beginTransaction() -// .add( new Back2LauncherFragment(), BackToLauncherConst.MODULE_NAME ) -// .commitAllowingStateLoss(); -// fragmentManager.executePendingTransactions(); -// } + mServiceApis = ( IMogoServiceApis ) ARouter.getInstance().build( MogoServicePaths.PATH_SERVICE_APIS ).navigation(); + mIntentManager = mServiceApis.getIntentManagerApi(); + mIntentManager.registerIntentListener( COMMAND_BACK, this ); + BackToMainHomeManager.init( mServiceApis.getFragmentManagerApi() ); } -// /** -// * 获取当前运行的activity -// */ -// private Activity getTopActivity(String process) { -// Log.i("activity", "[getTopActivity]"); -// try { -// Class activityThreadClass = Class.forName("android.app.ActivityThread"); -// Object activityThread = activityThreadClass.getMethod("currentActivityThread").invoke(null); -// Field activitiesField = activityThreadClass.getDeclaredField("mActivities"); -// activitiesField.setAccessible(true); -// //16~18 HashMap -// //19~27 ArrayMap -// Map activities; -// if ( Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { -// activities = ( HashMap ) activitiesField.get(activityThread); -// } else { -// activities = ( ArrayMap ) activitiesField.get(activityThread); -// } -// if (activities.size() < 1) { -// return null; -// } -// for (Object activityRecord : activities.values()) { -// Class activityRecordClass = activityRecord.getClass(); -// Field pausedField = activityRecordClass.getDeclaredField("paused"); -// pausedField.setAccessible(true); -// if (!pausedField.getBoolean(activityRecord)) { -// Field activityField = activityRecordClass.getDeclaredField("activity"); -// activityField.setAccessible(true); -// Activity activity = (Activity) activityField.get(activityRecord); -// if ( TextUtils.equals( process, activity.getPackageName() ) ) { -// return activity; -// } -// } -// } -// } catch (Exception e) { -// e.printStackTrace(); -// } -// return null; -// } + @Override + public void onIntentReceived( String intentStr, Intent intent ) { + if ( COMMAND_BACK.equals( intentStr ) ) { + Logger.d( TAG, "received back to home command." ); + BackToMainHomeManager.backToLauncher(); + } + } } diff --git a/modules/mogo-module-back/src/main/java/com/mogo/module/back/BackToMainHomeManager.java b/modules/mogo-module-back/src/main/java/com/mogo/module/back/BackToMainHomeManager.java index 73e1913002..d2c4259740 100644 --- a/modules/mogo-module-back/src/main/java/com/mogo/module/back/BackToMainHomeManager.java +++ b/modules/mogo-module-back/src/main/java/com/mogo/module/back/BackToMainHomeManager.java @@ -14,15 +14,35 @@ import android.view.WindowManager; import com.mogo.commons.AbsMogoApplication; import com.mogo.module.back.utils.Utils; import com.mogo.module.back.utils.WindowManagerViewHelper; +import com.mogo.service.fragmentmanager.IMogoFragmentManager; import com.mogo.utils.logger.Logger; public class BackToMainHomeManager { private static View mBackView; - public static void addMainHomeView(){ - Logger.d("BackToMainHomeManager","addMainHomeView"); - if (mBackView != null)WindowManagerViewHelper.removeView(mBackView); - mBackView = LayoutInflater.from(AbsMogoApplication.getApp()).inflate(R.layout.mogo_module_back_home_back_layout, null); + + private static IMogoFragmentManager mFragmentManager; + + public static void init( IMogoFragmentManager manager ) { + mFragmentManager = manager; + } + + public static void backToLauncher(){ + Intent intent = new Intent(); + intent.setAction( Intent.ACTION_MAIN ); + intent.addCategory( Intent.CATEGORY_HOME ); + intent.addFlags( Intent.FLAG_ACTIVITY_NEW_TASK ); + AbsMogoApplication.getApp().startActivity( intent ); + + if ( mFragmentManager != null ) { + mFragmentManager.clearAll(); + } + } + + public static void addMainHomeView() { + Logger.d( "BackToMainHomeManager", "addMainHomeView" ); + if ( mBackView != null ) WindowManagerViewHelper.removeView( mBackView ); + mBackView = LayoutInflater.from( AbsMogoApplication.getApp() ).inflate( R.layout.mogo_module_back_home_back_layout, null ); final Context context = mBackView.getContext(); if ( context == null || context.getApplicationContext() == null ) { return; @@ -31,32 +51,24 @@ public class BackToMainHomeManager { if ( windowManager == null ) { return; } - mBackView.setOnClickListener(view -> { - if (Utils.isActivityExits("com.mogo.launcher","com.mogo.module.main.MainActivity")){ - ComponentName cn = new ComponentName("com.mogo.launcher", "com.mogo.module.main.MainActivity") ; - Intent intent = new Intent() ; - intent.setComponent(cn) ; - if (!(AbsMogoApplication.getApp().getApplicationContext() instanceof Activity)) { - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - } - AbsMogoApplication.getApp().startActivity(intent); - } - }); + mBackView.setOnClickListener( view -> { + backToLauncher(); + } ); WindowManager.LayoutParams params = new WindowManager.LayoutParams(); params.height = WindowManager.LayoutParams.WRAP_CONTENT; params.width = WindowManager.LayoutParams.WRAP_CONTENT; - params.x = AbsMogoApplication.getApp().getResources().getDimensionPixelOffset(R.dimen.module_back_main_home_icon_left); - params.y = AbsMogoApplication.getApp().getResources().getDimensionPixelOffset(R.dimen.module_back_main_home_icon_top); + params.x = AbsMogoApplication.getApp().getResources().getDimensionPixelOffset( R.dimen.module_back_main_home_icon_left ); + params.y = AbsMogoApplication.getApp().getResources().getDimensionPixelOffset( R.dimen.module_back_main_home_icon_top ); params.gravity = Gravity.LEFT | Gravity.CENTER; params.type = getFitWindowParamsType(); params.format = PixelFormat.RGBA_8888; params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; windowManager.addView( mBackView, params ); - WindowManagerViewHelper.attachMovementEvent(mBackView,params); + WindowManagerViewHelper.attachMovementEvent( mBackView, params ); } - public static void removeMainHomeView(){ - WindowManagerViewHelper.removeView(mBackView); + public static void removeMainHomeView() { + WindowManagerViewHelper.removeView( mBackView ); } private static int getFitWindowParamsType() { diff --git a/modules/mogo-module-back/src/main/java/com/mogo/module/back/utils/Utils.java b/modules/mogo-module-back/src/main/java/com/mogo/module/back/utils/Utils.java index 16d4b0991c..ace6e4bdae 100644 --- a/modules/mogo-module-back/src/main/java/com/mogo/module/back/utils/Utils.java +++ b/modules/mogo-module-back/src/main/java/com/mogo/module/back/utils/Utils.java @@ -7,13 +7,13 @@ import android.content.pm.ResolveInfo; import com.mogo.commons.AbsMogoApplication; public class Utils { - public static boolean isActivityExits(String packageName,String classStr){ + public static boolean isActivityExits( String packageName, String classStr ) { Intent intent = new Intent(); - intent.setClassName(packageName, classStr); - ResolveInfo resolveInfo = AbsMogoApplication.getApp().getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY); - if(resolveInfo != null) { + intent.setClassName( packageName, classStr ); + ResolveInfo resolveInfo = AbsMogoApplication.getApp().getPackageManager().resolveActivity( intent, PackageManager.MATCH_DEFAULT_ONLY ); + if ( resolveInfo != null ) { return true; - }else{ + } else { return false; } } diff --git a/modules/mogo-module-common/src/main/java/com/mogo/module/common/entity/MarkerCarInfo.java b/modules/mogo-module-common/src/main/java/com/mogo/module/common/entity/MarkerCarInfo.java index 5ab642db01..42e9055779 100644 --- a/modules/mogo-module-common/src/main/java/com/mogo/module/common/entity/MarkerCarInfo.java +++ b/modules/mogo-module-common/src/main/java/com/mogo/module/common/entity/MarkerCarInfo.java @@ -11,6 +11,8 @@ public class MarkerCarInfo implements Serializable { private String carBrandLogoUrl; private String carTypeName; + private int carType; + private CarLive carLive; public String getCarBrandLogoUrl() { if (TextUtils.isEmpty(carBrandLogoUrl)) { @@ -34,11 +36,61 @@ public class MarkerCarInfo implements Serializable { this.carTypeName = carTypeName; } - @Override - public String toString() { - return "MarkerCarInfo{" + - "carBrandLogoUrl='" + carBrandLogoUrl + '\'' + - ", carTypeName='" + carTypeName + '\'' + - '}'; + public int getCarType() { + return carType; + } + + public void setCarType(int carType) { + this.carType = carType; + } + + public CarLive getCarLive() { + return carLive; + } + + public void setCarLive(CarLive carLive) { + this.carLive = carLive; + } + + class CarLive implements Serializable { + //rtmp视频直播地址rtmp:// + private String videoUrl; + //直播频道【直播心跳接口参数】C_1 + private String videoChannel; + //直播源sn【直播心跳接口参数】XTCBA90740400625 + private String videoSn; + + public String getVideoUrl() { + return videoUrl; + } + + public void setVideoUrl(String videoUrl) { + this.videoUrl = videoUrl; + } + + public String getVideoChannel() { + return videoChannel; + } + + public void setVideoChannel(String videoChannel) { + this.videoChannel = videoChannel; + } + + public String getVideoSn() { + return videoSn; + } + + public void setVideoSn(String videoSn) { + this.videoSn = videoSn; + } + + @Override + public String toString() { + return "CarLive{" + + "videoUrl='" + videoUrl + '\'' + + ", videoChannel='" + videoChannel + '\'' + + ", videoSn='" + videoSn + '\'' + + '}'; + } } } diff --git a/modules/mogo-module-common/src/main/java/com/mogo/module/common/entity/MarkerPoiTypeEnum.java b/modules/mogo-module-common/src/main/java/com/mogo/module/common/entity/MarkerPoiTypeEnum.java index 43e0a20977..a7467d616c 100644 --- a/modules/mogo-module-common/src/main/java/com/mogo/module/common/entity/MarkerPoiTypeEnum.java +++ b/modules/mogo-module-common/src/main/java/com/mogo/module/common/entity/MarkerPoiTypeEnum.java @@ -26,4 +26,10 @@ public interface MarkerPoiTypeEnum { public String FOURS_PONDING = "10008"; //超市打折 public String FOURS_SHOP_FREE = "10009"; + //浓雾 + public String FOURS_FOG = "10010"; + //结冰 + public String FOURS_ICE = "10011"; + //停车场 + public String FOURS_PARKING = "10012"; } \ No newline at end of file diff --git a/modules/mogo-module-common/src/main/java/com/mogo/module/common/entity/MarkerUserInfo.java b/modules/mogo-module-common/src/main/java/com/mogo/module/common/entity/MarkerUserInfo.java index e13d18d782..98c3b35002 100644 --- a/modules/mogo-module-common/src/main/java/com/mogo/module/common/entity/MarkerUserInfo.java +++ b/modules/mogo-module-common/src/main/java/com/mogo/module/common/entity/MarkerUserInfo.java @@ -16,6 +16,11 @@ public class MarkerUserInfo implements Serializable { private String gender;//gender": "男|女|无(也可以0|1|2根据实际库存返回即可) private Integer age;// 年龄段,可以为空,与车聊聊一致 + // TODO V2X临时字段,接口出好后进行修改 + private String lastActiveweekAvgscore;//末次活跃周驾驶行为平均得分 + private String safeLabel;//车辆安全标签 + private int safeLabelType;//1老司机 2安全驾驶 3危险驾驶 + public void setAge(Integer age) { this.age = age; } @@ -150,16 +155,46 @@ public class MarkerUserInfo implements Serializable { this.userName = userName; } + public void setUserId(long userId) { + this.userId = userId; + } + + public String getLastActiveweekAvgscore() { + return lastActiveweekAvgscore; + } + + public void setLastActiveweekAvgscore(String lastActiveweekAvgscore) { + this.lastActiveweekAvgscore = lastActiveweekAvgscore; + } + + public String getSafeLabel() { + return safeLabel; + } + + public void setSafeLabel(String safeLabel) { + this.safeLabel = safeLabel; + } + + public int getSafeLabelType() { + return safeLabelType; + } + + public void setSafeLabelType(int safeLabelType) { + this.safeLabelType = safeLabelType; + } @Override public String toString() { return "MarkerUserInfo{" + - "age=" + age + - ", gender='" + gender + '\'' + - ", sn='" + sn + '\'' + - ", userHead='" + userHead + '\'' + + "sn='" + sn + '\'' + ", userId=" + userId + ", userName='" + userName + '\'' + + ", userHead='" + userHead + '\'' + + ", gender='" + gender + '\'' + + ", age=" + age + + ", lastActiveweekAvgscore='" + lastActiveweekAvgscore + '\'' + + ", safeLabel='" + safeLabel + '\'' + + ", safeLabelType=" + safeLabelType + '}'; } } diff --git a/modules/mogo-module-extensions/src/main/java/com/mogo/module/extensions/entrance/EntranceFragment.java b/modules/mogo-module-extensions/src/main/java/com/mogo/module/extensions/entrance/EntranceFragment.java index bf93bec9ca..02863aa716 100644 --- a/modules/mogo-module-extensions/src/main/java/com/mogo/module/extensions/entrance/EntranceFragment.java +++ b/modules/mogo-module-extensions/src/main/java/com/mogo/module/extensions/entrance/EntranceFragment.java @@ -50,9 +50,9 @@ import java.util.Map; *

* 描述 */ -public class EntranceFragment extends MvpFragment - implements EntranceView, - IMogoNaviListener, IMogoMapListener { +public class EntranceFragment extends MvpFragment< EntranceView, EntrancePresenter > + implements EntranceView, + IMogoNaviListener, IMogoMapListener { private static final String TAG = "EntranceFragment"; @@ -100,37 +100,37 @@ public class EntranceFragment extends MvpFragment { - mSearchProvider = (IMogoModuleProvider) ARouter.getInstance() - .build(MogoModulePaths.PATH_MODULE_SEARCH) + mMogoFragmentManager = ( IMogoFragmentManager ) ARouter.getInstance() + .build( MogoServicePaths.PATH_FRAGMENT_MANAGER ) + .navigation(); + mMogoAddressManager = ( IMogoAddressManager ) ARouter.getInstance() + .build( MogoServicePaths.PATH_ADDRESS_MANAGER ) .navigation(); - final Fragment fragment = mSearchProvider.createFragment(getContext(), null); - mMogoFragmentManager.push(new FragmentDescriptor.Builder().fragment(fragment) - .tag(MogoModulePaths.PATH_FRAGMENT_SEARCH) - .notifyMainModule(true) - .build()); - }); - mHome = findViewById(R.id.module_entrance_id_home); - mHome.setOnClickListener(view -> { + mCommonAddress = findViewById( R.id.module_entrance_id_common_address ); + + mSearch = findViewById( R.id.module_entrance_id_search ); + + mSearch.setOnClickListener( view -> { + mSearchProvider = ( IMogoModuleProvider ) ARouter.getInstance() + .build( MogoModulePaths.PATH_MODULE_SEARCH ) + .navigation(); + final Fragment fragment = mSearchProvider.createFragment( getContext(), null ); + mMogoFragmentManager.push( new FragmentDescriptor.Builder().fragment( fragment ) + .tag( MogoModulePaths.PATH_FRAGMENT_SEARCH ) + .notifyMainModule( true ) + .build() ); + } ); + + mHome = findViewById( R.id.module_entrance_id_home ); + mHome.setOnClickListener( view -> { mMogoAddressManager.goHome(); - }); + } ); - mCompany = findViewById(R.id.module_entrance_id_company); - mCompany.setOnClickListener(view -> { + mCompany = findViewById( R.id.module_entrance_id_company ); + mCompany.setOnClickListener( view -> { mMogoAddressManager.goCompany(); - }); + } ); mUploadRoadCondition = findViewById( R.id.module_entrance_id_upload_road_condition ); mUploadRoadCondition.setOnClickListener( view -> { @@ -141,78 +141,79 @@ public class EntranceFragment extends MvpFragment { } ); - mMove2CurrentLocation = findViewById(R.id.module_entrance_id_move2_current_location); - mMove2CurrentLocation.setOnClickListener(view -> { + mMove2CurrentLocation = findViewById( R.id.module_entrance_id_move2_current_location ); + mMove2CurrentLocation.setOnClickListener( view -> { final MogoLocation location = mMogoLocationClient.getLastKnowLocation(); - if (location != null) { - mMogoStatusManager.setUserInteractionStatus(TAG, true, false); - mMApUIController.changeZoom(16.0f); - mMogoStatusManager.setUserInteractionStatus(TAG, true, false); + if ( location != null ) { + mMogoStatusManager.setUserInteractionStatus( TAG, true, false ); + mMApUIController.changeZoom( 16.0f ); + mMogoStatusManager.setUserInteractionStatus( TAG, true, false ); mMApUIController.recoverLockMode(); } - }); + } ); - mNaviInfo = findViewById(R.id.module_entrance_id_navi_info_panel); - mExitNavi = findViewById(R.id.module_entrance_id_exit_navi); - mExitNavi.setOnClickListener(view -> { - if (mMogoNavi != null) { + mNaviInfo = findViewById( R.id.module_entrance_id_navi_info_panel ); + mExitNavi = findViewById( R.id.module_entrance_id_exit_navi ); + mExitNavi.setOnClickListener( view -> { + if ( mMogoNavi != null ) { //if ( mIsLock ) { - NaviNoticeDialog naviNoticeDialog = new NaviNoticeDialog(getContext()); + NaviNoticeDialog naviNoticeDialog = new NaviNoticeDialog( getContext() ); naviNoticeDialog.show(); //} else { // mMApUIController.recoverLockMode(); //} } - }); + } ); - ivMode = findViewById(R.id.module_ext_id_north); - ivMode.setOnClickListener(new View.OnClickListener() { - @Override public void onClick(View v) { - if (ivMode.isSelected()) { - mMApUIController.changeMapMode(EnumMapUI.CarUp_2D); + ivMode = findViewById( R.id.module_ext_id_north ); + ivMode.setOnClickListener( new View.OnClickListener() { + @Override + public void onClick( View v ) { + if ( ivMode.isSelected() ) { + mMApUIController.changeMapMode( EnumMapUI.CarUp_2D ); } else { - mMApUIController.changeMapMode(EnumMapUI.NorthUP_2D); + mMApUIController.changeMapMode( EnumMapUI.NorthUP_2D ); } - ivMode.setSelected(!ivMode.isSelected()); + ivMode.setSelected( !ivMode.isSelected() ); ivMode.setText( - getString(ivMode.isSelected() ? R.string.mode_car_up : R.string.mode_north_up)); + getString( ivMode.isSelected() ? R.string.mode_car_up : R.string.mode_north_up ) ); } - }); + } ); - mSpeedLimit = findViewById(R.id.module_entrance_id_speed_limit_container); - mSpeedLimitValue = findViewById(R.id.module_entrance_id_speed_limit_value); - mSpeedLimitUnit = findViewById(R.id.module_entrance_id_speed_limit_unit); + mSpeedLimit = findViewById( R.id.module_entrance_id_speed_limit_container ); + mSpeedLimitValue = findViewById( R.id.module_entrance_id_speed_limit_value ); + mSpeedLimitUnit = findViewById( R.id.module_entrance_id_speed_limit_unit ); } @NonNull @Override protected EntrancePresenter createPresenter() { - return new EntrancePresenter(getContext(), this); + return new EntrancePresenter( getContext(), this ); } @Override - public void onActivityCreated(@Nullable Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - mService = (IMogoMapService) ARouter.getInstance() - .build(MogoServicePaths.PATH_SERVICES_MAP) - .navigation(getContext()); - mMogoRegisterCenter = (IMogoRegisterCenter) ARouter.getInstance() - .build(MogoServicePaths.PATH_REGISTER_CENTER) - .navigation(getContext()); + public void onActivityCreated( @Nullable Bundle savedInstanceState ) { + super.onActivityCreated( savedInstanceState ); + mService = ( IMogoMapService ) ARouter.getInstance() + .build( MogoServicePaths.PATH_SERVICES_MAP ) + .navigation( getContext() ); + mMogoRegisterCenter = ( IMogoRegisterCenter ) ARouter.getInstance() + .build( MogoServicePaths.PATH_REGISTER_CENTER ) + .navigation( getContext() ); mMApUIController = mService.getMapUIController(); - mMogoLocationClient = mService.getSingletonLocationClient(getContext()); - mMogoNavi = mService.getNavi(getContext()); - mAnalytics = (IMogoAnalytics) ARouter.getInstance() - .build(MogoServicePaths.PATH_UTILS_ANALYTICS) - .navigation(getContext()); - mMogoStatusManager = (IMogoStatusManager) ARouter.getInstance() - .build(MogoServicePaths.PATH_STATUS_MANAGER) - .navigation(getContext()); + mMogoLocationClient = mService.getSingletonLocationClient( getContext() ); + mMogoNavi = mService.getNavi( getContext() ); + mAnalytics = ( IMogoAnalytics ) ARouter.getInstance() + .build( MogoServicePaths.PATH_UTILS_ANALYTICS ) + .navigation( getContext() ); + mMogoStatusManager = ( IMogoStatusManager ) ARouter.getInstance() + .build( MogoServicePaths.PATH_STATUS_MANAGER ) + .navigation( getContext() ); - mMogoRegisterCenter.registerMogoNaviListener(ExtensionsModuleConst.TYPE_ENTRANCE, this); - mMogoRegisterCenter.registerMogoMapListener(ExtensionsModuleConst.TYPE_ENTRANCE, this); + mMogoRegisterCenter.registerMogoNaviListener( ExtensionsModuleConst.TYPE_ENTRANCE, this ); + mMogoRegisterCenter.registerMogoMapListener( ExtensionsModuleConst.TYPE_ENTRANCE, this ); - mMogoMarkerManager = mService.getMarkerManager(getContext()); + mMogoMarkerManager = mService.getMarkerManager( getContext() ); } @Override @@ -224,30 +225,30 @@ public class EntranceFragment extends MvpFragment properties = new HashMap<>(); - properties.put("from", from); - mAnalytics.track("Launcher_Share_Click", properties); + private void traceData( String from ) { + Map< String, Object > properties = new HashMap<>(); + properties.put( "from", from ); + mAnalytics.track( "Launcher_Share_Click", properties ); } } diff --git a/modules/mogo-module-main/src/main/java/com/mogo/module/main/MainActivity.java b/modules/mogo-module-main/src/main/java/com/mogo/module/main/MainActivity.java index b155b39538..8e5e7b14fd 100644 --- a/modules/mogo-module-main/src/main/java/com/mogo/module/main/MainActivity.java +++ b/modules/mogo-module-main/src/main/java/com/mogo/module/main/MainActivity.java @@ -40,6 +40,7 @@ import com.mogo.service.intent.IMogoIntentListener; import com.mogo.service.intent.IMogoIntentManager; import com.mogo.service.map.IMogoMapService; import com.mogo.service.module.IMogoModuleProvider; +import com.mogo.service.statusmanager.IMogoStatusManager; import com.mogo.utils.logger.Logger; import org.json.JSONException; @@ -65,9 +66,10 @@ public class MainActivity extends MvpActivity< MainView, MainPresenter > impleme private MogoModulesHandler mMogoModuleHandler; private IMogoCardManager mMogoCardManager; private IMogoFragmentManager mMogoFragmentManager; + private IMogoStatusManager mMogoStatusManager; private OrientedViewPager mCardsContainer; - private VerticalStackTransformer mTransformer; + //private VerticalStackTransformer mTransformer; private CardModulesAdapter mCardModulesAdapter; private View mHeader; @@ -98,75 +100,68 @@ public class MainActivity extends MvpActivity< MainView, MainPresenter > impleme @Override protected void initViews() { mCardsContainer = findViewById( R.id.module_main_id_cards_container ); - mCardsContainer.setOrientation( OrientedViewPager.Orientation.VERTICAL ); - mTransformer = new VerticalStackTransformer( this ); - mCardsContainer.setOnPageChangeListener( - mOnPageChangeListener = new OnPageChangeListenerAdapter() { - private boolean mIsLast = true; - private boolean mCardFlipStatus = false; + mCardsContainer.setOrientation( OrientedViewPager.Orientation.HORIZONTAL ); + //mTransformer = new VerticalStackTransformer( this ); + mCardsContainer.setOnPageChangeListener( mOnPageChangeListener = new OnPageChangeListenerAdapter() { + private boolean mIsLast = true; + private boolean mCardFlipStatus = false; - @Override - public void onPageSelected( int position ) { - final long start = System.currentTimeMillis(); - try { - IMogoModuleProvider provider = - mCardModulesAdapter.getProvider( mCurrentPosition ); - mPresenter.postTrackLastCardShowEvent( provider ); - mCurrentPosition = position; - provider = mCardModulesAdapter.getProvider( mCurrentPosition ); - mMogoModuleHandler.setModuleEnable( provider.getModuleName() ); - mMogoCardManager.invoke( position, - mMogoModuleHandler.getCurrentModuleName() ); - } catch ( Exception e ) { - e.printStackTrace(); - } - Logger.i( TAG, - "onPageSelected cost " + ( System.currentTimeMillis() - start ) + "ms" ); + @Override + public void onPageSelected( int position ) { + final long start = System.currentTimeMillis(); + try { + IMogoModuleProvider provider = mCardModulesAdapter.getProvider( mCurrentPosition ); + mPresenter.postTrackLastCardShowEvent( provider ); + mCurrentPosition = position; + provider = mCardModulesAdapter.getProvider( mCurrentPosition ); + mMogoModuleHandler.setModuleEnable( provider.getModuleName() ); + mMogoCardManager.invoke( position, mMogoModuleHandler.getCurrentModuleName() ); + } catch ( Exception e ) { + e.printStackTrace(); + } + Logger.i( TAG, "onPageSelected cost " + ( System.currentTimeMillis() - start ) + "ms" ); + } + + @Override + public void onPageScrollStateChanged( int state ) { + final long start = System.currentTimeMillis(); + super.onPageScrollStateChanged( state ); + if ( state == ViewPager.SCROLL_STATE_DRAGGING ) { + if ( !mCardFlipStatus ) { + mCardFlipStatus = true; + final IMogoModuleProvider provider = mCardModulesAdapter.getProvider( mCurrentPosition ); + mPresenter.postTrackCardFlipEvent( provider ); } + } else if ( state == ViewPager.SCROLL_STATE_IDLE ) { + mCardFlipStatus = false; + //mTransformer.resetOffsetScroll(); + } - @Override - public void onPageScrollStateChanged( int state ) { - final long start = System.currentTimeMillis(); - super.onPageScrollStateChanged( state ); - if ( state == ViewPager.SCROLL_STATE_DRAGGING ) { - if ( !mCardFlipStatus ) { - mCardFlipStatus = true; - final IMogoModuleProvider provider = - mCardModulesAdapter.getProvider( mCurrentPosition ); - mPresenter.postTrackCardFlipEvent( provider ); - } - } else if ( state == ViewPager.SCROLL_STATE_IDLE ) { - mCardFlipStatus = false; - mTransformer.resetOffsetScroll(); - } + int cardSize = mCardModulesAdapter.getCount(); - int cardSize = mCardModulesAdapter.getCount(); - - if ( state == ViewPager.SCROLL_STATE_SETTLING ) { - mIsLast = false; - } else if ( state == ViewPager.SCROLL_STATE_IDLE && mIsLast ) { - //此处为你需要的情况,再加入当前页码判断可知道是第一页还是最后一页 - if ( cardSize != 1 && mCurrentPosition == ( cardSize - 1 ) ) { - mCardsContainer.setCurrentItem( 0, false ); - } else if ( cardSize != 1 && mCurrentPosition == 0 ) { - mCardsContainer.setCurrentItem( cardSize - 1, false ); - } - } else { - mIsLast = true; - } - Logger.i( TAG, "onPageScrollStateChanged cost " - + ( System.currentTimeMillis() - start ) - + "ms" ); + if ( state == ViewPager.SCROLL_STATE_SETTLING ) { + mIsLast = false; + } else if ( state == ViewPager.SCROLL_STATE_IDLE && mIsLast ) { + //此处为你需要的情况,再加入当前页码判断可知道是第一页还是最后一页 + if ( cardSize != 1 && mCurrentPosition == ( cardSize - 1 ) ) { + mCardsContainer.setCurrentItem( 0, false ); + } else if ( cardSize != 1 && mCurrentPosition == 0 ) { + mCardsContainer.setCurrentItem( cardSize - 1, false ); } + } else { + mIsLast = true; + } + Logger.i( TAG, "onPageScrollStateChanged cost " + ( System.currentTimeMillis() - start ) + "ms" ); + } - @Override - public void onPageScrolled( int position, float positionOffset, - int positionOffsetPixels ) { - super.onPageScrolled( position, positionOffset, positionOffsetPixels ); - Logger.d( TAG, "pageScrolled : offset --- " + positionOffset ); - mTransformer.offsetScrollChanged( positionOffset ); - } - } ); + @Override + public void onPageScrolled( int position, float positionOffset, + int positionOffsetPixels ) { + super.onPageScrolled( position, positionOffset, positionOffsetPixels ); + Logger.d( TAG, "pageScrolled : offset --- " + positionOffset ); + //mTransformer.offsetScrollChanged( positionOffset ); + } + } ); mHeader = findViewById( R.id.module_main_id_header_fragment_container ); mCards = findViewById( R.id.module_main_id_cards_container ); @@ -261,6 +256,7 @@ public class MainActivity extends MvpActivity< MainView, MainPresenter > impleme } ); mMogoIntentManager = mServiceApis.getIntentManagerApi(); + mMogoStatusManager = mServiceApis.getStatusManagerApi(); registerVoiceCmd(); Log.i( "timer", "cost " + ( System.currentTimeMillis() - start ) + "ms" ); } @@ -303,7 +299,7 @@ public class MainActivity extends MvpActivity< MainView, MainPresenter > impleme List< IMogoModuleProvider > providers = mMogoModuleHandler.loadCardsModule(); mCardModulesAdapter = new CardModulesAdapter( this, providers ); mCardsContainer.setOffscreenPageLimit( providers.size() ); - mCardsContainer.setPageTransformer( true, mTransformer ); + //mCardsContainer.setPageTransformer( true, mTransformer ); mCardsContainer.setAdapter( mCardModulesAdapter ); mCardCoverUpBottomLayout.setVisibility( View.VISIBLE ); @@ -324,7 +320,7 @@ public class MainActivity extends MvpActivity< MainView, MainPresenter > impleme @Override public boolean onMarkerClicked( IMogoMarker marker ) { - switch2Card( marker.getOwner() ); + switch2Card( marker.getOwner(), false ); if ( mMogoModuleHandler != null ) { mMogoModuleHandler.onMarkerClicked( marker ); } @@ -332,17 +328,23 @@ public class MainActivity extends MvpActivity< MainView, MainPresenter > impleme } @Override - public void switch2Card( String cardType ) { - if ( mCardModulesAdapter != null ) { + public void switch2Card( String cardType, boolean lockCar ) { + if ( mCardModulesAdapter == null ) { + return; + } - int position = mCardModulesAdapter.getProviderPosition( cardType ); - if ( position != -1 ) { - int lastFactPosition = mCardModulesAdapter.getFactPosition( mCurrentPosition ); - mCardsContainer.setCurrentItem( mCurrentPosition + position - lastFactPosition, - Math.abs( lastFactPosition - position ) == 1 ); - } else { - Logger.e( TAG, "Can't find type of %s's position", cardType ); - } + int position = mCardModulesAdapter.getProviderPosition( cardType ); + if ( position != -1 ) { + int lastFactPosition = mCardModulesAdapter.getFactPosition( mCurrentPosition ); + mCardsContainer.setCurrentItem( mCurrentPosition + position - lastFactPosition, + Math.abs( lastFactPosition - position ) == 1 ); + } else { + Logger.e( TAG, "Can't find type of %s's position", cardType ); + } + + if ( lockCar ) { + mMogoStatusManager.setUserInteractionStatus( TAG, true, false ); + mMogoMapUIController.recoverLockMode(); } } diff --git a/modules/mogo-module-main/src/main/java/com/mogo/module/main/MainPresenter.java b/modules/mogo-module-main/src/main/java/com/mogo/module/main/MainPresenter.java index 459547fb36..717ff4cdc3 100644 --- a/modules/mogo-module-main/src/main/java/com/mogo/module/main/MainPresenter.java +++ b/modules/mogo-module-main/src/main/java/com/mogo/module/main/MainPresenter.java @@ -67,11 +67,11 @@ public class MainPresenter extends Presenter< MainView > { @Override public void onCreate( @NonNull LifecycleOwner owner ) { super.onCreate( owner ); - CardSwitchLiveData.getInstance().observeForever( to -> { - if ( TextUtils.isEmpty( to ) ) { + CardSwitchLiveData.getInstance().observeForever( cardInfo -> { + if ( TextUtils.isEmpty( cardInfo.mCardName ) ) { return; } - mView.switch2Card( to ); + mView.switch2Card( cardInfo.mCardName, true ); } ); mAnalytics = ( IMogoAnalytics ) ARouter.getInstance().build( MogoServicePaths.PATH_UTILS_ANALYTICS ).navigation( getContext() ); mCardStartShowTime = System.currentTimeMillis(); diff --git a/modules/mogo-module-main/src/main/java/com/mogo/module/main/MainView.java b/modules/mogo-module-main/src/main/java/com/mogo/module/main/MainView.java index ac69a5da5e..a048081549 100644 --- a/modules/mogo-module-main/src/main/java/com/mogo/module/main/MainView.java +++ b/modules/mogo-module-main/src/main/java/com/mogo/module/main/MainView.java @@ -15,7 +15,7 @@ public interface MainView extends IView { * * @param cardType */ - void switch2Card( String cardType ); + void switch2Card( String cardType, boolean lockCar ); /** * 加载卡片 diff --git a/modules/mogo-module-main/src/main/java/com/mogo/module/main/MogoCardManager.java b/modules/mogo-module-main/src/main/java/com/mogo/module/main/MogoCardManager.java index b34f781b5a..69b8c1bdd9 100644 --- a/modules/mogo-module-main/src/main/java/com/mogo/module/main/MogoCardManager.java +++ b/modules/mogo-module-main/src/main/java/com/mogo/module/main/MogoCardManager.java @@ -3,6 +3,7 @@ package com.mogo.module.main; import android.content.Context; import com.alibaba.android.arouter.facade.annotation.Route; +import com.mogo.module.main.livedata.CardInfo; import com.mogo.module.main.livedata.CardSwitchLiveData; import com.mogo.service.MogoServicePaths; import com.mogo.service.cardmanager.IMogoCardChangedListener; @@ -25,7 +26,7 @@ public class MogoCardManager implements IMogoCardManager { @Override public void switch2( String cardType ) { - CardSwitchLiveData.getInstance().postValue( cardType ); + CardSwitchLiveData.getInstance().postValue( new CardInfo( cardType, false ) ); } @Override @@ -51,6 +52,11 @@ public class MogoCardManager implements IMogoCardManager { } } + @Override + public void switch2( String cardType, boolean lockCar ) { + CardSwitchLiveData.getInstance().postValue( new CardInfo( cardType, lockCar ) ); + } + @Override public void init( Context context ) { diff --git a/modules/mogo-module-main/src/main/java/com/mogo/module/main/cards/MogoModulesManager.java b/modules/mogo-module-main/src/main/java/com/mogo/module/main/cards/MogoModulesManager.java index db9875ff36..2b34ce4a69 100644 --- a/modules/mogo-module-main/src/main/java/com/mogo/module/main/cards/MogoModulesManager.java +++ b/modules/mogo-module-main/src/main/java/com/mogo/module/main/cards/MogoModulesManager.java @@ -148,7 +148,8 @@ public class MogoModulesManager implements MogoModulesHandler, providers.add( provider ); } } - return sort( providers ); + return providers; +// return sort( providers ); v2.0.2暂不支持变顺序 } private List< IMogoModuleProvider > sort( List< IMogoModuleProvider > modules ) { diff --git a/modules/mogo-module-main/src/main/java/com/mogo/module/main/livedata/CardInfo.java b/modules/mogo-module-main/src/main/java/com/mogo/module/main/livedata/CardInfo.java new file mode 100644 index 0000000000..08cee036af --- /dev/null +++ b/modules/mogo-module-main/src/main/java/com/mogo/module/main/livedata/CardInfo.java @@ -0,0 +1,49 @@ +package com.mogo.module.main.livedata; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * @author congtaowang + * @since 2020-03-09 + *

+ * 描述 + */ +public class CardInfo implements Parcelable { + + public String mCardName; + public boolean mLockCar; + + public CardInfo( String cardName, boolean lockCar ) { + this.mCardName = cardName; + this.mLockCar = lockCar; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel( Parcel dest, int flags ) { + dest.writeString( this.mCardName ); + dest.writeByte( this.mLockCar ? ( byte ) 1 : ( byte ) 0 ); + } + + protected CardInfo( Parcel in ) { + this.mCardName = in.readString(); + this.mLockCar = in.readByte() != 0; + } + + public static final Parcelable.Creator< CardInfo > CREATOR = new Parcelable.Creator< CardInfo >() { + @Override + public CardInfo createFromParcel( Parcel source ) { + return new CardInfo( source ); + } + + @Override + public CardInfo[] newArray( int size ) { + return new CardInfo[size]; + } + }; +} diff --git a/modules/mogo-module-main/src/main/java/com/mogo/module/main/livedata/CardSwitchLiveData.java b/modules/mogo-module-main/src/main/java/com/mogo/module/main/livedata/CardSwitchLiveData.java index fafe630a3d..0f078ce718 100644 --- a/modules/mogo-module-main/src/main/java/com/mogo/module/main/livedata/CardSwitchLiveData.java +++ b/modules/mogo-module-main/src/main/java/com/mogo/module/main/livedata/CardSwitchLiveData.java @@ -8,7 +8,7 @@ import androidx.lifecycle.MutableLiveData; *

* 切换卡片 */ -public class CardSwitchLiveData extends MutableLiveData< String > { +public class CardSwitchLiveData extends MutableLiveData< CardInfo > { private CardSwitchLiveData() { // private constructor diff --git a/modules/mogo-module-main/src/main/res/drawable-xhdpi/module_apps_bg_card.png b/modules/mogo-module-main/src/main/res/drawable-xhdpi/module_apps_bg_card.png new file mode 100755 index 0000000000..bb0c8aef1c Binary files /dev/null and b/modules/mogo-module-main/src/main/res/drawable-xhdpi/module_apps_bg_card.png differ diff --git a/modules/mogo-module-main/src/main/res/layout/module_main_activity_main.xml b/modules/mogo-module-main/src/main/res/layout/module_main_activity_main.xml index 598967ebe2..c03383b847 100644 --- a/modules/mogo-module-main/src/main/res/layout/module_main_activity_main.xml +++ b/modules/mogo-module-main/src/main/res/layout/module_main_activity_main.xml @@ -1,6 +1,5 @@ - @@ -9,9 +8,7 @@ + android:layout_height="match_parent" /> - + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - + android:layout_below="@+id/module_main_id_header_fragment_container" + android:layout_marginTop="@dimen/module_main_card_container_marginTop" + android:layout_toRightOf="@+id/module_main_card_container_frame" /> - \ No newline at end of file + android:layout_height="match_parent" + android:background="@drawable/module_main_launcher_bg" /> + \ No newline at end of file diff --git a/modules/mogo-module-map/src/main/java/com/mogo/module/map/MapFragment.java b/modules/mogo-module-map/src/main/java/com/mogo/module/map/MapFragment.java index 9bad8a5c75..27b5b5b4c6 100644 --- a/modules/mogo-module-map/src/main/java/com/mogo/module/map/MapFragment.java +++ b/modules/mogo-module-map/src/main/java/com/mogo/module/map/MapFragment.java @@ -22,13 +22,12 @@ import com.mogo.service.statusmanager.StatusDescriptor; *

* 地图图层,地图操作都在这个图层完成 */ -public class MapFragment extends MvpFragment< MapView, MapPresenter > implements MapView, IMogoStatusChangedListener { +public class MapFragment extends MvpFragment< MapView, MapPresenter > implements MapView { private static final String TAG = "MapFragment"; private MogoMapView mMogoMapView; private IMogoMap mMogoMap; - private IMogoStatusManager mMogoStatusManager; private boolean mIsControllerByOthersStatus = false; @@ -67,8 +66,6 @@ public class MapFragment extends MvpFragment< MapView, MapPresenter > implements // mMogoMapView.onCreate( savedInstanceState ); //} initMapView(); - mMogoStatusManager = ( IMogoStatusManager ) ARouter.getInstance().build( MogoServicePaths.PATH_STATUS_MANAGER ).navigation( getContext() ); - mMogoStatusManager.registerStatusChangedListener( TAG, StatusDescriptor.APP_LIST_UI, this ); } @Override @@ -134,18 +131,6 @@ public class MapFragment extends MvpFragment< MapView, MapPresenter > implements return mMogoMap.getUIController(); } - @Override - public void onStatusChanged( StatusDescriptor descriptor, boolean isTrue ) { - if ( descriptor == StatusDescriptor.APP_LIST_UI ) { - mIsControllerByOthersStatus = isTrue; - if ( isTrue ) { - mMogoMapView.onPause(); - } else { - mMogoMapView.onResume(); - } - } - } - @Override public void onDestroyView() { super.onDestroyView(); diff --git a/modules/mogo-module-service/build.gradle b/modules/mogo-module-service/build.gradle index 88ce45edb7..4ccbff8bf0 100644 --- a/modules/mogo-module-service/build.gradle +++ b/modules/mogo-module-service/build.gradle @@ -29,6 +29,11 @@ android { } } + compileOptions { + sourceCompatibility 1.8 + targetCompatibility 1.8 + } + } dependencies { diff --git a/modules/mogo-module-service/src/main/java/com/mogo/module/service/MarkerServiceHandler.java b/modules/mogo-module-service/src/main/java/com/mogo/module/service/MarkerServiceHandler.java index c5b640fc98..19e50fb9a2 100644 --- a/modules/mogo-module-service/src/main/java/com/mogo/module/service/MarkerServiceHandler.java +++ b/modules/mogo-module-service/src/main/java/com/mogo/module/service/MarkerServiceHandler.java @@ -10,6 +10,7 @@ import com.mogo.map.uicontroller.IMogoMapUIController; import com.mogo.module.common.entity.MarkerResponse; import com.mogo.module.common.entity.MarkerShowEntity; import com.mogo.module.service.marker.MapMarkerManager; +import com.mogo.service.IMogoServiceApis; import com.mogo.service.MogoServicePaths; import com.mogo.service.analytics.IMogoAnalytics; import com.mogo.service.cardmanager.IMogoCardManager; @@ -28,6 +29,7 @@ import com.mogo.service.statusmanager.IMogoStatusManager; public class MarkerServiceHandler { private static final String TAG = "MarkerServiceHandler"; + private static IMogoServiceApis mApis; private static IMogoMapService mMapService; private static IMogoMarkerManager mMarkerManager; @@ -44,22 +46,22 @@ public class MarkerServiceHandler { private static MapMarkerManager mMapMarkerManager; + public static void init( final Context context ) { + mApis = ( IMogoServiceApis ) ARouter.getInstance().build( MogoServicePaths.PATH_SERVICE_APIS ).navigation( context ); + mMapService = mApis.getMapServiceApi(); + mImageloader = mApis.getImageLoaderApi(); + mMogoStatusManager = mApis.getStatusManagerApi(); + mMogoSocketManager = mApis.getSocketManagerApi( context ); + mMogoCardManager = mApis.getCardManagerApi(); + mMogoAnalytics = mApis.getAnalyticsApi(); - public static void init(final Context context) { - mMapService = (IMogoMapService) ARouter.getInstance().build(MogoServicePaths.PATH_SERVICES_MAP).navigation(context); - mImageloader = (IMogoImageloader) ARouter.getInstance().build(MogoServicePaths.PATH_UTILS_IMAGE_LOADER).navigation(context); - mMogoStatusManager = (IMogoStatusManager) ARouter.getInstance().build(MogoServicePaths.PATH_STATUS_MANAGER).navigation(context); - mMogoSocketManager = (IMogoSocketManager) ARouter.getInstance().build(MogoServicePaths.PATH_SOCKET_MANAGER).navigation(); - mMogoCardManager = (IMogoCardManager) ARouter.getInstance().build(MogoServicePaths.PATH_CARD_MANAGER).navigation(); - mMogoAnalytics = (IMogoAnalytics) ARouter.getInstance().build(MogoServicePaths.PATH_UTILS_ANALYTICS).navigation(); - - mMarkerManager = mMapService.getMarkerManager(context); - mNavi = mMapService.getNavi(context); + mMarkerManager = mMapService.getMarkerManager( context ); + mNavi = mMapService.getNavi( context ); mMapUIController = mMapService.getMapUIController(); - mLocationClient = mMapService.getSingletonLocationClient(context); + mLocationClient = mMapService.getSingletonLocationClient( context ); - mMapMarkerManager = MapMarkerManager.getInstance(context); - mMapMarkerManager.init(context); + mMapMarkerManager = MapMarkerManager.getInstance(); + mMapMarkerManager.init( context ); } public static IMogoMapService getMapService() { @@ -112,30 +114,33 @@ public class MarkerServiceHandler { /** * 绘制Marker * 建议使用 + * * @see MapMarkerManager#drawMapMarker(MarkerResponse) */ @Deprecated - public static void drawMapMarker(MarkerResponse response) { - getMapMarkerManager().drawMapMarker(response); + public static void drawMapMarker( MarkerResponse response ) { + getMapMarkerManager().drawMapMarker( response ); } /** * 绘制Marker * 建议使用 + * * @see MapMarkerManager#drawMapMarker(MarkerShowEntity) */ @Deprecated - public static void drawMapMarker(MarkerShowEntity markerShowEntity) { - getMapMarkerManager().drawMapMarker(markerShowEntity); + public static void drawMapMarker( MarkerShowEntity markerShowEntity ) { + getMapMarkerManager().drawMapMarker( markerShowEntity ); } /** * 对指定类型高亮处理 * 建议使用 - * @see MapMarkerManager#highlightedMarker(String,boolean) + * + * @see MapMarkerManager#highlightedMarker(String, boolean) */ @Deprecated - public static void highlightedMarker(String typeTag) { - getMapMarkerManager().highlightedMarker(typeTag,false); + public static void highlightedMarker( String typeTag ) { + getMapMarkerManager().highlightedMarker( typeTag, false ); } } diff --git a/modules/mogo-module-service/src/main/java/com/mogo/module/service/MogoServices.java b/modules/mogo-module-service/src/main/java/com/mogo/module/service/MogoServices.java index d258aa730f..3ecd3d0821 100644 --- a/modules/mogo-module-service/src/main/java/com/mogo/module/service/MogoServices.java +++ b/modules/mogo-module-service/src/main/java/com/mogo/module/service/MogoServices.java @@ -7,6 +7,7 @@ import android.content.IntentFilter; import android.os.Handler; import android.os.Looper; import android.os.Message; +import android.os.Trace; import android.text.TextUtils; import android.view.MotionEvent; @@ -143,11 +144,7 @@ public class MogoServices implements IMogoMapListener, mRefreshRemainingTime -= ServiceConst.DECREASE_INTERVAL; if ( mRefreshRemainingTime == 0 ) { Logger.d( TAG, "move to center and refresh data." ); - mStatusManager.setUserInteractionStatus( ServiceConst.TYPE, true, false ); - mUiController.recoverLockMode(); - mStatusManager.setUserInteractionStatus( TAG, true, false ); - mUiController.changeZoom( 16.0f ); - notifyRefreshData( mLastAutoRefreshLocation, getQueryRadius(), mAutoRefreshCallback ); + invokeAutoRefresh(); } else { mHandler.sendEmptyMessageDelayed( msg.what, ServiceConst.DECREASE_INTERVAL ); } @@ -158,11 +155,21 @@ public class MogoServices implements IMogoMapListener, } if ( mLoopRequest ) { Logger.d( TAG, "补偿刷新触发" ); - notifyRefreshData( mLastAutoRefreshLocation, getQueryRadius(), mAutoRefreshCallback ); + invokeAutoRefresh(); } break; } } + + /** + * 自动刷新:锁车、缩放比例:16、半径 2KM + */ + private void invokeAutoRefresh() { + mStatusManager.setUserInteractionStatus( ServiceConst.TYPE, true, false ); + mUiController.setLockZoom( ServiceConst.DEFAULT_LOCK_CAR_ZOOM_LEVEL ); + mUiController.recoverLockMode(); + notifyRefreshData( mLastAutoRefreshLocation, ServiceConst.DEFAULT_AUTO_REFRESH_DATA_RADIUS, mAutoRefreshCallback ); + } }; private Context mContext; @@ -246,6 +253,7 @@ public class MogoServices implements IMogoMapListener, registerCenter.registerMogoLocationListener( ServiceConst.TYPE, this ); registerCenter.registerMogoNaviListener( ServiceConst.TYPE, this ); registerCenter.registerMogoMapListener( ServiceConst.TYPE, this ); + registerCenter.registerMogoAimlessModeListener( ServiceConst.TYPE, this ); mIntentManager = ( IMogoIntentManager ) ARouter.getInstance().build( MogoServicePaths.PATH_INTENT_MANAGER ).navigation( context ); mIntentManager.registerIntentListener( MogoReceiver.ACTIION_ADAS, this ); @@ -454,6 +462,7 @@ public class MogoServices implements IMogoMapListener, */ private boolean invokeRefreshWhenTranslationByUser( MogoLatLng latLng ) { try { + Trace.beginSection( "timer.invokeRefreshWhenTranslationByUser" ); float factor = 0.0f; if ( mIsVertical ) { factor = getMapCameraFactWidth(); @@ -465,6 +474,7 @@ public class MogoServices implements IMogoMapListener, } Logger.d( TAG, "invokeRefreshWhenTranslationByUser,mLastCustomRefreshCenterLocation = %s, latLng = %s", mLastCustomRefreshCenterLocation, latLng ); float distance = Utils.calculateLineDistance( latLng, mLastCustomRefreshCenterLocation ); + Trace.endSection(); return distance > factor; } catch ( Exception e ) { Logger.e( TAG, e, "warming. " ); @@ -500,7 +510,7 @@ public class MogoServices implements IMogoMapListener, mStatusManager.setUserInteractionStatus( ServiceConst.TYPE, true, false ); mUiController.recoverLockMode(); mStatusManager.setUserInteractionStatus( TAG, true, false ); - mUiController.changeZoom( 16.0f ); + mUiController.changeZoom( ServiceConst.DEFAULT_ZOOM_LEVEL ); mLastAutoRefreshLocation = point; notifyRefreshData( mLastAutoRefreshLocation, getQueryRadius(), mAutoRefreshCallback ); } @@ -548,8 +558,8 @@ public class MogoServices implements IMogoMapListener, case USER_INTERACTED: if ( isTrue && !mRefreshRemainingTimeStatus ) { mRefreshRemainingTimeStatus = true; - mRefreshRemainingTime += mAutoRefreshStrategy.getInterruptInterval(); - Logger.i( TAG, "用户状态改变,自动刷新时间延时,%s ms后自动刷新", mRefreshRemainingTime ); + mRefreshRemainingTime = ServiceConst.DEFAULT_AUTO_REFRESH_WHEN_INTERRUPT; + Logger.i( TAG, "用户状态改变,下次刷新时间:%ss后", mRefreshRemainingTime ); } break; case SEARCH_UI: @@ -636,7 +646,7 @@ public class MogoServices implements IMogoMapListener, return; } int status = intent.getIntExtra( MogoReceiver.PARAM_ADAS_STATUS, 0 ); - mUiController.setLockZoom( status == 1 ? 15 : 16 ); + mUiController.setLockZoom( status == 1 ? 15 : ServiceConst.DEFAULT_LOCK_CAR_ZOOM_LEVEL ); mStatusManager.setADASUIShow( ServiceConst.TYPE, status == 1 ); mUiController.showMyLocation( true ); } else if ( Intent.ACTION_POWER_CONNECTED.equals( command ) ) { diff --git a/modules/mogo-module-service/src/main/java/com/mogo/module/service/ServiceConst.java b/modules/mogo-module-service/src/main/java/com/mogo/module/service/ServiceConst.java index 67fada7976..b2d7b285b2 100644 --- a/modules/mogo-module-service/src/main/java/com/mogo/module/service/ServiceConst.java +++ b/modules/mogo-module-service/src/main/java/com/mogo/module/service/ServiceConst.java @@ -62,4 +62,30 @@ public class ServiceConst { */ public static final String CARD_TYPE_NOVELTY = "CARD_TYPE_NOVELTY"; + /** + * 运营位 + */ + public static final String CARD_TYPE_BUSINESS_OPERATION = "CARD_TYPE_BUSINESS_OPERATION"; + + /** + * 默认地图缩放比例 + */ + public static final float DEFAULT_ZOOM_LEVEL = 16.0f; + + /** + * 默认地图锁车缩放比例 + */ + public static final int DEFAULT_LOCK_CAR_ZOOM_LEVEL = 16; + + /** + * 自动酸辛默认半径 + */ + public static final int DEFAULT_AUTO_REFRESH_DATA_RADIUS = 2_000; + + /** + * 30 s + */ + public static final int DEFAULT_AUTO_REFRESH_WHEN_INTERRUPT = 30 * 1_000; + + } diff --git a/modules/mogo-module-service/src/main/java/com/mogo/module/service/marker/MapMarkerManager.java b/modules/mogo-module-service/src/main/java/com/mogo/module/service/marker/MapMarkerManager.java index dcc23e26fa..196056f814 100644 --- a/modules/mogo-module-service/src/main/java/com/mogo/module/service/marker/MapMarkerManager.java +++ b/modules/mogo-module-service/src/main/java/com/mogo/module/service/marker/MapMarkerManager.java @@ -1,13 +1,10 @@ package com.mogo.module.service.marker; import android.content.Context; -import android.os.Handler; -import android.os.Looper; import android.text.TextUtils; import android.view.animation.BounceInterpolator; import android.view.animation.OvershootInterpolator; -import com.alibaba.android.arouter.launcher.ARouter; import com.mogo.map.MogoLatLng; import com.mogo.map.location.MogoLocation; import com.mogo.map.marker.IMogoMarker; @@ -24,7 +21,6 @@ import com.mogo.module.common.entity.MarkerResponse; import com.mogo.module.common.entity.MarkerShareMusic; import com.mogo.module.common.entity.MarkerShowEntity; import com.mogo.module.service.MarkerServiceHandler; -import com.mogo.module.service.MogoServiceProvider; import com.mogo.module.service.MogoServices; import com.mogo.module.service.ServiceConst; import com.mogo.module.service.Utils; @@ -51,31 +47,35 @@ import java.util.Map; * desc : 大而全的Marker管理 * version: 1.0 */ -public class MapMarkerManager implements IMogoMarkerClickListener, IMogoOnMessageListener { +public class MapMarkerManager implements IMogoMarkerClickListener, + IMogoOnMessageListener< MarkerResponse >, + IMogoCardChangedListener { private static final String TAG = "MapMarkerManager"; // 是否同步在线数据给在线卡片, ACC ON 的标记记录 - private boolean isACC_ON = false; + private boolean mIsAccOn = false; private boolean isSynchronousOnLineData = true; // 是否选中在线卡片及气泡,语音搜索触发 - private boolean isCheckOnLineData = false; + private boolean mIsAISearchOnlineData = false; - private static Context mContext; + private Context mContext; // 最后一次选中的气泡 - private static IMogoMarker mLastCheckMarker; + private IMogoMarker mLastCheckMarker; private static MapMarkerManager mMarkerManager; - private static String mLastHighLightModule = ""; + private String mCurrentModuleName = ServiceConst.CARD_TYPE_BUSINESS_OPERATION; // 记录其它已经缩小的Marker - public static ArrayList alreadySmallMarker = new ArrayList<>(); + public ArrayList< String > alreadySmallMarker = new ArrayList<>(); // 距离用户最近的Marker - private IMogoMarker mNearlyMogoMarker = null; + private IMogoMarker mNearlyMarker = null; + // 记录上次请求数据,切换卡片时做数据处理 + private MarkerCardResult mLastDataResult; private MapMarkerManager() { } - public static synchronized MapMarkerManager getInstance(Context context) { - synchronized (MapMarkerManager.class) { - if (mMarkerManager == null) { + public static synchronized MapMarkerManager getInstance() { + synchronized ( MapMarkerManager.class ) { + if ( mMarkerManager == null ) { mMarkerManager = new MapMarkerManager(); } } @@ -88,96 +88,100 @@ public class MapMarkerManager implements IMogoMarkerClickListener, IMogoOnMessag * * @param context */ - public void init(Context context) { + public void init( Context context ) { mContext = context; // 长连接 - MarkerServiceHandler - .getMogoSocketManager() - .registerOnMessageListener(401001, this); - - MarkerServiceHandler.getMogoCardManager().registerCardChangedListener("LAUNCHER_MARKER_MODULE", new IMogoCardChangedListener() { - - @Override - public void onSwitched(int position, String moduleName) { - Logger.d(TAG, "当前C位卡片:" + moduleName); - highlightedMarker(moduleName, false); - mLastHighLightModule = moduleName; - if (!isACC_ON) { - isACC_ON = true; - MogoServices.getInstance().refreshStrategy(); - } - } - }); + MarkerServiceHandler.getMogoSocketManager().registerOnMessageListener( 401001, this ); + MarkerServiceHandler.getMogoCardManager().registerCardChangedListener( "LAUNCHER_MARKER_MODULE", this ); } // ACC ON 的时候重置为true,ACC OFF 设置为 false - public void setCheckOnLineData(boolean checkOnLineData) { - isACC_ON = checkOnLineData; + // 保留 - 外部模块调用 + public void setCheckOnLineData( boolean checkOnLineData ) { + mIsAccOn = checkOnLineData; + } + + @Override + public void onSwitched( int position, String moduleName ) { + Logger.d( TAG, "当前C位卡片:" + moduleName ); +// highlightedMarker( moduleName, false ); + mCurrentModuleName = moduleName; + if ( !mIsAccOn ) { + mIsAccOn = true; + Logger.d( TAG, "refresh data" ); + MogoServices.getInstance().refreshStrategy(); + } else { + runOnTargetThread( () -> { + Logger.d( TAG, "switch data" ); + MarkerServiceHandler.getMarkerManager().removeMarkers(); + drawMarkerByCurrentType( mLastDataResult ); + } ); + } } /** * 地图上的Marker点击回调 */ @Override - public boolean onMarkerClicked(IMogoMarker marker) { - Logger.d(TAG, "onMarkerClicked 点击了大而全中的Marker:" + marker); + public boolean onMarkerClicked( IMogoMarker marker ) { + Logger.d( TAG, "onMarkerClicked 点击了大而全中的Marker:" + marker ); try { - if (mLastCheckMarker != null) { + if ( mLastCheckMarker != null ) { // 判断点击的是否是同一个 - if (marker.equals(mLastCheckMarker)) { - Logger.d(TAG, "onMarkerClicked 与上一次点击的Marker一样,不做处理:" + marker); + if ( marker.equals( mLastCheckMarker ) ) { + Logger.d( TAG, "onMarkerClicked 与上一次点击的Marker一样,不做处理:" + marker ); return false; } // 将上次选中 Marker 设置为未选中状态 - closeMarker(mLastCheckMarker); + closeMarker( mLastCheckMarker ); } // 将当前的Marker设置为选中 - openMarker(marker); + openMarker( marker ); // 数据统计代码 - final Map properties = new HashMap<>(); - switch (mLastCheckMarker.getOwner()) { + final Map< String, Object > properties = new HashMap<>(); + switch ( mLastCheckMarker.getOwner() ) { case ServiceConst.CARD_TYPE_CARS_CHATTING: - properties.put("type", 3); + properties.put( "type", 3 ); break; case ServiceConst.CARD_TYPE_USER_DATA: - properties.put("type", 5); + properties.put( "type", 5 ); break; case ServiceConst.CARD_TYPE_ROAD_CONDITION: - properties.put("type", 2); + properties.put( "type", 2 ); break; case ServiceConst.CARD_TYPE_NOVELTY: - MarkerShowEntity showEntity = (MarkerShowEntity) mLastCheckMarker.getObject(); + MarkerShowEntity showEntity = ( MarkerShowEntity ) mLastCheckMarker.getObject(); Object bindObj = showEntity.getBindObj(); - if (bindObj instanceof MarkerNoveltyInfo) { - switch (((MarkerNoveltyInfo) bindObj).getPoiType()) { + if ( bindObj instanceof MarkerNoveltyInfo ) { + switch ( ( ( MarkerNoveltyInfo ) bindObj ).getPoiType() ) { case MarkerPoiTypeEnum.GAS_STATION: - properties.put("type", 4); + properties.put( "type", 4 ); break; case MarkerPoiTypeEnum.TRAFFIC_CHECK: - properties.put("type", 8); + properties.put( "type", 8 ); break; case MarkerPoiTypeEnum.ROAD_CLOSED: - properties.put("type", 7); + properties.put( "type", 7 ); break; case MarkerPoiTypeEnum.SHOP_DISCOUNT: - properties.put("type", 9); + properties.put( "type", 9 ); break; case MarkerPoiTypeEnum.FOURS_4S: - properties.put("type", 10); + properties.put( "type", 10 ); break; } } break; case ServiceConst.CARD_TYPE_SHARE_MUSIC: - properties.put("type", 6); + properties.put( "type", 6 ); break; } - MarkerServiceHandler.getMogoAnalytics().track("Launcher_Icon_Click", properties); + MarkerServiceHandler.getMogoAnalytics().track( "Launcher_Icon_Click", properties ); - } catch (Exception e) { + } catch ( Exception e ) { e.printStackTrace(); } return false; @@ -185,81 +189,81 @@ public class MapMarkerManager implements IMogoMarkerClickListener, IMogoOnMessag // 对指定类型高亮处理 - public synchronized static void highlightedMarker(final String typeTag) { - highlightedMarker(typeTag, false); + public synchronized void highlightedMarker( final String typeTag ) { + highlightedMarker( typeTag, false ); } - public synchronized static void highlightedMarker(final String typeTag, final boolean netDataRefresh) { + public synchronized void highlightedMarker( final String typeTag, final boolean netDataRefresh ) { try { - Logger.e(TAG, "上一次选中的卡片类型:mLastHighLightModule==" + mLastHighLightModule); - if (!TextUtils.isEmpty(mLastHighLightModule) && TextUtils.equals(mLastHighLightModule, typeTag) && !netDataRefresh) { + Logger.e( TAG, "上一次选中的卡片类型:mCurrentModuleName==" + mCurrentModuleName ); + if ( !TextUtils.isEmpty( mCurrentModuleName ) && TextUtils.equals( mCurrentModuleName, typeTag ) && !netDataRefresh ) { return; } // 从已经缩小的记录删除 - alreadySmallMarker.remove(typeTag); - List currentHighLightList = MarkerServiceHandler.getMarkerManager().getMarkers(typeTag); + alreadySmallMarker.remove( typeTag ); + List< IMogoMarker > currentHighLightList = MarkerServiceHandler.getMarkerManager().getMarkers( typeTag ); - if (currentHighLightList == null || currentHighLightList.size() == 0) { + if ( currentHighLightList == null || currentHighLightList.size() == 0 ) { alreadySmallMarker.clear(); // 放大所有的气泡 - Map> lastHighLightList = MarkerServiceHandler.getMarkerManager().getAllMarkers(); - for (String markerName : lastHighLightList.keySet()) { - setMarkersBig(lastHighLightList.get(markerName)); + Map< String, List< IMogoMarker > > lastHighLightList = MarkerServiceHandler.getMarkerManager().getAllMarkers(); + for ( String markerName : lastHighLightList.keySet() ) { + setMarkersBig( lastHighLightList.get( markerName ) ); } } else { // 缩小其他的气泡 - Map> lastHighLightList = MarkerServiceHandler.getMarkerManager().getAllMarkers(); - for (String markerName : lastHighLightList.keySet()) { - if (!markerName.equals(typeTag)) { - if (!alreadySmallMarker.contains(markerName)) { - alreadySmallMarker.add(markerName); - setMarkersSmall(lastHighLightList.get(markerName)); + Map< String, List< IMogoMarker > > lastHighLightList = MarkerServiceHandler.getMarkerManager().getAllMarkers(); + for ( String markerName : lastHighLightList.keySet() ) { + if ( !markerName.equals( typeTag ) ) { + if ( !alreadySmallMarker.contains( markerName ) ) { + alreadySmallMarker.add( markerName ); + setMarkersSmall( lastHighLightList.get( markerName ) ); } } } // 将当前卡片选中的气泡放大 - setMarkersBig(currentHighLightList); + setMarkersBig( currentHighLightList ); } - } catch (Exception e) { + } catch ( Exception e ) { e.printStackTrace(); } } - private static void setMarkersBig(List markers) { - if (markers == null || markers.isEmpty()) { + private static void setMarkersBig( List< IMogoMarker > markers ) { + if ( markers == null || markers.isEmpty() ) { return; } - for (IMogoMarker mogoMarker : markers) { - if (mogoMarker == null || mogoMarker.isDestroyed()) { + for ( IMogoMarker mogoMarker : markers ) { + if ( mogoMarker == null || mogoMarker.isDestroyed() ) { continue; } try { - mogoMarker.startScaleAnimation(0.6f, 1f, 0.6f, 1f, 1000, new BounceInterpolator()); - } catch (Exception e) { - Logger.e(TAG, e, "error."); + mogoMarker.startScaleAnimation( 0.6f, 1f, 0.6f, 1f, 1000, new BounceInterpolator() ); + } catch ( Exception e ) { + Logger.e( TAG, e, "error." ); } } } - private static void setMarkersSmall(List markers) { - if (markers == null || markers.isEmpty()) { + private static void setMarkersSmall( List< IMogoMarker > markers ) { + if ( markers == null || markers.isEmpty() ) { return; } - for (IMogoMarker mogoMarker : markers) { - smallMarker(mogoMarker); + for ( IMogoMarker mogoMarker : markers ) { + smallMarker( mogoMarker ); } } - private static void smallMarker(IMogoMarker mogoMarker) { - if (mogoMarker == null || mogoMarker.isDestroyed()) { + private static void smallMarker( IMogoMarker mogoMarker ) { + if ( mogoMarker == null || mogoMarker.isDestroyed() ) { return; } try { - mogoMarker.startScaleAnimation(1f, 0.6f, 1f, 0.6f, 300, new OvershootInterpolator()); - } catch (Exception e) { - Logger.e(TAG, e, "error."); + mogoMarker.startScaleAnimation( 1f, 0.6f, 1f, 0.6f, 300, new OvershootInterpolator() ); + } catch ( Exception e ) { + Logger.e( TAG, e, "error." ); } } @@ -268,261 +272,375 @@ public class MapMarkerManager implements IMogoMarkerClickListener, IMogoOnMessag * * @param marker 要关闭的Marker */ - public synchronized void closeMarkerSelect(IMogoMarker marker) { + public synchronized void closeMarkerSelect( IMogoMarker marker ) { // 将上次选中 Marker 设置为未选中状态 - if (marker != null) { - Logger.i(TAG, "closeMarkerSelect 将出Marker详情关闭:" + marker); - closeMarker(marker); + if ( marker != null ) { + Logger.i( TAG, "closeMarkerSelect 将出Marker详情关闭:" + marker ); + closeMarker( marker ); mLastCheckMarker = null; } } // 展开气泡 - private void openMarker(IMogoMarker mogoMarker) { - if (mogoMarker != null) { - if (mLastCheckMarker != null) { - closeMarker(mLastCheckMarker); - } - mLastCheckMarker = mogoMarker; - Object object = mogoMarker.getObject(); - if (object != null) { - MarkerShowEntity markerShowEntity = (MarkerShowEntity) object; - markerShowEntity.setChecked(true); - IMarkerView markerView = MapMarkerAdapter.getMarkerView(mContext, markerShowEntity, mogoMarker.getMogoMarkerOptions()); - mogoMarker.setIcon(ViewUtils.fromView(markerView.getView())); - mogoMarker.setToTop(); - } + private void openMarker( IMogoMarker mogoMarker ) { + if ( mogoMarker == null ) { + return; + } + if ( mLastCheckMarker != null ) { + closeMarker( mLastCheckMarker ); + } + mLastCheckMarker = mogoMarker; + Object object = mogoMarker.getObject(); + if ( object != null ) { + MarkerShowEntity markerShowEntity = ( MarkerShowEntity ) object; + markerShowEntity.setChecked( true ); + IMarkerView markerView = MapMarkerAdapter.getMarkerView( mContext, markerShowEntity, mogoMarker.getMogoMarkerOptions() ); + mogoMarker.setIcon( ViewUtils.fromView( markerView.getView() ) ); + mogoMarker.setToTop(); } } // 折叠气泡 - private void closeMarker(IMogoMarker mogoMarker) { - if (mogoMarker != null) { - Object object = mogoMarker.getObject(); - if (object != null) { - MarkerShowEntity markerShowEntity = (MarkerShowEntity) object; - markerShowEntity.setChecked(false); - IMarkerView markerView = MapMarkerAdapter.getMarkerView(mContext, markerShowEntity, mogoMarker.getMogoMarkerOptions()); - mogoMarker.setIcon(ViewUtils.fromView(markerView.getView())); - } + private void closeMarker( IMogoMarker mogoMarker ) { + if ( mogoMarker == null ) { + return; + } + Object object = mogoMarker.getObject(); + if ( object != null ) { + MarkerShowEntity markerShowEntity = ( MarkerShowEntity ) object; + markerShowEntity.setChecked( false ); + IMarkerView markerView = MapMarkerAdapter.getMarkerView( mContext, markerShowEntity, mogoMarker.getMogoMarkerOptions() ); + mogoMarker.setIcon( ViewUtils.fromView( markerView.getView() ) ); } } // 绘制Marker - public synchronized void drawMapMarker(MarkerResponse response) { - JSONArray array = new JSONArray(); + public synchronized void drawMapMarker( MarkerResponse response ) { + + if ( response == null || response.getResult() == null ) { + return; + } // 解析不同的Marker类型,然后对应的进行绘制 - if (response != null && response.getResult() != null) { + if ( response != null && response.getResult() != null ) { - MarkerCardResult markerCardResult = response.getResult(); + mLastDataResult = response.getResult(); // 语音触发的在线车辆搜索,采用增量的形式绘制 - if (markerCardResult.getDataType() != null && - markerCardResult.getDataType().size() == 1 && - markerCardResult.getDataType().contains(ServiceConst.CARD_TYPE_USER_DATA)) { - MarkerServiceHandler.getMarkerManager().removeMarkers(ServiceConst.CARD_TYPE_USER_DATA); - MarkerServiceHandler.getMogoCardManager().switch2(ServiceConst.CARD_TYPE_USER_DATA); - isCheckOnLineData = true; + if ( mIsAISearchOnlineData = isOnlineCarDataOnly( mLastDataResult ) ) { + MarkerServiceHandler.getMarkerManager().removeMarkers( ServiceConst.CARD_TYPE_USER_DATA ); + MarkerServiceHandler.getMogoCardManager().switch2( ServiceConst.CARD_TYPE_USER_DATA ); } else { mLastCheckMarker = null; // 清空所有地图上绘制的Marker MarkerServiceHandler.getMarkerManager().removeMarkers(); } - List onlineCarList = markerCardResult.getOnlineCar(); - List exploreWayList = markerCardResult.getExploreWay(); - List shareMusicList = markerCardResult.getShareMusic(); - List noveltyInfoList = markerCardResult.getNoveltyInfo(); - - if (onlineCarList != null) { - double nearlyDistance = Float.MAX_VALUE; - for (MarkerOnlineCar markerOnlineCar : onlineCarList) { - MarkerLocation markerLocation = markerOnlineCar.getLocation(); - - MarkerShowEntity markerShowEntity = new MarkerShowEntity(); - markerShowEntity.setBindObj(markerOnlineCar); - markerShowEntity.setMarkerLocation(markerLocation); - markerShowEntity.setMarkerType(markerOnlineCar.getType()); - markerShowEntity.setTextContent(markerOnlineCar.getUserInfo().getUserName()); - markerShowEntity.setIconUrl(markerOnlineCar.getUserInfo().getUserHead()); - - IMogoMarker iMogoMarker = drawMapMarker(markerShowEntity); - // 计算在线车辆距离当前车辆的距离,每次都与最后一次距离最近的进行比较,保留距离最近的车辆,进行卡片展示 - try { - // 当前车辆的位置 - MogoLocation currentLocation = MarkerServiceHandler.getMogoLocationClient().getLastKnowLocation(); - - // 计算车辆距离指定气泡的距离 - float calculateDistance = Utils.calculateLineDistance( - new MogoLatLng(markerLocation.getLat(), markerLocation.getLon()), - new MogoLatLng(currentLocation.getLatitude(), currentLocation.getLongitude()) - ); - -// Logger.d("点之间距离", -// "当前车辆经纬度:" + -// "\n\tlatitude=" + currentLocation.getLatitude() + -// "\n\tlongitude=" + currentLocation.getLongitude() + -// "\n气泡经纬度:" + markerLocation + -// "\n相距:" + calculateDistance + "米"); - - // 进行比较,保留最近的一个数据 - if (calculateDistance < nearlyDistance) { - nearlyDistance = calculateDistance; - mNearlyMogoMarker = iMogoMarker; - } - - } catch (Exception e) { - e.printStackTrace(); - } - } - Logger.d(TAG, "距离当前车辆位置最近的距离为:" + nearlyDistance); - fillNumberTrackEventBody(array, 3, onlineCarList.size()); - } - - // 将数据同步给探路,避免探路每次 perform 的时候去拉取,造成消耗 - MogoDataHandler.getInstance().invoke(ServiceConst.CARD_TYPE_ROAD_CONDITION, exploreWayList); - if (exploreWayList != null) { - for (MarkerExploreWay markerExploreWay : exploreWayList) { - if (!markerExploreWay.getCanLive()) { - MarkerLocation markerLocation = markerExploreWay.getLocation(); - - MarkerShowEntity markerShowEntity = new MarkerShowEntity(); - markerShowEntity.setBindObj(markerExploreWay); - markerShowEntity.setMarkerLocation(markerLocation); - markerShowEntity.setMarkerType(markerExploreWay.getType()); - markerShowEntity.setTextContent(markerExploreWay.getAddr()); - - drawMapMarker(markerShowEntity); - } - } - fillNumberTrackEventBody(array, 1, exploreWayList.size()); - } - - if (shareMusicList != null) { - for (MarkerShareMusic markerShareMusic : shareMusicList) { - MarkerLocation markerLocation = markerShareMusic.getLocation(); - - MarkerShowEntity markerShowEntity = new MarkerShowEntity(); - markerShowEntity.setBindObj(markerShareMusic); - markerShowEntity.setMarkerLocation(markerLocation); - markerShowEntity.setMarkerType(markerShareMusic.getType()); - markerShowEntity.setTextContent(markerShareMusic.getMediaName()); - markerShowEntity.setIconUrl(markerShareMusic.getMediaImg()); - - drawMapMarker(markerShowEntity); - } - fillNumberTrackEventBody(array, 4, shareMusicList.size()); - } - - if (noveltyInfoList != null) { - int num_gas_station = 0; - int num_traffic_check = 0; - int num_road_closed = 0; - int num_shop_discount = 0; - int num_fours_shop = 0; - - for (MarkerNoveltyInfo noveltyInfo : noveltyInfoList) { - MarkerLocation markerLocation = noveltyInfo.getLocation(); - - MarkerShowEntity markerShowEntity = new MarkerShowEntity(); - markerShowEntity.setBindObj(noveltyInfo); - markerShowEntity.setMarkerLocation(markerLocation); - markerShowEntity.setMarkerType(noveltyInfo.getType()); - markerShowEntity.setTextContent(noveltyInfo.getLocation().getAddress()); - - drawMapMarker(markerShowEntity); - - switch (noveltyInfo.getPoiType()) { - case MarkerPoiTypeEnum.GAS_STATION: - num_gas_station++; - break; - case MarkerPoiTypeEnum.TRAFFIC_CHECK: - num_traffic_check++; - break; - case MarkerPoiTypeEnum.ROAD_CLOSED: - num_road_closed++; - break; - case MarkerPoiTypeEnum.SHOP_DISCOUNT: - num_shop_discount++; - break; - case MarkerPoiTypeEnum.FOURS_4S: - num_fours_shop++; - break; - } - } - fillNumberTrackEventBody(array, 2, num_gas_station); - fillNumberTrackEventBody(array, 6, num_road_closed); - fillNumberTrackEventBody(array, 5, num_traffic_check); - fillNumberTrackEventBody(array, 7, num_shop_discount); - fillNumberTrackEventBody(array, 8, num_fours_shop); - } - analyticData(array); - + drawMarkerByCurrentType( mLastDataResult ); // 同步新绘制的气泡状态 alreadySmallMarker.clear(); - highlightedMarker(mLastHighLightModule, true); +// highlightedMarker( mCurrentModuleName, true ); - try { - // 在ACC on 之后第一次获取到了在线车辆数据,选中最近的一个Marker - if (isCheckOnLineData) { - if (mNearlyMogoMarker != null) { - Logger.d(TAG, "语音搜索触发,默认选中最近的在线车辆:" + mNearlyMogoMarker); - // 移动地图到指定位置 - MarkerServiceHandler.getMogoStatusManager().setUserInteractionStatus(ServiceConst.TYPE, true, false); - MarkerServiceHandler.getMapUIController().moveToCenter(mNearlyMogoMarker.getPosition()); - onMarkerClicked(mNearlyMogoMarker); - MogoMarkersHandler.getInstance().onMarkerClicked(mNearlyMogoMarker); - isCheckOnLineData = false; - } - } - - if (isACC_ON && isSynchronousOnLineData) { - isSynchronousOnLineData = false; - if (mNearlyMogoMarker != null) { - Logger.d(TAG, "ACC ON 触发,将附近的在线车辆数据同步给卡片:" + mNearlyMogoMarker); - openMarker(mNearlyMogoMarker); - // 将数据同步给在线用户卡片 - MogoDataHandler.getInstance().invoke(ServiceConst.CARD_TYPE_USER_DATA, mNearlyMogoMarker); - } - } - } catch (Exception e) { - e.printStackTrace(); - } + trackData( mLastDataResult ); } } + /** + * 是否是语音搜索的在线车辆数据:目前根据返回数据判断 + * + * @param markerCardResult + * @return + */ + private boolean isOnlineCarDataOnly( MarkerCardResult markerCardResult ) { + if ( markerCardResult != null && + markerCardResult.getDataType() != null && + markerCardResult.getDataType().size() == 1 && + markerCardResult.getDataType().contains( ServiceConst.CARD_TYPE_USER_DATA ) ) { + return true; + } + return false; + } /** - * 统计埋点 + * 根据类型绘制 + * + * @param markerCardResult */ - private synchronized static void fillNumberTrackEventBody(JSONArray arr, int type, int size) { - JSONObject object = new JSONObject(); - try { - object.put("type", type); - object.put("num", size); - if (arr != null) { - arr.put(object); + private synchronized void drawMarkerByCurrentType( MarkerCardResult markerCardResult ) { + + if ( markerCardResult == null ) { + return; + } + + if ( TextUtils.isEmpty( mCurrentModuleName ) ) { + // 默认大而全 + mCurrentModuleName = ServiceConst.CARD_TYPE_BUSINESS_OPERATION; + } + + List< MarkerOnlineCar > onlineCarList = markerCardResult.getOnlineCar(); + List< MarkerExploreWay > exploreWayList = markerCardResult.getExploreWay(); + List< MarkerShareMusic > shareMusicList = markerCardResult.getShareMusic(); + List< MarkerNoveltyInfo > noveltyInfoList = markerCardResult.getNoveltyInfo(); + + switch ( mCurrentModuleName ) { + case ServiceConst.CARD_TYPE_BUSINESS_OPERATION: + drawAllMarker( markerCardResult ); + break; + case ServiceConst.CARD_TYPE_NOVELTY: + drawNoveltyMarker( noveltyInfoList ); + break; + case ServiceConst.CARD_TYPE_CARS_CHATTING: + case ServiceConst.CARD_TYPE_USER_DATA: + drawOnlineCarMarkers( onlineCarList ); + break; + case ServiceConst.CARD_TYPE_ROAD_CONDITION: + drawRoadConditionMarker( exploreWayList ); + break; + case ServiceConst.CARD_TYPE_SHARE_MUSIC: + drawShareMusicMarker( shareMusicList ); + break; + } + } + + /** + * 绘制所有数据 + * + * @param markerCardResult + */ + private void drawAllMarker( MarkerCardResult markerCardResult ) { + List< MarkerOnlineCar > onlineCarList = markerCardResult.getOnlineCar(); + List< MarkerExploreWay > exploreWayList = markerCardResult.getExploreWay(); + List< MarkerShareMusic > shareMusicList = markerCardResult.getShareMusic(); + List< MarkerNoveltyInfo > noveltyInfoList = markerCardResult.getNoveltyInfo(); + + drawOnlineCarMarkers( onlineCarList ); + drawRoadConditionMarker( exploreWayList ); + drawShareMusicMarker( shareMusicList ); + drawNoveltyMarker( noveltyInfoList ); + } + + /** + * 绘制在线车辆marker + * + * @param onlineCarList + */ + private void drawOnlineCarMarkers( List< MarkerOnlineCar > onlineCarList ) { + // 将数据同步给在线车辆,避免每次 perform 的时候去拉取,造成消耗 + if ( onlineCarList == null || onlineCarList.isEmpty() ) { + MogoDataHandler.getInstance().invoke( ServiceConst.CARD_TYPE_USER_DATA, new ArrayList<>( ) ); + return; + } + MogoDataHandler.getInstance().invoke( ServiceConst.CARD_TYPE_USER_DATA, onlineCarList ); + double nearlyDistance = Float.MAX_VALUE; + for ( MarkerOnlineCar markerOnlineCar : onlineCarList ) { + MarkerLocation markerLocation = markerOnlineCar.getLocation(); + + MarkerShowEntity markerShowEntity = new MarkerShowEntity(); + markerShowEntity.setBindObj( markerOnlineCar ); + markerShowEntity.setMarkerLocation( markerLocation ); + markerShowEntity.setMarkerType( markerOnlineCar.getType() ); + markerShowEntity.setTextContent( markerOnlineCar.getUserInfo().getUserName() ); + markerShowEntity.setIconUrl( markerOnlineCar.getUserInfo().getUserHead() ); + + IMogoMarker iMogoMarker = drawMapMarker( markerShowEntity ); + // 计算在线车辆距离当前车辆的距离,每次都与最后一次距离最近的进行比较,保留距离最近的车辆,进行卡片展示 + try { + // 当前车辆的位置 + MogoLocation currentLocation = MarkerServiceHandler.getMogoLocationClient().getLastKnowLocation(); + + // 计算车辆距离指定气泡的距离 + float calculateDistance = Utils.calculateLineDistance( + new MogoLatLng( markerLocation.getLat(), markerLocation.getLon() ), + new MogoLatLng( currentLocation.getLatitude(), currentLocation.getLongitude() ) + ); + + // 进行比较,保留最近的一个数据 + if ( calculateDistance < nearlyDistance ) { + nearlyDistance = calculateDistance; + mNearlyMarker = iMogoMarker; + } + + } catch ( Exception e ) { + e.printStackTrace(); } - } catch (JSONException e) { + } + Logger.d( TAG, "距离当前车辆位置最近的距离为:" + nearlyDistance ); + + try { + // 在ACC on 之后第一次获取到了在线车辆数据,选中最近的一个Marker + if ( mIsAISearchOnlineData ) { + if ( mNearlyMarker != null ) { + Logger.d( TAG, "语音搜索触发,默认选中最近的在线车辆:" + mNearlyMarker ); + // 移动地图到指定位置 + MarkerServiceHandler.getMogoStatusManager().setUserInteractionStatus( ServiceConst.TYPE, true, false ); + MarkerServiceHandler.getMapUIController().moveToCenter( mNearlyMarker.getPosition() ); + onMarkerClicked( mNearlyMarker ); + MogoMarkersHandler.getInstance().onMarkerClicked( mNearlyMarker ); + mIsAISearchOnlineData = false; + } + } + + if ( mIsAccOn && isSynchronousOnLineData ) { + isSynchronousOnLineData = false; + if ( mNearlyMarker != null ) { + Logger.d( TAG, "ACC ON 触发,将附近的在线车辆数据同步给卡片:" + mNearlyMarker ); + openMarker( mNearlyMarker ); + // 将数据同步给在线用户卡片 + MogoDataHandler.getInstance().invoke( ServiceConst.CARD_TYPE_USER_DATA, mNearlyMarker ); + } + } + } catch ( Exception e ) { e.printStackTrace(); } } + /** + * 探路数据 + * + * @param exploreWayList + */ + private void drawRoadConditionMarker( List< MarkerExploreWay > exploreWayList ) { + // 将数据同步给探路,避免探路每次 perform 的时候去拉取,造成消耗 + MogoDataHandler.getInstance().invoke( ServiceConst.CARD_TYPE_ROAD_CONDITION, exploreWayList ); + if ( exploreWayList == null || exploreWayList.isEmpty() ) { + return; + } + for ( MarkerExploreWay markerExploreWay : exploreWayList ) { + if ( !markerExploreWay.getCanLive() ) { + MarkerLocation markerLocation = markerExploreWay.getLocation(); + + MarkerShowEntity markerShowEntity = new MarkerShowEntity(); + markerShowEntity.setBindObj( markerExploreWay ); + markerShowEntity.setMarkerLocation( markerLocation ); + markerShowEntity.setMarkerType( markerExploreWay.getType() ); + markerShowEntity.setTextContent( markerExploreWay.getAddr() ); + + drawMapMarker( markerShowEntity ); + } + } + } + + /** + * 共享音乐 + * + * @param shareMusicList + */ + private void drawShareMusicMarker( List< MarkerShareMusic > shareMusicList ) { + if ( shareMusicList == null ) { + return; + } + for ( MarkerShareMusic markerShareMusic : shareMusicList ) { + MarkerLocation markerLocation = markerShareMusic.getLocation(); + + MarkerShowEntity markerShowEntity = new MarkerShowEntity(); + markerShowEntity.setBindObj( markerShareMusic ); + markerShowEntity.setMarkerLocation( markerLocation ); + markerShowEntity.setMarkerType( markerShareMusic.getType() ); + markerShowEntity.setTextContent( markerShareMusic.getMediaName() ); + markerShowEntity.setIconUrl( markerShareMusic.getMediaImg() ); + + drawMapMarker( markerShowEntity ); + } + } + + /** + * 新鲜事 + * + * @param noveltyInfoList + */ + private void drawNoveltyMarker( List< MarkerNoveltyInfo > noveltyInfoList ) { + if ( noveltyInfoList == null ) { + return; + } + for ( MarkerNoveltyInfo noveltyInfo : noveltyInfoList ) { + MarkerLocation markerLocation = noveltyInfo.getLocation(); + MarkerShowEntity markerShowEntity = new MarkerShowEntity(); + markerShowEntity.setBindObj( noveltyInfo ); + markerShowEntity.setMarkerLocation( markerLocation ); + markerShowEntity.setMarkerType( noveltyInfo.getType() ); + markerShowEntity.setTextContent( noveltyInfo.getLocation().getAddress() ); + drawMapMarker( markerShowEntity ); + } + } + + /** * 统计地图内数据获取 * - * @param array 埋点数据 + * @param markerCardResult */ - private synchronized static void analyticData(JSONArray array) { + private void trackData( MarkerCardResult markerCardResult ) { + if ( markerCardResult == null ) { + return; + } + JSONArray array = new JSONArray(); + List< MarkerOnlineCar > onlineCarList = markerCardResult.getOnlineCar(); + List< MarkerExploreWay > exploreWayList = markerCardResult.getExploreWay(); + List< MarkerShareMusic > shareMusicList = markerCardResult.getShareMusic(); + List< MarkerNoveltyInfo > noveltyInfoList = markerCardResult.getNoveltyInfo(); + + fillNumberTrackEventBody( array, 3, onlineCarList.size() ); + fillNumberTrackEventBody( array, 1, exploreWayList.size() ); + fillNumberTrackEventBody( array, 4, shareMusicList.size() ); + + int num_gas_station = 0; + int num_traffic_check = 0; + int num_road_closed = 0; + int num_shop_discount = 0; + int num_fours_shop = 0; + + for ( MarkerNoveltyInfo markerNoveltyInfo : noveltyInfoList ) { + if ( markerNoveltyInfo == null ) { + continue; + } + switch ( markerNoveltyInfo.getPoiType() ) { + case MarkerPoiTypeEnum.GAS_STATION: + num_gas_station++; + break; + case MarkerPoiTypeEnum.TRAFFIC_CHECK: + num_traffic_check++; + break; + case MarkerPoiTypeEnum.ROAD_CLOSED: + num_road_closed++; + break; + case MarkerPoiTypeEnum.SHOP_DISCOUNT: + num_shop_discount++; + break; + case MarkerPoiTypeEnum.FOURS_4S: + num_fours_shop++; + break; + } + } + fillNumberTrackEventBody( array, 2, num_gas_station ); + fillNumberTrackEventBody( array, 6, num_road_closed ); + fillNumberTrackEventBody( array, 5, num_traffic_check ); + fillNumberTrackEventBody( array, 7, num_shop_discount ); + fillNumberTrackEventBody( array, 8, num_fours_shop ); + try { - if (array == null || array.length() == 0) { + if ( array.length() == 0 ) { return; } - final Map properties = new HashMap<>(); - properties.put("data", array.toString()); - MarkerServiceHandler.getMogoAnalytics().track("Launcher_Data_Get", properties); - } catch (Exception e) { + final Map< String, Object > properties = new HashMap<>(); + properties.put( "data", array.toString() ); + MarkerServiceHandler.getMogoAnalytics().track( "Launcher_Data_Get", properties ); + } catch ( Exception e ) { + e.printStackTrace(); + } + } + + /** + * 统计埋点 + */ + private synchronized static void fillNumberTrackEventBody( JSONArray arr, int type, int size ) { + JSONObject object = new JSONObject(); + try { + object.put( "type", type ); + object.put( "num", size ); + if ( arr != null ) { + arr.put( object ); + } + } catch ( JSONException e ) { e.printStackTrace(); } } @@ -533,44 +651,44 @@ public class MapMarkerManager implements IMogoMarkerClickListener, IMogoOnMessag * @param markerShowEntity marker 绘制数据实体 * @return 绘制的Marker */ - public synchronized IMogoMarker drawMapMarker(MarkerShowEntity markerShowEntity) { - if (!TextUtils.isEmpty(mLastHighLightModule) - && mLastCheckMarker != null - && !TextUtils.isEmpty(mLastCheckMarker.getOwner()) - && TextUtils.equals(mLastHighLightModule, mLastCheckMarker.getOwner()) - ) { - return drawMapMarker(markerShowEntity, true); - } else { - return drawMapMarker(markerShowEntity, false); - } + public synchronized IMogoMarker drawMapMarker( MarkerShowEntity markerShowEntity ) { + return drawMapMarker( markerShowEntity, isSmallType() ); } - private synchronized IMogoMarker drawMapMarker(MarkerShowEntity markerShowEntity, boolean isSmall) { + private boolean isSmallType() { + return !TextUtils.isEmpty( mCurrentModuleName ) + && mLastCheckMarker != null + && !mLastCheckMarker.isDestroyed() + && TextUtils.equals( mCurrentModuleName, mLastCheckMarker.getOwner() ); + } + + private IMogoMarker drawMapMarker( MarkerShowEntity markerShowEntity, boolean isSmall ) { //Logger.i(TAG, "绘制Marker====drawMapMarker:" + markerShowEntity); try { - if (markerShowEntity.getMarkerLocation() != null) { + if ( markerShowEntity.getMarkerLocation() != null ) { MogoMarkerOptions options = new MogoMarkerOptions() - .owner(markerShowEntity.getMarkerType()) - .object(markerShowEntity) - .latitude(markerShowEntity.getMarkerLocation().getLat()) - .longitude(markerShowEntity.getMarkerLocation().getLon()); - IMarkerView markerView = MapMarkerAdapter.getMarkerView(mContext, markerShowEntity, options); - options.icon(markerView.getView()); + .owner( markerShowEntity.getMarkerType() ) + .object( markerShowEntity ) + .latitude( markerShowEntity.getMarkerLocation().getLat() ) + .longitude( markerShowEntity.getMarkerLocation().getLon() ); + IMarkerView markerView = MapMarkerAdapter.getMarkerView( mContext, markerShowEntity, options ); + options.icon( markerView.getView() ); - IMogoMarker marker = MarkerServiceHandler.getMarkerManager().addMarker(markerShowEntity.getMarkerType(), options); - markerView.setMarker(marker); - marker.setOnMarkerClickListener(this); + IMogoMarker marker = MarkerServiceHandler.getMarkerManager().addMarker( markerShowEntity.getMarkerType(), options ); + marker.setOwner( markerShowEntity.getMarkerType() ); + markerView.setMarker( marker ); + marker.setOnMarkerClickListener( this ); - if (isSmall) { - List markers = new ArrayList<>(); - markers.add(marker); - setMarkersSmall(markers); + if ( isSmall ) { + List< IMogoMarker > markers = new ArrayList<>(); + markers.add( marker ); + setMarkersSmall( markers ); } return marker; } else { - Logger.e(TAG, "Location 必须进行初始化!!!!!"); + Logger.e( TAG, "Location 必须进行初始化!!!!!" ); } - } catch (Exception e) { + } catch ( Exception e ) { e.printStackTrace(); } return null; @@ -578,23 +696,29 @@ public class MapMarkerManager implements IMogoMarkerClickListener, IMogoOnMessag @Override - public Class target() { + public Class< MarkerResponse > target() { return MarkerResponse.class; } @Override - public void onMsgReceived(final MarkerResponse response) { - Logger.d(TAG, "接收到了地图大而全数据"); - if (!MarkerServiceHandler.getMogoStatusManager().isSearchUIShow() - && isACC_ON - && !MarkerServiceHandler.getMogoStatusManager().isV2XShow()) { - Handler handler = new Handler(Looper.getMainLooper()); - handler.post(new Runnable() { - @Override - public void run() { - drawMapMarker(response); - } + public void onMsgReceived( final MarkerResponse response ) { + if ( !ignoreDrawRequest() ) { + Logger.d( TAG, "接收到了地图大而全数据" ); + runOnTargetThread( () -> { + drawMapMarker( response ); } ); } } + + private boolean ignoreDrawRequest() { + return MarkerServiceHandler.getMogoStatusManager().isSearchUIShow() + || MarkerServiceHandler.getMogoStatusManager().isV2XShow(); + } + + private void runOnTargetThread( Runnable runnable ) { + if ( runnable == null ) { + return; + } + ThreadPoolService.execute( runnable ); + } } diff --git a/modules/mogo-module-service/src/main/java/com/mogo/module/service/refresh/AutoRefreshStrategy.java b/modules/mogo-module-service/src/main/java/com/mogo/module/service/refresh/AutoRefreshStrategy.java index d620f20586..47d96799f4 100644 --- a/modules/mogo-module-service/src/main/java/com/mogo/module/service/refresh/AutoRefreshStrategy.java +++ b/modules/mogo-module-service/src/main/java/com/mogo/module/service/refresh/AutoRefreshStrategy.java @@ -21,9 +21,9 @@ public class AutoRefreshStrategy { private long interval = 3 * ONE_MINUTE; /** - * 用户打断后的延时(s) + * 用户打断后的延时(s)【2.0.2后不再延时】 */ - private long interruptInterval = 1 * ONE_MINUTE; + private long interruptInterval = 0 * ONE_MINUTE; /** * 距离(米) diff --git a/services/mogo-service-api/src/main/java/com/mogo/service/IMogoServiceApis.java b/services/mogo-service-api/src/main/java/com/mogo/service/IMogoServiceApis.java index c5f43a8e08..1983c7fe4e 100644 --- a/services/mogo-service-api/src/main/java/com/mogo/service/IMogoServiceApis.java +++ b/services/mogo-service-api/src/main/java/com/mogo/service/IMogoServiceApis.java @@ -3,6 +3,7 @@ package com.mogo.service; import android.content.Context; import com.alibaba.android.arouter.facade.template.IProvider; +import com.mogo.service.adas.IMogoADASController; import com.mogo.service.analytics.IMogoAnalytics; import com.mogo.service.cardmanager.IMogoCardManager; import com.mogo.service.connection.IMogoSocketManager; @@ -103,7 +104,7 @@ public interface IMogoServiceApis extends IProvider { * * @return */ - IMogoSettingManager getSettingManager(); + IMogoSettingManager getSettingManagerApi(); /** * 网络接口api @@ -129,5 +130,12 @@ public interface IMogoServiceApis extends IProvider { * * @return */ - IMogoWindowManager getWindowManager(); + IMogoWindowManager getWindowManagerApi(); + + /** + * 辅助驾驶控制接口 + * + * @return + */ + IMogoADASController getAdasControllerApi(); } diff --git a/services/mogo-service-api/src/main/java/com/mogo/service/MogoServicePaths.java b/services/mogo-service-api/src/main/java/com/mogo/service/MogoServicePaths.java index 7d1bee9a1e..e200c4401a 100644 --- a/services/mogo-service-api/src/main/java/com/mogo/service/MogoServicePaths.java +++ b/services/mogo-service-api/src/main/java/com/mogo/service/MogoServicePaths.java @@ -132,6 +132,12 @@ public class MogoServicePaths { @Deprecated public static final String PATH_DATA_MANAGER = "/datamanager/api"; + /** + * adas 控制 + */ + @Deprecated + public static final String PATH_ADAS_CONTROLLER = "/adascontroller/api"; + /** * 接口集合 */ diff --git a/services/mogo-service-api/src/main/java/com/mogo/service/adas/IMogoADASController.java b/services/mogo-service-api/src/main/java/com/mogo/service/adas/IMogoADASController.java new file mode 100644 index 0000000000..5a6f90560d --- /dev/null +++ b/services/mogo-service-api/src/main/java/com/mogo/service/adas/IMogoADASController.java @@ -0,0 +1,23 @@ +package com.mogo.service.adas; + +import com.alibaba.android.arouter.facade.template.IProvider; + +/** + * @author congtaowang + * @since 2020-03-10 + *

+ * v2x 页面控制 + */ +public interface IMogoADASController extends IProvider { + + /** + * 打开adas + */ + void openADAS(); + + /** + * 关闭adas + */ + void closeADAS(); + +} diff --git a/services/mogo-service-api/src/main/java/com/mogo/service/cardmanager/IMogoCardManager.java b/services/mogo-service-api/src/main/java/com/mogo/service/cardmanager/IMogoCardManager.java index 30c0ed5f17..a2eab1d620 100644 --- a/services/mogo-service-api/src/main/java/com/mogo/service/cardmanager/IMogoCardManager.java +++ b/services/mogo-service-api/src/main/java/com/mogo/service/cardmanager/IMogoCardManager.java @@ -12,11 +12,21 @@ public interface IMogoCardManager extends IProvider { /** * 切换卡片 + *

+ * 实际调用 switch2(cardType, false) * * @param cardType */ void switch2( String cardType ); + /** + * 切换卡片 + * + * @param cardType 卡片类型 + * @param lockCar 是否锁车[将视图拉回车位] + */ + void switch2( String cardType, boolean lockCar ); + /** * 注册卡片切换监听 */ diff --git a/services/mogo-service-api/src/main/java/com/mogo/service/datamanager/IMogoDataChangedListener.java b/services/mogo-service-api/src/main/java/com/mogo/service/datamanager/IMogoDataChangedListener.java index 2e2d76ff12..74ab4be6ee 100644 --- a/services/mogo-service-api/src/main/java/com/mogo/service/datamanager/IMogoDataChangedListener.java +++ b/services/mogo-service-api/src/main/java/com/mogo/service/datamanager/IMogoDataChangedListener.java @@ -1,7 +1,5 @@ package com.mogo.service.datamanager; -import java.util.List; - /** * @author congtaowang * @since 2020-02-11 diff --git a/services/mogo-service-api/src/main/java/com/mogo/service/map/IMogoMapService.java b/services/mogo-service-api/src/main/java/com/mogo/service/map/IMogoMapService.java index 38ec4f9548..d4a794ea16 100644 --- a/services/mogo-service-api/src/main/java/com/mogo/service/map/IMogoMapService.java +++ b/services/mogo-service-api/src/main/java/com/mogo/service/map/IMogoMapService.java @@ -11,6 +11,7 @@ import com.mogo.map.marker.IMogoMarkerManager; import com.mogo.map.navi.IMogoNavi; import com.mogo.map.navi.IMogoNaviListener; import com.mogo.map.navi.IMogoNaviListenerRegister; +import com.mogo.map.overlay.IMogoOverlayManager; import com.mogo.map.search.geo.IMogoGeoSearch; import com.mogo.map.search.inputtips.IMogoInputtipsSearch; import com.mogo.map.search.inputtips.query.MogoInputtipsQuery; @@ -68,7 +69,8 @@ public interface IMogoMapService extends IProvider { */ IMogoPoiSearch getPoiSearch( Context context, MogoPoiSearchQuery query ); - /**f + /** + * f * 获取导航操作实例 * * @param context @@ -96,4 +98,12 @@ public interface IMogoMapService extends IProvider { * @return */ IMogoHosListenerRegister getHostListenerRegister(); + + /** + * 覆盖物操作 + * + * @param context + * @return + */ + IMogoOverlayManager getOverlayManager( Context context ); } diff --git a/services/mogo-service/src/main/java/com/mogo/service/impl/MogoServiceApis.java b/services/mogo-service/src/main/java/com/mogo/service/impl/MogoServiceApis.java index 3297ec44fd..78df9b1960 100644 --- a/services/mogo-service/src/main/java/com/mogo/service/impl/MogoServiceApis.java +++ b/services/mogo-service/src/main/java/com/mogo/service/impl/MogoServiceApis.java @@ -8,6 +8,7 @@ import com.alibaba.android.arouter.launcher.ARouter; import com.mogo.connection.socket.SocketManager; import com.mogo.service.IMogoServiceApis; import com.mogo.service.MogoServicePaths; +import com.mogo.service.adas.IMogoADASController; import com.mogo.service.analytics.IMogoAnalytics; import com.mogo.service.cardmanager.IMogoCardManager; import com.mogo.service.connection.IMogoSocketManager; @@ -114,15 +115,20 @@ public class MogoServiceApis implements IMogoServiceApis { } @Override - public IMogoSettingManager getSettingManager() { + public IMogoSettingManager getSettingManagerApi() { return getApiInstance( IMogoSettingManager.class, MogoServicePaths.PATH_SETTING_MANAGER ); } @Override - public IMogoWindowManager getWindowManager() { + public IMogoWindowManager getWindowManagerApi() { return getApiInstance( IMogoWindowManager.class, MogoServicePaths.PATH_WINDOW_MANAGER ); } + @Override + public IMogoADASController getAdasControllerApi() { + return getApiInstance( IMogoADASController.class, MogoServicePaths.PATH_ADAS_CONTROLLER ); + } + private static < T extends IProvider > T getApiInstance( Class< T > clazz, String path ) { T inst = SingletonsHolder.get( clazz ); if ( inst == null ) { diff --git a/services/mogo-service/src/main/java/com/mogo/service/impl/adas/MogoADASController.java b/services/mogo-service/src/main/java/com/mogo/service/impl/adas/MogoADASController.java new file mode 100644 index 0000000000..a988dc8a80 --- /dev/null +++ b/services/mogo-service/src/main/java/com/mogo/service/impl/adas/MogoADASController.java @@ -0,0 +1,79 @@ +package com.mogo.service.impl.adas; + +import android.app.Application; +import android.content.Context; +import android.content.Intent; + +import com.alibaba.android.arouter.facade.annotation.Route; +import com.mogo.commons.AbsMogoApplication; +import com.mogo.service.MogoServicePaths; +import com.mogo.service.adas.IMogoADASController; +import com.mogo.utils.logger.Logger; + +import org.json.JSONObject; + +/** + * @author congtaowang + * @since 2020-03-10 + *

+ * 描述 + */ +@Route( path = MogoServicePaths.PATH_ADAS_CONTROLLER ) +public class MogoADASController implements IMogoADASController { + + private static final String TAG = "MogoADASController"; + + public static final String ACTION = "com.zhidao.speech.awake.notify"; + public static final String PARAM_COMMAND = "command"; + public static final String VAL_COMMAND = "system.application.operation"; + public static final String PARAM_DATA = "data"; + public static final String PARAM_OBJECT = "object"; + public static final String VAL_OBJECT = "辅助驾驶"; + public static final String PARAM_OPERATION = "operation"; + public static final String VAL_OPEN = "打开"; + public static final String VAL_CLOSE = "关闭"; + + @Override + public void openADAS() { + Intent intent = new Intent( ACTION ); + intent.putExtra( PARAM_COMMAND, VAL_COMMAND ); + JSONObject object = new JSONObject(); + try { + object.put( PARAM_OBJECT, VAL_OBJECT ); + object.put( PARAM_OPERATION, VAL_OPEN ); + intent.putExtra( PARAM_DATA, object.toString() ); + sendBroadcast( intent ); + } catch ( Exception e ) { + Logger.e( TAG, e, "error." ); + } + } + + @Override + public void closeADAS() { + Intent intent = new Intent( ACTION ); + intent.putExtra( PARAM_COMMAND, VAL_COMMAND ); + JSONObject object = new JSONObject(); + try { + object.put( PARAM_OBJECT, VAL_OBJECT ); + object.put( PARAM_OPERATION, VAL_CLOSE ); + intent.putExtra( PARAM_DATA, object.toString() ); + sendBroadcast( intent ); + } catch ( Exception e ) { + Logger.e( TAG, e, "error." ); + } + } + + private void sendBroadcast( Intent intent ) { + Application app = AbsMogoApplication.getApp(); + if ( app == null ) { + Logger.e( TAG, "un handle Application instance." ); + return; + } + app.sendBroadcast( intent ); + } + + @Override + public void init( Context context ) { + + } +} diff --git a/services/mogo-service/src/main/java/com/mogo/service/impl/map/MogoMapService.java b/services/mogo-service/src/main/java/com/mogo/service/impl/map/MogoMapService.java index b3bdbffbea..2f454add44 100644 --- a/services/mogo-service/src/main/java/com/mogo/service/impl/map/MogoMapService.java +++ b/services/mogo-service/src/main/java/com/mogo/service/impl/map/MogoMapService.java @@ -10,12 +10,14 @@ import com.mogo.map.MogoLocationClient; import com.mogo.map.MogoMapUIController; import com.mogo.map.MogoMarkerManager; import com.mogo.map.MogoNavi; +import com.mogo.map.MogoOverlayManager; import com.mogo.map.MogoPoiSearch; import com.mogo.map.listener.IMogoHosListenerRegister; import com.mogo.map.listener.MogoHosListenerRegister; import com.mogo.map.location.IMogoLocationClient; import com.mogo.map.marker.IMogoMarkerManager; import com.mogo.map.navi.IMogoNavi; +import com.mogo.map.overlay.IMogoOverlayManager; import com.mogo.map.search.geo.IMogoGeoSearch; import com.mogo.map.search.inputtips.IMogoInputtipsSearch; import com.mogo.map.search.inputtips.query.MogoInputtipsQuery; @@ -79,6 +81,11 @@ public class MogoMapService implements IMogoMapService { return MogoHosListenerRegister.getInstance(); } + @Override + public IMogoOverlayManager getOverlayManager( Context context ) { + return MogoOverlayManager.getInstance(); + } + @Override public void init( Context context ) { MogoInitor.init( context ); diff --git a/settings.gradle b/settings.gradle index 4747a1bb37..b813673c90 100644 --- a/settings.gradle +++ b/settings.gradle @@ -4,6 +4,7 @@ include ':foudations:mogo-utils' include ':services:mogo-service-api' include ':services:mogo-service' include ':libraries:mogo-map' +include ':libraries:card-library' include ':foudations:mogo-commons' include ':modules:mogo-module-map' include ':modules:mogo-module-common'