Android 11 的状态栏的隐藏

news2024/11/16 19:23:25

概述

Android 11 的状态栏与导航栏较之前的版本有较大的差异, 在Android 7.0 SystemUI 状态/导航栏的隐藏与显示中所描述的部分内容已不再适用.
比如, 自动隐藏的时间, 隐藏的动画, 较之前的版本已面目全非, 本文将对隐藏状态栏部分的内容进行一些补充.

APP如何隐藏状态栏

  • 参考文档:隐藏状态栏_Android 开发者_Android Developers.pdf)
方法一:
 <application
        ...
        android:theme="@android:style/Theme.Holo.NoActionBar.Fullscreen" >
        ...
    </application>

方法二:

    public class MainActivity extends Activity {

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            // If the Android version is lower than Jellybean, use this call to hide
            // the status bar.
            if (Build.VERSION.SDK_INT < 16) {
                getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                        WindowManager.LayoutParams.FLAG_FULLSCREEN);
            }
            setContentView(R.layout.activity_main);
        }
        ...
    }

方法三:(在4.1(SDK 16)及之上)

    View decorView = getWindow().getDecorView();
    // Hide the status bar.
    int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN;
    decorView.setSystemUiVisibility(uiOptions);
    // Remember that you should never show the action bar if the
    // status bar is hidden, so hide that too if necessary.
    ActionBar actionBar = getActionBar();
    actionBar.hide();
    

状态栏是怎么被隐藏的

1. 通过上面的方式主动调用接口设置窗口属性, 由系统判断并完成隐藏
在这里插入图片描述

frameworks/base/core/java/android/view/InsetsController.java

        @Override
        public void onReady(WindowInsetsAnimationController controller, int types) {
            mController = controller;
            if (DEBUG) Log.d(TAG, "default animation onReady types: " + types);

            if (mDisable) {
                onAnimationFinish();
                return;
            }
            mAnimator = ValueAnimator.ofFloat(0f, 1f);
            mAnimator.setDuration(mDurationMs);
            mAnimator.setInterpolator(new LinearInterpolator());
            Insets hiddenInsets = controller.getHiddenStateInsets();
            // IME with zero insets is a special case: it will animate-in from offscreen and end
            // with final insets of zero and vice-versa.
            hiddenInsets = controller.hasZeroInsetsIme()
                    ? Insets.of(hiddenInsets.left, hiddenInsets.top, hiddenInsets.right,
                            mFloatingImeBottomInset)
                    : hiddenInsets;
            Insets start = mShow
                    ? hiddenInsets
                    : controller.getShownStateInsets();
            Insets end = mShow
                    ? controller.getShownStateInsets()
                    : hiddenInsets;
            Interpolator insetsInterpolator = getInterpolator();
            Interpolator alphaInterpolator = getAlphaInterpolator();
            mAnimator.addUpdateListener(animation -> {
                float rawFraction = animation.getAnimatedFraction();
                float alphaFraction = mShow
                        ? rawFraction
                        : 1 - rawFraction;
                float insetsFraction = insetsInterpolator.getInterpolation(rawFraction);
                controller.setInsetsAndAlpha(
                        sEvaluator.evaluate(insetsFraction, start, end),
                        alphaInterpolator.getInterpolation(alphaFraction),
                        rawFraction);
                if (DEBUG) Log.d(TAG, "Default animation setInsetsAndAlpha fraction: "
                        + insetsFraction);
            });
            mAnimator.addListener(new AnimatorListenerAdapter() {

                @Override
                public void onAnimationEnd(Animator animation) {
                    onAnimationFinish();
                }
            });
            if (!mHasAnimationCallbacks) {
                mAnimator.setAnimationHandler(mSfAnimationHandlerThreadLocal.get());
            }
            mAnimator.start();
        }

为定位到这一段代码, 走了相当曲折又漫长的路.

  • 第一个误区: 参照之前的状态栏隐藏流程代码, 在frameworks/base/service中转了很长时间.
  • 第二个误区: 误判隐藏动画的是在SystemUI中实现.

在不断地调试分析后, 最终的突破口在SurfaceControl的子类Transaction
最终输出以下LOG, 最终定位到上面的代码.

2022-12-09 17:56:47.413   	at android.view.SurfaceControl$SurfaceControl.setPosition(SurfaceControl.java:2435)
2022-12-09 17:56:47.413   	at android.view.SurfaceControl$Transaction.setMatrix(SurfaceControl.java:2609)
2022-12-09 17:56:47.413   	at android.view.SyncRtSurfaceTransactionApplier.applyParams(SyncRtSurfaceTransactionApplier.java:97)
2022-12-09 17:56:47.413   	at com.android.server.wm.InsetsPolicy$InsetsPolicyAnimationControlListener$InsetsPolicyAnimationControlCallbacks.applySurfaceParams(InsetsPolicy.java:542)
2022-12-09 17:56:47.413   	at android.view.InsetsAnimationControlImpl.applyChangeInsets(InsetsAnimationControlImpl.java:214)
2022-12-09 17:56:47.413   	at com.android.server.wm.InsetsPolicy$InsetsPolicyAnimationControlListener$InsetsPolicyAnimationControlCallbacks.scheduleApplyChangeInsets(InsetsPolicy.java:510)
2022-12-09 17:56:47.413   	at android.view.InsetsAnimationControlImpl.setInsetsAndAlpha(InsetsAnimationControlImpl.java:186)
2022-12-09 17:56:47.413   	at android.view.InsetsAnimationControlImpl.setInsetsAndAlpha(InsetsAnimationControlImpl.java:170)
2022-12-09 17:56:47.414   	at android.view.InsetsController$InternalAnimationControlListener.lambda$onReady$0$InsetsController$InternalAnimationControlListener(InsetsController.java:332)
2022-12-09 17:56:47.414   	at android.view.-$$Lambda$InsetsController$InternalAnimationControlListener$SInf91MjJKDQFXwrp7C-HBi0xaQ.onAnimationUpdate(Unknown Source:13)
2022-12-09 17:56:47.414   	at android.animation.ValueAnimator.animateValue(ValueAnimator.java:1566)
2022-12-09 17:56:47.414   	at android.animation.ValueAnimator.animateBasedOnTime(ValueAnimator.java:1357)
2022-12-09 17:56:47.414   	at android.animation.ValueAnimator.doAnimationFrame(ValueAnimator.java:1489)
2022-12-09 17:56:47.414   	at android.animation.AnimationHandler.doAnimationFrame(AnimationHandler.java:146)
2022-12-09 17:56:47.414   	at android.animation.AnimationHandler.access$100(AnimationHandler.java:37)
2022-12-09 17:56:47.414   	at android.animation.AnimationHandler$1.doFrame(AnimationHandler.java:54)
2022-12-09 17:56:47.415   	at android.view.Choreographer$CallbackRecord.run(Choreographer.java:970)
2022-12-09 17:56:47.415   	at android.view.Choreographer.doCallbacks(Choreographer.java:796)
2022-12-09 17:56:47.415   	at android.view.Choreographer.doFrame(Choreographer.java:727)
2022-12-09 17:56:47.415   	at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:957)
2022-12-09 17:56:47.415   	at android.os.Handler.handleCallback(Handler.java:938)
2022-12-09 17:56:47.415   	at android.os.Handler.dispatchMessage(Handler.java:99)
2022-12-09 17:56:47.415   	at android.os.Looper.loop(Looper.java:223)
2022-12-09 17:56:47.415   	at android.os.HandlerThread.run(HandlerThread.java:67)
2022-12-09 17:56:47.415   	at com.android.server.ServiceThread.run(ServiceThread.java:44)

状态栏/导航栏 隐藏与显示动画过渡时长:
在定位到代码后, 最先做的事情, 就是把时间增加10倍, 编译看效果.

frameworks/base/core/java/android/view/InsetsController.java

    private static final int ANIMATION_DURATION_SHOW_MS = 275;
    private static final int ANIMATION_DURATION_HIDE_MS = 340;

2. 隐藏后, 用户下拉状态栏, SystemUI定时执行自动隐藏(AutoHideController)

frameworks/base/services/core/java/com/android/server/wm/InsetsPolicy.java

    void hideTransient() {
        if (mShowingTransientTypes.size() == 0) {
            return;
        }
        InsetsState state = new InsetsState(mStateController.getRawInsetsState());
        startAnimation(false /* show */, () -> {
            synchronized (mDisplayContent.mWmService.mGlobalLock) {
                mShowingTransientTypes.clear();
                mStateController.notifyInsetsChanged();
                updateBarControlTarget(mFocusedWin);
            }
        }, state);
        mStateController.onInsetsModified(mDummyControlTarget, state);
    }
    void startAnimation(boolean show, Runnable callback, InsetsState state) {
        int typesReady = 0;
        final SparseArray<InsetsSourceControl> controls = new SparseArray<>();
        final IntArray showingTransientTypes = mShowingTransientTypes;
        for (int i = showingTransientTypes.size() - 1; i >= 0; i--) {
            int type = showingTransientTypes.get(i);
            InsetsSourceProvider provider = mStateController.getSourceProvider(type);
            InsetsSourceControl control = provider.getControl(mDummyControlTarget);
            if (control == null || control.getLeash() == null) {
                continue;
            }
            typesReady |= InsetsState.toPublicType(type);
            controls.put(control.getType(), new InsetsSourceControl(control));
            state.setSourceVisible(type, show);
        }
        controlAnimationUnchecked(typesReady, controls, show, callback);
    }
    private void controlAnimationUnchecked(int typesReady,
            SparseArray<InsetsSourceControl> controls, boolean show, Runnable callback) {
        InsetsPolicyAnimationControlListener listener =
                new InsetsPolicyAnimationControlListener(show, callback, typesReady);
        listener.mControlCallbacks.controlAnimationUnchecked(typesReady, controls, show);
    }

    private class InsetsPolicyAnimationControlListener extends
            InsetsController.InternalAnimationControlListener {
        Runnable mFinishCallback;
        InsetsPolicyAnimationControlCallbacks mControlCallbacks;

        InsetsPolicyAnimationControlListener(boolean show, Runnable finishCallback, int types) {

            super(show, false /* hasCallbacks */, types, false /* disable */,
                    (int) (mDisplayContent.getDisplayMetrics().density * FLOATING_IME_BOTTOM_INSET
                            + 0.5f));
            mFinishCallback = finishCallback;
            mControlCallbacks = new InsetsPolicyAnimationControlCallbacks(this);
        }

        private class InsetsPolicyAnimationControlCallbacks implements
                InsetsAnimationControlCallbacks {
			...
            private void controlAnimationUnchecked(int typesReady,
                    SparseArray<InsetsSourceControl> controls, boolean show) {
                if (typesReady == 0) {
                    // nothing to animate.
                    return;
                }
                mAnimatingShown = show;

                mAnimationControl = new InsetsAnimationControlImpl(controls,
                        mFocusedWin.getDisplayContent().getBounds(), getState(),
                        mListener, typesReady, this, mListener.getDurationMs(),
                        InsetsController.SYSTEM_BARS_INTERPOLATOR,
                        show ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE);
                SurfaceAnimationThread.getHandler().post(
                        () -> mListener.onReady(mAnimationControl, typesReady));
            }

一些类图

在这里插入图片描述

一些关键代码.

frameworks/base/core/java/android/view/ViewRootImpl.java

                case MSG_SHOW_INSETS: {
                    if (mView == null) {
                        Log.e(TAG,
                                String.format("Calling showInsets(%d,%b) on window that no longer"
                                        + " has views.", msg.arg1, msg.arg2 == 1));
                    }
                    clearLowProfileModeIfNeeded(msg.arg1, msg.arg2 == 1);
                    mInsetsController.show(msg.arg1, msg.arg2 == 1);
                    break;
                }
    private void controlInsetsForCompatibility(WindowManager.LayoutParams params) {
        if (sNewInsetsMode != NEW_INSETS_MODE_FULL) {
            return;
        }
        final int sysUiVis = params.systemUiVisibility | params.subtreeSystemUiVisibility;
        final int flags = params.flags;
        final boolean matchParent = params.width == MATCH_PARENT && params.height == MATCH_PARENT;
        final boolean nonAttachedAppWindow = params.type >= FIRST_APPLICATION_WINDOW
                && params.type <= LAST_APPLICATION_WINDOW;
        final boolean statusWasHiddenByFlags = (mTypesHiddenByFlags & Type.statusBars()) != 0;
        final boolean statusIsHiddenByFlags = (sysUiVis & SYSTEM_UI_FLAG_FULLSCREEN) != 0
                || ((flags & FLAG_FULLSCREEN) != 0 && matchParent && nonAttachedAppWindow);
        final boolean navWasHiddenByFlags = (mTypesHiddenByFlags & Type.navigationBars()) != 0;
        final boolean navIsHiddenByFlags = (sysUiVis & SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0;

        @InsetsType int typesToHide = 0;
        @InsetsType int typesToShow = 0;
        if (statusIsHiddenByFlags && !statusWasHiddenByFlags) {
            typesToHide |= Type.statusBars();
        } else if (!statusIsHiddenByFlags && statusWasHiddenByFlags) {
            typesToShow |= Type.statusBars();
        }
        if (navIsHiddenByFlags && !navWasHiddenByFlags) {
            typesToHide |= Type.navigationBars();
        } else if (!navIsHiddenByFlags && navWasHiddenByFlags) {
            typesToShow |= Type.navigationBars();
        }
        if (typesToHide != 0) {
            getInsetsController().hide(typesToHide);
        }
        if (typesToShow != 0) {
            getInsetsController().show(typesToShow);
        }
        mTypesHiddenByFlags |= typesToHide;
        mTypesHiddenByFlags &= ~typesToShow;
    }

参考

隐藏状态栏| Android 开发者
Android 显示、隐藏状态栏和导航栏
SurfaceFlinger中Layer的修改 - 安卓R

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/83114.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Yield Guild Games 成功举办首届 SubDAO 峰会

Yield Guild Games&#xff08;YGG&#xff09;于 2022 年 11 月 18 日在菲律宾马尼拉举行了第一届 SubDAO 峰会。 SubDAO 峰会与菲律宾 Web3 狂欢节两个活动同时举行&#xff0c;为 YGG 的区域 SubDAO 提供了在 Web3 应用中心——菲律宾进行面对面交流的机会。此次活动旨在传达…

运维开发实践 - helm

1. helm介绍 helm 是一个用于管理部署在kubernetes上的应用的工具 使用要求&#xff1a;一个Kubernetes集群 2.下载安装 Helm Github Download Helm Huawei Source 按照自己的操作系统版本下载相应的helm压缩包 并将helm添加到环境变量中; # 检查是否安装成功 helm version…

read_thread解复用线程分析

read_thread() 线程的主要作用从 MP4 里面读取 AVPacket&#xff0c;然后丢进去 PacketQueue 队列。所以需要先学习一下 strcut PacketQueue 跟 struct MyAVPacketList 数据结构。如下&#xff1a; typedef struct MyAVPacketList {AVPacket *pkt;int serial; } MyAVPacketLis…

html文件里怎么引用vue组件?

这里我们使用 http-vue-loader 来实现&#xff1a;https://www.npmjs.com/package/http-vue-loader Load .vue files directly from your html/js. No node.js environment, no build step. 我做了个demo如下&#xff1a; html文件里面写下面的代码 <!DOCTYPE html> &l…

计算机研究生就业方向之当老师(中小学)

我一直跟学生们说你考计算机的研究生之前一定要想好你想干什么&#xff0c;如果你只是转码&#xff0c;那么你不一定要考研&#xff0c;至少以下几个职位研究生是没有啥优势的&#xff1a; 1&#xff0c;软件测试工程师&#xff08;培训一下就行&#xff09; 2&#xff0c;前…

股票购买接口系统怎么使用vn.py进行量化策略?

一般情况下&#xff0c;股票购买接口系统主要是可以运用在股票量化交易系统开发的一个大方向&#xff0c;也就是说&#xff0c;股票购买接口系统是根据这些量化的特点来开发的&#xff0c;就比如使用vn.py进行量化策略&#xff0c;在这方面&#xff0c;对交易者进行量化分析也起…

Web前端105天-day-41-JSCORE

JSCORE01 目录 前言 一、声明提升 二、宿主 window 三、断点功能 四、匿名函数解决全局污染 五、作用域链 六、闭包 七、私有 八、arguments 九、函数重载 十、方括号属性语法 十一、重载练习 十二、this 总结 前言 JSCORE01学习开始 一、声明提升 报错方案: 让…

走进SpringCloud微服务

微服务概述一、注册中心&#xff1a;Eureka ⭐⭐⭐1.1 原理1.2 代码二、负载均衡&#xff1a;Ribbon ⭐三、远程调用&#xff1a;Feigh ⭐⭐⭐3.1 原理3.2 代码四、熔断限流&#xff1a;Hystrix ⭐⭐⭐4.1线程池策略4.2 信号量隔离策略4.3 方法降级4.4 断路器、熔断器五、网关&…

MongoDB和MongoTemplate对于嵌套数据的判空查询

前言&#xff1a; 不知道有没有和小名一样&#xff0c;接触MongDB时间不长的小伙伴。由于MongoDB是以文档形式存储数据的&#xff0c;所以其中的数据类型相对MySql或者Oracle关系型数据库丰富一些&#xff08;MongoDB是NoSQL数据库这里比较不是很准确&#xff09; 我们在关系…

Dropout方法原理和使用方法

来源&#xff1a;投稿 作者&#xff1a;梦飞翔 编辑&#xff1a;学姐 为什么提出这种方法&#xff1f; 神经网络在训练过程中&#xff0c;由于正负样本不均衡、样本特征显著性不足、训练参数不合适等原因会导致发生过拟合现象&#xff0c;即模型参数陷入局部最优&#xff0c;仅…

QT6操作连接mysql数据库方法_增删改查

QT6操作mysql方法_增删改查 mysql数据库搭建相关方法&#xff1a; MySQL - 随笔分类 - txwtech - 博客园https://www.cnblogs.com/txwtech/category/1973054.htmlMySQL解压版配置方法 MySQL解压版配置方法 - txwtech - 博客园1.下载 https://downloads.mysql.com/archives/co…

【知识学习】C++QT配置opencv遇到的坑

最近要搞图像&#xff0c;老师说尽量用C&#xff0c;就开始研究配置opencv 当然&#xff0c;说在前面&#xff0c;C的比python的要麻烦特别多&#xff0c;所以如果不是必要的话&#xff0c;建议用python pip配opencv吧 C麻烦就在于要自己在本地编译一遍才能跑&#xff0c;直接…

如何将亚马逊Seller Central 用到极致~

不论是新手卖家还是有经验的老手&#xff0c;亚马逊卖家中心都是一个可以帮助卖家发展业务的好工具&#xff0c;对于许多新手小白来说&#xff0c;亚马逊这样巨大的平台仍有许多功能与服务等着挖掘。 什么是亚马逊卖家中心&#xff1f; 亚马逊卖家中心是第三方卖家用来管理和…

微信支付-全面详解(学习总结---从入门到深化)

微信支付_产品介绍 微信支付介绍 微信支付&#xff08;https://pay.weixin.qq.com&#xff09;是腾讯集团旗下中国领先 的第三方支付平台&#xff0c;一直致力于为用户和企业提供安全、便捷、专业的在线支付服务。 付款码支付 付款码支付是指用户展示微信钱包内的“付款码”给商…

指纹浏览器是什么?可以用来解决网络爬虫的什么问题?

在大数据时代的今天&#xff0c;各行各业的许多企业多多少少都会因为涉及到海外市场需要收集大量的市场信息&#xff0c;特别是对于跨境电商领域的商家来说&#xff0c;网络爬虫是必不可少的。因此&#xff0c;一定有很多从业者接触过网络爬虫&#xff0c;但对于刚打算进入这个…

ADI Blackfin DSP处理器-BF533的开发详解36:图像处理专题-RGB888 转 RGB565(含源代码)

硬件准备 ADSP-EDU-BF533&#xff1a;BF533开发板 AD-HP530ICE&#xff1a;ADI DSP仿真器 软件准备 Visual DSP软件 硬件链接 功能介绍 作为一个最高600M主频&#xff0c;单核或双核的定点DSP&#xff0c;做图像处理还是挺行的&#xff0c;属于是老本行&#xff0c;那么我…

广州蓝景分享—HTML+CSS功能,让页面加载速度提高数倍

Hello&#xff0c;各位小伙伴&#xff0c;今天跟大家分享前端技术干货&#xff0c;页面加载速度问题。 首先我们都讨厌加载缓慢的页面&#xff01; 要知道加载时间每增加1秒&#xff08;0-5秒之间&#xff09;&#xff0c;网站转化率就会平均下降4.42%。页面加载时间的前五秒…

linux 虚拟机nat模式网络配置

文章目录1. linux 版本&#xff1a;2. 下载地址 Index of /centos-store/7.6.1810/isos/x86_64/ (liu.se)3. 账号密码&#xff1a;root root4.选择nat 模式&#xff0c;勾选 将主机虚拟适配器连接到此网络&#xff0c;勾选 使用本地DHCP服务将iP地址分配给虚拟机5.点击Nat 设置…

数据仓库分享

前言 数据仓库&#xff0c;是为企业所有级别的决策制定过程&#xff0c;提供所有类型数据支持的战略集合。它出于分析性报告和决策支持的目的而创建的。 数据仓库是一个数据集合 数据仓库是一个为业务决策提供数据支持的数据集合 数据仓库是通过监控业务流程的形式为业务决策提…

Css不常用的方法

flex布局换行之后&#xff0c;下面一行的布局会异常 .homeItemBox{ display: flex; flex-wrap: wrap; justify-content: flex-start;} .homeItem{ display: flex; width: calc((100% - 20rpx) / 4); flex-direction: column; align-items: center; flex-shrink: 0; …