瀏覽代碼

增加网络诊断功能,使用时启动NetDetectActivity即可,可以携带url参数

weizhengliang 1 年之前
父節點
當前提交
8a48300411
共有 22 個文件被更改,包括 2318 次插入8 次删除
  1. 7 4
      common/build.gradle
  2. 二進制
      common/libs/armeabi-v7a/libtracepath.so
  3. 6 0
      common/src/main/AndroidManifest.xml
  4. 198 0
      common/src/main/code/com/wdkl/ncs/android/lib/netdetection/LDNetDiagnoService/LDNetAsyncTaskEx.java
  5. 17 0
      common/src/main/code/com/wdkl/ncs/android/lib/netdetection/LDNetDiagnoService/LDNetDiagnoListener.java
  6. 544 0
      common/src/main/code/com/wdkl/ncs/android/lib/netdetection/LDNetDiagnoService/LDNetDiagnoService.java
  7. 133 0
      common/src/main/code/com/wdkl/ncs/android/lib/netdetection/LDNetDiagnoService/LDNetPing.java
  8. 211 0
      common/src/main/code/com/wdkl/ncs/android/lib/netdetection/LDNetDiagnoService/LDNetSocket.java
  9. 312 0
      common/src/main/code/com/wdkl/ncs/android/lib/netdetection/LDNetDiagnoService/LDNetTraceRoute.java
  10. 43 0
      common/src/main/code/com/wdkl/ncs/android/lib/netdetection/task/BaseTask.java
  11. 9 0
      common/src/main/code/com/wdkl/ncs/android/lib/netdetection/task/TaskCallBack.java
  12. 107 0
      common/src/main/code/com/wdkl/ncs/android/lib/netdetection/task/TraceTask.java
  13. 108 0
      common/src/main/code/com/wdkl/ncs/android/lib/netdetection/ui/NetDetectActivity.java
  14. 58 0
      common/src/main/code/com/wdkl/ncs/android/lib/netdetection/util/ClipboardUtils.java
  15. 45 0
      common/src/main/code/com/wdkl/ncs/android/lib/netdetection/util/DeviceUtils.java
  16. 358 0
      common/src/main/code/com/wdkl/ncs/android/lib/netdetection/util/LDNetUtil.java
  17. 97 0
      common/src/main/code/com/wdkl/ncs/android/lib/netdetection/util/LDPingParse.java
  18. 54 0
      common/src/main/res/layout/activity_net_detect_main.xml
  19. 3 1
      resource/src/main/res/values-es/strings.xml
  20. 3 1
      resource/src/main/res/values-ru/strings.xml
  21. 3 2
      resource/src/main/res/values-zh/strings.xml
  22. 2 0
      resource/src/main/res/values/strings.xml

+ 7 - 4
common/build.gradle

@@ -16,10 +16,10 @@ android {
         dataBinding {
             enabled = true
         }
-//        ndk{
-//            moduleName "JavaShopCommonNDK"       //生成的so文件名字,调用C程序的代码中会用到该名字
-//            abiFilters "armeabi", "armeabi-v7a", "x86" //输出指定三种平台下的so库
-//        }
+        ndk{
+            //moduleName "JavaShopCommonNDK"       //生成的so文件名字,调用C程序的代码中会用到该名字
+            abiFilters "armeabi-v7a"
+        }
     }
     lintOptions {
         abortOnError false
@@ -36,6 +36,7 @@ android {
     }
     sourceSets {
         main.java.srcDirs += 'src/main/code'
+        main.jniLibs.srcDirs = ['libs']
 //        main.jni.srcDirs = []
 //        main.jniLibs.srcDir 'src/main/libs'
     }
@@ -264,6 +265,8 @@ dependencies {
     //linphone sip sdk
     api(name: 'linphone-sdk-android-5.2.10', ext: 'aar')
 //    compile files('libs/linphone-sdk-android-5.2.10.aar')
+
+    compile project(':resource')
 }
 
 //tasks.withType(JavaCompile) {

二進制
common/libs/armeabi-v7a/libtracepath.so


+ 6 - 0
common/src/main/AndroidManifest.xml

@@ -9,6 +9,12 @@
                 <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
             </intent-filter>
         </receiver>
+
+        <activity android:name="com.wdkl.ncs.android.lib.netdetection.ui.NetDetectActivity"
+            android:turnScreenOn="true"
+            android:screenOrientation="nosensor"
+            android:windowSoftInputMode="stateHidden">
+        </activity>
     </application>
 
     <uses-permission android:name="android.permission.VIBRATE"/>

+ 198 - 0
common/src/main/code/com/wdkl/ncs/android/lib/netdetection/LDNetDiagnoService/LDNetAsyncTaskEx.java

@@ -0,0 +1,198 @@
+package com.wdkl.ncs.android.lib.netdetection.LDNetDiagnoService;
+
+import android.os.Handler;
+import android.os.Message;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.FutureTask;
+import java.util.concurrent.ThreadPoolExecutor;
+
+public abstract class LDNetAsyncTaskEx<Params, Progress, Result> {
+    private static final int MESSAGE_POST_RESULT = 0x1;
+    private static final int MESSAGE_POST_PROGRESS = 0x2;
+    private static final int MESSAGE_POST_CANCEL = 0x3;
+
+    private volatile Status mStatus = Status.PENDING;
+
+    public enum Status {
+    	PENDING, RUNNING, FINISHED,
+    }
+
+    private static final LDNetInternalHandler sHandler = new LDNetInternalHandler();
+    private final LDNetWorkerRunnable<Params, Result> mWorker;
+    private final FutureTask<Result> mFuture;
+
+    // protected Hashtable<Params, LDNetAsyncTaskEx> mTaskCache = new
+    // Hashtable<Params, LDNetAsyncTaskEx>();
+
+    public LDNetAsyncTaskEx() {
+	mWorker = new LDNetWorkerRunnable<Params, Result>() {
+	    public Result call() throws Exception {
+		// Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+		return doInBackground(mParams);
+	    }
+	};
+
+	mFuture = new FutureTask<Result>(mWorker) {
+	    @SuppressWarnings("unchecked")
+	    @Override
+	    protected void done() {
+		Message message;
+		Result result = null;
+
+		try {
+		    result = get();
+		} catch (InterruptedException e) {
+		    android.util.Log.w(this.getClass().getSimpleName(), e);
+		} catch (ExecutionException e) {
+		    throw new RuntimeException(
+			    "An error occured while executing doInBackground()",
+			    e.getCause());
+		} catch (CancellationException e) {
+		    message = sHandler.obtainMessage(MESSAGE_POST_CANCEL,
+			    new LDNetAsyncTaskResult<Result>(LDNetAsyncTaskEx.this,
+				    (Result[]) null));
+		    message.sendToTarget();
+		    return;
+		} catch (Throwable t) {
+		    throw new RuntimeException(
+			    "An error occured while executing "
+				    + "doInBackground()", t);
+		}
+
+		message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
+			new LDNetAsyncTaskResult<Result>(LDNetAsyncTaskEx.this, result));
+		message.sendToTarget();
+	    }
+	};
+    }
+
+    private static class LDNetInternalHandler extends Handler {
+	@SuppressWarnings({ "rawtypes", "unchecked" })
+	@Override
+	public void handleMessage(Message msg) {
+	    LDNetAsyncTaskResult result = (LDNetAsyncTaskResult) msg.obj;
+	    switch (msg.what) {
+	    case MESSAGE_POST_RESULT:
+		// There is only one result
+		result.mTask.finish(result.mData[0]);
+		break;
+	    case MESSAGE_POST_PROGRESS:
+		result.mTask.onProgressUpdate(result.mData);
+		break;
+	    case MESSAGE_POST_CANCEL:
+		result.mTask.onCancelled();
+		break;
+	    }
+	}
+    }
+
+    public final Status getStatus() {
+	return mStatus;
+    }
+
+    protected abstract Result doInBackground(Params... params);
+    /**
+     *  后台线程准备运行阶段
+     */
+    protected void onPreExecute() {
+    }
+
+    /**
+     * 后台运行阶段,当前运行已经结束
+     * @param result
+     */
+    protected void onPostExecute(Result result) {
+    }
+
+    /**
+     * 进度更新阶段
+     * @param values
+     */
+    protected void onProgressUpdate(Progress... values) {
+    }
+
+    /**
+     * 取消运行
+     */
+    protected void onCancelled() {
+    }
+
+    public final boolean isCancelled() {
+    	return mFuture.isCancelled();
+    }
+
+    public final boolean cancel(boolean mayInterruptIfRunning) {
+    	return mFuture.cancel(mayInterruptIfRunning);
+    }
+
+    /**
+     * 初始化运行阶段
+     * @param params
+     * @return
+     */
+    @SuppressWarnings("incomplete-switch")
+    public final LDNetAsyncTaskEx<Params, Progress, Result> execute(Params... params) {
+	if (mStatus != Status.PENDING) {
+	    switch (mStatus) {
+	    case RUNNING:
+		throw new IllegalStateException("Cannot execute task:"
+			+ " the task is already running.");
+	    case FINISHED:
+		throw new IllegalStateException("Cannot execute task:"
+			+ " the task has already been executed "
+			+ "(a task can be executed only once)");
+	    }
+	}
+
+	mStatus = Status.RUNNING;
+
+	onPreExecute();
+
+	mWorker.mParams = params;
+	ThreadPoolExecutor sExecutor = getThreadPoolExecutor();
+	// ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,
+	// MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue,
+	// sThreadFactory);
+	if (sExecutor != null) {
+	    sExecutor.execute(mFuture);
+	    return this;
+	} else {
+	    return null;
+	}
+    }
+
+    protected abstract ThreadPoolExecutor getThreadPoolExecutor();
+
+    protected final void publishProgress(Progress... values) {
+	sHandler.obtainMessage(MESSAGE_POST_PROGRESS,
+		new LDNetAsyncTaskResult<Progress>(this, values)).sendToTarget();
+    }
+
+    protected void finish(Result result) {
+	if (isCancelled()) {
+	    result = null;
+	}
+	onPostExecute(result);
+	mStatus = Status.FINISHED;
+    }
+
+    private static abstract class LDNetWorkerRunnable<Params, Result> implements
+	    Callable<Result> {
+	Params[] mParams;
+    }
+
+    private static class LDNetAsyncTaskResult<Data> {
+	@SuppressWarnings("rawtypes")
+	final LDNetAsyncTaskEx mTask;
+	final Data[] mData;
+
+	LDNetAsyncTaskResult(@SuppressWarnings("rawtypes") LDNetAsyncTaskEx task,
+		Data... data) {
+	    mTask = task;
+	    mData = data;
+	}
+    }
+}

+ 17 - 0
common/src/main/code/com/wdkl/ncs/android/lib/netdetection/LDNetDiagnoService/LDNetDiagnoListener.java

@@ -0,0 +1,17 @@
+package com.wdkl.ncs.android.lib.netdetection.LDNetDiagnoService;
+
+public interface LDNetDiagnoListener {
+	
+	/**
+	 * 当结束之后返回日志
+	 * @param log
+	 */
+	public void OnNetDiagnoFinished(String log);
+
+	
+	/**
+	 * 跟踪过程中更新日志
+	 * @param log
+	 */
+	public void OnNetDiagnoUpdated(String log);
+}

+ 544 - 0
common/src/main/code/com/wdkl/ncs/android/lib/netdetection/LDNetDiagnoService/LDNetDiagnoService.java

@@ -0,0 +1,544 @@
+package com.wdkl.ncs.android.lib.netdetection.LDNetDiagnoService;
+
+import android.content.Context;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+
+import com.wdkl.ncs.android.lib.netdetection.util.LDNetUtil;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.InetAddress;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class LDNetDiagnoService extends
+        LDNetAsyncTaskEx<String, String, String> implements LDNetPing.LDNetPingListener,
+        LDNetTraceRoute.LDNetTraceRouteListener, LDNetSocket.LDNetSocketListener {
+
+    private String _appCode; // 客户端标记
+    private String _appName;
+    private String _appVersion;
+    private String _UID; // 用户ID
+    private String _deviceID; // 客户端机器ID,如果不传入会默认取API提供的机器ID
+    private String _dormain; // 接口域名
+    private String _carrierName;
+    private String _ISOCountryCode;
+    private String _MobileCountryCode;
+    private String _MobileNetCode;
+
+    private boolean _isNetConnected;// 当前是否联网
+    private boolean _isDomainParseOk;// 域名解析是否成功
+    private boolean _isSocketConnected;// conected是否成功
+    private Context _context;
+    private String _netType;
+    private String _localIp;
+    private String _gateWay;
+    private String _dns1;
+    private String _dns2;
+    private boolean _alwaysPing; //是否总是进行ping
+    private InetAddress[] _remoteInet;
+    private List<String> _remoteIpList;
+    private final StringBuilder _logInfo = new StringBuilder(256);
+    private LDNetSocket _netSocker;// 监控socket的连接时间
+    private LDNetPing _netPinger; // 监控ping命令的执行时间
+    private LDNetTraceRoute _traceRouter; // 监控ping模拟traceroute的执行过程
+    private boolean _isRunning;
+
+    private LDNetDiagnoListener _netDiagnolistener; // 将监控日志上报到前段页面
+    private boolean _isUseJNICConn = false;
+    private boolean _isUseJNICTrace = true;
+    private TelephonyManager _telManager = null; // 用于获取网络基本信息
+
+
+    /**
+     * 初始化网络诊断服务
+     *
+     * @param theAppCode
+     * @param theDeviceID
+     * @param theUID
+     * @param theDormain
+     */
+    public LDNetDiagnoService(Context context, String theAppCode,
+                              String theAppName, String theAppVersion, String theUID,
+                              String theDeviceID, String theDormain, String theCarrierName,
+                              String theISOCountryCode, String theMobileCountryCode,
+                              String theMobileNetCode, Boolean alwaysPing, LDNetDiagnoListener theListener) {
+        super();
+        this._context = context;
+        this._appCode = theAppCode;
+        this._appName = theAppName;
+        this._appVersion = theAppVersion;
+        this._UID = theUID;
+        this._deviceID = theDeviceID;
+        this._dormain = theDormain;
+        this._alwaysPing = alwaysPing;
+        this._carrierName = theCarrierName;
+        this._ISOCountryCode = theISOCountryCode;
+        this._MobileCountryCode = theMobileCountryCode;
+        this._MobileNetCode = theMobileNetCode;
+        this._netDiagnolistener = theListener;
+        //
+        this._isRunning = false;
+        _remoteIpList = new ArrayList<String>();
+        _telManager = (TelephonyManager) context
+                .getSystemService(Context.TELEPHONY_SERVICE);
+        sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE,
+                KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);
+
+    }
+
+    @Override
+    protected String doInBackground(String... params) {
+        if (this.isCancelled())
+            return null;
+        // TODO Auto-generated method stub
+        return this.startNetDiagnosis();
+    }
+
+    @Override
+    protected void onPostExecute(String result) {
+        if (this.isCancelled())
+            return;
+        super.onPostExecute(result);
+        // 线程执行结束
+        recordStepInfo("\nCheck end\n");
+        this.stopNetDialogsis();
+        if (_netDiagnolistener != null) {
+            _netDiagnolistener.OnNetDiagnoFinished(_logInfo.toString());
+        }
+    }
+
+    @Override
+    protected void onProgressUpdate(String... values) {
+        if (this.isCancelled())
+            return;
+        // TODO Auto-generated method stub
+        super.onProgressUpdate(values);
+        if (_netDiagnolistener != null) {
+            _netDiagnolistener.OnNetDiagnoUpdated(values[0]);
+        }
+    }
+
+    @Override
+    protected void onCancelled() {
+        this.stopNetDialogsis();
+    }
+
+    /**
+     * 开始诊断网络
+     */
+    public String startNetDiagnosis() {
+        if (TextUtils.isEmpty(this._dormain))
+            return "";
+        this._isRunning = true;
+        this._logInfo.setLength(0);
+        recordStepInfo("Start check...");
+        recordCurrentAppVersion();
+        recordLocalNetEnvironmentInfo();
+
+        if (_isNetConnected) {
+            // 获取运营商信息
+            //recordStepInfo("\n开始获取运营商信息...");
+            //String operatorInfo = requestOperatorInfo();
+            //if (operatorInfo != null) {
+            //recordStepInfo(operatorInfo);
+            //}
+
+            // TCP三次握手时间测试
+            recordStepInfo("\nStart TCP check...");
+            _netSocker = LDNetSocket.getInstance();
+            _netSocker._remoteInet = _remoteInet;
+            _netSocker._remoteIpList = _remoteIpList;
+            _netSocker.initListener(this);
+            _netSocker.isCConn = this._isUseJNICConn;// 设置是否启用C进行connected
+            _isSocketConnected = _netSocker.exec(_dormain);
+
+            // 诊断ping信息, 同步过程
+            if (_alwaysPing || !(_isNetConnected && _isDomainParseOk && _isSocketConnected)) {// 联网&&DNS解析成功&&connect测试成功
+                recordStepInfo("\nstart ping...");
+                _netPinger = new LDNetPing(this, 4);
+                recordStepInfo("ping...127.0.0.1");
+                _netPinger.exec("127.0.0.1", false);
+                recordStepInfo("ping IP..." + _localIp);
+                _netPinger.exec(_localIp, false);
+                if (LDNetUtil.NETWORKTYPE_WIFI.equals(_netType)) {// 在wifi下ping网关
+                    recordStepInfo("ping gateWay..." + _gateWay);
+                    _netPinger.exec(_gateWay, false);
+                }
+                recordStepInfo("ping DNS1..." + _dns1);
+                _netPinger.exec(_dns1, false);
+                recordStepInfo("ping DNS2..." + _dns2);
+                _netPinger.exec(_dns2, false);
+            } else {
+                recordStepInfo("\nping unnecessary");
+            }
+
+            if (_netPinger == null) {
+                _netPinger = new LDNetPing(this, 4);
+            }
+            if (_netPinger != null) {
+                //recordStepInfo("ping..." + LDNetUtil.OPEN_IP);
+                //_netPinger.exec(LDNetUtil.OPEN_IP, true);
+            }
+
+            // 开始诊断traceRoute
+            recordStepInfo("\nstart traceroute...");
+            _traceRouter = LDNetTraceRoute.getInstance();
+            _traceRouter.initListenter(this);
+            _traceRouter.isCTrace = this._isUseJNICTrace;
+            _traceRouter.startTraceRoute(_dormain);
+            return _logInfo.toString();
+        } else {
+            recordStepInfo("\n\nnone network!");
+            return _logInfo.toString();
+        }
+    }
+
+    /**
+     * 停止诊断网络
+     */
+    public void stopNetDialogsis() {
+        if (_isRunning) {
+            if (_netSocker != null) {
+                _netSocker.resetInstance();
+                _netSocker = null;
+            }
+
+            if (_netPinger != null) {
+                _netPinger = null;
+            }
+            if (_traceRouter != null) {
+                _traceRouter.resetInstance();
+                _traceRouter = null;
+            }
+            cancel(true);// 尝试去取消线程的执行
+            if (sExecutor != null && !sExecutor.isShutdown()) {
+                sExecutor.shutdown();
+                sExecutor = null;
+            }
+
+            _isRunning = false;
+        }
+    }
+
+    /**
+     * 设置是否需要JNICTraceRoute
+     *
+     * @param use
+     */
+    public void setIfUseJNICConn(boolean use) {
+        this._isUseJNICConn = use;
+    }
+
+    /**
+     * 设置是否需要JNICTraceRoute
+     *
+     * @param use
+     */
+    public void setIfUseJNICTrace(boolean use) {
+        this._isUseJNICTrace = use;
+    }
+
+    /**
+     * 打印整体loginInfo;
+     */
+    public void printLogInfo() {
+        System.out.print(_logInfo);
+    }
+
+    /**
+     * 如果调用者实现了stepInfo接口,输出信息
+     *
+     * @param stepInfo
+     */
+    private void recordStepInfo(String stepInfo) {
+        _logInfo.append(stepInfo + "\n");
+        publishProgress(stepInfo + "\n");
+    }
+
+    /**
+     * traceroute 消息跟踪
+     */
+    @Override
+    public void OnNetTraceFinished() {
+    }
+
+    @Override
+    public void OnNetTraceUpdated(String log) {
+        if (log == null) {
+            return;
+        }
+        if (this._traceRouter != null && this._traceRouter.isCTrace) {
+            if (log.contains("ms") || log.contains("***") || log.contains("timeout")) {
+                log += "\n";
+            }
+            _logInfo.append(log);
+            publishProgress(log);
+        } else {
+            this.recordStepInfo(log);
+        }
+    }
+
+    /**
+     * socket完成跟踪
+     */
+    @Override
+    public void OnNetSocketFinished(String log) {
+        _logInfo.append(log);
+        publishProgress(log);
+    }
+
+    /**
+     * socket更新跟踪
+     */
+    @Override
+    public void OnNetSocketUpdated(String log) {
+        _logInfo.append(log);
+        publishProgress(log);
+    }
+
+    /**
+     * 输出关于应用、机器、网络诊断的基本信息
+     */
+    private void recordCurrentAppVersion() {
+        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        recordStepInfo("time:" + simpleDateFormat.format(new Date()));
+        // 输出应用版本信息和用户ID
+        /*if (!TextUtils.isEmpty(_appCode)) {
+            recordStepInfo("应用code:\t" + _appCode);
+        }
+        if (!TextUtils.isEmpty(_appName)) {
+            recordStepInfo("应用名称:\t" + this._appName);
+        }*/
+        if (!TextUtils.isEmpty(_appVersion)) {
+            recordStepInfo("App ver:\t" + this._appVersion);
+        }
+        /*recordStepInfo("用户id:\t" + _UID);*/
+
+        // 输出机器信息
+        recordStepInfo("model:\t" + android.os.Build.MODEL);
+        //recordStepInfo("系统版本:\t" + android.os.Build.VERSION.RELEASE);
+        /*if (_telManager != null && TextUtils.isEmpty(_deviceID)) {
+            _deviceID = _telManager.getDeviceId();
+        }
+        recordStepInfo("机器ID:\t" + _deviceID);*/
+        if (!TextUtils.isEmpty(_deviceID)) {
+            recordStepInfo("ID:\t" + _deviceID);
+        }
+
+        // 运营商信息
+        /*if (TextUtils.isEmpty(_carrierName)) {
+            _carrierName = LDNetUtil.getMobileOperator(_context);
+        }
+        recordStepInfo("运营商:\t" + _carrierName);
+
+        if (_telManager != null && TextUtils.isEmpty(_ISOCountryCode)) {
+            _ISOCountryCode = _telManager.getNetworkCountryIso();
+        }
+        recordStepInfo("ISOCountryCode:\t" + _ISOCountryCode);
+
+        if (_telManager != null && TextUtils.isEmpty(_MobileCountryCode)) {
+            String tmp = _telManager.getNetworkOperator();
+            if (!TextUtils.isEmpty(tmp)) {
+                if (tmp.length() >= 3) {
+                    _MobileCountryCode = tmp.substring(0, 3);
+                }
+                if (tmp.length() >= 5) {
+                    _MobileNetCode = tmp.substring(3, 5);
+                }
+            }
+        }
+        recordStepInfo("MobileCountryCode:\t" + _MobileCountryCode);
+        recordStepInfo("MobileNetworkCode:\t" + _MobileNetCode);*/
+    }
+
+    /**
+     * 输出本地网络环境信息
+     */
+    private void recordLocalNetEnvironmentInfo() {
+        recordStepInfo("\nCheck domain: " + _dormain + "...");
+
+        // 网络状态
+        if (LDNetUtil.isNetworkConnected(_context)) {
+            _isNetConnected = true;
+            recordStepInfo("Net connect:\t" + "true");
+        } else {
+            _isNetConnected = false;
+            recordStepInfo("Net connect:\t" + "false");
+        }
+
+        // 获取当前网络类型
+        _netType = LDNetUtil.getNetWorkType(_context);
+        recordStepInfo("Net type:\t" + _netType);
+        if (_isNetConnected) {
+            if (LDNetUtil.NETWORKTYPE_WIFI.equals(_netType)) { // wifi:获取本地ip和网关,其他类型:只获取ip
+                _localIp = LDNetUtil.getLocalIpByWifi(_context);
+                _gateWay = LDNetUtil.pingGateWayInWifi(_context);
+            } else {
+                _localIp = LDNetUtil.getLocalIpBy3G();
+            }
+            recordStepInfo("IP:\t" + _localIp);
+        } else {
+            recordStepInfo("IP:\t" + "127.0.0.1");
+        }
+        if (_gateWay != null) {
+            recordStepInfo("gateWay:\t" + this._gateWay);
+        }
+
+        // 获取本地DNS地址
+        if (_isNetConnected) {
+            String[] dnsArr = LDNetUtil.getLocalDns(_context);
+            if (dnsArr != null && dnsArr.length > 0) {
+                _dns1 = dnsArr[0];
+                if (dnsArr.length > 1) {
+                    _dns2 = dnsArr[1];
+                }
+            }
+            recordStepInfo("DNS:\t" + this._dns1 + "," + this._dns2);
+        } else {
+            recordStepInfo("DNS:\t" + "0.0.0.0" + "," + "0.0.0.0");
+        }
+
+        // 获取远端域名的DNS解析地址
+        if (_isNetConnected) {
+            recordStepInfo("remote domain:\t" + this._dormain);
+            _isDomainParseOk = parseDomain(this._dormain);// 域名解析
+        }
+    }
+
+    /**
+     * 域名解析
+     */
+    private boolean parseDomain(String _dormain) {
+        boolean flag = false;
+        int len = 0;
+        String ipString = "";
+        Map<String, Object> map = LDNetUtil.getDomainIp(_dormain);
+        String useTime = (String) map.get("useTime");
+        _remoteInet = (InetAddress[]) map.get("remoteInet");
+        String timeShow = null;
+        if (Integer.parseInt(useTime) > 5000) {// 如果大于1000ms,则换用s来显示
+            timeShow = " (" + Integer.parseInt(useTime) / 1000 + "s)";
+        } else {
+            timeShow = " (" + useTime + "ms)";
+        }
+        if (_remoteInet != null) {// 解析正确
+            len = _remoteInet.length;
+            for (int i = 0; i < len; i++) {
+                _remoteIpList.add(_remoteInet[i].getHostAddress());
+                ipString += _remoteInet[i].getHostAddress() + ",";
+            }
+            ipString = ipString.substring(0, ipString.length() - 1);
+            recordStepInfo("DNS parse:\t" + ipString + timeShow);
+            flag = true;
+        } else {// 解析不到,判断第一次解析耗时,如果大于10s进行第二次解析
+            if (Integer.parseInt(useTime) > 10000) {
+                map = LDNetUtil.getDomainIp(_dormain);
+                useTime = (String) map.get("useTime");
+                _remoteInet = (InetAddress[]) map.get("remoteInet");
+                if (Integer.parseInt(useTime) > 5000) {// 如果大于1000ms,则换用s来显示
+                    timeShow = " (" + Integer.parseInt(useTime) / 1000 + "s)";
+                } else {
+                    timeShow = " (" + useTime + "ms)";
+                }
+                if (_remoteInet != null) {
+                    len = _remoteInet.length;
+                    for (int i = 0; i < len; i++) {
+                        _remoteIpList.add(_remoteInet[i].getHostAddress());
+                        ipString += _remoteInet[i].getHostAddress() + ",";
+                    }
+                    ipString = ipString.substring(0, ipString.length() - 1);
+                    recordStepInfo("DNS parse:\t" + ipString + timeShow);
+                    flag = true;
+                } else {
+                    recordStepInfo("DNS parse:\t" + "fail" + timeShow);
+                }
+            } else {
+                recordStepInfo("DNS parse:\t" + "fail" + timeShow);
+            }
+        }
+        return flag;
+    }
+
+    /**
+     * 获取运营商信息
+     */
+    private String requestOperatorInfo() {
+        String res = null;
+        String url = LDNetUtil.OPERATOR_URL;
+        HttpURLConnection conn = null;
+        URL Operator_url;
+        try {
+            Operator_url = new URL(url);
+            conn = (HttpURLConnection) Operator_url.openConnection();
+            conn.setRequestMethod("GET");
+            conn.setConnectTimeout(1000 * 10);
+            conn.connect();
+            int responseCode = conn.getResponseCode();
+            if (responseCode == 200) {
+                res = LDNetUtil.getStringFromStream(conn.getInputStream());
+                if (conn != null) {
+                    conn.disconnect();
+                }
+            }
+            return res;
+        } catch (MalformedURLException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        } catch (IOException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        } finally {
+            if (conn != null) {
+                conn.disconnect();
+            }
+        }
+        return res;
+    }
+
+    /**
+     * ping 消息跟踪
+     */
+    @Override
+    public void OnNetPingFinished(String log) {
+        this.recordStepInfo(log);
+    }
+
+    private static final int CORE_POOL_SIZE = 1;// 4
+    private static final int MAXIMUM_POOL_SIZE = 1;// 10
+    private static final int KEEP_ALIVE = 10;// 10
+
+    private static final BlockingQueue<Runnable> sWorkQueue = new LinkedBlockingQueue<Runnable>(
+            2);// 2
+    private static final ThreadFactory sThreadFactory = new ThreadFactory() {
+        private final AtomicInteger mCount = new AtomicInteger(1);
+
+        @Override
+        public Thread newThread(Runnable r) {
+            Thread t = new Thread(r, "Trace #" + mCount.getAndIncrement());
+            t.setPriority(Thread.MIN_PRIORITY);
+            return t;
+        }
+    };
+
+    private static ThreadPoolExecutor sExecutor = null;
+
+    @Override
+    protected ThreadPoolExecutor getThreadPoolExecutor() {
+        // TODO Auto-generated method stub
+        return sExecutor;
+    }
+
+}

+ 133 - 0
common/src/main/code/com/wdkl/ncs/android/lib/netdetection/LDNetDiagnoService/LDNetPing.java

@@ -0,0 +1,133 @@
+package com.wdkl.ncs.android.lib.netdetection.LDNetDiagnoService;
+
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.wdkl.ncs.android.lib.netdetection.util.LDPingParse;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * 直接通过ping命令监测网络
+ */
+public class LDNetPing {
+  LDNetPingListener listener; // 回传ping的结果
+  private final int _sendCount; // 每次ping发送数据包的个数
+
+  public LDNetPing(LDNetPingListener listener, int theSendCount) {
+    super();
+    this.listener = listener;
+    this._sendCount = theSendCount;
+  }
+
+  /**
+   * 监控NetPing的日志输出到Service
+   *
+   * @author panghui
+   *
+   */
+  public interface LDNetPingListener {
+    public void OnNetPingFinished(String log);
+  }
+
+  private static final String MATCH_PING_IP = "(?<=from ).*(?=: icmp_seq=1 ttl=)";
+
+  /**
+   * 执行ping命令,返回ping命令的全部控制台输出
+   *
+   * @param ping
+   * @return
+   */
+  private String execPing(PingTask ping, boolean isNeedL) {
+    String cmd = "ping -c ";
+    if (isNeedL) {
+      cmd = "ping -s 8185 -c  ";
+    }
+    Process process = null;
+    String str = "";
+    BufferedReader reader = null;
+    try {
+      process = Runtime.getRuntime().exec(
+          cmd + this._sendCount + " " + ping.getHost());
+      reader = new BufferedReader(new InputStreamReader(
+          process.getInputStream()));
+      String line = null;
+      while ((line = reader.readLine()) != null) {
+        str += line;
+      }
+      reader.close();
+      process.waitFor();
+
+    } catch (IOException e) {
+      e.printStackTrace();
+    } catch (InterruptedException e) {
+      e.printStackTrace();
+    } finally {
+      try {
+        if (reader != null) {
+          reader.close();
+        }
+        process.destroy();
+      } catch (Exception e) {
+      }
+    }
+    return str;
+  }
+
+  /**
+   * 执行指定host的traceroute
+   *
+   * @param host
+   * @return
+   */
+  public void exec(String host, boolean isNeedL) {
+    PingTask pingTask = new PingTask(host);
+    StringBuilder log = new StringBuilder(256);
+    String status = execPing(pingTask, isNeedL);
+    if (Pattern.compile(MATCH_PING_IP).matcher(status).find()) {
+      Log.i("LDNetPing", "status" + status);
+      log.append("\t" + status);
+    } else {
+      if (status.length() == 0) {
+        log.append("unknown host or network error");
+      } else {
+
+        log.append("timeout");
+      }
+    }
+    String logStr = LDPingParse.getFormattingStr(host, log.toString());
+    this.listener.OnNetPingFinished(logStr);
+  }
+
+  /**
+   * Ping任务
+   *
+   * @author panghui
+   *
+   */
+  private class PingTask {
+
+    private String host;
+    private static final String MATCH_PING_HOST_IP = "(?<=\\().*?(?=\\))";
+
+    public String getHost() {
+      return host;
+    }
+
+    public PingTask(String host) {
+      super();
+      if (TextUtils.isEmpty(host)) return;
+      this.host = host;
+      Pattern p = Pattern.compile(MATCH_PING_HOST_IP);
+      Matcher m = p.matcher(host);
+      if (m.find()) {
+        this.host = m.group();
+      }
+
+    }
+  }
+}

+ 211 - 0
common/src/main/code/com/wdkl/ncs/android/lib/netdetection/LDNetDiagnoService/LDNetSocket.java

@@ -0,0 +1,211 @@
+package com.wdkl.ncs.android.lib.netdetection.LDNetDiagnoService;
+
+import android.util.Log;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketTimeoutException;
+import java.util.List;
+
+public class LDNetSocket {
+  private static final int PORT = 8006;
+  private static final int CONN_TIMES = 4;
+  private static final String TIMEOUT = "DNS解析正常,连接超时,TCP建立失败";
+  private static final String IOERR = "DNS解析正常,IO异常,TCP建立失败";
+  private static final String HOSTERR = "DNS解析失败,主机地址不可达";
+  private static LDNetSocket instance=null;
+  private LDNetSocketListener listener;
+  private int timeOut = 6000;// 设置每次连接的timeout时间
+  public InetAddress[] _remoteInet;
+  public List<String> _remoteIpList;
+  private boolean[] isConnnected;
+  private final long[] RttTimes = new long[CONN_TIMES];// 用于存储三次测试中每次的RTT值
+
+  public boolean isCConn = true;
+  
+  private LDNetSocket() {
+  
+  }
+  public static LDNetSocket getInstance(){
+	  if(instance==null){
+		  instance=new LDNetSocket();
+	  }
+	  return instance;
+  }
+  
+  public void initListener(LDNetSocketListener listener){
+	  this.listener=listener;
+  }
+
+  /**
+   * 通过connect函数测试TCP的RTT时延
+   */
+  public boolean exec(String host) {
+    if (isCConn && loaded) {
+    	try{
+    		startJNITelnet(host, "8006"); //默认80端口
+    		return true;
+    	}catch(UnsatisfiedLinkError e){
+    		e.printStackTrace();
+    		Log.i("LDNetSocket", "call jni failed, call execUseJava");
+    		return execUseJava(host);
+    	}	
+    } else {
+      return execUseJava(host);
+    }
+  }
+
+  /**
+   * 使用java执行connected
+   */
+  private boolean execUseJava(String host) {
+    if (_remoteInet != null && _remoteIpList != null) {
+      int len = _remoteInet.length;
+      isConnnected = new boolean[len];
+      for (int i = 0; i < len; i++) {
+        if (i != 0) {
+          this.listener.OnNetSocketUpdated("\n");
+        }
+        isConnnected[i] = execIP(_remoteInet[i], _remoteIpList.get(i));
+      }
+      for (Boolean i : isConnnected) {
+        if (i == true) {// 一个连接成功即认为成功
+          this.listener.OnNetSocketFinished("\n");
+          return true;
+        }
+      }
+
+    } else {
+      this.listener.OnNetSocketFinished(HOSTERR);
+    }
+    this.listener.OnNetSocketFinished("\n");
+    return false;
+  }
+
+  /**
+   * 返回某个IP进行5次connect的最终结果
+   */
+  private boolean execIP(InetAddress inetAddress, String ip) {
+    boolean isConnected = true;
+    StringBuilder log = new StringBuilder();
+    InetSocketAddress socketAddress = null;
+    if (inetAddress != null && ip != null) {
+      socketAddress = new InetSocketAddress(inetAddress, PORT);
+      int flag = 0;
+      this.listener.OnNetSocketUpdated("Connect to host: " + ip + "..." + "\n");
+      for (int i = 0; i < CONN_TIMES; i++) {
+        execSocket(socketAddress, timeOut, i);
+        if (RttTimes[i] == -1) {// 一旦发生timeOut,则尝试加长连接时间
+          this.listener.OnNetSocketUpdated((i + 1) + "'s time=" + "TimeOut"
+              + ",  ");
+          timeOut += 4000;
+          if (i > 0 && RttTimes[i - 1] == -1) {// 连续两次连接超时,停止后续测试
+            flag = -1;
+            break;
+          }
+        } else if (RttTimes[i] == -2) {
+          this.listener
+              .OnNetSocketUpdated((i + 1) + "'s time=" + "IOException");
+          if (i > 0 && RttTimes[i - 1] == -2) {// 连续两次出现IO异常,停止后续测试
+            flag = -2;
+            break;
+          }
+        } else {
+          this.listener.OnNetSocketUpdated((i + 1) + "'s time=" + RttTimes[i]
+              + "ms,  ");
+        }
+      }
+      long time = 0;
+      int count = 0;
+      if (flag == -1) {
+        // log.append(TIMEOUT);
+        isConnected = false;
+      } else if (flag == -2) {
+        // log.append(IOERR);
+        isConnected = false;
+      } else {
+        for (int i = 0; i < CONN_TIMES; i++) {
+          if (RttTimes[i] > 0) {
+            time += RttTimes[i];
+            count++;
+          }
+        }
+        if (count > 0) {
+          time = time / count;
+          log.append("average=" + time + "ms");
+        }
+      }
+    } else {
+      isConnected = false;
+    }
+    this.listener.OnNetSocketUpdated(log.toString());
+    return isConnected;
+  }
+
+  /**
+   * 针对某个IP第index次connect
+   */
+  private void execSocket(InetSocketAddress socketAddress, int timeOut,
+      int index) {
+    Socket socket = null;
+    long start = 0;
+    long end = 0;
+    try {
+      socket = new Socket();
+      start = System.currentTimeMillis();
+      socket.connect(socketAddress, timeOut);
+      end = System.currentTimeMillis();
+      RttTimes[index] = end - start;
+    } catch (SocketTimeoutException e) {
+      RttTimes[index] = -1;// 作为TIMEOUT标识
+      e.printStackTrace();
+    } catch (IOException e) {
+      RttTimes[index] = -2;// 作为IO异常标识
+      e.printStackTrace();
+    } finally {
+      if (socket != null) {
+        try {
+          socket.close();
+        } catch (IOException e) {
+          e.printStackTrace();
+        }
+      }
+    }
+  }
+
+  public void resetInstance() {
+    if (instance != null) {
+      instance = null;
+    }
+  }
+
+  /*
+   * 调用jni中native方法
+   */
+  public native void startJNITelnet(String host, String port);
+
+  static boolean loaded;
+  static {
+    try {
+      System.loadLibrary("tracepath");
+      loaded = true;
+    } catch (UnsatisfiedLinkError e) {
+      e.printStackTrace();
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+  }
+  
+  public void printSocketInfo(String log){
+	  listener.OnNetSocketUpdated(log);
+  }
+  
+  public interface LDNetSocketListener {
+    public void OnNetSocketFinished(String log);
+
+    public void OnNetSocketUpdated(String log);
+  }
+
+}

+ 312 - 0
common/src/main/code/com/wdkl/ncs/android/lib/netdetection/LDNetDiagnoService/LDNetTraceRoute.java

@@ -0,0 +1,312 @@
+package com.wdkl.ncs.android.lib.netdetection.LDNetDiagnoService;
+
+import android.util.Log;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class LDNetTraceRoute {
+  private final String LOG_TAG = "LDNetTraceRoute";
+  private static LDNetTraceRoute instance;
+
+  private LDNetTraceRoute() {
+  }
+
+  public static LDNetTraceRoute getInstance() {
+    if (instance == null) {
+      instance = new LDNetTraceRoute();
+    }
+    return instance;
+  }
+
+  LDNetTraceRouteListener listener;
+  public boolean isCTrace = true;
+
+  public void initListenter(LDNetTraceRouteListener listener) {
+    this.listener = listener;
+  }
+
+  /**
+   * 监控NetPing的日志输出到Service
+   * 
+   * @author panghui
+   * 
+   */
+  public interface LDNetTraceRouteListener {
+    public void OnNetTraceUpdated(String log);
+
+    public void OnNetTraceFinished();
+  }
+
+  /**
+   * 执行指定host的traceroute
+   * 
+   * @param host
+   * @return
+   */
+  public void startTraceRoute(String host) {
+    if (isCTrace && loaded) {
+      try {
+        startJNICTraceRoute(host);
+        Log.i("LDNetTraceRoute", "调用JNI traceRoute成功");
+      } catch (UnsatisfiedLinkError e) {
+        e.printStackTrace();
+        // 如果c调用失败改调JAVA代码
+        Log.i("LDNetTraceRoute", "调用java模拟traceRoute");
+        TraceTask trace = new TraceTask(host, 1);
+        execTrace(trace);
+      }
+    } else {
+      TraceTask trace = new TraceTask(host, 1);
+      execTrace(trace);
+    }
+  }
+
+  public void resetInstance() {
+    if (instance != null) {
+      instance = null;
+    }
+  }
+
+  /**
+   * 调用jni c函数执行traceroute过程
+   */
+  public native void startJNICTraceRoute(String traceCommand);
+
+  static boolean loaded;
+  static {
+    try {
+      System.loadLibrary("tracepath");
+      loaded = true;
+    } catch (UnsatisfiedLinkError e) {
+      e.printStackTrace();
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+  }
+
+  /**
+   * 供jni c函数回调
+   * 
+   * @param log
+   */
+  public void printTraceInfo(String log) {
+    // Log.i(LOG_TAG, log);
+    listener.OnNetTraceUpdated(log.toString());
+  }
+
+  private static final String MATCH_TRACE_IP = "(?<=From )(?:[0-9]{1,3}\\.){3}[0-9]{1,3}";
+  private static final String MATCH_PING_IP = "(?<=from ).*(?=: icmp_seq=1 ttl=)";
+  private static final String MATCH_PING_TIME = "(?<=time=).*?ms";
+
+  /**
+   * 执行ping命令,返回ping命令的全部控制台输出
+   * 
+   * @param ping
+   * @return
+   */
+  private String execPing(PingTask ping) {
+    Process process = null;
+    String str = "";
+    BufferedReader reader = null;
+    try {
+      process = Runtime.getRuntime().exec("ping -c 1 " + ping.getHost());
+      reader = new BufferedReader(new InputStreamReader(
+          process.getInputStream()));
+      String line = null;
+      while ((line = reader.readLine()) != null) {
+        str += line;
+      }
+      reader.close();
+      process.waitFor();
+
+    } catch (IOException e) {
+      e.printStackTrace();
+    } catch (InterruptedException e) {
+      e.printStackTrace();
+    } finally {
+      try {
+        if (reader != null) {
+          reader.close();
+        }
+        process.destroy();
+      } catch (Exception e) {
+      }
+    }
+    return str;
+  }
+
+  /**
+   * 通过ping命令模拟执行traceroute的过程
+   * 
+   * @param trace
+   * @return
+   */
+  private void execTrace(TraceTask trace) {
+    Pattern patternTrace = Pattern.compile(MATCH_TRACE_IP);
+    Pattern patternIp = Pattern.compile(MATCH_PING_IP);
+    Pattern patternTime = Pattern.compile(MATCH_PING_TIME);
+
+    Process process = null;
+    BufferedReader reader = null;
+    boolean finish = false;
+    try {
+      // 通过ping的跳数控制,取得相应跳输的ip地址,然后再次执行ping命令读取时间
+      while (!finish && trace.getHop() < 30) {
+        // 先发出ping命令获得某个跳数的ip地址
+        String str = "";
+        // -c 1 同时发送消息次数 -t是指跳数
+        String command = "ping -c 1 -t " + trace.getHop() + " "
+            + trace.getHost();
+
+        Log.e(LOG_TAG, "execTrace: " + command);
+        process = Runtime.getRuntime().exec(command);
+        reader = new BufferedReader(new InputStreamReader(
+            process.getInputStream()));
+        String line = null;
+        while ((line = reader.readLine()) != null) {
+          str += line;
+        }
+        reader.close();
+        process.waitFor();
+
+        Matcher m = patternTrace.matcher(str);
+
+        // 如果成功获得trace:IP,则再次发送ping命令获取ping的时间
+        StringBuilder log = new StringBuilder(256);
+        if (m.find()) {
+          String pingIp = m.group();
+          PingTask pingTask = new PingTask(pingIp);
+
+          String status = execPing(pingTask);
+          if (status.length() == 0) {
+            log.append("unknown host or network error\n");
+            finish = true;
+          } else {
+            Matcher matcherTime = patternTime.matcher(status);
+            if (matcherTime.find()) {
+              String time = matcherTime.group();
+              log.append(trace.getHop());
+              log.append("\t\t");
+              log.append(pingIp);
+              log.append("\t\t");
+              log.append(time);
+              log.append("\t");
+            } else {
+              log.append(trace.getHop());
+              log.append("\t\t");
+              log.append(pingIp);
+              log.append("\t\t timeout \t"); //********
+            }
+            listener.OnNetTraceUpdated(log.toString());
+            trace.setHop(trace.getHop() + 1);
+          }
+
+        }
+
+        // 否则:what
+        else {
+          Matcher matchPingIp = patternIp.matcher(str);
+          if (matchPingIp.find()) {
+            String pingIp = matchPingIp.group();
+            Matcher matcherTime = patternTime.matcher(str);
+            if (matcherTime.find()) {
+              String time = matcherTime.group();
+              log.append(trace.getHop());
+              log.append("\t\t");
+              log.append(pingIp);
+              log.append("\t\t");
+              log.append(time);
+              log.append("\t");
+              listener.OnNetTraceUpdated(log.toString());
+            }
+            finish = true;
+          } else {
+            if (str.length() == 0) {
+              log.append("unknown host or network error\t");
+              finish = true;
+            } else {
+              log.append(trace.getHop());
+              log.append("\t\t timeout \t"); //********
+              trace.setHop(trace.getHop() + 1);
+            }
+            listener.OnNetTraceUpdated(log.toString());
+          }
+        }// else no match traceIPPattern
+      }// while
+    } catch (IOException e) {
+      e.printStackTrace();
+    } catch (InterruptedException e) {
+      e.printStackTrace();
+    } finally {
+      try {
+        if (reader != null) {
+          reader.close();
+        }
+        process.destroy();
+      } catch (Exception e) {
+      }
+    }
+
+    listener.OnNetTraceFinished();
+  }
+
+  /**
+   * Ping任务
+   * 
+   * @author panghui
+   * 
+   */
+  private class PingTask {
+
+    private String host;
+    private static final String MATCH_PING_HOST_IP = "(?<=\\().*?(?=\\))";
+
+    public String getHost() {
+      return host;
+    }
+
+    public PingTask(String host) {
+      super();
+      this.host = host;
+      Pattern p = Pattern.compile(MATCH_PING_HOST_IP);
+      Matcher m = p.matcher(host);
+      if (m.find()) {
+        this.host = m.group();
+      }
+
+    }
+  }
+
+  /**
+   * 生成trace任务
+   * 
+   * @author panghui
+   * 
+   */
+  private class TraceTask {
+    private final String host;
+    private int hop;
+
+    public TraceTask(String host, int hop) {
+      super();
+      this.host = host;
+      this.hop = hop;
+    }
+
+    public String getHost() {
+      return host;
+    }
+
+    public int getHop() {
+      return hop;
+    }
+
+    public void setHop(int hop) {
+      this.hop = hop;
+    }
+  }
+}

+ 43 - 0
common/src/main/code/com/wdkl/ncs/android/lib/netdetection/task/BaseTask.java

@@ -0,0 +1,43 @@
+package com.wdkl.ncs.android.lib.netdetection.task;
+
+public abstract class BaseTask {
+    String url;
+    String tag;
+    TaskCallBack callBack;
+
+    public BaseTask(String url, TaskCallBack callBack) {
+        this.url = url;
+        this.callBack = callBack;
+    }
+
+    public void doTask() {
+        tag = System.currentTimeMillis() + "";
+        // TraceTask运行于主线程
+        if (this instanceof TraceTask) {
+            getExecRunnable().run();
+        } else {
+            new Thread(getExecRunnable()).start();
+        }
+    }
+
+//    public class updateResultRunnable implements Runnable {
+//        String resultString;
+//
+//        public updateResultRunnable(String resultString) {
+//            this.resultString = resultString;
+//        }
+//
+//        @Override
+//        public void run() {
+//            /*if (resultTextView != null && resultTextView.getTag().equals(tag)) {
+//                resultTextView.append(resultString);
+//                resultTextView.requestFocus();
+//            }*/
+//            if (callBack != null) {
+//                callBack.onUpdated(resultString);
+//            }
+//        }
+//    }
+
+    public abstract Runnable getExecRunnable();
+}

+ 9 - 0
common/src/main/code/com/wdkl/ncs/android/lib/netdetection/task/TaskCallBack.java

@@ -0,0 +1,9 @@
+package com.wdkl.ncs.android.lib.netdetection.task;
+
+public interface TaskCallBack {
+    void onUpdated(String log);
+
+    void onFinish(String log);
+
+    void onFailed(Exception e);
+}

+ 107 - 0
common/src/main/code/com/wdkl/ncs/android/lib/netdetection/task/TraceTask.java

@@ -0,0 +1,107 @@
+package com.wdkl.ncs.android.lib.netdetection.task;
+
+import android.app.Application;
+import android.os.Handler;
+import android.os.Looper;
+
+import com.wdkl.ncs.android.lib.netdetection.LDNetDiagnoService.LDNetDiagnoListener;
+import com.wdkl.ncs.android.lib.netdetection.LDNetDiagnoService.LDNetDiagnoService;
+
+public class TraceTask extends BaseTask implements LDNetDiagnoListener {
+    String url;
+    Application context;
+    private String appCode;
+    private String appName;
+    private String deviceId;
+    private String appVersion;
+    private boolean alwaysPing;
+
+    LDNetDiagnoService netDiagnoService;
+
+    private Handler handler = new Handler(Looper.getMainLooper());
+
+    public void setAlwaysPing(boolean alwaysPing) {
+        this.alwaysPing = alwaysPing;
+    }
+
+    public void setAppCode(String appCode) {
+        this.appCode = appCode;
+    }
+
+    public void setAppName(String appName) {
+        this.appName = appName;
+    }
+
+    public void setDeviceId(String deviceId) {
+        this.deviceId = deviceId;
+    }
+
+    public void setAppVersion(String appVersion) {
+        this.appVersion = appVersion;
+    }
+
+    public TraceTask(Application context, String url, TaskCallBack callBack) {
+        super(url, callBack);
+        this.context = context;
+        this.url = url;
+    }
+
+    @Override
+    public Runnable getExecRunnable() {
+        return execRunnable;
+    }
+
+    public Runnable execRunnable = new Runnable() {
+        @Override
+        public void run() {
+            try {
+                netDiagnoService = new LDNetDiagnoService(context,
+                        appCode, appName, appVersion, "",
+                        deviceId, url, "", "",
+                        "", "", alwaysPing, TraceTask.this);
+                // 设置是否使用JNIC 完成traceroute
+                netDiagnoService.setIfUseJNICTrace(true);
+                netDiagnoService.execute();
+            } catch (final Exception e) {
+                if (callBack != null) {
+                    handler.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            callBack.onFailed(e);
+                        }
+                    });
+                }
+            }
+        }
+    };
+
+    @Override
+    public void OnNetDiagnoFinished(final String log) {
+        if (callBack != null) {
+            handler.post(new Runnable() {
+                @Override
+                public void run() {
+                    callBack.onFinish(log);
+                }
+            });
+        }
+    }
+
+    @Override
+    public void OnNetDiagnoUpdated(final String log) {
+        if (callBack != null) {
+            handler.post(new Runnable() {
+                @Override
+                public void run() {
+                    callBack.onUpdated(log);
+                }
+            });
+        }
+    }
+
+    public void stop() {
+        if (netDiagnoService != null) {
+            netDiagnoService.cancel(true);
+        }
+    }
+}

+ 108 - 0
common/src/main/code/com/wdkl/ncs/android/lib/netdetection/ui/NetDetectActivity.java

@@ -0,0 +1,108 @@
+package com.wdkl.ncs.android.lib.netdetection.ui;
+
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.app.AppCompatActivity;
+
+import com.wdkl.ncs.android.lib.R;
+import com.wdkl.ncs.android.lib.netdetection.task.TaskCallBack;
+import com.wdkl.ncs.android.lib.netdetection.task.TraceTask;
+import com.wdkl.ncs.android.lib.netdetection.util.ClipboardUtils;
+import com.wdkl.ncs.android.lib.netdetection.util.DeviceUtils;
+
+public class NetDetectActivity extends AppCompatActivity implements TaskCallBack {
+    Button traceButton;
+    Button exitButton;
+    TextView resultTextView;
+    EditText urlEditText;
+
+    TraceTask traceTask;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_net_detect_main);
+
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN |
+                WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON |
+                WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
+                WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
+
+        String url = getIntent().getStringExtra("url");
+
+        traceButton = findViewById(R.id.bt_trace);
+        exitButton = findViewById(R.id.bt_exit);
+        resultTextView = findViewById(R.id.tv_result);
+        urlEditText = findViewById(R.id.et_url);
+        urlEditText.setText(url);
+        urlEditText.setFocusable(false);
+        urlEditText.setFocusableInTouchMode(true);
+
+        traceButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                String url = urlEditText.getText().toString();
+                if (TextUtils.isEmpty(url)) {
+                    Toast.makeText(getApplicationContext(), "Empty url!", Toast.LENGTH_SHORT).show();
+                    return;
+                }
+
+                resultTextView.setText("");
+                traceTask = new TraceTask(getApplication(),
+                        url + "", NetDetectActivity.this);
+                traceTask.setAppVersion(DeviceUtils.getVersion(NetDetectActivity.this));
+                traceTask.setAppName("NetworkDetection");
+                traceTask.setAppCode("01");
+                traceTask.setDeviceId(DeviceUtils.getAndroidID(NetDetectActivity.this));
+                traceTask.setAlwaysPing(true); //是否永远进行Ping,如果是false,则根据当前网络环境判断是否要Ping
+                traceTask.doTask();
+            }
+        });
+
+        exitButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                traceTask.stop();
+                finish();
+            }
+        });
+    }
+
+    @Override
+    public void onUpdated(String log) {
+        resultTextView.append(log);
+    }
+
+    @Override
+    public void onFinish(String log) {
+        new AlertDialog.Builder(this)
+                .setTitle("Check end")
+                //.setMessage("可复制诊断信息到剪切板")
+                .setCancelable(false)
+                /*.setPositiveButton("复制", new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        String info = resultTextView.getText().toString();
+                        ClipboardUtils.copyToClipboard(NetDetectActivity.this, info);
+                        Toast.makeText(getApplicationContext(), "复制诊断信息成功!", Toast.LENGTH_SHORT).show();
+                    }
+                })*/
+                .setNegativeButton(R.string.str_cancel, null)
+                .show();
+    }
+
+    @Override
+    public void onFailed(Exception e) {
+        resultTextView.append("Check failed:" + e.getMessage());
+        Toast.makeText(this, "Check failed:" + e.getMessage(), Toast.LENGTH_SHORT).show();
+    }
+}

+ 58 - 0
common/src/main/code/com/wdkl/ncs/android/lib/netdetection/util/ClipboardUtils.java

@@ -0,0 +1,58 @@
+package com.wdkl.ncs.android.lib.netdetection.util;
+
+import android.annotation.TargetApi;
+import android.content.ClipData;
+import android.content.ClipboardManager;
+import android.content.Context;
+import android.os.Build;
+
+/**
+ * 剪切板工具类
+ */
+public class ClipboardUtils {
+
+    /**
+     * 复制到剪切板
+     *
+     * @param context
+     * @param text
+     */
+    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+    public static void copyToClipboard(Context context, String text) {
+        ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
+        clipboard.setPrimaryClip(ClipData.newPlainText(null, text));
+    }
+
+    /**
+     * 获取剪贴板指定Index的文本
+     *
+     * @param context
+     * @param index
+     * @return
+     */
+    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+    public static String getText(Context context, int index) {
+        ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
+        ClipData clip = clipboard.getPrimaryClip();
+        if (clip != null && clip.getItemCount() > index) {
+            return String.valueOf(clip.getItemAt(index).coerceToText(context));
+        }
+        return null;
+    }
+
+    /**
+     * 获取剪切板最后的文本
+     *
+     * @param context
+     * @return
+     */
+    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+    public static String getLatestText(Context context) {
+        ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
+        ClipData clip = clipboard.getPrimaryClip();
+        if (clip != null && clip.getItemCount() > 0) {
+            return String.valueOf(clip.getItemAt(0).coerceToText(context));
+        }
+        return null;
+    }
+}

+ 45 - 0
common/src/main/code/com/wdkl/ncs/android/lib/netdetection/util/DeviceUtils.java

@@ -0,0 +1,45 @@
+package com.wdkl.ncs.android.lib.netdetection.util;
+
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.provider.Settings;
+
+public class DeviceUtils {
+    /**
+     * 获取版本号
+     *
+     * @return 当前应用的版本号
+     */
+    public static String getVersion(Context context) {
+        try {
+            PackageManager manager = context.getPackageManager();
+            PackageInfo info = manager.getPackageInfo(context.getPackageName(), 0);
+            return info.versionName;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return "";
+        }
+    }
+
+    /**
+     * 获取版本号
+     *
+     * @return 当前应用的版本号
+     */
+    public static int getVersionCode(Context context) {
+        try {
+            PackageManager manager = context.getPackageManager();
+            PackageInfo info = manager.getPackageInfo(context.getPackageName(), 0);
+            return info.versionCode;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return 0;
+        }
+    }
+
+    public static String getAndroidID(Context context) {
+        String id = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
+        return id == null ? "" : id;
+    }
+}

+ 358 - 0
common/src/main/code/com/wdkl/ncs/android/lib/netdetection/util/LDNetUtil.java

@@ -0,0 +1,358 @@
+package com.wdkl.ncs.android.lib.netdetection.util;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.DhcpInfo;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkInfo;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.os.Build;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.LineNumberReader;
+import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.UnknownHostException;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+
+@SuppressLint("DefaultLocale")
+public class LDNetUtil {
+
+    public static final String OPEN_IP = "";// 可ping的IP地址
+    public static final String OPERATOR_URL = "";
+
+    public static final String NETWORKTYPE_INVALID = "UNKNOWN";// 没有网络
+    public static final String NETWORKTYPE_WAP = "WAP"; // wap网络
+    public static final String NETWORKTYPE_WIFI = "WIFI"; // wifi网络
+
+    @SuppressWarnings({"deprecation"})
+    public static String getNetWorkType(Context context) {
+        String mNetWorkType = null;
+        ConnectivityManager manager = (ConnectivityManager) context
+                .getSystemService(Context.CONNECTIVITY_SERVICE);
+        if (manager == null) {
+            return "ConnectivityManager not found";
+        }
+        NetworkInfo networkInfo = manager.getActiveNetworkInfo();
+        if (networkInfo != null && networkInfo.isConnected()) {
+            String type = networkInfo.getTypeName();
+            if (type.equalsIgnoreCase("WIFI")) {
+                mNetWorkType = NETWORKTYPE_WIFI;
+            } else if (type.equalsIgnoreCase("MOBILE")) {
+                String proxyHost = android.net.Proxy.getDefaultHost();
+                if (TextUtils.isEmpty(proxyHost)) {
+                    mNetWorkType = mobileNetworkType(context);
+                } else {
+                    mNetWorkType = NETWORKTYPE_WAP;
+                }
+            }
+        } else {
+            mNetWorkType = NETWORKTYPE_INVALID;
+        }
+        return mNetWorkType;
+    }
+
+    /**
+     * 判断网络是否连接
+     */
+    public static Boolean isNetworkConnected(Context context) {
+        ConnectivityManager manager = (ConnectivityManager) context
+                .getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE);
+        if (manager == null) {
+            return false;
+        }
+        NetworkInfo networkinfo = manager.getActiveNetworkInfo();
+        if (networkinfo == null || !networkinfo.isAvailable()) {
+            return false;
+        }
+        return true;
+    }
+
+    public static String getMobileOperator(Context context) {
+        TelephonyManager telManager = (TelephonyManager) context
+                .getSystemService(Context.TELEPHONY_SERVICE);
+        if (telManager == null)
+            return "未知运营商";
+        String operator = telManager.getSimOperator();
+        if (operator != null) {
+            if (operator.equals("46000") || operator.equals("46002")
+                    || operator.equals("46007")) {
+                return "中国移动";
+            } else if (operator.equals("46001")) {
+                return "中国联通";
+            } else if (operator.equals("46003")) {
+                return "中国电信";
+            }
+        }
+        return "未知运营商:" + operator;
+    }
+
+    /**
+     * 获取本机IP(wifi)
+     */
+    public static String getLocalIpByWifi(Context context) {
+        WifiManager wifiManager = (WifiManager) context
+                .getSystemService(Context.WIFI_SERVICE);
+        if (wifiManager == null) {
+            return "wifiManager not found";
+        }
+        WifiInfo wifiInfo = wifiManager.getConnectionInfo();
+        if (wifiInfo == null) {
+            return "wifiInfo not found";
+        }
+        int ipAddress = wifiInfo.getIpAddress();
+        return String.format("%d.%d.%d.%d", (ipAddress & 0xff),
+                (ipAddress >> 8 & 0xff), (ipAddress >> 16 & 0xff),
+                (ipAddress >> 24 & 0xff));
+    }
+
+    /**
+     * 获取本机IP(2G/3G/4G)
+     */
+    public static String getLocalIpBy3G() {
+        try {
+            for (Enumeration<NetworkInterface> en = NetworkInterface
+                    .getNetworkInterfaces(); en.hasMoreElements(); ) {
+                NetworkInterface intf = en.nextElement();
+                for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr
+                        .hasMoreElements(); ) {
+                    InetAddress inetAddress = enumIpAddr.nextElement();
+                    if (!inetAddress.isLoopbackAddress()
+                            && inetAddress instanceof Inet4Address) {
+                        // if (!inetAddress.isLoopbackAddress() && inetAddress
+                        // instanceof Inet6Address) {
+                        return inetAddress.getHostAddress().toString();
+                    }
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * wifi状态下获取网关
+     */
+    public static String pingGateWayInWifi(Context context) {
+        String gateWay = null;
+        WifiManager wifiManager = (WifiManager) context
+                .getSystemService(Context.WIFI_SERVICE);
+        if (wifiManager == null) {
+            return "wifiManager not found";
+        }
+        DhcpInfo dhcpInfo = wifiManager.getDhcpInfo();
+        if (dhcpInfo != null) {
+            int tmp = dhcpInfo.gateway;
+            gateWay = String.format("%d.%d.%d.%d", (tmp & 0xff), (tmp >> 8 & 0xff),
+                    (tmp >> 16 & 0xff), (tmp >> 24 & 0xff));
+        }
+        return gateWay;
+    }
+
+    /**
+     * 获取本地DNS
+     */
+    /*public static String getLocalDns(String dns) {
+        Process process = null;
+        String str = "";
+        BufferedReader reader = null;
+        try {
+            process = Runtime.getRuntime().exec("getprop net." + dns);
+            reader = new BufferedReader(new InputStreamReader(
+                    process.getInputStream()));
+            String line = null;
+            while ((line = reader.readLine()) != null) {
+                str += line;
+            }
+            reader.close();
+            process.waitFor();
+        } catch (IOException e) {
+            e.printStackTrace();
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        } finally {
+            try {
+                if (reader != null) {
+                    reader.close();
+                }
+                process.destroy();
+            } catch (Exception e) {
+            }
+        }
+        return str.trim();
+    }*/
+    public static String[] getLocalDns(Context context) {
+        /**
+         * 获取dns
+         */
+        String[] dnsServers = getDnsFromCommand();
+        if (dnsServers == null || dnsServers.length == 0) {
+            dnsServers = getDnsFromConnectionManager(context);
+        }
+        return dnsServers;
+    }
+
+    //通过 getprop 命令获取
+    private static String[] getDnsFromCommand() {
+        LinkedList<String> dnsServers = new LinkedList<>();
+        try {
+            Process process = Runtime.getRuntime().exec("getprop");
+            InputStream inputStream = process.getInputStream();
+            LineNumberReader lnr = new LineNumberReader(new InputStreamReader(inputStream));
+            String line = null;
+            while ((line = lnr.readLine()) != null) {
+                int split = line.indexOf("]: [");
+                if (split == -1) continue;
+                String property = line.substring(1, split);
+                String value = line.substring(split + 4, line.length() - 1);
+                if (property.endsWith(".dns")
+                        || property.endsWith(".dns1")
+                        || property.endsWith(".dns2")
+                        || property.endsWith(".dns3")
+                        || property.endsWith(".dns4")) {
+                    InetAddress ip = InetAddress.getByName(value);
+                    if (ip == null) continue;
+                    value = ip.getHostAddress();
+                    if (value == null) continue;
+                    if (value.length() == 0) continue;
+                    dnsServers.add(value);
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return dnsServers.isEmpty() ? new String[0] : dnsServers.toArray(new String[dnsServers.size()]);
+    }
+
+
+    private static String[] getDnsFromConnectionManager(Context context) {
+        LinkedList<String> dnsServers = new LinkedList<>();
+        if (Build.VERSION.SDK_INT >= 21 && context != null) {
+            ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(context.CONNECTIVITY_SERVICE);
+            if (connectivityManager != null) {
+                NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
+                if (activeNetworkInfo != null) {
+                    for (Network network : connectivityManager.getAllNetworks()) {
+                        NetworkInfo networkInfo = connectivityManager.getNetworkInfo(network);
+                        if (networkInfo != null && networkInfo.getType() == activeNetworkInfo.getType()) {
+                            LinkProperties lp = connectivityManager.getLinkProperties(network);
+                            for (InetAddress addr : lp.getDnsServers()) {
+                                dnsServers.add(addr.getHostAddress());
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return dnsServers.isEmpty() ? new String[0] : dnsServers.toArray(new String[dnsServers.size()]);
+    }
+
+    /**
+     * 域名解析
+     */
+    public static Map<String, Object> getDomainIp(String _dormain) {
+        Map<String, Object> map = new HashMap<String, Object>();
+        long start = 0;
+        long end = 0;
+        String time = null;
+        InetAddress[] remoteInet = null;
+        try {
+            start = System.currentTimeMillis();
+            remoteInet = InetAddress.getAllByName(_dormain);
+            if (remoteInet != null) {
+                end = System.currentTimeMillis();
+                time = (end - start) + "";
+            }
+        } catch (UnknownHostException e) {
+            end = System.currentTimeMillis();
+            time = (end - start) + "";
+            remoteInet = null;
+            e.printStackTrace();
+        } finally {
+            map.put("remoteInet", remoteInet);
+            map.put("useTime", time);
+        }
+        return map;
+    }
+
+    private static String mobileNetworkType(Context context) {
+        TelephonyManager telephonyManager = (TelephonyManager) context
+                .getSystemService(Context.TELEPHONY_SERVICE);
+        if (telephonyManager == null) {
+            return "TM==null";
+        }
+        switch (telephonyManager.getNetworkType()) {
+            case TelephonyManager.NETWORK_TYPE_1xRTT:// ~ 50-100 kbps
+                return "2G";
+            case TelephonyManager.NETWORK_TYPE_CDMA:// ~ 14-64 kbps
+                return "2G";
+            case TelephonyManager.NETWORK_TYPE_EDGE:// ~ 50-100 kbps
+                return "2G";
+            case TelephonyManager.NETWORK_TYPE_EVDO_0:// ~ 400-1000 kbps
+                return "3G";
+            case TelephonyManager.NETWORK_TYPE_EVDO_A:// ~ 600-1400 kbps
+                return "3G";
+            case TelephonyManager.NETWORK_TYPE_GPRS:// ~ 100 kbps
+                return "2G";
+            case TelephonyManager.NETWORK_TYPE_HSDPA:// ~ 2-14 Mbps
+                return "3G";
+            case TelephonyManager.NETWORK_TYPE_HSPA:// ~ 700-1700 kbps
+                return "3G";
+            case TelephonyManager.NETWORK_TYPE_HSUPA: // ~ 1-23 Mbps
+                return "3G";
+            case TelephonyManager.NETWORK_TYPE_UMTS:// ~ 400-7000 kbps
+                return "3G";
+            case TelephonyManager.NETWORK_TYPE_EHRPD:// ~ 1-2 Mbps
+                return "3G";
+            case TelephonyManager.NETWORK_TYPE_EVDO_B: // ~ 5 Mbps
+                return "3G";
+            case TelephonyManager.NETWORK_TYPE_HSPAP:// ~ 10-20 Mbps
+                return "3G";
+            case TelephonyManager.NETWORK_TYPE_IDEN:// ~25 kbps
+                return "2G";
+            case TelephonyManager.NETWORK_TYPE_LTE:// ~ 10+ Mbps
+                return "4G";
+            case TelephonyManager.NETWORK_TYPE_UNKNOWN:
+                return "UNKNOWN";
+            default:
+                return "UNKNOWN:" + telephonyManager.getNetworkType();
+        }
+    }
+
+    /**
+     * 输入流转变成字符串
+     */
+    public static String getStringFromStream(InputStream is) {
+        byte[] bytes = new byte[1024];
+        int len = 0;
+        String res = "";
+        try {
+            while ((len = is.read(bytes)) != -1) {
+                res = res + new String(bytes, 0, len, "gbk");
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            if (is != null) {
+                try {
+                    is.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        return res;
+    }
+}

+ 97 - 0
common/src/main/code/com/wdkl/ncs/android/lib/netdetection/util/LDPingParse.java

@@ -0,0 +1,97 @@
+package com.wdkl.ncs.android.lib.netdetection.util;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class LDPingParse {
+  public static String getFormattingStr(String host, String log) {
+    StringBuilder logRes = new StringBuilder();
+    if (log.contains("timeout")) {
+      logRes.append("ping: cannot resolve " + host + ": Timeout");
+    } else if (log.contains("unknown")) {
+      logRes.append("ping: cannot resolve " + host + ": Unknown host");
+    } else {
+      makePingResponse(log, logRes);
+    }
+    return logRes.toString();
+  }
+
+  public static void makePingResponse(String log, StringBuilder logRes) {
+    String hostIp = getIP(log);
+    List<String> bytesList = getSumBytes(log);
+    List<String> ttlList = getTTL(log);
+    List<String> timeList = getTime(log);
+    List<String> icmpList = getIcmp_seq(log);
+    int len = timeList.size();
+    for (int i = 0; i < len - 1; i++) {
+      logRes.append(bytesList.get(i) + "bytes from " + hostIp + ": icmp_seq=#"
+          + icmpList.get(i) + " ttl=" + ttlList.get(i) + " time="
+          + timeList.get(i) + "ms" + "\n");
+    }
+    logRes.append(bytesList.get(len - 1) + "bytes from " + hostIp
+        + ": icmp_seq=#" + icmpList.get(len - 1) + " ttl="
+        + ttlList.get(len - 1) + " time=" + timeList.get(len - 1) + "ms");
+  }
+
+  private static List<String> getTime(String log) {
+    List<String> timeList = new ArrayList<String>();
+    String regex = "(?<==)([\\.0-9\\s]+)(?=ms)";
+    Pattern p = Pattern.compile(regex);
+    Matcher m = p.matcher(log);
+    while (m.find()) {
+      timeList.add(m.group().toString().trim());
+    }
+    return timeList;
+  }
+
+  private static List<String> getSumBytes(String log) {
+    List<String> bytesList = new ArrayList<String>();
+    String regex = "(?<=\\D)([\\s0-9]+)(?=bytes)";
+    Pattern p = Pattern.compile(regex);
+    Matcher m = p.matcher(log);
+    while (m.find()) {
+      String string = m.group().toString().trim();
+      if (m.group().toString().trim().matches("\\d+")) {
+        bytesList.add(string);
+      }
+    }
+    return bytesList;
+  }
+
+  private static List<String> getTTL(String log) {
+    List<String> ttlList = new ArrayList<String>();
+    String regex = "(?<=ttl=)([0-9]+)(?=\\s)";
+    Pattern p = Pattern.compile(regex);
+    Matcher m = p.matcher(log);
+    while (m.find()) {
+      String tmp = m.group().toString().trim();
+      ttlList.add(tmp);
+    }
+    return ttlList;
+  }
+
+  private static String getIP(String log) {
+    String hostIp = null;
+    String regex = "(?<=\\()([\\d]+\\.)+[\\d]+(?=\\))";
+    Pattern p = Pattern.compile(regex);
+    Matcher m = p.matcher(log);
+    while (m.find()) {
+      hostIp = m.group().toString().trim();
+    }
+    return hostIp;
+  }
+
+  private static List<String> getIcmp_seq(String log) {
+    List<String> icmpList = new ArrayList<String>();
+    String regex = "(?<=icmp_seq=)([0-9]+)(?=\\s)";
+    Pattern p = Pattern.compile(regex);
+    Matcher m = p.matcher(log);
+    while (m.find()) {
+      String tmp = m.group().toString().trim();
+      icmpList.add(tmp);
+    }
+    return icmpList;
+  }
+}

+ 54 - 0
common/src/main/res/layout/activity_net_detect_main.xml

@@ -0,0 +1,54 @@
+<?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"
+    android:orientation="vertical">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+
+        <EditText
+            android:id="@+id/et_url"
+            android:layout_width="match_parent"
+            android:visibility="visible"
+            android:layout_height="wrap_content"
+            android:layout_weight="1" />
+
+        <Button
+            android:id="@+id/bt_trace"
+            android:layout_width="match_parent"
+            android:layout_weight="1"
+            android:layout_height="wrap_content"
+            android:layout_alignParentRight="true"
+            android:text="@string/str_start" />
+
+        <Button
+            android:id="@+id/bt_exit"
+            android:layout_width="match_parent"
+            android:layout_weight="1"
+            android:layout_height="wrap_content"
+            android:layout_alignParentRight="true"
+            android:text="@string/str_back" />
+
+    </LinearLayout>
+
+    <ScrollView
+        android:id="@+id/scrollView"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="#eeeeee"
+        android:scrollbars="none">
+
+        <TextView
+            android:id="@+id/tv_result"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_margin="4dp"
+            android:text="no detect result"
+            android:textColor="#ff000000"
+            android:textIsSelectable="true"
+            android:textSize="14sp" />
+    </ScrollView>
+</LinearLayout>

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

@@ -208,6 +208,8 @@
 
     <string name="your_card_number">Su número de tarjeta:</string>
     <string name="str_about">Acerca de</string>
-
     <string name="str_back">Atrás</string>
+
+    <string name="str_start">开始</string>
+    <string name="str_start_detection">开始诊断…</string>
 </resources>

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

@@ -195,6 +195,8 @@
 
     <string name="str_about">Около</string>
     <string name="your_card_number">Номер вашей карты:</string>
-
     <string name="str_back">Назад</string>
+
+    <string name="str_start">开始</string>
+    <string name="str_start_detection">开始诊断…</string>
 </resources>

+ 3 - 2
resource/src/main/res/values-zh/strings.xml

@@ -1,8 +1,6 @@
 <resources>
     <string name="javashop_app_name">NCS-门口机</string>
 
-
-
     <string name="data_empty">没有数据</string>
     <string name="register_server_ip">服务器IP:</string>
     <string name="register_device_identifier">识别码:</string>
@@ -210,4 +208,7 @@
     <string name="str_reset">重置</string>
     <string name="str_debug">调试</string>
     <string name="str_back">返回</string>
+
+    <string name="str_start">开始检测网络</string>
+    <string name="str_start_detection">开始诊断…</string>
 </resources>

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

@@ -211,4 +211,6 @@
     <string name="sync_timezone">Sync Timezone</string>
     <string name="str_back">Back</string>
 
+    <string name="str_start">Start</string>
+    <string name="str_start_detection">Start check…</string>
 </resources>