安卓 录屏、截屏_截屏录屏原理-程序员宅基地

技术标签: 录屏  手机录屏  安卓截屏录屏  android  screen shot  截屏  MediaProjection  

    

 

录屏工具和源码下载(gitee.com)

录屏工具和源码下载(github.com)

也可扫描二维码,安装录屏工具到手机

录屏工具下载

 

截屏、录屏 功能快速接入:

1、在项目中libs中添加ScreenShot.jar

2、在AndroidManifest.xml中添加存储权限和Activity声明

 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
 <uses-permission android:name="android.permission.RECORD_AUDIO"/>
 <activity
 android:name="sc.tool.screenshot.ScreenActivity"
 android:configChanges="orientation|keyboardHidden|screenSize"
 android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen" />

3、调用方法: 

截屏用法:
(1)初始化请求允许获取屏幕 ScreenActivity.Init(context); 
(2)获取屏幕图像 ScreenActivity.GetScreen_pic() 或 直接保存截屏ScreenActivity.GetScreen(); 
或 拓展调用接口:ScreenActivity.GetScreen(final long DellayMillionSecond, final int times) 


录屏用法:
(1)初始化请求允许获取屏幕 ScreenActivity.Init(context); 
(2)开始录屏:ScreenActivity.GetVedio_Start();
(3)停止录屏:ScreenActivity.GetVedio_Stop();

接入结束


附录:

截屏、录屏 调用示例


package sc.screen.demo;

import sc.tool.screenshot.ScreenActivity;
import sc.tool.screenshot.ScreenTool;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;


//import sc.tool.screenshot.ScreenActivity.ScreenCallBack;

public class MainActivity extends Activity
{
	EditText Interval;
	EditText Times;
	
	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		Interval = (EditText) this.findViewById(R.id.textInterval);
		Times = (EditText) this.findViewById(R.id.textTimes);
		
		ScreenActivity.Init(this);			// 初始化允许截屏请求
		
		// // 请求允许获取屏幕,用允许时截屏保存
		// ScreenActivity.Init(this, new ScreenCallBack()
		// {
		// 		@Override
		// 		public void Success()
		// 		{
		// 			ScreenActivity.GetScreen(); // 截屏保存
		// 		}
		// });
	}
	
	public void ScreeShot(View view)
	{
		ScreenTool.GetScreen(this);			// Activity截屏
		Toast.makeText(this, "截屏已保存", Toast.LENGTH_SHORT).show();
	}
	
	public void ScreeShot_Proj(View view)
	{
		ScreenActivity.GetScreen();			// 投影截屏
		Toast.makeText(this, "截屏已保存", Toast.LENGTH_SHORT).show();
	}
	
	public void ScreeShot_Proj_Auto(View view)
	{
		ScreenActivity.GetScreen(1000, 5);	// 投影截屏(延时多次截屏)
	}
	
	public void ScreeShot_sustom(View view)
	{
		try
		{
			Long inteval = Long.parseLong(Interval.getText().toString());
			int times = Integer.parseInt(Times.getText().toString());
			
			ScreenActivity.GetScreen(inteval, times);	// 投影截屏(延时多次截屏)
		}
		catch (Exception ex)
		{}
	}
	
	public void ScreeRecord(View view)
	{
		Button btn = (Button) view;
		String text = btn.getText().toString().trim();
		if (text.equals("开始录屏(3秒后开始)"))
		{
			btn.setText("停止录屏");
			
			ScreenActivity.GetVedio_Start(3000L);	// 开始录屏
		}
		else if (text.equals("停止录屏"))
		{
			btn.setText("开始录屏(3秒后开始)");
			String path = ScreenActivity.GetVedio_Stop();			// 停止录屏
			
			if (!path.equals(""))
			{
				Toast.makeText(this, "录屏已保存" + "\n" + path, Toast.LENGTH_SHORT).show();
			}
		}
	}
	
}

截屏、录屏 实现核心源码


package sc.tool.screenshot;

import java.io.File;
import java.io.IOException;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.PixelFormat;
import android.hardware.display.DisplayManager;
import android.media.Image;
import android.media.ImageReader;
import android.media.MediaRecorder;
import android.media.projection.MediaProjection;
import android.media.projection.MediaProjectionManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.DisplayMetrics;
import android.view.WindowManager;


/* 请在AndroidManifest.xml中添加存储权限和Activity声明
 * 
 * 截屏需要权限
 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
 
 <activity
	 android:name="sc.tool.screenshot.ScreenActivity"
	 android:configChanges="orientation|keyboardHidden|screenSize"
	 android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen"
	 android:launchMode="singleTop" />
	 
*/

/*	录屏需要权限
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
*/


/* ScreenActivity说明(封装MediaProjectionManager,方便获取屏幕操作 )
 * 
 * 截屏用法:
 *  1、初始化请求允许获取屏幕 ScreenActivity.Init(context); 
 *  2、获取屏幕图像 ScreenActivity.GetScreen_pic() 或 直接保存截屏
 * ScreenActivity.GetScreen(); 拓展调用接口:ScreenActivity.GetScreen(final long DellayMillionSecond, final int times) 
 * 
 * 截屏原理:
 * 1、通过MediaProjectionManager请求获取屏幕投影,在用户允许时获取屏幕投影,将屏幕投影到虚拟显示器(虚拟显示器创建时与ImageReader绑定)
 * 2、通过ImageReader读取投影屏幕
 *  
 *  
 * 录屏用法:
 * 	1、初始化请求允许获取屏幕 ScreenActivity.Init(context); 
 * 	2、开始录屏:ScreenActivity.GetVedio_Start();
 * 	3、停止录屏:ScreenActivity.GetVedio_Stop();
 * 
 * 录屏原理:
 *  1、通过MediaProjectionManager请求获取屏幕投影,在用户允许时获取屏幕投影,将屏幕投影到虚拟显示器(虚拟显示器创建时与MediaRecorder绑定)
 * 	2、通过MediaRecorder进行屏幕的录制
 *   */

/**
 * 请求获取屏幕投影:	ScreenActivity.Init(context);
 * 截屏: 			ScreenActivity.GetScreen();
 * 开始录屏:			ScreenActivity.GetVedio_Start();
 * 停止录屏:			ScreenActivity.GetVedio_Stop();
 * */
public class ScreenActivity extends Activity
{
	private static Context context_S = null;
	
	/** 截屏初始化(请求用户允许获取屏幕) */
	public static void Init(Context context)
	{
		if (isInit) return;
		context_S = context;
		
		if (context != null)
		{
			Intent intent = new Intent(context, ScreenActivity.class);
			// intent.setAction("intent.action.sc.ScreenShot");
			context.startActivity(intent);
		}
	}
	
	private static ScreenCallBack call;
	
	/** 截屏初始化(请求用户允许获取屏幕),在允许时执行回调 */
	public static void Init(Context context, ScreenCallBack initCall)
	{
		call = initCall;
		Init(context);
	}
	
	/** 标记是否初始化成功 */
	private static boolean isInit = false;
	private static MediaProjection Projection;
	private static ImageReader ImageR;			// 用于截屏
	private static MediaRecorder Recorder;		// 用于录屏
	
	private MediaProjectionManager PrManager;	// 屏幕投影管理器
	public static final int requestCode_Projection = 6556;
	
	private static int W;
	private static int H;
	private static int D;
	
	// 初始载入屏幕尺寸、分辨率信息
	private void LoadScreenInfo()
	{
		WindowManager mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
		
		DisplayMetrics metrics = new DisplayMetrics();
		mWindowManager.getDefaultDisplay().getMetrics(metrics);
		
		D = metrics.densityDpi;
		W = metrics.widthPixels;
		H = metrics.heightPixels;
	}
	
	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		// setContentView(R.layout.activity_main);
		
		try
		{
			if (Build.VERSION.SDK_INT >= 21)
			{
				LoadScreenInfo();
				
				PrManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);	// 获取Manager
				startActivityForResult(PrManager.createScreenCaptureIntent(), requestCode_Projection);	// 请求获取屏幕显示
				
				// Toast.makeText(this, "onCreate -> 已执行", Toast.LENGTH_SHORT).show();
			}
		}
		catch (Exception ex)
		{
			ex.printStackTrace();
		}
	}
	
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data)
	{
		super.onActivityResult(requestCode, resultCode, data);
		
		if (requestCode == requestCode_Projection)
		{
			// Toast.makeText(this, "onActivityResult -> 已执行0", Toast.LENGTH_SHORT).show();
			
			if (resultCode == RESULT_OK && data != null)
			{
				Projection = PrManager.getMediaProjection(Activity.RESULT_OK, data);	// 允许获取屏幕时,获取投影
				
				isInit = true;
				if (call != null) call.Success();	// 执行回调逻辑
					
				// Toast.makeText(this, "onActivityResult -> 已执行1", Toast.LENGTH_SHORT).show();
			}
		}
		
		// Toast.makeText(this, "onActivityResult -> 已执行2 : " + resultCode, Toast.LENGTH_SHORT).show();
		this.finish();	// 权限请求后关闭当前Activity
	}
	
	// ==========
	// 截屏
	// ----------
	
	/** 获取实时显示的屏幕图像 */
	public static Bitmap GetScreen_pic()
	{
		Bitmap pic = null;
		if (isInit)
		{
			try
			{
				if (ImageR == null)
				{
					// 根据屏幕尺寸创建ImageReader,用于读取投影屏幕
					// ImageR = ImageReader.newInstance(W, H, PixelFormat.RGB_888, 1); // 格式若不是PixelFormat.RGB_888,在获取截屏时会报错给出类型: The producer output buffer
					// format 0x03
					ImageR = ImageReader.newInstance(W, H, PixelFormat.RGBA_8888, 1);
					
					// 将屏幕投影到虚拟显示器(虚拟显示器创建时与ImageReader绑定)
					Projection.createVirtualDisplay("screen-mirror", W, H, D, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, ImageR.getSurface(), null, null);
				}
				
				Image image = ImageR.acquireLatestImage();	// 通过ImageReader从屏幕投影中读取最新的图像
				pic = ScreenTool.ToBitmap(image);			// 转化为Bitmap
				
				// boolean isNull = (image == null);
				// Toast.makeText(context_S, "startScreenShot -> " + (isNull ? "null" : "非空"), Toast.LENGTH_SHORT).show();
				
			}
			catch (Exception ex)
			{
				ex.printStackTrace();
				// Toast.makeText(this, "startScreenShot -> \n" + ex.toString(), Toast.LENGTH_SHORT).show();
			}
		}
		// else Init(context_S); // 若未初始化,则自动初始化请求允许获取屏幕
		
		return pic;
	}
	
	/** 获取实时显示的屏幕图像,自动保存 */
	public static boolean GetScreen()
	{
		Bitmap pic = GetScreen_pic();
		return ScreenTool.SaveScreen(pic);
		// return ScreenTool.SaveScreen(context_S, pic);
	}
	
	private static int count = 5;
	
	/** 截屏(延时毫秒、截屏次数) */
	public static void GetScreen(final long DellayMillionSecond, final int times)
	{
		count = times;
		final Handler mainHandler = new Handler(Looper.getMainLooper());
		Runnable r = new Runnable()
		{
			@Override
			public void run()
			{
				if (count > 0)
				{
					// Toast.makeText(context_S, "GetScreen" + count, Toast.LENGTH_SHORT).show();
					count--;
					ScreenActivity.GetScreen();
					mainHandler.postDelayed(this, DellayMillionSecond);
				}
				else mainHandler.removeCallbacks(this);
			}
		};
		
		if (count > 0) mainHandler.postDelayed(r, DellayMillionSecond);
	}
	
	/** 屏幕投影请求回调 */
	public static abstract class ScreenCallBack
	{
		/** 屏幕投影请求成功 */
		public abstract void Success();
	}

	// ==========
	// 录屏
	// ----------
	
	/** 记录最新的录屏文件保存路径 */
	private static String VeidoPath = "";
	
	/** 初始化MediaRecorder,设置录屏相关参数 */
	private static void InitRecorder(MediaProjection Projection)
	{
		if (Recorder == null)
		{
			Recorder = new MediaRecorder();
			
			String path = ScreenTool.GetDir() + ScreenTool.NewVedioName();	// 生成视屏文件路径
			VeidoPath = path;
			
			File vedioFile = new File(path);
			if (!vedioFile.getParentFile().exists()) vedioFile.getParentFile().mkdirs();
			
			Recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
			Recorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
			Recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
			Recorder.setOutputFile(path);
			Recorder.setVideoSize(W, H);
			Recorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
			Recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
			Recorder.setVideoEncodingBitRate(5 * W * H);	// 根据屏幕分辨率变动
			Recorder.setVideoFrameRate(20);					// 20帧每秒
			try
			{
				Recorder.prepare();
			}
			catch (IOException e)
			{
				e.printStackTrace();
				VeidoPath = "";
			}
			
			Projection.createVirtualDisplay("MainScreen", W, H, D, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, Recorder.getSurface(), null, null);
		}
	}
	
	private static boolean isRecordingVedio = false;
	/** 开始录屏 */
	public static void GetVedio_Start()
	{
		if (!isInit) return;
		
		if (!isRecordingVedio)
		{
			try
			{
				isRecordingVedio = true;
				InitRecorder(Projection);
				Recorder.start();
			}
			catch (Exception e)
			{
				isRecordingVedio = false;
				VeidoPath = "";
				e.printStackTrace();
			}
		}
	}
	
	/** 停止录屏 */
	public static String GetVedio_Stop()
	{
		if (isRecordingVedio)
		{
			Recorder.stop();
			Recorder = null;
			isRecordingVedio = false;
		}
		
		return VeidoPath;
	}
	
	/** 开始录屏(延时delayMillis毫秒后,开始录屏)*/
	public static void GetVedio_Start(Long delayMillis)
	{
		Handler handler = new Handler(Looper.getMainLooper());
		
		Runnable r = new Runnable()
		{
			@Override
			public void run()
			{
				ScreenActivity.GetVedio_Start();	// 开始录屏
			}
		};
		handler.postDelayed(r, delayMillis);
	}
	
	/** 开始录屏(延时delayMillis毫秒后,开始录屏; 录取recordMillions毫秒视屏后自动停止)*/
	public static void GetVedio(Long delayMillis, final Long recordMillis)
	{
		final Handler handler = new Handler(Looper.getMainLooper());
		
		final Runnable rs = new Runnable()
		{
			@Override
			public void run()
			{
				ScreenActivity.GetVedio_Stop();		// 停止录屏
			}
		};
		
		Runnable r = new Runnable()
		{
			@Override
			public void run()
			{
				ScreenActivity.GetVedio_Start();		// 开始录屏
				handler.postDelayed(rs, recordMillis);	// 延时自动停止
			}
		};
		handler.postDelayed(r, delayMillis);
	}
}

package sc.tool.screenshot;

import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

import android.app.Activity;
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Picture;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.media.Image;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
import android.view.View;
import android.view.WindowManager;
import android.webkit.WebView;
import android.widget.Toast;


public class ScreenTool
{
	// new Handler(Looper.getMainLooper()).postDelayed(r, 5000);
	
	/** Activity截取屏幕并自动保存 */
	public static boolean GetScreen(Activity activity)
	{
		Bitmap pic = GetScreen_Pic(activity);
		String picPath = GetDir() + NewName();
		
		boolean result = SavePic(pic, picPath);
//		Toast.makeText(activity, "截屏已保存" + "\n" + picPath, Toast.LENGTH_SHORT).show();
		
		return result;
	}
	
	/** 基于Activity的截屏(无需申请权限或root,仅能截取到当前Activity界面) */
	private static Bitmap GetScreen_Pic(Activity activity)
	{
		View decorView = activity.getWindow().getDecorView();    	// 获取当前activity所在的最顶层的view--DecorView
		// int statusBarHeight = GetStatusBarHeight(activity);
		decorView.setDrawingCacheEnabled(true);         			// 启用绘图缓存
		decorView.buildDrawingCache();                  			// 强制构建绘图缓存(防止上面启用绘图缓存的操作失败)
		Bitmap bitmap = decorView.getDrawingCache();     			// 获取绘图缓存中的 bitmap
		bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight());	// 创建副本作为返回对象
		
		// // 裁切图像,去除状态栏
		// int newBmpHeight = bitmap.getHeight() - statusBarHeight; // 最终截取的图片的高度(取出状态栏之后的高度)
		// bitmap = Bitmap.createBitmap(bitmap, 0, statusBarHeight, bitmap.getWidth(), newBmpHeight);
		// decorView.setDrawingCacheEnabled(false); // createBitmap完成之后一定要置为false,否则短时间内多次截图时内容不会变化!
		
		return bitmap;
	}
	
	/** 获取Activity状态栏高度 */
	private static int GetStatusBarHeight(Activity activity)
	{
		View decorView = activity.getWindow().getDecorView();	// 获取当前activity所在的最顶层的view--DecorView
		Rect rect = new Rect();
		decorView.getWindowVisibleDisplayFrame(rect);
		return rect.top;
	}
	
	/** 获取图像保存路径 */
	public static String GetDir()
	{
		String path = "sc/screeenShot/";
		if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))	// 如果SD存储设备可用
		{
			path = Environment.getExternalStorageDirectory().getPath() + File.separator + path;
			File dir = new File(path);
			if (!dir.exists()) dir.mkdirs();   // 创建目录
		}
		return path;
	}
	
	private static int count = 0;
	private static String preTime = "";
	
	/** 生成图像名称 */
	public static String NewName()
	{
		DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
		String date = formatter.format(new Date());
		
		DateFormat formatter2 = new SimpleDateFormat("HH.mm.ss");
		String time = formatter2.format(new Date());
		
		if (!preTime.equals(time))
		{
			count = 1;
			preTime = time;
		}
		else count++;
		
		String fileName = date + "_" + time + "_" + count + ".png";
		return fileName;
	}
	
	/** 生成视屏文件名称 */
	public static String NewVedioName()
	{
		DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
		String date = formatter.format(new Date());
		
		DateFormat formatter2 = new SimpleDateFormat("HH.mm.ss");
		String time = formatter2.format(new Date());
		
		String fileName = "vedio_" + date + "_" + time + ".mp4";
		return fileName;
	}
	
	/** 保存 bitmap到指定的文件路径 */
	private static boolean SavePic(Bitmap bitmap, String picPath)
	{
		boolean saveSuccess = false;
		if (bitmap != null)
		{
			try
			{
				File file = new File(picPath);
				
				File dir = file.getParentFile();
				if (!dir.exists()) dir.mkdirs();   			// 创建目录
				if (!file.exists()) file.createNewFile();	// 创建新的文件
					
				FileOutputStream fos = new FileOutputStream(file);
				saveSuccess = bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);	// 根据指定的格式、质量、输出流 将bitmap保存到本地,并返回是否保存成功
				fos.flush();
				fos.close();    // 关闭流防止溢出
			}
			catch (Exception ex)
			{
				ex.printStackTrace();
			}
		}
		return saveSuccess;
	}
	
	/** 保存 bitmap,自动生成图像名称 */
	public static boolean SaveScreen(final Context context, Bitmap pic)
	{
		if (pic == null) return false;
		
		final String picPath = GetDir() + NewName();
		boolean result = SavePic(pic, picPath);
		
		// 显示提示信息
		Runnable r = new Runnable()
		{
			@Override
			public void run()
			{
				Toast.makeText(context, "截屏已保存" + "\n" + picPath, Toast.LENGTH_SHORT).show();
			}
		};
		new Handler(Looper.getMainLooper()).post(r);
		
		return result;
	}
	
	/** 保存 bitmap,自动生成图像名称 */
	public static boolean SaveScreen(Bitmap pic)
	{
		if (pic == null) return false;
		
		String picPath = GetDir() + NewName();
		boolean result = SavePic(pic, picPath);
		// Toast.makeText(activity, "截屏已保存" + "\n" + picPath, Toast.LENGTH_SHORT).show();
		
		return result;
	}
	
	/** Image转化为Bitmap */
	public static Bitmap ToBitmap(Image image)
	{
		int width = image.getWidth();
		int height = image.getHeight();
		
		final Image.Plane[] planes = image.getPlanes();
		final ByteBuffer buffer = planes[0].getBuffer();
		int pixelStride = planes[0].getPixelStride();
		int rowStride = planes[0].getRowStride();
		int rowPadding = rowStride - pixelStride * width;
		Bitmap bitmap = Bitmap.createBitmap(width + rowPadding / pixelStride, height, Bitmap.Config.ARGB_8888);
		bitmap.copyPixelsFromBuffer(buffer);
		
		bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height);
		image.close();
		
		return bitmap;
	}
	
	// ----------
	
	/** 系统命令截屏,需要root权限 */
	public Bitmap captureScreenSystem(Activity activity)
	{
		// 获取屏幕大小:
		DisplayMetrics metrics = new DisplayMetrics();
		WindowManager WM = (WindowManager) activity.getSystemService(Context.WINDOW_SERVICE);
		Display display = WM.getDefaultDisplay();
		display.getMetrics(metrics);
		int height = metrics.heightPixels; 	// 屏幕高
		int width = metrics.widthPixels; 	// 屏幕的宽
		
		// 获取显示方式
		int pixelformat = display.getPixelFormat();
		PixelFormat localPixelFormat1 = new PixelFormat();
		PixelFormat.getPixelFormatInfo(pixelformat, localPixelFormat1);
		int deepth = localPixelFormat1.bytesPerPixel;		// 位深
		byte[] piex = new byte[height * width * deepth];
		try
		{
			Runtime.getRuntime().exec(new String[] { "/system/bin/su", "-c", "chmod 777 /dev/graphics/fb0" });
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
		try
		{
			// 获取fb0数据输入流
			InputStream stream = new FileInputStream(new File("/dev/graphics/fb0"));
			DataInputStream dStream = new DataInputStream(stream);
			dStream.readFully(piex);
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
		
		// 保存图片
		int[] colors = new int[height * width];
		for (int m = 0; m < colors.length; m++)
		{
			int r = (piex[m * 4] & 0xFF);
			int g = (piex[m * 4 + 1] & 0xFF);
			int b = (piex[m * 4 + 2] & 0xFF);
			int a = (piex[m * 4 + 3] & 0xFF);
			colors[m] = (a << 24) + (r << 16) + (g << 8) + b;
			
		}
		
		// piex生成Bitmap
		Bitmap bitmap = Bitmap.createBitmap(colors, width, height, Bitmap.Config.ARGB_8888);
		return bitmap;
	}
	
	// ----------
	
	/** 对WebView进行截图 */
	public static Bitmap captureWebView1(WebView webView)
	{
		Picture snapShot = webView.capturePicture();
		Bitmap bmp = Bitmap.createBitmap(snapShot.getWidth(), snapShot.getHeight(), Bitmap.Config.ARGB_8888);
		Canvas canvas = new Canvas(bmp);
		snapShot.draw(canvas);
		return bmp;
	}
	
	// 判断当前界面显示的是哪个Activity
	public static String getTopActivity(Context context)
	{
		ActivityManager am = (ActivityManager) context.getSystemService(context.ACTIVITY_SERVICE);
		ComponentName cn = am.getRunningTasks(1).get(0).topActivity;
		// Log.d("ScreenTool", "包名:" + cn.getPackageName()); // 包名
		Log.d("ScreenTool", "类名:" + cn.getClassName());	// 包名加类名
		return cn.getClassName();
	}
	
}

拍照、录像 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/scimence/article/details/86685189

智能推荐

由CString想到的-程序员宅基地

文章浏览阅读1.1k次。因为手头上的一个项目出问题了,调试跟踪的结果是由于CString的处理出现了问题,于是就大致的研究了一下这个会经常用到的类。Cstring出现的原因,是由于在大量实践中发现出现错误最多的是字串的操作出问题,例如溢出、泄露等;MFC中的CString类解决了上面的问题;CString的头文件是AFX.H文件,而实现文件则分成了几个,大致包括STREX.cpp,STRCORE.cpp和AFX.

通过文件的方式对硬盘扇区进行直接读写操作_createfile physicaldrive0 generic_write-程序员宅基地

文章浏览阅读7.1k次。CreateFile("\\\\.\\Physicaldrive0",GENERIC_READ,FILE_SHARE_WRITE,0,OPEN_EXISTING,0,0);功能:让物理磁盘0以文件,只读,共享写的方式打开,打开后会返回一个文件句柄,其实就是物理磁盘的句柄。ReadFile(hDev,Buffer,512,&dwRet,0);功能:然后以读文件的方式,把硬盘当成文件进行读_createfile physicaldrive0 generic_write

Error in nextTick: “TypeError: Cannot read property ‘resetFields‘ of undefined“_error in nexttick: "typeerror: _this.$refs.vin.set-程序员宅基地

文章浏览阅读651次。Error in nextTick: "TypeError: Cannot read property 'resetFields' of undefined" 报错解决办法this.$nextTick(()=>{ this.$refs['form'].resetFields(); // 清空数据})_error in nexttick: "typeerror: _this.$refs.vin.setattribute is not a functio

C#学习之操作excel表格_c# excel 指定范围插入表格-程序员宅基地

文章浏览阅读5.9k次,点赞2次,收藏12次。-------------------自己的实践方案 今天开始学习C#使用Excel。 首先,要先添加引用: 若发现没有这个项,可以重新安装office,我这里使用的是office2013:若发现还是没有在引用中找到对应的项,可尝试添加VS的功能:关于office的功能组件。-------------网上找到的资料[_c# excel 指定范围插入表格

实现UTF-8、UCS2编码和解码_ucs2在线编码转换-程序员宅基地

文章浏览阅读6k次。编码的原理知识可以看:https://www.zhihu.com/question/23374078 public void encodeDecode(){ String str = "测试字符转换"; try { //使用 URLEncoder、URLDecoder方法实现 String strGBK = URL_ucs2在线编码转换

为什么店铺的收藏加购很高,转化很低,如何将收藏加购的用户转化成真实买家?_商详加购率和停留时长高 转化低-程序员宅基地

文章浏览阅读3.5k次。现在市面上也出现很多做收藏加购的功能了,这就导致了店铺的收藏加购率很高,但是转化率却很低,最主要的原因是很多用户当时觉得产品还不错就收藏了,然后后面就看到更好的商品了,所以就导致忘记下单这件事了,那我们应该从哪些方面来提高店铺商品的转化率,而不仅仅只做到收藏加购。首先我们需要分析原因转化率低的原因:转化率这东西没有类目对比性,只有同行对比性。每个类目的行业平均转化率都是不一样的,我们要在同行里面做的转化率高于大部分同行其实就可以了。另外,销量=流量*购买转化率。那么在这个公式中,我们可以看到。流量和转换率_商详加购率和停留时长高 转化低

随便推点

Python基础学习:linecache模块_linecache open-程序员宅基地

文章浏览阅读6.4k次,点赞2次,收藏8次。 linecache——对文本行的随机访问资源代码:Lib/linecache.py linecache模块允许它获取Python资源文件的任一行。当系统试图进行内部优化时,就会使用一个高速缓存。在通常情况下,从单一文件中读取多行是普遍存在的。这被traceback模块用于检索格式化回溯的资源行。 tokenize.op..._linecache open

Winform中实现自定义水晶按钮控件(附代码下载)_vb.net 写一个水晶按钮的类并引用到form-程序员宅基地

文章浏览阅读428次。场景效果注:博客主页:https://blog.csdn.net/badao_liumang_qizhi关注公众号霸道的程序猿获取编程相关电子书、教程推送与免费下载。实现新建一个用户控件TransparencyButton,修改其代码如下using System;using System.Collections.Generic;using System..._vb.net 写一个水晶按钮的类并引用到form

转:quartus ii 设计分区和逻辑锁定的使用(design partition and logiclock)_quartus锁定 紫色-程序员宅基地

文章浏览阅读475次,点赞2次,收藏2次。注:括号里的红色字体为本人添加的注释,此注释为自己的实际项目体验或非括号里的红色字体为对文中重点的标识。首先,得先看看QuartusII的编译过程是个怎么样的,要了解这个过程很简单,看看下面这张图,谁都不陌生:当我们点全编译之后,下面的几个过程就会一个一个打上勾,而我们编译的过程也就是..._quartus锁定 紫色

BTA | 冯文和:5秒钟跨境交易将20亿被经济系统边缘化的人口,纳入全球金融体系!-程序员宅基地

文章浏览阅读918次。ALAX创始人冯文和是个连续创业者,有着丰富的营销与市场经验。由于多次旅行的经历,让他意识到当地货币回国后不容易兑换,导致很多人的外币越来越多,因此萌生出做跨境结算区块链的想法在日前的区块链技术及应用峰会(BTA)· 中国上,冯文和发表了主题为《新兴国家游戏-跨境结算5秒链》的演讲。他谈到,从区块链中的机遇开始,谈到ALAX的系统设计与实践。并表达出希望将区块链技术推广到数字内容分发和生活的方方面_冯文和

Linux编程实践1---ls命令实现_命令ls执行的系统调用-程序员宅基地

文章浏览阅读1.4k次,点赞2次,收藏15次。前言学习了两周时间的Linux后,对Linux的一些基本命令有了大致的了解,经过两周时间的期末复习后,暑期留校学习小组内接到的第一个任务–实现Linux命令:ls项目分析ls是Linux中最常见的命令之一,功能:列出目录内容。在Linux文件系统中所有的设备都是文件,从硬件设备到程序等等都是文件,包括目录也是文件,而目录这个文件的文件内容就是该目录下的所有文件。从ls的功能着手,那么l..._命令ls执行的系统调用

VS Code 配置Python环境以及代码补全提示_vscode python代码补全-程序员宅基地

文章浏览阅读1.1k次,点赞22次,收藏12次。点击 查看 -> 终端(快捷键 Ctrl + `)打开终端,输入 python 1.py 即可运行,跟在 cmd 中运行 python 代码是一样的。上文中提到,可以在终端直接运行 .py 文件,其实,终端就相当于命令提示符(cmd),所以直接在终端输入相应命令就可以了。安装完 python 之后,我们可以用任何一个文本编辑工具开始写 python 代码,然后在 cmd 中运行代码。在 VS Code 中,在不安装任何插件的情况下,也可以运行 python 代码。了,敲代码时,可以节省很多时间,非常方便,_vscode python代码补全

推荐文章

热门文章

相关标签