diff --git a/OCH/mogo-och-taxi-passenger/build.gradle b/OCH/mogo-och-taxi-passenger/build.gradle index 11d05e4d51..d3b586a5ed 100644 --- a/OCH/mogo-och-taxi-passenger/build.gradle +++ b/OCH/mogo-och-taxi-passenger/build.gradle @@ -49,6 +49,7 @@ dependencies { implementation rootProject.ext.dependencies.arouter implementation rootProject.ext.dependencies.androidxrecyclerview implementation rootProject.ext.dependencies.material + implementation rootProject.ext.dependencies.flexbox annotationProcessor rootProject.ext.dependencies.aroutercompiler implementation rootProject.ext.dependencies.rxandroid implementation rootProject.ext.dependencies.androidxconstraintlayout diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/bean/TaxiPassengerAllStarWorld.java b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/bean/TaxiPassengerAllStarWorld.java new file mode 100644 index 0000000000..4810e8d06f --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/bean/TaxiPassengerAllStarWorld.java @@ -0,0 +1,26 @@ +package com.mogo.och.taxi.passenger.bean; + +import com.mogo.eagle.core.data.BaseData; + +import java.util.List; + +/** + * Created by pangfan on 2021/8/19 + * + * 查询订单返回数据结构 + */ +public class TaxiPassengerAllStarWorld extends BaseData { + public List data; + + public static class TaxiPassengerStarWorld { + public TaxiPassengerStarWorld(String labelInfo) { + this.labelInfo = labelInfo; + } + + public String labelNo; + public String labelInfo; + public String star; + public String sort; + public Boolean isSelect = false; + } +} diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/bean/TaxiPassengerScoreUpdateOrderReqBean.java b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/bean/TaxiPassengerScoreUpdateOrderReqBean.java index 75234703cf..e5cc00ca24 100644 --- a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/bean/TaxiPassengerScoreUpdateOrderReqBean.java +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/bean/TaxiPassengerScoreUpdateOrderReqBean.java @@ -1,5 +1,7 @@ package com.mogo.och.taxi.passenger.bean; +import java.util.List; + /** * Created by pangfan on 2021/8/19 * @@ -9,9 +11,17 @@ public class TaxiPassengerScoreUpdateOrderReqBean { public String orderNo; public int star; + public List evalLabeBasicList; - public TaxiPassengerScoreUpdateOrderReqBean(String orderNo, int star) { + public TaxiPassengerScoreUpdateOrderReqBean(String orderNo, int star,List data) { this.orderNo = orderNo; this.star = star; + for (TaxiPassengerAllStarWorld.TaxiPassengerStarWorld datum : data) { + datum.isSelect=null; + datum.sort = null; + datum.star = null; + } + this.evalLabeBasicList = data; } + } diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/bean/TaxiPassengerVideoPlay.java b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/bean/TaxiPassengerVideoPlay.java new file mode 100644 index 0000000000..204760da46 --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/bean/TaxiPassengerVideoPlay.java @@ -0,0 +1,38 @@ +package com.mogo.och.taxi.passenger.bean; + +public class TaxiPassengerVideoPlay { + + public TaxiPassengerVideoPlay(String url, String imageUrl, String title) { + this.url = url; + this.imageUrl = imageUrl; + this.title = title; + } + + private String url; + private String imageUrl; + private String title; + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getImageUrl() { + return imageUrl; + } + + public void setImageUrl(String imageUrl) { + this.imageUrl = imageUrl; + } +} diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/callback/ITaxiPassengerScoreCallback.java b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/callback/ITaxiPassengerScoreCallback.java index 4bb7b6e187..8a726a52d2 100644 --- a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/callback/ITaxiPassengerScoreCallback.java +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/callback/ITaxiPassengerScoreCallback.java @@ -1,5 +1,7 @@ package com.mogo.och.taxi.passenger.callback; +import com.mogo.och.taxi.passenger.bean.TaxiPassengerScoreUpdateOrderReqBean; + public interface ITaxiPassengerScoreCallback { - void onScoreCallback(int fraction,String orderNo); + void onScoreCallback(TaxiPassengerScoreUpdateOrderReqBean taxiPassengerScoreUpdateOrderReqBean); } diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/model/TaxiPassengerModel.java b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/model/TaxiPassengerModel.java index b7335cac04..038e27f978 100644 --- a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/model/TaxiPassengerModel.java +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/model/TaxiPassengerModel.java @@ -40,6 +40,7 @@ import com.mogo.och.taxi.passenger.bean.TaxiPassengerOrderQueryRespBean; import com.mogo.och.taxi.passenger.bean.TaxiPassengerOrdersInServiceQueryRespBean; import com.mogo.och.taxi.passenger.bean.TaxiPassengerQueryOrderRouteResp; import com.mogo.och.taxi.passenger.bean.TaxiPassengerStartReqBean; +import com.mogo.och.taxi.passenger.bean.TaxiPassengerScoreUpdateOrderReqBean; import com.mogo.och.taxi.passenger.callback.IOCHTaxiPassengerADASStatusCallback; import com.mogo.och.taxi.passenger.callback.IOCHTaxiPassengerAutopilotPlanningCallback; import com.mogo.och.taxi.passenger.callback.IOCHTaxiPassengerControllerStatusCallback; @@ -731,7 +732,6 @@ public class TaxiPassengerModel implements IOCHTaxiPassengerNaviChangedCallback public void checkPhoneAndUpdateStatus(String phoneTail,ITaxiPassengerCommonCallback commonCallback) { if (mCurrentOCHOrder == null) return; - CallerLogger.INSTANCE.d(M_TAXI_P + TAG, "--route--- checkPhoneAndUpdateStatus"); TaxiPassengerServiceManager.getInstance().checkPhoneAndUpdateOrderStatus(mContext, mCurrentOCHOrder.orderNo, phoneTail, new TaxiPassengerServiceCallback() { @Override @@ -749,14 +749,14 @@ public class TaxiPassengerModel implements IOCHTaxiPassengerNaviChangedCallback @Override public void onFail(int code, String msg) { ToastUtils.showLong("当前网络异常,请重新验证;若始终异常,请您在手机端取消行程,给您带来不便,十分抱歉!"); - CallerLogger.INSTANCE.e(TAG,"提交用户输入的手机后4位、并进行状态扭转 后台结果错误"+code+msg); + CallerLogger.INSTANCE.e(M_TAXI_P + TAG,"提交用户输入的手机后4位、并进行状态扭转 后台结果错误"+code+msg); } }); } - public void arrivedAndScore(int score,String orderNo ,ITaxiPassengerCommonValueCallback commonCallback) { - if (orderNo == null) return; - TaxiPassengerServiceManager.getInstance().arrivedAndScore(mContext,orderNo,score, + public void arrivedAndScore(TaxiPassengerScoreUpdateOrderReqBean taxiPassengerScoreUpdateOrderReqBean , ITaxiPassengerCommonValueCallback commonCallback) { + if (taxiPassengerScoreUpdateOrderReqBean.orderNo == null) return; + TaxiPassengerServiceManager.getInstance().arrivedAndScore(mContext,taxiPassengerScoreUpdateOrderReqBean, new TaxiPassengerServiceCallback() { @Override public void onSuccess(TaxiPassengerBaseRespBean data) { @@ -768,7 +768,7 @@ public class TaxiPassengerModel implements IOCHTaxiPassengerNaviChangedCallback @Override public void onError() { ToastUtils.showLong("网络错误请稍后再试"); - CallerLogger.INSTANCE.e(TAG,"对订单进行打分 1-5分 网络错误"); + CallerLogger.INSTANCE.e(M_TAXI_P + TAG,"对订单进行打分 1-5分 网络错误"); if(commonCallback!=null) { commonCallback.onCommonCallback(false); } @@ -776,7 +776,7 @@ public class TaxiPassengerModel implements IOCHTaxiPassengerNaviChangedCallback @Override public void onFail(int code, String msg) { - CallerLogger.INSTANCE.e(TAG,"对订单进行打分 1-5分 后台结果错误"+code+msg); + CallerLogger.INSTANCE.e(M_TAXI_P + TAG,"对订单进行打分 1-5分 后台结果错误"+code+msg); if(commonCallback!=null) { commonCallback.onCommonCallback(false); } diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/network/TaxiPassengerServiceApi.java b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/network/TaxiPassengerServiceApi.java index 6dbbb3046d..e7c366c18a 100644 --- a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/network/TaxiPassengerServiceApi.java +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/network/TaxiPassengerServiceApi.java @@ -1,4 +1,5 @@ package com.mogo.och.taxi.passenger.network; +import com.mogo.och.taxi.passenger.bean.TaxiPassengerAllStarWorld; import com.mogo.och.taxi.passenger.bean.TaxiPassengerBaseRespBean; import com.mogo.och.taxi.passenger.bean.TaxiPassengerCheckPhoneUpdateOrderReqBean; import com.mogo.och.taxi.passenger.bean.TaxiPassengerOrderQueryRemainingResp; @@ -74,18 +75,33 @@ interface TaxiPassengerServiceApi { * @return */ @Headers( {"Content-type:application/json;charset=UTF-8"} ) - @POST( "/autopilot-car-hailing/order/v2/vehicle/taxi/passenger/verification/phone" ) + @POST( "/autopilot-car-hailing/cab/flow/v1/driver/taxi/passenger/verification/phone" ) Observable checkPhoneAndUpdateOrderStatus(@Header ("appId") String appId, @Header("ticket") String ticket, @Body TaxiPassengerCheckPhoneUpdateOrderReqBean data); /** - * 对订单进行打分 1-5分 + * 对订单进行打分 1-5分 加上文案评论 * @param data * @return */ @Headers( {"Content-type:application/json;charset=UTF-8"} ) - @POST( "/autopilot-car-hailing/evaluation/vehicle/taxi/passenger/add" ) + @POST( "/autopilot-car-hailing/evaluation/info/driver/taxi/submit" ) Observable arrivedAndScore(@Header ("appId") String appId, @Header("ticket") String ticket, @Body TaxiPassengerScoreUpdateOrderReqBean data); + /** + * 获取星星对应的文案(所有文案) + * @return + */ + @Headers( {"Content-type:application/json;charset=UTF-8"} ) + @GET( "/autopilot-car-hailing/evaluation/label/driver/taxi/list" ) + Observable getWorldAllStar(@Header ("appId") String appId, @Header("ticket") String ticket); + /** + * 获取星星对应的文案(和星星一一对应) + * @return + */ + @Headers( {"Content-type:application/json;charset=UTF-8"} ) + @GET( "/autopilot-car-hailing/evaluation/label/driver/taxi/listByStar" ) + Observable getWorldByStar(@Header ("appId") String appId, @Header("ticket") String ticket,@Query("star") String star); + /** * 查询司机是否已确认可开启自动驾驶 * @param appId diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/network/TaxiPassengerServiceManager.java b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/network/TaxiPassengerServiceManager.java index e1a8070769..d04556f0b9 100644 --- a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/network/TaxiPassengerServiceManager.java +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/network/TaxiPassengerServiceManager.java @@ -11,7 +11,7 @@ import com.mogo.eagle.core.network.MoGoRetrofitFactory; import com.mogo.eagle.core.network.RequestOptions; import com.mogo.eagle.core.network.SubscribeImpl; import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger; -import com.mogo.module.common.MogoApisHandler; +import com.mogo.och.taxi.passenger.bean.TaxiPassengerAllStarWorld; import com.mogo.och.taxi.passenger.bean.TaxiPassengerBaseRespBean; import com.mogo.och.taxi.passenger.bean.TaxiPassengerCheckPhoneUpdateOrderReqBean; import com.mogo.och.taxi.passenger.bean.TaxiPassengerOrderQueryRemainingResp; @@ -55,7 +55,7 @@ public class TaxiPassengerServiceManager { */ private String getDriverAppSn(){ if(DebugConfig.isDebug()){ - return CallerTelematicManager.INSTANCE.getServerToken(); + return "X20202206092431156"; }else { return CallerTelematicManager.INSTANCE.getServerToken(); } @@ -161,11 +161,20 @@ public class TaxiPassengerServiceManager { .observeOn(AndroidSchedulers.mainThread()) .subscribe(getSubscribeImpl(context, callback, "checkPhoneAndUpdateOrderStatus")); } - public void arrivedAndScore(Context context, String orderNo,int star,TaxiPassengerServiceCallback callback){ + public void arrivedAndScore(Context context,TaxiPassengerScoreUpdateOrderReqBean taxiPassengerScoreUpdateOrderReqBean, TaxiPassengerServiceCallback callback){ mOCHTaxiServiceApi.arrivedAndScore( MoGoAiCloudClientConfig.getInstance().getServiceAppId() ,MoGoAiCloudClientConfig.getInstance().getToken() - ,new TaxiPassengerScoreUpdateOrderReqBean(orderNo,star)) + ,taxiPassengerScoreUpdateOrderReqBean) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(getSubscribeImpl(context, callback, "checkPhoneAndUpdateOrderStatus")); + } + + public void getAllScoreWorld(Context context,TaxiPassengerServiceCallback callback){ + mOCHTaxiServiceApi.getWorldAllStar( + MoGoAiCloudClientConfig.getInstance().getServiceAppId() + ,MoGoAiCloudClientConfig.getInstance().getToken()) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(getSubscribeImpl(context, callback, "arrivedAndScore")); @@ -192,4 +201,13 @@ public class TaxiPassengerServiceManager { .observeOn(AndroidSchedulers.mainThread()) .subscribe(getSubscribeImpl(context,callback,"startServicePilotDone")); } + public void getWorldByStar(Context context,String start,TaxiPassengerServiceCallback callback){ + mOCHTaxiServiceApi.getWorldByStar( + MoGoAiCloudClientConfig.getInstance().getServiceAppId() + ,MoGoAiCloudClientConfig.getInstance().getToken(),start) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(getSubscribeImpl(context, callback, "checkPhoneAndUpdateOrderStatus")); + } + } diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/presenter/BaseTaxiPassengerPresenter.java b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/presenter/BaseTaxiPassengerPresenter.java index 24d7ed5468..ced41770c1 100644 --- a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/presenter/BaseTaxiPassengerPresenter.java +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/presenter/BaseTaxiPassengerPresenter.java @@ -14,6 +14,7 @@ import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatusListener; import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger; import com.mogo.eagle.core.utilcode.util.UiThreadHandler; import com.mogo.och.taxi.passenger.bean.TaxiPassengerOrderQueryRespBean; +import com.mogo.och.taxi.passenger.bean.TaxiPassengerScoreUpdateOrderReqBean; import com.mogo.och.taxi.passenger.callback.IOCHTaxiPassengerADASStatusCallback; import com.mogo.och.taxi.passenger.callback.IOCHTaxiPassengerControllerStatusCallback; import com.mogo.och.taxi.passenger.callback.IOCHTaxiPassengerOrderStatusCallback; @@ -232,11 +233,10 @@ public class BaseTaxiPassengerPresenter extends Presenter mView.showArrivedEndLayout2Thank(aBoolean)); + public void arrivedAndScore(TaxiPassengerScoreUpdateOrderReqBean taxiPassengerScoreUpdateOrderReqBean){ + TaxiPassengerModel.getInstance().arrivedAndScore(taxiPassengerScoreUpdateOrderReqBean,aBoolean -> mView.showArrivedEndLayout2Thank(aBoolean)); } /** diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/TaxiPassengerBaseFragment.java b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/TaxiPassengerBaseFragment.java index 76f1b9c59e..247ccc70de 100644 --- a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/TaxiPassengerBaseFragment.java +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/TaxiPassengerBaseFragment.java @@ -28,6 +28,8 @@ import com.mogo.module.common.constants.DataTypes; import com.mogo.och.taxi.passenger.R; import com.mogo.och.taxi.passenger.callback.ITPClickStartAutopilotCallback; import com.mogo.och.taxi.passenger.presenter.BaseTaxiPassengerPresenter; +import com.mogo.och.taxi.passenger.ui.comment.TaxiPassengerArrivedView; +import com.mogo.och.taxi.passenger.ui.leftmenu.OverlayLeftViewUtils; import java.lang.ref.WeakReference; @@ -119,19 +121,22 @@ public class TaxiPassengerBaseFragment extends MvpFragment { + OverlayLeftViewUtils.INSTANCE.showOverlayView(getActivity()); //showOrHideArrivedEndLayout(true, "北京北京北京", "1527481606997577728"); //showOrHidePressengerCheckPager(true, "开始站点开", "开始站点开始站点开始", "2", "京A888888", "18811539480"); - //CallerHmiManager.INSTANCE.showToolsView(); + //OCHFloatWindowManager.getInstance().ShowFloatWindow(getContext()); + //OverlayViewUtils.showOverlayView(getActivity(),new TaxiPassengerMogoConsultView(getContext())); }); } private void initArrivedView(){ mArrivedEndView = new WeakReference<>(new TaxiPassengerArrivedView(getContext())); - mArrivedEndView.get().setITaxiPassengerScoreCallback((fraction, orderNo) -> getPresenter().arrivedAndScore(fraction,orderNo)); + mArrivedEndView.get().setITaxiPassengerScoreCallback((taxiPassengerScoreUpdateOrderReqBean) -> getPresenter().arrivedAndScore(taxiPassengerScoreUpdateOrderReqBean)); } private void initCheckView() { @@ -248,6 +253,7 @@ public class TaxiPassengerBaseFragment extends MvpFragment() var showThanks:Boolean = false + var allStarWithWorld: TaxiPassengerAllStarWorld?=null private fun initView(context: Context) { d(SceneConstant.M_TAXI_P + TAG, "initView") @@ -90,6 +108,9 @@ class TaxiPassengerArrivedView :RelativeLayout, View.OnClickListener { ivAnimalList = findViewById(R.id.iv_animal_list) acivClose = findViewById(R.id.aciv_close) svpFrame = findViewById(R.id.svp_frame) + rvCommentList = findViewById(R.id.rv_comment_list) + clCommentContain = findViewById(R.id.cl_comment_contain) + btnSubmit = findViewById(R.id.btn_submit) svpFrame.setBackgroundResource(R.drawable.tail_ani_0000) svpFrame.setIsTouchWiget(false) svpFrame.setIsTouchWigetFull(false) @@ -97,15 +118,11 @@ class TaxiPassengerArrivedView :RelativeLayout, View.OnClickListener { svpFrame.enableDoubleClick = false allStartOrdered = mutableListOf() + initCommentList() initScore() findViewById(R.id.tv_please_score).setOnClickListener(this) - // debug 弹出 - mArrivedEndStation.setOnLongClickListener { - scoreSuccess() - false - } acivClose.setOnClickListener { ochShadowLayout.visibility = View.GONE @@ -125,6 +142,16 @@ class TaxiPassengerArrivedView :RelativeLayout, View.OnClickListener { GSYVideoType.setShowType(GSYVideoType.SCREEN_TYPE_FULL) } + private fun initCommentList() { + val recyclerVideoAdapter = CommentAdapter(context, mutableListOf()) + rvCommentList.adapter = recyclerVideoAdapter + val manager = FlexboxLayoutManager(context) + manager.justifyContent = JustifyContent.CENTER + manager.flexWrap = FlexWrap.WRAP + rvCommentList.layoutManager = manager + btnSubmit.setOnClickListener(this) + } + private fun initScore() { ivStarFirst = findViewById(R.id.iv_star_first) ivStarSecond = findViewById(R.id.iv_star_second) @@ -142,11 +169,20 @@ class TaxiPassengerArrivedView :RelativeLayout, View.OnClickListener { allStartOrdered.add(ivStarThird) allStartOrdered.add(ivStarFourth) allStartOrdered.add(ivStarFifth) + + // 请求文案 + requestStarWord() } override fun onDetachedFromWindow() { svpFrame.setBackgroundResource(R.drawable.tail_ani_0000) + tvFeel.text = "" + rvCommentList.visibility = View.INVISIBLE + btnSubmit.visibility = View.INVISIBLE + svpFrame.onVideoReset() + clCommentContain.getLayoutParams().height = 657 + clCommentContain.requestLayout() super.onDetachedFromWindow() subscribe?.let { if (!it.isDisposed) { @@ -158,23 +194,45 @@ class TaxiPassengerArrivedView :RelativeLayout, View.OnClickListener { override fun onClick(v: View?) { when (v?.id) { R.id.tv_please_score -> { - iTaxiPassengerScoreCallback?.onScoreCallback(2,orderNo) + //iTaxiPassengerScoreCallback?.onScoreCallback(2,orderNo) } R.id.iv_star_first -> {commitAndStartAnimation(1,"不满意")} R.id.iv_star_second -> {commitAndStartAnimation(2,"不满意")} R.id.iv_star_third -> {commitAndStartAnimation(3,"一般")} R.id.iv_star_fourth -> {commitAndStartAnimation(4,"舒适")} R.id.iv_star_fifth -> {commitAndStartAnimation(5,"舒适")} + R.id.btn_submit -> {submitScore()} else -> {} } } + /** + * 提交到后台 + */ + private fun submitScore() { + val commentAdapter = rvCommentList.adapter as CommentAdapter + val selectComment = commentAdapter.getSelectComment() + iTaxiPassengerScoreCallback?.onScoreCallback(TaxiPassengerScoreUpdateOrderReqBean(orderNo,currentFraction,selectComment)) + } + private fun commitAndStartAnimation(fraction: Int,title:String) { + resetStar() + currentFraction = fraction tvFeel.text = title - startStartAnimation(fraction) - allStartOrdered.forEach { - it.isEnabled = false + if(allStarWithWorld!=null&&allStarWithWorld!!.data!=null&&allStarWithWorld!!.data!!.size>0){ + // 已经请求到总量了 + val filter = allStarWithWorld!!.data.filter { it.star == fraction.toString() } + val commentAdapter = rvCommentList.adapter as CommentAdapter + commentAdapter.addAll(filter.toMutableList()) + startStartAnimation(fraction) + }else{ + // 总量请求失败 单独去取 + requestStarWordByStar(fraction) } + +// allStartOrdered.forEach { +// it.isEnabled = false +// } } private var currentAnimarion = 0 private var maxIndex = 0 @@ -235,13 +293,36 @@ class TaxiPassengerArrivedView :RelativeLayout, View.OnClickListener { set.addListener(object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator?) { super.onAnimationEnd(animation) - iTaxiPassengerScoreCallback?.onScoreCallback(fraction,orderNo) + // 启动变高动画 + startChangeHeightAnimarion() } }) } set.start() } + private fun startChangeHeightAnimarion() { + // 815 除了 点评的高度 + val resizeAnimation = ResizeAnimation(clCommentContain,815+rvCommentList.height, clCommentContain.height) + resizeAnimation.duration = 300 + resizeAnimation.setAnimationListener(object :Animation.AnimationListener{ + override fun onAnimationStart(animation: Animation?) { + rvCommentList.visibility = View.VISIBLE + btnSubmit.visibility = View.VISIBLE + } + + override fun onAnimationEnd(animation: Animation?) { + + } + + override fun onAnimationRepeat(animation: Animation?) { + + } + + }) + clCommentContain.startAnimation(resizeAnimation) + } + /** * 设置目的地重置星星状态 */ @@ -316,6 +397,59 @@ class TaxiPassengerArrivedView :RelativeLayout, View.OnClickListener { } } + private fun requestStarWord() { + TaxiPassengerServiceManager.getInstance().getAllScoreWorld(context, + object : TaxiPassengerServiceCallback { + override fun onError() { + CallerLogger.e( + SceneConstant.M_TAXI_P + TAG, + "/autopilot-car-hailing/evaluation/label/driver/taxi/list 接口 onError" + ) + } + + override fun onFail(code: Int, msg: String) { + CallerLogger.e( + SceneConstant.M_TAXI_P + TAG, + "/autopilot-car-hailing/evaluation/label/driver/taxi/list 接口:${code}---${msg}" + ) + } + + override fun onSuccess(data: TaxiPassengerAllStarWorld?) { + allStarWithWorld = data + } + + }) + } + + private fun requestStarWordByStar(start:Int) { + TaxiPassengerServiceManager.getInstance().getWorldByStar(context,start.toString(), + object : TaxiPassengerServiceCallback { + override fun onError() { + CallerLogger.e( + SceneConstant.M_TAXI_P + TAG, + "/autopilot-car-hailing/evaluation/label/driver/taxi/listByStar 接口 onError" + ) + } + + override fun onFail(code: Int, msg: String) { + CallerLogger.e( + SceneConstant.M_TAXI_P + TAG, + "/autopilot-car-hailing/evaluation/label/driver/taxi/listByStar 接口:${code}---${msg}" + ) + } + + override fun onSuccess(data: TaxiPassengerAllStarWorld?) { + if(data?.data != null &&data.data!!.size>0){ + val commentAdapter = rvCommentList.adapter as CommentAdapter + commentAdapter.addAll(data.data.toMutableList()) + startStartAnimation(start) + } + } + + }) + } + + companion object { const val TAG = "TaxiPassengerArrivedView" } diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/comment/adapter/CommentAdapter.kt b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/comment/adapter/CommentAdapter.kt new file mode 100644 index 0000000000..bc73f62522 --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/comment/adapter/CommentAdapter.kt @@ -0,0 +1,56 @@ +package com.mogo.och.taxi.passenger.ui.comment.adapter + +import android.content.Context +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.recyclerview.widget.RecyclerView +import com.mogo.och.taxi.passenger.R +import com.mogo.och.taxi.passenger.bean.TaxiPassengerAllStarWorld.TaxiPassengerStarWorld + +class CommentAdapter(private val context: Context?,private val itemDataList: MutableList) : + RecyclerView.Adapter() { + + fun add(taxiPassengerStarWorld: TaxiPassengerStarWorld) { + itemDataList.add(taxiPassengerStarWorld) + notifyItemInserted(itemDataList.size) + } + + fun addAll(itemDataList: MutableList){ + this.itemDataList.clear() + this.itemDataList.addAll(itemDataList) + this.notifyDataSetChanged() + } + fun getSelectComment(): List { + return itemDataList.filter { it.isSelect } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemCommentHolder { + val v = LayoutInflater.from(context).inflate(R.layout.list_comment_item, parent, false) + return ItemCommentHolder(context, v) + } + + override fun onBindViewHolder(holder: ItemCommentHolder, position: Int) { + val taxiPassengerStarWorld = itemDataList[position] + holder.commentItem.text = taxiPassengerStarWorld.labelInfo + if (taxiPassengerStarWorld.isSelect!=null&&taxiPassengerStarWorld.isSelect) { + taxiPassengerStarWorld.isSelect = true + holder.commentItem.setBackgroundResource(R.drawable.taxi_p_comment_selected) + } else { + taxiPassengerStarWorld.isSelect = false + holder.commentItem.setBackgroundResource(R.drawable.taxi_p_comment_select) + } + holder.commentItem.setOnClickListener { v: View? -> + taxiPassengerStarWorld.isSelect = !taxiPassengerStarWorld.isSelect + notifyItemChanged(holder.bindingAdapterPosition) + } + } + + override fun getItemCount(): Int { + return itemDataList.size + } + + companion object { + private const val TAG = "RecyclerBaseAdapter" + } +} \ No newline at end of file diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/comment/adapter/ItemCommentHolder.java b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/comment/adapter/ItemCommentHolder.java new file mode 100644 index 0000000000..b09b073cde --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/comment/adapter/ItemCommentHolder.java @@ -0,0 +1,25 @@ +package com.mogo.och.taxi.passenger.ui.comment.adapter; + +import android.content.Context; +import android.view.View; +import android.widget.CheckBox; + +import androidx.recyclerview.widget.RecyclerView; + +import com.mogo.och.taxi.passenger.R; + +public class ItemCommentHolder extends RecyclerView.ViewHolder { + + public final static String TAG = "ItemCommentHolder"; + + protected Context context; + + public CheckBox commentItem; + + public ItemCommentHolder(Context context, View v) { + super(v); + this.context = context; + commentItem = v.findViewById(R.id.tv_comment); + } + +} diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/leftmenu/ItemViewTouchListener.kt b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/leftmenu/ItemViewTouchListener.kt new file mode 100644 index 0000000000..bf061c2902 --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/leftmenu/ItemViewTouchListener.kt @@ -0,0 +1,75 @@ +package com.mogo.och.taxi.passenger.ui.leftmenu + +import android.view.MotionEvent +import android.view.View +import android.view.WindowManager +import androidx.constraintlayout.widget.ConstraintLayout + +class ItemViewTouchListener( + private val wl: WindowManager.LayoutParams, + private val windowManager: WindowManager?, + private val close: (view:View,windowManager: WindowManager?) -> Unit, + private val open : (view:View,windowManager: WindowManager?) -> Unit +) : + View.OnTouchListener { + private var x = 0 + // 判断并放跑点击事件 + private var dragTime = 0L + private val DEVIATION = 10 + private val NEGATIVEDEVIATION = -10 + override fun onTouch(view: View, motionEvent: MotionEvent): Boolean { + when (motionEvent.action) { + MotionEvent.ACTION_DOWN -> { + x = motionEvent.rawX.toInt() + dragTime = System.currentTimeMillis() + } + MotionEvent.ACTION_MOVE -> { + val nowX = motionEvent.rawX.toInt() + val movedX = nowX - x + x = nowX + wl.apply { + x += movedX + } + if (wl.x > 0 || wl.x < OverlayLeftViewUtils.DEVIATION_WIDTH) { + wl.apply { + x -= movedX + } + return false + } + + if (wl.x > NEGATIVEDEVIATION && movedX > 0) { + open(view.rootView,windowManager) + }else{ + //更新悬浮球控件位置 + windowManager?.updateViewLayout(view.rootView, wl) + } + if (wl.x < OverlayLeftViewUtils.DEVIATION_WIDTH +DEVIATION && movedX < 0) { + close(view.rootView,windowManager) + }else{ + //更新悬浮球控件位置 + windowManager?.updateViewLayout(view.rootView, wl) + } + + + } + MotionEvent.ACTION_UP -> { + val startX = wl.x + if (startX > OverlayLeftViewUtils.DEVIATION_WIDTH /2 && startX < 0) { + //拖动距离大于一半 自动打开 + open(view.rootView,windowManager) + } else if (startX < OverlayLeftViewUtils.DEVIATION_WIDTH /2 && startX >= OverlayLeftViewUtils.DEVIATION_WIDTH) { + // 拖动距离小于一半自动关闭 + close(view.rootView,windowManager) + } + if (System.currentTimeMillis() - dragTime > 500) { + dragTime = 0 + return true + } + } + else -> { + + } + } + return false + } +} \ No newline at end of file diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/leftmenu/ListAdapter.kt b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/leftmenu/ListAdapter.kt new file mode 100644 index 0000000000..d27143ba02 --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/leftmenu/ListAdapter.kt @@ -0,0 +1,55 @@ +package com.mogo.och.taxi.passenger.ui.leftmenu + +import android.content.Context +import android.view.View +import android.view.ViewGroup +import android.widget.BaseAdapter +import android.widget.ImageView +import com.mogo.och.taxi.passenger.ui.leftmenu.model.LeftMenuModel + +class ListAdapter(private val context: Context,val list: MutableList) : BaseAdapter() { + + override fun getCount(): Int { + return list.size + } + + override fun getItem(position: Int): Any { + return list[position] + } + + override fun getItemId(position: Int): Long { + return position.toLong() + } + + override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View { + val imageView = ImageView(context) + val leftMenuModel = list[position] + if (leftMenuModel.isChecked) { + imageView.setImageResource(leftMenuModel.selected) + } else { + imageView.setImageResource(leftMenuModel.select) + } + imageView.setOnClickListener { + for (i in list.indices) { + if(position==i){ + if(!list[i].isChecked){ + list[i].selectListener.onSelect(convertView) + } + } + list[i].isChecked = position == i + } + notifyDataSetChanged() + } + return imageView + } + + interface OnTabSelectListener { + /** + * Called when a view has been clicked. + * + * @param v The view that was clicked. + */ + fun onSelect(v: View?) + } + +} \ No newline at end of file diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/leftmenu/OverlayLeftViewUtils.kt b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/leftmenu/OverlayLeftViewUtils.kt new file mode 100644 index 0000000000..dd72043c95 --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/leftmenu/OverlayLeftViewUtils.kt @@ -0,0 +1,260 @@ +package com.mogo.och.taxi.passenger.ui.leftmenu + +import android.annotation.SuppressLint +import android.app.Activity +import android.content.Context +import android.graphics.PixelFormat +import android.graphics.Rect +import android.graphics.Region +import android.view.* +import android.widget.ListView +import androidx.constraintlayout.widget.ConstraintLayout +import com.mogo.eagle.core.utilcode.util.OverlayViewUtils +import com.mogo.och.taxi.passenger.R +import com.mogo.och.taxi.passenger.ui.leftmenu.model.LeftMenuModel +import com.mogo.och.taxi.passenger.ui.video.TaxiPassengerMogoConsultView +import com.mogo.och.taxi.passenger.ui.video.TaxiPassengerMogoMoviesView +import com.mogo.och.taxi.passenger.utils.windowdispatch.OnComputeInternalInsetsListener +import com.mogo.och.taxi.passenger.utils.windowdispatch.ReflectionUtils +import io.reactivex.Observable +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable +import java.lang.ref.WeakReference +import java.util.concurrent.TimeUnit + +/** + * 遮罩层工具类 + * + * @author mogoauto + */ +@SuppressLint("StaticFieldLeak") +object OverlayLeftViewUtils { + private const val TAG = "OverlayViewUtils" + private var windowManager: WindowManager? = null + private var applicationContext: Context? = null + + @Volatile + private var isShowing = false + + + private var mInvocationHandler: OnComputeInternalInsetsListener? = null + private val mTouchRegion = Region() + private var params:WindowManager.LayoutParams?=null + + const val WIDTH = 810 + const val DEVIATION_WIDTH = -669 + + + private var overlayView: View?=null + + private var subscribe: Disposable?=null + + private var taxiPassengerMogoConsultView: WeakReference? = null + private var taxiPassengerMogoMoviesView: WeakReference? = null + + /** + * 添加覆盖View在Activity上面 + */ + @JvmOverloads + fun showOverlayView(context: Activity, ani: Int = -1) { + if (isShowing) { + return + } + if (applicationContext == null) { + applicationContext = context.applicationContext + } + if (windowManager == null) { + windowManager = context.windowManager + } + + overlayView = LayoutInflater.from(context) + .inflate(R.layout.taxi_p_window_float_interphone, null) as ConstraintLayout + overlayView?.let { view -> + // 设置View显示模式,沉浸式的侵入到状态栏,导航栏 + view.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY + or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + or View.SYSTEM_UI_FLAG_LAYOUT_STABLE + or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) + layoutParams(ani,view) + + // 如果正在展示中,并且lastOverlayView不为null,先做移除操作,保证覆盖在最上面的View只有一个,防止叠加导致无法移除 + dismissOverlayView() + + val vDragField = view.findViewById(R.id.v_drag_field) + vDragField.setOnTouchListener(ItemViewTouchListener(params!!, windowManager, ::close, + ::open)) + vDragField.setOnClickListener { + val start: Int = params!!.x + if (start > DEVIATION_WIDTH /2 && start < 10) { + close(view, windowManager) + } else if (start < DEVIATION_WIDTH /2 && start >= DEVIATION_WIDTH) { + open(view, windowManager) + } + } + + val lvSelectItem = view.findViewById(R.id.lv_select_item) + val integers = mutableListOf() + + val liveSelected = object :ListAdapter.OnTabSelectListener{ + override fun onSelect(v: View?) { + close(view, windowManager) + if(taxiPassengerMogoConsultView?.get() != null){ + OverlayViewUtils.dismissOverlayView(taxiPassengerMogoConsultView?.get()) + } + if(taxiPassengerMogoMoviesView?.get() != null){ + OverlayViewUtils.dismissOverlayView(taxiPassengerMogoMoviesView?.get()) + } + } + } + + val consultSelect = object :ListAdapter.OnTabSelectListener{ + override fun onSelect(v: View?) { + close(view, windowManager) + if(taxiPassengerMogoMoviesView?.get() != null){ + OverlayViewUtils.dismissOverlayView(taxiPassengerMogoMoviesView?.get()) + } + if(taxiPassengerMogoConsultView?.get() != null){ + OverlayViewUtils.showOverlayView(context,taxiPassengerMogoConsultView?.get()) + }else{ + taxiPassengerMogoConsultView = + WeakReference(TaxiPassengerMogoConsultView(context)) + OverlayViewUtils.showOverlayView(context,taxiPassengerMogoConsultView?.get()) + } + } + } + + val entertainmentSelect = object :ListAdapter.OnTabSelectListener{ + override fun onSelect(v: View?) { + close(view, windowManager) + if(taxiPassengerMogoConsultView?.get() != null){ + OverlayViewUtils.dismissOverlayView(taxiPassengerMogoConsultView?.get()) + } + if(taxiPassengerMogoMoviesView?.get() != null){ + OverlayViewUtils.showOverlayView(context,taxiPassengerMogoMoviesView?.get()) + }else{ + taxiPassengerMogoMoviesView = + WeakReference(TaxiPassengerMogoMoviesView(context)) + OverlayViewUtils.showOverlayView(context,taxiPassengerMogoMoviesView?.get()) + } + } + } + + integers.add(LeftMenuModel(R.drawable.taxi_p_mogo_live_select,R.drawable.taxi_p_mogo_live_selected,true,liveSelected)) + integers.add(LeftMenuModel(R.drawable.taxi_p_mogo_consult_select,R.drawable.taxi_p_mogo_consult_selected,false,consultSelect)) + integers.add(LeftMenuModel(R.drawable.taxi_p_mogo_entertainment_select,R.drawable.taxi_p_mogo_entertainment_selected,false,entertainmentSelect)) + lvSelectItem.adapter = ListAdapter(context, integers) + + view.viewTreeObserver + .addOnGlobalLayoutListener(object :ViewTreeObserver.OnGlobalLayoutListener{ + override fun onGlobalLayout() { + mTouchRegion.setEmpty() + mTouchRegion.op(getViewBounds(vDragField), Region.Op.UNION) + mTouchRegion.op(getViewBounds(lvSelectItem), Region.Op.UNION) + mInvocationHandler?.touchRegion = mTouchRegion + view.viewTreeObserver.removeOnGlobalLayoutListener(this) + } + }) + try { + mInvocationHandler = + OnComputeInternalInsetsListener() + ReflectionUtils.removeOnComputeInternalInsetsListener(view.viewTreeObserver) + ReflectionUtils.addOnComputeInternalInsetsListener( + view.viewTreeObserver, + mInvocationHandler?.getListener() + ) + mInvocationHandler?.touchRegion = mTouchRegion + windowManager!!.addView(overlayView, params) + isShowing = true + } catch (e: Exception) { + e.printStackTrace() + } + } + } + + /** + * 打开状态栏 + */ + private fun open(overlayView: View,windowManager: WindowManager?) { + params?.x = 0 + windowManager?.updateViewLayout(overlayView, params) + closeByTime(overlayView, windowManager) + } + + private fun closeByTime( + overlayView: View, + windowManager: WindowManager? + ) { + subscribe?.let { + if (!it.isDisposed) { + it.dispose() + } + } + subscribe = Observable.timer(3000, TimeUnit.MILLISECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { + if (params?.x == 0) { + close(overlayView, windowManager) + } + } + } + + /** + * 关闭状态栏 + */ + fun close(overlayView: View,windowManager: WindowManager?) { + params?.x = DEVIATION_WIDTH + windowManager?.updateViewLayout(overlayView, params) + } + + private fun layoutParams(ani: Int,view :View) { + if(params ==null) { + params = WindowManager.LayoutParams() + } + params?.let { + it.width = WIDTH + it.height = WindowManager.LayoutParams.MATCH_PARENT + it.alpha = 1.0f + it.gravity = Gravity.START or Gravity.TOP + it.x = 0 + it.y = 0 + it.format = PixelFormat.RGBA_8888 + // 设置窗口类型为应用子窗口,和PopupWindow同类型 + it.type = WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL + // 没有边界限制,允许窗口扩展到屏幕外 + it.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or + WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS or + WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL + if (ani != -1) { + it.windowAnimations = ani + } + closeByTime(view, windowManager) + } + } + + /** + * 移除覆盖View在Activity上面 + */ + fun dismissOverlayView() { + if (!isShowing) { + return + } + subscribe?.let { + if (!it.isDisposed) { + it.dispose() + } + } + try { + if (windowManager != null && overlayView != null) { + windowManager!!.removeView(overlayView) + } + isShowing = false + } catch (e: Exception) { + e.printStackTrace() + } + } + + private fun getViewBounds(view: View): Rect { + return Rect(view.left, view.top, view.right, view.bottom) + } +} \ No newline at end of file diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/leftmenu/model/LeftMenuModel.kt b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/leftmenu/model/LeftMenuModel.kt new file mode 100644 index 0000000000..6907442c5d --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/leftmenu/model/LeftMenuModel.kt @@ -0,0 +1,10 @@ +package com.mogo.och.taxi.passenger.ui.leftmenu.model + +import com.mogo.och.taxi.passenger.ui.leftmenu.ListAdapter + +data class LeftMenuModel( + val select: Int, + val selected: Int, + var isChecked: Boolean, + val selectListener: ListAdapter.OnTabSelectListener +) \ No newline at end of file diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/video/FullVideoUtils.kt b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/video/FullVideoUtils.kt new file mode 100644 index 0000000000..6ad9edd4ad --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/video/FullVideoUtils.kt @@ -0,0 +1,88 @@ +package com.mogo.och.taxi.passenger.ui.video + +import android.annotation.SuppressLint +import android.app.Activity +import android.content.Context +import android.view.View +import android.view.WindowManager +import com.mogo.och.taxi.passenger.ui.video.FullVideoUtils +import java.lang.Exception + +/** + * 遮罩层工具类 + * + * @author mogoauto + */ +@SuppressLint("StaticFieldLeak") +object FullVideoUtils { + private const val TAG = "OverlayViewUtils" + private var windowManager: WindowManager? = null + private var applicationContext: Context? = null + + @Volatile + private var isShowing = false + + /** + * 记录上一次的View + */ + private var lastOverlayView: View? = null + + /** + * 添加覆盖View在Activity上面 + */ + @JvmOverloads + fun showOverlayView(context: Activity, overlayView: View, ani: Int = -1) { + if (applicationContext == null) { + applicationContext = context.applicationContext + } + if (windowManager == null) { + windowManager = context.windowManager + } + + // 设置View显示模式,沉浸式的侵入到状态栏,导航栏 + overlayView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN + or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY + or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + or View.SYSTEM_UI_FLAG_LAYOUT_STABLE + or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) + val params = WindowManager.LayoutParams() + params.width = WindowManager.LayoutParams.MATCH_PARENT + params.height = WindowManager.LayoutParams.MATCH_PARENT + params.alpha = 1.0f + // 设置窗口类型为应用子窗口,和PopupWindow同类型 + params.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL + // 没有边界限制,允许窗口扩展到屏幕外 + params.flags = WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS + if (ani != -1) { + params.windowAnimations = ani + } + try { + // 后门逻辑,长时间触摸消失 + lastOverlayView = overlayView + windowManager!!.addView(overlayView, params) + isShowing = true + } catch (e: Exception) { + e.printStackTrace() + } + } + + /** + * 移除覆盖View在Activity上面 + */ + fun dismissOverlayView() { + if (!isShowing) { + return + } + try { + if (windowManager != null) { + windowManager!!.removeView(lastOverlayView) + } + if (lastOverlayView != null) { + lastOverlayView = null + } + isShowing = false + } catch (e: Exception) { + e.printStackTrace() + } + } +} \ No newline at end of file diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/video/RecyclerItemVideoHolder.java b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/video/RecyclerItemVideoHolder.java new file mode 100644 index 0000000000..8eefd40f44 --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/video/RecyclerItemVideoHolder.java @@ -0,0 +1,31 @@ +package com.mogo.och.taxi.passenger.ui.video; + +import android.content.Context; +import android.graphics.Color; +import android.view.View; +import android.widget.ImageView; + +import androidx.recyclerview.widget.RecyclerView; + +import com.mogo.och.taxi.passenger.R; +import com.mogo.och.taxi.passenger.widget.ConsultVideoPlayer; +import com.shuyu.gsyvideoplayer.builder.GSYVideoOptionBuilder; + +public class RecyclerItemVideoHolder extends RecyclerView.ViewHolder { + + public final static String TAG = "RecyclerView2List"; + + protected Context context; + + public ConsultVideoPlayer gsyVideoPlayer; + + GSYVideoOptionBuilder gsyVideoOptionBuilder; + + public RecyclerItemVideoHolder(Context context, View v) { + super(v); + this.context = context; + gsyVideoPlayer = v.findViewById(R.id.video_item_player); + gsyVideoOptionBuilder = new GSYVideoOptionBuilder(); + } + +} diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/video/RecyclerVideoAdapter.java b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/video/RecyclerVideoAdapter.java new file mode 100644 index 0000000000..a7c868aa85 --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/video/RecyclerVideoAdapter.java @@ -0,0 +1,98 @@ +package com.mogo.och.taxi.passenger.ui.video; + +import android.content.Context; +import android.graphics.Color; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.request.RequestOptions; +import com.mogo.eagle.core.utilcode.util.ToastUtils; +import com.mogo.och.taxi.passenger.R; +import com.mogo.och.taxi.passenger.bean.TaxiPassengerVideoPlay; + +import java.util.List; + +public class RecyclerVideoAdapter extends RecyclerView.Adapter { + private final static String TAG = "RecyclerBaseAdapter"; + + private List itemDataList = null; + private Context context = null; + private OnThumbImageClilckListener onThumbImageClilckListener; + + public OnThumbImageClilckListener getOnThumbImageClilckListener() { + return onThumbImageClilckListener; + } + + public void setOnThumbImageClilckListener(OnThumbImageClilckListener onThumbImageClilckListener) { + this.onThumbImageClilckListener = onThumbImageClilckListener; + } + + public RecyclerVideoAdapter(Context context, List itemDataList) { + this.itemDataList = itemDataList; + this.context = context; + } + + public TaxiPassengerVideoPlay getItemByPosition(int position){ + if(itemDataList!=null){ + return itemDataList.get(position); + } + return null; + } + + @NonNull + @Override + public RecyclerItemVideoHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View v = LayoutInflater.from(context).inflate(R.layout.list_video_item_normal, parent, false); + RecyclerItemVideoHolder recyclerItemVideoHolder = new RecyclerItemVideoHolder(context, v); + recyclerItemVideoHolder.setIsRecyclable(false); + return recyclerItemVideoHolder; + } + + @Override + public void onBindViewHolder(@NonNull final RecyclerItemVideoHolder holder, int position) { + final TaxiPassengerVideoPlay taxiPassengerVideoPlay = itemDataList.get(position); + + holder.gsyVideoOptionBuilder + .setEnlargeImageRes(R.drawable.taxi_p_change_full) + .setUrl(taxiPassengerVideoPlay.getUrl()) + .setCacheWithPlay(true) + .setPlayTag(taxiPassengerVideoPlay.getImageUrl()+position) + .setThumbImageView(holder.gsyVideoPlayer.coverImage) + .setThumbPlay(false) + .build(holder.gsyVideoPlayer); + holder.gsyVideoPlayer.setTitle(taxiPassengerVideoPlay.getTitle()); + Glide.with(context) + .load(taxiPassengerVideoPlay.getImageUrl()) + .apply(new RequestOptions().placeholder(R.drawable.taxi_p_video_holder).centerCrop()) + .into(holder.gsyVideoPlayer.coverImage); + holder.gsyVideoPlayer.getThumbImageView().setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if(onThumbImageClilckListener!=null){ + onThumbImageClilckListener.onDxChanged(holder.getAbsoluteAdapterPosition()); + } + } + }); + } + + @Override + public int getItemCount() { + return itemDataList.size(); + } + + + @Override + public int getItemViewType(int position) { + return 1; + } + + + public interface OnThumbImageClilckListener { + void onDxChanged(int targetPosition); + } +} diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/video/TaxiPassengerMogoConsultView.kt b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/video/TaxiPassengerMogoConsultView.kt new file mode 100644 index 0000000000..c8f4bb7eba --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/video/TaxiPassengerMogoConsultView.kt @@ -0,0 +1,254 @@ +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.mogo.logger.CallerLogger.d +import com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant +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() + 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 = carouselLayoutManager.centerItemPosition + val player = carouselLayoutManager.findViewByPosition(centerItemPosition) + indicatorView.onPageSelected(centerItemPosition) + if(player is ConsultVideoPlayer){ + if(prePlayerPosition!=centerItemPosition) { + if(player.currentState==GSYVideoView.CURRENT_STATE_PAUSE){ + player.onVideoReset() + //player.startPlayLogic() + }else{ + //player.startPlayLogic() + } + val taxiPassengerVideoPlay = arrayListOf[centerItemPosition] + setBackageAndPlayNext(taxiPassengerVideoPlay, player, centerItemPosition) + }else{ + player.onVideoResume(false) + } + } + prePlayerPosition = centerItemPosition + } + + override fun pageStop() { + val centerItemPosition: Int = carouselLayoutManager.getCenterItemPosition() + val player = carouselLayoutManager.findViewByPosition(centerItemPosition) + 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 + }else { + currentIndex -= 1 + } + } + indicatorView.onPageScrolled(currentIndex, fl, 0) + } + recyclerVideoAdapter.setOnThumbImageClilckListener { + val centerItemPosition: Int = carouselLayoutManager.centerItemPosition + val player = carouselLayoutManager.findViewByPosition(centerItemPosition) + 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() { + override fun onResourceReady( + resource: Bitmap, + transition: Transition? + ) { + 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 onWindowFocusChanged(hasWindowFocus: Boolean) { + super.onWindowFocusChanged(hasWindowFocus) + val carouselLayoutManager = rvVideoPlaylist.layoutManager as CarouselLayoutManager + val centerItemPosition: Int = carouselLayoutManager.centerItemPosition + val player = carouselLayoutManager.findViewByPosition(centerItemPosition) + 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() + } + } + } + + } + + } + + + override fun onDetachedFromWindow() { + super.onDetachedFromWindow() + val carouselLayoutManager = rvVideoPlaylist.layoutManager as CarouselLayoutManager + val centerItemPosition: Int = carouselLayoutManager.centerItemPosition + val player = carouselLayoutManager.findViewByPosition(centerItemPosition) + player?.let { + if(player is ConsultVideoPlayer){ + player.release() + } + } + } + + companion object { + const val TAG = "TaxiPassengerMogoConsultView" + } + + init { + try { + initView(context) + } catch (e: Exception) { + e.printStackTrace() + } + } + +} \ No newline at end of file diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/video/TaxiPassengerMogoMoviesView.kt b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/video/TaxiPassengerMogoMoviesView.kt new file mode 100644 index 0000000000..ae3407a6e2 --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/video/TaxiPassengerMogoMoviesView.kt @@ -0,0 +1,237 @@ +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.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.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() + 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 = carouselLayoutManager.centerItemPosition + val player = carouselLayoutManager.findViewByPosition(centerItemPosition) + indicatorView.onPageSelected(centerItemPosition) + if(player is ConsultVideoPlayer){ + if(prePlayerPosition!=centerItemPosition) { + if(player.currentState==GSYVideoView.CURRENT_STATE_PAUSE){ + player.onVideoReset() + player.startPlayLogic() + }else{ + player.startPlayLogic() + } + val taxiPassengerVideoPlay = arrayListOf[centerItemPosition] + setBackageAndPlayNext(taxiPassengerVideoPlay, player, centerItemPosition) + }else{ + player.onVideoResume(false) + } + } + prePlayerPosition = centerItemPosition + } + + override fun pageStop() { + val centerItemPosition: Int = carouselLayoutManager.getCenterItemPosition() + val player = carouselLayoutManager.findViewByPosition(centerItemPosition) + 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 + }else { + currentIndex -= 1 + } + } + indicatorView.onPageScrolled(currentIndex, fl, 0) + } + 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() { + override fun onResourceReady( + resource: Bitmap, + transition: Transition? + ) { + 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 onWindowFocusChanged(hasWindowFocus: Boolean) { + super.onWindowFocusChanged(hasWindowFocus) + val carouselLayoutManager = rvVideoPlaylist.layoutManager as CarouselLayoutManager + val centerItemPosition: Int = carouselLayoutManager.centerItemPosition + val player = carouselLayoutManager.findViewByPosition(centerItemPosition) + 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() + } + } + } + + } + + } + + + override fun onDetachedFromWindow() { + super.onDetachedFromWindow() + val carouselLayoutManager = rvVideoPlaylist.layoutManager as CarouselLayoutManager + val centerItemPosition: Int = carouselLayoutManager.centerItemPosition + val player = carouselLayoutManager.findViewByPosition(centerItemPosition) + player?.let { + if(player is ConsultVideoPlayer){ + player.release() + } + } + } + + companion object { + const val TAG = "TaxiPassengerMogoConsultView" + } + + init { + try { + initView(context) + } catch (e: Exception) { + e.printStackTrace() + } + } + +} \ No newline at end of file diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/video/layoutmanage/CarouselLayoutManager.java b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/video/layoutmanage/CarouselLayoutManager.java new file mode 100644 index 0000000000..bbd7537f0b --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/video/layoutmanage/CarouselLayoutManager.java @@ -0,0 +1,964 @@ +package com.mogo.och.taxi.passenger.ui.video.layoutmanage; + +import android.graphics.PointF; +import android.os.Handler; +import android.os.Looper; +import android.os.Parcel; +import android.os.Parcelable; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.CallSuper; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.view.ViewCompat; +import androidx.recyclerview.widget.LinearSmoothScroller; +import androidx.recyclerview.widget.OrientationHelper; +import androidx.recyclerview.widget.RecyclerView; + +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * An implementation of {@link RecyclerView.LayoutManager} that layout items like carousel. + * Generally there is one center item and bellow this item there are maximum {@link CarouselLayoutManager#getMaxVisibleItems()} items on each side of the center + * item. By default {@link CarouselLayoutManager#getMaxVisibleItems()} is {@link CarouselLayoutManager#MAX_VISIBLE_ITEMS}.
+ *
+ * This LayoutManager supports only fixedSized adapter items.
+ *
+ * This LayoutManager supports {@link CarouselLayoutManager#HORIZONTAL} and {@link CarouselLayoutManager#VERTICAL} orientations.
+ *
+ * This LayoutManager supports circle layout. By default it if disabled. We don't recommend to use circle layout with adapter items count less then 3.
+ *
+ * Please be sure that layout_width of adapter item is a constant value and not {@link ViewGroup.LayoutParams#MATCH_PARENT} + * for {@link #HORIZONTAL} orientation. + * So like layout_height is not {@link ViewGroup.LayoutParams#MATCH_PARENT} for {@link CarouselLayoutManager#VERTICAL}
+ *
+ */ +public class CarouselLayoutManager extends RecyclerView.LayoutManager implements RecyclerView.SmoothScroller.ScrollVectorProvider { + + public static final int HORIZONTAL = OrientationHelper.HORIZONTAL; + public static final int VERTICAL = OrientationHelper.VERTICAL; + /** + * 固定值一直不变 + */ + public static final int INVALID_POSITION = -1; + public static final int MAX_VISIBLE_ITEMS = 3; + + private static final boolean CIRCLE_LAYOUT = false; + + private boolean mDecoratedChildSizeInvalid; + private Integer mDecoratedChildWidth; + private Integer mDecoratedChildHeight; + + private final int mOrientation; + private boolean mCircleLayout; + + private int mPendingScrollPosition; + + private final LayoutHelper mLayoutHelper = new LayoutHelper(MAX_VISIBLE_ITEMS); + + private PostLayoutListener mViewPostLayout; + + private final List mOnCenterItemSelectionListeners = new ArrayList<>(); + private final List onDargAutoDiffListeners = new ArrayList<>(); + private int mCenterItemPosition = INVALID_POSITION; + private int mItemsCount; + + @Nullable + private CarouselSavedState mPendingCarouselSavedState; + + /** + * @param orientation should be {@link #VERTICAL} or {@link #HORIZONTAL} + */ + @SuppressWarnings("unused") + public CarouselLayoutManager(final int orientation) { + this(orientation, CIRCLE_LAYOUT); + } + + /** + * If circleLayout is true then all items will be in cycle. Scroll will be infinite on both sides. + * + * @param orientation should be {@link #VERTICAL} or {@link #HORIZONTAL} + * @param circleLayout true for enabling circleLayout + */ + @SuppressWarnings("unused") + public CarouselLayoutManager(final int orientation, final boolean circleLayout) { + if (HORIZONTAL != orientation && VERTICAL != orientation) { + throw new IllegalArgumentException("orientation should be HORIZONTAL or VERTICAL"); + } + mOrientation = orientation; + mCircleLayout = circleLayout; + mPendingScrollPosition = INVALID_POSITION; + } + + /** + * Change circle layout type + */ + @SuppressWarnings("unused") + public void setCircleLayout(final boolean circleLayout) { + if (mCircleLayout != circleLayout) { + mCircleLayout = circleLayout; + requestLayout(); + } + } + + /** + * Setup {@link PostLayoutListener} for this LayoutManager. + * Its methods will be called for each visible view item after general LayoutManager layout finishes.
+ *
+ * Generally this method should be used for scaling and translating view item for better (different) view presentation of layouting. + * + * @param postLayoutListener listener for item layout changes. Can be null. + */ + @SuppressWarnings("unused") + public void setPostLayoutListener(@Nullable final PostLayoutListener postLayoutListener) { + mViewPostLayout = postLayoutListener; + requestLayout(); + } + + /** + * Setup maximum visible (layout) items on each side of the center item. + * Basically during scrolling there can be more visible items (+1 item on each side), but in idle state this is the only reached maximum. + * + * @param maxVisibleItems should be great then 0, if bot an {@link IllegalAccessException} will be thrown + */ + @CallSuper + @SuppressWarnings("unused") + public void setMaxVisibleItems(final int maxVisibleItems) { + if (0 > maxVisibleItems) { + throw new IllegalArgumentException("maxVisibleItems can't be less then 0"); + } + mLayoutHelper.mMaxVisibleItems = maxVisibleItems; + requestLayout(); + } + + /** + * @return current setup for maximum visible items. + * @see #setMaxVisibleItems(int) + */ + @SuppressWarnings("unused") + public int getMaxVisibleItems() { + return mLayoutHelper.mMaxVisibleItems; + } + + @Override + public RecyclerView.LayoutParams generateDefaultLayoutParams() { + return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); + } + + /** + * @return current layout orientation + * @see #VERTICAL + * @see #HORIZONTAL + */ + public int getOrientation() { + return mOrientation; + } + + @Override + public boolean canScrollHorizontally() { + return 0 != getChildCount() && HORIZONTAL == mOrientation; + } + + @Override + public boolean canScrollVertically() { + return 0 != getChildCount() && VERTICAL == mOrientation; + } + + /** + * @return current layout center item + */ + public int getCenterItemPosition() { + return mCenterItemPosition; + } + + /** + * @param onCenterItemSelectionListener listener that will trigger when ItemSelectionChanges. can't be null + */ + public void addOnItemSelectionListener(@NonNull final OnCenterItemSelectionListener onCenterItemSelectionListener) { + mOnCenterItemSelectionListeners.add(onCenterItemSelectionListener); + } + + /** + * @param onCenterItemSelectionListener listener that was previously added by {@link #addOnItemSelectionListener(OnCenterItemSelectionListener)} + */ + public void removeOnItemSelectionListener(@NonNull final OnCenterItemSelectionListener onCenterItemSelectionListener) { + mOnCenterItemSelectionListeners.remove(onCenterItemSelectionListener); + } + + public void addOnDargAutoDiffListener(@NonNull final OnDargAutoDiffListener onDargAutoDiffListener) { + onDargAutoDiffListeners.add(onDargAutoDiffListener); + } + + public void removeOnDargAutoDiffListener(@NonNull final OnDargAutoDiffListener onDargAutoDiffListener) { + onDargAutoDiffListeners.remove(onDargAutoDiffListener); + } + + @SuppressWarnings("RefusedBequest") + @Override + public void scrollToPosition(final int position) { + if (0 > position) { + throw new IllegalArgumentException("position can't be less then 0. position is : " + position); + } + mPendingScrollPosition = position; + requestLayout(); + } + + @SuppressWarnings("RefusedBequest") + @Override + public void smoothScrollToPosition(@NonNull final RecyclerView recyclerView, @NonNull final RecyclerView.State state, final int position) { + final LinearSmoothScroller linearSmoothScroller = new LinearSmoothScroller(recyclerView.getContext()) { + @Override + public int calculateDyToMakeVisible(final View view, final int snapPreference) { + if (!canScrollVertically()) { + return 0; + } + + return getOffsetForCurrentView(view); + } + + @Override + public int calculateDxToMakeVisible(final View view, final int snapPreference) { + if (!canScrollHorizontally()) { + return 0; + } + return getOffsetForCurrentView(view); + } + }; + linearSmoothScroller.setTargetPosition(position); + startSmoothScroll(linearSmoothScroller); + } + + @Override + @Nullable + public PointF computeScrollVectorForPosition(final int targetPosition) { + if (0 == getChildCount()) { + return null; + } + final float directionDistance = getScrollDirection(targetPosition); + //noinspection NumericCastThatLosesPrecision + final int direction = (int) -Math.signum(directionDistance); + + if (HORIZONTAL == mOrientation) { + return new PointF(direction, 0); + } else { + return new PointF(0, direction); + } + } + + private float getScrollDirection(final int targetPosition) { + final float currentScrollPosition = makeScrollPositionInRange0ToCount(getCurrentScrollPosition(), mItemsCount); + + if (mCircleLayout) { + final float t1 = currentScrollPosition - targetPosition; + final float t2 = Math.abs(t1) - mItemsCount; + if (Math.abs(t1) > Math.abs(t2)) { + return Math.signum(t1) * t2; + } else { + return t1; + } + } else { + return currentScrollPosition - targetPosition; + } + } + + @Override + public int scrollVerticallyBy(final int dy, @NonNull final RecyclerView.Recycler recycler, @NonNull final RecyclerView.State state) { + if (HORIZONTAL == mOrientation) { + return 0; + } + return scrollBy(dy, recycler, state); + } + + @Override + public int scrollHorizontallyBy(final int dx, final RecyclerView.Recycler recycler, final RecyclerView.State state) { + if (VERTICAL == mOrientation) { + return 0; + } + return scrollBy(dx, recycler, state); + } + + /** + * This method is called from {@link #scrollHorizontallyBy(int, RecyclerView.Recycler, RecyclerView.State)} and + * {@link #scrollVerticallyBy(int, RecyclerView.Recycler, RecyclerView.State)} to calculate needed scroll that is allowed.
+ *
+ * This method may do relayout work. + * + * @param diff 要滚动的距离 + * @param recycler 回收期 + * @param state Transient state of RecyclerView + * @return distance that we actually scrolled by + */ + @CallSuper + protected int scrollBy(final int diff, @NonNull final RecyclerView.Recycler recycler, @NonNull final RecyclerView.State state) { + if (null == mDecoratedChildWidth || null == mDecoratedChildHeight) { + return 0; + } + if (0 == getChildCount() || 0 == diff) { + return 0; + } + final int resultScroll; + if (mCircleLayout) { + resultScroll = diff; + + mLayoutHelper.mScrollOffset += resultScroll; + + final int maxOffset = getScrollItemSize() * mItemsCount; + while (0 > mLayoutHelper.mScrollOffset) { + mLayoutHelper.mScrollOffset += maxOffset; + } + while (mLayoutHelper.mScrollOffset > maxOffset) { + mLayoutHelper.mScrollOffset -= maxOffset; + } + + mLayoutHelper.mScrollOffset -= resultScroll; + } else { + final int maxOffset = getMaxScrollOffset(); + + if (0 > mLayoutHelper.mScrollOffset + diff) { + resultScroll = -mLayoutHelper.mScrollOffset; //to make it 0 + } else if (mLayoutHelper.mScrollOffset + diff > maxOffset) { + resultScroll = maxOffset - mLayoutHelper.mScrollOffset; //to make it maxOffset + } else { + resultScroll = diff; + } + } + if (0 != resultScroll) { + mLayoutHelper.mScrollOffset += resultScroll; + fillData(recycler, state); + } + return resultScroll; + } + + @Override + public void onMeasure(@NonNull final RecyclerView.Recycler recycler, @NonNull final RecyclerView.State state, final int widthSpec, final int heightSpec) { + mDecoratedChildSizeInvalid = true; + + super.onMeasure(recycler, state, widthSpec, heightSpec); + } + + @SuppressWarnings("rawtypes") + @Override + public void onAdapterChanged(final RecyclerView.Adapter oldAdapter, final RecyclerView.Adapter newAdapter) { + super.onAdapterChanged(oldAdapter, newAdapter); + + removeAllViews(); + } + + + @SuppressWarnings("RefusedBequest") + @Override + @CallSuper + public void onLayoutChildren(@NonNull final RecyclerView.Recycler recycler, @NonNull final RecyclerView.State state) { + if (0 == state.getItemCount()) { + removeAndRecycleAllViews(recycler); + selectItemCenterPosition(INVALID_POSITION); + return; + } + + detachAndScrapAttachedViews(recycler); + + if (null == mDecoratedChildWidth || mDecoratedChildSizeInvalid) { + final List scrapList = recycler.getScrapList(); + + final boolean shouldRecycle; + final View view; + if (scrapList.isEmpty()) { + shouldRecycle = true; + final int itemsCount = state.getItemCount(); + view = recycler.getViewForPosition( + mPendingScrollPosition == INVALID_POSITION ? + 0 : + Math.max(0, Math.min(itemsCount - 1, mPendingScrollPosition)) + ); + addView(view); + } else { + shouldRecycle = false; + view = scrapList.get(0).itemView; + } + measureChildWithMargins(view, 0, 0); + + final int decoratedChildWidth = getDecoratedMeasuredWidth(view); + final int decoratedChildHeight = getDecoratedMeasuredHeight(view); + if (shouldRecycle) { + detachAndScrapView(view, recycler); + } + + if (null != mDecoratedChildWidth && (mDecoratedChildWidth != decoratedChildWidth || mDecoratedChildHeight != decoratedChildHeight)) { + if (INVALID_POSITION == mPendingScrollPosition && null == mPendingCarouselSavedState) { + mPendingScrollPosition = mCenterItemPosition; + } + } + + mDecoratedChildWidth = decoratedChildWidth; + mDecoratedChildHeight = decoratedChildHeight; + mDecoratedChildSizeInvalid = false; + } + + if (INVALID_POSITION != mPendingScrollPosition) { + final int itemsCount = state.getItemCount(); + mPendingScrollPosition = 0 == itemsCount ? INVALID_POSITION : Math.max(0, Math.min(itemsCount - 1, mPendingScrollPosition)); + } + if (INVALID_POSITION != mPendingScrollPosition) { + mLayoutHelper.mScrollOffset = calculateScrollForSelectingPosition(mPendingScrollPosition, state); + mPendingScrollPosition = INVALID_POSITION; + mPendingCarouselSavedState = null; + } else if (null != mPendingCarouselSavedState) { + mLayoutHelper.mScrollOffset = calculateScrollForSelectingPosition(mPendingCarouselSavedState.mCenterItemPosition, state); + mPendingCarouselSavedState = null; + } else if (state.didStructureChange() && INVALID_POSITION != mCenterItemPosition) { + mLayoutHelper.mScrollOffset = calculateScrollForSelectingPosition(mCenterItemPosition, state); + } + + fillData(recycler, state); + } + + private int calculateScrollForSelectingPosition(final int itemPosition, final RecyclerView.State state) { + if (itemPosition == INVALID_POSITION) { + return 0; + } + + final int fixedItemPosition = itemPosition < state.getItemCount() ? itemPosition : state.getItemCount() - 1; + return fixedItemPosition * (VERTICAL == mOrientation ? mDecoratedChildHeight : mDecoratedChildWidth); + } + + private void fillData(@NonNull final RecyclerView.Recycler recycler, @NonNull final RecyclerView.State state) { + final float currentScrollPosition = getCurrentScrollPosition(); + + generateLayoutOrder(currentScrollPosition, state); + detachAndScrapAttachedViews(recycler); + recyclerOldViews(recycler); + + final int width = getWidthNoPadding(); + final int height = getHeightNoPadding(); + if (VERTICAL == mOrientation) { + fillDataVertical(recycler, width, height); + } else { + fillDataHorizontal(recycler, width, height); + } + + recycler.clear(); + + detectOnItemSelectionChanged(currentScrollPosition, state); + } + + private void detectOnItemSelectionChanged(final float currentScrollPosition, final RecyclerView.State state) { + final float absCurrentScrollPosition = makeScrollPositionInRange0ToCount(currentScrollPosition, state.getItemCount()); + final int centerItem = Math.round(absCurrentScrollPosition); + if(currentScrollPosition-centerItem!=0){ + new Handler(Looper.getMainLooper()).post(() -> dragDxDiff(currentScrollPosition,mCenterItemPosition)); + } + if (mCenterItemPosition != centerItem) { + mCenterItemPosition = centerItem; + new Handler(Looper.getMainLooper()).post(new Runnable() { + @Override + public void run() { + selectItemCenterPosition(centerItem); + } + }); + } + } + + private void selectItemCenterPosition(final int centerItem) { + for (final OnCenterItemSelectionListener onCenterItemSelectionListener : mOnCenterItemSelectionListeners) { + onCenterItemSelectionListener.onCenterItemChanged(centerItem); + } + } + private void dragDxDiff(final float centerItem,final int currentPosition) { + for (final OnDargAutoDiffListener onDargAutoDiffListener : onDargAutoDiffListeners) { + onDargAutoDiffListener.onDxChanged(centerItem,currentPosition); + } + } + + private void fillDataVertical(final RecyclerView.Recycler recycler, final int width, final int height) { + final int start = (width - mDecoratedChildWidth) / 2; + final int end = start + mDecoratedChildWidth; + + final int centerViewTop = (height - mDecoratedChildHeight) / 2; + + for (int i = 0, count = mLayoutHelper.mLayoutOrder.length; i < count; ++i) { + final LayoutOrder layoutOrder = mLayoutHelper.mLayoutOrder[i]; + final int offset = getCardOffsetByPositionDiff(layoutOrder.mItemPositionDiff); + final int top = centerViewTop + offset; + final int bottom = top + mDecoratedChildHeight; + fillChildItem(start, top, end, bottom, layoutOrder, recycler, i); + } + } + + private void fillDataHorizontal(final RecyclerView.Recycler recycler, final int width, final int height) { + final int top = (height - mDecoratedChildHeight) / 2; + final int bottom = top + mDecoratedChildHeight; + + final int centerViewStart = (width - mDecoratedChildWidth) / 2; + + for (int i = 0, count = mLayoutHelper.mLayoutOrder.length; i < count; ++i) { + final LayoutOrder layoutOrder = mLayoutHelper.mLayoutOrder[i]; + final int offset = getCardOffsetByPositionDiff(layoutOrder.mItemPositionDiff); + final int start = centerViewStart + offset; + final int end = start + mDecoratedChildWidth; + fillChildItem(start, top, end, bottom, layoutOrder, recycler, i); + } + } + + + @SuppressWarnings("MethodWithTooManyParameters") + private void fillChildItem(final int start, final int top, final int end, final int bottom, @NonNull final LayoutOrder layoutOrder, @NonNull final RecyclerView.Recycler recycler, final int i) { + final View view = bindChild(layoutOrder.mItemAdapterPosition, recycler); + ViewCompat.setElevation(view, i); + ItemTransformation transformation = null; + if (null != mViewPostLayout) { + transformation = mViewPostLayout.transformChild(view, layoutOrder.mItemPositionDiff, mOrientation, layoutOrder.mItemAdapterPosition); + } + if (null == transformation) { + view.layout(start, top, end, bottom); + } else { + view.layout(Math.round(start + transformation.mTranslationX), Math.round(top + transformation.mTranslationY), + Math.round(end + transformation.mTranslationX), Math.round(bottom + transformation.mTranslationY)); + view.setScaleX(transformation.mScaleX); + view.setScaleY(transformation.mScaleY); + } + } + + /** + * 中心项目的当前滚动位置。如果是循环布局,则该值可以在任何范围内。如果不是,那么它在[0,-1] + */ + private float getCurrentScrollPosition() { + final int fullScrollSize = getMaxScrollOffset(); + if (0 == fullScrollSize) { + return 0; + } + return 1.0f * mLayoutHelper.mScrollOffset / getScrollItemSize(); + } + + /** + * 填充布局中所有项目的最大滚动值。通常,这仅适用于非循环布局。 + */ + private int getMaxScrollOffset() { + return getScrollItemSize() * (mItemsCount - 1); + } + + /** + * Because we can support old Android versions, we should layout our children in specific order to make our center view in the top of layout + * (this item should layout last). So this method will calculate layout order and fill up {@link #mLayoutHelper} object. + * This object will be filled by only needed to layout items. Non visible items will not be there. + * + * @param currentScrollPosition current scroll position this is a value that indicates position of center item + * (if this value is int, then center item is really in the center of the layout, else it is near state). + * Be aware that this value can be in any range is it is cycle layout + * @param state Transient state of RecyclerView + * @see #getCurrentScrollPosition() + */ + private void generateLayoutOrder(final float currentScrollPosition, @NonNull final RecyclerView.State state) { + mItemsCount = state.getItemCount(); + final float absCurrentScrollPosition = makeScrollPositionInRange0ToCount(currentScrollPosition, mItemsCount); + final int centerItem = Math.round(absCurrentScrollPosition); + + if (mCircleLayout && 1 < mItemsCount) { + final int layoutCount = Math.min(mLayoutHelper.mMaxVisibleItems * 2 + 1, mItemsCount); + + mLayoutHelper.initLayoutOrder(layoutCount); + + final int countLayoutHalf = layoutCount / 2; + // before center item + for (int i = 1; i <= countLayoutHalf; ++i) { + final int position = Math.round(absCurrentScrollPosition - i + mItemsCount) % mItemsCount; + mLayoutHelper.setLayoutOrder(countLayoutHalf - i, position, centerItem - absCurrentScrollPosition - i); + } + // after center item + for (int i = layoutCount - 1; i >= countLayoutHalf + 1; --i) { + final int position = Math.round(absCurrentScrollPosition - i + layoutCount) % mItemsCount; + mLayoutHelper.setLayoutOrder(i - 1, position, centerItem - absCurrentScrollPosition + layoutCount - i); + } + mLayoutHelper.setLayoutOrder(layoutCount - 1, centerItem, centerItem - absCurrentScrollPosition); + + } else { + final int firstVisible = Math.max(centerItem - mLayoutHelper.mMaxVisibleItems, 0); + final int lastVisible = Math.min(centerItem + mLayoutHelper.mMaxVisibleItems, mItemsCount - 1); + final int layoutCount = lastVisible - firstVisible + 1; + + mLayoutHelper.initLayoutOrder(layoutCount); + + for (int i = firstVisible; i <= lastVisible; ++i) { + if (i == centerItem) { + mLayoutHelper.setLayoutOrder(layoutCount - 1, i, i - absCurrentScrollPosition); + } else if (i < centerItem) { + mLayoutHelper.setLayoutOrder(i - firstVisible, i, i - absCurrentScrollPosition); + } else { + mLayoutHelper.setLayoutOrder(layoutCount - (i - centerItem) - 1, i, i - absCurrentScrollPosition); + } + } + } + } + + public int getWidthNoPadding() { + return getWidth() - getPaddingStart() - getPaddingEnd(); + } + + public int getHeightNoPadding() { + return getHeight() - getPaddingEnd() - getPaddingStart(); + } + + private View bindChild(final int position, @NonNull final RecyclerView.Recycler recycler) { + final View view = recycler.getViewForPosition(position); + + addView(view); + measureChildWithMargins(view, 0, 0); + + return view; + } + + private void recyclerOldViews(final RecyclerView.Recycler recycler) { + for (RecyclerView.ViewHolder viewHolder : new ArrayList<>(recycler.getScrapList())) { + int adapterPosition = viewHolder.getAdapterPosition(); + boolean found = false; + for (LayoutOrder layoutOrder : mLayoutHelper.mLayoutOrder) { + if (layoutOrder.mItemAdapterPosition == adapterPosition) { + found = true; + break; + } + } + if (!found) { + recycler.recycleView(viewHolder.itemView); + } + } + } + + /** + * Called during {@link #fillData(RecyclerView.Recycler, RecyclerView.State)} to calculate item offset from layout center line.
+ *
+ * Returns {@link #convertItemPositionDiffToSmoothPositionDiff(float)} * (size off area above center item when it is on the center).
+ * Sign is: plus if this item is bellow center line, minus if not
+ *
+ * ----- - area above it
+ * ||||| - center item
+ * ----- - area bellow it (it has the same size as are above center item)
+ * + * @param itemPositionDiff current item difference with layout center line. if this is 0, then this item center is in layout center line. + * if this is 1 then this item is bellow the layout center line in the full item size distance. + * @return offset in scroll px coordinates. + */ + protected int getCardOffsetByPositionDiff(final float itemPositionDiff) { + final double smoothPosition = convertItemPositionDiffToSmoothPositionDiff(itemPositionDiff); + + final int dimenDiff; + if (VERTICAL == mOrientation) { + dimenDiff = (getHeightNoPadding() - mDecoratedChildHeight) / 2; + } else { + dimenDiff = (getWidthNoPadding() - mDecoratedChildWidth) / 2; + } + //noinspection NumericCastThatLosesPrecision + return (int) Math.round(Math.signum(itemPositionDiff) * dimenDiff * smoothPosition); + } + + /** + * Called during {@link #getCardOffsetByPositionDiff(float)} for better item movement.
+ * Current implementation speed up items that are far from layout center line and slow down items that are close to this line. + * This code is full of maths. If you want to make items move in a different way, probably you should override this method.
+ * Please see code comments for better explanations. + * + * @param itemPositionDiff current item difference with layout center line. if this is 0, then this item center is in layout center line. + * if this is 1 then this item is bellow the layout center line in the full item size distance. + * @return smooth position offset. needed for scroll calculation and better user experience. + * @see #getCardOffsetByPositionDiff(float) + */ + @SuppressWarnings({"MagicNumber", "InstanceMethodNamingConvention"}) + protected double convertItemPositionDiffToSmoothPositionDiff(final float itemPositionDiff) { + // generally item moves the same way above center and bellow it. So we don't care about diff sign. + final float absIemPositionDiff = Math.abs(itemPositionDiff); + + // we detect if this item is close for center or not. We use (1 / maxVisibleItem) ^ (1/3) as close definer. + if (absIemPositionDiff > StrictMath.pow(1.0f / mLayoutHelper.mMaxVisibleItems, 1.0f / 3)) { + // this item is far from center line, so we should make it move like square root function + return StrictMath.pow(absIemPositionDiff / mLayoutHelper.mMaxVisibleItems, 1 / 2.0f); + } else { + // this item is close from center line. we should slow it down and don't make it speed up very quick. + // so square function in range of [0, (1/maxVisible)^(1/3)] is quite good in it; + return StrictMath.pow(absIemPositionDiff, 2.0f); + } + } + + /** + * @return full item size + */ + protected int getScrollItemSize() { + if (VERTICAL == mOrientation) { + return mDecoratedChildHeight; + } else { + return mDecoratedChildWidth; + } + } + + @Override + public Parcelable onSaveInstanceState() { + if (null != mPendingCarouselSavedState) { + return new CarouselSavedState(mPendingCarouselSavedState); + } + final CarouselSavedState savedState = new CarouselSavedState(super.onSaveInstanceState()); + savedState.mCenterItemPosition = mCenterItemPosition; + return savedState; + } + + @Override + public void onRestoreInstanceState(final Parcelable state) { + if (state instanceof CarouselSavedState) { + mPendingCarouselSavedState = (CarouselSavedState) state; + + super.onRestoreInstanceState(mPendingCarouselSavedState.mSuperState); + } else { + super.onRestoreInstanceState(state); + } + } + + /** + * @return 从中心到最近项目的滚动偏移量 + */ + protected int getOffsetCenterView() { + return Math.round(getCurrentScrollPosition()) * getScrollItemSize() - mLayoutHelper.mScrollOffset; + } + + protected int getOffsetForCurrentView(@NonNull final View view) { + final int targetPosition = getPosition(view); + final float directionDistance = getScrollDirection(targetPosition); + + return Math.round(directionDistance * getScrollItemSize()); + } + + /** + * 使滚动范围在[0,count]内的Helper方法。通常,只有循环布局才需要此方法。 + * + * @param currentScrollPosition 滚动位置范围 个位数 view的index 小数滚动的范围 + * @param count adapter 中的数量 + * @return 在[0,总数]范围内滚动位置良好 + */ + private static float makeScrollPositionInRange0ToCount(final float currentScrollPosition, final int count) { + float absCurrentScrollPosition = currentScrollPosition; + while (0 > absCurrentScrollPosition) { + absCurrentScrollPosition += count; + } + while (Math.round(absCurrentScrollPosition) >= count) { + absCurrentScrollPosition -= count; + } + return absCurrentScrollPosition; + } + + /** + * This interface methods will be called for each visible view item after general LayoutManager layout finishes.
+ *
+ * Generally this method should be used for scaling and translating view item for better (different) view presentation of layouting. + */ + @SuppressWarnings("InterfaceNeverImplemented") + public abstract static class PostLayoutListener { + + /** + * 子布局完成后调用。通常,您可以在这里进行任何平移和缩放工作。 + * + * @param child view that was layout + * @param itemPositionToCenterDiff view center line difference to layout center. if > 0 then this item is bellow layout center line, else if not + * @param orientation layoutManager orientation {@link #getLayoutDirection()} + * @param itemPositionInAdapter item position inside adapter for this layout pass + */ + public ItemTransformation transformChild( + @NonNull final View child, + final float itemPositionToCenterDiff, + final int orientation, + final int itemPositionInAdapter + ) { + return transformChild(child, itemPositionToCenterDiff, orientation); + } + + /** + * Called after child layout finished. Generally you can do any translation and scaling work here. + * + * @param child view that was layout + * @param itemPositionToCenterDiff view center line difference to layout center. if > 0 then this item is bellow layout center line, else if not + * @param orientation layoutManager orientation {@link #getLayoutDirection()} + */ + public ItemTransformation transformChild( + @NonNull final View child, + final float itemPositionToCenterDiff, + final int orientation + ) { + throw new IllegalStateException("at least one transformChild should be implemented"); + } + } + + public interface OnCenterItemSelectionListener { + + /** + * Listener that will be called on every change of center item. + * This listener will be triggered on every layout operation if item was changed. + * Do not do any expensive operations in this method since this will effect scroll experience. + * + * @param adapterPosition current layout center item + */ + void onCenterItemChanged(final int adapterPosition); + } + + public interface OnDargAutoDiffListener { + void onDxChanged(final float adapterPosition,final int currentPosition); + } + + /** + * Helper class that holds currently visible items. + * Generally this class fills this list.
+ *
+ * This class holds all scroll and maxVisible items state. + * + * @see #getMaxVisibleItems() + */ + private static class LayoutHelper { + + private int mMaxVisibleItems; + + private int mScrollOffset; + + private LayoutOrder[] mLayoutOrder; + + private final List> mReusedItems = new ArrayList<>(); + + LayoutHelper(final int maxVisibleItems) { + mMaxVisibleItems = maxVisibleItems; + } + + /** + * Called before any fill calls. Needed to recycle old items and init new array list. Generally this list is an array an it is reused. + * + * @param layoutCount items count that will be layout + */ + void initLayoutOrder(final int layoutCount) { + if (null == mLayoutOrder || mLayoutOrder.length != layoutCount) { + if (null != mLayoutOrder) { + recycleItems(mLayoutOrder); + } + mLayoutOrder = new LayoutOrder[layoutCount]; + fillLayoutOrder(); + } + } + + /** + * Called during layout generation process of filling this list. Should be called only after {@link #initLayoutOrder(int)} method call. + * + * @param arrayPosition position in layout order + * @param itemAdapterPosition adapter position of item for future data filling logic + * @param itemPositionDiff difference of current item scroll position and center item position. + * if this is a center item and it is in real center of layout, then this will be 0. + * if current layout is not in the center, then this value will never be int. + * if this item center is bellow layout center line then this value is greater then 0, + * else less then 0. + */ + void setLayoutOrder(final int arrayPosition, final int itemAdapterPosition, final float itemPositionDiff) { + final LayoutOrder item = mLayoutOrder[arrayPosition]; + item.mItemAdapterPosition = itemAdapterPosition; + item.mItemPositionDiff = itemPositionDiff; + } + + /** + * Checks is this screen Layout has this adapterPosition view in layout + * + * @param adapterPosition adapter position of item for future data filling logic + * @return true is adapterItem is in layout + */ + boolean hasAdapterPosition(final int adapterPosition) { + if (null != mLayoutOrder) { + for (final LayoutOrder layoutOrder : mLayoutOrder) { + if (layoutOrder.mItemAdapterPosition == adapterPosition) { + return true; + } + } + } + return false; + } + + @SuppressWarnings("VariableArgumentMethod") + private void recycleItems(@NonNull final LayoutOrder... layoutOrders) { + for (final LayoutOrder layoutOrder : layoutOrders) { + //noinspection ObjectAllocationInLoop + mReusedItems.add(new WeakReference<>(layoutOrder)); + } + } + + private void fillLayoutOrder() { + for (int i = 0, length = mLayoutOrder.length; i < length; ++i) { + if (null == mLayoutOrder[i]) { + mLayoutOrder[i] = createLayoutOrder(); + } + } + } + + private LayoutOrder createLayoutOrder() { + final Iterator> iterator = mReusedItems.iterator(); + while (iterator.hasNext()) { + final WeakReference layoutOrderWeakReference = iterator.next(); + final LayoutOrder layoutOrder = layoutOrderWeakReference.get(); + iterator.remove(); + if (null != layoutOrder) { + return layoutOrder; + } + } + return new LayoutOrder(); + } + } + + /** + * Class that holds item data. + * This class is filled during {@link #generateLayoutOrder(float, RecyclerView.State)} and used during {@link #fillData(RecyclerView.Recycler, RecyclerView.State)} + */ + private static class LayoutOrder { + + /** + * Item adapter position + */ + private int mItemAdapterPosition; + /** + * Item center difference to layout center. If center of item is bellow layout center, then this value is greater then 0, else it is less. + */ + private float mItemPositionDiff; + } + + protected static class CarouselSavedState implements Parcelable { + + private final Parcelable mSuperState; + private int mCenterItemPosition; + + protected CarouselSavedState(@Nullable final Parcelable superState) { + mSuperState = superState; + } + + private CarouselSavedState(@NonNull final Parcel in) { + mSuperState = in.readParcelable(Parcelable.class.getClassLoader()); + mCenterItemPosition = in.readInt(); + } + + protected CarouselSavedState(@NonNull final CarouselSavedState other) { + mSuperState = other.mSuperState; + mCenterItemPosition = other.mCenterItemPosition; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(final Parcel parcel, final int i) { + parcel.writeParcelable(mSuperState, i); + parcel.writeInt(mCenterItemPosition); + } + + public static final Creator CREATOR + = new Creator() { + @Override + public CarouselSavedState createFromParcel(final Parcel parcel) { + return new CarouselSavedState(parcel); + } + + @Override + public CarouselSavedState[] newArray(final int i) { + return new CarouselSavedState[i]; + } + }; + } +} \ No newline at end of file diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/video/layoutmanage/CarouselZoomPostLayoutListener.java b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/video/layoutmanage/CarouselZoomPostLayoutListener.java new file mode 100644 index 0000000000..925b89ffa3 --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/video/layoutmanage/CarouselZoomPostLayoutListener.java @@ -0,0 +1,47 @@ +package com.mogo.och.taxi.passenger.ui.video.layoutmanage; + +import android.view.View; + +import androidx.annotation.NonNull; + +import com.mogo.och.taxi.passenger.widget.ConsultVideoPlayer; + +/** + * Implementation of {@link CarouselLayoutManager.PostLayoutListener} that makes interesting scaling of items.
+ * We are trying to make items scaling quicker for closer items for center and slower for when they are far away.
+ * Tis implementation uses atan function for this purpose. + */ +public class CarouselZoomPostLayoutListener extends CarouselLayoutManager.PostLayoutListener { + + private final float mScaleMultiplier; + + public CarouselZoomPostLayoutListener() { + this(0.21f); + } + + public CarouselZoomPostLayoutListener(final float scaleMultiplier) { + mScaleMultiplier = scaleMultiplier; + } + + @Override + public ItemTransformation transformChild(@NonNull final View child, final float itemPositionToCenterDiff, final int orientation) { + float scale = 1.0f - mScaleMultiplier * Math.abs(itemPositionToCenterDiff); + final float translateY; + final float translateX; + if (CarouselLayoutManager.VERTICAL == orientation) { + final float translateYGeneral = child.getMeasuredHeight() * (1 - scale) / 2f; + translateY = Math.signum(itemPositionToCenterDiff) * translateYGeneral; + translateX = 0; + } else { + final float translateXGeneral = child.getMeasuredWidth() * (1 - scale) / 2f; + translateX = Math.signum(itemPositionToCenterDiff) * translateXGeneral; + translateY = 0; + } + if(Math.abs(itemPositionToCenterDiff)==1){ + if(child instanceof ConsultVideoPlayer){ + ((ConsultVideoPlayer)child).hideAllWidget(); + } + } + return new ItemTransformation(scale, scale, translateX, translateY); + } +} \ No newline at end of file diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/video/layoutmanage/CenterScrollListener.java b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/video/layoutmanage/CenterScrollListener.java new file mode 100644 index 0000000000..4b04e7b957 --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/video/layoutmanage/CenterScrollListener.java @@ -0,0 +1,52 @@ +package com.mogo.och.taxi.passenger.ui.video.layoutmanage; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +/** + * Class for centering items after scroll event.
+ * This class will listen to current scroll state and if item is not centered after scroll it will automatically scroll it to center. + */ +public class CenterScrollListener extends RecyclerView.OnScrollListener { + + private boolean mAutoSet = true; + + @Override + public void onScrollStateChanged(@NonNull final RecyclerView recyclerView, final int newState) { + super.onScrollStateChanged(recyclerView, newState); + final RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager(); + if (!(layoutManager instanceof CarouselLayoutManager)) { + mAutoSet = true; + return; + } + + final CarouselLayoutManager lm = (CarouselLayoutManager) layoutManager; + if (!mAutoSet) { + if (RecyclerView.SCROLL_STATE_IDLE == newState) { + final int scrollNeeded = lm.getOffsetCenterView(); + // 滚动到中心位置 + if (CarouselLayoutManager.HORIZONTAL == lm.getOrientation()) { + recyclerView.smoothScrollBy(scrollNeeded, 0); + } else { + recyclerView.smoothScrollBy(0, scrollNeeded); + } + pageSelect(recyclerView,newState); + mAutoSet = true; + } + } + if (RecyclerView.SCROLL_STATE_DRAGGING == newState || RecyclerView.SCROLL_STATE_SETTLING == newState) { + mAutoSet = false; + } + if(RecyclerView.SCROLL_STATE_DRAGGING == newState){ + pageStop(); + } + } + + protected void pageStop() { + + } + + protected void pageSelect(RecyclerView recyclerView, final int newState) { + + } +} \ No newline at end of file diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/video/layoutmanage/ItemTransformation.java b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/video/layoutmanage/ItemTransformation.java new file mode 100644 index 0000000000..14003ca28b --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/ui/video/layoutmanage/ItemTransformation.java @@ -0,0 +1,16 @@ +package com.mogo.och.taxi.passenger.ui.video.layoutmanage; + +public class ItemTransformation { + + final float mScaleX; + final float mScaleY; + final float mTranslationX; + final float mTranslationY; + + public ItemTransformation(final float scaleX, final float scaleY, final float translationX, final float translationY) { + mScaleX = scaleX; + mScaleY = scaleY; + mTranslationX = translationX; + mTranslationY = translationY; + } +} \ No newline at end of file diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/utils/blur/DiskLruCache.java b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/utils/blur/DiskLruCache.java new file mode 100644 index 0000000000..d20bd4e65e --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/utils/blur/DiskLruCache.java @@ -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 [a-z0-9_-]{1,64}. Values are byte sequences, + * accessible as streams or files. Each value must be between {@code 0} and + * {@code Integer.MAX_VALUE} bytes in length. + * + *

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. + * + *

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. + * + *

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. + *

    + *
  • When an entry is being created it is necessary to + * supply a full set of values; the empty value should be used as a + * placeholder if necessary. + *
  • When an entry is being edited, it is not necessary + * to supply data for every value; values default to their previous + * value. + *
+ * 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. + * + *

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. + * + *

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 lruEntries = + new LinkedHashMap(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()); + private final Callable cleanupCallable = new Callable() { + 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 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(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 toEvict = lruEntries.entrySet().iterator().next(); + remove(toEvict.getKey()); + } + } + + private void trimToFileCount() throws IOException { + while (fileCount > maxFileCount) { + Map.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"); + } + } +} diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/utils/blur/DiskLruCacheManager.java b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/utils/blur/DiskLruCacheManager.java new file mode 100644 index 0000000000..424c5dce56 --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/utils/blur/DiskLruCacheManager.java @@ -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); + } + } +} diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/utils/blur/FastBlurUtil.java b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/utils/blur/FastBlurUtil.java new file mode 100644 index 0000000000..bab7819ba1 --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/utils/blur/FastBlurUtil.java @@ -0,0 +1,241 @@ +package com.mogo.och.taxi.passenger.utils.blur; + +import android.graphics.Bitmap; + +/** + * Created by jay on 11/7/15. + */ +public class FastBlurUtil { + + public static Bitmap doBlur(Bitmap sentBitmap, int scaleRadius, int radius) { + + // Stack Blur v1.0 from + // http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html + // + // Java Author: Mario Klingemann + // http://incubator.quasimondo.com + // created Feburary 29, 2004 + // Android port : Yahel Bouaziz + // http://www.kayenko.com + // ported april 5th, 2012 + + // This is a compromise between Gaussian Blur and Box blur + // It creates much better looking blurs than Box Blur, but is + // 7x faster than my Gaussian Blur implementation. + // + // I called it Stack Blur because this describes best how this + // filter works internally: it creates a kind of moving stack + // of colors whilst scanning through the image. Thereby it + // just has to add one new block of color to the right side + // of the stack and remove the leftmost color. The remaining + // colors on the topmost layer of the stack are either added on + // or reduced by one, depending on if they are on the right or + // on the left side of the stack. + // + // If you are using this algorithm in your code please add + // the following line: + // + // Stack Blur Algorithm by Mario Klingemann + if (scaleRadius > 0) { + sentBitmap = Bitmap.createScaledBitmap(sentBitmap, sentBitmap.getWidth() / scaleRadius, + sentBitmap.getHeight() / scaleRadius, false); + } + Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(), true); + + if (radius < 1) { + return (null); + } + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + + int[] pix = new int[w * h]; + bitmap.getPixels(pix, 0, w, 0, 0, w, h); + + int wm = w - 1; + int hm = h - 1; + int wh = w * h; + int div = radius + radius + 1; + + int r[] = new int[wh]; + int g[] = new int[wh]; + int b[] = new int[wh]; + int rsum, gsum, bsum, x, y, i, p, yp, yi, yw; + int vmin[] = new int[Math.max(w, h)]; + + int divsum = (div + 1) >> 1; + divsum *= divsum; + int dv[] = new int[256 * divsum]; + for (i = 0; i < 256 * divsum; i++) { + dv[i] = (i / divsum); + } + + yw = yi = 0; + + int[][] stack = new int[div][3]; + int stackpointer; + int stackstart; + int[] sir; + int rbs; + int r1 = radius + 1; + int routsum, goutsum, boutsum; + int rinsum, ginsum, binsum; + + for (y = 0; y < h; y++) { + rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0; + for (i = -radius; i <= radius; i++) { + p = pix[yi + Math.min(wm, Math.max(i, 0))]; + sir = stack[i + radius]; + sir[0] = (p & 0xff0000) >> 16; + sir[1] = (p & 0x00ff00) >> 8; + sir[2] = (p & 0x0000ff); + rbs = r1 - Math.abs(i); + rsum += sir[0] * rbs; + gsum += sir[1] * rbs; + bsum += sir[2] * rbs; + if (i > 0) { + rinsum += sir[0]; + ginsum += sir[1]; + binsum += sir[2]; + } else { + routsum += sir[0]; + goutsum += sir[1]; + boutsum += sir[2]; + } + } + stackpointer = radius; + + for (x = 0; x < w; x++) { + + r[yi] = dv[rsum]; + g[yi] = dv[gsum]; + b[yi] = dv[bsum]; + + rsum -= routsum; + gsum -= goutsum; + bsum -= boutsum; + + stackstart = stackpointer - radius + div; + sir = stack[stackstart % div]; + + routsum -= sir[0]; + goutsum -= sir[1]; + boutsum -= sir[2]; + + if (y == 0) { + vmin[x] = Math.min(x + radius + 1, wm); + } + p = pix[yw + vmin[x]]; + + sir[0] = (p & 0xff0000) >> 16; + sir[1] = (p & 0x00ff00) >> 8; + sir[2] = (p & 0x0000ff); + + rinsum += sir[0]; + ginsum += sir[1]; + binsum += sir[2]; + + rsum += rinsum; + gsum += ginsum; + bsum += binsum; + + stackpointer = (stackpointer + 1) % div; + sir = stack[(stackpointer) % div]; + + routsum += sir[0]; + goutsum += sir[1]; + boutsum += sir[2]; + + rinsum -= sir[0]; + ginsum -= sir[1]; + binsum -= sir[2]; + + yi++; + } + yw += w; + } + for (x = 0; x < w; x++) { + rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0; + yp = -radius * w; + for (i = -radius; i <= radius; i++) { + yi = Math.max(0, yp) + x; + + sir = stack[i + radius]; + + sir[0] = r[yi]; + sir[1] = g[yi]; + sir[2] = b[yi]; + + rbs = r1 - Math.abs(i); + + rsum += r[yi] * rbs; + gsum += g[yi] * rbs; + bsum += b[yi] * rbs; + + if (i > 0) { + rinsum += sir[0]; + ginsum += sir[1]; + binsum += sir[2]; + } else { + routsum += sir[0]; + goutsum += sir[1]; + boutsum += sir[2]; + } + + if (i < hm) { + yp += w; + } + } + yi = x; + stackpointer = radius; + for (y = 0; y < h; y++) { + // Preserve alpha channel: ( 0xff000000 & pix[yi] ) + pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16) | (dv[gsum] << 8) | dv[bsum]; + + rsum -= routsum; + gsum -= goutsum; + bsum -= boutsum; + + stackstart = stackpointer - radius + div; + sir = stack[stackstart % div]; + + routsum -= sir[0]; + goutsum -= sir[1]; + boutsum -= sir[2]; + + if (x == 0) { + vmin[y] = Math.min(y + r1, hm) * w; + } + p = x + vmin[y]; + + sir[0] = r[p]; + sir[1] = g[p]; + sir[2] = b[p]; + + rinsum += sir[0]; + ginsum += sir[1]; + binsum += sir[2]; + + rsum += rinsum; + gsum += ginsum; + bsum += binsum; + + stackpointer = (stackpointer + 1) % div; + sir = stack[stackpointer]; + + routsum += sir[0]; + goutsum += sir[1]; + boutsum += sir[2]; + + rinsum -= sir[0]; + ginsum -= sir[1]; + binsum -= sir[2]; + + yi += w; + } + } + + bitmap.setPixels(pix, 0, w, 0, 0, w, h); + + return (bitmap); + } +} diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/utils/blur/GlideBlurTransform.java b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/utils/blur/GlideBlurTransform.java new file mode 100644 index 0000000000..eee5c0cfdc --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/utils/blur/GlideBlurTransform.java @@ -0,0 +1,37 @@ +package com.mogo.och.taxi.passenger.utils.blur; + +import android.content.Context; +import android.graphics.Bitmap; + +import androidx.annotation.NonNull; + +import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; +import com.bumptech.glide.load.resource.bitmap.BitmapTransformation; + +import java.security.MessageDigest; + +public class GlideBlurTransform extends BitmapTransformation { + + private String key; + private Context context; + private int blurRadius; + + public GlideBlurTransform(Context context, String key, int blurRadius ) { + this.context = context; + this.key = key; + this.blurRadius = blurRadius; + } + + @Override + protected Bitmap transform( @NonNull BitmapPool pool, @NonNull Bitmap toTransform, int outWidth, int outHeight ) { + Bitmap bitmap = FastBlurUtil.doBlur( toTransform, 1, blurRadius ); + // 缓存高斯模糊图片 + DiskLruCacheManager.getInstance( context ).put( key, bitmap ); + return bitmap; + } + + @Override + public void updateDiskCacheKey( MessageDigest messageDigest ) { + + } +} \ No newline at end of file diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/utils/blur/StrictLineReader.java b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/utils/blur/StrictLineReader.java new file mode 100644 index 0000000000..94f756e38b --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/utils/blur/StrictLineReader.java @@ -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. + * + *

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}. + * + *

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. + * + *

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; + } +} + diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/utils/blur/Util.java b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/utils/blur/Util.java new file mode 100644 index 0000000000..7d9ad39ccb --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/utils/blur/Util.java @@ -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) { + } + } + } +} \ No newline at end of file diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/utils/windowdispatch/OnComputeInternalInsetsListener.java b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/utils/windowdispatch/OnComputeInternalInsetsListener.java new file mode 100644 index 0000000000..6fd67ae232 --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/utils/windowdispatch/OnComputeInternalInsetsListener.java @@ -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; + } +} diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/utils/windowdispatch/ReflectionUtils.java b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/utils/windowdispatch/ReflectionUtils.java new file mode 100644 index 0000000000..1ade41a62d --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/utils/windowdispatch/ReflectionUtils.java @@ -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 list = (ArrayList) 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(); + } + } + +} diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/ConsultVideoPlayer.kt b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/ConsultVideoPlayer.kt new file mode 100644 index 0000000000..b5d61fbb55 --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/ConsultVideoPlayer.kt @@ -0,0 +1,391 @@ +package com.mogo.och.taxi.passenger.widget + +import android.app.Activity +import android.content.Context +import android.graphics.Color +import android.util.AttributeSet +import android.view.* +import android.widget.FrameLayout +import android.widget.ImageView +import android.widget.TextView +import androidx.appcompat.widget.AppCompatImageView +import androidx.constraintlayout.widget.ConstraintLayout +import com.mogo.eagle.core.utilcode.util.TimeTransformUtils +import com.mogo.eagle.core.widget.media.video.TextureVideoViewOutlineProvider +import com.mogo.och.taxi.passenger.R +import com.mogo.och.taxi.passenger.ui.video.FullVideoUtils +import com.shuyu.gsyvideoplayer.listener.VideoAllCallBack +import com.shuyu.gsyvideoplayer.utils.Debuger +import com.shuyu.gsyvideoplayer.utils.GSYVideoType +import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer +import com.shuyu.gsyvideoplayer.video.base.GSYBaseVideoPlayer +import com.shuyu.gsyvideoplayer.video.base.GSYVideoPlayer +import com.shuyu.gsyvideoplayer.video.base.GSYVideoView +import java.lang.reflect.Constructor + +/** + * @author lixiaopeng + * @since 2021/11/3 + * + * 视频播放器,ui定制 + */ +class ConsultVideoPlayer : StandardGSYVideoPlayer { + + private lateinit var start: ImageView + lateinit var coverImage: ImageView + private lateinit var currentTimeTextView: TextView + private lateinit var totalTimeTextView: TextView + private lateinit var aivStartPlay: AppCompatImageView + private lateinit var tvTitle: TextView + private lateinit var layoutBottom: ConstraintLayout + + private var fullVideoPlayer:ConsultVideoPlayer?=null + + constructor(context: Context?) : super(context) + constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs) + constructor(context: Context?, fullFlag: Boolean?) : super(context, fullFlag) + + override fun init(context: Context) { + mEnlargeImageRes = R.drawable.taxi_p_change_full + super.init(context) + start = findViewById(R.id.start) + coverImage = findViewById(R.id.thumbImage) + currentTimeTextView = findViewById(R.id.current) + totalTimeTextView = findViewById(R.id.total) + aivStartPlay = findViewById(R.id.aiv_start_play) + layoutBottom = findViewById(R.id.layout_bottom) + tvTitle = findViewById(R.id.tv_title) + fullscreenButton.setOnClickListener(this) + aivStartPlay.setOnClickListener(this) + if (mThumbImageViewLayout != null + && (mCurrentState == -1 || mCurrentState == CURRENT_STATE_NORMAL || mCurrentState == CURRENT_STATE_ERROR) + ) { + mThumbImageViewLayout.visibility = View.VISIBLE + } + GSYVideoType.setShowType(GSYVideoType.SCREEN_TYPE_16_9) + } + + override fun getLayoutId(): Int { + return R.layout.taxi_p_video_show + } + + fun setTitle(title:String){ + tvTitle.text = title + } + + override fun updateStartImage() { + when (mCurrentState) { + GSYVideoView.CURRENT_STATE_PLAYING ->{ + start.setImageResource(R.drawable.notice_video_pause) + aivStartPlay.visibility = View.GONE + } + GSYVideoView.CURRENT_STATE_ERROR ->{ + start.setImageResource(R.drawable.notice_video_pause) + aivStartPlay.visibility = View.GONE + } + else -> { + start.setImageResource(R.drawable.notice_video_after_pause) + aivStartPlay.visibility = View.VISIBLE + } + } + } + + override fun touchDoubleUp() { + + } + + public override fun hideAllWidget() { + super.hideAllWidget() + } + + override fun setProgressAndTime( + progress: Int, + secProgress: Int, + currentTime: Int, + totalTime: Int, + forceChange: Boolean + ) { + super.setProgressAndTime(progress, secProgress, currentTime, totalTime, forceChange) + //时间显示 + currentTimeTextView.text = TimeTransformUtils.stringForTime(currentTime) + totalTimeTextView.text = TimeTransformUtils.stringForTime(totalTime) + + if (progress != 0) { + mProgressBar?.progress = progress + } + } + + override fun showWifiDialog() { + //直接播放,不显示WIFI对话框 + startPlayLogic() + } + + override fun onDetachedFromWindow() { + super.onDetachedFromWindow() + + mProgressBar?.progress = 0 + mFullPauseBitmap = null + if(mIfCurrentIsFullscreen){ + FullVideoUtils.dismissOverlayView() + fullVideoPlayer?.let { + clearFullscreenLayout(it) + } + fullVideoPlayer?.onVideoReset() + thumbImageViewLayout.visibility = View.VISIBLE + }else{ + onVideoReset() + } + } + + override fun onClick(v: View?) { + super.onClick(v) + when (v?.id) { + R.id.fullscreen -> { + startWindowFullscreenOwn(context, false, false) + } + R.id.aiv_start_play -> { + if(currentState==GSYVideoView.CURRENT_STATE_PAUSE){ + onVideoResume(false) + }else{ + startPlayLogic() + } + } + else -> {} + } + } + + override fun onCompletion() { + start.setImageResource(R.drawable.notice_video_after_pause) + } + + override fun onSurfaceUpdated(surface: Surface) { + super.onSurfaceUpdated(surface) + if (mThumbImageViewLayout != null && mThumbImageViewLayout.visibility == View.VISIBLE) { + mThumbImageViewLayout.visibility = View.INVISIBLE + } + } + + override fun onPrepared() { + super.onPrepared() + } + + override fun onBufferingUpdate(percent: Int) { + super.onBufferingUpdate(percent) + + } + + override fun onError(what: Int, extra: Int) { + super.onError(what, extra) + } + + override fun setViewShowState(view: View?, visibility: Int) { + if (view === mThumbImageViewLayout && visibility != View.VISIBLE) { + return + } + super.setViewShowState(view, visibility) + } + + override fun onSurfaceAvailable(surface: Surface) { + super.onSurfaceAvailable(surface) + if (GSYVideoType.getRenderType() != GSYVideoType.TEXTURE) { +// if (mThumbImageViewLayout != null && mThumbImageViewLayout.visibility == View.VISIBLE) { +// mThumbImageViewLayout.visibility = View.INVISIBLE +// } + } + } + + override fun onAutoCompletion() { + super.onAutoCompletion() + if(mIfCurrentIsFullscreen){ + FullVideoUtils.dismissOverlayView() + fullVideoPlayer?.let { + clearFullscreenLayout(it) + } + } + } + + override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { + super.onSizeChanged(w, h, oldw, oldh) + if (!mIfCurrentIsFullscreen) { + this.outlineProvider = TextureVideoViewOutlineProvider(40F) + this.clipToOutline = true + } + } + + private fun startWindowFullscreenOwn(context:Context, actionBar:Boolean, statusBar:Boolean){ + val gsyBaseVideoPlayer = startWindowFullscreen(context, actionBar, statusBar) + gsyBaseVideoPlayer?.let { + val gsyVideoPlayer = it as StandardGSYVideoPlayer + gsyVideoPlayer.setLockClickListener(mLockClickListener) + gsyVideoPlayer.isNeedLockFull = isNeedLockFull + initFullUI(gsyVideoPlayer) + } + } + + private fun initFullUI(standardGSYVideoPlayer: StandardGSYVideoPlayer) { + if (mBottomProgressDrawable != null) { + standardGSYVideoPlayer.setBottomProgressBarDrawable(mBottomProgressDrawable) + } + if (mBottomShowProgressDrawable != null && mBottomShowProgressThumbDrawable != null) { + standardGSYVideoPlayer.setBottomShowProgressBarDrawable( + mBottomShowProgressDrawable, + mBottomShowProgressThumbDrawable + ) + } + if (mVolumeProgressDrawable != null) { + standardGSYVideoPlayer.setDialogVolumeProgressBar(mVolumeProgressDrawable) + } + if (mDialogProgressBarDrawable != null) { + standardGSYVideoPlayer.setDialogProgressBar(mDialogProgressBarDrawable) + } + if (mDialogProgressHighLightColor >= 0 && mDialogProgressNormalColor >= 0) { + standardGSYVideoPlayer.setDialogProgressColor( + mDialogProgressHighLightColor, + mDialogProgressNormalColor + ) + } + } + + override fun startWindowFullscreen(context:Context, actionBar:Boolean, statusBar:Boolean):GSYBaseVideoPlayer?{ + + if (mTextureViewContainer.childCount > 0) { + mTextureViewContainer.removeAllViews() + } + var hadNewConstructor = true + + //切换时关闭非全屏定时器 + cancelProgressTimer() + try { + this@ConsultVideoPlayer.javaClass.getConstructor( + Context::class.java, + Boolean::class.java + ) + } catch (e: java.lang.Exception) { + hadNewConstructor = false + } + try { + //通过被重载的不同构造器来选择 + val constructor: Constructor + val gsyVideoPlayer: ConsultVideoPlayer + if (!hadNewConstructor) { + constructor = this@ConsultVideoPlayer.javaClass.getConstructor(Context::class.java) + gsyVideoPlayer = constructor.newInstance(mContext) + } else { + constructor = this@ConsultVideoPlayer.javaClass.getConstructor( + Context::class.java, + Boolean::class.java + ) + gsyVideoPlayer = constructor.newInstance(mContext, true) + } + this.fullVideoPlayer = gsyVideoPlayer + gsyVideoPlayer.id = fullId + gsyVideoPlayer.isIfCurrentIsFullscreen = true + gsyVideoPlayer.setVideoAllCallBack(mVideoAllCallBack) + cloneParams(this, gsyVideoPlayer) + val frameLayout = FrameLayout(context) + if (gsyVideoPlayer.fullscreenButton != null) { + gsyVideoPlayer.fullscreenButton.setImageResource(R.drawable.taxi_p_change_normal) + gsyVideoPlayer.fullscreenButton.setOnClickListener { v -> + if (mBackFromFullScreenListener == null) { + FullVideoUtils.dismissOverlayView() + clearFullscreenLayout(gsyVideoPlayer) + } else { + mBackFromFullScreenListener.onClick(v) + } + } + } + frameLayout.setBackgroundColor(Color.BLACK) + + val lp = LayoutParams( + width, height + ) + frameLayout.addView(gsyVideoPlayer, lp) + FullVideoUtils.showOverlayView(context as Activity,frameLayout,R.style.och_window_anim_alpha) + gsyVideoPlayer.visibility = INVISIBLE + frameLayout.visibility = INVISIBLE + resolveFullVideoShow(context, gsyVideoPlayer, frameLayout) + gsyVideoPlayer.addTextureView() + gsyVideoPlayer.startProgressTimer() + gsyVideoManager.setLastListener(this) + gsyVideoManager.setListener(gsyVideoPlayer) + checkoutState() + thumbImageViewLayout.visibility = View.VISIBLE + return gsyVideoPlayer + } catch (e: java.lang.Exception) { + e.printStackTrace() + } + + return null + } + + /** + * 全屏 + */ + override fun resolveFullVideoShow( + context: Context?, + gsyVideoPlayer: GSYBaseVideoPlayer, + frameLayout: FrameLayout + ) { + val lp = gsyVideoPlayer.layoutParams as LayoutParams + lp.setMargins(0, 0, 0, 0) + lp.height = ViewGroup.LayoutParams.MATCH_PARENT + lp.width = ViewGroup.LayoutParams.MATCH_PARENT + lp.gravity = Gravity.CENTER + gsyVideoPlayer.layoutParams = lp + gsyVideoPlayer.isIfCurrentIsFullscreen = true + val isVertical = isVerticalFullByVideoSize + val isLockLand = isLockLandByAutoFullSize + if (isShowFullAnimation) { + mInnerHandler.postDelayed({ //autoFull模式下,非横屏视频视频不横屏,并且不自动旋转 + if (!isVertical && isLockLand && mOrientationUtils != null && mOrientationUtils.isLand != 1) { + mOrientationUtils.resolveByClick() + } + gsyVideoPlayer.visibility = VISIBLE + frameLayout.visibility = VISIBLE + }, 300) + } else { + if (!isVertical && isLockLand && mOrientationUtils != null) { + mOrientationUtils.resolveByClick() + } + gsyVideoPlayer.visibility = VISIBLE + frameLayout.visibility = VISIBLE + } + if (mVideoAllCallBack != null) { + Debuger.printfError("onEnterFullscreen") + mVideoAllCallBack.onEnterFullscreen(mOriginUrl, mTitle, gsyVideoPlayer) + } + mIfCurrentIsFullscreen = true + checkoutState() + checkAutoFullWithSizeAndAdaptation(gsyVideoPlayer) + } + + fun clearFullscreenLayout(gsyVideoPlayer:GSYVideoPlayer) { + mIfCurrentIsFullscreen = false + val delay = 0 + mInnerHandler.postDelayed({ resolveNormalVideoShow(gsyVideoPlayer) }, delay.toLong()) + } + + private fun resolveNormalVideoShow(gsyVideoPlayer: GSYVideoPlayer) { + mCurrentState = gsyVideoManager.lastState + cloneParams(gsyVideoPlayer, this) + gsyVideoManager.setListener(gsyVideoManager.lastListener()) + gsyVideoManager.setLastListener(null) + setStateAndUi(mCurrentState) + addTextureView() + mSaveChangeViewTIme = System.currentTimeMillis() + if (mVideoAllCallBack != null) { + Debuger.printfError("onQuitFullscreen") + mVideoAllCallBack.onQuitFullscreen(mOriginUrl, mTitle, this) + } + mIfCurrentIsFullscreen = false + if (fullscreenButton != null) { + fullscreenButton.setImageResource(enlargeImageRes) + } + this.fullVideoPlayer = null + } + + fun getVideoAllCallBack(): VideoAllCallBack? { + return mVideoAllCallBack + } +} + diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/ResizeAnimation.java b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/ResizeAnimation.java new file mode 100644 index 0000000000..be2442a014 --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/ResizeAnimation.java @@ -0,0 +1,39 @@ +package com.mogo.och.taxi.passenger.widget; + +import android.view.View; +import android.view.animation.Animation; +import android.view.animation.Transformation; + +public class ResizeAnimation extends Animation { + + final int targetHeight; + View view; + int startHeight; + public ResizeAnimation(View view, int targetHeight, int startHeight) { + this.view = view; + this.targetHeight = targetHeight; + this.startHeight = startHeight; + } + + @Override + protected void applyTransformation(float interpolatedTime, Transformation t) { + + int newHeight = (int) (startHeight + (targetHeight-startHeight) * interpolatedTime); + view.getLayoutParams().height = newHeight; + + view.requestLayout(); + + } + + @Override + + public void initialize(int width, int height, int parentWidth, int parentHeight) { + super.initialize(width, height, parentWidth, parentHeight); + } + + @Override + public boolean willChangeBounds() { + return true; + } + +} diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/IndicatorView.kt b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/IndicatorView.kt new file mode 100644 index 0000000000..b458c4d498 --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/IndicatorView.kt @@ -0,0 +1,68 @@ +package com.mogo.och.taxi.passenger.widget.indicator + +import android.content.Context +import android.graphics.Canvas +import android.util.AttributeSet +import com.mogo.och.taxi.passenger.widget.indicator.annotation.AIndicatorOrientation + +import com.zhpan.indicator.base.BaseIndicatorView +import com.mogo.och.taxi.passenger.widget.indicator.drawer.DrawerProxy +import com.mogo.och.taxi.passenger.widget.indicator.enums.IndicatorOrientation +import com.mogo.och.taxi.passenger.widget.indicator.option.AttrsController +import com.mogo.och.taxi.passenger.widget.indicator.option.IndicatorOptions + +class IndicatorView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : BaseIndicatorView(context, attrs, defStyleAttr) { + + private var mDrawerProxy: DrawerProxy + + init { + AttrsController.initAttrs(context, attrs, mIndicatorOptions) + mDrawerProxy = DrawerProxy(mIndicatorOptions) + } + + override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) { + super.onLayout(changed, left, top, right, bottom) + mDrawerProxy.onLayout(changed, left, top, right, bottom) + } + + override fun onMeasure( + widthMeasureSpec: Int, + heightMeasureSpec: Int + ) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec) + val measureResult = mDrawerProxy.onMeasure(widthMeasureSpec, heightMeasureSpec) + setMeasuredDimension(measureResult.measureWidth, measureResult.measureHeight) + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + rotateCanvas(canvas) + mDrawerProxy.onDraw(canvas) + } + + override fun setIndicatorOptions(options: IndicatorOptions) { + super.setIndicatorOptions(options) + mDrawerProxy.setIndicatorOptions(options) + } + + override fun notifyDataChanged(itemCount:Int) { + mDrawerProxy = DrawerProxy(mIndicatorOptions) + super.notifyDataChanged(itemCount) + } + + private fun rotateCanvas(canvas: Canvas) { + if (mIndicatorOptions.orientation == IndicatorOrientation.INDICATOR_VERTICAL) { + canvas.rotate(90f, width / 2f, width / 2f) + } else if (mIndicatorOptions.orientation == IndicatorOrientation.INDICATOR_RTL) { + canvas.rotate(180f, width / 2f, height / 2f) + } + } + + fun setOrientation(@AIndicatorOrientation orientation: Int) { + mIndicatorOptions.orientation = orientation; + } +} diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/annotation/AIndicatorOrientation.kt b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/annotation/AIndicatorOrientation.kt new file mode 100644 index 0000000000..4e3ff14f56 --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/annotation/AIndicatorOrientation.kt @@ -0,0 +1,17 @@ +package com.mogo.och.taxi.passenger.widget.indicator.annotation + +import androidx.annotation.IntDef +import com.mogo.och.taxi.passenger.widget.indicator.enums.IndicatorOrientation + +/** + * + * @author zhangpan + * @date 2021/1/21 + */ +@IntDef( + IndicatorOrientation.INDICATOR_HORIZONTAL, IndicatorOrientation.INDICATOR_VERTICAL, + IndicatorOrientation.INDICATOR_RTL +) +@kotlin.annotation.Retention(AnnotationRetention.SOURCE) +@Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.FIELD) +annotation class AIndicatorOrientation() diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/annotation/AIndicatorSlideMode.kt b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/annotation/AIndicatorSlideMode.kt new file mode 100644 index 0000000000..2497e29f01 --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/annotation/AIndicatorSlideMode.kt @@ -0,0 +1,19 @@ +package com.mogo.och.taxi.passenger.widget.indicator.annotation + +import androidx.annotation.IntDef +import com.mogo.och.taxi.passenger.widget.indicator.enums.IndicatorSlideMode.Companion.COLOR +import com.mogo.och.taxi.passenger.widget.indicator.enums.IndicatorSlideMode.Companion.NORMAL +import com.mogo.och.taxi.passenger.widget.indicator.enums.IndicatorSlideMode.Companion.SCALE +import com.mogo.och.taxi.passenger.widget.indicator.enums.IndicatorSlideMode.Companion.SMOOTH +import com.mogo.och.taxi.passenger.widget.indicator.enums.IndicatorSlideMode.Companion.WORM + +/** + *
+ * Created by zhangpan on 2019-10-18.
+ * Description:
+
* + */ +@IntDef(NORMAL, SMOOTH, WORM, COLOR, SCALE) +@kotlin.annotation.Retention(AnnotationRetention.SOURCE) +@Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.FIELD) +annotation class AIndicatorSlideMode diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/annotation/AIndicatorStyle.kt b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/annotation/AIndicatorStyle.kt new file mode 100644 index 0000000000..783524aa97 --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/annotation/AIndicatorStyle.kt @@ -0,0 +1,15 @@ +package com.mogo.och.taxi.passenger.widget.indicator.annotation + +import androidx.annotation.IntDef +import com.mogo.och.taxi.passenger.widget.indicator.enums.IndicatorStyle + +/** + *
+ * Created by zhangpan on 2019-10-18.
+ * Description:
+
* + */ +@IntDef(IndicatorStyle.CIRCLE, IndicatorStyle.DASH, IndicatorStyle.ROUND_RECT) +@kotlin.annotation.Retention(AnnotationRetention.SOURCE) +@Target(AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.FIELD) +annotation class AIndicatorStyle diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/base/BaseIndicatorView.kt b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/base/BaseIndicatorView.kt new file mode 100644 index 0000000000..fea282bb9d --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/base/BaseIndicatorView.kt @@ -0,0 +1,207 @@ +package com.zhpan.indicator.base + +import android.content.Context +import android.util.AttributeSet +import android.view.View + +import androidx.annotation.ColorInt +import androidx.recyclerview.widget.RecyclerView +import androidx.viewpager.widget.ViewPager +import androidx.viewpager2.widget.ViewPager2 + +import com.mogo.och.taxi.passenger.widget.indicator.annotation.AIndicatorSlideMode +import com.mogo.och.taxi.passenger.widget.indicator.annotation.AIndicatorStyle +import com.mogo.och.taxi.passenger.widget.indicator.base.IIndicator +import com.mogo.och.taxi.passenger.widget.indicator.enums.IndicatorSlideMode +import com.mogo.och.taxi.passenger.widget.indicator.option.IndicatorOptions + +/** + *
+ * Created by zhangpan on 2019-09-04.
+ * Description:IndicatorView基类,处理了页面滑动。
+ * 
+ */ +@Suppress("UNUSED") +open class BaseIndicatorView constructor( + context: Context, + attrs: AttributeSet?, + defStyleAttr: Int +) : View(context, attrs, defStyleAttr), IIndicator { + + var mIndicatorOptions: IndicatorOptions + + private var recyclerView: RecyclerView? = null + + init { + mIndicatorOptions = IndicatorOptions() + } + + fun setPageSize(pageSize: Int): BaseIndicatorView { + mIndicatorOptions.pageSize = pageSize + return this + } + + // 页面选定 + fun onPageSelected(position: Int) { + System.err.println("BaseIndicatorView---onPageSelected:" + position) + if (getSlideMode() == IndicatorSlideMode.NORMAL) { + setCurrentPosition(position) + setSlideProgress(0f) + invalidate() + } + } + + // 滚动距离 + fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) { + if (getSlideMode() != IndicatorSlideMode.NORMAL && getPageSize() > 1) { + scrollSlider(position, positionOffset) + invalidate() + } + } + + private fun scrollSlider(position: Int, positionOffset: Float) { + if (mIndicatorOptions.slideMode == IndicatorSlideMode.SCALE + || mIndicatorOptions.slideMode == IndicatorSlideMode.COLOR) { + setCurrentPosition(position) + setSlideProgress(positionOffset) + } else { + if (position % getPageSize() == getPageSize() - 1) { // 最后一个页面与第一个页面 + if (positionOffset < 0.5) { + setCurrentPosition(position) + setSlideProgress(0f) + } else { + setCurrentPosition(0) + setSlideProgress(0f) + } + } else { // 中间页面 + setCurrentPosition(position) + setSlideProgress(positionOffset) + } + } + } + + override fun notifyDataChanged(itemCount: Int) { + setPageSize(itemCount) + requestLayout() + invalidate() + } + + private fun setupViewPager() { + + } + + fun getNormalSlideWidth(): Float { + return mIndicatorOptions.normalSliderWidth + } + + fun setNormalSlideWidth(normalSliderWidth: Float) { + mIndicatorOptions.normalSliderWidth = normalSliderWidth + } + + fun getCheckedSlideWidth(): Float { + return mIndicatorOptions.checkedSliderWidth + } + + fun setCheckedSlideWidth(checkedSliderWidth: Float) { + mIndicatorOptions.checkedSliderWidth = checkedSliderWidth + } + + val checkedSliderWidth: Float + get() = mIndicatorOptions.checkedSliderWidth + + fun setCurrentPosition(currentPosition: Int) { + mIndicatorOptions.currentPosition = currentPosition + } + + fun getCurrentPosition(): Int { + return mIndicatorOptions.currentPosition + } + + fun getIndicatorGap(indicatorGap: Float) { + mIndicatorOptions.sliderGap = indicatorGap + } + + fun setIndicatorGap(indicatorGap: Float) { + mIndicatorOptions.sliderGap = indicatorGap + } + + fun setCheckedColor(@ColorInt normalColor: Int) { + mIndicatorOptions.checkedSliderColor = normalColor + } + + fun getCheckedColor(): Int { + return mIndicatorOptions.checkedSliderColor + } + + fun setNormalColor(@ColorInt normalColor: Int) { + mIndicatorOptions.normalSliderColor = normalColor + } + + fun getSlideProgress(): Float { + return mIndicatorOptions.slideProgress + } + + fun setSlideProgress(slideProgress: Float) { + mIndicatorOptions.slideProgress = slideProgress + } + + fun getPageSize(): Int { + return mIndicatorOptions.pageSize + } + + fun setSliderColor( + @ColorInt normalColor: Int, + @ColorInt selectedColor: Int + ): BaseIndicatorView { + mIndicatorOptions.setSliderColor(normalColor, selectedColor) + return this + } + + fun setSliderWidth(sliderWidth: Float): BaseIndicatorView { + mIndicatorOptions.setSliderWidth(sliderWidth) + return this + } + + fun setSliderWidth( + normalSliderWidth: Float, + selectedSliderWidth: Float + ): BaseIndicatorView { + mIndicatorOptions.setSliderWidth(normalSliderWidth, selectedSliderWidth) + return this + } + + fun setSliderGap(sliderGap: Float): BaseIndicatorView { + mIndicatorOptions.sliderGap = sliderGap + return this + } + + fun getSlideMode(): Int { + return mIndicatorOptions.slideMode + } + + fun setSlideMode(@AIndicatorSlideMode slideMode: Int): BaseIndicatorView { + mIndicatorOptions.slideMode = slideMode + return this + } + + fun setIndicatorStyle(@AIndicatorStyle indicatorStyle: Int): BaseIndicatorView { + mIndicatorOptions.indicatorStyle = indicatorStyle + return this + } + + fun setSliderHeight(sliderHeight: Float): BaseIndicatorView { + mIndicatorOptions.sliderHeight = sliderHeight + return this + } + + fun showIndicatorWhenOneItem(showIndicatorWhenOneItem: Boolean) { + mIndicatorOptions.showIndicatorOneItem = showIndicatorWhenOneItem + } + + fun onPageScrollStateChanged(state: Int) { + } + + override fun setIndicatorOptions(options: IndicatorOptions) { + mIndicatorOptions = options + } +} diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/base/IIndicator.kt b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/base/IIndicator.kt new file mode 100644 index 0000000000..8fbe7dbba1 --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/base/IIndicator.kt @@ -0,0 +1,18 @@ +package com.mogo.och.taxi.passenger.widget.indicator.base + +import androidx.viewpager.widget.ViewPager + +import com.mogo.och.taxi.passenger.widget.indicator.option.IndicatorOptions + +/** + *
+ * Created by zhangpan on 2019-09-02.
+ * Description:
+
* + */ +interface IIndicator { + + fun notifyDataChanged(itemCount:Int) + + fun setIndicatorOptions(options: IndicatorOptions) +} diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/drawer/BaseDrawer.kt b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/drawer/BaseDrawer.kt new file mode 100644 index 0000000000..ae1e7a520b --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/drawer/BaseDrawer.kt @@ -0,0 +1,94 @@ +package com.mogo.och.taxi.passenger.widget.indicator.drawer + +import android.animation.ArgbEvaluator +import android.graphics.Paint +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.option.IndicatorOptions + +/** + *
+ * Created by zhpan on 2019/11/23.
+ * Description:
+
* + */ +abstract class BaseDrawer internal constructor(internal var mIndicatorOptions: IndicatorOptions) : + IDrawer { + + private val mMeasureResult: MeasureResult + internal var maxWidth: Float = 0.toFloat() + internal var minWidth: Float = 0.toFloat() + internal var mPaint: Paint = Paint() + internal var argbEvaluator: ArgbEvaluator? = null + + companion object { + const val INDICATOR_PADDING_ADDITION = 6 + const val INDICATOR_PADDING = 3 + } + + protected val isWidthEquals: Boolean + get() = mIndicatorOptions.normalSliderWidth == mIndicatorOptions.checkedSliderWidth + + init { + mPaint.isAntiAlias = true + mMeasureResult = MeasureResult() + if (mIndicatorOptions.slideMode == IndicatorSlideMode.SCALE + || mIndicatorOptions.slideMode == IndicatorSlideMode.COLOR + ) { + argbEvaluator = ArgbEvaluator() + } + } + + override fun onMeasure( + widthMeasureSpec: Int, + heightMeasureSpec: Int + ): MeasureResult { + maxWidth = + mIndicatorOptions.normalSliderWidth.coerceAtLeast(mIndicatorOptions.checkedSliderWidth) + minWidth = + mIndicatorOptions.normalSliderWidth.coerceAtMost(mIndicatorOptions.checkedSliderWidth) + if (mIndicatorOptions.orientation == IndicatorOrientation.INDICATOR_VERTICAL) { + mMeasureResult.setMeasureResult(measureHeight(), measureWidth()) + } else { + mMeasureResult.setMeasureResult(measureWidth(), measureHeight()) + } + return mMeasureResult + } + + protected open fun measureHeight(): Int { + return mIndicatorOptions.sliderHeight.toInt() + INDICATOR_PADDING + } + + private fun measureWidth(): Int { + val pageSize = mIndicatorOptions.pageSize + val indicatorGap = mIndicatorOptions.sliderGap + return ((pageSize - 1) * indicatorGap + maxWidth + (pageSize - 1) * minWidth).toInt() + INDICATOR_PADDING_ADDITION + } + + override fun onLayout( + changed: Boolean, + left: Int, + top: Int, + right: Int, + bottom: Int + ) { + } + + inner class MeasureResult { + + var measureWidth: Int = 0 + internal set + + var measureHeight: Int = 0 + internal set + + internal fun setMeasureResult( + measureWidth: Int, + measureHeight: Int + ) { + this.measureWidth = measureWidth + this.measureHeight = measureHeight + } + } +} diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/drawer/CircleDrawer.kt b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/drawer/CircleDrawer.kt new file mode 100644 index 0000000000..f7bde7a9ff --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/drawer/CircleDrawer.kt @@ -0,0 +1,157 @@ +package com.mogo.och.taxi.passenger.widget.indicator.drawer + +import android.graphics.Canvas +import android.graphics.RectF +import com.mogo.och.taxi.passenger.widget.indicator.enums.IndicatorSlideMode + +import com.mogo.och.taxi.passenger.widget.indicator.option.IndicatorOptions +import com.mogo.och.taxi.passenger.widget.indicator.utils.IndicatorUtils + +/** + *
+ * Created by zhpan on 2019/11/23.
+ * Description: Circle Indicator drawer.
+
* + */ +class CircleDrawer internal constructor(indicatorOptions: IndicatorOptions) : BaseDrawer( + indicatorOptions +) { + + private val rectF = RectF() + + override fun measureHeight(): Int { + return maxWidth.toInt() + INDICATOR_PADDING_ADDITION + } + + override fun onDraw(canvas: Canvas) { + val pageSize = mIndicatorOptions.pageSize + if (pageSize > 1 || mIndicatorOptions.showIndicatorOneItem && pageSize == 1) { + drawNormal(canvas) + drawSlider(canvas) + } + } + + private fun drawNormal(canvas: Canvas) { + val normalIndicatorWidth = mIndicatorOptions.normalSliderWidth + mPaint.color = mIndicatorOptions.normalSliderColor + for (i in 0 until mIndicatorOptions.pageSize) { + val coordinateX = IndicatorUtils.getCoordinateX(mIndicatorOptions, maxWidth, i) + val coordinateY = IndicatorUtils.getCoordinateY(maxWidth) + drawCircle(canvas, coordinateX, coordinateY, normalIndicatorWidth / 2) + } + } + + private fun drawSlider(canvas: Canvas) { + mPaint.color = mIndicatorOptions.checkedSliderColor + when (mIndicatorOptions.slideMode) { + IndicatorSlideMode.NORMAL, IndicatorSlideMode.SMOOTH -> drawCircleSlider(canvas) + IndicatorSlideMode.WORM -> drawWormSlider(canvas) + IndicatorSlideMode.SCALE -> drawScaleSlider(canvas) + IndicatorSlideMode.COLOR -> drawColor(canvas) + } + } + + private fun drawColor(canvas: Canvas) { + val currentPosition = mIndicatorOptions.currentPosition + val slideProgress = mIndicatorOptions.slideProgress + val coordinateX = IndicatorUtils.getCoordinateX(mIndicatorOptions, maxWidth, currentPosition) + val coordinateY = IndicatorUtils.getCoordinateY(maxWidth) + var evaluate = argbEvaluator?.evaluate( + slideProgress, mIndicatorOptions.checkedSliderColor, mIndicatorOptions.normalSliderColor + ) + mPaint.color = (evaluate as Int) + drawCircle(canvas, coordinateX, coordinateY, mIndicatorOptions.normalSliderWidth / 2) + + // 绘制可循环的ViewPager指示器渐变 + evaluate = argbEvaluator?.evaluate( + 1 - slideProgress, mIndicatorOptions.checkedSliderColor, mIndicatorOptions.normalSliderColor + ) + mPaint.color = evaluate as Int + val nextCoordinateX = if (currentPosition == mIndicatorOptions.pageSize - 1) { + IndicatorUtils.getCoordinateX(mIndicatorOptions, maxWidth, 0) + } else { + coordinateX + mIndicatorOptions.sliderGap + mIndicatorOptions.normalSliderWidth + } + drawCircle(canvas, nextCoordinateX, coordinateY, mIndicatorOptions.checkedSliderWidth / 2) + } + + private fun drawScaleSlider(canvas: Canvas) { + val currentPosition = mIndicatorOptions.currentPosition + val slideProgress = mIndicatorOptions.slideProgress + val coordinateX = IndicatorUtils.getCoordinateX(mIndicatorOptions, maxWidth, currentPosition) + val coordinateY = IndicatorUtils.getCoordinateY(maxWidth) + if (slideProgress < 1) { + val evaluate = argbEvaluator?.evaluate( + slideProgress, mIndicatorOptions.checkedSliderColor, mIndicatorOptions.normalSliderColor + ) + mPaint.color = (evaluate as Int) + val radius = + mIndicatorOptions.checkedSliderWidth / 2 - (mIndicatorOptions.checkedSliderWidth / 2 - mIndicatorOptions.normalSliderWidth / 2) * slideProgress + drawCircle(canvas, coordinateX, coordinateY, radius) + } + + if (currentPosition == mIndicatorOptions.pageSize - 1) { + val evaluate = argbEvaluator?.evaluate( + slideProgress, mIndicatorOptions.normalSliderColor, mIndicatorOptions.checkedSliderColor + ) + mPaint.color = evaluate as Int + val nextCoordinateX = maxWidth / 2 + val nextRadius = minWidth / 2 + (maxWidth / 2 - minWidth / 2) * (slideProgress) + drawCircle(canvas, nextCoordinateX, coordinateY, nextRadius) + } else { + if (slideProgress > 0) { + val evaluate = argbEvaluator?.evaluate( + slideProgress, mIndicatorOptions.normalSliderColor, mIndicatorOptions.checkedSliderColor + ) + mPaint.color = evaluate as Int + val nextCoordinateX = + coordinateX + mIndicatorOptions.sliderGap + mIndicatorOptions.normalSliderWidth + val nextRadius = + mIndicatorOptions.normalSliderWidth / 2 + (mIndicatorOptions.checkedSliderWidth / 2 - mIndicatorOptions.normalSliderWidth / 2) * slideProgress + drawCircle(canvas, nextCoordinateX, coordinateY, nextRadius) + } + } + } + + private fun drawCircleSlider(canvas: Canvas) { + val currentPosition = mIndicatorOptions.currentPosition + val startCoordinateX = + IndicatorUtils.getCoordinateX(mIndicatorOptions, maxWidth, currentPosition) + val endCoordinateX = IndicatorUtils.getCoordinateX( + mIndicatorOptions, maxWidth, (currentPosition + 1) % mIndicatorOptions.pageSize + ) + val coordinateX = + startCoordinateX + (endCoordinateX - startCoordinateX) * mIndicatorOptions.slideProgress + val coordinateY = IndicatorUtils.getCoordinateY(maxWidth) + val radius = mIndicatorOptions.checkedSliderWidth / 2 + drawCircle(canvas, coordinateX, coordinateY, radius) + } + + private fun drawWormSlider(canvas: Canvas) { + val sliderHeight = mIndicatorOptions.normalSliderWidth + val slideProgress = mIndicatorOptions.slideProgress + val currentPosition = mIndicatorOptions.currentPosition + val distance = mIndicatorOptions.sliderGap + mIndicatorOptions.normalSliderWidth + val startCoordinateX = + IndicatorUtils.getCoordinateX(mIndicatorOptions, maxWidth, currentPosition) + val left = startCoordinateX + (distance * (slideProgress - 0.5f) * 2.0f).coerceAtLeast( + 0f + ) - mIndicatorOptions.normalSliderWidth / 2 + INDICATOR_PADDING + val right = startCoordinateX + (distance * slideProgress * 2f).coerceAtMost( + distance + ) + mIndicatorOptions.normalSliderWidth / 2 + INDICATOR_PADDING + rectF.set(left, INDICATOR_PADDING.toFloat(), right, sliderHeight + INDICATOR_PADDING) + canvas.drawRoundRect(rectF, sliderHeight, sliderHeight, mPaint) + } + + private fun drawCircle( + canvas: Canvas, + coordinateX: Float, + coordinateY: Float, + radius: Float + ) { + canvas.drawCircle( + coordinateX + INDICATOR_PADDING, coordinateY + INDICATOR_PADDING, radius, mPaint + ) + } +} diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/drawer/DashDrawer.kt b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/drawer/DashDrawer.kt new file mode 100644 index 0000000000..6b2b7e12d1 --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/drawer/DashDrawer.kt @@ -0,0 +1,20 @@ +package com.mogo.och.taxi.passenger.widget.indicator.drawer + +import android.graphics.Canvas + +import com.mogo.och.taxi.passenger.widget.indicator.option.IndicatorOptions + +/** + *
+ * Created by zhpan on 2019/11/23.
+ * Description: Dash Indicator Drawer.
+
* + */ +class DashDrawer internal constructor(indicatorOptions: IndicatorOptions) : RectDrawer( + indicatorOptions +) { + + override fun drawDash(canvas: Canvas) { + canvas.drawRect(mRectF, mPaint) + } +} diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/drawer/DrawerFactory.kt b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/drawer/DrawerFactory.kt new file mode 100644 index 0000000000..2b5073a6b2 --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/drawer/DrawerFactory.kt @@ -0,0 +1,20 @@ +package com.mogo.och.taxi.passenger.widget.indicator.drawer + +import com.mogo.och.taxi.passenger.widget.indicator.enums.IndicatorStyle +import com.mogo.och.taxi.passenger.widget.indicator.option.IndicatorOptions + +/** + *
+ * Created by zhpan on 2019/11/24.
+ * Description: Indicator Drawer Factory.
+
* + */ +internal object DrawerFactory { + fun createDrawer(indicatorOptions: IndicatorOptions): IDrawer { + return when (indicatorOptions.indicatorStyle) { + IndicatorStyle.DASH -> DashDrawer(indicatorOptions) + IndicatorStyle.ROUND_RECT -> RoundRectDrawer(indicatorOptions) + else -> CircleDrawer(indicatorOptions) + } + } +} diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/drawer/DrawerProxy.kt b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/drawer/DrawerProxy.kt new file mode 100644 index 0000000000..30cb21e2ec --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/drawer/DrawerProxy.kt @@ -0,0 +1,48 @@ +package com.mogo.och.taxi.passenger.widget.indicator.drawer + +import android.graphics.Canvas + +import com.mogo.och.taxi.passenger.widget.indicator.option.IndicatorOptions + +/** + *
+ * Created by zhpan on 2019/11/23.
+ * Description: Indicator Drawer Proxy.
+
* + */ +class DrawerProxy(indicatorOptions: IndicatorOptions) : IDrawer { + + private lateinit var mIDrawer: IDrawer + + init { + init(indicatorOptions) + } + + private fun init(indicatorOptions: IndicatorOptions) { + mIDrawer = DrawerFactory.createDrawer(indicatorOptions) + } + + override fun onLayout( + changed: Boolean, + left: Int, + top: Int, + right: Int, + bottom: Int + ) { + } + + override fun onMeasure( + widthMeasureSpec: Int, + heightMeasureSpec: Int + ): BaseDrawer.MeasureResult { + return mIDrawer.onMeasure(widthMeasureSpec, heightMeasureSpec) + } + + override fun onDraw(canvas: Canvas) { + mIDrawer.onDraw(canvas) + } + + fun setIndicatorOptions(indicatorOptions: IndicatorOptions) { + init(indicatorOptions) + } +} diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/drawer/IDrawer.kt b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/drawer/IDrawer.kt new file mode 100644 index 0000000000..499ba78012 --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/drawer/IDrawer.kt @@ -0,0 +1,28 @@ +package com.mogo.och.taxi.passenger.widget.indicator.drawer + +import android.graphics.Canvas +import com.mogo.och.taxi.passenger.widget.indicator.drawer.BaseDrawer + +/** + *
+ * Created by zhpan on 2019/11/23.
+ * Description:
+
* + */ +interface IDrawer { + + fun onLayout( + changed: Boolean, + left: Int, + top: Int, + right: Int, + bottom: Int + ) + + fun onMeasure( + widthMeasureSpec: Int, + heightMeasureSpec: Int + ): BaseDrawer.MeasureResult + + fun onDraw(canvas: Canvas) +} diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/drawer/RectDrawer.kt b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/drawer/RectDrawer.kt new file mode 100644 index 0000000000..9e4cab5f9c --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/drawer/RectDrawer.kt @@ -0,0 +1,219 @@ +package com.mogo.och.taxi.passenger.widget.indicator.drawer + +import android.graphics.* + +import com.mogo.och.taxi.passenger.widget.indicator.enums.IndicatorSlideMode +import com.mogo.och.taxi.passenger.widget.indicator.option.IndicatorOptions +import com.mogo.och.taxi.passenger.widget.indicator.utils.IndicatorUtils + +/** + *
+ * Created by zhpan on 2020/1/17.
+ * Description:
+
* + */ +open class RectDrawer internal constructor(indicatorOptions: IndicatorOptions) : BaseDrawer( + indicatorOptions +) { + internal var mRectF: RectF = RectF() + + override fun onDraw(canvas: Canvas) { + val pageSize = mIndicatorOptions.pageSize + if (pageSize > 1 || mIndicatorOptions.showIndicatorOneItem && pageSize == 1) { + if (isWidthEquals && mIndicatorOptions.slideMode != IndicatorSlideMode.NORMAL) { + drawUncheckedSlider(canvas, pageSize) + drawCheckedSlider(canvas) + } else { // 单独处理normalWidth与checkedWidth不一致的情况 + if (mIndicatorOptions.slideMode == IndicatorSlideMode.SCALE) { + for (i in 0 until pageSize) { + drawScaleSlider(canvas, i) + } + } else { + drawInequalitySlider(canvas, pageSize) + } + } + } + } + + private fun drawScaleSlider( + canvas: Canvas, + i: Int + ) { + val checkedColor = mIndicatorOptions.checkedSliderColor + val indicatorGap = mIndicatorOptions.sliderGap + val sliderHeight = mIndicatorOptions.sliderHeight + val currentPosition = mIndicatorOptions.currentPosition + val normalWidth = mIndicatorOptions.normalSliderWidth + val checkedWidth = mIndicatorOptions.checkedSliderWidth + when { + i < currentPosition -> { + mPaint.color = mIndicatorOptions.normalSliderColor + val left: Float = if (currentPosition == mIndicatorOptions.pageSize - 1) { + (i * normalWidth + i * indicatorGap) + (checkedWidth - normalWidth) * mIndicatorOptions.slideProgress + } else { + (i * normalWidth + i * indicatorGap) + } + mRectF.set(left, 0f, left + normalWidth, sliderHeight) + drawRoundRect(canvas, sliderHeight, sliderHeight) + } + i == currentPosition -> { + mPaint.color = checkedColor + val slideProgress = mIndicatorOptions.slideProgress + if (currentPosition == mIndicatorOptions.pageSize - 1) { + val evaluate = argbEvaluator?.evaluate( + slideProgress, checkedColor, mIndicatorOptions.normalSliderColor + ) + mPaint.color = (evaluate as Int) + val right = + (mIndicatorOptions.pageSize - 1) * (normalWidth + mIndicatorOptions.sliderGap) + checkedWidth + val left = right - checkedWidth + (checkedWidth - normalWidth) * (slideProgress) + mRectF.set(left, 0f, right, sliderHeight) + drawRoundRect(canvas, sliderHeight, sliderHeight) + } else { + if (slideProgress < 1) { + val evaluate = argbEvaluator?.evaluate( + slideProgress, checkedColor, mIndicatorOptions.normalSliderColor + ) + mPaint.color = (evaluate as Int) + val left = i * normalWidth + i * indicatorGap + val right = left + normalWidth + (checkedWidth - normalWidth) * (1 - slideProgress) + mRectF.set(left, 0f, right, sliderHeight) + drawRoundRect(canvas, sliderHeight, sliderHeight) + } + } + + if (currentPosition == mIndicatorOptions.pageSize - 1) { + if (slideProgress > 0) { + val evaluate = argbEvaluator?.evaluate( + 1 - slideProgress, checkedColor, mIndicatorOptions.normalSliderColor + ) + mPaint.color = evaluate as Int + val left = 0f + val right = left + normalWidth + (checkedWidth - normalWidth) * slideProgress + + mRectF.set(left, 0f, right, sliderHeight) + drawRoundRect(canvas, sliderHeight, sliderHeight) + } + } else { + if (slideProgress > 0) { + val evaluate = argbEvaluator?.evaluate( + 1 - slideProgress, checkedColor, mIndicatorOptions.normalSliderColor + ) + mPaint.color = evaluate as Int + val right = + i * normalWidth + i * indicatorGap + normalWidth + (indicatorGap + checkedWidth) + val left = right - (normalWidth) - (checkedWidth - normalWidth) * (slideProgress) + mRectF.set(left, 0f, right, sliderHeight) + drawRoundRect(canvas, sliderHeight, sliderHeight) + } + } + } + else -> { + if ((currentPosition + 1 != i || mIndicatorOptions.slideProgress == 0f)) { // 避免多余绘制 + mPaint.color = mIndicatorOptions.normalSliderColor + val left = i * minWidth + i * indicatorGap + (checkedWidth - minWidth) + mRectF.set(left, 0f, left + minWidth, sliderHeight) + drawRoundRect(canvas, sliderHeight, sliderHeight) + } + } + } + } + + private fun drawUncheckedSlider( + canvas: Canvas, + pageSize: Int + ) { + for (i in 0 until pageSize) { + mPaint.color = mIndicatorOptions.normalSliderColor + val left = i * maxWidth + i * +mIndicatorOptions.sliderGap + (maxWidth - minWidth) + mRectF.set(left, 0f, left + minWidth, mIndicatorOptions.sliderHeight) + drawRoundRect(canvas, mIndicatorOptions.sliderHeight, mIndicatorOptions.sliderHeight) + } + } + + private fun drawInequalitySlider( + canvas: Canvas, + pageSize: Int + ) { + var left = 0f + for (i in 0 until pageSize) { + val sliderWidth = (if (i == mIndicatorOptions.currentPosition) maxWidth else minWidth) + mPaint.color = + if (i == mIndicatorOptions.currentPosition) mIndicatorOptions.checkedSliderColor else mIndicatorOptions.normalSliderColor + mRectF.set(left, 0f, left + sliderWidth, mIndicatorOptions.sliderHeight) + drawRoundRect(canvas, mIndicatorOptions.sliderHeight, mIndicatorOptions.sliderHeight) + left += sliderWidth + mIndicatorOptions.sliderGap + } + } + + private fun drawCheckedSlider(canvas: Canvas) { + mPaint.color = mIndicatorOptions.checkedSliderColor + when (mIndicatorOptions.slideMode) { + IndicatorSlideMode.SMOOTH -> drawSmoothSlider(canvas) + IndicatorSlideMode.WORM -> drawWormSlider(canvas) + IndicatorSlideMode.COLOR -> drawColorSlider(canvas) + } + } + + private fun drawColorSlider(canvas: Canvas) { + val currentPosition = mIndicatorOptions.currentPosition + val slideProgress = mIndicatorOptions.slideProgress + val left = currentPosition * minWidth + currentPosition * mIndicatorOptions.sliderGap + if (slideProgress < 0.99) { + val evaluate = argbEvaluator?.evaluate( + slideProgress, mIndicatorOptions.checkedSliderColor, mIndicatorOptions.normalSliderColor + ) + mPaint.color = (evaluate as Int) + mRectF.set(left, 0f, left + minWidth, mIndicatorOptions.sliderHeight) + drawRoundRect(canvas, mIndicatorOptions.sliderHeight, mIndicatorOptions.sliderHeight) + } + + var nextSliderLeft = left + mIndicatorOptions.sliderGap + mIndicatorOptions.normalSliderWidth + if (currentPosition == mIndicatorOptions.pageSize - 1) { + nextSliderLeft = 0f + } + val evaluate = argbEvaluator?.evaluate( + 1 - slideProgress, mIndicatorOptions.checkedSliderColor, mIndicatorOptions.normalSliderColor + ) + mPaint.color = evaluate as Int + mRectF.set(nextSliderLeft, 0f, nextSliderLeft + minWidth, mIndicatorOptions.sliderHeight) + drawRoundRect(canvas, mIndicatorOptions.sliderHeight, mIndicatorOptions.sliderHeight) + } + + private fun drawWormSlider(canvas: Canvas) { + val sliderHeight = mIndicatorOptions.sliderHeight + val slideProgress = mIndicatorOptions.slideProgress + val currentPosition = mIndicatorOptions.currentPosition + val distance = mIndicatorOptions.sliderGap + mIndicatorOptions.normalSliderWidth + val startCoordinateX = + IndicatorUtils.getCoordinateX(mIndicatorOptions, maxWidth, currentPosition) + val left = startCoordinateX + (distance * (slideProgress - 0.5f) * 2.0f).coerceAtLeast( + 0f + ) - mIndicatorOptions.normalSliderWidth / 2 + val right = startCoordinateX + (distance * slideProgress * 2f).coerceAtMost( + distance + ) + mIndicatorOptions.normalSliderWidth / 2 + mRectF.set(left, 0f, right, sliderHeight) + drawRoundRect(canvas, sliderHeight, sliderHeight) + } + + private fun drawSmoothSlider(canvas: Canvas) { + val currentPosition = mIndicatorOptions.currentPosition + val indicatorGap = mIndicatorOptions.sliderGap + val sliderHeight = mIndicatorOptions.sliderHeight + val left = + currentPosition * maxWidth + currentPosition * +indicatorGap + (maxWidth + indicatorGap) * mIndicatorOptions.slideProgress + mRectF.set(left, 0f, left + maxWidth, sliderHeight) + drawRoundRect(canvas, sliderHeight, sliderHeight) + } + + protected open fun drawRoundRect( + canvas: Canvas, + rx: Float, + ry: Float + ) { + drawDash(canvas) + } + + protected open fun drawDash(canvas: Canvas) {} +} diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/drawer/RoundRectDrawer.kt b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/drawer/RoundRectDrawer.kt new file mode 100644 index 0000000000..78c77633f4 --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/drawer/RoundRectDrawer.kt @@ -0,0 +1,24 @@ +package com.mogo.och.taxi.passenger.widget.indicator.drawer + +import android.graphics.Canvas + +import com.mogo.och.taxi.passenger.widget.indicator.option.IndicatorOptions + +/** + *
+ * Created by zhpan on 2019/11/26.
+ * Description:
+
* + */ +class RoundRectDrawer internal constructor(indicatorOptions: IndicatorOptions) : RectDrawer( + indicatorOptions +) { + + override fun drawRoundRect( + canvas: Canvas, + rx: Float, + ry: Float + ) { + canvas.drawRoundRect(mRectF, rx, ry, mPaint) + } +} diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/enums/IndicatorOrientation.kt b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/enums/IndicatorOrientation.kt new file mode 100644 index 0000000000..4f507e4c05 --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/enums/IndicatorOrientation.kt @@ -0,0 +1,16 @@ +package com.mogo.och.taxi.passenger.widget.indicator.enums + +import android.widget.LinearLayout + +/** + * + * @author zhangpan + * @date 2021/1/21 + */ +class IndicatorOrientation { + companion object { + const val INDICATOR_HORIZONTAL = LinearLayout.HORIZONTAL + const val INDICATOR_VERTICAL = LinearLayout.VERTICAL + const val INDICATOR_RTL = 3 + } +} \ No newline at end of file diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/enums/IndicatorSlideMode.kt b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/enums/IndicatorSlideMode.kt new file mode 100644 index 0000000000..0e9dfda078 --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/enums/IndicatorSlideMode.kt @@ -0,0 +1,17 @@ +package com.mogo.och.taxi.passenger.widget.indicator.enums + +/** + *
+ * Created by zhangpan on 2019-10-18.
+ * Description:
+
* + */ +interface IndicatorSlideMode { + companion object { + const val NORMAL = 0 + const val SMOOTH = 2 + const val WORM = 3 + const val SCALE = 4 + const val COLOR = 5 + } +} diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/enums/IndicatorStyle.kt b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/enums/IndicatorStyle.kt new file mode 100644 index 0000000000..e66ffb10fc --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/enums/IndicatorStyle.kt @@ -0,0 +1,15 @@ +package com.mogo.och.taxi.passenger.widget.indicator.enums + +/** + *
+ * Created by zhangpan on 2019-10-18.
+ * Description:
+
* + */ +interface IndicatorStyle { + companion object { + const val CIRCLE = 0 + const val DASH = 1 shl 1 + const val ROUND_RECT = 1 shl 2 + } +} diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/option/AttrsController.java b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/option/AttrsController.java new file mode 100644 index 0000000000..3a439ec7ea --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/option/AttrsController.java @@ -0,0 +1,38 @@ +package com.mogo.och.taxi.passenger.widget.indicator.option; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Color; +import android.util.AttributeSet; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.mogo.och.taxi.passenger.R; +import com.mogo.och.taxi.passenger.widget.indicator.utils.IndicatorUtils; + +public class AttrsController { + + public static void initAttrs(@NonNull Context context, @Nullable AttributeSet attrs, + IndicatorOptions indicatorOptions) { + if (attrs != null) { + TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.IndicatorView); + int indicatorSlideMode = typedArray.getInt(R.styleable.IndicatorView_vpi_slide_mode, 0); + int indicatorStyle = typedArray.getInt(R.styleable.IndicatorView_vpi_style, 0); + int checkedColor = typedArray.getColor(R.styleable.IndicatorView_vpi_slider_checked_color, + Color.parseColor("#6C6D72")); + int normalColor = typedArray.getColor(R.styleable.IndicatorView_vpi_slider_normal_color, + Color.parseColor("#8C18171C")); + int orientation = typedArray.getInt(R.styleable.IndicatorView_vpi_orientation, 0); + float radius = typedArray.getDimension(R.styleable.IndicatorView_vpi_slider_radius, + IndicatorUtils.dp2px(8)); + indicatorOptions.setCheckedColor(checkedColor); + indicatorOptions.setNormalSliderColor(normalColor); + indicatorOptions.setOrientation(orientation); + indicatorOptions.setIndicatorStyle(indicatorStyle); + indicatorOptions.setSlideMode(indicatorSlideMode); + indicatorOptions.setSliderWidth(radius * 2, radius * 2); + typedArray.recycle(); + } + } +} diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/option/IndicatorOptions.kt b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/option/IndicatorOptions.kt new file mode 100644 index 0000000000..168342d080 --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/option/IndicatorOptions.kt @@ -0,0 +1,108 @@ +package com.mogo.och.taxi.passenger.widget.indicator.option + +import android.graphics.Color +import com.mogo.och.taxi.passenger.widget.indicator.annotation.AIndicatorOrientation + +import com.mogo.och.taxi.passenger.widget.indicator.annotation.AIndicatorSlideMode +import com.mogo.och.taxi.passenger.widget.indicator.annotation.AIndicatorStyle +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.utils.IndicatorUtils + +/** + *
+ * Created by zhpan on 2019/11/20.
+ * Description:Indicator的配置参数
+
* + */ +class IndicatorOptions { + + @AIndicatorOrientation + var orientation = IndicatorOrientation.INDICATOR_HORIZONTAL + + @AIndicatorStyle + var indicatorStyle: Int = 0 + + /** + * Indicator滑动模式,目前仅支持两种 + * + * @see IndicatorSlideMode.NORMAL + * + * @see IndicatorSlideMode.SMOOTH + */ + @AIndicatorSlideMode + var slideMode: Int = 0 + + /** + * 页面size + */ + var pageSize: Int = 0 + + /** + * 未选中时Indicator颜色 + */ + var normalSliderColor: Int = 0 + + /** + * 选中时Indicator颜色 + */ + var checkedSliderColor: Int = 0 + + /** + * Indicator间距 + */ + var sliderGap: Float = 0f + + var sliderHeight: Float = 0f + get() = if (field > 0) field else normalSliderWidth / 2 + + var normalSliderWidth: Float = 0f + + var checkedSliderWidth: Float = 0f + + /** + * 指示器当前位置 + */ + var currentPosition: Int = 0 + + /** + * 从一个点滑动到另一个点的进度 + */ + var slideProgress: Float = 0f + + var showIndicatorOneItem: Boolean = false + + init { + normalSliderWidth = IndicatorUtils.dp2px(8f) + .toFloat() + checkedSliderWidth = normalSliderWidth + sliderGap = normalSliderWidth + normalSliderColor = Color.parseColor("#8C18171C") + checkedSliderColor = Color.parseColor("#8C6C6D72") + slideMode = IndicatorSlideMode.NORMAL + } + + fun setCheckedColor(checkedColor: Int) { + this.checkedSliderColor = checkedColor + } + + fun setSliderWidth( + normalIndicatorWidth: Float, + checkedIndicatorWidth: Float + ) { + this.normalSliderWidth = normalIndicatorWidth + this.checkedSliderWidth = checkedIndicatorWidth + } + + fun setSliderWidth(sliderWidth: Float) { + setSliderWidth(sliderWidth, sliderWidth) + } + + fun setSliderColor( + normalColor: Int, + checkedColor: Int + ) { + this.normalSliderColor = normalColor + this.checkedSliderColor = checkedColor + } +} diff --git a/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/utils/IndicatorUtils.kt b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/utils/IndicatorUtils.kt new file mode 100644 index 0000000000..6b0894f3a8 --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/java/com/mogo/och/taxi/passenger/widget/indicator/utils/IndicatorUtils.kt @@ -0,0 +1,32 @@ +package com.mogo.och.taxi.passenger.widget.indicator.utils + +import android.content.res.Resources + +import com.mogo.och.taxi.passenger.widget.indicator.option.IndicatorOptions + +/** + *
+ * Created by zhangpan on 2020-01-20.
+ * Description:
+
* + */ +object IndicatorUtils { + + @JvmStatic + fun dp2px(dpValue: Float): Int { + return (0.5f + dpValue * Resources.getSystem().displayMetrics.density).toInt() + } + + fun getCoordinateX( + indicatorOptions: IndicatorOptions, + maxDiameter: Float, + index: Int + ): Float { + val normalIndicatorWidth = indicatorOptions.normalSliderWidth + return maxDiameter / 2 + (normalIndicatorWidth + indicatorOptions.sliderGap) * index + } + + fun getCoordinateY(maxDiameter: Float): Float { + return maxDiameter / 2 + } +} diff --git a/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi-2560x1440/taxi_p_change_full.png b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi-2560x1440/taxi_p_change_full.png new file mode 100644 index 0000000000..d8084f5fce Binary files /dev/null and b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi-2560x1440/taxi_p_change_full.png differ diff --git a/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi-2560x1440/taxi_p_change_normal.png b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi-2560x1440/taxi_p_change_normal.png new file mode 100644 index 0000000000..90f33faa6d Binary files /dev/null and b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi-2560x1440/taxi_p_change_normal.png differ diff --git a/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi-2560x1440/taxi_p_mogo_consult_select.png b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi-2560x1440/taxi_p_mogo_consult_select.png new file mode 100755 index 0000000000..b3e4beb228 Binary files /dev/null and b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi-2560x1440/taxi_p_mogo_consult_select.png differ diff --git a/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi-2560x1440/taxi_p_mogo_consult_selected.png b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi-2560x1440/taxi_p_mogo_consult_selected.png new file mode 100755 index 0000000000..207ff8360d Binary files /dev/null and b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi-2560x1440/taxi_p_mogo_consult_selected.png differ diff --git a/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi-2560x1440/taxi_p_mogo_consult_title_icon.png b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi-2560x1440/taxi_p_mogo_consult_title_icon.png new file mode 100755 index 0000000000..55997f4ed2 Binary files /dev/null and b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi-2560x1440/taxi_p_mogo_consult_title_icon.png differ diff --git a/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi-2560x1440/taxi_p_mogo_entertainment_select.png b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi-2560x1440/taxi_p_mogo_entertainment_select.png new file mode 100755 index 0000000000..6ba07fba56 Binary files /dev/null and b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi-2560x1440/taxi_p_mogo_entertainment_select.png differ diff --git a/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi-2560x1440/taxi_p_mogo_entertainment_selected.png b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi-2560x1440/taxi_p_mogo_entertainment_selected.png new file mode 100755 index 0000000000..ba46e204b2 Binary files /dev/null and b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi-2560x1440/taxi_p_mogo_entertainment_selected.png differ diff --git a/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi-2560x1440/taxi_p_mogo_live_select.png b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi-2560x1440/taxi_p_mogo_live_select.png new file mode 100644 index 0000000000..b0436faf24 Binary files /dev/null and b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi-2560x1440/taxi_p_mogo_live_select.png differ diff --git a/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi-2560x1440/taxi_p_mogo_live_selected.png b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi-2560x1440/taxi_p_mogo_live_selected.png new file mode 100755 index 0000000000..7c31031e5b Binary files /dev/null and b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi-2560x1440/taxi_p_mogo_live_selected.png differ diff --git a/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi-2560x1440/taxi_p_mogo_movies_title_icon.png b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi-2560x1440/taxi_p_mogo_movies_title_icon.png new file mode 100755 index 0000000000..0768e35563 Binary files /dev/null and b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi-2560x1440/taxi_p_mogo_movies_title_icon.png differ diff --git a/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi-2560x1440/taxi_p_mogo_overview_selected.png b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi-2560x1440/taxi_p_mogo_overview_selected.png new file mode 100755 index 0000000000..9b9730bc83 Binary files /dev/null and b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi-2560x1440/taxi_p_mogo_overview_selected.png differ diff --git a/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi-2560x1440/taxi_p_mogo_video_play.png b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi-2560x1440/taxi_p_mogo_video_play.png new file mode 100755 index 0000000000..7b247d6780 Binary files /dev/null and b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi-2560x1440/taxi_p_mogo_video_play.png differ diff --git a/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi-2560x1440/taxi_p_video_holder.png b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi-2560x1440/taxi_p_video_holder.png new file mode 100644 index 0000000000..99bfcefc6f Binary files /dev/null and b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi-2560x1440/taxi_p_video_holder.png differ diff --git a/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_change_full.png b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_change_full.png new file mode 100644 index 0000000000..d8084f5fce Binary files /dev/null and b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_change_full.png differ diff --git a/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_change_normal.png b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_change_normal.png new file mode 100644 index 0000000000..90f33faa6d Binary files /dev/null and b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_change_normal.png differ diff --git a/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_left_flow_bg.png b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_left_flow_bg.png new file mode 100644 index 0000000000..c4a7c79f53 Binary files /dev/null and b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_left_flow_bg.png differ diff --git a/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_mogo_consult_select.png b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_mogo_consult_select.png new file mode 100755 index 0000000000..b3e4beb228 Binary files /dev/null and b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_mogo_consult_select.png differ diff --git a/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_mogo_consult_selected.png b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_mogo_consult_selected.png new file mode 100755 index 0000000000..207ff8360d Binary files /dev/null and b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_mogo_consult_selected.png differ diff --git a/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_mogo_consult_title_icon.png b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_mogo_consult_title_icon.png new file mode 100755 index 0000000000..55997f4ed2 Binary files /dev/null and b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_mogo_consult_title_icon.png differ diff --git a/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_mogo_entertainment_select.png b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_mogo_entertainment_select.png new file mode 100755 index 0000000000..6ba07fba56 Binary files /dev/null and b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_mogo_entertainment_select.png differ diff --git a/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_mogo_entertainment_selected.png b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_mogo_entertainment_selected.png new file mode 100755 index 0000000000..ba46e204b2 Binary files /dev/null and b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_mogo_entertainment_selected.png differ diff --git a/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_mogo_live_select.png b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_mogo_live_select.png new file mode 100644 index 0000000000..b0436faf24 Binary files /dev/null and b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_mogo_live_select.png differ diff --git a/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_mogo_live_selected.png b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_mogo_live_selected.png new file mode 100755 index 0000000000..7c31031e5b Binary files /dev/null and b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_mogo_live_selected.png differ diff --git a/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_mogo_movies_title_icon.png b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_mogo_movies_title_icon.png new file mode 100755 index 0000000000..0768e35563 Binary files /dev/null and b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_mogo_movies_title_icon.png differ diff --git a/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_mogo_overview_selected.png b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_mogo_overview_selected.png new file mode 100755 index 0000000000..9b9730bc83 Binary files /dev/null and b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_mogo_overview_selected.png differ diff --git a/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_mogo_video_play.png b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_mogo_video_play.png new file mode 100755 index 0000000000..7b247d6780 Binary files /dev/null and b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_mogo_video_play.png differ diff --git a/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_video_holder.png b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_video_holder.png new file mode 100644 index 0000000000..99bfcefc6f Binary files /dev/null and b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_video_holder.png differ diff --git a/OCH/mogo-och-taxi-passenger/src/main/res/drawable/bg_taxi_p_video_bg.xml b/OCH/mogo-och-taxi-passenger/src/main/res/drawable/bg_taxi_p_video_bg.xml new file mode 100644 index 0000000000..af00303b21 --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/res/drawable/bg_taxi_p_video_bg.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/OCH/mogo-och-taxi-passenger/src/main/res/drawable/bg_taxi_p_video_index.xml b/OCH/mogo-och-taxi-passenger/src/main/res/drawable/bg_taxi_p_video_index.xml new file mode 100644 index 0000000000..98435cd0f6 --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/res/drawable/bg_taxi_p_video_index.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/OCH/mogo-och-taxi-passenger/src/main/res/drawable/ic_baseline_arrow_right_24.xml b/OCH/mogo-och-taxi-passenger/src/main/res/drawable/ic_baseline_arrow_right_24.xml new file mode 100644 index 0000000000..b619644073 --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/res/drawable/ic_baseline_arrow_right_24.xml @@ -0,0 +1,6 @@ + + + + diff --git a/OCH/mogo-och-taxi-passenger/src/main/res/drawable/taxi_p_comment_select.xml b/OCH/mogo-och-taxi-passenger/src/main/res/drawable/taxi_p_comment_select.xml new file mode 100644 index 0000000000..8d229a5867 --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/res/drawable/taxi_p_comment_select.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/OCH/mogo-och-taxi-passenger/src/main/res/drawable/taxi_p_comment_selected.xml b/OCH/mogo-och-taxi-passenger/src/main/res/drawable/taxi_p_comment_selected.xml new file mode 100644 index 0000000000..674638b8d0 --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/res/drawable/taxi_p_comment_selected.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/OCH/mogo-och-taxi-passenger/src/main/res/drawable/taxi_p_comment_submit.xml b/OCH/mogo-och-taxi-passenger/src/main/res/drawable/taxi_p_comment_submit.xml new file mode 100644 index 0000000000..bf91236244 --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/res/drawable/taxi_p_comment_submit.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/OCH/mogo-och-taxi-passenger/src/main/res/drawable/taxi_video_seekbar_style.xml b/OCH/mogo-och-taxi-passenger/src/main/res/drawable/taxi_video_seekbar_style.xml new file mode 100644 index 0000000000..d593c74acf --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/res/drawable/taxi_video_seekbar_style.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/OCH/mogo-och-taxi-passenger/src/main/res/layout/list_comment_item.xml b/OCH/mogo-och-taxi-passenger/src/main/res/layout/list_comment_item.xml new file mode 100644 index 0000000000..d8197e2147 --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/res/layout/list_comment_item.xml @@ -0,0 +1,19 @@ + + diff --git a/OCH/mogo-och-taxi-passenger/src/main/res/layout/list_video_item_normal.xml b/OCH/mogo-och-taxi-passenger/src/main/res/layout/list_video_item_normal.xml new file mode 100644 index 0000000000..0d891e27eb --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/res/layout/list_video_item_normal.xml @@ -0,0 +1,5 @@ + + diff --git a/OCH/mogo-och-taxi-passenger/src/main/res/layout/taxi_p_arrived_end_panel.xml b/OCH/mogo-och-taxi-passenger/src/main/res/layout/taxi_p_arrived_end_panel.xml index af88f2d3bc..c3963c55ca 100644 --- a/OCH/mogo-och-taxi-passenger/src/main/res/layout/taxi_p_arrived_end_panel.xml +++ b/OCH/mogo-och-taxi-passenger/src/main/res/layout/taxi_p_arrived_end_panel.xml @@ -37,22 +37,25 @@ app:shadowColor="#80000000" app:shadowRadius="60px" android:visibility="gone" + tools:visibility="visible" app:shadow_position="outer" app:xOffset="0px" app:yOffset="0px"> + + android:layout_height="wrap_content" + android:src="@drawable/taxi_p_arrived_end_light" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent" /> + + + + diff --git a/OCH/mogo-och-taxi-passenger/src/main/res/layout/taxi_p_arrived_mogo_consult.xml b/OCH/mogo-och-taxi-passenger/src/main/res/layout/taxi_p_arrived_mogo_consult.xml new file mode 100644 index 0000000000..31ce000dbb --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/res/layout/taxi_p_arrived_mogo_consult.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/OCH/mogo-och-taxi-passenger/src/main/res/layout/taxi_p_mogo_movies.xml b/OCH/mogo-och-taxi-passenger/src/main/res/layout/taxi_p_mogo_movies.xml new file mode 100644 index 0000000000..6698f08824 --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/res/layout/taxi_p_mogo_movies.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/OCH/mogo-och-taxi-passenger/src/main/res/layout/taxi_p_video_show.xml b/OCH/mogo-och-taxi-passenger/src/main/res/layout/taxi_p_video_show.xml new file mode 100644 index 0000000000..fcd4159d92 --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/res/layout/taxi_p_video_show.xml @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OCH/mogo-och-taxi-passenger/src/main/res/layout/taxi_p_window_float_interphone.xml b/OCH/mogo-och-taxi-passenger/src/main/res/layout/taxi_p_window_float_interphone.xml new file mode 100644 index 0000000000..b78ed99993 --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/res/layout/taxi_p_window_float_interphone.xml @@ -0,0 +1,37 @@ + + + + + + + + + + diff --git a/OCH/mogo-och-taxi-passenger/src/main/res/values/attrs.xml b/OCH/mogo-och-taxi-passenger/src/main/res/values/attrs.xml new file mode 100644 index 0000000000..d77953e0a1 --- /dev/null +++ b/OCH/mogo-och-taxi-passenger/src/main/res/values/attrs.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app_ipc_monitoring/build.gradle b/app_ipc_monitoring/build.gradle index 127666f094..d375607a12 100644 --- a/app_ipc_monitoring/build.gradle +++ b/app_ipc_monitoring/build.gradle @@ -63,14 +63,14 @@ dependencies { implementation rootProject.ext.dependencies.material implementation rootProject.ext.dependencies.androidxconstraintlayout implementation rootProject.ext.dependencies.androidxappcompat - implementation rootProject.ext.dependencies.androidxrecyclerview + implementation "androidx.recyclerview:recyclerview:1.2.0" testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' implementation rootProject.ext.dependencies.gson implementation project(':libraries:mogo-adas') implementation project(':libraries:mogo-adas-other') -// implementation 'com.zhidao.support.adas:high:2.7.0.0' +// implementation 'com.zhidao.support.adas:high:2.8.0.0' // implementation 'com.zhjt.mogo.adas.data:adas-data:2.6.6.0' compileOnly project(':core:mogo-core-data') implementation project(':core:mogo-core-utils') diff --git a/core/function-impl/mogo-core-function-autopilot/src/main/java/com/mogo/eagle/core/function/autopilot/adapter/MoGoAdasListenerImpl.kt b/core/function-impl/mogo-core-function-autopilot/src/main/java/com/mogo/eagle/core/function/autopilot/adapter/MoGoAdasListenerImpl.kt index 7baf14e26f..463aa116f6 100644 --- a/core/function-impl/mogo-core-function-autopilot/src/main/java/com/mogo/eagle/core/function/autopilot/adapter/MoGoAdasListenerImpl.kt +++ b/core/function-impl/mogo-core-function-autopilot/src/main/java/com/mogo/eagle/core/function/autopilot/adapter/MoGoAdasListenerImpl.kt @@ -247,11 +247,11 @@ class MoGoAdasListenerImpl : OnAdasListener { override fun onPointCloud(header: MessagePad.Header?, pointCloud: MogoPointCloudOuterClass.MogoPointCloud?) { //点云数据透传 //Logger.d("pointCloud","pointCloud"+pointCloud); - CallerAutopilotPointCloudListenerManager.invokeAutopilotPointCloudDataUpdate(header,pointCloud) } override fun onPointCloud(pointCloud: ByteArray?) { //点云数据透传 + CallerAutopilotPointCloudListenerManager.invokeAutopilotPointCloudDataUpdate(pointCloud) } //planning障碍物 diff --git a/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/map/MapPointCloudSubscriber.kt b/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/map/MapPointCloudSubscriber.kt index 92b4fa575b..60561f01d9 100644 --- a/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/map/MapPointCloudSubscriber.kt +++ b/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/map/MapPointCloudSubscriber.kt @@ -4,10 +4,8 @@ import com.mogo.eagle.core.data.config.FunctionBuildConfig import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotPointCloudListener import com.mogo.eagle.core.function.api.base.IMoGoSubscriber import com.mogo.eagle.core.function.call.autopilot.CallerAutopilotPointCloudListenerManager -import com.zhidao.support.adas.high.common.PointCloudDecoder +import com.mogo.eagle.core.utilcode.mogo.logger.Logger import com.zhidaoauto.map.sdk.open.business.PointCloudHelper -import mogo.telematics.pad.MessagePad -import rule_segement.MogoPointCloudOuterClass /** * 订阅点云数据 @@ -40,14 +38,16 @@ class MapPointCloudSubscriber private constructor() : IMoGoSubscriber, IMoGoAuto CallerAutopilotPointCloudListenerManager.removeListener(TAG) } - override fun onAutopilotPointCloudDataUpdate(header: MessagePad.Header?, pointCloud: MogoPointCloudOuterClass.MogoPointCloud?) { + override fun onAutopilotPointCloudDataUpdate(pointCloud: ByteArray?) { // 根据配置动态控制点云是否绘制 if (FunctionBuildConfig.isDrawPointCloudData) { if (!isDrawPointCloud) { + Logger.d(TAG, "====开启点云渲染====") isDrawPointCloud = true PointCloudHelper.setIsDrawPointCloud(true)//打开点云绘制 } - val data = PointCloudDecoder.decode(header, pointCloud) + PointCloudHelper.setIsDrawPointCloud(true)//打开点云绘制 + /** * 更新点云数据 @@ -57,13 +57,15 @@ class MapPointCloudSubscriber private constructor() : IMoGoSubscriber, IMoGoAuto * @param isStrong 是否加粗显示 * @return 是否执行 */ - val result = PointCloudHelper.updatePointCloudData(data, false, true, true) + Logger.d(TAG, "====开始传入地图点云数据====") + val result = PointCloudHelper.updatePointCloudDataByPb(pointCloud, false, true, true) + Logger.d(TAG, "====结束传入地图点云数据=====$result") } else { if (isDrawPointCloud) { + Logger.d(TAG, "====停止点云绘制====") isDrawPointCloud = false PointCloudHelper.setIsDrawPointCloud(false)//停止点云绘制 } } - //Logger.d(TAG, "result=$result") } } \ No newline at end of file diff --git a/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/map/identify/IdentifyOriginDataDrawer.kt b/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/map/identify/IdentifyOriginDataDrawer.kt index e39ae44c44..418b0cc439 100644 --- a/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/map/identify/IdentifyOriginDataDrawer.kt +++ b/core/function-impl/mogo-core-function-map/src/main/java/com/mogo/eagle/core/function/map/identify/IdentifyOriginDataDrawer.kt @@ -13,6 +13,7 @@ import mogo.telematics.pad.MessagePad.TrackedObject import java.util.* import java.util.concurrent.ConcurrentHashMap import java.util.function.Consumer +import kotlin.collections.ArrayList /** * @author xiaoyuzhou @@ -52,37 +53,36 @@ class IdentifyOriginDataDrawer : Identify { //todo reset color override fun renderPlanningWarningObj(planningObjects: List?) { -// if (planningObjects == null) { -// if (colorTrafficData.size == 0) { -// return -// } -// colorTrafficData.forEach { -// val cacheData = mMarkersCaches[it] //todo 是否要直接绘制 还是等下一帧 -// if (cacheData != null) { -// mMarkersCaches[it] = cacheData.toBuilder().setColor("#D8D8D8FF").build() -// } -// } -// colorTrafficData.clear() -// return -// } -// val tempTrafficData = ArrayList() -// planningObjects.forEach { -// val trackId = it.uuid.toString() -// val cacheData = mMarkersCaches[trackId] -// if (cacheData != null) { -// colorTrafficData.add(trackId) -// when (it.type) { -// 0 -> { -// tempTrafficData.add(cacheData.toBuilder().setColor("#FF3C45FF").build()) -// } -// 1 -> { -// tempTrafficData.add(cacheData.toBuilder().setColor("#FFD53EFF").build()) -// } -// } -// } -// MogoMarkerManager.getInstance(AbsMogoApplication.getApp()) -// .updateBatchMarkerPosition(tempTrafficData) -// } +// todo test code 用于模拟感知物 +// val resultList: ArrayList = ArrayList() +// val obj = TrackedObject.newBuilder().setUuid(67025).setLongitude(112.57413261072935).setLatitude(26.821571389153718).setHeading(329.9748205834151).setSpeed(0.0).setType(3).build() +// resultList.add(obj) +// renderAdasRecognizedResult(resultList) + + if (planningObjects == null) { + if (colorTrafficData.size == 0) { + return + } + colorTrafficData.forEach { + val cacheData = mMarkersCaches[it] //todo 是否要直接绘制 还是等下一帧 + if (cacheData != null) { + mMarkersCaches[it] = cacheData.toBuilder().setColor("#D8D8D8FF").build() + } + } + colorTrafficData.clear() + return + } + val tempTrafficData = ArrayList() + planningObjects.forEach { + val trackId = it.uuid.toString() + val cacheData = mMarkersCaches[trackId] + if (cacheData != null) { + colorTrafficData.add(trackId) + tempTrafficData.add(cacheData.toBuilder().setColor("#FFD53EFF").build()) + } + MogoMarkerManager.getInstance(AbsMogoApplication.getApp()) + .updateBatchMarkerPosition(tempTrafficData) + } } /** diff --git a/core/mogo-core-function-api/src/main/java/com/mogo/eagle/core/function/api/autopilot/IMoGoAutopilotPointCloudListener.kt b/core/mogo-core-function-api/src/main/java/com/mogo/eagle/core/function/api/autopilot/IMoGoAutopilotPointCloudListener.kt index 3d73c8a06b..6bddda52bf 100644 --- a/core/mogo-core-function-api/src/main/java/com/mogo/eagle/core/function/api/autopilot/IMoGoAutopilotPointCloudListener.kt +++ b/core/mogo-core-function-api/src/main/java/com/mogo/eagle/core/function/api/autopilot/IMoGoAutopilotPointCloudListener.kt @@ -1,7 +1,5 @@ package com.mogo.eagle.core.function.api.autopilot -import mogo.telematics.pad.MessagePad -import rule_segement.MogoPointCloudOuterClass /** * @author xiaoyuzhou @@ -15,6 +13,6 @@ interface IMoGoAutopilotPointCloudListener { * * @param pointCloud 点云数据 */ - fun onAutopilotPointCloudDataUpdate(header: MessagePad.Header?, pointCloud: MogoPointCloudOuterClass.MogoPointCloud?) + fun onAutopilotPointCloudDataUpdate(pointCloud: ByteArray?) } \ No newline at end of file diff --git a/core/mogo-core-function-call/src/main/java/com/mogo/eagle/core/function/call/autopilot/CallerAutopilotPointCloudListenerManager.kt b/core/mogo-core-function-call/src/main/java/com/mogo/eagle/core/function/call/autopilot/CallerAutopilotPointCloudListenerManager.kt index e05b1fd725..60042117c5 100644 --- a/core/mogo-core-function-call/src/main/java/com/mogo/eagle/core/function/call/autopilot/CallerAutopilotPointCloudListenerManager.kt +++ b/core/mogo-core-function-call/src/main/java/com/mogo/eagle/core/function/call/autopilot/CallerAutopilotPointCloudListenerManager.kt @@ -1,12 +1,8 @@ package com.mogo.eagle.core.function.call.autopilot import androidx.annotation.Nullable -import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotIdentifyListener import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotPointCloudListener import com.mogo.eagle.core.function.call.base.CallerBase -import mogo.telematics.pad.MessagePad -import perception.TrafficLightOuterClass -import rule_segement.MogoPointCloudOuterClass import java.util.concurrent.ConcurrentHashMap /** @@ -62,11 +58,11 @@ object CallerAutopilotPointCloudListenerManager : CallerBase() { * 识别交通元素数据发生更新 回调 */ @Synchronized - fun invokeAutopilotPointCloudDataUpdate(header: MessagePad.Header?, pointCloud: MogoPointCloudOuterClass.MogoPointCloud?) { + fun invokeAutopilotPointCloudDataUpdate(pointCloud: ByteArray?) { M_AUTOPILOT_IDENTIFY_LISTENERS.forEach { val tag = it.key val listener = it.value - listener.onAutopilotPointCloudDataUpdate(header,pointCloud) + listener.onAutopilotPointCloudDataUpdate(pointCloud) } } diff --git a/gradle.properties b/gradle.properties index 4b1625c984..5f4228fc7f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -82,7 +82,7 @@ MOGO_LOCATION_VERSION=1.4.3.6 MOGO_TELEMATIC_VERSION=1.4.3.6 ######## MogoAiCloudSDK Version ######## # 自研地图 -MAP_SDK_VERSION=2.2.1.1 +MAP_SDK_VERSION=2.3.0.2 MAP_SDK_OPERATION_VERSION=1.0.13 # websocket WEBSOCKET_VERSION=1.1.7 diff --git a/libraries/mogo-adas-data/src/main/proto/mogo_point_cloud.proto b/libraries/mogo-adas-data/src/main/proto/mogo_point_cloud.proto index 4d2393d46d..7d5013e35d 100644 --- a/libraries/mogo-adas-data/src/main/proto/mogo_point_cloud.proto +++ b/libraries/mogo-adas-data/src/main/proto/mogo_point_cloud.proto @@ -12,6 +12,6 @@ message MogoPointCloud optional double self_roll = 5; optional double self_pitch = 6; optional double self_yaw = 7; - repeated float del_data = 8 [packed=true]; - repeated float add_data = 9 [packed=true]; + repeated uint32 del_data = 8 [packed=true]; + repeated double add_data = 9 [packed=true]; } \ No newline at end of file diff --git a/libraries/mogo-map/src/main/java/com/mogo/map/utils/ObjectUtils.java b/libraries/mogo-map/src/main/java/com/mogo/map/utils/ObjectUtils.java index 6db2022059..7ddd278518 100644 --- a/libraries/mogo-map/src/main/java/com/mogo/map/utils/ObjectUtils.java +++ b/libraries/mogo-map/src/main/java/com/mogo/map/utils/ObjectUtils.java @@ -130,6 +130,9 @@ public class ObjectUtils { markerOptions.setRotateAngle((float) trafficData.getHeading()); markerOptions.setLat(trafficData.getLatitude()); markerOptions.setLon(trafficData.getLongitude()); + if(trafficData.getColor()!=null && !trafficData.getColor().isEmpty()){ + markerOptions.setColor(trafficData.getColor()); + } } catch (Exception e) { e.printStackTrace(); } diff --git a/modules/mogo-module-service/src/main/java/com/mogo/module/service/routeoverlay/RouteOverlayDrawer.java b/modules/mogo-module-service/src/main/java/com/mogo/module/service/routeoverlay/RouteOverlayDrawer.java index df77438030..44fad090b1 100644 --- a/modules/mogo-module-service/src/main/java/com/mogo/module/service/routeoverlay/RouteOverlayDrawer.java +++ b/modules/mogo-module-service/src/main/java/com/mogo/module/service/routeoverlay/RouteOverlayDrawer.java @@ -376,9 +376,9 @@ public class RouteOverlayDrawer { isExcept = true; } long drawEnd = SystemClock.elapsedRealtime(); - Log.d("Route", "draw cost:" + (drawEnd - drawStart) + "ms and isExcept:" + isExcept + "::removeCount:" + removeCount + "::total:" + total); +// Log.d("Route", "draw cost:" + (drawEnd - drawStart) + "ms and isExcept:" + isExcept + "::removeCount:" + removeCount + "::total:" + total); } catch (Throwable t) { - Log.d("Route","error:" + Log.getStackTraceString(t)); +// Log.d("Route","error:" + Log.getStackTraceString(t)); } finally { try { if (isExcept) { @@ -394,7 +394,7 @@ public class RouteOverlayDrawer { } } } catch (Throwable t) { - Log.d("Route", "error2:" + Log.getStackTraceString(t)); +// Log.d("Route", "error2:" + Log.getStackTraceString(t)); } } } @@ -431,10 +431,10 @@ public class RouteOverlayDrawer { // 计算车辆与点之间的夹角 long diffAngle = DrivingDirectionUtils.getDegreeOfCar2Poi2( car_lon, car_lat, lon, lat, car_head); - Log.d("Route", "isPointOnCarFront: angle->" + diffAngle); +// Log.d("Route", "isPointOnCarFront: angle->" + diffAngle); return diffAngle; } finally { - Log.d("Route", "isPointOnCarFront cost:" + (SystemClock.elapsedRealtime() - start) + "ms"); +// Log.d("Route", "isPointOnCarFront cost:" + (SystemClock.elapsedRealtime() - start) + "ms"); } } }