2

我正在尝试检测Android应用的屏幕截图。 我使用contentObserver检测在媒体目录的变化,在Android上不使用FileObserver因为known issue它M.Android | contentObserver |内容URI不包含资源ID

这里是代码片段:

handlerThread = new HandlerThread("content_observer"); 
    handlerThread.start(); 
    final Handler handler = new Handler(handlerThread.getLooper()) { 
     @Override 
     public void handleMessage(Message msg) { 
      super.handleMessage(msg); 
     } 
    }; 

    getContentResolver().registerContentObserver(
      MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 
      true, 
      new ContentObserver(handler) { 
       @Override 
       public void onChange(boolean selfChange, Uri uri) { 
        Log.d(TAG, "URL : " + uri.toString()); 

        //Code to query using content resolver 
        if (uri.toString().matches(MediaStore.Images.Media.EXTERNAL_CONTENT_URI.toString())) { 

         Cursor cursor = null; 
         try { 
          cursor = getContentResolver().query(uri, new String[] { 
            MediaStore.Images.Media.DISPLAY_NAME, 
            MediaStore.Images.Media.DATA 
          }, null, null, null); 
          if (cursor != null && cursor.moveToFirst()) {   
          //Logic to filter if it is a screenshot file 
          } 
         } finally { 
          if (cursor != null) { 
           cursor.close(); 
          } 
         } 
        } 
        super.onChange(selfChange, uri); 
       } 
      } 
    ); 

的onChange时被调用(截图后/媒体文件夹中的任何其他改变)URI是“content:// media/external/images/media”而不是包含资源ID的整个URI,如:content:// media /外部/图像/媒体/ 12345,这发生在我尝试的大多数设备 - Moto G3(Androi d 6.0.1),Nexus 5(Android 6.0),在那里,我得到了运行6.0.1的三星S5上的整个URI(包括ID)。

这是已知问题吗?

我怎样才能得到身份证?

这不是一个优化的解决方案,它可以遍历整个媒体目录,并在应用程序处于活动状态时查找是否获取屏幕截图,而是通过内容URI获取资源ID将解决问题,因为我们可以直接获取文件路径并检测它是否为屏幕截图文件,但观察者仍然会观察所有媒体内容更改(例如,它也会观察在后台发生的WhatsApp图像下载)。

回答

2

不幸的是,我认为在插入到MediaStore中指定的表格后,您将无法指望收到正确的Uri

这是(来自here截取)的Android 5.1.1 MediaProvider#insert()方法的来源:

@Override 
public Uri insert(Uri uri, ContentValues initialValues) { 
    int match = URI_MATCHER.match(uri); 

    ArrayList<Long> notifyRowIds = new ArrayList<Long>(); 
    Uri newUri = insertInternal(uri, match, initialValues, notifyRowIds); 
    notifyMtp(notifyRowIds); 

    // do not signal notification for MTP objects. 
    // we will signal instead after file transfer is successful. 
    if (newUri != null && match != MTP_OBJECTS) { 
     getContext().getContentResolver().notifyChange(uri, null); 
    } 
    return newUri; 
} 

注意这一行:getContext().getContentResolver().notifyChange(uri, null)

以上意味着在插入MediaProvider时,会发送指定插入的Uri的通知,该通知始终是“目录”Uri。这可能是一个错误:如果不是uri,他们会使用newUri - 它的工作原理与您预期的一样。

如果它在三星的棉花糖上工作,那么这是固定在Android 6+,或三星固定在他们的AOSP构建。但我不认为你真的可以依靠这个来可靠地工作。