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構建。但我不認爲你真的可以依靠這個來可靠地工作。