[状态栏]状态栏需求代码提交
[状态栏]网络可访问状态获取
@@ -288,6 +288,10 @@ public class BusPassengerModel {
|
|||||||
|
|
||||||
private final IMoGoAutopilotStatusListener mGoAutopilotStatusListener = new IMoGoAutopilotStatusListener(){
|
private final IMoGoAutopilotStatusListener mGoAutopilotStatusListener = new IMoGoAutopilotStatusListener(){
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAutopilotNotData(long timestamp) {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAutopilotGuardian(@Nullable MogoReportMsg.MogoReportMessage guardianInfo) {
|
public void onAutopilotGuardian(@Nullable MogoReportMsg.MogoReportMessage guardianInfo) {
|
||||||
|
|
||||||
|
|||||||
@@ -277,4 +277,8 @@ public class BusPresenter extends Presenter<BusFragment>
|
|||||||
public void onAutopilotGuardian(MogoReportMsg.MogoReportMessage guardianInfo) {
|
public void onAutopilotGuardian(MogoReportMsg.MogoReportMessage guardianInfo) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAutopilotNotData(long timestamp) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -482,6 +482,11 @@ public class TaxiPassengerModel implements IOCHTaxiPassengerNaviChangedCallback
|
|||||||
|
|
||||||
private final IMoGoAutopilotStatusListener mGoAutopilotStatusListener = new IMoGoAutopilotStatusListener(){
|
private final IMoGoAutopilotStatusListener mGoAutopilotStatusListener = new IMoGoAutopilotStatusListener(){
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAutopilotNotData(long timestamp) {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAutopilotGuardian(@Nullable MogoReportMsg.MogoReportMessage guardianInfo) {
|
public void onAutopilotGuardian(@Nullable MogoReportMsg.MogoReportMessage guardianInfo) {
|
||||||
|
|
||||||
|
|||||||
@@ -1042,6 +1042,10 @@ public class TaxiModel {
|
|||||||
|
|
||||||
private final IMoGoAutopilotStatusListener mGoAutopilotStatusListener = new IMoGoAutopilotStatusListener() {
|
private final IMoGoAutopilotStatusListener mGoAutopilotStatusListener = new IMoGoAutopilotStatusListener() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAutopilotNotData(long timestamp) {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAutopilotGuardian(@Nullable MogoReportMsg.MogoReportMessage guardianInfo) {
|
public void onAutopilotGuardian(@Nullable MogoReportMsg.MogoReportMessage guardianInfo) {
|
||||||
|
|
||||||
|
|||||||
@@ -148,6 +148,11 @@ class MoGoAdasListenerImpl : OnAdasListener {
|
|||||||
CallerAutopilotVehicleStateListenerManager.invokeAutopilotSteeringData(vehicleState.steering)
|
CallerAutopilotVehicleStateListenerManager.invokeAutopilotSteeringData(vehicleState.steering)
|
||||||
//挂挡档位数据
|
//挂挡档位数据
|
||||||
CallerAutopilotVehicleStateListenerManager.invokeAutopilotGearData(vehicleState.gear)
|
CallerAutopilotVehicleStateListenerManager.invokeAutopilotGearData(vehicleState.gear)
|
||||||
|
} else {
|
||||||
|
/**
|
||||||
|
* 底盘没有返回数据
|
||||||
|
*/
|
||||||
|
CallerAutopilotVehicleStateListenerManager.invokeAutopilotNotData(header.timestamp.toLong())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -149,4 +149,8 @@ public class MoGoHandAdasMsgManager implements
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAutopilotNotData(long timestamp) {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.zhjt.mogo_core_function_devatools">
|
package="com.zhjt.mogo_core_function_devatools">
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||||
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
|
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
|
||||||
</manifest>
|
</manifest>
|
||||||
@@ -13,6 +13,7 @@ import com.zhjt.mogo_core_function_devatools.badcase.BadCaseManager
|
|||||||
import com.zhjt.mogo_core_function_devatools.feedback.FeedbackManager
|
import com.zhjt.mogo_core_function_devatools.feedback.FeedbackManager
|
||||||
import com.zhjt.mogo_core_function_devatools.logcatch.MogoLogCatchManager
|
import com.zhjt.mogo_core_function_devatools.logcatch.MogoLogCatchManager
|
||||||
import com.zhjt.mogo_core_function_devatools.scene.SceneManager.Companion.sceneManager
|
import com.zhjt.mogo_core_function_devatools.scene.SceneManager.Companion.sceneManager
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.*
|
||||||
import com.zhjt.mogo_core_function_devatools.trace.TraceManager.Companion.traceManager
|
import com.zhjt.mogo_core_function_devatools.trace.TraceManager.Companion.traceManager
|
||||||
import com.zhjt.mogo_core_function_devatools.upgrade.UpgradeManager.Companion.upgradeManager
|
import com.zhjt.mogo_core_function_devatools.upgrade.UpgradeManager.Companion.upgradeManager
|
||||||
import record_cache.RecordPanelOuterClass
|
import record_cache.RecordPanelOuterClass
|
||||||
@@ -97,4 +98,7 @@ class DevaToolsProvider : IDevaToolsProvider {
|
|||||||
upgradeManager.downLoadPackage(mContext!!, downloadKey,downloadUrl)
|
upgradeManager.downLoadPackage(mContext!!, downloadKey,downloadUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun showStatusBar(ctx: Context) {
|
||||||
|
StatusManager.init(ctx)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -27,7 +27,7 @@ import com.zhjt.mogo_core_function_devatools.badcase.repository.net.api.entity.B
|
|||||||
import com.zhjt.mogo_core_function_devatools.badcase.biz.BadCasePresenter
|
import com.zhjt.mogo_core_function_devatools.badcase.biz.BadCasePresenter
|
||||||
import com.zhjt.mogo_core_function_devatools.badcase.biz.BadCaseView
|
import com.zhjt.mogo_core_function_devatools.badcase.biz.BadCaseView
|
||||||
import com.zhjt.mogo_core_function_devatools.badcase.repository.db.entity.AutoPilotRecord
|
import com.zhjt.mogo_core_function_devatools.badcase.repository.db.entity.AutoPilotRecord
|
||||||
import com.zhjt.mogo_core_function_devatools.ext.pop
|
import com.zhjt.mogo_core_function_devatools.ext.enqueuePop
|
||||||
import com.zhjt.mogo_core_function_devatools.ext.toast
|
import com.zhjt.mogo_core_function_devatools.ext.toast
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.channels.Channel
|
import kotlinx.coroutines.channels.Channel
|
||||||
@@ -263,7 +263,7 @@ internal object BadCaseManager : LifecycleEventObserver {
|
|||||||
val activity = viewHolder?.get()?.context as? FragmentActivity ?: throw IllegalStateException("please ensure context is FragmentActivity.")
|
val activity = viewHolder?.get()?.context as? FragmentActivity ?: throw IllegalStateException("please ensure context is FragmentActivity.")
|
||||||
BadCaseView(activity).also { itx ->
|
BadCaseView(activity).also { itx ->
|
||||||
itx.register(record, onDismiss, onSelect)
|
itx.register(record, onDismiss, onSelect)
|
||||||
activity.pop(itx, 960.PX, WindowManager.LayoutParams.MATCH_PARENT, key = "BadCaseFloatWindow_").also {
|
activity.enqueuePop(itx, 960.PX, WindowManager.LayoutParams.MATCH_PARENT, key = "BadCaseFloatWindow_").also {
|
||||||
hideFloat = it
|
hideFloat = it
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import android.view.animation.AccelerateDecelerateInterpolator
|
|||||||
import android.widget.PopupWindow
|
import android.widget.PopupWindow
|
||||||
import android.widget.PopupWindow.INPUT_METHOD_NEEDED
|
import android.widget.PopupWindow.INPUT_METHOD_NEEDED
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
import androidx.core.view.*
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import com.mogo.eagle.core.utilcode.kotlin.PX
|
import com.mogo.eagle.core.utilcode.kotlin.PX
|
||||||
@@ -26,7 +27,6 @@ import com.mogo.eagle.core.utilcode.kotlin.shape
|
|||||||
import com.mogo.eagle.core.utilcode.reminder.Reminder
|
import com.mogo.eagle.core.utilcode.reminder.Reminder
|
||||||
import com.mogo.eagle.core.utilcode.reminder.api.impl.PopupWindowReminder
|
import com.mogo.eagle.core.utilcode.reminder.api.impl.PopupWindowReminder
|
||||||
import com.mogo.eagle.core.utilcode.util.BarUtils
|
import com.mogo.eagle.core.utilcode.util.BarUtils
|
||||||
import com.mogo.eagle.core.utilcode.util.WindowUtils
|
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
@@ -67,7 +67,7 @@ internal fun Context.toast(text: CharSequence, duration: Long = 2, unit: TimeUni
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
internal fun Context.pop(content: View, width: Int, height: Int, key: String, onOuterViewClicked:((focus: View) -> Unit)? = null): () -> Unit {
|
fun Context.enqueuePop(content: View, width: Int, height: Int, key: String = "", startX: Int = 0, startY: Int = 0, gravity: Int = Gravity.START, onOuterViewClicked:((focus: View) -> Unit)? = null, isOverride: Boolean = false, isFocusable: Boolean = true): () -> Unit {
|
||||||
val activity = (this as? FragmentActivity) ?: throw IllegalStateException("please use Activity to trigger pop show.")
|
val activity = (this as? FragmentActivity) ?: throw IllegalStateException("please use Activity to trigger pop show.")
|
||||||
val isImmersiveMode = BarUtils.isImmersiveMode(activity)
|
val isImmersiveMode = BarUtils.isImmersiveMode(activity)
|
||||||
var tempReminder: PopupWindowReminder? = null
|
var tempReminder: PopupWindowReminder? = null
|
||||||
@@ -75,11 +75,11 @@ internal fun Context.pop(content: View, width: Int, height: Int, key: String, on
|
|||||||
val pop = PopupWindow(width, height).also {
|
val pop = PopupWindow(width, height).also {
|
||||||
it.isOutsideTouchable = true
|
it.isOutsideTouchable = true
|
||||||
it.isTouchable = true
|
it.isTouchable = true
|
||||||
it.isFocusable = true
|
it.isFocusable = isFocusable
|
||||||
it.inputMethodMode = INPUT_METHOD_NEEDED
|
it.inputMethodMode = INPUT_METHOD_NEEDED
|
||||||
it.isClippingEnabled = false
|
it.isClippingEnabled = false
|
||||||
var startX = 0f
|
var x = 0f
|
||||||
var startY = 0f
|
var y = 0f
|
||||||
val touchSlop = ViewConfiguration.get(activity).scaledTouchSlop
|
val touchSlop = ViewConfiguration.get(activity).scaledTouchSlop
|
||||||
var isClicked = false
|
var isClicked = false
|
||||||
it.setTouchInterceptor { v, event ->
|
it.setTouchInterceptor { v, event ->
|
||||||
@@ -91,12 +91,12 @@ internal fun Context.pop(content: View, width: Int, height: Int, key: String, on
|
|||||||
|
|
||||||
when(event.actionMasked) {
|
when(event.actionMasked) {
|
||||||
MotionEvent.ACTION_DOWN -> {
|
MotionEvent.ACTION_DOWN -> {
|
||||||
startX = event.x
|
x = event.x
|
||||||
startY = event.y
|
y = event.y
|
||||||
}
|
}
|
||||||
MotionEvent.ACTION_MOVE -> {
|
MotionEvent.ACTION_MOVE -> {
|
||||||
val deltaX = event.x - startX
|
val deltaX = event.x - x
|
||||||
val deltaY = event.y - startY
|
val deltaY = event.y - y
|
||||||
isClicked = !(abs(deltaX) > touchSlop || abs(deltaY) > touchSlop)
|
isClicked = !(abs(deltaX) > touchSlop || abs(deltaY) > touchSlop)
|
||||||
}
|
}
|
||||||
MotionEvent.ACTION_UP -> {
|
MotionEvent.ACTION_UP -> {
|
||||||
@@ -115,7 +115,7 @@ internal fun Context.pop(content: View, width: Int, height: Int, key: String, on
|
|||||||
it.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
|
it.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
|
||||||
}
|
}
|
||||||
if (VERSION.SDK_INT >= VERSION_CODES.M) {
|
if (VERSION.SDK_INT >= VERSION_CODES.M) {
|
||||||
val transition = Slide(Gravity.START).also {
|
val transition = Slide(gravity).also {
|
||||||
it.interpolator = AccelerateDecelerateInterpolator()
|
it.interpolator = AccelerateDecelerateInterpolator()
|
||||||
it.duration = 200
|
it.duration = 200
|
||||||
}
|
}
|
||||||
@@ -130,9 +130,9 @@ internal fun Context.pop(content: View, width: Int, height: Int, key: String, on
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun show() {
|
override fun show() {
|
||||||
pop.showAtLocation(activity.window.decorView, Gravity.START, 0, if (isImmersiveMode) 0 else BarUtils.getStatusBarHeight())
|
pop.showAtLocation(activity.window.decorView, gravity, startX, if (isImmersiveMode) 0 else BarUtils.getStatusBarHeight() + startY)
|
||||||
}
|
}
|
||||||
override fun isOverride(): Boolean = false
|
override fun isOverride(): Boolean = isOverride
|
||||||
}
|
}
|
||||||
tempReminder = reminder
|
tempReminder = reminder
|
||||||
Reminder.enqueue(activity.lifeCycleOwner, reminder)
|
Reminder.enqueue(activity.lifeCycleOwner, reminder)
|
||||||
@@ -142,6 +142,94 @@ internal fun Context.pop(content: View, width: Int, height: Int, key: String, on
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
|
fun Context.normalPop(content: View, width: Int, height: Int, key: String = "", startX: Int = 0, startY: Int = 0, gravity: Int = Gravity.START, onOuterViewClicked:((focus: View) -> Unit)? = null, isFocusable: Boolean = true): () -> Unit {
|
||||||
|
val activity = (this as? FragmentActivity) ?: throw IllegalStateException("please use Activity to trigger pop show.")
|
||||||
|
val isImmersiveMode = BarUtils.isImmersiveMode(activity)
|
||||||
|
var tempPop: PopupWindow? = null
|
||||||
|
activity.lifecycleScope.launchWhenResumed {
|
||||||
|
val pop = PopupWindow(width, height).also {
|
||||||
|
tempPop = it
|
||||||
|
it.isOutsideTouchable = true
|
||||||
|
it.isTouchable = true
|
||||||
|
it.isFocusable = isFocusable
|
||||||
|
it.inputMethodMode = INPUT_METHOD_NEEDED
|
||||||
|
it.isClippingEnabled = false
|
||||||
|
var x = 0f
|
||||||
|
var y = 0f
|
||||||
|
val touchSlop = ViewConfiguration.get(activity).scaledTouchSlop
|
||||||
|
var isClicked = false
|
||||||
|
it.setTouchInterceptor { v, event ->
|
||||||
|
val out = Rect()
|
||||||
|
v.getGlobalVisibleRect(out)
|
||||||
|
if (out.contains(event.x.toInt(), event.y.toInt()) && isVisibleOnPoint(content, event.x.toInt(), event.y.toInt())) {
|
||||||
|
return@setTouchInterceptor false
|
||||||
|
}
|
||||||
|
|
||||||
|
when(event.actionMasked) {
|
||||||
|
MotionEvent.ACTION_DOWN -> {
|
||||||
|
x = event.x
|
||||||
|
y = event.y
|
||||||
|
}
|
||||||
|
MotionEvent.ACTION_MOVE -> {
|
||||||
|
val deltaX = event.x - x
|
||||||
|
val deltaY = event.y - y
|
||||||
|
isClicked = !(abs(deltaX) > touchSlop || abs(deltaY) > touchSlop)
|
||||||
|
}
|
||||||
|
MotionEvent.ACTION_UP -> {
|
||||||
|
if (isClicked) {
|
||||||
|
isClicked = false
|
||||||
|
onOuterViewClicked?.invoke(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return@setTouchInterceptor true
|
||||||
|
} finally {
|
||||||
|
activity.window.decorView.dispatchTouchEvent(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
it.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
|
||||||
|
}
|
||||||
|
if (VERSION.SDK_INT >= VERSION_CODES.M) {
|
||||||
|
val transition = Slide(gravity).also {
|
||||||
|
it.interpolator = AccelerateDecelerateInterpolator()
|
||||||
|
it.duration = 200
|
||||||
|
}
|
||||||
|
pop.enterTransition = transition
|
||||||
|
pop.exitTransition = transition
|
||||||
|
}
|
||||||
|
pop.contentView = content
|
||||||
|
pop.showAtLocation(activity.window.decorView, gravity, startX, if (isImmersiveMode) 0 else BarUtils.getStatusBarHeight() + startY)
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
tempPop?.takeIf { it.isShowing }?.dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isVisibleOnPoint(content: View, x: Int, y: Int): Boolean {
|
||||||
|
if (content is ViewGroup) {
|
||||||
|
for (i in 0 until content.childCount) {
|
||||||
|
val child = content.getChildAt(i)
|
||||||
|
val out = Rect()
|
||||||
|
child.getGlobalVisibleRect(out)
|
||||||
|
if (out.contains(x, y) && !child.isVisible) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
val ret = isVisibleOnPoint(child, x, y)
|
||||||
|
if (!ret) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
val out = Rect()
|
||||||
|
content.getGlobalVisibleRect(out)
|
||||||
|
return !(out.contains(x, y) && !content.isVisible)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal fun FragmentActivity.softKeyboardHeightChanged(block: ((height: Int) -> Unit)): ()-> Unit {
|
internal fun FragmentActivity.softKeyboardHeightChanged(block: ((height: Int) -> Unit)): ()-> Unit {
|
||||||
val decor = window.decorView
|
val decor = window.decorView
|
||||||
var softKeyboardDisplayed = false
|
var softKeyboardDisplayed = false
|
||||||
@@ -25,7 +25,7 @@ import com.zhjt.mogo_core_function_devatools.R
|
|||||||
import com.zhjt.mogo_core_function_devatools.badcase.repository.db.entity.AutoPilotRecord
|
import com.zhjt.mogo_core_function_devatools.badcase.repository.db.entity.AutoPilotRecord
|
||||||
import com.zhjt.mogo_core_function_devatools.badcase.repository.net.api.entity.BadCaseResponse.Reason
|
import com.zhjt.mogo_core_function_devatools.badcase.repository.net.api.entity.BadCaseResponse.Reason
|
||||||
import com.zhjt.mogo_core_function_devatools.badcase.toRecord
|
import com.zhjt.mogo_core_function_devatools.badcase.toRecord
|
||||||
import com.zhjt.mogo_core_function_devatools.ext.pop
|
import com.zhjt.mogo_core_function_devatools.ext.enqueuePop
|
||||||
import com.zhjt.mogo_core_function_devatools.ext.toast
|
import com.zhjt.mogo_core_function_devatools.ext.toast
|
||||||
import com.zhjt.mogo_core_function_devatools.feedback.biz.FeedBackView
|
import com.zhjt.mogo_core_function_devatools.feedback.biz.FeedBackView
|
||||||
import com.zhjt.mogo_core_function_devatools.feedback.biz.bean.Feedback.BadCase
|
import com.zhjt.mogo_core_function_devatools.feedback.biz.bean.Feedback.BadCase
|
||||||
@@ -46,7 +46,7 @@ internal object FeedbackManager {
|
|||||||
|
|
||||||
fun showFeedbackWindow(ctx: Context) {
|
fun showFeedbackWindow(ctx: Context) {
|
||||||
val activity = ctx as? FragmentActivity ?: throw IllegalStateException("please ensure context is FragmentActivity.")
|
val activity = ctx as? FragmentActivity ?: throw IllegalStateException("please ensure context is FragmentActivity.")
|
||||||
activity.pop(FeedBackView(ctx).also { itx ->
|
activity.enqueuePop(FeedBackView(ctx).also { itx ->
|
||||||
itx.registerCallback(object : IFeedbackCallback {
|
itx.registerCallback(object : IFeedbackCallback {
|
||||||
override fun onClose(v: View) {
|
override fun onClose(v: View) {
|
||||||
KeyboardUtils.hideSoftInput(v)
|
KeyboardUtils.hideSoftInput(v)
|
||||||
|
|||||||
@@ -0,0 +1,99 @@
|
|||||||
|
package com.zhjt.mogo_core_function_devatools.status
|
||||||
|
|
||||||
|
import android.content.*
|
||||||
|
import android.util.*
|
||||||
|
import android.view.*
|
||||||
|
import androidx.core.view.*
|
||||||
|
import androidx.lifecycle.*
|
||||||
|
import androidx.lifecycle.Lifecycle.Event
|
||||||
|
import androidx.lifecycle.Lifecycle.Event.ON_CREATE
|
||||||
|
import androidx.lifecycle.Lifecycle.Event.ON_DESTROY
|
||||||
|
import com.mogo.eagle.core.utilcode.kotlin.*
|
||||||
|
import com.zhjt.mogo_core_function_devatools.ext.*
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.entity.*
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.entity.CanStatus
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.entity.GpsStatus
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.entity.IpcStatus
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.entity.NetStatus
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.entity.RTKStatus
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.entity.Status
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.entity.TracingStatus
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.model.StatusModel
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.flow.IFlow
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.flow.can.CanImpl
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.flow.gps.GpsImpl
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.flow.ipc.IpcImpl
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.flow.nets.NetsImpl
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.flow.rtk.*
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.flow.rtk.RTKImpl
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.flow.trace.TracingImpl
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.ui.*
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
import kotlinx.coroutines.flow.*
|
||||||
|
|
||||||
|
object StatusManager {
|
||||||
|
|
||||||
|
private lateinit var model: StatusModel
|
||||||
|
|
||||||
|
private var hidePop: (() -> Unit)? = null
|
||||||
|
|
||||||
|
private val flows: ArrayList<IFlow<out Status>> by lazy {
|
||||||
|
ArrayList()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun init(ctx: Context) {
|
||||||
|
val owner = ctx as? ViewModelStoreOwner ?: throw IllegalStateException("ctx: $ctx is a instance of ViewModelStoreOwner.")
|
||||||
|
model = ViewModelProvider(owner).get(StatusModel::class.java)
|
||||||
|
ctx.lifeCycleOwner.lifecycle.addObserver(object : LifecycleEventObserver {
|
||||||
|
override fun onStateChanged(source: LifecycleOwner, event: Event) {
|
||||||
|
if (event == ON_CREATE) {
|
||||||
|
onCreate(ctx)
|
||||||
|
}
|
||||||
|
if (event == ON_DESTROY) {
|
||||||
|
onDestroy(ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onCreate(ctx: Context) {
|
||||||
|
val values = model.status.value?.second ?: throw IllegalStateException("state is not right.")
|
||||||
|
values.map {
|
||||||
|
when (it) {
|
||||||
|
is CanStatus -> CanImpl(ctx)
|
||||||
|
is IpcStatus -> IpcImpl(ctx)
|
||||||
|
is NetStatus -> NetsImpl(ctx)
|
||||||
|
is GpsStatus -> GpsImpl(ctx)
|
||||||
|
is TracingStatus -> TracingImpl(ctx)
|
||||||
|
is RTKStatus -> RTKImpl(ctx)
|
||||||
|
}
|
||||||
|
}.also { flows += it }
|
||||||
|
for (f in flows) {
|
||||||
|
ctx.lifeCycleScope.launch(Dispatchers.Default) {
|
||||||
|
f.asFlow().collect {
|
||||||
|
model.update(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hidePop?.invoke()
|
||||||
|
val content = StatusView(model, ctx)
|
||||||
|
content.doOnAttach {
|
||||||
|
Log.d("OOOO", "--- onAttach -----")
|
||||||
|
for (f in flows) {
|
||||||
|
f.onCreate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.normalPop(content,
|
||||||
|
width = 665.PX,
|
||||||
|
height = WindowManager.LayoutParams.WRAP_CONTENT,
|
||||||
|
gravity = Gravity.END,
|
||||||
|
startX = 55.PX,
|
||||||
|
isFocusable = false).also { hidePop = it }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onDestroy(ctx: Context) {
|
||||||
|
flows.clear()
|
||||||
|
hidePop?.invoke()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,191 @@
|
|||||||
|
package com.zhjt.mogo_core_function_devatools.status.entity
|
||||||
|
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.entity.TracingStatus.Tracing
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.entity.TracingStatus.Tracing.*
|
||||||
|
|
||||||
|
internal sealed class Status
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 工控机
|
||||||
|
*/
|
||||||
|
internal class IpcStatus(val enabled: Boolean = false): Status() {
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
other as IpcStatus
|
||||||
|
if (enabled != other.enabled) return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
return enabled.hashCode()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "IpcStatus(enabled=$enabled)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class NetStatus(val enabled: Boolean = false, val name: String? = null, val speed: Speed? = null): Status() {
|
||||||
|
class Speed(val tx: Int, val rx: Int) {
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "Speed(tx=$tx, rx=$rx)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
other as NetStatus
|
||||||
|
if (enabled != other.enabled) return false
|
||||||
|
if (name != other.name) return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
var result = enabled.hashCode()
|
||||||
|
result = 31 * result + (name?.hashCode() ?: 0)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "NetStatus(enabled=$enabled, name=$name, speed=$speed)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* android系统定位状态
|
||||||
|
*/
|
||||||
|
internal class GpsStatus(val enabled: Boolean = false, val isGranted: Boolean = false): Status() {
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
|
||||||
|
other as GpsStatus
|
||||||
|
if (enabled != other.enabled) return false
|
||||||
|
if (isGranted != other.isGranted) return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
var result = enabled.hashCode()
|
||||||
|
result = 31 * result + isGranted.hashCode()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "GpsStatus(enabled=$enabled, isGranted=$isGranted)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RTK/GNSS定位状态
|
||||||
|
*/
|
||||||
|
internal class RTKStatus(val enabled: Boolean = false): Status() {
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
other as RTKStatus
|
||||||
|
if (enabled != other.enabled) return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
return enabled.hashCode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Can总线
|
||||||
|
*/
|
||||||
|
internal class CanStatus(val enabled: Boolean = false): Status() {
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
other as CanStatus
|
||||||
|
if (enabled != other.enabled) return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
return enabled.hashCode()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "CanStatus(enabled=$enabled)"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 寻迹/算路/未知
|
||||||
|
*/
|
||||||
|
internal class TracingStatus(val state: Tracing): Status() {
|
||||||
|
|
||||||
|
enum class Tracing(val code: String? = "") {
|
||||||
|
/**
|
||||||
|
* 寻迹-已找到轨迹文件
|
||||||
|
*/
|
||||||
|
TRACK_FINDED("IMAP_TRA_EXIST"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 寻迹-轨迹文件加载成功
|
||||||
|
*/
|
||||||
|
TRACK_LOADED("IMAP_TRA_LOADED"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 寻迹-没有找到轨迹文件
|
||||||
|
*/
|
||||||
|
TRACK_NOT_EXIST("EMAP_TRA_NOT_EXIST"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 寻迹-找到了轨迹文件,加载失败了
|
||||||
|
*/
|
||||||
|
TRACK_LOAD_FAIL("EMAP_TRA_LOAD_FAILED"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 算路加载成功
|
||||||
|
*/
|
||||||
|
ROUTE_LOADED("IMAP_TRA_ROUTING"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 算路失败
|
||||||
|
*/
|
||||||
|
ROUTE_FAILED("EMAP_HADMAP_ENGINE_NO_ROUTING_INFO"),
|
||||||
|
|
||||||
|
UNKNOWN;
|
||||||
|
|
||||||
|
fun isException(): Boolean = this == TRACK_FINDED || this == TRACK_NOT_EXIST || this == TRACK_LOAD_FAIL || this == ROUTE_FAILED || this == UNKNOWN
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "TracingStatus(state=$state)"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
|
||||||
|
other as TracingStatus
|
||||||
|
|
||||||
|
if (state != other.state) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
return state.hashCode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun String.toState(): Tracing {
|
||||||
|
return when(this) {
|
||||||
|
"IMAP_TRA_EXIST" -> TRACK_FINDED
|
||||||
|
"IMAP_TRA_LOADED" -> TRACK_LOADED
|
||||||
|
"EMAP_TRA_NOT_EXIST" -> TRACK_NOT_EXIST
|
||||||
|
"EMAP_TRA_LOAD_FAILED" -> TRACK_LOAD_FAIL
|
||||||
|
"IMAP_TRA_ROUTING" -> ROUTE_LOADED
|
||||||
|
"EMAP_HADMAP_ENGINE_NO_ROUTING_INFO" -> ROUTE_FAILED
|
||||||
|
else -> UNKNOWN
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package com.zhjt.mogo_core_function_devatools.status.flow
|
||||||
|
|
||||||
|
import android.content.*
|
||||||
|
import android.util.*
|
||||||
|
import androidx.annotation.*
|
||||||
|
import com.mogo.eagle.core.utilcode.kotlin.*
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.entity.Status
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
import kotlinx.coroutines.channels.*
|
||||||
|
import kotlinx.coroutines.channels.Channel.Factory.CONFLATED
|
||||||
|
import kotlinx.coroutines.flow.*
|
||||||
|
import kotlin.OptIn
|
||||||
|
import kotlin.coroutines.*
|
||||||
|
|
||||||
|
internal abstract class IFlow< T : Status>(val ctx: Context) : CoroutineScope {
|
||||||
|
|
||||||
|
private val chl: Channel<T> by lazy {
|
||||||
|
Channel(CONFLATED)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Volatile
|
||||||
|
private var old: T? = null
|
||||||
|
|
||||||
|
override val coroutineContext: CoroutineContext
|
||||||
|
get() = ctx.lifeCycleScope.coroutineContext
|
||||||
|
|
||||||
|
abstract fun onCreate()
|
||||||
|
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
fun asFlow(): Flow<T> = channelFlow {
|
||||||
|
val it = chl.iterator()
|
||||||
|
while (it.hasNext()) {
|
||||||
|
send(it.next())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun send(t: T) {
|
||||||
|
if (old == t) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
old = t
|
||||||
|
launch {
|
||||||
|
chl.send(t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@CallSuper
|
||||||
|
open fun onDestroy() {
|
||||||
|
chl.safeCancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package com.zhjt.mogo_core_function_devatools.status.flow.can
|
||||||
|
|
||||||
|
import android.content.*
|
||||||
|
import android.util.*
|
||||||
|
import chassis.Chassis.GearPosition
|
||||||
|
import chassis.Chassis.LightSwitch
|
||||||
|
import com.mogo.eagle.core.data.autopilot.*
|
||||||
|
import com.mogo.eagle.core.function.api.autopilot.*
|
||||||
|
import com.mogo.eagle.core.function.call.autopilot.*
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.flow.IFlow
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.entity.CanStatus
|
||||||
|
|
||||||
|
internal class CanImpl(ctx: Context): IFlow<CanStatus>(ctx), IMoGoAutopilotVehicleStateListener, IMoGoAutopilotStatusListener {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TAG = "CanImpl"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate() {
|
||||||
|
Log.d(TAG, "-- onCreate --")
|
||||||
|
send(CanStatus(false))
|
||||||
|
CallerAutopilotVehicleStateListenerManager.addListener(TAG, this)
|
||||||
|
CallerAutoPilotStatusListenerManager.addListener(TAG, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAutopilotStatusResponse(autoPilotStatusInfo: AutopilotStatusInfo) {
|
||||||
|
super.onAutopilotStatusResponse(autoPilotStatusInfo)
|
||||||
|
if (!CallerAutoPilotManager.isConnected()) {
|
||||||
|
send(CanStatus(false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAutopilotLightSwitchData(lightSwitch: LightSwitch?) {
|
||||||
|
send(CanStatus(true))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAutopilotBrakeLightData(brakeLight: Boolean) {
|
||||||
|
send(CanStatus(true))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAutopilotSteeringData(steering: Float) {
|
||||||
|
send(CanStatus(true))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAutopilotGearData(gear: GearPosition) {
|
||||||
|
send(CanStatus(true))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAutopilotNotData(timestamp: Long) {
|
||||||
|
send(CanStatus(false))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
Log.d(TAG, "-- onDestroy --")
|
||||||
|
CallerAutoPilotStatusListenerManager.removeListener(TAG)
|
||||||
|
CallerAutoPilotStatusListenerManager.removeListener(TAG)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
package com.zhjt.mogo_core_function_devatools.status.flow.gps
|
||||||
|
|
||||||
|
import android.*
|
||||||
|
import android.content.*
|
||||||
|
import android.location.*
|
||||||
|
import android.util.*
|
||||||
|
import androidx.core.location.*
|
||||||
|
import com.mogo.eagle.core.utilcode.util.*
|
||||||
|
import com.mogo.eagle.core.utilcode.util.PermissionUtils.SimpleCallback
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.flow.IFlow
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.entity.GpsStatus
|
||||||
|
import java.util.concurrent.atomic.*
|
||||||
|
|
||||||
|
internal class GpsImpl(ctx: Context): IFlow<GpsStatus>(ctx) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TAG = "RTKImpl"
|
||||||
|
}
|
||||||
|
|
||||||
|
private val registered = AtomicBoolean(false)
|
||||||
|
|
||||||
|
private var receiver: CheckLocationReceiver? = null
|
||||||
|
|
||||||
|
inner class CheckLocationReceiver(private val onClose: ()->Unit, private val onOpen:()-> Unit) : BroadcastReceiver() {
|
||||||
|
|
||||||
|
override fun onReceive(context: Context?, intent: Intent?) {
|
||||||
|
if (intent?.action == LocationManager.MODE_CHANGED_ACTION) {
|
||||||
|
if (isLocationEnabled()) {
|
||||||
|
onOpen.invoke()
|
||||||
|
} else {
|
||||||
|
onClose.invoke()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val onClose = {
|
||||||
|
send(false, PermissionUtils.isGranted(Manifest.permission.ACCESS_FINE_LOCATION))
|
||||||
|
}
|
||||||
|
|
||||||
|
private val onOpen = {
|
||||||
|
send(true, PermissionUtils.isGranted(Manifest.permission.ACCESS_FINE_LOCATION))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate() {
|
||||||
|
val isGranted = PermissionUtils.isGranted(Manifest.permission.ACCESS_FINE_LOCATION)
|
||||||
|
send(isLocationEnabled(), isGranted)
|
||||||
|
if (!isGranted) {
|
||||||
|
PermissionUtils.requestAccessFineLocation(object : SimpleCallback {
|
||||||
|
override fun onGranted() {
|
||||||
|
Log.d(TAG,"权限: ${Manifest.permission.ACCESS_FINE_LOCATION} 被授予了....")
|
||||||
|
send(enabled = isLocationEnabled(), isGranted = false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDenied() {
|
||||||
|
ToastUtils.showShort("定位权限被拒绝, 可能导致RTK定位不准确,请开启~")
|
||||||
|
send(enabled = isLocationEnabled(), isGranted = false)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (registered.compareAndSet(false, true)) {
|
||||||
|
ctx.registerReceiver(CheckLocationReceiver(onClose, onOpen).also { receiver = it }, IntentFilter().also { it.addAction(LocationManager.MODE_CHANGED_ACTION) })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isLocationEnabled() =
|
||||||
|
LocationManagerCompat.isLocationEnabled(ctx.getSystemService(Context.LOCATION_SERVICE) as LocationManager)
|
||||||
|
|
||||||
|
private fun send(enabled: Boolean, isGranted: Boolean) {
|
||||||
|
send(GpsStatus(enabled, isGranted))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
try {
|
||||||
|
if (registered.compareAndSet(true, false) && receiver != null) {
|
||||||
|
ctx.unregisterReceiver(receiver)
|
||||||
|
}
|
||||||
|
} catch (t: Throwable) {
|
||||||
|
t.printStackTrace()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package com.zhjt.mogo_core_function_devatools.status.flow.ipc
|
||||||
|
|
||||||
|
import android.content.*
|
||||||
|
import android.util.*
|
||||||
|
import com.mogo.eagle.core.data.autopilot.*
|
||||||
|
import com.mogo.eagle.core.function.api.autopilot.*
|
||||||
|
import com.mogo.eagle.core.function.call.autopilot.*
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.flow.IFlow
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.entity.IpcStatus
|
||||||
|
|
||||||
|
internal class IpcImpl(ctx: Context): IFlow<IpcStatus>(ctx), IMoGoAutopilotStatusListener {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TAG = "IpcImpl"
|
||||||
|
}
|
||||||
|
|
||||||
|
private var state: Int = -1
|
||||||
|
|
||||||
|
override fun onCreate() {
|
||||||
|
Log.d(TAG, "-- onCreate --")
|
||||||
|
checkAndSend()
|
||||||
|
CallerAutoPilotStatusListenerManager.addListener(TAG, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun onAutopilotStatusResponse(autoPilotStatusInfo: AutopilotStatusInfo) {
|
||||||
|
super.onAutopilotStatusResponse(autoPilotStatusInfo)
|
||||||
|
Log.d(TAG, "-- onAutopilotStatusResponse -- state: ${autoPilotStatusInfo.state}")
|
||||||
|
if (state != autoPilotStatusInfo.state) {
|
||||||
|
checkAndSend()
|
||||||
|
state = autoPilotStatusInfo.state
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkAndSend() {
|
||||||
|
Log.d(TAG, "-- checkAndSend --")
|
||||||
|
send(IpcStatus(CallerAutoPilotManager.isConnected()))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
Log.d(TAG, "-- onDestroy --")
|
||||||
|
CallerAutoPilotStatusListenerManager.removeListener(TAG)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
package com.zhjt.mogo_core_function_devatools.status.flow.nets
|
||||||
|
|
||||||
|
import android.content.*
|
||||||
|
import android.net.*
|
||||||
|
import android.net.wifi.*
|
||||||
|
import android.os.Build.VERSION
|
||||||
|
import android.os.Build.VERSION_CODES
|
||||||
|
import android.util.*
|
||||||
|
import com.mogo.eagle.core.utilcode.kotlin.*
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.flow.IFlow
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.entity.NetStatus
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.entity.NetStatus.Speed
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
import java.util.concurrent.atomic.*
|
||||||
|
|
||||||
|
internal class NetsImpl(ctx: Context): IFlow<NetStatus>(ctx) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TAG = "NetsImpl"
|
||||||
|
}
|
||||||
|
|
||||||
|
private val registered = AtomicBoolean(false)
|
||||||
|
|
||||||
|
private val connectMgr by lazy {
|
||||||
|
ctx.applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||||
|
}
|
||||||
|
|
||||||
|
private val wifiMgr by lazy {
|
||||||
|
ctx.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
|
||||||
|
}
|
||||||
|
|
||||||
|
private val cb = object : ConnectivityManager.NetworkCallback() {
|
||||||
|
|
||||||
|
override fun onAvailable(network: Network) {
|
||||||
|
super.onAvailable(network)
|
||||||
|
Log.d(TAG, "-- onAvailable --:: $network")
|
||||||
|
checkAndSend()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onLosing(network: Network, maxMsToLive: Int) {
|
||||||
|
super.onLosing(network, maxMsToLive)
|
||||||
|
Log.d(TAG, "-- onLosing --:: $network::$maxMsToLive")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onLost(network: Network) {
|
||||||
|
super.onLost(network)
|
||||||
|
Log.d(TAG, "-- onLost --:: $network")
|
||||||
|
checkAndSend()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onUnavailable() {
|
||||||
|
super.onUnavailable()
|
||||||
|
Log.d(TAG, "-- onUnavailable --")
|
||||||
|
checkAndSend()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCapabilitiesChanged(network: Network, networkCapabilities: NetworkCapabilities) {
|
||||||
|
super.onCapabilitiesChanged(network, networkCapabilities)
|
||||||
|
Log.d(TAG, "-- onCapabilitiesChanged --:$network::$networkCapabilities")
|
||||||
|
checkAndSend()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onLinkPropertiesChanged(network: Network, linkProperties: LinkProperties) {
|
||||||
|
super.onLinkPropertiesChanged(network, linkProperties)
|
||||||
|
Log.d(TAG, "-- onLinkPropertiesChanged --:$network::$linkProperties")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBlockedStatusChanged(network: Network, blocked: Boolean) {
|
||||||
|
super.onBlockedStatusChanged(network, blocked)
|
||||||
|
Log.d(TAG, "-- onBlockedStatusChanged --:$network::$blocked")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun onCreate() {
|
||||||
|
Log.d(TAG, "-- onCreate --")
|
||||||
|
checkAndSend()
|
||||||
|
val builder = NetworkRequest.Builder()
|
||||||
|
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
|
||||||
|
if (VERSION.SDK_INT >= VERSION_CODES.O) {
|
||||||
|
builder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI_AWARE)
|
||||||
|
}
|
||||||
|
if (registered.compareAndSet(false, true)) {
|
||||||
|
connectMgr.registerNetworkCallback(builder.build(), cb)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var loopCheckAndSendJob: Job? = null
|
||||||
|
|
||||||
|
private fun checkAndSend() {
|
||||||
|
val connectionInfo = wifiMgr.connectionInfo
|
||||||
|
val enabled = isNetConnected()
|
||||||
|
val name = connectionInfo.ssid?.replace(Regex("[\\W]"), "")
|
||||||
|
loopCheckAndSendJob?.safeCancel()
|
||||||
|
launch(Dispatchers.Default) { delay(1000); checkAndSend() }.also { loopCheckAndSendJob = it }
|
||||||
|
var tr = 0
|
||||||
|
if (VERSION.SDK_INT >= VERSION_CODES.Q) {
|
||||||
|
tr = connectionInfo.txLinkSpeedMbps
|
||||||
|
}
|
||||||
|
var sr = 0
|
||||||
|
if (VERSION.SDK_INT >= VERSION_CODES.Q) {
|
||||||
|
sr = connectionInfo.rxLinkSpeedMbps
|
||||||
|
}
|
||||||
|
val speed = Speed(tr, sr)
|
||||||
|
Log.d(TAG, "checkAndSend----:enable: $enabled :: name: $name")
|
||||||
|
send(enabled, name, speed)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun isNetConnected(): Boolean =
|
||||||
|
if (VERSION.SDK_INT >= VERSION_CODES.M) {
|
||||||
|
val networkCapabilities = connectMgr.getNetworkCapabilities(connectMgr.activeNetwork)
|
||||||
|
networkCapabilities?.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED) ?: false
|
||||||
|
} else {
|
||||||
|
val activeNetworkInfo = connectMgr.activeNetworkInfo
|
||||||
|
activeNetworkInfo != null && activeNetworkInfo.isConnected
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun send(enabled: Boolean, name: String?, speed: Speed? = null) {
|
||||||
|
send(NetStatus(enabled, name, speed))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
Log.d(TAG, "-- onDestroy --")
|
||||||
|
if (registered.compareAndSet(true, false)) {
|
||||||
|
connectMgr.unregisterNetworkCallback(cb)
|
||||||
|
}
|
||||||
|
loopCheckAndSendJob?.safeCancel()
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package com.zhjt.mogo_core_function_devatools.status.flow.rtk
|
||||||
|
|
||||||
|
import android.content.*
|
||||||
|
import android.util.*
|
||||||
|
import com.mogo.eagle.core.function.api.autopilot.*
|
||||||
|
import com.mogo.eagle.core.function.call.autopilot.*
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.entity.RTKStatus
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.flow.IFlow
|
||||||
|
import mogo.telematics.pad.MessagePad.GnssInfo
|
||||||
|
|
||||||
|
internal class RTKImpl(ctx: Context): IFlow<RTKStatus>(ctx), IMoGoAutopilotCarStateListener {
|
||||||
|
companion object {
|
||||||
|
const val TAG = "RTKImpl"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreate() {
|
||||||
|
send(RTKStatus(isRTKEnabled()))
|
||||||
|
Log.d(TAG, "-- onCreate --")
|
||||||
|
CallerAutopilotCarStatusListenerManager.addListener(TAG, this)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isRTKEnabled() =
|
||||||
|
CallerAutoPilotManager.isConnected() && CallerAutoPilotStatusListenerManager.getAutoPilotReportMessageCode() != "EHW_RTK" && CallerAutopilotCarStatusListenerManager.getCurrentGnssInfo() != null
|
||||||
|
|
||||||
|
override fun onAutopilotCarStateData(gnssInfo: GnssInfo?) {
|
||||||
|
send(RTKStatus(isRTKEnabled()))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
Log.d(TAG, "-- onDestroy --")
|
||||||
|
CallerAutopilotCarStatusListenerManager.removeListener(TAG)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package com.zhjt.mogo_core_function_devatools.status.flow.trace
|
||||||
|
|
||||||
|
import android.content.*
|
||||||
|
import android.util.*
|
||||||
|
import com.mogo.eagle.core.function.api.autopilot.*
|
||||||
|
import com.mogo.eagle.core.function.call.autopilot.*
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.entity.*
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.entity.TracingStatus
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.flow.IFlow
|
||||||
|
import mogo_msg.MogoReportMsg.MogoReportMessage
|
||||||
|
|
||||||
|
internal class TracingImpl(ctx: Context): IFlow<TracingStatus>(ctx), IMoGoAutopilotStatusListener {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TAG = "TracingImpl"
|
||||||
|
}
|
||||||
|
|
||||||
|
private var old: String = ""
|
||||||
|
|
||||||
|
override fun onCreate() {
|
||||||
|
Log.d(TAG, "-- onCreate --")
|
||||||
|
val autoPilotReportMessageCode = CallerAutoPilotStatusListenerManager.getAutoPilotReportMessageCode()
|
||||||
|
old = autoPilotReportMessageCode
|
||||||
|
send(TracingStatus(autoPilotReportMessageCode.toState()))
|
||||||
|
CallerAutoPilotStatusListenerManager.addListener(TAG, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun onAutopilotGuardian(guardianInfo: MogoReportMessage?) {
|
||||||
|
super.onAutopilotGuardian(guardianInfo)
|
||||||
|
val current = guardianInfo?.code
|
||||||
|
if (current != null && current != old) {
|
||||||
|
Log.d(TAG, "-- onAutopilotGuardian --")
|
||||||
|
send(TracingStatus(current.toState()))
|
||||||
|
old = current
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
Log.d(TAG, "-- onDestroy --")
|
||||||
|
CallerAutoPilotStatusListenerManager.removeListener(TAG)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
package com.zhjt.mogo_core_function_devatools.status.model
|
||||||
|
|
||||||
|
import androidx.lifecycle.*
|
||||||
|
import com.mogo.eagle.core.function.call.autopilot.*
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.entity.CanStatus
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.entity.GpsStatus
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.entity.IpcStatus
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.entity.NetStatus
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.entity.RTKStatus
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.entity.Status
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.entity.TracingStatus
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.entity.TracingStatus.Tracing.UNKNOWN
|
||||||
|
import java.util.concurrent.atomic.*
|
||||||
|
import kotlin.Pair
|
||||||
|
|
||||||
|
internal class StatusModel : ViewModel() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
const val TAG = "StatusModel"
|
||||||
|
val DEFAULTS = Pair(null, ArrayList<Status>().also {
|
||||||
|
it += IpcStatus(CallerAutoPilotManager.isConnected())
|
||||||
|
it += NetStatus(false)
|
||||||
|
it += CanStatus(false)
|
||||||
|
it += TracingStatus(UNKNOWN)
|
||||||
|
it += RTKStatus(false)
|
||||||
|
it += GpsStatus(enabled = false, isGranted = false)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
val status: MutableLiveData<Pair<Status?, ArrayList<Status>>> = MutableLiveData()
|
||||||
|
|
||||||
|
private val preValue by lazy { AtomicReference<Pair<Status?, ArrayList<Status>>>() }
|
||||||
|
|
||||||
|
|
||||||
|
init {
|
||||||
|
status.value = DEFAULTS
|
||||||
|
}
|
||||||
|
|
||||||
|
fun update(s: Status) {
|
||||||
|
synchronized(preValue) {
|
||||||
|
val v = preValue.get()?.second ?: status.value?.second ?: throw IllegalStateException("live data can't be null.")
|
||||||
|
val nv = ArrayList(v).also { it.updateOrInsert(s) }
|
||||||
|
val data = Pair(getExceptionStatus(nv), nv)
|
||||||
|
preValue.set(data)
|
||||||
|
status.postValue(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getExceptionStatus(l: ArrayList<Status>): Status? {
|
||||||
|
var ret: Status? = null
|
||||||
|
for (s in l) {
|
||||||
|
ret = when(s) {
|
||||||
|
is IpcStatus -> {
|
||||||
|
if (!s.enabled) {
|
||||||
|
s
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is CanStatus -> {
|
||||||
|
if (CallerAutoPilotManager.isConnected() && !s.enabled) {
|
||||||
|
s
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is NetStatus -> {
|
||||||
|
if (!s.enabled) {
|
||||||
|
s
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is GpsStatus -> {
|
||||||
|
if (!s.enabled) {
|
||||||
|
s
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is TracingStatus -> {
|
||||||
|
if (CallerAutoPilotManager.isConnected() && s.state.isException()) {
|
||||||
|
s
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is RTKStatus -> {
|
||||||
|
if (!s.enabled) {
|
||||||
|
s
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret != null) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ArrayList<Status>.updateOrInsert(s: Status) {
|
||||||
|
val index = indexOfFirst { it.javaClass == s.javaClass }
|
||||||
|
if (index < 0) {
|
||||||
|
add(s)
|
||||||
|
} else {
|
||||||
|
set(index, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
package com.zhjt.mogo_core_function_devatools.status.ui
|
||||||
|
|
||||||
|
import android.annotation.*
|
||||||
|
import android.content.*
|
||||||
|
import android.graphics.*
|
||||||
|
import android.graphics.drawable.*
|
||||||
|
import android.transition.*
|
||||||
|
import android.util.*
|
||||||
|
import android.view.*
|
||||||
|
import androidx.appcompat.widget.*
|
||||||
|
import androidx.constraintlayout.widget.*
|
||||||
|
import androidx.core.content.*
|
||||||
|
import androidx.lifecycle.*
|
||||||
|
import androidx.recyclerview.widget.*
|
||||||
|
import com.mogo.eagle.core.utilcode.kotlin.*
|
||||||
|
import com.mogo.eagle.core.utilcode.rv.divider.*
|
||||||
|
import com.zhjt.mogo_core_function_devatools.R
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.entity.*
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.entity.Status
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.model.StatusModel
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.ui.adapter.StatusAdapter
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.ui.diff.StatusDiffCallback
|
||||||
|
import java.util.ArrayList
|
||||||
|
import kotlin.Pair
|
||||||
|
|
||||||
|
@SuppressLint("ViewConstructor")
|
||||||
|
internal class StatusView(private val model: StatusModel, ctx: Context): ConstraintLayout(ctx) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val TAG = "StatusView"
|
||||||
|
}
|
||||||
|
|
||||||
|
private val iv: AppCompatImageView
|
||||||
|
private val rv: RecyclerView
|
||||||
|
private val dot: View
|
||||||
|
|
||||||
|
private var observer: Observer<Pair<Status?, ArrayList<Status>>>? = null
|
||||||
|
init {
|
||||||
|
LayoutInflater.from(context).inflate(R.layout.layout_status_bar, this, true)
|
||||||
|
iv = findViewById(R.id.iv)
|
||||||
|
rv = findViewById(R.id.rv)
|
||||||
|
dot = findViewById(R.id.dot)
|
||||||
|
init()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun init() {
|
||||||
|
isClickable = true
|
||||||
|
dot.background = shape(solid = Color.RED, shape = GradientDrawable.OVAL, width = 30.PX, height = 30.PX)
|
||||||
|
iv.also {
|
||||||
|
it.background = ContextCompat.getDrawable(context, R.drawable.icon_dev_status_un_fold)
|
||||||
|
it.onClick { v ->
|
||||||
|
val expand = v.tag as? Boolean ?: false
|
||||||
|
animate(expand)
|
||||||
|
v.tag = !expand
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rv.also { itx ->
|
||||||
|
itx.itemAnimator?.run {
|
||||||
|
changeDuration = 0
|
||||||
|
addDuration = 0
|
||||||
|
moveDuration = 0
|
||||||
|
removeDuration = 0
|
||||||
|
}
|
||||||
|
itx.layoutManager = GridLayoutManager(context, 3, GridLayoutManager.VERTICAL, false)
|
||||||
|
itx.background = shape(solid = Color.parseColor("#80000000"), radius = 40.PX)
|
||||||
|
itx.addItemDecoration(
|
||||||
|
CommonDividerItemDecoration.Builder()
|
||||||
|
.horizontalExternalSpace(66.PX)
|
||||||
|
.verticalExternalSpace(60.PX)
|
||||||
|
.spanCountTBCare(false)
|
||||||
|
.verticalInnerSpace(50.PX)
|
||||||
|
.horizontalInnerSpace(116.PX)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
val adapter = model.status.value?.let { data -> StatusAdapter(context, data.second) }?.also { adapter -> itx.adapter = adapter }
|
||||||
|
adapter?.let { _ ->
|
||||||
|
model.status.observeForever(Observer<Pair<Status?, ArrayList<Status>>> { data ->
|
||||||
|
Log.d("OOOO", "--- observeForever -----")
|
||||||
|
|
||||||
|
if (data.first != null) {
|
||||||
|
dot.visibility = View.VISIBLE
|
||||||
|
} else {
|
||||||
|
dot.visibility = View.INVISIBLE
|
||||||
|
}
|
||||||
|
val old = adapter.data
|
||||||
|
Log.d(TAG, "receive update --new - data: ${data.second.joinToString(",")}")
|
||||||
|
Log.d(TAG, "receive update --old - data: ${old.joinToString(",")}")
|
||||||
|
val result = DiffUtil.calculateDiff(StatusDiffCallback(old, data.second))
|
||||||
|
adapter.data = data.second
|
||||||
|
result.dispatchUpdatesTo(adapter)
|
||||||
|
}.also { observer = it })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onDetach {
|
||||||
|
observer?.also { model.status.removeObserver(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun animate(expand: Boolean) {
|
||||||
|
iv.animate().rotation(if (expand) 0f else -180f).setDuration(200).start()
|
||||||
|
TransitionManager.beginDelayedTransition(this, AutoTransition().setDuration(200))
|
||||||
|
rv.visibility = if (expand) View.VISIBLE else View.INVISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
package com.zhjt.mogo_core_function_devatools.status.ui.adapter
|
||||||
|
|
||||||
|
import android.content.*
|
||||||
|
import android.view.*
|
||||||
|
import android.widget.*
|
||||||
|
import androidx.core.content.*
|
||||||
|
import androidx.recyclerview.widget.*
|
||||||
|
import com.zhjt.mogo_core_function_devatools.*
|
||||||
|
import com.zhjt.mogo_core_function_devatools.R.drawable
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.entity.*
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.entity.IpcStatus
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.entity.Status
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.entity.TracingStatus.Tracing.*
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.ui.adapter.StatusAdapter.StatusViewHolder
|
||||||
|
|
||||||
|
internal class StatusAdapter(val ctx: Context, var data: ArrayList<Status>): RecyclerView.Adapter<StatusViewHolder>() {
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): StatusViewHolder =
|
||||||
|
StatusViewHolder(LayoutInflater.from(ctx).inflate(R.layout.layout_status_bar_item, parent, false))
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: StatusViewHolder, position: Int) {
|
||||||
|
holder.bind(data[position])
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount(): Int = data.size
|
||||||
|
|
||||||
|
internal class StatusViewHolder(item: View) : RecyclerView.ViewHolder(item) {
|
||||||
|
|
||||||
|
private val iv: ImageView by lazy {
|
||||||
|
itemView.findViewById(R.id.iv)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val tv: TextView by lazy {
|
||||||
|
itemView.findViewById(R.id.tv)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bind(status: Status) {
|
||||||
|
when(status) {
|
||||||
|
is IpcStatus -> {
|
||||||
|
if (status.enabled) {
|
||||||
|
iv.background = ContextCompat.getDrawable(itemView.context, drawable.icon_dev_status_ipc_enable)
|
||||||
|
} else {
|
||||||
|
iv.background = ContextCompat.getDrawable(itemView.context, drawable.icon_dev_status_ipc_disable)
|
||||||
|
}
|
||||||
|
tv.text = "工控机"
|
||||||
|
}
|
||||||
|
is CanStatus -> {
|
||||||
|
if (status.enabled) {
|
||||||
|
iv.background = ContextCompat.getDrawable(itemView.context, drawable.icon_dev_status_can_enable)
|
||||||
|
} else {
|
||||||
|
iv.background = ContextCompat.getDrawable(itemView.context, drawable.icon_dev_status_can_disable)
|
||||||
|
}
|
||||||
|
tv.text = "Can"
|
||||||
|
}
|
||||||
|
is NetStatus -> {
|
||||||
|
if (status.enabled) {
|
||||||
|
iv.background = ContextCompat.getDrawable(itemView.context, drawable.icon_dev_status_net_enable)
|
||||||
|
tv.text = status.name ?: "Wi-Fi"
|
||||||
|
} else {
|
||||||
|
iv.background = ContextCompat.getDrawable(itemView.context, drawable.icon_dev_status_net_disable)
|
||||||
|
tv.text = "Wi-Fi"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is GpsStatus -> {
|
||||||
|
if (status.enabled && status.isGranted) {
|
||||||
|
iv.background = ContextCompat.getDrawable(itemView.context, drawable.icon_dev_status_gps_enable)
|
||||||
|
} else {
|
||||||
|
iv.background = ContextCompat.getDrawable(itemView.context, drawable.icon_dev_status_gps_disable)
|
||||||
|
}
|
||||||
|
tv.text = "Gps"
|
||||||
|
}
|
||||||
|
is TracingStatus -> {
|
||||||
|
when(status.state) {
|
||||||
|
ROUTE_FAILED, TRACK_LOAD_FAIL, TRACK_NOT_EXIST, TRACK_FINDED, UNKNOWN -> {
|
||||||
|
iv.background = ContextCompat.getDrawable(itemView.context, drawable.icon_dev_status_trace_unkown)
|
||||||
|
tv.text = "未知"
|
||||||
|
}
|
||||||
|
TRACK_LOADED -> {
|
||||||
|
iv.background = ContextCompat.getDrawable(itemView.context, drawable.icon_dev_status_track_enable)
|
||||||
|
tv.text = "T"
|
||||||
|
}
|
||||||
|
ROUTE_LOADED -> {
|
||||||
|
iv.background = ContextCompat.getDrawable(itemView.context, drawable.icon_dev_status_route_enable)
|
||||||
|
tv.text = "V"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is RTKStatus -> {
|
||||||
|
if (status.enabled) {
|
||||||
|
iv.background = ContextCompat.getDrawable(itemView.context, drawable.icon_dev_status_rtk_enable)
|
||||||
|
} else {
|
||||||
|
iv.background = ContextCompat.getDrawable(itemView.context, drawable.icon_dev_status_rtk_disable)
|
||||||
|
}
|
||||||
|
tv.text = "RTK"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package com.zhjt.mogo_core_function_devatools.status.ui.diff
|
||||||
|
|
||||||
|
import androidx.recyclerview.widget.*
|
||||||
|
import com.zhjt.mogo_core_function_devatools.status.entity.Status
|
||||||
|
|
||||||
|
internal class StatusDiffCallback(private val old: ArrayList<Status>, private val update: ArrayList<Status>): DiffUtil.Callback() {
|
||||||
|
|
||||||
|
override fun getOldListSize(): Int = old.size
|
||||||
|
|
||||||
|
override fun getNewListSize(): Int = update.size
|
||||||
|
|
||||||
|
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
|
||||||
|
val oldStatus = old[oldItemPosition]
|
||||||
|
val updateStatus = update[newItemPosition]
|
||||||
|
return oldStatus == updateStatus
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 6.1 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 6.7 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 6.0 KiB |
|
After Width: | Height: | Size: 9.4 KiB |
|
After Width: | Height: | Size: 7.4 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 8.1 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 9.6 KiB |
|
After Width: | Height: | Size: 9.4 KiB |
@@ -0,0 +1,37 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
tools:layout_height="wrap_content"
|
||||||
|
tools:layout_width="match_parent"
|
||||||
|
tools:parentTag="androidx.constraintlayout.widget.ConstraintLayout">
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/rv"
|
||||||
|
android:layout_width="0dip"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:minHeight="468px"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/iv"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintHorizontal_bias="0.5"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
|
android:id="@+id/iv"
|
||||||
|
android:layout_width="102px"
|
||||||
|
android:layout_height="102px"
|
||||||
|
android:layout_marginTop="30px"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/rv"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
android:background="@drawable/icon_dev_status_un_fold"/>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/dot"
|
||||||
|
android:layout_width="30px"
|
||||||
|
android:layout_height="30px"
|
||||||
|
app:layout_constraintEnd_toEndOf="@+id/iv"
|
||||||
|
app:layout_constraintTop_toTopOf="@+id/iv"
|
||||||
|
android:visibility="invisible"/>
|
||||||
|
</merge>
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="100px"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_horizontal">
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv"
|
||||||
|
android:layout_width="96px"
|
||||||
|
android:layout_height="96px" />
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="20px"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:textColor="#ffffff"
|
||||||
|
android:textSize="24px" />
|
||||||
|
</LinearLayout>
|
||||||
@@ -334,4 +334,7 @@ public class DispatchAutoPilotManager implements IMogoOnMessageListener<Dispatch
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAutopilotNotData(long timestamp) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -174,6 +174,10 @@ class MoGoHmiFragment : MvpFragment<MoGoHmiContract.View?, HmiPresenter?>(),
|
|||||||
setProxyTrafficLightView(viewTrafficLightVr)
|
setProxyTrafficLightView(viewTrafficLightVr)
|
||||||
setProxyLimitingSpeedView(viewLimitingVelocity)
|
setProxyLimitingSpeedView(viewLimitingVelocity)
|
||||||
setProxyNotificationView(V2XNotificationView(view.context))
|
setProxyNotificationView(V2XNotificationView(view.context))
|
||||||
|
|
||||||
|
context?.also {
|
||||||
|
CallerDevaToolsManager.showStatusBar(it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
|
|||||||
@@ -1779,6 +1779,10 @@ class DebugSettingView @JvmOverloads constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onAutopilotNotData(timestamp: Long) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 吐司提示
|
* 吐司提示
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -101,6 +101,10 @@ public class SteeringWheelView extends ConstraintLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private final IMoGoAutopilotStatusListener mGoAutopilotStatusListener = new IMoGoAutopilotStatusListener() {
|
private final IMoGoAutopilotStatusListener mGoAutopilotStatusListener = new IMoGoAutopilotStatusListener() {
|
||||||
|
@Override
|
||||||
|
public void onAutopilotNotData(long timestamp) {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAutopilotArriveAtStation(@org.jetbrains.annotations.Nullable MessagePad.ArrivalNotification arrivalNotification) {
|
public void onAutopilotArriveAtStation(@org.jetbrains.annotations.Nullable MessagePad.ArrivalNotification arrivalNotification) {
|
||||||
|
|
||||||
@@ -146,6 +150,11 @@ public class SteeringWheelView extends ConstraintLayout {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private final IMoGoAutopilotVehicleStateListener mIMoGoAutopilotVehicleStateListener = new IMoGoAutopilotVehicleStateListener() {
|
private final IMoGoAutopilotVehicleStateListener mIMoGoAutopilotVehicleStateListener = new IMoGoAutopilotVehicleStateListener() {
|
||||||
|
@Override
|
||||||
|
public void onAutopilotNotData(long timestamp) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 车辆转向灯
|
* 车辆转向灯
|
||||||
* @param lightSwitch
|
* @param lightSwitch
|
||||||
|
|||||||
@@ -75,6 +75,10 @@ public class MainActivity extends MvpActivity<MainView, MainPresenter> implement
|
|||||||
FragmentStackTransactionListener,
|
FragmentStackTransactionListener,
|
||||||
IMoGoAutopilotStatusListener {
|
IMoGoAutopilotStatusListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAutopilotNotData(long timestamp) {
|
||||||
|
}
|
||||||
|
|
||||||
protected static final String TAG = "MainActivity";
|
protected static final String TAG = "MainActivity";
|
||||||
private static final int REQUEST_CODE_DIALOG = 100;
|
private static final int REQUEST_CODE_DIALOG = 100;
|
||||||
|
|
||||||
@@ -473,4 +477,8 @@ public class MainActivity extends MvpActivity<MainView, MainPresenter> implement
|
|||||||
.commitAllowingStateLoss();
|
.commitAllowingStateLoss();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPointerCaptureChanged(boolean hasCapture) {
|
||||||
|
super.onPointerCaptureChanged(hasCapture);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,6 +55,10 @@ public class SmallMapFragment extends BaseFragment
|
|||||||
SmpServiceManager.init(getContext());
|
SmpServiceManager.init(getContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAutopilotNotData(long timestamp) {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initViews(Bundle savedInstanceState) {
|
protected void initViews(Bundle savedInstanceState) {
|
||||||
super.initViews(savedInstanceState);
|
super.initViews(savedInstanceState);
|
||||||
|
|||||||
@@ -35,6 +35,11 @@ interface IMoGoAutopilotStatusListener {
|
|||||||
*/
|
*/
|
||||||
fun onAutopilotGuardian(guardianInfo: MogoReportMsg.MogoReportMessage?) {}
|
fun onAutopilotGuardian(guardianInfo: MogoReportMsg.MogoReportMessage?) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 工控机底盘没有返回数据
|
||||||
|
*/
|
||||||
|
fun onAutopilotNotData(timestamp: Long) {}
|
||||||
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -30,4 +30,9 @@ interface IMoGoAutopilotVehicleStateListener {
|
|||||||
* @param gear 档位
|
* @param gear 档位
|
||||||
*/
|
*/
|
||||||
fun onAutopilotGearData(gear: Chassis.GearPosition)
|
fun onAutopilotGearData(gear: Chassis.GearPosition)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 底盘没有返回数据
|
||||||
|
*/
|
||||||
|
fun onAutopilotNotData(timestamp: Long)
|
||||||
}
|
}
|
||||||
@@ -99,4 +99,9 @@ interface IDevaToolsProvider : IProvider {
|
|||||||
* 下载指定包
|
* 下载指定包
|
||||||
*/
|
*/
|
||||||
fun downLoadPackage(downloadKey: String, downloadUrl: String)
|
fun downLoadPackage(downloadKey: String, downloadUrl: String)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 展示状态栏
|
||||||
|
*/
|
||||||
|
fun showStatusBar(ctx: Context)
|
||||||
}
|
}
|
||||||
@@ -4,6 +4,7 @@ import androidx.annotation.Nullable
|
|||||||
import com.mogo.eagle.core.data.autopilot.AutopilotStatusInfo
|
import com.mogo.eagle.core.data.autopilot.AutopilotStatusInfo
|
||||||
import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatusListener
|
import com.mogo.eagle.core.function.api.autopilot.IMoGoAutopilotStatusListener
|
||||||
import com.mogo.eagle.core.function.call.base.CallerBase
|
import com.mogo.eagle.core.function.call.base.CallerBase
|
||||||
|
import com.mogo.eagle.core.utilcode.kotlin.*
|
||||||
import com.mogo.eagle.core.utilcode.util.GsonUtils
|
import com.mogo.eagle.core.utilcode.util.GsonUtils
|
||||||
import mogo.telematics.pad.MessagePad
|
import mogo.telematics.pad.MessagePad
|
||||||
import mogo_msg.MogoReportMsg
|
import mogo_msg.MogoReportMsg
|
||||||
@@ -23,6 +24,9 @@ object CallerAutoPilotStatusListenerManager : CallerBase() {
|
|||||||
private val M_AUTOPILOT_STATUS_LISTENERS: ConcurrentHashMap<String, IMoGoAutopilotStatusListener> =
|
private val M_AUTOPILOT_STATUS_LISTENERS: ConcurrentHashMap<String, IMoGoAutopilotStatusListener> =
|
||||||
ConcurrentHashMap()
|
ConcurrentHashMap()
|
||||||
|
|
||||||
|
@Volatile
|
||||||
|
private var autoPilotMessageCode: String = ""
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询AutoPilot状态
|
* 查询AutoPilot状态
|
||||||
*/
|
*/
|
||||||
@@ -37,6 +41,8 @@ object CallerAutoPilotStatusListenerManager : CallerBase() {
|
|||||||
return GsonUtils.toJson(mAutopilotStatusInfo)
|
return GsonUtils.toJson(mAutopilotStatusInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getAutoPilotReportMessageCode(): String = autoPilotMessageCode
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过Gnss定位更新来同步更新自动驾驶状态
|
* 通过Gnss定位更新来同步更新自动驾驶状态
|
||||||
*/
|
*/
|
||||||
@@ -163,6 +169,7 @@ object CallerAutoPilotStatusListenerManager : CallerBase() {
|
|||||||
M_AUTOPILOT_STATUS_LISTENERS.forEach {
|
M_AUTOPILOT_STATUS_LISTENERS.forEach {
|
||||||
val tag = it.key
|
val tag = it.key
|
||||||
val listener = it.value
|
val listener = it.value
|
||||||
|
autoPilotMessageCode = guardianInfo?.code ?: ""
|
||||||
listener.onAutopilotGuardian(guardianInfo)
|
listener.onAutopilotGuardian(guardianInfo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ object CallerAutopilotCarStatusListenerManager : CallerBase() {
|
|||||||
private val M_AUTOPILOT_STATUS_LISTENERS: ConcurrentHashMap<String, IMoGoAutopilotCarStateListener> =
|
private val M_AUTOPILOT_STATUS_LISTENERS: ConcurrentHashMap<String, IMoGoAutopilotCarStateListener> =
|
||||||
ConcurrentHashMap()
|
ConcurrentHashMap()
|
||||||
|
|
||||||
|
@Volatile
|
||||||
|
private var gnssInfo: MessagePad.GnssInfo? = null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 添加 ADAS车辆状态&定位 监听
|
* 添加 ADAS车辆状态&定位 监听
|
||||||
@@ -56,12 +58,18 @@ object CallerAutopilotCarStatusListenerManager : CallerBase() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun getCurrentGnssInfo():MessagePad.GnssInfo? {
|
||||||
|
return gnssInfo
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 车辆状态数据 回调
|
* 车辆状态数据 回调
|
||||||
* @param gnssInfo
|
* @param gnssInfo
|
||||||
*/
|
*/
|
||||||
@Synchronized
|
@Synchronized
|
||||||
fun invokeAutopilotCarStateData(gnssInfo: MessagePad.GnssInfo?) {
|
fun invokeAutopilotCarStateData(gnssInfo: MessagePad.GnssInfo?) {
|
||||||
|
this.gnssInfo = gnssInfo
|
||||||
M_AUTOPILOT_STATUS_LISTENERS.forEach {
|
M_AUTOPILOT_STATUS_LISTENERS.forEach {
|
||||||
val tag = it.key
|
val tag = it.key
|
||||||
val listener = it.value
|
val listener = it.value
|
||||||
|
|||||||
@@ -113,4 +113,14 @@ object CallerAutopilotVehicleStateListenerManager : CallerBase() {
|
|||||||
fun getAutopilotTimeStamp(): Long {
|
fun getAutopilotTimeStamp(): Long {
|
||||||
return this.timeStamp
|
return this.timeStamp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 底盘没有返回数据
|
||||||
|
*/
|
||||||
|
fun invokeAutopilotNotData(timestamp: Long) {
|
||||||
|
M_AUTOPILOT_VEHICLE_LISTENERS.forEach{
|
||||||
|
val listener = it.value
|
||||||
|
listener.onAutopilotNotData(timestamp)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -136,4 +136,11 @@ object CallerDevaToolsManager {
|
|||||||
fun downLoadPackage(downloadKey: String, downloadUrl: String) {
|
fun downLoadPackage(downloadKey: String, downloadUrl: String) {
|
||||||
devaToolsProviderApi?.downLoadPackage(downloadKey, downloadUrl)
|
devaToolsProviderApi?.downLoadPackage(downloadKey, downloadUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 展示状态栏
|
||||||
|
*/
|
||||||
|
fun showStatusBar(ctx: Context) {
|
||||||
|
devaToolsProviderApi?.showStatusBar(ctx)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -8,8 +8,7 @@ import android.graphics.drawable.GradientDrawable
|
|||||||
import android.text.*
|
import android.text.*
|
||||||
import android.text.style.ForegroundColorSpan
|
import android.text.style.ForegroundColorSpan
|
||||||
import android.util.TypedValue
|
import android.util.TypedValue
|
||||||
import android.view.MotionEvent
|
import android.view.*
|
||||||
import android.view.View
|
|
||||||
import android.widget.EditText
|
import android.widget.EditText
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.annotation.ColorInt
|
import androidx.annotation.ColorInt
|
||||||
@@ -40,20 +39,38 @@ val <T: View> T.lifecycleOwner: LifecycleOwner
|
|||||||
if (it.currentState.isAtLeast(Lifecycle.State.INITIALIZED)) {
|
if (it.currentState.isAtLeast(Lifecycle.State.INITIALIZED)) {
|
||||||
it.currentState = Lifecycle.State.CREATED
|
it.currentState = Lifecycle.State.CREATED
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (it.currentState.isAtLeast(Lifecycle.State.CREATED)) {
|
||||||
|
it.currentState = Lifecycle.State.STARTED
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it.currentState.isAtLeast(Lifecycle.State.STARTED)) {
|
||||||
|
it.currentState = Lifecycle.State.RESUMED
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
|
addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
|
||||||
override fun onViewAttachedToWindow(v: View?) {
|
override fun onViewAttachedToWindow(v: View?) {
|
||||||
lifecycle.let {
|
lifecycle.let {
|
||||||
if (it.currentState.isAtLeast(Lifecycle.State.INITIALIZED)) {
|
if (it.currentState.isAtLeast(Lifecycle.State.INITIALIZED)) {
|
||||||
it.currentState = Lifecycle.State.CREATED
|
it.currentState = Lifecycle.State.CREATED
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (it.currentState.isAtLeast(Lifecycle.State.CREATED)) {
|
||||||
|
it.currentState = Lifecycle.State.STARTED
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it.currentState.isAtLeast(Lifecycle.State.STARTED)) {
|
||||||
|
it.currentState = Lifecycle.State.RESUMED
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewDetachedFromWindow(v: View?) {
|
override fun onViewDetachedFromWindow(v: View?) {
|
||||||
lifecycle.let {
|
lifecycle.let {
|
||||||
if (it.currentState.isAtLeast(Lifecycle.State.CREATED)) {
|
if (it.currentState.isAtLeast(Lifecycle.State.RESUMED)) {
|
||||||
this@lifecycleOwner.removeOnAttachStateChangeListener(this)
|
this@lifecycleOwner.removeOnAttachStateChangeListener(this)
|
||||||
it.currentState = Lifecycle.State.DESTROYED
|
it.currentState = Lifecycle.State.DESTROYED
|
||||||
}
|
}
|
||||||
@@ -159,7 +176,6 @@ val Int.PX: Int
|
|||||||
val Int.SP: Int
|
val Int.SP: Int
|
||||||
get() = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, this.toFloat(), Utils.getApp().resources.displayMetrics).toInt()
|
get() = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, this.toFloat(), Utils.getApp().resources.displayMetrics).toInt()
|
||||||
|
|
||||||
|
|
||||||
fun <T: EditText> T.watch(@IntRange(from = 1) maxCharCount: Int, onCountChanged:((count: Int) -> Unit)? = null, onTextChanged:((editable: Editable?) -> Unit)? = null, onReachMaxCountAction:((text: T) -> Unit)? = null, onGetFocus:((text: T) -> Unit)? = null) {
|
fun <T: EditText> T.watch(@IntRange(from = 1) maxCharCount: Int, onCountChanged:((count: Int) -> Unit)? = null, onTextChanged:((editable: Editable?) -> Unit)? = null, onReachMaxCountAction:((text: T) -> Unit)? = null, onGetFocus:((text: T) -> Unit)? = null) {
|
||||||
doAfterTextChanged { itx ->
|
doAfterTextChanged { itx ->
|
||||||
onTextChanged?.invoke(itx)
|
onTextChanged?.invoke(itx)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package com.mogo.eagle.core.utilcode.rv.divider
|
|||||||
|
|
||||||
import android.graphics.Canvas
|
import android.graphics.Canvas
|
||||||
import android.graphics.Rect
|
import android.graphics.Rect
|
||||||
import android.util.Pair
|
import android.util.*
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.annotation.IntRange
|
import androidx.annotation.IntRange
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
@@ -84,17 +84,23 @@ class CommonDividerItemDecoration internal constructor(builder: Builder) : ItemD
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val averageDistance = (((spanCount - 1) * mHorizontalInnerSpace + 2 * mHorizontalExternalSpace + deltaHL + deltaHR) * 1.0f / spanCount).toInt()
|
val averageDistance = (((spanCount - 1) * mHorizontalInnerSpace + 2 * mHorizontalExternalSpace + deltaHL + deltaHR) * 1.0f / spanCount).toInt()
|
||||||
|
Log.d("UUUU", "step::0::$averageDistance: lastRight: $mLastRight : state: $state " )
|
||||||
if (spanIndex == 0) {
|
if (spanIndex == 0) {
|
||||||
outRect.left = mHorizontalExternalSpace + deltaHL
|
outRect.left = mHorizontalExternalSpace + deltaHL
|
||||||
outRect.right = averageDistance - outRect.left
|
outRect.right = averageDistance - outRect.left
|
||||||
mLastRight = outRect.right
|
mLastRight = outRect.right
|
||||||
|
Log.d("UUUU", "step::1::$averageDistance: lastRight: $mLastRight" )
|
||||||
} else if (spanIndex == spanCount - 1) {
|
} else if (spanIndex == spanCount - 1) {
|
||||||
outRect.right = mHorizontalExternalSpace + deltaHR
|
outRect.right = mHorizontalExternalSpace + deltaHR
|
||||||
outRect.left = averageDistance - outRect.right
|
outRect.left = averageDistance - outRect.right
|
||||||
|
Log.d("UUUU", "step::2::$averageDistance: lastRight: $mLastRight ::outRect.left: ${outRect.left}" )
|
||||||
} else {
|
} else {
|
||||||
outRect.left = mHorizontalInnerSpace - mLastRight
|
outRect.left = mHorizontalInnerSpace - mLastRight
|
||||||
outRect.right = averageDistance - outRect.left
|
outRect.right = averageDistance - outRect.left
|
||||||
mLastRight = outRect.right
|
if (state.didStructureChange()) {
|
||||||
|
mLastRight = outRect.right
|
||||||
|
}
|
||||||
|
Log.d("UUUU", "step::2::$averageDistance: lastRight: $mLastRight ::outRect.left: ${outRect.left}" )
|
||||||
}
|
}
|
||||||
} //所在的行数
|
} //所在的行数
|
||||||
if (lookUp.getSpanGroupIndex(childPosition, spanCount) == lookUp.getSpanGroupIndex(mFromPosition, spanCount)) {
|
if (lookUp.getSpanGroupIndex(childPosition, spanCount) == lookUp.getSpanGroupIndex(mFromPosition, spanCount)) {
|
||||||
@@ -131,7 +137,9 @@ class CommonDividerItemDecoration internal constructor(builder: Builder) : ItemD
|
|||||||
} else {
|
} else {
|
||||||
outRect.top = mVerticalInnerSpace - mLastBottom
|
outRect.top = mVerticalInnerSpace - mLastBottom
|
||||||
outRect.bottom = averageDistance - outRect.top
|
outRect.bottom = averageDistance - outRect.top
|
||||||
mLastBottom = outRect.bottom
|
if (state.didStructureChange()) {
|
||||||
|
mLastBottom = outRect.bottom
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (lookUp.getSpanGroupIndex(childPosition, spanCount) == lookUp.getSpanGroupIndex(mFromPosition, spanCount)) { //第一列
|
if (lookUp.getSpanGroupIndex(childPosition, spanCount) == lookUp.getSpanGroupIndex(mFromPosition, spanCount)) { //第一列
|
||||||
@@ -222,7 +230,9 @@ class CommonDividerItemDecoration internal constructor(builder: Builder) : ItemD
|
|||||||
} else {
|
} else {
|
||||||
outRect.left = mHorizontalInnerSpace - mLastRight
|
outRect.left = mHorizontalInnerSpace - mLastRight
|
||||||
outRect.right = averageDistance - outRect.left
|
outRect.right = averageDistance - outRect.left
|
||||||
mLastRight = outRect.right
|
if (state.didStructureChange()) {
|
||||||
|
mLastRight = outRect.right
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (childPosition == mFromPosition) {
|
if (childPosition == mFromPosition) {
|
||||||
@@ -279,7 +289,9 @@ class CommonDividerItemDecoration internal constructor(builder: Builder) : ItemD
|
|||||||
} else {
|
} else {
|
||||||
outRect.top = mVerticalInnerSpace - mLastBottom
|
outRect.top = mVerticalInnerSpace - mLastBottom
|
||||||
outRect.bottom = averageDistance - outRect.top
|
outRect.bottom = averageDistance - outRect.top
|
||||||
mLastBottom = outRect.bottom
|
if (state.didStructureChange()) {
|
||||||
|
mLastBottom = outRect.bottom
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (childPosition == mFromPosition) {
|
if (childPosition == mFromPosition) {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.mogo.eagle.core.utilcode.util;
|
package com.mogo.eagle.core.utilcode.util;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
@@ -56,6 +57,7 @@ public final class PermissionUtils {
|
|||||||
|
|
||||||
private static SimpleCallback sSimpleCallback4WriteSettings;
|
private static SimpleCallback sSimpleCallback4WriteSettings;
|
||||||
private static SimpleCallback sSimpleCallback4DrawOverlays;
|
private static SimpleCallback sSimpleCallback4DrawOverlays;
|
||||||
|
private static SimpleCallback sSimpleCallback4AccessFineLocation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the permissions used in application.
|
* Return the permissions used in application.
|
||||||
@@ -152,6 +154,19 @@ public final class PermissionUtils {
|
|||||||
PermissionActivityImpl.start(PermissionActivityImpl.TYPE_WRITE_SETTINGS);
|
PermissionActivityImpl.start(PermissionActivityImpl.TYPE_WRITE_SETTINGS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void requestAccessFineLocation(final SimpleCallback callback) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
|
if (isGranted(Manifest.permission.ACCESS_FINE_LOCATION)) {
|
||||||
|
if (callback != null) {
|
||||||
|
callback.onGranted();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sSimpleCallback4AccessFineLocation = callback;
|
||||||
|
PermissionActivityImpl.start(PermissionActivityImpl.TYPE_ACCESS_FINE_LOCATION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@TargetApi(Build.VERSION_CODES.M)
|
@TargetApi(Build.VERSION_CODES.M)
|
||||||
private static void startWriteSettingsActivity(final Activity activity, final int requestCode) {
|
private static void startWriteSettingsActivity(final Activity activity, final int requestCode) {
|
||||||
Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);
|
Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);
|
||||||
@@ -424,6 +439,7 @@ public final class PermissionUtils {
|
|||||||
private static final int TYPE_RUNTIME = 0x01;
|
private static final int TYPE_RUNTIME = 0x01;
|
||||||
private static final int TYPE_WRITE_SETTINGS = 0x02;
|
private static final int TYPE_WRITE_SETTINGS = 0x02;
|
||||||
private static final int TYPE_DRAW_OVERLAYS = 0x03;
|
private static final int TYPE_DRAW_OVERLAYS = 0x03;
|
||||||
|
private static final int TYPE_ACCESS_FINE_LOCATION = 0x04;
|
||||||
|
|
||||||
private static int currentRequestCode = -1;
|
private static int currentRequestCode = -1;
|
||||||
|
|
||||||
@@ -483,6 +499,9 @@ public final class PermissionUtils {
|
|||||||
} else if (type == TYPE_DRAW_OVERLAYS) {
|
} else if (type == TYPE_DRAW_OVERLAYS) {
|
||||||
currentRequestCode = TYPE_DRAW_OVERLAYS;
|
currentRequestCode = TYPE_DRAW_OVERLAYS;
|
||||||
startOverlayPermissionActivity(activity, TYPE_DRAW_OVERLAYS);
|
startOverlayPermissionActivity(activity, TYPE_DRAW_OVERLAYS);
|
||||||
|
} else if (type == TYPE_ACCESS_FINE_LOCATION) {
|
||||||
|
currentRequestCode = TYPE_ACCESS_FINE_LOCATION;
|
||||||
|
startOverlayPermissionActivity(activity, TYPE_ACCESS_FINE_LOCATION);
|
||||||
} else {
|
} else {
|
||||||
activity.finish();
|
activity.finish();
|
||||||
Log.e("PermissionUtils", "type is wrong.");
|
Log.e("PermissionUtils", "type is wrong.");
|
||||||
@@ -550,6 +569,15 @@ public final class PermissionUtils {
|
|||||||
sSimpleCallback4DrawOverlays.onDenied();
|
sSimpleCallback4DrawOverlays.onDenied();
|
||||||
}
|
}
|
||||||
sSimpleCallback4DrawOverlays = null;
|
sSimpleCallback4DrawOverlays = null;
|
||||||
|
} else if (requestCode == TYPE_ACCESS_FINE_LOCATION) {
|
||||||
|
if (sSimpleCallback4AccessFineLocation == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (isGranted(Manifest.permission.ACCESS_FINE_LOCATION)) {
|
||||||
|
sSimpleCallback4AccessFineLocation.onGranted();
|
||||||
|
} else {
|
||||||
|
sSimpleCallback4AccessFineLocation.onDenied();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -210,4 +210,7 @@ public class MogoRouteOverlayManager implements
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onAutopilotNotData(long timestamp) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||