当前位置: 首页 > news >正文

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);}
}

相关文章:

  • GitHub开源的PDF管理工具Stirling-pdf
  • Godot模拟实现多人游戏平滑移动
  • SpringData基础学习
  • vue前端更新后需要清空缓存
  • MySQL中 EXPLAIN 的使用介绍
  • oracle共享池(shared pool):一、工作原理、组成部分 二、软硬解析过程
  • 边界dp注意重叠边界
  • Java使用Tesseract进行OCR图片文字识别
  • 老师是怎么分班的?用什么工具比较好?
  • 实战OpenCV之绘制图形
  • JVM 在GC 时的根对象都有那些
  • day_49
  • 代码断点调试
  • LLM 直接偏好优化(DPO)的一些研究
  • springboot框架中filter过滤器的urlPatterns的匹配源码
  • [PHP内核探索]PHP中的哈希表
  • hexo+github搭建个人博客
  • 自己简单写的 事件订阅机制
  • @angular/forms 源码解析之双向绑定
  • 8年软件测试工程师感悟——写给还在迷茫中的朋友
  • C学习-枚举(九)
  • HomeBrew常规使用教程
  • Java IO学习笔记一
  • js面向对象
  • js正则,这点儿就够用了
  • nginx(二):进阶配置介绍--rewrite用法,压缩,https虚拟主机等
  • PaddlePaddle-GitHub的正确打开姿势
  • php ci框架整合银盛支付
  • PHP变量
  • PyCharm搭建GO开发环境(GO语言学习第1课)
  • Redis中的lru算法实现
  • Vue小说阅读器(仿追书神器)
  • 规范化安全开发 KOA 手脚架
  • 开源SQL-on-Hadoop系统一览
  • 聊聊springcloud的EurekaClientAutoConfiguration
  • 普通函数和构造函数的区别
  • 十年未变!安全,谁之责?(下)
  • 跳前端坑前,先看看这个!!
  • 优秀架构师必须掌握的架构思维
  • 在 Chrome DevTools 中调试 JavaScript 入门
  • 这几个编码小技巧将令你 PHP 代码更加简洁
  • # Panda3d 碰撞检测系统介绍
  • #pragam once 和 #ifndef 预编译头
  • #调用传感器数据_Flink使用函数之监控传感器温度上升提醒
  • (0)Nginx 功能特性
  • (4) PIVOT 和 UPIVOT 的使用
  • (k8s中)docker netty OOM问题记录
  • (leetcode学习)236. 二叉树的最近公共祖先
  • (超详细)2-YOLOV5改进-添加SimAM注意力机制
  • (附源码)node.js知识分享网站 毕业设计 202038
  • (附源码)springboot优课在线教学系统 毕业设计 081251
  • (转)linux下的时间函数使用
  • ****三次握手和四次挥手
  • .bat批处理(十):从路径字符串中截取盘符、文件名、后缀名等信息
  • .net 重复调用webservice_Java RMI 远程调用详解,优劣势说明