Android?拍照功能實現(xiàn)(手機關(guān)閉依然拍照)詳解及實例代碼
Android 拍照功能/手機關(guān)閉能拍照
效果如下:

其實拍照與偷錄實現(xiàn)方式是一樣的,都是使用到的WindowManager來繪制桌面小控件的原理。那我就不多說了…
一、首先我們需要一個SurfaceView:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/small_window_layout"
android:layout_width="1dip"
android:layout_height="1dip"
>
<FrameLayout
android:id="@+id/percent"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
/>
</LinearLayout>
二、然后進(jìn)行的操作就是生產(chǎn)這個小控件了:
public PhotoWindowSmallView(Context context) {
super(context);
windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
LayoutInflater.from(context).inflate(R.layout.float_window_small, this);
View view = findViewById(R.id.small_window_layout);
viewWidth = view.getLayoutParams().width;
viewHeight = view.getLayoutParams().height;
// SurfaceView percentView = (SurfaceView) findViewById(R.id.percent);
// percentView.setText(MyWindowManager.getUsedPercentValue(context));
}
/**
* 將小懸浮窗的參數(shù)傳入,用于更新小懸浮窗的位置。
*
* @param params 小懸浮窗的參數(shù)
*/
public void setParams(WindowManager.LayoutParams params) {
mParams = params;
}
三、那桌面控件有了,下面當(dāng)然就是使用WindowManager添加到桌面上了:
/**
* 創(chuàng)建一個小懸浮窗。初始位置為屏幕的右部中間位置。
*
* @param context 必須為應(yīng)用程序的Context.
*/
public void createSmallWindow(Context context) {
mContext = context;
WindowManager windowManager = getWindowManager(context);
int screenWidth = windowManager.getDefaultDisplay().getWidth();
int screenHeight = windowManager.getDefaultDisplay().getHeight();
if (smallWindow == null) {
smallWindow = new PhotoWindowSmallView(context);
if (smallWindowParams == null) {
smallWindowParams = new LayoutParams();
smallWindowParams.type = LayoutParams.TYPE_PHONE;
smallWindowParams.format = PixelFormat.RGBA_8888;
smallWindowParams.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL
| LayoutParams.FLAG_NOT_FOCUSABLE;
smallWindowParams.gravity = Gravity.LEFT | Gravity.TOP;
smallWindowParams.width = PhotoWindowSmallView.viewWidth;
smallWindowParams.height = PhotoWindowSmallView.viewHeight;
smallWindowParams.x = screenWidth;
smallWindowParams.y = screenHeight / 2;
}
smallWindow.setParams(smallWindowParams);
windowManager.addView(smallWindow, smallWindowParams);
mSurfaceview = (FrameLayout) smallWindow.findViewById(R.id.percent);
}
}
/**
* 將小懸浮窗從屏幕上移除。
*
* @param context 必須為應(yīng)用程序的Context.
*/
public void removeSmallWindow(Context context) {
if (smallWindow != null) {
WindowManager windowManager = getWindowManager(context);
windowManager.removeView(smallWindow);
smallWindow = null;
}
}
四、這個時候我們需要的SurfaceView就有了,那么,怎么在后臺進(jìn)行操作呢?自然而然就想到了Service了
在Service中執(zhí)行桌面控件的操作:
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
myWindowManager = new MyPhotoWindowManager();
createWindow();
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
}
private void createWindow() {
// 當(dāng)前界面是桌面,且沒有懸浮窗顯示,則創(chuàng)建懸浮窗。
myWindowManager.removeSmallWindow(getApplicationContext());
myWindowManager.createSmallWindow(getApplicationContext());
}
五、在activity中對Service綁定,進(jìn)行拍照的操作
private class MyServiceConn implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
binder = (PhotoWindowService.myServiceBinder) service;
if (isVedio) {
binder.startCarema();
} else {
binder.stopCarema();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
}
}
六、在Service中控制myWindowManager中的拍照的開始和結(jié)束
public class myServiceBinder extends Binder {
public void startCarema() {
myWindowManager.startCarema();
}
public void stopCarema() {
myWindowManager.stopCarema();
}
}
七、在MyPhotoWindowManager開啟或終止拍照操作
public void startCarema() {
itt = InitTimetoTakePic.getInstance(mContext);
itt.initView(mSurfaceview);
itt.start();
}
public void stopCarema() {
if (itt != null)
itt.releaseCarema();
}
八、在InitTimetoTakePic進(jìn)行拍照的相關(guān)處理
package com.ddv.www.candidphotodemo;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.hardware.Camera;
import android.hardware.Camera.AutoFocusCallback;
import android.hardware.Camera.PictureCallback;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.widget.FrameLayout;
import java.io.File;
import java.io.FileOutputStream;
/**
* 設(shè)置定時拍照功能
*
* @author <p>
* 創(chuàng)建定時拍照任務(wù)
* cameraType 攝像頭
* resolutionString 分辨率
* tvSaveLocation 保存地址
* etExtension 拓展名
* cameraStart, 開始拍攝時間
* cameraNumber, 拍攝次數(shù)
* cameraStop 拍攝張數(shù)
*/
public class InitTimetoTakePic {
private static InitTimetoTakePic mInstance;
private static int cameraType = 1;
Context mContext;
static FrameLayout mSurfaceViewFrame;
private static Camera mCamera;
private static CameraPreview mPreview;
private static String resolutionString = "1920x1080";
private static String saveLocation = AppUtils.getSDCardPath();
private static String extension = "JPG";
private static String cameraStart = "1";
private static String cameraNumber = "1";
private static String cameraStop = "10";
private static int number = 0;
private static boolean clearVoice = false;
private Intent intent;
private InitTimetoTakePic(Context context) {
this.mContext = context;
}
public synchronized static InitTimetoTakePic getInstance(Context context) {
mInstance = null;
mInstance = new InitTimetoTakePic(context);
return mInstance;
}
public void initView(FrameLayout surfaceViewFrame) {
mSurfaceViewFrame = surfaceViewFrame;
}
/**
* 啟動定時拍照并上傳功能
*/
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
LogUtils.v("開始拍照");
initCarema();
break;
case 2:
if (mCamera == null) {
releaseCarema();
number = 0;
mHandler.removeCallbacksAndMessages(null);
} else {
if (number < Integer.valueOf(cameraStop)) {
mCamera.autoFocus(new AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
// 從Camera捕獲圖片
LogUtils.v("自動聚焦111" + success);
try {
mCamera.takePicture(null, null, mPicture);
mHandler.sendEmptyMessageDelayed(1, Integer.valueOf(cameraNumber) * 1000);
} catch (Exception e) {
releaseCarema();
mHandler.removeCallbacksAndMessages(null);
}
}
});
} else {
releaseCarema();
number = 0;
mHandler.removeCallbacksAndMessages(null);
}
}
break;
}
}
};
public void start() {
mHandler.sendEmptyMessageDelayed(1, 1 * 1000); //7s 后開始啟動相機
}
private void initCarema() {
LogUtils.v("initCarema");
if (mCamera == null) {
LogUtils.v("camera=null");
mCamera = getCameraInstance();
mPreview = new CameraPreview(mContext, mCamera);
mSurfaceViewFrame.removeAllViews();
mSurfaceViewFrame.addView(mPreview);
}
LogUtils.v(mCamera == null ? "mCamera is null" : "mCamera is not null");
mCamera.startPreview();
mHandler.sendEmptyMessageDelayed(2, Integer.valueOf(cameraStart) * 1000); //3s后拍照
}
/**
* 檢測設(shè)備是否存在Camera硬件
*/
private boolean checkCameraHardware(Context context) {
if (context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_CAMERA)) {
// 存在
return true;
} else {
// 不存在
return false;
}
}
/**
* 打開一個Camera
*/
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
public static Camera getCameraInstance() {
Camera c = null;
try {
c = Camera.open(cameraType);
c.setDisplayOrientation(90);
Camera.Parameters mParameters = c.getParameters();
//快門聲音
c.enableShutterSound(clearVoice);
//可以用得到當(dāng)前所支持的照片大小,然后
//List<Size> ms = mParameters.getSupportedPictureSizes();
//mParameters.setPictureSize(ms.get(0).width, ms.get(0).height); //默認(rèn)最大拍照取最大清晰度的照片
String[] xes = resolutionString.split("x");
// LogUtils.i("ms.get(0).width==>"+ms.get(0).width);
// LogUtils.i("ms.get(0).height==>"+ms.get(0).height);
// LogUtils.i("Integer.valueOf(xes[0])==>"+Integer.valueOf(xes[0]));
// LogUtils.i("Integer.valueOf(xes[1])==>"+Integer.valueOf(xes[1]));
mParameters.setPictureSize(Integer.valueOf(xes[0]), Integer.valueOf(xes[1])); //默認(rèn)最大拍照取最大清晰度的照片
c.setParameters(mParameters);
} catch (Exception e) {
LogUtils.v("打開Camera失敗失敗");
}
return c;
}
private PictureCallback mPicture = new PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
// 獲取Jpeg圖片,并保存在sd卡上
String path = saveLocation;
File dirF = new File(path);
if (!dirF.exists()) {
dirF.mkdirs();
}
File pictureFile = new File(path + "/" + System.currentTimeMillis() + "." + extension);//擴展名
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
LogUtils.v("保存圖成功");
number++;
intent = new Intent();
intent.setAction("CameraFragment.start");
intent.putExtra("number", number);
mContext.sendBroadcast(intent);
} catch (Exception e) {
LogUtils.v("保存圖片失敗");
e.printStackTrace();
}
releaseCarema();
}
};
public void releaseCarema() {
if (mCamera != null) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
}
}
demo下載地址://www.dbjr.com.cn/softs/519032.html
感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!
相關(guān)文章
Android使用內(nèi)置WebView打開TextView超鏈接的實現(xiàn)方法
這篇文章主要介紹了Android使用內(nèi)置WebView打開TextView超鏈接的實現(xiàn)方法,文中給出了詳細(xì)的示例代碼,對各位Android開發(fā)者們具有一定的參考價值,需要的朋友們下面來一起看看吧。2017-03-03
Android開發(fā)優(yōu)化之Apk瘦身優(yōu)化指南
隨著業(yè)務(wù)快速發(fā)展,各種業(yè)務(wù)功能上線,版本不斷迭代,apk體積也越來越大,下面這篇文章主要給大家介紹了關(guān)于Android開發(fā)優(yōu)化之Apk瘦身優(yōu)化的相關(guān)資料,需要的朋友可以參考下2022-05-05
Android開發(fā)之ProgressDialog進(jìn)度對話框用法示例
這篇文章主要介紹了Android開發(fā)之ProgressDialog進(jìn)度對話框用法,簡單介紹了ProgressDialog進(jìn)度對話框常見函數(shù)功能,并結(jié)合實例形式分析了ProgressDialog組件創(chuàng)建及使用進(jìn)度對話框相關(guān)操作技巧,需要的朋友可以參考下2019-03-03
Kotlin自定義View系列教程之標(biāo)尺控件(選擇身高、體重等)的實現(xiàn)
這篇文章主要給大家介紹了關(guān)于Kotlin自定義View系列教程之標(biāo)尺控件(選擇身高、體重等)實現(xiàn)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-07-07
Android?Flutter實現(xiàn)創(chuàng)意時鐘的示例代碼
時鐘這個東西很奇妙,總能當(dāng)做創(chuàng)意實現(xiàn)的入口。這篇文章主要介紹了如何通過Android?Flutter實現(xiàn)一個創(chuàng)意時鐘,感興趣的小伙伴可以了解一下2023-03-03

