`

自定义锁屏成功解锁两次失败,拍照(调用前置摄像头,没有前置摄像头就调用后置摄像头)和定位

 
阅读更多

项目需求:自定义锁屏成功后,输入解锁密码两次失败后要求调用前置摄像头拍照并定位,将结果返回服务器

因为本文主要是讲述如何拍照,拍照的方法只写了一个方法,可以不用管它

 

代码如下:

如此调用:

mBiz.enterWrongPasswordTwice(mContext, mSurfaceView);

mBiz是一个抽象类,它的实现类里实现了这个方法,参数的意义:1 代表一个上下文对象,可以穿当前Activity的context,我们项目里用得Application里的context:mContext = MyAppContext.getAppInstance();这里的MyAppContext是继承了android Application的,关于android Application的用法大家可以GOOLE或是BAIDU,

2 传进去一个surfaceview用来拍照用的,mSurfaceView = (SurfaceView) mView.findViewById(R.id.surfaceView);是从布局文件里找出来的,这里顺便提一下需要对这个SurfaceView做处理:mSurfaceView.getHolder().setType( SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

//当SurfaceHolder对象的类型设置为SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS时就只能拍照不能绘制了。
 SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS的意思是创建一个"PUSH"surface,这个surface没有自己的缓冲区 等待屏幕渲染引擎将内容推送至用户前面 接着往下

在mBizimpl实现类里如此调用的

@Override
 public void enterWrongPasswordTwice(Context context, SurfaceView surfaceView) {
  if (surfaceView != null) {
   Thread.getThreadInstant().locateAndTakePhoto(surfaceView);

//得到Thread的实例调用locateAndTakePhoto方法
  }
 }

 

接着要为大家来讲核心代码了,在Thread这个类里分别有个默认构造器

 private Thread() {
 }

然后有个getThreadInstant方法: public static Thread getThreadInstant() {
  if (mThread == null) {
   mThread = new Thread();
  }

  return mThread;
 }

 

接下来是上代码调用的时候了,一层接一层封装的方法调用,大家不要看得很混乱,里面带有注释的

补充:private boolean isTakingPicture = false;这个变量是类takephoto中一个私有变量,代表拍照是否正在进行

默认是false

 

public void locateAndTakePhoto(SurfaceView surfaceView) {
String  mLocationUrl = "";
String  mPhotoUrl = "";
boolean  mIsUpdateError = false;
 boolean   mIsLocateError = false;
 boolean  hasSendMessage = false;

//拍照

  TakePhoto.getPhotoInstance().takePicture(surfaceView);

//得到  TakePhoto的实例,方法同上面的一样

//定位
  startLocalLocate();
 }

 

TakePhoto中takePicture方法

 

 public void takePicture(final SurfaceView surfaceView) {
        new Thread(new Runnable() {

//此方法就是启动一个线程
                       public void run() {
                        removeRing();

 

 

【【

//这个方法是用来移除系统铃声的,大家知道手机拍照是有快门声的,此段代码就是可以去除拍照的时候去除声音

神不知鬼不觉的就调用摄像头拍照了

  private void removeRing(){
     AudioManager audioManager = (AudioManager)MyAppContext.getAppInstance().getSystemService(Context.AUDIO_SERVICE);
     mRingMode = audioManager.getRingerMode();//返回系统当前铃声模式
     mCurrentVolume = audioManager.getStreamVolume(AudioManager.STREAM_SYSTEM);

//返回系统当前的音量
     audioManager.setStreamVolume(AudioManager.STREAM_SYSTEM, 0,AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);

//设置系统静音
    }

】】
                      openCamera(surfaceView);

 

【【

//打开摄像头

    private void openCamera(SurfaceView surfaceView) {

//这里判断当isTakingPicture为true的时候是直接返回的,目的是防止打开摄像头准备拍照的时候再次重新打开摄像头进行拍照(连续点两下拍照按钮,只有第一次是成功的)
        if (isTakingPicture) {
            Log.d(TAG, "is taking picture,will return");
            return;
        }
        
        int cameraId = findFirstFrontFacingCamera();

 

】】

//优先找前置摄像头

    private int findFirstFrontFacingCamera() { 
        int foundId = -1; 
        // 此方法得到设备上实际摄像头的数量

        int numCams = Camera.getNumberOfCameras(); 

//循环得到的每个摄像头得到对应的每个摄像头的详细信息
        for (int camId = 0; camId < numCams; camId++) { 
            CameraInfo info = new CameraInfo(); 
            try {
             Camera.getCameraInfo(camId, info); 
            } catch (Exception e) {
                Log.e(TAG, "findFirstFrontFacingCamera getCameraInfo error: " + e.toString());
            }

//如果得到的是前置摄像头,那么返回前置摄像头对应的camId,否则就返回-1

            if (info.facing == CameraInfo.CAMERA_FACING_FRONT) { 
                Log.d(TAG, "Found front facing camera"); 
                foundId = camId; 
                break; 
            } 
        } 
        return foundId; 
    } 

】】

 

 

//如果cameraId == -1:即证明找不到前置摄像头,就找后置摄像头

        if(cameraId == -1){
         Log.d(TAG, "no front camera, get back camera");
         cameraId = findBackFacingCamera();

 

 

【【

    private int findBackFacingCamera() { 
        int foundId = -1; 
        int numCams = Camera.getNumberOfCameras(); 
        for (int camId = 0; camId < numCams; camId++) { 
            CameraInfo info = new CameraInfo(); 
            try {
             Camera.getCameraInfo(camId, info); 
            } catch (Exception e) {
                Log.e(TAG, "findBackFacingCamera getCameraInfo error: " + e.toString());
            }
            if (info.facing == CameraInfo.CAMERA_FACING_BACK) { 
                Log.d(TAG, "Found back facing camera"); 
                foundId = camId; 
                break; 
            } 
        } 
        return foundId; 
    }

 

 

】】
        }
 //得到Camera的实例
        mCamera = getCameraInstance(cameraId);


【【

    private Camera getCameraInstance(int cameraId) {
        Camera camera = null;
       
        try {
            camera = Camera.open(cameraId); // attempt to get a Camera instance
        } catch (Exception e) {
            Log.e(TAG, " Camera is not available (in use or does not exist):" + e.toString());
        }
        return camera; // returns null if camera is unavailable
    }

 

】】
        if (mCamera == null) {
            Log.d(TAG, "can not init, camera may in use");
            return;
        }

        Log.d(TAG, "isTakingPicture:" + isTakingPicture + "->true");


        isTakingPicture = true;//表示已经开始拍照

        try {

//通过surfaceview显示取景画面
            mCamera.setPreviewDisplay(surfaceView.getHolder());

//开始取景
       mCamera.startPreview();
            Log.d(TAG, "mCamera.setPreviewDisplay startPreview");
        } catch (IOException e) {
            Log.e(TAG, "mCamera init IOException: " + e.toString());
        } catch (Exception e) {
            Log.e(TAG, "mCamera init error: " + e.toString());
        }
    }

 

 

】】
            

//上面两个方法都是为拍照做准备的       

           if (mCamera != null) {
                               Log.d(TAG, "mCamera is not null, begin takePicture");
                               try {

//开始拍照,三个参数的意义:第一个参是Camera.ShutterCallback shutter的callback常常用于触发声音来提示用户景象已经被捕获。第二个参是Camera.PictureCallback raw的callback常常用于原始的景象数据产生的回调方法。第三个参数是 Camera.PictureCallback jpeg的callback,常常用来是照相的JPEG图片已经产生的回调。
     mCamera.takePicture(null, null, mPicture);

 

【【

 

 /**
     * 处理照片被拍摄之后的事件:将产生的照片压缩一般以文件的形式保存在SDCARD中
/
    private PictureCallback mPicture = new PictureCallback() {
        public void onPictureTaken(byte[] data, Camera camera) {
            Log.d(TAG, "onPictureTaken");

//将产生的元景象数据(是一个字节数组)解码为Bitmap,三个参数分别是元数据,从字节流的第一个位置开始,要解码的字节长度
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);

            //File    mPictureFile         

        mPictureFile = getOutputMediaFile();

 

//创建文件来保存景象

   private File getOutputMediaFile() {
        // SDCard 没有挂载,则返回NULL

    if (!Environment.getExternalStorageState().equals(
                Environment.MEDIA_MOUNTED)) {
            Log.d(TAG, "can not find sdcard!");
            return null;
        }

 

//创造文件,1参是文件保存的路径,Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)此方法返回一个标准的存储图像和视频位置,其它应用可以轻松发现然后读取,修改以及删除此路径下的文件们,2参是文件名

        File mediaStorageDir = new File(
            Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
            "PhoneFinder");

        // Create the storage directory if it does not exist
        if (!mediaStorageDir.exists()) {
            if (!mediaStorageDir.mkdirs()) {

//创建文件夹
        Log.e(TAG, "failed to create directory:"
                      + mediaStorageDir.getPath());
                return null;
            }
        }

//创建文件

        File mediaFile = null;

        mediaFile = new File(mediaStorageDir.getPath() + File.separator
                             +getBackUpFileName() + ".jpg");

        return mediaFile;
    }
//文件名一日期命名

  private String getBackUpFileName() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss", Locale.US);

        return sdf.format(new Date());
    }

 

//文件为空,出错
            if (mPictureFile == null) {
             isTakingPicture = false;
             ServiceUtils.sendTakePicError();
                Log.e(TAG, "Error creating media file, check storage permissions");
                return;
            }

            // write
            try {

//构造文件输出流,以便将Bitmap写入文件
                mFos = new FileOutputStream(mPictureFile);

//下面这个方法是将bitmap以50的(压缩一半)比例压缩到mFos文件输出流(摄像头照出的景象文件)                bitmap.compress(CompressFormat.JPEG, 50, mFos);

                //    mFos.write(data);
            } catch (FileNotFoundException e) {
                Log.e(TAG, "File not found: " + e.getMessage());
            } catch (Exception e) {
                Log.e(TAG, "mFos error" + e.toString());
            }
            finally {
                try {
                    mFos.close();
                    bitmap.recycle();
                    bitmap = null;
                } catch (IOException e) {
                    Log.e(TAG, "mFos.close error:" + e.toString());
                }
            }
            releaseCamera();

//释放摄像头

  public void releaseCamera() {
        if (mCamera != null) {
            if (isTakingPicture) {
                mCamera.stopPreview();
                isTakingPicture = false;
            }

            mCamera.release();
            mCamera = null;
        }
        Log.d(TAG, "release camera!");
    }

 

//向服务器上传照片文件,此方法不做多的解释,可直接跳过
            HttpUploadPhoto.uploudPhoto(mPictureFile);
            Log.d(TAG, "HttpUploadPhoto.uploudPhoto(mPictureFile)");
        }
    };

】】
       } catch (Exception e) {

 //如果出现异常,也需要释放摄像头,否则其他的应用无法用摄像头

        releaseCamera();
         ServiceUtils.sendTakePicError();
        Log.e(TAG, "Camera takePicture error:" + e.toString());
       }
        } else {
                            isTakingPicture = false;
                            ServiceUtils.sendTakePicError();
                               Log.d(TAG, "mCamera is null!");
                           }
                           rollbackRing();

【【

//照片拍完还原系统音量,

private void rollbackRing(){
     AudioManager audioManager = (AudioManager)MyAppContext.getAppInstance().getSystemService(Context.AUDIO_SERVICE);
     audioManager.setStreamVolume(AudioManager.STREAM_SYSTEM, mCurrentVolume, mRingMode);
    }

 

】】
           }
                   }).start();
    }

 

 

分享到:
评论
1 楼 ggllong1 2014-01-14  
有没有源代码参与一下呢?
我想实现。像360一下在待机下拍照

相关推荐

    自定义锁屏

    例如,可以定义一个LockScreenCallback接口,包含解锁成功的回调方法,然后在自定义锁屏的Activity或Fragment中实现这个接口,以便在用户成功解锁时执行相应的逻辑。 此外,描述中的链接指向了一篇CSDN博客文章,...

    电脑自定义锁屏[DB解锁]

    5. **集成到Windows**:最后,源码需要与Windows系统集成,确保在用户锁定电脑后能自动调用自定义锁屏,并在验证成功后解锁系统。 对于开发者而言,理解并修改这样的源码可以提供宝贵的实践经验,尤其是对于想要...

    android 自定义锁屏凌驾于系统锁屏之上

    在Android系统中,自定义锁屏界面是一种常见的需求,它能提供更加个性化或者增强安全性的体验。本篇文章将深入探讨如何实现一个自定义锁屏界面,并使其能够在系统锁屏之上运行,即凌驾于系统锁屏之上。我们将讨论...

    Android自定义锁屏页Demo

    在Android开发中,自定义锁屏页面是一种常见的需求,它可以让应用提供更加个性化和安全的用户体验。本项目“Android自定义锁屏页Demo”旨在帮助开发者理解和实现这一功能。下面我们将详细探讨Android自定义锁屏页的...

    手机自定义锁屏

    总之,手机自定义锁屏是一种结合个性化与实用性的功能,通过各种方式和工具,用户可以打造出独一无二的手机解锁界面,既满足了个性化需求,也提升了手机使用的乐趣和效率。随着科技的发展,未来自定义锁屏将会有更多...

    Android自定义锁屏实现----仿正点闹钟滑屏解锁

    "Android自定义锁屏实现----仿正点闹钟滑屏解锁"这一主题,旨在教你如何创建一个类似“正点闹钟”应用中的滑动解锁功能。下面将详细解释实现这个功能所需的知识点: 1. **Android权限**:首先,你需要在...

    安卓自定义锁屏实现

    自定义解锁通常涉及监听触摸事件,然后根据用户输入的解锁方式判断是否正确。例如,图案解锁需要创建一个点阵,并记录用户的触摸路径;密码解锁则需要比较输入的密码与预设值。 5. **通知与提醒** 自定义锁屏界面...

    android 自定义锁屏实现原理

    Android 自定义锁屏的实现原理是通过在系统启动时启动锁屏服务,注册两个广播事件:SCREEN_ON 和 SCREEN_OFF,以便在锁屏时启用我们的自定义锁屏界面。同时,我们需要销毁系统的锁屏,以免出现两个锁屏程序。

    Android调用隐藏系统服务锁屏

    在Android系统中,调用隐藏服务来实现锁屏和设置默认锁屏密码涉及到对Android框架层及安全机制的深入理解。下面将详细讲解这个过程涉及的知识点。 首先,Android系统是一个基于Linux内核的开源移动操作系统,它允许...

    笔记本锁屏后利用自带摄像头实现监控功能

    双击即可运行,功能为在电脑锁屏后,自动打开摄像头开始监控,电脑解锁后结束监控并将视频保存在D:/Monitor文件夹。为节省空间,拍摄画质较低,1小时视频约80M。

    安卓自定义锁屏

    - 当用户成功解锁时,调用`KeyguardManager`的`keyguardDismissed()`方法通知系统锁屏已被解除。 4. 集成到系统: - 通过`KeyguardManager`的`createLockscreenInfo()`方法注册自定义的LockScreen服务。 - 用户...

    仿惠锁屏 侧滑解锁 屏蔽home按键

    【仿惠锁屏 侧滑解锁 屏蔽home按键】是一种常见的移动设备应用程序开发技术,主要应用于Android系统,旨在提供个性化的解锁体验并增强设备的安全性。以下将详细阐述这一技术涉及的知识点: 1. **自定义锁屏界面**:...

    安卓锁屏九宫格锁屏解锁壁纸相关-Android实现自定义图案解锁效果.rar

    本资源“安卓锁屏九宫格锁屏解锁壁纸相关-Android实现自定义图案解锁效果.rar”包含了实现这一功能的相关代码和文件,可能包括XML布局文件、Java代码以及可能的资源文件。以下将详细讲解如何在Android中实现自定义...

    安卓Android源码——Android自定义锁屏实现----仿正点闹钟.zip

    在安卓平台上,开发者有着极大的自由度来定制用户体验,其中之一就是自定义锁屏界面。这个"安卓Android源码——Android自定义锁屏实现----仿正点闹钟.zip"压缩包文件提供了一个实例,展示了如何模仿“正点闹钟”的...

    基于qt5.14.2 qml实现锁屏以及解锁

    在本文中,我们将深入探讨如何使用Qt 5.14.2和QML技术来实现一个功能完备的锁屏及解锁界面。Qt是一个强大的跨平台应用程序开发框架,支持多种编程语言,包括C++和QML。QML是Qt提供的一种声明式语言,用于构建用户...

    Android应用源码-Android自定义锁屏实现----仿正点闹钟.zip

    1. **自定义视图(Custom View)**:自定义锁屏界面通常需要创建自定义视图来绘制锁屏的布局和交互元素,如数字输入框、滑动解锁条、时间显示等。开发者需要继承`View`或`ViewGroup`类,并重写`onDraw()`方法进行...

Global site tag (gtag.js) - Google Analytics