zoukankan      html  css  js  c++  java
  • Android使用百度地图定位并显示手机位置后使用前置摄像头“偷拍”

    今天老板让我验证一下技术可行性,记录下来。

    需求 :定位手机的位置并在百度地图上显示,得到位置后使用前置摄像头进行抓拍


    拿到这个需求后,对于摄像头的使用不太熟悉,于是我先做了定位手机并在百度地图上显示的功能


    访问了百度地图api官网http://lbsyun.baidu.com/找到Android地图以及定位使用部分,官网上有详尽的使用指南,这里只简单总结描述一下,首先复制粘贴jar包和so文件

    如图,jar包文件最好与so文件版本一致

      1 package com.agile.androiddgs.activity;
      2 
      3 import android.Manifest;
      4 import android.annotation.TargetApi;
      5 import android.app.Activity;
      6 import android.content.pm.PackageManager;
      7 import android.graphics.Bitmap;
      8 import android.graphics.BitmapFactory;
      9 import android.hardware.Camera;
     10 import android.media.MediaScannerConnection;
     11 import android.net.Uri;
     12 import android.os.Build;
     13 import android.os.Bundle;
     14 import android.os.Handler;
     15 import android.util.Log;
     16 import android.view.Surface;
     17 import android.view.SurfaceHolder;
     18 import android.view.SurfaceView;
     19 import android.view.Window;
     20 
     21 import com.agile.androiddgs.R;
     22 import com.baidu.location.BDLocation;
     23 import com.baidu.location.BDLocationListener;
     24 import com.baidu.location.LocationClient;
     25 import com.baidu.location.LocationClientOption;
     26 import com.baidu.mapapi.SDKInitializer;
     27 import com.baidu.mapapi.map.BaiduMap;
     28 import com.baidu.mapapi.map.BitmapDescriptor;
     29 import com.baidu.mapapi.map.MapStatusUpdate;
     30 import com.baidu.mapapi.map.MapStatusUpdateFactory;
     31 import com.baidu.mapapi.map.MapView;
     32 import com.baidu.mapapi.map.MyLocationData;
     33 import com.baidu.mapapi.model.LatLng;
     34 import com.baidu.mapapi.search.core.SearchResult;
     35 import com.baidu.mapapi.search.geocode.GeoCodeResult;
     36 import com.baidu.mapapi.search.geocode.GeoCoder;
     37 import com.baidu.mapapi.search.geocode.OnGetGeoCoderResultListener;
     38 import com.baidu.mapapi.search.geocode.ReverseGeoCodeOption;
     39 import com.baidu.mapapi.search.geocode.ReverseGeoCodeResult;
     40 
     41 import java.io.ByteArrayInputStream;
     42 import java.io.ByteArrayOutputStream;
     43 import java.util.ArrayList;
     44 import java.util.List;
     45 
     46 public class PositionActivity extends Activity implements OnGetGeoCoderResultListener{
     47     /**********************百度地图定位以及地图功能*********************************/
     48     private String permissionInfo;
     49     private final int SDK_PERMISSION_REQUEST = 127;
     50     private MapView mapView = null;
     51     private BaiduMap baiduMap = null;
     52 
     53     // 定位相关声明
     54     private LocationClient locationClient = null;
     55     //自定义图标
     56     private BitmapDescriptor mCurrentMarker = null;
     57     private boolean isFirstLoc = true;// 是否首次定位
     58 
     59     GeoCoder mSearch = null; // 搜索模块,也可去掉地图模块独立使用
     60 
     61     private BDLocationListener myListener = new BDLocationListener() {
     62         @Override
     63         public void onReceiveLocation(BDLocation location) {//定位成功
     64             // map view 销毁后不在处理新接收的位置
     65             if (location == null || mapView == null)
     66                 return;
     67             try {
     68                mSearch.reverseGeoCode(new ReverseGeoCodeOption().location(new LatLng(location.getLatitude(), location.getLongitude())));
     69 
     70             }catch (Exception e){
     71                 e.printStackTrace();
     72             }
     73 
     74             MyLocationData locData = new MyLocationData.Builder()
     75                     .accuracy(location.getRadius())
     76                     // 此处设置开发者获取到的方向信息,顺时针0-360
     77                     .direction(100).latitude(location.getLatitude())
     78                     .longitude(location.getLongitude()).build();
     79             baiduMap.setMyLocationData(locData);    //设置定位数据
     80 
     81 
     82             if (isFirstLoc) {//第一次定位
     83                 isFirstLoc = false;
     84 
     85 
     86                 LatLng ll = new LatLng(location.getLatitude(),
     87                         location.getLongitude());
     88                 MapStatusUpdate u = MapStatusUpdateFactory.newLatLngZoom(ll, 16);    //设置地图中心点以及缩放级别
     89 //                MapStatusUpdate u = MapStatusUpdateFactory.newLatLng(ll);
     90                 baiduMap.animateMapStatus(u);
     91             }
     92         }
     93     };
     94 
     95     /**********************************摄像头***********************************************/
     96     private SurfaceView mySurfaceView;
     97     private SurfaceHolder myHolder;
     98     private Camera myCamera;
     99     int mCurrentCamIndex = 0;
    100 
    101     @Override
    102     protected void onCreate(Bundle savedInstanceState) {
    103         super.onCreate(savedInstanceState);
    104         // after andrioid m,must request Permiision on runtime
    105         getPersimmions();
    106         requestWindowFeature(Window.FEATURE_NO_TITLE);
    107         // 在使用SDK各组件之前初始化context信息,传入ApplicationContext
    108         // 注意该方法要再setContentView方法之前实现
    109         SDKInitializer.initialize(getApplicationContext());
    110         setContentView(R.layout.activity_position);
    111 
    112         // 初始化搜索模块,注册事件监听
    113         mSearch = GeoCoder.newInstance();
    114 
    115         mapView = (MapView) this.findViewById(R.id.mapView); // 获取地图控件引用
    116         baiduMap = mapView.getMap();
    117         //开启定位图层
    118         baiduMap.setMyLocationEnabled(true);
    119 
    120         locationClient = new LocationClient(getApplicationContext()); // 实例化LocationClient类
    121         locationClient.registerLocationListener(myListener); // 注册监听函数
    122         this.setLocationOption();    //设置定位参数
    123         locationClient.start(); // 开始定位
    124         // baiduMap.setMapType(BaiduMap.MAP_TYPE_NORMAL); // 设置为一般地图
    125 
    126         // baiduMap.setMapType(BaiduMap.MAP_TYPE_SATELLITE); //设置为卫星地图
    127         // baiduMap.setTrafficEnabled(true); //开启交通图
    128       
    129     }
    130 
    131     @TargetApi(23)
    132     private void getPersimmions() {
    133         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    134             ArrayList<String> permissions = new ArrayList<String>();
    135             /***
    136              * 定位权限为必须权限,用户如果禁止,则每次进入都会申请
    137              */
    138             // 定位精确位置
    139             if(checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED){
    140                 permissions.add(Manifest.permission.ACCESS_FINE_LOCATION);
    141             }
    142             if(checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED){
    143                 permissions.add(Manifest.permission.ACCESS_COARSE_LOCATION);
    144             }
    145             /*
    146              * 读写权限和电话状态权限非必要权限(建议授予)只会申请一次,用户同意或者禁止,只会弹一次
    147              */
    148             // 读写权限
    149             if (addPermission(permissions, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
    150                 permissionInfo += "Manifest.permission.WRITE_EXTERNAL_STORAGE Deny 
    ";
    151             }
    152             // 读取电话状态权限
    153             if (addPermission(permissions, Manifest.permission.READ_PHONE_STATE)) {
    154                 permissionInfo += "Manifest.permission.READ_PHONE_STATE Deny 
    ";
    155             }
    156 
    157             if (permissions.size() > 0) {
    158                 requestPermissions(permissions.toArray(new String[permissions.size()]), SDK_PERMISSION_REQUEST);
    159             }
    160         }
    161     }
    162 
    163     @TargetApi(23)
    164     private boolean addPermission(ArrayList<String> permissionsList, String permission) {
    165         if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) { // 如果应用没有获得对应权限,则添加到列表中,准备批量申请
    166             if (shouldShowRequestPermissionRationale(permission)){
    167                 return true;
    168             }else{
    169                 permissionsList.add(permission);
    170                 return false;
    171             }
    172 
    173         }else{
    174             return true;
    175         }
    176     }
    177 
    178     @TargetApi(23)
    179     @Override
    180     public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    181         // TODO Auto-generated method stub
    182         super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    183 
    184     }
    185 
    186     // 三个状态实现地图生命周期管理
    187     @Override
    188     protected void onDestroy() {
    189         //退出时销毁定位
    190         locationClient.stop();
    191         baiduMap.setMyLocationEnabled(false);
    192         // TODO Auto-generated method stub
    193         super.onDestroy();
    194         mapView.onDestroy();
    195         mapView = null;
    196     }
    197 
    198     @Override
    199     protected void onResume() {
    200         // TODO Auto-generated method stub
    201         super.onResume();
    202         mapView.onResume();
    203     }
    204 
    205     @Override
    206     protected void onPause() {
    207         // TODO Auto-generated method stub
    208         super.onPause();
    209         mapView.onPause();
    210     }
    211 
    212 
    213 
    214     /**
    215      * 设置定位参数
    216      */
    217     private void setLocationOption() {
    218         LocationClientOption option = new LocationClientOption();
    219         option.setOpenGps(true); // 打开GPS
    220         option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);// 设置定位模式
    221         option.setCoorType("bd09ll"); // 返回的定位结果是百度经纬度,默认值gcj02
    222         option.setScanSpan(5000); // 设置发起定位请求的间隔时间为5000ms
    223         option.setIsNeedAddress(true); // 返回的定位结果包含地址信息
    224         option.setNeedDeviceDirect(true); // 返回的定位结果包含手机机头的方向
    225 
    226         locationClient.setLocOption(option);
    227     }
    228 
    229     
    230     @Override
    231     public void onGetGeoCodeResult(GeoCodeResult geoCodeResult) {
    232 
    233     }
    234     /**
    235     根据经纬度反编为具体地址
    236 */
    237     @Override
    238     public void onGetReverseGeoCodeResult(ReverseGeoCodeResult reverseGeoCodeResult) {
    239         if (reverseGeoCodeResult == null || reverseGeoCodeResult.error != SearchResult.ERRORNO.NO_ERROR)
    240         {
    241             return;
    242         }
    243 
    244         String address =  reverseGeoCodeResult.getAddress();
    245     }
    246 
    247 
    248 }

    上面是定位以及百度地图的使用,下面是摄像头的使用,以及图片压缩(本文使用质量压缩)

     1 //初始化surfaceview
     2         new Thread(new Runnable() {
     3             @Override
     4             public void run() {
     5 
     6                 mySurfaceView = (SurfaceView) findViewById(R.id.camera_surfaceview);
     7 
     8                 //初始化surfaceholder
     9                 myHolder = mySurfaceView.getHolder();
    10                 myHolder.addCallback(new SurfaceViewCallback());
    11                 myHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    12 
    13             }
    14         }).start();

    在onCreate()方法中另外开启一个线程,用来偷偷的拍照,初始化SurfaceView并为SurfaceView设置callBack方法

      1 /***************************************************************************************/
      2     private final class SurfaceViewCallback implements android.view.SurfaceHolder.Callback {
      3         public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3)
      4         {
      5 
      6             try {
      7                 myCamera.setPreviewDisplay(arg0);
      8                 myCamera.startPreview();
      9                 setCameraDisplayOrientation(PositionActivity.this, mCurrentCamIndex, myCamera);
     10                 new Handler().postDelayed(new Runnable(){
     11 
     12                     public void run() {
     13               //拍照
     14                         myCamera.takePicture(shutterCallback, rawPictureCallback,
     15                                 jpegPictureCallback);
     16                     }
     17 
     18                 }, 5000);
     19 
     20             } catch (Exception e) {
     21                 e.printStackTrace();
     22             }
     23         }
     24         public void surfaceCreated(SurfaceHolder holder) {
     25 //                mCamera = Camera.open();
     26             //change to front camera
     27             myCamera = openFrontFacingCameraGingerbread();
     28             // get Camera parameters
     29             Camera.Parameters params = myCamera.getParameters();
     30 
     31             List<String> focusModes = params.getSupportedFocusModes();
     32             if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
     33                 // Autofocus mode is supported
     34             }
     35         }
     36 
     37         public void surfaceDestroyed(SurfaceHolder holder) {
     38             myCamera.stopPreview();
     39             myCamera.release();
     40             myCamera = null;
     41         }
     42     }
     43 
     44     //根据横竖屏自动调节preview方向,Starting from API level 14, this method can be called when preview is active.
     45     private static void setCameraDisplayOrientation(Activity activity,int cameraId, Camera camera)
     46     {
     47         Camera.CameraInfo info = new Camera.CameraInfo();
     48         Camera.getCameraInfo(cameraId, info);
     49         int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
     50 
     51         //degrees  the angle that the picture will be rotated clockwise. Valid values are 0, 90, 180, and 270.
     52         //The starting position is 0 (landscape).
     53         int degrees = 0;
     54         switch (rotation)
     55         {
     56             case Surface.ROTATION_0: degrees = 0; break;
     57             case Surface.ROTATION_90: degrees = 90; break;
     58             case Surface.ROTATION_180: degrees = 180; break;
     59             case Surface.ROTATION_270: degrees = 270; break;
     60         }
     61         int result;
     62         if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT)
     63         {
     64             result = (info.orientation + degrees) % 360;
     65             result = (360 - result) % 360;  // compensate the mirror
     66         }
     67         else
     68         {
     69             // back-facing
     70             result = (info.orientation - degrees + 360) % 360;
     71         }
     72         camera.setDisplayOrientation(result);
     73     }
     74 
     75     public void scanFileToPhotoAlbum(String path) {
     76 
     77         MediaScannerConnection.scanFile(PositionActivity.this,
     78                 new String[] { path }, null,
     79                 new MediaScannerConnection.OnScanCompletedListener() {
     80 
     81                     public void onScanCompleted(String path, Uri uri) {
     82                         Log.i("TAG", "Finished scanning " + path);
     83                     }
     84                 });
     85     }
     86 
     87     private Camera openFrontFacingCameraGingerbread() {
     88         int cameraCount = 0;
     89         Camera cam = null;
     90         Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
     91         cameraCount = Camera.getNumberOfCameras();
     92 
     93         for (int camIdx = 0; camIdx < cameraCount; camIdx++) {
     94             Camera.getCameraInfo(camIdx, cameraInfo);
     95             if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
     96                 try {
     97                     cam = Camera.open(camIdx);
     98                     mCurrentCamIndex = camIdx;
     99                 } catch (RuntimeException e) {
    100                     e.printStackTrace();
    101                 }
    102             }
    103         }
    104 
    105         return cam;
    106     }
    107 
    108     Camera.ShutterCallback shutterCallback = new Camera.ShutterCallback() {
    109         @Override
    110         public void onShutter() {
    111         }
    112     };
    113 
    114     Camera.PictureCallback rawPictureCallback = new Camera.PictureCallback() {
    115         @Override
    116         public void onPictureTaken(byte[] arg0, Camera arg1) {
    117 
    118         }
    119     };
    120 
    121     Camera.PictureCallback jpegPictureCallback = new Camera.PictureCallback() {
    122         @Override
    123         public void onPictureTaken(byte[] arg0, Camera arg1) {
    124             ByteArrayOutputStream baos = new ByteArrayOutputStream();
    125 
    126             int options = 100;
    127             ByteArrayInputStream isBm = new ByteArrayInputStream(arg0);//把压缩后的数据baos存放到ByteArrayInputStream中
    128             Bitmap bitmap = BitmapFactory.decodeStream(isBm, null, null);//把ByteArrayInputStr
    129 
    130             bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);//质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中
    131 
    132 
    133             while ( baos.toByteArray().length / 1024>1) {  //循环判断如果压缩后图片是否大于100kb,大于继续压缩
    134                 baos.reset();//重置baos即清空baos
    135                 bitmap.compress(Bitmap.CompressFormat.JPEG, options, baos);//这里压缩options%,把压缩后的数据存放到baos中
    136                 options -= 10;//每次都减少10
    137             }
    138 
    139             /*String fileName = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)
    140                     .toString()
    141                     + File.separator
    142                     + "PicTest_" + System.currentTimeMillis() + ".jpg";
    143             File file = new File(fileName);
    144             if (!file.getParentFile().exists()) {
    145                 file.getParentFile().mkdir();
    146             }
    147 
    148             try {
    149                 BufferedOutputStream bos = new BufferedOutputStream(
    150                         new FileOutputStream(file));
    151                 bos.write(arg0);
    152                 bos.flush();
    153                 bos.close();
    154                 scanFileToPhotoAlbum(file.getAbsolutePath());
    155                 Toast.makeText(PositionActivity.this, "[Test] Photo take and store in" + file.toString(), Toast.LENGTH_LONG).show();
    156             } catch (Exception e) {
    157                 Toast.makeText(PositionActivity.this, "Picture Failed" + e.toString(),
    158                         Toast.LENGTH_LONG).show();
    159                 e.printStackTrace();
    160             }*/
    161         };
    162     };

    布局文件如下

     1 <?xml version="1.0" encoding="utf-8"?>
     2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     3     android:layout_width="fill_parent"
     4     android:layout_height="fill_parent"
     5     android:orientation="vertical" >
     6     <LinearLayout
     7         android:layout_width="fill_parent"
     8         android:layout_height="fill_parent"
     9         android:orientation="vertical" >
    10         <!-- 添加地图控件 -->
    11         <com.baidu.mapapi.map.MapView
    12             android:id="@+id/mapView"
    13             android:layout_width="fill_parent"
    14             android:layout_height="fill_parent"
    15             android:clickable="true" />
    16     </LinearLayout>
    17 
    18     <!-- 预览框,长宽都为0.1 -->
    19     <SurfaceView
    20         android:id="@+id/camera_surfaceview"
    21         android:layout_width="0.1dp"
    22         android:layout_height="0.1dp" >
    23     </SurfaceView>
    24 </LinearLayout>

    在布局文件中地图视图占据了整个屏幕,而摄像头预览图不可见,但是存在着,打开之后会开启一个新的线程用来偷偷使用前置摄像头拍照

  • 相关阅读:
    mysql 账户管理
    关于数据库设计的思考(三)
    学习 ThinkPHP 框架笔记
    学习 Ext Js 所感
    mysql 一个较特殊的问题:You can't specify target table 'wms_cabinet_form' for update in FROM clause
    关于数据库设计的思考(二)
    flash、flex 项目开发学习时的笔记
    web.config 中SessionState的配置
    公农历转换
    使用Microsoft Web Application Stress Tool对web进行压力测试
  • 原文地址:https://www.cnblogs.com/wangle12138/p/6024493.html
Copyright © 2011-2022 走看看