如何讓Android設(shè)備實(shí)現(xiàn)息屏顯示

前言

什么是息屏顯示?
息屏顯示就是手機(jī)在息屏狀態(tài)下,屏幕上會(huì)顯示當(dāng)前時(shí)間、日期信息,無需點(diǎn)亮手機(jī)屏幕即可查看。息屏顯示的原理主要是利用了OLED屏幕像素點(diǎn)自發(fā)光的特性,僅顯示時(shí)間的像素點(diǎn)發(fā)光,功耗相比LCD屏幕要低很多。


三星的息屏顯示

Android原生的主動(dòng)顯示

玩過Android源碼的同學(xué)應(yīng)該知道,在Settings里有一個(gè)開關(guān)項(xiàng):

設(shè)置 - 顯示 - 主動(dòng)顯示

這就是設(shè)置 - 顯示下的主動(dòng)顯示選項(xiàng),勾選了這個(gè)選項(xiàng)后,當(dāng)設(shè)備在息屏?xí)r接到一條新通知會(huì)顯示這樣的效果:


主動(dòng)顯示預(yù)覽

是不是發(fā)現(xiàn)與息屏顯示的效果一模一樣,但觸發(fā)條件卻不一樣,需要息屏后有通知才會(huì)顯示出來,并且過一段時(shí)間又會(huì)自動(dòng)消失回歸黑屏,那么怎樣才能做到像三星那樣的息屏后就能一直都顯示呢?

源碼分析

既然知道主動(dòng)顯示開關(guān)是放在設(shè)置里面的,那不妨先從Settings的源碼看起,首先找到主動(dòng)顯示對(duì)應(yīng)的Preference,

<Preference
        android:key="ambient_display"
        android:title="@string/ambient_display_screen_title"
        android:fragment="com.android.settings.display.AmbientDisplaySettings" />

然后發(fā)現(xiàn)在AmbientDisplaySettings里注冊(cè)了一些controller,

    private static List<AbstractPreferenceController> buildPreferenceControllers(Context context,
            Lifecycle lifecycle, AmbientDisplayConfiguration config,
            MetricsFeatureProvider metricsFeatureProvider,
            AmbientDisplayAlwaysOnPreferenceController.OnPreferenceChangedCallback aodCallback) {
        final List<AbstractPreferenceController> controllers = new ArrayList<>();
        controllers.add(new AmbientDisplayNotificationsPreferenceController(context, config,
                metricsFeatureProvider));
        controllers.add(new AmbientDisplayAlwaysOnPreferenceController(context, config,
                aodCallback));
        controllers.add(new DoubleTapScreenPreferenceController(context, lifecycle, config,
                MY_USER_ID, KEY_AMBIENT_DISPLAY_DOUBLE_TAP));
        controllers.add(new PickupGesturePreferenceController(context, lifecycle, config,
                MY_USER_ID, KEY_AMBIENT_DISPLAY_PICK_UP));
        return controllers;
    }

先關(guān)注里面的兩個(gè):AmbientDisplayNotificationsPreferenceController和AmbientDisplayAlwaysOnPreferenceController,看名字大概能知道,第一個(gè)與通知有關(guān),應(yīng)該是上文提到的息屏后來通知才顯示;而第二個(gè)就是我們要找的“始終開啟”。

AmbientDisplayAlwaysOnPreferenceController :

public class AmbientDisplayAlwaysOnPreferenceController extends
        AbstractPreferenceController implements PreferenceControllerMixin,
        Preference.OnPreferenceChangeListener {
    private final int ON = 1;
    private final int OFF = 0;
    ...
    // 每次進(jìn)入該P(yáng)referenceScreen都會(huì)調(diào)用一次刷新開關(guān)狀態(tài)
    @Override
    public void updateState(Preference preference) {
        ((SwitchPreference) preference).setChecked(isAlwaysOnEnabled(mConfig));
    }

    // 通過AmbientDisplayConfiguration獲得當(dāng)前enable狀態(tài)
    public static boolean isAlwaysOnEnabled(AmbientDisplayConfiguration config) {
        return config.alwaysOnEnabled(MY_USER);
    }

    // 每次點(diǎn)擊后寫入數(shù)據(jù)
    @Override
    public boolean onPreferenceChange(Preference preference, Object newValue) {
        int enabled = (boolean) newValue ? ON : OFF;
        Settings.Secure.putInt(
                mContext.getContentResolver(), Settings.Secure.DOZE_ALWAYS_ON, enabled);
        if (mCallback != null) {
            mCallback.onPreferenceChanged();
        }
        return true;
    }

    // 該P(yáng)reference是否可用
    @Override
    public boolean isAvailable() {
        return isAvailable(mConfig);
    }

    // 通過AmbientDisplayConfiguration 獲得available狀態(tài)
    public static boolean isAvailable(AmbientDisplayConfiguration config) {
        return config.alwaysOnAvailableForUser(MY_USER);
    }
    ...
}

分析AmbientDisplayAlwaysOnPreferenceController的源碼發(fā)現(xiàn),AlwaysOn的enable和available狀態(tài)都需要通過AmbientDisplayConfiguration 這個(gè)類來獲得,并且這個(gè)類位于framework中。

簡單介紹下AmbientDisplayConfiguration 中與alwaysOn有關(guān)的幾個(gè)函數(shù):

    public boolean alwaysOnEnabled(int user) {
        return boolSettingDefaultOn(Settings.Secure.DOZE_ALWAYS_ON, user) && alwaysOnAvailable()
                && !accessibilityInversionEnabled(user);
    }

    public boolean alwaysOnAvailable() {
        return (alwaysOnDisplayDebuggingEnabled() || alwaysOnDisplayAvailable())
                && ambientDisplayAvailable();
    }

    private boolean alwaysOnDisplayAvailable() {
        return mContext.getResources().getBoolean(R.bool.config_dozeAlwaysOnDisplayAvailable);
    }

    public boolean accessibilityInversionEnabled(int user) {
        return boolSettingDefaultOff(Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, user);
    }

    private boolean ambientDisplayAvailable() {
        return !TextUtils.isEmpty(ambientDisplayComponent());
    }

    public String ambientDisplayComponent() {
        return mContext.getResources().getString(R.string.config_dozeComponent);
    }

    private boolean boolSettingDefaultOn(String name, int user) {
        return boolSetting(name, user, 1);
    }

    private boolean boolSetting(String name, int user, int def) {
        return Settings.Secure.getIntForUser(mContext.getContentResolver(), name, def, user) != 0;
    }

alwaysOnAvailable為true需要同時(shí)滿足兩個(gè)條件:

  1. 處于debug模式,或者config_dozeAlwaysOnDisplayAvailable為true,這個(gè)值寫在frameworks/base/core/res/res/values/config.xml里,默認(rèn)是false;
  2. config_dozeComponent取值不為空,這個(gè)值同樣寫在上面講到的config.xml里,默認(rèn)是空著的。

alwaysOnEnabled為true需要同時(shí)滿足三個(gè)條件:

  1. DOZE_ALWAYS_ON值寫入了1,即Settings里開啟了開關(guān);
  2. alwaysOnAvailable為true;
  3. ACCESSIBILITY_DISPLAY_INVERSION_ENABLED值為0,即沒有開啟顏色反轉(zhuǎn)。

原來源碼里面默認(rèn)把AlwaysOn功能給關(guān)閉了,如果想啟用這個(gè)功能,需要修改config.xml里的兩個(gè)值或者強(qiáng)制alwaysOnAvailable返回true,修改后設(shè)置里的主動(dòng)顯示一欄就會(huì)多出一項(xiàng)“始終開啟”可以勾選,這樣一來我們的設(shè)備在息屏之后就能自動(dòng)開啟主動(dòng)顯示功能了。

以上源碼均取自Android O

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容