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;

    @Override
    public 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 {
        @Override
        public 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;
    }
    
    @Override
    public void registerLocked() {
        super.registerLocked();
        getHandler().post(new Runnable() {
            @Override
            public void run() {
            	//注册监听overlay_display_devices字段的内容变化
                getContext().getContentResolver().registerContentObserver(
                        Settings.Global.getUriFor(Settings.Global.OVERLAY_DISPLAY_DEVICES),
                        true, new ContentObserver(getHandler()) {
                            @Override
                            public 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() {
            //移除显示模拟辅助屏幕设备的Runnable
            mUiHandler.removeCallbacks(mShowRunnable);
            //执行销毁模拟辅助屏幕设备的Runnable
            mUiHandler.post(mDismissRunnable);
        }

        private void onActiveModeChangedLocked(int index) {
            mUiHandler.removeCallbacks(mResizeRunnable);
            mActiveMode = index;
            if (mWindow != null) {
                mUiHandler.post(mResizeRunnable);
            }
        }

        // Called on the UI thread.
        @Override
        public 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) {
                    @Override
                    public void onModeChangedLocked(int index) {
                        onActiveModeChangedLocked(index);
                    }
                };

                sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_ADDED);
            }
        }

        // Called on the UI thread.
        @Override
        public void onWindowDestroyed() {
            synchronized (getSyncRoot()) {
                if (mDevice != null) {
                    mDevice.destroyLocked();
                    sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_REMOVED);
                }
            }
        }

        // Called on the UI thread.
        @Override
        public 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() {
            @Override
            public 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() {
            @Override
            public 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() {
            @Override
            public 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_OVERLAY
        mWindowParams = 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() {
        @Override
        public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) {
            //触发Listener的onWindowCreated方法
            mListener.onWindowCreated(surfaceTexture,
                    mDefaultDisplayInfo.getRefreshRate(),
                    mDefaultDisplayInfo.presentationDeadlineNanos, mDefaultDisplayInfo.state);
        }

        @Override
        public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
            mListener.onWindowDestroyed();
            return true;
        }

        @Override
        public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture,
                int width, int height) {
        }

        @Override
        public 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.
        @Override
        public 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) {
                    @Override
                    public void onModeChangedLocked(int index) {
                        onActiveModeChangedLocked(index);
                    }
                };
                //通知DMS更新DisplayDevice事件,新增屏幕设备
                sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_ADDED);
            }
        }

        // Called on the UI thread.
        @Override
        public void onWindowDestroyed() {
            synchronized (getSyncRoot()) {
                if (mDevice != null) {
                    mDevice.destroyLocked();
                    //通知DMS更新DisplayDevice事件,屏幕设备被移除
                    sendDisplayDeviceEventLocked(mDevice, DISPLAY_DEVICE_EVENT_REMOVED);
                }
            }
        }

        // Called on the UI thread.
        @Override
        public 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());
        }

        @Override
        public boolean hasStableUniqueId() {
            return false;
        }

        @Override
        public 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;
        }

        @Override
        public 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 frame
                mInfo.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;
        }

        @Override
        public 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);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值