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

Android 11 SystemUI(状态/导航栏)-状态栏下拉时图标的隐藏与通知面板的半透黑色背景

概述

本文续自:Android 11 的状态栏的隐藏

PS
本文虽然同属于SystemUI, 但目前并 没有 打算整理成专橍或撰写一个系列的想法.
仅仅为了记录一些过程, 留下那些容易被遗忘的点滴.

开始下拉时状态栏图标被隐藏

   状态橍的图标在用户开始触摸(ACTION_DOWN)后, 会开始展开, 显示扩展面板, 同时, 隐藏状态橍上的通知和状态图标. 在手机上表现有可能不同, 在android 13上, 在点击没有作用, 只有下拉一定的距离,才会开始隐藏.

device-2022-12-21-190046

在这里插入图片描述

隐藏从触摸下按开始, 参照下图:
在这里插入图片描述

忽略过程代码, 直接上最后一部分:

frameworks/base/packages/SystemUI//src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java

    @Overridepublic void disable(int displayId, int state1, int state2, boolean animate) {if (displayId != getContext().getDisplayId()) {return;}state1 = adjustDisableFlags(state1);final int old1 = mDisabled1;final int diff1 = state1 ^ old1;mDisabled1 = state1;if ((diff1 & DISABLE_SYSTEM_INFO) != 0) {if ((state1 & DISABLE_SYSTEM_INFO) != 0) {hideSystemIconArea(animate);hideOperatorName(animate);} else {showSystemIconArea(animate);showOperatorName(animate);}}if ((diff1 & DISABLE_NOTIFICATION_ICONS) != 0) {if ((state1 & DISABLE_NOTIFICATION_ICONS) != 0) {hideNotificationIconArea(animate);} else {showNotificationIconArea(animate);}}// The clock may have already been hidden, but we might want to shift its// visibility to GONE from INVISIBLE or vice versaif ((diff1 & DISABLE_CLOCK) != 0 || mClockView.getVisibility() != clockHiddenMode()) {if ((state1 & DISABLE_CLOCK) != 0) {hideClock(animate);} else {showClock(animate);}}}protected int adjustDisableFlags(int state) {boolean headsUpVisible = mStatusBarComponent.headsUpShouldBeVisible();if (headsUpVisible) {state |= DISABLE_CLOCK;}if (!mKeyguardStateController.isLaunchTransitionFadingAway()&& !mKeyguardStateController.isKeyguardFadingAway()&& shouldHideNotificationIcons()&& !(mStatusBarStateController.getState() == StatusBarState.KEYGUARD&& headsUpVisible)) {state |= DISABLE_NOTIFICATION_ICONS;state |= DISABLE_SYSTEM_INFO;state |= DISABLE_CLOCK;}if (mNetworkController != null && EncryptionHelper.IS_DATA_ENCRYPTED) {if (mNetworkController.hasEmergencyCryptKeeperText()) {state |= DISABLE_NOTIFICATION_ICONS;}if (!mNetworkController.isRadioOn()) {state |= DISABLE_SYSTEM_INFO;}}// The shelf will be hidden when dozing with a custom clock, we must show notification// icons in this occasion.if (mStatusBarStateController.isDozing()&& mStatusBarComponent.getPanelController().hasCustomClock()) {state |= DISABLE_CLOCK | DISABLE_SYSTEM_INFO;}return state;}

关于CollapsedStatusBarFragment

    在读到CollapsedStatusBarFragment相关代码的时候, 一时没办法把Fragment与SystemUI串联起来, 这源于传统Fragment的使用习惯: 在Activity中, 获取一个FragmentManager, 创建各种Fragment, 调用replace, show, hide…
 
    难道SystemUI也吃这一套? 状态栏和导航栏不一直是通过WindowManager.addView()直接往里面丢的么!
 
    CollapsedStatusBarFragment 本身没什么特别的, 它只是一个android.app.Fragment, 没有特殊的地方, 特殊的是FragmentController, 它与传统的Fragment使用方法完全不同, 参考 frameworks/base/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
编写一段测试代码, 以便更直观了解它的用法:

public class TestActivity extends Activity{void testFragmentController(Context ctx, Handler h, int winAnim){if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {FragmentController fragCtrl = FragmentController.createController(new FragmentHostCallback<Object>(ctx, h, 0) {@Overridepublic Object onGetHost() {return null;}@Overridepublic <T extends View> T onFindViewById(int id) {return findViewById(id);}});//java.lang.IllegalStateException: Activity has been destroyed//    at android.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1913)fragCtrl.attachHost(null);fragCtrl.dispatchCreate();fragCtrl.dispatchStart();fragCtrl.dispatchResume();//java.lang.IllegalArgumentException: No view found for id 0x7f08007c (com.android.factorytest:id/flRoot) for fragment SimpleFragment{2b5da47 #0 id=0x7f08007c}fragCtrl.getFragmentManager().beginTransaction().replace(R.id.flRoot, new SimpleFragment()).commit();}}public static class SimpleFragment extends Fragment{@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {TextView tv = new TextView(getActivity());tv.setLayoutParams(new ViewGroup.LayoutParams(UiTools.MATCH_PARENT, UiTools.MATCH_PARENT));tv.setText("FragmentController");tv.setTextSize(36);return tv;}}
}

重点关注代码中的createControllerFragmentHostCallback, 当创建完成后, 便可以通过 FragmentControllergetFragmentManager获取FragmentManager, 接下来就是熟悉的操作, 不多描述.

 

下拉通知黑色背景

    在下拉通知面板的过程中, 存在两部分的半透明背景, 第一部分(上)比较明显, 第二部分比较隐藏晦.
效果如下图:
在这里插入图片描述
在这里插入图片描述
这是一个自定义的View, 从layout文件中可以找到它: ScrimView

frameworks/base/packages/SystemUI/res/layout/super_notification_shade.xml

<com.android.systemui.statusbar.phone.NotificationShadeWindowViewxmlns:android="http://schemas.android.com/apk/res/android"xmlns:sysui="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"android:fitsSystemWindows="true"><!-- 省略代码 --><com.android.systemui.statusbar.ScrimViewandroid:id="@+id/scrim_behind"android:layout_width="match_parent"android:layout_height="match_parent"android:importantForAccessibility="no"sysui:ignoreRightInset="true"/>

frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java

diff --git a/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java b/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
index 7f30009cda..907d58c267 100644
--- a/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
+++ b/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
@@ -69,7 +69,7 @@ public class ScrimView extends View {@Overrideprotected void onDraw(Canvas canvas) {
-        if (mDrawable.getAlpha() > 0) {
+        if (false && mDrawable.getAlpha() > 0) {//强制不进行绘制, 就不会出现半透明背景mDrawable.draw(canvas);}}

第二部分只有在下拉到底部时才会出现(不仔细分辨很难看出来):
在这里插入图片描述
同样, 来自另一个自定义控件:AlphaOptimizedView

frameworks\base\packages\SystemUI\res\layout\status_bar_expanded.xml

    <com.android.systemui.statusbar.AlphaOptimizedViewandroid:id="@+id/qs_navbar_scrim"android:layout_height="66dp"android:layout_width="match_parent"android:layout_gravity="bottom"android:visibility="invisible"android:background="@drawable/qs_navbar_scrim" />

扩展

Dagger, 绕得脑壳疼, 记录下out下的路径

out/soong/.intermediates/frameworks/base/packages/SystemUI/SystemUI-core/android_common/kapt/gen/sources/com/android/systemui/dagger/DaggerSystemUIRootComponent.java

public final class DaggerSystemUIRootComponent implements SystemUIRootComponent {private Provider<SystemUIRootComponent> systemUIRootComponentProvider;this.systemUIRootComponentProvider = InstanceFactory.create((SystemUIRootComponent) this);private Provider<FragmentService> fragmentServiceProvider;this.fragmentServiceProvider =DoubleCheck.provider(FragmentService_Factory.create(systemUIRootComponentProvider, provideConfigurationControllerProvider));
}

frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIAppComponentFactory.java

    @NonNull@Overridepublic Application instantiateApplicationCompat(@NonNull ClassLoader cl, @NonNull String className)throws InstantiationException, IllegalAccessException, ClassNotFoundException {Application app = super.instantiateApplicationCompat(cl, className);if (app instanceof ContextInitializer) {((ContextInitializer) app).setContextAvailableCallback(context -> {SystemUIFactory.createFromConfig(context);SystemUIFactory.getInstance().getRootComponent().inject(SystemUIAppComponentFactory.this);});}return app;}

frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java

    private void init(Context context) {mRootComponent = buildSystemUIRootComponent(context);// Every other part of our codebase currently relies on Dependency, so we// really need to ensure the Dependency gets initialized early on.Dependency dependency = new Dependency();mRootComponent.createDependency().createSystemUI(dependency);dependency.start();}public static void createFromConfig(Context context) {if (mFactory != null) {return;}final String clsName = context.getString(R.string.config_systemUIFactoryComponent);if (clsName == null || clsName.length() == 0) {throw new RuntimeException("No SystemUIFactory component configured");}try {Class<?> cls = null;cls = context.getClassLoader().loadClass(clsName);mFactory = (SystemUIFactory) cls.newInstance();mFactory.init(context);} catch (Throwable t) {Log.w(TAG, "Error creating SystemUIFactory component: " + clsName, t);throw new RuntimeException(t);}}

frameworks/base/packages/SystemUI/src/com/android/systemui/Dependency.java

    @Inject Lazy<FragmentService> mFragmentService;protected void start() {mProviders.put(FragmentService.class, mFragmentService::get);}

frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java

FragmentHostManager.get(mPhoneStatusBarWindow)

frameworks/base/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java

    public static FragmentHostManager get(View view) {try {return Dependency.get(FragmentService.class).getFragmentHostManager(view);} catch (ClassCastException e) {// TODO: Some auto handling here?throw e;}}

frameworks/base/packages/SystemUI/src/com/android/systemui/fragments/FragmentService.java

    public FragmentHostManager getFragmentHostManager(View view) {View root = view.getRootView();FragmentHostState state = mHosts.get(root);if (state == null) {state = new FragmentHostState(root);mHosts.put(root, state);}return state.getFragmentHostManager();}

参考

SystemUI源码分析之PhoneStatusBar初始化布局简单分析
Android SystemUI 状态栏网络图标显示分析(Android 11)
SystemUI之状态图标控制
Android 8.0 SystemUI(三):一说顶部 StatusBar
Android 8.0 SystemUI(四):二说顶部 StatusBar
Dagger 基础知识
在 Android 应用中使用 Dagger

http://www.xdnf.cn/news/796339.html

相关文章:

  • 环境对象以及回调函数
  • java swing 自定义标题栏,缩放窗口,阴影窗口
  • Android Matrix详解
  • 继电器模块详解
  • LED显示屏的秘密:揭秘模拟信号与模拟电路
  • java开发环境sdk_JAVA开发环境配置
  • 冠达管理:成交量突然放大意味着什么?
  • 框计算
  • ASP入门教程 1小时ASP入门,非常简单
  • Photoshop7.0 简体中文迷你版
  • 程序员国内外最受好评的接私活6大网站,有技术就不怕赚不到钱!
  • route.exe add mask
  • Editplus下载、安装并最佳配色方案(强烈推荐)
  • 解决office稿纸加载项,打开word老弹出窗口的问题
  • 力扣打卡2021.1.16 打砖块
  • java当单据变化触发,UAP开发(NC63)遇到的错误记录
  • 小程序开发外包费用一般是多少?
  • 越狱设备如何安装“AFC2”补丁?
  • 我的世界1.7.2服务器直连,我的世界1.7.2
  • Flex+Tree快速定位树结点
  • go学习之路
  • 白山搜索引擎优化收费_在网络推广中,SEO排名优化是成本最低的方式
  • QGIS编译过程记录
  • 丝路英雄单人辅助更新记录
  • 远程桌面控制软件Teamviewer免费版安装
  • 用Python分析了5万条相亲网站数据,看相亲男女画像
  • 社工裤
  • java中文简体和繁体互转
  • Visio 2003 Professional 安装序列号
  • 同性恋网站Grindr上市:市值超60亿美元 昆仑万维曾是股东