Android14 MTK SystemUI中设置时间为12小时制时,状态栏和锁屏界面显示AM/PM

本文详细介绍了在MTK设备的Android系统中,如何在状态栏和锁屏界面自定义显示AM/PM的时间,涉及XML布局文件、Java代码和系统组件的配置,包括Clock.java中的样式设置和Dimens.xml中的字体大小调整。
摘要由CSDN通过智能技术生成

一、状态栏显示AM/PM

先查看状态栏的布局文件:\vendor\mediatek\proprietary\packages\apps\SystemUI\res\layout\status_bar.xml
找到和时间相关的布局:

<com.android.systemui.statusbar.policy.Clock
                        android:id="@+id/clock"
                        android:layout_width="wrap_content"
                        android:layout_height="match_parent"
                        android:textAppearance="@style/TextAppearance.StatusBar.Clock"
                        android:singleLine="true"
                        android:paddingStart="@dimen/status_bar_left_clock_starting_padding"
                        android:paddingEnd="@dimen/status_bar_left_clock_end_padding"
                        android:gravity="center_vertical|start"
                    />
                   

再根据此自定义的java文件:
\vendor\mediatek\proprietary\packages\apps\SystemUI\src\com\android\systemui\statusbar\policy\Clock.java
其是继承TextView的自定义时钟布局文件,其中定义了三个跟AM/PM显示有关的静态全局变量:

	private static final int AM_PM_STYLE_NORMAL  = 0;// AM/PM大小与前面时间的大小一致。
    private static final int AM_PM_STYLE_SMALL   = 1;// AM/PM大小是前面时间的大小的0.7倍,具体是在getSmallTime()方法中实现。
    private static final int AM_PM_STYLE_GONE    = 2;// AM/PM不可见

状态栏显示AM/PM的修改方法如下(在其构造函数中进行修改):

public Clock(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        mCommandQueue = Dependency.get(CommandQueue.class);
        TypedArray a = context.getTheme().obtainStyledAttributes(
                attrs,
                R.styleable.Clock,
                0, 0);
        try {
            mSystemUIFactoryBase = OpSystemUICustomizationFactoryBase.getOpFactory(context);
            mStatusBarExt = mSystemUIFactoryBase.makeSystemUIStatusBar(context);
            /*mAmPmStyle = mStatusBarExt.getClockAmPmStyle(a.getInt(R.styleable.Clock_amPmStyle,
                    AM_PM_STYLE_GONE));*/
            mAmPmStyle = mStatusBarExt.getClockAmPmStyle(a.getInt(R.styleable.Clock_amPmStyle,
                    AM_PM_STYLE_SMALL));// 设置为AM/PM相对时间0.7倍显示,具体为啥为0.7倍参考方法getSmallTime
            mNonAdaptedColor = getCurrentTextColor();
        } finally {
            a.recycle();
        }
        mBroadcastDispatcher = Dependency.get(BroadcastDispatcher.class);
        mUserTracker = Dependency.get(UserTracker.class);
    }

查看Clock.java下的getSmallTime()方法:

private final CharSequence getSmallTime() {
        Context context = getContext();
        boolean is24 = DateFormat.is24HourFormat(context, mCurrentUserId);
        if (mDateTimePatternGenerator == null) {
            // Despite its name, getInstance creates a cloned instance, so reuse the generator to
            // avoid unnecessary churn.
            mDateTimePatternGenerator = DateTimePatternGenerator.getInstance(
                context.getResources().getConfiguration().locale);
        }

        final char MAGIC1 = '\uEF00';
        final char MAGIC2 = '\uEF01';

        final String formatSkeleton = mShowSeconds
                ? is24 ? "Hms" : "hms"
                : is24 ? "Hm" : "hm";
        String format = mDateTimePatternGenerator.getBestPattern(formatSkeleton);
        if (!format.equals(mContentDescriptionFormatString)) {
            mContentDescriptionFormatString = format;
            mContentDescriptionFormat = new SimpleDateFormat(format);
            /*
             * Search for an unquoted "a" in the format string, so we can
             * add marker characters around it to let us find it again after
             * formatting and change its size.
             */
            if (mAmPmStyle != AM_PM_STYLE_NORMAL) {
                int a = -1;
                boolean quoted = false;
                for (int i = 0; i < format.length(); i++) {
                    char c = format.charAt(i);

                    if (c == '\'') {
                        quoted = !quoted;
                    }
                    if (!quoted && c == 'a') {
                        a = i;
                        break;
                    }
                }

                if (a >= 0) {
                    // Move a back so any whitespace before AM/PM is also in the alternate size.
                    final int b = a;
                    while (a > 0 && Character.isWhitespace(format.charAt(a-1))) {
                        a--;
                    }
                    format = format.substring(0, a) + MAGIC1 + format.substring(a, b)
                        + "a" + MAGIC2 + format.substring(b + 1);
                }
            }
            mClockFormat = new SimpleDateFormat(format);
        }
        String result = mClockFormat.format(mCalendar.getTime());

        if (mAmPmStyle != AM_PM_STYLE_NORMAL) {
            int magic1 = result.indexOf(MAGIC1);
            int magic2 = result.indexOf(MAGIC2);
            if (magic1 >= 0 && magic2 > magic1) {
                SpannableStringBuilder formatted = new SpannableStringBuilder(result);
                if (mAmPmStyle == AM_PM_STYLE_GONE) {
                    formatted.delete(magic1, magic2+1);
                } else {
                    if (mAmPmStyle == AM_PM_STYLE_SMALL) { 
                        CharacterStyle style = new RelativeSizeSpan(0.7f);// 此RelativeSizeSpan就是实现文字相对大小的样式,故为上述提到的AM/PM为时间大小的0.7倍
                        formatted.setSpan(style, magic1, magic2,
                                          Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
                    }
                    formatted.delete(magic2, magic2 + 1);
                    formatted.delete(magic1, magic1 + 1);
                }
                return formatted;
            }
        }

        return result;

    }

二、锁屏界面显示AM/PM

锁屏界面对应的布局文件:\SystemUI\res-keyguard\layout\keyguard_clock_switch.xml

# 锁屏界面显示通知时的时间布局
<com.android.keyguard.KeyguardClockFrame
        android:id="@+id/lockscreen_clock_view"
        android:layout_width="match_parent"
        android:layout_height="@dimen/small_clock_height"
        android:layout_alignParentStart="true"
        android:layout_alignParentTop="true"
        android:clipChildren="false"
        android:paddingStart="@dimen/clock_padding_start"
        android:visibility="invisible" />
# 锁屏界面不显示通知的时间布局
<com.android.keyguard.KeyguardClockFrame
        android:id="@+id/lockscreen_clock_view_large"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clipChildren="false"
        android:visibility="gone" />

根据id查询具体布局使用到的位置:选中id对应的参数,Ctrl + N
查询到文件:SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
在如下加载布局的方法使用:

@Override
    protected void onFinishInflate() {
        super.onFinishInflate();

        mSmallClockFrame = findViewById(R.id.lockscreen_clock_view);
        mLargeClockFrame = findViewById(R.id.lockscreen_clock_view_large);
        mStatusArea = findViewById(R.id.keyguard_status_area);

        onConfigChanged();
    }

再根据对mSmallClockFrame、mLargeClockFrame两个参数在上述Java文件的查询和跟踪,发现在下面方法中设置了时间的布局:

void setClock(ClockController clock, int statusBarState) {
        mClock = clock;

        // Disconnect from existing plugin.
        mSmallClockFrame.removeAllViews();
        mLargeClockFrame.removeAllViews();

        if (clock == null) {
            if (mLogBuffer != null) {
                mLogBuffer.log(TAG, LogLevel.ERROR, "No clock being shown");
            }
            return;
        }

        // Attach small and big clock views to hierarchy.
        if (mLogBuffer != null) {
            mLogBuffer.log(TAG, LogLevel.INFO, "Attached new clock views to switch");
        }
        mSmallClockFrame.addView(clock.getSmallClock().getView());
        mLargeClockFrame.addView(clock.getLargeClock().getView());
        updateClockTargetRegions();
        updateStatusArea(/* animate= */false);
    }

在通过查找ClockController,发现其为定义在下面文件中的一个接口:
\vendor\mediatek\proprietary\packages\apps\SystemUI\plugin\src\com\android\systemui\plugins\ClockProviderPlugin.kt

/** Interface for controlling an active clock */
interface ClockController {
    /** A small version of the clock, appropriate for smaller viewports */
    val smallClock: ClockFaceController

    /** A large version of the clock, appropriate when a bigger viewport is available */
    val largeClock: ClockFaceController

    /** Determines the way the hosting app should behave when rendering either clock face */
    val config: ClockConfig

    /** Events that clocks may need to respond to */
    val events: ClockEvents

    /** Initializes various rendering parameters. If never called, provides reasonable defaults. */
    fun initialize(
        resources: Resources,
        dozeFraction: Float,
        foldFraction: Float,
    )

    /** Optional method for dumping debug information */
    fun dump(pw: PrintWriter)
}

在溯源ClockFaceController,发现其定义在如下文件中了一个内部类:
\vendor\mediatek\proprietary\packages\apps\SystemUI\customization\src\com\android\systemui\shared\clocks\DefaultClockController.kt
查看此文件,其中的init方法如下:

init {
        val parent = FrameLayout(ctx)
        smallClock =
            DefaultClockFaceController(
                layoutInflater.inflate(R.layout.clock_default_small, parent, false)
                    as AnimatableClockView,
                settings?.seedColor
            )
        largeClock =
            LargeClockFaceController(
                layoutInflater.inflate(R.layout.clock_default_large, parent, false)
                    as AnimatableClockView,
                settings?.seedColor
            )
        clocks = listOf(smallClock.view, largeClock.view)

        events = DefaultClockEvents()
        events.onLocaleChanged(Locale.getDefault())
    }

其中显示全部通知时的锁屏时间布局为:\vendor\mediatek\proprietary\packages\apps\SystemUI\customization\res\layout\clock_default_small.xml
不显示通知的锁屏时间布局为:
\vendor\mediatek\proprietary\packages\apps\SystemUI\customization\res\layout\clock_default_large.xml
下面查看clock_default_small.xml:

<com.android.systemui.shared.clocks.AnimatableClockView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="start"
    android:gravity="start"
    android:textSize="@dimen/small_clock_text_size"
    android:fontFamily="@*android:string/config_clockFontFamily"
    android:elegantTextHeight="false"
    android:ellipsize="none"
    android:singleLine="true"
    android:fontFeatureSettings="pnum"
    chargeAnimationDelay="350"
    dozeWeight="200"
    lockScreenWeight="400" />

其也是一个自定义布局:\vendor\mediatek\proprietary\packages\apps\SystemUI\customization\src\com\android\systemui\shared\clocks\AnimatableClockView.kt
锁屏界面显示AM/PM具体的修改如下:

fun refreshTime() {
        time.timeInMillis = timeOverrideInMillis ?: System.currentTimeMillis()
        contentDescription = DateFormat.format(descFormat, time)
        //add code 
        var formattedText = DateFormat.format(format, time)
        val formattedTextStr = trimAllWhitespace(formattedText.toString())
        if (format!!.contains("a")) {
            var formatted = SpannableStringBuilder(formattedTextStr)
            val ampm = DateFormat.format("a", time).toString()
            val style = RelativeSizeSpan(0.5f)  //参考Clock.java中设置字体风格
            val ampmStart = formattedTextStr!!.indexOf(ampm, 0)
            val ampmLength = ampm.length
            formatted.setSpan(style, ampmStart, ampmStart + ampmLength, Spannable.SPAN_EXCLUSIVE_INCLUSIVE)
            formattedText = formatted
        }
        //end code
        logBuffer?.log(TAG, DEBUG,
                { str1 = formattedText?.toString() },
                { "refreshTime: new formattedText=$str1" }
        )
        // Setting text actually triggers a layout pass (because the text view is set to
        // wrap_content width and TextView always relayouts for this). Avoid needless
        // relayout if the text didn't actually change.
        if (!TextUtils.equals(text, formattedText)) {
            text = formattedText
            logBuffer?.log(TAG, DEBUG,
                    { str1 = formattedText?.toString() },
                    { "refreshTime: done setting new time text to: $str1" }
            )
            // Because the TextLayout may mutate under the hood as a result of the new text, we
            // notify the TextAnimator that it may have changed and request a measure/layout. A
            // crash will occur on the next invocation of setTextStyle if the layout is mutated
            // without being notified TextInterpolator being notified.
            if (layout != null) {
                textAnimator?.updateLayout(layout)
                logBuffer?.log(TAG, DEBUG, "refreshTime: done updating textAnimator layout")
            }
            requestLayout()
            logBuffer?.log(TAG, DEBUG, "refreshTime: after requestLayout")
        }
    }
    // add function 去除解析的时间格式字符串中间的空白字符串
    fun trimAllWhitespace(str: String?): String? {
        if (str != null) {
            val len = str.length
            if (len > 0) {
                val dest = CharArray(len)
                var destPos = 0
                for (i in 0 until len) {
                    val c = str[i]
                    if (!java.lang.Character.isWhitespace(c)) {
                        dest[destPos++] = c
                    }
                }
                return String(dest, 0, destPos)
            }
        }
        return str
    }

做到此处,还是不能解决,需要修改下面参数,还是在AnimatableClockView.kt中,修改下面参数:

@VisibleForTesting
    var isAnimationEnabled: Boolean = false//true

取消动画,不然字体还是会显示为与时间同样大小(因为需求是需要设置锁屏界面的AM/PM比时间小)。
如果显示尺寸过大,则需要修改下面参数:
\vendor\mediatek\proprietary\packages\apps\SystemUI\customization\res\values\dimens.xml

<resources>
    <!-- Clock maximum font size (dp is intentional, to prevent any further scaling) -->
    <dimen name="large_clock_text_size">150dp</dimen>
    <dimen name="small_clock_text_size">60dp</dimen>

    <!-- Default line spacing multiplier between hours and minutes of the keyguard clock -->
    <item name="keyguard_clock_line_spacing_scale" type="dimen" format="float">.7</item>
    <!-- Burmese line spacing multiplier between hours and minutes of the keyguard clock -->
    <item name="keyguard_clock_line_spacing_scale_burmese" type="dimen" format="float">1</item>
</resources>

对上面的large_clock_text_size和small_clock_text_size进行修改。
最后编译运行解决。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值