前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android使用百度地图定位并显示手机位置后使用前置摄像头“偷拍”

Android使用百度地图定位并显示手机位置后使用前置摄像头“偷拍”

作者头像
LoveWFan
发布2018-08-07 15:57:49
1.4K0
发布2018-08-07 15:57:49
举报
文章被收录于专栏:Android中高级开发

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

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

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

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

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

代码语言:javascript
复制
  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 \n";
151             }
152             // 读取电话状态权限
153             if (addPermission(permissions, Manifest.permission.READ_PHONE_STATE)) {
154                 permissionInfo += "Manifest.permission.READ_PHONE_STATE Deny \n";
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 }

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

代码语言:javascript
复制
 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方法

代码语言:javascript
复制
  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     };

布局文件如下

代码语言:javascript
复制
 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>

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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2016-11-07 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
图片处理
图片处理(Image Processing,IP)是由腾讯云数据万象提供的丰富的图片处理服务,广泛应用于腾讯内部各产品。支持对腾讯云对象存储 COS 或第三方源的图片进行处理,提供基础处理能力(图片裁剪、转格式、缩放、打水印等)、图片瘦身能力(Guetzli 压缩、AVIF 转码压缩)、盲水印版权保护能力,同时支持先进的图像 AI 功能(图像增强、图像标签、图像评分、图像修复、商品抠图等),满足多种业务场景下的图片处理需求。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档