diff options
author | Keith Mok <kmok@cyngn.com> | 2016-02-04 11:10:22 -0800 |
---|---|---|
committer | alk3pInjection <webmaster@raspii.tech> | 2022-05-07 00:20:58 +0800 |
commit | dd48abd8680d5ef4dc9cef3573ef971a3f13adf1 (patch) | |
tree | 73e50624ef1ae0f22a3efa767ef8e9f0a30e3112 | |
parent | 83b70eeb358ccbc567148e6a67590c081916b565 (diff) |
SystemUI: Add Caffeine QS tile
Author: Keith Mok <kmok@cyngn.com>
Date: Thu Feb 4 11:10:22 2016 -0800
SystemUI: Add caffeine qs tile
Change-Id: I5d4aa97ae63fc0bcc40f0fa7d9305efbba091029
Author: chillger <alexander.loskutov@gmail.com>
Date: Fri May 22 13:16:00 2020 +0200
SystemUI: Long press Caffeine for infinite duration
Change-Id: Ic49539dcda6d7d6b1dab362eb8ec168d2ec65b07
Change-Id: I0b9a498285930cc397b7c4d20ddec3f447e6d332
5 files changed, 313 insertions, 3 deletions
diff --git a/packages/SystemUI/res/drawable/ic_qs_caffeine.xml b/packages/SystemUI/res/drawable/ic_qs_caffeine.xml new file mode 100644 index 000000000000..2c3ba974a7e1 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_qs_caffeine.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (c) 2015 The CyanogenMod Project + Copyright (c) 2017 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="48dp" + android:height="48dp" + android:viewportWidth="24" + android:viewportHeight="24"> + + <path + android:fillColor="#FFFFFFFF" + android:pathData="M2,21H20V19H2M20,8H18V5H20M20,3H4V13A4,4 0 0,0 8,17H14A4,4 0 0,0 18,13V10H20A2,2 0 0,0 22,8V5C22,3.89 21.1,3 20,3Z" /> +</vector> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index cc33cde8527b..114ab1e06aef 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -82,7 +82,7 @@ <!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" --> <string name="quick_settings_tiles_stock" translatable="false"> - internet,bt,flashlight,dnd,alarm,airplane,controls,wallet,rotation,battery,cast,screenrecord,mictoggle,cameratoggle,location,hotspot,inversion,saver,dark,work,night,reverse,reduce_brightness + internet,bt,flashlight,dnd,alarm,airplane,controls,wallet,rotation,battery,cast,screenrecord,mictoggle,cameratoggle,location,hotspot,inversion,saver,dark,work,night,reverse,reduce_brightness,caffeine </string> <!-- The tiles to display in QuickSettings --> diff --git a/packages/SystemUI/res/values/ice_strings.xml b/packages/SystemUI/res/values/ice_strings.xml new file mode 100644 index 000000000000..e933983103cd --- /dev/null +++ b/packages/SystemUI/res/values/ice_strings.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2008 The Android Open Source Project + Copyright (C) 2022 Project ICE + + 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. +--> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- Custom QS tiles --> + <!-- Caffeine QS tile --> + <string name="quick_settings_caffeine_label">Caffeine</string> + <string name="accessibility_quick_settings_caffeine_off">Caffeine off.</string> + <string name="accessibility_quick_settings_caffeine_on">Caffeine on.</string> +</resources> diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java index 842fd6c62d06..89d71ac6a28d 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java @@ -29,6 +29,7 @@ import com.android.systemui.qs.tiles.AirplaneModeTile; import com.android.systemui.qs.tiles.AlarmTile; import com.android.systemui.qs.tiles.BatterySaverTile; import com.android.systemui.qs.tiles.BluetoothTile; +import com.android.systemui.qs.tiles.CaffeineTile; import com.android.systemui.qs.tiles.CameraToggleTile; import com.android.systemui.qs.tiles.CastTile; import com.android.systemui.qs.tiles.CellularTile; @@ -90,6 +91,7 @@ public class QSFactoryImpl implements QSFactory { private final Provider<DeviceControlsTile> mDeviceControlsTileProvider; private final Provider<AlarmTile> mAlarmTileProvider; private final Provider<QuickAccessWalletTile> mQuickAccessWalletTileProvider; + private final Provider<CaffeineTile> mCaffeineTileProvider; private final Lazy<QSHost> mQsHostLazy; private final Provider<CustomTile.Builder> mCustomTileBuilderProvider; @@ -124,7 +126,8 @@ public class QSFactoryImpl implements QSFactory { Provider<MicrophoneToggleTile> microphoneToggleTileProvider, Provider<DeviceControlsTile> deviceControlsTileProvider, Provider<AlarmTile> alarmTileProvider, - Provider<QuickAccessWalletTile> quickAccessWalletTileProvider) { + Provider<QuickAccessWalletTile> quickAccessWalletTileProvider, + Provider<CaffeineTile> caffeineTileProvider) { mQsHostLazy = qsHostLazy; mCustomTileBuilderProvider = customTileBuilderProvider; @@ -155,6 +158,7 @@ public class QSFactoryImpl implements QSFactory { mDeviceControlsTileProvider = deviceControlsTileProvider; mAlarmTileProvider = alarmTileProvider; mQuickAccessWalletTileProvider = quickAccessWalletTileProvider; + mCaffeineTileProvider = caffeineTileProvider; } public QSTile createTile(String tileSpec) { @@ -167,8 +171,8 @@ public class QSFactoryImpl implements QSFactory { } private QSTileImpl createTileInternal(String tileSpec) { - // Stock tiles. switch (tileSpec) { + // Stock tiles. case "wifi": return mWifiTileProvider.get(); case "internet": @@ -221,6 +225,9 @@ public class QSFactoryImpl implements QSFactory { return mAlarmTileProvider.get(); case "wallet": return mQuickAccessWalletTileProvider.get(); + // Additional tiles. + case "caffeine": + return mCaffeineTileProvider.get(); } // Custom tiles diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CaffeineTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CaffeineTile.java new file mode 100644 index 000000000000..340de5648a1b --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CaffeineTile.java @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2016 The CyanogenMod Project + * Copyright (c) 2017 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 android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.CountDownTimer; +import android.os.Handler; +import android.os.Looper; +import android.os.PowerManager; +import android.os.SystemClock; +import android.service.quicksettings.Tile; +import android.view.View; + +import androidx.annotation.Nullable; + +import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.systemui.R; +import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.plugins.ActivityStarter; +import com.android.systemui.plugins.FalsingManager; +import com.android.systemui.plugins.qs.QSTile.BooleanState; +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.qs.QSHost; +import com.android.systemui.qs.logging.QSLogger; +import com.android.systemui.qs.tileimpl.QSTileImpl; + +import javax.inject.Inject; + +/** Quick settings tile: Caffeine **/ +public class CaffeineTile extends QSTileImpl<BooleanState> { + + private final Icon mIcon = ResourceIcon.get(R.drawable.ic_qs_caffeine); + + private final PowerManager.WakeLock mWakeLock; + private int mSecondsRemaining; + private int mDuration; + private static int[] DURATIONS = new int[] { + 5 * 60, // 5 min + 10 * 60, // 10 min + 30 * 60, // 30 min + -1, // infinity + }; + private static final int INFINITE_DURATION_INDEX = DURATIONS.length - 1; + private CountDownTimer mCountdownTimer = null; + public long mLastClickTime = -1; + private final Receiver mReceiver = new Receiver(); + + @Inject + public CaffeineTile( + QSHost host, + @Background Looper backgroundLooper, + @Main Handler mainHandler, + FalsingManager falsingManager, + MetricsLogger metricsLogger, + StatusBarStateController statusBarStateController, + ActivityStarter activityStarter, + QSLogger qsLogger + ) { + super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger, + statusBarStateController, activityStarter, qsLogger); + mWakeLock = mContext.getSystemService(PowerManager.class).newWakeLock( + PowerManager.FULL_WAKE_LOCK, "CaffeineTile"); + mReceiver.init(); + } + + @Override + public BooleanState newTileState() { + return new BooleanState(); + } + + @Override + protected void handleDestroy() { + super.handleDestroy(); + stopCountDown(); + mReceiver.destroy(); + if (mWakeLock.isHeld()) { + mWakeLock.release(); + } + } + + @Override + public void handleSetListening(boolean listening) { + } + + @Override + protected void handleClick(@Nullable View view) { + // If last user clicks < 5 seconds + // we cycle different duration + // otherwise toggle on/off + if (mWakeLock.isHeld() && (mLastClickTime != -1) && + (SystemClock.elapsedRealtime() - mLastClickTime < 5000)) { + // cycle duration + mDuration++; + if (mDuration >= DURATIONS.length) { + // all durations cycled, turn if off + mDuration = -1; + stopCountDown(); + if (mWakeLock.isHeld()) { + mWakeLock.release(); + } + } else { + // change duration + startCountDown(DURATIONS[mDuration]); + if (!mWakeLock.isHeld()) { + mWakeLock.acquire(); + } + } + } else { + // toggle + if (mWakeLock.isHeld()) { + mWakeLock.release(); + stopCountDown(); + } else { + mWakeLock.acquire(); + mDuration = 0; + startCountDown(DURATIONS[mDuration]); + } + } + mLastClickTime = SystemClock.elapsedRealtime(); + refreshState(); + } + + @Override + protected void handleLongClick(@Nullable View view) { + if (mWakeLock.isHeld()) { + if (mDuration == INFINITE_DURATION_INDEX) { + return; + } + } else { + mWakeLock.acquire(); + } + mDuration = INFINITE_DURATION_INDEX; + startCountDown(DURATIONS[INFINITE_DURATION_INDEX]); + refreshState(); + } + + @Override + public Intent getLongClickIntent() { + return null; + } + + @Override + public CharSequence getTileLabel() { + return mContext.getString(R.string.quick_settings_caffeine_label); + } + + @Override + public int getMetricsCategory() { + return MetricsEvent.ICE; + } + + private void startCountDown(long duration) { + stopCountDown(); + mSecondsRemaining = (int)duration; + if (duration == -1) { + // infinity timing, no need to start timer + return; + } + mCountdownTimer = new CountDownTimer(duration * 1000, 1000) { + @Override + public void onTick(long millisUntilFinished) { + mSecondsRemaining = (int) (millisUntilFinished / 1000); + refreshState(); + } + + @Override + public void onFinish() { + if (mWakeLock.isHeld()) + mWakeLock.release(); + refreshState(); + } + + }.start(); + } + + private void stopCountDown() { + if (mCountdownTimer != null) { + mCountdownTimer.cancel(); + mCountdownTimer = null; + } + } + + private String formatValueWithRemainingTime() { + if (mSecondsRemaining == -1) { + return "\u221E"; // infinity + } + return String.format("%02d:%02d", + mSecondsRemaining / 60 % 60, mSecondsRemaining % 60); + } + + @Override + protected void handleUpdateState(BooleanState state, Object arg) { + state.value = mWakeLock.isHeld(); + state.icon = mIcon; + state.label = mContext.getString(R.string.quick_settings_caffeine_label); + if (state.value) { + state.secondaryLabel = formatValueWithRemainingTime(); + state.contentDescription = mContext.getString( + R.string.accessibility_quick_settings_caffeine_on); + state.state = Tile.STATE_ACTIVE; + } else { + state.secondaryLabel = null; + state.contentDescription = mContext.getString( + R.string.accessibility_quick_settings_caffeine_off); + state.state = Tile.STATE_INACTIVE; + } + } + + private final class Receiver extends BroadcastReceiver { + public void init() { + // Register for Intent broadcasts for... + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_SCREEN_OFF); + mContext.registerReceiver(this, filter, null, mHandler); + } + + public void destroy() { + mContext.unregisterReceiver(this); + } + + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (Intent.ACTION_SCREEN_OFF.equals(action)) { + // disable caffeine if user force off (power button) + stopCountDown(); + if (mWakeLock.isHeld()) + mWakeLock.release(); + refreshState(); + } + } + } +} |