summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Mok <kmok@cyngn.com>2016-02-04 11:10:22 -0800
committeralk3pInjection <webmaster@raspii.tech>2022-02-17 10:03:45 +0800
commit6bfa9d5a1cb0c8a19c93a83f5935821bf6670c25 (patch)
tree6cf6012eedcfb20c26baaddfae855e6032125aad
parenta0067ad2366702513781cd488be66c3ab0a9760f (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
-rw-r--r--packages/SystemUI/res/drawable/ic_qs_caffeine.xml27
-rw-r--r--packages/SystemUI/res/values/config.xml2
-rw-r--r--packages/SystemUI/res/values/ice_strings.xml23
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/CaffeineTile.java253
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 4a6efddd87c3..9d5fd53118c4 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -107,7 +107,7 @@
<!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" -->
<string name="quick_settings_tiles_stock" translatable="false">
- internet,wifi,cell,bt,flashlight,dnd,alarm,airplane,controls,wallet,rotation,battery,cast,screenrecord,mictoggle,cameratoggle,location,hotspot,inversion,saver,dark,work,night,reverse,reduce_brightness
+ internet,wifi,cell,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();
+ }
+ }
+ }
+}