diff --git a/foudations/mogo-utils/src/main/java/com/mogo/utils/AssetsUtils.java b/foudations/mogo-utils/src/main/java/com/mogo/utils/AssetsUtils.java new file mode 100644 index 0000000000..7ec9448cd7 --- /dev/null +++ b/foudations/mogo-utils/src/main/java/com/mogo/utils/AssetsUtils.java @@ -0,0 +1,37 @@ +package com.mogo.utils; + +import android.content.Context; +import android.text.TextUtils; +import android.util.Log; +import java.io.BufferedInputStream; +import java.io.InputStream; + +/** + * @author congtaowang + * @since 2019-12-12 + *
+ * 读取asset文件 + */ +public class AssetsUtils { + + private static final String TAG = "amap.AssetsUtils"; + + public static byte[] read( Context context, String fileName ) { + if ( context == null || TextUtils.isEmpty( fileName ) ) { + return null; + } + byte[] buffer = null; + try { + InputStream is = context.getAssets().open( fileName ); + BufferedInputStream bis = new BufferedInputStream( is ); + buffer = new byte[is.available()]; + bis.read( buffer ); + bis.close(); + is.close(); + Log.d( TAG, "read assets success: " + fileName + " size=" + buffer.length ); + } catch ( Exception e ) { + e.printStackTrace(); + } + return buffer; + } +} diff --git a/foudations/mogo-utils/src/main/java/com/mogo/utils/NetworkUtils.java b/foudations/mogo-utils/src/main/java/com/mogo/utils/NetworkUtils.java new file mode 100644 index 0000000000..4481f10508 --- /dev/null +++ b/foudations/mogo-utils/src/main/java/com/mogo/utils/NetworkUtils.java @@ -0,0 +1,110 @@ +package com.mogo.utils; + +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import androidx.annotation.Nullable; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class NetworkUtils { + private static final String TAG = NetworkUtils.class.getSimpleName(); + + /** + * Returns true if device is connected to wifi or mobile network, false + * otherwise. + * + * @param context + * @return + */ + public static boolean isConnected( Context context ) { + + if ( context == null ) { + return false; + } + + ConnectivityManager conMan = (ConnectivityManager) context + .getSystemService( Context.CONNECTIVITY_SERVICE ); + + if ( conMan == null ) { + return false; + } + + NetworkInfo infoWifi = conMan.getNetworkInfo( ConnectivityManager.TYPE_WIFI ); + if ( infoWifi != null ) { + NetworkInfo.State wifi = infoWifi.getState(); + if ( wifi == NetworkInfo.State.CONNECTED ) { + return true; + } + } + + NetworkInfo infoMobile = conMan.getNetworkInfo( ConnectivityManager.TYPE_MOBILE ); + if ( infoMobile != null ) { + NetworkInfo.State mobile = infoMobile.getState(); + if ( mobile == NetworkInfo.State.CONNECTED ) { + return true; + } + } + return false; + } + + /** + * Check if there is any connectivity to a Wifi network + * + * @param context + * @return + */ + public static boolean isConnectedWifi( Context context ) { + if ( context == null ) { + return false; + } + NetworkInfo info = getNetworkInfo( context ); + return ( info != null && info.isConnected() && info.getType() == ConnectivityManager.TYPE_WIFI ); + } + + /** + * Check if there is any connectivity to a mobile network + * + * @param context + * @return + */ + public static boolean isConnectedMobile( Context context ) { + if ( context == null ) { + return false; + } + NetworkInfo info = getNetworkInfo( context ); + return ( info != null && info.isConnected() && info.getType() == ConnectivityManager.TYPE_MOBILE ); + } + + /** + * Get the network info + * + * @param context + * @return + */ + @Nullable + public static NetworkInfo getNetworkInfo( Context context ) { + if ( context == null ) { + return null; + } + ConnectivityManager cm = (ConnectivityManager) context.getSystemService( Context.CONNECTIVITY_SERVICE ); + if ( cm != null ) { + return cm.getActiveNetworkInfo(); + } + return null; + } + + /** + * URL + * + * @param url + * @return true ,false + */ + public static boolean isNetworkUrl( String url ) { + String regex = "^(https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]"; + Pattern patt = Pattern.compile( regex ); + Matcher matcher = patt.matcher( url ); + return matcher.matches(); + } + +} diff --git a/foudations/mogo-utils/src/main/java/com/mogo/utils/OnItemClickedListener.java b/foudations/mogo-utils/src/main/java/com/mogo/utils/OnItemClickedListener.java new file mode 100644 index 0000000000..fa7065448e --- /dev/null +++ b/foudations/mogo-utils/src/main/java/com/mogo/utils/OnItemClickedListener.java @@ -0,0 +1,12 @@ +package com.mogo.utils; + +/** + * @author congtaowang + * @since 2019-10-02 + *
+ * recyclerview item 点击回调 + */ +public interface OnItemClickedListener< T > { + + void onItemClicked(T obj); +} diff --git a/foudations/mogo-utils/src/main/java/com/mogo/utils/statusbar/Eyes.java b/foudations/mogo-utils/src/main/java/com/mogo/utils/statusbar/Eyes.java new file mode 100644 index 0000000000..b0eecffd79 --- /dev/null +++ b/foudations/mogo-utils/src/main/java/com/mogo/utils/statusbar/Eyes.java @@ -0,0 +1,177 @@ +package com.mogo.utils.statusbar; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Color; +import android.os.Build; +import android.util.TypedValue; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; +import androidx.core.view.ViewCompat; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +public class Eyes { + + + public static void setStatusBarColor( Activity activity, int statusColor ) { + if ( Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ) { + EyesLollipop.setStatusBarColor( activity, statusColor ); + } else if ( Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT ) { + EyesKitKat.setStatusBarColor( activity, statusColor ); + } + } + + public static void translucentStatusBar( Activity activity ) { + translucentStatusBar( activity, false ); + } + + public static void translucentStatusBar( Activity activity, boolean hideStatusBarBackground ) { + if ( Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ) { + EyesLollipop.translucentStatusBar( activity, hideStatusBarBackground ); + } else if ( Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT ) { + EyesKitKat.translucentStatusBar( activity ); + } + } +// +// public static void setStatusBarColorForCollapsingToolbar(@NonNull Activity activity, AppBarLayout appBarLayout, CollapsingToolbarLayout collapsingToolbarLayout, +// Toolbar toolbar, @ColorInt int statusColor) { +// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { +// EyesLollipop.setStatusBarColorForCollapsingToolbar(activity, appBarLayout, collapsingToolbarLayout, toolbar, statusColor); +// } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { +// EyesKitKat.setStatusBarColorForCollapsingToolbar(activity, appBarLayout, collapsingToolbarLayout, toolbar, statusColor); +// } +// } + + public static void setStatusBarLightMode( Activity activity, int color ) { + if ( Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT ) { + //判断是否为小米或魅族手机,如果是则将状态栏文字改为黑色 + if ( MIUISetStatusBarLightMode( activity, true ) || FlymeSetStatusBarLightMode( activity, true ) ) { + //设置状态栏为指定颜色 + if ( Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ) {//5.0 + activity.getWindow().setStatusBarColor( color ); + } else {//4.4 + //调用修改状态栏颜色的方法 + setStatusBarColor( activity, color ); + } + } else if ( Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ) { + //如果是6.0以上将状态栏文字改为黑色,并设置状态栏颜色 + activity.getWindow().setBackgroundDrawableResource( android.R.color.transparent ); + activity.getWindow().getDecorView().setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR ); + activity.getWindow().setStatusBarColor( color ); + + //fitsSystemWindow 为 false, 不预留系统栏位置. + ViewGroup mContentView = activity.getWindow().findViewById( Window.ID_ANDROID_CONTENT ); + View mChildView = mContentView.getChildAt( 0 ); + if ( mChildView != null ) { + mChildView.setFitsSystemWindows( true ); + ViewCompat.requestApplyInsets( mChildView ); + } + } + } + } + +// +// public static void setStatusBarLightForCollapsingToolbar(Activity activity, AppBarLayout appBarLayout, +// CollapsingToolbarLayout collapsingToolbarLayout, Toolbar toolbar, int statusBarColor) { +// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { +// EyesLollipop.setStatusBarWhiteForCollapsingToolbar(activity, appBarLayout, collapsingToolbarLayout, toolbar, statusBarColor); +// } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { +// EyesKitKat.setStatusBarWhiteForCollapsingToolbar(activity, appBarLayout, collapsingToolbarLayout, toolbar, statusBarColor); +// } +// } + + + /** + * MIUI的沉浸支持透明白色字体和透明黑色字体 + * https://dev.mi.com/console/doc/detail?pId=1159 + */ + static boolean MIUISetStatusBarLightMode( Activity activity, boolean darkmode ) { + try { + Class< ? > layoutParams = Class.forName( "android.view.MiuiWindowManager$LayoutParams" ); + + Window window = activity.getWindow(); + window.addFlags( WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS ); + window.clearFlags( WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS ); + window.getDecorView().setSystemUiVisibility( View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR ); + + Class< ? extends Window> clazz = activity.getWindow().getClass(); + Field field = layoutParams.getField( "EXTRA_FLAG_STATUS_BAR_DARK_MODE" ); + int darkModeFlag = field.getInt( layoutParams ); + Method extraFlagField = clazz.getMethod( "setExtraFlags", int.class, int.class ); + extraFlagField.invoke( activity.getWindow(), darkmode ? darkModeFlag : 0, darkModeFlag ); + return true; + } catch ( Exception e ) { + } + return false; + } + + /** + * 设置状态栏图标为深色和魅族特定的文字风格,Flyme4.0以上 + */ + static boolean FlymeSetStatusBarLightMode( Activity activity, boolean darkmode ) { + try { + WindowManager.LayoutParams lp = activity.getWindow().getAttributes(); + Field darkFlag = WindowManager.LayoutParams.class + .getDeclaredField( "MEIZU_FLAG_DARK_STATUS_BAR_ICON" ); + Field meizuFlags = WindowManager.LayoutParams.class + .getDeclaredField( "meizuFlags" ); + darkFlag.setAccessible( true ); + meizuFlags.setAccessible( true ); + int bit = darkFlag.getInt( null ); + int value = meizuFlags.getInt( lp ); + if ( darkmode ) { + value |= bit; + } else { + value &= ~bit; + } + meizuFlags.setInt( lp, value ); + activity.getWindow().setAttributes( lp ); + return true; + } catch ( Exception e ) { + } + return false; + } + + static void setContentTopPadding( Activity activity, int padding ) { + ViewGroup mContentView = activity.getWindow().findViewById( Window.ID_ANDROID_CONTENT ); + mContentView.setPadding( 0, padding, 0, 0 ); + } + + static int getPxFromDp( Context context, float dp ) { + return ( int ) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics() ); + } + + /** + * 设置状态栏颜色 + * + * @param activity + * @param isBlackText true黑色 false 白字 + */ + public static void setStatusBarStyle( Activity activity, boolean isBlackText, boolean isFitSystem ) { + setStatusBarStyle( activity, isBlackText, isBlackText ? Color.WHITE : Color.TRANSPARENT, isFitSystem ); + } + + public static void setStatusBarStyle( Activity activity, boolean isBlackText, int statusBarBgColor, boolean isFitSystem ) { + if ( Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ) { + activity.getWindow().setBackgroundDrawableResource( android.R.color.transparent ); + if ( isBlackText ) { + activity.getWindow().getDecorView().setSystemUiVisibility( ( isFitSystem ? View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN : View.SYSTEM_UI_FLAG_VISIBLE ) | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR ); + } else { + activity.getWindow().getDecorView().setSystemUiVisibility( ( isFitSystem ? View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN : View.SYSTEM_UI_FLAG_VISIBLE ) ); + } + activity.getWindow().setStatusBarColor( statusBarBgColor ); + } + } + + + public static void setMessageFragmentStatus( Activity activity ) { + if ( Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ) { + activity.getWindow().setBackgroundDrawableResource( android.R.color.transparent ); + activity.getWindow().getDecorView().setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR ); + } + } + +} diff --git a/foudations/mogo-utils/src/main/java/com/mogo/utils/statusbar/EyesKitKat.java b/foudations/mogo-utils/src/main/java/com/mogo/utils/statusbar/EyesKitKat.java new file mode 100644 index 0000000000..c922602529 --- /dev/null +++ b/foudations/mogo-utils/src/main/java/com/mogo/utils/statusbar/EyesKitKat.java @@ -0,0 +1,277 @@ +package com.mogo.utils.statusbar; + +import android.annotation.TargetApi; +import android.app.Activity; +import android.content.Context; +import android.os.Build; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; +import android.widget.FrameLayout; +import com.mogo.utils.R; + +@TargetApi( Build.VERSION_CODES.KITKAT ) +class EyesKitKat { + private static final String TAG_FAKE_STATUS_BAR_VIEW = "statusBarView"; + private static final String TAG_MARGIN_ADDED = "marginAdded"; + + static void setStatusBarColor( Activity activity, int statusColor ) { + Window window = activity.getWindow(); + //设置Window为全透明 + window.addFlags( WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS ); + + ViewGroup mContentView = window.findViewById( Window.ID_ANDROID_CONTENT ); + //获取父布局 + View mContentChild = mContentView.getChildAt( 0 ); + //获取状态栏高度 + int statusBarHeight = getStatusBarHeight( activity ); + + //如果已经存在假状态栏则移除,防止重复添加 + removeFakeStatusBarViewIfExist( activity ); + //添加一个View来作为状态栏的填充 + addFakeStatusBarView( activity, statusColor, statusBarHeight ); + //设置子控件到状态栏的间距 + addMarginTopToContentChild( mContentChild, statusBarHeight ); + //不预留系统栏位置 + if ( mContentChild != null ) { + mContentChild.setFitsSystemWindows( false ); + } + //如果在Activity中使用了ActionBar则需要再将布局与状态栏的高度跳高一个ActionBar的高度,否则内容会被ActionBar遮挡 + int action_bar_id = activity.getResources().getIdentifier( "action_bar", "id", activity.getPackageName() ); + View view = activity.findViewById( action_bar_id ); + if ( view != null ) { + TypedValue typedValue = new TypedValue(); + if ( activity.getTheme().resolveAttribute( R.attr.actionBarSize, typedValue, true ) ) { + int actionBarHeight = TypedValue.complexToDimensionPixelSize( typedValue.data, activity.getResources().getDisplayMetrics() ); + Eyes.setContentTopPadding( activity, actionBarHeight ); + } + } + } + + static void translucentStatusBar( Activity activity ) { + Window window = activity.getWindow(); + //设置Window为透明 + window.addFlags( WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS ); + + ViewGroup mContentView = activity.findViewById( Window.ID_ANDROID_CONTENT ); + View mContentChild = mContentView.getChildAt( 0 ); + + //移除已经存在假状态栏则,并且取消它的Margin间距 + removeFakeStatusBarViewIfExist( activity ); + removeMarginTopOfContentChild( mContentChild, getStatusBarHeight( activity ) ); + if ( mContentChild != null ) { + //fitsSystemWindow 为 false, 不预留系统栏位置. + mContentChild.setFitsSystemWindows( false ); + } + } + +// static void setStatusBarColorForCollapsingToolbar( final Activity activity, final AppBarLayout appBarLayout, final CollapsingToolbarLayout collapsingToolbarLayout, +// Toolbar toolbar, int statusColor ) { +// Window window = activity.getWindow(); +// //设置Window为全透明 +// window.addFlags( WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS ); +// ViewGroup mContentView = window.findViewById( Window.ID_ANDROID_CONTENT ); +// +// //AppBarLayout,CollapsingToolbarLayout,ToolBar,ImageView的fitsSystemWindow统一改为false, 不预留系统栏位置. +// View mContentChild = mContentView.getChildAt( 0 ); +// mContentChild.setFitsSystemWindows( false ); +// ( ( View ) appBarLayout.getParent() ).setFitsSystemWindows( false ); +// appBarLayout.setFitsSystemWindows( false ); +// collapsingToolbarLayout.setFitsSystemWindows( false ); +// collapsingToolbarLayout.getChildAt( 0 ).setFitsSystemWindows( false ); +// +// toolbar.setFitsSystemWindows( false ); +// //为Toolbar添加一个状态栏的高度, 同时为Toolbar添加paddingTop,使Toolbar覆盖状态栏,ToolBar的title可以正常显示. +// if ( toolbar.getTag() == null ) { +// CollapsingToolbarLayout.LayoutParams lp = ( CollapsingToolbarLayout.LayoutParams ) toolbar.getLayoutParams(); +// int statusBarHeight = getStatusBarHeight( activity ); +// lp.height += statusBarHeight; +// toolbar.setLayoutParams( lp ); +// toolbar.setPadding( toolbar.getPaddingLeft(), toolbar.getPaddingTop() + statusBarHeight, toolbar.getPaddingRight(), toolbar.getPaddingBottom() ); +// toolbar.setTag( true ); +// } +// //移除已经存在假状态栏则,并且取消它的Margin间距 +// int statusBarHeight = getStatusBarHeight( activity ); +// removeFakeStatusBarViewIfExist( activity ); +// removeMarginTopOfContentChild( mContentChild, statusBarHeight ); +// //添加一个View来作为状态栏的填充 +// final View statusView = addFakeStatusBarView( activity, statusColor, statusBarHeight ); +// +// CoordinatorLayout.Behavior behavior = ( ( CoordinatorLayout.LayoutParams ) appBarLayout.getLayoutParams() ).getBehavior(); +// if ( behavior != null && behavior instanceof AppBarLayout.Behavior ) { +// int verticalOffset = ( ( AppBarLayout.Behavior ) behavior ).getTopAndBottomOffset(); +// if ( Math.abs( verticalOffset ) > appBarLayout.getHeight() - collapsingToolbarLayout.getScrimVisibleHeightTrigger() ) { +// statusView.setAlpha( 1f ); +// } else { +// statusView.setAlpha( 0f ); +// } +// } else { +// statusView.setAlpha( 0f ); +// } +// appBarLayout.addOnOffsetChangedListener( new AppBarLayout.OnOffsetChangedListener() { +// @Override +// public void onOffsetChanged( AppBarLayout appBarLayout, int verticalOffset ) { +// if ( Math.abs( verticalOffset ) > appBarLayout.getHeight() - collapsingToolbarLayout.getScrimVisibleHeightTrigger() ) { +// //toolbar被折叠时显示状态栏 +// if ( statusView.getAlpha() == 0 ) { +// statusView.animate().cancel(); +// statusView.animate().alpha( 1f ).setDuration( collapsingToolbarLayout.getScrimAnimationDuration() ).start(); +// } +// } else { +// //toolbar展开时显示状态栏 +// if ( statusView.getAlpha() == 1 ) { +// statusView.animate().cancel(); +// statusView.animate().alpha( 0f ).setDuration( collapsingToolbarLayout.getScrimAnimationDuration() ).start(); +// } +// } +// } +// } ); +// } +// +// static void setStatusBarWhiteForCollapsingToolbar( final Activity activity, AppBarLayout appBarLayout, final CollapsingToolbarLayout collapsingToolbarLayout, Toolbar toolbar, final int statusBarColor ) { +// final Window window = activity.getWindow(); +// window.addFlags( WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS ); +// +// ViewGroup mContentView = window.findViewById( Window.ID_ANDROID_CONTENT ); +// View mContentChild = mContentView.getChildAt( 0 ); +// mContentChild.setFitsSystemWindows( false ); +// ( ( View ) appBarLayout.getParent() ).setFitsSystemWindows( false ); +// appBarLayout.setFitsSystemWindows( false ); +// collapsingToolbarLayout.setFitsSystemWindows( false ); +// collapsingToolbarLayout.getChildAt( 0 ).setFitsSystemWindows( false ); +// toolbar.setFitsSystemWindows( false ); +// +// if ( toolbar.getTag() == null ) { +// CollapsingToolbarLayout.LayoutParams lp = ( CollapsingToolbarLayout.LayoutParams ) toolbar.getLayoutParams(); +// int statusBarHeight = getStatusBarHeight( activity ); +// lp.height += statusBarHeight; +// toolbar.setLayoutParams( lp ); +// toolbar.setPadding( toolbar.getPaddingLeft(), toolbar.getPaddingTop() + statusBarHeight, toolbar.getPaddingRight(), toolbar.getPaddingBottom() ); +// toolbar.setTag( true ); +// } +// +// int statusBarHeight = getStatusBarHeight( activity ); +// int color = Color.BLACK; +// try { +// Class< ? > layoutParams = Class.forName( "android.view.MiuiWindowManager$LayoutParams" ); +// color = statusBarColor; +// } catch ( ClassNotFoundException e ) { +// e.printStackTrace(); +// } +// try { +// Field darkFlag = WindowManager.LayoutParams.class.getDeclaredField( "MEIZU_FLAG_DARK_STATUS_BAR_ICON" ); +// color = statusBarColor; +// } catch ( NoSuchFieldException e ) { +// e.printStackTrace(); +// } +// final View statusView = addFakeStatusBarView( activity, color, statusBarHeight ); +// CoordinatorLayout.Behavior behavior = ( ( CoordinatorLayout.LayoutParams ) appBarLayout.getLayoutParams() ).getBehavior(); +// if ( behavior != null && behavior instanceof AppBarLayout.Behavior ) { +// int verticalOffset = ( ( AppBarLayout.Behavior ) behavior ).getTopAndBottomOffset(); +// if ( Math.abs( verticalOffset ) > appBarLayout.getHeight() - collapsingToolbarLayout.getScrimVisibleHeightTrigger() ) { +// statusView.setAlpha( 1f ); +// } else { +// statusView.setAlpha( 0f ); +// } +// } else { +// statusView.setAlpha( 0f ); +// } +// +// appBarLayout.addOnOffsetChangedListener( new AppBarLayout.OnOffsetChangedListener() { +// private final static int EXPANDED = 0; +// private final static int COLLAPSED = 1; +// private int appBarLayoutState; +// +// @Override +// public void onOffsetChanged( AppBarLayout appBarLayout, int verticalOffset ) { +// if ( Math.abs( verticalOffset ) >= ( appBarLayout.getTotalScrollRange() - Eyes.getPxFromDp( activity, 56 ) ) ) { +// if ( appBarLayoutState != COLLAPSED ) { +// appBarLayoutState = COLLAPSED; +// +// if ( Eyes.MIUISetStatusBarLightMode( activity, true ) || Eyes.FlymeSetStatusBarLightMode( activity, true ) ) { +// } +// if ( statusView.getAlpha() == 0 ) { +// statusView.animate().cancel(); +// statusView.animate().alpha( 1f ).setDuration( collapsingToolbarLayout.getScrimAnimationDuration() ).start(); +// } +// } +// } else { +// if ( appBarLayoutState != EXPANDED ) { +// appBarLayoutState = EXPANDED; +// +// if ( Eyes.MIUISetStatusBarLightMode( activity, false ) || Eyes.FlymeSetStatusBarLightMode( activity, false ) ) { +// } +// if ( statusView.getAlpha() == 1 ) { +// statusView.animate().cancel(); +// statusView.animate().alpha( 0f ).setDuration( collapsingToolbarLayout.getScrimAnimationDuration() ).start(); +// } +// translucentStatusBar( activity ); +// } +// } +// } +// } ); +// } + + private static void removeFakeStatusBarViewIfExist( Activity activity ) { + Window window = activity.getWindow(); + ViewGroup mDecorView = (ViewGroup) window.getDecorView(); + + View fakeView = mDecorView.findViewWithTag( TAG_FAKE_STATUS_BAR_VIEW ); + if ( fakeView != null ) { + mDecorView.removeView( fakeView ); + } + } + + private static View addFakeStatusBarView( Activity activity, int statusBarColor, int statusBarHeight ) { + Window window = activity.getWindow(); + ViewGroup mDecorView = (ViewGroup) window.getDecorView(); + + View mStatusBarView = new View( activity ); + FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, statusBarHeight ); + layoutParams.gravity = Gravity.TOP; + mStatusBarView.setLayoutParams( layoutParams ); + mStatusBarView.setBackgroundColor( statusBarColor ); + mStatusBarView.setTag( TAG_FAKE_STATUS_BAR_VIEW ); + + mDecorView.addView( mStatusBarView ); + return mStatusBarView; + } + + private static void addMarginTopToContentChild( View mContentChild, int statusBarHeight ) { + if ( mContentChild == null ) { + return; + } + if ( !TAG_MARGIN_ADDED.equals( mContentChild.getTag() ) ) { + FrameLayout.LayoutParams lp = ( FrameLayout.LayoutParams ) mContentChild.getLayoutParams(); + lp.topMargin += statusBarHeight; + mContentChild.setLayoutParams( lp ); + mContentChild.setTag( TAG_MARGIN_ADDED ); + } + } + + private static int getStatusBarHeight( Context context ) { + int result = 0; + int resId = context.getResources().getIdentifier( "status_bar_height", "dimen", "android" ); + if ( resId > 0 ) { + result = context.getResources().getDimensionPixelOffset( resId ); + } + return result; + } + + private static void removeMarginTopOfContentChild( View mContentChild, int statusBarHeight ) { + if ( mContentChild == null ) { + return; + } + if ( TAG_MARGIN_ADDED.equals( mContentChild.getTag() ) ) { + FrameLayout.LayoutParams lp = ( FrameLayout.LayoutParams ) mContentChild.getLayoutParams(); + lp.topMargin -= statusBarHeight; + mContentChild.setLayoutParams( lp ); + mContentChild.setTag( null ); + } + } + + +} diff --git a/foudations/mogo-utils/src/main/java/com/mogo/utils/statusbar/EyesLollipop.java b/foudations/mogo-utils/src/main/java/com/mogo/utils/statusbar/EyesLollipop.java new file mode 100644 index 0000000000..f7426867ca --- /dev/null +++ b/foudations/mogo-utils/src/main/java/com/mogo/utils/statusbar/EyesLollipop.java @@ -0,0 +1,219 @@ +package com.mogo.utils.statusbar; + + +import android.annotation.TargetApi; +import android.app.Activity; +import android.content.Context; +import android.graphics.Color; +import android.os.Build; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; +import androidx.core.view.ViewCompat; + +@TargetApi(Build.VERSION_CODES.LOLLIPOP) +class EyesLollipop { + + static void setStatusBarColor(Activity activity, int statusColor) { + Window window = activity.getWindow(); + //取消状态栏透明 + window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + //添加Flag把状态栏设为可绘制模式 + window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + //设置状态栏颜色 + window.setStatusBarColor(statusColor); + //设置系统状态栏处于可见状态 + window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); + //让view不根据系统窗口来调整自己的布局 + ViewGroup mContentView = window.findViewById(Window.ID_ANDROID_CONTENT); + View mChildView = mContentView.getChildAt(0); + if (mChildView != null) { + mChildView.setFitsSystemWindows(false); + ViewCompat.requestApplyInsets(mChildView); + } + } + + static void translucentStatusBar(Activity activity, boolean hideStatusBarBackground) { + Window window = activity.getWindow(); + //添加Flag把状态栏设为可绘制模式 + window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + if (hideStatusBarBackground) { + //如果为全透明模式,取消设置Window半透明的Flag + window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + //设置状态栏为透明 + window.setStatusBarColor(Color.TRANSPARENT); + //设置window的状态栏不可见 + window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); + } else { + //如果为半透明模式,添加设置Window半透明的Flag + window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + //设置系统状态栏处于可见状态 + window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); + } + //view不根据系统窗口来调整自己的布局 + ViewGroup mContentView = window.findViewById(Window.ID_ANDROID_CONTENT); + View mChildView = mContentView.getChildAt(0); + if (mChildView != null) { + mChildView.setFitsSystemWindows(false); + ViewCompat.requestApplyInsets(mChildView); + } + } + +// static void setStatusBarColorForCollapsingToolbar(final Activity activity, final AppBarLayout appBarLayout, final CollapsingToolbarLayout collapsingToolbarLayout, +// Toolbar toolbar, final int statusColor) { +// final Window window = activity.getWindow(); +// //取消设置Window半透明的Flag +// window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); +// ////添加Flag把状态栏设为可绘制模式 +// window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); +// //设置状态栏为透明 +// window.setStatusBarColor(Color.TRANSPARENT); +// //设置系统状态栏处于可见状态 +// window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); +// //通过OnApplyWindowInsetsListener()使Layout在绘制过程中将View向下偏移了,使collapsingToolbarLayout可以占据状态栏 +// ViewCompat.setOnApplyWindowInsetsListener(collapsingToolbarLayout, new OnApplyWindowInsetsListener() { +// @Override +// public WindowInsetsCompat onApplyWindowInsets(View v, WindowInsetsCompat insets) { +// return insets; +// } +// }); +// +// ViewGroup mContentView = window.findViewById(Window.ID_ANDROID_CONTENT); +// View mChildView = mContentView.getChildAt(0); +// //view不根据系统窗口来调整自己的布局 +// if (mChildView != null) { +// mChildView.setFitsSystemWindows(false); +// ViewCompat.requestApplyInsets(mChildView); +// } +// +// ((View) appBarLayout.getParent()).setFitsSystemWindows(false); +// appBarLayout.setFitsSystemWindows(false); +// collapsingToolbarLayout.setFitsSystemWindows(false); +// collapsingToolbarLayout.getChildAt(0).setFitsSystemWindows(false); +// //设置状态栏的颜色 +// collapsingToolbarLayout.setStatusBarScrimColor(statusColor); +// toolbar.setFitsSystemWindows(false); +// //为Toolbar添加一个状态栏的高度, 同时为Toolbar添加paddingTop,使Toolbar覆盖状态栏,ToolBar的title可以正常显示. +// if (toolbar.getTag() == null) { +// CollapsingToolbarLayout.LayoutParams lp = (CollapsingToolbarLayout.LayoutParams) toolbar.getLayoutParams(); +// int statusBarHeight = getStatusBarHeight(activity); +// lp.height += statusBarHeight; +// toolbar.setLayoutParams(lp); +// toolbar.setPadding(toolbar.getPaddingLeft(), toolbar.getPaddingTop() + statusBarHeight, toolbar.getPaddingRight(), toolbar.getPaddingBottom()); +// toolbar.setTag(true); +// } +// +// appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() { +// private final static int EXPANDED = 0; +// private final static int COLLAPSED = 1; +// private int appBarLayoutState; +// +// @Override +// public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { +// //toolbar被折叠时显示状态栏 +// if (Math.abs(verticalOffset) > collapsingToolbarLayout.getScrimVisibleHeightTrigger()) { +// if (appBarLayoutState != COLLAPSED) { +// appBarLayoutState = COLLAPSED;//修改状态标记为折叠 +// setStatusBarColor(activity, statusColor); +// } +// } else { +// //toolbar显示时同时显示状态栏 +// if (appBarLayoutState != EXPANDED) { +// appBarLayoutState = EXPANDED;//修改状态标记为展开 +// translucentStatusBar(activity, true); +// } +// } +// } +// }); +// } +// +// static void setStatusBarWhiteForCollapsingToolbar(final Activity activity, final AppBarLayout appBarLayout, final CollapsingToolbarLayout collapsingToolbarLayout, final Toolbar toolbar, final int statusBarColor) { +// final Window window = activity.getWindow(); +// window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); +// window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); +// window.setStatusBarColor(Color.TRANSPARENT); +// window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); +// +// ViewCompat.setOnApplyWindowInsetsListener(collapsingToolbarLayout, new OnApplyWindowInsetsListener() { +// @Override +// public WindowInsetsCompat onApplyWindowInsets(View v, WindowInsetsCompat insets) { +// return insets; +// } +// }); +// +// ViewGroup mContentView = window.findViewById(Window.ID_ANDROID_CONTENT); +// View mChildView = mContentView.getChildAt(0); +// if (mChildView != null) { +// mChildView.setFitsSystemWindows(false); +// ViewCompat.requestApplyInsets(mChildView); +// } +// +// ((View) appBarLayout.getParent()).setFitsSystemWindows(false); +// appBarLayout.setFitsSystemWindows(false); +// toolbar.setFitsSystemWindows(false); +// if (toolbar.getTag() == null) { +// CollapsingToolbarLayout.LayoutParams lp = (CollapsingToolbarLayout.LayoutParams) toolbar.getLayoutParams(); +// int statusBarHeight = getStatusBarHeight(activity); +// lp.height += statusBarHeight; +// toolbar.setLayoutParams(lp); +// toolbar.setPadding(toolbar.getPaddingLeft(), toolbar.getPaddingTop() + statusBarHeight, toolbar.getPaddingRight(), toolbar.getPaddingBottom()); +// toolbar.setTag(true); +// } +// +// collapsingToolbarLayout.setFitsSystemWindows(false); +// collapsingToolbarLayout.getChildAt(0).setFitsSystemWindows(false); +// collapsingToolbarLayout.setStatusBarScrimColor(statusBarColor); +// appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() { +// private final static int EXPANDED = 0; +// private final static int COLLAPSED = 1; +// private int appBarLayoutState; +// +// @Override +// public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { +// //toolbar被折叠时显示状态栏 +// if (Math.abs(verticalOffset) > collapsingToolbarLayout.getScrimVisibleHeightTrigger()) { +// if (appBarLayoutState != COLLAPSED) { +// appBarLayoutState = COLLAPSED;//修改状态标记为折叠 +// +// //先判断是否为小米设备,设置状态栏不成功判断是否为6.0以上设备,不是6.0以上设备再判断是否为魅族设备,不是魅族设备就只设置状态栏颜色 +// if (Eyes.MIUISetStatusBarLightMode(activity, true)) { +// return; +// } +// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { +// activity.getWindow().setBackgroundDrawableResource(android.R.color.transparent); +// activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); +// activity.getWindow().setStatusBarColor(statusBarColor); +// } else if (!Eyes.FlymeSetStatusBarLightMode(activity, true)) { +// setStatusBarColor(activity, statusBarColor); +// } +// } +// } else { +// //toolbar显示时同时显示状态栏 +// if (appBarLayoutState != EXPANDED) { +// appBarLayoutState = EXPANDED;//修改状态标记为展开 +// +// if (Eyes.MIUISetStatusBarLightMode(activity, false)) { +// translucentStatusBar(activity, true); +// return; +// } +// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { +// activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE); +// } else if (Eyes.FlymeSetStatusBarLightMode(activity, true)) { +// } +// translucentStatusBar(activity, true); +// } +// } +// } +// }); +// } + + private static int getStatusBarHeight(Context context) { + int result = 0; + int resId = context.getResources().getIdentifier("status_bar_height", "dimen", "android"); + if (resId > 0) { + result = context.getResources().getDimensionPixelOffset(resId); + } + return result; + } +} diff --git a/libraries/map-amap/build.gradle b/libraries/map-amap/build.gradle index ae38f90032..b70d651de7 100644 --- a/libraries/map-amap/build.gradle +++ b/libraries/map-amap/build.gradle @@ -26,9 +26,9 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation rootProject.ext.dependencies.androidxappcompat - implementation rootProject.ext.dependencies.amapnavi3dmap - implementation rootProject.ext.dependencies.amapsearch - implementation rootProject.ext.dependencies.amaplocation + api rootProject.ext.dependencies.amapnavi3dmap + api rootProject.ext.dependencies.amapsearch + api rootProject.ext.dependencies.amaplocation if (Boolean.valueOf(RELEASE)) { implementation rootProject.ext.dependencies.mogoutils diff --git a/modules/mogo-module-common/src/main/java/com/mogo/module/common/TextWatcherAdapter.java b/modules/mogo-module-common/src/main/java/com/mogo/module/common/TextWatcherAdapter.java new file mode 100644 index 0000000000..469b5f538d --- /dev/null +++ b/modules/mogo-module-common/src/main/java/com/mogo/module/common/TextWatcherAdapter.java @@ -0,0 +1,28 @@ +package com.mogo.module.common; + +import android.text.Editable; +import android.text.TextWatcher; + +/** + * @author congtaowang + * @since 2019-10-02 + *
+ * 描述 + */ +public class TextWatcherAdapter implements TextWatcher { + + @Override + public void beforeTextChanged( CharSequence s, int start, int count, int after ) { + + } + + @Override + public void onTextChanged( CharSequence s, int start, int before, int count ) { + + } + + @Override + public void afterTextChanged( Editable s ) { + + } +} diff --git a/modules/mogo-module-map/build.gradle b/modules/mogo-module-map/build.gradle index d6c47f5377..e412f0b9f2 100644 --- a/modules/mogo-module-map/build.gradle +++ b/modules/mogo-module-map/build.gradle @@ -36,16 +36,16 @@ dependencies { implementation rootProject.ext.dependencies.arouter annotationProcessor rootProject.ext.dependencies.aroutercompiler if (Boolean.valueOf(RELEASE)) { - implementation rootProject.ext.dependencies.mogomap - implementation rootProject.ext.dependencies.mogomapapi - implementation rootProject.ext.dependencies.mogoutils + api rootProject.ext.dependencies.mogomap + api rootProject.ext.dependencies.mogomapapi + api rootProject.ext.dependencies.mogoutils api rootProject.ext.dependencies.mogocommons api rootProject.ext.dependencies.mogoserviceapi implementation rootProject.ext.dependencies.modulecommon } else { - implementation project(":libraries:mogo-map") - implementation project(":libraries:mogo-map-api") - implementation project(":foudations:mogo-utils") + api project(":libraries:mogo-map") + api project(":libraries:mogo-map-api") + api project(":foudations:mogo-utils") api project(":foudations:mogo-commons") api project(':services:mogo-service-api') implementation project(':modules:mogo-module-common') diff --git a/modules/mogo-module-map/src/main/java/com/mogo/module/map/location/AMapLocationManager.java b/modules/mogo-module-map/src/main/java/com/mogo/module/map/location/AMapLocationManager.java new file mode 100644 index 0000000000..2aeee6ba15 --- /dev/null +++ b/modules/mogo-module-map/src/main/java/com/mogo/module/map/location/AMapLocationManager.java @@ -0,0 +1,131 @@ +package com.mogo.module.map.location; + +import android.content.Context; +import android.util.Log; +import com.amap.api.location.AMapLocation; +import com.amap.api.location.AMapLocationClient; +import com.amap.api.location.AMapLocationClientOption; +import com.amap.api.location.AMapLocationListener; +import com.amap.api.maps.model.LatLng; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +public class AMapLocationManager { + + private static final String TAG = "AMapLocationManager"; + + private static final Set< AMapLocationListener > mLocationChangeListeners = new HashSet<>(); + private static final InternalLocationListener mInternalLocationListener = new InternalLocationListener(); + + private AMapLocationClient mLocationClient; + + private static AMapLocation sLastKnowLocation = null; + + private static volatile AMapLocationManager sInstance; + + public static AMapLocationManager getInstance( Context context ) { + if ( sInstance == null ) { + synchronized ( AMapLocationManager.class ) { + if ( sInstance == null ) { + sInstance = new AMapLocationManager( context ); + } + } + } + return sInstance; + } + + public synchronized void release() { + stop(); + mLocationChangeListeners.clear(); + mLocationClient = null; + sLastKnowLocation = null; + sInstance = null; + } + + private AMapLocationManager( Context context ) { + if ( context == null ) { + throw new NullPointerException( "context can't be null." ); + } + mLocationClient = new AMapLocationClient( context.getApplicationContext() ); + mLocationClient.setLocationListener( mInternalLocationListener ); + } + + private void setLocationOptions( long locateInterval ) { + AMapLocationClientOption option = new AMapLocationClientOption(); + option.setLocationMode( AMapLocationClientOption.AMapLocationMode.Hight_Accuracy ); + option.setNeedAddress( true ); + option.setInterval( locateInterval ); + if ( mLocationClient != null ) { + mLocationClient.setLocationOption( option ); + } + } + + public synchronized void start() { + start( 2000L ); + } + + public synchronized void start( long locateInterval ) { + if ( mLocationClient != null && mLocationClient.isStarted() ) { + stop(); + } + setLocationOptions( locateInterval ); + mLocationClient.startLocation(); + Log.d( TAG, "start location, location interval is " + locateInterval ); + } + + public synchronized void stop() { + if ( mLocationClient != null ) { + mLocationClient.stopLocation(); + } + Log.d( TAG, "stop location" ); + } + + public static AMapLocation getAMapLastKnowLocation() { + return sLastKnowLocation; + } + + public static LatLng getLastKnowPoint() { + final AMapLocation location = getAMapLastKnowLocation(); + if ( location != null ) { + return new LatLng( location.getLatitude(), location.getLongitude() ); + } + return null; + } + + public void addLocationListener( AMapLocationListener listener ) { + if ( listener != null ) { + synchronized ( mLocationChangeListeners ) { + mLocationChangeListeners.add( listener ); + } + } + } + + public void removeLocationListener( AMapLocationListener listener ) { + synchronized ( mLocationChangeListeners ) { + mLocationChangeListeners.remove( listener ); + } + } + + /** + * 定位SDK监听函数 + */ + private static class InternalLocationListener implements AMapLocationListener { + @Override + public void onLocationChanged( AMapLocation aMapLocation ) { + if ( aMapLocation == null || + aMapLocation.getLatitude() == 0.0D || + aMapLocation.getLongitude() == 0.0D ) { + return; + } + sLastKnowLocation = aMapLocation.clone(); + synchronized ( mLocationChangeListeners ) { + Iterator iterator = mLocationChangeListeners.iterator(); + while ( iterator.hasNext() ) { + AMapLocationListener listener = ( AMapLocationListener ) iterator.next(); + listener.onLocationChanged( sLastKnowLocation ); + } + } + } + } +} \ No newline at end of file diff --git a/modules/mogo-module-map/src/main/java/com/mogo/module/map/location/LocationUtils.java b/modules/mogo-module-map/src/main/java/com/mogo/module/map/location/LocationUtils.java new file mode 100644 index 0000000000..f989358fa4 --- /dev/null +++ b/modules/mogo-module-map/src/main/java/com/mogo/module/map/location/LocationUtils.java @@ -0,0 +1,29 @@ +package com.mogo.module.map.location; + +/** + * @author congtaowang + * @since 2019-09-27 + *
+ * 描述 + */ +public class LocationUtils { + + public static float bearing( double lat1, double lon1, double lat2, double lon2 ) { + + double longitude1 = lon1; + double longitude2 = lon2; + double latitude1 = Math.toRadians( lat1 ); + double latitude2 = Math.toRadians( lat2 ); + double longDiff = Math.toRadians( longitude2 - longitude1 ); + double y = Math.sin( longDiff ) * Math.cos( latitude2 ); + double x = Math.cos( latitude1 ) * Math.sin( latitude2 ) - Math.sin( latitude1 ) * Math.cos( latitude2 ) * Math + .cos( longDiff ); + + double result = ( Math.toDegrees( Math.atan2( y, x ) ) + 360 ) % 360; + if ( ( ( int ) result ) == ( ( int ) ( result + 0.5 ) ) ) { + return ( ( int ) result ); + } else { + return ( ( int ) result ) + 0.5f; + } + } +} diff --git a/modules/mogo-module-map/src/main/java/com/mogo/module/map/location/MyLocationUtils.java b/modules/mogo-module-map/src/main/java/com/mogo/module/map/location/MyLocationUtils.java new file mode 100644 index 0000000000..51118e107c --- /dev/null +++ b/modules/mogo-module-map/src/main/java/com/mogo/module/map/location/MyLocationUtils.java @@ -0,0 +1,53 @@ +package com.mogo.module.map.location; + +import com.amap.api.maps.model.MyLocationStyle; + +/** + * @author congtaowang + * @since 2019-10-17 + *
+ * 描述 + */ +public class MyLocationUtils { + + public static final long INTERVAL_FAST_SPEED = 2_000L; + public static final long INTERVAL_MIDDLE_SPEED = 2_000L; + public static final long INTERVAL_SLOW_SPEED = 10_000L; + + /** + * 前台快速定位 + * + * @return + */ + public static MyLocationStyle wrapperAsFast( MyLocationStyle style ) { + if ( style != null ) { + style.interval( INTERVAL_FAST_SPEED ); + } + return style; + } + + /** + * 后台慢速定位 + * + * @return + */ + public static MyLocationStyle wrapperAsMiddleSpeed( MyLocationStyle style ) { + if ( style != null ) { + style.interval( INTERVAL_MIDDLE_SPEED ); + } + return style; + } + + /** + * 后台慢速定位 + * + * @return + */ + public static MyLocationStyle wrapperAsSlow( MyLocationStyle style ) { + if ( style != null ) { + style.interval( INTERVAL_SLOW_SPEED ); + } + return style; + } + +} diff --git a/modules/mogo-module-navi/build.gradle b/modules/mogo-module-navi/build.gradle index bf3cdf338b..315cd98809 100644 --- a/modules/mogo-module-navi/build.gradle +++ b/modules/mogo-module-navi/build.gradle @@ -27,6 +27,11 @@ android { proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } } dependencies { @@ -38,8 +43,13 @@ dependencies { implementation rootProject.ext.dependencies.room annotationProcessor rootProject.ext.dependencies.roomAnnotationProcessor implementation rootProject.ext.dependencies.roomRxjava + implementation rootProject.ext.dependencies.androidxrecyclerview annotationProcessor rootProject.ext.dependencies.aroutercompiler implementation rootProject.ext.dependencies.jetbrainsannotationsjava5 + implementation rootProject.ext.dependencies.rxandroid +// api project(path: ':modules:mogo-module-common') +// api project(path: ':foudations:mogo-utils') +// api project(path: ':modules:mogo-module-map') if( Boolean.valueOf(RELEASE) ){ implementation rootProject.ext.dependencies.mogomap @@ -55,7 +65,7 @@ dependencies { implementation project(":foudations:mogo-utils") api project(":foudations:mogo-commons") api project(':services:mogo-service-api') - implementation project(':modules:mogo-module-common') + api project(':modules:mogo-module-common') implementation project(':modules:mogo-module-map') } } diff --git a/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/bean/EntityConvertUtils.java b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/bean/EntityConvertUtils.java new file mode 100644 index 0000000000..6254ab5068 --- /dev/null +++ b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/bean/EntityConvertUtils.java @@ -0,0 +1,95 @@ +package com.mogo.module.navi.bean; + +import com.amap.api.location.AMapLocation; +import com.amap.api.maps.model.CameraPosition; +import com.amap.api.services.core.LatLonPoint; +import com.amap.api.services.geocoder.RegeocodeAddress; +import com.amap.api.services.help.Tip; +import java.util.ArrayList; +import java.util.List; + +/** + * @author congtaowang + * @since 2019-10-02 + *
+ * 实体类操作工具 + */ +public class EntityConvertUtils { + + public static List< Tip > pois2Tips( List< SearchPoi > datums ) { + final List< Tip > output = new ArrayList<>(); + if ( datums == null || datums.isEmpty() ) { + return output; + } + for ( SearchPoi poi : datums ) { + Tip tip = poi2Tip( poi ); + if ( tip != null ) { + output.add( tip ); + } + } + return output; + } + + public static Tip poi2Tip( SearchPoi poi ) { + if ( poi == null ) { + return null; + } + Tip tip = new Tip(); + tip.setID( poi.pId ); + tip.setAdcode( poi.getAdCode() ); + tip.setAddress( poi.getAddress() ); + tip.setDistrict( poi.getDistrict() ); + tip.setName( poi.getName() ); + tip.setTypeCode( poi.getTypeCode() ); + tip.setPostion( new LatLonPoint( poi.getLat(), poi.getLng() ) ); + return tip; + } + + public static SearchPoi tipToPoi( Tip tip ) { + if ( tip == null ) { + return null; + } + double lat = 0.0; + double lng = 0.0; + if ( tip.getPoint() != null ) { + lat = tip.getPoint().getLatitude(); + lng = tip.getPoint().getLongitude(); + } + return new SearchPoi( tip.getPoiID(), + tip.getName(), + tip.getAddress(), + lat, + lng, + tip.getDistrict(), + tip.getAdcode(), + tip.getTypeCode() ); + } + + public static SearchPoi aMapLocation2Poi( AMapLocation location ) { + if ( location == null || location.getErrorCode() != AMapLocation.LOCATION_SUCCESS ) { + return null; + } + return new SearchPoi( System.currentTimeMillis() + "", + location.getPoiName(), + location.getAddress(), + location.getLatitude(), + location.getLongitude(), + location.getDistrict(), + location.getAdCode(), + location.getCoordType() ); + } + + public static SearchPoi geocodeAddress2Poi( RegeocodeAddress address, CameraPosition position ) { + if ( address == null || position == null ) { + return null; + } + return new SearchPoi( System.currentTimeMillis() + "", + address.getFormatAddress(), + address.getFormatAddress(), + position.target.latitude, + position.target.longitude, + address.getDistrict(), + address.getAdCode(), + "" ); + } +} diff --git a/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/bean/SearchPoi.java b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/bean/SearchPoi.java new file mode 100644 index 0000000000..7226cbcc11 --- /dev/null +++ b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/bean/SearchPoi.java @@ -0,0 +1,236 @@ +package com.mogo.module.navi.bean; + +import android.os.Parcel; +import android.os.Parcelable; +import androidx.annotation.NonNull; +import androidx.room.Entity; +import androidx.room.PrimaryKey; +import com.mogo.module.navi.constants.DataConstants; + +/** + * @author congtaowang + * @since 2019-10-02 + *
+ * 搜索地址表数据结构 + */ +@Entity( tableName = DataConstants.T_SEARCH_POI ) +public class SearchPoi implements Parcelable { + + public static final SearchPoi NULL = new SearchPoi( null, + null, + null, + 0.0, + 0.0, + null, + null, + null ); + + @PrimaryKey + @NonNull + public String pId; + private String name; + private String address; + private double lat; + private double lng; + private String district; + private String adCode; + private String typeCode; + private String province; + private String city; + + + /** + * 插入poi数据类型 + *
+ * {@link DataConstants#TYPE_COMPANY_ADDRESS} + * {@link DataConstants#TYPE_HOME_ADDRESS} + * {@link DataConstants#TYPE_POI} + */ + private int type; + + /** + * 数据记录时间,自动赋值 + */ + private long time; + + public SearchPoi( String pId, + String name, + String address, + double lat, + double lng, + String district, + String adCode, + String typeCode ) { + this( pId, name, address, lat, lng, district, adCode, typeCode, "", "", DataConstants.TYPE_POI ); + } + + private SearchPoi( String pId, + String name, + String address, + double lat, + double lng, + String district, + String adCode, + String typeCode, + String province, + String city, + int type ) { + this.pId = pId; + this.name = name; + this.address = address; + this.lat = lat; + this.lng = lng; + this.district = district; + this.adCode = adCode; + this.typeCode = typeCode; + this.province = province; + this.city = city; + this.type = type; + this.time = System.currentTimeMillis(); + } + + @NonNull + public String getpId() { + return pId; + } + + public void setpId( @NonNull String pId ) { + this.pId = pId; + } + + public String getName() { + return name; + } + + public void setName( String name ) { + this.name = name; + } + + public String getAddress() { + return address; + } + + public void setAddress( String address ) { + this.address = address; + } + + public double getLat() { + return lat; + } + + public void setLat( double lat ) { + this.lat = lat; + } + + public double getLng() { + return lng; + } + + public void setLng( double lng ) { + this.lng = lng; + } + + public String getDistrict() { + return district; + } + + public void setDistrict( String district ) { + this.district = district; + } + + public String getAdCode() { + return adCode; + } + + public void setAdCode( String adCode ) { + this.adCode = adCode; + } + + public String getTypeCode() { + return typeCode; + } + + public void setTypeCode( String typeCode ) { + this.typeCode = typeCode; + } + + public String getProvince() { + return province; + } + + public void setProvince( String province ) { + this.province = province; + } + + public String getCity() { + return city; + } + + public void setCity( String city ) { + this.city = city; + } + + public int getType() { + return type; + } + + public void setType( int type ) { + this.type = type; + } + + public long getTime() { + return time; + } + + public void setTime( long time ) { + this.time = time; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel( Parcel dest, int flags ) { + dest.writeString( this.pId ); + dest.writeString( this.name ); + dest.writeString( this.address ); + dest.writeDouble( this.lat ); + dest.writeDouble( this.lng ); + dest.writeString( this.district ); + dest.writeString( this.adCode ); + dest.writeString( this.typeCode ); + dest.writeString( this.province ); + dest.writeString( this.city ); + dest.writeInt( this.type ); + dest.writeLong( this.time ); + } + + protected SearchPoi( Parcel in ) { + this.pId = in.readString(); + this.name = in.readString(); + this.address = in.readString(); + this.lat = in.readDouble(); + this.lng = in.readDouble(); + this.district = in.readString(); + this.adCode = in.readString(); + this.typeCode = in.readString(); + this.province = in.readString(); + this.city = in.readString(); + this.type = in.readInt(); + this.time = in.readLong(); + } + + public static final Creator< SearchPoi > CREATOR = new Creator< SearchPoi >() { + @Override + public SearchPoi createFromParcel( Parcel source ) { + return new SearchPoi( source ); + } + + @Override + public SearchPoi[] newArray( int size ) { + return new SearchPoi[size]; + } + }; +} diff --git a/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/constants/AMapConstants.java b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/constants/AMapConstants.java new file mode 100644 index 0000000000..3b056b4c6c --- /dev/null +++ b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/constants/AMapConstants.java @@ -0,0 +1,29 @@ +package com.mogo.module.navi.constants; + +import com.amap.api.navi.enums.PathPlanningStrategy; + +/** + * @author congtaowang + * @since 2019-10-04 + *
+ * 地图基本参数配置 + */ +public class AMapConstants { + + /** + * 初始化地图缩放级别 + */ + public static final float AMAP_ZOOM_COMMON_LEVEL = 15.0f; + + /** + * 点击当前位置按钮的地图缩放级别 + */ + public static final float AMAP_ZOOM_CURRENT_LOCATION_LEVEL = AMAP_ZOOM_COMMON_LEVEL; + + public static final float AMPA_BEARING = 0.0f; + + public static final int DEFAULT_ROUTE_STRATEGY = PathPlanningStrategy.DRIVING_MULTIPLE_ROUTES_DEFAULT; + + public static final float AMAP_ROUTE_OVERLAY_TRANSPARENCY_SELECTED = 1f; + public static final float AMAP_ROUTE_OVERLAY_TRANSPARENCY_UNSELECTED = 0.3f; +} diff --git a/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/constants/CustomMapStyle.java b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/constants/CustomMapStyle.java new file mode 100644 index 0000000000..d23454c140 --- /dev/null +++ b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/constants/CustomMapStyle.java @@ -0,0 +1,16 @@ +package com.mogo.module.navi.constants; + +/** + * @author congtaowang + * @since 2019-12-12 + *
+ * 自定义地图样式 + */ +public class CustomMapStyle { + + public static final String STYLE_ID = "e3e33a3423230b219494b40c4d71d93a"; + + public static final String ASSET_STYLE_DATA = "style.data"; + + public static final String ASSET_STYLE_EXTRA_DATA = "style_extra.data"; +} diff --git a/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/constants/DataConstants.java b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/constants/DataConstants.java new file mode 100644 index 0000000000..a0dc988880 --- /dev/null +++ b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/constants/DataConstants.java @@ -0,0 +1,45 @@ +package com.mogo.module.navi.constants; + +import android.net.Uri; + +/** + * @author zyz + * @since 2019-10-02 + *
+ * 描述 + */ +public class DataConstants { + + public static final int DB_VERSION = 1; + public static final String DB_NAME = "zhidao.amap.db"; + + public static final String T_SEARCH_POI = "t_search_poi"; + + public static final int TYPE_POI = 0; // 普通搜索的类型 + public static final int TYPE_HOME_ADDRESS = 1; // 家地址 + public static final int TYPE_COMPANY_ADDRESS = 2; // 公司地址 + + public static final String POI_ID_HOME = "common_address_home"; + public static final String POI_ID_COMPANY = "common_address_company"; + + public static final String CP_AUTHORITY = "com.zhidao.amap"; + + // 家的地址 + public static final Uri CONTENT_HOME_ADDRESS_URI = Uri.parse( "content://com.zhidao.amap/homeAddress" ); + public static final int HOME_ADDRESS_CODE = TYPE_HOME_ADDRESS; + public static final String HOME_ADDRESS_PATH = "homeAddress"; + public static final String HOME_ADDRESS = "homeAddress"; + public static final String HOME_ADDRESS_NAME = "homeAddressName"; + public static final String HOME_ADDRESS_LATITUDE = "homeAddressLatitude"; + public static final String HOME_ADDRESS_LONGITUDE = "homeAddressLongitude"; + + // 公司地址 + public static final Uri CONTENT_COMPANY_ADDRESS_URI = Uri.parse( "content://com.zhidao.amap/companyAddress" ); + public static final int COMPANY_ADDRESS_CODE = TYPE_COMPANY_ADDRESS; + public static final String COMPANY_ADDRESS_PATH = "companyAddress"; + public static final String COMPANY_ADDRESS = "companyAddress"; + public static final String COMPANY_ADDRESS_NAME = "companyAddressName"; + public static final String COMPANY_ADDRESS_LATITUDE = "companyAddressLatitude"; + public static final String COMPANY_ADDRESS_LONGITUDE = "companyAddressLongitude"; + +} diff --git a/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/dao/SearchPoiDao.java b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/dao/SearchPoiDao.java new file mode 100644 index 0000000000..56a799272c --- /dev/null +++ b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/dao/SearchPoiDao.java @@ -0,0 +1,42 @@ +package com.mogo.module.navi.dao; + +import androidx.room.Dao; +import androidx.room.Delete; +import androidx.room.Insert; +import androidx.room.OnConflictStrategy; +import androidx.room.Query; +import com.mogo.module.navi.bean.SearchPoi; +import com.mogo.module.navi.constants.DataConstants; +import io.reactivex.Single; +import java.util.List; + +/** + * @author congtaowang + * @since 2019-10-02 + *
+ * 搜索页面数据操作
+ */
+@Dao
+public interface SearchPoiDao {
+
+ @Insert( onConflict = OnConflictStrategy.REPLACE )
+ List
+ * 描述
+ */
+public interface AMapNaviStatusChangedListener extends AMapNaviListener,
+ AMapNaviViewListener,
+ AMap.OnCameraChangeListener {
+
+ void onNaviInfoUpdate(NaviInfoWrapper wrapper);
+}
diff --git a/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/lib/AMapNaviStatusChangedListenerDefault.java b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/lib/AMapNaviStatusChangedListenerDefault.java
new file mode 100644
index 0000000000..90eaf15fc1
--- /dev/null
+++ b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/lib/AMapNaviStatusChangedListenerDefault.java
@@ -0,0 +1,281 @@
+package com.mogo.module.navi.lib;
+
+import com.amap.api.maps.model.CameraPosition;
+import com.amap.api.navi.model.AMapCalcRouteResult;
+import com.amap.api.navi.model.AMapLaneInfo;
+import com.amap.api.navi.model.AMapModelCross;
+import com.amap.api.navi.model.AMapNaviCameraInfo;
+import com.amap.api.navi.model.AMapNaviCross;
+import com.amap.api.navi.model.AMapNaviInfo;
+import com.amap.api.navi.model.AMapNaviLocation;
+import com.amap.api.navi.model.AMapNaviRouteNotifyData;
+import com.amap.api.navi.model.AMapNaviTrafficFacilityInfo;
+import com.amap.api.navi.model.AMapServiceAreaInfo;
+import com.amap.api.navi.model.AimLessModeCongestionInfo;
+import com.amap.api.navi.model.AimLessModeStat;
+import com.amap.api.navi.model.NaviInfo;
+import com.autonavi.tbt.TrafficFacilityInfo;
+import com.mogo.module.navi.database.wrapper.NaviInfoWrapper;
+
+/**
+ * @author congtaowang
+ * @since 2019-10-01
+ *
+ */
+public abstract class AMapNaviStatusChangedListenerDefault implements AMapNaviStatusChangedListener {
+
+ @Override
+ public void onNaviInfoUpdate( NaviInfoWrapper wrapper ) {
+
+ }
+
+ @Override
+ public void onCameraChange( CameraPosition cameraPosition ) {
+
+ }
+
+ @Override
+ public void onCameraChangeFinish( CameraPosition cameraPosition ) {
+
+ }
+
+ @Override
+ public void onInitNaviFailure() {
+
+ }
+
+ @Override
+ public void onInitNaviSuccess() {
+
+ }
+
+ @Override
+ public void onStartNavi( int i ) {
+
+ }
+
+ @Override
+ public void onTrafficStatusUpdate() {
+
+ }
+
+ @Override
+ public void onLocationChange( AMapNaviLocation aMapNaviLocation ) {
+
+ }
+
+ @Override
+ public void onGetNavigationText( int i, String s ) {
+
+ }
+
+ @Override
+ public void onGetNavigationText( String s ) {
+
+ }
+
+ @Override
+ public void onEndEmulatorNavi() {
+
+ }
+
+ @Override
+ public void onArriveDestination() {
+
+ }
+
+ @Override
+ public void onCalculateRouteFailure( int i ) {
+
+ }
+
+ @Override
+ public void onReCalculateRouteForYaw() {
+
+ }
+
+ @Override
+ public void onReCalculateRouteForTrafficJam() {
+
+ }
+
+ @Override
+ public void onArrivedWayPoint( int i ) {
+
+ }
+
+ @Override
+ public void onGpsOpenStatus( boolean b ) {
+
+ }
+
+ @Override
+ public void onNaviInfoUpdate( NaviInfo naviInfo ) {
+
+ }
+
+ @Override
+ public void onNaviInfoUpdated( AMapNaviInfo aMapNaviInfo ) {
+
+ }
+
+ @Override
+ public void updateCameraInfo( AMapNaviCameraInfo[] aMapNaviCameraInfos ) {
+
+ }
+
+ @Override
+ public void updateIntervalCameraInfo( AMapNaviCameraInfo aMapNaviCameraInfo, AMapNaviCameraInfo aMapNaviCameraInfo1, int i ) {
+
+ }
+
+ @Override
+ public void onServiceAreaUpdate( AMapServiceAreaInfo[] aMapServiceAreaInfos ) {
+
+ }
+
+ @Override
+ public void showCross( AMapNaviCross aMapNaviCross ) {
+
+ }
+
+ @Override
+ public void hideCross() {
+
+ }
+
+ @Override
+ public void showModeCross( AMapModelCross aMapModelCross ) {
+
+ }
+
+ @Override
+ public void hideModeCross() {
+
+ }
+
+ @Override
+ public void showLaneInfo( AMapLaneInfo[] aMapLaneInfos, byte[] bytes, byte[] bytes1 ) {
+
+ }
+
+ @Override
+ public void showLaneInfo( AMapLaneInfo aMapLaneInfo ) {
+
+ }
+
+ @Override
+ public void hideLaneInfo() {
+
+ }
+
+ @Override
+ public void onCalculateRouteSuccess( int[] ints ) {
+
+ }
+
+ @Override
+ public void notifyParallelRoad( int i ) {
+
+ }
+
+ @Override
+ public void OnUpdateTrafficFacility( AMapNaviTrafficFacilityInfo aMapNaviTrafficFacilityInfo ) {
+
+ }
+
+ @Override
+ public void OnUpdateTrafficFacility( AMapNaviTrafficFacilityInfo[] aMapNaviTrafficFacilityInfos ) {
+
+ }
+
+ @Override
+ public void OnUpdateTrafficFacility( TrafficFacilityInfo trafficFacilityInfo ) {
+
+ }
+
+ @Override
+ public void updateAimlessModeStatistics( AimLessModeStat aimLessModeStat ) {
+
+ }
+
+ @Override
+ public void updateAimlessModeCongestionInfo( AimLessModeCongestionInfo aimLessModeCongestionInfo ) {
+
+ }
+
+ @Override
+ public void onPlayRing( int i ) {
+
+ }
+
+ @Override
+ public void onCalculateRouteSuccess( AMapCalcRouteResult aMapCalcRouteResult ) {
+
+ }
+
+ @Override
+ public void onCalculateRouteFailure( AMapCalcRouteResult aMapCalcRouteResult ) {
+
+ }
+
+ @Override
+ public void onNaviRouteNotify( AMapNaviRouteNotifyData aMapNaviRouteNotifyData ) {
+
+ }
+
+ @Override
+ public void onNaviSetting() {
+
+ }
+
+ @Override
+ public void onNaviCancel() {
+
+ }
+
+ @Override
+ public boolean onNaviBackClick() {
+ return false;
+ }
+
+ @Override
+ public void onNaviMapMode( int i ) {
+
+ }
+
+ @Override
+ public void onNaviTurnClick() {
+
+ }
+
+ @Override
+ public void onNextRoadClick() {
+
+ }
+
+ @Override
+ public void onScanViewButtonClick() {
+
+ }
+
+ @Override
+ public void onLockMap( boolean b ) {
+
+ }
+
+ @Override
+ public void onNaviViewLoaded() {
+
+ }
+
+ @Override
+ public void onMapTypeChanged( int i ) {
+
+ }
+
+ @Override
+ public void onNaviViewShowMode( int i ) {
+
+ }
+}
diff --git a/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/ui/adapter/SearchPoiAdapter.java b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/ui/adapter/SearchPoiAdapter.java
new file mode 100644
index 0000000000..18c9f06343
--- /dev/null
+++ b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/ui/adapter/SearchPoiAdapter.java
@@ -0,0 +1,70 @@
+package com.mogo.module.navi.ui.adapter;
+
+import android.content.Context;
+import android.view.View;
+import com.amap.api.services.help.Tip;
+import com.mogo.module.navi.R;
+import com.mogo.module.navi.ui.adapter.base.RecycleBaseAdapter;
+import com.mogo.module.navi.ui.adapter.base.RecycleViewHolder;
+import com.mogo.utils.OnItemClickedListener;
+import java.util.List;
+
+/**
+ * @author zyz
+ * 2019-08-13.
+ */
+public class SearchPoiAdapter extends RecycleBaseAdapter
+ * Title: adapter
+ *
+ * Description:
+ *
+ * Copyright: Copyright (c) 2015
+ *
+ *
+ * 描述
+ */
+public abstract class AMapBaseFragment extends com.mogo.module.navi.database.ui.base.BaseFragment {
+
+ private static final String TAG = "amap.AMapBaseFragment";
+
+ @Override
+ public void onActivityCreated( @Nullable Bundle savedInstanceState ) {
+ super.onActivityCreated( savedInstanceState );
+ initViews();
+ }
+
+ protected abstract void initViews();
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ }
+
+ @Override
+ public void onSaveInstanceState( @NonNull Bundle outState ) {
+ super.onSaveInstanceState( outState );
+ }
+
+ @Override
+ public void onLowMemory() {
+ super.onLowMemory();
+ }
+}
+
diff --git a/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/ui/base/AMapServiceVisitor.java b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/ui/base/AMapServiceVisitor.java
new file mode 100644
index 0000000000..167b80fa83
--- /dev/null
+++ b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/ui/base/AMapServiceVisitor.java
@@ -0,0 +1,48 @@
+package com.mogo.module.navi.ui.base;
+
+import com.amap.api.maps.AMap;
+import com.amap.api.navi.AMapNavi;
+import com.amap.api.navi.AMapNaviView;
+import com.amap.api.navi.model.AMapNaviPath;
+import com.mogo.module.navi.lib.AMapNaviStatusChangedListener;
+
+/**
+ * @author congtaowang
+ * @since 2019-10-01
+ *
+ * 描述
+ */
+public interface AMapServiceVisitor {
+
+ AMapNaviView getNaviView();
+
+ AMap getMap();
+
+ AMapNavi getAMapNavi();
+
+ void registerNaviListener(AMapNaviStatusChangedListener listener);
+
+ /**
+ * 是否正在导航
+ */
+ boolean isNaving();
+
+ void stopNavi();
+
+ void setHost(String host);
+
+ /**
+ * 将导航路线发送给launcher
+ *
+ * @param path
+ */
+ void pushNaviPathToLauncher(AMapNaviPath path);
+
+ /**
+ * 将导航路线发送给launcher
+ *
+ * @param path 导航路线
+ * @param directly 是否直接发送
+ */
+ void pushNaviPathToLauncher(AMapNaviPath path, boolean directly);
+}
\ No newline at end of file
diff --git a/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/ui/base/BaseActivity.java b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/ui/base/BaseActivity.java
new file mode 100644
index 0000000000..907a9685dc
--- /dev/null
+++ b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/ui/base/BaseActivity.java
@@ -0,0 +1,65 @@
+package com.mogo.module.navi.ui.base;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.os.Build;
+import android.os.Bundle;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.WindowManager;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
+import com.mogo.utils.SoftKeyBoardJobber;
+import com.mogo.utils.statusbar.Eyes;
+
+/**
+ * @author congtaowang
+ * @since 2019-10-02
+ *
+ * 地图 activity 基类
+ */
+public class BaseActivity extends AppCompatActivity {
+
+ //@Override
+ //public Context getContext() {
+ // return this;
+ //}
+
+ @Override
+ protected void onCreate( @Nullable Bundle savedInstanceState ) {
+ super.onCreate( savedInstanceState );
+ Eyes.setStatusBarStyle( this, false, Color.parseColor( "#66000000" ), true );
+ getWindow().setSoftInputMode( WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN );
+ hideSystemUI();
+ }
+
+ protected void hideSystemUI() {
+ //隐藏虚拟按键
+ if ( Build.VERSION.SDK_INT > 11 && Build.VERSION.SDK_INT < 19 ) { // lower api
+ View v = this.getWindow().getDecorView();
+ v.setSystemUiVisibility( View.GONE );
+ } else if ( Build.VERSION.SDK_INT >= 19 ) {
+ //for new api versions.
+ View decorView = getWindow().getDecorView();
+ int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+ decorView.setSystemUiVisibility( uiOptions );
+ }
+ }
+
+ protected boolean enableDispatchTouchEventToDismissSoftKeyBoard() {
+ return true;
+ }
+
+ @Override
+ public boolean dispatchTouchEvent( MotionEvent ev ) {
+ if ( ev.getAction() == MotionEvent.ACTION_DOWN && enableDispatchTouchEventToDismissSoftKeyBoard() ) {
+ SoftKeyBoardJobber.hideIfNecessary( this, ev );
+ return super.dispatchTouchEvent( ev );
+ }
+ // 必不可少,否则所有的组件都不会有TouchEvent了
+ if ( getWindow().superDispatchTouchEvent( ev ) ) {
+ return true;
+ }
+ return onTouchEvent( ev );
+ }
+}
diff --git a/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/ui/base/BaseFragment.java b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/ui/base/BaseFragment.java
new file mode 100644
index 0000000000..369cf25c78
--- /dev/null
+++ b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/ui/base/BaseFragment.java
@@ -0,0 +1,73 @@
+package com.mogo.module.navi.ui.base;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Toast;
+import androidx.annotation.IdRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.fragment.app.Fragment;
+import com.mogo.utils.NetworkUtils;
+
+/**
+ * @author congtaowang
+ * @since 2019-10-03
+ *
+ * 描述
+ */
+public abstract class BaseFragment extends Fragment {
+
+ protected Context mContext;
+ private View mRootView;
+
+ @Override
+ public void onAttach( Context context ) {
+ super.onAttach( context );
+ mContext = context;
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView( @NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable
+ Bundle savedInstanceState ) {
+ mRootView = inflater.inflate( getLayoutId(), container, false );
+ return mRootView;
+ }
+
+ protected abstract int getLayoutId();
+
+ protected < T extends View> T findViewById( @IdRes int id ) {
+ if ( mRootView != null ) {
+ return mRootView.findViewById( id );
+ }
+ if ( getView() != null ) {
+ return getView().findViewById( id );
+ }
+ return null;
+ }
+
+ protected void overridePendingTransition( int enter, int exit ) {
+ if ( getActivity() != null ) {
+ getActivity().overridePendingTransition( enter, exit );
+ }
+ }
+
+ protected boolean checkNetwork() {
+ return NetworkUtils.isConnected( mContext );
+ }
+
+ protected void shortToast( CharSequence msg ) {
+ if ( mContext != null && msg != null ) {
+ Toast.makeText( mContext, msg, Toast.LENGTH_SHORT ).show();
+ }
+ }
+
+ protected void longToast( CharSequence msg ) {
+ if ( mContext != null && msg != null ) {
+ Toast.makeText( mContext, msg, Toast.LENGTH_LONG ).show();
+ }
+ }
+}
diff --git a/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/ui/base/MapUIController.java b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/ui/base/MapUIController.java
new file mode 100644
index 0000000000..1a0564ac6d
--- /dev/null
+++ b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/ui/base/MapUIController.java
@@ -0,0 +1,430 @@
+package com.mogo.module.navi.ui.base;
+
+import android.content.Context;
+import android.graphics.BitmapFactory;
+import android.graphics.Color;
+import android.util.Log;
+import com.amap.api.maps.AMap;
+import com.amap.api.maps.CameraUpdateFactory;
+import com.amap.api.maps.UiSettings;
+import com.amap.api.maps.model.BitmapDescriptorFactory;
+import com.amap.api.maps.model.CameraPosition;
+import com.amap.api.maps.model.CustomMapStyleOptions;
+import com.amap.api.maps.model.LatLng;
+import com.amap.api.maps.model.Marker;
+import com.amap.api.maps.model.MarkerOptions;
+import com.amap.api.maps.model.MyLocationStyle;
+import com.amap.api.navi.AMapNaviView;
+import com.amap.api.navi.AMapNaviViewOptions;
+import com.mogo.module.navi.R;
+import com.mogo.module.navi.constants.AMapConstants;
+import com.mogo.module.navi.constants.CustomMapStyle;
+import com.mogo.utils.AssetsUtils;
+
+/**
+ * @author congtaowang
+ * @since 2019-10-27
+ *
+ * 描述
+ */
+public class MapUIController {
+
+ private static final String TAG = "MapUIController";
+
+ private static volatile MapUIController sInstance;
+ private int mLastZoomLevel;
+
+ private MapUIController() {
+ }
+
+ public static MapUIController getInstance() {
+ if ( sInstance == null ) {
+ synchronized ( MapUIController.class ) {
+ if ( sInstance == null ) {
+ sInstance = new MapUIController();
+ }
+ }
+ }
+ return sInstance;
+ }
+
+ public synchronized void release() {
+ mContext = null;
+ mMapView = null;
+ mAMap = null;
+ sInstance = null;
+ }
+
+ private Context mContext;
+ private AMapNaviView mMapView;
+ private AMap mAMap;
+
+ public synchronized void init( Context context, AMapNaviView mapView, AMap aMap ) {
+ this.mContext = context;
+ this.mMapView = mapView;
+ this.mAMap = aMap;
+ initMap();
+ changeMyLocationVisibility( true );
+ }
+
+ private boolean checkAMap() {
+ return mAMap != null;
+ }
+
+ private boolean checkAMapView() {
+ return mMapView != null;
+ }
+
+ /**
+ * 移除所有导航mapView的默认UI
+ */
+ private void initMap() {
+ if ( mMapView != null ) {
+ AMapNaviViewOptions options = mMapView.getViewOptions();
+ if ( options != null ) {
+ // 设置是否开启自动黑夜模式切换,默认为false,不自动切换
+ options.setAutoNaviViewNightMode( false );
+ // 设置6秒后是否自动锁车
+ options.setAutoLockCar( true );
+ // 设置路线上的摄像头气泡是否显示
+ options.setCameraBubbleShow( true );
+ // 设置路线相关的配置属性,如:路线的路况颜色,路线上是否显示摄像头气泡等。
+// options.setRouteOverlayOptions( MapStyleUtils.getRouteOverlayOptions() );
+ // 设置自车的图片对象
+ options.setCarBitmap( BitmapFactory.decodeResource( mContext.getResources(), R.drawable.ic_amap_navi_cursor ) );
+ // 设置指南针图标否在导航界面显示,默认显示。true,显示;false,隐藏。
+ options.setCompassEnabled( false );
+ //设置路况光柱条是否显示(只适用于驾车导航,需要联网)。
+ options.setTrafficBarEnabled( false );
+ // 设置[实时交通图层开关按钮]是否显示(只适用于驾车导航,需要联网)。
+ options.setTrafficLayerEnabled( false );
+ // 设置导航界面是否显示路线全览按钮。
+ options.setRouteListButtonShow( false );
+ // 设置起点位图,须在画路前设置
+ options.setStartPointBitmap( BitmapFactory.decodeResource( mContext.getResources(), R.drawable.ic_current_location_cursor ) );
+ // 设置终点位图,须在画路前设置
+ options.setEndPointBitmap( BitmapFactory.decodeResource( mContext.getResources(), R.drawable.ic_search_choice_point ) );
+ // 设置导航状态下屏幕是否一直开启。
+ options.setScreenAlwaysBright( true );
+ // 设置交通播报是否打开(只适用于驾车导航,需要联网)。
+ options.setTrafficInfoUpdateEnabled( true );
+ // 设置摄像头播报是否打开(只适用于驾车导航)。
+ options.setCameraInfoUpdateEnabled( true );
+ // 设置菜单按钮是否在导航界面显示。
+ options.setSettingMenuEnabled( false );
+ // 设置是否绘制显示交通路况的线路(彩虹线),拥堵-红色,畅通-绿色,缓慢-黄色,未知-蓝色。默认不绘制彩虹线。
+ options.setTrafficLine( true );
+ // 设置是否绘制牵引线(当前位置到目的地的指引线)。默认不绘制牵引线。
+ options.setLeaderLineEnabled( -1 );
+ // 设置导航界面UI是否显示。
+ options.setLayoutVisible( false );
+ // 设置是否自动画路
+ options.setAutoDrawRoute( false );
+ // 设置是否显示路口放大图(实景图)
+ options.setRealCrossDisplayShow( false );
+ // 设置是否显示路口放大图(路口模型图)
+ options.setModeCrossDisplayShow( false );
+ // 设置是否显示道路信息view
+ options.setLaneInfoShow( false );
+ // 设置是否自动改变缩放等级
+ options.setAutoChangeZoom( false );
+ // 设置是否自动全览模式,即在算路成功后自动进入全览模式
+ options.setAutoDisplayOverview( false );
+ // 设置路线转向箭头隐藏和显示
+ options.setNaviArrowVisible( false );
+ // 通过路线是否自动置灰,仅支持驾车导航
+ options.setAfterRouteAutoGray( true );
+ options.setPointToCenter( 0.5D, 0.5D );
+ mMapView.setViewOptions( options );
+ }
+ mMapView.setNaviMode( AMapNaviView.CAR_UP_MODE );
+ }
+
+ if ( mAMap != null ) {
+
+ mAMap.setTrafficEnabled( true );
+
+ UiSettings uiSettings = mAMap.getUiSettings();
+ if ( uiSettings != null ) {
+ //设置所有手势是否可用
+ uiSettings.setAllGesturesEnabled( true );
+ //设置指南针是否可见。
+ uiSettings.setCompassEnabled( false );
+ //设置是否以地图中心点缩放
+ uiSettings.setGestureScaleByMapCenter( true );
+ //设置室内地图楼层切换控件是否可见。
+ uiSettings.setIndoorSwitchEnabled( true );
+ //设置定位按钮是否可见。
+ uiSettings.setMyLocationButtonEnabled( false );
+ //设置旋转手势是否可用。
+ uiSettings.setRotateGesturesEnabled( false );
+ //设置比例尺控件是否可见
+ uiSettings.setScaleControlsEnabled( false );
+ //设置拖拽手势是否可用。
+ uiSettings.setScrollGesturesEnabled( true );
+ //设置倾斜手势是否可用。
+ uiSettings.setTiltGesturesEnabled( true );
+ //设置缩放按钮是否可见。
+ uiSettings.setZoomControlsEnabled( false );
+ //设置双指缩放手势是否可用。
+ uiSettings.setZoomGesturesEnabled( true );
+ }
+ mAMap.setCustomMapStyle( new CustomMapStyleOptions()
+ .setEnable( true )
+ .setStyleId( CustomMapStyle.STYLE_ID )
+ .setStyleData( AssetsUtils.read( mContext, CustomMapStyle.ASSET_STYLE_DATA ) )
+ .setStyleExtraData( AssetsUtils.read( mContext, CustomMapStyle.ASSET_STYLE_EXTRA_DATA ) )
+ );
+ }
+
+ }
+
+ /**
+ * 控制我的位置图层及定位回调能力
+ *
+ * @param visibility
+ */
+ public void changeMyLocationVisibility( boolean visibility ) {
+ if ( mAMap == null ) {
+ return;
+ }
+ mAMap.setMyLocationEnabled( visibility );
+ Log.d( TAG, visibility ? "开启定位" : "关闭定位" );
+ if ( visibility ) {
+ MyLocationStyle style = mAMap.getMyLocationStyle();
+ if ( style == null ) {
+ style = new MyLocationStyle();
+ }
+ style.myLocationType( MyLocationStyle.LOCATION_TYPE_LOCATION_ROTATE_NO_CENTER )
+ .strokeWidth( 0 )
+ .interval( 2_000L )
+ .showMyLocation( visibility )
+ .myLocationIcon( BitmapDescriptorFactory.fromResource( R.drawable.ic_current_location_cursor ) )
+ .radiusFillColor( Color.TRANSPARENT );
+ mAMap.setMyLocationStyle( style );
+ }
+ }
+
+ /**
+ * 导航模式:中心点偏下
+ */
+ public void showNaviUI() {
+ changeMyLocationVisibility( false );
+ changeCarOverlayVisibility( true );
+ changeRouteOverlayVisibility( false );
+ if ( mMapView != null ) {
+ mMapView.setNaviMode( AMapNaviView.CAR_UP_MODE );
+ mMapView.post( () -> {
+ AMapNaviViewOptions options = mMapView.getViewOptions();
+ if ( options != null ) {
+ Log.d( TAG, "中心点切换到页面偏下" );
+ options.setPointToCenter( 0.5D, 0.6666666666666666D );
+ mMapView.setViewOptions( options );
+ if ( checkAMap() ) {
+ mAMap.moveCamera( CameraUpdateFactory.zoomBy( 15 ) );
+ }
+ }
+ } );
+ }
+ }
+
+ /**
+ * 正常地图模式:中心点居中
+ */
+ public void showMapUI() {
+ changeMyLocationVisibility( true );
+ changeCarOverlayVisibility( false );
+ changeRouteOverlayVisibility( false );
+ if ( mMapView != null ) {
+ AMapNaviViewOptions options = mMapView.getViewOptions();
+ if ( options != null ) {
+ Log.d( TAG, "中心点切换到页面中心" );
+ options.setPointToCenter( 0.5D, 0.5D );
+ mMapView.setViewOptions( options );
+ }
+ }
+ }
+
+ /**
+ * 显示规划UI样式:中心点右移
+ */
+ public void showCalculateUI() {
+ changeMyLocationVisibility( false );
+ }
+
+ /**
+ * 控制自车marker
+ *
+ * @param visibility
+ */
+ public void changeCarOverlayVisibility( boolean visibility ) {
+ try {
+ mMapView.setCarOverlayVisible( visibility );
+ } catch ( Exception e ) {
+ }
+ }
+
+ /**
+ * 控制导航路线图层
+ *
+ * @param visibility
+ */
+ public void changeRouteOverlayVisibility( boolean visibility ) {
+ try {
+ mMapView.setRouteOverlayVisible( visibility );
+ } catch ( Exception e ) {
+ }
+ }
+
+
+ /**
+ * 将地图移动到中心点,正北方向
+ *
+ * @param latlng
+ */
+ public void moveCurrentPositionToCenter( LatLng latlng ) {
+ if ( checkAMap() ) {
+ mAMap.animateCamera( CameraUpdateFactory.newCameraPosition( new CameraPosition.Builder()
+ .tilt( mMapView.getLockTilt() )
+ .zoom( mMapView.getLockZoom() )
+ .target( latlng )
+ .bearing( AMapConstants.AMPA_BEARING )
+ .build() ) );
+ }
+ }
+
+ /**
+ * 改变地图缩放级别
+ *
+ * @param level
+ */
+ public void changeCameraZoomLevel( float level, boolean animate ) {
+ if ( checkAMap() ) {
+ if ( animate ) {
+ mAMap.animateCamera( CameraUpdateFactory.zoomTo( level ) );
+ } else {
+ mAMap.moveCamera( CameraUpdateFactory.zoomTo( level ) );
+ }
+ }
+ }
+
+ /**
+ * 添加marker
+ *
+ * @param options
+ * @return
+ */
+ public Marker addMarker( MarkerOptions options ) {
+ return mAMap.addMarker( options );
+ }
+
+ /**
+ * 缓存上次地图缩放级别
+ *
+ * @return
+ */
+ public boolean storeMapZoomLevel() {
+ if ( checkAMapView() ) {
+ final AMapNaviViewOptions options = mMapView.getViewOptions();
+ if ( options != null ) {
+ mLastZoomLevel = options.getZoom();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * 还原上次的缩放级别
+ */
+ public void restoreMapZoomLevel() {
+ if ( checkAMapView() ) {
+ final AMapNaviViewOptions options = mMapView.getViewOptions();
+ if ( options != null ) {
+ options.setZoom( mLastZoomLevel );
+ mMapView.setViewOptions( options );
+ }
+ }
+ }
+
+ /**
+ * 交通态势开关
+ *
+ * @param enable
+ */
+ public void setTrafficEnabled( boolean enable ) {
+ if ( checkAMap() ) {
+ mAMap.setTrafficEnabled( enable );
+ }
+ }
+
+ /**
+ * 缩放地图
+ *
+ * @param zoomIn 放大
+ */
+ public void changeZoom( boolean zoomIn ) {
+ if ( checkAMapView() ) {
+ if ( zoomIn ) {
+ mMapView.zoomIn();
+ } else {
+ mMapView.zoomOut();
+ }
+ }
+ }
+
+ /**
+ * 设置地图类型
+ *
+ * @param type
+ */
+ public void setMapType( int type ) {
+ if ( checkAMap() ) {
+ mAMap.setMapType( type );
+ }
+ }
+
+ /**
+ * 导航样式:
+ *
+ * @param naviMode
+ */
+ public void setNaviMode( int naviMode ) {
+ if ( checkAMapView() ) {
+ mMapView.setNaviMode( naviMode );
+ }
+ }
+
+ /**
+ * 地图倾斜度
+ *
+ * @param tile
+ */
+ public void setTilt( int tile ) {
+ if ( checkAMapView() ) {
+ final AMapNaviViewOptions options = mMapView.getViewOptions();
+ if ( options != null ) {
+ options.setTilt( tile );
+ mMapView.setViewOptions( options );
+ }
+ }
+ }
+
+ /**
+ * 预览全程
+ */
+ public void displayOverview() {
+ if ( checkAMapView() ) {
+ mMapView.displayOverview();
+ }
+ }
+
+ /**
+ * 关闭全程预览
+ */
+ public void recoverLockMode() {
+ if ( checkAMapView() ) {
+ mMapView.recoverLockMode();
+ }
+ }
+}
diff --git a/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/ui/base/UiController.java b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/ui/base/UiController.java
new file mode 100644
index 0000000000..8530553011
--- /dev/null
+++ b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/ui/base/UiController.java
@@ -0,0 +1,53 @@
+package com.mogo.module.navi.ui.base;
+
+import androidx.fragment.app.FragmentManager;
+
+/**
+ * @author congtaowang
+ * @since 2019-10-04
+ *
+ * 描述
+ */
+public interface UiController {
+
+ /**
+ * 显示地图模式
+ */
+ void onMapMode();
+
+ /**
+ * 显示导航模式
+ */
+ void onNaviMode();
+
+ /**
+ * 搜索地址
+ *
+ * @param searchType {@link com.zhidao.amap.splitunit.ui.search.SearchConstants}
+ */
+ void onSearchMode(int searchType);
+
+ /**
+ * 规划路径
+ */
+ void onCalculateMode();
+
+ /**
+ * 设置
+ */
+ void onSettingsMode();
+
+
+ /**
+ * 直接退出应用
+ */
+ void finishDirectly();
+
+ FragmentManager _getSupportFragmentManager();
+
+ AMapServiceVisitor getAMapServiceVisitor();
+
+ //CommonAddressModel getCommonAddressModel();
+
+ void popBackStackImmediate();
+}
diff --git a/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/ui/search/SearchConstants.java b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/ui/search/SearchConstants.java
new file mode 100644
index 0000000000..5c81a6339c
--- /dev/null
+++ b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/ui/search/SearchConstants.java
@@ -0,0 +1,54 @@
+package com.mogo.module.navi.ui.search;
+
+import com.mogo.module.navi.constants.DataConstants;
+
+/**
+ * @author congtaowang
+ * @since 2019-12-08
+ *
+ * 搜索页面常量字段
+ */
+public class SearchConstants {
+
+ /**
+ * 搜索页面类型
+ */
+ public static final String KEY_SEARCH_TYPE = "type";
+
+ /**
+ * 普通搜索:首页搜索按钮点击
+ */
+ public static final int SEARCH_TYPE_COMMON = DataConstants.TYPE_POI;
+
+ /**
+ * 设置家:多种搜索方式:普通搜索、我的位置、地图选点
+ */
+ public static final int SEARCH_TYPE_MULTI_HOME = DataConstants.TYPE_HOME_ADDRESS;
+
+ /**
+ * 设置公司:多种搜索方式:普通搜索、我的位置、地图选点
+ */
+ public static final int SEARCH_TYPE_MULTI_COMPANY = DataConstants.TYPE_COMPANY_ADDRESS;
+
+ /**
+ * 搜索页面当前状态
+ */
+ public static final int UI_MODE_COMMON = 1;
+ /**
+ * 搜索页面当前状态:常用地址搜索模式
+ */
+ public static final int UI_MODE_MULTI = 2;
+
+ /**
+ * 搜索页面当前状态:常用地址搜索模式
+ */
+ public static final int UI_MODE_MULTI_SEARCH = 5;
+ /**
+ * 搜索页面当前状态:我的位置模式
+ */
+ public static final int UI_MODE_MULTI_MY_LOCATION = 3;
+ /**
+ * 搜索页面当前状态:选点模式
+ */
+ public static final int UI_MODE_MULTI_CHOICE_POINT = 4;
+}
diff --git a/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/ui/search/SearchFragment.java b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/ui/search/SearchFragment.java
new file mode 100644
index 0000000000..8beea1b768
--- /dev/null
+++ b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/ui/search/SearchFragment.java
@@ -0,0 +1,569 @@
+package com.mogo.module.navi.ui.search;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Point;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.view.View;
+import android.view.animation.Interpolator;
+import android.widget.EditText;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+import android.widget.Toast;
+import androidx.annotation.Nullable;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import com.alibaba.android.arouter.facade.annotation.Route;
+import com.amap.api.location.AMapLocation;
+import com.amap.api.location.AMapLocationListener;
+import com.amap.api.maps.AMap;
+import com.amap.api.maps.AMapUtils;
+import com.amap.api.maps.model.BitmapDescriptorFactory;
+import com.amap.api.maps.model.LatLng;
+import com.amap.api.maps.model.Marker;
+import com.amap.api.maps.model.MarkerOptions;
+import com.amap.api.maps.model.animation.Animation;
+import com.amap.api.maps.model.animation.TranslateAnimation;
+import com.amap.api.services.geocoder.RegeocodeAddress;
+import com.amap.api.services.help.Tip;
+
+import com.mogo.module.map.location.AMapLocationManager;
+import com.mogo.module.navi.R;
+import com.mogo.module.navi.bean.EntityConvertUtils;
+import com.mogo.module.navi.bean.SearchPoi;
+import com.mogo.module.navi.ui.adapter.SearchPoiAdapter;
+import com.mogo.module.navi.ui.base.BaseFragment;
+import com.mogo.module.navi.ui.base.MapUIController;
+import com.mogo.module.navi.ui.base.UiController;
+import com.mogo.utils.WindowUtils;
+import io.reactivex.disposables.Disposable;
+import java.util.List;
+
+/**
+ * 搜索页面
+ *
+ * 普通搜索:从首页点击搜索按钮进入:包含:仅输入搜索(列表不包含设置按钮)
+ * {@link SearchConstants#SEARCH_TYPE_COMMON}
+ *
+ * 地址设置搜索:设置家、公司、其他的地址:包含当前位置、选点、搜索列表(列表包含设置按钮)、普通页面
+ * {@link SearchConstants#SEARCH_TYPE_MULTI_COMPANY}
+ * {@link SearchConstants#SEARCH_TYPE_MULTI_HOME}
+ */
+@Route( path = "/amap/search" )
+public class SearchFragment extends BaseFragment implements SearchView,
+ AMapLocationListener {
+
+ public static final String TAG = "search";
+
+ public int mSearchType;
+
+ private SearchPresenter mSearchPresenter;
+
+ private View mClose;
+ private EditText mSearchBox;
+
+ private RecyclerView mSearchResult;
+ private SearchPoiAdapter mPoiAdapter;
+
+ private View mMyLocation;
+ private View mChoicePoint;
+ private View mCurrentLocation;
+
+ /**
+ * 设置常用地址(我的位置、选点)时的设置按钮
+ */
+ private TextView mActionButton;
+
+ private UiController mUiController;
+
+ private Bitmap mSearchBoxRightDrawableBitmap = null;
+
+ /**
+ * 地址设置是否完成
+ */
+ private boolean mActionSuccess = false;
+
+ /**
+ * 当前UI的样式(具体是哪个操作)
+ */
+ private int mUiMode = SearchConstants.UI_MODE_COMMON;
+
+ /**
+ * 地图选点的marker
+ */
+ private Marker mChoicePointMaker = null;
+ private AMapLocation mLastAMapLocation;
+
+ @Override
+ public void onAttach( Context context ) {
+ super.onAttach( context );
+ if ( context instanceof UiController) {
+ mUiController = ( ( UiController ) context );
+ }
+ }
+
+ @Override
+ protected int getLayoutId() {
+ return R.layout.fragment_search;
+ }
+
+ @Override
+ public void onActivityCreated( @Nullable Bundle savedInstanceState ) {
+ super.onActivityCreated( savedInstanceState );
+ initViews();
+ getLifecycle().addObserver( mSearchPresenter = new SearchPresenter( this ) );
+ }
+
+ private void initViews() {
+ mClose = findViewById( R.id.amap_search_close );
+ mClose.setOnClickListener( view -> {
+ exitSearch();
+ } );
+
+ mSearchBox = findViewById( R.id.amap_search_search_box );
+ mSearchResult = findViewById( R.id.amap_search_poi_result );
+ mSearchResult.setLayoutManager( new LinearLayoutManager( mContext, LinearLayoutManager.VERTICAL, false ) );
+
+ mMyLocation = findViewById( R.id.amap_search_poi_my_location );
+ mMyLocation.setOnClickListener( view -> {
+ if ( !checkNetwork() ) {
+ shortToast( "网络未连接,请检查网络" );
+ return;
+ }
+ multiSearchMyLocationUI();
+ AMapLocationManager.getInstance( mContext ).addLocationListener( this );
+ AMapLocationManager.getInstance( mContext ).start();
+ } );
+ mChoicePoint = findViewById( R.id.amap_search_poi_choice_point );
+ mChoicePoint.setOnClickListener( view -> {
+ multiSearchChoicePointUI();
+ } );
+ mCurrentLocation = findViewById( R.id.amap_search_current_location );
+ mCurrentLocation.setOnClickListener( view -> {
+ if ( !checkNetwork() ) {
+ shortToast( "网络未连接,请检查网络" );
+ return;
+ }
+ AMapLocationManager.getInstance( mContext ).addLocationListener( this );
+ AMapLocationManager.getInstance( mContext ).start();
+ } );
+
+ mActionButton = findViewById( R.id.amap_search_action_setting );
+ mActionButton.setOnClickListener( view -> {
+ if ( mUiMode == SearchConstants.UI_MODE_MULTI_MY_LOCATION ) {
+ saveCurrentLocationAsCommonAddress();
+ } else if ( mUiMode == SearchConstants.UI_MODE_MULTI_CHOICE_POINT ) {
+ saveRegeoAddressAsCommonAddress();
+ }
+ } );
+
+ switch ( mSearchType ) {
+ case SearchConstants.SEARCH_TYPE_COMMON:
+ commonSearchUI();
+ break;
+ case SearchConstants.SEARCH_TYPE_MULTI_HOME:
+ case SearchConstants.SEARCH_TYPE_MULTI_COMPANY:
+ multiSearchUI();
+ break;
+ }
+ }
+
+ /**
+ * 普通搜索UI:不显示我的位置、地图选点、我的定位
+ */
+ private void commonSearchUI() {
+ mUiMode = SearchConstants.UI_MODE_COMMON;
+ mSearchBox.setEnabled( true );
+ mMyLocation.setVisibility( View.GONE );
+ mChoicePoint.setVisibility( View.GONE );
+ mCurrentLocation.setVisibility( View.GONE );
+ mActionButton.setVisibility( View.INVISIBLE );
+ mSearchResult.setVisibility( View.GONE );
+ if ( mSearchBox.getCompoundDrawables()[2] == null ) {
+ Drawable rightDrawable = null;
+ if ( mSearchBoxRightDrawableBitmap == null ) {
+ mSearchBoxRightDrawableBitmap = BitmapFactory.decodeResource( getResources(), R.drawable.ic_search_unshadow );
+ }
+ rightDrawable = new BitmapDrawable( getResources(), mSearchBoxRightDrawableBitmap );
+ mSearchBox.setCompoundDrawables( null, null, rightDrawable, null );
+ rightDrawable.setBounds( 0, 0, rightDrawable.getIntrinsicWidth(), rightDrawable.getIntrinsicHeight() );
+ }
+ removeChoicePointMarker();
+ mSearchBox.setTag( null );
+ if ( mSearchBox.getLayoutParams() instanceof RelativeLayout.LayoutParams ) {
+ final RelativeLayout.LayoutParams params = ( ( RelativeLayout.LayoutParams ) mSearchBox.getLayoutParams() );
+ params.removeRule( RelativeLayout.LEFT_OF );
+ mSearchBox.setPadding( 0, 0, WindowUtils.dip2px( mContext, 0 ), 0 );
+ mSearchBox.setLayoutParams( params );
+ }
+ mLastAMapLocation = null;
+ }
+
+ /**
+ * 多项搜索:显示我的位置、地图选点、我的定位
+ */
+ private void multiSearchUI() {
+ mUiMode = SearchConstants.UI_MODE_MULTI;
+ mSearchBox.setText( "" );
+ mSearchBox.setEnabled( true );
+ mMyLocation.setVisibility( View.VISIBLE );
+ mChoicePoint.setVisibility( View.VISIBLE );
+ mCurrentLocation.setVisibility( View.VISIBLE );
+ mSearchResult.setVisibility( View.GONE );
+ if ( mSearchBox.getCompoundDrawables()[2] == null ) {
+ Drawable rightDrawable = null;
+ if ( mSearchBoxRightDrawableBitmap == null ) {
+ mSearchBoxRightDrawableBitmap = BitmapFactory.decodeResource( getResources(), R.drawable.ic_search_unshadow );
+ }
+ rightDrawable = new BitmapDrawable( getResources(), mSearchBoxRightDrawableBitmap );
+ rightDrawable.setBounds( 0, 0, rightDrawable.getIntrinsicWidth(), rightDrawable.getIntrinsicHeight() );
+ mSearchBox.setCompoundDrawables( null, null, rightDrawable, null );
+ }
+ mActionButton.setVisibility( View.INVISIBLE );
+ removeChoicePointMarker();
+ mSearchBox.setTag( null );
+ if ( mSearchBox.getLayoutParams() instanceof RelativeLayout.LayoutParams ) {
+ final RelativeLayout.LayoutParams params = ( ( RelativeLayout.LayoutParams ) mSearchBox.getLayoutParams() );
+ params.removeRule( RelativeLayout.LEFT_OF );
+ mSearchBox.setPadding( 0, 0, WindowUtils.dip2px( mContext, 0 ), 0 );
+ mSearchBox.setLayoutParams( params );
+ }
+ mLastAMapLocation = null;
+ }
+
+ /**
+ * 显示我的位置,并且可设置为家
+ */
+ private void multiSearchMyLocationUI() {
+ mUiMode = SearchConstants.UI_MODE_MULTI_MY_LOCATION;
+ mSearchBox.setEnabled( false );
+ mMyLocation.setVisibility( View.GONE );
+ mChoicePoint.setVisibility( View.GONE );
+ mCurrentLocation.setVisibility( View.GONE );
+ mSearchResult.setVisibility( View.GONE );
+ mActionButton.setVisibility( View.VISIBLE );
+ mActionButton.setText( SearchUtils.getSearchTypeActionName( mSearchType ) );
+ mSearchBox.setCompoundDrawables( null, null, null, null );
+ removeChoicePointMarker();
+ mSearchBox.setTag( null );
+ if ( mSearchBox.getLayoutParams() instanceof RelativeLayout.LayoutParams ) {
+ final RelativeLayout.LayoutParams params = ( ( RelativeLayout.LayoutParams ) mSearchBox.getLayoutParams() );
+ params.addRule( RelativeLayout.LEFT_OF, R.id.amap_search_action_setting );
+ mSearchBox.setPadding( 0, 0, WindowUtils.dip2px( mContext, 15 ), 0 );
+ mSearchBox.setLayoutParams( params );
+ }
+ }
+
+ /**
+ * 显示我的位置,并且可设置为家
+ */
+ private void multiSearchChoicePointUI() {
+ mUiMode = SearchConstants.UI_MODE_MULTI_CHOICE_POINT;
+ mSearchBox.setEnabled( false );
+ mMyLocation.setVisibility( View.GONE );
+ mChoicePoint.setVisibility( View.GONE );
+ mCurrentLocation.setVisibility( View.GONE );
+ mSearchResult.setVisibility( View.GONE );
+ mActionButton.setVisibility( View.VISIBLE );
+ mActionButton.setText( SearchUtils.getSearchTypeActionName( mSearchType ) );
+ mSearchBox.setCompoundDrawables( null, null, null, null );
+ showChoicePointMarker();
+ mSearchBox.setTag( null );
+ if ( mSearchBox.getLayoutParams() instanceof RelativeLayout.LayoutParams ) {
+ final RelativeLayout.LayoutParams params = ( ( RelativeLayout.LayoutParams ) mSearchBox.getLayoutParams() );
+ params.addRule( RelativeLayout.LEFT_OF, R.id.amap_search_action_setting );
+ mSearchBox.setPadding( 0, 0, WindowUtils.dip2px( mContext, 15 ), 0 );
+ mSearchBox.setLayoutParams( params );
+ }
+ mLastAMapLocation = null;
+ }
+
+ private void saveCurrentLocationAsCommonAddress() {
+ if ( mLastAMapLocation == null ) {
+ shortToast( "定位失败,请重试" );
+ return;
+ }
+ final Disposable disposable = mSearchPresenter.cacheCommonAddressPoi( mLastAMapLocation ).subscribe( output -> {
+ Toast.makeText( mContext, "设置成功!", Toast.LENGTH_SHORT ).show();
+ mActionSuccess = true;
+ }, error -> {
+ if ( error instanceof Exception) {
+ Toast.makeText( mContext, ( (Exception) error ).getMessage(), Toast.LENGTH_SHORT ).show();
+ mActionSuccess = false;
+ }
+ } );
+ mSearchPresenter.addDisposable( disposable );
+ }
+
+ private void saveRegeoAddressAsCommonAddress() {
+ if ( mSearchBox.getTag() instanceof RegeocodeAddress ) {
+ final Disposable disposable = mSearchPresenter.cacheCommonAddressPoi( ( ( RegeocodeAddress ) mSearchBox.getTag() ) ).subscribe( output -> {
+ Toast.makeText( mContext, "设置成功!", Toast.LENGTH_SHORT ).show();
+ mActionSuccess = true;
+ }, error -> {
+ if ( error instanceof Exception) {
+ Toast.makeText( mContext, ( (Exception) error ).getMessage(), Toast.LENGTH_SHORT ).show();
+ mActionSuccess = false;
+ }
+ } );
+ mSearchPresenter.addDisposable( disposable );
+ } else {
+ Toast.makeText( mContext, "请选择位置", Toast.LENGTH_SHORT ).show();
+ }
+ }
+
+ @Override
+ public void onLocationChanged( AMapLocation aMapLocation ) {
+ //final String checkMsg = AMapUtils.getAMapLocationErrorMsg( aMapLocation );
+ //if ( AMapUtils.LOC_SUCCESS.equals( checkMsg ) ) {
+ // mLastAMapLocation = aMapLocation;
+ // MapUIController.getInstance().moveCurrentPositionToCenter( new LatLng( aMapLocation.getLatitude(), aMapLocation.getLongitude() ) );
+ // if ( mUiMode == SearchConstants.UI_MODE_MULTI_MY_LOCATION ) {
+ // showMyLocationAddress( aMapLocation );
+ // } else if ( mUiMode == SearchConstants.UI_MODE_MULTI_CHOICE_POINT ) {
+ // showChoicePointAddress( aMapLocation );// 显示当前中心点地址
+ // }
+ //} else {
+ // Toast.makeText( mContext, checkMsg, Toast.LENGTH_SHORT ).show();
+ //}
+ AMapLocationManager.getInstance( mContext ).removeLocationListener( this );
+ AMapLocationManager.getInstance( mContext ).stop();
+ }
+
+ private void showMyLocationAddress( AMapLocation location ) {
+ if ( location == null ) {
+ return;
+ }
+ mSearchBox.setEnabled( false );
+ mSearchBox.setText( location.getPoiName() );
+ }
+
+ /**
+ * 显示点选marker,隐藏自车marker
+ */
+ private void showChoicePointMarker() {
+
+ final AMap aMap = mUiController.getAMapServiceVisitor().getMap();
+ if ( aMap == null ) {
+ return;
+ }
+ // AMapService 里设置了监听,此处会覆盖
+ LatLng latLng = aMap.getCameraPosition().target;
+ Point screenPosition = aMap.getProjection().toScreenLocation( latLng );
+ mChoicePointMaker = aMap.addMarker( new MarkerOptions().zIndex( 1 ).anchor( 0.5f, 0.5f ).position( latLng ).icon( BitmapDescriptorFactory.fromResource( R.drawable.ic_search_choice_point ) ) );
+ mChoicePointMaker.setPositionByPixels( screenPosition.x, screenPosition.y );
+ MapUIController.getInstance().changeMyLocationVisibility( false );
+ }
+
+ /**
+ * 隐藏点选marker,显示自车marker
+ */
+ private void removeChoicePointMarker() {
+ if ( mChoicePointMaker != null ) {
+ mChoicePointMaker.remove();
+ }
+ mChoicePointMaker = null;
+ MapUIController.getInstance().changeMyLocationVisibility( true );
+ }
+
+ private void showChoicePointAddress( AMapLocation location ) {
+ if ( location == null ) {
+ return;
+ }
+ mSearchBox.setEnabled( false );
+ mSearchBox.setText( location.getPoiName() );
+ }
+
+ // view interface
+
+ @Override
+ public EditText getSearchBox() {
+ return mSearchBox;
+ }
+
+ @Override
+ public void renderSearchPoiResult( List< Tip > datums, boolean showDelete ) {
+
+ if ( datums == null || datums.isEmpty() ) {
+ mSearchResult.setVisibility( View.GONE );
+ } else {
+ mSearchResult.setVisibility( View.VISIBLE );
+ }
+
+ if ( mPoiAdapter == null ) {
+ mPoiAdapter = new SearchPoiAdapter(getContext(), datums );
+ mPoiAdapter.setOnItemClickedListener( item -> {
+ if ( mSearchType == SearchConstants.SEARCH_TYPE_COMMON ) {
+ final Disposable disposable = mSearchPresenter.cacheSelectPoiItem( item ).subscribe( output -> {
+ navi2Location( EntityConvertUtils.tipToPoi( item ) );
+ } );
+ mSearchPresenter.addDisposable( disposable );
+ } else {
+ // do nothing.
+ }
+ } );
+ mPoiAdapter.setOnDeleteAllClickedListener( NULL -> {
+ mSearchPresenter.deleteAllCachedPoi();
+ } );
+ mPoiAdapter.setOnActionButtonClickedListener( poi -> {
+ final Disposable disposable = mSearchPresenter.cacheCommonAddressPoi( poi ).subscribe( output -> {
+ Toast.makeText( mContext, "设置成功!", Toast.LENGTH_SHORT ).show();
+ mActionSuccess = true;
+ } );
+ mSearchPresenter.addDisposable( disposable );
+ } );
+ mPoiAdapter.setShowDelete( showDelete );
+ mSearchResult.setAdapter( mPoiAdapter );
+ } else {
+ if ( datums != null && !datums.isEmpty() ) {
+ mSearchResult.scrollToPosition( 0 );
+ }
+ mPoiAdapter.refresh( datums, showDelete );
+ }
+ }
+
+ @Override
+ public int getSearchType() {
+ return mSearchType;
+ }
+
+ @Override
+ public int getUiMode() {
+ return mUiMode;
+ }
+
+ @Override
+ public void renderChoicePointResult( RegeocodeAddress address ) {
+ if ( address == null ) {
+ mSearchBox.setTag( null );
+ mSearchBox.setText( "" );
+ return;
+ }
+ mSearchBox.setTag( address );
+ mSearchBox.setText( address.getFormatAddress() );
+ }
+
+ //@Override
+ //public void renderErrorView() {
+ //
+ //}
+ //
+ //@Override
+ //public void renderContentView() {
+ //
+ //}
+
+ // view interface end
+
+ /**
+ * 屏幕中心marker 跳动
+ */
+ @Override
+ public void startJumpAnimation() {
+
+ final AMap aMap = mUiController.getAMapServiceVisitor().getMap();
+
+ if ( mChoicePointMaker != null ) {
+ //根据屏幕距离计算需要移动的目标点
+ final LatLng latLng = mChoicePointMaker.getPosition();
+ Point point = aMap.getProjection().toScreenLocation( latLng );
+ point.y -= WindowUtils.dip2px( mContext, 125 );
+ LatLng target = aMap.getProjection()
+ .fromScreenLocation( point );
+ //使用TranslateAnimation,填写一个需要移动的目标点
+ Animation animation = new TranslateAnimation( target );
+ animation.setInterpolator( new Interpolator() {
+ @Override
+ public float getInterpolation( float input ) {
+ // 模拟重加速度的interpolator
+ if ( input <= 0.5 ) {
+ return ( float ) ( 0.5f - 2 * ( 0.5 - input ) * ( 0.5 - input ) );
+ } else {
+ return ( float ) ( 0.5f - Math.sqrt( ( input - 0.5f ) * ( 1.5f - input ) ) );
+ }
+ }
+ } );
+ //整个移动所需要的时间
+ animation.setDuration( 600 );
+ //设置动画
+ mChoicePointMaker.setAnimation( animation );
+ //开始动画
+ mChoicePointMaker.startAnimation();
+
+ }
+ }
+
+ /**
+ * @param searchPoi 导航目的地
+ */
+ private void navi2Location( SearchPoi searchPoi ) {
+
+ if ( searchPoi == null || searchPoi == SearchPoi.NULL ) {
+ Toast.makeText( mContext, "未设置", Toast.LENGTH_SHORT ).show();
+ return;
+ }
+ //SearchPoiLiveData.getInstance().postValue( searchPoi );
+ exitSearch();
+ }
+
+ /**
+ * 退出搜索,进行清理
+ */
+ private void exitSearch() {
+
+ switch ( mSearchType ) {
+ case SearchConstants.SEARCH_TYPE_COMMON:
+ try {
+ mUiController.popBackStackImmediate();
+ } catch ( Exception e ) {
+ e.printStackTrace();
+ }
+ break;
+ case SearchConstants.SEARCH_TYPE_MULTI_HOME:
+ case SearchConstants.SEARCH_TYPE_MULTI_COMPANY:
+ if ( !mActionSuccess ) {
+ // 通过搜索框搜索,在设置成功之前点击返回按钮,返回到未搜索状态
+ if ( mUiMode != SearchConstants.UI_MODE_MULTI || mSearchResult.getVisibility() == View.VISIBLE ) {
+ multiSearchUI();
+ return;
+ }
+ }
+ try {
+ mUiController.popBackStackImmediate();
+ mUiController.onSettingsMode();
+ } catch ( Exception e ) {
+ e.printStackTrace();
+ }
+ break;
+ }
+ }
+
+ @Override
+ public void onDestroyView() {
+ super.onDestroyView();
+ if ( mSearchPresenter != null ) {
+ mSearchPresenter.onDestroy( getViewLifecycleOwner() );
+ getLifecycle().removeObserver( mSearchPresenter );
+ mSearchPresenter = null;
+ }
+ mSearchBox.setTag( null );
+ mUiController = null;
+ if ( mSearchBoxRightDrawableBitmap != null ) {
+ try {
+ mSearchBoxRightDrawableBitmap.recycle();
+ } catch ( Exception e ) {
+ }
+ }
+ if ( mPoiAdapter != null ) {
+ mPoiAdapter.clear();
+ }
+ mPoiAdapter = null;
+ mSearchBoxRightDrawableBitmap = null;
+ removeChoicePointMarker();
+ AMapLocationManager.getInstance( mContext ).release();
+
+ }
+}
diff --git a/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/ui/search/SearchPresenter.java b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/ui/search/SearchPresenter.java
new file mode 100644
index 0000000000..717f37044f
--- /dev/null
+++ b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/ui/search/SearchPresenter.java
@@ -0,0 +1,294 @@
+package com.mogo.module.navi.ui.search;
+
+
+import android.app.AlertDialog;
+import android.text.Editable;
+import android.text.TextUtils;
+import android.widget.EditText;
+import androidx.annotation.NonNull;
+import androidx.lifecycle.LifecycleOwner;
+import com.amap.api.location.AMapLocation;
+import com.amap.api.maps.model.CameraPosition;
+import com.amap.api.services.core.LatLonPoint;
+import com.amap.api.services.geocoder.GeocodeResult;
+import com.amap.api.services.geocoder.GeocodeSearch;
+import com.amap.api.services.geocoder.RegeocodeAddress;
+import com.amap.api.services.geocoder.RegeocodeQuery;
+import com.amap.api.services.geocoder.RegeocodeResult;
+import com.amap.api.services.help.Inputtips;
+import com.amap.api.services.help.InputtipsQuery;
+import com.amap.api.services.help.Tip;
+import com.mogo.commons.mvp.Presenter;
+import com.mogo.module.common.TextWatcherAdapter;
+import com.mogo.module.navi.bean.EntityConvertUtils;
+import com.mogo.module.navi.bean.SearchPoi;
+import com.mogo.module.navi.constants.DataConstants;
+import com.mogo.module.navi.database.AppDataBase;
+import io.reactivex.Single;
+import io.reactivex.SingleEmitter;
+import io.reactivex.android.schedulers.AndroidSchedulers;
+import io.reactivex.disposables.CompositeDisposable;
+import io.reactivex.disposables.Disposable;
+import io.reactivex.schedulers.Schedulers;
+import java.util.List;
+
+/**
+ * @author congtaowang
+ * @since 2019-10-02
+ *
+ * 搜搜页逻辑处理
+ */
+public class SearchPresenter extends Presenter< SearchView >
+ implements Inputtips.InputtipsListener, GeocodeSearch.OnGeocodeSearchListener {
+
+ private Inputtips mSearchEngine;
+ private GeocodeSearch mGeocodeSearch;
+
+ private CompositeDisposable mCompositeDisposable;
+ private CameraPosition mLastCameraPosition;
+
+ public SearchPresenter( SearchView view ) {
+ super( view );
+ mCompositeDisposable = new CompositeDisposable();
+ }
+
+ @Override
+ public void onCreate( @NonNull LifecycleOwner owner ) {
+ super.onCreate( owner );
+ attachSearchBoxTextWatcher( mView.getSearchBox() );
+ switch ( mView.getSearchType() ) {
+ case SearchConstants.SEARCH_TYPE_COMMON:
+ loadHistories();
+ break;
+ }
+
+ }
+
+ private void loadHistories() {
+ }
+
+ private void attachSearchBoxTextWatcher( EditText editText ) {
+ if ( editText == null ) {
+ return;
+ }
+ editText.addTextChangedListener(watcherAdapter);
+ }
+
+ private final TextWatcherAdapter watcherAdapter = new TextWatcherAdapter() {
+ @Override
+ public void afterTextChanged( Editable s ) {
+ // 避免 disable 设置内容时触发
+ final String input = s.toString();
+ startSearchPoiByInput( input );
+ }
+ };
+
+ private void startSearchPoiByInput( String keyword ) {
+ switch ( mView.getUiMode() ) {
+ // 如果是普通搜索,清空搜索内容后需要加载缓存历史,否则不需要
+ case SearchConstants.UI_MODE_COMMON:
+ if ( TextUtils.isEmpty( keyword ) ) {
+ loadHistories();
+ return;
+ }
+ break;
+ case SearchConstants.UI_MODE_MULTI_CHOICE_POINT:
+ case SearchConstants.UI_MODE_MULTI_MY_LOCATION:
+ return;
+ case SearchConstants.UI_MODE_MULTI:
+ if ( TextUtils.isEmpty( keyword ) ) {
+ mView.renderSearchPoiResult( null, false );
+ return;
+ }
+ break;
+ }
+ final InputtipsQuery searchQuery = new InputtipsQuery( keyword, "" );
+ if ( mSearchEngine == null ) {
+ mSearchEngine = new Inputtips( getContext(), searchQuery );
+ mSearchEngine.setInputtipsListener( this );
+ } else {
+ mSearchEngine.setQuery( searchQuery );
+ }
+ mSearchEngine.requestInputtipsAsyn();
+ }
+
+ @Override
+ public void onGetInputtips( List
+ * 搜索工具类
+ */
+public class SearchUtils {
+
+ /**
+ * @param searchType
+ * @return
+ */
+ public static int checkAndResetSearchType( int searchType ) {
+ switch ( searchType ) {
+ case SearchConstants.SEARCH_TYPE_COMMON:
+ case SearchConstants.SEARCH_TYPE_MULTI_HOME:
+ case SearchConstants.SEARCH_TYPE_MULTI_COMPANY:
+ break;
+ default:
+ searchType = SearchConstants.SEARCH_TYPE_COMMON;
+ break;
+ }
+ return searchType;
+ }
+
+ public static String getSearchTypeActionName( int searchType ) {
+ switch ( searchType ) {
+ case SearchConstants.SEARCH_TYPE_COMMON:
+ return null;
+ case SearchConstants.SEARCH_TYPE_MULTI_HOME:
+ return "设为家";
+ case SearchConstants.SEARCH_TYPE_MULTI_COMPANY:
+ return "设为公司";
+ }
+ return null;
+ }
+}
diff --git a/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/ui/search/SearchView.java b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/ui/search/SearchView.java
new file mode 100644
index 0000000000..feee118364
--- /dev/null
+++ b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/ui/search/SearchView.java
@@ -0,0 +1,46 @@
+package com.mogo.module.navi.ui.search;
+
+import android.widget.EditText;
+import com.amap.api.services.geocoder.RegeocodeAddress;
+import com.amap.api.services.help.Tip;
+import com.mogo.commons.mvp.IView;
+import java.util.List;
+
+/**
+ * @author congtaowang
+ * @since 2019-10-02
+ *
+ * 描述
+ */
+public interface SearchView extends IView {
+
+ EditText getSearchBox();
+
+ /**
+ * @param datums
+ * @param showDelete 是否显示清空历史记录项
+ */
+ void renderSearchPoiResult(List
+ * 描述
+ */
+public class AMapCalcRouteResultWrapper implements Parcelable {
+
+ private final int errorCode;
+ private final int[] routeId;
+ private final int calcRouteType;
+ private final String errorDetail;
+
+ public AMapCalcRouteResultWrapper( AMapCalcRouteResult result ) {
+ errorCode = result.getErrorCode();
+ routeId = result.getRouteid();
+ calcRouteType = result.getCalcRouteType();
+ errorDetail = result.getErrorDetail();
+ }
+
+ public AMapCalcRouteResult parse() {
+ final AMapCalcRouteResult inst = new AMapCalcRouteResult();
+ inst.setErrorCode( getErrorCode() );
+ inst.setRouteid( getRouteId() );
+ inst.setCalcRouteType( getCalcRouteType() );
+ inst.setErrorDetail( getErrorDetail() );
+ return inst;
+ }
+
+ public int getErrorCode() {
+ return errorCode;
+ }
+
+ public int[] getRouteId() {
+ return routeId;
+ }
+
+ public int getCalcRouteType() {
+ return calcRouteType;
+ }
+
+ public String getErrorDetail() {
+ return errorDetail;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel( Parcel dest, int flags ) {
+ dest.writeInt( this.errorCode );
+ dest.writeIntArray( this.routeId );
+ dest.writeInt( this.calcRouteType );
+ dest.writeString( this.errorDetail );
+ }
+
+ protected AMapCalcRouteResultWrapper( Parcel in ) {
+ this.errorCode = in.readInt();
+ this.routeId = in.createIntArray();
+ this.calcRouteType = in.readInt();
+ this.errorDetail = in.readString();
+ }
+
+ public static final Creator< AMapCalcRouteResultWrapper > CREATOR = new Creator< AMapCalcRouteResultWrapper >() {
+ @Override
+ public AMapCalcRouteResultWrapper createFromParcel( Parcel source ) {
+ return new AMapCalcRouteResultWrapper( source );
+ }
+
+ @Override
+ public AMapCalcRouteResultWrapper[] newArray( int size ) {
+ return new AMapCalcRouteResultWrapper[size];
+ }
+ };
+}
diff --git a/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/wrapper/AMapNaviCameraInfoWrapper.java b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/wrapper/AMapNaviCameraInfoWrapper.java
new file mode 100644
index 0000000000..9463cdc52a
--- /dev/null
+++ b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/wrapper/AMapNaviCameraInfoWrapper.java
@@ -0,0 +1,99 @@
+package com.mogo.module.navi.wrapper;
+
+import com.amap.api.navi.model.AMapNaviCameraInfo;
+
+/**
+ * @author congtaowang
+ * @since 2019-10-10
+ *
+ * 描述
+ */
+public class AMapNaviCameraInfoWrapper {
+
+ private int cameraDistance;
+ private double x;
+ private double y;
+ /**
+ * {@link AMapNaviCameraInfo#getCameraType()}
+ * {@link com.amap.api.navi.enums.CameraType#SPEED} 测速摄像
+ * {@link com.amap.api.navi.enums.CameraType#SURVEILLANCE}监控摄像
+ * {@link com.amap.api.navi.enums.CameraType#TRAFFICLIGHT} 闯红灯拍照
+ * {@link com.amap.api.navi.enums.CameraType#BREAKRULE} 违章拍照
+ * {@link com.amap.api.navi.enums.CameraType#BUSWAY} 公交专用道摄像头
+ * {@link com.amap.api.navi.enums.CameraType#EMERGENCY}应急车道拍照
+ * {@link com.amap.api.navi.enums.CameraType#BICYCLE}非机动车道(暂未使用)
+ * {@link com.amap.api.navi.enums.CameraType#INTERVALVELOCITYSTART}区间测速起始
+ * {@link com.amap.api.navi.enums.CameraType#INTERVALVELOCITYEND}区间测速解除
+ */
+ private int cameraType;
+ private int cameraSpeed;
+ private int averageSpeed;
+ private int reasonableSpeedInRemainDist;
+ private int distance;
+ private int[] speed;
+
+ public AMapNaviCameraInfoWrapper( AMapNaviCameraInfo info ) {
+ if ( info != null ) {
+ cameraDistance = info.getCameraDistance();
+ x = info.getX();
+ y = info.getY();
+ cameraType = info.getCameraType();
+ cameraSpeed = info.getCameraSpeed();
+ averageSpeed = info.getAverageSpeed();
+ reasonableSpeedInRemainDist = info.getReasonableSpeedInRemainDist();
+ distance = info.getDistance();
+ speed = info.getSpeed();
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append( "cameraDistance" ).append( "=" ).append( cameraDistance ).append( "\n" );
+ builder.append( "cameraType" ).append( "=" ).append( cameraType ).append( "\n" );
+ builder.append( "cameraSpeed" ).append( "=" ).append( cameraSpeed ).append( "\n" );
+ builder.append( "averageSpeed" ).append( "=" ).append( averageSpeed ).append( "\n" );
+ builder.append( "reasonableSpeedInRemainDist" ).append( "=" ).append( reasonableSpeedInRemainDist ).append( "\n" );
+ builder.append( "distance" ).append( "=" ).append( distance ).append( "\n" );
+ if ( speed != null ) {
+ builder.append( "speed" ).append( "=" ).append( speed ).append( "\n" );
+ }
+ return builder.toString();
+ }
+
+ public int getCameraDistance() {
+ return cameraDistance;
+ }
+
+ public double getX() {
+ return x;
+ }
+
+ public double getY() {
+ return y;
+ }
+
+ public int getCameraType() {
+ return cameraType;
+ }
+
+ public int getCameraSpeed() {
+ return cameraSpeed;
+ }
+
+ public int getAverageSpeed() {
+ return averageSpeed;
+ }
+
+ public int getReasonableSpeedInRemainDist() {
+ return reasonableSpeedInRemainDist;
+ }
+
+ public int getDistance() {
+ return distance;
+ }
+
+ public int[] getSpeed() {
+ return speed;
+ }
+}
diff --git a/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/wrapper/AMapNaviLocationWrapper.java b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/wrapper/AMapNaviLocationWrapper.java
new file mode 100644
index 0000000000..0bba71fdd9
--- /dev/null
+++ b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/wrapper/AMapNaviLocationWrapper.java
@@ -0,0 +1,148 @@
+package com.mogo.module.navi.wrapper;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import com.amap.api.navi.model.AMapNaviLocation;
+import com.amap.api.navi.model.NaviLatLng;
+
+/**
+ * @author congtaowang
+ * @since 2019-09-26
+ *
+ * 描述
+ */
+public class AMapNaviLocationWrapper implements Parcelable {
+
+ private final float accuracy;
+ private final double altitude;
+ private final float bearing;
+ private final float speed;
+ private final long time;
+ private final int matchStatus;
+ private final NaviLatLng coord;
+ private final int curStepIndex;
+ private final int curLinkIndex;
+ private final int curPointIndex;
+ private final int type;
+
+ public AMapNaviLocationWrapper( AMapNaviLocation aMapNaviLocation ) {
+ this.accuracy = aMapNaviLocation.getAccuracy();
+ this.altitude = aMapNaviLocation.getAltitude();
+ this.bearing = aMapNaviLocation.getBearing();
+ this.speed = aMapNaviLocation.getSpeed();
+ this.time = aMapNaviLocation.getTime();
+ this.matchStatus = aMapNaviLocation.getMatchStatus();
+ this.coord = aMapNaviLocation.getCoord();
+ this.curStepIndex = aMapNaviLocation.getCurStepIndex();
+ this.curLinkIndex = aMapNaviLocation.getCurLinkIndex();
+ this.curPointIndex = aMapNaviLocation.getCurPointIndex();
+ this.type = aMapNaviLocation.getType();
+ }
+
+ public AMapNaviLocation parse() {
+ final AMapNaviLocation inst = new AMapNaviLocation();
+ inst.setAccuracy( getAccuracy() );
+ inst.setAltitude( getAltitude() );
+ inst.setBearing( getBearing() );
+ inst.setSpeed( getSpeed() );
+ inst.setTime( getTime() );
+ inst.setMatchStatus( getMatchStatus() );
+ inst.setCoord( getCoord() );
+ inst.setCurStepIndex( getCurStepIndex() );
+ inst.setCurLinkIndex( getCurLinkIndex() );
+ inst.setCurPointIndex( getCurPointIndex() );
+ inst.setType( getType() );
+ return inst;
+ }
+
+ public float getAccuracy() {
+ return accuracy;
+ }
+
+ public double getAltitude() {
+ return altitude;
+ }
+
+ public float getBearing() {
+ return bearing;
+ }
+
+ public float getSpeed() {
+ return speed;
+ }
+
+ public long getTime() {
+ return time;
+ }
+
+ public int getMatchStatus() {
+ return matchStatus;
+ }
+
+ public NaviLatLng getCoord() {
+ return coord;
+ }
+
+ public int getCurStepIndex() {
+ return curStepIndex;
+ }
+
+ public int getCurLinkIndex() {
+ return curLinkIndex;
+ }
+
+ public int getCurPointIndex() {
+ return curPointIndex;
+ }
+
+ public int getType() {
+ return type;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel( Parcel dest, int flags ) {
+ dest.writeFloat( this.accuracy );
+ dest.writeDouble( this.altitude );
+ dest.writeFloat( this.bearing );
+ dest.writeFloat( this.speed );
+ dest.writeLong( this.time );
+ dest.writeInt( this.matchStatus );
+ dest.writeParcelable( this.coord, flags );
+ dest.writeInt( this.curStepIndex );
+ dest.writeInt( this.curLinkIndex );
+ dest.writeInt( this.curPointIndex );
+ dest.writeInt( this.type );
+ }
+
+ protected AMapNaviLocationWrapper( Parcel in ) {
+ this.accuracy = in.readFloat();
+ this.altitude = in.readDouble();
+ this.bearing = in.readFloat();
+ this.speed = in.readFloat();
+ this.time = in.readLong();
+ this.matchStatus = in.readInt();
+ this.coord = in.readParcelable( NaviLatLng.class.getClassLoader() );
+ this.curStepIndex = in.readInt();
+ this.curLinkIndex = in.readInt();
+ this.curPointIndex = in.readInt();
+ this.type = in.readInt();
+ }
+
+ public static final Creator< AMapNaviLocationWrapper >
+ CREATOR = new Parcelable.Creator< AMapNaviLocationWrapper >() {
+ @Override
+ public AMapNaviLocationWrapper createFromParcel( Parcel source ) {
+ return new AMapNaviLocationWrapper( source );
+ }
+
+ @Override
+ public AMapNaviLocationWrapper[] newArray( int size ) {
+ return new AMapNaviLocationWrapper[size];
+ }
+ };
+}
diff --git a/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/wrapper/LatLngWrapper.java b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/wrapper/LatLngWrapper.java
new file mode 100644
index 0000000000..e8dedf1ef8
--- /dev/null
+++ b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/wrapper/LatLngWrapper.java
@@ -0,0 +1,104 @@
+package com.mogo.module.navi.wrapper;
+
+import android.location.Location;
+import android.os.Parcel;
+import android.os.Parcelable;
+import com.amap.api.maps.model.LatLng;
+import com.amap.api.navi.model.AMapNaviLocation;
+import com.amap.api.navi.model.NaviLatLng;
+
+/**
+ * @author congtaowang
+ * @since 2019-09-26
+ *
+ * 经纬度
+ */
+public class LatLngWrapper implements Parcelable {
+
+ private final double lat;
+ private final double lng;
+
+ public LatLngWrapper( double lat, double lng ) {
+ this.lat = lat;
+ this.lng = lng;
+ }
+
+ public double getLat() {
+ return lat;
+ }
+
+ public double getLng() {
+ return lng;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel( Parcel dest, int flags ) {
+ dest.writeDouble( this.lat );
+ dest.writeDouble( this.lng );
+ }
+
+ protected LatLngWrapper( Parcel in ) {
+ this.lat = in.readDouble();
+ this.lng = in.readDouble();
+ }
+
+ public static final Creator< LatLngWrapper > CREATOR = new Creator< LatLngWrapper >() {
+ @Override
+ public LatLngWrapper createFromParcel( Parcel source ) {
+ return new LatLngWrapper( source );
+ }
+
+ @Override
+ public LatLngWrapper[] newArray( int size ) {
+ return new LatLngWrapper[size];
+ }
+ };
+
+ public static LatLngWrapper from( LatLng latlng ) {
+ return new LatLngWrapper( latlng.latitude, latlng.longitude );
+ }
+
+ public static LatLngWrapper from( NaviLatLng latlng ) {
+ return new LatLngWrapper( latlng.getLatitude(), latlng.getLongitude() );
+ }
+
+ public static LatLngWrapper from( AMapNaviLocation latlng ) {
+ return from( latlng.getCoord() );
+ }
+
+ public LatLng parseLatLngInst() {
+ return new LatLng( getLat(), getLng() );
+ }
+
+ public static LatLng parse( NaviLatLng latLng ) {
+ if ( latLng == null ) {
+ return null;
+ }
+ return new LatLng( latLng.getLatitude(), latLng.getLongitude() );
+ }
+
+ public static LatLng parse( Location location ) {
+ if ( location == null ) {
+ return null;
+ }
+ return new LatLng( location.getLatitude(), location.getLongitude() );
+ }
+
+ public static LatLng parse( double lat, double lng ) {
+ if ( isRightLatLng( lat, lng ) ) {
+ return new LatLng( lat, lng );
+ }
+ return null;
+ }
+
+ public static boolean isRightLatLng( double lat, double lng ) {
+ return lat > 0 && lat < 90 && lng > 0 && lng < 180;
+ }
+
+
+}
diff --git a/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/wrapper/NaviInfoWrapper.java b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/wrapper/NaviInfoWrapper.java
new file mode 100644
index 0000000000..7ec2849867
--- /dev/null
+++ b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/wrapper/NaviInfoWrapper.java
@@ -0,0 +1,116 @@
+package com.mogo.module.navi.wrapper;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import com.amap.api.navi.model.NaviInfo;
+
+/**
+ * @author congtaowang
+ * @since 2019-09-29
+ *
+ * 导航信息对象
+ */
+public class NaviInfoWrapper implements Parcelable {
+
+ private static final NaviInfoWrapper INST = new NaviInfoWrapper();
+
+ private int nextIconType;
+ private int nextDistance;
+ private String nextRoad;
+ private int surplusDistance;
+ private int surplusTime;
+ private int currentSpeed;
+
+ private NaviInfoWrapper() {
+
+ }
+
+ public static NaviInfoWrapper getInst() {
+ return INST;
+ }
+
+ public synchronized NaviInfoWrapper fillWith( NaviInfo naviInfo ) {
+ INST.nextIconType = naviInfo.getIconType();
+ INST.nextDistance = naviInfo.getCurStepRetainDistance();
+ INST.nextRoad = naviInfo.getNextRoadName();
+ INST.surplusDistance = naviInfo.getPathRetainDistance();
+ INST.surplusTime = naviInfo.getPathRetainTime();
+ INST.currentSpeed = naviInfo.getCurrentSpeed();
+ return INST;
+ }
+
+ public NaviInfoWrapper( NaviInfo naviInfo ) {
+ this.nextIconType = naviInfo.getIconType();
+ this.nextDistance = naviInfo.getCurStepRetainDistance();
+ this.nextRoad = naviInfo.getNextRoadName();
+ this.surplusDistance = naviInfo.getPathRetainDistance();
+ this.surplusTime = naviInfo.getPathRetainTime();
+ this.currentSpeed = naviInfo.getCurrentSpeed();
+ }
+
+ public synchronized int getNextIconType() {
+ return nextIconType;
+ }
+
+ public synchronized int getNextDistance() {
+ return nextDistance;
+ }
+
+ public synchronized String getNextRoad() {
+ return nextRoad;
+ }
+
+ public synchronized int getSurplusDistance() {
+ return surplusDistance;
+ }
+
+ public synchronized int getSurplusTime() {
+ return surplusTime;
+ }
+
+ public synchronized int getCurrentSpeed() {
+ return currentSpeed;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel( Parcel dest, int flags ) {
+ dest.writeInt( getNextIconType() );
+ dest.writeInt( getNextDistance() );
+ dest.writeString( getNextRoad() );
+ dest.writeInt( getSurplusDistance() );
+ dest.writeInt( getSurplusTime() );
+ dest.writeInt( getCurrentSpeed() );
+ }
+
+ protected NaviInfoWrapper( Parcel in ) {
+ this.nextIconType = in.readInt();
+ this.nextDistance = in.readInt();
+ this.nextRoad = in.readString();
+ this.surplusDistance = in.readInt();
+ this.surplusTime = in.readInt();
+ this.currentSpeed = in.readInt();
+ }
+
+ public static final Creator< NaviInfoWrapper > CREATOR = new Parcelable.Creator< NaviInfoWrapper >() {
+ @Override
+ public NaviInfoWrapper createFromParcel( Parcel source ) {
+ return new NaviInfoWrapper( source );
+ }
+
+ @Override
+ public NaviInfoWrapper[] newArray( int size ) {
+ return new NaviInfoWrapper[size];
+ }
+ };
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ return builder.toString();
+ }
+}
diff --git a/modules/mogo-module-navi/src/main/res/drawable/amap_white_shadow_bkg.9.png b/modules/mogo-module-navi/src/main/res/drawable/amap_white_shadow_bkg.9.png
new file mode 100644
index 0000000000..0c5f028dbe
Binary files /dev/null and b/modules/mogo-module-navi/src/main/res/drawable/amap_white_shadow_bkg.9.png differ
diff --git a/modules/mogo-module-navi/src/main/res/layout/fragment_search.xml b/modules/mogo-module-navi/src/main/res/layout/fragment_search.xml
new file mode 100644
index 0000000000..dfa977c77f
--- /dev/null
+++ b/modules/mogo-module-navi/src/main/res/layout/fragment_search.xml
@@ -0,0 +1,137 @@
+
+> getLastN(int limit);
+
+ @Query( "SELECT * FROM " + DataConstants.T_SEARCH_POI + " WHERE type=" + DataConstants.TYPE_POI )
+ Single
> getAll();
+
+ @Query( "SELECT * FROM " + DataConstants.T_SEARCH_POI + " WHERE type=" + DataConstants.TYPE_HOME_ADDRESS )
+ Single
> getHomeAddress();
+
+ @Query( "SELECT * FROM " + DataConstants.T_SEARCH_POI + " WHERE type=" + DataConstants.TYPE_COMPANY_ADDRESS )
+ Single
> getCompanyAddress();
+
+ @Delete
+ int delete(SearchPoi poi);
+
+ @Delete
+ int deleteAll(List
> load();
-}
diff --git a/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/lib/AMapNaviStatusChangedListener.java b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/lib/AMapNaviStatusChangedListener.java
new file mode 100644
index 0000000000..60d98b8933
--- /dev/null
+++ b/modules/mogo-module-navi/src/main/java/com/mogo/module/navi/lib/AMapNaviStatusChangedListener.java
@@ -0,0 +1,19 @@
+package com.mogo.module.navi.lib;
+
+import com.amap.api.maps.AMap;
+import com.amap.api.navi.AMapNaviListener;
+import com.amap.api.navi.AMapNaviViewListener;
+import com.mogo.module.navi.database.wrapper.NaviInfoWrapper;
+
+/**
+ * @author congtaowang
+ * @since 2019-09-27
+ *
>create( emitter -> {
+ SearchPoi poi = EntityConvertUtils.tipToPoi( tip );
+ emitterCommonAddress( emitter, poi );
+ } ).subscribeOn( Schedulers.io() ).observeOn( AndroidSchedulers.mainThread() );
+ }
+
+ /**
+ * 缓存地理位置常用地址设置
+ *
+ * @param location
+ * @return
+ */
+ public Single cacheCommonAddressPoi( AMapLocation location ) {
+ return Single.
+
>create( emitter -> {
+ SearchPoi poi = EntityConvertUtils.aMapLocation2Poi( location );
+ emitterCommonAddress( emitter, poi );
+ } )
+ .subscribeOn( Schedulers.io() )
+ .observeOn( AndroidSchedulers.mainThread() );
+ }
+
+ /**
+ * 缓存反地理位置编码常用地址设置
+ *
+ * @param address
+ * @return
+ */
+ public Single cacheCommonAddressPoi( RegeocodeAddress address ) {
+
+ return Single.
+
>create( emitter -> {
+ SearchPoi poi = EntityConvertUtils.geocodeAddress2Poi( address, mLastCameraPosition );
+ emitterCommonAddress( emitter, poi );
+ } )
+ .subscribeOn( Schedulers.io() )
+ .observeOn( AndroidSchedulers.mainThread() );
+ }
+
+ private void emitterCommonAddress( SingleEmitter
> emitter, SearchPoi poi ) {
+ String poiId = null;
+ switch ( mView.getSearchType() ) {
+ case SearchConstants.SEARCH_TYPE_MULTI_HOME:
+ poiId = DataConstants.POI_ID_HOME;
+ break;
+ case SearchConstants.SEARCH_TYPE_MULTI_COMPANY:
+ poiId = DataConstants.POI_ID_COMPANY;
+ break;
+ }
+ if ( TextUtils.isEmpty( poiId ) ) {
+ emitter.onError( new IllegalArgumentException( "设置类型错误,请重试" ) );
+ return;
+ }
+ if ( poi == null ) {
+ emitter.onError( new IllegalArgumentException( "位置类型转换错误,请重试" ) );
+ return;
+ }
+ poi.setpId( poiId );
+ poi.setType( mView.getSearchType() );
+ //ignore insert result
+ final List