Ver código fonte

增加自动获取和手动配置服务器IP

weizhengliang 3 anos atrás
pai
commit
7733f0ba69
27 arquivos alterados com 1468 adições e 51 exclusões
  1. 147 3
      callingdoor/src/main/java/com/wdkl/app/ncs/callingdoor/activity/CallingdoorActivity.kt
  2. 56 0
      callingdoor/src/main/java/com/wdkl/app/ncs/callingdoor/adapter/NumAdapter.java
  3. 2 0
      callingdoor/src/main/java/com/wdkl/app/ncs/callingdoor/agreement/CallingdoorAgreement.kt
  4. 7 0
      callingdoor/src/main/java/com/wdkl/app/ncs/callingdoor/fragment/QrCodeFragment.kt
  5. 2 5
      callingdoor/src/main/java/com/wdkl/app/ncs/callingdoor/fragment/SkyCallFragment.kt
  6. 151 0
      callingdoor/src/main/java/com/wdkl/app/ncs/callingdoor/helper/ServerConfigDialogHelper.java
  7. 17 0
      callingdoor/src/main/res/layout/digital_item.xml
  8. 13 0
      callingdoor/src/main/res/layout/qr_code_lay.xml
  9. 189 0
      callingdoor/src/main/res/layout/server_config_dialog_lay.xml
  10. 1 1
      janus/build.gradle
  11. 21 20
      janus/src/main/java/com/wdkl/ncs/janus/rtc/WebRTCEngine.java
  12. 0 14
      janus/src/main/java/com/wdkl/ncs/janus/util/Constant.java
  13. 15 0
      janus/src/main/java/com/wdkl/ncs/janus/util/JanusConstant.java
  14. 3 0
      middleware/src/main/code/com/wdkl/ncs/android/middleware/api/DoorDeviceApi.kt
  15. 12 3
      middleware/src/main/code/com/wdkl/ncs/android/middleware/api/UrlManager.kt
  16. 5 0
      middleware/src/main/code/com/wdkl/ncs/android/middleware/logic/contract/callingdoor/CallingdoorActivityContract.kt
  17. 17 4
      middleware/src/main/code/com/wdkl/ncs/android/middleware/logic/presenter/callingdoor/CallingdoorActivityPresenter.kt
  18. 56 0
      middleware/src/main/code/com/wdkl/ncs/android/middleware/model/JsonResponse.java
  19. 178 0
      middleware/src/main/code/com/wdkl/ncs/android/middleware/model/ServerInfo.java
  20. 33 0
      middleware/src/main/code/com/wdkl/ncs/android/middleware/model/ThirdServerInfo.java
  21. 108 0
      middleware/src/main/code/com/wdkl/ncs/android/middleware/udp/NetIpUtil.java
  22. 108 0
      middleware/src/main/code/com/wdkl/ncs/android/middleware/udp/ServerInfoUtil.java
  23. 123 0
      middleware/src/main/code/com/wdkl/ncs/android/middleware/udp/UdpClient.java
  24. 43 0
      middleware/src/main/code/com/wdkl/ncs/android/middleware/udp/UdpClientHandler.java
  25. 94 0
      middleware/src/main/code/com/wdkl/ncs/android/middleware/utils/CommonUtils.java
  26. 58 0
      resource/src/main/res/values-zh/strings.xml
  27. 9 1
      resource/src/main/res/values/strings.xml

+ 147 - 3
callingdoor/src/main/java/com/wdkl/app/ncs/callingdoor/activity/CallingdoorActivity.kt

@@ -6,6 +6,7 @@ import android.net.ConnectivityManager
 import android.os.Build
 import android.os.Bundle
 import android.os.Handler
+import android.os.Looper
 import android.support.v4.app.Fragment
 import android.text.TextUtils
 import android.util.Log
@@ -33,6 +34,8 @@ import com.wdkl.ncs.android.middleware.common.MessageEvent
 import com.wdkl.ncs.android.middleware.common.SipStatus
 import com.wdkl.ncs.android.middleware.logic.contract.callingdoor.CallingdoorActivityContract
 import com.wdkl.ncs.android.middleware.logic.presenter.callingdoor.CallingdoorActivityPresenter
+import com.wdkl.ncs.android.middleware.model.ServerInfo
+import com.wdkl.ncs.android.middleware.model.ThirdServerInfo
 import com.wdkl.ncs.android.middleware.model.dos.AppVersionDO
 import com.wdkl.ncs.android.middleware.model.dos.PartSettingDO
 import com.wdkl.ncs.android.middleware.model.dto.TcpSeverDTO
@@ -45,7 +48,10 @@ import com.wdkl.ncs.android.middleware.tcp.channel.VoiceUtil
 import com.wdkl.ncs.android.middleware.tcp.dto.TcpModel
 import com.wdkl.ncs.android.middleware.tcp.enums.TcpAction
 import com.wdkl.ncs.android.middleware.tcp.enums.TcpType
+import com.wdkl.ncs.android.middleware.udp.ServerInfoUtil
 import com.wdkl.ncs.android.middleware.utils.AppUtil
+import com.wdkl.ncs.android.middleware.utils.CommonUtils
+import com.wdkl.ncs.janus.util.JanusConstant
 import kotlinx.android.synthetic.main.callingdoor_main_lay.*
 import kotlinx.android.synthetic.main.callingdoor_main_lay.app_version
 import kotlinx.android.synthetic.main.callingdoor_main_lay.room_action_call
@@ -57,6 +63,8 @@ import kotlinx.android.synthetic.main.callingdoor_main_lay.tv_room_name
 import kotlinx.android.synthetic.main.callingdoor_main_lay_rk3288.*
 import kotlinx.android.synthetic.main.view_bed_name.*
 import kotlinx.android.synthetic.main.view_title_layout.*
+import okhttp3.OkHttpClient
+import okhttp3.Request
 import org.greenrobot.eventbus.EventBus
 import org.greenrobot.eventbus.Subscribe
 import org.greenrobot.eventbus.ThreadMode
@@ -64,6 +72,7 @@ import serialporttest.utils.SerialPortUtil
 import java.io.DataOutputStream
 import java.io.IOException
 import java.io.PrintWriter
+import java.util.concurrent.TimeUnit
 
 
 /**
@@ -101,6 +110,11 @@ class CallingdoorActivity :BaseActivity<CallingdoorActivityPresenter, Callingdoo
 
     private val uninstallApk = false
 
+    private var serverSuccess = false
+    private var cancelRestart = false
+
+    private val handler by lazy { Handler(Looper.getMainLooper()) }
+
     //网络异常计数
     private var netErrCount : Int = 0
 
@@ -133,7 +147,7 @@ class CallingdoorActivity :BaseActivity<CallingdoorActivityPresenter, Callingdoo
             Constant.DEVICE_REGISTER_ID = Constant.LOCAL_MAC
         }
 
-        presenter.loadTcpServerHost()
+        //presenter.loadTcpServerHost()
         //注册广播
         regReceiver()
         RecordHelper.getInstance().init()
@@ -187,6 +201,8 @@ class CallingdoorActivity :BaseActivity<CallingdoorActivityPresenter, Callingdoo
                 }
             }.start()
         }
+
+        checkServer()
     }
 
     private fun checkAppExist() : Boolean {
@@ -218,6 +234,96 @@ class CallingdoorActivity :BaseActivity<CallingdoorActivityPresenter, Callingdoo
         }
     }
 
+    private fun checkServer() {
+        Thread {
+            while (!serverSuccess) {
+                val okHttpClient = OkHttpClient().newBuilder()
+                    .connectTimeout(15 * 1000L, TimeUnit.MILLISECONDS)
+                    .readTimeout(15 * 1000L, TimeUnit.MILLISECONDS)
+                    .writeTimeout(15 * 1000L, TimeUnit.MILLISECONDS)
+                    .build()
+                val url: String = CommonUtils.getUrl(BaseApplication.appContext)
+                val port: String = CommonUtils.getUrlPort(BaseApplication.appContext)
+                val request = Request.Builder()
+                    .url("http://$url:$port/ncs_url/server_info")
+                    .get()
+                    .build()
+
+                try {
+                    val response = okHttpClient.newCall(request).execute()
+                    if (response != null && response.isSuccessful) {
+                        //接口数据获取成功,进入下一步获取设备信息
+                        serverSuccess = true
+                        presenter.loadServerInfo()
+                    } else {
+                        //接口数据获取失败,可能服务器ip不对,尝试重新获取服务器ip
+                        val info = ServerInfoUtil.get(Constant.DEVICE_REGISTER_ID!!)
+                        checkServerInfo(info)
+                    }
+                } catch (e: Exception) {
+                    //接口数据获取失败,可能服务器ip不对,尝试重新获取服务器ip
+                    val info = ServerInfoUtil.get(Constant.DEVICE_REGISTER_ID!!)
+                    checkServerInfo(info)
+                    //e.printStackTrace()
+                }
+
+                try {
+                    Thread.sleep(30000)
+                } catch (ex: Exception) {
+                    ex.printStackTrace()
+                }
+            }
+        }.start()
+    }
+
+    private fun checkServerInfo(info: ThirdServerInfo?) {
+        //检查获取到的服务器ip是否可用,可用则重启app重新初始化,不可用则什么都不做,等待下次重新获取服务器ip
+        if (info != null) {
+            if (info.thirdServer == null || info.thirdServerPort == null) {
+                Log.d(TAG, "server info data null")
+                showMsgMain("get server data null")
+            } else {
+                val okHttpClient = OkHttpClient().newBuilder()
+                    .connectTimeout(15 * 1000L, TimeUnit.MILLISECONDS)
+                    .readTimeout(15 * 1000L, TimeUnit.MILLISECONDS)
+                    .writeTimeout(15 * 1000L, TimeUnit.MILLISECONDS)
+                    .build()
+                val request = Request.Builder()
+                    .url("http://${info.thirdServer}:${info.thirdServerPort}/ncs_url/server_info")
+                    .get()
+                    .build()
+
+                try {
+                    val response = okHttpClient.newCall(request).execute()
+                    if (response != null && response.isSuccessful) {
+                        //接口数据获取成功,稍后重启app
+                        serverSuccess = true
+                        CommonUtils.setUrl(activity, info.thirdServer)
+                        CommonUtils.setUrlPort(activity, info.thirdServerPort.toString())
+                        showMsgMain("restart...")
+                        handler.postDelayed({
+                            if (!cancelRestart) {
+                                AppUpdateHelper.restartApp(activity)
+                            }
+                        }, 10000)
+                    }
+                } catch (e: Exception) {
+                    e.printStackTrace()
+                    showMsgMain("server error or net error")
+                }
+            }
+        } else {
+            Log.d(TAG, "server info null")
+            showMsgMain("get server null")
+        }
+    }
+
+    private fun showMsgMain(msg: String) {
+        runOnUiThread {
+            showMessage(msg)
+        }
+    }
+
     fun switchFragment(id: Int, fragment: Fragment, tag: String) {
         supportFragmentManager.beginTransaction()
                 .replace(id, fragment, tag)
@@ -452,6 +558,11 @@ class CallingdoorActivity :BaseActivity<CallingdoorActivityPresenter, Callingdoo
         Log.d("AppUpdate", "checkAppVersion =====>>  Constant.PART_ID: " + Constant.PART_ID)
     }
 
+    override fun cancelRestart() {
+        cancelRestart = true
+        handler.removeCallbacksAndMessages(null)
+    }
+
 
     override fun destory() {
         SoundPoolManager.getInstance().release()
@@ -498,7 +609,7 @@ class CallingdoorActivity :BaseActivity<CallingdoorActivityPresenter, Callingdoo
     }
 
     override fun setTcpServerHost(tcpSeverDTO: TcpSeverDTO) {
-        if (loaded) {
+        /*if (loaded) {
             return
         }
         loaded = true
@@ -522,6 +633,39 @@ class CallingdoorActivity :BaseActivity<CallingdoorActivityPresenter, Callingdoo
                     //
                 }
             }
+        }).start()*/
+    }
+
+    override fun setServerInfo(data: ServerInfo) {
+        if (loaded) {
+            return
+        }
+        loaded = true
+
+
+        Constant.TCP_SERVER_URL = data.tcpPublicIp
+        Constant.TCP_PORT = data.tcpPort
+        Constant.TCP_HEART_BEAT = data.tcpIdleSeconds
+
+        JanusConstant.JANUS_URL = "ws://" + data.rtcLocalIp + ":" + data.rtcPort
+        JanusConstant.STUN_SERVER = arrayOf<String>(data.stunServer)
+        //JanusConstant.TURN_SERVER = data.turnServer
+
+        //开启TCP连接
+        startTcp()
+        showMessage("tcp开始连接...host: " + Constant.TCP_SERVER_URL + ", port: " + Constant.TCP_PORT)
+
+        Thread(Runnable {
+            while (!initialized) {
+                runOnUiThread(Runnable {
+                    initDevice()
+                })
+                try {
+                    Thread.sleep(20000)
+                } catch (e: Exception) {
+                    //
+                }
+            }
         }).start()
     }
 
@@ -1009,7 +1153,7 @@ class CallingdoorActivity :BaseActivity<CallingdoorActivityPresenter, Callingdoo
                     }
                 } else if (TextUtils.isEmpty(Constant.TCP_SERVER_URL)) {
                     //还未连接tcp服务器
-                    presenter.loadTcpServerHost()
+                    //presenter.loadTcpServerHost()
                 }
             } else if (intent.action == ConnectivityManager.CONNECTIVITY_ACTION) {
                 updateNetState()

+ 56 - 0
callingdoor/src/main/java/com/wdkl/app/ncs/callingdoor/adapter/NumAdapter.java

@@ -0,0 +1,56 @@
+package com.wdkl.app.ncs.callingdoor.adapter;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.TextView;
+
+import com.wdkl.app.ncs.callingdoor.R;
+
+public class NumAdapter extends BaseAdapter {
+    private String[] num;
+    private Context context;
+
+    public NumAdapter(String[] numbers, Context context) {
+        this.num = numbers;
+        this.context = context;
+    }
+
+
+    @Override
+    public int getCount() {
+        return num.length;
+    }
+
+    @Override
+    public Object getItem(int position) {
+        return num[position];
+    }
+
+    @Override
+    public long getItemId(int position) {
+        return position;
+    }
+
+    @Override
+    public View getView(int position, View convertView, ViewGroup parent) {
+        ViewHolder viewHolder;
+        if (convertView == null) {
+            convertView = LayoutInflater.from(context).inflate(R.layout.digital_item, null);
+            viewHolder = new ViewHolder();
+            viewHolder.numTv = convertView.findViewById(R.id.tv_number);
+            convertView.setTag(viewHolder);
+        } else {
+            viewHolder = (ViewHolder) convertView.getTag();
+        }
+        viewHolder.numTv.setText(num[position]);
+
+        return convertView;
+    }
+
+    static class ViewHolder {
+        TextView numTv;
+    }
+}

+ 2 - 0
callingdoor/src/main/java/com/wdkl/app/ncs/callingdoor/agreement/CallingdoorAgreement.kt

@@ -6,4 +6,6 @@ interface CallingdoorAgreement {
 
     //检查APP版本
     fun checkAppVersion()
+
+    fun cancelRestart()
 }

+ 7 - 0
callingdoor/src/main/java/com/wdkl/app/ncs/callingdoor/fragment/QrCodeFragment.kt

@@ -8,6 +8,7 @@ import com.wdkl.app.ncs.callingdoor.activity.CallingdoorActivity
 import com.wdkl.app.ncs.callingdoor.databinding.QrCodeLayBinding
 import com.wdkl.app.ncs.callingdoor.helper.AppUpdateHelper
 import com.wdkl.app.ncs.callingdoor.helper.NetHelper
+import com.wdkl.app.ncs.callingdoor.helper.ServerConfigDialogHelper
 import com.wdkl.app.ncs.callingdoor.launch.CallingdoorLaunch
 import com.wdkl.ncs.android.lib.base.BaseFragment
 import com.wdkl.ncs.android.lib.utils.*
@@ -76,8 +77,14 @@ class QrCodeFragment : BaseFragment<QrCodeFragmentPresenter, QrCodeLayBinding>()
         }
 
         tv_btn_reboot.setOnClickListener {
+            (activity as CallingdoorActivity).cancelRestart()
             AppUpdateHelper.reboot(context)
         }
+
+        tv_btn_server_config.setOnClickListener {
+            (activity as CallingdoorActivity).cancelRestart()
+            ServerConfigDialogHelper.showPasswordDialog(activity)
+        }
     }
 
     override fun destory() {

+ 2 - 5
callingdoor/src/main/java/com/wdkl/app/ncs/callingdoor/fragment/SkyCallFragment.kt

@@ -7,7 +7,6 @@ import android.os.SystemClock
 import android.text.TextUtils
 import android.util.Log
 import android.view.View
-import android.view.ViewGroup
 import com.google.gson.Gson
 import com.wdkl.app.ncs.callingdoor.R
 import com.wdkl.app.ncs.callingdoor.helper.RingPlayHelper
@@ -17,8 +16,6 @@ import com.wdkl.ncs.android.lib.utils.showMessage
 import com.wdkl.ncs.android.middleware.common.Constant
 import com.wdkl.ncs.android.middleware.common.MessageEvent
 import com.wdkl.ncs.android.middleware.model.vo.InteractionVO
-import com.wdkl.ncs.android.middleware.tcp.channel.DeviceChannel
-import com.wdkl.ncs.android.middleware.tcp.channel.VideoUtil
 import com.wdkl.ncs.android.middleware.tcp.channel.VoiceUtil
 import com.wdkl.ncs.android.middleware.tcp.dto.TcpModel
 import com.wdkl.ncs.android.middleware.tcp.enums.DeviceTypeEnum
@@ -30,12 +27,12 @@ import com.wdkl.ncs.janus.client.VideoRoomCallback
 import com.wdkl.ncs.janus.entity.Room
 import com.wdkl.ncs.janus.rtc.WebRTCEngine
 import com.wdkl.ncs.janus.util.EnumType
+import com.wdkl.ncs.janus.util.JanusConstant
 import kotlinx.android.synthetic.main.sky_voice_call_layout.*
 import org.greenrobot.eventbus.Subscribe
 import org.greenrobot.eventbus.ThreadMode
 import org.webrtc.SurfaceViewRenderer
 import java.math.BigInteger
-import java.util.*
 
 class SkyCallFragment: BaseCallFragment(), CallSessionCallback {
     private val TAG = "SkyCallFragment"
@@ -80,7 +77,7 @@ class SkyCallFragment: BaseCallFragment(), CallSessionCallback {
         //初始化 engine
         WebRTCEngine.getInstance().init(true, activity)
         //初始化 janusClient
-        janusClient = JanusClient(com.wdkl.ncs.janus.util.Constant.JANUS_URL, Constant.SIP_ID.toBigInteger())
+        janusClient = JanusClient(JanusConstant.JANUS_URL, Constant.SIP_ID.toBigInteger())
 
         when (callState) {
             0 -> {

+ 151 - 0
callingdoor/src/main/java/com/wdkl/app/ncs/callingdoor/helper/ServerConfigDialogHelper.java

@@ -0,0 +1,151 @@
+package com.wdkl.app.ncs.callingdoor.helper;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.AdapterView;
+import android.widget.EditText;
+import android.widget.GridView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.wdkl.app.ncs.callingdoor.R;
+import com.wdkl.app.ncs.callingdoor.adapter.NumAdapter;
+import com.wdkl.ncs.android.lib.base.BaseApplication;
+import com.wdkl.ncs.android.middleware.utils.CommonUtils;
+
+
+public class ServerConfigDialogHelper {
+
+    private static AlertDialog callDialog;
+    private static String pwd = "";
+
+    public static void showPasswordDialog(final Activity activity) {
+        View contentView = LayoutInflater.from(activity).inflate(R.layout.server_config_dialog_lay, null);
+        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+        builder.setView(contentView);
+
+        final String[] numbers = {"1","2","3","4","5","6","7","8","9"};
+        final TextView password = contentView.findViewById(R.id.tv_psw_view);
+        final LinearLayout llPwd = contentView.findViewById(R.id.ll_password);
+        final LinearLayout llServer = contentView.findViewById(R.id.ll_server_config);
+        GridView gridView = contentView.findViewById(R.id.grid_psw);
+        NumAdapter adapter = new NumAdapter(numbers, activity);
+        gridView.setAdapter(adapter);
+        gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+            @Override
+            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+                if (pwd.length() <= 2) {
+                    pwd = pwd + numbers[position];
+                    password.setText(pwd);
+                }
+                Log.d("serverIp", "input password len: " + pwd.length() + "--" + pwd);
+            }
+        });
+
+        TextView delete = contentView.findViewById(R.id.btn_delete);
+        TextView cancel = contentView.findViewById(R.id.btn_cancel);
+        TextView confirm = contentView.findViewById(R.id.btn_confirm);
+        delete.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                Log.d("serverIp", "delete password len: " + pwd.length() + "--" + pwd);
+                if (pwd.length() > 1) {
+                    pwd = pwd.substring(0, pwd.length()-1);
+                    password.setText(pwd);
+                } else {
+                    pwd = "";
+                    password.setText(pwd);
+                    password.setHint(R.string.input_password);
+                }
+            }
+        });
+
+        cancel.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                dismissCallDialog();
+            }
+        });
+
+        confirm.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                if ("666".equals(pwd)) {
+                    llPwd.setVisibility(View.GONE);
+                    llServer.setVisibility(View.VISIBLE);
+                } else {
+                    Toast.makeText(activity, R.string.invalid_password, Toast.LENGTH_SHORT).show();
+                }
+            }
+        });
+
+        final EditText editUrl = contentView.findViewById(R.id.edit_url);
+        final EditText editPort = contentView.findViewById(R.id.edit_port);
+        final EditText editSipUrl = contentView.findViewById(R.id.edit_sip_url);
+        final EditText editSipPort = contentView.findViewById(R.id.edit_sip_port);
+        TextView saveConfig = contentView.findViewById(R.id.btn_save_config);
+        TextView cancelConfig = contentView.findViewById(R.id.btn_cancel_config);
+        editUrl.setText(CommonUtils.getUrl(BaseApplication.appContext));
+        editPort.setText(CommonUtils.getUrlPort(BaseApplication.appContext));
+        //editSipUrl.setText(CommonUtils.getSipUrl(BaseApplication.appContext));
+        //editSipPort.setText(CommonUtils.getSipPort(BaseApplication.appContext));
+        saveConfig.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                //保存配置
+                CommonUtils.setUrl(BaseApplication.appContext, editUrl.getText().toString());
+                CommonUtils.setUrlPort(BaseApplication.appContext, editPort.getText().toString());
+                //CommonUtils.setSipUrl(BaseApplication.appContext, editSipUrl.getText().toString());
+                //CommonUtils.setSipPort(BaseApplication.appContext, editSipPort.getText().toString());
+                dismissCallDialog();
+            }
+        });
+        cancelConfig.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                dismissCallDialog();
+            }
+        });
+
+
+        callDialog = builder.create();
+        callDialog.setCanceledOnTouchOutside(false);
+        callDialog.setCancelable(false);
+        callDialog.show();
+
+        //设置dialog宽高及位置
+        try {
+            Window window = callDialog.getWindow();
+            window.setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
+            WindowManager.LayoutParams lp = window.getAttributes();
+            lp.width = 400;
+            lp.height = 480;
+            lp.gravity = Gravity.CENTER;
+            window.setAttributes(lp);
+
+            window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
+                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                    | View.SYSTEM_UI_FLAG_FULLSCREEN);
+            window.clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    public static void dismissCallDialog() {
+        pwd = "";
+        if (callDialog != null && callDialog.isShowing()) {
+            callDialog.dismiss();
+        }
+    }
+}

+ 17 - 0
callingdoor/src/main/res/layout/digital_item.xml

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <TextView
+        android:id="@+id/tv_number"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="@color/color_gray"
+        android:layout_margin="4dp"
+        android:padding="10dp"
+        android:gravity="center"
+        android:textSize="32sp"
+        android:textColor="@color/main_color"/>
+
+</LinearLayout>

+ 13 - 0
callingdoor/src/main/res/layout/qr_code_lay.xml

@@ -126,6 +126,19 @@
             android:visibility="gone"/>
 
         <TextView
+            android:id="@+id/tv_btn_server_config"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_above="@id/tv_btn_update_app"
+            android:layout_marginBottom="10dp"
+            android:padding="10dp"
+            android:background="@color/main_color"
+            android:gravity="center_horizontal"
+            android:text="服务器配置"
+            android:textColor="@drawable/selector_bottom_btn_text_color"
+            android:textSize="24sp" />
+
+        <TextView
             android:id="@+id/tv_detail_title"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"

+ 189 - 0
callingdoor/src/main/res/layout/server_config_dialog_lay.xml

@@ -0,0 +1,189 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <!--密码框-->
+    <LinearLayout
+        android:id="@+id/ll_password"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:gravity="center"
+        android:orientation="vertical">
+
+        <TextView
+            android:id="@+id/tv_psw_view"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center"
+            android:textSize="24sp"
+            android:hint="@string/input_password"
+            android:textColor="@color/main_color"/>
+
+        <GridView
+            android:id="@+id/grid_psw"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="10dp"
+            android:verticalSpacing="5dp"
+            android:horizontalSpacing="5dp"
+            android:numColumns="3"/>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="20dp"
+            android:orientation="horizontal">
+            <TextView
+                android:id="@+id/btn_delete"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:padding="4dp"
+                android:gravity="center_horizontal"
+                android:text="@string/str_delete"
+                android:textSize="24sp"
+                android:textColor="@color/main_color"/>
+
+            <TextView
+                android:id="@+id/btn_cancel"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:padding="4dp"
+                android:gravity="center_horizontal"
+                android:text="@string/str_cancel"
+                android:textSize="24sp"
+                android:textColor="@color/main_color"/>
+            <TextView
+                android:id="@+id/btn_confirm"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:padding="4dp"
+                android:gravity="center_horizontal"
+                android:text="@string/str_confirm"
+                android:textSize="24sp"
+                android:textColor="@color/main_color"/>
+        </LinearLayout>
+    </LinearLayout>
+
+
+    <!--服务器ip配置-->
+    <LinearLayout
+        android:id="@+id/ll_server_config"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_marginTop="20dp"
+        android:padding="10dp"
+        android:orientation="vertical"
+        android:visibility="gone">
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content">
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:gravity="center"
+                android:text="Server IP:"
+                android:textSize="20sp"
+                android:textColor="@color/main_color"/>
+
+            <EditText
+                android:id="@+id/edit_url"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="4dp"
+                android:inputType="textUri"
+                android:textSize="20sp"/>
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content">
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:gravity="center"
+                android:text="Port:"
+                android:textSize="20sp"
+                android:textColor="@color/main_color"/>
+
+            <EditText
+                android:id="@+id/edit_port"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="4dp"
+                android:inputType="number"
+                android:textSize="20sp"/>
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:visibility="gone">
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:gravity="center"
+                android:text="Sip IP:"
+                android:textSize="20sp"
+                android:textColor="@color/main_color"/>
+
+            <EditText
+                android:id="@+id/edit_sip_url"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="4dp"
+                android:inputType="textUri"
+                android:textSize="20sp"/>
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:visibility="gone">
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:gravity="center"
+                android:text="Sip port:"
+                android:textSize="20sp"
+                android:textColor="@color/main_color"/>
+
+            <EditText
+                android:id="@+id/edit_sip_port"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="4dp"
+                android:inputType="number"
+                android:textSize="20sp" />
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="20dp">
+            <TextView
+                android:id="@+id/btn_cancel_config"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:gravity="center"
+                android:text="@string/str_cancel"
+                android:textSize="28sp"
+                android:textColor="@color/black"/>
+
+            <TextView
+                android:id="@+id/btn_save_config"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:gravity="center"
+                android:text="@string/str_save"
+                android:textSize="28sp"
+                android:textColor="@color/black" />
+        </LinearLayout>
+    </LinearLayout>
+</RelativeLayout>

+ 1 - 1
janus/build.gradle

@@ -36,5 +36,5 @@ dependencies {
     implementation fileTree(include: ['*.jar'], dir: 'libs')
 
     compile 'org.webrtc:google-webrtc:1.0.32006'
-    compile project(':common')
+    compile project(':middleware')
 }

+ 21 - 20
janus/src/main/java/com/wdkl/ncs/janus/rtc/WebRTCEngine.java

@@ -17,7 +17,7 @@ import android.view.View;
 
 import com.wdkl.ncs.janus.render.ProxyVideoSink;
 import com.wdkl.ncs.janus.rtc.observer.CreatePeerConnectionCallback;
-import com.wdkl.ncs.janus.util.Constant;
+import com.wdkl.ncs.janus.util.JanusConstant;
 
 import org.webrtc.AudioSource;
 import org.webrtc.AudioTrack;
@@ -112,27 +112,28 @@ public class WebRTCEngine {
     }
 
     private void initIceServer(){
-        PeerConnection.IceServer iceServer = null;
-        for(String stunServer: Constant.STUN_SERVER) {
-            if (stunServer.contains("|"))
-            {
-                String[] stunParams = stunServer.split("|");
-                iceServer = PeerConnection.IceServer
-                        .builder(stunParams[0])
-                        .setUsername(stunParams[1])
-                        .setPassword(stunParams[2])
-                        .setTlsCertPolicy(PeerConnection.TlsCertPolicy.TLS_CERT_POLICY_INSECURE_NO_CHECK)
-                        .createIceServer();
-            } else {
-                iceServer = PeerConnection.IceServer
-                        .builder(stunServer)
-                        .setTlsCertPolicy(PeerConnection.TlsCertPolicy.TLS_CERT_POLICY_INSECURE_NO_CHECK)
-                        .createIceServer();
+        PeerConnection.IceServer iceServer;
+        if (JanusConstant.STUN_SERVER != null) {
+            for (String stunServer : JanusConstant.STUN_SERVER) {
+                if (stunServer.contains("|")) {
+                    String[] stunParams = stunServer.split("|");
+                    iceServer = PeerConnection.IceServer
+                            .builder(stunParams[0])
+                            .setUsername(stunParams[1])
+                            .setPassword(stunParams[2])
+                            .setTlsCertPolicy(PeerConnection.TlsCertPolicy.TLS_CERT_POLICY_INSECURE_NO_CHECK)
+                            .createIceServer();
+                } else {
+                    iceServer = PeerConnection.IceServer
+                            .builder(stunServer)
+                            .setTlsCertPolicy(PeerConnection.TlsCertPolicy.TLS_CERT_POLICY_INSECURE_NO_CHECK)
+                            .createIceServer();
+                }
+                iceServers.add(iceServer);
             }
-            iceServers.add(iceServer);
         }
-        if (Constant.TURN_SERVER != null){
-            for(String turnServer:Constant.TURN_SERVER){
+        if (JanusConstant.TURN_SERVER != null){
+            for(String turnServer: JanusConstant.TURN_SERVER){
                 if (turnServer.contains("|"))
                 {
                     String[] turnParams = turnServer.split("|");

+ 0 - 14
janus/src/main/java/com/wdkl/ncs/janus/util/Constant.java

@@ -1,14 +0,0 @@
-package com.wdkl.ncs.janus.util;
-
-public class Constant {
-    public final static String GATEWAY_URL="8.129.220.143";
-    //public final static String GATEWAY_URL="172.28.100.100";
-    //public final static String GATEWAY_URL="119.23.151.229";
-    public final static String GATEWAY_WS_PORT="8188";
-    public final static String JANUS_URL = "ws://"+Constant.GATEWAY_URL+":" + Constant.GATEWAY_WS_PORT;
-
-    public final static String[] STUN_SERVER = new String[]{"stun:8.129.220.143:3478"};
-    //public final static String[] STUN_SERVER = new String[]{"stun:172.28.100.100:3478"};
-    //public final static String[] STUN_SERVER = new String[]{"stun:119.23.151.229:3478"};
-    public final static String[] TURN_SERVER = null; //new String[]{"turn:stun.l.google.com:19302|username|password"};
-}

+ 15 - 0
janus/src/main/java/com/wdkl/ncs/janus/util/JanusConstant.java

@@ -0,0 +1,15 @@
+package com.wdkl.ncs.janus.util;
+
+public class JanusConstant {
+    //public final static String GATEWAY_URL="8.129.220.143";
+    //public static String GATEWAY_URL="172.28.100.100";
+    //public final static String GATEWAY_URL="119.23.151.229";
+    //public final static String GATEWAY_URL="172.18.0.33";
+    //public static String GATEWAY_WS_PORT="8188";
+
+    public static String JANUS_URL = "ws://172.28.100.100:8188"; //默认的
+    //public static String STUN1 = "stun:" +GATEWAY_URL+ ":3478";
+    public static String[] STUN_SERVER = null; //new String[]{STUN1};
+
+    public static String[] TURN_SERVER = null; //new String[]{"turn:stun.l.google.com:19302|username|password"};
+}

+ 3 - 0
middleware/src/main/code/com/wdkl/ncs/android/middleware/api/DoorDeviceApi.kt

@@ -22,6 +22,9 @@ interface DoorDeviceApi {
     @GET("/ncs_url/getHostIP")
     fun getTcpServerHost(): Observable<ResponseBody>
 
+    @GET("/ncs_url/server_info")
+    fun getServerInfo(): Observable<ResponseBody>
+
     //获取APP版本信息
     @POST("/deviceRoom/get_app_version")
     fun getAppVersion(@Query("part_id") part_id:Int, @Query("device_type") device_type:Int): Observable<ResponseBody>

+ 12 - 3
middleware/src/main/code/com/wdkl/ncs/android/middleware/api/UrlManager.kt

@@ -1,6 +1,8 @@
 package com.wdkl.ncs.android.middleware.api
 
+import com.wdkl.ncs.android.lib.base.BaseApplication
 import com.wdkl.ncs.android.middleware.config.WdklNcsConfigCenter
+import com.wdkl.ncs.android.middleware.utils.CommonUtils
 
 /**
  * @author LDD
@@ -34,11 +36,13 @@ interface UrlManager {
          * @Note   构架Url控制器
          */
         fun build() : UrlManager{
-            if (WdklNcsConfigCenter.INSTANCE.APP_DEV){
+            return ProUrlManager()
+
+            /*if (WdklNcsConfigCenter.INSTANCE.APP_DEV){
                 return DevUrlManager()
             }else{
                 return ProUrlManager()
-            }
+            }*/
         }
 
     }
@@ -72,13 +76,18 @@ private class DevUrlManager : UrlManager{
  * @Note   生产模式Url控制器
  */
 private class ProUrlManager : UrlManager{
+    val url: String = CommonUtils.getUrl(BaseApplication.appContext)
+    val port: String = CommonUtils.getUrlPort(BaseApplication.appContext)
 
     override val base: String
+        get() = "http://$url:$port/"
+
         //get() = "http://api.%s.wdklian.com/"
         //get() = "http://172.28.100.100:8006/"
-        get() = "http://8.129.220.143:8006/"
+        //get() = "http://8.129.220.143:8006/"
         //get() = "http://dev.base.wdklian.com:6005/"
         //get() = "http://47.106.200.55:8006"
+        //get() = "http://119.23.151.229:8006/"
 
     override val buyer: String
         get() = String.format(base,"buyer")

+ 5 - 0
middleware/src/main/code/com/wdkl/ncs/android/middleware/logic/contract/callingdoor/CallingdoorActivityContract.kt

@@ -1,6 +1,7 @@
 package com.wdkl.ncs.android.middleware.logic.contract.callingdoor
 
 import com.wdkl.ncs.android.lib.base.BaseContract
+import com.wdkl.ncs.android.middleware.model.ServerInfo
 import com.wdkl.ncs.android.middleware.model.dos.AppVersionDO
 import com.wdkl.ncs.android.middleware.model.dos.PartSettingDO
 import com.wdkl.ncs.android.middleware.model.dto.TcpSeverDTO
@@ -17,6 +18,8 @@ interface CallingdoorActivityContract {
 
         fun setTcpServerHost(tcpSeverDTO: TcpSeverDTO)
 
+        fun setServerInfo(data: ServerInfo)
+
         fun loadAppVersion(appInfo: AppVersionDO)
 
         fun onNoNet()
@@ -33,6 +36,8 @@ interface CallingdoorActivityContract {
         //获取tcp服务器地址
         fun loadTcpServerHost()
 
+        fun loadServerInfo()
+
         //获取APP版本信息
         fun getAppVersion(partId: Int, deviceType: Int)
     }

+ 17 - 4
middleware/src/main/code/com/wdkl/ncs/android/middleware/logic/presenter/callingdoor/CallingdoorActivityPresenter.kt

@@ -10,6 +10,7 @@ import com.wdkl.ncs.android.lib.utils.*
 import com.wdkl.ncs.android.middleware.api.DoorDeviceApi
 import com.wdkl.ncs.android.middleware.di.MiddlewareDaggerComponent
 import com.wdkl.ncs.android.middleware.logic.contract.callingdoor.CallingdoorActivityContract
+import com.wdkl.ncs.android.middleware.model.ServerInfo
 import com.wdkl.ncs.android.middleware.model.dos.AppVersionDO
 import com.wdkl.ncs.android.middleware.model.dos.PartSettingDO
 import com.wdkl.ncs.android.middleware.model.dto.TcpSeverDTO
@@ -34,25 +35,25 @@ class CallingdoorActivityPresenter @Inject constructor() :RxPresenter<Callingdoo
             when (result) {
                 is DeviceRoomInfoVO -> {
                     //设备信息
-                    providerView().complete("")
                     providerView().showDeviceInfo(result)
                 }
 
                 is PartSettingDO -> {
                     //设置参数
-                    providerView().complete("")
                     providerView().setPartSettings(result)
                 }
 
                 is TcpSeverDTO -> {
                     //tcp服务器地址
-                    providerView().complete("")
                     providerView().setTcpServerHost(result)
                 }
 
+                is ServerInfo -> {
+                    providerView().setServerInfo(result)
+                }
+
                 is AppVersionDO -> {
                     //app版本信息
-                    providerView().complete("")
                     providerView().loadAppVersion(result)
                 }
             }
@@ -108,6 +109,18 @@ class CallingdoorActivityPresenter @Inject constructor() :RxPresenter<Callingdoo
                 .subscribe(observer)
     }
 
+    override fun loadServerInfo() {
+        doorDeviceApi.getServerInfo()
+            .map {
+                val gson = GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create()
+                val serverInfo = gson.fromJson(it.getJsonString(), ServerInfo::class.java)
+
+                return@map serverInfo
+            }
+            .compose(ThreadFromUtils.defaultSchedulers())
+            .subscribe(observer)
+    }
+
     override fun getAppVersion(partId: Int, deviceType: Int) {
         doorDeviceApi.getAppVersion(partId, deviceType)
                 .map {

+ 56 - 0
middleware/src/main/code/com/wdkl/ncs/android/middleware/model/JsonResponse.java

@@ -0,0 +1,56 @@
+package com.wdkl.ncs.android.middleware.model;
+
+import java.io.Serializable;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * 描述
+ *
+ * @author allen
+ * 2019-03-29 15:34
+ */
+@ApiModel("接口操作结果返回对象")
+public class JsonResponse implements Serializable {
+    //成功失败标识
+    @ApiModelProperty("操作结果成功与否标识")
+    public boolean success;
+    //一般用于失败时的错误提示
+    @ApiModelProperty("操作结果消息提示")
+    public String message;
+    //返回的对象
+    @ApiModelProperty("操作结果返回对象")
+    public Object data;
+
+    public JsonResponse() {
+    }
+
+    public static JsonResponse successResponse() {
+        JsonResponse response = new JsonResponse();
+        response.success = true;
+        return response;
+    }
+
+    public static JsonResponse successResponse(Object data) {
+        JsonResponse response = new JsonResponse();
+        response.success = true;
+        response.data = data;
+        return response;
+    }
+
+    public static JsonResponse successResponse(String message, Object data) {
+        JsonResponse response = new JsonResponse();
+        response.success = true;
+        response.message = message;
+        response.data = data;
+        return response;
+    }
+
+    public static JsonResponse errorResponse(String message) {
+        JsonResponse response = new JsonResponse();
+        response.success = false;
+        response.message = message;
+        return response;
+    }
+}

+ 178 - 0
middleware/src/main/code/com/wdkl/ncs/android/middleware/model/ServerInfo.java

@@ -0,0 +1,178 @@
+package com.wdkl.ncs.android.middleware.model;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.PropertyNamingStrategy;
+import com.fasterxml.jackson.databind.annotation.JsonNaming;
+
+import java.io.Serializable;
+
+import io.swagger.annotations.ApiModelProperty;
+
+@JsonNaming(value = PropertyNamingStrategy.SnakeCaseStrategy.class)
+public class ServerInfo implements Serializable {
+    @ApiModelProperty(notes = "局域网TCP服务器IP")
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private String tcpLocalIp;
+
+    @ApiModelProperty(notes = "互联网TCP服务器IP")
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private String tcpPublicIp;
+
+    @ApiModelProperty(notes = "TCP端口")
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private Integer tcpPort;
+
+    @ApiModelProperty(notes = "TCP体征数据库端口")
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private Integer tcpVsPort;
+
+    @ApiModelProperty(notes = "TCP心跳间隔,单位:秒")
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private Integer tcpIdleSeconds;
+
+    @ApiModelProperty(notes = "局域网HTTP服务器IP")
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private String httpLocalIp;
+
+    @ApiModelProperty(notes = "互联网HTTP服务器IP")
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private String httpPublicIp;
+
+    @ApiModelProperty(notes = "HTTP端口")
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private Integer httpPort;
+
+    @ApiModelProperty(notes = "RTC Local IP")
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private String rtcLocalIp;
+
+    @ApiModelProperty(notes = "RTC Public IP")
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private String rtcPublicIp;
+
+    @ApiModelProperty(notes = "RTC 端口")
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private Integer rtcPort;
+
+    @ApiModelProperty(notes = "stun地址", example = "stun:xxx.xxx.xxx.xxx:3478")
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private String stunServer;
+
+    @ApiModelProperty(notes = "turn地址", example = "turn:xxx.xxx.xxx.xxx:3478|username|password")
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private String[] turnServer;
+
+    private Long serverTime;
+
+    public String getTcpLocalIp() {
+        return tcpLocalIp;
+    }
+
+    public void setTcpLocalIp(String tcpLocalIp) {
+        this.tcpLocalIp = tcpLocalIp;
+    }
+
+    public String getTcpPublicIp() {
+        return tcpPublicIp;
+    }
+
+    public void setTcpPublicIp(String tcpPublicIp) {
+        this.tcpPublicIp = tcpPublicIp;
+    }
+
+    public Integer getTcpPort() {
+        return tcpPort;
+    }
+
+    public void setTcpPort(Integer tcpPort) {
+        this.tcpPort = tcpPort;
+    }
+
+    public Integer getTcpVsPort() {
+        return tcpVsPort;
+    }
+
+    public void setTcpVsPort(Integer tcpVsPort) {
+        this.tcpVsPort = tcpVsPort;
+    }
+
+    public Integer getTcpIdleSeconds() {
+        return tcpIdleSeconds;
+    }
+
+    public void setTcpIdleSeconds(Integer tcpIdleSeconds) {
+        this.tcpIdleSeconds = tcpIdleSeconds;
+    }
+
+    public String getHttpLocalIp() {
+        return httpLocalIp;
+    }
+
+    public void setHttpLocalIp(String httpLocalIp) {
+        this.httpLocalIp = httpLocalIp;
+    }
+
+    public String getHttpPublicIp() {
+        return httpPublicIp;
+    }
+
+    public void setHttpPublicIp(String httpPublicIp) {
+        this.httpPublicIp = httpPublicIp;
+    }
+
+    public Integer getHttpPort() {
+        return httpPort;
+    }
+
+    public void setHttpPort(Integer httpPort) {
+        this.httpPort = httpPort;
+    }
+
+    public String getRtcLocalIp() {
+        return rtcLocalIp;
+    }
+
+    public void setRtcLocalIp(String rtcLocalIp) {
+        this.rtcLocalIp = rtcLocalIp;
+    }
+
+    public String getRtcPublicIp() {
+        return rtcPublicIp;
+    }
+
+    public void setRtcPublicIp(String rtcPublicIp) {
+        this.rtcPublicIp = rtcPublicIp;
+    }
+
+    public Integer getRtcPort() {
+        return rtcPort;
+    }
+
+    public void setRtcPort(Integer rtcPort) {
+        this.rtcPort = rtcPort;
+    }
+
+    public String getStunServer() {
+        return stunServer;
+    }
+
+    public void setStunServer(String stunServer) {
+        this.stunServer = stunServer;
+    }
+
+    public String[] getTurnServer() {
+        return turnServer;
+    }
+
+    public void setTurnServer(String[] turnServer) {
+        this.turnServer = turnServer;
+    }
+
+    public Long getServerTime() {
+        return serverTime;
+    }
+
+    public void setServerTime(Long serverTime) {
+        this.serverTime = serverTime;
+    }
+}

+ 33 - 0
middleware/src/main/code/com/wdkl/ncs/android/middleware/model/ThirdServerInfo.java

@@ -0,0 +1,33 @@
+package com.wdkl.ncs.android.middleware.model;
+
+import com.fasterxml.jackson.databind.PropertyNamingStrategy;
+import com.fasterxml.jackson.databind.annotation.JsonNaming;
+
+import java.io.Serializable;
+
+@JsonNaming(value = PropertyNamingStrategy.SnakeCaseStrategy.class)
+public class ThirdServerInfo implements Serializable {
+    private String thirdServer;
+    private Integer thirdServerPort;
+
+    public ThirdServerInfo(String thirdServer, Integer thirdServerPort){
+        this.thirdServer = thirdServer;
+        this.thirdServerPort = thirdServerPort;
+    }
+
+    public String getThirdServer() {
+        return thirdServer;
+    }
+
+    public void setThirdServer(String thirdServer) {
+        this.thirdServer = thirdServer;
+    }
+
+    public Integer getThirdServerPort() {
+        return thirdServerPort;
+    }
+
+    public void setThirdServerPort(Integer thirdServerPort) {
+        this.thirdServerPort = thirdServerPort;
+    }
+}

+ 108 - 0
middleware/src/main/code/com/wdkl/ncs/android/middleware/udp/NetIpUtil.java

@@ -0,0 +1,108 @@
+package com.wdkl.ncs.android.middleware.udp;
+
+import java.net.InetAddress;
+import java.net.InterfaceAddress;
+import java.net.NetworkInterface;
+import java.net.UnknownHostException;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+
+public class NetIpUtil {
+
+    public static void main(String[] args) {
+        System.out.println(calBroadcastAddress());
+    }
+
+    public static String calBroadcastAddress() {
+        try {
+            Enumeration<NetworkInterface> eni = NetworkInterface
+                    .getNetworkInterfaces();
+            while (eni.hasMoreElements()) {
+
+                NetworkInterface networkCard = eni.nextElement();
+                List<InterfaceAddress> ncAddrList = networkCard
+                        .getInterfaceAddresses();
+                Iterator<InterfaceAddress> ncAddrIterator = ncAddrList.iterator();
+                while (ncAddrIterator.hasNext()) {
+                    InterfaceAddress networkCardAddress = ncAddrIterator.next();
+                    InetAddress address = networkCardAddress.getAddress();
+                    if (!address.isLoopbackAddress()) {
+                        String hostAddress = address.getHostAddress();
+
+                        if (hostAddress.indexOf(":") > 0) {
+                            // case : ipv6
+                            continue;
+                        } else {
+//                            System.out.println("address        =   " + hostAddress);
+                            // case : ipv4
+//                            String maskAddress = calcMaskByPrefixLength(networkCardAddress.getNetworkPrefixLength());
+//                            String subnetAddress = calcSubnetAddress(hostAddress, maskAddress);
+                            String broadcastAddress = networkCardAddress.getBroadcast().getHostAddress();
+                            return broadcastAddress;
+
+//                            System.out.println("subnetmask     =   "+ maskAddress);
+//                            System.out.println("subnet         =   "+ subnetAddress);
+//                            System.out.println("broadcast      =   "+ broadcastAddress+"\n");
+                        }
+                    } else {
+                        String loopback = networkCardAddress.getAddress().getHostAddress();
+//                        System.out.println("loopback addr  =   " + loopback +"\n");
+                    }
+                }
+
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    public static String calcMaskByPrefixLength(int length) {
+        int mask = -1 << (32 - length);
+        int partsNum = 4;
+        int bitsOfPart = 8;
+        int maskParts[] = new int[partsNum];
+        int selector = 0x000000ff;
+
+        for (int i = 0; i < maskParts.length; i++) {
+            int pos = maskParts.length - 1 - i;
+            maskParts[pos] = (mask >> (i * bitsOfPart)) & selector;
+        }
+
+        String result = "";
+        result = result + maskParts[0];
+        for (int i = 1; i < maskParts.length; i++) {
+            result = result + "." + maskParts[i];
+        }
+        return result;
+    }
+
+    public static String calcSubnetAddress(String ip, String mask) {
+        String result = "";
+        try {
+            // calc sub-net IP
+            InetAddress ipAddress = InetAddress.getByName(ip);
+            InetAddress maskAddress = InetAddress.getByName(mask);
+
+            byte[] ipRaw = ipAddress.getAddress();
+            byte[] maskRaw = maskAddress.getAddress();
+
+            int unsignedByteFilter = 0x000000ff;
+            int[] resultRaw = new int[ipRaw.length];
+            for (int i = 0; i < resultRaw.length; i++) {
+                resultRaw[i] = (ipRaw[i] & maskRaw[i] & unsignedByteFilter);
+            }
+
+            // make result string
+            result = result + resultRaw[0];
+            for (int i = 1; i < resultRaw.length; i++) {
+                result = result + "." + resultRaw[i];
+            }
+        } catch (UnknownHostException e) {
+            e.printStackTrace();
+        }
+
+        return result;
+    }
+}

+ 108 - 0
middleware/src/main/code/com/wdkl/ncs/android/middleware/udp/ServerInfoUtil.java

@@ -0,0 +1,108 @@
+package com.wdkl.ncs.android.middleware.udp;
+
+import android.os.Environment;
+import android.util.Log;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.wdkl.ncs.android.middleware.model.JsonResponse;
+import com.wdkl.ncs.android.middleware.model.ThirdServerInfo;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.concurrent.TimeUnit;
+
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+
+public class ServerInfoUtil {
+    private final static String TAG = ServerInfoUtil.class.getSimpleName();
+
+    private final static String WdklCloudServerAPIUrl = "http://api.base.wdklian.com/ncs_sync/server_info/";
+    /**
+     * 获取服务器IP及相关。注意:放在子线程调用,会阻塞主线程
+     * @param id,设备识别码,IMEI、MAC或其它
+     *
+     * 优先从文件获取服务器信息
+     * 文件示例:
+    {
+        "success":true,
+        "data":{
+            "third_server":"192.168.1.188",
+            "third_server_port":8006
+        }
+    }
+
+     第二段请求 /ncs_url/server_info
+     返回示例:{"tcp_local_ip":"192.168.1.188","tcp_public_ip":"192.168.1.188","tcp_port":5080,"tcp_idle_seconds":60,"http_local_ip":"192.168.1.188","http_public_ip":"192.168.1.188","http_port":8006,"rtc_local_ip":"192.168.1.188","rtc_public_ip":"192.168.1.188","rtc_port":8188,"stun_server":"stun:8.129.220.143:3478","turn_server":["turn:8.129.220.143:3478?transport=tcp|wdklrtc|Wdkl2021Rtc","turn:8.129.220.143:3478?transport=udp|wdklrtc|Wdkl2021Rtc"],"server_time":1640767161}
+     */
+    public static ThirdServerInfo get(String id){
+        //--------------------优先从文件获取
+        JsonResponse jsonResponse = getFromStorageFile();
+        if (jsonResponse != null && jsonResponse.success){
+            JSONObject jsonObject = JSON.parseObject(jsonResponse.data.toString());
+            ThirdServerInfo thirdServerInfo = new ThirdServerInfo(jsonObject.getString("third_server"), jsonObject.getInteger("third_server_port"));
+            return thirdServerInfo;
+        }
+
+        //--------------------HTTP请求全局服务器获取
+        OkHttpClient okHttpClient = new OkHttpClient().newBuilder()
+                .connectTimeout(15 * 1000, TimeUnit.MILLISECONDS)
+                .readTimeout(15 * 1000, TimeUnit.MILLISECONDS)
+                .writeTimeout(15 * 1000, TimeUnit.MILLISECONDS)
+                .build();
+        Request request = new Request.Builder().url(WdklCloudServerAPIUrl + id)
+                .get().build();
+        try {
+            Response response = okHttpClient.newCall(request).execute();
+            if (response != null && response.isSuccessful()){
+                jsonResponse = JSON.parseObject(response.body().string(), JsonResponse.class);
+                if (jsonResponse.success){
+                    JSONObject jsonObject = JSON.parseObject(jsonResponse.data.toString());
+                    ThirdServerInfo thirdServerInfo = new ThirdServerInfo(jsonObject.getString("third_server"), jsonObject.getInteger("third_server_port"));
+                    return thirdServerInfo;
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+        //--------------------HTTP未请求成功,发送UDP获取
+        String udpResponse = UdpClient.getInstance().broadMsg(UdpClient.SEARCH_SERVER,UdpClient.UDP_TARGET_PORT);
+        jsonResponse = JSON.parseObject(udpResponse, JsonResponse.class);
+        if (jsonResponse != null && jsonResponse.success){
+            JSONObject jsonObject = JSON.parseObject(jsonResponse.data.toString());
+            ThirdServerInfo thirdServerInfo = new ThirdServerInfo(jsonObject.getString("third_server"), jsonObject.getInteger("third_server_port"));
+            return thirdServerInfo;
+        }
+        return null;
+    }
+
+    private static JsonResponse getFromStorageFile(){
+        String encoding = "UTF-8";
+        File file = new File(Environment.getExternalStorageDirectory() + "/server_info.json");
+        Long filelength = file.length();
+        byte[] filecontent = new byte[filelength.intValue()];
+        try {
+            FileInputStream in = new FileInputStream(file);
+            in.read(filecontent);
+            in.close();
+        } catch (FileNotFoundException e) {
+        } catch (IOException e) {
+        }
+        try {
+            String content = new String(filecontent, encoding);
+            Log.i(TAG,content);
+            JsonResponse response = JSON.parseObject(content, JsonResponse.class);
+            return response;
+        } catch (UnsupportedEncodingException e) {
+            return JsonResponse.errorResponse(e.getMessage());
+        } catch (Exception e){
+            return JsonResponse.errorResponse(e.getMessage());
+        }
+    }
+}

+ 123 - 0
middleware/src/main/code/com/wdkl/ncs/android/middleware/udp/UdpClient.java

@@ -0,0 +1,123 @@
+package com.wdkl.ncs.android.middleware.udp;
+
+import java.net.InetSocketAddress;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import io.netty.bootstrap.Bootstrap;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelOption;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.DatagramPacket;
+import io.netty.channel.socket.nio.NioDatagramChannel;
+import io.netty.util.CharsetUtil;
+import io.netty.util.concurrent.Future;
+import io.netty.util.concurrent.GenericFutureListener;
+
+public class UdpClient {
+    private final String TAG = getClass().getSimpleName();
+
+    private NioEventLoopGroup workGroup;
+    public Channel channel;
+    private Bootstrap bootstrap;
+
+    Lock lock = new ReentrantLock();
+    public static String result = null;
+
+    public static final String SEARCH_SERVER = "search_server";
+    public static final Integer UDP_TARGET_PORT = 10010;
+    static Integer retrySendCountLimit = 5; //最大重发次数
+    static Integer retrySendSeconds = 3;    //重发间隔
+    static Integer retrySendCount = 0;  //重发计数
+
+    UdpClientHandler udpClientHandler = new UdpClientHandler();
+
+    //单例
+    private static class UdpClientHolder {
+        private static UdpClient instance = new UdpClient();
+    }
+
+    public static UdpClient getInstance() {
+        return UdpClientHolder.instance;
+    }
+
+    private void run(){
+        workGroup = new NioEventLoopGroup(2);
+        bootstrap = new Bootstrap();
+        bootstrap.group(workGroup)
+                .channel(NioDatagramChannel.class)
+                .option(ChannelOption.SO_BROADCAST,true)
+                .handler(udpClientHandler);
+        try {
+            channel = bootstrap.bind(0).sync().channel();
+        }catch (Exception ex){
+            System.out.println(ex.getMessage());
+        }
+    }
+
+
+    public String broadMsg(String msg, Integer serverPort){
+        lock.lock();
+        CountDownLatch latch = new CountDownLatch(1);
+        udpClientHandler.resetLatch(latch);
+        run();
+        System.out.println("发送消息:" + msg);
+        try {
+            String broadcastAddress = NetIpUtil.calBroadcastAddress();
+            channel.writeAndFlush(new DatagramPacket(
+                    Unpooled.copiedBuffer(msg, CharsetUtil.UTF_8),
+                    new InetSocketAddress(broadcastAddress, serverPort)
+            )).sync().addListener(new GenericFutureListener<Future<? super Void>>() {
+                @Override
+                public void operationComplete(Future<? super Void> future) throws Exception {
+                    if (future.isSuccess()){
+                        System.out.println("发送成功");
+                    }
+                }
+            });
+            //等待3秒后,未收到信息,再次发送udp
+            if (latch.await(retrySendSeconds, TimeUnit.SECONDS)){
+                if (retrySendCount>=retrySendCountLimit){
+                    retrySendCount = 0;
+                    result = null;
+                    close();
+                }
+                if (result==null) {
+                    retrySendCount++;
+                    broadMsg(msg, serverPort);
+                } else {
+                    return result;
+                }
+            }
+            if (!channel.closeFuture().await(retrySendSeconds*retrySendCountLimit*1000)){
+                //超时15秒
+                System.out.println("超时停止");
+                result = null;
+            }
+        }catch (Exception ex){
+            System.out.println(ex.getMessage());
+            result = null;
+        }finally {
+            close();
+        }
+        return null;
+    }
+
+    private void close(){
+        workGroup.shutdownGracefully();
+        try{
+            if (lock!=null){
+                lock.unlock();
+            }
+        }catch (IllegalMonitorStateException ex){
+            Thread.currentThread().interrupt();
+        }
+    }
+
+    public static void main(String[] args) {
+        System.out.println("result = " + UdpClient.getInstance().broadMsg(SEARCH_SERVER,UDP_TARGET_PORT));
+    }
+}

+ 43 - 0
middleware/src/main/code/com/wdkl/ncs/android/middleware/udp/UdpClientHandler.java

@@ -0,0 +1,43 @@
+package com.wdkl.ncs.android.middleware.udp;
+
+import java.util.concurrent.CountDownLatch;
+
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.channel.socket.DatagramPacket;
+import io.netty.util.CharsetUtil;
+
+@ChannelHandler.Sharable
+public class UdpClientHandler extends SimpleChannelInboundHandler<DatagramPacket> {
+
+    //使用此应用为同步回调
+    private CountDownLatch latch;
+
+    @Override
+    protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception {
+        String response = msg.content().toString(CharsetUtil.UTF_8);
+        System.out.println(response);
+        /*
+        jsonObject.put("public_ip", tcpServerDTO.getPublicIp());
+        jsonObject.put("local_ip", tcpServerDTO.getLocalIp());
+        jsonObject.put("tcp_port", tcpServerDTO.getTcpPort());
+        jsonObject.put("reader_idle_time", tcpServerDTO.getReaderIdleTime());
+         */
+//        JsonResponse jsonResponse = JSON.parseObject(response, JsonResponse.class);
+//        if (jsonResponse.success){
+            UdpClient.result = response;
+            latchCountDown();
+//        }
+        ctx.close();
+    }
+
+    public void latchCountDown(){
+        latch.countDown();
+    }
+
+    public void resetLatch(CountDownLatch latch){
+        this.latch = latch;
+    }
+
+}

+ 94 - 0
middleware/src/main/code/com/wdkl/ncs/android/middleware/utils/CommonUtils.java

@@ -0,0 +1,94 @@
+package com.wdkl.ncs.android.middleware.utils;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.text.TextUtils;
+
+public class CommonUtils {
+
+    private static final String SP_NAME = "SP_URL";
+    private static final String KEY_SP_THIRD_URL = "KEY_SP_THIRD_URL";
+    private static final String KEY_SP_THIRD_URL_PORT = "KEY_SP_THIRD_URL_PORT";
+    private static final String KEY_SP_URL = "KEY_SP_URL";
+    private static final String KEY_SP_URL_PORT = "KEY_SP_URL_PORT";
+    private static final String KEY_SP_SIP_URL = "KEY_SP_SIP_URL";
+    private static final String KEY_SP_SIP_PORT = "KEY_SP_SIP_PORT";
+
+    //默认ip端口
+    //private static final String DEFAULT_URL = "8.129.220.143";
+    private static final String DEFAULT_URL = "172.28.100.100";
+    //private static final String DEFAULT_URL = "192.168.8.5";
+    private static final String DEFAULT_URL_PORT = "8006";
+    private static final String DEFAULT_SIP_PORT = "8188";
+
+
+    public static String getUrl(Context context) {
+        return getSP(context).getString(KEY_SP_URL, DEFAULT_URL);
+    }
+
+    public static void setUrl(Context context, String url) {
+        getEditor(context).putString(KEY_SP_URL, url).apply();
+    }
+
+    public static String getUrlPort(Context context) {
+        return getSP(context).getString(KEY_SP_URL_PORT, DEFAULT_URL_PORT);
+    }
+
+    public static void setUrlPort(Context context, String port) {
+        getEditor(context).putString(KEY_SP_URL_PORT, port).apply();
+    }
+
+    /*public static String getSipUrl(Context context) {
+        if (TextUtils.isEmpty(getSP(context).getString(KEY_SP_SIP_URL, DEFAULT_URL))) {
+            return DEFAULT_URL;
+        }
+        return getSP(context).getString(KEY_SP_SIP_URL, DEFAULT_URL);
+    }
+
+    public static void setSipUrl(Context context, String url) {
+        getEditor(context).putString(KEY_SP_SIP_URL, url).apply();
+    }
+
+    public static String getSipPort(Context context) {
+        if (TextUtils.isEmpty(getSP(context).getString(KEY_SP_SIP_PORT, DEFAULT_SIP_PORT))) {
+            return DEFAULT_SIP_PORT;
+        }
+        return getSP(context).getString(KEY_SP_SIP_PORT, DEFAULT_SIP_PORT);
+    }
+
+    public static void setSipPort(Context context, String port) {
+        getEditor(context).putString(KEY_SP_SIP_PORT, port).apply();
+    }
+
+    public static String getThirdUrl(Context context) {
+        if (TextUtils.isEmpty(getSP(context).getString(KEY_SP_THIRD_URL, DEFAULT_URL))) {
+            return DEFAULT_URL;
+        }
+        return getSP(context).getString(KEY_SP_THIRD_URL, DEFAULT_URL);
+    }
+
+    public static void setThirdUrl(Context context, String port) {
+        getEditor(context).putString(KEY_SP_THIRD_URL, port).apply();
+    }
+
+    public static String getThirdUrlPort(Context context) {
+        if (TextUtils.isEmpty(getSP(context).getString(KEY_SP_THIRD_URL_PORT, DEFAULT_URL_PORT))) {
+            return DEFAULT_URL_PORT;
+        }
+        return getSP(context).getString(KEY_SP_THIRD_URL_PORT, DEFAULT_URL_PORT);
+    }
+
+    public static void setThirdUrlPort(Context context, String port) {
+        getEditor(context).putString(KEY_SP_THIRD_URL_PORT, port).apply();
+    }*/
+
+
+
+    private static SharedPreferences getSP(Context context) {
+        return context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
+    }
+
+    private static SharedPreferences.Editor getEditor(Context context) {
+        return getSP(context).edit();
+    }
+}

+ 58 - 0
resource/src/main/res/values-zh/strings.xml

@@ -0,0 +1,58 @@
+<resources>
+    <string name="javashop_app_name">NCS-门口机</string>
+    <string name="javashop_qrcode_name">扫啊扫</string>
+    <string name="javashop_navigation_home_title">首页</string>
+    <string name="javashop_navigation_category_title">分类</string>
+    <string name="javashop_navigation_cart_title">购物车</string>
+    <string name="javashop_navigation_persion_title">我的</string>
+    <string name="javashop_cart_shop_item_title">优惠券</string>
+    <string name="javashop_group_promotion_fulldiscount">满折</string>
+    <string name="javashop_group_promotion_fullminus">满减</string>
+    <string name="javashop_group_promotion_point">积分</string>
+    <string name="javashop_group_promotion_freeship">免邮</string>
+    <string name="javashop_group_promotion_gift">赠品</string>
+    <string name="javashop_group_promotion_bonus">赠券</string>
+    <string name="javashop_group_not_full_tobuy">再逛逛</string>
+    <string name="javashop_promotion_string">促销</string>
+    <string name="javashop_singgle_promotion_edit_string">修改</string>
+    <string name="javashop_member_action_order_wait_pay">待付款</string>
+    <string name="javashop_member_action_order_wait_rog">待收货</string>
+    <string name="javashop_member_action_order_wait_comment">待评论</string>
+    <string name="javashop_member_action_aftersale">退换/售后</string>
+    <string name="javashop_member_action_order_all">我的订单</string>
+    <string name="javashop_member_action_point">积分</string>
+    <string name="javashop_member_action_bouns">优惠券</string>
+    <string name="javashop_member_action_goods">收藏商品</string>
+    <string name="javashop_member_action_shop">收藏店铺</string>
+    <string name="javashop_member_action_security">账户安全</string>
+    <string name="javashop_member_action_history">我的足迹</string>
+    <string name="javashop_member_action_address">我的地址</string>
+    <string name="javashop_member_action_user_service">客户服务</string>
+    <string name="javashop_setting_action_receipt">我的发票</string>
+    <string name="javashop_setting_action_privacy">隐私设置</string>
+    <string name="javashop_setting_action_share">应用分享</string>
+    <string name="javashop_setting_action_about">关于</string>
+    <string name="javashop_setting_action_logout">退出登录</string>
+    <string name="javashop_setting_action_cache">清除缓存</string>
+    <string name="javashop_goods_filter_all">全部</string>
+    <string name="javashop_all_brand">全部品牌</string>
+    <string name="javashop_confrim">确定</string>
+    <string name="javashop_cancel">取消</string>
+    <string name="javashop_add_cart">加入购物车</string>
+    <string name="javashop_shop">店铺</string>
+    <string name="javashop_self">自营</string>
+    <string name="javashop_collect">关注</string>
+    <string name="javashop_cart">购物车</string>
+    <string name="javashop_login">登录</string>
+    <string name="javashop_send_message">发送验证码</string>
+    <string name="javashop_use">立即使用</string>
+    <string name="javashop_get">立即领取</string>
+
+    <string name="input_password">请输入密码</string>
+    <string name="invalid_password">密码错误</string>
+
+    <string name="str_delete">删除</string>
+    <string name="str_confirm">确定</string>
+    <string name="str_cancel">取消</string>
+    <string name="str_save">保存</string>
+</resources>

+ 9 - 1
resource/src/main/res/values/strings.xml

@@ -1,5 +1,5 @@
 <resources>
-    <string name="javashop_app_name">NCS-门口机</string>
+    <string name="javashop_app_name">NCS-Door device</string>
     <string name="javashop_qrcode_name">扫啊扫</string>
     <string name="javashop_navigation_home_title">首页</string>
     <string name="javashop_navigation_category_title">分类</string>
@@ -47,4 +47,12 @@
     <string name="javashop_send_message">发送验证码</string>
     <string name="javashop_use">立即使用</string>
     <string name="javashop_get">立即领取</string>
+
+    <string name="input_password">Please enter password</string>
+    <string name="invalid_password">invalid password</string>
+
+    <string name="str_delete">Delete</string>
+    <string name="str_confirm">Confirm</string>
+    <string name="str_cancel">Cancel</string>
+    <string name="str_save">Save</string>
 </resources>