Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6cf08783 authored by Steve Kondik's avatar Steve Kondik Committed by Luca Stefani
Browse files

SystemUI: Add LiveDisplay tile



Author: Steve Kondik <steve@cyngn.com>
Date:   Sun Nov 5 16:37:52 2017 +0100

    SystemUI: LiveDisplay tile

    Change-Id: I53d492e5cb9998268104d5750705aa5ed55d9658
    Signed-off-by: default avatarJoey Rizzoli <joey@lineageos.org>

Author: Unpublished <unpublished@gmx.net>
Date:   Fri Dec 29 23:00:01 2017 +0100

    livedisplay: Allow tile creation before boot completed phase [2/2]

    Change-Id: Ibef44d4e07da9baf296796515288c9d42aba8608

Author: Michael Bestas <mkbestas@lineageos.org>
Date:   Thu Feb 1 16:39:16 2018 +0000
Edit:   Refactor for Oreo

Change-Id: Ibef44d4e07da9baf296796515288c9d42aba8608

Author: Bruno Martins <bgcngm@gmail.com>
Date:   Thu Feb 1 17:01:43 2018 +0000

    LiveDisplayTile: Avoid NPE during boot up phase

     * During boot, with LineageHW not yet initialized there is no way to
       check the current LiveDisplay mode. In such cases, fallback to AUTO.

    Change-Id: Ifc004c86dfd68f73b8a362a1c833cbc3e7397811

Author: Han Wang <416810799@qq.com>
Date:   Tue Jun 4 18:03:59 2019 +0200

    LiveDisplayTile: Report unavailable on HWC2

    Change-Id: Ic10381e25046a2338bc6bda36ecbb5d5cefc1ab8

Change-Id: I188df4f401e506db355ad8bb4b5307a8d0c3c35b
parent 95a3a583
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
    <!-- QS Tiles -->
    <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
    <uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
    <uses-permission android:name="lineageos.permission.MANAGE_LIVEDISPLAY" />
    <uses-permission android:name="lineageos.permission.WRITE_SETTINGS" />
    <uses-permission android:name="lineageos.permission.WRITE_SECURE_SETTINGS" />

+27 −0
Original line number Diff line number Diff line
@@ -280,4 +280,31 @@ public interface QSTile {
            return state;
        }
    }

    @ProvidesInterface(version = LiveDisplayState.VERSION)
    public static class LiveDisplayState extends State {
        public static final int VERSION = 1;
        public int mode;

        @Override
        public boolean copyTo(State other) {
            final LiveDisplayState o = (LiveDisplayState) other;
            final boolean changed = mode != o.mode;
            return super.copyTo(other) || changed;
        }

        @Override
        protected StringBuilder toStringBuilder() {
            final StringBuilder rt = super.toStringBuilder();
            rt.insert(rt.length() - 1, ",mode=" + mode);
            return rt;
        }

        @Override
        public State copy() {
            LiveDisplayState state = new LiveDisplayState();
            copyTo(state);
            return state;
        }
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -117,7 +117,7 @@

    <!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" -->
    <string name="quick_settings_tiles_stock" translatable="false">
        wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,nfc,location,hotspot,inversion,saver,dark,work,cast,night,adb_network,ambient_display,caffeine,heads_up,sync,usb_tether,volume_panel
        wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,nfc,location,hotspot,inversion,saver,dark,work,cast,night,adb_network,ambient_display,caffeine,heads_up,livedisplay,sync,usb_tether,volume_panel
    </string>

    <!-- The tiles to display in QuickSettings -->
+6 −0
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import com.android.systemui.qs.tiles.FlashlightTile;
import com.android.systemui.qs.tiles.HeadsUpTile;
import com.android.systemui.qs.tiles.HotspotTile;
import com.android.systemui.qs.tiles.IntentTile;
import com.android.systemui.qs.tiles.LiveDisplayTile;
import com.android.systemui.qs.tiles.LocationTile;
import com.android.systemui.qs.tiles.NfcTile;
import com.android.systemui.qs.tiles.NightDisplayTile;
@@ -87,6 +88,7 @@ public class QSFactoryImpl implements QSFactory {
    private final Provider<AmbientDisplayTile> mAmbientDisplayTileProvider;
    private final Provider<CaffeineTile> mCaffeineTileProvider;
    private final Provider<HeadsUpTile> mHeadsUpTileProvider;
    private final Provider<LiveDisplayTile> mLiveDisplayTileProvider;
    private final Provider<SyncTile> mSyncTileProvider;
    private final Provider<UsbTetherTile> mUsbTetherTileProvider;
    private final Provider<VolumeTile> mVolumeTileProvider;
@@ -117,6 +119,7 @@ public class QSFactoryImpl implements QSFactory {
            Provider<AmbientDisplayTile> ambientDisplayTileProvider,
            Provider<CaffeineTile> caffeineTileProvider,
            Provider<HeadsUpTile> headsUpTileProvider,
            Provider<LiveDisplayTile> liveDisplayTileProvider,
            Provider<SyncTile> syncTileProvider,
            Provider<UsbTetherTile> usbTetherTileProvider,
            Provider<VolumeTile> volumeTileProvider) {
@@ -143,6 +146,7 @@ public class QSFactoryImpl implements QSFactory {
        mAmbientDisplayTileProvider = ambientDisplayTileProvider;
        mCaffeineTileProvider = caffeineTileProvider;
        mHeadsUpTileProvider = headsUpTileProvider;
        mLiveDisplayTileProvider = liveDisplayTileProvider;
        mSyncTileProvider = syncTileProvider;
        mUsbTetherTileProvider = usbTetherTileProvider;
        mVolumeTileProvider = volumeTileProvider;
@@ -208,6 +212,8 @@ public class QSFactoryImpl implements QSFactory {
                return mCaffeineTileProvider.get();
            case "heads_up":
                return mHeadsUpTileProvider.get();
            case "livedisplay":
                return mLiveDisplayTileProvider.get();
            case "sync":
                return mSyncTileProvider.get();
            case "usb_tether":
+230 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 The CyanogenMod Project
 * Copyright (C) 2018-2019 The LineageOS Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.qs.tiles;

import static lineageos.hardware.LiveDisplayManager.FEATURE_MANAGED_OUTDOOR_MODE;
import static lineageos.hardware.LiveDisplayManager.MODE_AUTO;
import static lineageos.hardware.LiveDisplayManager.MODE_DAY;
import static lineageos.hardware.LiveDisplayManager.MODE_OFF;
import static lineageos.hardware.LiveDisplayManager.MODE_OUTDOOR;

import android.content.Intent;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.database.ContentObserver;
import android.hardware.display.ColorDisplayManager;
import android.os.Handler;
import android.os.UserHandle;
import android.provider.Settings;
import android.service.quicksettings.Tile;

import com.android.internal.util.ArrayUtils;
import com.android.systemui.plugins.qs.QSTile.LiveDisplayState;
import com.android.systemui.qs.QSHost;
import com.android.systemui.qs.tileimpl.QSTileImpl;

import org.lineageos.internal.logging.LineageMetricsLogger;
import org.lineageos.platform.internal.R;

import lineageos.hardware.LiveDisplayManager;
import lineageos.providers.LineageSettings;

import javax.inject.Inject;

/** Quick settings tile: LiveDisplay mode switcher **/
public class LiveDisplayTile extends QSTileImpl<LiveDisplayState> {

    private static final Intent LIVEDISPLAY_SETTINGS =
            new Intent("org.lineageos.lineageparts.LIVEDISPLAY_SETTINGS");

    private final LiveDisplayObserver mObserver;
    private String mTitle;
    private String[] mEntries;
    private String[] mDescriptionEntries;
    private String[] mAnnouncementEntries;
    private String[] mValues;
    private final int[] mEntryIconRes;

    private boolean mListening;

    private int mDayTemperature;

    private final boolean mOutdoorModeAvailable;

    private final LiveDisplayManager mLiveDisplay;

    private static final int OFF_TEMPERATURE = 6500;

    @Inject
    public LiveDisplayTile(QSHost host) {
        super(host);

        Resources res = mContext.getResources();
        TypedArray typedArray = res.obtainTypedArray(R.array.live_display_drawables);
        mEntryIconRes = new int[typedArray.length()];
        for (int i = 0; i < mEntryIconRes.length; i++) {
            mEntryIconRes[i] = typedArray.getResourceId(i, 0);
        }
        typedArray.recycle();

        updateEntries();

        mLiveDisplay = LiveDisplayManager.getInstance(mContext);
        if (mLiveDisplay.getConfig() != null) {
            mOutdoorModeAvailable = mLiveDisplay.getConfig().hasFeature(MODE_OUTDOOR) &&
                    !mLiveDisplay.getConfig().hasFeature(FEATURE_MANAGED_OUTDOOR_MODE);
            mDayTemperature = mLiveDisplay.getDayColorTemperature();
        } else {
            mOutdoorModeAvailable = false;
            mDayTemperature = -1;
        }

        mObserver = new LiveDisplayObserver(mHandler);
        mObserver.startObserving();
    }

    private void updateEntries() {
        Resources res = mContext.getResources();
        mTitle = res.getString(R.string.live_display_title);
        mEntries = res.getStringArray(R.array.live_display_entries);
        mDescriptionEntries = res.getStringArray(R.array.live_display_description);
        mAnnouncementEntries = res.getStringArray(R.array.live_display_announcement);
        mValues = res.getStringArray(R.array.live_display_values);
    }

    @Override
    public boolean isAvailable() {
        return !ColorDisplayManager.isNightDisplayAvailable(mContext);
    }

    @Override
    public LiveDisplayState newTileState() {
        return new LiveDisplayState();
    }

    @Override
    public void handleSetListening(boolean listening) {
        if (mListening == listening)
            return;
        mListening = listening;
        if (listening) {
            mObserver.startObserving();
        } else {
            mObserver.endObserving();
        }
    }

    @Override
    protected void handleClick() {
        changeToNextMode();
    }

    @Override
    protected void handleUpdateState(LiveDisplayState state, Object arg) {
        updateEntries();
        state.mode = arg == null ? getCurrentModeIndex() : (Integer) arg;
        state.label = mTitle;
        state.secondaryLabel = mEntries[state.mode];
        state.icon = ResourceIcon.get(mEntryIconRes[state.mode]);
        state.contentDescription = mDescriptionEntries[state.mode];
        state.state = mLiveDisplay.getMode() != MODE_OFF ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
    }

    @Override
    public int getMetricsCategory() {
        return LineageMetricsLogger.TILE_LIVE_DISPLAY;
    }

    @Override
    public CharSequence getTileLabel() {
        return mContext.getString(R.string.live_display_title);
    }

    @Override
    public Intent getLongClickIntent() {
        return LIVEDISPLAY_SETTINGS;
    }

    @Override
    protected String composeChangeAnnouncement() {
        return mAnnouncementEntries[getCurrentModeIndex()];
    }

    private int getCurrentModeIndex() {
        String currentLiveDisplayMode = null;
        try {
            currentLiveDisplayMode = String.valueOf(mLiveDisplay.getMode());
        } catch (NullPointerException e) {
            currentLiveDisplayMode = String.valueOf(MODE_AUTO);
        } finally {
            return ArrayUtils.indexOf(mValues, currentLiveDisplayMode);
        }
    }

    private void changeToNextMode() {
        int next = getCurrentModeIndex() + 1;

        if (next >= mValues.length) {
            next = 0;
        }

        int nextMode = 0;

        while (true) {
            nextMode = Integer.valueOf(mValues[next]);
            // Skip outdoor mode if it's unsupported, and skip the day setting
            // if it's the same as the off setting
            if ((!mOutdoorModeAvailable && nextMode == MODE_OUTDOOR) ||
                    (mDayTemperature == OFF_TEMPERATURE && nextMode == MODE_DAY)) {
                next++;
                if (next >= mValues.length) {
                    next = 0;
                }
            } else {
                break;
            }
        }

        mLiveDisplay.setMode(nextMode);
    }

    private class LiveDisplayObserver extends ContentObserver {
        public LiveDisplayObserver(Handler handler) {
            super(handler);
        }

        @Override
        public void onChange(boolean selfChange) {
            mDayTemperature = mLiveDisplay.getDayColorTemperature();
            refreshState(getCurrentModeIndex());
        }

        public void startObserving() {
            mContext.getContentResolver().registerContentObserver(
                    LineageSettings.System.getUriFor(LineageSettings.System.DISPLAY_TEMPERATURE_MODE),
                    false, this, UserHandle.USER_ALL);
            mContext.getContentResolver().registerContentObserver(
                    LineageSettings.System.getUriFor(LineageSettings.System.DISPLAY_TEMPERATURE_DAY),
                    false, this, UserHandle.USER_ALL);
        }

        public void endObserving() {
            mContext.getContentResolver().unregisterContentObserver(this);
        }
    }
}