Android 偷拍功能实现(手机关闭依然拍照)详解及实例代码

 Android 偷拍功能/手机关闭能拍照

效果如下:

其实偷拍与偷录实现方式是一样的,都是使用到的WindowManager来绘制桌面小控件的原理。那我就不多说了…

一、首先我们需要一个SurfaceView:

<?xml version="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>

二、然后进行的操作就是生产这个小控件了:

public PhotoWindowSmallView(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 小悬浮窗的参数
   */
  public void setParams(WindowManager.LayoutParams params) {
    mParams = params;
  }

三、那桌面控件有了,下面当然就是使用WindowManager添加到桌面上了:

 /**
     * 创建一个小悬浮窗。初始位置为屏幕的右部中间位置。
     *
     * @param context 必须为应用程序的Context.
     */
    public void createSmallWindow(Context context) {
      mContext = context;
      WindowManager windowManager = getWindowManager(context);
      int screenWidth = windowManager.getDefaultDisplay().getWidth();
      int screenHeight = windowManager.getDefaultDisplay().getHeight();
      if (smallWindow == null) {
        smallWindow = new PhotoWindowSmallView(context);
        if (smallWindowParams == null) {
          smallWindowParams = new LayoutParams();
          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.
     */
    public void removeSmallWindow(Context context) {
      if (smallWindow != null) {
        WindowManager windowManager = getWindowManager(context);
        windowManager.removeView(smallWindow);
        smallWindow = null;
      }
    }

四、这个时候我们需要的SurfaceView就有了,那么,怎么在后台进行操作呢?自然而然就想到了Service了

在Service中执行桌面控件的操作:

 @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
    myWindowManager = new MyPhotoWindowManager();
    createWindow();
    return super.onStartCommand(intent, flags, startId);
  }

  @Override
  public void onDestroy() {
    super.onDestroy();

  }

  private void createWindow() {
    // 当前界面是桌面,且没有悬浮窗显示,则创建悬浮窗。
    myWindowManager.removeSmallWindow(getApplicationContext());
    myWindowManager.createSmallWindow(getApplicationContext());

  }

五、在activity中对Service绑定,进行拍照的操作

private class MyServiceConn implements ServiceConnection {

    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
      // TODO Auto-generated method stub
      binder = (PhotoWindowService.myServiceBinder) service;
      if (isVedio) {
        binder.startCarema();
      } else {
        binder.stopCarema();
      }
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
      // TODO Auto-generated method stub
    }

  }

六、在Service中控制myWindowManager中的拍照的开始和结束

 public class myServiceBinder extends Binder {
    public void startCarema() {
      myWindowManager.startCarema();
    }

    public void stopCarema() {
      myWindowManager.stopCarema();
    }
  }

七、在MyPhotoWindowManager开启或终止拍照操作

 public void startCarema() {
    itt = InitTimetoTakePic.getInstance(mContext);
    itt.initView(mSurfaceview);
    itt.start();
  }

  public void stopCarema() {
    if (itt != null)
      itt.releaseCarema();
  }

八、在InitTimetoTakePic进行拍照的相关处理

package com.ddv.www.candidphotodemo;

import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.hardware.Camera;
import android.hardware.Camera.AutoFocusCallback;
import android.hardware.Camera.PictureCallback;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.widget.FrameLayout;

import java.io.File;
import java.io.FileOutputStream;

/**
 * 设置定时拍照功能
 *
 * @author <p>
 *     创建定时拍照任务
 *     cameraType 摄像头
 *     resolutionString 分辨率
 *     tvSaveLocation 保存地址
 *     etExtension 拓展名
 *     cameraStart, 开始拍摄时间
 *     cameraNumber, 拍摄次数
 *     cameraStop 拍摄张数
 */
public class InitTimetoTakePic {

  private static InitTimetoTakePic mInstance;
  private static int cameraType = 1;
  Context mContext;
  static FrameLayout mSurfaceViewFrame;
  private static Camera mCamera;
  private static CameraPreview mPreview;
  private static String resolutionString = "1920x1080";
  private static String saveLocation = AppUtils.getSDCardPath();
  private static String extension = "JPG";
  private static String cameraStart = "1";
  private static String cameraNumber = "1";
  private static String cameraStop = "10";
  private static int number = 0;
  private static boolean clearVoice = false;
  private Intent intent;

  private InitTimetoTakePic(Context context) {
    this.mContext = context;
  }

  public synchronized static InitTimetoTakePic getInstance(Context context) {
    mInstance = null;
    mInstance = new InitTimetoTakePic(context);

    return mInstance;
  }

  public void initView(FrameLayout surfaceViewFrame) {
    mSurfaceViewFrame = surfaceViewFrame;
  }

  /**
   * 启动定时拍照并上传功能
   */
  Handler mHandler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
      switch (msg.what) {
        case 1:
          LogUtils.v("开始拍照");
          initCarema();
          break;
        case 2:
          if (mCamera == null) {
            releaseCarema();
            number = 0;
            mHandler.removeCallbacksAndMessages(null);
          } else {
            if (number < Integer.valueOf(cameraStop)) {
              mCamera.autoFocus(new AutoFocusCallback() {
                @Override
                public void onAutoFocus(boolean success, 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;
      }
    }
  };

  public void start() {
    mHandler.sendEmptyMessageDelayed(1, 1 * 1000); //7s 后开始启动相机
  }

  private void initCarema() {
    LogUtils.v("initCarema");
    if (mCamera == null) {
      LogUtils.v("camera=null");
      mCamera = getCameraInstance();
      mPreview = new CameraPreview(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硬件
   */
  private boolean checkCameraHardware(Context context) {
    if (context.getPackageManager().hasSystemFeature(
        PackageManager.FEATURE_CAMERA)) {
      // 存在
      return true;
    } else {
      // 不存在
      return false;
    }
  }

  /**
   * 打开一个Camera
   */
  @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
  public static Camera 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失败失败");
    }
    return c;
  }

  private PictureCallback mPicture = new PictureCallback() {

    @Override
    public void onPictureTaken(byte[] data, Camera camera) {
      // 获取Jpeg图片,并保存在sd卡上
      String path = saveLocation;
      File dirF = new File(path);
      if (!dirF.exists()) {
        dirF.mkdirs();
      }
      File pictureFile = new File(path + "/" + System.currentTimeMillis() + "." + extension);//扩展名
      try {
        FileOutputStream fos = new FileOutputStream(pictureFile);
        fos.write(data);
        fos.close();

        LogUtils.v("保存图成功");
        number++;
        intent = new Intent();
        intent.setAction("CameraFragment.start");
        intent.putExtra("number", number);
        mContext.sendBroadcast(intent);
      } catch (Exception e) {
        LogUtils.v("保存图片失败");
        e.printStackTrace();
      }
      releaseCarema();
    }
  };

  public void releaseCarema() {
    if (mCamera != null) {
      mCamera.stopPreview();
      mCamera.release();
      mCamera = null;
    }
  }
}

demo下载地址:http://www.jb51.net/softs/519032.html

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

(0)

相关推荐

  • Android仿微信单击拍照长按录像功能实例代码

    此文章是看郭神公众号发的一篇,仅作学习. 在modlue gradle中添加 compile 'cjt.library.wheel:camera:0.0.7' 在project gradle中添加 compile 'cjt.library.wheel:camera:0.0.7' 添加的地方是 allprojects { repositories { jcenter() /*在此处添加*/ } } 使用起来很方便,只需在xml布局中 <com.cjt2325.cameralibrary.JCame

  • Android 开发手机(三星)拍照应用照片旋转问题解决办法

    Android 开发手机(三星)拍照应用照片旋转问题解决办法 最近解决了一个令我头疼好久的问题,就是三星手机拍照图片旋转的问题,项目中有上传图片的功能,那么涉及到拍照,从相册中选择图片,别的手机都ok没有问题,唯独三星的手机拍照之后,你会很清楚的看到会把照片旋转一下,然后你根据路径找到的图片就是已经被旋转的了,解决办法终于被我找到了.我们可以根据图片的路径读取照片exif(Exchangeable Image File 可交换图像文件)信息中的旋转角度 根据调试,可以清楚的发现三星手机拍照的图片

  • Android 7.0中拍照和图片裁剪适配的问题详解

    前言 Android 7.0系统发布后,拿到能升级的nexus 6P,就开始了7.0的适配.发现在Android 7.0以上,在相机拍照和图片裁剪上,可能会碰到以下一些错误: Process: com.yuyh.imgsel, PID: 22995 // 错误1 android.os.FileUriExposedException: file:///storage/emulated/0/Android/data/com.yuyh.imgsel/cache/1486438962645.jpg ex

  • Android调用系统拍照裁剪图片模糊的解决方法

    在Android中,调用系统相机拍照时,将会接收到返回的图像数据,但是这些图片并不是全尺寸的图像,而是系统给的缩略图,当对拍照的图片进行裁切后显示时,得到的却是模糊的图片.下面针对这个问题提出解决的方法. 首先,我们知道调用系统的裁切是通过Intent intent = new Intent("com.android.camera.action.CROP"); 但是intent到底能够携带哪些数据呢,都有什么含义呢,我们可以看到如下: 上面包含了所有可选的操作,其中有一些非常重要的参数

  • Android实现拍照及图片显示效果

    本文实例为大家分享了Android拍照及图片显示的具体代码,供大家参考,具体内容如下 1.功能声明 当应用需要使用相机.NFC等外设时,需要在AndroidManifest.xml中进行声明. 这样,当设备缺少这些外设时,应用商店的安装程序可以拒绝安装设备. 声明示例代码如下: <uses-feature android:name="android.hardware.camera2" <!-- required为false时,不强制要求设备支持该功能 --> <

  • Android获取本地相册图片和拍照获取图片的实现方法

    需求:从本地相册找图片,或通过调用系统相机拍照得到图片. 容易出错的地方: 1.当我们指定了照片的uri路径,我们就不能通过data.getData();来获取uri,而应该直接拿到uri(用全局变量或者其他方式)然后设置给imageView imageView.setImageURI(uri); 2.我发现手机前置摄像头拍出来的照片只有几百KB,直接用imageView.setImageURI(uri);没有很大问题,但是后置摄像头拍出来的照片比较大,这个时候使用imageView.setIm

  • Android SurfaceView拍照录像实现方法

    Surface的拍照实现也是很简单,一个小demo就可以把流程看懂了. 话不多说,直接上代码 布局文件 <SurfaceView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/sv_main_surface" /> <Button android:layout_width="match_

  • Android 偷拍功能实现(手机关闭依然拍照)详解及实例代码

     Android 偷拍功能/手机关闭能拍照 效果如下: 其实偷拍与偷录实现方式是一样的,都是使用到的WindowManager来绘制桌面小控件的原理.那我就不多说了- 一.首先我们需要一个SurfaceView: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android&quo

  • Android 实现获取手机里面的所有图片详解及实例

    Android 实现获取手机里面的所有图片详解及实例 实现代码: public class MainActivity extends Activity { //查看图片按钮 private Button look; private Button add; //显示图片名称的list ListView show_list; ArrayList names = null; ArrayList descs= null; ArrayList fileNames = null; @Override pro

  • android实现搜索功能并将搜索结果保存到SQLite中(实例代码)

    运行结果: 涉及要点: ListView+EditText+ScrollView实现搜索效果显示 监听软键盘回车执行搜索 使用TextWatcher( )实时筛选 将搜索内容存储到SQLite中(可清空历史记录) 监听EditText的焦点,获得焦点弹出软键盘同时显示搜索历史,失去焦点隐藏软件盘和ListView. 实现过程比较简单,都是常用的,这里就不讲解了.代码可直接复制使用. 实现过程: MainActivity.java public class MainActivity extends

  • Android Dialog详解及实例代码

     Android Dialog详解及实例代码 概述: Android开发中最常用的就是Dialog类,除了自定义dialog布局,最多的就是用在弹出对话框.进度条.输入框.单选.复选框. 1.选择对话框: AlertDialog.Builder dialog = new AlertDialog.Builder(this); dialog.setTitle("选择对话框"); dialog.setMessage("请选择确认或取消"); dialog.setCance

  • Android ViewPagerIndicator详解及实例代码

    Android ViewPagerIndicator详解及实例代码 关于自定义View的属性零碎知识 自定义View和自定义属性的知识不再此提及,这里着重说的是属性在自定义View中的获取方式,自定义的属性如下: <?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="Wisely"> <attr name=&

  • Android Webview上的ssl warning的处理方式详解及实例

    Android Webview上的ssl warning的处理方式详解 前言: 因为最近遇到google pay上汇报的安全漏洞问题,需要处理ssl warning. 安全提醒 您的应用中 WebViewClient.onReceivedSslError 处理程序的实施方式很不安全.具体来说,这种实施方式会忽略所有 SSL 证书验证错误,从而使您的应用容易受到中间人攻击.攻击者可能会更改受影响的 WebView 内容.读取传输的数据(例如登录凭据),以及执行应用中使用 JavaScript 的代

  • Android 活动条ActionBar的详解及实例代码

    Android 活动条ActionBar的详解 图一 图二 图三 图四 图五 ActionBar其提供的功能总结 图一使用ActionBar显示选项菜单项 menu_mainxml代码 启用程序图标导航 如何添加Action View 图二Activity代码区 menu_mainxml代码 clockxml 图三使用ActionBar实现Tab导航 创建ActionBar实现Tab导航步骤 MainActivity代码 DummyFragmentjava代码 图四Android 30之前的Fr

  • Android CoordinatorLayout详解及实例代码

    Android CoordinatorLayout详解 一.CoordinatorLayout有什么作用 CoordinatorLayout作为"super-powered FrameLayout"基本实现两个功能: 1.作为顶层布局 2.调度协调子布局 CoordinatorLayout使用新的思路通过协调调度子布局的形式实现触摸影响布局的形式产生动画效果.CoordinatorLayout通过设置子View的 Behaviors来调度子View.系统(Support V7)提供了A

  • Android 文件选择器详解及实例代码

    本文给大家讲解下Android文件选择器的使用.实际上就是获取用户在SD卡中选择的文件或文件夹的路径,这很像C#中的OpenFileDialog控件. 此实例的实现过程很简单,这样可以让大家快速的熟悉Android文件选择器,提高开发效率. 网上曾经见到过一个关于文件选择器的实例,很多人都看过,本实例是根据它修改而成的,但更容易理解,效率也更高,另外,本实例有自己的特点:   1.监听了用户按下Back键的事件,使其返回上一层目录.        2.针对不同的文件类型(文件vs文件夹 , 目标

  • Android 欢迎全屏图片详解及实例代码

    Android 欢迎全屏图片详解 其实欢迎界面就是在主Activity之前再添加一个欢迎的Activity.在这个Activity中实现欢迎界面,和其他的Activity用法 是基本一样,只有细微的差别.     1.在Activity的onCreate方法中实现: @Override ic void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); /**全屏设置,隐藏窗口所有装饰**/ getW

随机推荐