Android 如何实现偷拍功能(手机关闭依然拍照)的教程
Android 偷拍功能/手机关闭能拍照
效果如下:
其实偷拍与偷录实现方式是一样的,都是使用到的WindowManager来绘制桌面小控件的原理。那我就不多说了…
一、首先我们需要一个SurfaceView:
<?xmlversion="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>
|
二、然后进行的操作就是生产这个小控件了:
publicPhotoWindowSmallView(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));
}
/**
* 将小悬浮窗的参数传入,用于更新小悬浮窗的位置。
*
* @param params 小悬浮窗的参数
*/
publicvoidsetParams(WindowManager.LayoutParams params) {
mParams = params;
}
|
三、那桌面控件有了,下面当然就是使用WindowManager添加到桌面上了:
/**
* 创建一个小悬浮窗。初始位置为屏幕的右部中间位置。
*
* @param context 必须为应用程序的Context.
*/
publicvoidcreateSmallWindow(Context context) {
mContext = context;
WindowManager windowManager = getWindowManager(context);
intscreenWidth = windowManager.getDefaultDisplay().getWidth();
intscreenHeight = windowManager.getDefaultDisplay().getHeight();
if(smallWindow ==null) {
smallWindow =newPhotoWindowSmallView(context);
if(smallWindowParams ==null) {
smallWindowParams =newLayoutParams();
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 必须为应用程序的Context.
*/
publicvoidremoveSmallWindow(Context context) {
if(smallWindow !=null) {
WindowManager windowManager = getWindowManager(context);
windowManager.removeView(smallWindow);
smallWindow =null;
}
}
|
四、这个时候我们需要的SurfaceView就有了,那么,怎么在后台进行操作呢?自然而然就想到了Service了
在Service中执行桌面控件的操作:
@Override
publicintonStartCommand(Intent intent,intflags,intstartId) {
myWindowManager =newMyPhotoWindowManager();
createWindow();
returnsuper.onStartCommand(intent, flags, startId);
}
@Override
publicvoidonDestroy() {
super.onDestroy();
}
privatevoidcreateWindow() {
// 当前界面是桌面,且没有悬浮窗显示,则创建悬浮窗。
myWindowManager.removeSmallWindow(getApplicationContext());
myWindowManager.createSmallWindow(getApplicationContext());
}
|
五、在activity中对Service绑定,进行拍照的操作
privateclassMyServiceConnimplementsServiceConnection {
@Override
publicvoidonServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
binder = (PhotoWindowService.myServiceBinder) service;
if(isVedio) {
binder.startCarema();
}else{
binder.stopCarema();
}
}
@Override
publicvoidonServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
}
}
|
六、在Service中控制myWindowManager中的拍照的开始和结束
publicclassmyServiceBinderextendsBinder {
publicvoidstartCarema() {
myWindowManager.startCarema();
}
publicvoidstopCarema() {
myWindowManager.stopCarema();
}
}
|
七、在MyPhotoWindowManager开启或终止拍照操作
publicvoidstartCarema() {
itt = InitTimetoTakePic.getInstance(mContext);
itt.initView(mSurfaceview);
itt.start();
}
publicvoidstopCarema() {
if(itt !=null)
itt.releaseCarema();
}
|
八、在InitTimetoTakePic进行拍照的相关处理
packagecom.ddv.www.candidphotodemo;
importandroid.annotation.TargetApi;
importandroid.app.Activity;
importandroid.content.Context;
importandroid.content.Intent;
importandroid.content.pm.PackageManager;
importandroid.hardware.Camera;
importandroid.hardware.Camera.AutoFocusCallback;
importandroid.hardware.Camera.PictureCallback;
importandroid.os.Build;
importandroid.os.Handler;
importandroid.os.Message;
importandroid.widget.FrameLayout;
importjava.io.File;
importjava.io.FileOutputStream;
/**
* 设置定时拍照功能
*
* @author <p>
* 创建定时拍照任务
* cameraType 摄像头
* resolutionString 分辨率
* tvSaveLocation 保存地址
* etExtension 拓展名
* cameraStart, 开始拍摄时间
* cameraNumber, 拍摄次数
* cameraStop 拍摄张数
*/
publicclassInitTimetoTakePic {
privatestaticInitTimetoTakePic mInstance;
privatestaticintcameraType =1;
Context mContext;
staticFrameLayout mSurfaceViewFrame;
privatestaticCamera mCamera;
privatestaticCameraPreview mPreview;
privatestaticString resolutionString ="1920x1080";
privatestaticString saveLocation = AppUtils.getSDCardPath();
privatestaticString extension ="JPG";
privatestaticString cameraStart ="1";
privatestaticString cameraNumber ="1";
privatestaticString cameraStop ="10";
privatestaticintnumber =0;
privatestaticbooleanclearVoice =false;
privateIntent intent;
privateInitTimetoTakePic(Context context) {
this.mContext = context;
}
publicsynchronizedstaticInitTimetoTakePic getInstance(Context context) {
mInstance =null;
mInstance =newInitTimetoTakePic(context);
returnmInstance;
}
publicvoidinitView(FrameLayout surfaceViewFrame) {
mSurfaceViewFrame = surfaceViewFrame;
}
/**
* 启动定时拍照并上传功能
*/
Handler mHandler =newHandler() {
@Override
publicvoidhandleMessage(Message msg) {
switch(msg.what) {
case1:
LogUtils.v("开始拍照");
initCarema();
break;
case2:
if(mCamera ==null) {
releaseCarema();
number =0;
mHandler.removeCallbacksAndMessages(null);
}else{
if(number < Integer.valueOf(cameraStop)) {
mCamera.autoFocus(newAutoFocusCallback() {
@Override
publicvoidonAutoFocus(booleansuccess, 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;
}
}
};
publicvoidstart() {
mHandler.sendEmptyMessageDelayed(1,1*1000);//7s 后开始启动相机
}
privatevoidinitCarema() {
LogUtils.v("initCarema");
if(mCamera ==null) {
LogUtils.v("camera=null");
mCamera = getCameraInstance();
mPreview =newCameraPreview(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后拍照
}
/**
* 检测设备是否存在Camera硬件
*/
privatebooleancheckCameraHardware(Context context) {
if(context.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_CAMERA)) {
// 存在
returntrue;
}else{
// 不存在
returnfalse;
}
}
/**
* 打开一个Camera
*/
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
publicstaticCamera getCameraInstance() {
Camera c =null;
try{
c = Camera.open(cameraType);
c.setDisplayOrientation(90);
Camera.Parameters mParameters = c.getParameters();
//快门声音
c.enableShutterSound(clearVoice);
//可以用得到当前所支持的照片大小,然后
//List<Size> ms = mParameters.getSupportedPictureSizes();
//mParameters.setPictureSize(ms.get(0).width, ms.get(0).height); //默认最大拍照取最大清晰度的照片
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]));//默认最大拍照取最大清晰度的照片
c.setParameters(mParameters);
}catch(Exception e) {
LogUtils.v("打开Camera失败失败");
}
returnc;
}
privatePictureCallback mPicture =newPictureCallback() {
@Override
publicvoidonPictureTaken(byte[] data, Camera camera) {
// 获取Jpeg图片,并保存在sd卡上
String path = saveLocation;
File dirF =newFile(path);
if(!dirF.exists()) {
dirF.mkdirs();
}
File pictureFile =newFile(path +"/"+ System.currentTimeMillis() +"."+ extension);//扩展名
try{
FileOutputStream fos =newFileOutputStream(pictureFile);
fos.write(data);
fos.close();
LogUtils.v("保存图成功");
number++;
intent =newIntent();
intent.setAction("CameraFragment.start");
intent.putExtra("number", number);
mContext.sendBroadcast(intent);
}catch(Exception e) {
LogUtils.v("保存图片失败");
e.printStackTrace();
}
releaseCarema();
}
};
publicvoidreleaseCarema() {
if(mCamera !=null) {
mCamera.stopPreview();
mCamera.release();
mCamera =null;
}
}
}
|
Android 7.0调用相机崩溃解决办法
错误提示:
android.os.FileUriExposedException: file:///storage/emulated/0/DCIM/IMG_1041503431.jpg exposed beyond app through ClipData.Item.getUri()
|
处理方式
/**
* Open camera
*/
privatevoidshowCameraAction() {
if(ContextCompat.checkSelfPermission(getContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
requestPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE,
getString(R.string.mis_permission_rationale_write_storage),
REQUEST_STORAGE_WRITE_ACCESS_PERMISSION);
}else{
Intent intent =newIntent(MediaStore.ACTION_IMAGE_CAPTURE);
if(intent.resolveActivity(getActivity().getPackageManager()) !=null) {
try{
mTmpFile = FileUtils.createTmpFile(getActivity());
}catch(IOException e) {
e.printStackTrace();
}
if(mTmpFile !=null&& mTmpFile.exists()) {
/*获取当前系统的android版本号*/
intcurrentapiVersion = android.os.Build.VERSION.SDK_INT;
Log.e("currentapiVersion","currentapiVersion====>"+currentapiVersion);
if(currentapiVersion<24){
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mTmpFile));
startActivityForResult(intent, REQUEST_CAMERA);
}else{
ContentValues contentValues =newContentValues(1);
contentValues.put(MediaStore.Images.Media.DATA, mTmpFile.getAbsolutePath());
Uri uri = getContext().getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,contentValues);
intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
startActivityForResult(intent, REQUEST_CAMERA);
}
}else{
Toast.makeText(getActivity(), R.string.mis_error_image_not_exist, Toast.LENGTH_SHORT).show();
}
}else{
Toast.makeText(getActivity(), R.string.mis_msg_no_camera, Toast.LENGTH_SHORT).show();
}
}
}
|
原文链接:http://blog.csdn.net/huangxiaoguo1/article/details/52830015
小米手机自带了一些如手机找回服务、备份等服务。MIUI的老用户都知道这些功能需要进“小米云服务”里设置,但是系统改版之后很多人都找不到小米云服务在哪里打开了。本文小编就为大家带来小米云服务在哪里打开的介绍教程,有需要的朋友一起看看吧。新版MIUI小米云服务设置教程:
1、下拉通知栏,在搜索框里搜索【我的小米】,并点击打开。
2、点击【云服务】,这就时旧版小米云服务的设置位置啦,以前云服务的设置选项已经全部搬迁到了“我的小米”里面。
以上就是小米手机云服务在哪里的介绍教程了,有需要设置云服务配置的朋友快点拿出手机按照教程来尝试一下吧。
Android GridView滑动条怎么设置一直显示状态?小编给大家推荐一篇文章,详细介绍了Android GridView的滑动条设置怎么一直显示状态,非常具有参考价值,希望大家喜欢模拟GridView控件:
<GridView
android:id="@+id/picture_grid"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:columnWidth="100dp"
android:numColumns="auto_fit"
android:gravity="center"
android:verticalSpacing="8dp"
android:horizontalSpacing="10dp"
android:stretchMode="columnWidth"
android:fadeScrollbars="false"/>
|
设置GridView滑动条一直显示状态:
android:fadeScrollbars="false"
|
以上所述是小编给大家介绍的Android GridView 滑动条设置一直显示状态,希望对大家有所帮助。
相关文章
- 下面我们来看一篇关于Android子控件超出父控件的范围显示出来方法,希望这篇文章能够帮助到各位朋友,有碰到此问题的朋友可以进来看看哦。 <RelativeLayout xmlns:an...2016-10-02
Android开发中findViewById()函数用法与简化
findViewById方法在android开发中是获取页面控件的值了,有没有发现我们一个页面控件多了会反复研究写findViewById呢,下面我们一起来看它的简化方法。 Android中Fin...2016-09-20- 如果我们的项目需要做来电及短信的功能,那么我们就得在Android模拟器开发这些功能,本来就来告诉我们如何在Android模拟器上模拟来电及来短信的功能。 在Android模拟...2016-09-20
- 夜神android模拟器如何设置代理呢?对于这个问题其实操作起来是非常的简单,下面小编来为各位详细介绍夜神android模拟器设置代理的方法,希望例子能够帮助到各位。 app...2016-09-20
- 为了增强android应用的用户体验,我们可以在一些Button按钮上自定义动态的设置一些样式,比如交互时改变字体、颜色、背景图等。 今天来看一个通过重写Button来动态实...2016-09-20
- 如果我们要在Android应用APP中加载html5页面,我们可以使用WebView,本文我们分享两个WebView加载html5页面实例应用。 实例一:WebView加载html5实现炫酷引导页面大多...2016-09-20
- 深入理解Android中View和ViewGroup从组成架构上看,似乎ViewGroup在View之上,View需要继承ViewGroup,但实际上不是这样的。View是基类,ViewGroup是它的子类。本教程我们深...2016-09-20
- 下面我们来看一篇关于Android自定义WebView网络视频播放控件开发例子,这个文章写得非常的不错下面给各位共享一下吧。 因为业务需要,以下代码均以Youtube网站在线视...2016-10-02
- java开发的Android应用,性能一直是一个大问题,,或许是Java语言本身比较消耗内存。本文我们来谈谈Android 性能优化之MemoryFile文件读写。 Android匿名共享内存对外A...2016-09-20
- TextView默认是横着显示了,今天我们一起来看看Android设置TextView竖着显示如何来实现吧,今天我们就一起来看看操作细节,具体的如下所示。 在开发Android程序的时候,...2016-10-02
android.os.BinderProxy cannot be cast to com解决办法
本文章来给大家介绍关于android.os.BinderProxy cannot be cast to com解决办法,希望此文章对各位有帮助呀。 Android在绑定服务的时候出现java.lang.ClassCastExc...2016-09-20- 这篇文章主要介绍了Android 实现钉钉自动打卡功能的步骤,帮助大家更好的理解和学习使用Android,感兴趣的朋友可以了解下...2021-03-15
- 下面我们来看一篇关于Android 开发之布局细节对比:RTL模式 ,希望这篇文章对各位同学会带来帮助,具体的细节如下介绍。 前言 讲真,好久没写博客了,2016都过了一半了,赶紧...2016-10-02
- 首先如果要在程序中使用sdcard进行存储,我们必须要在AndroidManifset.xml文件进行下面的权限设置: 在AndroidManifest.xml中加入访问SDCard的权限如下: <!--...2016-09-20
- 下面来给各位简单的介绍一下关于Android开发之PhoneGap打包及错误解决办法,希望碰到此类问题的同学可进入参考一下哦。 在我安装、配置好PhoneGap项目的所有依赖...2016-09-20
用Intel HAXM给Android模拟器Emulator加速
Android 模拟器 Emulator 速度真心不给力,, 现在我们来介绍使用 Intel HAXM 技术为 Android 模拟器加速,使模拟器运行度与真机比肩。 周末试玩了一下在Eclipse中使...2016-09-20- 在安卓开发时我碰到一个问题就是需要实现全屏,但又需要我们来判断出用户是使用了全屏或非全屏了,下面我分别找了两段代码,大家可参考。 先来看一个android屏幕全屏实...2016-09-20
Android开发中布局中的onClick简单完成多控件时的监听的利与弊
本文章来为各位介绍一篇关于Android开发中布局中的onClick简单完成多控件时的监听的利与弊的例子,希望这个例子能够帮助到各位朋友. 首先在一个控件加上这么一句:and...2016-09-20- 这篇文章主要介绍了C#实现图片放大功能的按照像素放大图像方法,功能非常实用,需要的朋友可以参考下...2020-06-25
Ubuntu 系统下安装Android开发环境 Android Studio 1.0 步骤
Android Studio 是一个Android开发环境,基于IntelliJ IDEA. 类似 Eclipse ADT,Android Studio 提供了集成的 Android 开发工具用于开发和调试,可以在Linux,Mac OS X,Window...2016-09-20