• 监听Android系统截屏


    公司的项目由于安全需要,对某一特定的页面需要监听是否被用户截屏了。

    简单搜了一下,很少有这方面的问题,没办法,只能自己折腾了。

    目前想到三种思路:

    1、监听广播

    当然,前提是系统在截屏的时候发送某一广播,然而并没有。

    2、监听按键

    Android手机按下“电源键+音量减”会进行截屏,此外大部分手机状态栏下拉的页面中也会有截屏按钮。遗憾的是,监听这两处的操作并不是一件让人开心的事儿~~。

    3、监听手机中图片的变化

    开始只想到了MediaStore这个类,可以通过它拿到手机中的所有图片,每隔一段时间监听图片数量。这似乎是个不错的主意,直到我转角遇到了ContentObserver。

    从名字就可以知道,它是一个内容观察者。通过给ContentProvider注册ContentObserver,可以实现对数据的监听。

    [java] view plain copy
     
     在CODE上查看代码片派生到我的代码片
    1. public class ScreenshotContentObserver extends ContentObserver {  
    2.   
    3.     private Context mContext;  
    4.     private int imageNum;  
    5.   
    6.     private static ScreenshotContentObserver instance;  
    7.   
    8.     private ScreenshotContentObserver(Context context) {  
    9.         super(null);  
    10.         mContext = context;  
    11.     }  
    12.   
    13.     public static void startObserve() {  
    14.         if (instance == null) {  
    15.             instance = new ScreenshotContentObserver(Facade.context());  
    16.         }  
    17.         instance.register();  
    18.     }  
    19.   
    20.     public static void stopObserve() {  
    21.         instance.unregister();  
    22.     }  
    23.   
    24.     private void register() {  
    25.         mContext.getContentResolver().registerContentObserver(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, false, this);  
    26.     }  
    27.   
    28.     private void unregister() {  
    29.         mContext.getContentResolver().unregisterContentObserver(this);  
    30.     }  
    31.   
    32.     @Override  
    33.     public void onChange(boolean selfChange) {  
    34.         super.onChange(selfChange);  
    35.         String[] columns = {  
    36.                 MediaStore.MediaColumns.DATE_ADDED,  
    37.                 MediaStore.MediaColumns.DATA,  
    38.         };  
    39.         Cursor cursor = null;  
    40.         try {  
    41.             cursor = mContext.getContentResolver().query(  
    42.                     MediaStore.Images.Media.EXTERNAL_CONTENT_URI,  
    43.                     columns,  
    44.                     null,  
    45.                     null,  
    46.                     MediaStore.MediaColumns.DATE_MODIFIED + " desc");  
    47.             if (cursor == null) {  
    48.                 return;  
    49.             }  
    50.             int count = cursor.getCount();  
    51.             if (imageNum == 0) {  
    52.                 imageNum = count;  
    53.             } else if (imageNum >= count) {  
    54.                 return;  
    55.             }  
    56.             imageNum = count;  
    57.             if (cursor.moveToFirst()) {  
    58.                 String filePath = cursor.getString(cursor.getColumnIndex(MediaStore.MediaColumns.DATA));  
    59.                 long addTime = cursor.getLong(cursor.getColumnIndex(MediaStore.MediaColumns.DATE_ADDED));  
    60.                 if (matchAddTime(addTime) && matchPath(filePath) && matchSize(filePath)) {  
    61.                     doReport(filePath);  
    62.                 }  
    63.             }  
    64.         } catch (Exception e) {  
    65.             e.printStackTrace();  
    66.         } finally {  
    67.             if (cursor != null) {  
    68.                 try {  
    69.                     cursor.close();  
    70.                 } catch (Exception e) {  
    71.                     e.printStackTrace();  
    72.                 }  
    73.             }  
    74.         }  
    75.     }  
    76.   
    77.     /** 
    78.      * 添加时间与当前时间不超过1.5s,大部分时候不超过1s。 
    79.      * 
    80.      * @param addTime 图片添加时间,单位:秒 
    81.      */  
    82.     private boolean matchAddTime(long addTime) {  
    83.         return System.currentTimeMillis() - addTime * 1000 < 1500;  
    84.     }  
    85.   
    86.     /** 
    87.      * 尺寸不大于屏幕尺寸(发现360奇酷手机可以对截屏进行裁剪) 
    88.      */  
    89.     private boolean matchSize(String filePath) {  
    90.         Point size = Util.getScreenWidthAndHeight(mContext);//获取屏幕尺寸  
    91.   
    92.         BitmapFactory.Options options = new BitmapFactory.Options();  
    93.         options.inJustDecodeBounds = true;  
    94.         BitmapFactory.decodeFile(filePath, options);  
    95.   
    96.         return size.x >= options.outWidth && size.y >= options.outHeight;  
    97.     }  
    98.   
    99.     /** 
    100.      * 已调查的手机截屏图片的路径中带有screenshot 
    101.      */  
    102.     private boolean matchPath(String filePath) {  
    103.         String lower = filePath.toLowerCase();  
    104.         return lower.contains("screenshot");  
    105.     }  
    106.   
    107.     private void doReport(String filePath) {  
    108.         //删除截屏  
    109.         File file = new File(filePath);  
    110.         file.delete();  
    111.         //TODO:  
    112.     }  
    113. }  


    上面通过register()和unregister()两个静态方法进行监听器的注册和反注册。建议在onStart()方法中进行注册,在onStop()方法中进行反注册,因为截屏并不会引起当前页面生命周期的变化。

    在onChange()回调方法中,通过查询,拿到最近添加的那张图片,从创建时间、尺寸、路径3个方面进行匹配,判断是否是截屏图片。

    • 创建时间:大多时候,截屏图片的创建时间和当前系统时间不超过1000ms
    • 图片尺寸:大多数手机截屏之后,直接保存图片,所以尺寸和屏幕尺寸一致。但有些手机,比如360奇酷手机,截屏后允许用户裁剪。所以图片尺寸的判断放宽到不大于屏幕尺寸
    • 图片路径:目前,大多数手机的截屏路径中包含“screenshot”,还未发现例外

    匹配成功后,就可以在doReport中做自己想做的事了~~

  • 相关阅读:
    Vmware 可用的激活码
    查询某网址的百度收藏量
    SQL 分页实现
    JS 分页实现
    分页逻辑分析
    Mysql总结概述
    解析select *
    teradata中EXPLAIN执行计划总结
    Teradata Join类型
    Teradata中join总结
  • 原文地址:https://www.cnblogs.com/tonny-li/p/5725620.html
Copyright © 2020-2023  润新知