Capture Image while Device is Locked with Password

2019-03-10 00:41发布

问题:

I want to implement a functionality to capture image through front camera when someone tries to unlock my device and enter incorrect password 3 times. I checked that it is possible in Android and some applications are also available in Market.

I have done some work to achieve this but I am getting a black Image. Here's the code :

Register with Device admin to get the broadcast for incorrect password attempt :

public class DeviceAdminSample extends DeviceAdminReceiver {

static Context ctx;

static SharedPreferences getSamplePreferences(Context context) {

    ctx = context;

    return context.getSharedPreferences(
            DeviceAdminReceiver.class.getName(), 0);
}

@Override
public void onPasswordFailed(Context context, Intent intent) {
    super.onPasswordFailed(context, intent);

    System.out.println("Password Attempt is Failed...");

    Intent i = new Intent(context, CameraView.class);
    i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    context.startActivity(i);

}

}

Camera Class to capture image and save it to SD Card :

public class CameraView extends Activity implements SurfaceHolder.Callback,
    OnClickListener {
private static final String TAG = "CameraTest";
Camera mCamera;
boolean mPreviewRunning = false;

public void onCreate(Bundle icicle) {
    super.onCreate(icicle);
    Log.e(TAG, "onCreate");

    setContentView(R.layout.cameraview);

    mSurfaceView = (SurfaceView) findViewById(R.id.surface_camera);

    // mSurfaceView.setOnClickListener(this);

    mSurfaceHolder = mSurfaceView.getHolder();
    mSurfaceHolder.addCallback(this);

    mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    mSurfaceHolder.setKeepScreenOn(true);

    // mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);
}

protected void onResume() {
    Log.e(TAG, "onResume");
    super.onResume();
}

protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
}

protected void onStop() {
    Log.e(TAG, "onStop");
    super.onStop();
}

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
    Log.e(TAG, "surfaceChanged");

    // XXX stopPreview() will crash if preview is not running
    if (mPreviewRunning) {
        mCamera.stopPreview();
    }

    Camera.Parameters p = mCamera.getParameters();

    mCamera.setParameters(p);

    mCamera.startPreview();
    mPreviewRunning = true;
    mCamera.takePicture(null, null, mPictureCallback);


}

public void surfaceDestroyed(SurfaceHolder holder) {
    Log.e(TAG, "surfaceDestroyed");
    // mCamera.stopPreview();
    // mPreviewRunning = false;
    // mCamera.release();

    stopCamera();
}

private SurfaceView mSurfaceView;
private SurfaceHolder mSurfaceHolder;

public void onClick(View v) {
    mCamera.takePicture(null, mPictureCallback, mPictureCallback);
}

public void surfaceCreated(SurfaceHolder holder) {
    Log.e(TAG, "surfaceCreated");

    int i = findFrontFacingCamera();

    if (i > 0); 
    while (true) {
        try {
            this.mCamera = Camera.open(i);
            try {
                this.mCamera.setPreviewDisplay(holder);
                return;
            } catch (IOException localIOException2) {
                stopCamera();
                return;
            }
        } catch (RuntimeException localRuntimeException) {
            localRuntimeException.printStackTrace();
            if (this.mCamera == null)
                continue;
            stopCamera();
            this.mCamera = Camera.open(i);
            try {
                this.mCamera.setPreviewDisplay(holder);
                Log.d("HiddenEye Plus", "Camera open RE");
                return;
            } catch (IOException localIOException1) {
                stopCamera();
                localIOException1.printStackTrace();
                return;
            }

        } catch (Exception localException) {
            if (this.mCamera != null)
                stopCamera();
            localException.printStackTrace();
            return;
        }
    }
}

private void stopCamera() {
    if (this.mCamera != null) {
        /*this.mCamera.stopPreview();
        this.mCamera.release();
        this.mCamera = null;*/
        this.mPreviewRunning = false;
    }
}

private int findFrontFacingCamera() {
    int i = Camera.getNumberOfCameras();
    for (int j = 0;; j++) {
        if (j >= i)
            return -1;
        Camera.CameraInfo localCameraInfo = new Camera.CameraInfo();
        Camera.getCameraInfo(j, localCameraInfo);
        if (localCameraInfo.facing == 1)
            return j;
    }
}

Camera.PictureCallback mPictureCallback = new Camera.PictureCallback() {

    public void onPictureTaken(byte[] data, Camera camera) {
        if (data != null) {
            // Intent mIntent = new Intent();
            // mIntent.putExtra("image",imageData);

            mCamera.stopPreview();
            mPreviewRunning = false;
            mCamera.release();

            try {
                BitmapFactory.Options opts = new BitmapFactory.Options();
                Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0,
                        data.length, opts);
                bitmap = Bitmap.createScaledBitmap(bitmap, 300, 300, false);
                int width = bitmap.getWidth();
                int height = bitmap.getHeight();
                int newWidth = 300;
                int newHeight = 300;

                // calculate the scale - in this case = 0.4f
                float scaleWidth = ((float) newWidth) / width;
                float scaleHeight = ((float) newHeight) / height;

                // createa matrix for the manipulation
                Matrix matrix = new Matrix();
                // resize the bit map
                matrix.postScale(scaleWidth, scaleHeight);
                // rotate the Bitmap
                matrix.postRotate(-90);
                Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0,
                        width, height, matrix, true);

                ByteArrayOutputStream bytes = new ByteArrayOutputStream();
                resizedBitmap.compress(Bitmap.CompressFormat.JPEG, 40,
                        bytes);

                // you can create a new file name "test.jpg" in sdcard
                // folder.
                File f = new File(Environment.getExternalStorageDirectory()
                        + File.separator + "test.jpg");

                System.out.println("File F : " + f );

                f.createNewFile();
                // write the bytes in file
                FileOutputStream fo = new FileOutputStream(f);
                fo.write(bytes.toByteArray());

                // remember close de FileOutput
                fo.close();

            } catch (Exception e) {
                e.printStackTrace();
            }
            // StoreByteImage(mContext, imageData, 50,"ImageName");
            // setResult(FOTO_MODE, mIntent);
            setResult(585);
            finish();
        }
    }
};
}

回答1:

I have tested your code and I get a proper image so I think your camera code works fine.

You can check my code here. I copied the CameraView class from yours. The device admin part I took from https://github.com/marakana/DevicePolicyDemo The picture is taken when the first attempt fails.

I doubt that it might be some kind of hardware issue. I am not sure if you've seen Taking picture from camera without preview.

The second answer there mentions that faking the preview with a dummy SurfaceView does not work on all Android devices. Please see his blog. He's done the test on various phones. You could try my project and if it doesn't work on your phone. This might be the case. (The other answers might also be useful for you.)

I tried my code on Galaxy S3 with CM10.

Hope this helps.

Edit1: Tested on HTC One, HTC One X, Sony Experia. Works fine.

Edit2: Worked on Galaxy Note.



回答2:

I'm not sure this will work on other devices, but if it does it might offer some insight into whats happening.

In the Camera.Parameters, there is a feature to save the raw bayer image directly to the SD card. This image happens before the .jpeg file is created, so if the operating system is blanking out the image, this image might not be effected.

  Camera.Parameters parameters=camera.getParameters();
  parameters.set("rawsave-mode", "1");
  parameters.set("rawfname", "/mnt/sdcard2/test5.raw");
  camera.setParameters(parameters);

If this feature works on your device, you should be able to determine if the picture is being taken and wiped out or if it not being taken at all.

If the raw image works, it is fairly easy to convert a bayer to an RGB image or grayscale image.

The other area i'd be looking is the logcat information and compare the logs between an unlocked context of the code and a locked context of the code. If there is a security issue, it should be reflected in the logcat.