zengjiebin лет назад: 7
Родитель
Сommit
dc1e9b74fd
49 измененных файлов с 1086 добавлено и 127 удалено
  1. 2 1
      .gitignore
  2. 7 0
      app/build.gradle
  3. BIN
      app/libs/com.kfzs.safe.aar
  4. 2 0
      app/src/main/AndroidManifest.xml
  5. 25 0
      app/src/main/java/com/kfzs/duanduan/react/FileUtil.java
  6. 0 20
      app/src/main/java/com/sheep/gamegroup/util/BinaryUtil.java
  7. 37 5
      app/src/main/java/com/sheep/gamegroup/util/DataUtil.java
  8. 9 7
      app/src/main/java/com/sheep/gamegroup/util/Jump2View.java
  9. 19 0
      app/src/main/java/com/sheep/gamegroup/util/PngUtil.java
  10. 397 0
      app/src/main/java/com/sheep/gamegroup/util/ScreenShotListenManager.java
  11. 8 1
      app/src/main/java/com/sheep/gamegroup/util/TestUtil.java
  12. 143 0
      app/src/main/java/com/sheep/gamegroup/view/activity/ActSheepPngList.java
  13. 7 6
      app/src/main/java/com/sheep/gamegroup/view/activity/TaskDetailAct.java
  14. 17 4
      app/src/main/java/com/sheep/jiuyan/samllsheep/SheepApp.java
  15. 37 0
      app/src/main/java/com/sheep/jiuyan/samllsheep/utils/FileUtil.java
  16. 0 82
      app/src/main/java/com/sheep/jiuyan/samllsheep/utils/HexUtils.java
  17. 6 0
      app/src/main/jni/Android.mk
  18. 1 0
      app/src/main/jni/Application.mk
  19. 29 0
      app/src/main/jni/com_sheep_gamegroup_util_PngUtil.h
  20. 337 0
      app/src/main/jni/pngUtil.c
  21. BIN
      app/src/main/jniLibs/arm64-v8a/libindoor.so
  22. BIN
      app/src/main/jniLibs/arm64-v8a/libjcore120.so
  23. BIN
      app/src/main/jniLibs/arm64-v8a/liblocSDK7b.so
  24. BIN
      app/src/main/jniLibs/arm64-v8a/libsecurityenv.so
  25. BIN
      app/src/main/jniLibs/armeabi-v7a/libindoor.so
  26. BIN
      app/src/main/jniLibs/armeabi-v7a/libjcore120.so
  27. BIN
      app/src/main/jniLibs/armeabi-v7a/liblocSDK7b.so
  28. BIN
      app/src/main/jniLibs/armeabi-v7a/libsecurityenv.so
  29. BIN
      app/src/main/jniLibs/armeabi/libindoor.so
  30. BIN
      app/src/main/jniLibs/armeabi/libjcore120.so
  31. BIN
      app/src/main/jniLibs/armeabi/liblocSDK7b.so
  32. BIN
      app/src/main/jniLibs/armeabi/libsecurityenv.so
  33. BIN
      app/src/main/jniLibs/mips/libjcore120.so
  34. BIN
      app/src/main/jniLibs/mips64/libjcore120.so
  35. BIN
      app/src/main/jniLibs/x86/libindoor.so
  36. BIN
      app/src/main/jniLibs/x86/libjcore120.so
  37. BIN
      app/src/main/jniLibs/x86/liblocSDK7b.so
  38. BIN
      app/src/main/jniLibs/x86/libsecurityenv.so
  39. BIN
      app/src/main/jniLibs/x86_64/libindoor.so
  40. BIN
      app/src/main/jniLibs/x86_64/libjcore120.so
  41. BIN
      app/src/main/jniLibs/x86_64/liblocSDK7b.so
  42. BIN
      app/src/main/libs/arm64-v8a/libPngUtil.so
  43. BIN
      app/src/main/libs/armeabi-v7a/libPngUtil.so
  44. BIN
      app/src/main/libs/armeabi/libPngUtil.so
  45. BIN
      app/src/main/libs/mips/libPngUtil.so
  46. BIN
      app/src/main/libs/mips64/libPngUtil.so
  47. BIN
      app/src/main/libs/x86/libPngUtil.so
  48. BIN
      app/src/main/libs/x86_64/libPngUtil.so
  49. 3 1
      gradle.properties

+ 2 - 1
.gitignore

@@ -9,4 +9,5 @@
 .externalNativeBuild
 /.idea
 /kfzslibrary
-/banner
+/banner
+/app/src/main/obj

+ 7 - 0
app/build.gradle

@@ -108,6 +108,13 @@ android {
 
         }
     }
+    sourceSets {
+        main() {
+            jniLibs.srcDirs = ['src/main/libs']
+            jni.srcDirs = [] //屏蔽掉默认的jni编译生成过程
+        }
+    }
+
 }
 
 repositories {

BIN
app/libs/com.kfzs.safe.aar


+ 2 - 0
app/src/main/AndroidManifest.xml

@@ -562,6 +562,8 @@
             android:screenOrientation="portrait"/>
         <activity android:name="com.sheep.gamegroup.view.activity.ActSheepApkList"
             android:screenOrientation="portrait"/>
+        <activity android:name="com.sheep.gamegroup.view.activity.ActSheepPngList"
+            android:screenOrientation="portrait"/>
         <activity android:name="com.sheep.gamegroup.view.activity.ActFindGame"
             android:screenOrientation="portrait"/>
         <activity android:name="com.sheep.gamegroup.view.activity.ActFindInformation"

+ 25 - 0
app/src/main/java/com/kfzs/duanduan/react/FileUtil.java

@@ -149,4 +149,29 @@ public class FileUtil {
             e.printStackTrace();
         }
     }
+    /*
+     * Java文件操作 获取文件扩展名
+     * */
+    public static String getExtensionName(String filename) {
+        if ((filename != null) && (filename.length() > 0)) {
+            int dot = filename.lastIndexOf('.');
+            if ((dot >-1) && (dot < (filename.length() - 1))) {
+                return filename.substring(dot + 1);
+            }
+        }
+        return filename;
+    }
+    /*
+     * Java文件操作 获取不带扩展名的文件名
+     * */
+    public static String getFileNameNoEx(String filename) {
+        if ((filename != null) && (filename.length() > 0)) {
+            int dot = filename.lastIndexOf('.');
+            if ((dot >-1) && (dot < (filename.length()))) {
+                return filename.substring(0, dot);
+            }
+        }
+        return filename;
+    }
+
 }

+ 0 - 20
app/src/main/java/com/sheep/gamegroup/util/BinaryUtil.java

@@ -1,20 +0,0 @@
-package com.sheep.gamegroup.util;
-
-/**
- * Created by realicing on 2018/4/18.
- * realicing@sina.com
- */
-public class BinaryUtil {
-    public static boolean isInt(int num, int index, int thsInt) {
-        return get(num, index) == thsInt;
-    }
-
-    /**
-     * @param num:要获取二进制值的数
-     * @param index:倒数第一位为0,依次类推
-     */
-    public static int get(int num, int index) {
-        return (num & (0x1 << index)) >> index;
-    }
-
-}

+ 37 - 5
app/src/main/java/com/sheep/gamegroup/util/DataUtil.java

@@ -13,7 +13,6 @@ import android.text.TextUtils;
 import com.alibaba.fastjson.JSON;
 import com.sheep.gamegroup.model.api.BaseMessageConverter;
 import com.sheep.gamegroup.model.entity.BaseMessage;
-import com.sheep.gamegroup.model.entity.TaskAcceptedEty;
 import com.sheep.gamegroup.model.entity.UserEntity;
 import com.sheep.gamegroup.model.util.AutoTaskListUtil;
 import com.sheep.jiuyan.samllsheep.BuildConfig;
@@ -27,12 +26,17 @@ import org.afinal.simplecache.ACache;
 import org.afinal.simplecache.ApiKey;
 
 import java.io.File;
+import java.io.IOException;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.TreeMap;
+import java.util.concurrent.TimeUnit;
 
+import rx.Observable;
+import rx.android.schedulers.AndroidSchedulers;
 import rx.functions.Action1;
+import rx.schedulers.Schedulers;
 
 import static android.app.Activity.RESULT_OK;
 
@@ -292,7 +296,9 @@ public class DataUtil {
         return null;
     }
     //是否使用小绵羊截图方案
-    public static final boolean IS_USE_SCREEN_SHOT = false;//BuildConfig.DEBUG;
+    public static final boolean IS_USE_SCREEN_SHOT = true;
+    //是否监听媒体库图片变化
+    public static final boolean IS_LISTEN_SCREEN_SHOT = true;
     /**
      * 截图路径
      *
@@ -300,8 +306,6 @@ public class DataUtil {
      */
     public File getScreenShotsFile(String packageName) {
         File dir = getScreenShotsDir(packageName);
-        if(!dir.exists())
-            dir.mkdirs();
         return new File(dir, TimeUtil.getDate("yyyy-MM-dd-hh-mm-ss")+".png");
     }
 
@@ -319,7 +323,10 @@ public class DataUtil {
      * @return
      */
     public File getScreenShotsDir(String packageName) {
-        return new File(SheepApp.getInstance().getDir("ScreenShots", Context.MODE_PRIVATE), packageName);
+        File dir = new File(SheepApp.getInstance().getDir("ScreenShots", Context.MODE_PRIVATE), packageName);
+        if(!dir.exists())
+            dir.mkdirs();
+        return dir;
     }
 
     /**
@@ -410,6 +417,31 @@ public class DataUtil {
     public static boolean 是官方包吗(){
         return "kfzs".equals(ChannelContent.getInstance().getChannel_name());
     }
+
+    public void addPng(final String imagePath) {
+        final String packageName = getPackageNameInForeground();
+        if(TextUtils.isEmpty(packageName)){
+            LogUtil.println("ScreenShotListenManager", "无法获取到当前运行的应用的包名");
+            return;
+        }
+//        File shotFile = getScreenShotsFile(packageName);
+        LogUtil.println("ScreenShotListenManager", packageName);
+        Observable.just(1).delay(1, TimeUnit.SECONDS)
+                .subscribeOn(Schedulers.io())
+                .observeOn(AndroidSchedulers.mainThread())
+                .subscribe(new Action1<Integer>() {
+                    @Override
+                    public void call(Integer integer) {
+                        try {
+                            FileUtil.copyFile(new File (imagePath), getScreenShotsDir(packageName));
+                        } catch (IOException e) {
+                            e.printStackTrace();
+                            LogUtil.println("ScreenShotListenManager", "复制截屏图片失败");
+                        }
+                    }
+                });
+
+    }
 //    //正在运行的任务
 //    List<TaskAcceptedEty> taskAcceptedEtyList = ListUtil.emptyList();
 //    public void addTaskAcceptedEtyList(List<TaskAcceptedEty> list) {

+ 9 - 7
app/src/main/java/com/sheep/gamegroup/util/Jump2View.java

@@ -981,14 +981,16 @@ public class Jump2View {
      */
     public void startShotScreenFloat(Context context, Object object) {
         if(DataUtil.IS_USE_SCREEN_SHOT) {
-            Intent intent = new Intent(context, FloatShotScreenService.class);
-            if(object instanceof Boolean) {
-                intent.putExtra("isShow", (Boolean) object);
-                intent.putExtra("type", SET_SHOW_OR_HIDE);
-            } else if(object instanceof Integer){
-                intent.putExtra("type", (Integer) object);
+            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {//5.0才上系统才使用
+                Intent intent = new Intent(context, FloatShotScreenService.class);
+                if (object instanceof Boolean) {
+                    intent.putExtra("isShow", (Boolean) object);
+                    intent.putExtra("type", SET_SHOW_OR_HIDE);
+                } else if (object instanceof Integer) {
+                    intent.putExtra("type", (Integer) object);
+                }
+                context.startService(intent);
             }
-            context.startService(intent);
         }
     }
 

+ 19 - 0
app/src/main/java/com/sheep/gamegroup/util/PngUtil.java

@@ -0,0 +1,19 @@
+package com.sheep.gamegroup.util;
+
+/**
+ * Created by realicing on 2018/8/15.
+ * realicing@sina.com
+ */
+public class PngUtil {
+
+    // 动态导入 so 库
+    static {
+        System.loadLibrary("PngUtil");
+    }
+
+    //给png图片添加备注
+    public native static String decodePng(String filePath, String gamePackageName, String comment) throws Exception;
+    //检查是否是正版小绵羊app
+    public native static String isKfzsSheepApp();
+
+}

+ 397 - 0
app/src/main/java/com/sheep/gamegroup/util/ScreenShotListenManager.java

@@ -0,0 +1,397 @@
+package com.sheep.gamegroup.util;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.database.Cursor;
+import android.graphics.BitmapFactory;
+import android.graphics.Point;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Handler;
+import android.os.Looper;
+import android.provider.MediaStore;
+import android.text.TextUtils;
+import android.view.Display;
+import android.view.WindowManager;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+/**
+ * 截屏监听管理器 <br/><br/>
+ *
+ * <p>
+ * 截屏判断依据: 监听媒体数据库的数据改变, 在有数据改变时获取最后
+ * 插入数据库的一条图片数据, 如果符合以下规则, 则认为截屏了: <br/>
+ *
+ * 1. 时间判断, 图片的生成时间在开始监听之后, 并与当前时间相隔10秒内; <br/>
+ * 2. 尺寸判断, 图片的尺寸没有超过屏幕的尺寸; <br/>
+ * 3. 路径判断, 图片路径符合包含特定的关键词。<br/>
+ *
+ * <p>
+ * Demo:
+ * <pre> {@code
+ *
+ *      // Requires Permission: android.permission.READ_EXTERNAL_STORAGE
+ *
+ *      ScreenShotListenManager manager = ScreenShotListenManager.newInstance(context);
+ *
+ *      manager.setListener(
+ *          new OnScreenShotListener() {
+ *              public void onShot(String imagePath) {
+ *                  // do something
+ *              }
+ *          }
+ *      );
+ *
+ *      manager.startListen();
+ *      ...
+ *      manager.stopListen();
+ *
+ * }</pre>
+ *
+ * @author xietansheng
+ */
+public class ScreenShotListenManager {
+
+    private static final String TAG = "ScreenShotListenManager";
+
+    /** 读取媒体数据库时需要读取的列 */
+    private static final String[] MEDIA_PROJECTIONS =  {
+            MediaStore.Images.ImageColumns.DATA,
+            MediaStore.Images.ImageColumns.DATE_TAKEN,
+    };
+    /** 读取媒体数据库时需要读取的列, 其中 WIDTH 和 HEIGHT 字段在 API 16 以后才有 */
+    private static final String[] MEDIA_PROJECTIONS_API_16 = {
+            MediaStore.Images.ImageColumns.DATA,
+            MediaStore.Images.ImageColumns.DATE_TAKEN,
+            MediaStore.Images.ImageColumns.WIDTH,
+            MediaStore.Images.ImageColumns.HEIGHT,
+    };
+
+    /** 截屏依据中的路径判断关键字 */
+    private static final String[] KEYWORDS = {
+            "screenshot", "screen_shot", "screen-shot", "screen shot",
+            "screencapture", "screen_capture", "screen-capture", "screen capture",
+            "screencap", "screen_cap", "screen-cap", "screen cap"
+    };
+
+    private static Point sScreenRealSize;
+
+    /** 已回调过的路径 */
+    private final List<String> sHasCallbackPaths = new ArrayList<String>();
+
+    private Context mContext;
+
+    private OnScreenShotListener mListener;
+
+    private long mStartListenTime;
+
+    /** 内部存储器内容观察者 */
+    private MediaContentObserver mInternalObserver;
+
+    /** 外部存储器内容观察者 */
+    private MediaContentObserver mExternalObserver;
+
+    /** 运行在 UI 线程的 Handler, 用于运行监听器回调 */
+    private final Handler mUiHandler = new Handler(Looper.getMainLooper());
+
+    private ScreenShotListenManager(Context context) {
+        if (context == null) {
+            throw new IllegalArgumentException("The context must not be null.");
+        }
+        mContext = context;
+
+        // 获取屏幕真实的分辨率
+        if (sScreenRealSize == null) {
+            sScreenRealSize = getRealScreenSize();
+            if (sScreenRealSize != null) {
+                LogUtil.println(TAG, "Screen Real Size: " + sScreenRealSize.x + " * " + sScreenRealSize.y);
+            } else {
+                LogUtil.println(TAG, "Get screen real size failed.");
+            }
+        }
+    }
+
+    public static ScreenShotListenManager newInstance(Context context) {
+        assertInMainThread();
+        return new ScreenShotListenManager(context);
+    }
+
+    /**
+     * 启动监听
+     */
+    public void startListen() {
+        assertInMainThread();
+
+        sHasCallbackPaths.clear();
+
+        // 记录开始监听的时间戳
+        mStartListenTime = System.currentTimeMillis();
+
+        // 创建内容观察者
+        mInternalObserver = new MediaContentObserver(MediaStore.Images.Media.INTERNAL_CONTENT_URI, mUiHandler);
+        mExternalObserver = new MediaContentObserver(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, mUiHandler);
+
+        // 注册内容观察者
+        mContext.getContentResolver().registerContentObserver(
+                MediaStore.Images.Media.INTERNAL_CONTENT_URI,
+                false,
+                mInternalObserver
+        );
+        mContext.getContentResolver().registerContentObserver(
+                MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
+                false,
+                mExternalObserver
+        );
+    }
+
+    /**
+     * 停止监听
+     */
+    public void stopListen() {
+        assertInMainThread();
+
+        // 注销内容观察者
+        if (mInternalObserver != null) {
+            try {
+                mContext.getContentResolver().unregisterContentObserver(mInternalObserver);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+            mInternalObserver = null;
+        }
+        if (mExternalObserver != null) {
+            try {
+                mContext.getContentResolver().unregisterContentObserver(mExternalObserver);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+            mExternalObserver = null;
+        }
+
+        // 清空数据
+        mStartListenTime = 0;
+        sHasCallbackPaths.clear();
+    }
+
+    /**
+     * 处理媒体数据库的内容改变
+     */
+    private void handleMediaContentChange(Uri contentUri) {
+        Cursor cursor = null;
+        try {
+            // 数据改变时查询数据库中最后加入的一条数据
+            cursor = mContext.getContentResolver().query(
+                    contentUri,
+                    Build.VERSION.SDK_INT < 16 ? MEDIA_PROJECTIONS : MEDIA_PROJECTIONS_API_16,
+                    null,
+                    null,
+                    MediaStore.Images.ImageColumns.DATE_ADDED + " desc limit 1"
+            );
+
+            if (cursor == null) {
+                LogUtil.println(TAG, "Deviant logic.");
+                return;
+            }
+            if (!cursor.moveToFirst()) {
+                LogUtil.println(TAG, "Cursor no data.");
+                return;
+            }
+
+            // 获取各列的索引
+            int dataIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
+            int dateTakenIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATE_TAKEN);
+            int widthIndex = -1;
+            int heightIndex = -1;
+            if (Build.VERSION.SDK_INT >= 16) {
+                widthIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.WIDTH);
+                heightIndex = cursor.getColumnIndex(MediaStore.Images.ImageColumns.HEIGHT);
+            }
+
+            // 获取行数据
+            String data = cursor.getString(dataIndex);
+            long dateTaken = cursor.getLong(dateTakenIndex);
+            int width = 0;
+            int height = 0;
+            if (widthIndex >= 0 && heightIndex >= 0) {
+                width = cursor.getInt(widthIndex);
+                height = cursor.getInt(heightIndex);
+            } else {
+                // API 16 之前, 宽高要手动获取
+                Point size = getImageSize(data);
+                width = size.x;
+                height = size.y;
+            }
+
+            // 处理获取到的第一行数据
+            handleMediaRowData(data, dateTaken, width, height);
+
+        } catch (Exception e) {
+            e.printStackTrace();
+
+        } finally {
+            if (cursor != null && !cursor.isClosed()) {
+                cursor.close();
+            }
+        }
+    }
+
+    private Point getImageSize(String imagePath) {
+        BitmapFactory.Options options = new BitmapFactory.Options();
+        options.inJustDecodeBounds = true;
+        BitmapFactory.decodeFile(imagePath, options);
+        return new Point(options.outWidth, options.outHeight);
+    }
+
+    /**
+     * 处理获取到的一行数据
+     */
+    private void handleMediaRowData(String data, long dateTaken, int width, int height) {
+        if (checkScreenShot(data, dateTaken, width, height)) {
+            LogUtil.println(TAG, "ScreenShot: path = " + data + "; size = " + width + " * " + height
+                    + "; date = " + dateTaken);
+            if (mListener != null && !checkCallback(data)) {
+                mListener.onShot(data);
+            }
+        } else {
+            // 如果在观察区间媒体数据库有数据改变,又不符合截屏规则,则输出到 log 待分析
+            LogUtil.println(TAG, "Media content changed, but not screenshot: path = " + data
+                    + "; size = " + width + " * " + height + "; date = " + dateTaken);
+        }
+    }
+
+    /**
+     * 判断指定的数据行是否符合截屏条件
+     */
+    private boolean checkScreenShot(String data, long dateTaken, int width, int height) {
+        /*
+         * 判断依据一: 时间判断
+         */
+        // 如果加入数据库的时间在开始监听之前, 或者与当前时间相差大于10秒, 则认为当前没有截屏
+        if (dateTaken < mStartListenTime || (System.currentTimeMillis() - dateTaken) > 10 * 1000) {
+            return false;
+        }
+
+        /*
+         * 判断依据二: 尺寸判断
+         */
+        if (sScreenRealSize != null) {
+            // 如果图片尺寸超出屏幕, 则认为当前没有截屏
+            if (
+                    !(
+                            (width <= sScreenRealSize.x && height <= sScreenRealSize.y)
+                                    ||
+                                    (height <= sScreenRealSize.x && width <= sScreenRealSize.y)
+                    )) {
+                return false;
+            }
+        }
+
+        /*
+         * 判断依据三: 路径判断
+         */
+        if (TextUtils.isEmpty(data)) {
+            return false;
+        }
+        data = data.toLowerCase();
+        // 判断图片路径是否含有指定的关键字之一, 如果有, 则认为当前截屏了
+        for (String keyWork : KEYWORDS) {
+            if (data.contains(keyWork)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * 判断是否已回调过, 某些手机ROM截屏一次会发出多次内容改变的通知; <br/>
+     * 删除一个图片也会发通知, 同时防止删除图片时误将上一张符合截屏规则的图片当做是当前截屏.
+     */
+    private boolean checkCallback(String imagePath) {
+        if (sHasCallbackPaths.contains(imagePath)) {
+            return true;
+        }
+        // 大概缓存15~20条记录便可
+        if (sHasCallbackPaths.size() >= 20) {
+            for (int i = 0; i < 5; i++) {
+                sHasCallbackPaths.remove(0);
+            }
+        }
+        sHasCallbackPaths.add(imagePath);
+        return false;
+    }
+
+    /**
+     * 获取屏幕分辨率
+     */
+    private Point getRealScreenSize() {
+        Point screenSize = null;
+        try {
+            screenSize = new Point();
+            WindowManager windowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
+            Display defaultDisplay = windowManager.getDefaultDisplay();
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
+                defaultDisplay.getRealSize(screenSize);
+            } else {
+                try {
+                    Method mGetRawW = Display.class.getMethod("getRawWidth");
+                    Method mGetRawH = Display.class.getMethod("getRawHeight");
+                    screenSize.set(
+                            (Integer) mGetRawW.invoke(defaultDisplay),
+                            (Integer) mGetRawH.invoke(defaultDisplay)
+                    );
+                } catch (Exception e) {
+                    screenSize.set(defaultDisplay.getWidth(), defaultDisplay.getHeight());
+                    e.printStackTrace();
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return screenSize;
+    }
+
+    /**
+     * 设置截屏监听器
+     */
+    public void setListener(OnScreenShotListener listener) {
+        mListener = listener;
+    }
+
+    public static interface OnScreenShotListener {
+        public void onShot(String imagePath);
+    }
+
+    private static void assertInMainThread() {
+        if (Looper.myLooper() != Looper.getMainLooper()) {
+            StackTraceElement[] elements = Thread.currentThread().getStackTrace();
+            String methodMsg = null;
+            if (elements != null && elements.length >= 4) {
+                methodMsg = elements[3].toString();
+            }
+            throw new IllegalStateException("Call the method must be in main thread: " + methodMsg);
+        }
+    }
+
+    /**
+     * 媒体内容观察者(观察媒体数据库的改变)
+     */
+    private class MediaContentObserver extends ContentObserver {
+
+        private Uri mContentUri;
+
+        public MediaContentObserver(Uri contentUri, Handler handler) {
+            super(handler);
+            mContentUri = contentUri;
+        }
+
+        @Override
+        public void onChange(boolean selfChange) {
+            super.onChange(selfChange);
+            LogUtil.println(TAG, "onChange", selfChange);
+            handleMediaContentChange(mContentUri);
+        }
+    }
+}

+ 8 - 1
app/src/main/java/com/sheep/gamegroup/util/TestUtil.java

@@ -29,6 +29,7 @@ import com.sheep.gamegroup.model.util.SheepSubscriber;
 import com.sheep.gamegroup.usage.AppUsageManager;
 import com.sheep.gamegroup.view.activity.ActInstallApkList;
 import com.sheep.gamegroup.view.activity.ActSheepApkList;
+import com.sheep.gamegroup.view.activity.ActSheepPngList;
 import com.sheep.gamegroup.view.activity.ActWeb;
 import com.sheep.gamegroup.view.dialog.DialogLoading;
 import com.sheep.gamegroup.view.dialog.DialogNewbieTaskList;
@@ -285,7 +286,7 @@ public class TestUtil {
      * @param activity
      */
     public static void test(final Activity activity) {
-        final String[] items = {"审核中心","复制token","复制打点数据","loading","progress","查看截图","复制imsi","小米游戏","测试可用金额","测试定位信息","测试apk的渠道","幂动科技","游戏搜索",
+        final String[] items = {"复制token","复制打点数据","审核中心","检查正版","crc32","loading","progress","查看截图","复制imsi","小米游戏","测试可用金额","测试定位信息","测试apk的渠道","幂动科技","游戏搜索",
                 "游戏帐号","游戏代充","尝试开启第三方应用使用情况","测试代理页面","第三方应用使用情况",
                 "开启第三方应用使用情况","h5跳转","新手对话框","md5","空间不足提示框",
                 "显示已经安装应用列表","复制faq地址","复制代理地址","复制世界杯地址","任务游戏列表","世界杯活动","交通银行信用卡测试",
@@ -300,6 +301,12 @@ public class TestUtil {
                             case "审核中心":
                                 Jump2View.getInstance().goAuditTastList(activity, null);
                                 break;
+                            case "检查正版":
+                                PngUtil.isKfzsSheepApp();
+                                break;
+                            case "crc32":
+                                activity.startActivity(new Intent(activity, ActSheepPngList.class));
+                                break;
                             case "loading":
                                 DialogLoading.showDialog(activity);
                                 break;

+ 143 - 0
app/src/main/java/com/sheep/gamegroup/view/activity/ActSheepPngList.java

@@ -0,0 +1,143 @@
+package com.sheep.gamegroup.view.activity;
+
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.text.TextUtils;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.bumptech.glide.Glide;
+import com.kfzs.duanduan.react.FileUtil;
+import com.sheep.gamegroup.absBase.BaseActivity;
+import com.sheep.gamegroup.util.ListUtil;
+import com.sheep.gamegroup.util.PngUtil;
+import com.sheep.gamegroup.util.ViewHolder;
+import com.sheep.gamegroup.view.adapter.AdbCommonRecycler;
+import com.sheep.jiuyan.samllsheep.R;
+import com.sheep.jiuyan.samllsheep.SheepApp;
+import com.sheep.jiuyan.samllsheep.utils.G;
+import com.sheep.jiuyan.samllsheep.utils.TitleBarUtils;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.util.List;
+
+import butterknife.BindView;
+import butterknife.OnClick;
+
+import static com.sheep.jiuyan.samllsheep.utils.ClassFileHelper.DIR;
+
+/**
+ * Created by realicing on 2018/6/19.
+ * realicing@sina.com
+ */
+public class ActSheepPngList extends BaseActivity {
+    @Override
+    protected int getLayoutId() {
+        return R.layout.act_user_label_list;
+    }
+
+
+    @BindView(R.id.user_label_list)
+    RecyclerView user_label_list;
+
+    @BindView(R.id.user_label_commit_tv)
+    TextView user_label_commit_tv;
+
+    @Override
+    public void initView() {
+        TitleBarUtils
+                .getInstance()
+                .setTitle(this, "Sheep目录png测试")
+                .setTitleFinish(this);
+        user_label_commit_tv.setVisibility(View.GONE);
+    }
+
+    @Override
+    public void initListener() {
+
+    }
+
+    @Override
+    public void initData() {
+        loadData(getList());
+    }
+
+    private List<File> getList() {
+        File dir = new File(DIR);
+        File[] files = dir.listFiles(new FileFilter() {
+            @Override
+            public boolean accept(File file) {
+                return TextUtils.equals(FileUtil.getExtensionName(file.getName()), "png");
+            }
+        });
+        return ListUtil.asList(files);
+    }
+    private void loadData(List<File> list) {
+        user_label_list.setLayoutManager(new LinearLayoutManager(SheepApp.getInstance()));
+        user_label_list.setAdapter(new AdbCommonRecycler<File>(SheepApp.getInstance(), list){
+
+            @Override
+            public int getViewIdByType(int type) {
+                return R.layout.app_info_item;
+            }
+
+            @Override
+            public void convert(ViewHolder holder, final File item) {
+                ImageView app_info_iv = holder.itemView.findViewById(R.id.app_info_iv);
+                TextView app_info_name_tv = holder.itemView.findViewById(R.id.app_info_name_tv);
+                TextView app_info_package_name_tv = holder.itemView.findViewById(R.id.app_info_package_name_tv);
+                TextView app_info_size_tv = holder.itemView.findViewById(R.id.app_info_size_tv);
+                TextView app_info_path_tv = holder.itemView.findViewById(R.id.app_info_path_tv);
+
+                Glide.with(SheepApp.getInstance())
+                        .load(item)
+                        .into(app_info_iv);
+
+                holder.itemView.setOnClickListener(new View.OnClickListener() {
+                    @Override
+                    public void onClick(View view) {
+                        try {
+                            onClickItem(item);
+                        } catch (Exception e) {
+                            e.printStackTrace();
+                            G.showToast(e.getMessage());
+                        }
+                    }
+                });
+                holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
+                    @Override
+                    public boolean onLongClick(View view) {
+                        return true;
+                    }
+                });
+            }
+        });
+
+    }
+
+    private void onClickItem(final File file) throws Exception {
+        String iEndData = PngUtil.decodePng(file.getAbsolutePath(), "com.realicing.android.upgrade.sheep", "280;7;0");
+        if(iEndData == null){
+            G.showToast("失败");
+        } else if(TextUtils.isEmpty(iEndData)){
+            G.showToast("添加iEnd data成功");
+        } else {
+            G.showToast(iEndData);
+        }
+    }
+
+    @OnClick({R.id.user_label_commit_tv})
+    public void onViewClicked(View view) {
+        switch (view.getId()) {
+            case R.id.user_label_commit_tv:
+                toCommit();
+                break;
+        }
+    }
+
+    private void toCommit() {
+    }
+
+}

+ 7 - 6
app/src/main/java/com/sheep/gamegroup/view/activity/TaskDetailAct.java

@@ -782,7 +782,7 @@ public class TaskDetailAct extends AbsChooseImageActivity implements TaskDetailC
                 break;
         }
         if (commitScreenShotTaskId > 0) {
-            if (DataUtil.IS_USE_SCREEN_SHOT) {//小绵羊截图方案
+            if (DataUtil.IS_USE_SCREEN_SHOT || DataUtil.IS_LISTEN_SCREEN_SHOT) {//小绵羊截图方案
                 File dir = DataUtil.getInstance().getScreenShotsDir(taskEty.getPackage_names());
                 showChooseDialog(false, true, DEFAULT_MAX_COUNT, dir);
             } else {//用户手动截图方案
@@ -938,12 +938,13 @@ public class TaskDetailAct extends AbsChooseImageActivity implements TaskDetailC
 //                            onGetNetImageUrl(data);
         dismissLoaddingDialog();
         G.showToast("提交成功,等待审核!");
-        //这里领取了奖励,要刷新用户信息
-        CommonUtil.getInstance().updateUserInfo(null);
-        if (DataUtil.IS_USE_SCREEN_SHOT) {//小绵羊截图方案:上传截图成功后删除之前的截图
-            DataUtil.getInstance().clearScreenShots();
+        if (DataUtil.IS_USE_SCREEN_SHOT || DataUtil.IS_LISTEN_SCREEN_SHOT) {//小绵羊截图方案或者监听方案:上传截图成功后删除之前的截图
+            //这里领取了奖励,要刷新用户信息
+            CommonUtil.getInstance().updateUserInfo(null);
+            if (DataUtil.IS_USE_SCREEN_SHOT) {//小绵羊截图方案:上传截图成功后删除之前的截图
+                DataUtil.getInstance().clearScreenShots();
+            }
         }
-
         UMConfigUtils.finishTask();
         if (taskEty.hasCommitLast(commitScreenShotTaskId)) {//非自动审核任务中的连续任务已经提交了最后一个子任务,或者普通任务提交截图成功
             if (isFromTaskList)//之前界面为任务记录界面,需要回调刷新任务记录列表

+ 17 - 4
app/src/main/java/com/sheep/jiuyan/samllsheep/SheepApp.java

@@ -20,6 +20,7 @@ import com.sheep.gamegroup.util.ConnectAddress;
 import com.sheep.gamegroup.util.DataUtil;
 import com.sheep.gamegroup.util.Jump2View;
 import com.sheep.gamegroup.util.LogUtil;
+import com.sheep.gamegroup.util.ScreenShotListenManager;
 import com.sheep.gamegroup.util.SysAppUtil;
 import com.sheep.gamegroup.util.UMConfigUtils;
 import com.sheep.gamegroup.view.activity.LoginAct;
@@ -142,6 +143,7 @@ public class SheepApp extends BaseApplication {
      * Activity 生命周期监听,用于监控app前后台状态切换
      */
     ActivityLifecycleCallbacks activityLifecycleCallbacks = new ActivityLifecycleCallbacks() {
+        private ScreenShotListenManager manager;
         @Override
         public void onActivityCreated(final Activity activity, Bundle savedInstanceState) {
             ActivityManager.getInstance().pushActivity(activity);
@@ -163,6 +165,17 @@ public class SheepApp extends BaseApplication {
                 }
                 AppUsageManager.getInstance().needOpenLookAppUsageStatsPermisson(true);//尝试保存应用使用情况的数据
                 LogUtil.println("SheepApp onActivityCreated", mActivityCount);
+                if(DataUtil.IS_LISTEN_SCREEN_SHOT) {
+                    manager = ScreenShotListenManager.newInstance(context);
+                    manager.setListener(
+                            new ScreenShotListenManager.OnScreenShotListener() {
+                                public void onShot(String imagePath) {
+                                    DataUtil.getInstance().addPng(imagePath);
+                                }
+                            }
+                    );
+                    manager.startListen();
+                }
                 UMConfigUtils.Event.SHEEP_CREATED.onEvent();
             }
         }
@@ -177,8 +190,7 @@ public class SheepApp extends BaseApplication {
                     LogUtil.println("SheepApp onActivityStarted", mActivityCount);
                     UMConfigUtils.Event.SHEEP_STARTED.onEvent();
                     Jump2View.getInstance().startFloat(activity, false);
-                    if(DataUtil.IS_USE_SCREEN_SHOT)
-                        Jump2View.getInstance().startShotScreenFloat(activity, false);
+                    Jump2View.getInstance().startShotScreenFloat(activity, false);
                 }
             }
         }
@@ -201,8 +213,7 @@ public class SheepApp extends BaseApplication {
                     LogUtil.println("SheepApp onActivityStopped", mActivityCount);
                     UMConfigUtils.Event.SHEEP_STOPPED.onEvent();
                     Jump2View.getInstance().startFloat(activity, true);
-                    if(DataUtil.IS_USE_SCREEN_SHOT)
-                        Jump2View.getInstance().startShotScreenFloat(activity, true);
+                    Jump2View.getInstance().startShotScreenFloat(activity, true);
                 }
             }
         }
@@ -219,6 +230,8 @@ public class SheepApp extends BaseApplication {
                 stopService(new Intent(SheepApp.this, FloatService.class));
                 if(DataUtil.IS_USE_SCREEN_SHOT)
                     stopService(new Intent(SheepApp.this, FloatShotScreenService.class));
+                if(manager != null)
+                    manager.stopListen();
                 UMConfigUtils.Event.SHEEP_DESTROYED.onEvent();
             }
         }

+ 37 - 0
app/src/main/java/com/sheep/jiuyan/samllsheep/utils/FileUtil.java

@@ -1,7 +1,15 @@
 package com.sheep.jiuyan.samllsheep.utils;
 
 
+import android.support.annotation.NonNull;
+
+import com.sheep.gamegroup.util.LogUtil;
+
 import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.channels.FileChannel;
 
 /**
  * Created by realicing on 2018/6/1.
@@ -29,4 +37,33 @@ public class FileUtil {
             }
         }
     }
+
+    public static void copyFile(@NonNull File fileFrom, @NonNull File dirTo) throws IOException {
+        LogUtil.println("copyFile", fileFrom.getAbsolutePath(), dirTo.getAbsolutePath());
+        if(!dirTo.isDirectory()){
+            return;
+        }
+        if(!dirTo.exists())
+            dirTo.mkdirs();
+        File dest= new File(dirTo, fileFrom.getName());
+        if (dest.exists()) {
+            if(dest.delete()){
+                LogUtil.println("copyFile", "删除文件失败");
+            }
+        }
+        if(!dest.createNewFile()){
+            LogUtil.println("copyFile", "创建文件失败");
+        }
+        FileChannel outputChannel = null;
+        FileChannel inputChannel = null;
+        try {
+            inputChannel = new FileInputStream(fileFrom).getChannel();
+            outputChannel = new FileOutputStream(dest).getChannel();
+            inputChannel.transferTo(0, inputChannel.size(), outputChannel);
+            inputChannel.close();
+        } finally {
+            if (inputChannel != null) inputChannel.close();
+            if (outputChannel != null) outputChannel.close();
+        }
+    }
 }

+ 0 - 82
app/src/main/java/com/sheep/jiuyan/samllsheep/utils/HexUtils.java

@@ -1,82 +0,0 @@
-package com.sheep.jiuyan.samllsheep.utils;
-
-/**
- * Created by kemllor on 2018/1/22.
- */
-
-public class HexUtils {
-    private static final String HEX_STR_POOL = "0123456789ABCDEF";
-    private static StringBuffer buf = new StringBuffer();
-
-    public static byte[] hexStr2Bytes(String hexStr) {
-        if (hexStr.length() < 1) {
-            return null;
-        } else {
-            byte[] result = new byte[hexStr.length() / 2];
-
-            for (int i = 0; i < hexStr.length() / 2; ++i) {
-                int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
-                int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);
-                result[i] = (byte) (high * 16 + low);
-            }
-
-            return result;
-        }
-    }
-
-    public static byte[] hexStringToBytes(String hexString) {
-        if (hexString != null && !hexString.equals("")) {
-            hexString = hexString.toUpperCase();
-            int length = hexString.length() / 2;
-            char[] hexChars = hexString.toCharArray();
-            byte[] d = new byte[length];
-
-            for (int i = 0; i < length; ++i) {
-                int pos = i * 2;
-                byte h = charToByte(hexChars[pos]);
-                byte l = charToByte(hexChars[pos + 1]);
-                d[i] = (byte) (h << 4 | l);
-            }
-
-            return d;
-        } else {
-            return null;
-        }
-    }
-
-    private static byte charToByte(char c) {
-        return (byte) "0123456789ABCDEF".indexOf(c);
-    }
-
-    public static String bytes2HexStr(byte[] datas) {
-        if (datas != null && datas.length != 0) {
-            buf.setLength(0);
-
-            for (int i = 0; i < datas.length; ++i) {
-                if ((datas[i] & 255) < 16) {
-                    buf.append("0");
-                }
-
-                buf.append(Long.toHexString((long) (datas[i] & 255)));
-            }
-
-            return buf.toString();
-        } else {
-            return null;
-        }
-    }
-
-    public static String byte2HexStr(byte data) {
-        buf.setLength(0);
-        buf.append("0x");
-        if ((data & 255) < 16) {
-            buf.append("0");
-        }
-
-        buf.append(Long.toHexString((long) (data & 255)));
-        return buf.toString();
-    }
-
-    private HexUtils() {
-    }
-}

+ 6 - 0
app/src/main/jni/Android.mk

@@ -0,0 +1,6 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := PngUtil
+LOCAL_SRC_FILES := pngUtil.c
+include $(BUILD_SHARED_LIBRARY)

+ 1 - 0
app/src/main/jni/Application.mk

@@ -0,0 +1 @@
+APP_ABI := all

+ 29 - 0
app/src/main/jni/com_sheep_gamegroup_util_PngUtil.h

@@ -0,0 +1,29 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class com_sheep_gamegroup_util_PngUtil */
+
+#ifndef _Included_com_sheep_gamegroup_util_PngUtil
+#define _Included_com_sheep_gamegroup_util_PngUtil
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class:     com_sheep_gamegroup_util_PngUtil
+ * Method:    decodePng
+ * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_com_sheep_gamegroup_util_PngUtil_decodePng
+  (JNIEnv *, jclass, jstring, jstring, jstring);
+
+/*
+ * Class:     com_sheep_gamegroup_util_PngUtil
+ * Method:    isKfzsSheepApp
+ * Signature: ()Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_com_sheep_gamegroup_util_PngUtil_isKfzsSheepApp
+  (JNIEnv *, jclass);
+
+#ifdef __cplusplus
+}
+#endif
+#endif

+ 337 - 0
app/src/main/jni/pngUtil.c

@@ -0,0 +1,337 @@
+#include<jni.h>
+#include<stdio.h>
+#include<string.h>
+//导入我们创建的头文件
+#include "com_sheep_gamegroup_util_PngUtil.h"
+//全局获取Context
+jobject getGlobalContext(JNIEnv *env);
+//根据Context获取对应安装的apk文件的md5值
+char* getSignatureMd5(JNIEnv * env, jobject obj_package_manager, jobject obj_package_name);
+//根据Context获取对应安装的apk文件的hashCode值
+//jint getSignatureHashCode(JNIEnv* env, jobject obj_package_manager, jobject obj_package_name);
+// 字节流转换为十六进制字符串
+void ByteToHexStr(const unsigned char* source, char* dest, int sourceLen);
+//调用android toast
+void android_toast(JNIEnv *env, jobject context, jstring str);
+//判断java String 与c String 是否相同
+int j_str_cmp_c_str(JNIEnv *env, jstring jStr, char* cStr);
+//合并字符串
+jstring android_string_concat(JNIEnv *env, jstring jStr, char* cStr);
+//合并字符串
+jstring android_string_concat_string(JNIEnv *env, jstring jStr, jstring jStr2);
+//根据Context获取PackageManager
+jobject getPackageManager(JNIEnv * env, jobject context);
+//根据Context获取对应的包名
+jobject getPackageName(JNIEnv * env, jobject context);
+
+/*
+ * cd app\src\main
+ * ndk-build
+ * Class:     com_sheep_gamegroup_util_PngUtil
+ * Method:    isKfzsSheepApp
+ * Signature: ()Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_com_sheep_gamegroup_util_PngUtil_isKfzsSheepApp
+  (JNIEnv *env, jclass jclassp){
+        jobject context = getGlobalContext(env);
+        if(context == NULL){
+            return (*env)->NewStringUTF(env, "error context is NULL");
+        }
+        jobject obj_package_manager = getPackageManager(env, context);
+        jobject obj_package_name = getPackageName(env, context);
+        char* md5 = getSignatureMd5(env, obj_package_manager, obj_package_name);
+        //result已经释放
+        if(strcmp(md5, "C69316882EADA62AE560C31076740400")  == 0){
+            android_toast(env, context, (*env)->NewStringUTF(env, "恭喜,您使用的是正版小绵羊!"));
+        } else {
+            android_toast(env, context, (*env)->NewStringUTF(env, "注意,您使用的不是正版小绵羊!"));
+            return (*env)->NewStringUTF(env, "error this is pirate app");
+        }
+        return NULL;
+  }
+/*
+ * Class:     com_sheep_gamegroup_util_PngUtil
+ * Method:    decodePng
+ * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_com_sheep_gamegroup_util_PngUtil_decodePng
+  (JNIEnv *env, jclass jclassp, jstring filePath, jstring gamePackageName, jstring comment){
+        jobject context = getGlobalContext(env);
+        if(context == NULL){
+            return (*env)->NewStringUTF(env, "error context is NULL");
+        }
+        jobject obj_package_manager = getPackageManager(env, context);
+        jobject obj_package_name = getPackageName(env, context);
+        char* md5 = getSignatureMd5(env, obj_package_manager, obj_package_name);
+        //result已经释放
+        if(strcmp(md5, "C69316882EADA62AE560C31076740400")  == 0){
+    //        android_toast(env, context, (*env)->NewStringUTF(env, "恭喜,您使用的是正版小绵羊!"));
+        } else {
+//            android_toast(env, context, (*env)->NewStringUTF(env, "注意,您使用的不是正版小绵羊!"));
+            return (*env)->NewStringUTF(env, "error this is pirate app");
+        }
+        char* gameMd5 = getSignatureMd5(env, obj_package_manager, gamePackageName);
+
+        //加密文本内容:包名;签名md5;试玩应用包名;试玩应用签名md5;任务id;图片总数;图片位置
+
+        jstring result_a;
+        jstring result_b;
+        result_a = android_string_concat(env, obj_package_name, ";");
+        (*env)->DeleteLocalRef(env, obj_package_name);
+        result_b = android_string_concat(env, result_a, md5);
+        (*env)->DeleteLocalRef(env, result_a);
+        result_a = android_string_concat(env, result_b, ";");
+        (*env)->DeleteLocalRef(env, result_b);
+        result_b = android_string_concat_string(env, result_a, gamePackageName);
+        (*env)->DeleteLocalRef(env, result_a);
+        result_a = android_string_concat(env, result_b, ";");
+        (*env)->DeleteLocalRef(env, result_b);
+        result_b = android_string_concat(env, result_a, gameMd5);
+        (*env)->DeleteLocalRef(env, result_a);
+        result_a = android_string_concat(env, result_b, ";");
+        (*env)->DeleteLocalRef(env, result_b);
+
+        result_b = android_string_concat_string(env, result_a, comment);
+        (*env)->DeleteLocalRef(env, result_a);
+//        android_toast(env, context, result_b);
+
+        //rsa公钥加密
+        jclass kfzssafeClass = (*env)->FindClass(env, "go/kfzssafe/Kfzssafe");
+        jmethodID publicEncryptMethodID = (*env)->GetStaticMethodID(env, kfzssafeClass,"publicEncrypt","(Ljava/lang/String;)Ljava/lang/String;");
+        result_a = (*env)->CallStaticObjectMethod(env, kfzssafeClass, publicEncryptMethodID, result_b);
+        (*env)->DeleteLocalRef(env, result_b);
+
+//        JNIDecodePngUtil.addIEndData(file, result_a);
+
+        jmethodID addIEndDataMethodID = (*env)->GetStaticMethodID(env, kfzssafeClass,"addIEndData2","(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
+        jstring result = (*env)->CallStaticObjectMethod(env, kfzssafeClass, addIEndDataMethodID, filePath, result_a);
+        (*env)->DeleteLocalRef(env, result_a);
+
+
+
+        free(md5);
+        free(gameMd5);
+        (*env)->DeleteLocalRef(env, gamePackageName);
+        (*env)->DeleteLocalRef(env, obj_package_manager);
+        (*env)->DeleteLocalRef(env, context);
+        return result;
+  }
+//合并字符串
+jstring android_string_concat(JNIEnv *env, jstring jStr, char* cStr){
+    jclass String_clazz = (*env)->FindClass(env, "java/lang/String");
+    jmethodID concat_methodID = (*env)->GetMethodID(env, String_clazz, "concat", "(Ljava/lang/String;)Ljava/lang/String;");
+    //需要在后面拼接的字符串...
+    jstring strEnd = (*env)->NewStringUTF(env, cStr);
+    jstring result = (*env)->CallObjectMethod(env, jStr, concat_methodID, strEnd);
+    //释放内存
+    (*env)->DeleteLocalRef(env, strEnd);
+    return result;
+}
+//合并字符串
+jstring android_string_concat_string(JNIEnv *env, jstring jStr, jstring jStr2){
+    jclass String_clazz = (*env)->FindClass(env, "java/lang/String");
+    jmethodID concat_methodID = (*env)->GetMethodID(env, String_clazz, "concat", "(Ljava/lang/String;)Ljava/lang/String;");
+    jstring result = (*env)->CallObjectMethod(env, jStr, concat_methodID, jStr2);
+    return result;
+}
+  //判断java String 与c String 是否相同
+int j_str_cmp_c_str(JNIEnv *env, jstring jStr, char* cStr){
+    const char *jStrToCStr = (*env)->GetStringUTFChars(env, jStr, 0);
+    int result = strcmp(jStrToCStr, cStr);
+    (*env)->ReleaseStringUTFChars(env, jStr, jStrToCStr);
+    return result;
+}
+//调用android toast
+void android_toast(JNIEnv *env, jobject context, jstring str){
+    jclass tclss = (*env)->FindClass(env, "android/widget/Toast");
+     jmethodID mid = (*env)->GetStaticMethodID(env, tclss,"makeText","(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;");
+     jobject job = (*env)->CallStaticObjectMethod(env, tclss,mid,context,str);
+     jmethodID showId = (*env)->GetMethodID(env, tclss,"show","()V");
+     (*env)->CallVoidMethod(env, job,showId,context,str);
+}
+//获取Context
+jobject getGlobalContext(JNIEnv *env)
+{
+    //获取Activity Thread的实例对象
+    jclass activityThread = (*env)->FindClass(env, "android/app/ActivityThread");
+    jmethodID currentActivityThread = (*env)->GetStaticMethodID(env, activityThread, "currentActivityThread", "()Landroid/app/ActivityThread;");
+    jobject at = (*env)->CallStaticObjectMethod(env, activityThread, currentActivityThread);
+    //获取Application,也就是全局的Context
+    jmethodID getApplication = (*env)->GetMethodID(env, activityThread, "getApplication", "()Landroid/app/Application;");
+    jobject context = (*env)->CallObjectMethod(env, at, getApplication);
+    return context;
+}
+
+// 字节流转换为十六进制字符串
+//http://blog.csdn.net/pingd/article/details/41945417
+void ByteToHexStr(const unsigned char* source, char* dest, int sourceLen)
+{
+    short i;
+    unsigned char highByte, lowByte;
+
+    for (i = 0; i < sourceLen; i++)
+    {
+        highByte = source[i] >> 4;
+        lowByte = source[i] & 0x0f;
+
+        highByte += 0x30;
+
+        if (highByte > 0x39)
+                dest[i * 2] = highByte + 0x07;
+        else
+                dest[i * 2] = highByte;
+
+        lowByte += 0x30;
+        if (lowByte > 0x39)
+            dest[i * 2 + 1] = lowByte + 0x07;
+        else
+            dest[i * 2 + 1] = lowByte;
+    }
+    return;
+}
+//根据Context获取PackageManager
+jobject getPackageManager(JNIEnv * env, jobject context) {
+    jclass class_context = (*env)->GetObjectClass(env, context);
+    jmethodID tem_method = (*env)->GetMethodID(env, class_context, "getPackageManager", "()Landroid/content/pm/PackageManager;");
+    jobject obj_package_manager = (*env)->CallObjectMethod(env, context, tem_method);
+    return obj_package_manager;
+}
+//根据Context获取对应的包名
+jobject getPackageName(JNIEnv * env, jobject context) {
+    jclass class_context = (*env)->GetObjectClass(env, context);
+    // getPackageName
+    jmethodID tem_method = (*env)->GetMethodID(env, class_context, "getPackageName", "()Ljava/lang/String;");
+    jobject obj_package_name = (*env)->CallObjectMethod(env, context, tem_method);
+    return obj_package_name;
+}
+//根据Context获取对应安装的apk文件的md5值
+//TODO 这个方法中,获取PackageInfo可能会报错,直接挂掉,因为没有安装应用
+char* getSignatureMd5(JNIEnv * env, jobject obj_package_manager, jobject obj_package_name) {
+    jclass tem_class;
+    jmethodID tem_method;
+    // getPackageInfo
+    tem_class = (*env)->GetObjectClass(env, obj_package_manager);
+    tem_method = (*env)->GetMethodID(env, tem_class, "getPackageInfo", "(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");
+    jobject obj_package_info = (*env)->CallObjectMethod(env, obj_package_manager, tem_method, obj_package_name, 64);
+
+    // Signature[] arrayOfSignature = localPackageInfo.signatures;
+    // Signature localSignature = arrayOfSignature[0];
+    tem_class = (*env)->GetObjectClass(env, obj_package_info);
+    jfieldID fieldID_signatures = (*env)->GetFieldID(env, tem_class, "signatures", "[Landroid/content/pm/Signature;");
+    jobjectArray signatures = (*env)->GetObjectField(env, obj_package_info, fieldID_signatures);
+    jobject signature = (*env)->GetObjectArrayElement(env, signatures, 0);
+    // localSignature.toByteArray()
+    tem_class = (*env)->GetObjectClass(env, signature);
+    tem_method = (*env)->GetMethodID(env, tem_class, "toByteArray", "()[B");
+    jobject obj_sign_byte_array = (*env)->CallObjectMethod(env, signature, tem_method);// 这个就是拿到的签名byte数组
+
+    //      MessageDigest localMessageDigest = MessageDigest.getInstance("MD5");
+    jclass class_MessageDigest = (*env)->FindClass(env, "java/security/MessageDigest");
+    tem_method = (*env)->GetStaticMethodID(env, class_MessageDigest, "getInstance", "(Ljava/lang/String;)Ljava/security/MessageDigest;");
+    jobject obj_md5 = (*env)->CallStaticObjectMethod(env, class_MessageDigest, tem_method, (*env)->NewStringUTF(env, "md5"));
+    //      localMessageDigest.update(localSignature.toByteArray());
+    //tem_class = (*env)->GetObjectClass(env, obj_md5);
+    tem_method = (*env)->GetMethodID(env, class_MessageDigest, "update", "([B)V");// 这个函数的返回值是void,写V
+    (*env)->CallVoidMethod(env, obj_md5, tem_method, obj_sign_byte_array);
+    // localMessageDigest.digest()
+    tem_method = (*env)->GetMethodID(env, class_MessageDigest, "digest", "()[B");
+    // 这个是md5以后的byte数组,现在只要将它转换成16进制字符串,就可以和之前的比较了
+    jobject obj_array_sign = (*env)->CallObjectMethod(env, obj_md5, tem_method);// jni中有强转类型的概念吗
+    //      // 这个就是签名的md5值
+    //      String str2 = toHex(localMessageDigest.digest());
+
+    // 尝试用c写一下:http://blog.csdn.net/pingd/article/details/41945417
+    jsize int_array_length = (*env)->GetArrayLength(env, obj_array_sign);
+    jbyte* byte_array_elements = (*env)->GetByteArrayElements(env, obj_array_sign, JNI_FALSE);
+    char* char_result = (char*) malloc(int_array_length*2+1);// 开始没有+1,在有的情况下会越界产生问题,还是在后面补上\0比较好
+    // 将byte数组转换成16进制字符串,发现这里不用强转,jbyte和unsigned char应该字节数是一样的
+    ByteToHexStr(byte_array_elements, char_result, int_array_length);
+    *(char_result+int_array_length*2) = '\0';// 在末尾补\0
+    // release
+    (*env)->ReleaseByteArrayElements(env, obj_array_sign, byte_array_elements, JNI_ABORT);
+    return char_result;
+
+
+    //java code=======================================================
+    //      PackageInfo localPackageInfo = context.getPackageManager()
+    //              .getPackageInfo(context.getPackageName(), 64);
+    //      StringBuilder localStringBuilder = new StringBuilder();
+    //      Signature[] arrayOfSignature = localPackageInfo.signatures;
+    //      Signature localSignature = arrayOfSignature[0];
+    //      MessageDigest localMessageDigest = MessageDigest.getInstance("MD5");
+    //      localMessageDigest.update(localSignature.toByteArray());
+    //      // 这个就是签名的md5值
+    //      String str2 = toHex(localMessageDigest.digest());
+    //      localStringBuilder.append("Signature of ")
+    //              .append(localPackageInfo.packageName).append('\n').append(str2);
+    //      System.out.println(localStringBuilder.toString());
+    //      TextView tv = (TextView) findViewById(R.id.tv);
+    //      tv.setText(localStringBuilder.toString());
+
+
+    //  private String toHex(byte[] paramArrayOfByte) {
+    //      StringBuffer localStringBuffer = new StringBuffer();
+    //      for (int i = 0; i < paramArrayOfByte.length; i++) {
+    //          Object[] arrayOfObject = new Object[1];
+    //          arrayOfObject[0] = Byte.valueOf(paramArrayOfByte[i]);
+    //          localStringBuffer.append(String.format("%02x", arrayOfObject));
+    //      }
+    //      return localStringBuffer.toString();
+    //  }
+    //java code======================================================
+}
+/**
+*校验APP包名和签名是否合法返回值为1表示合法
+*/
+// jint getSignatureHashCode(JNIEnv* env, jobject packageManager, jobject application_package){
+//	// //获得PackageManager类
+//	jclass packageManager_clazz=(*env)->GetObjectClass(env,packageManager);
+//
+//	//得到getPackageInfo方法的ID
+//	jmethodID methodID_getPackageInfo=(*env)->GetMethodID(env,packageManager_clazz,"getPackageInfo",
+//						"(Ljava/lang/String;I)Landroid/content/pm/PackageInfo;");
+//
+//	// //得到getPackageName方法的ID
+//	jmethodID methodID_getPackageName = (*env)->GetMethodID(env,context_clazz,"getPackageName","()Ljava/lang/String;");
+//
+//
+//	//获得PackageInfo
+//	jobject packageInfo = (*env)->CallObjectMethod(env,packageManager,methodID_getPackageInfo,application_package,64);
+//	jclass packageinfo_clazz = (*env)->GetObjectClass(env,packageInfo);
+//
+//	//获取签名
+//	jfieldID fieldID_signatures = (*env)->GetFieldID(env,packageinfo_clazz,"signatures","[Landroid/content/pm/Signature;");
+//	jobjectArray signature_arr = (jobjectArray)(*env)->GetObjectField(env,packageInfo,fieldID_signatures);
+//
+//	//Signature数组中取出第一个元素
+//	jobject signature = (*env)->GetObjectArrayElement(env,signature_arr,0);
+//
+//	//读signature的hashcode
+//	jclass signature_clazz = (*env)->GetObjectClass(env,signature);
+//	jmethodID methodID_hashcode = (*env)->GetMethodID(env,signature_clazz,"hashCode","()I");
+//	jint hashCode = (*env)->CallIntMethod(env,signature,methodID_hashcode);
+//
+//	return hashCode;
+////	public class SignatureUtils {
+////        public static int getSignatureHashCode(Context context){
+////            Signature signature = getSignature(context);
+////            int hashCode = signature.hashCode();
+////            return hashCode;
+////        }
+////        public static Signature getSignature(Context argContext) {
+////            Signature signature = null;
+////            try {
+////                String packageName = argContext.getPackageName();
+////                PackageManager packageManager = argContext.getPackageManager();
+////                PackageInfo packageInfo = packageManager.getPackageInfo(packageName,packageManager.GET_SIGNATURES);
+////                Signature[] signatures = packageInfo.signatures;
+////                signature = signatures[0];
+////            } catch (PackageManager.NameNotFoundException e) {
+////                e.printStackTrace();
+////            }
+////            return signature;
+////        }
+////    }
+//
+//}
+

BIN
app/src/main/jniLibs/arm64-v8a/libindoor.so


BIN
app/src/main/jniLibs/arm64-v8a/libjcore120.so


BIN
app/src/main/jniLibs/arm64-v8a/liblocSDK7b.so


BIN
app/src/main/jniLibs/arm64-v8a/libsecurityenv.so


BIN
app/src/main/jniLibs/armeabi-v7a/libindoor.so


BIN
app/src/main/jniLibs/armeabi-v7a/libjcore120.so


BIN
app/src/main/jniLibs/armeabi-v7a/liblocSDK7b.so


BIN
app/src/main/jniLibs/armeabi-v7a/libsecurityenv.so


BIN
app/src/main/jniLibs/armeabi/libindoor.so


BIN
app/src/main/jniLibs/armeabi/libjcore120.so


BIN
app/src/main/jniLibs/armeabi/liblocSDK7b.so


BIN
app/src/main/jniLibs/armeabi/libsecurityenv.so


BIN
app/src/main/jniLibs/mips/libjcore120.so


BIN
app/src/main/jniLibs/mips64/libjcore120.so


BIN
app/src/main/jniLibs/x86/libindoor.so


BIN
app/src/main/jniLibs/x86/libjcore120.so


BIN
app/src/main/jniLibs/x86/liblocSDK7b.so


BIN
app/src/main/jniLibs/x86/libsecurityenv.so


BIN
app/src/main/jniLibs/x86_64/libindoor.so


BIN
app/src/main/jniLibs/x86_64/libjcore120.so


BIN
app/src/main/jniLibs/x86_64/liblocSDK7b.so


BIN
app/src/main/libs/arm64-v8a/libPngUtil.so


BIN
app/src/main/libs/armeabi-v7a/libPngUtil.so


BIN
app/src/main/libs/armeabi/libPngUtil.so


BIN
app/src/main/libs/mips/libPngUtil.so


BIN
app/src/main/libs/mips64/libPngUtil.so


BIN
app/src/main/libs/x86/libPngUtil.so


BIN
app/src/main/libs/x86_64/libPngUtil.so


+ 3 - 1
gradle.properties

@@ -33,4 +33,6 @@ POM_LICENCE_NAME=The Apache Software License, Version 2.0
 POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0
 POM_LICENCE_DIST=repo
 POM_DEVELOPER_ID=yalantis
-POM_DEVELOPER_NAME=Yalantis
+POM_DEVELOPER_NAME=Yalantis
+
+android.useDeprecatedNdk=true