2015-04-14 33 views
11

Şu anda Android için bir uygulama geliştiriyorum ve bir ekran görüntüsünün nasıl algılanacağını öğrenmek istedim. FileObserver ile çalıştım ama sorun tüm olayların algılanmasıdır (cihaz uykuya geçtiğinde, mesaj, vb.). Sadece ekran görüntüsünü nasıl algılayabilirim?FileObserver Android ile sadece ekran görüntüsünü tespit edin

Teşekkürler!

cevap

15

Ekran görüntüsü oluşturmayı algılamak için FileObserver'u nasıl kullandınız? FileObserver kullanırken, yalnızca ekran görüntüsü oluşturma dizinindeki dosya oluşturma olayını izleyin. SD karttaki içeriğe erişmek için ilgili izinleri bildirmeyi unutmayın. ekran görüntüsü sonra sistem ortam veri tabanında yerleştirilen bir kayıt olacaktır, çünkü

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> 

Diğer bir çözüm

, ekran görüntüsü ContentObserver kullanarak tespit etmek. Olayı izlemek için ContentObserver'u kullanan kod snippet'i aşağıdadır. ContentObserver kullanarak, write/read external storage izinlerini bildirmek gerekli değildir, ancak bir ekran görüntüsü olayı olduğundan emin olmak için dosya adında bazı filtreler yapmanız gerekir.
HandlerThread 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 boolean deliverSelfNotifications() { 
        Log.d(TAG, "deliverSelfNotifications"); 
        return super.deliverSelfNotifications(); 
       } 

       @Override 
       public void onChange(boolean selfChange) { 
        super.onChange(selfChange); 
       } 

       @Override 
       public void onChange(boolean selfChange, Uri uri) { 
        Log.d(TAG, "onChange " + uri.toString()); 
        if (uri.toString().matches(MediaStore.Images.Media.EXTERNAL_CONTENT_URI.toString() + "/[0-9]+")) { 

         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()) { 
           final String fileName = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME)); 
           final String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA)); 
           // TODO: apply filter on the file name to ensure it's screen shot event 
           Log.d(TAG, "screen shot added " + fileName + " " + path); 
          } 
         } finally { 
          if (cursor != null) { 
           cursor.close(); 
          } 
         } 
        } 
        super.onChange(selfChange, uri); 
       } 
      } 
    ); 

aksi takdirde SecurityException atacağım, sen sürümü Android M sonra READ_EXTERNAL_STORAGE istemek zorunda,

ikinci yöntemi kullanırsanız güncellendi. Çalışma zamanı izni isteme konusunda daha fazla bilgi için, bkz. here.

+1

'FileObserver' iş için beni değil, ContentProvider yolu çalışmaları • , biraz değişiklik gerektirmesine rağmen. Bu "onChange" etkinliğine neden olan en son görüntüyü almak için "DESC" siparişiyle sorgu görüntüsü içeriğine ihtiyacımız var. okuma com.android.providers.media.MediaProvider uri içerik:: İzin Denial: istisna "java.lang.SecurityException veren – Piasy

+0

ContentObserver pid = 31855 den // medya/harici/görüntü/medya, uid = 10341 android.permission gerektirir. READ_EXTERNAL_STORAGE veya grantUriPermission() ", Depolama İzni MARSHMELLOW – shanraisshan

+0

@ ssrais'te verilmiyorsa Evet, Android M'de çalışma zamanı iznini kontrol etmeli ve sormalısınız. Lütfen http://developer.android.com/training/permissions/ Daha fazla bilgi için requesting.html. – alijandro

0

Android ekran görüntüsü için git projesini yaptım.

İçerik Gözlemcisi kullandım.

- (> ekran görüntüsü alınmış bilgilendirmek ve ekran bitmap vermek orijinal ekran görüntüsü silme) Son Sürüm

için API 14 ince çalışma

Sen here



1.ScreenShotContentObserver .class
kontrol edebilirsiniz

public class ScreenShotContentObserver extends ContentObserver { 


private final String TAG = this.getClass().getSimpleName(); 
private static final String[] PROJECTION = new String[]{ 
     MediaStore.Images.Media.DISPLAY_NAME, MediaStore.Images.Media.DATA, 
     MediaStore.Images.Media.DATE_ADDED, MediaStore.Images.ImageColumns._ID 
}; 
private static final long DEFAULT_DETECT_WINDOW_SECONDS = 10; 
private static final String SORT_ORDER = MediaStore.Images.Media.DATE_ADDED + " DESC"; 

public static final String FILE_POSTFIX = "FROM_ASS"; 
private static final String WATERMARK = "Scott"; 
private ScreenShotListener mListener; 
private ContentResolver mContentResolver; 
private String lastPath; 

public ScreenShotContentObserver(Handler handler, ContentResolver contentResolver, ScreenShotListener listener) { 
    super(handler); 
    mContentResolver = contentResolver; 
    mListener = listener; 
} 

@Override 
public boolean deliverSelfNotifications() { 
    Log.e(TAG, "deliverSelfNotifications"); 
    return super.deliverSelfNotifications(); 
} 

@Override 
synchronized public void onChange(boolean selfChange) { 
    super.onChange(selfChange); 
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { 
     //above API 16 Pass~!(duplicated call...) 
     return; 
    } 
    Log.e(TAG, "[Start] onChange : " + selfChange); 
    try { 
     process(MediaStore.Images.Media.EXTERNAL_CONTENT_URI); 
     Log.e(TAG, "[Finish] general"); 
    } catch (Exception e) { 
     Log.e(TAG, "[Finish] error : " + e.toString(), e); 
    } 
} 

@Override 
synchronized public void onChange(boolean selfChange, Uri uri) { 
    super.onChange(selfChange, uri); 
    Log.e(TAG, "[Start] onChange : " + selfChange + "/uri : " + uri.toString()); 

    if (uri.toString().startsWith(MediaStore.Images.Media.EXTERNAL_CONTENT_URI.toString())) { 
     try { 
      process(uri); 
      Log.e(TAG, "[Finish] general"); 
     } catch (Exception e) { 
      Log.e(TAG, "[Finish] error : " + e.toString(), e); 
     } 
    } else { 
     Log.e(TAG, "[Finish] not EXTERNAL_CONTENT_URI "); 
    } 
} 

public void register() { 
    Log.d(TAG, "register"); 
    mContentResolver.registerContentObserver(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, true, this); 
} 

public void unregister() { 
    Log.d(TAG, "unregister"); 
    mContentResolver.unregisterContentObserver(this); 
} 

private boolean process(Uri uri) throws Exception { 
    Data result = getLatestData(uri); 
    if (result == null) { 
     Log.e(TAG, "[Result] result is null!!"); 
     return false; 
    } 
    if (lastPath != null && lastPath.equals(result.path)) { 
     Log.e(TAG, "[Result] duplicate!!"); 
     return false; 
    } 
    long currentTime = System.currentTimeMillis()/1000; 
    if (matchPath(result.path) && matchTime(currentTime, result.dateAdded)) { 
     lastPath = result.path; 
     Uri screenUri = Uri.parse(MediaStore.Images.Media.EXTERNAL_CONTENT_URI.toString() + "/" + result.id); 
     Log.e(TAG, "[Result] This is screenshot!! : " + result.fileName + " | dateAdded : " + result.dateAdded + "/" + currentTime); 
     Bitmap bitmap = MediaStore.Images.Media.getBitmap(mContentResolver, screenUri); 
     Bitmap copyBitmap = bitmap.copy(bitmap.getConfig(), true); 
     bitmap.recycle(); 
     int temp = mContentResolver.delete(screenUri, null, null); 
     Log.e(TAG, "Delete Result : " + temp); 
     if (mListener != null) { 
      mListener.onScreenshotTaken(copyBitmap, result.fileName); 
     } 
     return true; 
    } else { 
     Log.e(TAG, "[Result] No ScreenShot : " + result.fileName); 
    } 
    return false; 
} 

private Data getLatestData(Uri uri) throws Exception { 
    Data data = null; 
    Cursor cursor = null; 
    try { 
     cursor = mContentResolver.query(uri, PROJECTION, null, null, SORT_ORDER); 
     if (cursor != null && cursor.moveToFirst()) { 
      long id = cursor.getLong(cursor.getColumnIndex(MediaStore.Images.ImageColumns._ID)); 
      String fileName = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME)); 
      String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA)); 
      long dateAdded = cursor.getLong(cursor.getColumnIndex(MediaStore.Images.Media.DATE_ADDED)); 

      if (fileName.contains(FILE_POSTFIX)) { 
       if (cursor.moveToNext()) { 
        id = cursor.getLong(cursor.getColumnIndex(MediaStore.Images.ImageColumns._ID)); 
        fileName = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME)); 
        path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA)); 
        dateAdded = cursor.getLong(cursor.getColumnIndex(MediaStore.Images.Media.DATE_ADDED)); 
       } else { 
        return null; 
       } 
      } 

      data = new Data(); 
      data.id = id; 
      data.fileName = fileName; 
      data.path = path; 
      data.dateAdded = dateAdded; 
      Log.e(TAG, "[Recent File] Name : " + fileName); 
     } 
    } finally { 
     if (cursor != null) { 
      cursor.close(); 
     } 
    } 
    return data; 
} 

private boolean matchPath(String path) { 
    return (path.toLowerCase().contains("screenshots/") && !path.contains(FILE_POSTFIX)); 
} 

private boolean matchTime(long currentTime, long dateAdded) { 
    return Math.abs(currentTime - dateAdded) <= DEFAULT_DETECT_WINDOW_SECONDS; 
} 

class Data { 
    long id; 
    String fileName; 
    String path; 
    long dateAdded; 
} 
} 
  1. Util.class

    public static void saveImage(Context context, Bitmap bitmap, String title) throws Exception { 
    OutputStream fOut = null; 
    title = title.replaceAll(" ", "+"); 
    int index = title.lastIndexOf(".png"); 
    String fileName = title.substring(0, index) + ScreenShotContentObserver.FILE_POSTFIX + ".png"; 
    final String appDirectoryName = "Screenshots"; 
    final File imageRoot = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), appDirectoryName); 
    imageRoot.mkdirs(); 
    final File file = new File(imageRoot, fileName); 
    fOut = new FileOutputStream(file); 
    
    bitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut); 
    fOut.flush(); 
    fOut.close(); 
    
    ContentValues values = new ContentValues(); 
    values.put(MediaStore.Images.Media.TITLE, "XXXXX"); 
    values.put(MediaStore.Images.Media.DESCRIPTION, "description here"); 
    values.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis()); 
    values.put(MediaStore.Images.ImageColumns.BUCKET_ID, file.hashCode()); 
    values.put(MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME, file.getName()); 
    values.put("_data", file.getAbsolutePath()); 
    ContentResolver cr = context.getContentResolver(); 
    Uri newUri = cr.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values); 
    context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, newUri)); 
    } 
    
1

Yalnızca ekran görüntüsü dizin izler artı sadece dosya veya dizin oluşturma için olayları tetikleyebilir FileObserver oluşturabilir. Daha fazla bilgi için, here'u tıklatın.

1

İçerik gözlemcisi görüntüyü kameradan algıladığında kullanımı kolay sınıf yapmak ve sorunu gidermek için alijandro'nun yorumunu geliştirdim (yalnızca ekran görüntüsünde olması gerekir). Daha sonra kullanımı uygun sınıf deleğine sarın. ScreenshotDetectionDelegate •


.java

public class ScreenshotDetectionDelegate { 
    private WeakReference<Activity> activityWeakReference; 
    private ScreenshotDetectionListener listener; 

    public ScreenshotDetectionDelegate(Activity activityWeakReference, ScreenshotDetectionListener listener) { 
     this.activityWeakReference = new WeakReference<>(activityWeakReference); 
     this.listener = listener; 
    } 

    public void startScreenshotDetection() { 
     activityWeakReference.get() 
       .getContentResolver() 
       .registerContentObserver(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, true, contentObserver); 
    } 

    public void stopScreenshotDetection() { 
     activityWeakReference.get().getContentResolver().unregisterContentObserver(contentObserver); 
    } 

    private ContentObserver contentObserver = new ContentObserver(new Handler()) { 
     @Override 
     public boolean deliverSelfNotifications() { 
      return super.deliverSelfNotifications(); 
     } 

     @Override 
     public void onChange(boolean selfChange) { 
      super.onChange(selfChange); 
     } 

     @Override 
     public void onChange(boolean selfChange, Uri uri) { 
      super.onChange(selfChange, uri); 
      if (isReadExternalStoragePermissionGranted()) { 
       String path = getFilePathFromContentResolver(activityWeakReference.get(), uri); 
       if (isScreenshotPath(path)) { 
        onScreenCaptured(path); 
       } 
      } else { 
       onScreenCapturedWithDeniedPermission(); 
      } 
     } 
    }; 

    private void onScreenCaptured(String path) { 
     if (listener != null) { 
      listener.onScreenCaptured(path); 
     } 
    } 

    private void onScreenCapturedWithDeniedPermission() { 
     if (listener != null) { 
      listener.onScreenCapturedWithDeniedPermission(); 
     } 
    } 

    private boolean isScreenshotPath(String path) { 
     return path != null && path.toLowerCase().contains("screenshots"); 
    } 

    private String getFilePathFromContentResolver(Context context, Uri uri) { 
     try { 
      Cursor cursor = context.getContentResolver().query(uri, new String[]{ 
        MediaStore.Images.Media.DISPLAY_NAME, 
        MediaStore.Images.Media.DATA 
      }, null, null, null); 
      if (cursor != null && cursor.moveToFirst()) { 
       String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA)); 
       cursor.close(); 
       return path; 
      } 
     } catch (IllegalStateException ignored) { 
     } 
     return null; 
    } 

    private boolean isReadExternalStoragePermissionGranted() { 
     return ContextCompat.checkSelfPermission(activityWeakReference.get(), Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED; 
    } 

    public interface ScreenshotDetectionListener { 
     void onScreenCaptured(String path); 

     void onScreenCapturedWithDeniedPermission(); 
    } 
} 

ScreenshotDetectionActivity.java

import android.Manifest; 
import android.content.pm.PackageManager; 
import android.os.Bundle; 
import android.support.annotation.NonNull; 
import android.support.annotation.Nullable; 
import android.support.v4.app.ActivityCompat; 
import android.support.v4.content.ContextCompat; 
import android.support.v7.app.AppCompatActivity; 
import android.widget.Toast; 

public abstract class ScreenshotDetectionActivity extends AppCompatActivity implements ScreenshotDetectionDelegate.ScreenshotDetectionListener { 
    private static final int REQUEST_CODE_READ_EXTERNAL_STORAGE_PERMISSION = 3009; 

    private ScreenshotDetectionDelegate screenshotDetectionDelegate = new ScreenshotDetectionDelegate(this, this); 

    @Override 
    protected void onCreate(@Nullable Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     checkReadExternalStoragePermission(); 
    } 

    @Override 
    protected void onStart() { 
     super.onStart(); 
     screenshotDetectionDelegate.startScreenshotDetection(); 
    } 

    @Override 
    protected void onStop() { 
     super.onStop(); 
     screenshotDetectionDelegate.stopScreenshotDetection(); 
    } 

    @Override 
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { 
     switch (requestCode) { 
      case REQUEST_CODE_READ_EXTERNAL_STORAGE_PERMISSION: 
       if (grantResults[0] == PackageManager.PERMISSION_DENIED) { 
        showReadExternalStoragePermissionDeniedMessage(); 
       } 
       break; 
      default: 
       super.onRequestPermissionsResult(requestCode, permissions, grantResults); 
     } 
    } 

    @Override 
    public void onScreenCaptured(String path) { 
     // Do something when screen was captured 
    } 

    @Override 
    public void onScreenCapturedWithDeniedPermission() { 
     // Do something when screen was captured but read external storage permission has denied 
    } 

    private void checkReadExternalStoragePermission() { 
     if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { 
      requestReadExternalStoragePermission(); 
     } 
    } 

    private void requestReadExternalStoragePermission() { 
     ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, REQUEST_CODE_READ_EXTERNAL_STORAGE_PERMISSION); 
    } 

    private void showReadExternalStoragePermissionDeniedMessage() { 
     Toast.makeText(this, "Read external storage permission has denied", Toast.LENGTH_SHORT).show(); 
    } 
} 

• MainActivity.java

import android.os.Bundle; 
import android.view.View; 
import android.widget.Toast; 

public class MainActivity extends ScreenshotDetectionActivity { 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 
    } 

    @Override 
    public void onScreenCaptured(String path) { 
     Toast.make(this, path, Toast.LENGTH_SHORT).show(); 
    } 

    @Override 
    public void onScreenCapturedWithDeniedPermission() { 
     Toast.make(this, "Please grant read external storage permission for screenshot detection", Toast.LENGTH_SHORT).show(); 
    } 
} 
+0

Merhaba, Bu kod benim için çalışıyor ama bazı cihazlarda sorun var. – bhoomika

+0

@bhoomika Bu cihazlar hakkında herhangi bir bilginiz var mı? – Akexorcist

İlgili konular