Android Background Service Photo-Solution

Source: Internet
Author: User

First, Background introduction

Recently encountered a requirement in the project to achieve a background photo-taking function. The first to find a solution on the internet, but also tried a lot of ways to achieve, there is no satisfactory solution. However, the difficulty is determined: The photo should be previewed before the camera method is called. The problem comes with the fact that you want to be able to take pictures in the background, hopefully in a service or an asynchronous thread, which is a bit contradictory to previewing this step. What is the way to achieve a normal preview, take pictures, and do not let users notice it? Presumably you will also think of a trickery approach: Hide the Preview interface.

To illustrate, this is just a solution that I think of in my groping, can solve the business demand very well. I'm not sure how they'll be implemented for the photos that are provided by many handset makers, such as the "Find Phone" feature. If you have a better implementation of the plan, may wish to exchange.

The question of whether this feature infringes the privacy of the user, the security of the user, etc. is beyond our consideration and discussion.

Ii. Introduction of the programme

The program implementation steps are outlined below:

1. Initialize the preview screen (core part) of the camera; 2. Get camera cameras when you need to take a photo, and set a preview screen for the camera; 3. Open the preview, complete the photo shoot, release the camera resources (important) 4. Save, rotate, upload ... (by business decision)

first of all, about the business requirements: from the user login to logoff this period of time, received background photos of the instructions to complete the photo, save, upload. the Following is a detailed description of the implementation of each step based on this business scenario.

1. Initialize the photo preview screenDuring the testing process, it was found that the preview screen of the photo should be generated in the case of display, in order to take a normal picture, if the Surfaceview instance is created directly as the preview interface, then the direct call to take the picture will throw the native layer exception: Take_ Failed Think of the source to look for the cause of the problem, found that the core of the camera function code on the native layer above, so for the time being put down, it is assumed that the preview screen must be in the top layer of the display. since the application, whether in the foreground or the home back to the desktop, the need to meet this condition, the preview interface should be global, it is easy to associate with a global window as a vector for the preview interface. This global window, if not visible, does not affect the normal interaction of the subsequent interface. Therefore, it is thought to use the global context to get WindowManager object management this global window. Then look directly at the code:
Package Com.yuexunit.zjjk.service;import Com.yuexunit.zjjk.util.logger;import Android.content.context;import Android.view.surfaceview;import Android.view.windowmanager;import android.view.windowmanager.layoutparams;/** * Hidden Global window for background photography * * @author wurs */public class Camerawindow {private static final String TAG = CameraWindow.class.getSimp Lename ();p rivate static WindowManager windowmanager;private static Context applicationcontext;private static Surfaceview dummycameraview;/** * Show Global Window * * @param context */public static void Show (context context) {if (Applicationco ntext = = null) {ApplicationContext = Context.getapplicationcontext (); WindowManager = (WindowManager) Applicationcontext.getsystemservice (context.window_service);d Ummycameraview = new Surfaceview (applicationContext) ; Layoutparams params = new Layoutparams ();p arams.width = 1;params.height = 1;params.alpha = 0;params.type = LayoutParams.TY pe_system_alert;//Shielded Click event Params.flags = layoutparams.flag_not_touch_modal| Layoutparams.flag_not_focusable| Layoutparams.flag_not_touchable;windowmanager.addview (Dummycameraview, params); LOGGER.D (tag, tag + "showing");}} /** * @return Get window view */public static Surfaceview Getdummycameraview () {return dummycameraview;} /** * Hidden window */public static void dismiss () {try {if (WindowManager! = NULL && Dummycameraview! = null) {Windowmanag Er.removeview (Dummycameraview); LOGGER.D (tag, tag + "dismissed");}} catch (Exception e) {e.printstacktrace ();}}}


the code is simple, and the main function is to display this window, get the Surfaceview for previewing, and close the window. in this business, the show method can be called directly into the custom application class. This way, after the app launches, the window is on, only the application is destroyed (note that the end of all activity does not close, because it initializes in application, its life cycle is applied, unless the active call to the dismiss method is actively closed). complete the Preview interface initialization, the entire implementation is actually very simple. Many people may encounter the problem is the card in the absence of a preview screen how to take pictures here, I hope that such a trickery way can help you in future projects encountered can not directly solve the problem, you may consider from another point of view to solve the problem. 2. Complete the service photo functionThis will merge the next steps above. First on the code:
Package Com.yuexunit.zjjk.service;import Java.io.file;import Java.io.filenotfoundexception;import Java.io.fileoutputstream;import Java.io.ioexception;import Android.app.service;import android.content.Intent; Import Android.graphics.bitmap;import Android.graphics.bitmapfactory;import Android.graphics.bitmapfactory.options;import Android.hardware.camera;import Android.hardware.Camera.CameraInfo; Import Android.hardware.camera.picturecallback;import Android.os.ibinder;import Android.os.message;import Android.text.textutils;import Android.view.surfaceview;import Com.yuexunit.sortnetwork.android4task.UiHandler; Import Com.yuexunit.sortnetwork.task.taskstatus;import Com.yuexunit.zjjk.network.requesthttp;import Com.yuexunit.zjjk.util.filepathutil;import Com.yuexunit.zjjk.util.imagecompressutil;import Com.yuexunit.zjjk.util.logger;import com.yuexunit.zjjk.util.wakelockmanager;/** * Background photo service, use with global window * * @author WuRS */ public class Cameraservice extends Service implements Picturecallback {private STatic final String TAG = CameraService.class.getSimpleName ();p rivate Camera mcamera;private boolean isrunning; Whether the private String CommandId has been photographed in the surveillance; Directive id@overridepublic void OnCreate () {LOGGER.D (TAG, "onCreate ..."); Super.oncreate ();} @Overridepublic int Onstartcommand (Intent Intent, int flags, int startid) {wakelockmanager.acquire (this); LOGGER.D (TAG, "Onstartcommand ..."); Starttakepic (intent); return start_not_sticky;} private void Starttakepic (Intent Intent) {if (!isrunning) {commandId = Intent.getstringextra ("CommandId"); Surfaceview preview = Camerawindow.getdummycameraview (); if (! Textutils.isempty (commandId) && preview! = null) {autotakepic (preview);} else {stopself ();}}} private void Autotakepic (Surfaceview preview) {LOGGER.D (TAG, "autotakepic ..."); isrunning = True;mcamera = Getfacingfrontcamera (); if (Mcamera = = null) {LOGGER.W (TAG, "Getfacingfrontcamera return null"); Stopself (); return;} try {mcamera.setpreviewdisplay (Preview.getholder ()); Mcamera.startpreview ()//Start preview//Prevent some phonesThe photo taken is not bright enough thread.sleep ($); Takepicture ();} catch (Exception e) {e.printstacktrace (); Releasecamera (); Stopself ();}} private void Takepicture () throws Exception {LOGGER.D (TAG, "takepicture ..."); try {mcamera.takepicture (null, NULL, this) ;} catch (Exception e) {logger.d (TAG, "Takepicture failed!"); E.printstacktrace (); throw e;}} Private Camera Getfacingfrontcamera () {camerainfo camerainfo = new Camerainfo (); int numberofcameras = Camera.getnumberofcameras (); for (int i = 0; i < Numberofcameras; i++) {Camera.getcamerainfo (I, camerainfo); if (Camerai nfo.facing = = Camerainfo.camera_facing_front) {try {return camera.open (i)} catch (Exception e) {e.printstacktrace ();}}} return null;} @Overridepublic void Onpicturetaken (byte[] data, camera camera) {LOGGER.D (TAG, "Onpicturetaken ..."); Releasecamera (); try {//greater than 500K, compression prevents memory overflow options opts = null;if (data.length > * 1024x768) {opts = new Options (); opts.insamplesize = 2;} Bitmap Bitmap = bitmapfactory.decodebytearray (data, 0, data.length,opts);//rotate 270-degree biTMap Newbitmap = Imagecompressutil.rotatebitmap (bitmap, 270);//save string fullfilename = Filepathutil.getmonitorpicpath () + system.currenttimemillis () + ". jpeg"; File saveFile = Imagecompressutil.convertbmptofile (newbitmap,fullfilename); Imagecompressutil.recylebitmap ( NEWBITMAP); if (saveFile! = null) {//uploads requesthttp.uploadmonitorpic (CallbackHandler, commandid,savefile);} else {// Save failed, close stopself ();}} catch (Exception e) {e.printstacktrace (); Stopself ();}}  Private Uihandler CallbackHandler = new Uihandler () {@Overridepublic void Receivermessage (Message msg) {switch (MSG.ARG1) {Case TaskStatus.LISTENNERTIMEOUT:case TaskStatus.ERROR:case taskstatus.finished://request ended, close service stopself (); break;}}};/ /Save Photo Private Boolean savepic (byte[] data, File savefile) {FileOutputStream fos = null;try {fos = new FileOutputStream (sav efile); fos.write (data); Fos.flush (); Fos.close (); return true;} catch (FileNotFoundException e) {e.printstacktrace ();} catch (IOException e) {e.printstacktrace ();} finally {if (Fos! = Nu ll{try {fos.close ();} catch (IOException e) {e.printstacktrace ();}}} return false;} private void Releasecamera () {if (Mcamera! = null) {LOGGER.D (TAG, "Releasecamera ..."); Mcamera.stoppreview (); Mcamera.release (); mcamera = null;}} @Overridepublic void OnDestroy () {Super.ondestroy (); LOGGER.D (TAG, "OnDestroy ..."); commandId = Null;isrunning = false; Filepathutil.deletemonitoruploadfiles (); Releasecamera (); Wakelockmanager.release ();} @Overridepublic ibinder onbind (Intent Intent) {return null;}}
The code is not much, but there are a few points that need special attention,1. Cameras are captured when the camera is not available during a call, or when another application holds the camera. Open () exception to prevent application errors when the camera is not acquired;2. When testing with Huawei camera, we started to preview the photos immediately, and found that the photo was very low in brightness, because it was just speculation, and we need to check the information. So the solution for the moment is to let the thread hibernate 200ms and then call the camera. 3. When you do not use the camera resource or any anomalies, please remember to release the camera resources, otherwise the camera is always held, other applications including the system's camera can not be used, only restart the phone solution. Code can be optimized, the non-normal business logic to deal with the unified. Or, use a custom Uncaughtexceptionhandler to handle the uncaught exception. 4. Regarding the Wakelocamanager class in the code, it is my own package of wake-up lock management class, which is also a point of special concern when dealing with the background of critical business, to ensure that the business logic is processed, the system will not go into hibernation. After the business logic is processed, the wake-up lock is released and the system goes to sleep. Iii. Summarythe problem of the program is also more, but provides a way of thinking. The global window is at the heart of the solution. Camera operation needs to be cautious, get the time to catch the exception (native exception, connect the camera error, I believe you have encountered), do not use or abnormal when released in a timely manner (you can write the camera object as static, and then in the global exception capture to the camera to release, Prevent the camera from being held abnormally when an exception is applied during the time the camera is held, or else the camera application will not be used. code you can use a little change, remember to add the relevant permissions. The following are the system windows, wake-up locks, and camera permissions. If you use autofocus to take pictures again, remember to declare the following uses-feature tags. Other commonly used permissions are not mentioned here. <uses-permission android:name= "Android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name= "Android.permission.WAKE_LOCK"/>
<uses-permission android:name= "Android.permission.CAMERA"/>


Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.

Android Background Service Photo-Solution

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.