网站平台怎么做的好,手机网站转换小程序,中国建设银行晋中分行网站,免费的行情网站app软件Android 大版本升级变更截图方法总结 一、Android R (11) 平台二、Android S (12) 平台三、Android U (14) 平台 Android 原生的截屏功能是集成在 SystemUI 中#xff0c;因此我们普通应用想要获取截图方法#xff0c;就需要研读下 SystemUI 截屏部分的功能实现。 一、Androi… Android 大版本升级变更截图方法总结 一、Android R (11) 平台二、Android S (12) 平台三、Android U (14) 平台 Android 原生的截屏功能是集成在 SystemUI 中因此我们普通应用想要获取截图方法就需要研读下 SystemUI 截屏部分的功能实现。 一、Android R (11) 平台
SystemUI中截屏时获取当前的屏幕截图方法如下
frameworks/base/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshotMoreAction.java
private Bitmap captureScreenshotBitmap() {mDisplay.getRealMetrics(mDisplayMetrics);float[] dims {mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels};int rot mDisplay.getRotation();Rect sourceCrop new Rect(0, 0, (int) dims[0], (int) dims[1]);// Take the screenshotBitmap bitmap SurfaceControl.screenshot(sourceCrop, (int) dims[0], (int) dims[1], rot);Log.d(TAG, capture screenshot bitmap);if (bitmap null) {Log.d(TAG, capture screenshot bitmap is null!);}return bitmap;
}核心代码SurfaceControl.screenshot(sourceCrop, (int) dims[0], (int) dims[1], rot)
关于 SurfaceControl.screenshot 的具体实现查看源码如下
frameworks/base/core/java/android/view/SurfaceControl.java/*** see SurfaceControl#screenshot(Rect, int, int, boolean, int)}* hide*/
UnsupportedAppUsage
public static Bitmap screenshot(Rect sourceCrop, int width, int height, int rotation) {return screenshot(sourceCrop, width, height, false, rotation);/*** Copy the current screen contents into a hardware bitmap and return it.* Note: If you want to modify the Bitmap in software, you will need to copy the Bitmap into* a software Bitmap using {link Bitmap#copy(Bitmap.Config, boolean)}** CAVEAT: Versions of screenshot that return a {link Bitmap} can be extremely slow; avoid use* unless absolutely necessary; prefer the versions that use a {link Surface} such as* {link SurfaceControl#screenshot(IBinder, Surface)} or {link GraphicBuffer} such as* {link SurfaceControl#screenshotToBuffer(IBinder, Rect, int, int, boolean, int)}.** see SurfaceControl#screenshotToBuffer(IBinder, Rect, int, int, boolean, int)}* hide*/
UnsupportedAppUsage
public static Bitmap screenshot(Rect sourceCrop, int width, int height,boolean useIdentityTransform, int rotation) {// TODO: should take the display as a parameterfinal IBinder displayToken SurfaceControl.getInternalDisplayToken();if (displayToken null) {Log.w(TAG, Failed to take screenshot because internal display is disconnected);return null;}if (rotation ROTATION_90 || rotation ROTATION_270) {rotation (rotation ROTATION_90) ? ROTATION_270 : ROTATION_90;}SurfaceControl.rotateCropForSF(sourceCrop, rotation);final ScreenshotGraphicBuffer buffer screenshotToBuffer(displayToken, sourceCrop, width,height, useIdentityTransform, rotation);if (buffer null) {Log.w(TAG, Failed to take screenshot);return null;}return Bitmap.wrapHardwareBuffer(buffer.getGraphicBuffer(), buffer.getColorSpace());
}看到注解UnsupportedAppUsage这个注解的存在旨在提醒开发者某些 API 或代码元素可能在未来版本中发生变化可能会有风险或不稳定。 UnsupportedAppUsage 注解用于标记不建议应用程序使用的 API。它通常用于标记已被弃用或将在未来版本中删除的 API。 作为普通应用我们需要兼容多版本所以在使用高targetSdkVersion时此方法在SDK中就会找不到因此我们需要使用反射来完成。在 Android R (11) 上可使用的截图工具方法如下
private static Bitmap screenshotR(int width, int height, Display defaultDisplay) {Bitmap bmp null;Rect sourceCrop new Rect(0, 0, width, height);try {Class? demo Class.forName(android.view.SurfaceControl);Method method demo.getMethod(screenshot, Rect.class, int.class, int.class, int.class);bmp (Bitmap) method.invoke(null, sourceCrop, (int) width, (int) height,defaultDisplay.getRotation());} catch (Exception e) {e.printStackTrace();}return bmp;
}二、Android S (12) 平台
Android S (12) 和 Android T (13) 平台截图方法无变化SystemUI 中相比较于 R 平台代码有变化梳理下代码找到截屏时获取当前的屏幕截图方法如下
frameworks/base/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
private Bitmap captureScreenshot(Rect crop) {int width crop.width();int height crop.height();Bitmap screenshot null;final Display display getDefaultDisplay();final DisplayAddress address display.getAddress();if (!(address instanceof DisplayAddress.Physical)) {Log.e(TAG, Skipping Screenshot - Default display does not have a physical address: display);} else {final DisplayAddress.Physical physicalAddress (DisplayAddress.Physical) address;final IBinder displayToken SurfaceControl.getPhysicalDisplayToken(physicalAddress.getPhysicalDisplayId());final SurfaceControl.DisplayCaptureArgs captureArgs new SurfaceControl.DisplayCaptureArgs.Builder(displayToken).setSourceCrop(crop).setSize(width, height).build();final SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer SurfaceControl.captureDisplay(captureArgs);screenshot screenshotBuffer null ? null : screenshotBuffer.asBitmap();}return screenshot;
}核心代码SurfaceControl.captureDisplay(captureArgs)
关于 SurfaceControl.captureDisplay 的具体实现需要查看源码这里多了几个新类DisplayCaptureArgs、ScreenshotHardwareBuffer
frameworks/base/core/java/android/view/SurfaceControl.java/*** param captureArgs Arguments about how to take the screenshot* param captureListener A listener to receive the screenshot callback* hide*/
public static int captureDisplay(NonNull DisplayCaptureArgs captureArgs,NonNull ScreenCaptureListener captureListener) {return nativeCaptureDisplay(captureArgs, captureListener);
}/*** Captures all the surfaces in a display and returns a {link ScreenshotHardwareBuffer} with* the content.** hide*/
public static ScreenshotHardwareBuffer captureDisplay(DisplayCaptureArgs captureArgs) {SyncScreenCaptureListener screenCaptureListener new SyncScreenCaptureListener();int status captureDisplay(captureArgs, screenCaptureListener);if (status ! 0) {return null;}return screenCaptureListener.waitForScreenshot();
}在 Android S 和 Android T 上可使用的截图工具方法如下
private static Bitmap screenshotS(int width, int height, Display defaultDisplay) {Bitmap bmp;Rect sourceCrop new Rect(0, 0, width, height);final DisplayAddress.Physical physicalAddress (DisplayAddress.Physical) defaultDisplay.getAddress();final IBinder displayToken SurfaceControl.getPhysicalDisplayToken(physicalAddress.getPhysicalDisplayId());final SurfaceControl.DisplayCaptureArgs captureArgs new SurfaceControl.DisplayCaptureArgs.Builder(displayToken).setSourceCrop(sourceCrop).setSize(width, height).build();final SurfaceControl.ScreenshotHardwareBuffer screenshotBuffer SurfaceControl.captureDisplay(captureArgs);bmp screenshotBuffer null ? null : screenshotBuffer.asBitmap();return bmp;
}三、Android U (14) 平台
Android 14 平台上的 SystemUI 中的截图方法类是使用Kotlin编写
frameworks/base/packages/SystemUI/src/com/android/systemui/screenshot/ImageCaptureImpl.kt
override fun captureDisplay(displayId: Int, crop: Rect?): Bitmap? {val captureArgs CaptureArgs.Builder().setSourceCrop(crop).build()val syncScreenCapture ScreenCapture.createSyncCaptureListener()windowManager.captureDisplay(displayId, captureArgs, syncScreenCapture)val buffer syncScreenCapture.getBuffer()return buffer?.asBitmap()
}我这里将 Kotlin 转化为 Java 编写的代码
// 导包为隐藏方法请使用反射重写此代码
import android.view.IWindowManager;
import android.window.ScreenCapture;
import android.window.ScreenCapture.CaptureArgs;
import android.window.ScreenCapture.SynchronousScreenCaptureListener;
import android.window.ScreenCapture.ScreenshotHardwareBuffer;IWindowManager windowManager IWindowManager.Stub.asInterface(ServiceManager.getServiceOrThrow(Context.WINDOW_SERVICE));
CaptureArgs captureArgs new CaptureArgs.Builder().setSourceCrop(sourceCrop).build();
SynchronousScreenCaptureListener syncScreenCapture ScreenCapture.createSyncCaptureListener();
windowManager.captureDisplay(defaultDisplay.getDisplayId(), captureArgs, syncScreenCapture);
ScreenshotHardwareBuffer buffer syncScreenCapture.getBuffer();
if (buffer ! null) {bitmap buffer.asBitmap();
}核心代码indowManager.captureDisplay(displayId, captureArgs, syncScreenCapture)
之前的方法都封装在了SurfaceControl中最新的U平台将逻辑挪到了IWindowManager中
frameworks/base/core/java/android/view/IWindowManager.aidl/*** Captures the entire display specified by the displayId using the args provided. If the args* are null or if the sourceCrop is invalid or null, the entire display bounds will be captured.*/oneway void captureDisplay(int displayId, in nullable ScreenCapture.CaptureArgs captureArgs,in ScreenCapture.ScreenCaptureListener listener);// aidl 是接口相关实现在 WindowManagerService 中
//frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java
Override
public void captureDisplay(int displayId, Nullable ScreenCapture.CaptureArgs captureArgs,ScreenCapture.ScreenCaptureListener listener) {Slog.d(TAG, captureDisplay);if (!checkCallingPermission(READ_FRAME_BUFFER, captureDisplay())) {throw new SecurityException(Requires READ_FRAME_BUFFER permission);}ScreenCapture.LayerCaptureArgs layerCaptureArgs getCaptureArgs(displayId, captureArgs);ScreenCapture.captureLayers(layerCaptureArgs, listener);if (Binder.getCallingUid() ! SYSTEM_UID) {// Release the SurfaceControl objects only if the caller is not in system server as no// parcelling occurs in this case.layerCaptureArgs.release();}
}IWindowManager 和 WindowManager 是 Android 系统中的两个不同的类它们有以下区别 接口 vs 类IWindowManager 是一个接口定义了窗口管理器的方法和功能而 WindowManager 是一个具体的实现类用于实际管理窗口的显示和操作。 系统服务 vs 上下文获取IWindowManager 通常是通过系统服务机制获取的可以通过 ServiceManager.getService(window) 来获取 IWindowManager 的实例。而 WindowManager 是通过上下文Context的 getSystemService() 方法获取的例如 context.getSystemService(Context.WINDOW_SERVICE)。 系统级权限 vs 应用级权限IWindowManager 通常被用于系统级别的窗口管理例如修改窗口属性、调整窗口的位置和大小等因此访问 IWindowManager 需要特定的系统级权限。相比之下应用程序可以通过 WindowManager 类来管理自己的窗口但受到应用程序权限的限制。 总的来说IWindowManager 是用于系统级窗口管理的接口而 WindowManager 是用于应用程序级窗口管理的类。在大多数情况下应用程序开发者更常使用 WindowManager 类来管理应用程序的窗口。 在 Android U (14) 上可使用的截图工具方法如下
private static Bitmap screenshotU(int width, int height, Display defaultDisplay) {Bitmap bmp null;Rect sourceCrop new Rect(0, 0, width, height);try {IWindowManager windowManager IWindowManager.Stub.asInterface(ServiceManager.getServiceOrThrow(Context.WINDOW_SERVICE));Class? screenCaptureClass Class.forName(android.window.ScreenCapture);Class? captureArgsClass Class.forName(android.window.ScreenCapture$CaptureArgs);Class? captureArgsBuilderClass Class.forName(android.window.ScreenCapture$CaptureArgs$Builder);Class? screenCaptureListenerClass Class.forName(android.window.ScreenCapture$ScreenCaptureListener);Class? synchronousScreenCaptureListenerClass Class.forName(android.window.ScreenCapture$SynchronousScreenCaptureListener);Class? screenshotHardwareBufferClass Class.forName(android.window.ScreenCapture$ScreenshotHardwareBuffer);Method setSourceCropMethod captureArgsBuilderClass.getDeclaredMethod(setSourceCrop, Rect.class);Object captureArgsBuilder captureArgsBuilderClass.newInstance();setSourceCropMethod.invoke(captureArgsBuilder, sourceCrop);Method buildMethod captureArgsBuilderClass.getDeclaredMethod(build);Object captureArgs buildMethod.invoke(captureArgsBuilder);Method createSyncCaptureListenerMethod screenCaptureClass.getMethod(createSyncCaptureListener);Object syncScreenCapture createSyncCaptureListenerMethod.invoke(null);Method captureDisplayMethod windowManager.getClass().getMethod(captureDisplay, int.class, captureArgsClass, screenCaptureListenerClass);captureDisplayMethod.invoke(windowManager, defaultDisplay.getDisplayId(), captureArgs, syncScreenCapture);Method getBufferMethod synchronousScreenCaptureListenerClass.getMethod(getBuffer);Object buffer getBufferMethod.invoke(syncScreenCapture);if (buffer ! null) {Method asBitmapMethod screenshotHardwareBufferClass.getMethod(asBitmap);bmp (Bitmap) asBitmapMethod.invoke(buffer);}} catch (Exception e) {e.printStackTrace();}return bmp;
}