release V740
authorsnickersun <scy@incartech.cn>
Sat, 6 Mar 2021 13:47:29 +0000 (21:47 +0800)
committersnickersun <scy@incartech.cn>
Sat, 6 Mar 2021 13:47:29 +0000 (21:47 +0800)
添加sc7a21 跌倒功能

app/build.gradle
app/release/L05_ICSer_V740_2103062145_release.apk [new file with mode: 0644]
app/release/output.json
app/src/main/java/com/enqualcomm/support/service/AntiMonitorService.java
app/src/main/java/com/enqualcomm/support/service/InputEventReader.java [new file with mode: 0644]
app/src/main/java/com/enqualcomm/support/utils/ThreadPool.java [new file with mode: 0644]
app/src/main/java/com/enqualcomm/support/utils/Util.java
app/version_code.properties
icsupport.iml [deleted file]

index f3bc2d3..b4dde88 100644 (file)
@@ -3,7 +3,7 @@ apply plugin: 'com.android.application'
 
 // APK 名称
 static def getApkBaseName() {
-    return "ICSer"
+    return "L05_ICSer"
 }
 
 android {
diff --git a/app/release/L05_ICSer_V740_2103062145_release.apk b/app/release/L05_ICSer_V740_2103062145_release.apk
new file mode 100644 (file)
index 0000000..0f21192
Binary files /dev/null and b/app/release/L05_ICSer_V740_2103062145_release.apk differ
index 617ce71..a9dcace 100644 (file)
@@ -1 +1 @@
-[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":738,"versionName":"2012221145","enabled":true,"outputFile":"ICSer_V738_2012221145_release.apk","fullName":"release","baseName":"release"},"path":"ICSer_V738_2012221145_release.apk","properties":{}}]
\ No newline at end of file
+[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":740,"versionName":"2103062145","enabled":true,"outputFile":"L05_ICSer_V740_2103062145_release.apk","fullName":"release","baseName":"release"},"path":"L05_ICSer_V740_2103062145_release.apk","properties":{}}]
\ No newline at end of file
index 427bd5e..977cbf2 100644 (file)
@@ -16,12 +16,14 @@ import com.enqualcomm.support.CoreService;
 import com.enqualcomm.support.LocationClient;
 import com.enqualcomm.support.R;
 import com.enqualcomm.support.bean.Runtime;
+import com.enqualcomm.support.bean.StringMessage;
 import com.enqualcomm.support.service.base.AbstractInvokeHandlerService;
 import com.enqualcomm.support.utils.AlarmHelper;
 import com.enqualcomm.support.utils.Connection;
 import com.enqualcomm.support.utils.ICLogger;
 import com.enqualcomm.support.utils.Util;
 import com.enqualcomm.support.utils.VibrateUtil;
+import com.ic.protocols.protocolAPIHelper;
 
 import java.lang.ref.WeakReference;
 
@@ -33,7 +35,7 @@ import static com.enqualcomm.support.Constants.KEY_ANTI_TXT;
 import static java.lang.Thread.sleep;
 
 
-public class AntiMonitorService extends AbstractInvokeHandlerService {
+public class AntiMonitorService extends AbstractInvokeHandlerService implements InputEventReader.InputEventReceiver {
 
 
     private static final String TAG = "AntiMonitorService";
@@ -42,7 +44,7 @@ public class AntiMonitorService extends AbstractInvokeHandlerService {
     Runtime mRuntime;
 
     Connection mConnection;
-
+    private InputEventReader m_inputEventReader=null;
     private SensorManager mSensorManager;
     //current_anti_status == 2 表示表带 锁定 , ==12 表示表带非法解锁
     //current_anti_status == 0 表示佩戴       ==10 表示脱腕
@@ -58,6 +60,19 @@ public class AntiMonitorService extends AbstractInvokeHandlerService {
     private Handler mHandler = null;
     PowerManager.WakeLock mWakeLock = null;
 
+    @Override
+    public void onInputEventRecevied(int type, int event) {
+        if(type== InputEventReader.EVENT_TYPE_CUT && event == InputEventReader.EVENT_FALLOFF){
+            send_fall_off_event();
+        }
+    }
+
+    private void send_fall_off_event(){
+        mRuntime.setAlarmType(Runtime.AlarmType.ALARM_FALL);
+        StringMessage alarmmsg=protocolAPIHelper.getWarningMSG(mRuntime);
+        Deliver.sendLocationMSG(alarmmsg);
+        ICLogger.i(" send fall off event !");
+    }
 
     private static class InnerHandler extends Handler {
 
@@ -98,6 +113,8 @@ public class AntiMonitorService extends AbstractInvokeHandlerService {
 //            mWakeLock = mPowerManager.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, AntiMonitorService.class.getSimpleName());
             mWakeLock = mPowerManager.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, AntiMonitorService.class.getSimpleName());
         }
+
+        m_inputEventReader=new InputEventReader(this);
     }
 
     private void play_notify() {
diff --git a/app/src/main/java/com/enqualcomm/support/service/InputEventReader.java b/app/src/main/java/com/enqualcomm/support/service/InputEventReader.java
new file mode 100644 (file)
index 0000000..f09aa75
--- /dev/null
@@ -0,0 +1,267 @@
+package com.enqualcomm.support.service;
+
+import com.enqualcomm.support.utils.ICLogger;
+import com.enqualcomm.support.utils.ThreadPool;
+import com.enqualcomm.support.utils.Util;
+
+import java.io.FileInputStream;
+
+public class InputEventReader {
+    public static final int EVENT_TYPE_ANTI=0;
+    public static final int EVENT_TYPE_CUT=0;
+    public static final int EVENT_ANTI_OFF=10;
+    public static final int EVENT_WEARED=1;
+    public static final int EVENT_CUT_OFF=12;
+    public static final int EVENT_LOCKED=2;
+    public static final int EVENT_FALLOFF=3;
+
+
+    /***
+     *循环读取设备的name 匹配对应的设备名,确定是否制定设备
+     * /sys/class/input/input0/name
+     * /sys/class/input/input1/name
+     * ...
+     * /sys/class/input/inputX/name
+     */
+    private static final String SYS_INPUT_BASE="/sys/class/input/input";
+    private static final String EVENT_PATH_BASE="/dev/input/event";
+    /***
+     * 读取/sys/class/input/inputX/name 对应的名称 符合 antiDevNames 即是 佩戴检测事件节点
+     * 检测对应 /dev/input/eventX 节点可以获取佩戴事件
+     */
+    private static final String antiDevNames= Util.getSystemProperties("persist.sys.AntiInputName","");
+    /***
+     * 读取/sys/class/input/inputX/name 对应的名称 符合 cutDevNames 即是 剪断检测事件节点
+     * 检测对应 /dev/input/eventX 节点可以获取剪断事件
+     */
+    private static final String cutDevNames= Util.getSystemProperties("persist.sys.ic.falldev","");
+
+
+    private String getInputDevNameByID(int id){
+        byte buffer[]=new byte[255];
+        String ret="";
+        String input=SYS_INPUT_BASE+id+"/name";
+        try {
+            FileInputStream fis=new FileInputStream(input);
+            int len=fis.read(buffer);
+            if (len > 0){
+                ret=new String(buffer,0,len);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        ICLogger.i("getInputDevNameByID "+input+ " "+ret);
+        return ret.trim();
+    }
+
+    private int get_DevID_By_Name(String name){
+        int devid=-1;
+        for ( int i=0;i< 10;i++){
+            if(getInputDevNameByID(i).startsWith(name.trim())) {
+                devid = i;
+                break;
+            }
+        }
+        return devid;
+    }
+
+
+
+    public int getEventFromData(boolean isAntiEvent,byte[] eventMsgs){
+    /***
+     * 4d3bfc5fd1ab0a0001008e00010000004d3bfc5fd1ab0a0001008e00000000004d3bfc5fd1ab0a000000000000000000
+     *
+     * 4d3bfc5fd1ab0a00    timestamp  8bytes
+     * 0100             eventtype   2bytes
+     * 8e00             eventcode   2bytes
+     * 01000000          value      4bytes
+     * 4d3bfc5fd1ab0a00   timestamp
+     * 0100             eventtype
+     * 8e00             eventcode
+     * 00000000        value
+     * 4d3bfc5fd1ab0a00   timestamp
+     * 0000             eventtype
+     * 0000             eventcode
+     * 00000000         value
+     *
+     * 0001 008e 00000001
+     * 0001 008e 00000000
+     * 0000 0000 00000000
+     */
+        int ret=0;
+        byte int_bytes[]=new byte[4];
+        boolean msg_printted=false;
+        if(eventMsgs.length%16==0){
+            int eventtype,eventvalue;
+            long eventcode;
+            for(int i=0;i<eventMsgs.length/16;i++)
+            {
+                StringBuilder sb=new StringBuilder("Received EventType ");
+                int_bytes[0]=int_bytes[1]=int_bytes[2]=int_bytes[3]=0;
+                int_bytes[3]=eventMsgs[8+i*16];
+                int_bytes[2]=eventMsgs[9+i*16];
+                eventtype=Util.byteArray4ToInt(int_bytes);
+                sb.append(Util.byte2hex(int_bytes));
+                int_bytes[3]=eventMsgs[10+i*16];
+                int_bytes[2]=eventMsgs[11+i*16];
+                eventcode=Util.byteArray4ToInt(int_bytes);
+                sb.append(" EventCode ").append(Util.byte2hex(int_bytes));
+                int_bytes[3]=eventMsgs[12+i*16];
+                int_bytes[2]=eventMsgs[13+i*16];
+                int_bytes[1]=eventMsgs[14+i*16];
+                int_bytes[0]=eventMsgs[15+i*16];
+                eventvalue=Util.byteArray4ToInt(int_bytes);
+                sb.append(" Value ").append(Util.byte2hex(int_bytes));
+                if( eventcode == 0x28 )
+                {
+                    if (!msg_printted)
+                    {
+                        ICLogger.i("read cut Event " + eventMsgs.length+ " "+ Util.bytesToHexString(eventMsgs));
+                    }
+                    ICLogger.i("Received EventType " + eventtype + " EventCode " + eventcode + " Value " + eventvalue);
+                }
+                if(eventcode==0x28 && eventvalue==1){
+
+                    ICLogger.i("Received EventType FALL OFF " );
+                    ret=EVENT_FALLOFF;
+                }
+                if(eventtype==1 && eventvalue==1){
+                    /***
+                     *     case 0x8e: //KeyCode AntiOff 脱腕
+                     *         if(value==1){
+                     * #ifdef GPIO_CUTOFF
+                     *             value= 12;
+                     * #else
+                     *             value= 10;
+                     *
+                     * #endif
+                     *     case 0x8d: //KeyCode Wear 佩戴
+                     *         if(value==1){
+                     * #ifdef GPIO_CUTOFF
+                     *             value=2;
+                     * #else
+                     *             value=0;
+                     * #endif
+                     */
+                    int f=Math.abs((int)eventcode);
+//                    ICLogger.i(" eventcode "+eventcode+" "+f+" 0x8e "+0x8e+" 0x8d "+0x8d);
+                    switch(f){
+                        case 0x8e: //KeyCode AntiOff 脱腕
+                            if(isAntiEvent){
+                                ret=EVENT_ANTI_OFF;
+                            }else{
+                                ret=EVENT_CUT_OFF;
+                            }
+                            break;
+                        case 0x8d://KeyCode Wear 佩戴
+                            if(isAntiEvent){
+                                ret=EVENT_WEARED;
+                            }else{
+                                ret=EVENT_LOCKED;
+                            }
+                            break;
+                    }
+                    sb.append(" ret ").append(ret);
+
+                }
+                if( eventcode == 0x28 )
+                {
+                    ICLogger.i(sb.toString());
+                }
+            }
+
+        }else{
+            ICLogger.e("Error Input Event Format!");
+        }
+        return ret;
+    }
+    /***
+     * 佩戴检测事件读取线程
+     */
+    private Runnable antiEventThread=new Runnable() {
+        @Override
+        public void run() {
+            ICLogger.i("Enter antiEventThread "+Thread.currentThread().getName()+" "+ antiDevNames);
+            int devid=get_DevID_By_Name(antiDevNames);
+            if (devid>-1){
+
+                try{
+                    String antipath=EVENT_PATH_BASE+devid;
+                    ICLogger.i("open AntiEventPATH "+antipath);
+                    FileInputStream br=new FileInputStream(antipath);
+                    byte buf[]=new byte[50];
+                    int len=0;
+                    while(true){
+                        len=br.read(buf);
+                        if(len>0) {
+                            byte t[]=new byte[len];
+                            for(int i=0;i<len;i++)
+                                t[i]=buf[i];
+                            ICLogger.i("read anti Event " + len+ " "+ Util.bytesToHexString(t));
+                            int event=getEventFromData(true,t);
+                            if(callback!=null){
+                                callback.onInputEventRecevied(EVENT_TYPE_ANTI,event);
+                            }
+                        }
+                    }
+                }catch (Exception e){
+                    ICLogger.e(e.getMessage(),e);
+                }
+
+            }else{
+                ICLogger.e("no AntiDev antiEventThread exit! ");
+            }
+        }
+    } ;
+    /***
+     * 剪断检测事件读取线程
+     */
+    private Runnable cutEventThread=new Runnable() {
+        @Override
+        public void run() {
+            ICLogger.i("Enter cutEventThread "+Thread.currentThread().getName() +" "+cutDevNames);
+            int devid=get_DevID_By_Name(cutDevNames);
+            if (devid>-1){
+
+                try{
+                    String cutpath=EVENT_PATH_BASE+devid;
+                    ICLogger.i("open CutEventPATH "+cutpath);
+                    FileInputStream br=new FileInputStream(cutpath);
+                    byte buf[]=new byte[50];
+                    int len=0;
+                    while(true){
+                        len=br.read(buf);
+                        if(len>0) {
+                            byte t[]=new byte[len];
+                            for(int i=0;i<len;i++)
+                                t[i]=buf[i];
+                           // ICLogger.i("read cut Event " + len+ " "+ Util.bytesToHexString(t));
+                            int event=getEventFromData(false,t);
+                            if(callback!=null){
+                                callback.onInputEventRecevied(EVENT_TYPE_CUT,event);
+                            }
+                        }
+                    }
+                }catch (Exception e){
+                    ICLogger.e(e.getMessage(),e);
+                }
+
+            }else{
+                ICLogger.e("no CutDev cutEventThread exit! ");
+            }
+        }
+    } ;
+
+    private InputEventReceiver callback=null;
+
+    public InputEventReader(InputEventReceiver ier){
+        callback=ier;
+      //  ThreadPool.getInstance().submitThreadPool(antiEventThread);
+        ThreadPool.getInstance().submitThreadPool(cutEventThread);
+
+    }
+
+    public interface InputEventReceiver{
+         void onInputEventRecevied(int type,int event);
+    }
+}
diff --git a/app/src/main/java/com/enqualcomm/support/utils/ThreadPool.java b/app/src/main/java/com/enqualcomm/support/utils/ThreadPool.java
new file mode 100644 (file)
index 0000000..cb3cf2d
--- /dev/null
@@ -0,0 +1,35 @@
+package com.enqualcomm.support.utils;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+final public class ThreadPool {
+
+    private ExecutorService mService;
+
+    private volatile static ThreadPool instance;
+
+    public ThreadPool() {
+        mService = Executors.newCachedThreadPool();
+    }
+
+
+    public static ThreadPool getInstance() {
+        if (instance == null) {
+            synchronized (ThreadPool.class) {
+                if (instance == null) {
+                    instance = new ThreadPool();
+                }
+            }
+        }
+        return instance;
+    }
+
+    public Future<?> submitThreadPool(Runnable runnable) {
+        if (runnable == null) {
+            return null;
+        }
+        return mService.submit(runnable);
+    }
+}
index 2594970..41a8c4c 100644 (file)
@@ -37,6 +37,7 @@ import java.io.UnsupportedEncodingException;
 import java.lang.reflect.Method;
 import java.net.InetAddress;
 import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
 import java.nio.charset.Charset;
 import java.util.ArrayList;
 import java.util.Enumeration;
@@ -1159,5 +1160,58 @@ public class Util {
   private static byte charToByte(char c) {
     return (byte) "0123456789ABCDEF".indexOf(c);
   }
+
+  public static int byteArray4ToInt(byte[] b) {
+    return   b[3] & 0xFF |
+            (b[2] & 0xFF) << 8 |
+            (b[1] & 0xFF) << 16 |
+            (b[0] & 0xFF) << 24;
+  }
+  public static byte[] intToByteArray4(int a) {
+    return new byte[] {
+            (byte) ((a >> 24) & 0xFF),
+            (byte) ((a >> 16) & 0xFF),
+            (byte) ((a >> 8) & 0xFF),
+            (byte) (a & 0xFF)
+    };
+  }
+
+  /**
+   * 将字节数组转为long<br>
+   * 如果input为null,或offset指定的剩余数组长度不足8字节则抛出异常
+   * @param input
+   * @param offset 起始偏移量
+   * @param littleEndian 输入数组是否小端模式
+   * @return
+   */
+  public static long longFrom8Bytes(byte[] input, int offset, boolean littleEndian){
+    if(offset <0 || offset+8>input.length)
+      throw new IllegalArgumentException(String.format("less than 8 bytes from index %d  is insufficient for long",offset));
+    long value=0;
+    for(int  count=0;count<8;++count){
+      int shift=(littleEndian?count:(7-count))<<3;
+      value |=((long)0xff<< shift) & ((long)input[offset+count] << shift);
+    }
+    return value;
+  }
+
+  /**
+   * 利用 {@link java.nio.ByteBuffer}实现byte[]转long
+   * @param input
+   * @param offset
+   * @param littleEndian 输入数组是否小端模式
+   * @return
+   */
+  public static long bytesToLong(byte[] input, int offset, boolean littleEndian) {
+    if(offset <0 || offset+8>input.length)
+      throw new IllegalArgumentException(String.format("less than 8 bytes from index %d  is insufficient for long",offset));
+    ByteBuffer buffer = ByteBuffer.wrap(input,offset,8);
+    if(littleEndian){
+      // ByteBuffer.order(ByteOrder) 方法指定字节序,即大小端模式(BIG_ENDIAN/LITTLE_ENDIAN)
+      // ByteBuffer 默认为大端(BIG_ENDIAN)模式
+      buffer.order(ByteOrder.LITTLE_ENDIAN);
+    }
+    return buffer.getLong();
+  }
 }
 
index 5d97b96..82028c5 100644 (file)
@@ -1,2 +1,2 @@
-#Tue Dec 22 11:45:50 CST 2020
-VERSION_CODE=738
+#Sat Mar 06 21:45:52 CST 2021
+VERSION_CODE=740
diff --git a/icsupport.iml b/icsupport.iml
deleted file mode 100644 (file)
index 30277a3..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>\r
-<module external.linked.project.id="icsupport" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">\r
-  <component name="FacetManager">\r
-    <facet type="java-gradle" name="Java-Gradle">\r
-      <configuration>\r
-        <option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/build" />\r
-        <option name="BUILDABLE" value="false" />\r
-      </configuration>\r
-    </facet>\r
-  </component>\r
-  <component name="NewModuleRootManager" inherit-compiler-output="true">\r
-    <exclude-output />\r
-    <content url="file://$MODULE_DIR$">\r
-      <excludeFolder url="file://$MODULE_DIR$/.gradle" />\r
-      <excludeFolder url="file://$MODULE_DIR$/build" />\r
-    </content>\r
-    <orderEntry type="inheritedJdk" />\r
-    <orderEntry type="sourceFolder" forTests="false" />\r
-  </component>\r
-</module>
\ No newline at end of file