From d8dde7bc023cc921e7ba2a7f92f232478a2649fd Mon Sep 17 00:00:00 2001
From: Luca Stefani <luca.stefani.ge1@gmail.com>
Date: Thu, 30 Dec 2021 22:33:02 +0100
Subject: [PATCH] SystemUI: Add support for timeout-reboot

By exploiting the already existing implementation used in Keyguard
to "lock" the device after a specific timeout has been reached
we add our own custom action that starts right when the display
is in the "locked" state and stops when we enter the "exit"
phase of keyguard ( aka unlocked )

Also cancel reboot timeout when unlocking without a secure lock screen.
Add a debugging statement to make this easier to troubleshoot (needs
`adb shell setprop persist.log.tag.Keyguard DEBUG`).

Issue: calyxos#1683
Co-authored-by: Tommy Webb <tommy@calyxinstitute.org>
Change-Id: I23170e5ec3ae296a4aa1d9c1793d61c8399c4d54
---
 data/etc/com.android.systemui.xml             |  1 +
 packages/SystemUI/AndroidManifest.xml         |  2 +
 .../keyguard/KeyguardViewMediator.java        | 60 +++++++++++++++++++
 3 files changed, 63 insertions(+)

diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml
index 43683ffad432..d031108d77f7 100644
--- a/data/etc/com.android.systemui.xml
+++ b/data/etc/com.android.systemui.xml
@@ -87,5 +87,6 @@
         <permission name="android.permission.SET_UNRESTRICTED_KEEP_CLEAR_AREAS" />
         <permission name="android.permission.READ_SEARCH_INDEXABLES" />
         <permission name="android.permission.ACCESS_AMBIENT_CONTEXT_EVENT"/>
+        <permission name="android.permission.REBOOT" />
     </privapp-permissions>
 </permissions>
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index a58e9db61515..96e935f47acf 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -349,6 +349,8 @@
 
     <uses-permission android:name="android.permission.MONITOR_KEYBOARD_BACKLIGHT" />
 
+    <uses-permission android:name="android.permission.REBOOT" />
+
     <protected-broadcast android:name="com.android.settingslib.action.REGISTER_SLICE_RECEIVER" />
     <protected-broadcast android:name="com.android.settingslib.action.UNREGISTER_SLICE_RECEIVER" />
     <protected-broadcast android:name="com.android.settings.flashlight.action.FLASHLIGHT_CHANGED" />
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index e9f494013e30..9abccb05083a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -171,6 +171,8 @@ import com.android.systemui.util.time.SystemClock;
 import com.android.systemui.wallpapers.data.repository.WallpaperRepository;
 import com.android.wm.shell.keyguard.KeyguardTransitions;
 
+import com.libremobileos.providers.LMOSettings;
+
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -238,6 +240,8 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
         "com.android.internal.policy.impl.PhoneWindowManager.DELAYED_KEYGUARD";
     private static final String DELAYED_LOCK_PROFILE_ACTION =
             "com.android.internal.policy.impl.PhoneWindowManager.DELAYED_LOCK";
+    private static final String DELAYED_REBOOT_ACTION =
+        "com.android.internal.policy.impl.PhoneWindowManager.DELAYED_REBOOT";
 
     private static final String SYSTEMUI_PERMISSION = "com.android.systemui.permission.SELF";
 
@@ -287,6 +291,12 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
      */
     public static final int KEYGUARD_LOCK_AFTER_DELAY_DEFAULT = 5000;
 
+    /**
+     * How long to wait after the screen turns off due to timeout before
+     * rebooting the device.
+     */
+    private static final int KEYGUARD_REBOOT_AFTER_DELAY_DEFAULT = 0;
+
     /**
      * How long we'll wait for the {@link ViewMediatorCallback#keyguardDoneDrawing()}
      * callback before unblocking a call to {@link #setKeyguardEnabled(boolean)}
@@ -408,6 +418,11 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
      */
     private int mDelayedProfileShowingSequence;
 
+    /**
+     * Simiar to {@link #mDelayedProfileShowingSequence}, but it is for automatic reboot.
+     */
+    private int mDelayedRebootSequence;
+
     private final DismissCallbackRegistry mDismissCallbackRegistry;
 
     // the properties of the keyguard
@@ -823,6 +838,9 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
         public void keyguardGone() {
             Trace.beginSection("KeyguardViewMediator.mViewMediatorCallback#keyguardGone");
             if (DEBUG) Log.d(TAG, "keyguardGone");
+            synchronized (this) {
+                cancelDoRebootLaterLocked();
+            }
             mKeyguardViewControllerLazy.get().setKeyguardGoingAwayState(false);
             mKeyguardDisplayManager.hide();
             mUpdateMonitor.startBiometricWatchdog();
@@ -1480,6 +1498,7 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
         final IntentFilter delayedActionFilter = new IntentFilter();
         delayedActionFilter.addAction(DELAYED_KEYGUARD_ACTION);
         delayedActionFilter.addAction(DELAYED_LOCK_PROFILE_ACTION);
+        delayedActionFilter.addAction(DELAYED_REBOOT_ACTION);
         delayedActionFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
         mContext.registerReceiver(mDelayedLockBroadcastReceiver, delayedActionFilter,
                 SYSTEMUI_PERMISSION, null /* scheduler */,
@@ -1800,6 +1819,17 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
         return timeout;
     }
 
+    private long getRebootTimeout() {
+        final ContentResolver cr = mContext.getContentResolver();
+
+        // From Global Settings
+        final long timeout = Settings.Global.getLong(cr,
+                LMOSettings.Global.DEVICE_REBOOT_TIMEOUT,
+                KEYGUARD_REBOOT_AFTER_DELAY_DEFAULT);
+
+        return timeout;
+    }
+
     private void doKeyguardLaterLocked() {
         long timeout = getLockTimeout(KeyguardUpdateMonitor.getCurrentUser());
         if (timeout == 0) {
@@ -1859,6 +1889,19 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
         }
     }
 
+    private void doRebootLaterLocked(long timeout) {
+        // Reboot in the future
+        long when = mSystemClock.elapsedRealtime() + timeout;
+        Intent intent = new Intent(DELAYED_REBOOT_ACTION);
+        intent.putExtra("seq", mDelayedRebootSequence);
+        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+        PendingIntent sender = PendingIntent.getBroadcast(mContext,
+                0, intent, PendingIntent.FLAG_CANCEL_CURRENT |  PendingIntent.FLAG_IMMUTABLE);
+        mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME_WAKEUP, when, sender);
+        if (DEBUG) Log.d(TAG, "setting alarm to reboot device, seq = "
+                         + mDelayedRebootSequence);
+    }
+
     private void cancelDoKeyguardLaterLocked() {
         mDelayedShowingSequence++;
     }
@@ -1867,6 +1910,12 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
         mDelayedProfileShowingSequence++;
     }
 
+    private void cancelDoRebootLaterLocked() {
+        if (DEBUG) Log.d(TAG, "cancelling alarm to reboot device, seq = "
+                         + mDelayedRebootSequence);
+        mDelayedRebootSequence++;
+    }
+
     /**
      * It will let us know when the device is waking up.
      */
@@ -2256,6 +2305,10 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
 
         if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen");
         showLocked(options);
+        final long timeout = getRebootTimeout();
+        if (timeout > 0) {
+            doRebootLaterLocked(timeout);
+        }
     }
 
     private void lockProfile(int userId) {
@@ -2444,6 +2497,13 @@ public class KeyguardViewMediator implements CoreStartable, Dumpable,
                         }
                     }
                 }
+            } else if (DELAYED_REBOOT_ACTION.equals(intent.getAction())) {
+                final int sequence = intent.getIntExtra("seq", 0);
+                synchronized (KeyguardViewMediator.this) {
+                    if (mDelayedRebootSequence == sequence) {
+                        mContext.getSystemService(PowerManager.class).reboot("RebootTimeout");
+                    }
+                }
             }
         }
     };
-- 
GitLab