Android 手持設備的畫中畫 (PIP) 功能可讓用戶將正在進行的活動的應用程序調整到小窗口中。 PIP 對於視頻應用程序特別有用,因為當用戶可以自由執行其他操作時,內容會繼續播放。用戶可以通過 SystemUI 操縱此窗口的位置,並使用(最多三個)應用程序提供的操作與當前處於畫中畫狀態的應用程序進行交互。
PIP 需要支持它的應用程序明確選擇加入,並且基於每個活動進行工作。 (單個應用程序可以有多個 Activity,其中只有一個處於 PIP 模式。)Activity 通過調用enterPictureInPictureMode()
請求進入畫中畫,並以onPictureInPictureModeChanged()
的形式接收 Activity 回調。
setPictureInPictureParams()
方法允許活動在 PIP 和自定義操作中控制其寬高比,從而允許用戶與活動進行交互,而無需展開它。在 PIP 中,活動處於暫停但渲染狀態,並且不直接接收觸摸輸入或窗口焦點。 PIP 中一次只能包含一個任務。
更多信息請參閱 Android 開發者畫中畫文檔。
設備要求
要支持 PIP,請在/android/frameworks/base/core/java/android/content/pm/PackageManager.java
中啟用PackageManager#FEATURE_PICTURE_IN_PICTURE
系統功能。支持 PIP 的設備的最小寬度必須大於 220dp。與分屏多窗口類似,PIP 允許多個活動同時在屏幕上運行。因此,設備應具有足夠的 CPU 和 RAM 來支持此用例。
執行
大多數活動生命週期管理是在系統中的ActivityManager
和WindowManager
之間完成的。參考 UI 實現位於SystemUI
包中。
對系統的修改不應影響兼容性測試套件 (CTS) 測試所定義的其內在行為。 PIP 的系統邏輯主要圍繞“固定”堆棧內的任務和活動的管理。以下是課程的快速概述:
-
ActivityRecord
:跟踪每個活動的畫中畫狀態。要防止用戶在某些情況下(例如從鎖定屏幕或在 VR 期間)輸入 PIP,請向checkEnterPictureInPictureState()
添加案例。 -
ActivityManagerService
:請求進入 PIP 的活動的主要接口,以及從WindowManager
和SystemUI
調用以更改 PIP 活動狀態的接口。 -
ActivityStackSupervisor
:從ActivityManagerService
調用,將任務移入或移出固定堆棧,並根據需要更新WindowManager
。 -
PinnedStackWindowController
:ActivityManager
的WindowManager
接口。 -
PinnedStackController
:向SystemUI
報告系統中的更改,例如 IME 顯示/隱藏、寬高比更改或操作更改。 -
BoundsAnimationController
:以在調整大小時不會觸發配置更改的方式對 PIP 活動窗口進行動畫處理。 -
PipSnapAlgorithm
:系統和 SystemUI 中使用的共享類,用於控制屏幕邊緣附近 PIP 窗口的捕捉行為。
參考SystemUI
提供了 PIP 的完整實現,支持向用戶呈現自定義操作和常規操作,例如擴展和關閉。設備製造商可以在這些更改的基礎上進行構建,只要它們不影響 CDD 定義的固有行為即可。以下是課程的快速概述:
-
PipManager
:隨SystemUI
一起啟動的SystemUI
組件。 -
PipTouchHandler
:觸摸處理程序,控制操作 PIP 的手勢。僅當 PIP 的輸入使用者處於活動狀態時才使用它(請參閱InputConsumerController
)。可以在此處添加新手勢。 -
PipMotionHelper
:一個方便的類,用於跟踪 PIP 位置以及屏幕上允許的區域。調用ActivityManagerService
以更新或設置 PIP 的位置和大小的動畫。 -
PipMenuActivityController
:啟動一個活動,顯示當前 PIP 中活動提供的操作。此活動是任務覆蓋活動,並刪除覆蓋輸入使用者以允許其交互。 -
PipMenuActivity
:菜單活動的實現。 -
PipMediaController
:當媒體會話更改可能影響 PIP 上的默認操作時更新SystemUI
偵聽器。 -
PipNotificationController
:確保用戶使用 PIP 功能時通知處於活動狀態的控制器。 -
PipDismissViewController
:當用戶開始與 PIP 交互時向用戶顯示的覆蓋層,以指示它可以被關閉。
默認展示位置
有多種系統資源可以控制 PIP 的默認位置:
-
config_defaultPictureInPictureGravity
:重力整數,控制放置 PIP 的角點,例如BOTTOM|RIGHT
。 -
config_defaultPictureInPictureScreenEdgeInsets
:放置 PIP 時距屏幕兩側的偏移量。 -
config_pictureInPictureDefaultSizePercent
和config_pictureInPictureDefaultAspectRatio
:屏幕寬度百分比和寬高比的組合控制 PIP 的大小。計算出的默認 PIP 大小不應小於 CTS 和 CDD 定義的@dimen/default_minimal_size_pip_resizable_task
。 -
config_pictureInPictureSnapMode
:PipSnapAlgorithm
中定義的捕捉行為。
設備實現不應更改 CDD 和 CTS 中定義的最小和最大縱橫比。
權限
AppOpsManager
( master/core/java/android/app/AppOpsManager.java
) 中的每個包“應用程序操作”( OP_PICTURE_IN_PICTURE
) 允許用戶通過系統設置在每個應用程序級別上控制 PIP。當活動請求進入畫中畫模式時,設備實現需要遵守此檢查。
測試
要測試 PIP 實現,請運行/cts/hostsidetests/services/activitymanager
下的主機端 CTS 測試中找到的所有畫中畫相關測試,特別是在ActivityManagerPinnedStackTests.java
中。