我正在开发一个应用,该应用可以拍摄试图以错误的密码或图案解锁设备的人的照片。
该应用使用DeviceAdminReceiver.onPasswordFailed()
例程检测失败的尝试。一切都可以在所有版本的Android上正常运行,除非我在Android O真实设备上使用它(在模拟器上运行正常)。
这是我的代码:
public class AdminReceiver extends DeviceAdminReceiver {
@Override
public void onPasswordFailed(Context context, Intent intent) {
super.onPasswordFailed(context, intent);
Intent i = new Intent(context, CameraActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
拍照的代码是在透明的活动中进行的:
public class CameraActivity extends AppCompatActivity {
private static final String TAG = CameraActivity.class.getSimpleName();
private Camera mCamera;
private boolean executed = false;
private CameraPreview.CamCallback camCallback = (data, camera) -> {
//used to prevent picture from being captured twice, because apparently
// Camera.stopPreview() takes sometime to execute
if (!executed) {
executed = true;
log.d(TAG, "CameraActivity camCallback executed");
Camera.Parameters params = camera.getParameters();
Camera.Size size = params.getPreviewSize();
camera.stopPreview();
File dir = new File(STORE_DIRECTORY);
if (!(dir.exists() || dir.mkdirs())) {
Log.e(TAG, "Failed to create file storage directory.");
return;
}
String imgname = new SimpleDateFormat("dd-MMM-yyyy hh:mm:ss",
Locale.getDefault()).format(new Date());
File file = new File(dir, imgname + ".jpg");
OutputStream fOut;
try {
if (file.exists() && !file.delete()) {
Log.e(TAG, "File already exists and could not be deleted!");
finish();
return;
}
if (!file.exists() && !file.createNewFile()) {
Log.e(TAG, "failed to create image file.");
finish();
return;
}
fOut = new FileOutputStream(file);
YuvImage yuvImage = new YuvImage(data, params.getPreviewFormat(),
size.width, size.height, null);
processImage(yuvImage, fOut);
fOut.flush();
fOut.close();
} catch (FileNotFoundException e) {
Log.e(TAG, "Output file not found!");
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
finish();
};
private void processImage(@NotNull YuvImage yuvImage, OutputStream fOut) {
ByteArrayOutputStream os = new ByteArrayOutputStream();
yuvImage.compressToJpeg(new Rect(0, 0, yuvImage.getWidth(), yuvImage.getHeight()),90, os);
byte[] bytes = os.toByteArray();
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
Matrix matrix = new Matrix();
matrix.postRotate(bitmap.getWidth() > bitmap.getHeight() ? -90.0f : 0.0f);
Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true)
.compress(Bitmap.CompressFormat.JPEG, 100, fOut);
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
log.i(TAG, "CameraActivity->onCreate");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON);
// Setup the camera and the preview object
int frontCamIndex = findFrontFacingCamera();
if (frontCamIndex == -1) {
Log.e(TAG, "findFrontFacingCamera: ",
new IOException("No facing Camera detected on this device"));
finish();
return;
}
mCamera = Camera.open(frontCamIndex);
CameraPreview camPreview = new CameraPreview(this, mCamera, camCallback);
camPreview.setSurfaceTextureListener(camPreview);
// Connect the preview object to a FrameLayout in your UI
// You'll have to create a FrameLayout object in your UI to place this preview in
FrameLayout preview = findViewById(R.id.cameraView);
preview.addView(camPreview);
// Attach a callback for preview
mCamera.setPreviewCallback(camCallback);
}
@Override
protected void onDestroy() {
super.onDestroy();
Logger.log("CameraActivity->onDestroy");
if (mCamera != null)
mCamera.release();
}
}
清单中的 CameraActivity
:
<activity
android:name=".activities.CameraActivity"
android:showWhenLocked="true"
android:theme="@style/Theme.Transparent" />
CameraActivity
的样式:
<style name="Theme.Transparent" parent="android:Theme">
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsFloating">true</item>
<item name="android:backgroundDimEnabled">false</item>
</style>
还有带有CameraPreview
接口的CamCallback
类:
public class CameraPreview extends TextureView implements TextureView.SurfaceTextureListener {
public interface CamCallback extends Camera.PreviewCallback {
void onPreviewFrame(byte[] data, Camera camera);
}
private Camera mCamera;
private CamCallback callback;
public CameraPreview(Context context) {
super(context);
}
public CameraPreview(Context context, Camera camera, CamCallback callback) {
super(context);
mCamera = camera;
this.callback = callback;
}
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
Camera.Parameters params = mCamera.getParameters();
try {
mCamera.setPreviewTexture(surface);
} catch (IOException t) {
t.printStackTrace();
}
Camera.Size size = getBiggestPictureSize();
setLayoutParams(new FrameLayout.LayoutParams(size.width, size.height, Gravity.CENTER));
params.setPreviewSize(size.width, size.height);
mCamera.setParameters(params);
mCamera.setPreviewCallback(callback);
try {
mCamera.setPreviewTexture(surface);
} catch (IOException e) {
e.printStackTrace();
}
mCamera.startPreview();
setVisibility(INVISIBLE); // Make the surface invisible as soon as it is created
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
// Put code here to handle texture size change if you want to
try {
mCamera.stopPreview();
mCamera.setPreviewCallback(callback);
try {
mCamera.setPreviewTexture(surface);
} catch (IOException e) {
e.printStackTrace();
}
mCamera.startPreview();
} catch (Exception ex) {
ex.printStackTrace();
}
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
return true;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
// Update your view here!
}
private Camera.Size getBiggestPictureSize() {
Camera.Size result = null;
for (Camera.Size size : mCamera.getParameters().getSupportedPictureSizes()) {
if (result == null) {
result = size;
} else {
int resultArea = result.width * result.height;
int newArea = size.width * size.height;
if (newArea > resultArea) {
result = size;
}
}
}
return (result);
}
}
正在创建CameraActivity
,因为我可以在logcat中看到它,并且logcat完全没有显示错误。