launcher修改--获取屏幕缩略(预览)图

本文介绍了Android Launcher中实现长按按钮显示屏幕缩略图的功能。通过分析源代码,详细解释了如何通过长按向前、向后及所有应用按钮来展示预览图,并探讨了缩略图的绘制过程。

在android原生代码中,长按图片中的向前屏切换或者向后屏切换或者中间的那个所有应用的按钮,在其上方就会出现5个小的屏幕缩略图。

由此,我们在launcher的代码里面查找一下,首先,我们要找到onLongClick(View v)这个方法,看下代码:

public boolean onLongClick(View v) { switch (v.getId()) { case R.id.previous_screen: if (!isAllAppsVisible()) { mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); showPreviews(v); } return true; case R.id.next_screen: if (!isAllAppsVisible()) { mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); showPreviews(v); } return true; case R.id.all_apps_button: if (!isAllAppsVisible()) { mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); showPreviews(v); } return true;
在这里只截取了代码中的一部分,我们看到,都调用了showPreviews方法。private void showPreviews(View anchor) { showPreviews(anchor, 0, mWorkspace.getChildCount()); } private void showPreviews(final View anchor, int start, int end) { final Resources resources = getResources(); final Workspace workspace = mWorkspace; CellLayout cell = ((CellLayout) workspace.getChildAt(start)); float max = workspace.getChildCount(); final Rect r = new Rect(); resources.getDrawable(R.drawable.preview_background).getPadding(r); int extraW = (int) ((r.left + r.right) * max); int extraH = r.top + r.bottom; int aW = cell.getWidth() - extraW; float w = aW / max; int width = cell.getWidth(); int height = cell.getHeight(); int x = cell.getLeftPadding(); int y = cell.getTopPadding(); width -= (x + cell.getRightPadding()); height -= (y + cell.getBottomPadding()); float scale = w / width; int count = end - start; final float sWidth = width * scale; float sHeight = height * scale; LinearLayout preview = new LinearLayout(this); PreviewTouchHandler handler = new PreviewTouchHandler(anchor); ArrayList<Bitmap> bitmaps = new ArrayList<Bitmap>(count); for (int i = start; i < end; i++) { ImageView image = new ImageView(this); cell = (CellLayout) workspace.getChildAt(i); final Bitmap bitmap = Bitmap.createBitmap((int) sWidth, (int) sHeight, Bitmap.Config.ARGB_8888); final Canvas c = new Canvas(bitmap); c.scale(scale, scale); c.translate(-cell.getLeftPadding(), -cell.getTopPadding()); cell.dispatchDraw(c); image.setBackgroundDrawable(resources.getDrawable(R.drawable.preview_background)); image.setImageBitmap(bitmap); image.setTag(i); image.setOnClickListener(handler); image.setOnFocusChangeListener(handler); image.setFocusable(true); if (i == mWorkspace.getCurrentScreen()) image.requestFocus(); //添加到LinearLayout中 preview.addView(image, LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); //最后添加到ArrayList里面去 bitmaps.add(bitmap); } //把上面的LinearLayout放到PopupWindow中。 final PopupWindow p = new PopupWindow(this); p.setContentView(preview); p.setWidth((int) (sWidth * count + extraW)); p.setHeight((int) (sHeight + extraH)); p.setAnimationStyle(R.style.AnimationPreview); p.setOutsideTouchable(true); p.setFocusable(true); p.setBackgroundDrawable(new ColorDrawable(0)); p.showAsDropDown(anchor, 0, 0); p.setOnDismissListener(new PopupWindow.OnDismissListener() { public void onDismiss() { dismissPreview(anchor); } }); anchor.setTag(p); anchor.setTag(R.id.workspace, preview); anchor.setTag(R.id.icon, bitmaps); }

方法一共有三个参数,第一个,被点击的View,第二个从第几个开始,第三个是第几个结束。缩略图是从又向坐开始排列的。

在for循环中,是绘制预览图的代码。

for (int i = start; i < end; i++) { ImageView image = new ImageView(this); //获取屏幕 cell = (CellLayout) workspace.getChildAt(i); //按照上面设定的大小创建一个bitmap final Bitmap bitmap = Bitmap.createBitmap((int) sWidth, (int) sHeight, Bitmap.Config.ARGB_8888); //绘制 final Canvas c = new Canvas(bitmap); //设置比例 c.scale(scale, scale); c.translate(-cell.getLeftPadding(), -cell.getTopPadding()); cell.dispatchDraw(c); //设置image image.setBackgroundDrawable(resources.getDrawable(R.drawable.preview_background)); image.setImageBitmap(bitmap); //设置标记 image.setTag(i); image.setOnClickListener(handler); image.setOnFocusChangeListener(handler); image.setFocusable(true); if (i == mWorkspace.getCurrentScreen()) image.requestFocus(); //添加到LinearLayout中 preview.addView(image, LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); //最后添加到ArrayList里面去 bitmaps.add(bitmap); bitmaps.add(bitmap); } 在源代码中有很多setTag()和getTag()方法,主要用于标记被点击的View,判断跳转事件时,根据tag里面的信息进行相应的跳转。以上面的代码为例,简单说下setTag():

image.setTag(i);
image.setOnClickListener(handler);
image.setOnFocusChangeListener(handler);
image.setFocusable(true);

我们找到handler的代码:

class PreviewTouchHandler implements View.OnClickListener, Runnable, View.OnFocusChangeListener { private final View mAnchor; public PreviewTouchHandler(View anchor) { mAnchor = anchor; } //响应image的点击事件 public void onClick(View v) { mWorkspace.snapToScreen((Integer) v.getTag()); v.post(this); } public void run() { dismissPreview(mAnchor); } public void onFocusChange(View v, boolean hasFocus) { if (hasFocus) { mWorkspace.snapToScreen((Integer) v.getTag()); } } }当点击image,会触发相应事件,然后是获取image中带的信息,然后跳转到相应屏幕。





                
public class MainActivity3 extends AppCompatActivity { private static final String TAG = "camera2api"; private static final int REQUEST_CAMERA_PERMISSIONS = 100; private boolean isTextureAvailable = false; // 跟踪Surface状态 // 所需权限列表 private static final String[] REQUIRED_PERMISSIONS = { Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO }; // UI组件 private TextureView textureView; private ImageButton captureButton,recordButton, switchButton, filterButton; private ImageView thumbnailView; private View flashView; // 相机相关变量 private CameraManager cameraManager; private String cameraId; // 当前使用的相机ID private CameraDevice cameraDevice; private CameraCaptureSession captureSession; private CaptureRequest.Builder previewRequestBuilder; // 后台线程 private HandlerThread backgroundThread; private Handler backgroundHandler; // 像读取器(用于拍照) private ImageReader imageReader; // 视频录制相关 private MediaRecorder mediaRecorder; private boolean isRecording = false; // 滤镜相关 private int currentFilter = 0; // 0:无滤镜 1:黑白 2:复古 private boolean useFilter = false; // 缩略图相关 private String lastCapturedPath; private StreamConfigurationMap map; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main3); // 初始化UI组件 initViews(); } // 初始化UI组件 private void initViews() { textureView = findViewById(R.id.textureView); captureButton = findViewById(R.id.btnCapture); recordButton = findViewById(R.id.btnRecord); switchButton = findViewById(R.id.btnSwitch); filterButton = findViewById(R.id.btnFilter); thumbnailView = findViewById(R.id.ivThumbnail); flashView = findViewById(R.id.flashView); try { // 初始化相机管理器 cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE); cameraId = cameraManager.getCameraIdList()[0]; CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId); map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); } catch (CameraAccessException e) { throw new RuntimeException(e); } Log.i(TAG, "使用相机ID: " + cameraId); } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_CAMERA_PERMISSIONS) { boolean allGranted = true; for (int result : grantResults) { if (result != PackageManager.PERMISSION_GRANTED) { allGranted = false; break; } } } } // 继续在MainActivity中添加以下代码 // TextureView监听 private final TextureView.SurfaceTextureListener surfaceTextureListener = new TextureView.SurfaceTextureListener() { @Override public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { // 当TextureView可用时,准备打开相机 openCamera(); // 在此处打开相机 isTextureAvailable = true; // 设置可用标志 } @Override public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { // 预览尺寸变化时处理 } @Override public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { // TextureView销毁时释放资源 return true; } @Override public void onSurfaceTextureUpdated(SurfaceTexture surface) { // 纹理更新时调用(每一帧都会调用) } }; // 选择合适的预览尺寸 private Size chooseOptimalSize(Size[] choices, int width, int height) { List<Size> bigEnough = new ArrayList<>(); for (Size option : choices) { if (option.getHeight() == option.getWidth() * height / width && option.getWidth() >= width && option.getHeight() >= height) { bigEnough.add(option); } } if (bigEnough.size() > 0) { return Collections.min(bigEnough, new CompareSizesByArea()); } else { return choices[0]; } } // 比较尺寸大小的工具类 static class CompareSizesByArea implements Comparator<Size> { @Override public int compare(Size lhs, Size rhs) { return Long.signum((long) lhs.getWidth() * lhs.getHeight() - (long) rhs.getWidth() * rhs.getHeight()); } } // 打开相机 private void openCamera() { try { Log.i(TAG, "打开相机"); if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { return; } // 打开相机 cameraManager.openCamera(cameraId, stateCallback, backgroundHandler); } catch (CameraAccessException e) { e.printStackTrace(); } } // 相机状态回调 private final CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() { @Override public void onOpened(@NonNull CameraDevice camera) { Log.i(TAG, "打开相机成功"); // 相机打开成功 cameraDevice = camera; // 创建预览会话 createCameraPreviewSession(); } @Override public void onDisconnected(@NonNull CameraDevice camera) { // 相机关闭连接 camera.close(); cameraDevice = null; } @Override public void onError(@NonNull CameraDevice camera, int error) { // 相机出错 camera.close(); cameraDevice = null; finish(); } }; // 创建相机预览会话 private void createCameraPreviewSession() { try { Log.i(TAG, "创建相机预览会话"); SurfaceTexture texture = textureView.getSurfaceTexture(); if (texture == null) { Log.i(TAG, "texture为空"); return; } // 配置预览尺寸 Size[] previewSizes = map.getOutputSizes(SurfaceTexture.class); Size previewSize = chooseOptimalSize(previewSizes, textureView.getWidth(), textureView.getHeight()); texture.setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight()); // 创建预览的Surface Surface previewSurface = new Surface(texture); // 配置拍照尺寸 Size[] outputSizes = map.getOutputSizes(ImageFormat.JPEG); Size imageSize = outputSizes[0]; // 选择第一个可用尺寸 imageReader = ImageReader.newInstance( imageSize.getWidth(), imageSize.getHeight(), ImageFormat.JPEG, 2); imageReader.setOnImageAvailableListener(onImageAvailableListener, backgroundHandler); // 创建预览请求 previewRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); previewRequestBuilder.addTarget(previewSurface); // 创建捕获会话 cameraDevice.createCaptureSession(Arrays.asList(previewSurface, imageReader.getSurface()), new CameraCaptureSession.StateCallback() { @Override public void onConfigured(@NonNull CameraCaptureSession session) { Log.i(TAG, "预览流配置成功"); if (cameraDevice == null) { return; } // 会话配置成功 captureSession = session; try { // 设置自动对焦和自动曝光 previewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); previewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); // 开始预览 CaptureRequest previewRequest = previewRequestBuilder.build(); Log.i(TAG, "预览下发"); captureSession.setRepeatingRequest(previewRequest, null, backgroundHandler); } catch (CameraAccessException e) { e.printStackTrace(); } } @Override public void onConfigureFailed(@NonNull CameraCaptureSession session) { Toast.makeText(MainActivity3.this, "配置相机失败", Toast.LENGTH_SHORT).show(); } }, backgroundHandler); } catch (CameraAccessException e) { e.printStackTrace(); } } // 像可用回调(拍照后) private final ImageReader.OnImageAvailableListener onImageAvailableListener = new ImageReader.OnImageAvailableListener() { @Override public void onImageAvailable(ImageReader reader) { // 获取拍摄的像 Image image = reader.acquireLatestImage(); if (image == null) { return; } // 处理像数据 ByteBuffer buffer = image.getPlanes()[0].getBuffer(); byte[] bytes = new byte[buffer.remaining()]; buffer.get(bytes); // 应用滤镜(如果启用) if (useFilter) { bytes = applyFilter(bytes); } // 保存像 String path = saveImageToFile(bytes); // 更新缩略图 if (path != null) { lastCapturedPath = path; runOnUiThread(() -> updateThumbnail(path)); } // 释放像资源 image.close(); // 恢复预览 try { captureSession.setRepeatingRequest(previewRequestBuilder.build(), null, backgroundHandler); } catch (CameraAccessException e) { e.printStackTrace(); } } }; // 保存像到文件 private String saveImageToFile(byte[] data) { File pictureFile = createImageFile(); if (pictureFile == null) { return null; } try (FileOutputStream fos = new FileOutputStream(pictureFile)) { fos.write(data); // 通知媒体库更新 MediaScannerConnection.scanFile(this, new String[]{pictureFile.getAbsolutePath()}, null, (path, uri) -> Log.d(TAG, "像已保存: " + path)); return pictureFile.getAbsolutePath(); } catch (IOException e) { Log.e(TAG, "保存像失败: " + e.getMessage()); } return null; } // 创建像文件 private File createImageFile() { try { // 创建文件名 String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date()); String imageFileName = "JPEG_" + timeStamp + "_"; // 获取存储目录 File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES); if (!storageDir.exists()) { storageDir.mkdirs(); } // 创建文件 File imageFile = File.createTempFile( imageFileName, /* 前缀 */ ".jpg", /* 后缀 */ storageDir /* 目录 */ ); return imageFile; } catch (IOException e) { Log.e(TAG, "创建像文件失败: " + e.getMessage()); } return null; } // 拍照方法 private void takePicture() { if (cameraDevice == null || captureSession == null) { return; } try { // 创建拍照请求 final CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); captureBuilder.addTarget(imageReader.getSurface()); // 设置自动对焦 captureBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); captureBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); // 设置照片方向 int rotation = getWindowManager().getDefaultDisplay().getRotation(); captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOrientation(rotation)); // 停止预览 captureSession.stopRepeating(); // 执行拍照 captureSession.capture(captureBuilder.build(), new CameraCaptureSession.CaptureCallback() { @Override public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) { super.onCaptureCompleted(session, request, result); // 拍照完成,显示黑闪效果 runOnUiThread(() -> flash()); } }, backgroundHandler); } catch (CameraAccessException e) { e.printStackTrace(); } } // 获取照片方向 private int getOrientation(int rotation) { switch (rotation) { case Surface.ROTATION_0: return 90; case Surface.ROTATION_90: return 0; case Surface.ROTATION_180: return 270; case Surface.ROTATION_270: return 180; default: return 90; } } // 拍照黑闪效果 private void flash() { flashView.setVisibility(View.VISIBLE); AlphaAnimation anim = new AlphaAnimation(1.0f, 0.0f); anim.setDuration(200); anim.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { flashView.setVisibility(View.INVISIBLE); } @Override public void onAnimationRepeat(Animation animation) { } }); flashView.startAnimation(anim); } // 初始化媒体录制器 private void initMediaRecorder() { try { mediaRecorder = new MediaRecorder(); // 设置音频源 mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); // 设置视频源 mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE); // 设置输出格式 mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); // 创建视频文件 String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date()); String videoFileName = "VIDEO_" + timeStamp + ".mp4"; File storageDir = getExternalFilesDir(Environment.DIRECTORY_MOVIES); if (!storageDir.exists()) { storageDir.mkdirs(); } File videoFile = new File(storageDir, videoFileName); lastCapturedPath = videoFile.getAbsolutePath(); // 设置输出文件 mediaRecorder.setOutputFile(videoFile.getAbsolutePath()); // 设置视频尺寸 CameraCharacteristics characteristics = null; try { characteristics = cameraManager.getCameraCharacteristics(cameraId); } catch (CameraAccessException e) { throw new RuntimeException(e); } StreamConfigurationMap map = characteristics.get( CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); if (map != null) { Size videoSize = map.getOutputSizes(MediaRecorder.class)[0]; mediaRecorder.setVideoSize(videoSize.getWidth(), videoSize.getHeight()); } // 设置视频编码格式 mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); // 设置音频编码格式 mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC); // 设置视频比特率 mediaRecorder.setVideoEncodingBitRate(10000000); // 设置视频帧率 mediaRecorder.setVideoFrameRate(30); // 设置方向 int rotation = getWindowManager().getDefaultDisplay().getRotation(); mediaRecorder.setOrientationHint(getOrientation(rotation)); // 准备录制 mediaRecorder.prepare(); } catch (IOException e) { e.printStackTrace(); } } // 开始录制视频 private void startRecording() { if (cameraDevice == null) { return; } try { // 停止预览 captureSession.stopRepeating(); captureSession.abortCaptures(); // 初始化媒体录制器 initMediaRecorder(); // 创建新的捕获会话,用于录制 SurfaceTexture texture = textureView.getSurfaceTexture(); Size previewSize = chooseOptimalSize( cameraManager.getCameraCharacteristics(cameraId) .get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP) .getOutputSizes(SurfaceTexture.class), textureView.getWidth(), textureView.getHeight()); texture.setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight()); Surface previewSurface = new Surface(texture); Surface recorderSurface = mediaRecorder.getSurface(); // 创建录制请求 final CaptureRequest.Builder recordRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD); recordRequestBuilder.addTarget(previewSurface); recordRequestBuilder.addTarget(recorderSurface); // 设置自动对焦和曝光 recordRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); recordRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); // 创建新的捕获会话 cameraDevice.createCaptureSession(Arrays.asList(previewSurface, recorderSurface), new CameraCaptureSession.StateCallback() { @Override public void onConfigured(@NonNull CameraCaptureSession session) { captureSession = session; try { // 开始录制 mediaRecorder.start(); // 开始预览 captureSession.setRepeatingRequest(recordRequestBuilder.build(), null, backgroundHandler); isRecording = true; // runOnUiThread(() -> { // recordButton.setImageResource(R.drawable.ic_launcher_background); // Toast.makeText(MainActivity3.this, "开始录制", // Toast.LENGTH_SHORT).show(); // }); } catch (CameraAccessException e) { e.printStackTrace(); } } @Override public void onConfigureFailed(@NonNull CameraCaptureSession session) { runOnUiThread(() -> Toast.makeText(MainActivity3.this, "录制配置失败", Toast.LENGTH_SHORT).show()); } }, backgroundHandler); } catch (CameraAccessException e) { e.printStackTrace(); } } // 停止录制视频 private void stopRecording() { if (!isRecording) { return; } // 停止录制 isRecording = false; // runOnUiThread(() -> recordButton.setImageResource(R.drawable.ic_launcher_foreground)); try { mediaRecorder.stop(); mediaRecorder.reset(); Toast.makeText(this, "视频已保存", Toast.LENGTH_SHORT).show(); // 更新缩略图 runOnUiThread(() -> updateThumbnail(lastCapturedPath)); // 恢复预览 createCameraPreviewSession(); } catch (IllegalStateException e) { e.printStackTrace(); } } // 应用滤镜 private byte[] applyFilter(byte[] originalData) { // 将字节数据转换为Bitmap Bitmap originalBitmap = BitmapFactory.decodeByteArray(originalData, 0, originalData.length); if (originalBitmap == null) { return originalData; } // 根据当前选择的滤镜处理Bitmap Bitmap filteredBitmap; switch (currentFilter) { case 1: // 黑白滤镜 filteredBitmap = applyBlackWhiteFilter(originalBitmap); break; case 2: // 复古滤镜 filteredBitmap = applyVintageFilter(originalBitmap); break; default: // 无滤镜 return originalData; } // 将处理后的Bitmap转换回字节数组 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); filteredBitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream); // 回收Bitmap资源 originalBitmap.recycle(); filteredBitmap.recycle(); return outputStream.toByteArray(); } // 黑白滤镜 private Bitmap applyBlackWhiteFilter(Bitmap original) { int width = original.getWidth(); int height = original.getHeight(); Bitmap filtered = Bitmap.createBitmap(width, height, original.getConfig()); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { int pixel = original.getPixel(x, y); // 获取RGB值 int red = Color.red(pixel); int green = Color.green(pixel); int blue = Color.blue(pixel); // 计算灰度值 int gray = (int) (0.299 * red + 0.587 * green + 0.114 * blue); // 创建新像素(保持透明度不变) int newPixel = (Color.alpha(pixel) << 24) | (gray << 16) | (gray << 8) | gray; filtered.setPixel(x, y, newPixel); } } return filtered; } // 复古滤镜 private Bitmap applyVintageFilter(Bitmap original) { int width = original.getWidth(); int height = original.getHeight(); Bitmap filtered = Bitmap.createBitmap(width, height, original.getConfig()); for (int x = 0; x < width; x++) { for (int y = 0; y < height; y++) { int pixel = original.getPixel(x, y); // 获取RGB值 int red = Color.red(pixel); int green = Color.green(pixel); int blue = Color.blue(pixel); // 复古效果:增加红色,减少蓝色 int newRed = Math.min(255, red + 30); int newGreen = Math.min(255, green + 10); int newBlue = Math.max(0, blue - 30); // 创建新像素 int newPixel = (Color.alpha(pixel) << 24) | (newRed << 16) | (newGreen << 8) | newBlue; filtered.setPixel(x, y, newPixel); } } return filtered; } // 切换滤镜 private void toggleFilter() { currentFilter = (currentFilter + 1) % 3; useFilter = currentFilter != 0; String filterName; switch (currentFilter) { case 0: filterName = "无滤镜"; break; case 1: filterName = "黑白滤镜"; break; case 2: filterName = "复古滤镜"; break; default: filterName = "无滤镜"; } Toast.makeText(this, "当前滤镜: " + filterName, Toast.LENGTH_SHORT).show(); } // 更新缩略图 private void updateThumbnail(String path) { if (path == null) { return; } // 判断是片还是视频 if (path.endsWith(".jpg")) { // 加载缩略图 Bitmap thumbnail = BitmapFactory.decodeFile(path); if (thumbnail != null) { // 缩放缩略图 Bitmap scaled = Bitmap.createScaledBitmap(thumbnail, 100, 150, true); thumbnailView.setImageBitmap(scaled); thumbnail.recycle(); } } else if (path.endsWith(".mp4")) { // 加载视频缩略图 MediaMetadataRetriever retriever = new MediaMetadataRetriever(); try { retriever.setDataSource(path); Bitmap thumbnail = retriever.getFrameAtTime(); if (thumbnail != null) { Bitmap scaled = Bitmap.createScaledBitmap(thumbnail, 100, 150, true); thumbnailView.setImageBitmap(scaled); thumbnail.recycle(); } } catch (IllegalArgumentException e) { e.printStackTrace(); } finally { try { retriever.release(); } catch (IOException e) { throw new RuntimeException(e); } } } } // 切换相机(前置/后置) private void switchCamera() { // 关闭当前相机 closeCamera(); try { // 查找另一个相机 for (String id : cameraManager.getCameraIdList()) { if (!id.equals(cameraId)) { CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(id); Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING); if (facing != null) { cameraId = id; break; } } } // 重新打开相机 openCamera(); } catch (CameraAccessException e) { e.printStackTrace(); } } // 设置按钮点击事件 private void setupButtonListeners() { // 设置按钮点击事件 Log.i(TAG, "设置按钮点击事件"); captureButton.setOnClickListener(v -> { if (!isRecording) { takePicture(); } }); recordButton.setOnClickListener(v -> { if (isRecording) { stopRecording(); } else { startRecording(); } }); switchButton.setOnClickListener(v -> switchCamera()); filterButton.setOnClickListener(v -> toggleFilter()); // 点击缩略图查看原 thumbnailView.setOnClickListener(v -> { if (lastCapturedPath != null) { viewMediaFile(lastCapturedPath); } }); } // 查看媒体文件 private void viewMediaFile(String path) { Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); File file = new File(path); Uri uri = FileProvider.getUriForFile(this, getPackageName() + ".fileprovider", file); intent.setDataAndType(uri, path.endsWith(".jpg") ? "image/*" : "video/*"); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); startActivity(intent); } @Override protected void onResume() { super.onResume(); // 1. 启动后台线程(必须先执行) startBackgroundThread(); Log.i(TAG, "判断是否有相机权限"); List<String> permissions=new ArrayList<>(); permissions.add(Manifest.permission.CAMERA); permissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); permissions.add(Manifest.permission.READ_EXTERNAL_STORAGE); permissions.add(Manifest.permission.RECORD_AUDIO); if (!checkPermission(permissions)){ Log.i(TAG, "没有相机权限——>开始请求相机权限"); ActivityCompat.requestPermissions(this, permissions.toArray(new String[0]), REQUEST_CAMERA_PERMISSIONS); } // // 设置预览监听 textureView.setSurfaceTextureListener(surfaceTextureListener); // 设置按钮监听 setupButtonListeners(); Log.i(TAG, "授权判断"); if (textureView.isAvailable()) { Log.i(TAG, "授权成功"); openCamera(); } } // 新增辅助方法:检查单权限 private boolean checkPermission(List<String> permissions) { boolean isPermissionFlag=true; for (String permission : permissions) { if (ActivityCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED){ isPermissionFlag=false; } } return isPermissionFlag; } @Override protected void onPause() { closeCamera(); stopBackgroundThread(); super.onPause(); } // 打开后台线程 private void startBackgroundThread() { backgroundThread = new HandlerThread("CameraBackground"); backgroundThread.start(); backgroundHandler = new Handler(backgroundThread.getLooper()); } // 停止后台线程 private void stopBackgroundThread() { backgroundThread.quitSafely(); try { backgroundThread.join(); backgroundThread = null; backgroundHandler = null; } catch (InterruptedException e) { e.printStackTrace(); } } // 关闭相机 private void closeCamera() { if (captureSession != null) { captureSession.close(); captureSession = null; } if (cameraDevice != null) { cameraDevice.close(); cameraDevice = null; } if (imageReader != null) { imageReader.close(); imageReader = null; } if (mediaRecorder != null) { mediaRecorder.release(); mediaRecorder = null; } } }为什么会闪退
最新发布
09-18
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值