Merge branch 'feat_overview_mode_290' into dev_robotaxi-d-app-module_290_220715_2.9.0
全览模式合并到远端290
@@ -61,12 +61,14 @@ dependencies {
|
||||
implementation rootProject.ext.dependencies.modulecommon
|
||||
implementation rootProject.ext.dependencies.mogo_core_data
|
||||
implementation rootProject.ext.dependencies.mogo_core_function_call
|
||||
implementation rootProject.ext.dependencies.mogo_core_function_hmi
|
||||
}else {
|
||||
implementation project(":core:mogo-core-utils")
|
||||
implementation project(":foudations:mogo-commons")
|
||||
implementation project(':modules:mogo-module-common')
|
||||
implementation project(':core:mogo-core-data')
|
||||
implementation project(':core:mogo-core-function-call')
|
||||
implementation project(':core:function-impl:mogo-core-function-hmi')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ import com.mogo.eagle.core.function.call.autopilot.CallerAutoPilotStatusListener
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutopilotRecordListenerManager;
|
||||
import com.mogo.eagle.core.function.call.devatools.CallerDevaToolsManager;
|
||||
import com.mogo.eagle.core.function.call.hmi.CallerHmiManager;
|
||||
import com.mogo.eagle.core.function.hmi.ui.widget.TrafficDataView;
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger;
|
||||
import com.mogo.eagle.core.utilcode.util.ToastUtils;
|
||||
import com.mogo.eagle.core.utilcode.util.UiThreadHandler;
|
||||
@@ -76,7 +77,8 @@ public abstract class BaseBusTabFragment<V extends IView, P extends Presenter<V>
|
||||
private FrameLayout flStationPanelContainer;
|
||||
private Group groupTestPanel;
|
||||
private FrameLayout flSpeed;
|
||||
private BusArcView mouduleArc;
|
||||
// private BusArcView mouduleArc;
|
||||
private TrafficDataView mTrafficDataView;
|
||||
private ImageView mUpgradeTipIv;
|
||||
// private BusTrafficLightView mTrafficLightView;
|
||||
|
||||
@@ -122,7 +124,7 @@ public abstract class BaseBusTabFragment<V extends IView, P extends Presenter<V>
|
||||
tvOperationStatus = findViewById(R.id.module_mogo_och_operation_status);
|
||||
|
||||
flSpeed = (FrameLayout) findViewById(R.id.fl_speed);
|
||||
mouduleArc = (BusArcView) findViewById(R.id.bus_arc);
|
||||
mTrafficDataView = (TrafficDataView) findViewById(R.id.bus_arc);
|
||||
|
||||
panelView = LayoutInflater.from(getContext()).inflate(getStationPanelViewId(), flStationPanelContainer);
|
||||
slidePanelView.setOnSlidePanelMoveToEndListener(onSlideToEndListener);
|
||||
@@ -150,8 +152,8 @@ public abstract class BaseBusTabFragment<V extends IView, P extends Presenter<V>
|
||||
});
|
||||
|
||||
if (DebugConfig.isDebug()) {
|
||||
mouduleArc.setLongClickable(true);
|
||||
mouduleArc.setOnLongClickListener(v -> {
|
||||
mTrafficDataView.setLongClickable(true);
|
||||
mTrafficDataView.setOnLongClickListener(v -> {
|
||||
CallerLogger.INSTANCE.d(M_BUS + TAG, "长按显示状态工具栏");
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra("oper", 52);
|
||||
@@ -483,9 +485,9 @@ public abstract class BaseBusTabFragment<V extends IView, P extends Presenter<V>
|
||||
*/
|
||||
public void updateSpeedView(float newSpeed) {
|
||||
int speed = (int) (Math.abs(newSpeed) * 3.6F); // 倒车时工控机反馈定位信息中speed为负值
|
||||
mouduleArc.setArcColor(Color.parseColor(speed > 60 ? "#DB3137" : "#3E77F6"));
|
||||
mouduleArc.setValues(speed);
|
||||
flSpeed.setBackgroundResource(speed > 60 ? R.drawable.bus_yi_biao_pan_bg_speeding : R.drawable.bus_yi_biao_pan_bg_nor);
|
||||
if (mTrafficDataView != null){
|
||||
mTrafficDataView.updateSpeedWithValue(speed);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -5,23 +5,22 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="@dimen/dp_72">
|
||||
<FrameLayout
|
||||
android:id="@+id/fl_speed"
|
||||
android:layout_width="@dimen/bus_ext_speed_width"
|
||||
android:layout_height="@dimen/bus_ext_speed_height"
|
||||
android:layout_marginLeft="@dimen/module_mogo_och_margin_left"
|
||||
android:layout_marginTop="@dimen/module_mogo_och_margin_left"
|
||||
android:background="@drawable/bus_yi_biao_pan_bg_nor"
|
||||
android:elevation="@dimen/bus_dp_10"
|
||||
android:padding="@dimen/bus_dp_20"
|
||||
android:visibility="visible"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
<FrameLayout
|
||||
android:id="@+id/fl_speed"
|
||||
android:layout_width="@dimen/dp_616"
|
||||
android:layout_height="@dimen/dp_320"
|
||||
android:layout_marginLeft="@dimen/dp_10"
|
||||
android:layout_marginTop="@dimen/dp_40"
|
||||
android:elevation="@dimen/bus_dp_10"
|
||||
android:padding="@dimen/bus_dp_20"
|
||||
android:visibility="visible"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<com.mogo.och.bus.view.BusArcView
|
||||
<com.mogo.eagle.core.function.hmi.ui.widget.TrafficDataView
|
||||
android:id="@+id/bus_arc"
|
||||
android:layout_width="@dimen/bus_ext_arcView_width"
|
||||
android:layout_height="@dimen/bus_ext_arcView_height"
|
||||
android:layout_width="@dimen/dp_616"
|
||||
android:layout_height="@dimen/dp_320"
|
||||
android:layout_gravity="center" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
@@ -104,9 +104,9 @@
|
||||
<dimen name="bus_ext_arcView_stroke_with">20px</dimen>
|
||||
<dimen name="bus_ext_arcView_top">40px</dimen>
|
||||
<dimen name="bus_ext_arcView_width">320px</dimen>
|
||||
<dimen name="bus_ext_speed_height">460px</dimen>
|
||||
<dimen name="bus_ext_speed_height">320px</dimen>
|
||||
<dimen name="bus_ext_speed_padding">70px</dimen>
|
||||
<dimen name="bus_ext_speed_width">460px</dimen>
|
||||
<dimen name="bus_ext_speed_width">616px</dimen>
|
||||
<dimen name="bus_ext_speed_width_big_radius">130px</dimen>
|
||||
<dimen name="bus_ext_speed_width_sm_radius">30px</dimen>
|
||||
<dimen name="bus_switch_map">279px</dimen>
|
||||
|
||||
@@ -0,0 +1,265 @@
|
||||
package com.mogo.och.taxi.passenger.ui.video
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.RelativeLayout
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.request.RequestOptions
|
||||
import com.bumptech.glide.request.target.SimpleTarget
|
||||
import com.bumptech.glide.request.transition.Transition
|
||||
import com.mogo.eagle.core.utilcode.util.ToastUtils
|
||||
import com.mogo.och.taxi.passenger.R
|
||||
import com.mogo.och.taxi.passenger.bean.TaxiPassengerVideoPlay
|
||||
import com.mogo.och.taxi.passenger.ui.video.layoutmanage.CarouselLayoutManager
|
||||
import com.mogo.och.taxi.passenger.ui.video.layoutmanage.CarouselZoomPostLayoutListener
|
||||
import com.mogo.och.taxi.passenger.ui.video.layoutmanage.CenterScrollListener
|
||||
import com.mogo.och.taxi.passenger.utils.blur.GlideBlurTransform
|
||||
import com.mogo.och.taxi.passenger.widget.ConsultVideoPlayer
|
||||
import com.mogo.och.taxi.passenger.widget.indicator.IndicatorView
|
||||
import com.mogo.och.taxi.passenger.widget.indicator.enums.IndicatorOrientation
|
||||
import com.mogo.och.taxi.passenger.widget.indicator.enums.IndicatorSlideMode
|
||||
import com.mogo.och.taxi.passenger.widget.indicator.enums.IndicatorStyle
|
||||
import com.shuyu.gsyvideoplayer.listener.GSYSampleCallBack
|
||||
import com.shuyu.gsyvideoplayer.video.base.GSYVideoView
|
||||
import java.util.*
|
||||
import kotlin.math.floor
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* 蘑菇咨询
|
||||
* Created on 2022/5/16
|
||||
*/
|
||||
class TaxiPassengerMogoConsultView :RelativeLayout {
|
||||
|
||||
constructor(context: Context?) : super(context)
|
||||
|
||||
constructor(context: Context?, attributeSet: AttributeSet) : super(context, attributeSet)
|
||||
|
||||
constructor(context: Context?, attributeSet: AttributeSet, defStyleAttr: Int) : super(context, attributeSet, defStyleAttr)
|
||||
|
||||
constructor(context: Context?, attributeSet: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attributeSet, defStyleAttr, defStyleRes)
|
||||
|
||||
private lateinit var rvVideoPlaylist: RecyclerView
|
||||
private lateinit var indicatorView: IndicatorView
|
||||
private lateinit var clContain: ConstraintLayout
|
||||
|
||||
private fun initView(context: Context) {
|
||||
LayoutInflater.from(context).inflate(R.layout.taxi_p_arrived_mogo_consult, this, true)
|
||||
rvVideoPlaylist = findViewById(R.id.rv_video_playlist)
|
||||
indicatorView = findViewById(R.id.indicatorView)
|
||||
clContain = findViewById(R.id.cl_contain)
|
||||
|
||||
val arrayListOf = ArrayList<TaxiPassengerVideoPlay>()
|
||||
arrayListOf.add(TaxiPassengerVideoPlay("https://img.zhidaohulian.com/fileServer/online_car_hailing/1655708409810/20210610重新排版3屏.m4v","https://img.zhidaohulian.com/fileServer/online_car_hailing/1655969579713/三屏.png","重新排版"))
|
||||
arrayListOf.add(TaxiPassengerVideoPlay("https://img.zhidaohulian.com/fileServer/online_car_hailing/1655708499497/大运会合作解说版.m4v","https://img.zhidaohulian.com/fileServer/online_car_hailing/1655969536177/大运会.png","大运会"))
|
||||
arrayListOf.add(TaxiPassengerVideoPlay("https://img.zhidaohulian.com/fileServer/online_car_hailing/1655708554279/红旗车队.m4v","https://img.zhidaohulian.com/fileServer/online_car_hailing/1655969553174/红旗重新排版.png","红旗车队"))
|
||||
arrayListOf.add(TaxiPassengerVideoPlay("https://img.zhidaohulian.com/fileServer/online_car_hailing/1655708596763/全车型混剪增加红旗车队.m4v","https://img.zhidaohulian.com/fileServer/online_car_hailing/1655969511280/车队.png","全车型混剪增加红旗车队"))
|
||||
val recyclerVideoAdapter = RecyclerVideoAdapter(context, arrayListOf)
|
||||
val carouselLayoutManager = CarouselLayoutManager(CarouselLayoutManager.HORIZONTAL, true)
|
||||
carouselLayoutManager.setPostLayoutListener(CarouselZoomPostLayoutListener ())
|
||||
carouselLayoutManager.maxVisibleItems = 1
|
||||
indicatorView.notifyDataChanged(arrayListOf.size)
|
||||
indicatorView.setSlideMode(IndicatorSlideMode.SCALE)
|
||||
indicatorView.setOrientation(IndicatorOrientation.INDICATOR_HORIZONTAL)
|
||||
indicatorView.setIndicatorStyle(IndicatorStyle.ROUND_RECT)
|
||||
indicatorView.setSliderColor(Color.parseColor("#80FFFFFF"), Color.parseColor("#2972FF"))
|
||||
indicatorView.setSliderWidth(16f, 101f)
|
||||
indicatorView.setSliderHeight(16f)
|
||||
indicatorView.setSliderGap(30f)
|
||||
rvVideoPlaylist.addOnScrollListener(object: CenterScrollListener() {
|
||||
var prePlayerPosition = 0
|
||||
override fun pageSelect(recyclerView: RecyclerView?, newState: Int) {
|
||||
//播放视频
|
||||
val (centerItemPosition: Int, player) = getPlayer(carouselLayoutManager)
|
||||
indicatorView.onPageSelected(centerItemPosition)
|
||||
if(player is ConsultVideoPlayer){
|
||||
if(prePlayerPosition!=centerItemPosition) {
|
||||
if(player.currentState==GSYVideoView.CURRENT_STATE_PAUSE){
|
||||
player.onVideoReset()
|
||||
}else{
|
||||
}
|
||||
val playerHolder = carouselLayoutManager.findViewByPosition(prePlayerPosition)
|
||||
val prePlayer = playerHolder?.findViewById<ConsultVideoPlayer>(R.id.video_item_player)
|
||||
prePlayer?.let {
|
||||
if(it is ConsultVideoPlayer){
|
||||
it.onVideoReset()
|
||||
}
|
||||
}
|
||||
val taxiPassengerVideoPlay = arrayListOf[centerItemPosition]
|
||||
if (player.getVideoAllCallBack()==null) {
|
||||
setBackageAndPlayNext(taxiPassengerVideoPlay, player, centerItemPosition)
|
||||
}
|
||||
}else{
|
||||
player.onVideoResume(false)
|
||||
}
|
||||
}
|
||||
prePlayerPosition = centerItemPosition
|
||||
}
|
||||
|
||||
override fun pageStop() {
|
||||
val (centerItemPosition: Int, player) = getPlayer(carouselLayoutManager)
|
||||
if(player is ConsultVideoPlayer){
|
||||
player.onVideoPause()
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
carouselLayoutManager.addOnDargAutoDiffListener { adapterPosition, currentPosition ->
|
||||
val fl = adapterPosition - floor(adapterPosition)
|
||||
var currentIndex = currentPosition
|
||||
if(fl>0.5){
|
||||
if(currentPosition==0){
|
||||
currentIndex = rvVideoPlaylist.adapter!!.itemCount-1
|
||||
}else {
|
||||
currentIndex -= 1
|
||||
}
|
||||
}
|
||||
indicatorView.onPageScrolled(currentIndex, fl, 0)
|
||||
}
|
||||
recyclerVideoAdapter.setOnThumbImageClilckListener {
|
||||
val (centerItemPosition: Int, player) = getPlayer(carouselLayoutManager)
|
||||
if(player is ConsultVideoPlayer) {
|
||||
player.onVideoReset()
|
||||
player.thumbImageViewLayout.visibility = View.VISIBLE
|
||||
}
|
||||
rvVideoPlaylist.smoothScrollToPosition(it)
|
||||
}
|
||||
rvVideoPlaylist.layoutManager = carouselLayoutManager
|
||||
rvVideoPlaylist.setHasFixedSize(true)
|
||||
rvVideoPlaylist.adapter = recyclerVideoAdapter
|
||||
}
|
||||
|
||||
private fun setBackageAndPlayNext(
|
||||
taxiPassengerVideoPlay: TaxiPassengerVideoPlay,
|
||||
player: ConsultVideoPlayer,
|
||||
centerItemPosition: Int,
|
||||
) {
|
||||
// 设置背景图片
|
||||
Glide.with(context).asBitmap()
|
||||
.load(taxiPassengerVideoPlay.imageUrl)
|
||||
.apply(
|
||||
RequestOptions().transform(
|
||||
GlideBlurTransform(context, taxiPassengerVideoPlay.imageUrl, 5)
|
||||
)
|
||||
)
|
||||
.into(object : SimpleTarget<Bitmap?>() {
|
||||
override fun onResourceReady(
|
||||
resource: Bitmap,
|
||||
transition: Transition<in Bitmap?>?
|
||||
) {
|
||||
clContain.background = BitmapDrawable(context.resources, resource)
|
||||
}
|
||||
})
|
||||
if(player.getVideoAllCallBack()==null) {
|
||||
player.setVideoAllCallBack(object : GSYSampleCallBack() {
|
||||
override fun onAutoComplete(url: String?, vararg objects: Any?) {
|
||||
player.onVideoReset()
|
||||
val itemCount = rvVideoPlaylist.adapter?.itemCount
|
||||
itemCount?.let {
|
||||
if (centerItemPosition == itemCount - 1) {
|
||||
rvVideoPlaylist.smoothScrollToPosition(0)
|
||||
} else {
|
||||
rvVideoPlaylist.smoothScrollToPosition(centerItemPosition + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onClickBlank(url: String?, vararg objects: Any?) {
|
||||
super.onClickBlank(url, *objects)
|
||||
rvVideoPlaylist.smoothScrollToPosition(centerItemPosition)
|
||||
}
|
||||
|
||||
override fun onPlayError(url: String?, vararg objects: Any?) {
|
||||
super.onPlayError(url, *objects)
|
||||
ToastUtils.showLong("哎呀,出错了,看看其他视频吧")
|
||||
}
|
||||
|
||||
override fun onClickStartError(url: String?, vararg objects: Any?) {
|
||||
super.onClickStartError(url, *objects)
|
||||
ToastUtils.showLong("哎呀,出错了,看看其他视频吧")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun onWindowFocusChanged(hasWindowFocus: Boolean) {
|
||||
super.onWindowFocusChanged(hasWindowFocus)
|
||||
val carouselLayoutManager = rvVideoPlaylist.layoutManager as CarouselLayoutManager
|
||||
val (centerItemPosition: Int, player) = getPlayer(carouselLayoutManager)
|
||||
player?.let {
|
||||
if (player is ConsultVideoPlayer) {
|
||||
if(hasWindowFocus){// 获取焦点两种情况
|
||||
// 恢复播放和开始播放
|
||||
if(player.isIfCurrentIsFullscreen){// 全屏了
|
||||
|
||||
}else {
|
||||
when (player.currentState) {
|
||||
GSYVideoView.CURRENT_STATE_PAUSE -> {
|
||||
player.onVideoResume(false)
|
||||
}
|
||||
GSYVideoView.CURRENT_STATE_PLAYING -> {
|
||||
}
|
||||
else -> {
|
||||
val recyclerVideoAdapter =
|
||||
rvVideoPlaylist.adapter as RecyclerVideoAdapter
|
||||
setBackageAndPlayNext(
|
||||
recyclerVideoAdapter.getItemByPosition(centerItemPosition),
|
||||
player, centerItemPosition
|
||||
)
|
||||
//player.startPlayLogic()
|
||||
}
|
||||
}
|
||||
}
|
||||
}else {
|
||||
// 离开应用 暂停视频
|
||||
// 关闭 onDetachedFromWindow 会reset
|
||||
if(player.isIfCurrentIsFullscreen){// 全屏了
|
||||
|
||||
}else {
|
||||
player.onVideoPause()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun getPlayer(carouselLayoutManager: CarouselLayoutManager): Pair<Int, ConsultVideoPlayer?> {
|
||||
val centerItemPosition: Int = carouselLayoutManager.centerItemPosition
|
||||
val playerHolder = carouselLayoutManager.findViewByPosition(centerItemPosition)
|
||||
val player = playerHolder?.findViewById<ConsultVideoPlayer>(R.id.video_item_player)
|
||||
return Pair(centerItemPosition, player)
|
||||
}
|
||||
|
||||
|
||||
override fun onDetachedFromWindow() {
|
||||
val carouselLayoutManager = rvVideoPlaylist.layoutManager as CarouselLayoutManager
|
||||
val (_: Int, player) = getPlayer(carouselLayoutManager)
|
||||
player?.let {
|
||||
if(player is ConsultVideoPlayer){
|
||||
player.currentPlayer.release()
|
||||
player.onVideoReset()
|
||||
}
|
||||
}
|
||||
super.onDetachedFromWindow()
|
||||
}
|
||||
|
||||
init {
|
||||
try {
|
||||
initView(context)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,268 @@
|
||||
package com.mogo.och.taxi.passenger.ui.video
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.RelativeLayout
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.request.RequestOptions
|
||||
import com.bumptech.glide.request.target.SimpleTarget
|
||||
import com.bumptech.glide.request.transition.Transition
|
||||
import com.mogo.eagle.core.utilcode.util.ToastUtils
|
||||
import com.mogo.och.taxi.passenger.R
|
||||
import com.mogo.och.taxi.passenger.bean.TaxiPassengerVideoPlay
|
||||
import com.mogo.och.taxi.passenger.ui.video.layoutmanage.CarouselLayoutManager
|
||||
import com.mogo.och.taxi.passenger.ui.video.layoutmanage.CarouselZoomPostLayoutListener
|
||||
import com.mogo.och.taxi.passenger.ui.video.layoutmanage.CenterScrollListener
|
||||
import com.mogo.och.taxi.passenger.utils.blur.GlideBlurTransform
|
||||
import com.mogo.och.taxi.passenger.widget.ConsultVideoPlayer
|
||||
import com.mogo.och.taxi.passenger.widget.indicator.IndicatorView
|
||||
import com.mogo.och.taxi.passenger.widget.indicator.enums.IndicatorOrientation
|
||||
import com.mogo.och.taxi.passenger.widget.indicator.enums.IndicatorSlideMode
|
||||
import com.mogo.och.taxi.passenger.widget.indicator.enums.IndicatorStyle
|
||||
import com.shuyu.gsyvideoplayer.listener.GSYSampleCallBack
|
||||
import com.shuyu.gsyvideoplayer.video.base.GSYVideoView
|
||||
import java.util.*
|
||||
import kotlin.math.floor
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* 蘑菇咨询
|
||||
* Created on 2022/5/16
|
||||
*/
|
||||
class TaxiPassengerMogoMoviesView :RelativeLayout {
|
||||
|
||||
constructor(context: Context?) : super(context)
|
||||
|
||||
constructor(context: Context?, attributeSet: AttributeSet) : super(context, attributeSet)
|
||||
|
||||
constructor(context: Context?, attributeSet: AttributeSet, defStyleAttr: Int) : super(context, attributeSet, defStyleAttr)
|
||||
|
||||
constructor(context: Context?, attributeSet: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attributeSet, defStyleAttr, defStyleRes)
|
||||
|
||||
private lateinit var rvVideoPlaylist: RecyclerView
|
||||
private lateinit var indicatorView: IndicatorView
|
||||
private lateinit var clContain: ConstraintLayout
|
||||
|
||||
private fun initView(context: Context) {
|
||||
LayoutInflater.from(context).inflate(R.layout.taxi_p_mogo_movies, this, true)
|
||||
rvVideoPlaylist = findViewById(R.id.rv_video_playlist)
|
||||
indicatorView = findViewById(R.id.indicatorView)
|
||||
clContain = findViewById(R.id.cl_contain)
|
||||
|
||||
val arrayListOf = ArrayList<TaxiPassengerVideoPlay>()
|
||||
arrayListOf.add(TaxiPassengerVideoPlay("https://img.zhidaohulian.com/fileServer/online_car_hailing/1655708409810/20210610重新排版3屏.m4v","https://img.zhidaohulian.com/fileServer/online_car_hailing/1655969579713/三屏.png","重新排版"))
|
||||
arrayListOf.add(TaxiPassengerVideoPlay("https://img.zhidaohulian.com/fileServer/online_car_hailing/1655708499497/大运会合作解说版.m4v","https://img.zhidaohulian.com/fileServer/online_car_hailing/1655969536177/大运会.png","大运会"))
|
||||
arrayListOf.add(TaxiPassengerVideoPlay("https://img.zhidaohulian.com/fileServer/online_car_hailing/1655708554279/红旗车队.m4v","https://img.zhidaohulian.com/fileServer/online_car_hailing/1655969553174/红旗重新排版.png","红旗车队"))
|
||||
arrayListOf.add(TaxiPassengerVideoPlay("https://img.zhidaohulian.com/fileServer/online_car_hailing/1655708596763/全车型混剪增加红旗车队.m4v","https://img.zhidaohulian.com/fileServer/online_car_hailing/1655969511280/车队.png","全车型混剪增加红旗车队"))
|
||||
val recyclerVideoAdapter = RecyclerVideoAdapter(context, arrayListOf)
|
||||
val carouselLayoutManager = CarouselLayoutManager(CarouselLayoutManager.HORIZONTAL, true)
|
||||
carouselLayoutManager.setPostLayoutListener(CarouselZoomPostLayoutListener ())
|
||||
carouselLayoutManager.maxVisibleItems = 1
|
||||
indicatorView.notifyDataChanged(arrayListOf.size)
|
||||
indicatorView.setSlideMode(IndicatorSlideMode.SCALE)
|
||||
indicatorView.setOrientation(IndicatorOrientation.INDICATOR_HORIZONTAL)
|
||||
indicatorView.setIndicatorStyle(IndicatorStyle.ROUND_RECT)
|
||||
indicatorView.setSliderColor(Color.parseColor("#80FFFFFF"), Color.parseColor("#2972FF"))
|
||||
indicatorView.setSliderWidth(14f, 90f)
|
||||
indicatorView.setSliderHeight(14f)
|
||||
rvVideoPlaylist.addOnScrollListener(object: CenterScrollListener() {
|
||||
var prePlayerPosition = 0
|
||||
override fun pageSelect(recyclerView: RecyclerView?, newState: Int) {
|
||||
//播放视频
|
||||
val (centerItemPosition: Int, player) = getPlayer(carouselLayoutManager)
|
||||
indicatorView.onPageSelected(centerItemPosition)
|
||||
if(player is ConsultVideoPlayer){
|
||||
if(prePlayerPosition!=centerItemPosition) {
|
||||
if(player.currentState==GSYVideoView.CURRENT_STATE_PAUSE){
|
||||
player.onVideoReset()
|
||||
}else{
|
||||
}
|
||||
val playerHolder = carouselLayoutManager.findViewByPosition(prePlayerPosition)
|
||||
val prePlayer = playerHolder?.findViewById<ConsultVideoPlayer>(R.id.video_item_player)
|
||||
prePlayer?.let {
|
||||
if(it is ConsultVideoPlayer){
|
||||
it.onVideoReset()
|
||||
}
|
||||
}
|
||||
val taxiPassengerVideoPlay = arrayListOf[centerItemPosition]
|
||||
if (player.getVideoAllCallBack()==null) {
|
||||
setBackageAndPlayNext(taxiPassengerVideoPlay, player, centerItemPosition)
|
||||
}
|
||||
}else{
|
||||
player.onVideoResume(false)
|
||||
}
|
||||
}
|
||||
prePlayerPosition = centerItemPosition
|
||||
}
|
||||
|
||||
override fun pageStop() {
|
||||
val (centerItemPosition: Int, player) = getPlayer(carouselLayoutManager)
|
||||
if(player is ConsultVideoPlayer){
|
||||
player.onVideoPause()
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
carouselLayoutManager.addOnDargAutoDiffListener { adapterPosition, currentPosition ->
|
||||
val fl = adapterPosition - floor(adapterPosition)
|
||||
var currentIndex = currentPosition
|
||||
if(fl>0.5){
|
||||
if(currentPosition==0){
|
||||
currentIndex = rvVideoPlaylist.adapter!!.itemCount-1
|
||||
}else {
|
||||
currentIndex -= 1
|
||||
}
|
||||
}
|
||||
indicatorView.onPageScrolled(currentIndex, fl, 0)
|
||||
}
|
||||
recyclerVideoAdapter.setOnThumbImageClilckListener {
|
||||
val (centerItemPosition: Int, player) = getPlayer(carouselLayoutManager)
|
||||
if(player is ConsultVideoPlayer) {
|
||||
player.onVideoReset()
|
||||
player.thumbImageViewLayout.visibility = View.VISIBLE
|
||||
}
|
||||
rvVideoPlaylist.smoothScrollToPosition(it)
|
||||
}
|
||||
rvVideoPlaylist.layoutManager = carouselLayoutManager
|
||||
rvVideoPlaylist.setHasFixedSize(true)
|
||||
rvVideoPlaylist.adapter = recyclerVideoAdapter
|
||||
}
|
||||
|
||||
private fun setBackageAndPlayNext(
|
||||
taxiPassengerVideoPlay: TaxiPassengerVideoPlay,
|
||||
player: ConsultVideoPlayer,
|
||||
centerItemPosition: Int,
|
||||
) {
|
||||
// 设置背景图片
|
||||
Glide.with(context).asBitmap()
|
||||
.load(taxiPassengerVideoPlay.imageUrl)
|
||||
.apply(
|
||||
RequestOptions().transform(
|
||||
GlideBlurTransform(
|
||||
context,
|
||||
taxiPassengerVideoPlay.imageUrl,
|
||||
5
|
||||
)
|
||||
)
|
||||
)
|
||||
.into(object : SimpleTarget<Bitmap?>() {
|
||||
override fun onResourceReady(
|
||||
resource: Bitmap,
|
||||
transition: Transition<in Bitmap?>?
|
||||
) {
|
||||
clContain.background = BitmapDrawable(context.resources, resource)
|
||||
}
|
||||
})
|
||||
if(player.getVideoAllCallBack()==null) {
|
||||
player.setVideoAllCallBack(object : GSYSampleCallBack() {
|
||||
override fun onAutoComplete(url: String?, vararg objects: Any?) {
|
||||
player.onVideoReset()
|
||||
val itemCount = rvVideoPlaylist.adapter?.itemCount
|
||||
itemCount?.let {
|
||||
if (centerItemPosition == itemCount - 1) {
|
||||
rvVideoPlaylist.smoothScrollToPosition(0)
|
||||
} else {
|
||||
rvVideoPlaylist.smoothScrollToPosition(centerItemPosition + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onClickBlank(url: String?, vararg objects: Any?) {
|
||||
super.onClickBlank(url, *objects)
|
||||
rvVideoPlaylist.smoothScrollToPosition(centerItemPosition)
|
||||
}
|
||||
|
||||
override fun onPlayError(url: String?, vararg objects: Any?) {
|
||||
super.onPlayError(url, *objects)
|
||||
ToastUtils.showLong("哎呀,出错了,看看其他视频吧")
|
||||
}
|
||||
|
||||
override fun onClickStartError(url: String?, vararg objects: Any?) {
|
||||
super.onClickStartError(url, *objects)
|
||||
ToastUtils.showLong("哎呀,出错了,看看其他视频吧")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun onWindowFocusChanged(hasWindowFocus: Boolean) {
|
||||
super.onWindowFocusChanged(hasWindowFocus)
|
||||
val carouselLayoutManager = rvVideoPlaylist.layoutManager as CarouselLayoutManager
|
||||
val (centerItemPosition: Int, player) = getPlayer(carouselLayoutManager)
|
||||
player?.let {
|
||||
if (player is ConsultVideoPlayer) {
|
||||
if(hasWindowFocus){// 获取焦点两种情况
|
||||
// 恢复播放和开始播放
|
||||
if(player.isIfCurrentIsFullscreen){// 全屏了
|
||||
|
||||
}else {
|
||||
when (player.currentState) {
|
||||
GSYVideoView.CURRENT_STATE_PAUSE -> {
|
||||
player.onVideoResume(false)
|
||||
}
|
||||
GSYVideoView.CURRENT_STATE_PLAYING -> {
|
||||
}
|
||||
else -> {
|
||||
val recyclerVideoAdapter =
|
||||
rvVideoPlaylist.adapter as RecyclerVideoAdapter
|
||||
setBackageAndPlayNext(
|
||||
recyclerVideoAdapter.getItemByPosition(centerItemPosition),
|
||||
player, centerItemPosition
|
||||
)
|
||||
//player.startPlayLogic()
|
||||
}
|
||||
}
|
||||
}
|
||||
}else {
|
||||
// 离开应用 暂停视频
|
||||
// 关闭 onDetachedFromWindow 会reset
|
||||
if(player.isIfCurrentIsFullscreen){// 全屏了
|
||||
|
||||
}else {
|
||||
player.onVideoPause()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun getPlayer(carouselLayoutManager: CarouselLayoutManager): Pair<Int, ConsultVideoPlayer?> {
|
||||
val centerItemPosition: Int = carouselLayoutManager.centerItemPosition
|
||||
val playerHolder = carouselLayoutManager.findViewByPosition(centerItemPosition)
|
||||
val player = playerHolder?.findViewById<ConsultVideoPlayer>(R.id.video_item_player)
|
||||
return Pair(centerItemPosition, player)
|
||||
}
|
||||
|
||||
|
||||
override fun onDetachedFromWindow() {
|
||||
val carouselLayoutManager = rvVideoPlaylist.layoutManager as CarouselLayoutManager
|
||||
val (_: Int, player) = getPlayer(carouselLayoutManager)
|
||||
player?.let {
|
||||
if(player is ConsultVideoPlayer){
|
||||
player.currentPlayer.release()
|
||||
player.onVideoReset()
|
||||
}
|
||||
}
|
||||
super.onDetachedFromWindow()
|
||||
}
|
||||
|
||||
init {
|
||||
try {
|
||||
initView(context)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,974 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.mogo.och.taxi.passenger.utils.blur;
|
||||
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.Closeable;
|
||||
import java.io.EOFException;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FilterOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* A cache that uses a bounded amount of space on a filesystem. Each cache
|
||||
* entry has a string key and a fixed number of values. Each key must match
|
||||
* the regex <strong>[a-z0-9_-]{1,64}</strong>. Values are byte sequences,
|
||||
* accessible as streams or files. Each value must be between {@code 0} and
|
||||
* {@code Integer.MAX_VALUE} bytes in length.
|
||||
*
|
||||
* <p>The cache stores its data in a directory on the filesystem. This
|
||||
* directory must be exclusive to the cache; the cache may delete or overwrite
|
||||
* files from its directory. It is an error for multiple processes to use the
|
||||
* same cache directory at the same time.
|
||||
*
|
||||
* <p>This cache limits the number of bytes that it will store on the
|
||||
* filesystem. When the number of stored bytes exceeds the limit, the cache will
|
||||
* remove entries in the background until the limit is satisfied. The limit is
|
||||
* not strict: the cache may temporarily exceed it while waiting for files to be
|
||||
* deleted. The limit does not include filesystem overhead or the cache
|
||||
* journal so space-sensitive applications should set a conservative limit.
|
||||
*
|
||||
* <p>Clients call {@link #edit} to create or update the values of an entry. An
|
||||
* entry may have only one editor at one time; if a value is not available to be
|
||||
* edited then {@link #edit} will return null.
|
||||
* <ul>
|
||||
* <li>When an entry is being <strong>created</strong> it is necessary to
|
||||
* supply a full set of values; the empty value should be used as a
|
||||
* placeholder if necessary.
|
||||
* <li>When an entry is being <strong>edited</strong>, it is not necessary
|
||||
* to supply data for every value; values default to their previous
|
||||
* value.
|
||||
* </ul>
|
||||
* Every {@link #edit} call must be matched by a call to {@link Editor#commit}
|
||||
* or {@link Editor#abort}. Committing is atomic: a read observes the full set
|
||||
* of values as they were before or after the commit, but never a mix of values.
|
||||
*
|
||||
* <p>Clients call {@link #get} to read a snapshot of an entry. The read will
|
||||
* observe the value at the time that {@link #get} was called. Updates and
|
||||
* removals after the call do not impact ongoing reads.
|
||||
*
|
||||
* <p>This class is tolerant of some I/O errors. If files are missing from the
|
||||
* filesystem, the corresponding entries will be dropped from the cache. If
|
||||
* an error occurs while writing a cache value, the edit will fail silently.
|
||||
* Callers should handle other problems by catching {@code IOException} and
|
||||
* responding appropriately.
|
||||
*/
|
||||
final class DiskLruCache implements Closeable {
|
||||
static final String JOURNAL_FILE = "journal";
|
||||
static final String JOURNAL_FILE_TEMP = "journal.tmp";
|
||||
static final String JOURNAL_FILE_BACKUP = "journal.bkp";
|
||||
static final String MAGIC = "libcore.io.DiskLruCache";
|
||||
static final String VERSION_1 = "1";
|
||||
static final long ANY_SEQUENCE_NUMBER = -1;
|
||||
static final Pattern LEGAL_KEY_PATTERN = Pattern.compile("[a-z0-9_-]{1,64}");
|
||||
private static final String CLEAN = "CLEAN";
|
||||
private static final String DIRTY = "DIRTY";
|
||||
private static final String REMOVE = "REMOVE";
|
||||
private static final String READ = "READ";
|
||||
|
||||
/*
|
||||
* This cache uses a journal file named "journal". A typical journal file
|
||||
* looks like this:
|
||||
* libcore.io.DiskLruCache
|
||||
* 1
|
||||
* 100
|
||||
* 2
|
||||
*
|
||||
* CLEAN 3400330d1dfc7f3f7f4b8d4d803dfcf6 832 21054
|
||||
* DIRTY 335c4c6028171cfddfbaae1a9c313c52
|
||||
* CLEAN 335c4c6028171cfddfbaae1a9c313c52 3934 2342
|
||||
* REMOVE 335c4c6028171cfddfbaae1a9c313c52
|
||||
* DIRTY 1ab96a171faeeee38496d8b330771a7a
|
||||
* CLEAN 1ab96a171faeeee38496d8b330771a7a 1600 234
|
||||
* READ 335c4c6028171cfddfbaae1a9c313c52
|
||||
* READ 3400330d1dfc7f3f7f4b8d4d803dfcf6
|
||||
*
|
||||
* The first five lines of the journal form its header. They are the
|
||||
* constant string "libcore.io.DiskLruCache", the disk cache's version,
|
||||
* the application's version, the value count, and a blank line.
|
||||
*
|
||||
* Each of the subsequent lines in the file is a record of the state of a
|
||||
* cache entry. Each line contains space-separated values: a state, a key,
|
||||
* and optional state-specific values.
|
||||
* o DIRTY lines track that an entry is actively being created or updated.
|
||||
* Every successful DIRTY action should be followed by a CLEAN or REMOVE
|
||||
* action. DIRTY lines without a matching CLEAN or REMOVE indicate that
|
||||
* temporary files may need to be deleted.
|
||||
* o CLEAN lines track a cache entry that has been successfully published
|
||||
* and may be read. A publish line is followed by the lengths of each of
|
||||
* its values.
|
||||
* o READ lines track accesses for LRU.
|
||||
* o REMOVE lines track entries that have been deleted.
|
||||
*
|
||||
* The journal file is appended to as cache operations occur. The journal may
|
||||
* occasionally be compacted by dropping redundant lines. A temporary file named
|
||||
* "journal.tmp" will be used during compaction; that file should be deleted if
|
||||
* it exists when the cache is opened.
|
||||
*/
|
||||
|
||||
private final File directory;
|
||||
private final File journalFile;
|
||||
private final File journalFileTmp;
|
||||
private final File journalFileBackup;
|
||||
private final int appVersion;
|
||||
private long maxSize;
|
||||
private int maxFileCount;
|
||||
private final int valueCount;
|
||||
private long size = 0;
|
||||
private int fileCount = 0;
|
||||
private Writer journalWriter;
|
||||
private final LinkedHashMap<String, Entry> lruEntries =
|
||||
new LinkedHashMap<String, Entry>(0, 0.75f, true);
|
||||
private int redundantOpCount;
|
||||
|
||||
/**
|
||||
* To differentiate between old and current snapshots, each entry is given
|
||||
* a sequence number each time an edit is committed. A snapshot is stale if
|
||||
* its sequence number is not equal to its entry's sequence number.
|
||||
*/
|
||||
private long nextSequenceNumber = 0;
|
||||
|
||||
/** This cache uses a single background thread to evict entries. */
|
||||
final ThreadPoolExecutor executorService =
|
||||
new ThreadPoolExecutor(0, 1, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
|
||||
private final Callable<Void> cleanupCallable = new Callable<Void>() {
|
||||
public Void call() throws Exception {
|
||||
synchronized (DiskLruCache.this) {
|
||||
if (journalWriter == null) {
|
||||
return null; // Closed.
|
||||
}
|
||||
trimToSize();
|
||||
trimToFileCount();
|
||||
if (journalRebuildRequired()) {
|
||||
rebuildJournal();
|
||||
redundantOpCount = 0;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
private DiskLruCache(File directory, int appVersion, int valueCount, long maxSize, int maxFileCount) {
|
||||
this.directory = directory;
|
||||
this.appVersion = appVersion;
|
||||
this.journalFile = new File(directory, JOURNAL_FILE);
|
||||
this.journalFileTmp = new File(directory, JOURNAL_FILE_TEMP);
|
||||
this.journalFileBackup = new File(directory, JOURNAL_FILE_BACKUP);
|
||||
this.valueCount = valueCount;
|
||||
this.maxSize = maxSize;
|
||||
this.maxFileCount = maxFileCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the cache in {@code directory}, creating a cache if none exists
|
||||
* there.
|
||||
*
|
||||
* @param directory a writable directory
|
||||
* @param valueCount the number of values per cache entry. Must be positive.
|
||||
* @param maxSize the maximum number of bytes this cache should use to store
|
||||
* @param maxFileCount the maximum file count this cache should store
|
||||
* @throws IOException if reading or writing the cache directory fails
|
||||
*/
|
||||
public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize, int maxFileCount)
|
||||
throws IOException {
|
||||
if (maxSize <= 0) {
|
||||
throw new IllegalArgumentException("maxSize <= 0");
|
||||
}
|
||||
if (maxFileCount <= 0) {
|
||||
throw new IllegalArgumentException("maxFileCount <= 0");
|
||||
}
|
||||
if (valueCount <= 0) {
|
||||
throw new IllegalArgumentException("valueCount <= 0");
|
||||
}
|
||||
|
||||
// If a bkp file exists, use it instead.
|
||||
File backupFile = new File(directory, JOURNAL_FILE_BACKUP);
|
||||
if (backupFile.exists()) {
|
||||
File journalFile = new File(directory, JOURNAL_FILE);
|
||||
// If journal file also exists just delete backup file.
|
||||
if (journalFile.exists()) {
|
||||
backupFile.delete();
|
||||
} else {
|
||||
renameTo(backupFile, journalFile, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Prefer to pick up where we left off.
|
||||
DiskLruCache cache = new DiskLruCache(directory, appVersion, valueCount, maxSize, maxFileCount);
|
||||
if (cache.journalFile.exists()) {
|
||||
try {
|
||||
cache.readJournal();
|
||||
cache.processJournal();
|
||||
cache.journalWriter = new BufferedWriter(
|
||||
new OutputStreamWriter(new FileOutputStream(cache.journalFile, true), Util.US_ASCII));
|
||||
return cache;
|
||||
} catch (IOException journalIsCorrupt) {
|
||||
System.out
|
||||
.println("DiskLruCache "
|
||||
+ directory
|
||||
+ " is corrupt: "
|
||||
+ journalIsCorrupt.getMessage()
|
||||
+ ", removing");
|
||||
cache.delete();
|
||||
}
|
||||
}
|
||||
|
||||
// Create a new empty cache.
|
||||
directory.mkdirs();
|
||||
cache = new DiskLruCache(directory, appVersion, valueCount, maxSize, maxFileCount);
|
||||
cache.rebuildJournal();
|
||||
return cache;
|
||||
}
|
||||
|
||||
private void readJournal() throws IOException {
|
||||
StrictLineReader reader = new StrictLineReader(new FileInputStream(journalFile), Util.US_ASCII);
|
||||
try {
|
||||
String magic = reader.readLine();
|
||||
String version = reader.readLine();
|
||||
String appVersionString = reader.readLine();
|
||||
String valueCountString = reader.readLine();
|
||||
String blank = reader.readLine();
|
||||
if (!MAGIC.equals(magic)
|
||||
|| !VERSION_1.equals(version)
|
||||
|| !Integer.toString(appVersion).equals(appVersionString)
|
||||
|| !Integer.toString(valueCount).equals(valueCountString)
|
||||
|| !"".equals(blank)) {
|
||||
throw new IOException("unexpected journal header: [" + magic + ", " + version + ", "
|
||||
+ valueCountString + ", " + blank + "]");
|
||||
}
|
||||
|
||||
int lineCount = 0;
|
||||
while (true) {
|
||||
try {
|
||||
readJournalLine(reader.readLine());
|
||||
lineCount++;
|
||||
} catch (EOFException endOfJournal) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
redundantOpCount = lineCount - lruEntries.size();
|
||||
} finally {
|
||||
Util.closeQuietly(reader);
|
||||
}
|
||||
}
|
||||
|
||||
private void readJournalLine(String line) throws IOException {
|
||||
int firstSpace = line.indexOf(' ');
|
||||
if (firstSpace == -1) {
|
||||
throw new IOException("unexpected journal line: " + line);
|
||||
}
|
||||
|
||||
int keyBegin = firstSpace + 1;
|
||||
int secondSpace = line.indexOf(' ', keyBegin);
|
||||
final String key;
|
||||
if (secondSpace == -1) {
|
||||
key = line.substring(keyBegin);
|
||||
if (firstSpace == REMOVE.length() && line.startsWith(REMOVE)) {
|
||||
lruEntries.remove(key);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
key = line.substring(keyBegin, secondSpace);
|
||||
}
|
||||
|
||||
Entry entry = lruEntries.get(key);
|
||||
if (entry == null) {
|
||||
entry = new Entry(key);
|
||||
lruEntries.put(key, entry);
|
||||
}
|
||||
|
||||
if (secondSpace != -1 && firstSpace == CLEAN.length() && line.startsWith(CLEAN)) {
|
||||
String[] parts = line.substring(secondSpace + 1).split(" ");
|
||||
entry.readable = true;
|
||||
entry.currentEditor = null;
|
||||
entry.setLengths(parts);
|
||||
} else if (secondSpace == -1 && firstSpace == DIRTY.length() && line.startsWith(DIRTY)) {
|
||||
entry.currentEditor = new Editor(entry);
|
||||
} else if (secondSpace == -1 && firstSpace == READ.length() && line.startsWith(READ)) {
|
||||
// This work was already done by calling lruEntries.get().
|
||||
} else {
|
||||
throw new IOException("unexpected journal line: " + line);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the initial size and collects garbage as a part of opening the
|
||||
* cache. Dirty entries are assumed to be inconsistent and will be deleted.
|
||||
*/
|
||||
private void processJournal() throws IOException {
|
||||
deleteIfExists(journalFileTmp);
|
||||
for (Iterator<Entry> i = lruEntries.values().iterator(); i.hasNext(); ) {
|
||||
Entry entry = i.next();
|
||||
if (entry.currentEditor == null) {
|
||||
for (int t = 0; t < valueCount; t++) {
|
||||
size += entry.lengths[t];
|
||||
fileCount++;
|
||||
}
|
||||
} else {
|
||||
entry.currentEditor = null;
|
||||
for (int t = 0; t < valueCount; t++) {
|
||||
deleteIfExists(entry.getCleanFile(t));
|
||||
deleteIfExists(entry.getDirtyFile(t));
|
||||
}
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new journal that omits redundant information. This replaces the
|
||||
* current journal if it exists.
|
||||
*/
|
||||
private synchronized void rebuildJournal() throws IOException {
|
||||
if (journalWriter != null) {
|
||||
journalWriter.close();
|
||||
}
|
||||
|
||||
Writer writer = new BufferedWriter(
|
||||
new OutputStreamWriter(new FileOutputStream(journalFileTmp), Util.US_ASCII));
|
||||
try {
|
||||
writer.write(MAGIC);
|
||||
writer.write("\n");
|
||||
writer.write(VERSION_1);
|
||||
writer.write("\n");
|
||||
writer.write(Integer.toString(appVersion));
|
||||
writer.write("\n");
|
||||
writer.write(Integer.toString(valueCount));
|
||||
writer.write("\n");
|
||||
writer.write("\n");
|
||||
|
||||
for (Entry entry : lruEntries.values()) {
|
||||
if (entry.currentEditor != null) {
|
||||
writer.write(DIRTY + ' ' + entry.key + '\n');
|
||||
} else {
|
||||
writer.write(CLEAN + ' ' + entry.key + entry.getLengths() + '\n');
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
writer.close();
|
||||
}
|
||||
|
||||
if (journalFile.exists()) {
|
||||
renameTo(journalFile, journalFileBackup, true);
|
||||
}
|
||||
renameTo(journalFileTmp, journalFile, false);
|
||||
journalFileBackup.delete();
|
||||
|
||||
journalWriter = new BufferedWriter(
|
||||
new OutputStreamWriter(new FileOutputStream(journalFile, true), Util.US_ASCII));
|
||||
}
|
||||
|
||||
private static void deleteIfExists(File file) throws IOException {
|
||||
if (file.exists() && !file.delete()) {
|
||||
throw new IOException();
|
||||
}
|
||||
}
|
||||
|
||||
private static void renameTo(File from, File to, boolean deleteDestination) throws IOException {
|
||||
if (deleteDestination) {
|
||||
deleteIfExists(to);
|
||||
}
|
||||
if (!from.renameTo(to)) {
|
||||
throw new IOException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a snapshot of the entry named {@code key}, or null if it doesn't
|
||||
* exist is not currently readable. If a value is returned, it is moved to
|
||||
* the head of the LRU queue.
|
||||
*/
|
||||
public synchronized Snapshot get(String key) throws IOException {
|
||||
checkNotClosed();
|
||||
validateKey(key);
|
||||
Entry entry = lruEntries.get(key);
|
||||
if (entry == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!entry.readable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Open all streams eagerly to guarantee that we see a single published
|
||||
// snapshot. If we opened streams lazily then the streams could come
|
||||
// from different edits.
|
||||
File[] files = new File[valueCount];
|
||||
InputStream[] ins = new InputStream[valueCount];
|
||||
try {
|
||||
File file;
|
||||
for (int i = 0; i < valueCount; i++) {
|
||||
file = entry.getCleanFile(i);
|
||||
files[i] = file;
|
||||
ins[i] = new FileInputStream(file);
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
// A file must have been deleted manually!
|
||||
for (int i = 0; i < valueCount; i++) {
|
||||
if (ins[i] != null) {
|
||||
Util.closeQuietly(ins[i]);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
redundantOpCount++;
|
||||
journalWriter.append(READ + ' ' + key + '\n');
|
||||
if (journalRebuildRequired()) {
|
||||
executorService.submit(cleanupCallable);
|
||||
}
|
||||
|
||||
return new Snapshot(key, entry.sequenceNumber, files, ins, entry.lengths);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an editor for the entry named {@code key}, or null if another
|
||||
* edit is in progress.
|
||||
*/
|
||||
public Editor edit(String key) throws IOException {
|
||||
return edit(key, ANY_SEQUENCE_NUMBER);
|
||||
}
|
||||
|
||||
private synchronized Editor edit(String key, long expectedSequenceNumber) throws IOException {
|
||||
checkNotClosed();
|
||||
validateKey(key);
|
||||
Entry entry = lruEntries.get(key);
|
||||
if (expectedSequenceNumber != ANY_SEQUENCE_NUMBER && (entry == null
|
||||
|| entry.sequenceNumber != expectedSequenceNumber)) {
|
||||
return null; // Snapshot is stale.
|
||||
}
|
||||
if (entry == null) {
|
||||
entry = new Entry(key);
|
||||
lruEntries.put(key, entry);
|
||||
} else if (entry.currentEditor != null) {
|
||||
return null; // Another edit is in progress.
|
||||
}
|
||||
|
||||
Editor editor = new Editor(entry);
|
||||
entry.currentEditor = editor;
|
||||
|
||||
// Flush the journal before creating files to prevent file leaks.
|
||||
journalWriter.write(DIRTY + ' ' + key + '\n');
|
||||
journalWriter.flush();
|
||||
return editor;
|
||||
}
|
||||
|
||||
/** Returns the directory where this cache stores its data. */
|
||||
public File getDirectory() {
|
||||
return directory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum number of bytes that this cache should use to store
|
||||
* its data.
|
||||
*/
|
||||
public synchronized long getMaxSize() {
|
||||
return maxSize;
|
||||
}
|
||||
|
||||
/** Returns the maximum number of files that this cache should store */
|
||||
public synchronized int getMaxFileCount() {
|
||||
return maxFileCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the maximum number of bytes the cache can store and queues a job
|
||||
* to trim the existing store, if necessary.
|
||||
*/
|
||||
public synchronized void setMaxSize(long maxSize) {
|
||||
this.maxSize = maxSize;
|
||||
executorService.submit(cleanupCallable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of bytes currently being used to store the values in
|
||||
* this cache. This may be greater than the max size if a background
|
||||
* deletion is pending.
|
||||
*/
|
||||
public synchronized long size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of files currently being used to store the values in
|
||||
* this cache. This may be greater than the max file count if a background
|
||||
* deletion is pending.
|
||||
*/
|
||||
public synchronized long fileCount() {
|
||||
return fileCount;
|
||||
}
|
||||
|
||||
private synchronized void completeEdit(Editor editor, boolean success) throws IOException {
|
||||
Entry entry = editor.entry;
|
||||
if (entry.currentEditor != editor) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
// If this edit is creating the entry for the first time, every index must have a value.
|
||||
if (success && !entry.readable) {
|
||||
for (int i = 0; i < valueCount; i++) {
|
||||
if (!editor.written[i]) {
|
||||
editor.abort();
|
||||
throw new IllegalStateException("Newly created entry didn't create value for index " + i);
|
||||
}
|
||||
if (!entry.getDirtyFile(i).exists()) {
|
||||
editor.abort();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < valueCount; i++) {
|
||||
File dirty = entry.getDirtyFile(i);
|
||||
if (success) {
|
||||
if (dirty.exists()) {
|
||||
File clean = entry.getCleanFile(i);
|
||||
dirty.renameTo(clean);
|
||||
long oldLength = entry.lengths[i];
|
||||
long newLength = clean.length();
|
||||
entry.lengths[i] = newLength;
|
||||
size = size - oldLength + newLength;
|
||||
fileCount++;
|
||||
}
|
||||
} else {
|
||||
deleteIfExists(dirty);
|
||||
}
|
||||
}
|
||||
|
||||
redundantOpCount++;
|
||||
entry.currentEditor = null;
|
||||
if (entry.readable | success) {
|
||||
entry.readable = true;
|
||||
journalWriter.write(CLEAN + ' ' + entry.key + entry.getLengths() + '\n');
|
||||
if (success) {
|
||||
entry.sequenceNumber = nextSequenceNumber++;
|
||||
}
|
||||
} else {
|
||||
lruEntries.remove(entry.key);
|
||||
journalWriter.write(REMOVE + ' ' + entry.key + '\n');
|
||||
}
|
||||
journalWriter.flush();
|
||||
|
||||
if (size > maxSize || fileCount > maxFileCount || journalRebuildRequired()) {
|
||||
executorService.submit(cleanupCallable);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We only rebuild the journal when it will halve the size of the journal
|
||||
* and eliminate at least 2000 ops.
|
||||
*/
|
||||
private boolean journalRebuildRequired() {
|
||||
final int redundantOpCompactThreshold = 2000;
|
||||
return redundantOpCount >= redundantOpCompactThreshold //
|
||||
&& redundantOpCount >= lruEntries.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Drops the entry for {@code key} if it exists and can be removed. Entries
|
||||
* actively being edited cannot be removed.
|
||||
*
|
||||
* @return true if an entry was removed.
|
||||
*/
|
||||
public synchronized boolean remove(String key) throws IOException {
|
||||
checkNotClosed();
|
||||
validateKey(key);
|
||||
Entry entry = lruEntries.get(key);
|
||||
if (entry == null || entry.currentEditor != null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < valueCount; i++) {
|
||||
File file = entry.getCleanFile(i);
|
||||
if (file.exists() && !file.delete()) {
|
||||
throw new IOException("failed to delete " + file);
|
||||
}
|
||||
size -= entry.lengths[i];
|
||||
fileCount--;
|
||||
entry.lengths[i] = 0;
|
||||
}
|
||||
|
||||
redundantOpCount++;
|
||||
journalWriter.append(REMOVE + ' ' + key + '\n');
|
||||
lruEntries.remove(key);
|
||||
|
||||
if (journalRebuildRequired()) {
|
||||
executorService.submit(cleanupCallable);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Returns true if this cache has been closed. */
|
||||
public synchronized boolean isClosed() {
|
||||
return journalWriter == null;
|
||||
}
|
||||
|
||||
private void checkNotClosed() {
|
||||
if (journalWriter == null) {
|
||||
throw new IllegalStateException("cache is closed");
|
||||
}
|
||||
}
|
||||
|
||||
/** Force buffered operations to the filesystem. */
|
||||
public synchronized void flush() throws IOException {
|
||||
checkNotClosed();
|
||||
trimToSize();
|
||||
trimToFileCount();
|
||||
journalWriter.flush();
|
||||
}
|
||||
|
||||
/** Closes this cache. Stored values will remain on the filesystem. */
|
||||
public synchronized void close() throws IOException {
|
||||
if (journalWriter == null) {
|
||||
return; // Already closed.
|
||||
}
|
||||
for (Entry entry : new ArrayList<Entry>(lruEntries.values())) {
|
||||
if (entry.currentEditor != null) {
|
||||
entry.currentEditor.abort();
|
||||
}
|
||||
}
|
||||
trimToSize();
|
||||
trimToFileCount();
|
||||
journalWriter.close();
|
||||
journalWriter = null;
|
||||
}
|
||||
|
||||
private void trimToSize() throws IOException {
|
||||
while (size > maxSize) {
|
||||
Map.Entry<String, Entry> toEvict = lruEntries.entrySet().iterator().next();
|
||||
remove(toEvict.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
private void trimToFileCount() throws IOException {
|
||||
while (fileCount > maxFileCount) {
|
||||
Map.Entry<String, Entry> toEvict = lruEntries.entrySet().iterator().next();
|
||||
remove(toEvict.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the cache and deletes all of its stored values. This will delete
|
||||
* all files in the cache directory including files that weren't created by
|
||||
* the cache.
|
||||
*/
|
||||
public void delete() throws IOException {
|
||||
close();
|
||||
Util.deleteContents(directory);
|
||||
}
|
||||
|
||||
private void validateKey(String key) {
|
||||
Matcher matcher = LEGAL_KEY_PATTERN.matcher(key);
|
||||
if (!matcher.matches()) {
|
||||
throw new IllegalArgumentException("keys must match regex [a-z0-9_-]{1,64}: \"" + key + "\"");
|
||||
}
|
||||
}
|
||||
|
||||
private static String inputStreamToString(InputStream in) throws IOException {
|
||||
return Util.readFully(new InputStreamReader(in, Util.UTF_8));
|
||||
}
|
||||
|
||||
/** A snapshot of the values for an entry. */
|
||||
public final class Snapshot implements Closeable {
|
||||
private final String key;
|
||||
private final long sequenceNumber;
|
||||
private File[] files;
|
||||
private final InputStream[] ins;
|
||||
private final long[] lengths;
|
||||
|
||||
private Snapshot(String key, long sequenceNumber, File[] files, InputStream[] ins, long[] lengths) {
|
||||
this.key = key;
|
||||
this.sequenceNumber = sequenceNumber;
|
||||
this.files = files;
|
||||
this.ins = ins;
|
||||
this.lengths = lengths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an editor for this snapshot's entry, or null if either the
|
||||
* entry has changed since this snapshot was created or if another edit
|
||||
* is in progress.
|
||||
*/
|
||||
public Editor edit() throws IOException {
|
||||
return DiskLruCache.this.edit(key, sequenceNumber);
|
||||
}
|
||||
|
||||
/** Returns file with the value for {@code index}. */
|
||||
public File getFile(int index) {
|
||||
return files[index];
|
||||
}
|
||||
|
||||
/** Returns the unbuffered stream with the value for {@code index}. */
|
||||
public InputStream getInputStream(int index) {
|
||||
return ins[index];
|
||||
}
|
||||
|
||||
/** Returns the string value for {@code index}. */
|
||||
public String getString(int index) throws IOException {
|
||||
return inputStreamToString(getInputStream(index));
|
||||
}
|
||||
|
||||
/** Returns the byte length of the value for {@code index}. */
|
||||
public long getLength(int index) {
|
||||
return lengths[index];
|
||||
}
|
||||
|
||||
public void close() {
|
||||
for (InputStream in : ins) {
|
||||
Util.closeQuietly(in);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final OutputStream NULL_OUTPUT_STREAM = new OutputStream() {
|
||||
@Override
|
||||
public void write(int b) throws IOException {
|
||||
// Eat all writes silently. Nom nom.
|
||||
}
|
||||
};
|
||||
|
||||
/** Edits the values for an entry. */
|
||||
public final class Editor {
|
||||
private final Entry entry;
|
||||
private final boolean[] written;
|
||||
private boolean hasErrors;
|
||||
private boolean committed;
|
||||
|
||||
private Editor(Entry entry) {
|
||||
this.entry = entry;
|
||||
this.written = (entry.readable) ? null : new boolean[valueCount];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an unbuffered input stream to read the last committed value,
|
||||
* or null if no value has been committed.
|
||||
*/
|
||||
public InputStream newInputStream(int index) throws IOException {
|
||||
synchronized (DiskLruCache.this) {
|
||||
if (entry.currentEditor != this) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
if (!entry.readable) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return new FileInputStream(entry.getCleanFile(index));
|
||||
} catch (FileNotFoundException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last committed value as a string, or null if no value
|
||||
* has been committed.
|
||||
*/
|
||||
public String getString(int index) throws IOException {
|
||||
InputStream in = newInputStream(index);
|
||||
return in != null ? inputStreamToString(in) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new unbuffered output stream to write the value at
|
||||
* {@code index}. If the underlying output stream encounters errors
|
||||
* when writing to the filesystem, this edit will be aborted when
|
||||
* {@link #commit} is called. The returned output stream does not throw
|
||||
* IOExceptions.
|
||||
*/
|
||||
public OutputStream newOutputStream(int index) throws IOException {
|
||||
synchronized (DiskLruCache.this) {
|
||||
if (entry.currentEditor != this) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
if (!entry.readable) {
|
||||
written[index] = true;
|
||||
}
|
||||
File dirtyFile = entry.getDirtyFile(index);
|
||||
FileOutputStream outputStream;
|
||||
try {
|
||||
outputStream = new FileOutputStream(dirtyFile);
|
||||
} catch (FileNotFoundException e) {
|
||||
// Attempt to recreate the cache directory.
|
||||
directory.mkdirs();
|
||||
try {
|
||||
outputStream = new FileOutputStream(dirtyFile);
|
||||
} catch (FileNotFoundException e2) {
|
||||
// We are unable to recover. Silently eat the writes.
|
||||
return NULL_OUTPUT_STREAM;
|
||||
}
|
||||
}
|
||||
return new FaultHidingOutputStream(outputStream);
|
||||
}
|
||||
}
|
||||
|
||||
/** Sets the value at {@code index} to {@code value}. */
|
||||
public void set(int index, String value) throws IOException {
|
||||
Writer writer = null;
|
||||
try {
|
||||
writer = new OutputStreamWriter(newOutputStream(index), Util.UTF_8);
|
||||
writer.write(value);
|
||||
} finally {
|
||||
Util.closeQuietly(writer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Commits this edit so it is visible to readers. This releases the
|
||||
* edit lock so another edit may be started on the same key.
|
||||
*/
|
||||
public void commit() throws IOException {
|
||||
if (hasErrors) {
|
||||
completeEdit(this, false);
|
||||
remove(entry.key); // The previous entry is stale.
|
||||
} else {
|
||||
completeEdit(this, true);
|
||||
}
|
||||
committed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Aborts this edit. This releases the edit lock so another edit may be
|
||||
* started on the same key.
|
||||
*/
|
||||
public void abort() throws IOException {
|
||||
completeEdit(this, false);
|
||||
}
|
||||
|
||||
public void abortUnlessCommitted() {
|
||||
if (!committed) {
|
||||
try {
|
||||
abort();
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class FaultHidingOutputStream extends FilterOutputStream {
|
||||
private FaultHidingOutputStream(OutputStream out) {
|
||||
super(out);
|
||||
}
|
||||
|
||||
@Override public void write(int oneByte) {
|
||||
try {
|
||||
out.write(oneByte);
|
||||
} catch (IOException e) {
|
||||
hasErrors = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void write(byte[] buffer, int offset, int length) {
|
||||
try {
|
||||
out.write(buffer, offset, length);
|
||||
} catch (IOException e) {
|
||||
hasErrors = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void close() {
|
||||
try {
|
||||
out.close();
|
||||
} catch (IOException e) {
|
||||
hasErrors = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void flush() {
|
||||
try {
|
||||
out.flush();
|
||||
} catch (IOException e) {
|
||||
hasErrors = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class Entry {
|
||||
private final String key;
|
||||
|
||||
/** Lengths of this entry's files. */
|
||||
private final long[] lengths;
|
||||
|
||||
/** True if this entry has ever been published. */
|
||||
private boolean readable;
|
||||
|
||||
/** The ongoing edit or null if this entry is not being edited. */
|
||||
private Editor currentEditor;
|
||||
|
||||
/** The sequence number of the most recently committed edit to this entry. */
|
||||
private long sequenceNumber;
|
||||
|
||||
private Entry(String key) {
|
||||
this.key = key;
|
||||
this.lengths = new long[valueCount];
|
||||
}
|
||||
|
||||
public String getLengths() throws IOException {
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (long size : lengths) {
|
||||
result.append(' ').append(size);
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/** Set lengths using decimal numbers like "10123". */
|
||||
private void setLengths(String[] strings) throws IOException {
|
||||
if (strings.length != valueCount) {
|
||||
throw invalidLengths(strings);
|
||||
}
|
||||
|
||||
try {
|
||||
for (int i = 0; i < strings.length; i++) {
|
||||
lengths[i] = Long.parseLong(strings[i]);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
throw invalidLengths(strings);
|
||||
}
|
||||
}
|
||||
|
||||
private IOException invalidLengths(String[] strings) throws IOException {
|
||||
throw new IOException("unexpected journal line: " + java.util.Arrays.toString(strings));
|
||||
}
|
||||
|
||||
public File getCleanFile(int i) {
|
||||
return new File(directory, key + "" + i);
|
||||
}
|
||||
|
||||
public File getDirtyFile(int i) {
|
||||
return new File(directory, key + "" + i + ".tmp");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package com.mogo.och.taxi.passenger.utils.blur;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.math.BigInteger;
|
||||
import java.security.MessageDigest;
|
||||
|
||||
/*******************************************************************************
|
||||
* Description: 用于缓存经过高斯模糊的图片
|
||||
*
|
||||
* Author: Freeman
|
||||
*
|
||||
* Date: 2018/9/4
|
||||
*
|
||||
* Copyright: all rights reserved by Freeman.
|
||||
*******************************************************************************/
|
||||
public class DiskLruCacheManager {
|
||||
|
||||
private DiskLruCache diskLruCache;
|
||||
private static DiskLruCacheManager instance;
|
||||
|
||||
private final int MAX_CACHE_SIZE = 64 * 1024 * 1024;
|
||||
|
||||
private DiskLruCacheManager(Context context) {
|
||||
try {
|
||||
diskLruCache = DiskLruCache.open(context.getCacheDir(), 1, 1,
|
||||
MAX_CACHE_SIZE, Integer.MAX_VALUE);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
|
||||
public static DiskLruCacheManager getInstance(Context context) {
|
||||
if (instance == null) {
|
||||
synchronized (DiskLruCacheManager.class) {
|
||||
if (instance == null) {
|
||||
instance = new DiskLruCacheManager(context.getApplicationContext());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void put(String url, Bitmap bitmap) {
|
||||
if (TextUtils.isEmpty(url) || bitmap == null || bitmap.isRecycled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
DiskLruCache.Editor editor = diskLruCache.edit(getKey(url));
|
||||
OutputStream outputStream = editor.newOutputStream(0);
|
||||
if (bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream)) {
|
||||
editor.commit();
|
||||
}
|
||||
diskLruCache.flush();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
|
||||
public Bitmap get(String url) {
|
||||
try {
|
||||
DiskLruCache.Snapshot snapshot = diskLruCache.get(getKey(url));
|
||||
if (snapshot != null) {
|
||||
InputStream inputStream = snapshot.getInputStream(0);
|
||||
return BitmapFactory.decodeStream(inputStream);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String getKey(String url) {
|
||||
try {
|
||||
MessageDigest digest = MessageDigest.getInstance("MD5");
|
||||
byte[] md5 = digest.digest(url.getBytes());
|
||||
BigInteger bigInteger = new BigInteger(1, md5);
|
||||
return bigInteger.toString(16);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
try {
|
||||
diskLruCache.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright (C) 2012 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.mogo.och.taxi.passenger.utils.blur;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.Closeable;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
* Buffers input from an {@link InputStream} for reading lines.
|
||||
*
|
||||
* <p>This class is used for buffered reading of lines. For purposes of this class, a line ends
|
||||
* with "\n" or "\r\n". End of input is reported by throwing {@code EOFException}. Unterminated
|
||||
* line at end of input is invalid and will be ignored, the caller may use {@code
|
||||
* hasUnterminatedLine()} to detect it after catching the {@code EOFException}.
|
||||
*
|
||||
* <p>This class is intended for reading input that strictly consists of lines, such as line-based
|
||||
* cache entries or cache journal. Unlike the {@link java.io.BufferedReader} which in conjunction
|
||||
* with {@link java.io.InputStreamReader} provides similar functionality, this class uses different
|
||||
* end-of-input reporting and a more restrictive definition of a line.
|
||||
*
|
||||
* <p>This class supports only charsets that encode '\r' and '\n' as a single byte with value 13
|
||||
* and 10, respectively, and the representation of no other character contains these values.
|
||||
* We currently check in constructor that the charset is one of US-ASCII, UTF-8 and ISO-8859-1.
|
||||
* The default charset is US_ASCII.
|
||||
*/
|
||||
class StrictLineReader implements Closeable {
|
||||
private static final byte CR = (byte) '\r';
|
||||
private static final byte LF = (byte) '\n';
|
||||
|
||||
private final InputStream in;
|
||||
private final Charset charset;
|
||||
|
||||
/*
|
||||
* Buffered data is stored in {@code buf}. As long as no exception occurs, 0 <= pos <= end
|
||||
* and the data in the range [pos, end) is buffered for reading. At end of input, if there is
|
||||
* an unterminated line, we set end == -1, otherwise end == pos. If the underlying
|
||||
* {@code InputStream} throws an {@code IOException}, end may remain as either pos or -1.
|
||||
*/
|
||||
private byte[] buf;
|
||||
private int pos;
|
||||
private int end;
|
||||
|
||||
/**
|
||||
* Constructs a new {@code LineReader} with the specified charset and the default capacity.
|
||||
*
|
||||
* @param in the {@code InputStream} to read data from.
|
||||
* @param charset the charset used to decode data. Only US-ASCII, UTF-8 and ISO-8859-1 are
|
||||
* supported.
|
||||
* @throws NullPointerException if {@code in} or {@code charset} is null.
|
||||
* @throws IllegalArgumentException if the specified charset is not supported.
|
||||
*/
|
||||
public StrictLineReader(InputStream in, Charset charset) {
|
||||
this(in, 8192, charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code LineReader} with the specified capacity and charset.
|
||||
*
|
||||
* @param in the {@code InputStream} to read data from.
|
||||
* @param capacity the capacity of the buffer.
|
||||
* @param charset the charset used to decode data. Only US-ASCII, UTF-8 and ISO-8859-1 are
|
||||
* supported.
|
||||
* @throws NullPointerException if {@code in} or {@code charset} is null.
|
||||
* @throws IllegalArgumentException if {@code capacity} is negative or zero
|
||||
* or the specified charset is not supported.
|
||||
*/
|
||||
public StrictLineReader(InputStream in, int capacity, Charset charset) {
|
||||
if (in == null || charset == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
if (capacity < 0) {
|
||||
throw new IllegalArgumentException("capacity <= 0");
|
||||
}
|
||||
if (!(charset.equals(Util.US_ASCII))) {
|
||||
throw new IllegalArgumentException("Unsupported encoding");
|
||||
}
|
||||
|
||||
this.in = in;
|
||||
this.charset = charset;
|
||||
buf = new byte[capacity];
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the reader by closing the underlying {@code InputStream} and
|
||||
* marking this reader as closed.
|
||||
*
|
||||
* @throws IOException for errors when closing the underlying {@code InputStream}.
|
||||
*/
|
||||
public void close() throws IOException {
|
||||
synchronized (in) {
|
||||
if (buf != null) {
|
||||
buf = null;
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the next line. A line ends with {@code "\n"} or {@code "\r\n"},
|
||||
* this end of line marker is not included in the result.
|
||||
*
|
||||
* @return the next line from the input.
|
||||
* @throws IOException for underlying {@code InputStream} errors.
|
||||
* @throws EOFException for the end of source stream.
|
||||
*/
|
||||
public String readLine() throws IOException {
|
||||
synchronized (in) {
|
||||
if (buf == null) {
|
||||
throw new IOException("LineReader is closed");
|
||||
}
|
||||
|
||||
// Read more data if we are at the end of the buffered data.
|
||||
// Though it's an error to read after an exception, we will let {@code fillBuf()}
|
||||
// throw again if that happens; thus we need to handle end == -1 as well as end == pos.
|
||||
if (pos >= end) {
|
||||
fillBuf();
|
||||
}
|
||||
// Try to find LF in the buffered data and return the line if successful.
|
||||
for (int i = pos; i != end; ++i) {
|
||||
if (buf[i] == LF) {
|
||||
int lineEnd = (i != pos && buf[i - 1] == CR) ? i - 1 : i;
|
||||
String res = new String(buf, pos, lineEnd - pos, charset.name());
|
||||
pos = i + 1;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
// Let's anticipate up to 80 characters on top of those already read.
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream(end - pos + 80) {
|
||||
@Override
|
||||
public String toString() {
|
||||
int length = (count > 0 && buf[count - 1] == CR) ? count - 1 : count;
|
||||
try {
|
||||
return new String(buf, 0, length, charset.name());
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new AssertionError(e); // Since we control the charset this will never happen.
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
while (true) {
|
||||
out.write(buf, pos, end - pos);
|
||||
// Mark unterminated line in case fillBuf throws EOFException or IOException.
|
||||
end = -1;
|
||||
fillBuf();
|
||||
// Try to find LF in the buffered data and return the line if successful.
|
||||
for (int i = pos; i != end; ++i) {
|
||||
if (buf[i] == LF) {
|
||||
if (i != pos) {
|
||||
out.write(buf, pos, i - pos);
|
||||
}
|
||||
pos = i + 1;
|
||||
return out.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads new input data into the buffer. Call only with pos == end or end == -1,
|
||||
* depending on the desired outcome if the function throws.
|
||||
*/
|
||||
private void fillBuf() throws IOException {
|
||||
int result = in.read(buf, 0, buf.length);
|
||||
if (result == -1) {
|
||||
throw new EOFException();
|
||||
}
|
||||
pos = 0;
|
||||
end = result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.mogo.och.taxi.passenger.utils.blur;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.io.StringWriter;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/** Junk drawer of utility methods. */
|
||||
final class Util {
|
||||
static final Charset US_ASCII = Charset.forName("US-ASCII");
|
||||
static final Charset UTF_8 = Charset.forName("UTF-8");
|
||||
|
||||
private Util() {
|
||||
}
|
||||
|
||||
static String readFully(Reader reader) throws IOException {
|
||||
try {
|
||||
StringWriter writer = new StringWriter();
|
||||
char[] buffer = new char[1024];
|
||||
int count;
|
||||
while ((count = reader.read(buffer)) != -1) {
|
||||
writer.write(buffer, 0, count);
|
||||
}
|
||||
return writer.toString();
|
||||
} finally {
|
||||
reader.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the contents of {@code dir}. Throws an IOException if any file
|
||||
* could not be deleted, or if {@code dir} is not a readable directory.
|
||||
*/
|
||||
static void deleteContents(File dir) throws IOException {
|
||||
File[] files = dir.listFiles();
|
||||
if (files == null) {
|
||||
throw new IOException("not a readable directory: " + dir);
|
||||
}
|
||||
for (File file : files) {
|
||||
if (file.isDirectory()) {
|
||||
deleteContents(file);
|
||||
}
|
||||
if (!file.delete()) {
|
||||
throw new IOException("failed to delete file: " + file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void closeQuietly(/*Auto*/Closeable closeable) {
|
||||
if (closeable != null) {
|
||||
try {
|
||||
closeable.close();
|
||||
} catch (RuntimeException rethrown) {
|
||||
throw rethrown;
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.mogo.och.taxi.passenger.utils.windowdispatch;
|
||||
|
||||
import android.graphics.Region;
|
||||
import android.inputmethodservice.InputMethodService;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
|
||||
public class OnComputeInternalInsetsListener implements InvocationHandler {
|
||||
|
||||
private Region touchRegion = null;
|
||||
public Object getListener() {
|
||||
Object target = null;
|
||||
try {
|
||||
Class class1 = Class.forName("android.view.ViewTreeObserver$OnComputeInternalInsetsListener");
|
||||
target = Proxy.newProxyInstance(OnComputeInternalInsetsListener.class.getClassLoader(),
|
||||
new Class[]{class1}, this);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
public Region getTouchRegion() {
|
||||
return touchRegion;
|
||||
}
|
||||
|
||||
public void setTouchRegion(Region touchRegion) {
|
||||
this.touchRegion = touchRegion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(Object proxy, Method method, Object[] args) {
|
||||
try {
|
||||
Field regionField = args[0].getClass()
|
||||
.getDeclaredField("touchableRegion");
|
||||
regionField.setAccessible(true);
|
||||
Field insetField = args[0].getClass()
|
||||
.getDeclaredField("mTouchableInsets");
|
||||
insetField.setAccessible(true);
|
||||
if (touchRegion != null) {
|
||||
Region region = (Region) regionField.get(args[0]);
|
||||
region.set(touchRegion);
|
||||
insetField.set(args[0], InputMethodService.Insets.TOUCHABLE_INSETS_REGION);
|
||||
} else {
|
||||
insetField.set(args[0], InputMethodService.Insets.TOUCHABLE_INSETS_FRAME);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.mogo.och.taxi.passenger.utils.windowdispatch;
|
||||
|
||||
import android.view.ViewTreeObserver;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ReflectionUtils {
|
||||
|
||||
private ReflectionUtils() {
|
||||
|
||||
}
|
||||
|
||||
public static void removeOnComputeInternalInsetsListener(ViewTreeObserver viewTree) {
|
||||
if (viewTree == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Class<?> clazz = Class.forName("android.view.ViewTreeObserver");
|
||||
Field field = viewTree.getClass().getDeclaredField("mOnComputeInternalInsetsListeners");
|
||||
field.setAccessible(true);
|
||||
Object listenerList = field.get(viewTree);
|
||||
Method method = listenerList.getClass().getDeclaredMethod("getArray");
|
||||
method.setAccessible(true);
|
||||
ArrayList<Object> list = (ArrayList<Object>) method.invoke(listenerList);
|
||||
Class<?> classes[] = {Class.forName("android.view.ViewTreeObserver$OnComputeInternalInsetsListener")};
|
||||
if (list != null && list.size() > 0) {
|
||||
clazz.getDeclaredMethod("removeOnComputeInternalInsetsListener", classes).invoke(viewTree,
|
||||
list.get(0));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static void addOnComputeInternalInsetsListener(ViewTreeObserver viewTree, Object object) {
|
||||
if (viewTree == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Class<?> classes[] = {Class.forName("android.view.ViewTreeObserver$OnComputeInternalInsetsListener")};
|
||||
Class<?> clazz = Class.forName("android.view.ViewTreeObserver");
|
||||
clazz.getDeclaredMethod("addOnComputeInternalInsetsListener", classes).invoke(viewTree,
|
||||
object);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -81,8 +81,8 @@ public class TaxiNaviFragment extends BaseTaxiUIFragment implements AMapNaviView
|
||||
aMap.setCustomMapStyle(
|
||||
new CustomMapStyleOptions()
|
||||
.setEnable(true)
|
||||
.setStyleData(MapAssetStyleUtils.getAssetsStyle(getContext()))
|
||||
.setStyleExtraData(MapAssetStyleUtils.getAssetsExtraStyle(getContext()))
|
||||
.setStyleData(MapAssetStyleUtils.getAssetsStyle(getContext(), "small_map_style.data"))
|
||||
.setStyleExtraData(MapAssetStyleUtils.getAssetsExtraStyle(getContext(), "small_map_style_extra.data"))
|
||||
);
|
||||
|
||||
//设置希望展示的地图缩放级别
|
||||
|
||||
@@ -6,7 +6,7 @@ ext {
|
||||
independentApplicationId : "com.mogo.launcher.app",
|
||||
fLauncherApplicationId : "com.mogo.launcher.f",
|
||||
bydautoIndependentApplicationId: "com.mogo.launcher.app.bydauto",
|
||||
fLauncherAmapApiValue : "aa2c8a0547378ead2f9a37762d9dd179",
|
||||
fLauncherAmapApiValue : "ace34d685cc04836c03905e4d1536125",
|
||||
bydautoIndependentApiValue : "b1e1d527b02a493913c50985827c943a",
|
||||
commonLauncherAmapApiValue : "a36b9f7b086fa3951bb35338a5a06dd3",
|
||||
commonIndependentAmapApiValue : "1c3fbc5f5e183619ffb1e7bc01e6751f",
|
||||
|
||||
@@ -149,4 +149,9 @@ public class MoGoHandAdasMsgManager implements
|
||||
@Override
|
||||
public void onAutopilotDataException(long timestamp) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAutopilotAcc(float carAcc) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -95,6 +95,7 @@ public class BindingcarProvider implements IMoGoBindingcarProvider {
|
||||
private void driverScreen(String macAddress, String widevineIDWithMd5) {
|
||||
long currentHour = System.currentTimeMillis() / (1000 * 60);
|
||||
long oldHour = SharedPrefsMgr.getInstance(mContext).getLong("typeDriver", 0);
|
||||
Log.d("liyz", "driverScreen --------> ");
|
||||
//如果2分钟内频繁调,需要拦截,业务导致的会多次请求工控机信息
|
||||
if (HmiBuildConfig.isShowSnBindingView) {
|
||||
if (currentHour - oldHour > 1) {
|
||||
@@ -107,6 +108,7 @@ public class BindingcarProvider implements IMoGoBindingcarProvider {
|
||||
private void passengerScreen(String macAddress, String widevineIDWithMd5) {
|
||||
long currentHour = System.currentTimeMillis() / (1000 * 60);
|
||||
long oldHour = SharedPrefsMgr.getInstance(mContext).getLong("typePassenger", 0);
|
||||
Log.d("liyz", "passengerScreen --------> ");
|
||||
//如果2分钟内频繁调,需要拦截,业务导致的会多次请求工控机信息
|
||||
if (HmiBuildConfig.isShowSnBindingView) {
|
||||
if (currentHour - oldHour > 1) {
|
||||
|
||||
@@ -66,6 +66,11 @@ internal class CanImpl(ctx: Context): IFlow<CanStatus>(ctx), IMoGoAutopilotVehic
|
||||
send(CanStatus(false))
|
||||
}
|
||||
|
||||
override fun onAutopilotAcc(carAcc: Float) {
|
||||
send(CanStatus(isCanEnabled()))
|
||||
timeOutCheck()
|
||||
}
|
||||
|
||||
override fun onAutopilotGuardian(guardianInfo: MogoReportMessage?) {
|
||||
super.onAutopilotGuardian(guardianInfo)
|
||||
send(CanStatus(isCanEnabled()))
|
||||
|
||||
@@ -1956,6 +1956,10 @@ class DebugSettingView @JvmOverloads constructor(
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAutopilotAcc(carAcc: Float) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 吐司提示
|
||||
*/
|
||||
|
||||
@@ -176,6 +176,15 @@ public class SteeringWheelView extends ConstraintLayout {
|
||||
Log.d(TAG, "刹车灯:" + String.valueOf(brakeLight));
|
||||
}
|
||||
|
||||
/**
|
||||
* 车辆加速度
|
||||
* @param carAcc
|
||||
*/
|
||||
@Override
|
||||
public void onAutopilotAcc(float carAcc) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 方向盘转向角 左+右-
|
||||
* @param steering
|
||||
@@ -223,7 +232,7 @@ public class SteeringWheelView extends ConstraintLayout {
|
||||
ThreadUtils.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Log.d(TAG, "档位" + gear.toString());
|
||||
Log.d(TAG, "乘客屏档位" + gear.toString());
|
||||
if (tapPositionView != null) {
|
||||
tapPositionView.updateWithGear(gear);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.mogo.eagle.core.function.hmi.ui.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
@@ -30,6 +31,7 @@ public class TapPositionView extends ConstraintLayout {
|
||||
private TextView tabR;
|
||||
private TextView tabN;
|
||||
private TextView tabD;
|
||||
private TypedArray typedArray;
|
||||
|
||||
public TapPositionView(Context context, @Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
@@ -39,90 +41,48 @@ public class TapPositionView extends ConstraintLayout {
|
||||
tabR = findViewById(R.id.tap_r);
|
||||
tabN = findViewById(R.id.tap_n);
|
||||
tabD = findViewById(R.id.tap_d);
|
||||
typedArray = context.obtainStyledAttributes(attrs, R.styleable.TapPositionView);
|
||||
}
|
||||
|
||||
public void updateWithGear(@NotNull Chassis.GearPosition gear) {
|
||||
if (tabP != null && tabR != null && tabN != null && tabD != null) {
|
||||
if (AppIdentityModeUtils.isTaxi(FunctionBuildConfig.appIdentityMode)) {
|
||||
taxiGear(gear);
|
||||
} else {
|
||||
busGear(gear);
|
||||
int defaultColor = typedArray.getColor(R.styleable.TapPositionView_defaultColor, -1);
|
||||
int selectColor = typedArray.getColor(R.styleable.TapPositionView_selectColor, -1);
|
||||
Log.d(TAG, "gear:" + gear);
|
||||
switch (gear) {
|
||||
case GEAR_NONE:
|
||||
tabP.setTextColor(defaultColor);
|
||||
tabR.setTextColor(defaultColor);
|
||||
tabN.setTextColor(defaultColor);
|
||||
tabD.setTextColor(defaultColor);
|
||||
break;
|
||||
case GEAR_P:
|
||||
tabP.setTextColor(selectColor);
|
||||
tabR.setTextColor(defaultColor);
|
||||
tabN.setTextColor(defaultColor);
|
||||
tabD.setTextColor(defaultColor);
|
||||
break;
|
||||
case GEAR_R:
|
||||
tabR.setTextColor(selectColor);
|
||||
tabP.setTextColor(defaultColor);
|
||||
tabN.setTextColor(defaultColor);
|
||||
tabD.setTextColor(defaultColor);
|
||||
break;
|
||||
case GEAR_N:
|
||||
tabN.setTextColor(selectColor);
|
||||
tabR.setTextColor(defaultColor);
|
||||
tabP.setTextColor(defaultColor);
|
||||
tabD.setTextColor(defaultColor);
|
||||
break;
|
||||
case GEAR_D:
|
||||
tabD.setTextColor(selectColor);
|
||||
tabN.setTextColor(defaultColor);
|
||||
tabR.setTextColor(defaultColor);
|
||||
tabP.setTextColor(defaultColor);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void busGear(@NotNull Chassis.GearPosition gear) {
|
||||
switch (gear) {
|
||||
case GEAR_NONE:
|
||||
tabP.setTextColor(Color.parseColor("#6E8EC9"));
|
||||
tabR.setTextColor(Color.parseColor("#6E8EC9"));
|
||||
tabN.setTextColor(Color.parseColor("#6E8EC9"));
|
||||
tabD.setTextColor(Color.parseColor("#6E8EC9"));
|
||||
break;
|
||||
case GEAR_P:
|
||||
tabP.setTextColor(Color.parseColor("#0043FF"));
|
||||
tabR.setTextColor(Color.parseColor("#6E8EC9"));
|
||||
tabN.setTextColor(Color.parseColor("#6E8EC9"));
|
||||
tabD.setTextColor(Color.parseColor("#6E8EC9"));
|
||||
break;
|
||||
case GEAR_R:
|
||||
tabR.setTextColor(Color.parseColor("#0043FF"));
|
||||
tabP.setTextColor(Color.parseColor("#6E8EC9"));
|
||||
tabN.setTextColor(Color.parseColor("#6E8EC9"));
|
||||
tabD.setTextColor(Color.parseColor("#6E8EC9"));
|
||||
break;
|
||||
case GEAR_N:
|
||||
tabN.setTextColor(Color.parseColor("#0043FF"));
|
||||
tabR.setTextColor(Color.parseColor("#6E8EC9"));
|
||||
tabP.setTextColor(Color.parseColor("#6E8EC9"));
|
||||
tabD.setTextColor(Color.parseColor("#6E8EC9"));
|
||||
break;
|
||||
case GEAR_D:
|
||||
tabD.setTextColor(Color.parseColor("#0043FF"));
|
||||
tabN.setTextColor(Color.parseColor("#6E8EC9"));
|
||||
tabR.setTextColor(Color.parseColor("#6E8EC9"));
|
||||
tabP.setTextColor(Color.parseColor("#6E8EC9"));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void taxiGear(@NotNull Chassis.GearPosition gear) {
|
||||
switch (gear) {
|
||||
case GEAR_NONE:
|
||||
tabP.setTextColor(Color.parseColor("#FF6E8EC9"));
|
||||
tabR.setTextColor(Color.parseColor("#FF6E8EC9"));
|
||||
tabN.setTextColor(Color.parseColor("#FF6E8EC9"));
|
||||
tabD.setTextColor(Color.parseColor("#FF6E8EC9"));
|
||||
break;
|
||||
case GEAR_P:
|
||||
tabP.setTextColor(Color.parseColor("#FFFFFFFF"));
|
||||
tabR.setTextColor(Color.parseColor("#FF6E8EC9"));
|
||||
tabN.setTextColor(Color.parseColor("#FF6E8EC9"));
|
||||
tabD.setTextColor(Color.parseColor("#FF6E8EC9"));
|
||||
break;
|
||||
case GEAR_R:
|
||||
tabR.setTextColor(Color.parseColor("#FFFFFFFF"));
|
||||
tabP.setTextColor(Color.parseColor("#FF6E8EC9"));
|
||||
tabN.setTextColor(Color.parseColor("#FF6E8EC9"));
|
||||
tabD.setTextColor(Color.parseColor("#FF6E8EC9"));
|
||||
break;
|
||||
case GEAR_N:
|
||||
tabN.setTextColor(Color.parseColor("#FFFFFFFF"));
|
||||
tabR.setTextColor(Color.parseColor("#FF6E8EC9"));
|
||||
tabP.setTextColor(Color.parseColor("#FF6E8EC9"));
|
||||
tabD.setTextColor(Color.parseColor("#FF6E8EC9"));
|
||||
break;
|
||||
case GEAR_D:
|
||||
tabD.setTextColor(Color.parseColor("#FFFFFFFF"));
|
||||
tabN.setTextColor(Color.parseColor("#FF6E8EC9"));
|
||||
tabR.setTextColor(Color.parseColor("#FF6E8EC9"));
|
||||
tabP.setTextColor(Color.parseColor("#FF6E8EC9"));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
package com.mogo.eagle.core.function.hmi.ui.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
|
||||
import com.mogo.eagle.core.data.config.FunctionBuildConfig;
|
||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotVehicleStateListener;
|
||||
import com.mogo.eagle.core.function.call.autopilot.CallerAutopilotVehicleStateListenerManager;
|
||||
import com.mogo.eagle.core.function.hmi.R;
|
||||
import com.mogo.eagle.core.utilcode.mogo.AppIdentityModeUtils;
|
||||
import com.mogo.eagle.core.utilcode.util.ThreadUtils;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import chassis.Chassis;
|
||||
|
||||
/**
|
||||
* @author Jing
|
||||
* @description 速度 加速度 档位 刹车 油门状态值
|
||||
* @since: 6/24/22
|
||||
*/
|
||||
public class TrafficDataView extends ConstraintLayout {
|
||||
private static final String TAG = "TrafficDataView";
|
||||
private TapPositionView tapPositionView;
|
||||
private TextView speedTextView;
|
||||
private TextView accTextView;
|
||||
private ImageView speedImage;
|
||||
//圆弧颜色
|
||||
private int mArcColor;
|
||||
|
||||
public TrafficDataView(@NonNull Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public TrafficDataView(@NonNull Context context, @Nullable AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
initView(context);
|
||||
CallerAutopilotVehicleStateListenerManager.INSTANCE.addListener(TAG, mIMoGoAutopilotVehicleStateListener);
|
||||
}
|
||||
|
||||
public TrafficDataView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
}
|
||||
|
||||
public TrafficDataView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
}
|
||||
|
||||
private void initView(@NonNull Context context) {
|
||||
if (AppIdentityModeUtils.isBus(FunctionBuildConfig.appIdentityMode)) {
|
||||
// LayoutInflater.from(context).inflate(R.layout.hmi_traffic_data, this);
|
||||
} else {
|
||||
}
|
||||
LayoutInflater.from(context).inflate(R.layout.hmi_traffic_data, this);
|
||||
tapPositionView = findViewById(R.id.traffic_position);
|
||||
speedImage = findViewById(R.id.speedImage);
|
||||
speedTextView = findViewById(R.id.speedTextView);
|
||||
accTextView = findViewById(R.id.speedAccTextView);
|
||||
}
|
||||
|
||||
private final IMoGoAutopilotVehicleStateListener mIMoGoAutopilotVehicleStateListener = new IMoGoAutopilotVehicleStateListener() {
|
||||
/**
|
||||
* 车辆转向灯
|
||||
* @param lightSwitch
|
||||
*/
|
||||
@Override
|
||||
public void onAutopilotLightSwitchData(@org.jetbrains.annotations.Nullable Chassis.LightSwitch lightSwitch) {
|
||||
Log.d(TAG, "车辆转向灯:" + lightSwitch.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* 刹车灯
|
||||
* @param brakeLight
|
||||
*/
|
||||
@Override
|
||||
public void onAutopilotBrakeLightData(boolean brakeLight) {
|
||||
Log.d(TAG, "刹车灯:" + String.valueOf(brakeLight));
|
||||
}
|
||||
|
||||
/**
|
||||
* 方向盘转向角 左+右-
|
||||
* @param steering
|
||||
*/
|
||||
@Override
|
||||
public void onAutopilotSteeringData(float steering) {
|
||||
Log.d(TAG, "steering原始值====" + String.valueOf(steering));
|
||||
if (Math.abs(steering) < 1) {
|
||||
steering = 0;
|
||||
}
|
||||
float steeringValue = steering;
|
||||
ThreadUtils.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Log.d(TAG, "steering忽略小数点后====" + String.valueOf((int) steeringValue));
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 档位
|
||||
* @param gear
|
||||
*/
|
||||
@Override
|
||||
public void onAutopilotGearData(@NotNull Chassis.GearPosition gear) {
|
||||
ThreadUtils.runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Log.d(TAG, "司机屏档位" + gear.toString());
|
||||
if (tapPositionView != null) {
|
||||
tapPositionView.updateWithGear(gear);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAutopilotDataException(long timestamp) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAutopilotAcc(float carAcc) {
|
||||
Log.d(TAG, "司机屏加速度:" + carAcc);
|
||||
java.text.DecimalFormat myformat = new java.text.DecimalFormat("0.00");
|
||||
String accStr = myformat.format(carAcc);
|
||||
accTextView.setText("a: " + accStr);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 设置弧形颜色
|
||||
*
|
||||
* @param value 颜色值
|
||||
*/
|
||||
public void setArcColor(int value) {
|
||||
mArcColor = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置数据
|
||||
*
|
||||
* @param value 当前绘制的值
|
||||
*/
|
||||
public void setValues(int value) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* value呈现
|
||||
*/
|
||||
public void updateSpeedWithValue(int newSpeed) {
|
||||
if (speedTextView != null) {
|
||||
speedTextView.setText(String.valueOf(newSpeed));
|
||||
}
|
||||
if (speedImage != null) {
|
||||
speedImage.setBackgroundResource(newSpeed > 60 ? R.drawable.traffic_data_speed_warning : R.drawable.traffic_data_speed);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 42 KiB |
@@ -51,7 +51,7 @@
|
||||
android:layout_marginTop="@dimen/dp_72"
|
||||
android:layout_marginRight="-16px"
|
||||
android:gravity="right"
|
||||
android:text="180°"
|
||||
android:text="0°"
|
||||
android:textColor="#415479"
|
||||
android:textSize="@dimen/dp_38"
|
||||
android:visibility="invisible"
|
||||
@@ -65,7 +65,7 @@
|
||||
android:layout_marginLeft="-16px"
|
||||
android:layout_marginTop="@dimen/dp_72"
|
||||
android:gravity="left"
|
||||
android:text="180°"
|
||||
android:text="0°"
|
||||
android:textColor="#415479"
|
||||
android:textSize="@dimen/dp_38"
|
||||
app:layout_constraintLeft_toRightOf="@+id/steering_circular"
|
||||
@@ -87,6 +87,8 @@
|
||||
android:layout_width="@dimen/dp_390"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/dp_42"
|
||||
app:defaultColor = "@color/p_default_txt_color"
|
||||
app:selectColor="@color/bus_p_select_txt_color"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
|
||||
@@ -88,6 +88,8 @@
|
||||
android:layout_width="@dimen/dp_272"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/dp_30"
|
||||
app:defaultColor="@color/p_default_txt_color"
|
||||
app:selectColor="@color/dark_mode_select_txt_color"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/steering_circular_alpha" />
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
android:gravity="center"
|
||||
android:text="P"
|
||||
android:textAlignment="center"
|
||||
android:textColor="#6E8EC9"
|
||||
android:textColor="@color/p_default_txt_color"
|
||||
android:textSize="@dimen/dp_46"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
@@ -27,7 +27,7 @@
|
||||
android:gravity="center"
|
||||
android:text="R"
|
||||
android:textAlignment="center"
|
||||
android:textColor="#6E8EC9"
|
||||
android:textColor="@color/p_default_txt_color"
|
||||
android:textSize="@dimen/dp_46"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
@@ -42,7 +42,7 @@
|
||||
android:gravity="center"
|
||||
android:text="N"
|
||||
android:textAlignment="center"
|
||||
android:textColor="#6E8EC9"
|
||||
android:textColor="@color/p_default_txt_color"
|
||||
android:textSize="@dimen/dp_46"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
@@ -57,7 +57,7 @@
|
||||
android:gravity="center"
|
||||
android:text="D"
|
||||
android:textAlignment="center"
|
||||
android:textColor="#0043FF"
|
||||
android:textColor="@color/p_default_txt_color"
|
||||
android:textSize="@dimen/dp_46"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="@dimen/dp_616"
|
||||
android:layout_height="@dimen/dp_320"
|
||||
android:background="@drawable/traffic_data_back">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/speedImage"
|
||||
android:layout_width="@dimen/dp_270"
|
||||
android:layout_height="@dimen/dp_270"
|
||||
android:layout_marginLeft="@dimen/dp_46"
|
||||
android:background="@drawable/traffic_data_speed"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/speedTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="80px"
|
||||
android:text="0"
|
||||
android:textAlignment="center"
|
||||
android:textColor="#fff"
|
||||
android:textSize="@dimen/dp_70"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintLeft_toLeftOf="@+id/speedImage"
|
||||
app:layout_constraintRight_toRightOf="@+id/speedImage"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/kmTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/dp_176"
|
||||
android:text="KM/H"
|
||||
android:textAlignment="center"
|
||||
android:textColor="#fff"
|
||||
android:textSize="@dimen/dp_30"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintLeft_toLeftOf="@+id/speedImage"
|
||||
app:layout_constraintRight_toRightOf="@+id/speedImage"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.mogo.eagle.core.function.hmi.ui.widget.TapPositionView
|
||||
android:id="@+id/traffic_position"
|
||||
android:layout_width="@dimen/dp_220"
|
||||
app:defaultColor="@color/acc_default_txt_color"
|
||||
app:selectColor="@color/dark_mode_select_txt_color"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/dp_28"
|
||||
android:layout_marginTop="@dimen/dp_80"
|
||||
android:layout_marginRight="@dimen/dp_80"
|
||||
app:layout_constraintLeft_toRightOf="@+id/speedImage"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/brakeStatus"
|
||||
android:layout_width="@dimen/dp_66"
|
||||
android:layout_height="@dimen/dp_68"
|
||||
android:layout_marginLeft="@dimen/dp_20"
|
||||
android:layout_marginTop="@dimen/dp_174"
|
||||
android:layout_marginBottom="@dimen/dp_57"
|
||||
android:src="@drawable/traffic_data_empty"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toRightOf="@id/speedImage"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/speedAccTextView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/dp_56"
|
||||
android:layout_marginLeft="@dimen/dp_42"
|
||||
android:layout_marginTop="@dimen/dp_190"
|
||||
android:text="a: "
|
||||
android:textAlignment="viewStart"
|
||||
android:textColor="#fff"
|
||||
android:textSize="@dimen/dp_40"
|
||||
app:layout_constraintLeft_toLeftOf="@+id/brakeStatus"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -6,4 +6,5 @@
|
||||
<color name="notice_check_dialog_bg_color">#E63B4577</color>
|
||||
<color name="notice_traffic_line">#555C7E</color>
|
||||
<color name="notice_dialog_back">#3B4577</color>
|
||||
<color name="acc_default_txt_color">#FF343C63</color>
|
||||
</resources>
|
||||
@@ -49,4 +49,8 @@
|
||||
<attr name="progress" format="integer" /> <!--圆环进度-->
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="TapPositionView">
|
||||
<attr name="defaultColor" format="color"/> <!--档位默认色值-->
|
||||
<attr name="selectColor" format="color"/> <!--当前档位色值-->
|
||||
</declare-styleable>
|
||||
</resources>
|
||||
@@ -60,4 +60,9 @@
|
||||
<color name="hmi_light_blue_alpha_00">#D945D3FF</color>
|
||||
<color name="hmi_light_blue_alpha_ff">#D93261B6</color>
|
||||
<color name="hmi_clear_00">#00FFFFFF</color>
|
||||
<color name="acc_default_txt_color">#FF343C63</color>
|
||||
<color name="bus_p_select_txt_color">#0043FF</color>
|
||||
<color name="p_default_txt_color">#FF6E8EC9</color>
|
||||
<color name="dark_mode_select_txt_color">#FFFFFFFF</color>
|
||||
|
||||
</resources>
|
||||
@@ -211,6 +211,7 @@ public class MapFragment extends MvpFragment<MapView, MapPresenter>
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
CallerSkinModeListenerManager.INSTANCE.removeListener(TAG);
|
||||
CallerAutopilotPlanningListenerManager.INSTANCE.removeListener(TAG);
|
||||
if (mMogoMapView != null) {
|
||||
mMogoMapView.onDestroy();
|
||||
mMogoMapView = null;
|
||||
|
||||
@@ -203,7 +203,7 @@ public class AMapCustomView
|
||||
// options.setTilt((int) tilt);
|
||||
//自车车标
|
||||
options.setCarBitmap(BitmapFactory.decodeResource(this.getResources(), R.drawable.module_small_map_view_my_location_logo));
|
||||
// options.setFourCornersBitmap(BitmapFactory.decodeResource(this.getResources(), R.drawable.amap_custom_corner));
|
||||
options.setFourCornersBitmap(BitmapFactory.decodeResource(this.getResources(), R.drawable.amap_custom_corner));
|
||||
options.setStartPointBitmap(BitmapFactory.decodeResource(this.getResources(), R.drawable.module_small_map_view_dir_start));
|
||||
options.setWayPointBitmap(BitmapFactory.decodeResource(this.getResources(), R.drawable.icon_module_small_map_four_corners));
|
||||
options.setEndPointBitmap(BitmapFactory.decodeResource(this.getResources(), R.drawable.module_small_map_view_dir_end));
|
||||
@@ -212,11 +212,11 @@ public class AMapCustomView
|
||||
//路线纹理自定义
|
||||
RouteOverlayOptions routeOverlayOptions = new RouteOverlayOptions();
|
||||
routeOverlayOptions.setTurnArrowIs3D(false);
|
||||
// routeOverlayOptions.setUnknownTraffic(BitmapFactory.decodeResource(getResources(), R.drawable.custtexture_no));//未知路段
|
||||
// routeOverlayOptions.setSmoothTraffic(BitmapFactory.decodeResource(getResources(), R.drawable.amap_custom_smooth_route));
|
||||
// routeOverlayOptions.setJamTraffic(BitmapFactory.decodeResource(getResources(), R.drawable.custtexture_bad));//拥堵路段
|
||||
// routeOverlayOptions.setVeryJamTraffic(BitmapFactory.decodeResource(getResources(), R.drawable.custtexture_grayred));//超级拥堵路段
|
||||
// routeOverlayOptions.setPassRoute(BitmapFactory.decodeResource(getResources(), R.drawable.amap_custom_pass_route));//走过的路段
|
||||
routeOverlayOptions.setUnknownTraffic(BitmapFactory.decodeResource(getResources(), R.drawable.custtexture_no));//未知路段
|
||||
routeOverlayOptions.setSmoothTraffic(BitmapFactory.decodeResource(getResources(), R.drawable.amap_custom_smooth_route));
|
||||
routeOverlayOptions.setJamTraffic(BitmapFactory.decodeResource(getResources(), R.drawable.custtexture_bad));//拥堵路段
|
||||
routeOverlayOptions.setVeryJamTraffic(BitmapFactory.decodeResource(getResources(), R.drawable.custtexture_grayred));//超级拥堵路段
|
||||
routeOverlayOptions.setPassRoute(BitmapFactory.decodeResource(getResources(), R.drawable.amap_custom_pass_route));//走过的路段
|
||||
options.setRouteOverlayOptions(routeOverlayOptions);
|
||||
mAMapNaviView.setViewOptions(options);
|
||||
}
|
||||
@@ -691,8 +691,8 @@ public class AMapCustomView
|
||||
// 加载自定义样式
|
||||
CustomMapStyleOptions customMapStyleOptions = new CustomMapStyleOptions()
|
||||
.setEnable(true)
|
||||
.setStyleData(MapAssetStyleUtils.getAssetsStyle(getContext()))
|
||||
.setStyleExtraData(MapAssetStyleUtils.getAssetsExtraStyle(getContext()));
|
||||
.setStyleData(MapAssetStyleUtils.getAssetsStyle(getContext(),"over_view_style.data"))
|
||||
.setStyleExtraData(MapAssetStyleUtils.getAssetsExtraStyle(getContext(),"over_view_style_extra.data"));
|
||||
// 设置自定义样式
|
||||
mAMap.setCustomMapStyle(customMapStyleOptions);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
package com.mogo.eagle.core.function.smp;
|
||||
|
||||
import com.amap.api.maps.AMapUtils;
|
||||
import com.amap.api.maps.model.LatLng;
|
||||
import com.amap.api.navi.model.NaviLatLng;
|
||||
import com.autonavi.amap.mapcore.IPoint;
|
||||
import com.autonavi.amap.mapcore.MapProjection;
|
||||
|
||||
/**
|
||||
* 包名: com.amap.navi.demo.util
|
||||
* <p>
|
||||
* 创建时间:2018/4/19
|
||||
* 项目名称:NaviDemo
|
||||
*
|
||||
* @author guibao.ggb
|
||||
* @email guibao.ggb@alibaba-inc.com
|
||||
* <p>
|
||||
* 类说明:
|
||||
*/
|
||||
public class NaviUtil {
|
||||
|
||||
public static float calculateDistance(NaviLatLng start, NaviLatLng end) {
|
||||
double x1 = start.getLongitude();
|
||||
double y1 = start.getLatitude();
|
||||
double x2 = end.getLongitude();
|
||||
double y2 = end.getLatitude();
|
||||
return AMapUtils.calculateLineDistance(new LatLng(y1, x1), new LatLng(y2, x2));
|
||||
}
|
||||
|
||||
|
||||
public static NaviLatLng getPointForDis(NaviLatLng sPt, NaviLatLng ePt, double dis) {
|
||||
double lSegLength = calculateDistance(sPt, ePt);
|
||||
NaviLatLng pt = new NaviLatLng();
|
||||
double preResult = dis / lSegLength;
|
||||
pt.setLatitude(((ePt.getLatitude() - sPt.getLatitude()) * preResult + sPt.getLatitude()));
|
||||
pt.setLongitude(((ePt.getLongitude() - sPt.getLongitude()) * preResult + sPt.getLongitude()));
|
||||
return pt;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据经纬度计算需要偏转的角度
|
||||
*
|
||||
* @param startPoi
|
||||
* @param secondPoi
|
||||
* @return
|
||||
*/
|
||||
public static float getRotate(NaviLatLng startPoi, NaviLatLng secondPoi) {
|
||||
float rotate = 0;
|
||||
try {
|
||||
IPoint point1 = new IPoint();
|
||||
IPoint point2 = new IPoint();
|
||||
MapProjection.lonlat2Geo(startPoi.getLongitude(), startPoi.getLatitude(), point1);
|
||||
MapProjection.lonlat2Geo(secondPoi.getLongitude(), secondPoi.getLatitude(), point2);
|
||||
double x1 = point1.x;
|
||||
double x2 = point2.x;
|
||||
double y1 = point1.y;
|
||||
double y2 = point2.y;
|
||||
rotate = (float) (Math.atan2(y2 - y1, x2 - x1) / Math.PI * 180);
|
||||
rotate = rotate + 90;
|
||||
return rotate;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return rotate;
|
||||
}
|
||||
|
||||
|
||||
public static final int MAXZOOMLEVEL = 20;
|
||||
public static final int PIXELSPERTILE = 256;
|
||||
public static final double MINLATITUDE = -85.0511287798;
|
||||
public static final double MAXLATITUDE = 85.0511287798;
|
||||
public static final double MINLONGITUDE = -180;
|
||||
public static final double MAXLONGITUDE = 180;
|
||||
public static final int EARTHRADIUSINMETERS = 6378137;
|
||||
public static final int TILESPLITLEVEL = 0;
|
||||
|
||||
|
||||
public static final double EarthCircumferenceInMeters = 2 * Math.PI
|
||||
* EARTHRADIUSINMETERS;
|
||||
|
||||
|
||||
public static double clip(double n, double minValue, double maxValue) {
|
||||
return Math.min(Math.max(n, minValue), maxValue);
|
||||
}
|
||||
|
||||
public static IPoint lonlat2Geo(double latitude, double longitude,
|
||||
int levelOfDetail) {
|
||||
IPoint rPnt = new IPoint();
|
||||
latitude = clip(latitude, MINLATITUDE, MAXLATITUDE) * Math.PI / 180;
|
||||
longitude = clip(longitude, MINLONGITUDE, MAXLONGITUDE) * Math.PI / 180;
|
||||
double sinLatitude = Math.sin(latitude);
|
||||
double xMeters = EARTHRADIUSINMETERS * longitude;
|
||||
double lLog = Math.log((1 + sinLatitude) / (1 - sinLatitude));
|
||||
double yMeters = EARTHRADIUSINMETERS / 2 * lLog;
|
||||
long numPixels = (long) PIXELSPERTILE << levelOfDetail;
|
||||
double metersPerPixel = EarthCircumferenceInMeters / numPixels;
|
||||
rPnt.x = (int) clip((EarthCircumferenceInMeters / 2 + xMeters)
|
||||
/ metersPerPixel + 0.5, 0, numPixels - 1);
|
||||
long tmp = (long) (EarthCircumferenceInMeters / 2 - yMeters);
|
||||
rPnt.y = (int) clip((double) tmp / metersPerPixel + 0.5, 0,
|
||||
numPixels - 1);
|
||||
return rPnt;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static String formatKM(int d) {
|
||||
if (d == 0) {
|
||||
return "0米";
|
||||
} else if (d < 100) {
|
||||
return d + "米";
|
||||
} else if ((100 <= d) && (d < 1000)) {
|
||||
return d + "米";
|
||||
} else if ((1000 <= d) && (d < 10000)) {
|
||||
return (d / 10) * 10 / 1000.0D + "公里";
|
||||
} else if ((10000 <= d) && (d < 100000)) {
|
||||
return (d / 100) * 100 / 1000.0D + "公里";
|
||||
}
|
||||
return (d / 1000) + "公里";
|
||||
}
|
||||
}
|
||||
@@ -1,356 +0,0 @@
|
||||
package com.mogo.eagle.core.function.smp;
|
||||
|
||||
import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_MAP;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.location.Location;
|
||||
import android.os.Bundle;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.widget.RelativeLayout;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.amap.api.maps.AMap;
|
||||
import com.amap.api.maps.CameraUpdate;
|
||||
import com.amap.api.maps.CameraUpdateFactory;
|
||||
import com.amap.api.maps.CoordinateConverter;
|
||||
import com.amap.api.maps.TextureMapView;
|
||||
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.LatLngBounds;
|
||||
import com.amap.api.maps.model.Marker;
|
||||
import com.amap.api.maps.model.MarkerOptions;
|
||||
import com.amap.api.maps.model.Polyline;
|
||||
import com.amap.api.maps.model.PolylineOptions;
|
||||
import com.mogo.cloud.commons.utils.CoordinateUtils;
|
||||
import com.mogo.eagle.core.data.map.MogoLatLng;
|
||||
import com.mogo.eagle.core.data.map.MogoLocation;
|
||||
import com.mogo.eagle.core.function.api.map.listener.IMoGoMapLocationListener;
|
||||
import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger;
|
||||
import com.mogo.eagle.core.function.call.map.CallerMapLocationListenerManager;
|
||||
import com.mogo.eagle.core.function.map.R;
|
||||
import com.mogo.eagle.core.utilcode.mogo.MapAssetStyleUtils;
|
||||
import com.mogo.eagle.core.function.smp.view.ISmallMapDirectionView;
|
||||
import com.mogo.eagle.core.widget.RoundLayout;
|
||||
import com.mogo.module.common.utils.DrivingDirectionUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 小地图的方向View
|
||||
*
|
||||
* @author donghongyu
|
||||
* @date 12/14/20 4:40 PM
|
||||
*/
|
||||
public class SmallMapDirectionView
|
||||
extends RelativeLayout
|
||||
implements IMoGoMapLocationListener, ISmallMapDirectionView {
|
||||
|
||||
//小地图名称
|
||||
public static final String TAG = "SmallMapDirectionView";
|
||||
|
||||
private RoundLayout rlSmallMapBorder;
|
||||
private TextureMapView mAMapNaviView;
|
||||
private AMap mAMap;
|
||||
private Marker mCarMarker;
|
||||
private Marker mStartMarker;
|
||||
private Marker mEndMarker;
|
||||
|
||||
private int zoomLevel = 15;
|
||||
private final List<LatLng> mCoordinatesLatLng = new ArrayList<>();
|
||||
private final List<MogoLatLng> mCoordinatesLatLngCurrent = new ArrayList<>();
|
||||
private Polyline mPolyline;
|
||||
private CameraUpdate mCameraUpdate;
|
||||
private Context mContext;
|
||||
|
||||
public SmallMapDirectionView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public SmallMapDirectionView(Context context, @Nullable AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public SmallMapDirectionView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
try {
|
||||
initView(context);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void initView(Context context) {
|
||||
mContext = context;
|
||||
View smpView = LayoutInflater.from(context).inflate(R.layout.module_small_map_view, this);
|
||||
|
||||
mAMapNaviView = smpView.findViewById(R.id.aMapNaviView);
|
||||
// rlSmallMapBorder = findViewById(R.id.rlSmallMapBorder);
|
||||
// rlSmallMapBorder.addView(mAMapNaviView);
|
||||
|
||||
initAMapView();
|
||||
|
||||
// 注册定位监听
|
||||
CallerMapLocationListenerManager.INSTANCE.addListener(TAG, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
// 注册定位监听
|
||||
CallerMapLocationListenerManager.INSTANCE.removeListener(TAG);
|
||||
}
|
||||
|
||||
private void initAMapView() {
|
||||
mCameraUpdate = CameraUpdateFactory.zoomTo(zoomLevel);
|
||||
mAMap = mAMapNaviView.getMap();
|
||||
// 关闭地图文字标注
|
||||
mAMap.showMapText(false);
|
||||
// 设置导航地图模式,aMap是地图控制器对象。
|
||||
mAMap.setMapType(AMap.MAP_TYPE_NIGHT);
|
||||
// 关闭显示实时路况图层,aMap是地图控制器对象。
|
||||
mAMap.setTrafficEnabled(false);
|
||||
// 设置 锚点 图标
|
||||
mCarMarker = mAMap.addMarker(new MarkerOptions()
|
||||
.icon(BitmapDescriptorFactory.fromResource(R.drawable.module_small_map_view_my_location_logo))
|
||||
.anchor(0.5f, 0.5f));
|
||||
mStartMarker = mAMap.addMarker(new MarkerOptions()
|
||||
.icon(BitmapDescriptorFactory.fromResource(R.drawable.module_small_map_view_dir_start)));
|
||||
mEndMarker = mAMap.addMarker(new MarkerOptions()
|
||||
.icon(BitmapDescriptorFactory.fromResource(R.drawable.module_small_map_view_dir_end)));
|
||||
// 加载自定义样式
|
||||
CustomMapStyleOptions customMapStyleOptions = new CustomMapStyleOptions()
|
||||
.setEnable(true)
|
||||
.setStyleData(MapAssetStyleUtils.getAssetsStyle(getContext()))
|
||||
.setStyleExtraData(MapAssetStyleUtils.getAssetsExtraStyle(getContext()));
|
||||
// 设置自定义样式
|
||||
mAMap.setCustomMapStyle(customMapStyleOptions);
|
||||
//设置希望展示的地图缩放级别
|
||||
mAMap.moveCamera(mCameraUpdate);
|
||||
// 设置地图的样式
|
||||
UiSettings uiSettings = mAMap.getUiSettings();
|
||||
uiSettings.setZoomControlsEnabled(false);// 地图缩放级别的交换按钮
|
||||
uiSettings.setAllGesturesEnabled(false);// 所有手势
|
||||
uiSettings.setMyLocationButtonEnabled(false); // 显示默认的定位按钮
|
||||
uiSettings.setLogoBottomMargin(-150); //设置Logo下边界距离屏幕底部的边距,设置为负值即可
|
||||
mAMap.setOnMapLoadedListener(() -> {
|
||||
CallerLogger.INSTANCE.d(M_MAP + TAG, "smp---onMapLoaded");
|
||||
// 加载自定义样式
|
||||
CustomMapStyleOptions customMapStyleOptions1 = new CustomMapStyleOptions()
|
||||
.setEnable(true)
|
||||
.setStyleData(MapAssetStyleUtils.getAssetsStyle(getContext()))
|
||||
.setStyleExtraData(MapAssetStyleUtils.getAssetsExtraStyle(getContext()));
|
||||
// 设置自定义样式
|
||||
mAMap.setCustomMapStyle(customMapStyleOptions1);
|
||||
mAMapNaviView.getMap().setPointToCenter(mAMapNaviView.getWidth() / 2, mAMapNaviView.getHeight() / 2);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onLocationChanged(@org.jetbrains.annotations.Nullable MogoLocation location, int from) {
|
||||
if (location == null) {
|
||||
return;
|
||||
}
|
||||
if (mCarMarker == null){
|
||||
mCarMarker = mAMap.addMarker(new MarkerOptions()
|
||||
.icon(BitmapDescriptorFactory.fromResource(R.drawable.module_small_map_view_my_location_logo))
|
||||
.anchor(0.5f, 0.5f));
|
||||
}
|
||||
if(mCarMarker == null){
|
||||
return;
|
||||
}
|
||||
LatLng currentLatLng = new LatLng(location.getLatitude(), location.getLongitude());
|
||||
//更新车辆位置
|
||||
mCarMarker.setPosition(currentLatLng);
|
||||
|
||||
CameraPosition cameraPosition;
|
||||
if (mCoordinatesLatLng.size() > 1) {
|
||||
// mCoordinatesLatLngCurrent.clear();
|
||||
// for (LatLng lng : mCoordinatesLatLng) {
|
||||
// MogoLatLng mogoLatLng = new MogoLatLng(lng.latitude, lng.longitude);
|
||||
// mCoordinatesLatLngCurrent.add(mogoLatLng);
|
||||
// }
|
||||
// removeLoction(latLng);
|
||||
|
||||
// 结束位置
|
||||
LatLng endLatLng = mCoordinatesLatLng.get(mCoordinatesLatLng.size() - 1);
|
||||
// 与结束位置进行 GeoHash 0-12
|
||||
// GeoHash endGeoHash = GeoHash.withCharacterPrecision(endLatLng.latitude, endLatLng.longitude, 7);
|
||||
// GeoHash currentGeoHash = GeoHash.withCharacterPrecision(currentLatLng.latitude, currentLatLng.longitude, 7);
|
||||
|
||||
float calculateDistance = CoordinateUtils.calculateLineDistance(
|
||||
endLatLng.latitude, endLatLng.longitude,
|
||||
currentLatLng.latitude, currentLatLng.longitude
|
||||
);
|
||||
|
||||
CallerLogger.INSTANCE.d(M_MAP + TAG, "calculateDistance=" + calculateDistance);
|
||||
if (calculateDistance <= 5) {
|
||||
clearPolyline();
|
||||
mCoordinatesLatLng.clear();
|
||||
}
|
||||
cameraPosition = new CameraPosition.Builder().target(mCarMarker.getPosition()).tilt(0).bearing(location.getBearing()).zoom(zoomLevel).build();
|
||||
} else {
|
||||
//设置希望展示的地图缩放级别
|
||||
cameraPosition = new CameraPosition.Builder().target(mCarMarker.getPosition()).tilt(0).bearing(location.getBearing()).zoom(zoomLevel).build();
|
||||
// mAMap.moveCamera(CameraUpdateFactory.newLatLngZoom(currentLatLng, zoomLevel));
|
||||
}
|
||||
mAMap.moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
|
||||
}
|
||||
|
||||
private void removeLocation(Location latLng) {
|
||||
for (LatLng l : mCoordinatesLatLng) {
|
||||
if (!isPointOnCarFront(latLng, l)) {
|
||||
mCoordinatesLatLng.remove(l);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isPointOnCarFront(Location carLocal, LatLng pointLocal) {
|
||||
double carLon = carLocal.getLongitude();
|
||||
double carLat = carLocal.getLatitude();
|
||||
double poiLon = pointLocal.longitude;
|
||||
double poiLat = pointLocal.latitude;
|
||||
float carAngle = carLocal.getBearing();
|
||||
|
||||
// 计算车辆与点之间的夹角
|
||||
int diffAngle = DrivingDirectionUtils.getDegreeOfCar2Poi(
|
||||
carLon, carLat, poiLon, poiLat, (int) carAngle);
|
||||
|
||||
return diffAngle <= 90;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void drawablePolyline() {
|
||||
clearPolyline();
|
||||
// mCoordinatesLatLng.clear();
|
||||
// List<LatLng> latLngs = CoordinateConverterFrom84ForList(mContext,coordinates);
|
||||
// mCoordinatesLatLng.addAll(latLngs);
|
||||
// for (LatLng coordinate : mCoordinatesLatLng) {
|
||||
// mCoordinatesLatLng.add(new LatLng(coordinate.getLat(), coordinate.getLon()));
|
||||
// }
|
||||
if (mAMap != null) {
|
||||
if (mCoordinatesLatLng.size() > 2) {
|
||||
// 设置开始结束Marker位置
|
||||
mStartMarker.setPosition(mCoordinatesLatLng.get(0));
|
||||
mEndMarker.setPosition(mCoordinatesLatLng.get(mCoordinatesLatLng.size() - 1));
|
||||
mStartMarker.setToTop();
|
||||
mStartMarker.setVisible(true);
|
||||
mEndMarker.setVisible(true);
|
||||
mEndMarker.setToTop();
|
||||
|
||||
|
||||
//存放所有点的经纬度
|
||||
LatLngBounds.Builder boundsBuilder = new LatLngBounds.Builder();
|
||||
|
||||
for (int i = 0; i < mCoordinatesLatLng.size(); i++) {
|
||||
//把所有点都include进去(LatLng类型)
|
||||
boundsBuilder.include(mCoordinatesLatLng.get(i));
|
||||
}
|
||||
//第二个参数为四周留空宽度
|
||||
mAMap.animateCamera(CameraUpdateFactory.newLatLngBounds(boundsBuilder.build(), 30));
|
||||
// 绘制线
|
||||
mPolyline = mAMap.addPolyline(
|
||||
new PolylineOptions()
|
||||
.addAll(mCoordinatesLatLng)
|
||||
.color(Color.argb(255, 31, 127, 255))
|
||||
.width(12));
|
||||
|
||||
}
|
||||
// else {
|
||||
// //设置希望展示的地图缩放级别
|
||||
// mAMap.moveCamera(CameraUpdateFactory.newLatLngZoom(mCoordinatesLatLng.get(0), zoomLevel));
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public LatLng CoordinateConverterFrom84(Context mContext, MogoLatLng mogoLatLng) {
|
||||
CoordinateConverter mCoordinateConverter = new CoordinateConverter(mContext);
|
||||
mCoordinateConverter.from(CoordinateConverter.CoordType.GPS);
|
||||
mCoordinateConverter.coord(new LatLng(mogoLatLng.lat, mogoLatLng.lon));
|
||||
return mCoordinateConverter.convert();
|
||||
}
|
||||
|
||||
public List<LatLng> CoordinateConverterFrom84ForList(Context mContext, List<MogoLatLng> mogoLatLngList) {
|
||||
List<LatLng> list = new ArrayList<>();
|
||||
for (MogoLatLng m : mogoLatLngList) {
|
||||
LatLng mogoLatLng = CoordinateConverterFrom84(mContext, m);
|
||||
list.add(mogoLatLng);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearPolyline() {
|
||||
// mCoordinatesLatLng.clear();
|
||||
if (mPolyline != null) {
|
||||
mPolyline.remove();
|
||||
}
|
||||
if (mStartMarker != null) {
|
||||
mStartMarker.setVisible(false);
|
||||
}
|
||||
if (mEndMarker != null) {
|
||||
mEndMarker.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void resetPolyLine() {
|
||||
mCoordinatesLatLng.clear();
|
||||
if (mPolyline != null) {
|
||||
mPolyline.remove();
|
||||
}
|
||||
if (mStartMarker != null) {
|
||||
mStartMarker.setVisible(false);
|
||||
}
|
||||
if (mEndMarker != null) {
|
||||
mEndMarker.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
public void onCreateView(Bundle savedInstanceState) {
|
||||
if (mAMapNaviView != null) {
|
||||
mAMapNaviView.onCreate(savedInstanceState);
|
||||
}
|
||||
}
|
||||
|
||||
public void onResume() {
|
||||
if (mAMapNaviView != null) {
|
||||
mAMapNaviView.onResume();
|
||||
}
|
||||
}
|
||||
|
||||
public void onPause() {
|
||||
if (mAMapNaviView != null) {
|
||||
mAMapNaviView.onPause();
|
||||
}
|
||||
}
|
||||
|
||||
public void onDestroy() {
|
||||
if (mAMapNaviView != null) {
|
||||
mAMapNaviView.onDestroy();
|
||||
}
|
||||
}
|
||||
|
||||
public void convert(List<MogoLatLng> coordinates) {
|
||||
mCoordinatesLatLng.clear();
|
||||
List<LatLng> latLngs = CoordinateConverterFrom84ForList(mContext, coordinates);
|
||||
mCoordinatesLatLng.addAll(latLngs);
|
||||
}
|
||||
|
||||
}
|
||||
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 218 B |
|
After Width: | Height: | Size: 215 B |
|
After Width: | Height: | Size: 218 B |
|
After Width: | Height: | Size: 218 B |
|
After Width: | Height: | Size: 179 B |
|
After Width: | Height: | Size: 159 B |
|
After Width: | Height: | Size: 139 B |
|
After Width: | Height: | Size: 361 B |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 29 KiB |
BIN
core/function-impl/mogo-core-function-map/src/main/res/drawable-xhdpi-2560x1440/module_small_map_view_dir_end.png
Normal file → Executable file
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 9.9 KiB |
|
After Width: | Height: | Size: 159 B |
BIN
core/function-impl/mogo-core-function-map/src/main/res/drawable-xhdpi-2560x1440/module_small_map_view_dir_start.png
Normal file → Executable file
|
Before Width: | Height: | Size: 7.5 KiB After Width: | Height: | Size: 9.6 KiB |
@@ -4,7 +4,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.mogo.eagle.core.function.smp.SmallMapDirectionView
|
||||
<com.mogo.eagle.core.function.smp.AMapCustomView
|
||||
android:id="@+id/smallMapDirectionView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
<dimen name="module_map_display_overview_right_margin">200px</dimen>
|
||||
|
||||
<dimen name="module_small_map_padding">40px</dimen>
|
||||
<dimen name="module_small_map_view_border_width">400px</dimen>
|
||||
<dimen name="module_small_map_view_border_width">700px</dimen>
|
||||
<dimen name="module_small_map_border_view_width">550px</dimen>
|
||||
<dimen name="module_small_map_view_width">360px</dimen>
|
||||
<dimen name="module_small_map_view_width">660px</dimen>
|
||||
|
||||
</resources>
|
||||
@@ -12,7 +12,7 @@
|
||||
<dimen name="module_map_display_overview_right_margin">100px</dimen>
|
||||
|
||||
<dimen name="module_small_map_padding">30px</dimen>
|
||||
<dimen name="module_small_map_view_border_width">288px</dimen>
|
||||
<dimen name="module_small_map_border_view_width">450px</dimen>
|
||||
<dimen name="module_small_map_view_width">260px</dimen>
|
||||
<dimen name="module_small_map_view_border_width">588px</dimen>
|
||||
<dimen name="module_small_map_border_view_width">550px</dimen>
|
||||
<dimen name="module_small_map_view_width">560px</dimen>
|
||||
</resources>
|
||||
@@ -10,7 +10,7 @@ import com.mogo.eagle.core.data.R
|
||||
object HdMapBuildConfig {
|
||||
/**
|
||||
* 自车模型(默认是出租车)
|
||||
* 可以指定,R.raw.chuzuche,R.raw.xiaobache
|
||||
* 可以指定,R.raw.chuzuche,R.raw.xiaobache,R.raw.hongqi
|
||||
*/
|
||||
@JvmField
|
||||
var currentCarVrIconRes = R.raw.chuzuche
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.mogo.eagle.core.function.api.autopilot
|
||||
|
||||
import chassis.Chassis
|
||||
import mogo.telematics.pad.MessagePad
|
||||
|
||||
/**
|
||||
* 车辆底盘 数据 回调监听
|
||||
@@ -36,4 +37,9 @@ interface IMoGoAutopilotVehicleStateListener {
|
||||
* 没有自车状态数据
|
||||
*/
|
||||
fun onAutopilotDataException(timestamp: Long){}
|
||||
|
||||
/**
|
||||
* 车辆加速度
|
||||
*/
|
||||
fun onAutopilotAcc(carAcc: Float)
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import androidx.annotation.Nullable
|
||||
import chassis.Chassis
|
||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotVehicleStateListener
|
||||
import com.mogo.eagle.core.function.call.base.CallerBase
|
||||
import mogo.telematics.pad.MessagePad
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
/**
|
||||
@@ -100,6 +101,18 @@ object CallerAutopilotVehicleStateListenerManager : CallerBase() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 车辆加速度
|
||||
* acc 加速度
|
||||
*/
|
||||
fun invokeAutopilotAcc(carAcc: Float){
|
||||
M_AUTOPILOT_VEHICLE_LISTENERS.forEach{
|
||||
val listener = it.value
|
||||
listener.onAutopilotAcc(carAcc)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 工控机时间回调
|
||||
*/
|
||||
|
||||
BIN
core/mogo-core-res/src/main/assets/over_view_style.data
Normal file
BIN
core/mogo-core-res/src/main/assets/over_view_style_extra.data
Normal file
BIN
core/mogo-core-res/src/main/res/raw/chuzuche.nt3d
Executable file → Normal file
@@ -12,11 +12,11 @@ import java.io.InputStream;
|
||||
*/
|
||||
public class MapAssetStyleUtils {
|
||||
|
||||
public static byte[] getAssetsStyle(Context context) {
|
||||
public static byte[] getAssetsStyle(Context context,String fileName) {
|
||||
byte[] buffer1 = null;
|
||||
InputStream is1 = null;
|
||||
try {
|
||||
is1 = context.getResources().getAssets().open("small_map_style.data");
|
||||
is1 = context.getResources().getAssets().open(fileName); //eg. small_map_style.data
|
||||
int lenght1 = is1.available();
|
||||
buffer1 = new byte[lenght1];
|
||||
is1.read(buffer1);
|
||||
@@ -35,11 +35,11 @@ public class MapAssetStyleUtils {
|
||||
}
|
||||
|
||||
|
||||
public static byte[] getAssetsExtraStyle(Context context) {
|
||||
public static byte[] getAssetsExtraStyle(Context context, String fileName) {
|
||||
byte[] buffer1 = null;
|
||||
InputStream is1 = null;
|
||||
try {
|
||||
is1 = context.getResources().getAssets().open("small_map_style_extra.data");
|
||||
is1 = context.getResources().getAssets().open(fileName); //eg. small_map_style_extra.data
|
||||
int lenght1 = is1.available();
|
||||
buffer1 = new byte[lenght1];
|
||||
is1.read(buffer1);
|
||||
|
||||
@@ -178,6 +178,12 @@ public interface IMogoMapUIController {
|
||||
*/
|
||||
void setCarCursorOption(@Nullable CarCursorOption option);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param type :车尾灯类型 time: 闪烁时间 最小500ms 小于500ms 默认为500ms
|
||||
*/
|
||||
void setCarLightsType(int type, int time);
|
||||
|
||||
/**
|
||||
* 获取地图视图描述快照
|
||||
*
|
||||
|
||||
@@ -639,6 +639,17 @@ public class AMapViewWrapper implements IMogoMapView,
|
||||
mMapView.getMapAutoViewHelper().setMyLocationStyle(style);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置转向灯和刹车灯
|
||||
* @param type :车尾灯类型 time: 闪烁时间 最小500ms 小于500ms 默认为500ms
|
||||
* @param time
|
||||
*/
|
||||
@Override
|
||||
public void setCarLightsType(int type, int time) {
|
||||
Log.d("liyz", "AMapViewWrapper setCarLightsType type = " + type + "---time = " + time);
|
||||
mMapView.getMapAutoViewHelper().setTailLightsType(type, time);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapCameraPosition getMapCameraPosition() {
|
||||
if (checkAMapView()) {
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.mogo.map;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.location.Location;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import com.mogo.eagle.core.data.map.CenterLine;
|
||||
@@ -252,6 +253,15 @@ public class MogoMapUIController implements IMogoMapUIController {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCarLightsType(int type, int time) {
|
||||
initDelegate();
|
||||
if (mDelegate != null) {
|
||||
// Log.d("liyz", "MogoMapUIController type = " + type + "---time = " + time);
|
||||
mDelegate.setCarLightsType(type, time);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapCameraPosition getMapCameraPosition() {
|
||||
initDelegate();
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.mogo.map.uicontroller;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.location.Location;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import com.mogo.eagle.core.data.map.CenterLine;
|
||||
@@ -220,6 +221,14 @@ public class AMapUIController implements IMogoMapUIController {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCarLightsType(int type, int time) {
|
||||
// Log.d("liyz", "AMapUIController type = " + type + "---time = " + time);
|
||||
if (mClient != null) {
|
||||
mClient.setCarLightsType(type, time);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapCameraPosition getMapCameraPosition() {
|
||||
if (mClient != null) {
|
||||
|
||||
@@ -3,8 +3,13 @@
|
||||
<dimen name="dp_12">12px</dimen>
|
||||
<dimen name="dp_20">20px</dimen>
|
||||
<dimen name="dp_22">22px</dimen>
|
||||
<dimen name="dp_43">43px</dimen>
|
||||
<dimen name="dp_57">57px</dimen>
|
||||
<dimen name="dp_72">72px</dimen>
|
||||
<dimen name="dp_88">88px</dimen>
|
||||
<dimen name="module_v2n_tip_text_margin_right">26px</dimen>
|
||||
<dimen name="warning_distance_right">30px</dimen>
|
||||
<dimen name="dp_270">270px</dimen>
|
||||
<dimen name="dp_320">320px</dimen>
|
||||
<dimen name="dp_630">630px</dimen>
|
||||
</resources>
|
||||
|
||||