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

Commit 31fbc981 authored by Steve Kondik's avatar Steve Kondik Committed by Michael Bestas
Browse files

SystemUI: LiveDisplay tile



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

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

[mikeioannina]: Refactor for Oreo

Change-Id: Ibef44d4e07da9baf296796515288c9d42aba8608
parent 19243ce2
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -29,6 +29,9 @@
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />

    <!-- LiveDisplay tile -->
    <uses-permission android:name="lineageos.permission.MANAGE_LIVEDISPLAY" />

    <!-- SystemUI Tuner -->
    <application>
        <activity-alias
+27 −0
Original line number Diff line number Diff line
@@ -291,4 +291,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
@@ -112,7 +112,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,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,work,cast,night,adb_network,ambient_display,caffeine,heads_up,livedisplay,sync,usb_tether,volume_panel
    </string>

    <!-- The tiles to display in QuickSettings -->
+2 −0
Original line number Diff line number Diff line
@@ -38,6 +38,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;
@@ -82,6 +83,7 @@ public class QSFactoryImpl implements QSFactory {
        else if (tileSpec.equals("ambient_display")) return new AmbientDisplayTile(mHost);
        else if (tileSpec.equals("caffeine")) return new CaffeineTile(mHost);
        else if (tileSpec.equals("heads_up")) return new HeadsUpTile(mHost);
        else if (tileSpec.equals("livedisplay")) return new LiveDisplayTile(mHost);
        else if (tileSpec.equals("sync")) return new SyncTile(mHost);
        else if (tileSpec.equals("usb_tether")) return new UsbTetherTile(mHost);
        else if (tileSpec.equals("volume_panel")) return new VolumeTile(mHost);
+209 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 The CyanogenMod Project
 * Copyright (C) 2018 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_DAY;
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.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;

/** 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[] 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;

    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();
        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 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 = mEntries[state.mode];
        state.icon = ResourceIcon.get(mEntryIconRes[state.mode]);
        state.contentDescription = mDescriptionEntries[state.mode];
        state.state = Tile.STATE_ACTIVE;
    }

    @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() {
        return ArrayUtils.indexOf(mValues, String.valueOf(mLiveDisplay.getMode()));
    }

    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);
        }
    }
}