忽如一夜春风来,千树万树梨花开
时光如白驹过隙,寥寥草草,今年的冬天又要到来了,怀念火炉打边的日子——

概述

这里的文章主要是介绍关于我在开发和debug一些Android系统框架代码中遇到的问题,有不妥之处大家一起讨论。
开发环境:Android O、P 、Q。
开发工具:AndroidStudio、codeblock。

SystemUI 相关。

keyguard

  1. 关于判断是否锁屏的方法isKeyguardLocked当设置密码锁屏时才会返回true。
@Override
   public boolean isKeyguardLocked() {
       return keyguardOn();
   }
  1. 关于锁屏界面显示应用或三方窗口需要添加FLAG_SHOW_WHEN_LOCKED标签。
   /** Window flag: special flag to let windows be shown when the screen
	* is locked. This will let application windows take precedence over
	* key guard or any other lock screens. Can be used with
	* {@link #FLAG_KEEP_SCREEN_ON} to turn screen on and display windows
	* directly before showing the key guard window.  Can be used with
	* {@link #FLAG_DISMISS_KEYGUARD} to automatically fully dismisss
	* non-secure keyguards.  This flag only applies to the top-most
	* full-screen window.
	* @deprecated Use {@link android.R.attr#showWhenLocked} or
	* {@link android.app.Activity#setShowWhenLocked(boolean)} instead to prevent an
	* unintentional double life-cycle event.
	*/
	@Deprecated
	public static final int FLAG_SHOW_WHEN_LOCKED = 0x00080000;
  1. keyguard上控制导航栏三个按钮Recent、HOME、back。
    Android O 上是默认不显示 Recent键
// SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
void adjustStatusBarLocked() {
        if (mStatusBarManager == null) {
            mStatusBarManager = (StatusBarManager)
                    mContext.getSystemService(Context.STATUS_BAR_SERVICE);
        }
        if (mStatusBarManager == null) {
            Log.w(TAG, "Could not get status bar manager");
        } else {
            // Disable aspects of the system/status/navigation bars that must not be re-enabled by
            // windows that appear on top, ever
            int flags = StatusBarManager.DISABLE_NONE;
            if (mShowing) {
                // Permanently disable components not available when keyguard is enabled
                // (like recents). Temporary enable/disable (e.g. the "back" button) are
                // done in KeyguardHostView.
                flags |= StatusBarManager.DISABLE_RECENT;//默认屏蔽Recent键。
                boolean isDisableSearch = false;
                // if (mLockScreenMediatorExt != null) {
                   // isDisableSearch = mLockScreenMediatorExt.disableSearch(mContext);
                // }
                /// M: [ALPS00604438] Disable search view for alarm boot
                if (PowerOffAlarmManager.isAlarmBoot() || isDisableSearch) {
                    flags |= StatusBarManager.DISABLE_SEARCH;
                }
            }
            if (isShowingAndNotOccluded()) {
                flags |= StatusBarManager.DISABLE_HOME;
            }
            mStatusBarManager.disable(flags);
        }
    }

Android P 上是默认打开
// SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java

 private void adjustStatusBarLocked() {
        adjustStatusBarLocked(false /* forceHideHomeRecentsButtons */);
    }

    private void adjustStatusBarLocked(boolean forceHideHomeRecentsButtons) {
       		... ...
            int flags = StatusBarManager.DISABLE_NONE;
            /// M: [ALPS00604438] Disable search view for alarm boot
            if (mShowing && PowerOffAlarmManager.isAlarmBoot()) {
                flags |= StatusBarManager.DISABLE_SEARCH;
            }
            if (forceHideHomeRecentsButtons || isShowingAndNotOccluded()) {
                flags |= StatusBarManager.DISABLE_HOME | StatusBarManager.DISABLE_RECENT;
            }
            mStatusBarManager.disable(flags);
        }
    }

Android Q 上与P基本相同,但没有disable_search.

private void adjustStatusBarLocked() {
1907         adjustStatusBarLocked(false /* forceHideHomeRecentsButtons */);
1908     }
1909 
1910     private void adjustStatusBarLocked(boolean forceHideHomeRecentsButtons) {
1911         if (mStatusBarManager == null) {
1912             mStatusBarManager = (StatusBarManager)
1913                     mContext.getSystemService(Context.STATUS_BAR_SERVICE);
1914         }
1915         if (mStatusBarManager == null) {
1916             Log.w(TAG, "Could not get status bar manager");
1917         } else {
1918             // Disable aspects of the system/status/navigation bars that must not be re-enabled by
1919             // windows that appear on top, ever
1920             int flags = StatusBarManager.DISABLE_NONE;
1921             if (forceHideHomeRecentsButtons || isShowingAndNotOccluded()) {
1922                 flags |= StatusBarManager.DISABLE_HOME | StatusBarManager.DISABLE_RECENT;
1923             }
1931             mStatusBarManager.disable(flags);
1932         }
1933     }

状态栏和导航栏颜色的 Tint

系统的systemui的颜色排除我们自己设定颜色外,系统是在窗口计算的过程中回去更新systemuiflag,主要在 PhoneWindowManager这个类中的 updateSystemUiVisibilityLw(…) 这其中还有flag的计算。

WindowManagerService

  1. 当你的窗口使用了toast这种东西,窗口生命周期会被toast延长,在窗口计算的过程中 windowstate 会在toast消失后消失。

  2. 窗口的flag public static final int FLAG_SLIPPERY = 0x20000000; 是允许move事件传递给隔壁老王窗口。

// frameworks/native/services/inputflinger/InputDispatcher.cpp
int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
        const MotionEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime,
        bool* outConflictingPointerActions) {
    enum InjectionPermission {
        INJECTION_PERMISSION_UNKNOWN,
        INJECTION_PERMISSION_GRANTED,
        INJECTION_PERMISSION_DENIED
    };
    ...
    ...
    // Check whether touches should slip outside of the current foreground window.
        if (maskedAction == AMOTION_EVENT_ACTION_MOVE//一定是move事件。
                && entry->pointerCount == 1
                && mTempTouchState.isSlippery()) {//判断符合条件
                //得到坐标值
            int32_t x = int32_t(entry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X));
            int32_t y = int32_t(entry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y));
			//分别找到原配和小三
            sp<InputWindowHandle> oldTouchedWindowHandle =
                    mTempTouchState.getFirstForegroundWindowHandle();
            sp<InputWindowHandle> newTouchedWindowHandle =
                    findTouchedWindowAtLocked(displayId, x, y);
            if (oldTouchedWindowHandle != newTouchedWindowHandle
                    && newTouchedWindowHandle != NULL) {
#if DEBUG_FOCUS
                ALOGD("Touch is slipping out of window %s into window %s.",
                        oldTouchedWindowHandle->getName().c_str(),
                        newTouchedWindowHandle->getName().c_str());
#endif
                // Make a slippery exit from the old window.休了原配
                mTempTouchState.addOrUpdateWindow(oldTouchedWindowHandle,
                        InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT, BitSet32(0));

                // Make a slippery entrance into the new window.//小三进门考核
                if (newTouchedWindowHandle->getInfo()->supportsSplitTouch()) {
                    isSplit = true;
                }

                int32_t targetFlags = InputTarget::FLAG_FOREGROUND
                        | InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER;
                if (isSplit) {
                    targetFlags |= InputTarget::FLAG_SPLIT;
                }
                if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) {
                    targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
                }

                BitSet32 pointerIds;
                if (isSplit) {
                    pointerIds.markBit(entry->pointerProperties[0].id);
                }
                //小三进门
                mTempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds);
            }
        }
        ....

  1. 窗口的flag FLAG_NOT_TOUCHABLE、FLAG_NOT_FOCUSABLE、FLAG_NOT_TOUCH_MODAL 为什么not_touchable的窗口不接收事件,因为底层根本就不发给他。
sp<InputWindowHandle> InputDispatcher::findTouchedWindowAtLocked(int32_t displayId,
        int32_t x, int32_t y) {
    // Traverse windows from front to back to find touched window.
    size_t numWindows = mWindowHandles.size();
    for (size_t i = 0; i < numWindows; i++) {//遍历window集合
        sp<InputWindowHandle> windowHandle = mWindowHandles.itemAt(i);
        const InputWindowInfo* windowInfo = windowHandle->getInfo();
        if (windowInfo->displayId == displayId) {
            int32_t flags = windowInfo->layoutParamsFlags;
            if (windowInfo->visible) {//不可见不参与
                if (!(flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) {//没有nottouchable属性
                //如果是isTouchModal不管落没落在窗口上都给窗口,否则必须落在窗口上,不然就给下一层窗口。
                    bool isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE
                            | InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0;
                    if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) {
                        // Found window.
                        return windowHandle;
                    }
                }
            }
        }
    }
    return NULL;
}
  1. 自由控制窗口可点击区域

结合not_focusable和not_touch_modal我们可以自由定制窗口某个区域可点击,其他区域传下去。
英文可自己翻译

//home/dongchunyang/code_dcy/android_source/Q_r/frameworks/base/core/java/android/view/ViewTreeObserver.java
 /**
         * Option for {@link #setTouchableInsets(int)}: the entire window frame
         * can be touched.
         */
        public static final int TOUCHABLE_INSETS_FRAME = 0;

        /**
         * Option for {@link #setTouchableInsets(int)}: the area inside of
         * the content insets can be touched.
         */
        public static final int TOUCHABLE_INSETS_CONTENT = 1;

        /**
         * Option for {@link #setTouchableInsets(int)}: the area inside of
         * the visible insets can be touched.
         */
        public static final int TOUCHABLE_INSETS_VISIBLE = 2;

        /**
         * Option for {@link #setTouchableInsets(int)}: the area inside of
         * the provided touchable region in {@link #touchableRegion} can be touched.
         */
        @UnsupportedAppUsage
        public static final int TOUCHABLE_INSETS_REGION = 3;
        /**
         * Set which parts of the window can be touched: either
         * {@link #TOUCHABLE_INSETS_FRAME}, {@link #TOUCHABLE_INSETS_CONTENT},
         * {@link #TOUCHABLE_INSETS_VISIBLE}, or {@link #TOUCHABLE_INSETS_REGION}.
         */
        @UnsupportedAppUsage
        public void setTouchableInsets(int val) {
            mTouchableInsets = val;
        }

上面第3条中有这么个判断
if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) {

//这个windowinfo 就是我们的window,而这个touchableRegion就是我们在java层给window设定好的信息。
bool InputWindowInfo::touchableRegionContainsPoint(int32_t x, int32_t y) const {
    return touchableRegion.contains(x,y);
}

看一下栗子

OnComputeInternalInsetsListener 是当视图树发生改变时调用的。

private final OnComputeInternalInsetsListener mOnComputeInternalInsetsListener = info -> {
        // When the nav bar is in 2-button or 3-button mode, or when IME is visible in fully
        // gestural mode, the entire nav bar should be touchable.
        if (!isGesturalMode(mNavBarMode) || mImeVisible) {
            info.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_FRAME);//触摸区域是整个窗口
            return;
        }

        info.setTouchableInsets(InternalInsetsInfo.TOUCHABLE_INSETS_REGION);//触摸区域取决于全局变量touchableRegion
        ButtonDispatcher imeSwitchButton = getImeSwitchButton();
        if (imeSwitchButton.getVisibility() == VISIBLE) {
            // If the IME is not up, but the ime switch button is visible, then make sure that
            // button is touchable
            int[] loc = new int[2];
            View buttonView = imeSwitchButton.getCurrentView();
            buttonView.getLocationInWindow(loc);
            info.touchableRegion.set(loc[0], loc[1], loc[0] + buttonView.getWidth(),
                    loc[1] + buttonView.getHeight());//修改区域。
            return;
        }
        info.touchableRegion.setEmpty();//置空,全不可点
    };

通过 adb 控制应用全屏和状态栏导航栏

settings put global policy_control  immersive.status=-com.android.calendar

‘-’ 是黑名单,不加该符号是白名单。

查看Android 系统环境变量

Android 里有这样几个方法

  1. System.getenv(“SECOND_STORAGE_TYPE”) // java环境里
  2. getenv(“ANDROID_ROOT”) // native 环境里

这些信息可以通过 adb shell 进入手机环境进行查看与修改

 1. adb shell
 2. export
 会输出
 ANDROID_ROOT
 SECOND_STORAGE_TYPE
 ....  .....
3. echo $ANDROID_ROOT //查看
4.export ANDROID_ROOT=xxxxxx //修改

删除文本

引用文本

H2O is是液体。

210 运算结果是 1024.

插入链接与图片

链接: link.

图片: Alt

带尺寸的图片: Alt

居中的图片: Alt

居中并且带尺寸的图片: Alt

当然,我们为了让用户更加便捷,我们增加了图片拖拽功能。

如何插入一段漂亮的代码片

博客设置页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 代码片.

// An highlighted block
var foo = 'bar';

生成一个适合你的列表

  • 项目
    • 项目
      • 项目
  1. 项目1
  2. 项目2
  3. 项目3
  • 计划任务
  • 完成任务

创建一个表格

一个简单的表格是这么创建的:

项目Value
电脑$1600
手机$12
导管$1

设定内容居中、居左、居右

使用:---------:居中
使用:----------居左
使用----------:居右

第一列第二列第三列
第一列文本居中第二列文本居右第三列文本居左

SmartyPants

SmartyPants将ASCII标点字符转换为“智能”印刷标点HTML实体。例如:

TYPEASCIIHTML
Single backticks'Isn't this fun?'‘Isn’t this fun?’
Quotes"Isn't this fun?"“Isn’t this fun?”
Dashes-- is en-dash, --- is em-dash– is en-dash, — is em-dash

创建一个自定义列表

Markdown
Text-to- HTML conversion tool
Authors
John
Luke

如何创建一个注脚

一个具有注脚的文本。1

注释也是必不可少的

Markdown将文本转换为 HTML

KaTeX数学公式

您可以使用渲染LaTeX数学表达式 KaTeX:

Gamma公式展示 Γ ( n ) = ( n − 1 ) ! ∀ n ∈ N \Gamma(n) = (n-1)!\quad\forall n\in\mathbb N Γ(n)=(n1)!nN 是通过欧拉积分

Γ ( z ) = ∫ 0 ∞ t z − 1 e − t d t   . \Gamma(z) = \int_0^\infty t^{z-1}e^{-t}dt\,. Γ(z)=0tz1etdt.

你可以找到更多关于的信息 LaTeX 数学表达式here.

新的甘特图功能,丰富你的文章

Mon 06 Mon 13 Mon 20 已完成 进行中 计划一 计划二 现有任务 Adding GANTT diagram functionality to mermaid
  • 关于 甘特图 语法,参考 这儿,

UML 图表

可以使用UML图表进行渲染。 Mermaid. 例如下面产生的一个序列图::

张三 李四 王五 你好!李四, 最近怎么样? 你最近怎么样,王五? 我很好,谢谢! 我很好,谢谢! 李四想了很长时间, 文字太长了 不适合放在一行. 打量着王五... 很好... 王五, 你怎么样? 张三 李四 王五

这将产生一个流程图。:

链接
长方形
圆角长方形
菱形
  • 关于 Mermaid 语法,参考 这儿,

FLowchart流程图

我们依旧会支持flowchart的流程图:

Created with Raphaël 2.2.0 开始 我的操作 确认? 结束 yes no
  • 关于 Flowchart流程图 语法,参考 这儿.

导出与导入

导出

如果你想尝试使用此编辑器, 你可以在此篇文章任意编辑。当你完成了一篇文章的写作, 在上方工具栏找到 文章导出 ,生成一个.md文件或者.html文件进行本地保存。

导入

如果你想加载一篇你写过的.md文件,在上方工具栏可以选择导入功能进行对应扩展名的文件导入,
继续你的创作。


  1. 注脚的解释 ↩︎

posted on 2019-08-26 15:27  寒风凛凛  阅读(513)  评论(0编辑  收藏  举报