Android Q锁屏左右下角的圆弧实现逻辑

Android Q的锁屏左右下角各有一个90度的直角,本来也没注意,但是用着用着发现这两个view会消失。便去追踪了下这个直角的来源。
在这里插入图片描述
首先很自然的先到这个view应该跟P上水滴的ScreenDecorations,这样一个屏幕装饰器相关。在该类下查找其加载的R.layout.rounded_corners,看到有个叫CornerHandleView的,角落的view,看名字比较像,该类的onDraw方法中主要是再canvas上绘制一个path路径,path的赋值如下:

private void updatePath() {
        mPath = new Path();

        float marginPx = getMarginPx();
        float radiusPx = getInnerRadiusPx();
        float halfStrokePx = getStrokePx() / 2f;
        float angle = getAngle();
        float startAngle = 180 + ((90 - angle) / 2);
        RectF circle = new RectF(marginPx + halfStrokePx,
                marginPx + halfStrokePx,
                marginPx + 2 * radiusPx - halfStrokePx,
                marginPx + 2 * radiusPx - halfStrokePx);

        if (angle >= 90f) {
            float innerCircumferenceDp = convertPixelToDp(radiusPx * 2 * (float) Math.PI,
                    mContext);
            float arcDp = innerCircumferenceDp * getAngle() / 360f;
            // Add additional "arms" to the two ends of the arc. The length computation is
            // hand-tuned.
            float lineLengthPx = convertDpToPixel((ARC_LENGTH_DP - arcDp - MARGIN_DP) / 2,
                    mContext);

            mPath.moveTo(marginPx + halfStrokePx, marginPx + radiusPx + lineLengthPx);
            mPath.lineTo(marginPx + halfStrokePx, marginPx + radiusPx);
            mPath.arcTo(circle, startAngle, angle);
            mPath.moveTo(marginPx + radiusPx, marginPx + halfStrokePx);
            mPath.lineTo(marginPx + radiusPx + lineLengthPx, marginPx + halfStrokePx);
        } else {
            mPath.arcTo(circle, startAngle, angle);
        }
    }

mPath.arcTo是绘制一段弧线,if中显然是线绘制一条竖线,在绘制一段弧线,在绘制一条横线。显然就与效果图比较贴近了。在追踪该类下的相关读取dimen中的数值,都是跟这个直角的角度相关的。

在来看下是谁在控制这个CornerHandleView的显示/隐藏的

很直接的在ScreenDecorations中有一个

private void updateWindowVisibility(View overlay) {
        boolean visibleForCutout = shouldDrawCutout()
                && overlay.findViewById(R.id.display_cutout).getVisibility() == View.VISIBLE;
        boolean visibleForRoundedCorners = hasRoundedCorners();
        boolean visibleForHandles = overlay.findViewById(R.id.assist_hint_left).getVisibility()
                == View.VISIBLE || overlay.findViewById(R.id.assist_hint_right).getVisibility()
                == View.VISIBLE;
        overlay.setVisibility(visibleForCutout || visibleForRoundedCorners || visibleForHandles
                ? View.VISIBLE : View.GONE);
    }

设置整个layout的Visibility,打log发现者3个条件都是true,看来不是在这里。
在看setAssistHintVisible()
在这里插入图片描述
这里直接对这个CornerHandleView操作了,fade方法。

    private void fade(View view, boolean fadeIn, boolean isLeft) {
        Log.e("cyy","fade################:"+fadeIn);
        if (fadeIn) {
            view.animate().cancel();
            view.setAlpha(1f);
            view.setVisibility(View.VISIBLE);

            // A piecewise spring-like interpolation.
            // End value in one animator call must match the start value in the next, otherwise
            // there will be a discontinuity.
            AnimatorSet anim = new AnimatorSet();
            Animator first = getHandleAnimator(view, 0, 1.1f, isLeft, 750,
                    new PathInterpolator(0, 0.45f, .67f, 1f));
            Interpolator secondInterpolator = new PathInterpolator(0.33f, 0, 0.67f, 1f);
            Animator second = getHandleAnimator(view, 1.1f, 0.97f, isLeft, 400,
                    secondInterpolator);
            Animator third = getHandleAnimator(view, 0.97f, 1.02f, isLeft, 400,
                    secondInterpolator);
            Animator fourth = getHandleAnimator(view, 1.02f, 1f, isLeft, 400,
                    secondInterpolator);
            anim.play(first).before(second);
            anim.play(second).before(third);
            anim.play(third).before(fourth);
            anim.start();
        } else {
            view.animate().cancel();
            view.animate()
                    .setInterpolator(new AccelerateInterpolator(1.5f))
                    .setDuration(250)
                    .alpha(0f);
        }

    }

这个fade方法:if是做了个动画,else设置了alpha为0,就是隐藏了。
怀疑就是这里处理的,public void setAssistHintVisible(boolean visible)是public类型的,就可以被外部调用,这里添加trace查看调用路径。
在这里插入图片描述
流程转到了AssistHandleBehaviorController中,该类的内容也不多,

@Override // AssistHandleCallbacks
    public void hide() {
        clearPendingCommands();
        mHandler.post(mHideHandles);
    }

    @Override // AssistHandleCallbacks
    public void showAndGo() {
        clearPendingCommands();
        mHandler.post(mShowAndGo);
    }

    private void showAndGoInternal() {
        maybeShowHandles(/* ignoreThreshold = */ false);
        mHandler.postDelayed(mHideHandles, getShowAndGoDuration());
    }

    @Override // AssistHandleCallbacks
    public void showAndGoDelayed(long delayMs, boolean hideIfShowing) {
        clearPendingCommands();
        if (hideIfShowing) {
            mHandler.post(mHideHandles);
        }
        mHandler.postDelayed(mShowAndGo, delayMs);
    }

    @Override // AssistHandleCallbacks
    public void showAndStay() {
        clearPendingCommands();
        mHandler.post(() -> maybeShowHandles(/* ignoreThreshold = */ true));
    }

这些以show开头的方法中,前3个都是调到了showAndGoInternal(),最终调到了hide的,是隐藏CornerHandleVIew的,最后一个showAndStay

private void maybeShowHandles(boolean ignoreThreshold) {
        if (mHandlesShowing) {
            return;
        }

        if (handlesUnblocked(ignoreThreshold)) {
            ScreenDecorations screenDecorations = mScreenDecorationsSupplier.get();
            if (screenDecorations == null) {
                Log.w(TAG, "Couldn't show handles, ScreenDecorations unavailable");
            } else {
                mHandlesShowing = true;
                screenDecorations.setAssistHintVisible(true);
            }
        }
    }

是screenDecorations.setAssistHintVisible(true);即显示CornerHandleView的。
手机灭下屏,绘制锁屏,同时CornerHandleView会被绘制出来
在这里插入图片描述
复现灭屏在亮屏时,CornerHandleView不显示的情况,查看trace是断在了哪里。
追踪到是AssistHandleReminderExpBehavior.java下的一个mIsLearned的变量发生了变化。
在这里插入图片描述
mIsLearned的赋值是通过上面的updateLearningStatus来的,当mLearningCount > 设定的固定值是,mIsLearned值变化,导致后面的调用逻辑变化,而mLearningCount 是在每次成功调起google 助手时就会被+1。

@Override
    public void onAssistantGesturePerformed() {
        if (mContext == null) {
            return;
        }

        Settings.Secure.putLong(
                mContext.getContentResolver(), LEARNING_EVENT_COUNT_KEY, ++mLearningCount);
    }

同时查看google pixel机器,发现恢复出厂设置后操作10次也是锁屏上的CornerHandleView也会消失,因此得出,该现象是google的原生设计,ConnerHandleVIew就是给新用户的一个提示,告之用户在锁屏上,从最左边/右边滑动,会触发google serach,当用户成功触发该操作10次,就认为用户已经learned,就不在显示该view。

Q上还有很多新特性,有待发现。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值