本文主要是介绍Android 12系统源码_多屏幕(三)模拟辅助设备功能实现原理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
前言
上一篇我们我们具体分析了Android系统开发者选项页面,模拟辅助设备功能开关的具体实现原理,当我们选择以下条目:
<!-- 模拟辅助设备的条目标题 --><string-array name="overlay_display_devices_entries"><item msgid="4497393944195787240">"无"</item><item msgid="8461943978957133391">"480p"</item><item msgid="6923083594932909205">"480p(安全)"</item><item msgid="1226941831391497335">"720p"</item><item msgid="7051983425968643928">"720p(安全)"</item><item msgid="7765795608738980305">"1080p"</item><item msgid="8084293856795803592">"1080p(安全)"</item><item msgid="938784192903353277">"4K"</item><item msgid="8612549335720461635">"4K(安全)"</item><item msgid="7322156123728520872">"4K(画质提升)"</item><item msgid="7735692090314849188">"4K(画质提升、安全)"</item><item msgid="7346816300608639624">"720p,1080p(双屏)"</item></string-array>
发现该开关的本质就是修改global数据库的overlay_display_devices字段的内容为以下条目属性值:
<!-- 模拟辅助设备的条目属性值 --><string-array name="overlay_display_devices_values" translatable="false" ><item></item><item>720x480/142</item><item>720x480/142,secure</item><item>1280x720/213</item><item>1280x720/213,secure</item><item>1920x1080/320</item><item>1920x1080/320,secure</item><item>3840x2160/320</item><item>3840x2160/320,secure</item><item>1920x1080/320|3840x2160/640</item><item>1920x1080/320|3840x2160/640,secure</item><item>1280x720/213;1920x1080/320</item></string-array>
然后DisplayManagerService模块的OverlayDisplayAdapter会收到该字段变化的回调并做出响应,本篇文章我们具体来分析一下OverlayDisplayAdapter的响应过程。
一、DMS注册屏幕设配器
系统启动的时候会在SystemServer中启动DisplayManagerService,DisplayManagerService会依次注册内置物理屏幕适配器LocalDisplayAdapter、虚拟屏幕适配器VirtualDisplayAdapter 、模拟辅助屏幕适配器OverlayDisplayAdapter、Wifi屏幕适配器WifiDisplayAdapter。
frameworks/base/services/core/java/com/android/server/display/DisplayManagerService.java
public final class DisplayManagerService extends SystemService {private static final int MSG_REGISTER_DEFAULT_DISPLAY_ADAPTERS = 1;//注册默认屏幕适配器private static final int MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS = 2;//注册其他屏幕适配器//当前已经注册的屏幕适配器集合private final ArrayList<DisplayAdapter> mDisplayAdapters = new ArrayList<DisplayAdapter>();//虚拟屏幕适配器private VirtualDisplayAdapter mVirtualDisplayAdapter;//WIFI屏幕适配器private WifiDisplayAdapter mWifiDisplayAdapter;@Overridepublic void onStart() {...代码省略...// 在android.display线程中创建默认DisplayAdapter,并进行注册mHandler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTERS);...代码省略...}public void systemReady(boolean safeMode, boolean onlyCore) {...代码省略... //注册除了物理屏幕适配器、虚拟屏幕适配器以外的其他屏幕适配器mHandler.sendEmptyMessage(MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS);...代码省略...}private final class DisplayManagerHandler extends Handler {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case MSG_REGISTER_DEFAULT_DISPLAY_ADAPTERS://注册默认的屏幕适配器registerDefaultDisplayAdapters();break;case MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS://注册额外的屏幕设备适配器registerAdditionalDisplayAdapters();break;...代码省略... }}}//注册默认的屏幕适配器private void registerDefaultDisplayAdapters() {synchronized (mSyncRoot) {//注册内置物理屏幕适配器registerDisplayAdapterLocked(new LocalDisplayAdapter(mSyncRoot, mContext, mHandler, mDisplayDeviceRepo));//注册虚拟屏幕适配器mVirtualDisplayAdapter = mInjector.getVirtualDisplayAdapter(mSyncRoot, mContext,mHandler, mDisplayDeviceRepo);if (mVirtualDisplayAdapter != null) {registerDisplayAdapterLocked(mVirtualDisplayAdapter);}}}//注册额外的屏幕适配器对象private void registerAdditionalDisplayAdapters() {synchronized (mSyncRoot) {if (shouldRegisterNonEssentialDisplayAdaptersLocked()) {registerOverlayDisplayAdapterLocked();//注册模拟辅助设备屏幕适配器registerWifiDisplayAdapterLocked();//注册WIFI屏幕适配器}}}//注册模拟辅助屏幕设备适配器private void registerOverlayDisplayAdapterLocked() {registerDisplayAdapterLocked(new OverlayDisplayAdapter(mSyncRoot, mContext, mHandler, mDisplayDeviceRepo, mUiHandler));}//注册Wifi屏幕设备适配器private void registerWifiDisplayAdapterLocked() {if (mContext.getResources().getBoolean(com.android.internal.R.bool.config_enableWifiDisplay)|| SystemProperties.getInt(FORCE_WIFI_DISPLAY_ENABLE, -1) == 1) {mWifiDisplayAdapter = new WifiDisplayAdapter(mSyncRoot, mContext, mHandler, mDisplayDeviceRepo,mPersistentDataStore);registerDisplayAdapterLocked(mWifiDisplayAdapter);}}private void registerDisplayAdapterLocked(DisplayAdapter adapter) {mDisplayAdapters.add(adapter);//将适配器对象添加到mDisplayAdapters集合中adapter.registerLocked();//进行适配器注册操作}}
对以上代码做个简单总结:
- onStart阶段,调用registerDefaultDisplayAdapters方法,注册内置物理屏幕适配器和虚拟屏幕适配器。
- systemReady阶段,调用registerAdditionalDisplayAdapters方法,注册模拟辅助设备屏幕适配器和WIFI屏幕适配器。
- 不管是注册哪种适配器,都是先创建适配器对象,将该对象添加到适配器集合mDisplayAdapters里面,并且会调用每个适配器对象的registerLocked方法。
二、OverlayDisplayAdapter的监听模拟辅助设备功能开关
2.1 监听overlay_display_devices字段属性值的变化
OverlayDisplayAdapter的registerLocked方法如下所示。
frameworks/base/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
final class OverlayDisplayAdapter extends DisplayAdapter {private final Handler mUiHandler;//处于UI线程的Handler// Called with SyncRoot lock held.public OverlayDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,Context context, Handler handler, Listener listener, Handler uiHandler) {super(syncRoot, context, handler, listener, TAG);mUiHandler = uiHandler;}@Overridepublic void registerLocked() {super.registerLocked();getHandler().post(new Runnable() {@Overridepublic void run() {//注册监听overlay_display_devices字段的内容变化getContext().getContentResolver().registerContentObserver(Settings.Global.getUriFor(Settings.Global.OVERLAY_DISPLAY_DEVICES),true, new ContentObserver(getHandler()) {@Overridepublic void onChange(boolean selfChange) { //触发回调updateOverlayDisplayDevices();}});updateOverlayDisplayDevices();}});}private void updateOverlayDisplayDevices() {synchronized (getSyncRoot()) {//继续调用updateOverlayDisplayDevicesLocked方法updateOverlayDisplayDevicesLocked();}}}
该方法只是在当前线程中注册监听overlay_display_devices字段的内容变化,初次以及后续该字段变化的时候都会调用updateOverlayDisplayDevices方法。
2.2 解析overlay_display_devices的属性值
final class OverlayDisplayAdapter extends DisplayAdapter {private final ArrayList<OverlayDisplayHandle> mOverlays = new ArrayList<OverlayDisplayHandle>();//更新模拟辅助屏幕设备private void updateOverlayDisplayDevices() {synchronized (getSyncRoot()) {updateOverlayDisplayDevicesLocked();}}private void updateOverlayDisplayDevicesLocked() {//获取当前overlay_display_devices的属性值,例如【1920x1080/320】String value = Settings.Global.getString(getContext().getContentResolver(),Settings.Global.OVERLAY_DISPLAY_DEVICES);//如果为空直接返回if (value == null) {value = "";}//如果没有发生变化直接返回if (value.equals(mCurrentOverlaySetting)) {return;}mCurrentOverlaySetting = value;//清除目前已经存在的所有模拟辅助显示设备if (!mOverlays.isEmpty()) {Slog.i(TAG, "Dismissing all overlay display devices.");for (OverlayDisplayHandle overlay : mOverlays) {overlay.dismissLocked();}mOverlays.clear();}//对overlay_display_devices字段的内容进行解析int count = 0;for (String part : value.split(DISPLAY_SPLITTER)) {Matcher displayMatcher = DISPLAY_PATTERN.matcher(part);if (displayMatcher.matches()) {if (count >= 4) {Slog.w(TAG, "Too many overlay display devices specified: " + value);break;}String modeString = displayMatcher.group(1);String flagString = displayMatcher.group(2);//将字符串转化为OverlayMode集合ArrayList<OverlayMode> modes = new ArrayList<>();for (String mode : modeString.split(MODE_SPLITTER)) {Matcher modeMatcher = MODE_PATTERN.matcher(mode);if (modeMatcher.matches()) {try {int width = Integer.parseInt(modeMatcher.group(1), 10);int height = Integer.parseInt(modeMatcher.group(2), 10);int densityDpi = Integer.parseInt(modeMatcher.group(3), 10);if (width >= MIN_WIDTH && width <= MAX_WIDTH&& height >= MIN_HEIGHT && height <= MAX_HEIGHT&& densityDpi >= DisplayMetrics.DENSITY_LOW&& densityDpi <= DisplayMetrics.DENSITY_XXXHIGH) {modes.add(new OverlayMode(width, height, densityDpi));continue;} else {Slog.w(TAG, "Ignoring out-of-range overlay display mode: " + mode);}} catch (NumberFormatException ex) {}} else if (mode.isEmpty()) {continue;}}//解析OverlayMode集合if (!modes.isEmpty()) {int number = ++count;String name = getContext().getResources().getString(com.android.internal.R.string.display_manager_overlay_display_name,number);int gravity = chooseOverlayGravity(number);OverlayFlags flags = OverlayFlags.parseFlags(flagString);Slog.i(TAG, "Showing overlay display device #" + number+ ": name=" + name + ", modes=" + Arrays.toString(modes.toArray())+ ", flags=" + flags);//为其创建OverlayDisplayHandle对象,并将该对象添加到mOverlays集合中mOverlays.add(new OverlayDisplayHandle(name, modes, gravity, flags, number));continue;}}Slog.w(TAG, "Malformed overlay display devices setting: " + value);}}private final class OverlayDisplayHandle implements OverlayDisplayWindow.Listener {private static final int DEFAULT_MODE_INDEX = 0;private final String mName;private final List<OverlayMode> mModes;private final int mGravity;private final OverlayFlags mFlags;private final int mNumber;private OverlayDisplayWindow mWindow;private OverlayDisplayDevice mDevice;private int mActiveMode;OverlayDisplayHandle(String name,List<OverlayMode> modes,int gravity,OverlayFlags flags,int number) {mName = name;mModes = modes;mGravity = gravity;mFlags = flags;mNumber = number;mActiveMode = 0;showLocked();//显示模拟辅助屏幕设备}private void showLocked() {//保证mShowRunnable是运行在UI线程中的mUiHandler.post(mShowRunnable);}public void dismissLocked() {//移除显示模拟辅助屏幕设备的RunnablemUiHandler.removeCallbacks(mShowRunnable);//执行销毁模拟辅助屏幕设备的RunnablemUiHandler.post(mDismissRunnable);}private void onActiveModeChangedLocked(int index) {mUiHandler.removeCallbacks(mResizeRunnable);mActiveMode = index;if (mWindow != null) {mUiHandler.post(mResizeRunnable);}}// Called on the UI thread.@Overridepublic void onWindowCreated(SurfaceTexture surfaceTexture, float refreshRate,long presentationDeadlineNanos, int state) {synchronized (getSyncRoot()) {IBinder displayToken = SurfaceControl.createDisplay(mName, mFlags.mSecure);mDevice = new OverlayDisplayDevice(displayToken, mName, mModes, mActiveMode,DEFAULT_MODE_INDEX, refreshRate, presentationDeadlineNanos,mFlags, state, surfaceTexture, mNumber) {@Overridepublic void onModeChangedLocked(int index) {onActiveModeChangedLocked(index);}};sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_ADDED);}}// Called on the UI thread.@Overridepublic void onWindowDestroyed() {synchronized (getSyncRoot()) {if (mDevice != null) {mDevice.destroyLocked();sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_REMOVED);}}}// Called on the UI thread.@Overridepublic void onStateChanged(int state) {synchronized (getSyncRoot()) {if (mDevice != null) {mDevice.setStateLocked(state);sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_CHANGED);}}}public void dumpLocked(PrintWriter pw) {pw.println(" " + mName + ":");pw.println(" mModes=" + Arrays.toString(mModes.toArray()));pw.println(" mActiveMode=" + mActiveMode);pw.println(" mGravity=" + mGravity);pw.println(" mFlags=" + mFlags);pw.println(" mNumber=" + mNumber);// Try to dump the window state.if (mWindow != null) {final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");ipw.increaseIndent();DumpUtils.dumpAsync(mUiHandler, mWindow, ipw, "", 200);}}// Runs on the UI thread. 显示窗口private final Runnable mShowRunnable = new Runnable() {@Overridepublic void run() {OverlayMode mode = mModes.get(mActiveMode);//创建模拟辅助设备屏幕对应的窗口OverlayDisplayWindow window = new OverlayDisplayWindow(getContext(),mName, mode.mWidth, mode.mHeight, mode.mDensityDpi, mGravity,mFlags.mSecure, OverlayDisplayHandle.this);//显示窗口window.show();synchronized (getSyncRoot()) {mWindow = window;}}};// Runs on the UI thread. 关闭窗口private final Runnable mDismissRunnable = new Runnable() {@Overridepublic void run() {OverlayDisplayWindow window;synchronized (getSyncRoot()) {window = mWindow;mWindow = null;}if (window != null) {window.dismiss();}}};// Runs on the UI thread. 缩放窗口private final Runnable mResizeRunnable = new Runnable() {@Overridepublic void run() {OverlayMode mode;OverlayDisplayWindow window;synchronized (getSyncRoot()) {if (mWindow == null) {return;}mode = mModes.get(mActiveMode);window = mWindow;}window.resize(mode.mWidth, mode.mHeight, mode.mDensityDpi);}};}private static final class OverlayMode {final int mWidth;//宽度final int mHeight;//高度final int mDensityDpi;//像素密度OverlayMode(int width, int height, int densityDpi) {mWidth = width;mHeight = height;mDensityDpi = densityDpi;}}
}
此方法先获取当前global数据库中overlay_display_devices的属性值,对该属性值内容进行字符串解析,将该字符串转化为OverlayMode对象集合,然后以该集合中的每个对象作为参数创建OverlayDisplayHandle对象,并将其添加到mOverlays集合中;OverlayDisplayHandle的构造方法中会调用showLocked方法,该方法会在UI线程中创建模拟辅助设备屏幕对应的OverlayDisplayWindow窗口。
三、模拟辅助显示设备窗口
通过第二节的分析可知,模拟辅助设备屏幕适配器OverlayDisplayAdapter会解析global数据库overlay_display_devices字段的属性内容,然后在默认屏幕中创建对应的OverlayDisplayWindow窗口。
3.1 构造方法
OverlayDisplayWindow的构造方法如下所示。
frameworks/base/services/core/java/com/android/server/display/OverlayDisplayWindow.java
final class OverlayDisplayWindow implements DumpUtils.Dump {public interface Listener {public void onWindowCreated(SurfaceTexture surfaceTexture,float refreshRate, long presentationDeadlineNanos, int state);public void onWindowDestroyed();public void onStateChanged(int state);}private final Context mContext;private final String mName;//窗口名称private int mWidth;//宽度private int mHeight;//高度private int mDensityDpi;//像素密度private final int mGravity;//窗口显示位置private final boolean mSecure;//是否是安全模式private final Listener mListener;//窗口事件回调private String mTitle;//窗口标题public OverlayDisplayWindow(Context context, String name,int width, int height, int densityDpi, int gravity, boolean secure,Listener listener) {ThreadedRenderer.disableVsync();mContext = context;mName = name;mGravity = gravity;mSecure = secure;mListener = listener;mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);//当前系统的默认屏幕设备mDefaultDisplay = mContext.getDisplay();//更新默认屏幕设备信息updateDefaultDisplayInfo();//设置窗口的宽高像素密度resize(width, height, densityDpi, false /* doLayout */);//创建窗口createWindow();}private void resize(int width, int height, int densityDpi, boolean doLayout) {mWidth = width;mHeight = height;mDensityDpi = densityDpi;//窗口标题mTitle = mContext.getResources().getString(com.android.internal.R.string.display_manager_overlay_display_title,mName, mWidth, mHeight, mDensityDpi);if (mSecure) {mTitle += mContext.getResources().getString(com.android.internal.R.string.display_manager_overlay_display_secure_suffix);}if (doLayout) {relayout();}}public void relayout() {//如果窗口可见,更新窗口参数if (mWindowVisible) {updateWindowParams();mWindowManager.updateViewLayout(mWindowContent, mWindowParams);}}private void createWindow() {...代码省略...}}
构造方法主要是对窗口属性进行赋值操作,最后会调用createWindow来创建具体的窗口视图。
3.2 加载窗口视图内容
来看下OverlayDisplayWindow的createWindow方法。
final class OverlayDisplayWindow implements DumpUtils.Dump {private final boolean DISABLE_MOVE_AND_RESIZE = false;//禁止移动缩放private View mWindowContent;//窗口视图private WindowManager.LayoutParams mWindowParams;//窗口参数private TextureView mTextureView;//模拟辅助显示设备的屏幕内容private TextView mTitleTextView;//窗口标题private GestureDetector mGestureDetector;private ScaleGestureDetector mScaleGestureDetector;private boolean mWindowVisible;//窗口是否可见private int mWindowX;//窗口左上角X坐标private int mWindowY;//窗口左上角Y坐标private float mWindowScale;//窗口缩放比例private void createWindow() {LayoutInflater inflater = LayoutInflater.from(mContext);//窗口对应的UI视图mWindowContent = inflater.inflate(com.android.internal.R.layout.overlay_display_window, null);mWindowContent.setOnTouchListener(mOnTouchListener);mTextureView = (TextureView)mWindowContent.findViewById(com.android.internal.R.id.overlay_display_window_texture);mTextureView.setPivotX(0);mTextureView.setPivotY(0);mTextureView.getLayoutParams().width = mWidth;mTextureView.getLayoutParams().height = mHeight;mTextureView.setOpaque(false);mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);mTitleTextView = (TextView)mWindowContent.findViewById(com.android.internal.R.id.overlay_display_window_title);mTitleTextView.setText(mTitle);//窗口类型为TYPE_DISPLAY_OVERLAYmWindowParams = new WindowManager.LayoutParams(WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY);//窗口默认属性mWindowParams.flags |= WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL| WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;//安全模式if (mSecure) {mWindowParams.flags |= WindowManager.LayoutParams.FLAG_SECURE;}//禁止移动和缩放if (DISABLE_MOVE_AND_RESIZE) {mWindowParams.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;}mWindowParams.privateFlags |=WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED;//窗口透明度mWindowParams.alpha = WINDOW_ALPHA;//窗口所在位置,默认为左上角mWindowParams.gravity = Gravity.TOP | Gravity.LEFT;//窗口标题mWindowParams.setTitle(mTitle);mGestureDetector = new GestureDetector(mContext, mOnGestureListener);mScaleGestureDetector = new ScaleGestureDetector(mContext, mOnScaleGestureListener);// Set the initial position and scale.// The position and scale will be clamped when the display is first shown.mWindowX = (mGravity & Gravity.LEFT) == Gravity.LEFT ?0 : mDefaultDisplayInfo.logicalWidth;mWindowY = (mGravity & Gravity.TOP) == Gravity.TOP ?0 : mDefaultDisplayInfo.logicalHeight;mWindowScale = INITIAL_SCALE;}}
frameworks/base/core/res/res/layout/overlay_display_window.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:background="#000000"><TextureView android:id="@+id/overlay_display_window_texture"android:layout_width="0px"android:layout_height="0px" /><TextView android:id="@+id/overlay_display_window_title"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="top|center_horizontal" />
</FrameLayout>
createWindow方法先是加载overlay_display_window布局文件,该布局只有两个控件,负责模拟辅助显示设备屏幕视图内容渲染的TextureView控件和标识窗口标题的TextView控件,随后会在代码中对这两个控件进行初始化并设置窗口显示需要的相关参数。
3.3 显示和隐藏窗口
可以通过调用OverlayDisplayWindow的show和dismiss方法控制OverlayDisplayWindow的显示和隐藏。
final class OverlayDisplayWindow implements DumpUtils.Dump {private final DisplayManager mDisplayManager;private final WindowManager mWindowManager;//显示窗口public void show() {if (!mWindowVisible) {mDisplayManager.registerDisplayListener(mDisplayListener, null);if (!updateDefaultDisplayInfo()) {mDisplayManager.unregisterDisplayListener(mDisplayListener);return;}clearLiveState();updateWindowParams();//将窗口视图添加到WindowManagerService中mWindowManager.addView(mWindowContent, mWindowParams);mWindowVisible = true;}}//隐藏窗口public void dismiss() {if (mWindowVisible) {mDisplayManager.unregisterDisplayListener(mDisplayListener);//将窗口视图从WindowManagerService中移除mWindowManager.removeView(mWindowContent);mWindowVisible = false;}}
}
四、模拟屏幕内容显示同步
每个模拟辅助显示设备的屏幕信息都是通过TextureView控件实时显示到OverlayDisplayWindow窗口上的。
4.1 OverlayDisplayWindow回调阶段
final class OverlayDisplayWindow implements DumpUtils.Dump {public interface Listener {public void onWindowCreated(SurfaceTexture surfaceTexture,float refreshRate, long presentationDeadlineNanos, int state);public void onWindowDestroyed();public void onStateChanged(int state);}private final Listener mListener;private TextureView mTextureView;//模拟辅助显示设备的屏幕内容private void createWindow() {LayoutInflater inflater = LayoutInflater.from(mContext);mWindowContent = inflater.inflate(com.android.internal.R.layout.overlay_display_window, null);mWindowContent.setOnTouchListener(mOnTouchListener);mTextureView = (TextureView)mWindowContent.findViewById(com.android.internal.R.id.overlay_display_window_texture);mTextureView.setPivotX(0);mTextureView.setPivotY(0);mTextureView.getLayoutParams().width = mWidth;mTextureView.getLayoutParams().height = mHeight;mTextureView.setOpaque(false);mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);//设置回调...代码省略...}private final SurfaceTextureListener mSurfaceTextureListener =new SurfaceTextureListener() {@Overridepublic void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) {//触发Listener的onWindowCreated方法mListener.onWindowCreated(surfaceTexture,mDefaultDisplayInfo.getRefreshRate(),mDefaultDisplayInfo.presentationDeadlineNanos, mDefaultDisplayInfo.state);}@Overridepublic boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {mListener.onWindowDestroyed();return true;}@Overridepublic void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture,int width, int height) {}@Overridepublic void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {}};
}
结合以上代码可以发现OverlayDisplayWindow窗口被添加到WindowManagerService之后,会触发SurfaceTextureListener的onSurfaceTextureAvailable方法,该方法会进一步回调Listener的onWindowCreated方法,OverlayDisplayAdapter$OverlayDisplayHandle类实现了这个回调接口。
4.2 OverlayDisplayAdapter$OverlayDisplayHandle回调阶段
final class OverlayDisplayAdapter extends DisplayAdapter {private final class OverlayDisplayHandle implements OverlayDisplayWindow.Listener {// Called on the UI thread.@Overridepublic void onWindowCreated(SurfaceTexture surfaceTexture, float refreshRate,long presentationDeadlineNanos, int state) {synchronized (getSyncRoot()) {//通过SurfaceControl创建一个屏幕设备,并返回该屏幕对应的令牌IBinder displayToken = SurfaceControl.(mName, mFlags.mSecure);//创建模拟辅助屏幕设备对象mDevice = new OverlayDisplayDevice(displayToken, mName, mModes, mActiveMode,DEFAULT_MODE_INDEX, refreshRate, presentationDeadlineNanos,mFlags, state, surfaceTexture, mNumber) {@Overridepublic void onModeChangedLocked(int index) {onActiveModeChangedLocked(index);}};//通知DMS更新DisplayDevice事件,新增屏幕设备sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_ADDED);}}// Called on the UI thread.@Overridepublic void onWindowDestroyed() {synchronized (getSyncRoot()) {if (mDevice != null) {mDevice.destroyLocked();//通知DMS更新DisplayDevice事件,屏幕设备被移除sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_REMOVED);}}}// Called on the UI thread.@Overridepublic void onStateChanged(int state) {synchronized (getSyncRoot()) {if (mDevice != null) {mDevice.setStateLocked(state);//通知DMS更新DisplayDevice事件,屏幕设备状态发生变化sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_CHANGED);}}}}
}
- onWindowCreated方法被回调的时候,会调用SurfaceControl的createDisplay方法创建屏幕设备,然后会创建OverlayDisplayDevice对象实例,并通知DMS更新DisplayDevice事件,新增屏幕设备。
- onWindowDestroyed方法被回调的时候,会调用OverlayDisplayDevice对象实例的destroyLocked方法,并通知DMS更新DisplayDevice事件,屏幕设备被移除
- onStateChanged方法被回调的时候,会调用OverlayDisplayDevice对象实例的setStateLocked方法,并通知DMS更新DisplayDevice事件,屏幕设备状态发生变化。
4.3 OverlayDisplayDevice对象
final class OverlayDisplayAdapter extends DisplayAdapter {private abstract class OverlayDisplayDevice extends DisplayDevice {private final String mName;private final float mRefreshRate;private final long mDisplayPresentationDeadlineNanos;private final OverlayFlags mFlags;private final List<OverlayMode> mRawModes;private final Display.Mode[] mModes;private final int mDefaultMode;private int mState;private SurfaceTexture mSurfaceTexture;//模拟辅助显示弹窗对应的渲染视图private Surface mSurface;//屏幕视图private DisplayDeviceInfo mInfo;private int mActiveMode;OverlayDisplayDevice(IBinder displayToken, String name,List<OverlayMode> modes, int activeMode, int defaultMode,float refreshRate, long presentationDeadlineNanos,OverlayFlags flags, int state, SurfaceTexture surfaceTexture, int number) {super(OverlayDisplayAdapter.this, displayToken, UNIQUE_ID_PREFIX + number,getContext());mName = name;mRefreshRate = refreshRate;mDisplayPresentationDeadlineNanos = presentationDeadlineNanos;mFlags = flags;mState = state;mSurfaceTexture = surfaceTexture;mRawModes = modes;mModes = new Display.Mode[modes.size()];for (int i = 0; i < modes.size(); i++) {OverlayMode mode = modes.get(i);mModes[i] = createMode(mode.mWidth, mode.mHeight, refreshRate);}mActiveMode = activeMode;mDefaultMode = defaultMode;}public void destroyLocked() {mSurfaceTexture = null;if (mSurface != null) {mSurface.release();mSurface = null;}SurfaceControl.destroyDisplay(getDisplayTokenLocked());}@Overridepublic boolean hasStableUniqueId() {return false;}@Overridepublic void performTraversalLocked(SurfaceControl.Transaction t) {//实时更新屏幕视图内容到模拟辅助弹窗的UI上if (mSurfaceTexture != null) {if (mSurface == null) {mSurface = new Surface(mSurfaceTexture);}setSurfaceLocked(t, mSurface);}}public void setStateLocked(int state) {mState = state;mInfo = null;}@Overridepublic DisplayDeviceInfo getDisplayDeviceInfoLocked() {if (mInfo == null) {Display.Mode mode = mModes[mActiveMode];OverlayMode rawMode = mRawModes.get(mActiveMode);mInfo = new DisplayDeviceInfo();mInfo.name = mName;mInfo.uniqueId = getUniqueId();mInfo.width = mode.getPhysicalWidth();mInfo.height = mode.getPhysicalHeight();mInfo.modeId = mode.getModeId();mInfo.defaultModeId = mModes[0].getModeId();mInfo.supportedModes = mModes;mInfo.densityDpi = rawMode.mDensityDpi;mInfo.xDpi = rawMode.mDensityDpi;mInfo.yDpi = rawMode.mDensityDpi;mInfo.presentationDeadlineNanos = mDisplayPresentationDeadlineNanos +1000000000L / (int) mRefreshRate; // display's deadline + 1 framemInfo.flags = DisplayDeviceInfo.FLAG_PRESENTATION;if (mFlags.mSecure) {mInfo.flags |= DisplayDeviceInfo.FLAG_SECURE;}if (mFlags.mOwnContentOnly) {mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY;}if (mFlags.mShouldShowSystemDecorations) {mInfo.flags |= DisplayDeviceInfo.FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS;}mInfo.type = Display.TYPE_OVERLAY;mInfo.touch = DisplayDeviceInfo.TOUCH_VIRTUAL;mInfo.state = mState;// The display is trusted since it is created by system.mInfo.flags |= FLAG_TRUSTED;}return mInfo;}@Overridepublic void setDesiredDisplayModeSpecsLocked(DisplayModeDirector.DesiredDisplayModeSpecs displayModeSpecs) {final int id = displayModeSpecs.baseModeId;int index = -1;if (id == 0) {// Use the default.index = 0;} else {for (int i = 0; i < mModes.length; i++) {if (mModes[i].getModeId() == id) {index = i;break;}}}if (index == -1) {Slog.w(TAG, "Unable to locate mode " + id + ", reverting to default.");index = mDefaultMode;}if (mActiveMode == index) {return;}mActiveMode = index;mInfo = null;sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED);onModeChangedLocked(index);}/*** Called when the device switched to a new mode.** @param index index of the mode in the list of modes*/public abstract void onModeChangedLocked(int index);}
}
这篇关于Android 12系统源码_多屏幕(三)模拟辅助设备功能实现原理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!