Android 自由窗口实现小窗模式的(Android 10)
Android 基于自由窗口实现小窗模式分析(Android 10)
在小窗口模式定制过程中,难免会遇到一些奇怪的问题,需要系统层去做支持。
1 如何更新 TOP RESUMED 窗口UI
在多窗口模式下,如何在最顶部(TOP RESUMED状态)的应用更新时获取到通知,以便我们去更新窗口的相关UI。这里有两种思路:
- 获取当前resumed窗口列表,提供接口与窗口通信,并通知窗口更新。
- 当top resumed 更新时,通知当前窗口做相关更新。
以下均使用伪代码 FreeformManager.isInSmallScreen() 代表处于小窗模式。
//frameworks/base/core/java/android/app/freeform/FreeformManager.java
public class FreeformManager {
// 启动自由窗口
public static void startFreeSplit(Context context, Intent intent, Rect rect, int position) {
if (intent == null || context == null) {
return;
}
intent.setFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT | Intent.FLAG_ACTIVITY_NEW_TASK);
ActivityOptions options = ActivityOptions.makeBasic();
options.setLaunchWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM);
if (rect != null) {
options.setLaunchBounds(rect);
}
context.startActivity(intent, options.toBundle());
}
// 是否处于小窗模式
public static void isInSmallScreen() {
if (intent == null || context == null) {
return;
}
intent.setFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT | Intent.FLAG_ACTIVITY_NEW_TASK);
ActivityOptions options = ActivityOptions.makeBasic();
options.setLaunchWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM);
if (rect != null) {
options.setLaunchBounds(rect);
}
context.startActivity(intent, options.toBundle());
}
这里提供思路2的相关实现:
Top resumed activity 更新时通知UI更新:
//frameworks/base/core/java/android/app/Activity.java
final void performTopResumedActivityChanged(boolean isTopResumedActivity, String reason) {
//当活动获得或失去系统中的顶部恢复位置时调用。从 AndroidQ 开始,可以在多窗口和多显示模式下同时恢复多个活动。
//应使用此回调而不是 onResume 来指示活动可以尝试打开独占访问设备(如相机)。它将始终在活动恢复之后和暂停之前传递。
onTopResumedActivityChanged(isTopResumedActivity);
// add by ian4u: top resumed activity 更新时通知UI更新
if (isInMultiWindowMode() && FreeformManager.isInSmallScreen()) {
updateDecorCaption();
}
}
private void updateDecorCaption() {
mHandler.postDelayed(() -> {
if (mDecor != null) {
DecorView decorView = (DecorView) this.mDecor;
// 更新 decorView UI, decorView包含了自由窗口的UI实现,有兴趣的自行分析。。。
decorView.updateDecorTitle();
}
}, 30);
}
以下是 DecorView 的修改:
// frameworks/base/core/java/com/android/internal/policy/DecorView.java
private View mForegroundView;
public void updateDecorTitle() {
boolean inCenterScale = FreeformManager.isInSmallScreen();
//设置小窗口顶部控制栏是否显示
if (mDecorCaptionView != null) {
mDecorCaptionView.updateCaption(inCenterScale ? View.VISIBLE : View.GONE);
}
Drawable foreDrawable = mContext.getDrawable(inCenterScale
? R.drawable.decor_caption_content_unfocused
: R.drawable.decor_caption_content);
// setForeground(foreDrawable);
// 设置小窗口的焦点样式
LayoutInflater layoutInflater = mWindow.getLayoutInflater();
if (mForegroundView == null) {
mForegroundView = layoutInflater.inflate(R.layout.decor_foreground, null);
addView(mForegroundView, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
}
mForegroundView.setForeground(foreDrawable);
// 设置小窗口圆角
ViewOutlineProvider viewOutlineProvider = new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
if (view.getWidth() != 0 && view.getHeight() != 0) {
outline.setRoundRect(new Rect(0, 0, view.getMeasuredWidth(),
view.getMeasuredHeight()), 26);
}
}
};
setOutlineProvider(inCenterScale ? viewOutlineProvider : null);
setClipToOutline(inCenterScale);
}
以下是 DecorCaptionView 的修改,该类是顶部控制栏控件, 布局文件在
frameworks/base/core/res/res/layout/decor_caption.xml
// frameworks/base/core/java/com/android/internal/widget/DecorCaptionView.java
public class DecorCaptionView extends ViewGroup implements View.OnTouchListener,
GestureDetector.OnGestureListener {
private View mSwitch;
public void updateCaption(int visible) {
if (mCaption != null) {
mCaption.setVisibility(visible);
}
}
}
ResizeTask 时,发送广播通知activity 更新UI:
final void performCreate(Bundle icicle, PersistableBundle persistentState) {
dispatchActivityPreCreated(icicle);
mCanEnterPictureInPicture = true;
restoreHasCurrentPermissionRequest(icicle);
if (persistentState != null) {
onCreate(icicle, persistentState);
} else {
onCreate(icicle);
}
//省略代码。。。
mFragments.dispatchActivityCreated();
mActivityTransitionState.setEnterActivityOptions(this, getActivityOptions());
dispatchActivityPostCreated(icicle);
// add by ian4u:
//当任务栈大小改变(ATMS.resizeTask)时,发送广播, 通知当前窗口做修改
if (isInMultiWindowMode() && FreeformManager.isInSmallScreen() ) {
IntentFilter filter = new IntentFilter(Intent.ACTION_CAPTION_UPDATE);
registerReceiver(mBroadcastReceiver, filter);
}
}
final void performDestroy() {
// 销毁广播注册
if (isInMultiWindowMode() && FreeformManager.isInSmallScreen()) {
unregisterReceiver(mBroadcastReceiver);
}
dispatchActivityPreDestroyed();
mDestroyed = true;
mWindow.destroy()
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhgfhkae
系列文章
更多
同类精品
更多
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01 -
怎样阻止微信小程序自动打开
PHP中文网 06-13