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 b98ff00c16..d47490d697 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 @@ -143,13 +143,6 @@ public class TaxiPassengerBaseFragment extends MvpFragment { - OverlayLeftViewUtils.INSTANCE.showOverlayView(getActivity(),0,true,-1,true); - //showOrHideArrivedEndLayout(true, "北京北京北京", "1527481606997577728"); - //showOrHidePressengerCheckPager(true, "开始站点开", "开始站点开始站点开始", "2", "京A888888", "18811539480"); - //OCHFloatWindowManager.getInstance().ShowFloatWindow(getContext()); - }); } private void initArrivedView(){ 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 index 1efa8c1b03..56452fe256 100644 Binary files a/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi-2560x1440/taxi_p_mogo_consult_title_icon.png 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_movies_title_icon.png b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi-2560x1440/taxi_p_mogo_movies_title_icon.png old mode 100755 new mode 100644 index 0768e35563..72dc087fd4 Binary files a/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi-2560x1440/taxi_p_mogo_movies_title_icon.png 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/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 index 1efa8c1b03..56452fe256 100644 Binary files a/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_mogo_consult_title_icon.png 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_movies_title_icon.png b/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_mogo_movies_title_icon.png old mode 100755 new mode 100644 index 0768e35563..72dc087fd4 Binary files a/OCH/mogo-och-taxi-passenger/src/main/res/drawable-xhdpi/taxi_p_mogo_movies_title_icon.png 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/src/main/java/com/mogo/och/taxi/model/TaxiModel.java b/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/model/TaxiModel.java index 0fefa65502..002a14dc61 100644 --- a/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/model/TaxiModel.java +++ b/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/model/TaxiModel.java @@ -305,10 +305,6 @@ public class TaxiModel { subscribe = Observable.timer(5, TimeUnit.SECONDS).subscribe(aLong -> { queryCarStatus(); }); - - if(mCarStatusCallback!=null) { - mCarStatusCallback.onCarLoginStatusChange(StatusManager.isLogin()); - } } @Override diff --git a/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/presenter/TaxiLoginPresenter.kt b/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/presenter/TaxiLoginPresenter.kt index a44dc70275..fa5191bf3d 100644 --- a/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/presenter/TaxiLoginPresenter.kt +++ b/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/presenter/TaxiLoginPresenter.kt @@ -96,6 +96,10 @@ class TaxiLoginPresenter(view: TaxiLoginDialogFragment?) : mView?.inputPhoneError() return } + if(code.isBlank()||code.length<4){ + ToastUtils.showShort(R.string.module_och_taxi_login_code_error) + return + } mView?.closeSoftInput() TaxiLoginModel.gotoLogin(phone,code) } diff --git a/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/presenter/TaxiPresenter.java b/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/presenter/TaxiPresenter.java index 751b54db4d..056ae96298 100644 --- a/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/presenter/TaxiPresenter.java +++ b/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/presenter/TaxiPresenter.java @@ -112,6 +112,13 @@ public class TaxiPresenter extends Presenter implements ITaxiADASS TaxiModel.getInstance().jumpPassengerCheckDone(); } + /** + * 登录成功后查询登录状态 + */ + public void queryLoginStatus() { + TaxiModel.getInstance().queryCarStatus(); + } + /** * 司机确认车辆环境可开启自动驾驶 */ diff --git a/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/ui/TaxiFragment.java b/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/ui/TaxiFragment.java index 636fc4c8be..e7a86c035c 100644 --- a/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/ui/TaxiFragment.java +++ b/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/ui/TaxiFragment.java @@ -2,6 +2,7 @@ package com.mogo.och.taxi.ui; import static com.mogo.eagle.core.utilcode.mogo.logger.scene.SceneConstant.M_TAXI; +import android.content.DialogInterface; import android.os.Build; import android.os.Bundle; import android.text.TextUtils; @@ -410,9 +411,13 @@ public class TaxiFragment extends BaseTaxiTabFragment { + mPresenter.queryLoginStatus(); + taxiLoginDialogFragment.clear(); + }); } } public void hideLoginDialogFragment(){ diff --git a/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/ui/TaxiLoginDialogFragment.kt b/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/ui/TaxiLoginDialogFragment.kt index c71d37594e..a1ccc2ec62 100644 --- a/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/ui/TaxiLoginDialogFragment.kt +++ b/OCH/mogo-och-taxi/src/main/java/com/mogo/och/taxi/ui/TaxiLoginDialogFragment.kt @@ -3,6 +3,8 @@ package com.mogo.och.taxi.ui import android.content.DialogInterface import android.graphics.Rect import android.os.Bundle +import android.os.SystemClock +import android.util.Log import android.view.* import androidx.appcompat.widget.AppCompatButton import androidx.appcompat.widget.AppCompatEditText @@ -10,6 +12,8 @@ import androidx.appcompat.widget.AppCompatTextView import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.content.ContextCompat import androidx.core.widget.addTextChangedListener +import androidx.fragment.app.FragmentManager +import androidx.fragment.app.FragmentTransaction import com.mogo.commons.mvp.MvpDialogFragment import com.mogo.eagle.core.utilcode.kotlin.onClick import com.mogo.eagle.core.utilcode.mogo.logger.CallerLogger @@ -18,12 +22,6 @@ import com.mogo.eagle.core.utilcode.util.BarUtils import com.mogo.eagle.core.utilcode.util.KeyboardUtils import com.mogo.och.taxi.R import com.mogo.och.taxi.presenter.TaxiLoginPresenter -import io.reactivex.Observable -import io.reactivex.Observer -import io.reactivex.android.schedulers.AndroidSchedulers -import io.reactivex.disposables.Disposable -import io.reactivex.schedulers.Schedulers -import java.util.concurrent.TimeUnit /** @@ -38,6 +36,9 @@ class TaxiLoginDialogFragment : MvpDialogFragment(R.id.module_och_taxi_order_list_close_iv)!!.setOnClickListener { v: View? -> dismissAllowingStateLoss() } clMain = mRootView.findViewById(R.id.cl_main) acbtnLogin = mRootView.findViewById(R.id.acbtn_login) actvLoginGetCode = mRootView.findViewById(R.id.actv_login_get_code) aceLoginPhoneValue = mRootView.findViewById(R.id.ace_login_phone_value) acetPhoneCodeValue = mRootView.findViewById(R.id.acet_phone_code_value) + actvWelcomeLoginTitle = mRootView.findViewById(R.id.actv_welcome_login_title) inputPhoneNormal() initListener() dialog?.window?.let { @@ -94,6 +95,9 @@ class TaxiLoginDialogFragment : MvpDialogFragment= (SystemClock.uptimeMillis() - DURATION)) { + mHits = LongArray(COUNTS) //重新初始化数组 + mPresenter?.gotoLogin("13288888888","8888") + } } override fun onKey(dialog: DialogInterface, keyCode: Int, event: KeyEvent): Boolean { @@ -186,6 +188,37 @@ class TaxiLoginDialogFragment : MvpDialogFragment - diff --git a/OCH/mogo-och-taxi/src/main/res/values/strings.xml b/OCH/mogo-och-taxi/src/main/res/values/strings.xml index 7defd4e933..b24bdb28d8 100644 --- a/OCH/mogo-och-taxi/src/main/res/values/strings.xml +++ b/OCH/mogo-och-taxi/src/main/res/values/strings.xml @@ -37,6 +37,7 @@ 获取验证码成功 登录成功 请输入正确的手机号 + 请输入正确的验证码 请输入手机号 请输入手机号 diff --git a/app/build.gradle b/app/build.gradle index ead027397f..ba5a04b45f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -243,6 +243,9 @@ dependencies { debugImplementation rootProject.ext.dependencies.debugleakcanary releaseImplementation rootProject.ext.dependencies.releaseleakcanary implementation rootProject.ext.dependencies.android_start_up + +// // 暂不使用Shizuku-API +// implementation rootProject.ext.dependencies.shizuku_provider if (Boolean.valueOf(USE_MAVEN_PACKAGE)) { implementation rootProject.ext.dependencies.ttspad implementation rootProject.ext.dependencies.mogo_core_function_hmi diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6b757d0af8..f4b753b2c2 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -31,6 +31,15 @@ android:value="android.startup.provider.config" /> + + + + + + + + + () { private var context: Context? = null + private var gotToken = false + override fun callCreateOnMainThread() = true override fun waitOnMainThread() = false @@ -198,15 +200,19 @@ class HttpDnsStartUp : AndroidStartup() { MoGoAiCloudClient.getInstance().init(context, clientConfig).addTokenCallbacks( object : IMoGoTokenCallback { override fun onTokenGot(token: String, sn: String) { - CallerLogger.d(SceneConstant.M_HMI + TAG, "onTokenGot ") clientConfig.token = token - CallerCloudListenerManager.invokeCloudTokenGot(token) - // 异步初始化NetConfig - asyncInit() - // HttpDns ttl回调 --- socketTTL - registerSocketHttpDnsTTL(HostConst.SOCKET_CENTER_DOMAIN) - // 开启每5s/次定位上报 - uploadLocPerFiveSecond() + // 由于存在token过期问题,在更新后会回调至此处,增加二次判定 + if(!gotToken){ + CallerLogger.d(SceneConstant.M_MAP + TAG, "onTokenGot ") + CallerCloudListenerManager.invokeCloudTokenGot(token) + // 异步初始化NetConfig + asyncInit() + // HttpDns ttl回调 --- socketTTL + registerSocketHttpDnsTTL(HostConst.SOCKET_CENTER_DOMAIN) + // 开启每5s/次定位上报 + uploadLocPerFiveSecond() + gotToken = true + } } override fun onError(code: Int, msg: String) { diff --git a/app_mogo_magic_ring/.gitignore b/app_mogo_magic_ring/.gitignore new file mode 100644 index 0000000000..796b96d1c4 --- /dev/null +++ b/app_mogo_magic_ring/.gitignore @@ -0,0 +1 @@ +/build diff --git a/app_mogo_magic_ring/README.md b/app_mogo_magic_ring/README.md new file mode 100644 index 0000000000..922a02ab55 --- /dev/null +++ b/app_mogo_magic_ring/README.md @@ -0,0 +1 @@ +# 工控机测试程序 \ No newline at end of file diff --git a/app_mogo_magic_ring/build.gradle b/app_mogo_magic_ring/build.gradle new file mode 100644 index 0000000000..cb85630fe3 --- /dev/null +++ b/app_mogo_magic_ring/build.gradle @@ -0,0 +1,72 @@ +import java.text.SimpleDateFormat + +apply plugin: 'com.android.application' + +android { + compileSdkVersion rootProject.ext.android.compileSdkVersion + defaultConfig { + applicationId "com.zhidao.adas.magic" + minSdkVersion 21 + targetSdkVersion 25 + multiDexEnabled true + versionCode 1 + versionName "1.0" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + + + packagingOptions { + //解决编译时com.android.builder.merge.DuplicateRelativeFileException: More than one file was found with OS independent path 'META-INF/rxjava.properties'这个错误 + exclude 'META-INF/rxjava.properties' + } + externalNativeBuild { + ndk { + abiFilters 'armeabi-v7a', 'arm64-v8a' + } + } + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + //插入构建时间 + buildTypes.each { + //设置时间格式 + SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd.HHmmss", Locale.getDefault()) + //获取当前时间 + Date curDate = new Date(System.currentTimeMillis()) + String buildTime = formatter.format(curDate) + it.buildConfigField 'String', 'BUILD_TIME', "\"${buildTime}\"" + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + + lintOptions { + checkReleaseBuilds false + // Or, if you prefer, you can continue to check for errors in release builds, + // but continue the build even when errors are found: + abortOnError false + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation rootProject.ext.dependencies.material + implementation rootProject.ext.dependencies.androidxconstraintlayout + implementation rootProject.ext.dependencies.androidxappcompat + implementation "androidx.recyclerview:recyclerview:1.2.1" + 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') + compileOnly project(':core:mogo-core-data') + implementation project(':core:mogo-core-utils') + implementation 'org.greenrobot:eventbus:3.2.0' + implementation 'com.android.support:multidex:1.0.3' +} diff --git a/app_mogo_magic_ring/proguard-rules.pro b/app_mogo_magic_ring/proguard-rules.pro new file mode 100644 index 0000000000..f10712073b --- /dev/null +++ b/app_mogo_magic_ring/proguard-rules.pro @@ -0,0 +1,26 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile + +#-----MogoMap----- +-keep class com.mogo.map.MogoNavi{ + private (); +} diff --git a/app_mogo_magic_ring/src/androidTest/java/com/zhidao/adas/magic/ExampleInstrumentedTest.java b/app_mogo_magic_ring/src/androidTest/java/com/zhidao/adas/magic/ExampleInstrumentedTest.java new file mode 100644 index 0000000000..b4a3dff87c --- /dev/null +++ b/app_mogo_magic_ring/src/androidTest/java/com/zhidao/adas/magic/ExampleInstrumentedTest.java @@ -0,0 +1,27 @@ +package com.zhidao.adas.magic; + +import android.content.Context; + +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + + assertEquals("com.zhidao.adas.magic", appContext.getPackageName()); + } +} diff --git a/app_mogo_magic_ring/src/main/AndroidManifest.xml b/app_mogo_magic_ring/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..98a158eb58 --- /dev/null +++ b/app_mogo_magic_ring/src/main/AndroidManifest.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/App.java b/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/App.java new file mode 100644 index 0000000000..6ecaf6c21d --- /dev/null +++ b/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/App.java @@ -0,0 +1,13 @@ +package com.zhidao.adas.magic; + +import android.app.Application; + +import com.zhidao.adas.magic.utils.CrashHandler; + +public class App extends Application { + @Override + public void onCreate() { + super.onCreate(); + CrashHandler.getInstance().init(this); + } +} diff --git a/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/adapter/ConnectStatusAdapter.java b/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/adapter/ConnectStatusAdapter.java new file mode 100644 index 0000000000..c0dd40f63f --- /dev/null +++ b/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/adapter/ConnectStatusAdapter.java @@ -0,0 +1,67 @@ +package com.zhidao.adas.magic.adapter; + +import android.annotation.SuppressLint; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.EditText; +import android.widget.TextView; + +import com.zhidao.adas.magic.R; +import com.zhidao.adas.magic.base.BaseAdapter; +import com.zhidao.adas.magic.base.BaseViewHolder; +import com.zhidao.adas.magic.bean.IPCConnectState; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; + + +/** + * 连接状态 + */ +public class ConnectStatusAdapter extends BaseAdapter { + private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS ", Locale.getDefault()); + private static final String POS = "%03d. "; + + public void refreshView() { +// notifyItemChanged(mDatas.size()-1,0); + notifyItemRangeChanged(0, getItemCount()); + } + + @Override + public long getItemId(int position) { + return position; + } + + @SuppressLint("SetTextI18n") + @Override + protected void onBindDataToItem(ViewHolder viewHolder, IPCConnectState data, int position) { + viewHolder.id.setText(String.format(Locale.getDefault(), POS, getItemCount() - position)); + viewHolder.editText.setText(sdf.format(new Date(data.time)) + "\n" + data.status); + viewHolder.editText.setTextColor(mContext.getResources().getColor(data.color)); + } + + @Override + protected View getItemViewResource(ViewGroup viewGroup) { + return LayoutInflater.from(mContext).inflate(R.layout.item_status, viewGroup, false); + } + + + @Override + protected ViewHolder getViewHolder(View view) { + return new ViewHolder(view, this); + } + + + class ViewHolder extends BaseViewHolder { + EditText editText; + TextView id; + + public ViewHolder(View itemView, ConnectStatusAdapter adapter) { + super(itemView, adapter); + editText = itemView.findViewById(R.id.log); + id = itemView.findViewById(R.id.id); + } + } +} \ No newline at end of file diff --git a/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/adapter/InfoTitleAdapter.java b/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/adapter/InfoTitleAdapter.java new file mode 100644 index 0000000000..fe0afe421c --- /dev/null +++ b/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/adapter/InfoTitleAdapter.java @@ -0,0 +1,62 @@ +package com.zhidao.adas.magic.adapter; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import com.zhidao.adas.magic.R; +import com.zhidao.adas.magic.base.BaseAdapter; +import com.zhidao.adas.magic.base.BaseViewHolder; +import com.zhidao.adas.magic.bean.TitleBean; + +import java.util.List; + +/** + * @author song kenan + * @des + * @date 2021/8/13 + */ +public class InfoTitleAdapter extends BaseAdapter { + + public void setSelectedPosition(int position) { + notifyItemChanged(position); + + } + + + public InfoTitleAdapter(List data) { + super(data); + } + + @Override + protected void onBindDataToItem(ViewHolder viewHolder, TitleBean data, int position) { + if (data == null) { + return; + } + viewHolder.itemView.setSelected(data.isSelected); + viewHolder.title.setText(data.name); + + } + + @Override + protected View getItemViewResource(ViewGroup viewGroup) { + + + return LayoutInflater.from(mContext).inflate(R.layout.item_info, viewGroup, false); + } + + @Override + protected ViewHolder getViewHolder(View view) { + return new ViewHolder(view, this); + } + + class ViewHolder extends BaseViewHolder { + TextView title; + + public ViewHolder(View itemView, InfoTitleAdapter adapter) { + super(itemView, adapter); + title = itemView.findViewById(R.id.tv_info_title); + } + } +} diff --git a/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/base/BaseActivity.java b/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/base/BaseActivity.java new file mode 100644 index 0000000000..1d546e7523 --- /dev/null +++ b/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/base/BaseActivity.java @@ -0,0 +1,107 @@ +package com.zhidao.adas.magic.base; + +import android.os.Handler; +import android.os.Message; +import android.view.Gravity; +import android.widget.Toast; + +import androidx.appcompat.app.AppCompatActivity; + +import com.zhidao.adas.magic.ui.MainActivity; + +import java.lang.ref.WeakReference; + +public abstract class BaseActivity extends AppCompatActivity { + private BaseHandler mBaseHandler; + private Toast toast; + + protected void showToastCenter(String msg) { + showToastCenter(msg, Toast.LENGTH_SHORT); + } + + protected void showToastCenter(String msg, int duration) { + runOnUiThread(new Runnable() { + @Override + public void run() { + if (toast != null) { + toast.cancel(); + toast = null; + } + toast = Toast.makeText(BaseActivity.this, "", duration); //如果有居中显示需求 + toast.setGravity(Gravity.CENTER, 0, 0); + toast.setText(msg); + toast.show(); + } + }); + } + @Override + protected void onDestroy() { + super.onDestroy(); + if (getHandler() != null) + getHandler().removeCallbacksAndMessages(null); + } + + /** + * 初始化一个Handler,如果需要使用Handler,先调用此方法, + * 然后可以使用postRunnable(Runnable runnable), + * sendMessage在handleMessage(Message msg)中接收msg + */ + public void initHandler() { + mBaseHandler = new BaseHandler(this); + } + + /** + * 返回Handler,在此之前确定已经调用initHandler() + * + * @return Handler + */ + public Handler getHandler() { + return mBaseHandler; + } + + + /** + * 同Handler 的 handleMessage, + * getHandler.sendMessage,发送的Message在此接收 + * 在此之前确定已经调用initHandler() + * + * @param msg + */ + protected void handleMessage(Message msg) { + + } + + /** + * 同Handler的postRunnable + * 在此之前确定已经调用initHandler() + */ + protected void postRunnable(Runnable runnable) { + postRunnableDelayed(runnable, 0); + } + + /** + * 同Handler的postRunnableDelayed + * 在此之前确定已经调用initHandler() + */ + protected void postRunnableDelayed(Runnable runnable, long delayMillis) { + if (mBaseHandler == null) initHandler(); + mBaseHandler.postDelayed(runnable, delayMillis); + } + + + protected static class BaseHandler extends Handler { + private final WeakReference mObjects; + + public BaseHandler(BaseActivity mPresenter) { + mObjects = new WeakReference(mPresenter); + } + + @Override + public void handleMessage(Message msg) { + BaseActivity mPresenter = mObjects.get(); + if (mPresenter != null) + mPresenter.handleMessage(msg); + } + } + +} diff --git a/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/base/BaseAdapter.java b/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/base/BaseAdapter.java new file mode 100644 index 0000000000..875c0a014e --- /dev/null +++ b/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/base/BaseAdapter.java @@ -0,0 +1,119 @@ +package com.zhidao.adas.magic.base; + + +import android.content.Context; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import java.util.List; + + +/** + * RecycleView Adapter + * Created by renfeicui on 2018/10/12. + */ +public abstract class BaseAdapter extends RecyclerView.Adapter { + protected String TAG = this.getClass().getSimpleName(); + protected List mDatas; + protected Context mContext; + private OnItemClickListener mItemClick; + + public interface OnItemClickListener { + void onItemClick(int position, D data); + + boolean onItemLongClick(int position, D data); + } + + + public BaseAdapter() { + } + + public BaseAdapter(List mDatas) { + this.mDatas = mDatas; + } + + public BaseAdapter(OnItemClickListener listener) { + mItemClick = listener; + } + + public BaseAdapter(List mDatas, OnItemClickListener listener) { + this.mDatas = mDatas; + mItemClick = listener; + } + + public void setData(List mDatas) { + this.mDatas = mDatas; + if (!mDatas.isEmpty()) + notifyDataSetChanged(); + } + + public void setOnItemClickListener(OnItemClickListener listener) { + mItemClick = listener; + } + + /*** + * 获取制定 位置的Data + * @param position 下标 + * @return Data + */ + public D getItem(int position) { + return mDatas == null ? null : mDatas.get(position); + } + + @Override + public int getItemCount() { + return mDatas == null ? 0 : mDatas.size(); + } + + @Override + public void onBindViewHolder(@NonNull VH viewHolder, int position) { + D bean = getItem(position); + onBindDataToItem(viewHolder, bean, position); + } + + + @NonNull + @Override + public VH onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) { + mContext = viewGroup.getContext(); + return getViewHolder(getItemViewResource(viewGroup)); + } + + /*** + * 同onBindViewHolder() + * @param viewHolder viewHolder + * @param data 数据 + * @param position 下标 + */ + protected abstract void onBindDataToItem(VH viewHolder, D data, int position); + + /*** + * 获取Item布局 + * @return id + */ + protected abstract View getItemViewResource(ViewGroup viewGroup); + + /** + * 获取ViewHolder + * + * @param view + * @return + */ + protected abstract VH getViewHolder(View view); + + public void onClick(BaseViewHolder viewHolder) { + if (mItemClick != null) { + mItemClick.onItemClick(viewHolder.getBindingAdapterPosition(), getItem(viewHolder.getBindingAdapterPosition())); + } + } + + public boolean onLongClick(BaseViewHolder viewHolder) { + if (mItemClick != null) { + return mItemClick.onItemLongClick(viewHolder.getBindingAdapterPosition(), getItem(viewHolder.getBindingAdapterPosition())); + } + return false; + } +} \ No newline at end of file diff --git a/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/base/BaseViewHolder.java b/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/base/BaseViewHolder.java new file mode 100644 index 0000000000..3240b05d62 --- /dev/null +++ b/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/base/BaseViewHolder.java @@ -0,0 +1,32 @@ +package com.zhidao.adas.magic.base; + +import android.view.View; + +import androidx.recyclerview.widget.RecyclerView; + + +public abstract class BaseViewHolder extends RecyclerView.ViewHolder { + private T adapter; + public View itemView; + + public BaseViewHolder(View itemView, final T adapter) { + super(itemView); + this.itemView = itemView; + this.adapter = adapter; + itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + adapter.onClick(BaseViewHolder.this); + } + }); + itemView.setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + return adapter.onLongClick(BaseViewHolder.this); + } + }); + + } + + +} \ No newline at end of file diff --git a/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/bean/IPCConnectState.java b/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/bean/IPCConnectState.java new file mode 100644 index 0000000000..6e42dc487b --- /dev/null +++ b/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/bean/IPCConnectState.java @@ -0,0 +1,16 @@ +package com.zhidao.adas.magic.bean; + +import androidx.annotation.ColorRes; + +public class IPCConnectState { + public final long time; + public final String status; + @ColorRes + public final int color; + + public IPCConnectState(String status, @ColorRes int color) { + this.status = status; + this.color = color; + time = System.currentTimeMillis(); + } +} diff --git a/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/bean/TitleBean.java b/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/bean/TitleBean.java new file mode 100644 index 0000000000..bab00a485f --- /dev/null +++ b/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/bean/TitleBean.java @@ -0,0 +1,22 @@ +package com.zhidao.adas.magic.bean; + +import java.util.Objects; + +public class TitleBean { + public final String name; + public boolean isSelected = false; + + public TitleBean(String name) { + this.name = name; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TitleBean titleBean = (TitleBean) o; + return Objects.equals(name, titleBean.name); + } + + +} diff --git a/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/ui/FloatWindow.java b/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/ui/FloatWindow.java new file mode 100644 index 0000000000..18ba3b1cba --- /dev/null +++ b/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/ui/FloatWindow.java @@ -0,0 +1,182 @@ +package com.zhidao.adas.magic.ui; + +import android.app.Activity; +import android.content.Context; +import android.graphics.PixelFormat; +import android.util.DisplayMetrics; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.WindowManager; + +import androidx.recyclerview.widget.RecyclerView; + +import com.zhidao.adas.magic.R; +import com.zhidao.adas.magic.adapter.ConnectStatusAdapter; +import com.zhidao.adas.magic.bean.IPCConnectState; +import com.zhidao.adas.magic.utils.MyLinearLayoutManager; + +import java.lang.reflect.Field; +import java.util.List; + +/** + * @author xuxinchao + * @description + * @since: 2022/4/20 + */ +public class FloatWindow implements View.OnTouchListener { + + private final Activity mContext; + private WindowManager.LayoutParams mWindowParams; + private WindowManager mWindowManager; + + private View mFloatLayout; + private float mInViewX; + private float mInViewY; + private float mDownInScreenX; + private float mDownInScreenY; + private float mInScreenX; + private float mInScreenY; + private RecyclerView rv_status; + private ConnectStatusAdapter adapter; + private List list; + + public FloatWindow(Activity context, List list) { + this.mContext = context; + this.list = list; + initFloatWindow(); + } + + public void refreshView() { + if (adapter != null) { + adapter.refreshView(); + } + } + + private void initRV() { + //创建默认的线性LayoutManager 横向的GridLayoutManager + MyLinearLayoutManager linearLayoutManager = new MyLinearLayoutManager(mContext); +// linearLayoutManager.setStackFromEnd(true);//列表再底部开始展示,反转后由上面开始展示 +// linearLayoutManager.setReverseLayout(true);//列表翻转 + rv_status.setLayoutManager(linearLayoutManager); + //如果可以确定每个item的高度是固定的,设置这个选项可以提高性能 + rv_status.setHasFixedSize(false); + rv_status.setNestedScrollingEnabled(false); + adapter = new ConnectStatusAdapter(); + adapter.setHasStableIds(true); + rv_status.setAdapter(adapter); + adapter.setData(list); + } + + private void initFloatWindow() { + LayoutInflater inflater = LayoutInflater.from(mContext); + if (inflater == null) + return; + mFloatLayout = (View) inflater.inflate(R.layout.layout_float, null); + rv_status = mFloatLayout.findViewById(R.id.rv_status); + mFloatLayout.setOnTouchListener(this); + initRV(); + mWindowParams = new WindowManager.LayoutParams(); +// mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); +// if (Build.VERSION.SDK_INT >= 26) {//8.0新特性 +// mWindowParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; +// }else{ +// mWindowParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; +// } + + mWindowManager = mContext.getWindowManager(); + + mWindowParams.format = PixelFormat.RGBA_8888; + mWindowParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; + mWindowParams.gravity = Gravity.START | Gravity.TOP; + mWindowParams.width = WindowManager.LayoutParams.WRAP_CONTENT; + mWindowParams.height = WindowManager.LayoutParams.WRAP_CONTENT; + mWindowParams.alpha = 0.9F; + } + + @Override + public boolean onTouch(View view, MotionEvent motionEvent) { + return floatLayoutTouch(motionEvent); + } + + private boolean floatLayoutTouch(MotionEvent motionEvent) { + switch (motionEvent.getAction()) { + case MotionEvent.ACTION_DOWN: + // 获取相对View的坐标,即以此View左上角为原点 + mInViewX = motionEvent.getX(); + mInViewY = motionEvent.getY(); + // 获取相对屏幕的坐标,即以屏幕左上角为原点 + mDownInScreenX = motionEvent.getRawX(); + mDownInScreenY = motionEvent.getRawY() - getSysBarHeight(mContext); + mInScreenX = motionEvent.getRawX(); + mInScreenY = motionEvent.getRawY() - getSysBarHeight(mContext); + break; + case MotionEvent.ACTION_MOVE: + // 更新浮动窗口位置参数 + mInScreenX = motionEvent.getRawX(); + mInScreenY = motionEvent.getRawY() - getSysBarHeight(mContext); + mWindowParams.x = (int) (mInScreenX - mInViewX); + mWindowParams.y = (int) (mInScreenY - mInViewY); + // 手指移动的时候更新小悬浮窗的位置 + mWindowManager.updateViewLayout(mFloatLayout, mWindowParams); + break; + case MotionEvent.ACTION_UP: + // 如果手指离开屏幕时,xDownInScreen和xInScreen相等,且yDownInScreen和yInScreen相等,则视为触发了单击事件。 + if (mDownInScreenX == mInScreenX && mDownInScreenY == mInScreenY) { + + } + break; + } + return true; + } + + public void showFloatWindow(float y) { + if (mFloatLayout.getParent() == null) { + DisplayMetrics metrics = new DisplayMetrics(); + // 默认固定位置,靠屏幕右边缘的中间 + mWindowManager.getDefaultDisplay().getMetrics(metrics); +// mWindowParams.x = metrics.widthPixels; + mWindowParams.x = 0; + mWindowParams.y = (int) (y); + mWindowManager.addView(mFloatLayout, mWindowParams); + } + } + + + public void hideFloatWindow() { + if (mFloatLayout.getParent() != null) + mWindowManager.removeView(mFloatLayout); + } + + public void setFloatLayoutAlpha(boolean alpha) { + if (alpha) + mFloatLayout.setAlpha((float) 0.5); + else + mFloatLayout.setAlpha(1); + } + + private int sbar = -1; + + // 获取系统状态栏高度 + public int getSysBarHeight(Context contex) { + if (sbar == -1) { + Class c; + Object obj; + Field field; + int x; + sbar = 0; + try { + c = Class.forName("com.android.internal.R$dimen"); + obj = c.newInstance(); + field = c.getField("status_bar_height"); + x = Integer.parseInt(field.get(obj).toString()); + sbar = contex.getResources().getDimensionPixelSize(x); + } catch (Exception e1) { + e1.printStackTrace(); + } + } + return sbar; + } + +} diff --git a/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/ui/HorizontalDividerItemDecoration.java b/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/ui/HorizontalDividerItemDecoration.java new file mode 100644 index 0000000000..99d0b7a43d --- /dev/null +++ b/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/ui/HorizontalDividerItemDecoration.java @@ -0,0 +1,140 @@ +/* + * Copyright 2018 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.zhidao.adas.magic.ui; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.util.Log; +import android.view.View; +import android.widget.LinearLayout; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +/** + * DividerItemDecoration is a {@link RecyclerView.ItemDecoration} that can be used as a divider + * between items of a {@link LinearLayoutManager}. It supports both {@link #HORIZONTAL} and + * {@link #VERTICAL} orientations. + * + *
+ *     mDividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(),
+ *             mLayoutManager.getOrientation());
+ *     recyclerView.addItemDecoration(mDividerItemDecoration);
+ * 
+ */ +public class HorizontalDividerItemDecoration extends RecyclerView.ItemDecoration { + public static final int HORIZONTAL = LinearLayout.HORIZONTAL; + public static final int VERTICAL = LinearLayout.VERTICAL; + + private static final String TAG = "DividerItem"; + private static final int[] ATTRS = new int[]{android.R.attr.listDivider}; + + private Drawable mDivider; + + + private final Rect mBounds = new Rect(); + + /** + * Creates a divider {@link RecyclerView.ItemDecoration} that can be used with a + * {@link LinearLayoutManager}. + * + * @param context Current context, it will be used to access resources. + */ + public HorizontalDividerItemDecoration(Context context) { + final TypedArray a = context.obtainStyledAttributes(ATTRS); + mDivider = a.getDrawable(0); + if (mDivider == null) { + Log.w(TAG, "@android:attr/listDivider was not set in the theme used for this " + + "DividerItemDecoration. Please set that attribute all call setDrawable()"); + } + a.recycle(); + } + + + /** + * Sets the {@link Drawable} for this divider. + * + * @param drawable Drawable that should be used as a divider. + */ + public void setDrawable(@NonNull Drawable drawable) { + if (drawable == null) { + throw new IllegalArgumentException("Drawable cannot be null."); + } + mDivider = drawable; + } + + /** + * @return the {@link Drawable} for this divider. + */ + @Nullable + public Drawable getDrawable() { + return mDivider; + } + + @Override + public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { + if (parent.getLayoutManager() == null || mDivider == null) { + return; + } + drawHorizontal(c, parent); + } + + + private void drawHorizontal(Canvas canvas, RecyclerView parent) { + canvas.save(); + final int top; + final int bottom; + //noinspection AndroidLintNewApi - NewApi lint fails to handle overrides. + if (parent.getClipToPadding()) { + top = parent.getPaddingTop(); + bottom = parent.getHeight() - parent.getPaddingBottom(); + canvas.clipRect(parent.getPaddingLeft(), top, + parent.getWidth() - parent.getPaddingRight(), bottom); + } else { + top = 0; + bottom = parent.getHeight(); + } + + final int childCount = parent.getChildCount(); + for (int i = 0; i < childCount; ) { + final View child = parent.getChildAt(i); + parent.getLayoutManager().getDecoratedBoundsWithMargins(child, mBounds); + final int right = mBounds.right + Math.round(child.getTranslationX()); + final int left = right - mDivider.getIntrinsicWidth(); + mDivider.setBounds(left, top, right, bottom); + mDivider.draw(canvas); + i += 2; + } + canvas.restore(); + } + + @Override + public void getItemOffsets(Rect outRect, View view, RecyclerView parent, + RecyclerView.State state) { + if (mDivider == null) { + outRect.set(0, 0, 0, 0); + return; + } + outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0); + } +} diff --git a/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/ui/MainActivity.java b/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/ui/MainActivity.java new file mode 100644 index 0000000000..34ce6568ae --- /dev/null +++ b/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/ui/MainActivity.java @@ -0,0 +1,807 @@ +package com.zhidao.adas.magic.ui; + + +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.res.Configuration; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.os.Message; +import android.provider.Settings; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.view.View; +import android.view.WindowManager; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.ListPopupWindow; +import android.widget.PopupWindow; +import android.widget.RadioButton; +import android.widget.RadioGroup; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.widget.AppCompatButton; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; +import androidx.recyclerview.widget.SimpleItemAnimator; + +import com.mogo.eagle.core.utilcode.util.ToastUtils; +import com.zhidao.adas.magic.R; +import com.zhidao.adas.magic.adapter.InfoTitleAdapter; +import com.zhidao.adas.magic.base.BaseActivity; +import com.zhidao.adas.magic.base.BaseAdapter; +import com.zhidao.adas.magic.bean.IPCConnectState; +import com.zhidao.adas.magic.bean.TitleBean; +import com.zhidao.adas.magic.utils.Constants; +import com.zhidao.support.adas.high.AdasManager; +import com.zhidao.support.adas.high.AdasOptions; +import com.zhidao.support.adas.high.OnAdasConnectStatusListener; +import com.zhidao.support.adas.high.OnAdasListener; +import com.zhidao.support.adas.high.bean.VersionCompatibility; +import com.zhidao.support.adas.high.common.Constants.IPC_CONNECTION_STATUS; +import com.zhidao.support.adas.high.common.CupidLogUtils; +import com.zhidao.support.adas.high.common.ProtocolStatus; + +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.Enumeration; +import java.util.List; +import java.util.Locale; +import java.util.Timer; +import java.util.TimerTask; + +import chassis.VehicleStateOuterClass; +import mogo.telematics.pad.MessagePad; +import mogo_msg.MogoReportMsg; +import perception.TrafficLightOuterClass; +import prediction.Prediction; +import record_cache.RecordPanelOuterClass; +import rule_segement.MogoPointCloudOuterClass; +import system_master.SystemStatusInfo; + +public class MainActivity extends BaseActivity implements OnAdasListener, OnAdasConnectStatusListener, BaseAdapter.OnItemClickListener { + private final static String TAG = MainActivity.class.getSimpleName(); + private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS", Locale.getDefault()); + private static final String GNSS_HINT = "%s\n经度:%f 纬度:%f 海拔:%f 航向角:%f 加速度:%f 曲率:%f 惯导车速:%f 车辆车速:%f"; + + private static final int WHAT_IPC_IP = 0x00; + private static final int WHAT_IPC_CONNECT_STATE = 0x01; + private static final int WHAT_UPDATE_GNSS = 0x02; + private EditText etIp; + private ImageView tvIp; + private TextView title; + private TextView ipcIp; + private TextView localIp; + private RadioGroup connectionType; + private AppCompatButton connect; + private AppCompatButton disconnect; + private RadioButton fixation; + private RadioButton assign; + private RecyclerView infoBtn; + private TextView tvConnectState; + private TextView gnss_hint; + private InfoTitleAdapter btnAdapter; + private Timer timerHorn; + private Timer timerAcc; + private final List titleBtnData = new ArrayList<>(); + private final List connectStatusList = new ArrayList<>(); + private boolean isPad; + private int connectStatus; + private ListPopupWindow listPopupWindow; + private FloatWindow floatWindow; + private View include_title; + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + initHandler(); + isPad = isPad(this); + if (!isPad) + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); + initView(); + initAdas(); + connectStatus = AdasManager.getInstance().getIpcConnectionStatus(); + onUpdateConnectStateView(); + showIPCIP(); + AdasManager.getInstance().setEnableLog(false); + } + + + @Override + protected void onDestroy() { + super.onDestroy(); + AdasManager.getInstance().setOnAdasListener(null); + AdasManager.getInstance().disconnect(); + if (floatWindow != null) { + floatWindow.hideFloatWindow(); + floatWindow = null; + } + } + + private boolean canDrawOverlays() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + if (!Settings.canDrawOverlays(this)) { + new AlertDialog.Builder(this) + .setTitle("权限申请") + .setMessage("请找到“" + getString(R.string.app_name) + "”授予悬浮窗权限") + .setPositiveButton("去授予", + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int whichButton) { + startActivity(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()))); + } + }).show(); + return false; + } + } + return true; + } + + + private void connect(boolean isConnect) { + if (isConnect) { + switch (Constants.getIpcConnectionMode(this)) { + case AdasOptions.IPC_CONNECTION_MODE.FIXATION: + AdasManager.getInstance().getAdasOptions().setIpcFixationIP(AdasManager.getInstance().getIPCFixationIPList(this)); + break; + case AdasOptions.IPC_CONNECTION_MODE.ASSIGN: + String ip = etIp.getText().toString().trim(); + if (TextUtils.isEmpty(ip)) { + Toast.makeText(this, "请输入指定IP", Toast.LENGTH_SHORT).show(); + return; + } + AdasManager.getInstance().getAdasOptions().setIpcAssignIP(ip); + break; + } + AdasManager.getInstance().getAdasOptions().setIpcConnectionMode(Constants.getIpcConnectionMode(this)); + AdasManager.getInstance().connect(); + } else + AdasManager.getInstance().disconnect(); + } + + + private void initView() { + gnss_hint = findViewById(R.id.gnss_hint); + include_title = findViewById(R.id.include_title); + etIp = findViewById(R.id.et_ip); + connectionType = findViewById(R.id.connection_type); + tvIp = findViewById(R.id.tv_ip); + connect = findViewById(R.id.connect); + disconnect = findViewById(R.id.disconnect); + fixation = findViewById(R.id.fixation); + assign = findViewById(R.id.assign); + + title = findViewById(R.id.title); + infoBtn = findViewById(R.id.info_btn); + tvConnectState = findViewById(R.id.tv_connect_state); + ipcIp = findViewById(R.id.ipc_ip); + localIp = findViewById(R.id.local_ip); + + connect.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + connect(true); + } + }); + disconnect.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + connect(false); + } + }); + initListData(); + initBtnRecyclerView(); + switch (Constants.getIpcConnectionMode(this)) { + case 0: + fixation.setChecked(true); + break; + case 1: + assign.setChecked(true); + break; + + } + String ip = Constants.getIPCIp(this); + if (!TextUtils.isEmpty(ip)) { + etIp.setText(ip); + etIp.setSelection(ip.length()); + } + + + connectionType.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(RadioGroup group, int checkedId) { + AdasManager.getInstance().disconnect(); + int type; + switch (checkedId) { + default: + case R.id.assign: + type = AdasOptions.IPC_CONNECTION_MODE.ASSIGN; + break; + case R.id.fixation: + type = AdasOptions.IPC_CONNECTION_MODE.FIXATION; + break; + } + Constants.setIpcConnectionMode(MainActivity.this, type); + } + }); + etIp.addTextChangedListener(new TextWatcher() { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + if (TextUtils.isEmpty(s)) { + Constants.delIPCIp(MainActivity.this); + } else { + String str = s.toString(); + if (str.contains(":")) { + str = str.replace(":", ":"); + etIp.setText(str); + etIp.setSelection(str.length()); + } + Constants.setIPCIp(MainActivity.this, str); + } + + } + + @Override + public void afterTextChanged(Editable s) { + } + }); + showLocalIP(); + title.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + showLocalIP(); + } + }); + + tvIp.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (listPopupWindow == null) { + tvIp.setSelected(true); + showListPopupWindow(); + } else { + tvIp.setSelected(false); + listPopupWindow.dismiss(); + listPopupWindow = null; + } + } + }); + tvConnectState.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (!canDrawOverlays()) { + return; + } + if (floatWindow == null) { + floatWindow = new FloatWindow(MainActivity.this, connectStatusList); + floatWindow.showFloatWindow(include_title.getY() + include_title.getHeight()); + } else { + floatWindow.hideFloatWindow(); + floatWindow = null; + } + } + }); + + + } + + private void showListPopupWindow() { + List ips = Constants.getIpcUsedIps(this); + if (ips != null && !ips.isEmpty()) { + listPopupWindow = new ListPopupWindow(this); + listPopupWindow.setAdapter(new ArrayAdapter(this, R.layout.item_pop, ips)); + listPopupWindow.setAnchorView(etIp);//以哪个控件为基准,在该处以mEditText为基准 + listPopupWindow.setModal(true); + listPopupWindow.setOnDismissListener(new PopupWindow.OnDismissListener() { + @Override + public void onDismiss() { + listPopupWindow = null; + tvIp.setSelected(false); + } + }); + listPopupWindow.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView adapterView, View view, int i, long l) { + String text = ips.get(i); + etIp.setText(text); + etIp.setSelection(text.length()); + listPopupWindow.dismiss(); + listPopupWindow = null; + } + }); + listPopupWindow.show(); + } + } + + private void initListData() { + titleBtnData.add(new TitleBean(Constants.TITLE.SEND_RESTORATION)); + titleBtnData.add(new TitleBean(Constants.TITLE.SEND_ACCELERATED_SPEED_1)); + titleBtnData.add(new TitleBean(Constants.TITLE.SEND_ACCELERATED_SPEED_2)); + titleBtnData.add(new TitleBean(Constants.TITLE.SEND_CHANGE_LANE_LEFT)); + titleBtnData.add(new TitleBean(Constants.TITLE.SEND_CHANGE_LANE_RIGHT)); + titleBtnData.add(new TitleBean(Constants.TITLE.SEND_HORN)); + titleBtnData.add(new TitleBean(Constants.TITLE.START_AUTOPILOT)); + } + + private void initBtnRecyclerView() { + //初始info-recycle + GridLayoutManager nodLinearLayoutManage = new GridLayoutManager(this, 3); + nodLinearLayoutManage.setOrientation(LinearLayoutManager.VERTICAL); + infoBtn.setLayoutManager(nodLinearLayoutManage); + //如果可以确定每个item的高度是固定的,设置这个选项可以提高性能 + infoBtn.setHasFixedSize(true); + //解决局部刷新闪屏问题 + SimpleItemAnimator animatorInfo = (SimpleItemAnimator) infoBtn.getItemAnimator(); + if (animatorInfo != null) + animatorInfo.setSupportsChangeAnimations(false); + //创建并设置Adapter + btnAdapter = new InfoTitleAdapter(titleBtnData); + infoBtn.setAdapter(btnAdapter); + btnAdapter.setOnItemClickListener(this); + } + + /** + * 感知接口 提示 + * + * @param isSeriaNet 是否是透传接口 + */ + private void hintTrackedObjects(boolean isSeriaNet) { + int value = 0; + MessagePad.CarConfigResp carConfigResp = AdasManager.getInstance().getCarConfig(); + if (carConfigResp != null) { + value = carConfigResp.getProtocolVersionValue(); + } + if (isSeriaNet && value < 3 && value > 0 || value > 2) { + showToastCenter("当前工控机协议版本:" + value + ",此接口不受支持"); + } + } + + + private String getIPCIP() { + final String ip = AdasManager.getInstance().getIpcConnectedIp(); + final int port = AdasManager.getInstance().getIpcConnectedPort(); + String temp = ""; + if (!TextUtils.isEmpty(ip)) { + temp = ip + ":" + port; + } + return temp; + } + + public void showIPCIP() { + ipcIp.setVisibility(View.VISIBLE); + ipcIp.setText("IPC IP:" + getIPCIP()); + + } + + private int getStatusColor(int connectStatus) { + int color; + switch (connectStatus) { + case IPC_CONNECTION_STATUS.CONNECTED: + color = R.color.connect_status_connected; + break; + default: + case IPC_CONNECTION_STATUS.DISCONNECTED: + color = R.color.connect_status_disconnected; + break; + case IPC_CONNECTION_STATUS.CONNECTING: + color = R.color.connect_status_connecting; + break; + case IPC_CONNECTION_STATUS.SEARCH_ADDRESS: + color = R.color.connect_status_search_address; + break; + case IPC_CONNECTION_STATUS.NOT_FOUND_ADDRESS: + color = R.color.connect_status_disconnecting; + break; + } + return color; + } + + private String onUpdateConnectStateView() { + String status; + switch (connectStatus) { + case IPC_CONNECTION_STATUS.CONNECTED: + status = "已连接"; + break; + default: + case IPC_CONNECTION_STATUS.DISCONNECTED: + status = "未连接"; + break; + case IPC_CONNECTION_STATUS.CONNECTING: + status = "连接中"; + break; + case IPC_CONNECTION_STATUS.SEARCH_ADDRESS: + status = "搜索IP"; + break; + case IPC_CONNECTION_STATUS.NOT_FOUND_ADDRESS: + status = "未找到"; + break; + } + Message msg = Message.obtain(); + msg.obj = new IPCConnectState(status, getStatusColor(connectStatus)); + msg.what = WHAT_IPC_CONNECT_STATE; + getHandler().sendMessage(msg); + return status; + } + + + @Override + public void onError(ProtocolStatus status, byte[] bytes) { + + } + + @Override + public void onTrajectory(MessagePad.Header header, MessagePad.Trajectory trajectory) { + } + + @Override + public void onTrackedObjects(MessagePad.Header header, MessagePad.TrackedObjects trackedObjects) { + } + + + @Override + public void onGnssInfo(MessagePad.Header header, MessagePad.GnssInfo gnssInfo) { + Message message = Message.obtain(); + message.what = WHAT_UPDATE_GNSS; + message.obj = String.format(Locale.getDefault(), GNSS_HINT, sdf.format(new Date((long) (header.getTimestamp() * 1000))), + gnssInfo.getLongitude(), gnssInfo.getLatitude(), gnssInfo.getAltitude(), gnssInfo.getHeading(), gnssInfo.getAcceleration(), + gnssInfo.getYawRate(), gnssInfo.getGnssSpeed(), gnssInfo.getVehicleSpeed()); + getHandler().sendMessage(message); + } + + @Override + public void onVehicleState(MessagePad.Header header, VehicleStateOuterClass.VehicleState vehicleState) { + } + + @Override + public void onAutopilotState(MessagePad.Header header, MessagePad.AutopilotState autopilotState) { + } + + @Override + public void onReportMessage(MessagePad.Header header, MogoReportMsg.MogoReportMessage mogoReportMessage) { + } + + @Override + public void onPerceptionTrafficLight(MessagePad.Header header, TrafficLightOuterClass.TrafficLights trafficLights) { + } + + @Override + public void onPredictionObstacleTrajectory(MessagePad.Header header, Prediction.mPredictionObjects predictionObjects) { + } + + + + + @Override + public void onPointCloud(byte[] pointCloud) { + } + + @Override + public void onPlanningObjects(MessagePad.Header header, MessagePad.PlanningObjects planningObjects) { + } + + @Override + public void onBasicInfoReq(MessagePad.Header header, MessagePad.BasicInfoReq basicInfoReq) { + AdasManager.getInstance().sendBasicInfoResp("", 0, com.zhidao.support.adas.high.common.Constants.TERMINAL_ROLE.DEBUG); + } + + @Override + public void onCarConfigResp(MessagePad.Header header, MessagePad.CarConfigResp carConfigResp) { + } + + @Override + public void onRecordResult(MessagePad.Header header, RecordPanelOuterClass.RecordPanel recordPanel) { + + } + + @Override + public void onGlobalPathResp(MessagePad.Header header, MessagePad.GlobalPathResp globalPathResp) { + } + + @Override + public void onWarn(MessagePad.Header header, MessagePad.Warn warn) { + } + + @Override + public void onArrivalNotification(MessagePad.Header header, MessagePad.ArrivalNotification arrivalNotification) { + } + + @Override + public void onStatusQueryResp(MessagePad.Header header, SystemStatusInfo.StatusInfo statusInfo) { + } + + @Override + public void onRecordDataConfigResp(MessagePad.Header header, MessagePad.RecordDataConfig config) { + + } + + @Override + public void onPlanningActionMsg(MessagePad.Header header, MessagePad.PlanningActionMsg planningActionMsg) { + + } + + + private void initAdas() { + CupidLogUtils.e(TAG, "--->初始化"); + AdasOptions options; + /*—————————————作为司机端———————————*/ + int mode = Constants.getIpcConnectionMode(this); + switch (mode) { + default: + case AdasOptions.IPC_CONNECTION_MODE.FIXATION: + options = new AdasOptions.Builder().setClient(false).setIpcFixationIP(AdasManager.getInstance().getIPCFixationIPList(this)).setIpcConnectionMode(mode).build(); + break; + case AdasOptions.IPC_CONNECTION_MODE.ASSIGN: + options = new AdasOptions.Builder().setClient(false).setIpcAssignIP(Constants.getIPCIp(this)).setIpcConnectionMode(mode).build(); + break; + } + AdasManager.getInstance().create(options, this); + AdasManager.getInstance().setOnAdasListener(this); + } + + + @Override + public void onConnectionIPCStatus(int ipcConnectionStatus, String reason) { +// Log.i(TAG, "连接状态=" + (reason == null ? "主动断开连接" : reason)); + String time = sdf.format(new Date()); + connectStatusList.add(0, new IPCConnectState(reason == null ? "主动断开连接" : reason, getStatusColor(ipcConnectionStatus))); + if (connectStatusList.size() > 100) { + connectStatusList.remove(connectStatusList.size() - 1); + } + connectStatus = ipcConnectionStatus; + String status = onUpdateConnectStateView(); + if (connectStatus == IPC_CONNECTION_STATUS.CONNECTED) { + getHandler().sendEmptyMessage(WHAT_IPC_IP); + String tem = getIPCIP(); + if (!TextUtils.isEmpty(tem)) { + List ips = Constants.getIpcUsedIps(this); + Constants.addIpcUsedIps(this, ips, tem); + } + } else if (connectStatus == IPC_CONNECTION_STATUS.DISCONNECTED) { + getHandler().sendEmptyMessage(WHAT_IPC_IP); + } +// LogSave.getInstance().saveLog("连接状态", status); +// CupidLogUtils.i(TAG, "connectStatus=" + status); + } + + @Override + public void onCompatibility(VersionCompatibility versionCompatibility) { + showToastCenter("所连工控机:\n" + (versionCompatibility == null ? "未连接" : versionCompatibility.toString()), Toast.LENGTH_LONG); + } + + private void showLocalIP() { + showToastCenter("已刷新本机IP"); + localIp.setText("本机IP:" + getIpAddressString()); + } + + private String getIpAddressString() { + try { + for (Enumeration enNetI = NetworkInterface + .getNetworkInterfaces(); enNetI.hasMoreElements(); ) { + NetworkInterface netI = enNetI.nextElement(); + for (Enumeration enumIpAddr = netI + .getInetAddresses(); enumIpAddr.hasMoreElements(); ) { + InetAddress inetAddress = enumIpAddr.nextElement(); + if (inetAddress instanceof Inet4Address && !inetAddress.isLoopbackAddress()) { + return inetAddress.getHostAddress(); + } + } + } + } catch (SocketException e) { + e.printStackTrace(); + } + return "127.0.0.1"; + } + + /** + * 判断当前设备是手机还是平板,代码来自 Google I/O App for Android + * + * @param context + * @return 平板返回 True,手机返回 False + */ + public static boolean isPad(Context context) { + return (context.getResources().getConfiguration().screenLayout + & Configuration.SCREENLAYOUT_SIZE_MASK) + >= Configuration.SCREENLAYOUT_SIZE_LARGE; + } + + + @Override + public void onItemClick(int position, TitleBean data) { + if (connectStatus != IPC_CONNECTION_STATUS.CONNECTED) { + String msg = "未连接工控机"; + showToastCenter(msg); + return; + } + switch (data.name) { + case Constants.TITLE.SEND_RESTORATION: + updateItem(Constants.TITLE.SEND_ACCELERATED_SPEED_2, -1, null); + updateItem(Constants.TITLE.SEND_ACCELERATED_SPEED_1, -1, null); + sendAcc(false, 0.0); + break; + case Constants.TITLE.SEND_CHANGE_LANE_LEFT: + AdasManager.getInstance().sendOperatorCmdChangeLaneLeft(); + break; + case Constants.TITLE.SEND_CHANGE_LANE_RIGHT: + AdasManager.getInstance().sendOperatorCmdChangeLaneRight(); + break; + case Constants.TITLE.SEND_ACCELERATED_SPEED_1: + updateItem(Constants.TITLE.SEND_ACCELERATED_SPEED_2, position, data); + sendAcc(true, -1); + break; + case Constants.TITLE.SEND_ACCELERATED_SPEED_2: + updateItem(Constants.TITLE.SEND_ACCELERATED_SPEED_1, position, data); + sendAcc(true, -2); + break; + case Constants.TITLE.SEND_HORN: + if (timerHorn == null) { + updateItem(null, position, data); + AdasManager.getInstance().sendOperatorCmdStartHonking(); + timerHorn = new Timer(); + timerHorn.schedule(new TimerTask() { + @Override + public void run() { + AdasManager.getInstance().sendOperatorCmdStopHonking(); + timerHorn = null; + runOnUiThread(new Runnable() { + @Override + public void run() { + updateItem(Constants.TITLE.SEND_HORN, -1, null); + } + }); + } + }, Constants.getHornDuration(this)); + } + break; + case Constants.TITLE.START_AUTOPILOT: + AdasManager.getInstance().sendAutoPilotModeReq(1, 0, null); + break; + } + } + + private void updateItem(String name, int position, TitleBean data) { + if (!TextUtils.isEmpty(name)) { + int index = titleBtnData.indexOf(new TitleBean(name)); + if (index != -1) { + titleBtnData.get(index).isSelected = false; + btnAdapter.setSelectedPosition(index); + } + } + if (data != null) { + data.isSelected = true; + btnAdapter.setSelectedPosition(position); + } + } + + private volatile double accelerated;//加速度 + + /** + * 定频发送加速度 + * + * @param isSend 是否发送 + * @param acc 加速度 + */ + private synchronized void sendAcc(boolean isSend, double acc) { + if (isSend) { + accelerated = acc; + if (timerAcc == null) { + timerAcc = new Timer(); + timerAcc.schedule(new TimerTask() { + @Override + public void run() { + AdasManager.getInstance().sendOperatorCmdSetAcceleratedSpeed(accelerated); + } + }, 0, Constants.getAccelerateDuration(this)); + } + } else { + if (timerAcc != null) { + timerAcc.cancel(); + timerAcc = null; + } + AdasManager.getInstance().sendOperatorCmdSetAcceleratedSpeed(acc); + } + + } + + + @Override + public boolean onItemLongClick(int position, TitleBean data) { + if (Constants.TITLE.SEND_HORN.equals(data.name)) { + AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this); + builder.setTitle("鸣笛时长配置"); + View view = getLayoutInflater().inflate(R.layout.dialog_time, null); + final EditText et = view.findViewById(R.id.et); + String timeout = String.valueOf(Constants.getHornDuration(this)); + et.setText(timeout); + et.setSelection(timeout.length()); + builder.setView(view);// + builder.setPositiveButton("确定", null); + //设置反面按钮,并做事件处理 + builder.setNegativeButton("取消", null); + AlertDialog alertDialog = builder.show();//显示Dialog对话框 + alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Editable editable = et.getText(); + if (TextUtils.isEmpty(editable)) { + // 条件不成立不能关闭 AlertDialog 窗口 + Toast.makeText(MainActivity.this, "请输入时长", Toast.LENGTH_SHORT).show(); + return; + } + String temp = et.getText().toString().trim(); + Constants.setHornDuration(MainActivity.this, Long.parseLong(temp)); + alertDialog.dismiss(); + } + }); + return true; + } else if (Constants.TITLE.SEND_ACCELERATED_SPEED_1.equals(data.name) || Constants.TITLE.SEND_ACCELERATED_SPEED_2.equals(data.name)) { + AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this); + builder.setTitle("ACC发送频率配置"); + View view = getLayoutInflater().inflate(R.layout.dialog_time, null); + final EditText et = view.findViewById(R.id.et); + String timeout = String.valueOf(Constants.getAccelerateDuration(this)); + et.setText(timeout); + et.setSelection(timeout.length()); + builder.setView(view);// + builder.setPositiveButton("确定", null); + //设置反面按钮,并做事件处理 + builder.setNegativeButton("取消", null); + AlertDialog alertDialog = builder.show();//显示Dialog对话框 + alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Editable editable = et.getText(); + if (TextUtils.isEmpty(editable)) { + // 条件不成立不能关闭 AlertDialog 窗口 + Toast.makeText(MainActivity.this, "请输入频率", Toast.LENGTH_SHORT).show(); + return; + } + String temp = et.getText().toString().trim(); + Constants.setAccelerateDuration(MainActivity.this, Long.parseLong(temp)); + alertDialog.dismiss(); + } + }); + return true; + } + return false; + } + + + @Override + protected void handleMessage(Message msg) { + super.handleMessage(msg); + switch (msg.what) { + case WHAT_IPC_IP: + showIPCIP(); + break; + case WHAT_IPC_CONNECT_STATE: + if (floatWindow != null) { + floatWindow.refreshView(); + } + IPCConnectState status = (IPCConnectState) msg.obj; + tvConnectState.setText(status.status); + tvConnectState.setTextColor(getResources().getColor(status.color)); + break; + case WHAT_UPDATE_GNSS: + gnss_hint.setText((String) msg.obj); + break; + } + } +} diff --git a/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/utils/Constants.java b/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/utils/Constants.java new file mode 100644 index 0000000000..e56f4751ba --- /dev/null +++ b/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/utils/Constants.java @@ -0,0 +1,133 @@ +package com.zhidao.adas.magic.utils; + +import android.content.Context; +import android.os.Environment; +import android.text.TextUtils; + +import com.google.gson.reflect.TypeToken; +import com.zhidao.adas.client.utils.PreferencesUtils; +import com.zhidao.support.adas.high.common.JsonUtil; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +/** + * @author song kenan + * @des + * @date 2021/10/8 + */ +public class Constants { + public static final String ROOT_PATH = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "IPCMonitoring" + File.separator;//程序外部存储跟目录 + public static final String FILE_PATH = ROOT_PATH + "Crash" + File.separator; + + + /***********************是否使用固定IP******************/ + // 0:固定IP 1:指定 2:UDP + private static final String IPC_CONNECTION_MODE = "ipc_connection_mode"; + + public static void setIpcConnectionMode(Context context, int type) { + PreferencesUtils.putInt(context, IPC_CONNECTION_MODE, type); + } + + public static int getIpcConnectionMode(Context context) { + return PreferencesUtils.getInt(context, IPC_CONNECTION_MODE, 0); + } + + public static boolean delIpcConnectionMode(Context context) { + return PreferencesUtils.delete(context, IPC_CONNECTION_MODE); + } + + /***********************保存IP******************/ + private static final String IPC_IP = "ipc_ip"; + + public static void setIPCIp(Context context, String ip) { + PreferencesUtils.putString(context, IPC_IP, ip); + } + + public static String getIPCIp(Context context) { + return PreferencesUtils.getString(context, IPC_IP, null); + } + + public static boolean delIPCIp(Context context) { + return PreferencesUtils.delete(context, IPC_IP); + } + + + /***********************保存使用过的IP列表******************/ + + + private static final String IPC_USED_IP = "ipc_used_ip"; + + public static List getIpcUsedIps(Context context) { + String json = PreferencesUtils.getString(context, IPC_USED_IP, null); + if (TextUtils.isEmpty(json)) return null; + List list = JsonUtil.fromJson(json, new TypeToken>() { + }.getType()); + return list; + } + + public static boolean addIpcUsedIps(Context context, List list, String mode) { + if (list == null) + list = new ArrayList<>(); + list.remove(mode); + list.add(0, mode); + if (list.size() > 10) { + list.remove(list.size() - 1); + } + return PreferencesUtils.putString(context, IPC_USED_IP, JsonUtil.toJson(list)); + } + + public static boolean delIpcUsedIps(Context context, List list, String mode) { + if (list == null) { + return PreferencesUtils.delete(context, IPC_USED_IP); + } else { + if (list.contains(mode)) { + list.remove(mode); + return PreferencesUtils.putString(context, IPC_USED_IP, JsonUtil.toJson(list)); + } + } + return false; + } + + /********************acc 发送频率******************/ + private static final String ACCELERATE_DURATION = "accelerate_duration"; + + public static void setAccelerateDuration(Context context, long duration) { + PreferencesUtils.putLong(context, ACCELERATE_DURATION, duration); + } + + public static long getAccelerateDuration(Context context) { + return PreferencesUtils.getLong(context, ACCELERATE_DURATION, 500); + } + + public static boolean delAccelerateDuration(Context context) { + return PreferencesUtils.delete(context, ACCELERATE_DURATION); + } + /********************鸣笛时长******************/ + private static final String HORN_DURATION = "horn_duration"; + + public static void setHornDuration(Context context, long duration) { + PreferencesUtils.putLong(context, HORN_DURATION, duration); + } + + public static long getHornDuration(Context context) { + return PreferencesUtils.getLong(context, HORN_DURATION, 500); + } + + public static boolean delHornDuration(Context context) { + return PreferencesUtils.delete(context, HORN_DURATION); + } + + public interface TITLE { + + String SEND_RESTORATION = "复位"; + String SEND_CHANGE_LANE_LEFT = "向左变道"; + String SEND_CHANGE_LANE_RIGHT = "向右变道"; + String SEND_ACCELERATED_SPEED_1 = "-1减速"; + String SEND_ACCELERATED_SPEED_2 = "-2减速"; + String SEND_HORN = "鸣笛"; + String START_AUTOPILOT = "开启自动驾驶"; + + } +} diff --git a/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/utils/CrashHandler.java b/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/utils/CrashHandler.java new file mode 100644 index 0000000000..a1fbf50402 --- /dev/null +++ b/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/utils/CrashHandler.java @@ -0,0 +1,293 @@ +package com.zhidao.adas.magic.utils; + +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.os.Build; +import android.os.Environment; +import android.os.Looper; +import android.util.Log; +import android.widget.Toast; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.Writer; +import java.lang.Thread.UncaughtExceptionHandler; +import java.lang.reflect.Field; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + + +/** + * ClassName: CrashHandler + * Function: UncaughtException处理类,当程序发生Uncaught异常的时候,由该类来接管程序,并记录发送错误报告. + * + * @author Norris Norris.sly@gmail.com + * @Date 2013 2013-3-24 下午12:27:10 + * @Fields ────────────────────────────────────────────────────────────────────────────────────────────────────── + * @Methods ────────────────────────────────────────────────────────────────────────────────────────────────────── + * 2013-3-24下午12:27:10 Modified By Norris + * ────────────────────────────────────────────────────────────────────────────────────────────────────── + * @see ────────────────────────────────────────────────────────────────────────────────────────────────────── + * @since Ver 1.0 I used to be a programmer like you, then I took an arrow in the knee + */ +public class CrashHandler implements UncaughtExceptionHandler { + + /** + * Log日志的tag + * String : TAG + * + * @since 2013-3-21下午8:44:28 + */ + private static final String TAG = "NorrisInfo"; + /** + * 系统默认的UncaughtException处理类 + * Thread.UncaughtExceptionHandler : mDefaultHandler + * + * @since 2013-3-21下午8:44:43 + */ + private UncaughtExceptionHandler mDefaultHandler; + /** + * CrashHandler实例 + * CrashHandler : mInstance + * + * @since 2013-3-21下午8:44:53 + */ + private static CrashHandler mInstance = new CrashHandler(); + /** + * 程序的Context对象 + * Context : mContext + * + * @since 2013-3-21下午8:45:02 + */ + private Context mContext; + /** + * 用来存储设备信息和异常信息 + * Map : mLogInfo + * + * @since 2013-3-21下午8:46:15 + */ + private Map mLogInfo = new HashMap(); + /** + * 用于格式化日期,作为日志文件名的一部分(FIXME 注意在windows下文件名无法使用:等符号!) + * SimpleDateFormat : mSimpleDateFormat + * + * @since 2013-3-21下午8:46:39 + */ + private SimpleDateFormat mSimpleDateFormat = new SimpleDateFormat("yyyyMMdd_HH-mm-ss"); + + /** + * Creates a new instance of CrashHandler. + */ + private CrashHandler() { + } + + /** + * getInstance:{获取CrashHandler实例 ,单例模式 } + * ────────────────────────────────── + * + * @return CrashHandler + * @throws + * @since I used to be a programmer like you, then I took an arrow in the knee Ver 1.0 + * ────────────────────────────────────────────────────────────────────────────────────────────────────── + * 2013-3-21下午8:52:24 Modified By Norris + * ────────────────────────────────────────────────────────────────────────────────────────────────────── + */ + public static CrashHandler getInstance() { + return mInstance; + } + + /** + * init:{初始化} + * ────────────────────────────────── + * + * @param paramContext + * @return void + * @throws + * @since I used to be a programmer like you, then I took an arrow in the knee Ver 1.0 + * ────────────────────────────────────────────────────────────────────────────────────────────────────── + * 2013-3-21下午8:52:45 Modified By Norris + * ────────────────────────────────────────────────────────────────────────────────────────────────────── + */ + public void init(Context paramContext) { + mContext = paramContext; + // 获取系统默认的UncaughtException处理器 + mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler(); + // 设置该CrashHandler为程序的默认处理器 + Thread.setDefaultUncaughtExceptionHandler(this); + } + + /** + * 当UncaughtException发生时会转入该重写的方法来处理 + * (non-Javadoc) + * + * @see UncaughtExceptionHandler#uncaughtException(Thread, Throwable) + */ + public void uncaughtException(Thread paramThread, Throwable paramThrowable) { + // 获取设备参数信息 + getDeviceInfo(mContext); +// mLogInfo.put("versionName", String.valueOf(BuildConfig.VERSION_CODE)); +// mLogInfo.put("versionCode", BuildConfig.VERSION_NAME); + // 保存日志文件 + String result = saveCrashLogToFile(paramThrowable); + mDefaultHandler.uncaughtException(paramThread, paramThrowable); +// if (!handleException(paramThrowable) && mDefaultHandler != null) { +// // 如果自定义的没有处理则让系统默认的异常处理器来处理 +// mDefaultHandler.uncaughtException(paramThread, paramThrowable); +// } else { +//// try { +//// // 如果处理了,让程序继续运行1秒再退出,保证文件保存并上传到服务器 +//// paramThread.sleep(1000); +//// } catch (InterruptedException e) { +//// e.printStackTrace(); +//// } +// // 退出程序 +// android.os.Process.killProcess(android.os.Process.myPid()); +// System.exit(1); +// } + } + + /** + * handleException:{自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.} + * ────────────────────────────────── + * + * @param paramThrowable + * @return true:如果处理了该异常信息;否则返回false. + * @throws + * @since I used to be a programmer like you, then I took an arrow in the knee Ver 1.0 + * ────────────────────────────────────────────────────────────────────────────────────────────────────── + * 2013-3-24下午12:28:53 Modified By Norris + * ────────────────────────────────────────────────────────────────────────────────────────────────────── + */ + public boolean handleException(Throwable paramThrowable) { + if (paramThrowable == null) + return false; + new Thread() { + public void run() { + Looper.prepare(); + Toast.makeText(mContext, "很抱歉,程序出现异常,即将退出", Toast.LENGTH_SHORT).show(); + Looper.loop(); + } + }.start(); + // 获取设备参数信息 + getDeviceInfo(mContext); + // 保存日志文件 + String result = saveCrashLogToFile(paramThrowable); + //上传崩溃日志 + return true; + } + + /** + * getDeviceInfo:{获取设备参数信息} + * ────────────────────────────────── + * + * @param paramContext + * @throws + * @since I used to be a programmer like you, then I took an arrow in the knee Ver 1.0 + * ────────────────────────────────────────────────────────────────────────────────────────────────────── + * 2013-3-24下午12:30:02 Modified By Norris + * ────────────────────────────────────────────────────────────────────────────────────────────────────── + */ + public void getDeviceInfo(Context paramContext) { + try { + // 获得包管理器 + PackageManager mPackageManager = paramContext.getPackageManager(); + // 得到该应用的信息,即主Activity + PackageInfo mPackageInfo = mPackageManager.getPackageInfo( + paramContext.getPackageName(), PackageManager.GET_ACTIVITIES); + if (mPackageInfo != null) { + String versionName = mPackageInfo.versionName == null ? "null" + : mPackageInfo.versionName; + String versionCode = mPackageInfo.versionCode + ""; + mLogInfo.put("versionName", versionName); + mLogInfo.put("versionCode", versionCode); + } + } catch (NameNotFoundException e) { + e.printStackTrace(); + } + // 反射机制 + Field[] mFields = Build.class.getDeclaredFields(); + // 迭代Build的字段key-value 此处的信息主要是为了在服务器端手机各种版本手机报错的原因 + for (Field field : mFields) { + try { + field.setAccessible(true); + mLogInfo.put(field.getName(), field.get("").toString()); + Log.d(TAG, field.getName() + ":" + field.get("")); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + } + + /** + * saveCrashLogToFile:{将崩溃的Log保存到本地} + * TODO 可拓展,将Log上传至指定服务器路径 + * ────────────────────────────────── + * + * @param paramThrowable + * @return FileName + * @throws + * @since I used to be a programmer like you, then I took an arrow in the knee Ver 1.0 + * ────────────────────────────────────────────────────────────────────────────────────────────────────── + * 2013-3-24下午12:31:01 Modified By Norris + * ────────────────────────────────────────────────────────────────────────────────────────────────────── + */ + + + private String saveCrashLogToFile(Throwable paramThrowable) { + StringBuffer mStringBuffer = new StringBuffer(); + for (Map.Entry entry : mLogInfo.entrySet()) { + String key = entry.getKey(); + String value = entry.getValue(); + mStringBuffer.append(key + "=" + value + "\r\n"); + } + Writer mWriter = new StringWriter(); + PrintWriter mPrintWriter = new PrintWriter(mWriter); + paramThrowable.printStackTrace(mPrintWriter); + paramThrowable.printStackTrace(); + Throwable mThrowable = paramThrowable.getCause(); + // 迭代栈队列把所有的异常信息写入writer中 + while (mThrowable != null) { + mThrowable.printStackTrace(mPrintWriter); + // 换行 每个个异常栈之间换行 + mThrowable = mThrowable.getCause(); + } + + //记得关闭 + + String mResult = mWriter.toString(); + // String mResult = mWriter.toString().replace("\n", "").replace(":", "").replace("/", "").replace("\t", ""); + mStringBuffer.append(mResult); + // 保存文件,设置文件名 + String mTime = mSimpleDateFormat.format(new Date()); + String mFileName = mContext.getPackageName() + "_Exception-" + mTime + ".log"; + if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { + try { + File mDirectory = new File(Constants.FILE_PATH); + Log.d(TAG, mDirectory.toString()); + if (!mDirectory.exists()) + mDirectory.mkdirs(); + FileOutputStream mFileOutputStream = new FileOutputStream(mDirectory + File.separator + mFileName); + mFileOutputStream.write(mStringBuffer.toString().getBytes()); + mFileOutputStream.close(); + return mResult; + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return mResult; + } + + +} diff --git a/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/utils/MyLinearLayoutManager.java b/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/utils/MyLinearLayoutManager.java new file mode 100644 index 0000000000..f7d60f4afe --- /dev/null +++ b/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/utils/MyLinearLayoutManager.java @@ -0,0 +1,36 @@ +package com.zhidao.adas.magic.utils; + +import android.content.Context; +import android.util.AttributeSet; + +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +public class MyLinearLayoutManager extends LinearLayoutManager { + public MyLinearLayoutManager(Context context) { + super(context); + } + + public MyLinearLayoutManager(Context context, int orientation, boolean reverseLayout) { + super(context, orientation, reverseLayout); + } + + public MyLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + } + + @Override + public boolean supportsPredictiveItemAnimations() { + return false; + } + + @Override + public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) { + //override this method and implement code as below + try { + super.onLayoutChildren(recycler, state); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/utils/PreferencesUtils.java b/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/utils/PreferencesUtils.java new file mode 100644 index 0000000000..f9a8006feb --- /dev/null +++ b/app_mogo_magic_ring/src/main/java/com/zhidao/adas/magic/utils/PreferencesUtils.java @@ -0,0 +1,286 @@ +package com.zhidao.adas.client.utils; + +import android.content.Context; +import android.content.SharedPreferences; + +public class PreferencesUtils { + + public static String PREFERENCE_NAME = "control"; + + public static boolean hasString(Context context, String key) { + if (context == null) return false; + SharedPreferences settings = context.getSharedPreferences( + PREFERENCE_NAME, Context.MODE_PRIVATE); + return settings.contains(key); + } + + /** + * put string preferences + * + * @param context + * @param key The name of the preference to modify + * @param value The new value for the preference + * @return True if the new values were successfully written to persistent + * storage. + */ + public static boolean putString(Context context, String key, String value) { + + if (context == null) return false; + SharedPreferences settings = context.getSharedPreferences( + PREFERENCE_NAME, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = settings.edit(); + editor.putString(key, value); + return editor.commit(); + } + + /** + * get string preferences + * + * @param context + * @param key The name of the preference to retrieve + * @return The preference value if it exists, or null. Throws + * ClassCastException if there is a preference with this name that + * is not a string + * @see #getString(Context, String, String) + */ + public static String getString(Context context, String key) { + if (context == null) return null; + return getString(context, key, null); + } + + /** + * get string preferences + * + * @param context + * @param key The name of the preference to retrieve + * @param defaultValue Value to return if this preference does not exist + * @return The preference value if it exists, or defValue. Throws + * ClassCastException if there is a preference with this name that + * is not a string + */ + public static String getString(Context context, String key, + String defaultValue) { + + if (context == null) return defaultValue; + SharedPreferences settings = context.getSharedPreferences( + PREFERENCE_NAME, Context.MODE_PRIVATE); + return settings.getString(key, defaultValue); + } + + /** + * put int preferences + * + * @param context + * @param key The name of the preference to modify + * @param value The new value for the preference + * @return True if the new values were successfully written to persistent + * storage. + */ + public static boolean putInt(Context context, String key, int value) { + + if (context == null) return false; + SharedPreferences settings = context.getSharedPreferences( + PREFERENCE_NAME, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = settings.edit(); + editor.putInt(key, value); + return editor.commit(); + } + + /** + * get int preferences + * + * @param context + * @param key The name of the preference to retrieve + * @return The preference value if it exists, or -1. Throws + * ClassCastException if there is a preference with this name that + * is not a int + * @see #getInt(Context, String, int) + */ + public static int getInt(Context context, String key) { + + if (context == null) return -1; + SharedPreferences settings = context.getSharedPreferences( + PREFERENCE_NAME, Context.MODE_PRIVATE); + return getInt(context, key, -1); + } + + /** + * get int preferences + * + * @param context + * @param key The name of the preference to retrieve + * @param defaultValue Value to return if this preference does not exist + * @return The preference value if it exists, or defValue. Throws + * ClassCastException if there is a preference with this name that + * is not a int + */ + public static int getInt(Context context, String key, int defaultValue) { + if (context == null) return defaultValue; + SharedPreferences settings = context.getSharedPreferences( + PREFERENCE_NAME, Context.MODE_PRIVATE); + return settings.getInt(key, defaultValue); + } + + /** + * put long preferences + * + * @param context + * @param key The name of the preference to modify + * @param value The new value for the preference + * @return True if the new values were successfully written to persistent + * storage. + */ + public static boolean putLong(Context context, String key, long value) { + if (context == null) return false; + SharedPreferences settings = context.getSharedPreferences( + PREFERENCE_NAME, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = settings.edit(); + editor.putLong(key, value); + return editor.commit(); + } + + /** + * get long preferences + * + * @param context + * @param key The name of the preference to retrieve + * @return The preference value if it exists, or -1. Throws + * ClassCastException if there is a preference with this name that + * is not a long + * @see #getLong(Context, String, long) + */ + public static long getLong(Context context, String key) { + if (context == null) return -1; + return getLong(context, key, -1); + } + + /** + * get long preferences + * + * @param context + * @param key The name of the preference to retrieve + * @param defaultValue Value to return if this preference does not exist + * @return The preference value if it exists, or defValue. Throws + * ClassCastException if there is a preference with this name that + * is not a long + */ + public static long getLong(Context context, String key, long defaultValue) { + if (context == null) return defaultValue; + SharedPreferences settings = context.getSharedPreferences( + PREFERENCE_NAME, Context.MODE_PRIVATE); + + return settings.getLong(key, defaultValue); + } + + /** + * put float preferences + * + * @param context + * @param key The name of the preference to modify + * @param value The new value for the preference + * @return True if the new values were successfully written to persistent + * storage. + */ + public static boolean putFloat(Context context, String key, float value) { + if (context == null) return false; + SharedPreferences settings = context.getSharedPreferences( + PREFERENCE_NAME, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = settings.edit(); + editor.putFloat(key, value); + return editor.commit(); + } + + /** + * get float preferences + * + * @param context + * @param key The name of the preference to retrieve + * @return The preference value if it exists, or -1. Throws + * ClassCastException if there is a preference with this name that + * is not a float + * @see #getFloat(Context, String, float) + */ + public static float getFloat(Context context, String key) { + if (context == null) return -1; + return getFloat(context, key, -1); + } + + /** + * get float preferences + * + * @param context + * @param key The name of the preference to retrieve + * @param defaultValue Value to return if this preference does not exist + * @return The preference value if it exists, or defValue. Throws + * ClassCastException if there is a preference with this name that + * is not a float + */ + public static float getFloat(Context context, String key, float defaultValue) { + if (context == null) return defaultValue; + SharedPreferences settings = context.getSharedPreferences( + PREFERENCE_NAME, Context.MODE_PRIVATE); + return settings.getFloat(key, defaultValue); + } + + /** + * put boolean preferences + * + * @param context + * @param key The name of the preference to modify + * @param value The new value for the preference + * @return True if the new values were successfully written to persistent + * storage. + */ + public static boolean putBoolean(Context context, String key, boolean value) { + if (context == null) return false; + SharedPreferences settings = context.getSharedPreferences( + PREFERENCE_NAME, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = settings.edit(); + editor.putBoolean(key, value); + return editor.commit(); + } + + /** + * get boolean preferences, default is false + * + * @param context + * @param key The name of the preference to retrieve + * @return The preference value if it exists, or false. Throws + * ClassCastException if there is a preference with this name that + * is not a boolean + * @see #getBoolean(Context, String, boolean) + */ + public static boolean getBoolean(Context context, String key) { + if (context == null) return false; + return getBoolean(context, key, false); + } + + /** + * get boolean preferences + * + * @param context + * @param key The name of the preference to retrieve + * @param defaultValue Value to return if this preference does not exist + * @return The preference value if it exists, or defValue. Throws + * ClassCastException if there is a preference with this name that + * is not a boolean + */ + public static boolean getBoolean(Context context, String key, + boolean defaultValue) { + if (context == null) return defaultValue; + SharedPreferences settings = context.getSharedPreferences( + PREFERENCE_NAME, Context.MODE_PRIVATE); + return settings.getBoolean(key, defaultValue); + } + + + public static boolean delete(Context context, String key) { + if (context == null) return false; + SharedPreferences settings = context.getSharedPreferences( + PREFERENCE_NAME, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = settings.edit(); + editor.remove(key); + return editor.commit(); + } + +} diff --git a/app_mogo_magic_ring/src/main/res/drawable/bg_adas_dialog.xml b/app_mogo_magic_ring/src/main/res/drawable/bg_adas_dialog.xml new file mode 100644 index 0000000000..cbfb69f454 --- /dev/null +++ b/app_mogo_magic_ring/src/main/res/drawable/bg_adas_dialog.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/app_mogo_magic_ring/src/main/res/drawable/btn_bg.xml b/app_mogo_magic_ring/src/main/res/drawable/btn_bg.xml new file mode 100644 index 0000000000..ba61bf76b4 --- /dev/null +++ b/app_mogo_magic_ring/src/main/res/drawable/btn_bg.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app_mogo_magic_ring/src/main/res/drawable/ic_pack_up.xml b/app_mogo_magic_ring/src/main/res/drawable/ic_pack_up.xml new file mode 100644 index 0000000000..328407001b --- /dev/null +++ b/app_mogo_magic_ring/src/main/res/drawable/ic_pack_up.xml @@ -0,0 +1,9 @@ + + + diff --git a/app_mogo_magic_ring/src/main/res/drawable/ic_pull.xml b/app_mogo_magic_ring/src/main/res/drawable/ic_pull.xml new file mode 100644 index 0000000000..2a5cad0c1e --- /dev/null +++ b/app_mogo_magic_ring/src/main/res/drawable/ic_pull.xml @@ -0,0 +1,9 @@ + + + diff --git a/app_mogo_magic_ring/src/main/res/drawable/icon.xml b/app_mogo_magic_ring/src/main/res/drawable/icon.xml new file mode 100644 index 0000000000..0e2c205a40 --- /dev/null +++ b/app_mogo_magic_ring/src/main/res/drawable/icon.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app_mogo_magic_ring/src/main/res/drawable/item_bg.xml b/app_mogo_magic_ring/src/main/res/drawable/item_bg.xml new file mode 100644 index 0000000000..3476874a12 --- /dev/null +++ b/app_mogo_magic_ring/src/main/res/drawable/item_bg.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app_mogo_magic_ring/src/main/res/drawable/item_text_color.xml b/app_mogo_magic_ring/src/main/res/drawable/item_text_color.xml new file mode 100644 index 0000000000..4b611429b1 --- /dev/null +++ b/app_mogo_magic_ring/src/main/res/drawable/item_text_color.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app_mogo_magic_ring/src/main/res/drawable/selector_history_ip.xml b/app_mogo_magic_ring/src/main/res/drawable/selector_history_ip.xml new file mode 100644 index 0000000000..a36a8d2aa8 --- /dev/null +++ b/app_mogo_magic_ring/src/main/res/drawable/selector_history_ip.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app_mogo_magic_ring/src/main/res/layout/activity_main.xml b/app_mogo_magic_ring/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000000..e8bd0716bd --- /dev/null +++ b/app_mogo_magic_ring/src/main/res/layout/activity_main.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app_mogo_magic_ring/src/main/res/layout/dialog_time.xml b/app_mogo_magic_ring/src/main/res/layout/dialog_time.xml new file mode 100644 index 0000000000..acd118ceb8 --- /dev/null +++ b/app_mogo_magic_ring/src/main/res/layout/dialog_time.xml @@ -0,0 +1,29 @@ + + + + + + + \ No newline at end of file diff --git a/app_mogo_magic_ring/src/main/res/layout/include_line.xml b/app_mogo_magic_ring/src/main/res/layout/include_line.xml new file mode 100644 index 0000000000..c7d8f0f77a --- /dev/null +++ b/app_mogo_magic_ring/src/main/res/layout/include_line.xml @@ -0,0 +1,14 @@ + + + + + + \ No newline at end of file diff --git a/app_mogo_magic_ring/src/main/res/layout/item_info.xml b/app_mogo_magic_ring/src/main/res/layout/item_info.xml new file mode 100644 index 0000000000..7fda3f9417 --- /dev/null +++ b/app_mogo_magic_ring/src/main/res/layout/item_info.xml @@ -0,0 +1,21 @@ + + + + + + \ No newline at end of file diff --git a/app_mogo_magic_ring/src/main/res/layout/item_main.xml b/app_mogo_magic_ring/src/main/res/layout/item_main.xml new file mode 100644 index 0000000000..56460fa16e --- /dev/null +++ b/app_mogo_magic_ring/src/main/res/layout/item_main.xml @@ -0,0 +1,177 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app_mogo_magic_ring/src/main/res/layout/item_pop.xml b/app_mogo_magic_ring/src/main/res/layout/item_pop.xml new file mode 100644 index 0000000000..501a4044bd --- /dev/null +++ b/app_mogo_magic_ring/src/main/res/layout/item_pop.xml @@ -0,0 +1,12 @@ + + diff --git a/app_mogo_magic_ring/src/main/res/layout/item_status.xml b/app_mogo_magic_ring/src/main/res/layout/item_status.xml new file mode 100644 index 0000000000..a4cfdf3b81 --- /dev/null +++ b/app_mogo_magic_ring/src/main/res/layout/item_status.xml @@ -0,0 +1,31 @@ + + + + + + + + + + diff --git a/app_mogo_magic_ring/src/main/res/layout/layout_float.xml b/app_mogo_magic_ring/src/main/res/layout/layout_float.xml new file mode 100644 index 0000000000..7e199841eb --- /dev/null +++ b/app_mogo_magic_ring/src/main/res/layout/layout_float.xml @@ -0,0 +1,17 @@ + + + + + + + + \ No newline at end of file diff --git a/app_mogo_magic_ring/src/main/res/values/colors.xml b/app_mogo_magic_ring/src/main/res/values/colors.xml new file mode 100644 index 0000000000..bfe52b115c --- /dev/null +++ b/app_mogo_magic_ring/src/main/res/values/colors.xml @@ -0,0 +1,20 @@ + + + #008577 + #00574B + #D81B60 + #FFD700 + #102b6a + #224b8f + #FFFFFF + #000000 + #FF1493 + #DC143C + #32CD32 + #708090 + #32CD32 + #DC143C + #FF00FF + #DAA520 + #1E90FF + diff --git a/app_mogo_magic_ring/src/main/res/values/strings.xml b/app_mogo_magic_ring/src/main/res/values/strings.xml new file mode 100644 index 0000000000..34406718c6 --- /dev/null +++ b/app_mogo_magic_ring/src/main/res/values/strings.xml @@ -0,0 +1,5 @@ + + 蘑戒 + 复位按钮:下发减速命令之后需要复位操作\n减速按钮:单机触发减速,长按配置减速发送频率\n鸣笛按钮:单机触发鸣笛,长按配置鸣笛时长 + + diff --git a/app_mogo_magic_ring/src/main/res/values/styles.xml b/app_mogo_magic_ring/src/main/res/values/styles.xml new file mode 100644 index 0000000000..71a18efd24 --- /dev/null +++ b/app_mogo_magic_ring/src/main/res/values/styles.xml @@ -0,0 +1,34 @@ + + + + + + + +