Merge tag 'android-15.0.0_r32' of https://android.googlesource.com/platform/frameworks/base into HEAD

Android 15.0.0 Release 32 (BP1A.250505.005)

Change-Id: I0eebb6a89cdb74ec9daf96eb529517f6f88d154d
diff --git a/Android.bp b/Android.bp
index 529da53..d2f16e7 100644
--- a/Android.bp
+++ b/Android.bp
@@ -147,6 +147,7 @@
         ":statslog-framework-java-gen", // FrameworkStatsLog.java
         ":statslog-hwui-java-gen", // HwuiStatsLog.java
         ":audio_policy_configuration_V7_0",
+        "//packages/apps/OmniLib:omnirom-internal",
     ] + select(release_flag("RELEASE_ATTEST_MODULES"), {
         true: [
             ":android.hardware.security.keymint-V4-java-source",
@@ -287,6 +288,7 @@
         ":framework-non-updatable-sources",
         "core/java/**/*.logtags",
         ":apex-info-list",
+        "//packages/apps/OmniLib:omnirom-internal",
     ],
     aidl: {
         generate_get_transaction_name: true,
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp
index 6902d6d..7765d20 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.cpp
+++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp
@@ -60,6 +60,7 @@
 namespace {
 
 constexpr std::string_view kFrameworkPath = "/system/framework/framework-res.apk";
+constexpr std::string_view kOmniRomPath = "/system/framework/omnirom-res.apk";
 
 Status ok() {
   return Status::ok();
@@ -213,9 +214,10 @@
 idmap2::Result<Idmap2Service::TargetResourceContainerPtr> Idmap2Service::GetTargetContainer(
     const std::string& target_path) {
   const bool is_framework = target_path == kFrameworkPath;
+  const bool is_OmniRomPath = target_path == kOmniRomPath;
   bool use_cache;
   struct stat st = {};
-  if (is_framework || !::stat(target_path.c_str(), &st)) {
+  if (is_framework || is_OmniRomPath || !::stat(target_path.c_str(), &st)) {
     use_cache = true;
   } else {
     LOG(WARNING) << "failed to stat target path '" << target_path << "' for the cache";
@@ -226,7 +228,7 @@
     std::lock_guard lock(container_cache_mutex_);
     if (auto cache_it = container_cache_.find(target_path); cache_it != container_cache_.end()) {
       const auto& item = cache_it->second;
-      if (is_framework ||
+      if (is_framework || is_OmniRomPath ||
         (item.dev == st.st_dev && item.inode == st.st_ino && item.size == st.st_size
           && item.mtime.tv_sec == st.st_mtim.tv_sec && item.mtime.tv_nsec == st.st_mtim.tv_nsec)) {
         return {item.apk};
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 3d85ea6..5398f57 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -1457,7 +1457,7 @@
                         false, false);
                 for (int i = 0, n = packageIdentifiers.size(); i < n; i++) {
                     final int id = packageIdentifiers.keyAt(i);
-                    if (id == 0x01 || id == 0x7f) {
+                    if (id == 0x01 || id == 0x7f || id == 0x3f) {
                         continue;
                     }
 
diff --git a/core/java/android/app/admin/SystemUpdateInfo.java b/core/java/android/app/admin/SystemUpdateInfo.java
index 9e6c91f..e5a3825 100644
--- a/core/java/android/app/admin/SystemUpdateInfo.java
+++ b/core/java/android/app/admin/SystemUpdateInfo.java
@@ -133,7 +133,7 @@
         out.startTag(null, tag);
         out.attributeLong(null, ATTR_RECEIVED_TIME, mReceivedTime);
         out.attributeInt(null, ATTR_SECURITY_PATCH_STATE, mSecurityPatchState);
-        out.attribute(null, ATTR_ORIGINAL_BUILD , Build.FINGERPRINT);
+        out.attribute(null, ATTR_ORIGINAL_BUILD , String.valueOf(Build.TIME));
         out.endTag(null, tag);
     }
 
@@ -142,7 +142,7 @@
     public static SystemUpdateInfo readFromXml(TypedXmlPullParser parser) {
         // If an OTA has been applied (build fingerprint has changed), discard stale info.
         final String buildFingerprint = parser.getAttributeValue(null, ATTR_ORIGINAL_BUILD );
-        if (!Build.FINGERPRINT.equals(buildFingerprint)) {
+        if (!String.valueOf(Build.TIME).equals(buildFingerprint)) {
             return null;
         }
         try {
diff --git a/core/java/android/content/pm/PackagePartitions.java b/core/java/android/content/pm/PackagePartitions.java
index ff80e61..f6420bc 100644
--- a/core/java/android/content/pm/PackagePartitions.java
+++ b/core/java/android/content/pm/PackagePartitions.java
@@ -131,7 +131,7 @@
             final String partitionName = SYSTEM_PARTITIONS.get(i).getName();
             digestProperties[i] = "ro." + partitionName + ".build.fingerprint";
         }
-        digestProperties[SYSTEM_PARTITIONS.size()] = "ro.build.fingerprint"; // build fingerprint
+        digestProperties[SYSTEM_PARTITIONS.size()] = "ro.build.date.utc"; // build fingerprint
         return SystemProperties.digestOf(digestProperties);
     }
 
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index bbfae81..cbb4cbb 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -81,6 +81,7 @@
     public static final String FRAMEWORK_APK_PATH = getFrameworkApkPath();
     private static final String FRAMEWORK_APK_PATH_DEVICE = "/system/framework/framework-res.apk";
     private static final String FRAMEWORK_APK_PATH_RAVENWOOD = "ravenwood-data/framework-res.apk";
+    private static final String OMNIROM_APK_PATH = "/system/framework/omnirom-res.apk";
 
     private static final Object sSync = new Object();
 
@@ -288,6 +289,7 @@
             for (String idmapPath : systemIdmapPaths) {
                 apkAssets.add(ApkAssets.loadOverlayFromPath(idmapPath, ApkAssets.PROPERTY_SYSTEM));
             }
+            apkAssets.add(ApkAssets.loadFromPath(OMNIROM_APK_PATH, ApkAssets.PROPERTY_SYSTEM));
 
             sSystemApkAssetsSet = new ArraySet<>(apkAssets);
             sSystemApkAssets = apkAssets.toArray(new ApkAssets[0]);
diff --git a/core/java/android/hardware/display/AmbientDisplayConfiguration.java b/core/java/android/hardware/display/AmbientDisplayConfiguration.java
index 7361d4f..0f49428 100644
--- a/core/java/android/hardware/display/AmbientDisplayConfiguration.java
+++ b/core/java/android/hardware/display/AmbientDisplayConfiguration.java
@@ -31,6 +31,8 @@
 import com.android.internal.R;
 import com.android.internal.util.ArrayUtils;
 
+import org.omnirom.omnilib.utils.OmniSettings;
+
 import java.util.Map;
 
 /**
@@ -55,7 +57,8 @@
             Settings.Secure.DOZE_DOUBLE_TAP_GESTURE,
             Settings.Secure.DOZE_WAKE_LOCK_SCREEN_GESTURE,
             Settings.Secure.DOZE_WAKE_DISPLAY_GESTURE,
-            Settings.Secure.DOZE_TAP_SCREEN_GESTURE
+            Settings.Secure.DOZE_TAP_SCREEN_GESTURE,
+            OmniSettings.OMNI_DOZE_ON_CHARGE
     };
 
     /** Non-user configurable doze settings */
@@ -231,8 +234,7 @@
      */
     @TestApi
     public boolean alwaysOnEnabled(int user) {
-        return boolSetting(Settings.Secure.DOZE_ALWAYS_ON, user, mAlwaysOnByDefault ? 1 : 0)
-                && alwaysOnAvailable() && !accessibilityInversionEnabled(user);
+        return alwaysOnEnabledSetting(user) || alwaysOnChargingEnabled(user);
     }
 
     /**
@@ -343,4 +345,25 @@
     private void putDozeSetting(String name, String value, int userId) {
         Settings.Secure.putStringForUser(mContext.getContentResolver(), name, value, userId);
     }
+
+    // omni additions start
+    private boolean boolSettingSystem(String name, int user, int def) {
+        return Settings.System.getIntForUser(mContext.getContentResolver(), name, def, user) != 0;
+    }
+
+    /** @hide */
+    public boolean alwaysOnEnabledSetting(int user) {
+        boolean alwaysOnEnabled = boolSetting(Settings.Secure.DOZE_ALWAYS_ON, user, mAlwaysOnByDefault ? 1 : 0);
+        return alwaysOnEnabled && alwaysOnAvailable() && !accessibilityInversionEnabled(user);
+    }
+
+    /** @hide */
+    public boolean alwaysOnChargingEnabled(int user) {
+        final boolean dozeOnChargeEnabled = boolSettingSystem(OmniSettings.OMNI_DOZE_ON_CHARGE, user, 0);
+        if (dozeOnChargeEnabled) {
+            final boolean dozeOnChargeEnabledNow = boolSettingSystem(OmniSettings.OMNI_DOZE_ON_CHARGE_NOW, user, 0);
+            return dozeOnChargeEnabledNow && alwaysOnAvailable() && !accessibilityInversionEnabled(user);
+        }
+        return false;
+    }
 }
diff --git a/core/java/android/hardware/fingerprint/HidlFingerprintSensorConfig.java b/core/java/android/hardware/fingerprint/HidlFingerprintSensorConfig.java
index d481153..9febcab 100644
--- a/core/java/android/hardware/fingerprint/HidlFingerprintSensorConfig.java
+++ b/core/java/android/hardware/fingerprint/HidlFingerprintSensorConfig.java
@@ -17,7 +17,9 @@
 package android.hardware.fingerprint;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.Context;
+import android.content.res.TypedArray;
 import android.hardware.biometrics.BiometricAuthenticator;
 import android.hardware.biometrics.BiometricManager;
 import android.hardware.biometrics.common.CommonProps;
@@ -25,16 +27,22 @@
 import android.hardware.biometrics.fingerprint.FingerprintSensorType;
 import android.hardware.biometrics.fingerprint.SensorLocation;
 import android.hardware.biometrics.fingerprint.SensorProps;
+import android.util.Slog;
 
 import com.android.internal.R;
 import com.android.internal.util.ArrayUtils;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * Parse HIDL fingerprint sensor config and map it to SensorProps.aidl to match AIDL.
  * See core/res/res/values/config.xml config_biometric_sensors
  * @hide
  */
 public final class HidlFingerprintSensorConfig extends SensorProps {
+    private static final String TAG = "HidlFingerprintSensorConfig";
+
     private int mSensorId;
     private int mModality;
     private int mStrength;
@@ -70,6 +78,10 @@
         halControlsIllumination = false;
         sensorLocations = new SensorLocation[1];
 
+        // Non-empty workaroundLocations indicates that the sensor is SFPS.
+        final List<SensorLocation> workaroundLocations =
+                getWorkaroundSensorProps(context);
+
         final int[] udfpsProps = context.getResources().getIntArray(
                 com.android.internal.R.array.config_udfps_sensor_props);
         final boolean isUdfps = !ArrayUtils.isEmpty(udfpsProps);
@@ -78,7 +90,7 @@
                 R.bool.config_is_powerbutton_fps);
 
         if (isUdfps) {
-            sensorType = FingerprintSensorType.UNKNOWN;
+            sensorType = FingerprintSensorType.UNDER_DISPLAY_OPTICAL;
         } else if (isPowerbuttonFps) {
             sensorType = FingerprintSensorType.POWER_BUTTON;
         } else {
@@ -87,6 +99,9 @@
 
         if (isUdfps && udfpsProps.length == 3) {
             setSensorLocation(udfpsProps[0], udfpsProps[1], udfpsProps[2]);
+        } else if (!workaroundLocations.isEmpty()) {
+            sensorLocations = new SensorLocation[workaroundLocations.size()];
+            workaroundLocations.toArray(sensorLocations);
         } else {
             setSensorLocation(540 /* sensorLocationX */, 1636 /* sensorLocationY */,
                     130 /* sensorRadius */);
@@ -103,6 +118,48 @@
         sensorLocations[0].sensorRadius = sensorRadius;
     }
 
+    // TODO(b/174868353): workaround for gaps in HAL interface (remove and get directly from HAL)
+    // reads values via an overlay instead of querying the HAL
+    @NonNull
+    public static List<SensorLocation> getWorkaroundSensorProps(@NonNull Context context) {
+        final List<SensorLocation> sensorLocations = new ArrayList<>();
+
+        final TypedArray sfpsProps = context.getResources().obtainTypedArray(
+                com.android.internal.R.array.config_sfps_sensor_props);
+        for (int i = 0; i < sfpsProps.length(); i++) {
+            final int id = sfpsProps.getResourceId(i, -1);
+            if (id > 0) {
+                final SensorLocation location = parseSensorLocation(
+                        context.getResources().obtainTypedArray(id));
+                if (location != null) {
+                    sensorLocations.add(location);
+                }
+            }
+        }
+        sfpsProps.recycle();
+
+        return sensorLocations;
+    }
+
+    @Nullable
+    private static SensorLocation parseSensorLocation(@Nullable TypedArray array) {
+        if (array == null) {
+            return null;
+        }
+
+        try {
+            SensorLocation sensorLocation = new SensorLocation();
+            sensorLocation.display = array.getString(0);
+            sensorLocation.sensorLocationX = array.getInt(1, 0);
+            sensorLocation.sensorLocationY = array.getInt(2, 0);
+            sensorLocation.sensorRadius = array.getInt(3, 0);
+            return sensorLocation;
+        } catch (Exception e) {
+            Slog.w(TAG, "malformed sensor location", e);
+        }
+        return null;
+    }
+
     private byte authenticatorStrengthToPropertyStrength(
             @BiometricManager.Authenticators.Types int strength) {
         switch (strength) {
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index c41e626..9923e54 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -1995,8 +1995,7 @@
 
         // STATES2 bits that are used for Power Stats tracking
         public static final int IMPORTANT_FOR_POWER_STATS_STATES2 =
-                STATE2_VIDEO_ON_FLAG | STATE2_FLASHLIGHT_FLAG | STATE2_CAMERA_FLAG
-                | STATE2_GPS_SIGNAL_QUALITY_MASK;
+                STATE2_VIDEO_ON_FLAG | STATE2_FLASHLIGHT_FLAG | STATE2_CAMERA_FLAG;
 
         public static final int GNSS_SIGNAL_QUALITY_NONE = 2;
 
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 4cac4dee..00ebcf1 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -115,6 +115,7 @@
     @UnsupportedAppUsage
     void reboot(boolean confirm, String reason, boolean wait);
     void rebootSafeMode(boolean confirm, boolean wait);
+    void rebootCustom(boolean confirm, String reason, boolean wait);
     void shutdown(boolean confirm, String reason, boolean wait);
     void crash(String message);
     int getLastShutdownReason();
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index cd48f08..88a4496 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -864,6 +864,17 @@
     public static final String REBOOT_RECOVERY = "recovery";
 
     /**
+     * The value to pass as the 'reason' argument to reboot() to
+     * reboot into bootloader mode
+     * <p>
+     * Requires the permission
+     * {@link android.Manifest.permission#REBOOT}).
+     * </p>
+     * @hide
+     */
+    public static final String REBOOT_BOOTLOADER = "bootloader";
+
+    /**
      * The value to pass as the 'reason' argument to reboot() to reboot into
      * recovery mode for applying system updates.
      * <p>
@@ -876,6 +887,17 @@
     public static final String REBOOT_RECOVERY_UPDATE = "recovery-update";
 
     /**
+     * The value to pass as the 'reason' argument to reboot() to
+     * reboot into fastboot mode
+     * <p>
+     * Requires the permission
+     * {@link android.Manifest.permission#REBOOT}).
+     * </p>
+     * @hide
+     */
+    public static final String REBOOT_FASTBOOT = "fastboot";
+
+    /**
      * The value to pass as the 'reason' argument to reboot() when device owner requests a reboot on
      * the device.
      * @hide
@@ -1929,6 +1951,24 @@
     }
 
     /**
+     * Reboot the device with custom progress meassges.
+     * Will not return if the reboot is successful.
+     * <p>
+     * Requires the {@link android.Manifest.permission#REBOOT} permission.
+     * </p>
+     *
+     * @param reason code to pass to the kernel (e.g., "recovery") to
+     *               request special boot modes, or null.
+     * @hide
+     */
+    public void rebootCustom(String reason) {
+        try {
+            mService.rebootCustom(false, reason, true);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
      * Returns true if the device is currently in power save mode.  When in this mode,
      * applications should reduce their functionality in order to conserve battery as
      * much as possible.  You can monitor for changes to this state with
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index 2473de4..614a981 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -264,6 +264,9 @@
 
     private List<SplitPermissionInfo> mSplitPermissionInfos;
 
+    private static String[] sLocationProviderPkgNames;
+    private static String[] sLocationExtraPkgNames;
+
     /**
      * Creates a new instance.
      *
@@ -1367,6 +1370,16 @@
                 pkgNames.add(exemptedPackage);
             }
         }
+        for (String pkgName: sLocationProviderPkgNames) {
+            if (pkgName != null) {
+                pkgNames.add(pkgName);
+            }
+        }
+        for (String pkgName: sLocationExtraPkgNames) {
+            if (pkgName != null) {
+                pkgNames.add(pkgName);
+            }
+        }
         return pkgNames;
     }
 
@@ -1382,6 +1395,10 @@
             for (int i = 0; i < EXEMPTED_ROLES.length; i++) {
                 INDICATOR_EXEMPTED_PACKAGES[i] = context.getString(EXEMPTED_ROLES[i]);
             }
+            sLocationProviderPkgNames = context.getResources().getStringArray(
+                    R.array.config_locationProviderPackageNames);
+            sLocationExtraPkgNames = context.getResources().getStringArray(
+                    R.array.config_locationExtraPackageNames);
         }
     }
     /**
diff --git a/core/java/android/preference/RingtonePreference.java b/core/java/android/preference/RingtonePreference.java
index e15244a..3576ec8 100644
--- a/core/java/android/preference/RingtonePreference.java
+++ b/core/java/android/preference/RingtonePreference.java
@@ -33,6 +33,7 @@
  * <p>
  * If the user chooses the "Default" item, the saved string will be one of
  * {@link System#DEFAULT_RINGTONE_URI},
+ * {@link System#DEFAULT_RINGTONE2_URI},
  * {@link System#DEFAULT_NOTIFICATION_URI}, or
  * {@link System#DEFAULT_ALARM_ALERT_URI}. If the user chooses the "Silent"
  * item, the saved string will be an empty string.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 4acb631..82d2612c 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5663,6 +5663,16 @@
         public static final String RINGTONE = "ringtone";
 
         /**
+         * Persistent store for the system-wide default ringtone for Slot2 URI.
+         *
+         * @see #RINGTONE
+         * @see #DEFAULT_RINGTONE2_URI
+         *
+         */
+        /** {@hide} */
+        public static final String RINGTONE2 = "ringtone2";
+
+        /**
          * A {@link Uri} that will point to the current default ringtone at any
          * given time.
          * <p>
@@ -5672,11 +5682,26 @@
          */
         public static final Uri DEFAULT_RINGTONE_URI = getUriFor(RINGTONE);
 
+        /**
+         * A {@link Uri} that will point to the current default ringtone for Slot2
+         * at any given time.
+         *
+         * @see #DEFAULT_RINGTONE_URI
+         *
+         */
+        /** {@hide} */
+        public static final Uri DEFAULT_RINGTONE2_URI = getUriFor(RINGTONE2);
+
         /** {@hide} */
         public static final String RINGTONE_CACHE = "ringtone_cache";
         /** {@hide} */
         public static final Uri RINGTONE_CACHE_URI = getUriFor(RINGTONE_CACHE);
 
+        /** {@hide} */
+        public static final String RINGTONE2_CACHE = "ringtone2_cache";
+        /** {@hide} */
+        public static final Uri RINGTONE2_CACHE_URI = getUriFor(RINGTONE2_CACHE);
+
         /**
          * Persistent store for the system-wide default notification sound.
          *
@@ -6493,6 +6518,7 @@
             PUBLIC_SETTINGS.add(VOLUME_BLUETOOTH_SCO);
             PUBLIC_SETTINGS.add(VOLUME_ASSISTANT);
             PUBLIC_SETTINGS.add(RINGTONE);
+            PUBLIC_SETTINGS.add(RINGTONE2);
             PUBLIC_SETTINGS.add(NOTIFICATION_SOUND);
             PUBLIC_SETTINGS.add(ALARM_ALERT);
             PUBLIC_SETTINGS.add(TEXT_AUTO_REPLACE);
@@ -6616,6 +6642,7 @@
         public static final Map<String, String> CLONE_FROM_PARENT_ON_VALUE = new ArrayMap<>();
         static {
             CLONE_FROM_PARENT_ON_VALUE.put(RINGTONE, Secure.SYNC_PARENT_SOUNDS);
+            CLONE_FROM_PARENT_ON_VALUE.put(RINGTONE2, Secure.SYNC_PARENT_SOUNDS);
             CLONE_FROM_PARENT_ON_VALUE.put(NOTIFICATION_SOUND, Secure.SYNC_PARENT_SOUNDS);
             CLONE_FROM_PARENT_ON_VALUE.put(ALARM_ALERT, Secure.SYNC_PARENT_SOUNDS);
         }
diff --git a/core/java/android/service/dreams/DreamManagerInternal.java b/core/java/android/service/dreams/DreamManagerInternal.java
index e9bb28c..bf25453 100644
--- a/core/java/android/service/dreams/DreamManagerInternal.java
+++ b/core/java/android/service/dreams/DreamManagerInternal.java
@@ -99,4 +99,9 @@
         default void onDreamingStopped() {
         }
     }
+
+    /**
+     * Called by the power manager to determine whether the dream has gone to doze mode.
+     */
+    public abstract boolean isDozing();
 }
diff --git a/core/java/android/service/dreams/IDreamManager.aidl b/core/java/android/service/dreams/IDreamManager.aidl
index 1c0a2c0..e3a58a8 100644
--- a/core/java/android/service/dreams/IDreamManager.aidl
+++ b/core/java/android/service/dreams/IDreamManager.aidl
@@ -36,6 +36,7 @@
     void testDream(int userId, in ComponentName componentName);
     @UnsupportedAppUsage
     boolean isDreaming();
+    boolean isDozing();
     @UnsupportedAppUsage
     boolean isDreamingOrInPreview();
     boolean canStartDreaming(boolean isScreenOn);
diff --git a/core/java/android/speech/tts/TtsEngines.java b/core/java/android/speech/tts/TtsEngines.java
index a8aea7c..ef63c8f 100644
--- a/core/java/android/speech/tts/TtsEngines.java
+++ b/core/java/android/speech/tts/TtsEngines.java
@@ -507,7 +507,7 @@
         for (String value : prefValues) {
             final int delimiter = value.indexOf(':');
             if (delimiter > 0) {
-                if (engineName.equals(value.substring(0, delimiter))) {
+                if ((value.substring(0, delimiter)).equals(engineName)) {
                     return value.substring(delimiter + 1);
                 }
             }
@@ -560,7 +560,7 @@
             for (String value : prefValues) {
                 final int delimiter = value.indexOf(':');
                 if (delimiter > 0) {
-                    if (key.equals(value.substring(0, delimiter))) {
+                    if (value.substring(0, delimiter).equals(key)) {
                         if (first) {
                             first = false;
                         } else {
diff --git a/core/java/com/android/internal/content/om/OverlayConfig.java b/core/java/com/android/internal/content/om/OverlayConfig.java
index 38593b4..86e7e30 100644
--- a/core/java/com/android/internal/content/om/OverlayConfig.java
+++ b/core/java/com/android/internal/content/om/OverlayConfig.java
@@ -489,13 +489,14 @@
      * precedence.
      */
     @VisibleForTesting
-    public ArrayList<IdmapInvocation> getImmutableFrameworkOverlayIdmapInvocations() {
+    public ArrayList<IdmapInvocation> getImmutableFrameworkOverlayIdmapInvocations(
+            String packageName) {
         final ArrayList<IdmapInvocation> idmapInvocations = new ArrayList<>();
         final ArrayList<Configuration> sortedConfigs = getSortedOverlays();
         for (int i = 0, n = sortedConfigs.size(); i < n; i++) {
             final Configuration overlay = sortedConfigs.get(i);
             if (overlay.parsedConfig.mutable || !overlay.parsedConfig.enabled
-                    || !"android".equals(overlay.parsedConfig.parsedInfo.targetPackageName)) {
+                    || !packageName.equals(overlay.parsedConfig.parsedInfo.targetPackageName)) {
                 continue;
             }
 
@@ -534,26 +535,32 @@
      */
     @NonNull
     public String[] createImmutableFrameworkIdmapsInZygote() {
-        final String targetPath = AssetManager.FRAMEWORK_APK_PATH;
         final ArrayList<String> idmapPaths = new ArrayList<>();
-        final ArrayList<IdmapInvocation> idmapInvocations =
-                getImmutableFrameworkOverlayIdmapInvocations();
 
-        for (int i = 0, n = idmapInvocations.size(); i < n; i++) {
-            final IdmapInvocation invocation = idmapInvocations.get(i);
-            final String[] idmaps = createIdmap(targetPath,
-                    invocation.overlayPaths.toArray(new String[0]),
-                    new String[]{OverlayConfigParser.OverlayPartition.POLICY_PUBLIC,
-                            invocation.policy},
-                    invocation.enforceOverlayable);
+        for (Map.Entry<String, String> target : new HashMap<String, String>() {{
+                put(AssetManager.FRAMEWORK_APK_PATH, "android");
+                put("/system/framework/omnirom-res.apk", "omnirom.platform");
+        }}.entrySet()) {
+            final String targetPath = target.getKey();
+            final String targetPackageName = target.getValue();
+            final ArrayList<IdmapInvocation> idmapInvocations =
+                    getImmutableFrameworkOverlayIdmapInvocations(targetPackageName);
+            for (int i = 0, n = idmapInvocations.size(); i < n; i++) {
+                final IdmapInvocation invocation = idmapInvocations.get(i);
+                final String[] idmaps = createIdmap(targetPath,
+                        invocation.overlayPaths.toArray(new String[0]),
+                        new String[]{OverlayConfigParser.OverlayPartition.POLICY_PUBLIC,
+                                invocation.policy},
+                        invocation.enforceOverlayable);
 
-            if (idmaps == null) {
-                Log.w(TAG, "'idmap2 create-multiple' failed: no mutable=\"false\" overlays"
-                        + " targeting \"android\" will be loaded");
-                return new String[0];
+                if (idmaps == null) {
+                    Log.w(TAG, "'idmap2 create-multiple' failed: no mutable=\"false\" overlays"
+                            + " targeting \"android\" will be loaded");
+                    return new String[0];
+                }
+
+                idmapPaths.addAll(Arrays.asList(idmaps));
             }
-
-            idmapPaths.addAll(Arrays.asList(idmaps));
         }
 
         return idmapPaths.toArray(new String[0]);
diff --git a/core/java/com/android/internal/notification/SystemNotificationChannels.java b/core/java/com/android/internal/notification/SystemNotificationChannels.java
index 4aebde5..8ec6a03 100644
--- a/core/java/com/android/internal/notification/SystemNotificationChannels.java
+++ b/core/java/com/android/internal/notification/SystemNotificationChannels.java
@@ -109,7 +109,7 @@
                 DEVELOPER_IMPORTANT,
                 context.getString(R.string.notification_channel_developer_important),
                 NotificationManager.IMPORTANCE_HIGH);
-        developer.setBlockable(true);
+        developerImportant.setBlockable(true);
         channelsList.add(developerImportant);
 
         final NotificationChannel updates = new NotificationChannel(
@@ -143,6 +143,7 @@
                 VPN,
                 context.getString(R.string.notification_channel_vpn),
                 NotificationManager.IMPORTANCE_LOW);
+        vpn.setBlockable(true);
         channelsList.add(vpn);
 
         final NotificationChannel deviceAdmin = new NotificationChannel(
@@ -167,6 +168,7 @@
                 USB,
                 context.getString(R.string.notification_channel_usb),
                 NotificationManager.IMPORTANCE_MIN);
+        usb.setBlockable(true);
         channelsList.add(usb);
 
         NotificationChannel foregroundChannel = new NotificationChannel(
diff --git a/core/java/com/android/internal/policy/GestureNavigationSettingsObserver.java b/core/java/com/android/internal/policy/GestureNavigationSettingsObserver.java
index b7e68ba..51159bd 100644
--- a/core/java/com/android/internal/policy/GestureNavigationSettingsObserver.java
+++ b/core/java/com/android/internal/policy/GestureNavigationSettingsObserver.java
@@ -29,6 +29,8 @@
 import android.util.DisplayMetrics;
 import android.util.TypedValue;
 
+import org.omnirom.omnilib.utils.OmniSettings;
+
 /**
  * @hide
  */
@@ -73,6 +75,9 @@
             r.registerContentObserver(
                     Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE),
                     false, this, UserHandle.USER_ALL);
+            r.registerContentObserver(
+                Settings.System.getUriFor(OmniSettings.OMNI_BACK_GESTURE_HEIGHT),
+                false, this, UserHandle.USER_ALL);
             DeviceConfig.addOnPropertiesChangedListener(
                     DeviceConfig.NAMESPACE_SYSTEMUI,
                     runnable -> mMainHandler.post(runnable),
@@ -95,6 +100,9 @@
             r.registerContentObserver(
                     Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE),
                     false, this);
+            r.registerContentObserver(
+                Settings.System.getUriFor(OmniSettings.OMNI_BACK_GESTURE_HEIGHT),
+                false, this);
             DeviceConfig.addOnPropertiesChangedListener(
                     DeviceConfig.NAMESPACE_SYSTEMUI,
                     runnable -> mMainHandler.post(runnable),
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index c834dde..119b734 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -173,7 +173,7 @@
     void showPinningEnterExitToast(boolean entering);
     void showPinningEscapeToast();
 
-    void showShutdownUi(boolean isReboot, String reason);
+    void showShutdownUi(boolean isReboot, String reason, boolean rebootCustom);
 
     /**
     * Used to show the authentication dialog (Biometrics, Device Credential).
@@ -390,4 +390,10 @@
     * @param displayId the id of the current display.
     */
     void moveFocusedTaskToDesktop(int displayId);
+
+    /**
+     *Omni
+     */
+    void toggleCameraFlash();
+    void toggleCameraFlashState(boolean enable);
 }
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 3e2f301..286ae68 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -108,7 +108,7 @@
      * These methods are needed for global actions control which the UI is shown in sysui.
      */
     void shutdown();
-    void reboot(boolean safeMode);
+    void reboot(boolean safeMode, String reason);
 
     /** just restarts android without rebooting device. Used for some feature flags. */
     void restart();
@@ -236,4 +236,11 @@
 
     /** Shows rear display educational dialog */
     void showRearDisplayDialog(int currentBaseState);
+
+    /**
+     * Omni
+     */
+    void toggleCameraFlash();
+    void toggleCameraFlashState(boolean enable);
+    boolean getSessionStatus(int sessionType);
 }
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index 0eb7c4a..5a21291 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -44,6 +44,7 @@
         "/sys/kernel/debug/tracing/trace_marker",
         "/sys/kernel/tracing/trace_marker",
         "/system/framework/framework-res.apk",
+        "/system/framework/omnirom-res.apk",
         "/dev/urandom",
         "/dev/ion",
         "/dev/dri/renderD129", // Fixes b/31172436
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 6b8056c..0b808b8 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4873,6 +4873,11 @@
         android:description="@string/permdesc_getPackageSize"
         android:protectionLevel="normal" />
 
+    <!-- @hide Allows an application to change the package signature as
+	 seen by applications -->
+    <permission android:name="android.permission.FAKE_PACKAGE_SIGNATURE"
+        android:protectionLevel="signature|privileged" />
+
     <!-- @deprecated No longer useful, see
          {@link android.content.pm.PackageManager#addPackageToPreferred}
          for details. -->
diff --git a/core/res/res/values/custom_arrays.xml b/core/res/res/values/custom_arrays.xml
new file mode 100644
index 0000000..a67890b
--- /dev/null
+++ b/core/res/res/values/custom_arrays.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+** Not a Contribution.
+**
+** Copyright 2012, The Android Open Source 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.
+*/
+-->
+<resources>
+
+    <string-array translatable="false" name="config_rebootActionsList">
+        <item>restart</item>
+        <item>reboot_recovery</item>
+        <item>reboot_bootloader</item>
+    </string-array>
+
+</resources>
diff --git a/core/res/res/values/custom_symbols.xml b/core/res/res/values/custom_symbols.xml
new file mode 100644
index 0000000..f8f3a91
--- /dev/null
+++ b/core/res/res/values/custom_symbols.xml
@@ -0,0 +1,4 @@
+<resources>
+    <java-symbol type="color" name="primary_text_material_light" />
+    <java-symbol type="color" name="primary_text_material_dark" />
+</resources>
diff --git a/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigTest.java b/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigTest.java
index 43cff8d..4c9b187 100644
--- a/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigTest.java
+++ b/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigTest.java
@@ -471,7 +471,7 @@
         final OverlayConfig overlayConfig = createConfigImpl();
         if (mScannerRule.getIteration() == OverlayConfigIterationRule.Iteration.ZYGOTE) {
             final ArrayList<IdmapInvocation> idmapInvocations =
-                    overlayConfig.getImmutableFrameworkOverlayIdmapInvocations();
+                    overlayConfig.getImmutableFrameworkOverlayIdmapInvocations("android");
             assertEquals(2, idmapInvocations.size());
 
             final IdmapInvocation i0 = idmapInvocations.get(0);
@@ -508,7 +508,7 @@
 
         if (mScannerRule.getIteration() == OverlayConfigIterationRule.Iteration.ZYGOTE) {
             final ArrayList<IdmapInvocation> idmapInvocations =
-                    overlayConfig.getImmutableFrameworkOverlayIdmapInvocations();
+                    overlayConfig.getImmutableFrameworkOverlayIdmapInvocations("android");
             assertEquals(3, idmapInvocations.size());
 
             final IdmapInvocation i0 = idmapInvocations.get(0);
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index e618245..f4a77ec 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -63,6 +63,7 @@
 static const char* kAssetsRoot = "assets";
 static const char* kAppZipName = NULL; //"classes.jar";
 static const char* kSystemAssets = "framework/framework-res.apk";
+static const char* kOmniRomAssets = "framework/omnirom-res.apk";
 static const char* kResourceCache = "resource-cache";
 
 static const char* kExcludeExtension = ".EXCLUDE";
@@ -367,10 +368,19 @@
     const char* root = getenv("ANDROID_ROOT");
     LOG_ALWAYS_FATAL_IF(root == NULL, "ANDROID_ROOT not set");
 
-    String8 path(root);
-    appendPath(path, kSystemAssets);
+    bool success = true;
+    {
+       String8 path(root);
+       appendPath(path, kSystemAssets);
+       success &= addAssetPath(path, NULL, false /* appAsLib */, true /* isSystemAsset */);
+    }
+    {
+       String8 path(root);
+       appendPath(path, kOmniRomAssets);
+       success &= addAssetPath(path, NULL, false /* appAsLib */, true /* isSystemAsset */);
+    }
 
-    return addAssetPath(path, NULL, false /* appAsLib */, true /* isSystemAsset */);
+    return success;
 }
 
 int32_t AssetManager::nextAssetPath(const int32_t cookie) const
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index de9991a..311f3fe 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -70,6 +70,7 @@
 #define IDMAP_MAGIC             0x504D4449
 
 #define APP_PACKAGE_ID      0x7f
+#define OMNIROMSDK_PACKAGE_ID    0x3f
 #define SYS_PACKAGE_ID      0x01
 
 static const bool kDebugStringPoolNoisy = false;
@@ -5802,7 +5803,8 @@
                 }
 
                 uint32_t packageId = Res_GETPACKAGE(rid) + 1;
-                if (packageId != APP_PACKAGE_ID && packageId != SYS_PACKAGE_ID) {
+                if (packageId != APP_PACKAGE_ID && packageId != SYS_PACKAGE_ID &&
+                        packageId != OMNIROMSDK_PACKAGE_ID) {
                     outValue->dataType = Res_value::TYPE_DYNAMIC_REFERENCE;
                 }
                 outValue->data = rid;
@@ -5823,7 +5825,8 @@
                         outValue->data = rid;
                         outValue->dataType = Res_value::TYPE_DYNAMIC_REFERENCE;
                         return true;
-                    } else if (packageId == APP_PACKAGE_ID || packageId == SYS_PACKAGE_ID) {
+                    } else if (packageId == APP_PACKAGE_ID || packageId == SYS_PACKAGE_ID ||
+                            packageId == OMNIROMSDK_PACKAGE_ID) {
                         // We accept packageId's generated as 0x01 in order to support
                         // building the android system resources
                         outValue->data = rid;
@@ -5969,7 +5972,8 @@
             }
 
             uint32_t packageId = Res_GETPACKAGE(rid) + 1;
-            if (packageId != APP_PACKAGE_ID && packageId != SYS_PACKAGE_ID) {
+            if (packageId != APP_PACKAGE_ID && packageId != SYS_PACKAGE_ID &&
+                    packageId != OMNIROMSDK_PACKAGE_ID) {
                 outValue->dataType = Res_value::TYPE_DYNAMIC_ATTRIBUTE;
             }
             outValue->data = rid;
@@ -5984,7 +5988,8 @@
                     outValue->data = rid;
                     outValue->dataType = Res_value::TYPE_DYNAMIC_ATTRIBUTE;
                     return true;
-                } else if (packageId == APP_PACKAGE_ID || packageId == SYS_PACKAGE_ID) {
+                } else if (packageId == APP_PACKAGE_ID || packageId == SYS_PACKAGE_ID ||
+                        packageId == OMNIROMSDK_PACKAGE_ID) {
                     // We accept packageId's generated as 0x01 in order to support
                     // building the android system resources
                     outValue->data = rid;
@@ -7159,6 +7164,7 @@
     // Reserved package ids
     mLookupTable[APP_PACKAGE_ID] = APP_PACKAGE_ID;
     mLookupTable[SYS_PACKAGE_ID] = SYS_PACKAGE_ID;
+    mLookupTable[OMNIROMSDK_PACKAGE_ID] = OMNIROMSDK_PACKAGE_ID;
 }
 
 status_t DynamicRefTable::load(const ResTable_lib_header* const header)
diff --git a/libs/androidfw/include/androidfw/AttributeFinder.h b/libs/androidfw/include/androidfw/AttributeFinder.h
index 03fad49..f12a964 100644
--- a/libs/androidfw/include/androidfw/AttributeFinder.h
+++ b/libs/androidfw/include/androidfw/AttributeFinder.h
@@ -74,6 +74,7 @@
 
   // Package offsets (best-case, fast look-up).
   Iterator framework_start_;
+  Iterator omnirom_framework_start_;
   Iterator app_start_;
 
   // Worst case, we have shared-library resources.
@@ -100,6 +101,9 @@
     case 0x01u:
       current_ = framework_start_;
       break;
+    case 0x3fu:
+      current_ = omnirom_framework_start_;
+      break;
     case 0x7fu:
       current_ = app_start_;
       break;
@@ -134,6 +138,9 @@
     case 0x01u:
       framework_start_ = current_;
       break;
+    case 0x3fu:
+      omnirom_framework_start_ = current_;
+      break;
     case 0x7fu:
       app_start_ = current_;
       break;
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index 0f24654..b3dc6d4 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -48,6 +48,8 @@
 import android.provider.MediaStore.MediaColumns;
 import android.provider.Settings;
 import android.provider.Settings.System;
+import android.telephony.SubscriptionManager;
+import android.text.TextUtils;
 import android.util.Log;
 
 import com.android.internal.database.SortCursor;
@@ -149,6 +151,7 @@
      * for this {@link Uri}. If showing an item for "Default" (@see
      * {@link #EXTRA_RINGTONE_SHOW_DEFAULT}), this can also be one of
      * {@link System#DEFAULT_RINGTONE_URI},
+     * {@link System#DEFAULT_RINGTONE2_URI},
      * {@link System#DEFAULT_NOTIFICATION_URI}, or
      * {@link System#DEFAULT_ALARM_ALERT_URI} to have the "Default" item
      * checked.
@@ -162,7 +165,7 @@
      * Given to the ringtone picker as a {@link Uri}. The {@link Uri} of the
      * ringtone to play when the user attempts to preview the "Default"
      * ringtone. This can be one of {@link System#DEFAULT_RINGTONE_URI},
-     * {@link System#DEFAULT_NOTIFICATION_URI}, or
+     * {@link System#DEFAULT_RINGTONE2_URI}, {@link System#DEFAULT_NOTIFICATION_URI}, or
      * {@link System#DEFAULT_ALARM_ALERT_URI} to have the "Default" point to
      * the current sound for the given default sound type. If you are showing a
      * ringtone picker for some other type of sound, you are free to provide any
@@ -201,7 +204,7 @@
      * It will be one of:
      * <li> the picked ringtone,
      * <li> a {@link Uri} that equals {@link System#DEFAULT_RINGTONE_URI},
-     * {@link System#DEFAULT_NOTIFICATION_URI}, or
+     * {@link System#DEFAULT_RINGTONE2_URI}, {@link System#DEFAULT_NOTIFICATION_URI}, or
      * {@link System#DEFAULT_ALARM_ALERT_URI} if the default was chosen,
      * <li> null if the "Silent" item was picked.
      * 
@@ -876,8 +879,8 @@
     /**
      * Gets the current default sound's {@link Uri}. This will give the actual
      * sound {@link Uri}, instead of using this, most clients can use
-     * {@link System#DEFAULT_RINGTONE_URI}.
-     * 
+     * {@link System#DEFAULT_RINGTONE_URI} or {@link System#DEFAULT_RINGTONE2_URI}.
+     *
      * @param context A context used for querying.
      * @param type The type whose default sound should be returned. One of
      *            {@link #TYPE_RINGTONE}, {@link #TYPE_NOTIFICATION}, or
@@ -886,7 +889,28 @@
      * @see #setActualDefaultRingtoneUri(Context, int, Uri)
      */
     public static Uri getActualDefaultRingtoneUri(Context context, int type) {
-        String setting = getSettingForType(type);
+        return getActualDefaultRingtoneUriBySlot(context, type,
+                SubscriptionManager.getDefaultVoicePhoneId());
+    }
+
+    /**
+     * Gets the current default sound's {@link Uri} by slotId. This will give the actual
+     * sound {@link Uri}, instead of using this, most clients can use
+     * {@link System#DEFAULT_RINGTONE_URI} or {@link System#DEFAULT_RINGTONE2_URI}.
+     *
+     * @param context A context used for querying.
+     * @param type The type whose default sound should be returned. One of
+     *            {@link #TYPE_RINGTONE}, {@link #TYPE_NOTIFICATION}, or
+     *            {@link #TYPE_ALARM}.
+     * @param slotId The slotId whose default sound should be returned.
+     * @return A {@link Uri} pointing to the default sound for the sound type.
+     * @see #setActualDefaultRingtoneUriBySlot(Context, int, Uri, int)
+     *
+     * @hide
+     */
+
+    public static Uri getActualDefaultRingtoneUriBySlot(Context context, int type, int slotId) {
+        String setting = getSettingForTypeBySlot(type, slotId);
         if (setting == null) return null;
         final String uriString = Settings.System.getStringForUser(context.getContentResolver(),
                 setting, context.getUserId());
@@ -913,7 +937,26 @@
      * @see #getActualDefaultRingtoneUri(Context, int)
      */
     public static void setActualDefaultRingtoneUri(Context context, int type, Uri ringtoneUri) {
-        String setting = getSettingForType(type);
+        setActualDefaultRingtoneUriBySlot(context, type, ringtoneUri,
+                SubscriptionManager.getDefaultVoicePhoneId());
+    }
+
+    /**
+     * Sets the {@link Uri} of the default sound by slotId for a given sound type.
+     *
+     * @param context A context used for querying.
+     * @param type The type whose default sound should be set. One of
+     *            {@link #TYPE_RINGTONE}, {@link #TYPE_NOTIFICATION}, or
+     *            {@link #TYPE_ALARM}.
+     * @param ringtoneUri A {@link Uri} pointing to the default sound to set.
+     * @param slotId The slotId whose default sound should be set.
+     * @see #getActualDefaultRingtoneUriBySlot(Context, int, int)
+     *
+     * @hide
+     */
+    public static void setActualDefaultRingtoneUriBySlot(Context context, int type,
+                Uri ringtoneUri, int slotId) {
+        String setting = getSettingForTypeBySlot(type, slotId);
         if (setting == null) return;
 
         final ContentResolver resolver = context.getContentResolver();
@@ -1036,9 +1079,9 @@
         }
     }
 
-    private static String getSettingForType(int type) {
+    private static String getSettingForTypeBySlot(int type, int slotId) {
         if ((type & TYPE_RINGTONE) != 0) {
-            return Settings.System.RINGTONE;
+            return slotId == 1 ? Settings.System.RINGTONE2 : Settings.System.RINGTONE;
         } else if ((type & TYPE_NOTIFICATION) != 0) {
             return Settings.System.NOTIFICATION_SOUND;
         } else if ((type & TYPE_ALARM) != 0) {
@@ -1050,13 +1093,22 @@
 
     /** {@hide} */
     public static Uri getCacheForType(int type) {
-        return getCacheForType(type, UserHandle.getCallingUserId());
+        return getCacheForTypeBySlot(type, UserHandle.getCallingUserId(),
+                SubscriptionManager.getDefaultVoicePhoneId());
     }
 
     /** {@hide} */
     public static Uri getCacheForType(int type, int userId) {
+        return getCacheForTypeBySlot(type, userId, SubscriptionManager.getDefaultVoicePhoneId());
+    }
+
+    /** {@hide} */
+    public static Uri getCacheForTypeBySlot(int type, int userId, int slotId) {
         if ((type & TYPE_RINGTONE) != 0) {
-            return ContentProvider.maybeAddUserId(Settings.System.RINGTONE_CACHE_URI, userId);
+                        Uri ringtoneUri = slotId == 1
+                    ? Settings.System.RINGTONE2_CACHE_URI
+                    : Settings.System.RINGTONE_CACHE_URI;
+            return ContentProvider.maybeAddUserId(ringtoneUri, userId);
         } else if ((type & TYPE_NOTIFICATION) != 0) {
             return ContentProvider.maybeAddUserId(Settings.System.NOTIFICATION_SOUND_CACHE_URI,
                     userId);
@@ -1081,6 +1133,7 @@
      * 
      * @param defaultRingtoneUri The default {@link Uri}. For example,
      *            {@link System#DEFAULT_RINGTONE_URI},
+     *            {@link System#DEFAULT_RINGTONE2_URI},
      *            {@link System#DEFAULT_NOTIFICATION_URI}, or
      *            {@link System#DEFAULT_ALARM_ALERT_URI}.
      * @return The type of the defaultRingtoneUri, or -1.
@@ -1106,7 +1159,8 @@
             }
         }
 
-        if (defaultRingtoneUri.equals(Settings.System.DEFAULT_RINGTONE_URI)) {
+        if (defaultRingtoneUri.equals(Settings.System.DEFAULT_RINGTONE_URI)
+                    || defaultRingtoneUri.equals(Settings.System.DEFAULT_RINGTONE2_URI)) {
             return TYPE_RINGTONE;
         } else if (defaultRingtoneUri.equals(Settings.System.DEFAULT_NOTIFICATION_URI)) {
             return TYPE_NOTIFICATION;
@@ -1122,13 +1176,31 @@
      * Rather than returning the actual ringtone's sound {@link Uri}, this will
      * return the symbolic {@link Uri} which will resolved to the actual sound
      * when played.
-     * 
+     *
      * @param type The ringtone type whose default should be returned.
      * @return The {@link Uri} of the default ringtone for the given type.
      */
     public static Uri getDefaultUri(int type) {
+        return getDefaultUriBySlot(type, SubscriptionManager.getDefaultVoicePhoneId());
+    }
+
+    /**
+     * Returns the {@link Uri} for the default ringtone by slotId of a particular type.
+     * Rather than returning the actual ringtone's sound {@link Uri}, this will
+     * return the symbolic {@link Uri} which will resolved to the actual sound
+     * when played.
+     *
+     * @param type The ringtone type whose default should be returned.
+     * @param slotId The slotId whose default should be returned.
+     * @return The {@link Uri} of the default ringtone for the given type.
+     *
+     * @hide
+     */
+    public static Uri getDefaultUriBySlot(int type, int slotId) {
         if ((type & TYPE_RINGTONE) != 0) {
-            return Settings.System.DEFAULT_RINGTONE_URI;
+            return slotId == 1
+                    ? Settings.System.DEFAULT_RINGTONE2_URI
+                    : Settings.System.DEFAULT_RINGTONE_URI;
         } else if ((type & TYPE_NOTIFICATION) != 0) {
             return Settings.System.DEFAULT_NOTIFICATION_URI;
         } else if ((type & TYPE_ALARM) != 0) {
@@ -1242,14 +1314,20 @@
             // Skip if we've already defined it at least once, so we don't
             // overwrite the user changing to null
             final String setting = getDefaultRingtoneSetting(type);
+            String defaultRingtone2 = Settings.System.getString(context.getContentResolver(), Settings.System.RINGTONE2);
             if (Settings.System.getInt(context.getContentResolver(), setting, 0) != 0) {
-                continue;
+                if (!TextUtils.isEmpty(defaultRingtone2)) {
+                    continue;
+                }
             }
 
             // Try finding the scanned ringtone
             Uri ringtoneUri = computeDefaultRingtoneUri(context, type);
             if (ringtoneUri != null) {
                 RingtoneManager.setActualDefaultRingtoneUri(context, type, ringtoneUri);
+                if (TextUtils.isEmpty(defaultRingtone2)) {
+                    RingtoneManager.setActualDefaultRingtoneUriBySlot(context, TYPE_RINGTONE, ringtoneUri, 1);
+                }
                 Settings.System.putInt(context.getContentResolver(), setting, 1);
             }
         }
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfo.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfo.kt
index 5a524d9..55aed78 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfo.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfo.kt
@@ -119,7 +119,7 @@
     }
 
     @Composable
-    fun FooterAppVersion(showPackageName: Boolean = rememberIsDevelopmentSettingsEnabled()) {
+    fun FooterAppVersion(showPackageName: Boolean = true /*rememberIsDevelopmentSettingsEnabled()*/) {
         val context = LocalContext.current
         val footer =
             remember(packageInfo, showPackageName) {
diff --git a/packages/SettingsLib/res/values/custom_strings.xml b/packages/SettingsLib/res/values/custom_strings.xml
new file mode 100644
index 0000000..fab17bb
--- /dev/null
+++ b/packages/SettingsLib/res/values/custom_strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2015 The Android Open Source 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.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="status_deep_sleep">(Deep sleep: %1$d%2$s)</string>
+</resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractUptimePreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractUptimePreferenceController.java
index 5f72269..5816578 100644
--- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractUptimePreferenceController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractUptimePreferenceController.java
@@ -26,6 +26,7 @@
 import androidx.preference.Preference;
 import androidx.preference.PreferenceScreen;
 
+import com.android.settingslib.R;
 import com.android.settingslib.core.AbstractPreferenceController;
 import com.android.settingslib.core.lifecycle.Lifecycle;
 import com.android.settingslib.core.lifecycle.LifecycleObserver;
@@ -89,7 +90,14 @@
     }
 
     private void updateTimes() {
-        mUptime.setSummary(DateUtils.formatElapsedTime(SystemClock.elapsedRealtime() / 1000));
+        float deepSleepRatio = Math.max((float) (SystemClock.elapsedRealtime() - SystemClock.uptimeMillis()), 0f)
+                / SystemClock.elapsedRealtime();
+        int deepSleepPercent = Math.round(deepSleepRatio * 100);
+
+        String summary = DateUtils.formatElapsedTime(SystemClock.elapsedRealtime() / 1000) +
+                " " + mContext.getString(R.string.status_deep_sleep, deepSleepPercent, "%");
+
+        mUptime.setSummary(summary.toString());
     }
 
     private static class MyHandler extends Handler {
diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/BluetoothDeviceLayerDrawable.java b/packages/SettingsLib/src/com/android/settingslib/graph/BluetoothDeviceLayerDrawable.java
index 65d53f3..ca70a7f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/graph/BluetoothDeviceLayerDrawable.java
+++ b/packages/SettingsLib/src/com/android/settingslib/graph/BluetoothDeviceLayerDrawable.java
@@ -88,6 +88,41 @@
         return drawable;
     }
 
+    /**
+     * Create the {@link LayerDrawable} that contains bluetooth device icon and battery icon.
+     * This is a horizontal layout drawable while bluetooth icon at start and battery icon at end.
+     *
+     * @param context      used to get the spec for icon
+     * @param resId        represents the bluetooth device drawable
+     * @param batteryLevel the battery level for bluetooth device
+     * @param iconScale    the ratio of height between battery icon and bluetooth icon
+     * @param gap          the gap between battery icon and bluetooth icon
+     * @param paddingSide  the side padding of the battery icon
+     * @param paddingTop   the top and bottom badding of the battery icon
+     */
+    public static BluetoothDeviceLayerDrawable createLayerDrawable(Context context, int resId,
+            int batteryLevel, float iconScale, int gap, int paddingTop, int paddingSide) {
+        final Drawable deviceDrawable = context.getDrawable(resId);
+
+        final BatteryMeterDrawable batteryDrawable = new BatteryMeterDrawable(context,
+                context.getColor(R.color.meter_background_color), batteryLevel);
+        batteryDrawable.setPadding(paddingSide, paddingTop, paddingSide, paddingTop);
+
+        final BluetoothDeviceLayerDrawable drawable = new BluetoothDeviceLayerDrawable(
+                new Drawable[]{deviceDrawable, batteryDrawable});
+        // Set the bluetooth icon at the left
+        drawable.setLayerGravity(0 /* index of deviceDrawable */, Gravity.START);
+        // Set battery icon to the right of the bluetooth icon
+        drawable.setLayerInsetStart(1 /* index of batteryDrawable */,
+                deviceDrawable.getIntrinsicWidth() + gap);
+        drawable.setLayerInsetTop(1 /* index of batteryDrawable */,
+                (int) (deviceDrawable.getIntrinsicHeight() * (1 - iconScale)));
+
+        drawable.setConstantState(context, resId, batteryLevel, iconScale);
+
+        return drawable;
+    }
+
     public void setConstantState(Context context, int resId, int batteryLevel, float iconScale) {
         mState = new BluetoothDeviceLayerDrawableState(context, resId, batteryLevel, iconScale);
     }
diff --git a/packages/SettingsProvider/Android.bp b/packages/SettingsProvider/Android.bp
index 00ae05c..2bbe882 100644
--- a/packages/SettingsProvider/Android.bp
+++ b/packages/SettingsProvider/Android.bp
@@ -40,6 +40,7 @@
         "device_config_service_flags_java",
         "libaconfig_java_proto_lite",
         "notification_flags_lib",
+        "OmniLib",
         "SettingsLibDeviceStateRotationLock",
         "SettingsLibDisplayUtils",
     ],
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java
index 255b1ad..4c281f0 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SettingsValidators.java
@@ -35,6 +35,15 @@
  */
 public class SettingsValidators {
 
+    public static final Validator OMNI_CHARGING_CONTROL_LIMIT_VALIDATOR =
+            new InclusiveIntegerRangeValidator(70, 100);
+
+    public static final Validator OMNI_CHARGING_CONTROL_MODE_VALIDATOR =
+            new InclusiveIntegerRangeValidator(1, 3);
+
+    public static final Validator OMNI_CHARGING_CONTROL_TIME_VALIDATOR =
+            new InclusiveIntegerRangeValidator(0, 86400);
+
     public static final Validator BOOLEAN_VALIDATOR =
             new DiscreteValueValidator(new String[] {"0", "1"});
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 326bff4..daf25a4e 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -45,6 +45,7 @@
 import android.provider.settings.backup.SystemSettings;
 import android.provider.settings.validators.GlobalSettingsValidators;
 import android.provider.settings.validators.SecureSettingsValidators;
+import android.provider.settings.validators.SettingsValidators;
 import android.provider.settings.validators.SystemSettingsValidators;
 import android.provider.settings.validators.Validator;
 import android.telephony.SubscriptionManager;
@@ -62,6 +63,8 @@
 import com.android.settingslib.display.DisplayDensityConfiguration;
 import com.android.window.flags.Flags;
 
+import org.omnirom.omnilib.utils.OmniSettings;
+
 import java.io.BufferedOutputStream;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
@@ -715,7 +718,9 @@
         Cursor cursor = getContentResolver().query(Settings.System.CONTENT_URI, PROJECTION, null,
                 null, null);
         try {
-            return extractRelevantValues(cursor, SystemSettings.SETTINGS_TO_BACKUP, KEY_SYSTEM);
+            String[] settings = ArrayUtils.concat(String.class, SystemSettings.SETTINGS_TO_BACKUP,
+                    OmniSettings.OMNI_SETTINGS_TO_BACKUP, KEY_SYSTEM);
+            return extractRelevantValues(cursor, settings);
         } finally {
             cursor.close();
         }
@@ -1101,8 +1106,32 @@
             validators = SecureSettingsValidators.VALIDATORS;
         } else if (contentUri.equals(Settings.System.CONTENT_URI)) {
             allowlist = ArrayUtils.concat(String.class, SystemSettings.SETTINGS_TO_BACKUP,
-                    Settings.System.LEGACY_RESTORE_SETTINGS);
+                    Settings.System.LEGACY_RESTORE_SETTINGS, OmniSettings.OMNI_SETTINGS_TO_BACKUP);
             validators = SystemSettingsValidators.VALIDATORS;
+
+            final Map<String, Integer> omniValidators = OmniSettings.OMNI_SETTINGS_VALIDATORS;
+            // BOOLEAN_VALIDATOR == 0
+            // ANY_INTEGER_VALIDATOR == 1
+            // ANY_STRING_VALIDATOR == 2
+            // OMNI_CHARGING_CONTROL_LIMIT_VALIDATOR == 3 +++InclusiveIntegerRangeValidator
+            // OMNI_CHARGING_CONTROL_MODE_VALIDATOR == 4
+            // OMNI_CHARGING_CONTROL_TIME_VALIDATOR == 5 ---InclusiveIntegerRangeValidator
+            for (String key : omniValidators.keySet()) {
+                Integer validatorId = omniValidators.get(key);
+                if (validatorId == 0) {
+                    validators.put(key, SettingsValidators.BOOLEAN_VALIDATOR);
+                } else if (validatorId == 1) {
+                    validators.put(key, SettingsValidators.ANY_INTEGER_VALIDATOR);
+                } else if (validatorId == 2) {
+                    validators.put(key, SettingsValidators.ANY_STRING_VALIDATOR);
+                } else if (validatorId == 3) {
+                    validators.put(key, SettingsValidators.OMNI_CHARGING_CONTROL_LIMIT_VALIDATOR);
+                } else if (validatorId == 4) {
+                    validators.put(key, SettingsValidators.OMNI_CHARGING_CONTROL_MODE_VALIDATOR);
+                } else if (validatorId == 5) {
+                    validators.put(key, SettingsValidators.OMNI_CHARGING_CONTROL_TIME_VALIDATOR);
+                }
+            }
         } else if (contentUri.equals(Settings.Global.CONTENT_URI)) {
             allowlist = ArrayUtils.concat(String.class, getGlobalSettingsToBackup(),
                     Settings.Global.LEGACY_RESTORE_SETTINGS);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index ea8ae7b..2b93f16 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -207,6 +207,7 @@
             } else if (isAlreadyConfiguredCriticalAccessibilitySetting(name)) {
                 return;
             } else if (Settings.System.RINGTONE.equals(name)
+                    || Settings.System.RINGTONE2.equals(name)
                     || Settings.System.NOTIFICATION_SOUND.equals(name)
                     || Settings.System.ALARM_ALERT.equals(name)) {
                 setRingtone(name, value);
@@ -291,11 +292,12 @@
 
     public String onBackupValue(String name, String value) {
         // Special processing for backing up ringtones & notification sounds
-        if (Settings.System.RINGTONE.equals(name)
+        if (Settings.System.RINGTONE.equals(name) || Settings.System.RINGTONE2.equals(name)
                 || Settings.System.NOTIFICATION_SOUND.equals(name)
                 || Settings.System.ALARM_ALERT.equals(name)) {
             if (value == null) {
-                if (Settings.System.RINGTONE.equals(name)) {
+                if (Settings.System.RINGTONE.equals(name)
+                        || Settings.System.RINGTONE2.equals(name)) {
                     // For ringtones, we need to distinguish between non-telephony vs telephony
                     if (mTelephonyManager != null && mTelephonyManager.isVoiceCapable()) {
                         // Backup a null ringtone as silent on voice-capable devices
@@ -352,7 +354,7 @@
     /**
      * Sets the ringtone of type specified by the name.
      *
-     * @param name should be Settings.System.RINGTONE, Settings.System.NOTIFICATION_SOUND
+     * @param name should be Settings.System.RINGTONE, Settings.System.RINGTONE2, Settings.System.NOTIFICATION_SOUND
      * or Settings.System.ALARM_ALERT.
      * @param value can be a canonicalized uri or "_silent" to indicate a silent (null) ringtone.
      */
@@ -397,6 +399,8 @@
         switch (name) {
             case Settings.System.RINGTONE:
                 return RingtoneManager.TYPE_RINGTONE;
+            case Settings.System.RINGTONE2:
+                return RingtoneManager.TYPE_RINGTONE;
             case Settings.System.NOTIFICATION_SOUND:
                 return RingtoneManager.TYPE_NOTIFICATION;
             case Settings.System.ALARM_ALERT:
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 37eda3e..c6e8ac1 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -2934,8 +2934,14 @@
                 Settings.System.RINGTONE,
                 SystemSettingsProto.Ringtone.DEFAULT_URI);
         dumpSetting(s, p,
+                Settings.System.RINGTONE2,
+                SystemSettingsProto.Ringtone.DEFAULT_URI);
+        dumpSetting(s, p,
                 Settings.System.RINGTONE_CACHE,
                 SystemSettingsProto.Ringtone.CACHE);
+        dumpSetting(s, p,
+                Settings.System.RINGTONE2_CACHE,
+                SystemSettingsProto.Ringtone.CACHE);
         p.end(ringtoneToken);
 
         final long rotationToken = p.start(SystemSettingsProto.ROTATION);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 6128d45..b60e18c 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -821,6 +821,8 @@
         final String cacheRingtoneSetting;
         if (Settings.System.RINGTONE_CACHE_URI.equals(uri)) {
             cacheRingtoneSetting = Settings.System.RINGTONE;
+        } else if (Settings.System.RINGTONE2_CACHE_URI.equals(uri)) {
+            cacheRingtoneSetting = Settings.System.RINGTONE2;
         } else if (Settings.System.NOTIFICATION_SOUND_CACHE_URI.equals(uri)) {
             cacheRingtoneSetting = Settings.System.NOTIFICATION_SOUND;
         } else if (Settings.System.ALARM_ALERT_CACHE_URI.equals(uri)) {
@@ -838,6 +840,8 @@
     private String getCacheName(String setting) {
         if (Settings.System.RINGTONE.equals(setting)) {
             return Settings.System.RINGTONE_CACHE;
+        } else if (Settings.System.RINGTONE2.equals(setting)) {
+            return Settings.System.RINGTONE2_CACHE;
         } else if (Settings.System.NOTIFICATION_SOUND.equals(setting)) {
             return Settings.System.NOTIFICATION_SOUND_CACHE;
         } else if (Settings.System.ALARM_ALERT.equals(setting)) {
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 3d250fd..ec18a77 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -512,6 +512,7 @@
         "androidx.activity_activity-compose",
         "androidx.compose.animation_animation-graphics",
         "androidx.lifecycle_lifecycle-viewmodel-compose",
+        "OmniLib",
     ],
     libs: [
         "keepanno-annotations",
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 11cb070..a3eaeb3 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -394,6 +394,9 @@
     <protected-broadcast android:name="com.android.systemui.action.ACTION_LAUNCH_MEDIA_OUTPUT_BROADCAST_DIALOG" />
     <protected-broadcast android:name="com.android.systemui.STARTED" />
 
+    <!-- OmniJaws -->
+    <uses-permission android:name="org.omnirom.omnijaws.READ_WEATHER" />
+
     <application
         android:name=".SystemUIApplication"
         android:persistent="true"
@@ -572,6 +575,10 @@
             </intent-filter>
         </activity-alias>
 
+        <!-- Callback for deleting screenshot notification -->
+        <receiver android:name=".screenshot.DeleteScreenshotReceiver"
+            android:exported="false" />
+
         <!-- Callback for invoking a smart action from the screenshot notification. -->
         <receiver android:name=".screenshot.SmartActionsReceiver"
                   android:exported="false"/>
@@ -1154,5 +1161,9 @@
             android:exported="false"
             />
 
+        <!-- omni additions start -->
+        <service android:name=".omni.CPUInfoService"
+                android:exported="false" />
+
     </application>
 </manifest>
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
index ad9eba8..2079bf4 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
@@ -18,6 +18,7 @@
 import android.graphics.Color
 import android.graphics.Rect
 import android.icu.text.NumberFormat
+import android.provider.Settings.System
 import android.util.TypedValue
 import android.view.LayoutInflater
 import android.view.View
@@ -40,6 +41,7 @@
 import com.android.systemui.plugins.clocks.ThemeConfig
 import com.android.systemui.plugins.clocks.WeatherData
 import com.android.systemui.plugins.clocks.ZenData
+import org.omnirom.omnilib.utils.OmniSettings
 import java.io.PrintWriter
 import java.util.Locale
 import java.util.TimeZone
@@ -146,12 +148,21 @@
                 override fun onThemeChanged(theme: ThemeConfig) {
                     this@DefaultClockFaceController.theme = theme
 
+                    val coloredClock = System.getInt(ctx.getContentResolver(),
+                        OmniSettings.OMNI_LOCKSCREEN_CLOCK_COLORED, 1) != 0
                     val color =
                         when {
                             theme.seedColor != null -> theme.seedColor!!
                             theme.isDarkTheme ->
-                                resources.getColor(android.R.color.system_accent1_100)
-                            else -> resources.getColor(android.R.color.system_accent2_600)
+                                if (coloredClock)
+                                    resources.getColor(android.R.color.system_accent1_100)
+                                else
+                                    resources.getColor(com.android.internal.R.color.primary_text_material_dark)
+                            else ->
+                                if (coloredClock)
+                                    resources.getColor(android.R.color.system_accent2_600)
+                                else
+                                    resources.getColor(com.android.internal.R.color.primary_text_material_light)
                         }
 
                     if (currentColor == color) {
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/GlobalActions.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/GlobalActions.java
index 95ff13b..7775551 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/GlobalActions.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/GlobalActions.java
@@ -26,7 +26,7 @@
     int VERSION = 1;
 
     void showGlobalActions(GlobalActionsManager manager);
-    default void showShutdownUi(boolean isReboot, String reason) {
+    default void showShutdownUi(boolean isReboot, String reason, boolean rebootCustom) {
     }
 
     default void destroy() {
@@ -40,6 +40,6 @@
         void onGlobalActionsHidden();
 
         void shutdown();
-        void reboot(boolean safeMode);
+        void reboot(boolean safeMode, String reason);
     }
 }
diff --git a/packages/SystemUI/res-keyguard/drawable/ic_access_alarms_big_dim.xml b/packages/SystemUI/res-keyguard/drawable/ic_access_alarms_big_dim.xml
new file mode 100644
index 0000000..eaada7a
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/ic_access_alarms_big_dim.xml
@@ -0,0 +1,25 @@
+<!--
+Copyright (C) 2017 The Android Open Source 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="18dp"
+    android:height="18dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0">
+    <path
+        android:fillColor="@android:color/white"
+        android:fillAlpha="0.3"
+        android:pathData="M21.35,6.49c-0.35,0.42 -0.98,0.47 -1.4,0.12l-3.07,-2.57a1,1 0,1 1,1.29 -1.53l3.07,2.57c0.42,0.35 0.47,0.98 0.11,1.41zM7.24,2.63a1,1 0,0 0,-1.41 -0.13L2.77,5.07A0.996,0.996 0,1 0,4.05 6.6l3.06,-2.57c0.43,-0.35 0.48,-0.98 0.13,-1.4zM11.75,8c-0.41,0 -0.75,0.34 -0.75,0.75v4.68c0,0.35 0.18,0.68 0.49,0.86l3.65,2.19c0.34,0.2 0.78,0.1 0.98,-0.24a0.71,0.71 0,0 0,-0.25 -0.99l-3.37,-2v-4.5c0,-0.41 -0.34,-0.75 -0.75,-0.75zM12,5.9c-3.91,0 -7.1,3.18 -7.1,7.1s3.19,7.1 7.1,7.1 7.1,-3.18 7.1,-7.1 -3.19,-7.1 -7.1,-7.1M12,4a9,9 0,1 1,-0.001 18.001A9,9 0,0 1,12 4z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable-nodpi/udfps_icon_pressed.png b/packages/SystemUI/res/drawable-nodpi/udfps_icon_pressed.png
new file mode 100644
index 0000000..4102e28
--- /dev/null
+++ b/packages/SystemUI/res/drawable-nodpi/udfps_icon_pressed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/brightness_progress_drawable.xml b/packages/SystemUI/res/drawable/brightness_progress_drawable.xml
index ec15b10..31643e2 100644
--- a/packages/SystemUI/res/drawable/brightness_progress_drawable.xml
+++ b/packages/SystemUI/res/drawable/brightness_progress_drawable.xml
@@ -19,15 +19,11 @@
             android:paddingMode="stack" >
     <item android:id="@android:id/background"
         android:gravity="center_vertical|fill_horizontal">
-        <inset
-            android:insetLeft="@dimen/rounded_slider_track_inset"
-            android:insetRight="@dimen/rounded_slider_track_inset" >
-            <shape>
-                <size android:height="@dimen/rounded_slider_track_width" />
-                <corners android:radius="@dimen/rounded_slider_track_corner_radius" />
-                <solid android:color="?androidprv:attr/customColorShadeInactive" />
-            </shape>
-        </inset>
+        <shape>
+             <size android:height="@dimen/rounded_slider_track_width" />
+             <corners android:radius="@dimen/rounded_slider_track_corner_radius" />
+             <solid android:color="?androidprv:attr/customColorShadeInactive" />
+        </shape>
     </item>
     <item android:id="@android:id/progress"
           android:gravity="center_vertical|fill_horizontal">
diff --git a/packages/SystemUI/res/drawable/brightness_progress_full_drawable.xml b/packages/SystemUI/res/drawable/brightness_progress_full_drawable.xml
index a9e7adf..03b470a 100644
--- a/packages/SystemUI/res/drawable/brightness_progress_full_drawable.xml
+++ b/packages/SystemUI/res/drawable/brightness_progress_full_drawable.xml
@@ -19,11 +19,11 @@
     xmlns:priv-android="http://schemas.android.com/apk/prv/res/android"
     android:autoMirrored="true">
     <item android:id="@+id/slider_foreground"
-        android:height="@dimen/rounded_slider_height">
+        android:gravity="center_vertical|fill_horizontal">
         <shape>
-            <size android:height="@dimen/rounded_slider_height" />
+            <size android:height="@dimen/rounded_slider_progress_width" />
             <solid android:color="?attr/shadeActive" />
-            <corners android:radius="@dimen/rounded_slider_corner_radius"/>
+            <corners android:radius="@dimen/rounded_slider_progress_corner_radius"/>
         </shape>
     </item>
     <item>
@@ -33,15 +33,4 @@
             <solid android:color="@color/brightness_slider_overlay_color" />
         </shape>
     </item>
-    <item
-        android:id="@+id/slider_icon"
-        android:gravity="center_vertical|right"
-        android:height="@dimen/rounded_slider_icon_size"
-        android:width="@dimen/rounded_slider_icon_size"
-        android:right="@dimen/rounded_slider_icon_inset">
-        <com.android.systemui.util.AlphaTintDrawableWrapper
-            android:drawable="@drawable/ic_brightness"
-            android:tint="?attr/onShadeActive"
-        />
-    </item>
 </layer-list>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/brightness_progress_thumb.xml b/packages/SystemUI/res/drawable/brightness_progress_thumb.xml
new file mode 100644
index 0000000..0e37987
--- /dev/null
+++ b/packages/SystemUI/res/drawable/brightness_progress_thumb.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2020 The Android Open Source 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.
+  -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:priv-android="http://schemas.android.com/apk/prv/res/android"
+    android:autoMirrored="true">
+    <item
+        android:width="@dimen/rounded_slider_height"
+        android:height="@dimen/rounded_slider_height">
+        <shape>
+            <size android:height="@dimen/rounded_slider_height" />
+            <solid android:color="?priv-android:attr/colorAccentPrimary" />
+            <corners android:radius="@dimen/rounded_slider_corner_radius" />
+        </shape>
+    </item>
+    <item
+        android:id="@+id/slider_icon"
+        android:width="@dimen/rounded_slider_icon_size"
+        android:height="@dimen/rounded_slider_icon_size"
+        android:gravity="center">
+        <com.android.systemui.util.AlphaTintDrawableWrapper
+            android:drawable="@drawable/ic_brightness"
+            android:tint="?android:attr/textColorPrimaryInverse" />
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_navbar_chevron_left.xml b/packages/SystemUI/res/drawable/ic_navbar_chevron_left.xml
new file mode 100644
index 0000000..c6329f0
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_navbar_chevron_left.xml
@@ -0,0 +1,24 @@
+<!--
+  ~ Copyright (C) 2014 The Android Open Source 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:height="24dp"
+        android:width="24dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24">
+    <path
+        android:fillColor="?attr/singleToneColor"
+        android:pathData="M15.41,16.58L10.83,12L15.41,7.41L14,6L8,12L14,18L15.41,16.58Z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_navbar_chevron_right.xml b/packages/SystemUI/res/drawable/ic_navbar_chevron_right.xml
new file mode 100644
index 0000000..86d20cb
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_navbar_chevron_right.xml
@@ -0,0 +1,24 @@
+<!--
+  ~ Copyright (C) 2014 The Android Open Source 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:height="24dp"
+        android:width="24dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24">
+    <path
+        android:fillColor="?attr/singleToneColor"
+        android:pathData="M8.59,16.58L13.17,12L8.59,7.41L10,6L16,12L10,18L8.59,16.58Z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_aod.xml b/packages/SystemUI/res/drawable/ic_qs_aod.xml
new file mode 100644
index 0000000..4bb2d4a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_aod.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="#ffffff"
+        android:pathData="M17,19 L17,5 L7,5 L7,19 L17,19 M17,1 C18.1046,1,19,1.89543,19,3 L19,21 C19,22.1046,18.1046,23,17,23 L7,23 C5.89,23,5,22.1,5,21 L5,3 C5,1.89,5.89,1,7,1 L17,1 M9,7 L15,7 L15,9 L9,9 L9,7" />
+</vector>
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 0000000..2c3ba97
--- /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/drawable/ic_qs_data_switch_0.xml b/packages/SystemUI/res/drawable/ic_qs_data_switch_0.xml
new file mode 100644
index 0000000..81b58ab
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_data_switch_0.xml
@@ -0,0 +1,4 @@
+<vector android:height="48dp" android:viewportHeight="24"
+    android:viewportWidth="24" android:width="48dp" xmlns:android="http://schemas.android.com/apk/res/android">
+    <path android:fillColor="#ffffffff" android:pathData="M19.99,4c0,-1.1 -0.89,-2 -1.99,-2h-7.17c-0.53,0 -1.04,0.21 -1.42,0.59L4.59,7.41C4.21,7.79 4,8.3 4,8.83L4,20c0,1.1 0.9,2 2,2h12.01c1.1,0 1.99,-0.9 1.99,-2l-0.01,-16zM8,19c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1zM16,19c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1zM8,15c-0.55,0 -1,-0.45 -1,-1v-2c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v2c0,0.55 -0.45,1 -1,1zM12,19c-0.55,0 -1,-0.45 -1,-1v-2c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v2c0,0.55 -0.45,1 -1,1zM12,13c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1 1,0.45 1,1 -0.45,1 -1,1zM16,15c-0.55,0 -1,-0.45 -1,-1v-2c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v2c0,0.55 -0.45,1 -1,1z" android:strokeColor="#00000000"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_data_switch_1.xml b/packages/SystemUI/res/drawable/ic_qs_data_switch_1.xml
new file mode 100644
index 0000000..1747678
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_data_switch_1.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:aapt="http://schemas.android.com/aapt" android:height="48dp" android:width="48dp" android:viewportWidth="72" android:viewportHeight="72">
+    <path android:fillColor="#ffffffff" android:pathData="m36,66 l-18,0c-3.3,0 -6,-2.7 -6,-6L12,24 30,6 54,6c3.3,0 5.97,2.7 5.97,6l0.02,33 -20.99,0C37.35,45 36,46.34 36,47.99zM42,28 L48,35 54,28zM54,19 L48,12 42,19zM51.32,66 L47.36,66 47.36,53.39 43.47,54.53 43.47,51.53 50.96,48.94 51.32,48.94z" android:strokeColor="#00000000"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_data_switch_2.xml b/packages/SystemUI/res/drawable/ic_qs_data_switch_2.xml
new file mode 100644
index 0000000..438fc94
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_data_switch_2.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:aapt="http://schemas.android.com/aapt" android:height="48dp" android:width="48dp" android:viewportWidth="72" android:viewportHeight="72">
+    <path android:fillColor="#ffffffff" android:pathData="m36,66 l-18,0c-3.3,0 -6,-2.7 -6,-6L12,24 30,6 54,6c3.3,0 5.97,2.7 5.97,6l0.02,33 -20.99,0C37.35,45 36,46.34 36,47.99zM42,28 L48,35 54,28zM48,12 L42,19 54,19zM54.48,66 L42.57,66 42.57,63.42 48.06,57.66c0.73,-0.83 1.25,-1.54 1.56,-2.13 0.31,-0.59 0.47,-1.1 0.47,-1.54 0,-0.73 -0.16,-1.29 -0.48,-1.68 -0.32,-0.38 -0.79,-0.57 -1.39,-0.57 -0.3,0 -0.58,0.07 -0.83,0.21 -0.25,0.14 -0.46,0.33 -0.64,0.57 -0.18,0.24 -0.31,0.53 -0.41,0.85 -0.1,0.32 -0.15,0.68 -0.15,1.06l-3.96,0c0,-0.78 0.15,-1.52 0.44,-2.21 0.29,-0.7 0.71,-1.3 1.24,-1.83 0.54,-0.52 1.18,-0.94 1.92,-1.24 0.75,-0.3 1.57,-0.45 2.48,-0.45 0.95,0 1.78,0.11 2.49,0.33 0.71,0.22 1.31,0.54 1.8,0.97 0.48,0.42 0.85,0.94 1.1,1.55 0.25,0.61 0.37,1.31 0.37,2.09 0,0.59 -0.09,1.16 -0.28,1.71 -0.19,0.54 -0.46,1.08 -0.81,1.62 -0.35,0.54 -0.78,1.09 -1.29,1.65 -0.51,0.56 -1.08,1.16 -1.71,1.79l-2.2,2.54 6.71,0z" android:strokeColor="#00000000"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_restart_bootloader.xml b/packages/SystemUI/res/drawable/ic_restart_bootloader.xml
new file mode 100644
index 0000000..6029f4f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_restart_bootloader.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24.0dp"
+    android:height="24.0dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0"
+    android:tint="?android:attr/colorControlNormal" >
+
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M12.6329,4.07972 C17.2364,4.07972,20.9658,7.82577,20.9658,12.4043
+C20.9658,16.9828,17.2364,20.7288,12.6329,20.7288
+C9.71098,20.7288,7.15535,19.2137,5.66525,16.9245 L6.98053,15.8839
+C8.15429,17.7902,10.2438,19.0639,12.6412,19.0639
+C16.3192,19.0639,19.3008,16.0823,19.3008,12.4043
+C19.3008,8.72628,16.3192,5.74466,12.6412,5.74466
+C9.24478,5.74466,6.44774,8.29197,6.03983,11.5718 L8.33741,11.5718
+L5.22403,14.6769 L2.11897,11.5718 L4.35827,11.5718
+C4.77451,7.36791,8.32077,4.07972,12.6329,4.07972 M15.097,10.9391
+C15.5132,10.9474,15.8545,11.2804,15.8545,11.705 L15.8545,15.5426
+C15.8545,15.9588,15.5132,16.3085,15.0886,16.3085 L10.4851,16.3085
+C10.0605,16.3085,9.71924,15.9589,9.71924,15.5426 L9.71924,11.705
+C9.71924,11.2804,10.0605,10.9475,10.4768,10.9391 M10.4768,10.9391
+L10.4768,10.0983 M10.4768,10.0983 C10.4768,8.82464,11.5174,7.7924,12.7827,7.7924
+C14.0564,7.7924,15.0969,8.82464,15.0969,10.0983 M15.0969,10.0983
+L15.0969,10.9391 M11.6422,10.0983 L11.6422,10.9391 M11.6422,10.9391
+L13.9315,10.9391 M13.9315,10.9391 L13.9315,10.0983 M13.9315,10.0983
+C13.9315,9.46563,13.4154,8.95784,12.7827,8.95784
+C12.1584,8.95784,11.6422,9.46564,11.6422,10.0983" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_restart_fastboot.xml b/packages/SystemUI/res/drawable/ic_restart_fastboot.xml
new file mode 100644
index 0000000..495c618
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_restart_fastboot.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:width="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24"
+    android:tint="?android:attr/colorControlNormal" >
+
+    <path android:fillColor="#000" android:pathData="M18,18.5A1.5,1.5 0 0,0 19.5,17A1.5,1.5 0 0,0 18,15.5A1.5,1.5 0 0,0 16.5,17A1.5,1.5 0 0,0 18,18.5M19.5,9.5H17V12H21.46L19.5,9.5M6,18.5A1.5,1.5 0 0,0 7.5,17A1.5,1.5 0 0,0 6,15.5A1.5,1.5 0 0,0 4.5,17A1.5,1.5 0 0,0 6,18.5M20,8L23,12V17H21A3,3 0 0,1 18,20A3,3 0 0,1 15,17H9A3,3 0 0,1 6,20A3,3 0 0,1 3,17H1V6C1,4.89 1.89,4 3,4H17V8H20M8,6V9H5V11H8V14H10V11H13V9H10V6H8Z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_restart_recovery.xml b/packages/SystemUI/res/drawable/ic_restart_recovery.xml
new file mode 100644
index 0000000..ee3cd17
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_restart_recovery.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24.0dp"
+    android:height="24.0dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0"
+    android:tint="?android:attr/colorControlNormal" >
+
+    <path
+        android:fillColor="#FF000000"
+        android:strokeWidth="1"
+        android:pathData="M12.6123,18.971 L12.6123,17.1438 L13.7308,17.1438
+C14.346,17.1438,14.8925,17.1274,14.9453,17.1073
+C14.9981,17.0872,15.0414,17.0192,15.0414,16.9561
+C15.0414,16.893,13.9977,15.529,12.722,13.9249
+C10.7629,11.4614,10.3813,11.0111,10.2655,11.0263
+C10.1642,11.0395,9.56144,11.783,7.96108,13.8686
+C5.49619,17.0809,5.60376,16.9327,5.65048,17.0531
+C5.68017,17.1297,5.87403,17.1437,6.90206,17.1437 L8.11851,17.1437
+L8.11851,18.5259 C8.11851,19.2861,8.10278,19.9081,8.08356,19.9081
+C8.01872,19.9081,7.18025,19.4101,6.78251,19.1353
+C6.20418,18.7359,5.04692,17.5583,4.64819,16.9635
+C3.95753,15.9333,3.51884,14.8937,3.25353,13.6583
+C3.05947,12.7547,3.05947,11.1966,3.25353,10.293
+C3.64609,8.46515,4.42025,7.04017,5.7189,5.75504
+C7.0163,4.47116,8.49362,3.68495,10.2838,3.32565
+C10.6231,3.25757,11.0125,3.20186,11.1492,3.20186 L11.3977,3.20186
+L11.3977,5.0335 L11.3977,6.86514 L10.168,6.88141
+C8.98219,6.8971,8.93839,6.90198,8.94149,7.01811
+C8.94599,7.18646,13.5756,12.9973,13.7053,12.9973
+C13.8372,12.9973,18.3206,7.16517,18.3206,6.9936
+C18.3206,6.87365,18.2856,6.86968,17.0909,6.85388 L15.8612,6.83761
+L15.8449,5.44041 C15.8359,4.67195,15.8437,4.04321,15.8621,4.04321
+C15.8805,4.04321,16.0382,4.11436,16.2124,4.20132
+C16.8508,4.51994,17.6363,5.10703,18.2911,5.75507
+C19.5898,7.04019,20.3639,8.46518,20.7565,10.293
+C20.8673,10.8087,20.892,11.1162,20.892,11.9756
+C20.892,12.8351,20.8672,13.1426,20.7565,13.6582
+C20.3585,15.5114,19.6077,16.8933,18.2911,18.1962
+C16.7779,19.6937,15.0196,20.5282,12.8703,20.7691 L12.6122,20.798
+L12.6122,18.9708 Z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/qs_customize_tile_decoration.xml b/packages/SystemUI/res/drawable/qs_customize_tile_decoration.xml
index d7a9edc..45efa41 100644
--- a/packages/SystemUI/res/drawable/qs_customize_tile_decoration.xml
+++ b/packages/SystemUI/res/drawable/qs_customize_tile_decoration.xml
@@ -15,6 +15,6 @@
 -->
 <shape xmlns:android="http://schemas.android.com/apk/res/android">
     <solid android:color="?android:attr/colorBackground"/>
-    <corners android:topLeftRadius="20dp"
-             android:topRightRadius="20dp" />
+    <corners android:topLeftRadius="?android:attr/dialogCornerRadius"
+             android:topRightRadius="?android:attr/dialogCornerRadius" />
 </shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/volume_row_seekbar.xml b/packages/SystemUI/res/drawable/volume_row_seekbar.xml
index d7d75d4..b0c8189 100644
--- a/packages/SystemUI/res/drawable/volume_row_seekbar.xml
+++ b/packages/SystemUI/res/drawable/volume_row_seekbar.xml
@@ -23,11 +23,15 @@
     <!-- The groove used for indicating max volume !-->
     <item android:id="@android:id/background"
         android:gravity="center_vertical|fill_horizontal">
-        <shape>
-            <size android:height="@dimen/volume_dialog_track_width" />
-            <corners android:radius="@dimen/volume_dialog_panel_width_half" />
-            <solid android:color="?androidprv:attr/materialColorOutlineVariant" />
-        </shape>
+        <inset
+            android:insetLeft="@dimen/rounded_slider_track_negative_inset"
+            android:insetRight="@dimen/rounded_slider_track_negative_inset" >
+            <shape>
+                <size android:height="@dimen/volume_dialog_track_width" />
+                <corners android:radius="@dimen/volume_dialog_panel_width_half" />
+                <solid android:color="?androidprv:attr/materialColorOutlineVariant" />
+            </shape>
+        </inset>
     </item>
     <item android:id="@android:id/progress"
         android:gravity="center_vertical|fill_horizontal">
diff --git a/packages/SystemUI/res/drawable/volume_row_seekbar_progress.xml b/packages/SystemUI/res/drawable/volume_row_seekbar_progress.xml
index fa06bd6..3cef748 100644
--- a/packages/SystemUI/res/drawable/volume_row_seekbar_progress.xml
+++ b/packages/SystemUI/res/drawable/volume_row_seekbar_progress.xml
@@ -22,24 +22,9 @@
     android:autoMirrored="true">
     <item android:id="@+id/volume_seekbar_progress_solid">
         <shape>
-            <size android:height="@dimen/volume_dialog_slider_width_legacy" />
+            <size android:height="@dimen/volume_seekbar_progress_width" />
             <solid android:color="?android:attr/colorAccent" />
-            <corners android:radius="@dimen/volume_dialog_slider_corner_radius"/>
+            <corners android:radius="@dimen/volume_seekbar_progress_corner_radius"/>
         </shape>
     </item>
-    <item
-        android:id="@+id/volume_seekbar_progress_icon"
-        android:gravity="center_vertical|right"
-        android:height="@dimen/rounded_slider_icon_size"
-        android:width="@dimen/rounded_slider_icon_size"
-        android:right="@dimen/volume_slider_icon_inset">
-        <rotate
-            android:fromDegrees="-270"
-            android:toDegrees="-270">
-            <!-- A placeholder drawable is required here - it'll be replaced in code. -->
-            <com.android.systemui.util.AlphaTintDrawableWrapper
-                android:drawable="@drawable/ic_volume_media"
-                android:tint="?androidprv:attr/colorAccentPrimaryVariant" />
-        </rotate>
-    </item>
 </layer-list>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/volume_row_seekbar_thumb.xml b/packages/SystemUI/res/drawable/volume_row_seekbar_thumb.xml
new file mode 100644
index 0000000..2abd3f4
--- /dev/null
+++ b/packages/SystemUI/res/drawable/volume_row_seekbar_thumb.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2021 The Android Open Source 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.
+  -->
+
+<!-- Progress drawable for volume row SeekBars. This is the accent-colored round rect that moves up
+     and down as the progress value changes. -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    android:autoMirrored="true">
+    <item
+        android:width="@dimen/volume_dialog_slider_width"
+        android:height="@dimen/volume_dialog_slider_width">
+        <shape>
+            <size android:height="@dimen/volume_dialog_slider_width" />
+            <solid android:color="?android:attr/colorAccent" />
+            <corners android:radius="@dimen/volume_dialog_slider_corner_radius"/>
+        </shape>
+    </item>
+    <item
+        android:id="@+id/volume_seekbar_progress_icon"
+        android:height="@dimen/rounded_slider_icon_size"
+        android:width="@dimen/rounded_slider_icon_size"
+        android:gravity="center">
+        <rotate
+            android:fromDegrees="-270"
+            android:toDegrees="-270">
+            <!-- A placeholder drawable is required here - it'll be replaced in code. -->
+            <com.android.systemui.util.AlphaTintDrawableWrapper
+                android:drawable="@drawable/ic_volume_media"
+                android:tint="?androidprv:attr/colorAccentPrimaryVariant" />
+        </rotate>
+    </item>
+</layer-list>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/global_actions_grid_item_lite.xml b/packages/SystemUI/res/layout/global_actions_grid_item_lite.xml
index e1ee06d..ccf629f 100644
--- a/packages/SystemUI/res/layout/global_actions_grid_item_lite.xml
+++ b/packages/SystemUI/res/layout/global_actions_grid_item_lite.xml
@@ -29,7 +29,7 @@
             android:layout_marginBottom="@dimen/global_actions_grid_container_bottom_margin"
             android:padding="@dimen/global_actions_button_padding"
             android:scaleType="centerInside"
-            android:tint="@color/global_actions_lite_text"
+            android:tint="@color/global_actions_lite_icon"
             android:background="@drawable/global_actions_lite_button"/>
         <TextView
             android:id="@*android:id/message"
diff --git a/packages/SystemUI/res/layout/home_handle.xml b/packages/SystemUI/res/layout/home_handle.xml
index c9d3f98..b7fb374 100644
--- a/packages/SystemUI/res/layout/home_handle.xml
+++ b/packages/SystemUI/res/layout/home_handle.xml
@@ -19,8 +19,9 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/home_handle"
     android:layout_width="@dimen/navigation_home_handle_width"
-    android:layout_height="match_parent"
+    android:layout_height="@dimen/navigation_home_handle_height"
     android:layout_weight="0"
+    android:layout_gravity="bottom"
     android:contentDescription="@string/accessibility_home"
     android:paddingStart="@dimen/navigation_key_padding"
     android:paddingEnd="@dimen/navigation_key_padding"
diff --git a/packages/SystemUI/res/layout/home_handle_small.xml b/packages/SystemUI/res/layout/home_handle_small.xml
new file mode 100644
index 0000000..d9fc55a
--- /dev/null
+++ b/packages/SystemUI/res/layout/home_handle_small.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2019 The Android Open Source 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.
+  -->
+
+<com.android.systemui.navigationbar.gestural.NavigationHandle
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/home_handle"
+    android:layout_width="@dimen/navigation_home_handle_small_width"
+    android:layout_height="@dimen/navigation_home_handle_height"
+    android:layout_weight="0"
+    android:layout_gravity="bottom"
+    android:contentDescription="@string/accessibility_home"
+    android:paddingStart="@dimen/navigation_key_padding"
+    android:paddingEnd="@dimen/navigation_key_padding"
+    />
+
diff --git a/packages/SystemUI/res/layout/nav_buttons_dpad_group.xml b/packages/SystemUI/res/layout/nav_buttons_dpad_group.xml
new file mode 100644
index 0000000..6afc9de
--- /dev/null
+++ b/packages/SystemUI/res/layout/nav_buttons_dpad_group.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The CyanogenMod 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.
+-->
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/dpad_group"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:clipChildren="false">
+
+        <com.android.systemui.navigationbar.views.buttons.KeyButtonView
+            android:id="@+id/dpad_left"
+            android:layout_width="@dimen/navigation_extra_key_width"
+            android:layout_height="match_parent"
+            android:layout_alignParentLeft="true"
+            systemui:keyCode="21"
+            android:visibility="gone"
+            android:scaleType="center"
+            android:contentDescription="@string/accessibility_dpad_left" />
+
+        <com.android.systemui.navigationbar.views.buttons.KeyButtonView
+            android:id="@+id/dpad_right"
+            android:layout_width="@dimen/navigation_extra_key_width"
+            android:layout_height="match_parent"
+            android:layout_alignParentRight="true"
+            systemui:keyCode="22"
+            android:visibility="gone"
+            android:scaleType="center"
+            android:contentDescription="@string/accessibility_dpad_right" />
+
+</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/nav_buttons_dpad_group_vertical.xml b/packages/SystemUI/res/layout/nav_buttons_dpad_group_vertical.xml
new file mode 100644
index 0000000..7139368
--- /dev/null
+++ b/packages/SystemUI/res/layout/nav_buttons_dpad_group_vertical.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The CyanogenMod 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.
+-->
+<RelativeLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/dpad_group"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:clipChildren="false">
+
+        <com.android.systemui.navigationbar.views.buttons.KeyButtonView
+            android:id="@+id/dpad_left"
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/navigation_extra_key_width"
+            android:layout_alignParentTop="true"
+            systemui:keyCode="21"
+            android:visibility="gone"
+            android:scaleType="center"
+            android:contentDescription="@string/accessibility_dpad_left" />
+
+        <com.android.systemui.navigationbar.views.buttons.KeyButtonView
+            android:id="@+id/dpad_right"
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/navigation_extra_key_width"
+            android:layout_alignParentBottom="true"
+            systemui:keyCode="22"
+            android:visibility="gone"
+            android:scaleType="center"
+            android:contentDescription="@string/accessibility_dpad_right" />
+
+</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/navigation_layout.xml b/packages/SystemUI/res/layout/navigation_layout.xml
index 5c6c9a4..fb79645 100644
--- a/packages/SystemUI/res/layout/navigation_layout.xml
+++ b/packages/SystemUI/res/layout/navigation_layout.xml
@@ -53,6 +53,8 @@
             android:clipToPadding="false"
             android:clipChildren="false" />
 
+        <include layout="@layout/nav_buttons_dpad_group" />
+
     </com.android.systemui.navigationbar.views.buttons.NearestTouchFrame>
 
 </FrameLayout>
diff --git a/packages/SystemUI/res/layout/navigation_layout_vertical.xml b/packages/SystemUI/res/layout/navigation_layout_vertical.xml
index c64e3f7..773de3c 100644
--- a/packages/SystemUI/res/layout/navigation_layout_vertical.xml
+++ b/packages/SystemUI/res/layout/navigation_layout_vertical.xml
@@ -50,6 +50,8 @@
             android:clipToPadding="false"
             android:clipChildren="false" />
 
+        <include layout="@layout/nav_buttons_dpad_group_vertical" />
+
     </com.android.systemui.navigationbar.views.buttons.NearestTouchFrame>
 
 </FrameLayout>
diff --git a/packages/SystemUI/res/layout/qs_tile_label_vertical.xml b/packages/SystemUI/res/layout/qs_tile_label_vertical.xml
new file mode 100644
index 0000000..de2eae3
--- /dev/null
+++ b/packages/SystemUI/res/layout/qs_tile_label_vertical.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    Copyright (C) 2021 The Android Open Source 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.
+-->
+<com.android.systemui.qs.tileimpl.IgnorableChildLinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:clipChildren="false"
+    android:clipToPadding="false"
+    android:orientation="vertical"
+    android:layout_gravity="center_horizontal">
+
+    <TextView
+        android:id="@+id/tile_label"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1"
+        android:gravity="center"
+        android:textDirection="locale"
+        android:ellipsize="marquee"
+        android:marqueeRepeatLimit="1"
+        android:singleLine="true"
+        android:textAppearance="@style/TextAppearance.QS.TileLabel"/>
+
+    <TextView
+        android:id="@+id/app_label"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center_horizontal"
+        android:textDirection="locale"
+        android:ellipsize="marquee"
+        android:marqueeRepeatLimit="1"
+        android:singleLine="true"
+        android:visibility="gone"
+        android:textAppearance="@style/TextAppearance.QS.TileLabel.Secondary"
+        android:textColor="?attr/onShadeInactive"/>
+
+</com.android.systemui.qs.tileimpl.IgnorableChildLinearLayout>
diff --git a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
index 62ceb07..571b5a9 100644
--- a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
+++ b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
@@ -30,9 +30,9 @@
             android:layout_height="@dimen/brightness_mirror_height"
             android:layout_gravity="center_vertical"
             android:minHeight="48dp"
-            android:thumb="@null"
-            android:paddingStart="0dp"
-            android:paddingEnd="0dp"
+            android:thumb="@drawable/brightness_progress_thumb"
+            android:paddingStart="@dimen/brightness_progress_padding"
+            android:paddingEnd="@dimen/brightness_progress_padding"
             android:progressDrawable="@drawable/brightness_progress_drawable"
             android:splitTrack="false"
         />
diff --git a/packages/SystemUI/res/layout/udfps_touch_overlay.xml b/packages/SystemUI/res/layout/udfps_touch_overlay.xml
index 498d59b..687f404 100644
--- a/packages/SystemUI/res/layout/udfps_touch_overlay.xml
+++ b/packages/SystemUI/res/layout/udfps_touch_overlay.xml
@@ -18,4 +18,9 @@
     android:id="@+id/udfps_touch_overlay"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
+    <com.android.systemui.biometrics.UdfpsSurfaceView
+        android:id="@+id/hbm_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:visibility="invisible"/>
 </com.android.systemui.biometrics.ui.view.UdfpsTouchOverlay>
diff --git a/packages/SystemUI/res/layout/volume_dialog_row.xml b/packages/SystemUI/res/layout/volume_dialog_row.xml
index dc9c4f1..ff0031a 100644
--- a/packages/SystemUI/res/layout/volume_dialog_row.xml
+++ b/packages/SystemUI/res/layout/volume_dialog_row.xml
@@ -48,14 +48,14 @@
             android:layout_height="@dimen/volume_row_slider_height">
             <SeekBar
                 android:id="@+id/volume_row_slider"
-                android:paddingLeft="0dp"
-                android:paddingRight="0dp"
-                android:paddingStart="0dp"
-                android:paddingEnd="0dp"
+                android:paddingLeft="@dimen/rounded_slider_track_inset"
+                android:paddingRight="@dimen/rounded_slider_track_inset"
+                android:paddingStart="@dimen/rounded_slider_track_inset"
+                android:paddingEnd="@dimen/rounded_slider_track_inset"
                 android:layout_width="@dimen/volume_row_slider_height"
                 android:layout_height="match_parent"
                 android:layout_gravity="center"
-                android:thumb="@null"
+                android:thumb="@drawable/volume_row_seekbar_thumb"
                 android:splitTrack="false"
                 android:progressDrawable="@drawable/volume_row_seekbar"
                 android:background="@null"
diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml
index c1eff5f..459f057 100644
--- a/packages/SystemUI/res/values-night/colors.xml
+++ b/packages/SystemUI/res/values-night/colors.xml
@@ -62,6 +62,11 @@
     <!-- The color of the text in the Global Actions menu -->
     <color name="global_actions_alert_text">@color/GM2_red_300</color>
 
+    <color name="global_actions_lite_background">@android:color/system_neutral1_800</color>
+    <color name="global_actions_lite_button_background">@android:color/system_accent1_100</color>
+    <color name="global_actions_lite_text">#ffffff</color>
+    <color name="global_actions_lite_icon">#000000</color>
+
     <!-- Floating overlay actions -->
     <color name="overlay_background_protection_start">#80000000</color> <!-- 50% black -->
 
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index a375264..b3d51dd 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -38,9 +38,10 @@
     <color name="global_actions_grid_background">#F1F3F4</color>
 
     <!-- Colors for Power Menu Lite -->
-    <color name="global_actions_lite_background">#191C18</color>
-    <color name="global_actions_lite_button_background">#303030</color>
-    <color name="global_actions_lite_text">#F0F0F0</color>
+    <color name="global_actions_lite_background">@android:color/system_neutral1_0</color>
+    <color name="global_actions_lite_button_background">@android:color/system_accent1_600</color>
+    <color name="global_actions_lite_text">#000000</color>
+    <color name="global_actions_lite_icon">#ffffff</color>
     <color name="global_actions_lite_emergency_background">#F85D4D</color>
     <color name="global_actions_lite_emergency_icon">@color/GM2_grey_900</color>
 
diff --git a/packages/SystemUI/res/values/custom_config.xml b/packages/SystemUI/res/values/custom_config.xml
new file mode 100644
index 0000000..6f0bebf
--- /dev/null
+++ b/packages/SystemUI/res/values/custom_config.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2009, The Android Open Source 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources>
+
+    <!-- to hide statusbar and qs batteryy on unknown state
+        needed for battery less devices -->
+    <bool name="config_battery_hide_on_unknown">false</bool>
+
+    <!-- The default tiles to display in QuickSettings -->
+    <string name="quick_settings_tiles_extra" translatable="false">
+        aod,nfc,screenshot,caffeine,dataswitch
+    </string>
+
+    <!-- The CPU temperature sensor path, defaults to empty -->
+    <string name="config_cpuTempSensor" translatable="false"></string>
+    <!-- The battery temperature divider, if needed -->
+    <integer name="config_battTempDivider" translatable="false">10</integer>
+    <!-- The CPU temperature divider, if needed -->
+    <integer name="config_cpuTempDivider" translatable="false">1</integer>
+    <!-- The CPUs to display in CPUInfoService view -->
+    <string name="config_displayCpus" translatable="false"></string>
+
+    <!-- Navigation bar dpad -->
+    <string name="config_navBarLayoutHandleArrows" translatable="false">back[1.7WC];home_handle;ime_switcher[1.7WC]</string>
+
+    <!-- qs columns count settings -->
+    <bool name="qs_tile_vertical_layout">false</bool>
+
+    <!-- hack - we want a way to access the landscape default resource config -->
+    <!-- obviously whenever the default is changed or anyone wants
+    to use a different default in his device tree he must be aware of that -->
+    <integer name="quick_settings_num_columns_landscape">4</integer>
+
+    <!-- Color of the UDFPS pressed view -->
+     <color name="config_udfpsColor">#ffffffff</color>
+</resources>
diff --git a/packages/SystemUI/res/values/custom_dimens.xml b/packages/SystemUI/res/values/custom_dimens.xml
new file mode 100644
index 0000000..63ea702
--- /dev/null
+++ b/packages/SystemUI/res/values/custom_dimens.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2022, The Android Open Source 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.
+*/
+-->
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources>
+    <dimen name="cpu_info_text_height">12dp</dimen>
+
+    <!-- Navigation bar dpad -->
+    <dimen name="navigation_extra_key_width">36dp</dimen>
+
+    <dimen name="navigation_home_handle_small_width">40dp</dimen>
+    <!-- 2 * navigation_handle_radius + 2 * navigation_handle_bottom-->
+    <dimen name="navigation_home_handle_height">14dp</dimen>
+
+    <!-- Brightness and volume slider-->
+    <dimen name="rounded_slider_progress_width">8dp</dimen>
+    <dimen name="rounded_slider_progress_corner_radius">4dp</dimen>
+    <dimen name="rounded_slider_track_negative_inset">-22dp</dimen>
+    <dimen name="brightness_progress_padding">24dp</dimen>
+    <dimen name="volume_seekbar_progress_width">8dp</dimen>
+    <dimen name="volume_seekbar_progress_corner_radius">4dp</dimen>
+</resources>
diff --git a/packages/SystemUI/res/values/custom_strings.xml b/packages/SystemUI/res/values/custom_strings.xml
new file mode 100644
index 0000000..1124ee3
--- /dev/null
+++ b/packages/SystemUI/res/values/custom_strings.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 2006, The Android Open Source 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.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- alarm tile -->
+    <string name="alarm_title_dnd_indicator">(Off by DnD)</string>
+
+    <!-- AOD QS tile -->
+    <string name="quick_settings_aod_label">AOD</string>
+    <string name="quick_settings_aod_off_powersave_label">AOD off\nBattery saver</string>
+    <string name="aod_on">On</string>
+    <string name="aod_off">Off</string>
+
+    <!-- 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>
+
+    <!-- DataSwitch Tile -->
+    <string name="qs_data_switch_label">Switch data card</string>
+    <string name="qs_data_switch_changed_1">Using SIM 1 for Mobile data</string>
+    <string name="qs_data_switch_changed_2">Using SIM 2 for Mobile data</string>
+    <string name="qs_data_no_sim">No SIM</string>
+    <string name="qs_data_sim_1">SIM 1</string>
+    <string name="qs_data_sim_2">SIM 2</string>
+
+    <!-- Keyguard -->
+    <string name="keyguard_slice_dnd">Do Not Disturb</string>
+
+    <!-- Navigation bar dpad -->
+    <string name="accessibility_dpad_left">Cursor left</string>
+    <string name="accessibility_dpad_right">Cursor right</string>
+
+    <!-- Power menu reboot -->
+    <string name="global_action_reboot">Restart</string>
+    <string name="global_action_reboot_more">Restart\u2026</string>
+    <string name="global_action_reboot_sub">System</string>
+    <string name="global_action_reboot_recovery">Recovery</string>
+    <string name="global_action_reboot_bootloader">Bootloader</string>
+    <string name="global_action_reboot_fastboot">Fastboot</string>
+
+    <!-- Label for area where tiles can be added to the qs panel -->
+    <string name="drag_or_tap_to_add_tiles">Hold &amp; drag or tap to add tiles</string>
+
+    <!-- Label for UI element which allows deleting the screenshot [CHAR LIMIT=30] -->
+    <string name="screenshot_delete_label">Delete</string>
+    <!-- Content description indicating that tapping the element will allow deleting the screenshot [CHAR LIMIT=NONE] -->
+    <string name="screenshot_delete_description">Delete screenshot</string>
+
+    <string name="screenshot_scroll_label_empty"></string>
+    <string name="screenshot_delete_label_empty"></string>
+    <string name="screenshot_edit_label_empty"></string>
+    <string name="screenshot_share_label_empty"></string>
+    
+</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 5894f29..6448ea8 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1073,8 +1073,8 @@
     <dimen name="global_actions_power_dialog_item_bottom_margin">45dp</dimen>
 
     <!-- Power Menu Lite -->
-    <dimen name="global_actions_button_size">96dp</dimen>
-    <dimen name="global_actions_button_padding">38dp</dimen>
+    <dimen name="global_actions_button_size">80dp</dimen>
+    <dimen name="global_actions_button_padding">24dp</dimen>
     <dimen name="global_actions_corner_radius">28dp</dimen>
     <dimen name="global_actions_lite_padding">24dp</dimen>
     <dimen name="global_actions_info_margin">32dp</dimen>
diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
index 5af80cb..0c38057 100644
--- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
@@ -41,6 +41,7 @@
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.DisplaySpecific
 import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.Dependency
 import com.android.systemui.flags.FeatureFlagsClassic
 import com.android.systemui.flags.Flags.REGION_SAMPLING
 import com.android.systemui.keyguard.MigrateClocksToBlueprint
@@ -54,6 +55,7 @@
 import com.android.systemui.lifecycle.repeatWhenAttached
 import com.android.systemui.log.core.Logger
 import com.android.systemui.modes.shared.ModesUi
+import com.android.systemui.omni.OmniSettingsService
 import com.android.systemui.plugins.clocks.AlarmData
 import com.android.systemui.plugins.clocks.ClockController
 import com.android.systemui.plugins.clocks.ClockFaceController
@@ -72,6 +74,7 @@
 import com.android.systemui.statusbar.policy.ZenModeController
 import com.android.systemui.statusbar.policy.domain.interactor.ZenModeInteractor
 import com.android.systemui.util.concurrency.DelayableExecutor
+import org.omnirom.omnilib.utils.OmniSettings
 import java.util.Locale
 import java.util.TimeZone
 import java.util.concurrent.Executor
@@ -436,6 +439,13 @@
             }
         }
 
+    private val settingsListener = object : OmniSettingsService.OmniSettingsObserver {
+        override fun onIntSettingChanged(key: String, newValue: Int) {
+            clock?.events?.onColorPaletteChanged(resources)
+            updateColors()
+        }
+    }
+
     private fun handleZenMode(zen: Int) {
         val mode = ZenMode.fromInt(zen)
         if (mode == null) {
@@ -495,6 +505,7 @@
             }
         smallTimeListener?.update(shouldTimeListenerRun)
         largeTimeListener?.update(shouldTimeListenerRun)
+        Dependency.get(OmniSettingsService::class.java).addIntObserver(settingsListener, OmniSettings.OMNI_LOCKSCREEN_CLOCK_COLORED)
 
         bgExecutor.execute {
             // Query ZenMode data
@@ -521,6 +532,7 @@
         largeRegionSampler?.stopRegionSampler()
         smallTimeListener?.stop()
         largeTimeListener?.stop()
+        Dependency.get(OmniSettingsService::class.java).removeObserver(settingsListener)
         clock?.run {
             smallClock.view.removeOnAttachStateChangeListener(smallClockOnAttachStateChangeListener)
             largeClock.view.removeOnAttachStateChangeListener(largeClockOnAttachStateChangeListener)
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 40c1f0f9..b4d8a60 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -35,6 +35,7 @@
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.navigationbar.NavigationBarController;
 import com.android.systemui.navigationbar.NavigationModeController;
+import com.android.systemui.omni.OmniSettingsService;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.PluginManager;
 import com.android.systemui.plugins.VolumeDialogController;
@@ -52,6 +53,7 @@
 import com.android.systemui.statusbar.phone.SystemUIDialogManager;
 import com.android.systemui.statusbar.policy.BluetoothController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.FlashlightController;
 import com.android.systemui.statusbar.window.StatusBarWindowControllerStore;
 import com.android.systemui.tuner.TunerService;
 
@@ -117,6 +119,7 @@
 
     @Inject Lazy<BroadcastDispatcher> mBroadcastDispatcher;
     @Inject Lazy<BluetoothController> mBluetoothController;
+    @Inject Lazy<FlashlightController> mFlashlightController;
     @Inject Lazy<KeyguardUpdateMonitor> mKeyguardUpdateMonitor;
     @Inject Lazy<DeviceProvisionedController> mDeviceProvisionedController;
     @Inject Lazy<PluginManager> mPluginManager;
@@ -132,6 +135,7 @@
     @Inject Lazy<OverviewProxyService> mOverviewProxyService;
     @Inject Lazy<NavigationModeController> mNavBarModeController;
     @Inject Lazy<NavigationBarController> mNavigationBarController;
+    @Inject Lazy<OmniSettingsService> mOmniSettingsService;
     @Inject Lazy<StatusBarStateController> mStatusBarStateController;
     @Inject Lazy<NotificationMediaManager> mNotificationMediaManager;
     @Inject @Background Lazy<Looper> mBgLooper;
@@ -164,6 +168,7 @@
         mProviders.put(BG_LOOPER, mBgLooper::get);
         mProviders.put(BroadcastDispatcher.class, mBroadcastDispatcher::get);
         mProviders.put(BluetoothController.class, mBluetoothController::get);
+        mProviders.put(FlashlightController.class, mFlashlightController::get);
         mProviders.put(KeyguardUpdateMonitor.class, mKeyguardUpdateMonitor::get);
         mProviders.put(DeviceProvisionedController.class, mDeviceProvisionedController::get);
         mProviders.put(PluginManager.class, mPluginManager::get);
@@ -178,6 +183,7 @@
         mProviders.put(OverviewProxyService.class, mOverviewProxyService::get);
         mProviders.put(NavigationModeController.class, mNavBarModeController::get);
         mProviders.put(NavigationBarController.class, mNavigationBarController::get);
+        mProviders.put(OmniSettingsService.class, mOmniSettingsService::get);
         mProviders.put(StatusBarStateController.class, mStatusBarStateController::get);
         mProviders.put(NotificationMediaManager.class, mNotificationMediaManager::get);
         mProviders.put(SysUiState.class, mSysUiStateFlagsContainer::get);
diff --git a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
index 1176cb0..28067f8 100644
--- a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterView.java
@@ -16,6 +16,7 @@
 package com.android.systemui.battery;
 
 import static android.provider.Settings.System.SHOW_BATTERY_PERCENT;
+import static org.omnirom.omnilib.utils.OmniSettings.OMNI_SHOW_BATTERY_IMAGE;
 
 import static com.android.settingslib.flags.Flags.newStatusBarIcons;
 import static com.android.systemui.DejankUtils.whitelistIpcs;
@@ -43,6 +44,8 @@
 import android.util.TypedValue;
 import android.view.Gravity;
 import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.TextView;
@@ -92,6 +95,7 @@
     private boolean mIsIncompatibleCharging;
     // Error state where we know nothing about the current battery state
     private boolean mBatteryStateUnknown;
+    private boolean mHideBatteryOnUnknown;
     // Lazily-loaded since this is expected to be a rare-if-ever state
     private Drawable mUnknownStateDrawable;
 
@@ -106,6 +110,8 @@
     private BatteryDrawableState mUnifiedBatteryState =
             BatteryDrawableState.Companion.getDefaultInitialState();
 
+    private boolean mHideImage;
+
     public BatteryMeterView(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
     }
@@ -127,6 +133,8 @@
 
         mShowPercentAvailable = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_battery_percentage_setting_available);
+        mHideBatteryOnUnknown = context.getResources().getBoolean(
+                R.bool.config_battery_hide_on_unknown);
 
         setupLayoutTransition();
 
@@ -153,6 +161,7 @@
         }
 
         updateShowPercent();
+
         mDualToneHandler = new DualToneHandler(context);
         // Init to not dark at all.
         onDarkChanged(new ArrayList<Rect>(), 0, DarkIconDispatcher.DEFAULT_ICON_TINT);
@@ -314,7 +323,7 @@
             return;
         }
         mPowerSaveEnabled = isPowerSave;
-        if (!newStatusBarIcons()) {
+        if (!newStatusBarIcons() || isImageHidden()) {
             mDrawable.setPowerSaveEnabled(isPowerSave);
         } else {
             setBatteryDrawableState(
@@ -415,7 +424,7 @@
     }
 
     void updatePercentText() {
-        if (!newStatusBarIcons()) {
+        if (!newStatusBarIcons() || mHideImage) {
             updatePercentTextLegacy();
             return;
         }
@@ -527,7 +536,7 @@
     }
 
     void updateShowPercent() {
-        if (!newStatusBarIcons()) {
+        if (!newStatusBarIcons() || mHideImage) {
             updateShowPercentLegacy();
             return;
         }
@@ -556,10 +565,11 @@
 
         // The legacy impl used the percent view for the estimate and the percent text. The modern
         // version only uses it for estimate. It can be safely removed here
-        if (mShowPercentMode != MODE_ESTIMATE) {
+        // Omni: Don't remove mBatteryPercentView for percent on lockscreen with hideImage
+        /*if (mShowPercentMode != MODE_ESTIMATE) {
             removeView(mBatteryPercentView);
             mBatteryPercentView = null;
-        }
+        }*/
     }
 
     private void updateShowPercentLegacy() {
@@ -589,6 +599,23 @@
         }
     }
 
+    void updateShowImage() {
+        mHideImage = Settings.System.getIntForUser(getContext().getContentResolver(),
+            OMNI_SHOW_BATTERY_IMAGE, 1, UserHandle.USER_CURRENT) == 0;
+        mBatteryIconView.setVisibility(mHideImage ? View.GONE : View.VISIBLE);
+        if (mHideImage) {
+            updateShowPercentLegacy();
+            updatePercentTextLegacy();
+        } else {
+            removeView(mBatteryPercentView);
+            mBatteryPercentView = null;
+        }
+    }
+
+    boolean isImageHidden() {
+        return mHideImage && mBatteryPercentView != null;
+    }
+
     private Drawable getUnknownStateDrawable() {
         if (mUnknownStateDrawable == null) {
             mUnknownStateDrawable = mContext.getDrawable(R.drawable.ic_battery_unknown);
@@ -608,13 +635,29 @@
 
         if (mBatteryStateUnknown) {
             mBatteryIconView.setImageDrawable(getUnknownStateDrawable());
+            if (mHideBatteryOnUnknown) {
+                setVisibility(View.GONE);
+            }
         } else {
             mBatteryIconView.setImageDrawable(mDrawable);
+            setVisibility(View.VISIBLE);
         }
 
         updateShowPercent();
     }
 
+    @Override
+    public void setVisibility(@Visibility int visibility) {
+        if (visibility == View.VISIBLE && isBatteryHidden()) {
+            return;
+        }
+        super.setVisibility(visibility);
+    }
+
+    boolean isBatteryHidden() {
+        return mBatteryStateUnknown && mHideBatteryOnUnknown;
+    }
+
     void scaleBatteryMeterViews() {
         if (!newStatusBarIcons()) {
             scaleBatteryMeterViewsLegacy();
@@ -695,7 +738,7 @@
     public void onDarkChanged(ArrayList<Rect> areas, float darkIntensity, int tint) {
         if (mIsStaticColor) return;
 
-        if (!newStatusBarIcons()) {
+        if (!newStatusBarIcons() || isImageHidden()) {
             onDarkChangedLegacy(areas, darkIntensity, tint);
             return;
         }
@@ -755,7 +798,7 @@
 
     /** For newStatusBarIcons(), we use a BatteryColors object to declare the theme */
     public void setUnifiedBatteryColors(BatteryColors colors) {
-        if (!newStatusBarIcons()) return;
+        if (!newStatusBarIcons() || isImageHidden()) return;
 
         mUnifiedBatteryColors = colors;
         mUnifiedBattery.setColors(mUnifiedBatteryColors);
diff --git a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java
index 9a30c21..fc49a6c 100644
--- a/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/battery/BatteryMeterViewController.java
@@ -16,6 +16,7 @@
 package com.android.systemui.battery;
 
 import static android.provider.Settings.System.SHOW_BATTERY_PERCENT;
+import static org.omnirom.omnilib.utils.OmniSettings.OMNI_SHOW_BATTERY_IMAGE;
 
 import android.content.ContentResolver;
 import android.content.Context;
@@ -74,7 +75,7 @@
             if (StatusBarIconController.ICON_HIDE_LIST.equals(key)) {
                 ArraySet<String> icons = StatusBarIconController.getIconHideList(
                         getContext(), newValue);
-                mView.setVisibility(icons.contains(mSlotBattery) ? View.GONE : View.VISIBLE);
+                mView.setVisibility((icons.contains(mSlotBattery) || mView.isBatteryHidden()) ? View.GONE : View.VISIBLE);
             }
         }
     };
@@ -168,6 +169,8 @@
         mUserTracker.addCallback(mUserChangedCallback, new HandlerExecutor(mMainHandler));
 
         mView.updateShowPercent();
+        mView.updateShowImage();
+        mView.isImageHidden();
     }
 
     @Override
@@ -213,6 +216,11 @@
                 false,
                 mSettingObserver,
                 user);
+        mContentResolver.registerContentObserver(
+                Settings.System.getUriFor(OMNI_SHOW_BATTERY_IMAGE),
+                false,
+                mSettingObserver,
+                user);
     }
 
     private void registerGlobalBatteryUpdateObserver() {
@@ -231,6 +239,8 @@
         public void onChange(boolean selfChange, Uri uri) {
             super.onChange(selfChange, uri);
             mView.updateShowPercent();
+            mView.updateShowImage();
+            mView.isImageHidden();
             if (TextUtils.equals(uri.getLastPathSegment(),
                     Settings.Global.BATTERY_ESTIMATES_LAST_UPDATE_TIME)) {
                 // update the text for sure if the estimate in the cache was updated
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
index 4c2dc41..e2be047 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
@@ -29,6 +29,7 @@
 import android.view.animation.PathInterpolator
 import com.android.internal.graphics.ColorUtils
 import com.android.app.animation.Interpolators
+import com.android.settingslib.Utils
 import com.android.systemui.surfaceeffects.ripple.RippleShader
 
 private const val RIPPLE_SPARKLE_STRENGTH: Float = 0.3f
@@ -89,7 +90,8 @@
         rippleShader.sparkleStrength = RIPPLE_SPARKLE_STRENGTH
         updateRippleFadeParams()
         ripplePaint.shader = rippleShader
-        setLockScreenColor(0xffffffff.toInt()) // default color
+        setLockScreenColor(Utils.getColorAttr(context,
+                android.R.attr.colorAccent).defaultColor) // default color
 
         dwellShader.color = 0xffffffff.toInt() // default color
         dwellShader.progress = 0f
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index a9133e4..2b2d85d 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -79,6 +79,7 @@
 import com.android.systemui.biometrics.udfps.SinglePointerTouchProcessor;
 import com.android.systemui.biometrics.udfps.TouchProcessor;
 import com.android.systemui.biometrics.udfps.TouchProcessorResult;
+import com.android.systemui.biometrics.ui.view.UdfpsTouchOverlay;
 import com.android.systemui.biometrics.ui.viewmodel.DefaultUdfpsTouchOverlayViewModel;
 import com.android.systemui.biometrics.ui.viewmodel.DeviceEntryUdfpsTouchOverlayViewModel;
 import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
@@ -865,8 +866,9 @@
         if (!isOptical()) {
             return;
         }
-        if (mUdfpsDisplayMode != null) {
-            mUdfpsDisplayMode.disable(null);
+        UdfpsTouchOverlay udfpsView = (UdfpsTouchOverlay) view;
+        if (udfpsView.isDisplayConfigured()) {
+            udfpsView.unconfigureDisplay();
         }
     }
 
@@ -1059,7 +1061,7 @@
             if (mIgnoreRefreshRate) {
                 dispatchOnUiReady(requestId);
             } else {
-                    mUdfpsDisplayMode.enable(() -> dispatchOnUiReady(requestId));
+                    ((UdfpsTouchOverlay) view).configureDisplay(() -> dispatchOnUiReady(requestId));
             }
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
index 51eb139..6da2743 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
@@ -198,6 +198,7 @@
                     (inflater.inflate(R.layout.udfps_touch_overlay, null, false)
                             as UdfpsTouchOverlay)
                         .apply {
+                            setUdfpsDisplayModeProvider(udfpsDisplayModeProvider)
                             // This view overlaps the sensor area
                             // prevent it from being selectable during a11y
                             if (requestReason.isImportantForAccessibility()) {
@@ -219,6 +220,7 @@
                                         udfpsOverlayInteractor = udfpsOverlayInteractor,
                                     )
                             }
+                            sensorRect = sensorBounds
                         }
 
                 getTouchOverlay()?.apply {
@@ -291,6 +293,11 @@
     fun hide(): Boolean {
         val wasShowing = isShowing
 
+        overlayTouchView?.apply {
+            if (isDisplayConfigured) {
+                unconfigureDisplay()
+            }
+        }
         udfpsDisplayModeProvider.disable(null)
         getTouchOverlay()?.apply {
             if (this.parent != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsSurfaceView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsSurfaceView.java
new file mode 100644
index 0000000..3bfddde
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsSurfaceView.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2021 The Android Open Source 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.biometrics;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.RectF;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+
+import com.android.systemui.res.R;
+
+/**
+ * Surface View for providing the Global High-Brightness Mode (GHBM) illumination for UDFPS.
+ */
+public class UdfpsSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
+    private static final String TAG = "UdfpsSurfaceView";
+
+    /**
+     * Notifies {@link UdfpsView} when to enable GHBM illumination.
+     */
+    interface GhbmIlluminationListener {
+        /**
+         * @param surface the surface for which GHBM should be enabled.
+         * @param onDisplayConfigured a runnable that should be run after GHBM is enabled.
+         */
+        void enableGhbm(@NonNull Surface surface, @Nullable Runnable onDisplayConfigured);
+    }
+
+    @NonNull private final SurfaceHolder mHolder;
+    @NonNull private final Paint mSensorPaint;
+
+    @Nullable private GhbmIlluminationListener mGhbmIlluminationListener;
+    @Nullable private Runnable mOnDisplayConfigured;
+    boolean mAwaitingSurfaceToStartIllumination;
+    boolean mHasValidSurface;
+
+    private Drawable mUdfpsIconPressed;
+
+    public UdfpsSurfaceView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        // Make this SurfaceView draw on top of everything else in this window. This allows us to
+        // 1) Always show the HBM circle on top of everything else, and
+        // 2) Properly composite this view with any other animations in the same window no matter
+        //    what contents are added in which order to this view hierarchy.
+        setZOrderOnTop(true);
+
+        mHolder = getHolder();
+        mHolder.addCallback(this);
+        mHolder.setFormat(PixelFormat.RGBA_8888);
+
+        mSensorPaint = new Paint(0 /* flags */);
+        mSensorPaint.setAntiAlias(true);
+        mSensorPaint.setColor(context.getColor(R.color.config_udfpsColor));
+        mSensorPaint.setStyle(Paint.Style.FILL);
+
+        mUdfpsIconPressed = context.getDrawable(R.drawable.udfps_icon_pressed);
+    }
+
+    @Override public void surfaceCreated(SurfaceHolder holder) {
+        mHasValidSurface = true;
+        if (mAwaitingSurfaceToStartIllumination) {
+            doIlluminate(mOnDisplayConfigured);
+            mOnDisplayConfigured = null;
+            mAwaitingSurfaceToStartIllumination = false;
+        }
+    }
+
+    @Override
+    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+        // Unused.
+    }
+
+    @Override public void surfaceDestroyed(SurfaceHolder holder) {
+        mHasValidSurface = false;
+    }
+
+    public void setGhbmIlluminationListener(@Nullable GhbmIlluminationListener listener) {
+        mGhbmIlluminationListener = listener;
+    }
+
+    /**
+     * Note: there is no corresponding method to stop GHBM illumination. It is expected that
+     * {@link UdfpsView} will hide this view, which would destroy the surface and remove the
+     * illumination dot.
+     */
+    public void startGhbmIllumination(@Nullable Runnable onDisplayConfigured) {
+        if (mGhbmIlluminationListener == null) {
+            Log.e(TAG, "startIllumination | mGhbmIlluminationListener is null");
+            return;
+        }
+
+        if (mHasValidSurface) {
+            doIlluminate(onDisplayConfigured);
+        } else {
+            mAwaitingSurfaceToStartIllumination = true;
+            mOnDisplayConfigured = onDisplayConfigured;
+        }
+    }
+
+    private void doIlluminate(@Nullable Runnable onDisplayConfigured) {
+        if (mGhbmIlluminationListener == null) {
+            Log.e(TAG, "doIlluminate | mGhbmIlluminationListener is null");
+            return;
+        }
+
+        mGhbmIlluminationListener.enableGhbm(mHolder.getSurface(), onDisplayConfigured);
+    }
+
+    /**
+     * Immediately draws the illumination dot on this SurfaceView's surface.
+     */
+    public void drawIlluminationDot(@NonNull RectF sensorRect) {
+        if (!mHasValidSurface) {
+            Log.e(TAG, "drawIlluminationDot | the surface is destroyed or was never created.");
+            return;
+        }
+        Canvas canvas = null;
+        try {
+            canvas = mHolder.lockCanvas();
+            mUdfpsIconPressed.setBounds(
+                    Math.round(sensorRect.left),
+                    Math.round(sensorRect.top),
+                    Math.round(sensorRect.right),
+                    Math.round(sensorRect.bottom)
+            );
+            mUdfpsIconPressed.draw(canvas);
+            canvas.drawOval(sensorRect, mSensorPaint);
+        } finally {
+            // Make sure the surface is never left in a bad state.
+            if (canvas != null) {
+                mHolder.unlockCanvasAndPost(canvas);
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/view/UdfpsTouchOverlay.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/view/UdfpsTouchOverlay.kt
index 2484c33..484f2bb 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/view/UdfpsTouchOverlay.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/view/UdfpsTouchOverlay.kt
@@ -16,11 +16,65 @@
 package com.android.systemui.biometrics.ui.view
 
 import android.content.Context
+import android.graphics.Rect
+import android.graphics.RectF
 import android.util.AttributeSet
+import android.view.Surface
 import android.widget.FrameLayout
 
+import com.android.systemui.biometrics.UdfpsDisplayModeProvider
+import com.android.systemui.biometrics.UdfpsSurfaceView
+import com.android.systemui.res.R
+
 /**
  * A translucent (not visible to the user) view that receives touches to send to FingerprintManager
  * for fingerprint authentication.
  */
-class UdfpsTouchOverlay(context: Context, attrs: AttributeSet?) : FrameLayout(context, attrs)
+class UdfpsTouchOverlay(context: Context, attrs: AttributeSet?) : FrameLayout(context, attrs) {
+    private var ghbmView: UdfpsSurfaceView? = null
+    private var udfpsDisplayMode: UdfpsDisplayModeProvider? = null
+
+    // sensorRect may be bigger than the sensor. True sensor dimensions are defined in
+    // overlayParams.sensorBounds
+    var sensorRect = Rect()
+
+    /** True after the call to [configureDisplay] and before the call to [unconfigureDisplay]. */
+    var isDisplayConfigured: Boolean = false
+        private set
+
+    override fun onFinishInflate() {
+        ghbmView = findViewById(R.id.hbm_view)
+    }
+
+   fun setUdfpsDisplayModeProvider(udfpsDisplayModeProvider: UdfpsDisplayModeProvider?) {
+        udfpsDisplayMode = udfpsDisplayModeProvider
+    }
+
+    fun configureDisplay(onDisplayConfigured: Runnable) {
+        isDisplayConfigured = true
+        val gView = ghbmView
+        if (gView != null) {
+            gView.setGhbmIlluminationListener(this::doIlluminate)
+            gView.visibility = VISIBLE
+            gView.startGhbmIllumination(onDisplayConfigured)
+        } else {
+            doIlluminate(null /* surface */, onDisplayConfigured)
+        }
+    }
+
+    private fun doIlluminate(surface: Surface?, onDisplayConfigured: Runnable?) {
+        udfpsDisplayMode?.enable {
+            onDisplayConfigured?.run()
+            ghbmView?.drawIlluminationDot(RectF(sensorRect))
+        }
+    }
+
+    fun unconfigureDisplay() {
+        isDisplayConfigured = false
+        ghbmView?.let { view ->
+            view.setGhbmIlluminationListener(null)
+            view.visibility = INVISIBLE
+        }
+        udfpsDisplayMode?.disable(null /* onDisabled */)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultBroadcastReceiverBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultBroadcastReceiverBinder.java
index 5a0eb72..93f6a1b 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultBroadcastReceiverBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultBroadcastReceiverBinder.java
@@ -24,6 +24,7 @@
 import com.android.systemui.media.dialog.MediaOutputDialogReceiver;
 import com.android.systemui.people.widget.PeopleSpaceWidgetPinnedReceiver;
 import com.android.systemui.people.widget.PeopleSpaceWidgetProvider;
+import com.android.systemui.screenshot.DeleteScreenshotReceiver;
 import com.android.systemui.screenshot.SmartActionsReceiver;
 
 import dagger.Binds;
@@ -41,6 +42,15 @@
      */
     @Binds
     @IntoMap
+    @ClassKey(DeleteScreenshotReceiver.class)
+    public abstract BroadcastReceiver bindDeleteScreenshotReceiver(
+            DeleteScreenshotReceiver broadcastReceiver);
+
+    /**
+     *
+     */
+    @Binds
+    @IntoMap
     @ClassKey(SmartActionsReceiver.class)
     public abstract BroadcastReceiver bindSmartActionsReceiver(
             SmartActionsReceiver broadcastReceiver);
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
index fcc3ea9..4e437f7 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
@@ -49,6 +49,7 @@
 import com.android.systemui.media.taptotransfer.receiver.MediaTttChipControllerReceiver
 import com.android.systemui.media.taptotransfer.sender.MediaTttSenderCoordinator
 import com.android.systemui.mediaprojection.taskswitcher.MediaProjectionTaskSwitcherCoreStartable
+import com.android.systemui.omni.CPUInfoManager
 import com.android.systemui.settings.MultiUserUtilsModule
 import com.android.systemui.shortcut.ShortcutKeyDispatcher
 import com.android.systemui.statusbar.ImmersiveModeConfirmation
@@ -353,4 +354,10 @@
     @IntoMap
     @ClassKey(ComplicationTypesUpdater::class)
     abstract fun bindComplicationTypesUpdater(updater: ComplicationTypesUpdater): CoreStartable
+
+    /** Inject into Omni CPUInfoManager.  */
+    @Binds
+    @IntoMap
+    @ClassKey(CPUInfoManager::class)
+    abstract fun bindCPUInfoManager(sysui: CPUInfoManager): CoreStartable
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index d6f8957..67fbfdc 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -89,6 +89,7 @@
 import com.android.systemui.navigationbar.NavigationBarComponent;
 import com.android.systemui.navigationbar.gestural.dagger.GestureModule;
 import com.android.systemui.notetask.NoteTaskModule;
+import com.android.systemui.omni.dagger.OmniModule;
 import com.android.systemui.people.PeopleModule;
 import com.android.systemui.plugins.BcSmartspaceConfigPlugin;
 import com.android.systemui.plugins.BcSmartspaceDataPlugin;
@@ -281,6 +282,7 @@
         UserModule.class,
         UtilModule.class,
         NoteTaskModule.class,
+        OmniModule.class,
         WalletModule.class
 },
         subcomponents = {
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsComponent.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsComponent.java
index 9f321d8..ed6ab98 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsComponent.java
@@ -78,8 +78,8 @@
     }
 
     @Override
-    public void handleShowShutdownUi(boolean isReboot, String reason) {
-        mExtension.get().showShutdownUi(isReboot, reason);
+    public void handleShowShutdownUi(boolean isReboot, String reason, boolean rebootCustom) {
+        mExtension.get().showShutdownUi(isReboot, reason, rebootCustom);
     }
 
     @Override
@@ -114,9 +114,9 @@
     }
 
     @Override
-    public void reboot(boolean safeMode) {
+    public void reboot(boolean safeMode, String reason) {
         try {
-            mBarService.reboot(safeMode);
+            mBarService.reboot(safeMode, reason);
         } catch (RemoteException e) {
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
index 91b44e7..5d5ca2a 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialogLite.java
@@ -57,6 +57,7 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
+import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.os.Trace;
@@ -143,6 +144,8 @@
 import com.android.systemui.util.settings.GlobalSettings;
 import com.android.systemui.util.settings.SecureSettings;
 
+import org.omnirom.omnilib.utils.OmniSettings;
+
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.Executor;
@@ -188,6 +191,9 @@
     static final String GLOBAL_ACTION_KEY_EMERGENCY = "emergency";
     static final String GLOBAL_ACTION_KEY_SCREENSHOT = "screenshot";
     static final String GLOBAL_ACTION_KEY_SYSTEM_UPDATE = "system_update";
+    private static final String GLOBAL_ACTION_KEY_REBOOT_RECOVERY = "reboot_recovery";
+    private static final String GLOBAL_ACTION_KEY_REBOOT_BOOTLOADER = "reboot_bootloader";
+    private static final String GLOBAL_ACTION_KEY_REBOOT_FASTBOOT = "reboot_fastboot";
 
     // See NotificationManagerService#scheduleDurationReachedLocked
     private static final long TOAST_FADE_TIME = 333;
@@ -262,6 +268,12 @@
     private final UserLogoutInteractor mLogoutInteractor;
     private final GlobalActionsInteractor mInteractor;
 
+    // omni additions start
+    private String[] mRootMenuActions;
+    private String[] mRebootMenuActions;
+    private String[] mCurrentMenuActions;
+    private boolean mRebootMenu;
+
     @VisibleForTesting
     public enum GlobalActionsEvent implements UiEventLogger.UiEventEnum {
         @UiEvent(doc = "The global actions / power menu surface became visible on the screen.")
@@ -442,6 +454,11 @@
         mScreenshotHelper = new ScreenshotHelper(context);
 
         mConfigurationController.addCallback(this);
+
+        mRootMenuActions = mContext.getResources().getStringArray(
+                R.array.config_globalActionsList);
+        mRebootMenuActions = mContext.getResources().getStringArray(
+                org.omnirom.omnilib.R.array.config_rebootActionsList);
     }
 
     /**
@@ -478,6 +495,8 @@
             @Nullable Expandable expandable) {
         mKeyguardShowing = keyguardShowing;
         mDeviceProvisioned = isDeviceProvisioned;
+        mRebootMenu = false;
+        mCurrentMenuActions = mRootMenuActions;
         if (mDialog != null && mDialog.isShowing()) {
             // In order to force global actions to hide on the same affordance press, we must
             // register a call to onGlobalActionsShown() first to prevent the default actions
@@ -588,22 +607,25 @@
         mItems.clear();
         mOverflowItems.clear();
         mPowerItems.clear();
-        String[] defaultActions = getDefaultActions();
 
         ShutDownAction shutdownAction = new ShutDownAction();
         RestartAction restartAction = new RestartAction();
+        RebootRecoveryAction rebootRecoveryAction = new RebootRecoveryAction();
+        RebootBootloaderAction rebootBootloaderAction = new RebootBootloaderAction();
+        RebootFastbootAction rebootFastbootAction = new RebootFastbootAction();
+
         ArraySet<String> addedKeys = new ArraySet<>();
         List<Action> tempActions = new ArrayList<>();
         CurrentUserProvider currentUser = new CurrentUserProvider();
 
         // make sure emergency affordance action is first, if needed
-        if (mEmergencyAffordanceManager.needsEmergencyAffordance()) {
+        if (mEmergencyAffordanceManager.needsEmergencyAffordance() && !mRebootMenu) {
             addIfShouldShowAction(tempActions, new EmergencyAffordanceAction());
             addedKeys.add(GLOBAL_ACTION_KEY_EMERGENCY);
         }
 
-        for (int i = 0; i < defaultActions.length; i++) {
-            String actionKey = defaultActions[i];
+        for (int i = 0; i < mCurrentMenuActions.length; i++) {
+            String actionKey = mCurrentMenuActions[i];
             if (addedKeys.contains(actionKey)) {
                 // If we already have added this, don't add it again.
                 continue;
@@ -648,6 +670,12 @@
                 }
             } else if (GLOBAL_ACTION_KEY_SYSTEM_UPDATE.equals(actionKey)) {
                 addIfShouldShowAction(tempActions, new SystemUpdateAction());
+            } else if (GLOBAL_ACTION_KEY_REBOOT_RECOVERY.equals(actionKey)) {
+                addIfShouldShowAction(tempActions, rebootRecoveryAction);
+            } else if (GLOBAL_ACTION_KEY_REBOOT_BOOTLOADER.equals(actionKey)) {
+                addIfShouldShowAction(tempActions, rebootBootloaderAction);
+            } else if (GLOBAL_ACTION_KEY_REBOOT_FASTBOOT.equals(actionKey)) {
+                addIfShouldShowAction(tempActions, rebootFastbootAction);
             } else {
                 Log.e(TAG, "Invalid global action key " + actionKey);
             }
@@ -666,6 +694,15 @@
             mPowerItems.add(shutdownAction);
             mPowerItems.add(restartAction);
 
+            if (advancedRebootEnabled(mContext)) {
+                tempActions.remove(rebootRecoveryAction);
+                tempActions.remove(rebootBootloaderAction);
+                tempActions.remove(rebootFastbootAction);
+                mPowerItems.add(rebootRecoveryAction);
+                mPowerItems.add(rebootBootloaderAction);
+                mPowerItems.add(rebootFastbootAction);
+            }
+
             // add the PowerOptionsAction after Emergency, if present
             tempActions.add(powerOptionsIndex, new PowerOptionsAction());
         }
@@ -720,6 +757,19 @@
         return dialog;
     }
 
+    private boolean advancedRebootEnabled(Context context) {
+        boolean advancedRebootEnabled = Settings.System.getIntForUser(context.getContentResolver(),
+                OmniSettings.OMNI_ADVANCED_REBOOT, 0, UserHandle.USER_CURRENT) == 1;
+        return advancedRebootEnabled;
+    }
+
+    private boolean isSecureLocked() {
+        if (mKeyguardShowing) {
+            return mKeyguardStateController.isUnlocked();
+        }
+        return false;
+    }
+
     @VisibleForTesting
     boolean shouldDisplayLockdown(UserInfo user) {
         if (user == null) {
@@ -813,7 +863,7 @@
             }
             mUiEventLogger.log(GlobalActionsEvent.GA_SHUTDOWN_LONG_PRESS);
             if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) {
-                mWindowManagerFuncs.reboot(true);
+                mWindowManagerFuncs.reboot(true, null);
                 return true;
             }
             return false;
@@ -942,7 +992,12 @@
     @VisibleForTesting
     final class RestartAction extends SinglePressAction implements LongPressAction {
         RestartAction() {
-            super(R.drawable.ic_restart, R.string.global_action_restart);
+            super(R.drawable.ic_restart, com.android.systemui.R.string.global_action_reboot);
+            if (mRebootMenu) {
+                mMessageResId = com.android.systemui.R.string.global_action_reboot_sub;
+            } else if (advancedRebootEnabled(mContext)) {
+                mMessageResId = com.android.systemui.R.string.global_action_reboot_more;
+            }
         }
 
         @Override
@@ -954,7 +1009,7 @@
             }
             mUiEventLogger.log(GlobalActionsEvent.GA_REBOOT_LONG_PRESS);
             if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) {
-                mWindowManagerFuncs.reboot(true);
+                mWindowManagerFuncs.reboot(true, null);
                 return true;
             }
             return false;
@@ -978,7 +1033,82 @@
                 return;
             }
             mUiEventLogger.log(GlobalActionsEvent.GA_REBOOT_PRESS);
-            mWindowManagerFuncs.reboot(false);
+            if (!mRebootMenu && advancedRebootEnabled(mContext) && !isSecureLocked()) {
+                mRebootMenu = true;
+                mCurrentMenuActions = mRebootMenuActions;
+                createActionItems();
+                mDialog.updateList();
+            } else {
+                doReboot();
+            }
+        }
+
+        private void doReboot() {
+            mHandler.sendEmptyMessageDelayed(MESSAGE_DISMISS, DIALOG_DISMISS_DELAY);
+            mWindowManagerFuncs.reboot(false, null);
+        }
+    }
+
+    private final class RebootRecoveryAction extends SinglePressAction {
+        private RebootRecoveryAction() {
+            super(com.android.systemui.R.drawable.ic_restart_recovery, com.android.systemui.R.string.global_action_reboot_recovery);
+        }
+
+        @Override
+        public boolean showDuringKeyguard() {
+            return true;
+        }
+
+        @Override
+        public boolean showBeforeProvisioning() {
+            return true;
+        }
+
+        @Override
+        public void onPress() {
+            mWindowManagerFuncs.reboot(false, PowerManager.REBOOT_RECOVERY);
+        }
+    }
+
+    private final class RebootBootloaderAction extends SinglePressAction {
+        private RebootBootloaderAction() {
+            super(com.android.systemui.R.drawable.ic_restart_bootloader, com.android.systemui.R.string.global_action_reboot_bootloader);
+        }
+
+        @Override
+        public boolean showDuringKeyguard() {
+            return true;
+        }
+
+        @Override
+        public boolean showBeforeProvisioning() {
+            return true;
+        }
+
+        @Override
+        public void onPress() {
+            mWindowManagerFuncs.reboot(false, PowerManager.REBOOT_BOOTLOADER);
+        }
+    }
+
+    private final class RebootFastbootAction extends SinglePressAction {
+        private RebootFastbootAction() {
+            super(com.android.systemui.R.drawable.ic_restart_fastboot, com.android.systemui.R.string.global_action_reboot_fastboot);
+        }
+
+        @Override
+        public boolean showDuringKeyguard() {
+            return true;
+        }
+
+        @Override
+        public boolean showBeforeProvisioning() {
+            return true;
+        }
+
+        @Override
+        public void onPress() {
+            mWindowManagerFuncs.reboot(false, PowerManager.REBOOT_FASTBOOT);
         }
     }
 
@@ -1373,6 +1503,14 @@
         mInteractor.onShown();
     }
 
+    public void onClick(DialogInterface dialog, int which) {
+        Action item = mAdapter.getItem(which);
+        if (!(item instanceof SilentModeTriStateAction) && !(item instanceof RestartAction)) {
+            dialog.dismiss();
+        }
+        item.onPress();
+    }
+
     /**
      * The adapter used for power menu items shown in the global actions dialog.
      */
@@ -1479,7 +1617,7 @@
             if (!(item instanceof SilentModeTriStateAction)) {
                 if (mDialog != null) {
                     // don't dismiss the dialog if we're opening the power options menu
-                    if (!(item instanceof PowerOptionsAction)) {
+                    if (!(item instanceof PowerOptionsAction) && !(item instanceof RestartAction)) {
                         // Usually clicking an item shuts down the phone, locks, or starts an
                         // activity. We don't want to animate back into the power button when that
                         // happens, so we disable the dialog animation before dismissing.
@@ -1745,7 +1883,7 @@
     private abstract class SinglePressAction implements Action {
         private final int mIconResId;
         private final Drawable mIcon;
-        private final int mMessageResId;
+        protected int mMessageResId;
         private final CharSequence mMessage;
 
         protected SinglePressAction(int iconResId, int messageResId) {
@@ -2764,5 +2902,9 @@
         public void onRotate(int from, int to) {
             refreshDialog();
         }
+
+        public void updateList() {
+            mGlobalActionsLayout.updateList();
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
index c5027cc..e565ee1 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
@@ -67,9 +67,10 @@
     }
 
     @Override
-    public void showShutdownUi(boolean isReboot, String reason) {
-        mShutdownUi.showShutdownUi(isReboot, reason);
+    public void showShutdownUi(boolean isReboot, String reason, boolean rebootCustom) {
+        mShutdownUi.showShutdownUi(isReboot, reason, rebootCustom);
     }
+
     @Override
     public void disable(int displayId, int state1, int state2, boolean animate) {
         final boolean disabled = (state2 & DISABLE2_GLOBAL_ACTIONS) != 0;
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/ShutdownUi.java b/packages/SystemUI/src/com/android/systemui/globalactions/ShutdownUi.java
index 4599afa..db87923 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/ShutdownUi.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/ShutdownUi.java
@@ -60,7 +60,7 @@
      * @param reason Cause for the shutdown.
      * @return Shutdown dialog.
      */
-    public Dialog showShutdownUi(boolean isReboot, String reason) {
+    public Dialog showShutdownUi(boolean isReboot, String reason, boolean rebootCustom) {
         ScrimDrawable background = new ScrimDrawable();
 
         final Dialog d = new Dialog(mContext,
@@ -110,8 +110,8 @@
         reasonView.setTextColor(color);
         messageView.setTextColor(color);
 
-        messageView.setText(getRebootMessage(isReboot, reason));
-        String rebootReasonMessage = getReasonMessage(reason);
+        messageView.setText(getRebootMessage(isReboot, reason, rebootCustom));
+        String rebootReasonMessage = getReasonMessage(reason, rebootCustom);
         if (rebootReasonMessage != null) {
             reasonView.setVisibility(View.VISIBLE);
             reasonView.setText(rebootReasonMessage);
@@ -147,11 +147,17 @@
     }
 
     @StringRes
-    @VisibleForTesting int getRebootMessage(boolean isReboot, @Nullable String reason) {
+    @VisibleForTesting int getRebootMessage(boolean isReboot, @Nullable String reason, boolean custom) {
         if (reason != null && reason.startsWith(PowerManager.REBOOT_RECOVERY_UPDATE)) {
             return R.string.reboot_to_update_reboot;
-        } else if (reason != null && reason.equals(PowerManager.REBOOT_RECOVERY)) {
+        } else if (reason != null && !custom && reason.equals(PowerManager.REBOOT_RECOVERY)) {
             return R.string.reboot_to_reset_message;
+        } else if (reason != null && reason.equals(PowerManager.REBOOT_RECOVERY)) {
+            return org.omnirom.omnilib.R.string.reboot_to_recovery_message;
+        } else if (reason != null && reason.equals(PowerManager.REBOOT_BOOTLOADER)) {
+            return org.omnirom.omnilib.R.string.reboot_to_bootloader_message;
+        } else if (reason != null && reason.equals(PowerManager.REBOOT_FASTBOOT)) {
+            return org.omnirom.omnilib.R.string.reboot_to_fastboot_message;
         } else if (isReboot) {
             return R.string.reboot_to_reset_message;
         } else {
@@ -160,10 +166,10 @@
     }
 
     @Nullable
-    @VisibleForTesting String getReasonMessage(@Nullable String reason) {
+    @VisibleForTesting String getReasonMessage(@Nullable String reason, boolean custom) {
         if (reason != null && reason.startsWith(PowerManager.REBOOT_RECOVERY_UPDATE)) {
             return mContext.getString(R.string.reboot_to_update_title);
-        } else if (reason != null && reason.equals(PowerManager.REBOOT_RECOVERY)) {
+        } else if (reason != null && reason.equals(PowerManager.REBOOT_RECOVERY) && !custom) {
             return mContext.getString(R.string.reboot_to_reset_title);
         } else {
             return null;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
index 3b85b57..eccdba9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -18,12 +18,14 @@
 
 import android.annotation.AnyThread;
 import android.app.AlarmManager;
+import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.database.ContentObserver;
 import android.graphics.Typeface;
 import android.graphics.drawable.Icon;
 import android.icu.text.DateFormat;
@@ -33,6 +35,7 @@
 import android.net.Uri;
 import android.os.Handler;
 import android.os.Trace;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.service.notification.ZenModeConfig;
 import android.text.TextUtils;
@@ -45,12 +48,15 @@
 import androidx.slice.builders.ListBuilder;
 import androidx.slice.builders.ListBuilder.RowBuilder;
 import androidx.slice.builders.SliceAction;
+import androidx.slice.widget.SliceViewUtil;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.systemui.Dependency;
 import com.android.systemui.SystemUIAppComponentFactoryBase;
 import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.omni.OmniSettingsService;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.res.R;
 import com.android.systemui.settings.UserTracker;
@@ -64,6 +70,9 @@
 import com.android.systemui.util.wakelock.WakeLock;
 import com.android.systemui.util.wakelock.WakeLockLogger;
 
+import org.omnirom.omnilib.utils.OmniSettings;
+import org.omnirom.omnilib.weather.OmniJawsClient;
+
 import java.util.Date;
 import java.util.Locale;
 import java.util.TimeZone;
@@ -80,7 +89,8 @@
 public class KeyguardSliceProvider extends SliceProvider implements
         NextAlarmController.NextAlarmChangeCallback, ZenModeController.Callback,
         NotificationMediaManager.MediaListener, StatusBarStateController.StateListener,
-        SystemUIAppComponentFactoryBase.ContextInitializer {
+        SystemUIAppComponentFactoryBase.ContextInitializer, OmniJawsClient.OmniJawsObserver,
+        OmniSettingsService.OmniSettingsObserver {
 
     private static final String TAG = "KgdSliceProvider";
 
@@ -96,6 +106,7 @@
             "content://com.android.systemui.keyguard/media";
     public static final String KEYGUARD_ACTION_URI =
             "content://com.android.systemui.keyguard/action";
+    public static final String KEYGUARD_WEATHER_URI = "content://com.android.systemui.keyguard/weather";
 
     /**
      * Only show alarms that will ring within N hours.
@@ -157,6 +168,14 @@
     @Background
     Handler mBgHandler;
 
+    protected final Uri mWeatherUri;
+    private OmniJawsClient mWeatherClient;
+    private OmniJawsClient.WeatherInfo mWeatherData;
+    private boolean mShowWeatherSlice;
+    private boolean mShowAlarmSlice = true;
+    private boolean mShowDndSlice;
+    private boolean mAlarmSliceTimed;
+
     /**
      * Receiver responsible for time ticking and updating the date format.
      */
@@ -208,6 +227,7 @@
         mAlarmUri = Uri.parse(KEYGUARD_NEXT_ALARM_URI);
         mDndUri = Uri.parse(KEYGUARD_DND_URI);
         mMediaUri = Uri.parse(KEYGUARD_MEDIA_URI);
+        mWeatherUri = Uri.parse(KEYGUARD_WEATHER_URI);
     }
 
     @AnyThread
@@ -227,6 +247,7 @@
                 addNextAlarmLocked(builder);
                 addZenModeLocked(builder);
                 addPrimaryActionLocked(builder);
+                addWeatherLocked(builder);
                 slice = builder.build();
             }
         } catch (IllegalStateException e) {
@@ -281,28 +302,42 @@
     }
 
     protected void addNextAlarmLocked(ListBuilder builder) {
-        if (TextUtils.isEmpty(mNextAlarm)) {
+        if (TextUtils.isEmpty(mNextAlarm) || !mShowAlarmSlice) {
             return;
         }
+        final boolean zenNone = !zenAllowsAlarm();
         IconCompat alarmIcon = IconCompat.createWithResource(getContext(),
-                R.drawable.ic_access_alarms_big);
+                zenNone ? R.drawable.ic_access_alarms_big_dim : R.drawable.ic_access_alarms_big);
         RowBuilder alarmRowBuilder = new RowBuilder(mAlarmUri)
                 .setTitle(mNextAlarm)
                 .addEndItem(alarmIcon, ListBuilder.ICON_IMAGE);
         builder.addRow(alarmRowBuilder);
     }
 
+    protected void addWeatherLocked(ListBuilder builder) {
+        if (!mShowWeatherSlice || !mWeatherClient.isOmniJawsEnabled() || mWeatherData == null) {
+            return;
+        }
+        IconCompat weatherIcon = SliceViewUtil.createIconFromDrawable(mWeatherClient.getWeatherConditionImage(mWeatherData.conditionCode));
+        RowBuilder weatherRowBuilder = new RowBuilder(mWeatherUri)
+                .setTitle(mWeatherData.temp + " " + mWeatherData.tempUnits + " " + mWeatherData.city)
+                .addEndItem(weatherIcon, ListBuilder.ICON_IMAGE);
+        builder.addRow(weatherRowBuilder);
+    }
+
     /**
      * Add zen mode (DND) icon to slice if it's enabled.
      * @param builder The slice builder.
      */
     protected void addZenModeLocked(ListBuilder builder) {
-        if (!isDndOn()) {
+        if (!isDndOn() || !mShowDndSlice) {
             return;
         }
         RowBuilder dndBuilder = new RowBuilder(mDndUri)
                 .setContentDescription(getContext().getResources()
                         .getString(R.string.accessibility_quick_settings_dnd))
+                .setTitle(getContext().getResources()
+                        .getString(R.string.keyguard_slice_dnd))
                 .addEndItem(
                     IconCompat.createWithResource(getContext(), R.drawable.stat_sys_dnd),
                     ListBuilder.ICON_IMAGE);
@@ -342,6 +377,9 @@
             KeyguardSliceProvider.sInstance = this;
             registerClockUpdate();
             updateClockLocked();
+            Dependency.get(OmniSettingsService.class).addIntObserver(this, OmniSettings.OMNI_LOCKSCREEN_WEATHER_ENABLED,
+                    OmniSettings.OMNI_LOCKSCREEN_ALARM_ENABLED, OmniSettings.OMNI_LOCKSCREEN_DND_ENABLED);
+            enableWeatherUpdates();
         }
         return true;
     }
@@ -358,6 +396,8 @@
                 mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateMonitorCallback);
                 getContext().unregisterReceiver(mIntentReceiver);
             }
+            disableWeatherUpdates();
+            Dependency.get(OmniSettingsService.class).removeObserver(this);
             KeyguardSliceProvider.sInstance = null;
         }
     }
@@ -375,8 +415,9 @@
     private void updateNextAlarm() {
         synchronized (this) {
             if (withinNHoursLocked(mNextAlarmInfo, ALARM_VISIBILITY_HOURS)) {
-                String pattern = android.text.format.DateFormat.is24HourFormat(getContext(),
-                        mUserTracker.getUserId()) ? "HH:mm" : "h:mm";
+                String skeleton = android.text.format.DateFormat.is24HourFormat(getContext(),
+                        mUserTracker.getUserId()) ? "EHm" : "Ehma";
+                String pattern = android.text.format.DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton);
                 mNextAlarm = android.text.format.DateFormat.format(pattern,
                         mNextAlarmInfo.getTriggerTime()).toString();
             } else {
@@ -391,6 +432,9 @@
             return false;
         }
 
+        if (!mAlarmSliceTimed) {
+            return true;
+        }
         long limit = System.currentTimeMillis() + TimeUnit.HOURS.toMillis(hours);
         return mNextAlarmInfo.getTriggerTime() <= limit;
     }
@@ -457,13 +501,15 @@
     public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) {
         synchronized (this) {
             mNextAlarmInfo = nextAlarm;
-            mAlarmManager.cancel(mUpdateNextAlarm);
+            if (mAlarmSliceTimed) {
+                mAlarmManager.cancel(mUpdateNextAlarm);
 
-            long triggerAt = mNextAlarmInfo == null ? -1 : mNextAlarmInfo.getTriggerTime()
-                    - TimeUnit.HOURS.toMillis(ALARM_VISIBILITY_HOURS);
-            if (triggerAt > 0) {
-                mAlarmManager.setExact(AlarmManager.RTC, triggerAt, "lock_screen_next_alarm",
-                        mUpdateNextAlarm, mHandler);
+                long triggerAt = mNextAlarmInfo == null ? -1 : mNextAlarmInfo.getTriggerTime()
+                        - TimeUnit.HOURS.toMillis(ALARM_VISIBILITY_HOURS);
+                if (triggerAt > 0) {
+                    mAlarmManager.setExact(AlarmManager.RTC, triggerAt, "lock_screen_next_alarm",
+                            mUpdateNextAlarm, mHandler);
+                }
             }
         }
         updateNextAlarm();
@@ -560,4 +606,82 @@
             SystemUIAppComponentFactoryBase.ContextAvailableCallback callback) {
         mContextAvailableCallback = callback;
     }
+
+    private void enableWeatherUpdates() {
+        mWeatherClient = new OmniJawsClient(getContext());
+        mWeatherClient.addObserver(this);
+        queryAndUpdateWeather();
+    }
+
+    private void disableWeatherUpdates() {
+        if (mWeatherClient != null) {
+            mWeatherClient.removeObserver(this);
+        }
+    }
+
+    @Override
+    public void weatherError(int errorReason) {
+        // since this is shown in ambient and lock screen
+        // it would look bad to show every error since the
+        // screen-on revovery of the service had no chance
+        // to run fast enough
+        // so only show the disabled state
+        if (errorReason == OmniJawsClient.EXTRA_ERROR_DISABLED) {
+            mWeatherData = null;
+            notifyChange();
+        }
+    }
+
+    @Override
+    public void weatherUpdated() {
+        queryAndUpdateWeather();
+    }
+
+    @Override
+    public void updateSettings() {
+        queryAndUpdateWeather();
+    }
+
+    private void queryAndUpdateWeather() {
+        if (mWeatherClient != null) {
+            mWeatherClient.queryWeather();
+            mWeatherData = mWeatherClient.getWeatherInfo();
+            notifyChange();
+        }
+    }
+
+    @Override
+    public void onConsolidatedPolicyChanged(NotificationManager.Policy policy) {
+        notifyChange();
+    }
+
+    private boolean zenAllowsAlarm() {
+        int zen = mZenModeController.getZen();
+        if (zen == Settings.Global.ZEN_MODE_OFF) {
+            return true;
+        }
+        if (zen == Settings.Global.ZEN_MODE_NO_INTERRUPTIONS) {
+            return false;
+        }
+        if (zen == Settings.Global.ZEN_MODE_ALARMS) {
+            return true;
+        }
+        boolean allowAlarms = (mZenModeController.getConsolidatedPolicy().priorityCategories & NotificationManager.Policy
+                .PRIORITY_CATEGORY_ALARMS) != 0;
+        return allowAlarms;
+    }
+
+    @Override
+    public void onIntSettingChanged(String key, Integer newValue) {
+        mShowWeatherSlice = Settings.System.getIntForUser(mContentResolver,
+                    OmniSettings.OMNI_LOCKSCREEN_WEATHER_ENABLED,
+                    0, UserHandle.USER_CURRENT) != 0;
+        mShowAlarmSlice = Settings.System.getIntForUser(mContentResolver,
+                    OmniSettings.OMNI_LOCKSCREEN_ALARM_ENABLED,
+                    1, UserHandle.USER_CURRENT) != 0;
+        mShowDndSlice = Settings.System.getIntForUser(mContentResolver,
+                    OmniSettings.OMNI_LOCKSCREEN_DND_ENABLED,
+                    0, UserHandle.USER_CURRENT) != 0;
+        notifyChange();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/log/SessionTracker.java b/packages/SystemUI/src/com/android/systemui/log/SessionTracker.java
index e8ded03..74bdfa1 100644
--- a/packages/SystemUI/src/com/android/systemui/log/SessionTracker.java
+++ b/packages/SystemUI/src/com/android/systemui/log/SessionTracker.java
@@ -181,6 +181,20 @@
             mKeyguardSessionStarted = true;
             startSession(SESSION_KEYGUARD);
         }
+
+        @Override
+        public void onStartedWakingUp() {
+            boolean wasSessionStarted = mKeyguardSessionStarted;
+            boolean keyguardShowing = mKeyguardStateController.isShowing();
+
+            // pressed power button BEFORE onKeyguardShowingChanged came
+            // left us with a dangling session start that wont go away
+            // until the next sleep cycle
+            if (wasSessionStarted && !keyguardShowing) {
+                endSession(SESSION_KEYGUARD, SessionUiEvent.KEYGUARD_SESSION_END_GOING_TO_SLEEP);
+                mKeyguardSessionStarted = false;
+            }
+        }
     };
 
 
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index b1719107..2aea3b2 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -52,8 +52,10 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.Trace;
+import android.os.UserHandle;
 import android.provider.DeviceConfig;
 import android.util.ArraySet;
+import android.provider.Settings;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.TypedValue;
@@ -109,6 +111,8 @@
 import dagger.assisted.AssistedFactory;
 import dagger.assisted.AssistedInject;
 
+import org.omnirom.omnilib.utils.OmniSettings;
+
 import kotlinx.coroutines.Job;
 
 import java.io.PrintWriter;
@@ -364,6 +368,9 @@
     private final Consumer<Boolean> mOnIsInPipStateChangedListener =
             (isInPip) -> mIsInPip = isInPip;
 
+    // omni additions start
+    private int mEdgeHeight;
+
     private final Consumer<Region> mDesktopCornersChangedListener =
             (desktopExcludeRegion) -> mDesktopModeExcludeRegion.set(desktopExcludeRegion);
 
@@ -586,6 +593,7 @@
         mNonLinearFactor = getDimenFloat(res,
                 com.android.internal.R.dimen.back_progress_non_linear_factor);
         updateBackAnimationThresholds();
+        updateEdgeHeightValue();
         mBackgroundExecutor.execute(this::disableNavBarVirtualKeyHapticFeedback);
     }
 
@@ -607,6 +615,25 @@
         }
     }
 
+    private void updateEdgeHeightValue() {
+        int edgeHeightSetting = Settings.System.getIntForUser(mContext.getContentResolver(),
+                OmniSettings.OMNI_BACK_GESTURE_HEIGHT, 0, UserHandle.USER_CURRENT);
+        // edgeHeigthSettings cant be range 0 - 3
+        // 0 means full height
+        // 1 measns half of the screen
+        // 2 means lower third of the screen
+        // 3 means lower sicth of the screen
+        if (edgeHeightSetting == 0) {
+            mEdgeHeight = mDisplaySize.y;
+        } else if (edgeHeightSetting == 1) {
+            mEdgeHeight = mDisplaySize.y / 2;
+        } else if (edgeHeightSetting == 2) {
+            mEdgeHeight = mDisplaySize.y / 3;
+        } else {
+            mEdgeHeight = mDisplaySize.y / 6;
+        }
+    }
+
     private void updateTopActivity() {
         if (edgebackGestureHandlerGetRunningTasksBackground()) {
             mBackgroundExecutor.execute(() -> updateTopActivityPackageName());
@@ -937,6 +964,12 @@
         if (y >= (mDisplaySize.y - mBottomGestureHeight)) {
             return false;
         }
+        if (mEdgeHeight != 0) {
+            if (y < (mDisplaySize.y - mBottomGestureHeight - mEdgeHeight)) {
+                return false;
+            }
+        }
+
         // If the point is way too far (twice the margin), it is
         // not interesting to us for logging purposes, nor we
         // should process it.  Simply return false and keep
@@ -1258,6 +1291,7 @@
             mEdgeBackPlugin.setDisplaySize(mDisplaySize);
         }
         updateBackAnimationThresholds();
+        updateEdgeHeightValue();
     }
 
     private void updateBackAnimationThresholds() {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBar.java
index c895732..10e322f 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBar.java
@@ -165,6 +165,8 @@
 
 import dagger.Lazy;
 
+import org.omnirom.omnilib.utils.TaskUtils;
+
 import java.io.PrintWriter;
 import java.util.Locale;
 import java.util.Map;
@@ -1332,6 +1334,10 @@
         ButtonDispatcher backButton = mView.getBackButton();
         backButton.setNavBarButtonClickLogger(mNavBarButtonClickLogger);
 
+        ButtonDispatcher homeHandleButton = mView.getHomeHandle();
+        homeHandleButton.setLongClickable(true);
+        homeHandleButton.setOnLongClickListener(this::onHomeHandleLongClick);
+
         reconfigureHomeLongClick();
 
         ButtonDispatcher accessibilityButton = mView.getAccessibilityButton();
@@ -1933,6 +1939,10 @@
         updateButtonLocation(
                 region, touchRegionCache, mView.getAccessibilityButton(), inScreenSpace,
                 useNearestRegion);
+        updateButtonLocation(region, mView.getKeyButtonViewById(R.id.dpad_left), inScreenSpace);
+        updateButtonLocation(region, mView.getKeyButtonViewById(R.id.dpad_right), inScreenSpace);
+        updateButtonLocation(
+                region, touchRegionCache, mView.getHomeHandle(), inScreenSpace, useNearestRegion);
         if (mView.getFloatingRotationButton().isVisible()) {
             // Note: this button is floating so the nearest region doesn't apply
             updateButtonLocation(
@@ -2099,4 +2109,9 @@
             return false;
         }
     };
+
+    private boolean onHomeHandleLongClick(View v) {
+        TaskUtils.toggleLastApp(mContext, mUserTracker.getUserId());
+        return true;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBarInflaterView.java
index 96b730c..e8a228f 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBarInflaterView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBarInflaterView.java
@@ -23,6 +23,8 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.graphics.drawable.Icon;
+import android.os.UserHandle;
+import android.provider.Settings;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.SparseArray;
@@ -41,15 +43,20 @@
 import com.android.systemui.navigationbar.views.buttons.KeyButtonView;
 import com.android.systemui.navigationbar.views.buttons.ReverseLinearLayout;
 import com.android.systemui.navigationbar.views.buttons.ReverseLinearLayout.ReverseRelativeLayout;
+import com.android.systemui.omni.OmniSettingsService;
 import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.res.R;
 import com.android.systemui.shared.system.QuickStepContract;
 
+import org.omnirom.omnilib.utils.OmniSettings;
+
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.Objects;
 
-public class NavigationBarInflaterView extends FrameLayout {
+public class NavigationBarInflaterView extends FrameLayout
+        implements OmniSettingsService.OmniSettingsObserver {
+
     private static final String TAG = "NavBarInflater";
 
     public static final String NAV_BAR_VIEWS = "sysui_nav_bar";
@@ -157,12 +164,21 @@
     }
 
     protected String getDefaultLayout() {
-        final int defaultResource = QuickStepContract.isGesturalMode(mNavBarMode)
-                ? R.string.config_navBarLayoutHandle
-                : mOverviewProxyService.shouldShowSwipeUpUI()
-                        ? R.string.config_navBarLayoutQuickstep
-                        : R.string.config_navBarLayout;
-        return getContext().getString(defaultResource);
+        if (QuickStepContract.isGesturalMode(mNavBarMode)) {
+            String navbarLayout = getContext().getString(showDpadArrowKeys()
+                    ? R.string.config_navBarLayoutHandleArrows
+                    : R.string.config_navBarLayoutHandle);
+            if (hideGestureHandle()) {
+                return navbarLayout.replace(HOME_HANDLE, NAVSPACE);
+            } else {
+                return navbarLayout;
+            }
+        } else {
+            final int defaultResource = mOverviewProxyService.shouldShowSwipeUpUI()
+                            ? R.string.config_navBarLayoutQuickstep
+                            : R.string.config_navBarLayout;
+            return getContext().getString(defaultResource);
+        }
     }
 
     private void onNavigationModeChanged(int mode) {
@@ -172,9 +188,21 @@
     @Override
     protected void onDetachedFromWindow() {
         Dependency.get(NavigationModeController.class).removeListener(mListener);
+        Dependency.get(OmniSettingsService.class).removeObserver(this);
         super.onDetachedFromWindow();
     }
 
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        Dependency.get(OmniSettingsService.class).addIntObserver(this,
+            OmniSettings.OMNI_NAVIGATION_BAR_ARROW_KEYS);
+        Dependency.get(OmniSettingsService.class).addIntObserver(this,
+            OmniSettings.OMNI_GESTURE_HANDLE_HIDE);
+        Dependency.get(OmniSettingsService.class).addIntObserver(this, 
+            OmniSettings.OMNI_GESTURE_HANDLE_SMALL);
+    }
+
     public void onLikelyDefaultLayoutChange() {
         // Reevaluate new layout
         final String newValue = getDefaultLayout();
@@ -184,6 +212,12 @@
         }
     }
 
+    private void onForceDefaultLayoutChange() {
+        final String newValue = getDefaultLayout();
+        clearViews();
+        inflateLayout(newValue);
+    }
+
     public void setButtonDispatchers(SparseArray<ButtonDispatcher> buttonDispatchers) {
         mButtonDispatchers = buttonDispatchers;
         clearDispatcherViews();
@@ -402,7 +436,7 @@
         } else if (CONTEXTUAL.equals(button)) {
             v = inflater.inflate(R.layout.contextual, parent, false);
         } else if (HOME_HANDLE.equals(button)) {
-            v = inflater.inflate(R.layout.home_handle, parent, false);
+            v = inflater.inflate(isSmallGestureHandle() ? R.layout.home_handle_small : R.layout.home_handle, parent, false);
         } else if (IME_SWITCHER.equals(button)) {
             v = inflater.inflate(R.layout.ime_switcher, parent, false);
         } else if (button.startsWith(KEY)) {
@@ -489,7 +523,9 @@
 
     private void clearAllChildren(ViewGroup group) {
         for (int i = 0; i < group.getChildCount(); i++) {
-            ((ViewGroup) group.getChildAt(i)).removeAllViews();
+            if (group.getChildAt(i).getId() != R.id.dpad_group) {
+                ((ViewGroup) group.getChildAt(i)).removeAllViews();
+            }
         }
     }
 
@@ -497,6 +533,26 @@
         return dp * context.getResources().getDisplayMetrics().density;
     }
 
+    private boolean showDpadArrowKeys() {
+        return Settings.System.getIntForUser(getContext().getContentResolver(),
+                OmniSettings.OMNI_NAVIGATION_BAR_ARROW_KEYS, 0, UserHandle.USER_CURRENT) != 0;
+    }
+
+    private boolean hideGestureHandle() {
+        return Settings.System.getIntForUser(getContext().getContentResolver(),
+                OmniSettings.OMNI_GESTURE_HANDLE_HIDE, 0, UserHandle.USER_CURRENT) != 0;
+    }
+
+    private boolean isSmallGestureHandle() {
+        return Settings.System.getIntForUser(getContext().getContentResolver(),
+                OmniSettings.OMNI_GESTURE_HANDLE_SMALL, 0, UserHandle.USER_CURRENT) != 0;
+    }
+
+    @Override
+    public void onIntSettingChanged(String key, Integer newValue) {
+        onForceDefaultLayoutChange();
+    }
+
     public void dump(PrintWriter pw) {
         pw.println("NavigationBarInflaterView");
         pw.println("  mCurrentLayout: " + mCurrentLayout);
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBarTransitions.java
index 251745d..735337d 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBarTransitions.java
@@ -191,6 +191,7 @@
             buttonDispatchers.valueAt(i).setDarkIntensity(darkIntensity);
         }
         mView.getRotationButtonController().setDarkIntensity(darkIntensity);
+        mView.setDpadDarkIntensity(darkIntensity);
 
         for (DarkIntensityListener listener : mDarkIntensityListeners) {
             listener.onDarkIntensity(darkIntensity);
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBarView.java
index c4abcd2..2284eef 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/views/NavigationBarView.java
@@ -39,6 +39,8 @@
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.RemoteException;
+import android.os.UserHandle;
+import android.provider.Settings;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.SparseArray;
@@ -63,6 +65,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.settingslib.Utils;
 import com.android.systemui.Gefingerpoken;
+import com.android.systemui.Dependency;
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.navigationbar.ScreenPinningNotify;
 import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler;
@@ -71,7 +74,9 @@
 import com.android.systemui.navigationbar.views.buttons.ContextualButtonGroup;
 import com.android.systemui.navigationbar.views.buttons.DeadZone;
 import com.android.systemui.navigationbar.views.buttons.KeyButtonDrawable;
+import com.android.systemui.navigationbar.views.buttons.KeyButtonView;
 import com.android.systemui.navigationbar.views.buttons.NearestTouchFrame;
+import com.android.systemui.omni.OmniSettingsService;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.res.R;
 import com.android.systemui.settings.DisplayTracker;
@@ -87,6 +92,8 @@
 import com.android.wm.shell.back.BackAnimation;
 import com.android.wm.shell.pip.Pip;
 
+import org.omnirom.omnilib.utils.OmniSettings;
+
 import java.io.PrintWriter;
 import java.util.Map;
 import java.util.Optional;
@@ -94,7 +101,8 @@
 import java.util.function.Consumer;
 
 /** */
-public class NavigationBarView extends FrameLayout {
+public class NavigationBarView extends FrameLayout implements
+        OmniSettingsService.OmniSettingsObserver {
     final static boolean DEBUG = false;
     final static String TAG = "NavBarView";
 
@@ -117,6 +125,8 @@
     private int mNavBarMode;
     private boolean mImeDrawsImeNavBar;
 
+    private KeyButtonDrawable mArrowLeftIcon;
+    private KeyButtonDrawable mArrowRightIcon;
     private KeyButtonDrawable mBackIcon;
     private KeyButtonDrawable mHomeDefaultIcon;
     private KeyButtonDrawable mRecentIcon;
@@ -142,6 +152,7 @@
     private boolean mInCarMode = false;
     private boolean mDockedStackExists;
     private boolean mScreenOn = true;
+    private boolean mShowDpadArrowKeys;
 
     private final SparseArray<ButtonDispatcher> mButtonDispatchers = new SparseArray<>();
     private final ContextualButtonGroup mContextualButtonGroup;
@@ -454,6 +465,10 @@
         return mShowSwipeUpUi && isOverviewEnabled();
     }
 
+    public KeyButtonView getKeyButtonViewById(int id) {
+        return (KeyButtonView) getCurrentView().findViewById(id);
+    }
+
     private void reloadNavIcons() {
         updateIcons(Configuration.EMPTY);
     }
@@ -474,6 +489,8 @@
         if (orientationChange || densityChange || dirChange) {
             mBackIcon = getBackDrawable();
         }
+        mArrowLeftIcon = getDrawable(R.drawable.ic_navbar_chevron_left);
+        mArrowRightIcon = getDrawable(R.drawable.ic_navbar_chevron_right);
     }
 
     /**
@@ -600,12 +617,23 @@
 
         updateRecentsIcon();
 
+        if (mShowDpadArrowKeys) {
+            getKeyButtonViewById(R.id.dpad_left).setImageDrawable(mArrowLeftIcon);
+            getKeyButtonViewById(R.id.dpad_right).setImageDrawable(mArrowRightIcon);
+            updateDpadKeys();
+        }
+
         // Update IME button visibility, a11y and rotate button always overrides the appearance
         boolean disableImeSwitcher =
                 (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SWITCHER_SHOWN) == 0
                 || isImeRenderingNavButtons();
         mContextualButtonGroup.setButtonVisibility(R.id.ime_switcher, !disableImeSwitcher);
 
+        // right arrow overrules ime in 3 button mode cause there is not enough space
+        if (QuickStepContract.isLegacyMode(mNavBarMode) && mShowDpadArrowKeys) {
+            mContextualButtonGroup.setButtonVisibility(R.id.ime_switcher, false);
+        }
+
         mBarTransitions.reapplyDarkIntensity();
 
         boolean disableHome = isGesturalMode(mNavBarMode)
@@ -1082,6 +1110,8 @@
         }
 
         updateNavButtonIcons();
+        Dependency.get(OmniSettingsService.class).addIntObserver(this,
+                OmniSettings.OMNI_NAVIGATION_BAR_ARROW_KEYS);
     }
 
     @Override
@@ -1094,6 +1124,7 @@
             mFloatingRotationButton.hide();
             mRotationButtonController.unregisterListeners();
         }
+        Dependency.get(OmniSettingsService.class).removeObserver(this);
     }
 
     void dump(PrintWriter pw) {
@@ -1202,4 +1233,28 @@
     interface UpdateActiveTouchRegionsCallback {
         void update();
     }
+
+    private void updateDpadKeys() {
+        final int visibility = mShowDpadArrowKeys && (mNavigationIconHints
+                & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0 ? View.VISIBLE : View.GONE;
+        getKeyButtonViewById(R.id.dpad_left).setVisibility(visibility);
+        getKeyButtonViewById(R.id.dpad_right).setVisibility(visibility);
+    }
+    public void setDpadDarkIntensity(float darkIntensity) {
+        if (mShowDpadArrowKeys) {
+            getKeyButtonViewById(R.id.dpad_left).setDarkIntensity(darkIntensity);
+            getKeyButtonViewById(R.id.dpad_right).setDarkIntensity(darkIntensity);
+        }
+    }
+    private boolean showDpadArrowKeys() {
+        return Settings.System.getIntForUser(getContext().getContentResolver(),
+                OmniSettings.OMNI_NAVIGATION_BAR_ARROW_KEYS, 0, UserHandle.USER_CURRENT) != 0;
+    }
+
+    @Override
+    public void onIntSettingChanged(String key, Integer newValue) {
+        mShowDpadArrowKeys = showDpadArrowKeys();
+        updateNavButtonIcons();
+        notifyActiveTouchRegions();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/views/buttons/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/views/buttons/KeyButtonView.java
index 111a2d4..74fffbd 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/views/buttons/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/views/buttons/KeyButtonView.java
@@ -69,6 +69,9 @@
 public class KeyButtonView extends ImageView implements ButtonInterface {
     private static final String TAG = KeyButtonView.class.getSimpleName();
 
+    public static final int CURSOR_REPEAT_FLAGS = KeyEvent.FLAG_SOFT_KEYBOARD
+            | KeyEvent.FLAG_KEEP_TOUCH_MODE;
+
     private final boolean mPlaySounds;
     private final UiEventLogger mUiEventLogger;
     private int mContentDescriptionRes;
@@ -134,7 +137,13 @@
         public void run() {
             if (isPressed()) {
                 // Log.d("KeyButtonView", "longpressed: " + this);
-                if (isLongClickable()) {
+                if (mCode == KeyEvent.KEYCODE_DPAD_LEFT || mCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
+                    sendEvent(KeyEvent.ACTION_UP, CURSOR_REPEAT_FLAGS,
+                            System.currentTimeMillis(), false);
+                    sendEvent(KeyEvent.ACTION_DOWN, CURSOR_REPEAT_FLAGS,
+                            System.currentTimeMillis(), false);
+                    postDelayed(mCheckLongPress, ViewConfiguration.getKeyRepeatDelay());
+                } else if (isLongClickable()) {
                     // Just an old-fashioned ImageView
                     performLongClick();
                     mLongClicked = true;
@@ -301,7 +310,10 @@
 
                 mTouchDownX = (int) ev.getX();
                 mTouchDownY = (int) ev.getY();
-                if (mCode != KEYCODE_UNKNOWN) {
+                if (mCode == KeyEvent.KEYCODE_DPAD_LEFT || mCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
+                    sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.FLAG_VIRTUAL_HARD_KEY
+                            | KeyEvent.FLAG_KEEP_TOUCH_MODE, mDownTime, false);
+                } else if (mCode != KEYCODE_UNKNOWN) {
                     sendEvent(KeyEvent.ACTION_DOWN, 0, mDownTime);
                 } else {
                     // Provide the same haptic feedback that the system offers for virtual keys.
@@ -438,6 +450,10 @@
     }
 
     private void sendEvent(int action, int flags, long when) {
+        sendEvent(action, flags, when, true);
+    }
+
+    private void sendEvent(int action, int flags, long when, boolean applyDefaultFlags) {
         mMetricsLogger.write(new LogMaker(MetricsEvent.ACTION_NAV_BUTTON_EVENT)
                 .setType(MetricsEvent.TYPE_ACTION)
                 .setSubtype(mCode)
@@ -448,9 +464,12 @@
             Log.i(TAG, "Back button event: " + KeyEvent.actionToString(action));
         }
         final int repeatCount = (flags & KeyEvent.FLAG_LONG_PRESS) != 0 ? 1 : 0;
+        if (applyDefaultFlags) {
+            flags |= KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY;
+        }
         final KeyEvent ev = new KeyEvent(mDownTime, when, action, mCode, repeatCount,
                 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
-                flags | KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
+                flags,
                 InputDevice.SOURCE_KEYBOARD);
 
         int displayId = INVALID_DISPLAY;
diff --git a/packages/SystemUI/src/com/android/systemui/omni/CPUInfoManager.java b/packages/SystemUI/src/com/android/systemui/omni/CPUInfoManager.java
new file mode 100644
index 0000000..2fa69fd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/omni/CPUInfoManager.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2020 The OmniROM 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.omni;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+import com.android.systemui.res.R;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.CoreStartable;
+import com.android.systemui.Dependency;
+
+import javax.inject.Inject;
+
+@SysUISingleton
+public class CPUInfoManager implements CoreStartable, OmniSettingsService.OmniSettingsObserver {
+    private final String TAG = "CPUInfoManager";
+    private final String OMNI_SHOW_CPU_OVERLAY = "show_cpu_overlay";
+    private Context mContext;
+
+    @Inject
+    public CPUInfoManager(Context context) {
+        mContext = context;
+    }
+
+    @Override
+    public void start() {
+    }
+
+    @Override
+    public void onBootCompleted() {
+        Log.d(TAG, "CPUInfoManager onBootCompleted");
+        Dependency.get(OmniSettingsService.class).addIntObserver(this, OMNI_SHOW_CPU_OVERLAY);
+    }
+
+    @Override
+    public void onIntSettingChanged(String key, Integer newValue) {
+        if (OMNI_SHOW_CPU_OVERLAY.equals(key)) {
+            try {
+                Intent cpuinfo = new Intent(mContext, com.android.systemui.omni.CPUInfoService.class);
+                if (newValue != null && newValue == 1) {
+                    mContext.startService(cpuinfo);
+                } else {
+                    mContext.stopService(cpuinfo);
+                }
+            } catch (Exception e) {
+                Log.e(TAG, "CPUInfoManager update ", e);
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/omni/CPUInfoService.java b/packages/SystemUI/src/com/android/systemui/omni/CPUInfoService.java
new file mode 100644
index 0000000..93b1eeb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/omni/CPUInfoService.java
@@ -0,0 +1,469 @@
+/*
+ * Copyright (C) 2017 The OmniROM 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.omni;
+
+import android.app.Service;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.Typeface;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.service.dreams.DreamService;
+import android.service.dreams.IDreamManager;
+import android.view.Gravity;
+import android.view.View;
+import android.view.WindowManager;
+import android.util.Log;
+
+import com.android.systemui.res.R;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.lang.StringBuffer;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class CPUInfoService extends Service {
+    private View mView;
+    private Thread mCurCPUThread;
+    private final String TAG = "CPUInfoService";
+    private final boolean DEBUG = false;
+    private int mNumCpus = 2;
+    private String[] mCpu = null;
+    private String[] mCurrFreq = null;
+    private String[] mCurrGov = null;
+
+    private int CPU_TEMP_DIVIDER = 1;
+    private String CPU_TEMP_SENSOR = "";
+    private String DISPLAY_CPUS = "";
+    private boolean mCpuTempAvail;
+    private int mTextHeight;
+
+    private static final String NUM_OF_CPUS_PATH = "/sys/devices/system/cpu/present";
+    private static final String CURRENT_CPU = "/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq";
+    private static final String CPU_ROOT = "/sys/devices/system/cpu/cpu";
+    private static final String CPU_CUR_TAIL = "/cpufreq/scaling_cur_freq";
+    private static final String CPU_GOV_TAIL = "/cpufreq/scaling_governor";
+
+    private IDreamManager mDreamManager;
+
+    private class CPUView extends View {
+        private Paint mOnlinePaint;
+        private Paint mOfflinePaint;
+        private float mAscent;
+        private int mFH;
+        private int mMaxWidth;
+        private int mExtraPaddingTop;
+
+        private int mNeededWidth;
+        private int mNeededHeight;
+        private String mCpuTemp;
+
+        private boolean mDataAvail;
+
+        private Handler mCurCPUHandler = new Handler() {
+            public void handleMessage(Message msg) {
+                if(msg.obj==null){
+                    return;
+                }
+                if(msg.what==1){
+                    String msgData = (String) msg.obj;
+                    try {
+                        if (DEBUG) Log.d(TAG, "msgData = " + msgData);
+                        String[] parts=msgData.split(";");
+                        mCpuTemp=parts[0];
+
+                        String[] cpuParts=parts[1].split("\\|");
+                        for(int i=0; i<cpuParts.length; i++){
+                            String cpuInfo=cpuParts[i];
+                            String cpuInfoParts[]=cpuInfo.split(":");
+                            if(cpuInfoParts.length==3){
+                                mCurrFreq[i]=cpuInfoParts[1];
+                                mCurrGov[i]=cpuInfoParts[2];
+                            } else {
+                                mCurrFreq[i]="0";
+                                mCurrGov[i]="";
+                            }
+                        }
+                        mDataAvail = true;
+                        updateDisplay();
+                    } catch(ArrayIndexOutOfBoundsException e) {
+                        Log.e(TAG, "illegal data " + msgData);
+                    }
+                }
+            }
+        };
+
+        CPUView(Context c) {
+            super(c);
+            float density = c.getResources().getDisplayMetrics().density;
+            int paddingPx = Math.round(5 * density);
+            setPadding(paddingPx, paddingPx, paddingPx, paddingPx);
+            setBackgroundColor(Color.argb(0x60, 0, 0, 0));
+
+            final int textSize = mTextHeight;
+            mExtraPaddingTop = c.getResources().getDimensionPixelSize(R.dimen.status_bar_height);
+
+            Typeface typeface = Typeface.create("monospace", Typeface.NORMAL);
+
+            mOnlinePaint = new Paint();
+            mOnlinePaint.setTypeface(typeface);
+            mOnlinePaint.setAntiAlias(true);
+            mOnlinePaint.setTextSize(textSize);
+            mOnlinePaint.setColor(Color.WHITE);
+            mOnlinePaint.setShadowLayer(5.0f, 0.0f, 0.0f, Color.BLACK);
+
+            mOfflinePaint = new Paint();
+            mOfflinePaint.setTypeface(typeface);
+            mOfflinePaint.setAntiAlias(true);
+            mOfflinePaint.setTextSize(textSize);
+            mOfflinePaint.setColor(Color.RED);
+
+            mAscent = mOnlinePaint.ascent();
+            float descent = mOnlinePaint.descent();
+            mFH = (int)(descent - mAscent + .5f);
+
+            final String maxWidthStr="cpuX: interactive 00000000";
+            mMaxWidth = (int)mOnlinePaint.measureText(maxWidthStr);
+
+            updateDisplay();
+        }
+
+        @Override
+        protected void onAttachedToWindow() {
+            super.onAttachedToWindow();
+        }
+
+        @Override
+        protected void onDetachedFromWindow() {
+            super.onDetachedFromWindow();
+            mCurCPUHandler.removeMessages(1);
+        }
+
+        @Override
+        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+            setMeasuredDimension(resolveSize(mNeededWidth, widthMeasureSpec),
+                    resolveSize(mNeededHeight, heightMeasureSpec));
+        }
+
+        private String getCPUInfoString(int i) {
+            String cpu=mCpu[i];
+            String freq=mCurrFreq[i];
+            String gov=mCurrGov[i];
+            return "cpu" + cpu + ": " + gov + " " + String.format("%8s", toMHz(freq));
+        }
+
+        private String getCpuTemp(String cpuTemp) {
+            if (CPU_TEMP_DIVIDER > 1) {
+                return String.format("%s",
+                        Integer.parseInt(cpuTemp) / CPU_TEMP_DIVIDER);
+            } else {
+                return cpuTemp;
+            }
+        }
+
+        @Override
+        public void onDraw(Canvas canvas) {
+            super.onDraw(canvas);
+            if (!mDataAvail) {
+                return;
+            }
+
+            final int W = mNeededWidth;
+            final int RIGHT = getWidth()-1;
+
+            int x = RIGHT - mPaddingRight;
+            int top = mExtraPaddingTop + mPaddingTop + 2;
+            int bottom = mExtraPaddingTop + mPaddingTop + mFH - 2;
+
+            int y = mExtraPaddingTop + mPaddingTop - (int)mAscent;
+
+            if(!mCpuTemp.equals("0")) {
+                canvas.drawText("Temp: " + getCpuTemp(mCpuTemp) + "°C",
+                        RIGHT-mPaddingRight-mMaxWidth, y-1, mOnlinePaint);
+                y += mFH;
+            }
+
+            for(int i=0; i<mCurrFreq.length; i++){
+                String s=getCPUInfoString(i);
+                String freq=mCurrFreq[i];
+                if(!freq.equals("0")){
+                    canvas.drawText(s, RIGHT-mPaddingRight-mMaxWidth,
+                        y-1, mOnlinePaint);
+                } else {
+                    canvas.drawText("cpu" + mCpu[i] + ": offline", RIGHT-mPaddingRight-mMaxWidth,
+                        y-1, mOfflinePaint);
+                }
+                y += mFH;
+            }
+        }
+
+        void updateDisplay() {
+            if (!mDataAvail) {
+                return;
+            }
+            final int NW = mNumCpus;
+
+            int neededWidth = mPaddingLeft + mPaddingRight + mMaxWidth;
+            int neededHeight = mExtraPaddingTop + mPaddingTop + mPaddingBottom + (mFH*((mCpuTempAvail?1:0)+NW));
+            if (neededWidth != mNeededWidth || neededHeight != mNeededHeight) {
+                mNeededWidth = neededWidth;
+                mNeededHeight = neededHeight;
+                requestLayout();
+            } else {
+                invalidate();
+            }
+        }
+
+        private String toMHz(String mhzString) {
+            return new StringBuilder().append(Integer.valueOf(mhzString) / 1000).append(" MHz").toString();
+        }
+
+        public Handler getHandler(){
+            return mCurCPUHandler;
+        }
+    }
+
+    protected class CurCPUThread extends Thread {
+        private boolean mInterrupt = false;
+        private Handler mHandler;
+
+        public CurCPUThread(Handler handler, int numCpus){
+            mHandler=handler;
+            mNumCpus = numCpus;
+        }
+
+        public void interrupt() {
+            mInterrupt = true;
+        }
+
+        @Override
+        public void run() {
+            try {
+                while (!mInterrupt) {
+                    sleep(500);
+                    StringBuffer sb=new StringBuffer();
+                    String cpuTemp = CPUInfoService.readOneLine(CPU_TEMP_SENSOR);
+                    sb.append(cpuTemp == null ? "0" : cpuTemp);
+                    sb.append(";");
+
+                    for(int i=0; i<mNumCpus; i++) {
+                        final String currCpu = mCpu[i];
+                        final String freqFile=CPU_ROOT + mCpu[i] + CPU_CUR_TAIL;
+                        String currFreq = CPUInfoService.readOneLine(freqFile);
+                        final String govFile=CPU_ROOT + mCpu[i] + CPU_GOV_TAIL;
+                        String currGov = CPUInfoService.readOneLine(govFile);
+
+                        if(currFreq==null){
+                            currFreq="0";
+                            currGov="";
+                        }
+
+                        sb.append(currCpu+":"+currFreq+":"+currGov+"|");
+                    }
+                    sb.deleteCharAt(sb.length()-1);
+                    mHandler.sendMessage(mHandler.obtainMessage(1, sb.toString()));
+                }
+            } catch (InterruptedException e) {
+                return;
+            }
+        }
+    };
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        Log.d(TAG, "CPUInfoService onCreate");
+
+        CPU_TEMP_DIVIDER = getResources().getInteger(R.integer.config_cpuTempDivider);
+        CPU_TEMP_SENSOR = getResources().getString(R.string.config_cpuTempSensor);
+        DISPLAY_CPUS = getResources().getString(R.string.config_displayCpus);
+        mTextHeight = getResources().getDimensionPixelSize(R.dimen.cpu_info_text_height);
+
+        mNumCpus = getCpus(DISPLAY_CPUS);
+        mCurrFreq = new String[mNumCpus];
+        mCurrGov = new String[mNumCpus];
+
+        mCpuTempAvail = readOneLine(CPU_TEMP_SENSOR) != null;
+
+        mView = new CPUView(this);
+        WindowManager.LayoutParams params = new WindowManager.LayoutParams(
+            WindowManager.LayoutParams.WRAP_CONTENT,
+            WindowManager.LayoutParams.WRAP_CONTENT,
+            WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY,
+            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|
+            WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
+            PixelFormat.TRANSLUCENT);
+        params.gravity = Gravity.RIGHT | Gravity.TOP;
+        params.setTitle("CPU Info");
+        // we force a unified top margin in mExtraPaddingTop under status bar
+        params.layoutInDisplayCutoutMode =
+                WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+        startThread();
+
+        mDreamManager = IDreamManager.Stub.asInterface(
+                ServiceManager.checkService(DreamService.DREAM_SERVICE));
+        IntentFilter screenStateFilter = new IntentFilter(Intent.ACTION_SCREEN_ON);
+        screenStateFilter.addAction(Intent.ACTION_SCREEN_OFF);
+        registerReceiver(mScreenStateReceiver, screenStateFilter);
+
+        WindowManager wm = (WindowManager)getSystemService(WINDOW_SERVICE);
+        wm.addView(mView, params);
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        Log.d(TAG, "CPUInfoService onDestroy");
+        stopThread();
+        ((WindowManager)getSystemService(WINDOW_SERVICE)).removeView(mView);
+        mView = null;
+        unregisterReceiver(mScreenStateReceiver);
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        return null;
+    }
+
+    private static String readOneLine(String fname) {
+        BufferedReader br;
+        String line = null;
+        try {
+            br = new BufferedReader(new FileReader(fname), 512);
+            try {
+                line = br.readLine();
+            } finally {
+                br.close();
+            }
+        } catch (Exception e) {
+            return null;
+        }
+        return line;
+    }
+
+    private int getCpus(String displayCpus) {
+        int numOfCpu = 1;
+        String[] cpuList = null;
+
+        if (displayCpus != null) {
+            cpuList = displayCpus.split(",");
+            if (cpuList.length > 0) {
+                numOfCpu = cpuList.length;
+                mCpu = new String[numOfCpu];
+
+                for (int i = 0; i < numOfCpu; i++) {
+                    try {
+                        int cpu = Integer.parseInt(cpuList[i]);
+                        mCpu[i] = cpuList[i];
+                    } catch (NumberFormatException ex) {
+                        // derped overlay
+                        return getCpus(null);
+                    }
+                }
+            } else {
+                // derped overlay
+                return getCpus(null);
+            }
+        } else {
+            // empty overlay, take all cores
+            String numOfCpus = readOneLine(NUM_OF_CPUS_PATH);
+            cpuList = numOfCpus.split("-");
+            if (cpuList.length > 1) {
+                try {
+                    int cpuStart = Integer.parseInt(cpuList[0]);
+                    int cpuEnd = Integer.parseInt(cpuList[1]);
+
+                    numOfCpu = cpuEnd - cpuStart + 1;
+
+                    if (numOfCpu < 0)
+                        numOfCpu = 1;
+                } catch (NumberFormatException ex) {
+                    numOfCpu = 1;
+                }
+            }
+
+            mCpu = new String[numOfCpu];
+            for (int i = 0; i < numOfCpu; i++)
+            {
+                mCpu[i] = String.valueOf(i);
+            }
+        }
+        return numOfCpu;
+    }
+
+    private BroadcastReceiver mScreenStateReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
+                if (DEBUG) Log.d(TAG, "ACTION_SCREEN_ON " + isDozeMode());
+                if (!isDozeMode()) {
+                    startThread();
+                    mView.setVisibility(View.VISIBLE);
+                }
+            } else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
+                if (DEBUG) Log.d(TAG, "ACTION_SCREEN_OFF");
+                mView.setVisibility(View.GONE);
+                stopThread();
+            }
+        }
+    };
+
+    private boolean isDozeMode() {
+        try {
+            if (mDreamManager != null && mDreamManager.isDozing()) {
+                return true;
+            }
+        } catch (RemoteException e) {
+            return false;
+        }
+        return false;
+    }
+
+    private void startThread() {
+        if (DEBUG) Log.d(TAG, "started CurCPUThread");
+        mCurCPUThread = new CurCPUThread(mView.getHandler(), mNumCpus);
+        mCurCPUThread.start();
+    }
+
+    private void stopThread() {
+        if (mCurCPUThread != null && mCurCPUThread.isAlive()) {
+            if (DEBUG) Log.d(TAG, "stopping CurCPUThread");
+            mCurCPUThread.interrupt();
+            try {
+                mCurCPUThread.join();
+            } catch (InterruptedException e) {
+            }
+        }
+        mCurCPUThread = null;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/omni/OmniSettingsService.java b/packages/SystemUI/src/com/android/systemui/omni/OmniSettingsService.java
new file mode 100644
index 0000000..239db49
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/omni/OmniSettingsService.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2017 The Android Open Source 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.omni;
+
+public abstract class OmniSettingsService {
+
+    public abstract void addStringObserver(OmniSettingsObserver observer, String... keys);
+    public abstract void addIntObserver(OmniSettingsObserver observer, String... keys);
+    public abstract void removeObserver(OmniSettingsObserver observer);
+    public abstract void destroy();
+
+    public interface OmniSettingsObserver {
+        default void onStringSettingChanged(String key, String newValue) {}
+        default void onIntSettingChanged(String key, Integer newValue) {}
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/omni/OmniSettingsServiceImpl.java b/packages/SystemUI/src/com/android/systemui/omni/OmniSettingsServiceImpl.java
new file mode 100644
index 0000000..a1e1bd6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/omni/OmniSettingsServiceImpl.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2015 The Android Open Source 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.omni;
+
+import android.app.ActivityManager;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.UserInfo;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.HandlerExecutor;
+import android.os.Looper;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.provider.Settings.Secure;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Log;
+
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.settings.UserTracker;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.inject.Inject;
+
+/**
+ */
+@SysUISingleton
+public class OmniSettingsServiceImpl extends OmniSettingsService {
+    private static final String TAG = "OmniSettingsService";
+    private final Observer mObserver = new Observer();
+    // Map of Uris we listen on to their settings keys.
+    private final ArrayMap<Uri, String> mListeningUris = new ArrayMap<>();
+    // Map of settings keys to the listener.
+    private final HashMap<String, Set<OmniSettingsObserver>> mObserverLookup = new HashMap<>();
+    private final HashSet<String> mStringSettings = new HashSet<>();
+    private final HashSet<String> mIntSettings = new HashSet<>();
+    private final Context mContext;
+    private ContentResolver mContentResolver;
+    private int mCurrentUser;
+    private UserTracker.Callback mCurrentUserTracker;
+    private UserTracker mUserTracker;
+
+    /**
+     */
+    @Inject
+    public OmniSettingsServiceImpl(Context context, @Main Handler mainHandler,
+            UserTracker userTracker) {
+        mContext = context;
+        mContentResolver = mContext.getContentResolver();
+
+        mUserTracker = userTracker;
+        mCurrentUser = mUserTracker.getUserId();
+        mCurrentUserTracker = new UserTracker.Callback() {
+            @Override
+            public void onUserChanged(int newUser, Context userContext) {
+                mCurrentUser = newUser;
+                reloadAll();
+                reregisterAll();
+            }
+        };
+        mUserTracker.addCallback(mCurrentUserTracker,
+                new HandlerExecutor(mainHandler));
+    }
+
+    @Override
+    public void destroy() {
+        mUserTracker.removeCallback(mCurrentUserTracker);
+    }
+
+    @Override
+    public void addStringObserver(OmniSettingsObserver observer, String... keys) {
+        for (String key : keys) {
+            addStringObserver(observer, key);
+        }
+    }
+
+    @Override
+    public void addIntObserver(OmniSettingsObserver observer, String... keys) {
+        for (String key : keys) {
+            addIntObserver(observer, key);
+        }
+    }
+
+    private void addObserver(OmniSettingsObserver observer, String key) {
+        if (!mObserverLookup.containsKey(key)) {
+            mObserverLookup.put(key, new ArraySet<OmniSettingsObserver>());
+        }
+        if (!mObserverLookup.get(key).contains(observer)) {
+            mObserverLookup.get(key).add(observer);
+        }
+        Uri uri = Settings.System.getUriFor(key);
+        if (!mListeningUris.containsKey(uri)) {
+            mListeningUris.put(uri, key);
+            mContentResolver.registerContentObserver(uri, false, mObserver, mCurrentUser);
+        }
+    }
+
+    private void addStringObserver(OmniSettingsObserver observer, String key) {
+        mStringSettings.add(key);
+        addObserver(observer, key);
+        // Send the first state.
+        String value = Settings.System.getStringForUser(mContentResolver, key, mCurrentUser);
+        observer.onStringSettingChanged(key, value);
+    }
+
+    private void addIntObserver(OmniSettingsObserver observer, String key) {
+        mIntSettings.add(key);
+        addObserver(observer, key);
+        // Send the first state.
+        try {
+            Integer value = Settings.System.getIntForUser(mContentResolver, key, mCurrentUser);
+            observer.onIntSettingChanged(key, value);
+        } catch(Settings.SettingNotFoundException e) {
+        }
+    }
+
+    @Override
+    public void removeObserver(OmniSettingsObserver observer) {
+        for (Set<OmniSettingsObserver> list : mObserverLookup.values()) {
+            list.remove(observer);
+        }
+    }
+
+    protected void reregisterAll() {
+        if (mListeningUris.size() == 0) {
+            return;
+        }
+        mContentResolver.unregisterContentObserver(mObserver);
+        for (Uri uri : mListeningUris.keySet()) {
+            mContentResolver.registerContentObserver(uri, false, mObserver, mCurrentUser);
+        }
+    }
+
+    private void reloadSetting(Uri uri) {
+        String key = mListeningUris.get(uri);
+        Set<OmniSettingsObserver> observers = mObserverLookup.get(key);
+        if (observers == null) {
+            return;
+        }
+        if (mStringSettings.contains(key)) {
+            String value = Settings.System.getStringForUser(mContentResolver, key, mCurrentUser);
+            for (OmniSettingsObserver observer : observers) {
+                observer.onStringSettingChanged(key, value);
+            }
+        }
+        if (mIntSettings.contains(key)) {
+            try {
+                Integer value = Settings.System.getIntForUser(mContentResolver, key, mCurrentUser);
+                for (OmniSettingsObserver observer : observers) {
+                    observer.onIntSettingChanged(key, value);
+                }
+            } catch(Settings.SettingNotFoundException e) {
+            }
+        }
+    }
+
+    private void reloadAll() {
+        for (String key : mObserverLookup.keySet()) {
+            if (mStringSettings.contains(key)) {
+                String value = Settings.System.getStringForUser(mContentResolver, key, mCurrentUser);
+                for (OmniSettingsObserver observer : mObserverLookup.get(key)) {
+                    observer.onStringSettingChanged(key, value);
+                }
+            }
+            if (mIntSettings.contains(key)) {
+                try {
+                    Integer value = Settings.System.getIntForUser(mContentResolver, key, mCurrentUser);
+                    for (OmniSettingsObserver observer : mObserverLookup.get(key)) {
+                        observer.onIntSettingChanged(key, value);
+                    }
+                } catch(Settings.SettingNotFoundException e) {
+                }
+            }
+        }
+    }
+
+    private class Observer extends ContentObserver {
+        public Observer() {
+            super(new Handler(Looper.getMainLooper()));
+        }
+
+        @Override
+        public void onChange(boolean selfChange, java.util.Collection<Uri> uris,
+                int flags, int userId) {
+            if (userId == mUserTracker.getUserId()) {
+                for (Uri u : uris) {
+                    reloadSetting(u);
+                }
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/omni/dagger/OmniModule.java b/packages/SystemUI/src/com/android/systemui/omni/dagger/OmniModule.java
new file mode 100644
index 0000000..6ba05ff
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/omni/dagger/OmniModule.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2020 The Android Open Source 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.omni.dagger;
+
+import com.android.systemui.omni.OmniSettingsService;
+import com.android.systemui.omni.OmniSettingsServiceImpl;
+
+import com.android.systemui.qs.tiles.AODTile;
+import com.android.systemui.qs.tiles.CaffeineTile;
+import com.android.systemui.qs.tiles.DataSwitchTile;
+import com.android.systemui.qs.tiles.ScreenshotTile;
+
+import com.android.systemui.qs.tileimpl.QSTileImpl;
+
+import dagger.Binds;
+import dagger.Module;
+import dagger.multibindings.ClassKey;
+import dagger.multibindings.IntoMap;
+import dagger.multibindings.StringKey;
+
+
+/** Dagger Module for code in the systemui package. */
+@Module
+public interface OmniModule {
+    /** */
+    @Binds
+    OmniSettingsService provideOmniSettingsService(OmniSettingsServiceImpl impl);
+    
+    /** Inject Tiles */
+    @Binds
+    @IntoMap
+    @StringKey(AODTile.TILE_SPEC)
+    public abstract QSTileImpl<?> bindAODTile(AODTile aodTile);
+
+    @Binds
+    @IntoMap
+    @StringKey(CaffeineTile.TILE_SPEC)
+    public abstract QSTileImpl<?> bindCaffeineTile(CaffeineTile caffeineTile);
+
+    @Binds
+    @IntoMap
+    @StringKey(DataSwitchTile.TILE_SPEC)
+    public abstract QSTileImpl<?> bindDataSwitchTile(DataSwitchTile dataSwitchTile);
+
+    @Binds
+    @IntoMap
+    @StringKey(ScreenshotTile.TILE_SPEC)
+    public abstract QSTileImpl<?> bindScreenshotTile(ScreenshotTile screenshotTile);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index ca7b06a..1d9f5b6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -641,6 +641,20 @@
         return mPages.get(0).mRecords.size();
     }
 
+    @Override
+    public int getResourceColumns() {
+        if (mPages.size() == 0) return TileLayout.NO_MAX_COLUMNS;
+        TileLayout currentPage = mPages.get(getCurrentPageNumber());
+        return currentPage.getResourceColumns();
+    }
+    @Override
+    public void updateSettings() {
+        for (int i = 0; i < mPages.size(); i++) {
+            mPages.get(i).updateSettings();
+        }
+        mDistributeTiles = true;
+    }
+
     public void startTileReveal(Set<String> tilesToReveal, final Runnable postAnimation) {
         if (shouldNotRunAnimation(tilesToReveal)) {
             return;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java
index 5a872d6..5f35e3c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterView.java
@@ -86,7 +86,7 @@
 
     private void setBuildText() {
         if (mBuildText == null) return;
-        if (DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(mContext)) {
+        if (DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(mContext) && false) {
             mBuildText.setText(mContext.getString(
                     com.android.internal.R.string.bugreport_status,
                     Build.VERSION.RELEASE_OR_CODENAME,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 602f593..8b449f9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -682,7 +682,7 @@
 
     void setColumnRowLayout(boolean withMedia) {
         mTileLayout.setMinRows(withMedia ? 2 : 1);
-        mTileLayout.setMaxColumns(withMedia ? 2 : 4);
+        mTileLayout.setMaxColumns(withMedia ? mTileLayout.getResourceColumns() / 2 : mTileLayout.getResourceColumns());
         placeTileLayoutForScene(withMedia);
     }
 
@@ -843,6 +843,10 @@
         int getNumVisibleTiles();
 
         default void setLogger(QSLogger qsLogger) { }
+
+        int getResourceColumns();
+
+        void updateSettings();
     }
 
     interface OnConfigurationChangedListener {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
index afb852a..3dd3ba5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
@@ -31,10 +31,12 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.Dependency;
 import com.android.systemui.Dumpable;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.haptics.qs.QSLongPressEffect;
 import com.android.systemui.media.controls.ui.view.MediaHost;
+import com.android.systemui.omni.OmniSettingsService;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.plugins.qs.QSTileView;
 import com.android.systemui.qs.customize.QSCustomizerController;
@@ -53,6 +55,8 @@
 import kotlinx.coroutines.DisposableHandle;
 import kotlinx.coroutines.flow.StateFlow;
 
+import org.omnirom.omnilib.utils.OmniSettings;
+
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -70,7 +74,7 @@
  * @param <T> Type of QSPanel.
  */
 public abstract class QSPanelControllerBase<T extends QSPanel> extends ViewController<T>
-        implements Dumpable{
+        implements Dumpable, OmniSettingsService.OmniSettingsObserver {
     private static final String TAG = "QSPanelControllerBase";
     protected final QSHost mHost;
     private final QSCustomizerController mQsCustomizerController;
@@ -82,6 +86,7 @@
     private final DumpManager mDumpManager;
     protected final ArrayList<TileRecord> mRecords = new ArrayList<>();
     protected boolean mShouldUseSplitNotificationShade;
+    private boolean shouldChangeTiles = false;
 
     @Nullable
     private Consumer<Boolean> mMediaVisibilityChangedListener;
@@ -256,6 +261,14 @@
         switchTileLayout(true);
 
         mDumpManager.registerDumpable(mView.getDumpableTag(), this);
+        Dependency.get(OmniSettingsService.class).addIntObserver(this,
+                OmniSettings.OMNI_QS_TILE_VERTICAL_LAYOUT);
+        Dependency.get(OmniSettingsService.class).addIntObserver(this,
+                OmniSettings.OMNI_QS_LAYOUT_COLUMNS);
+        Dependency.get(OmniSettingsService.class).addIntObserver(this,
+                OmniSettings.OMNI_QS_LAYOUT_COLUMNS_LANDSCAPE);
+        Dependency.get(OmniSettingsService.class).addIntObserver(this,
+                OmniSettings.OMNI_QS_TILE_LABEL_HIDE);
 
         setListening(mLastListening);
     }
@@ -283,6 +296,8 @@
         mMediaHost.removeVisibilityChangeListener(mMediaHostVisibilityListener);
 
         mDumpManager.unregisterDumpable(mView.getDumpableTag());
+        Dependency.get(OmniSettingsService.class).removeObserver(this);
+        shouldChangeTiles = false;
     }
 
     @Nullable
@@ -334,7 +349,7 @@
 
         // If we detected that the existing tiles are different than the requested tiles, clear them
         // and add the new tiles.
-        if (shouldChangeAll) {
+        if (shouldChangeAll || shouldChangeTiles) {
             for (QSPanelControllerBase.TileRecord record : mRecords) {
                 mView.removeTile(record);
                 record.tile.removeCallback(record.callback);
@@ -602,6 +617,15 @@
         return mView.getBrightnessView();
     }
 
+    @Override
+    public void onIntSettingChanged(String key, Integer newValue) {
+        if (mView.getTileLayout() != null) {
+            mView.getTileLayout().updateSettings();
+            setTiles();
+            shouldChangeTiles = true;
+        }
+    }
+
     /**
      * Set a listener to collapse/expand QS.
      * @param action
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index 168be40..89d5e93 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -28,6 +28,8 @@
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.res.R;
 
+import org.omnirom.omnilib.utils.OmniUtils;
+
 /**
  * Version of QSPanel that only shows N Quick Tiles in the QS Header.
  */
@@ -36,13 +38,14 @@
     private static final String TAG = "QuickQSPanel";
     // A fallback value for max tiles number when setting via Tuner (parseNumTiles)
     public static final int TUNER_MAX_TILES_FALLBACK = 6;
+    public static final int DEFAULT_MIN_TILES = 4;
 
     private boolean mDisabledByPolicy;
     private int mMaxTiles;
 
     public QuickQSPanel(Context context, AttributeSet attrs) {
         super(context, attrs);
-        mMaxTiles = getResources().getInteger(R.integer.quick_qs_panel_max_tiles);
+        mMaxTiles = Math.max(DEFAULT_MIN_TILES, getResources().getInteger(R.integer.quick_qs_panel_max_tiles));
     }
 
     @Override
@@ -53,7 +56,7 @@
 
     @Override
     public TileLayout getOrCreateTileLayout() {
-        QQSSideLabelTileLayout layout = new QQSSideLabelTileLayout(mContext);
+        QQSSideLabelTileLayout layout = new QQSSideLabelTileLayout(mContext,this);
         layout.setId(R.id.qqs_tile_layout);
         return layout;
     }
@@ -90,7 +93,7 @@
     }
 
     public void setMaxTiles(int maxTiles) {
-        mMaxTiles = maxTiles;
+        mMaxTiles = Math.max(DEFAULT_MIN_TILES, maxTiles);
     }
 
     @Override
@@ -171,15 +174,17 @@
     static class QQSSideLabelTileLayout extends SideLabelTileLayout {
 
         private boolean mLastSelected;
+        private QuickQSPanel mQSPanel;
 
-        QQSSideLabelTileLayout(Context context) {
+        QQSSideLabelTileLayout(Context context, QuickQSPanel qsPanel) {
             super(context, null);
+            mQSPanel = qsPanel;
             setClipChildren(false);
             setClipToPadding(false);
             LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,
                     LayoutParams.WRAP_CONTENT);
             setLayoutParams(lp);
-            setMaxColumns(4);
+            setMaxColumns(getResourceColumns());
         }
 
         @Override
@@ -251,5 +256,17 @@
             setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
             mLastSelected = selected;
         }
+
+        @Override
+        public int getResourceColumns() {
+            int columns = getResources().getInteger(R.integer.quick_qs_panel_max_tiles);
+            return OmniUtils.getQuickQSColumnsCount(mContext, columns);
+        }
+
+        @Override
+        public void updateSettings() {
+            mQSPanel.setMaxTiles(getResourceColumns());
+            super.updateSettings();
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
index bc695bdd4..a86a45b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanelController.java
@@ -40,6 +40,8 @@
 
 import kotlinx.coroutines.flow.StateFlow;
 
+import org.omnirom.omnilib.utils.OmniUtils;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -125,6 +127,7 @@
     @Override
     protected void onConfigurationChanged() {
         int newMaxTiles = getResources().getInteger(R.integer.quick_qs_panel_max_tiles);
+        newMaxTiles = OmniUtils.getQuickQSColumnsCount(getContext(), newMaxTiles);
         if (newMaxTiles != mView.getNumQuickTiles()) {
             setMaxTiles(newMaxTiles);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index ef44e5f..6979e58 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -4,6 +4,7 @@
 
 import android.content.Context;
 import android.content.res.Resources;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.AttributeSet;
 import android.view.View;
@@ -24,6 +25,8 @@
 import com.android.systemui.qs.tileimpl.QSTileViewImplKt;
 import com.android.systemui.res.R;
 
+import org.omnirom.omnilib.utils.OmniUtils;
+
 import java.util.ArrayList;
 
 public class TileLayout extends ViewGroup implements QSTileLayout {
@@ -51,7 +54,6 @@
     private final boolean mLessRows;
     private int mMinRows = 1;
     private int mMaxColumns = NO_MAX_COLUMNS;
-    protected int mResourceColumns;
     private float mSquishinessFraction = 1f;
     protected int mLastTileBottom;
     protected TextView mTempTextView;
@@ -148,10 +150,6 @@
 
     public boolean updateResources() {
         Resources res = getResources();
-        int columns = useSmallLandscapeLockscreenResources()
-                ? res.getInteger(R.integer.small_land_lockscreen_quick_settings_num_columns)
-                : res.getInteger(R.integer.quick_settings_num_columns);
-        mResourceColumns = Math.max(1, columns);
         mResourceCellHeight = res.getDimensionPixelSize(mResourceCellHeightResId);
         mCellMarginHorizontal = res.getDimensionPixelSize(R.dimen.qs_tile_margin_horizontal);
         mSidePadding = useSidePadding() ? mCellMarginHorizontal / 2 : 0;
@@ -190,7 +188,7 @@
 
     private boolean updateColumns() {
         int oldColumns = mColumns;
-        mColumns = Math.min(mResourceColumns, mMaxColumns);
+        mColumns = Math.min(getResourceColumns(), mMaxColumns);
         return oldColumns != mColumns;
     }
 
@@ -270,6 +268,9 @@
     }
 
     protected int getCellHeight() {
+        if (OmniUtils.getQSTileLabelHide(mContext)) {
+            return getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size);
+        }
         // Compare estimated height with resource height and return the larger one.
         // If estimated height > resource height, it means the resource height is not enough
         // for the tile content under current font scaling. Therefore, we need to use the estimated
@@ -377,4 +378,15 @@
         info.setCollectionInfo(
                 new AccessibilityNodeInfo.CollectionInfo(mRecords.size(), 1, false));
     }
+
+    public int getResourceColumns() {
+        int resourceColumns = Math.max(2, getResources().getInteger(R.integer.quick_settings_num_columns));
+        return OmniUtils.getQSColumnsCount(mContext, resourceColumns);
+    }
+
+    @Override
+    public void updateSettings() {
+        setMaxColumns(getResourceColumns());
+        requestLayout();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizerController.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizerController.java
index c606ce4..e270ce0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizerController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizerController.java
@@ -34,7 +34,9 @@
 import androidx.recyclerview.widget.RecyclerView;
 
 import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.Dependency;
 import com.android.systemui.keyguard.ScreenLifecycle;
+import com.android.systemui.omni.OmniSettingsService;
 import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.plugins.qs.QSContainerController;
 import com.android.systemui.plugins.qs.QSTile;
@@ -50,6 +52,8 @@
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.util.ViewController;
 
+import org.omnirom.omnilib.utils.OmniSettings;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -57,7 +61,8 @@
 
 /** {@link ViewController} for {@link QSCustomizer}. */
 @QSScope
-public class QSCustomizerController extends ViewController<QSCustomizer> {
+public class QSCustomizerController extends ViewController<QSCustomizer>
+        implements OmniSettingsService.OmniSettingsObserver {
     private final TileQueryHelper mTileQueryHelper;
     private final QSHost mQsHost;
     private final TileAdapter mTileAdapter;
@@ -95,12 +100,7 @@
         public void onConfigChanged(Configuration newConfig) {
             mView.updateNavBackDrop(newConfig, mLightBarController);
             mView.updateResources();
-            if (mTileAdapter.updateNumColumns()) {
-                RecyclerView.LayoutManager lm = mView.getRecyclerView().getLayoutManager();
-                if (lm instanceof GridLayoutManager) {
-                    ((GridLayoutManager) lm).setSpanCount(mTileAdapter.getNumColumns());
-                }
-            }
+            updateColumns();
         }
     };
 
@@ -171,6 +171,11 @@
 
         mToolbar.setOnMenuItemClickListener(mOnMenuItemClickListener);
         mToolbar.setNavigationOnClickListener(v -> hide());
+
+        Dependency.get(OmniSettingsService.class).addIntObserver(this,
+                OmniSettings.OMNI_QS_LAYOUT_COLUMNS);
+        Dependency.get(OmniSettingsService.class).addIntObserver(this,
+                OmniSettings.OMNI_QS_LAYOUT_COLUMNS_LANDSCAPE);
     }
 
     @Override
@@ -178,6 +183,7 @@
         mTileQueryHelper.setListener(null);
         mToolbar.setOnMenuItemClickListener(null);
         mConfigurationController.removeCallback(mConfigurationListener);
+        Dependency.get(OmniSettingsService.class).removeObserver(this);
     }
 
 
@@ -281,4 +287,18 @@
         }
         mTileAdapter.setTileSpecs(specs);
     }
+
+    private void updateColumns() {
+        if (mTileAdapter.updateNumColumns()) {
+            RecyclerView.LayoutManager lm = mView.getRecyclerView().getLayoutManager();
+            if (lm instanceof GridLayoutManager) {
+                ((GridLayoutManager) lm).setSpanCount(mTileAdapter.getNumColumns());
+            }
+        }
+    }
+
+    @Override
+    public void onIntSettingChanged(String key, Integer newValue) {
+        updateColumns();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index db778a2..4ab3592 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -26,9 +26,11 @@
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
 import android.view.LayoutInflater;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.View.OnLayoutChangeListener;
+import android.view.View.OnTouchListener;
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 import android.widget.TextView;
@@ -61,6 +63,8 @@
 import com.android.systemui.qs.tileimpl.QSTileViewImpl;
 import com.android.systemui.res.R;
 
+import org.omnirom.omnilib.utils.OmniUtils;
+
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
@@ -143,6 +147,7 @@
                 ? context.getResources().getInteger(
                         R.integer.small_land_lockscreen_quick_settings_num_columns)
                 : context.getResources().getInteger(NUM_COLUMNS_ID);
+        mNumColumns = OmniUtils.getQSColumnsCount(mContext, mNumColumns);
         mAccessibilityDelegate = new TileAdapterDelegate();
         mSizeLookup.setSpanIndexCacheEnabled(true);
         mTempTextView = new TextView(context);
@@ -169,6 +174,7 @@
                 ? mContext.getResources().getInteger(
                         R.integer.small_land_lockscreen_quick_settings_num_columns)
                 : mContext.getResources().getInteger(NUM_COLUMNS_ID);
+        numColumns = OmniUtils.getQSColumnsCount(mContext, numColumns);
         if (numColumns != mNumColumns) {
             mNumColumns = numColumns;
             return true;
@@ -382,7 +388,7 @@
             final String titleText;
             Resources res = mContext.getResources();
             if (mCurrentDrag == null) {
-                titleText = res.getString(R.string.drag_to_add_tiles);
+                titleText = res.getString(R.string.drag_or_tap_to_add_tiles);
             } else if (!canRemoveTiles() && mCurrentDrag.getAdapterPosition() < mEditIndex) {
                 titleText = res.getString(R.string.drag_to_remove_disabled, mMinNumTiles);
             } else {
@@ -468,6 +474,18 @@
         if (position == mFocusIndex) {
             focusOnHolder(holder);
         }
+        holder.mTileView.setOnTouchListener(new OnTouchListener() {
+            @Override
+            public boolean onTouch(View v, MotionEvent ev) {
+                if (ev.getAction() == MotionEvent.ACTION_UP) {
+                    int position = holder.getLayoutPosition();
+                    if (position >= mEditIndex || canRemoveTiles()) {
+                        move(position, mEditIndex, true);
+                    }
+                }
+                return false;
+            }
+        });
     }
 
     private void focusOnHolder(Holder holder) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
index 15e3499..0fb3e7c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -28,6 +28,7 @@
 import android.service.quicksettings.TileService;
 import android.text.TextUtils;
 import android.util.ArraySet;
+import android.util.Log;
 import android.widget.Button;
 
 import androidx.annotation.Nullable;
@@ -49,6 +50,8 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
+import java.util.Set;
+import java.util.HashSet;
 import java.util.concurrent.Executor;
 
 import javax.inject.Inject;
@@ -101,19 +104,14 @@
         String stock = mContext.getString(R.string.quick_settings_tiles_stock);
         String current = Settings.Secure.getString(mContext.getContentResolver(),
                 Settings.Secure.QS_TILES);
-        final ArrayList<String> possibleTiles = new ArrayList<>();
+        String possible = stock
+                + "," + mContext.getString(R.string.quick_settings_tiles_extra);
+
+        final Set<String> possibleTiles = new HashSet<>();
         if (current != null) {
-            // The setting QS_TILES is not populated immediately upon Factory Reset
             possibleTiles.addAll(Arrays.asList(current.split(",")));
-        } else {
-            current = "";
         }
-        String[] stockSplit =  stock.split(",");
-        for (String spec : stockSplit) {
-            if (!current.contains(spec)) {
-                possibleTiles.add(spec);
-            }
-        }
+        possibleTiles.addAll(Arrays.asList(possible.split(",")));
 
         final ArrayList<QSTile> tilesToAdd = new ArrayList<>();
         possibleTiles.remove("cell");
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
index b7ebce2..348684a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileViewImpl.kt
@@ -33,6 +33,8 @@
 import android.graphics.drawable.LayerDrawable
 import android.graphics.drawable.RippleDrawable
 import android.os.Trace
+import android.os.UserHandle
+import android.provider.Settings
 import android.service.quicksettings.Tile
 import android.text.TextUtils
 import android.util.Log
@@ -73,6 +75,8 @@
 import com.android.systemui.res.R
 import java.util.Objects
 
+import org.omnirom.omnilib.utils.OmniUtils
+
 private const val TAG = "QSTileViewImpl"
 
 open class QSTileViewImpl
@@ -193,6 +197,9 @@
     private var lastDisabledByPolicy = false
 
     private val locInScreen = IntArray(2)
+    private var vertical = false
+    private val forceHideCheveron = true
+    private var labelHide = false
 
     /** Visuo-haptic long-press effects */
     private var longPressEffectAnimator: ValueAnimator? = null
@@ -218,8 +225,22 @@
             )
         }
         setId(generateViewId())
-        orientation = LinearLayout.HORIZONTAL
-        gravity = Gravity.CENTER_VERTICAL or Gravity.START
+
+        vertical = resources.getBoolean(R.bool.qs_tile_vertical_layout)
+        vertical = OmniUtils.getQSTileVerticalLayout(context, if (vertical) 1 else 0)
+        if (vertical) {
+            orientation = LinearLayout.VERTICAL
+            gravity = Gravity.CENTER_HORIZONTAL
+        } else {
+            orientation = LinearLayout.HORIZONTAL
+            gravity = Gravity.CENTER_VERTICAL or Gravity.START
+        }
+
+        labelHide = OmniUtils.getQSTileLabelHide(context)
+
+        if (labelHide)
+            gravity = Gravity.CENTER_HORIZONTAL or Gravity.CENTER_VERTICAL
+
         importantForAccessibility = IMPORTANT_FOR_ACCESSIBILITY_YES
         clipChildren = false
         clipToPadding = false
@@ -228,7 +249,7 @@
         setColor(getBackgroundColorForState(QSTile.State.DEFAULT_STATE))
 
         val padding = resources.getDimensionPixelSize(R.dimen.qs_tile_padding)
-        val startPadding = resources.getDimensionPixelSize(R.dimen.qs_tile_start_padding)
+        val startPadding = if (vertical) padding else resources.getDimensionPixelSize(R.dimen.qs_tile_start_padding)
         setPaddingRelative(startPadding, padding, padding, padding)
 
         val iconSize = resources.getDimensionPixelSize(R.dimen.qs_icon_size)
@@ -268,11 +289,24 @@
             width = iconSize
         }
 
+        vertical = resources.getBoolean(R.bool.qs_tile_vertical_layout)
+        vertical = OmniUtils.getQSTileVerticalLayout(context, if (vertical) 1 else 0)
+        if (vertical) {
+            orientation = LinearLayout.VERTICAL
+            gravity = Gravity.CENTER_HORIZONTAL
+        } else {
+            orientation = LinearLayout.HORIZONTAL
+            gravity = Gravity.CENTER_VERTICAL or Gravity.START
+        }
+
+        if (labelHide)
+            gravity = Gravity.CENTER_HORIZONTAL or Gravity.CENTER_VERTICAL
+
         val padding = resources.getDimensionPixelSize(R.dimen.qs_tile_padding)
-        val startPadding = resources.getDimensionPixelSize(R.dimen.qs_tile_start_padding)
+        val startPadding = if (vertical) padding else resources.getDimensionPixelSize(R.dimen.qs_tile_start_padding)
         setPaddingRelative(startPadding, padding, padding, padding)
 
-        val labelMargin = resources.getDimensionPixelSize(R.dimen.qs_label_container_margin)
+        val labelMargin = if (vertical) 0 else resources.getDimensionPixelSize(R.dimen.qs_label_container_margin)
         (labelContainer.layoutParams as MarginLayoutParams).apply { marginStart = labelMargin }
 
         (sideView.layoutParams as MarginLayoutParams).apply { marginStart = labelMargin }
@@ -294,7 +328,8 @@
 
     private fun createAndAddLabels() {
         labelContainer =
-            LayoutInflater.from(context).inflate(R.layout.qs_tile_label, this, false)
+            LayoutInflater.from(context).inflate(if (vertical)
+                R.layout.qs_tile_label_vertical else R.layout.qs_tile_label,this, false)
                 as IgnorableChildLinearLayout
         label = labelContainer.requireViewById(R.id.tile_label)
         secondaryLabel = labelContainer.requireViewById(R.id.app_label)
@@ -317,7 +352,8 @@
             secondaryLabel.apply { typeface = Typeface.create("gsf-label-medium", Typeface.NORMAL) }
         }
 
-        addView(labelContainer)
+        if (!labelHide)
+            addView(labelContainer)
     }
 
     private fun createAndAddSideView() {
@@ -836,7 +872,7 @@
             customDrawableView.setImageDrawable(state.sideViewCustomDrawable)
             customDrawableView.visibility = VISIBLE
             chevronView.visibility = GONE
-        } else if (state !is AdapterState || state.forceExpandIcon) {
+        } else if ((state !is AdapterState || state.forceExpandIcon) && !forceHideCheveron) {
             customDrawableView.setImageDrawable(null)
             customDrawableView.visibility = GONE
             chevronView.visibility = VISIBLE
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AODTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AODTile.java
new file mode 100644
index 0000000..66f1c01
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AODTile.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2018 The OmniROM 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.ComponentName;
+import android.content.Intent;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.provider.Settings;
+import android.service.quicksettings.Tile;
+
+import androidx.annotation.Nullable;
+
+import com.android.systemui.animation.Expandable;
+import com.android.internal.logging.MetricsLogger;
+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.logging.QSLogger;
+import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.QsEventLogger;
+import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.qs.UserSettingObserver;
+import com.android.systemui.res.R;
+import com.android.systemui.settings.UserTracker;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.util.settings.SecureSettings;
+
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+import javax.inject.Inject;
+
+public class AODTile extends QSTileImpl<BooleanState> implements
+        BatteryController.BatteryStateChangeCallback {
+
+    public static final String TILE_SPEC = "aod";
+
+    private boolean mListening;
+    private final Icon mIcon = ResourceIcon.get(R.drawable.ic_qs_aod);
+    private final BatteryController mBatteryController;
+    private final UserSettingObserver mSetting;
+
+    @Inject
+    public AODTile(
+            QSHost host,
+            QsEventLogger uiEventLogger,
+            @Background Looper backgroundLooper,
+            @Main Handler mainHandler,
+            FalsingManager falsingManager,
+            MetricsLogger metricsLogger,
+            StatusBarStateController statusBarStateController,
+            ActivityStarter activityStarter,
+            QSLogger qsLogger,
+            SecureSettings secureSettings,
+            BatteryController batteryController,
+            UserTracker userTracker
+    ) {
+        super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+                statusBarStateController, activityStarter, qsLogger);
+
+        mSetting = new UserSettingObserver(secureSettings, mHandler, Settings.Secure.DOZE_ALWAYS_ON,
+                userTracker.getUserId()) {
+            @Override
+            protected void handleValueChanged(int value, boolean observedChange) {
+                handleRefreshState(value);
+            }
+        };
+
+        mBatteryController = batteryController;
+        batteryController.observe(getLifecycle(), this);
+    }
+
+    @Override
+    public void onPowerSaveChanged(boolean isPowerSave) {
+        refreshState();
+    }
+
+    @Override
+    protected void handleDestroy() {
+        super.handleDestroy();
+        mSetting.setListening(false);
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_dozeAlwaysOnDisplayAvailable);
+    }
+
+    @Override
+    public BooleanState newTileState() {
+        BooleanState state = new BooleanState();
+        state.handlesLongClick = false;
+        return state;
+    }
+
+    @Override
+    public void handleSetListening(boolean listening) {
+        super.handleSetListening(listening);
+        mSetting.setListening(listening);
+    }
+
+    @Override
+    protected void handleUserSwitch(int newUserId) {
+        mSetting.setUserId(newUserId);
+        handleRefreshState(mSetting.getValue());
+    }
+
+    @Override
+    public void handleClick(@Nullable Expandable expandable) {
+        mSetting.setValue(mState.value ? 0 : 1);
+    }
+
+    @Override
+    public Intent getLongClickIntent() {
+        return null;
+    }
+
+    @Override
+    public CharSequence getTileLabel() {
+        return mContext.getString(R.string.quick_settings_aod_label);
+    }
+
+    @Override
+    protected void handleUpdateState(BooleanState state, Object arg) {
+        final int value = arg instanceof Integer ? (Integer) arg : mSetting.getValue();
+        final boolean enable = value != 0;
+        state.icon = mIcon;
+        state.value = enable;
+        state.label = mContext.getString(R.string.quick_settings_aod_label);
+        if (mBatteryController.isAodPowerSave()) {
+            state.state = Tile.STATE_UNAVAILABLE;
+            state.secondaryLabel = mContext.getString(
+                           R.string.quick_settings_aod_off_powersave_label);
+        } else {
+            state.state = enable ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
+            if (enable) {
+                state.secondaryLabel = mContext.getString(R.string.aod_on);
+            } else {
+                state.secondaryLabel = mContext.getString(R.string.aod_off);
+            }
+        }
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return MetricsEvent.CUSTOM_QUICK_TILES;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.kt
index 9efdd98..ae79d8f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AlarmTile.kt
@@ -2,10 +2,12 @@
 
 import android.app.AlarmManager
 import android.app.AlarmManager.AlarmClockInfo
+import android.app.NotificationManager
 import android.content.Intent
 import android.os.Handler
 import android.os.Looper
 import android.provider.AlarmClock
+import android.provider.Settings
 import android.service.quicksettings.Tile
 import android.text.TextUtils
 import android.text.format.DateFormat
@@ -27,6 +29,7 @@
 import com.android.systemui.res.R
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.statusbar.policy.NextAlarmController
+import com.android.systemui.statusbar.policy.ZenModeController
 import java.util.Locale
 import javax.inject.Inject
 
@@ -44,6 +47,7 @@
     qsLogger: QSLogger,
     private val userTracker: UserTracker,
     nextAlarmController: NextAlarmController,
+    private val zenModeController: ZenModeController,
 ) :
     QSTileImpl<QSTile.State>(
         host,
@@ -59,6 +63,7 @@
 
     private var lastAlarmInfo: AlarmManager.AlarmClockInfo? = null
     private var icon: QSTile.Icon? = null
+    private val iconDim = ResourceIcon.get(R.drawable.ic_alarm_dim)
     @VisibleForTesting internal val defaultIntent = Intent(AlarmClock.ACTION_SHOW_ALARMS)
     private val callback =
         NextAlarmController.NextAlarmChangeCallback { nextAlarm ->
@@ -66,8 +71,14 @@
             refreshState()
         }
 
+    private val zenCallback = object : ZenModeController.Callback {
+        override fun onZenChanged(zen: Int) { refreshState() }
+        override fun onConsolidatedPolicyChanged(policy: NotificationManager.Policy) { refreshState() }
+    }
+
     init {
         nextAlarmController.observe(this, callback)
+        zenModeController.observe(this, zenCallback)
     }
 
     override fun newTileState(): QSTile.State {
@@ -98,8 +109,8 @@
         if (icon == null) {
             icon = maybeLoadResourceIcon(R.drawable.ic_alarm)
         }
-        state.icon = icon
-        state.label = tileLabel
+        state.icon = if (zenAllowsAlarm()) icon else iconDim
+        state.label = if (zenAllowsAlarm()) tileLabel else tileLabel.toString() + mContext.getString(R.string.alarm_title_dnd_indicator)
         lastAlarmInfo?.let {
             state.secondaryLabel = formatNextAlarm(it)
             state.state = Tile.STATE_ACTIVE
@@ -133,6 +144,21 @@
         return null
     }
 
+
+    private fun zenAllowsAlarm() : Boolean {
+        val zen = zenModeController.getZen()
+        if (zen == Settings.Global.ZEN_MODE_OFF) {
+            return true
+        }
+        if (zen == Settings.Global.ZEN_MODE_NO_INTERRUPTIONS) {
+            return false
+        }
+        if (zen == Settings.Global.ZEN_MODE_ALARMS) {
+            return true
+        }
+        return (zenModeController.getConsolidatedPolicy().priorityCategories and NotificationManager.Policy.PRIORITY_CATEGORY_ALARMS) != 0
+    }
+
     companion object {
         const val TILE_SPEC = "alarm"
     }
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 0000000..43660c0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CaffeineTile.java
@@ -0,0 +1,257 @@
+/*
+ * 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 androidx.annotation.Nullable;
+
+import com.android.systemui.animation.Expandable;
+import com.android.internal.logging.MetricsLogger;
+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.QsEventLogger;
+import com.android.systemui.qs.logging.QSLogger;
+import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.res.R;
+
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+import javax.inject.Inject;
+
+/** Quick settings tile: Caffeine **/
+public class CaffeineTile extends QSTileImpl<BooleanState> {
+    public static final String TILE_SPEC = "caffeine";
+
+    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,
+            QsEventLogger uiEventLogger,
+            @Background Looper backgroundLooper,
+            @Main Handler mainHandler,
+            FalsingManager falsingManager,
+            MetricsLogger metricsLogger,
+            StatusBarStateController statusBarStateController,
+            ActivityStarter activityStarter,
+            QSLogger qsLogger
+    ) {
+        super(host, uiEventLogger, 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 Expandable expandable) {
+        // 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 Expandable expandable) {
+        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.CUSTOM_QUICK_TILES;
+    }
+
+    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();
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index 30c2adf..56916b3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -90,7 +90,7 @@
     private final TileJavaAdapter mJavaAdapter;
     private final FeatureFlags mFeatureFlags;
     private boolean mCastTransportAllowed;
-    private boolean mHotspotConnected;
+    private boolean mHotspotEnabled;
 
     @Inject
     public CastTile(
@@ -320,23 +320,23 @@
     }
 
     private boolean canCastToNetwork() {
-        return mCastTransportAllowed || mHotspotConnected;
+        return mCastTransportAllowed || mHotspotEnabled;
     }
 
-    private void setCastTransportAllowed(boolean connected) {
-        if (connected != mCastTransportAllowed) {
-            mCastTransportAllowed = connected;
-            // Hotspot is not connected, so changes here should update
-            if (!mHotspotConnected) {
+    private void setCastTransportAllowed(boolean enabled) {
+        if (enabled != mCastTransportAllowed) {
+            mCastTransportAllowed = enabled;
+            // Hotspot is not enabled, so changes here should update
+            if (!mHotspotEnabled) {
                 refreshState();
             }
         }
     }
 
-    private void setHotspotConnected(boolean connected) {
-        if (connected != mHotspotConnected) {
-            mHotspotConnected = connected;
-            // Wifi is not connected, so changes here should update
+    private void setHotspotEnabled(boolean enabled) {
+        if (enabled != mHotspotEnabled) {
+            mHotspotEnabled = enabled;
+            // Wifi is not enabled, so changes here should update
             if (!mCastTransportAllowed) {
                 refreshState();
             }
@@ -353,10 +353,7 @@
     private final SignalCallback mSignalCallback = new SignalCallback() {
         @Override
         public void setWifiIndicators(@NonNull WifiIndicators indicators) {
-            // statusIcon.visible has the connected status information
-            boolean enabledAndConnected = indicators.enabled
-                    && (indicators.qsIcon != null && indicators.qsIcon.visible);
-            setCastTransportAllowed(enabledAndConnected);
+            setCastTransportAllowed(indicators.enabled);
         }
     };
 
@@ -364,8 +361,7 @@
             new HotspotController.Callback() {
                 @Override
                 public void onHotspotChanged(boolean enabled, int numDevices) {
-                    boolean enabledAndConnected = enabled && numDevices > 0;
-                    setHotspotConnected(enabledAndConnected);
+                    setHotspotEnabled(enabled);
                 }
             };
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSwitchTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSwitchTile.java
new file mode 100644
index 0000000..a672aa5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSwitchTile.java
@@ -0,0 +1,239 @@
+package com.android.systemui.qs.tiles;
+
+import android.annotation.Nullable;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.SystemProperties;
+import android.provider.Settings;
+import android.telephony.PhoneStateListener;
+import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
+import android.util.Log;
+import android.widget.Toast;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.telephony.IccCardConstants;
+import com.android.internal.telephony.TelephonyIntents;
+import com.android.systemui.animation.Expandable;
+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.logging.QSLogger;
+import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.QsEventLogger;
+import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.systemui.qs.tileimpl.QSTileImpl.ResourceIcon;
+import com.android.systemui.res.R;
+
+import java.util.concurrent.Executors;
+import java.util.List;
+
+import javax.inject.Inject;
+
+public class DataSwitchTile extends QSTileImpl<BooleanState> {
+    public static final String TILE_SPEC = "dataswitch";
+
+    private boolean mCanSwitch = true;
+    private boolean mRegistered;
+    private int mSimCount;
+
+    private final Intent mLongClickIntent;
+    private final String mTileLabel;
+    private final BroadcastReceiver mSimReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (DEBUG) Log.d(TAG, "mSimReceiver:onReceive");
+            refreshState();
+        }
+    };
+    private final PhoneStateListener mPhoneStateListener;
+    private final SubscriptionManager mSubscriptionManager;
+    private final TelephonyManager mTelephonyManager;
+
+    @Inject
+    public DataSwitchTile(
+        QSHost host,
+        QsEventLogger uiEventLogger,
+        @Background Looper backgroundLooper,
+        @Main Handler mainHandler,
+        FalsingManager falsingManager,
+        MetricsLogger metricsLogger,
+        StatusBarStateController statusBarStateController,
+        ActivityStarter activityStarter,
+        QSLogger qsLogger
+    ) {
+        super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+                statusBarStateController, activityStarter, qsLogger);
+        mLongClickIntent = new Intent(Settings.ACTION_NETWORK_OPERATOR_SETTINGS);
+        mTileLabel = mContext.getString(R.string.qs_data_switch_label);
+        mSubscriptionManager = SubscriptionManager.from(mContext);
+        mTelephonyManager = TelephonyManager.from(mContext);
+        mPhoneStateListener = new PhoneStateListener() {
+            @Override
+            public void onCallStateChanged(int state, String arg1) {
+                mCanSwitch = mTelephonyManager.getCallState() == 0;
+                refreshState();
+            }
+        };
+    }
+
+    @Override
+    public boolean isAvailable() {
+        int count = TelephonyManager.getDefault().getPhoneCount();
+        if (DEBUG) Log.d(TAG, "phoneCount: " + count);
+        return count >= 2;
+    }
+
+    @Override
+    public BooleanState newTileState() {
+        final BooleanState state = new BooleanState();
+        state.label = mContext.getString(R.string.qs_data_switch_label);
+        return state;
+    }
+
+    @Override
+    public void handleSetListening(boolean listening) {
+        if (listening) {
+            if (!mRegistered) {
+                final IntentFilter filter = new IntentFilter(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
+                mContext.registerReceiver(mSimReceiver, filter);
+                mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
+                mRegistered = true;
+            }
+            refreshState();
+        } else if (mRegistered) {
+            mContext.unregisterReceiver(mSimReceiver);
+            mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
+            mRegistered = false;
+        }
+    }
+
+    private void updateSimCount() {
+        String simState = SystemProperties.get("gsm.sim.state");
+        if (DEBUG) Log.d(TAG, "DataSwitchTile:updateSimCount:simState=" + simState);
+        mSimCount = 0;
+        try {
+            final String[] sims = TextUtils.split(simState, ",");
+            for (String sim : sims) {
+                if (!sim.isEmpty()
+                        && !sim.equalsIgnoreCase(IccCardConstants.INTENT_VALUE_ICC_ABSENT)
+                        && !sim.equalsIgnoreCase(IccCardConstants.INTENT_VALUE_ICC_NOT_READY)) {
+                    mSimCount++;
+                }
+            }
+        } catch (NullPointerException e) {
+            Log.e(TAG, "Error on parsing sim state " + e.getMessage());
+        }
+        if (DEBUG) Log.d(TAG, "DataSwitchTile:updateSimCount:mSimCount=" + mSimCount);
+    }
+
+    @Override
+    protected void handleClick(@Nullable Expandable expandable) {
+        if (!mCanSwitch) {
+            if (DEBUG) Log.d(TAG, "Call state=" + mTelephonyManager.getCallState());
+        } else if (mSimCount == 0) {
+            if (DEBUG) Log.d(TAG, "handleClick:no sim card");
+        } else if (mSimCount == 1) {
+            if (DEBUG) Log.d(TAG, "handleClick:only one sim card");
+        } else {
+            Executors.newSingleThreadExecutor().execute(() -> {
+                toggleMobileDataEnabled();
+                refreshState();
+            });
+        }
+    }
+
+    @Override
+    public Intent getLongClickIntent() {
+        return mLongClickIntent;
+    }
+
+    @Override
+    public CharSequence getTileLabel() {
+        return mTileLabel;
+    }
+
+    @Override
+    protected void handleUpdateState(BooleanState state, Object arg) {
+        boolean activeSIMZero;
+        if (arg == null) {
+            int defaultPhoneId = mSubscriptionManager.getPhoneId(mSubscriptionManager.getDefaultDataSubscriptionId());
+            if (DEBUG) Log.d(TAG, "default data phone id=" + defaultPhoneId);
+            activeSIMZero = defaultPhoneId == 0;
+        } else {
+            activeSIMZero = (Boolean) arg;
+        }
+        updateSimCount();
+        state.value = mSimCount == 2;
+        if (mSimCount == 1 || mSimCount == 2) {
+            state.icon = ResourceIcon.get(activeSIMZero
+                    ? R.drawable.ic_qs_data_switch_1
+                    : R.drawable.ic_qs_data_switch_2);
+            state.secondaryLabel = mContext.getString(activeSIMZero
+                    ? R.string.qs_data_sim_1
+                    : R.string.qs_data_sim_2);
+        } else {
+            if (mSimCount == 0) {
+                state.icon = ResourceIcon.get(R.drawable.ic_qs_data_switch_0);
+                state.secondaryLabel = mContext.getString(R.string.qs_data_no_sim);
+            } else {
+                state.icon = ResourceIcon.get(R.drawable.ic_qs_data_switch_1);
+                state.secondaryLabel = mContext.getString(R.string.qs_data_sim_1);
+            }
+        }
+        if (mSimCount < 2 || !mCanSwitch) {
+            state.state = 0;
+            if (!mCanSwitch && DEBUG) Log.d(TAG, "call state isn't idle, set to unavailable.");
+        } else {
+            state.state = state.value ? 2 : 1;
+        }
+
+        state.contentDescription =
+                mContext.getString(activeSIMZero
+                        ? R.string.qs_data_switch_changed_1
+                        : R.string.qs_data_switch_changed_2);
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return MetricsEvent.CUSTOM_QUICK_TILES;
+    }
+
+    /**
+     * Set whether to enable data for {@code subId}, also whether to disable data for other
+     * subscription
+     */
+    private void toggleMobileDataEnabled() {
+        // Get opposite slot 2 ^ 3 = 1, 1 ^ 3 = 2
+        int subId = SubscriptionManager.getDefaultDataSubscriptionId() ^ 3;
+        final TelephonyManager telephonyManager =
+                mTelephonyManager.createForSubscriptionId(subId);
+        telephonyManager.setDataEnabled(true);
+        mSubscriptionManager.setDefaultDataSubId(subId);
+        if (DEBUG) Log.d(TAG, "Enabled subID: " + subId);
+
+        final List<SubscriptionInfo> subInfoList =
+                mSubscriptionManager.getActiveSubscriptionInfoList(true);
+        if (subInfoList != null) {
+            // We never disable mobile data for opportunistic subscriptions.
+            subInfoList.stream()
+                .filter(subInfo -> !subInfo.isOpportunistic())
+                .map(subInfo -> subInfo.getSubscriptionId())
+                .filter(id -> id != subId)
+                .forEach(id -> {
+                    mTelephonyManager.createForSubscriptionId(id).setDataEnabled(false);
+                    if (DEBUG) Log.d(TAG, "Disabled subID: " + id);
+                });
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
index 683e4e9..06992b3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
@@ -102,9 +102,10 @@
     @Override
     public boolean isAvailable() {
         String stockTiles = mContext.getString(R.string.quick_settings_tiles_stock);
+        String extraStockTiles = mContext.getString(R.string.quick_settings_tiles_extra);
         // For the restore from backup case
         // Return false when "nfc" is not listed in quick_settings_tiles_stock.
-        if (stockTiles.contains(NFC)) {
+        if (stockTiles.contains(NFC) || extraStockTiles.contains(NFC)) {
             return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC);
         }
         return false;
@@ -160,7 +161,7 @@
     private NfcAdapter getAdapter() {
         if (mAdapter == null) {
             try {
-                mAdapter = NfcAdapter.getDefaultAdapter(mContext);
+                mAdapter = NfcAdapter.getDefaultAdapter(mContext.getApplicationContext());
             } catch (UnsupportedOperationException e) {
                 mAdapter = null;
             }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenshotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenshotTile.java
new file mode 100644
index 0000000..a008d12
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenshotTile.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2020 The OmniROM 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.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.service.quicksettings.Tile;
+import android.view.WindowManager;
+import static android.view.WindowManager.ScreenshotSource.SCREENSHOT_GLOBAL_ACTIONS;
+import static android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN;
+
+import androidx.annotation.Nullable;
+
+import com.android.internal.util.ScreenshotHelper;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.animation.Expandable;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.QsEventLogger;
+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.logging.QSLogger;
+import com.android.systemui.qs.pipeline.domain.interactor.PanelInteractor;
+import com.android.systemui.qs.tileimpl.QSTileImpl;
+import com.android.internal.R;
+
+import javax.inject.Inject;
+
+/** Quick settings tile: Screenshot **/
+public class ScreenshotTile extends QSTileImpl<BooleanState> {
+    public static final String TILE_SPEC = "screenshot";
+    private final PanelInteractor mPanelInteractor;
+
+    @Inject
+    public ScreenshotTile(
+            QSHost host,
+            QsEventLogger uiEventLogger,
+            @Background Looper backgroundLooper,
+            @Main Handler mainHandler,
+            FalsingManager falsingManager,
+            MetricsLogger metricsLogger,
+            StatusBarStateController statusBarStateController,
+            ActivityStarter activityStarter,
+            QSLogger qsLogger,
+            PanelInteractor panelInteractor
+    ) {
+        super(host, uiEventLogger, backgroundLooper, mainHandler, falsingManager, metricsLogger,
+                statusBarStateController, activityStarter, qsLogger);
+        mPanelInteractor = panelInteractor;
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return MetricsEvent.CUSTOM_QUICK_TILES;
+    }
+
+    @Override
+    public BooleanState newTileState() {
+        return new BooleanState();
+    }
+
+    @Override
+    public void handleSetListening(boolean listening) {}
+
+    @Override
+    public boolean isAvailable() {
+        return true;
+    }
+
+    @Override
+    public void handleClick(@Nullable Expandable expandable) {
+        mPanelInteractor.collapsePanels();
+        final ScreenshotHelper screenshotHelper = new ScreenshotHelper(mContext);
+        mHandler.postDelayed(() -> {
+            screenshotHelper.takeScreenshot(SCREENSHOT_GLOBAL_ACTIONS, mHandler, null);
+        }, 1000);
+    }
+
+    @Override
+    public Intent getLongClickIntent() {
+        return null;
+    }
+
+    @Override
+    public CharSequence getTileLabel() {
+        return mContext.getString(R.string.global_action_screenshot);
+    }
+
+    @Override
+    protected void handleUpdateState(BooleanState state, Object arg) {
+        state.label = mContext.getString(
+                R.string.global_action_screenshot);
+        state.contentDescription =  mContext.getString(
+                R.string.global_action_screenshot);
+        state.icon = ResourceIcon.get(R.drawable.ic_screenshot);
+        state.value = true;
+        state.state = Tile.STATE_INACTIVE;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
index f7b5271..48657ad9 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
@@ -25,6 +25,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.drawable.Icon;
+import android.media.AudioAttributes;
 import android.media.MediaRecorder;
 import android.media.projection.StopReason;
 import android.net.Uri;
@@ -182,6 +183,8 @@
                 NotificationManager.IMPORTANCE_DEFAULT);
         channel.setDescription(getString(R.string.screenrecord_channel_description));
         channel.enableVibration(true);
+        channel.setSound(null, // silent
+                new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_NOTIFICATION).build());
         mNotificationManager.createNotificationChannel(channel);
 
         int currentUid = Process.myUid();
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt
index 15638d3..a409fc6 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.screenshot
 
+import android.app.PendingIntent
 import android.content.ClipData
 import android.content.ClipDescription
 import android.content.ComponentName
@@ -91,6 +92,16 @@
             .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
     }
 
+    fun createDelete(rawUri: Uri, context: Context): PendingIntent {
+        return PendingIntent.getBroadcast(context, rawUri.toString().hashCode(),
+                Intent(context, DeleteScreenshotReceiver::class.java)
+                        .putExtra(SmartActionsReceiver.SCREENSHOT_URI_ID, rawUri.toString())
+                        .addFlags(Intent.FLAG_RECEIVER_FOREGROUND),
+                        (PendingIntent.FLAG_CANCEL_CURRENT
+                        or PendingIntent.FLAG_ONE_SHOT
+                        or PendingIntent.FLAG_IMMUTABLE))
+    }
+
     /** @return an Intent to start the LongScreenshotActivity */
     fun createLongScreenshotIntent(owner: UserHandle, context: Context): Intent {
         return Intent(context, LongScreenshotActivity::class.java)
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/DeleteScreenshotReceiver.java b/packages/SystemUI/src/com/android/systemui/screenshot/DeleteScreenshotReceiver.java
new file mode 100644
index 0000000..e556e4e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/DeleteScreenshotReceiver.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2020 The Android Open Source 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.screenshot;
+
+import static com.android.systemui.screenshot.SmartActionsReceiver.ACTION_TYPE_DELETE;
+import static com.android.systemui.screenshot.SmartActionsReceiver.EXTRA_ID;
+import static com.android.systemui.screenshot.SmartActionsReceiver.EXTRA_SMART_ACTIONS_ENABLED;
+import static com.android.systemui.screenshot.SmartActionsReceiver.SCREENSHOT_URI_ID;
+
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+
+import com.android.systemui.dagger.qualifiers.Background;
+
+import java.util.concurrent.Executor;
+
+import javax.inject.Inject;
+
+/**
+ * Removes the file at a provided URI.
+ */
+public class DeleteScreenshotReceiver extends BroadcastReceiver {
+
+    private final ScreenshotSmartActions mScreenshotSmartActions;
+    private final Executor mBackgroundExecutor;
+
+    @Inject
+    public DeleteScreenshotReceiver(ScreenshotSmartActions screenshotSmartActions,
+            @Background Executor backgroundExecutor) {
+        mScreenshotSmartActions = screenshotSmartActions;
+        mBackgroundExecutor = backgroundExecutor;
+    }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        if (!intent.hasExtra(SCREENSHOT_URI_ID)) {
+            return;
+        }
+
+        // And delete the image from the media store
+        final Uri uri = Uri.parse(intent.getStringExtra(SCREENSHOT_URI_ID));
+        mBackgroundExecutor.execute(() -> {
+            ContentResolver resolver = context.getContentResolver();
+            resolver.delete(uri, null, null);
+        });
+        if (intent.getBooleanExtra(EXTRA_SMART_ACTIONS_ENABLED, false)) {
+            mScreenshotSmartActions.notifyScreenshotAction(
+                    intent.getStringExtra(EXTRA_ID), ACTION_TYPE_DELETE, false, null);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt
index 1c232e9..05aa887 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt
@@ -25,9 +25,11 @@
 import com.android.systemui.Flags.screenshotContextUrl
 import com.android.systemui.log.DebugLogger.debugLog
 import com.android.systemui.res.R
+import com.android.systemui.screenshot.ActionIntentCreator.createDelete
 import com.android.systemui.screenshot.ActionIntentCreator.createEdit
 import com.android.systemui.screenshot.ActionIntentCreator.createShareWithSubject
 import com.android.systemui.screenshot.ActionIntentCreator.createShareWithText
+import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_DELETE_TAPPED
 import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_EDIT_TAPPED
 import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_PREVIEW_TAPPED
 import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_SHARE_TAPPED
@@ -99,7 +101,7 @@
         actionsCallback.provideActionButton(
             ActionButtonAppearance(
                 AppCompatResources.getDrawable(context, R.drawable.ic_screenshot_share),
-                context.resources.getString(R.string.screenshot_share_label),
+                context.resources.getString(R.string.screenshot_share_label_empty),
                 context.resources.getString(R.string.screenshot_share_description),
             ),
             showDuringEntrance = true,
@@ -121,7 +123,7 @@
         actionsCallback.provideActionButton(
             ActionButtonAppearance(
                 AppCompatResources.getDrawable(context, R.drawable.ic_screenshot_edit),
-                context.resources.getString(R.string.screenshot_edit_label),
+                context.resources.getString(R.string.screenshot_edit_label_empty),
                 context.resources.getString(R.string.screenshot_edit_description),
             ),
             showDuringEntrance = true,
@@ -136,6 +138,23 @@
                 )
             }
         }
+
+        actionsCallback.provideActionButton(
+            ActionButtonAppearance(
+                AppCompatResources.getDrawable(context, R.drawable.ic_screenshot_delete),
+                context.resources.getString(R.string.screenshot_delete_label_empty),
+                context.resources.getString(R.string.screenshot_delete_description),
+            ),
+            showDuringEntrance = true,
+        ) {
+            debugLog(LogConfig.DEBUG_ACTIONS) { "Delete tapped" }
+            uiEventLogger.log(SCREENSHOT_DELETE_TAPPED, 0, request.packageNameString)
+            onDeferrableActionTapped { result ->
+                actionExecutor.sendPendingIntent(
+                    createDelete(result.uri, context)
+                )
+            }
+        }
     }
 
     override fun onScrollChipReady(onClick: Runnable) {
@@ -144,7 +163,7 @@
             actionsCallback.provideActionButton(
                 ActionButtonAppearance(
                     AppCompatResources.getDrawable(context, R.drawable.ic_screenshot_scroll),
-                    context.resources.getString(R.string.screenshot_scroll_label),
+                    context.resources.getString(R.string.screenshot_scroll_label_empty),
                     context.resources.getString(R.string.screenshot_scroll_label),
                 ),
                 showDuringEntrance = true,
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java
index 7a62bae..ce1acd6 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotEvent.java
@@ -54,6 +54,8 @@
     SCREENSHOT_EDIT_TAPPED(308),
     @UiEvent(doc = "screenshot share button tapped")
     SCREENSHOT_SHARE_TAPPED(309),
+    @UiEvent(doc = "screenshot delete button tapped")
+    SCREENSHOT_DELETE_TAPPED(369),
     @UiEvent(doc = "screenshot smart action chip tapped")
     SCREENSHOT_SMART_ACTION_TAPPED(374),
     @UiEvent(doc = "screenshot scroll tapped")
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsReceiver.java b/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsReceiver.java
index f902693..0153022 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/SmartActionsReceiver.java
@@ -34,6 +34,7 @@
     private static final String TAG = "SmartActionsReceiver";
     // These strings are used for communicating the action invoked to
     // ScreenshotNotificationSmartActionsProvider.
+    public static final String ACTION_TYPE_DELETE = "Delete";
     public static final String EXTRA_ACTION_TYPE = "android:screenshot_action_type";
     public static final String EXTRA_ID = "android:screenshot_id";
     public static final String EXTRA_SMART_ACTIONS_ENABLED = "android:smart_actions_enabled";
@@ -41,6 +42,7 @@
     public static final String EXTRA_ACTION_INTENT_FILLIN =
             "android:screenshot_action_intent_fillin";
 
+    static final String SCREENSHOT_URI_ID = "android:screenshot_uri_id";
 
     private final ScreenshotSmartActions mScreenshotSmartActions;
 
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java
index 90d27f4..3036961 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessController.java
@@ -488,6 +488,7 @@
             // animating it from two different sources causes janky motion.
             // Don't animate if the value is changed via the brightness keys of a keyboard.
             mControl.setValue(target);
+            mControl.updateThumb(target);
             mControlValueInitialized = true;
         }
         mSliderAnimator = ValueAnimator.ofInt(mControl.getValue(), target);
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java
index 503d0bf..bf43051 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderController.java
@@ -247,6 +247,10 @@
         return mView.isVisibleToUser();
     }
 
+    public void updateThumb(int value) {
+        mView.updateThumb(value);
+    }
+
     private final SeekBar.OnSeekBarChangeListener mSeekListener =
             new SeekBar.OnSeekBarChangeListener() {
         @Override
@@ -257,6 +261,7 @@
                     mBrightnessSliderHapticPlugin.onProgressChanged(progress, true);
                 }
             }
+            mView.updateThumb(progress);
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderView.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderView.java
index a39d25a..2323728 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderView.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/BrightnessSliderView.java
@@ -166,6 +166,13 @@
         mSlider.setProgress(value);
     }
 
+    public void updateThumb(int value) {
+        if (mSlider.getThumb() != null) {
+            final int level = (int) (((float)value / getMax()) * /*ProgressBar.MAX_LEVEL*/ 10000);
+            mSlider.getThumb().setLevel(level);
+        }
+    }
+
     /**
      * @return the current value of the {@link ToggleSeekBar}
      */
@@ -213,10 +220,11 @@
 
     private void applySliderScale() {
         if (mProgressDrawable != null) {
-            final Rect r = mProgressDrawable.getBounds();
+            // TODO
+            /*final Rect r = mProgressDrawable.getBounds();
             int height = (int) (mProgressDrawable.getIntrinsicHeight() * mScale);
             int inset = (mProgressDrawable.getIntrinsicHeight() - height) / 2;
-            mProgressDrawable.setBounds(r.left, inset, r.right, inset + height);
+            mProgressDrawable.setBounds(r.left, inset, r.right, inset + height);*/
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/ToggleSlider.java b/packages/SystemUI/src/com/android/systemui/settings/brightness/ToggleSlider.java
index ed69d35..7ff112a 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/ToggleSlider.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/ToggleSlider.java
@@ -40,4 +40,6 @@
     void hideView();
     void showToast(@StringRes int resId);
     boolean isVisible();
+
+    void updateThumb(int value);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
index e8a792c..defcc91 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeHeaderController.kt
@@ -344,6 +344,11 @@
             v.pivotY = v.height.toFloat() / 2
         }
         clock.setOnClickListener { launchClockActivity() }
+        batteryIcon.setOnClickListener {
+            activityStarter.postStartActivityDismissingKeyguard(
+                Intent(Intent.ACTION_POWER_USAGE_SUMMARY), 0
+            )
+        }
 
         dumpManager.registerDumpable(this)
         configurationController.addCallback(configurationControllerListener)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 862f33bb..a75498d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -183,6 +183,9 @@
     private static final int MSG_ENTER_DESKTOP = 80 << MSG_SHIFT;
     private static final int MSG_SET_SPLITSCREEN_FOCUS = 81 << MSG_SHIFT;
     private static final int MSG_TOGGLE_QUICK_SETTINGS_PANEL = 82 << MSG_SHIFT;
+    private static final int MSG_TOGGLE_CAMERA_FLASH               = 83 << MSG_SHIFT;
+    private static final int MSG_TOGGLE_CAMERA_FLASH_STATE         = 84 << MSG_SHIFT;
+
     public static final int FLAG_EXCLUDE_NONE = 0;
     public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
     public static final int FLAG_EXCLUDE_RECENTS_PANEL = 1 << 1;
@@ -366,7 +369,7 @@
         default void showPinningEnterExitToast(boolean entering) { }
         default void showPinningEscapeToast() { }
         default void handleShowGlobalActionsMenu() { }
-        default void handleShowShutdownUi(boolean isReboot, String reason) { }
+        default void handleShowShutdownUi(boolean isReboot, String reason, boolean rebootCustom) { }
 
         default void showWirelessChargingAnimation(int batteryLevel) {  }
 
@@ -574,6 +577,12 @@
          * @see IStatusBar#moveFocusedTaskToDesktop(int)
          */
         default void moveFocusedTaskToDesktop(int displayId) {}
+
+        /**
+         * Omni
+         */
+        default void toggleCameraFlash() { }
+        default void toggleCameraFlashState(boolean enable) { }
     }
 
     @VisibleForTesting
@@ -1047,10 +1056,10 @@
     }
 
     @Override
-    public void showShutdownUi(boolean isReboot, String reason) {
+    public void showShutdownUi(boolean isReboot, String reason, boolean rebootCustom) {
         synchronized (mLock) {
             mHandler.removeMessages(MSG_SHOW_SHUTDOWN_UI);
-            mHandler.obtainMessage(MSG_SHOW_SHUTDOWN_UI, isReboot ? 1 : 0, 0, reason)
+            mHandler.obtainMessage(MSG_SHOW_SHUTDOWN_UI, isReboot ? 1 : 0, rebootCustom ? 1 : 0, reason)
                     .sendToTarget();
         }
     }
@@ -1492,6 +1501,22 @@
         mHandler.obtainMessage(MSG_ENTER_DESKTOP, args).sendToTarget();
     }
 
+    @Override
+    public void toggleCameraFlash() {
+        synchronized (mLock) {
+            mHandler.removeMessages(MSG_TOGGLE_CAMERA_FLASH);
+            mHandler.sendEmptyMessage(MSG_TOGGLE_CAMERA_FLASH);
+        }
+    }
+
+    @Override
+    public void toggleCameraFlashState(boolean enable) {
+        synchronized (mLock) {
+            mHandler.removeMessages(MSG_TOGGLE_CAMERA_FLASH_STATE);
+            mHandler.obtainMessage(MSG_TOGGLE_CAMERA_FLASH_STATE,enable ? 1 : 0, 0, null).sendToTarget();
+        }
+    }
+
     private final class H extends Handler {
         private H(Looper l) {
             super(l);
@@ -1699,7 +1724,7 @@
                     break;
                 case MSG_SHOW_SHUTDOWN_UI:
                     for (int i = 0; i < mCallbacks.size(); i++) {
-                        mCallbacks.get(i).handleShowShutdownUi(msg.arg1 != 0, (String) msg.obj);
+                        mCallbacks.get(i).handleShowShutdownUi(msg.arg1 != 0, (String) msg.obj, msg.arg2 != 0);
                     }
                     break;
                 case MSG_SET_TOP_APP_HIDES_STATUS_BAR:
@@ -2013,6 +2038,16 @@
                     }
                     break;
                 }
+                case MSG_TOGGLE_CAMERA_FLASH:
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).toggleCameraFlash();
+                    }
+                    break;
+                case MSG_TOGGLE_CAMERA_FLASH_STATE:
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).toggleCameraFlashState(msg.arg1 != 0);
+                    }
+                    break;
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index f37f7f9..0676fe4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -137,6 +137,8 @@
 
 import com.google.errorprone.annotations.CompileTimeConstant;
 
+import org.omnirom.omnilib.utils.OmniUtils;
+
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.util.ArrayList;
@@ -471,6 +473,7 @@
     private final Runnable mReflingAndAnimateScroll = this::animateScroll;
     private int mCornerRadius;
     private int mMinimumPaddings;
+    private int mQsTileColumns;
     private int mQsTilePadding;
     private boolean mSkinnyNotifsInLandscape;
     private int mSidePaddings;
@@ -986,6 +989,8 @@
         mBottomPadding = res.getDimensionPixelSize(R.dimen.notification_panel_padding_bottom);
         mMinimumPaddings = res.getDimensionPixelSize(R.dimen.notification_side_paddings);
         mQsTilePadding = res.getDimensionPixelOffset(R.dimen.qs_tile_margin_horizontal);
+        mQsTileColumns = res.getInteger(R.integer.quick_settings_num_columns);
+        mQsTileColumns = OmniUtils.getQSColumnsCount(mContext, mQsTileColumns);
         mSidePaddings = mMinimumPaddings;  // Updated in onMeasure by updateSidePadding()
         mMinInteractionHeight = res.getDimensionPixelSize(
                 R.dimen.notification_min_interaction_height);
@@ -1023,7 +1028,7 @@
         }
 
         final int innerWidth = viewWidth - mMinimumPaddings * 2;
-        final int qsTileWidth = (innerWidth - mQsTilePadding * 3) / 4;
+        final int qsTileWidth = (innerWidth - mQsTilePadding * (mQsTileColumns - 1)) / mQsTileColumns;
         mSidePaddings = mMinimumPaddings + qsTileWidth + mQsTilePadding;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
index adfcb71..ad939f9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
@@ -46,6 +46,7 @@
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.DisplayId;
 import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.Dependency;
 import com.android.systemui.emergency.EmergencyGesture;
 import com.android.systemui.emergency.EmergencyGestureModule.EmergencyGestureIntentFactory;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
@@ -66,8 +67,9 @@
 import com.android.systemui.shade.domain.interactor.ShadeInteractor;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
-import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.FlashlightController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
 
@@ -120,6 +122,9 @@
 
     private final EmergencyGestureIntentFactory mEmergencyGestureIntentFactory;
 
+    /*omni add-on*/
+    private FlashlightController mFlashlightController;
+
     @Inject
     CentralSurfacesCommandQueueCallbacks(
             CentralSurfaces centralSurfaces,
@@ -186,6 +191,9 @@
                 mVibratorOptional, resources);
         mActivityStarter = activityStarter;
         mEmergencyGestureIntentFactory = emergencyGestureIntentFactory;
+
+        // omni
+        mFlashlightController = Dependency.get(FlashlightController.class);
     }
 
     @Override
@@ -577,4 +585,24 @@
                 HapticFeedbackConstants.GESTURE_START
         );
     }
+
+    @Override
+    public void toggleCameraFlash() {
+        if (mFlashlightController != null) {
+            mFlashlightController.initFlashLight();
+            if (mFlashlightController.hasFlashlight() && mFlashlightController.isAvailable()) {
+                mFlashlightController.setFlashlight(!mFlashlightController.isEnabled());
+            }
+        }
+    }
+
+    @Override
+    public void toggleCameraFlashState(boolean enable) {
+        if (mFlashlightController != null) {
+            mFlashlightController.initFlashLight();
+            if (mFlashlightController.hasFlashlight() && mFlashlightController.isAvailable()) {
+                mFlashlightController.setFlashlight(enable);
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 7bea480..d6835d2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -241,6 +241,8 @@
 
 import dagger.Lazy;
 
+import org.omnirom.omnilib.utils.OmniUtils;
+
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.util.Map;
@@ -347,6 +349,16 @@
         return mQSPanelController;
     }
 
+    /** */
+    public void toggleCameraFlash() {
+        mCommandQueueCallbacks.toggleCameraFlash();
+    }
+
+    /** */
+    public void toggleCameraFlashState(boolean enable) {
+        mCommandQueueCallbacks.toggleCameraFlashState(enable);
+    }
+
     /**
      * The {@link StatusBarState} of the status bar.
      */
@@ -1465,6 +1477,7 @@
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
         filter.addAction(Intent.ACTION_SCREEN_OFF);
+        filter.addAction(OmniUtils.ACTION_DISMISS_KEYGUARD);
         mBroadcastDispatcher.registerReceiver(mBroadcastReceiver, filter, null, UserHandle.ALL);
     }
 
@@ -1962,6 +1975,15 @@
                 }
                 finishBarAnimations();
                 mNotificationsController.resetUserExpandedStates();
+            } else if (OmniUtils.ACTION_DISMISS_KEYGUARD.equals(action)) {
+                if (intent.hasExtra(OmniUtils.DISMISS_KEYGUARD_EXTRA_INTENT)) {
+                    Intent launchIntent = (Intent) intent.getParcelableExtra(OmniUtils.DISMISS_KEYGUARD_EXTRA_INTENT);
+                    mActivityStarter.startActivityDismissingKeyguard(
+                        launchIntent,
+                        true /* onlyProvisioned */,
+                        true /* dismissShade */,
+                        null /* customMessage */);
+                }
             }
             Trace.endSection();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index 4915b84..8f1d113 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -93,7 +93,6 @@
     private final UserTracker mUserTracker;
     private final SecureSettings mSecureSettings;
 
-    private boolean mDozeAlwaysOn;
     private boolean mControlScreenOffAnimation;
     private boolean mIsQuickPickupEnabled;
 
@@ -158,7 +157,6 @@
         keyguardUpdateMonitor.registerCallback(mKeyguardVisibilityCallback);
         tunerService.addTunable(
                 this,
-                Settings.Secure.DOZE_ALWAYS_ON,
                 Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);
         configurationController.addCallback(this);
         statusBarStateController.addCallback(this);
@@ -275,7 +273,8 @@
      * @return {@code true} if enabled and available.
      */
     public boolean getAlwaysOn() {
-        return mDozeAlwaysOn && !mBatteryController.isAodPowerSave();
+        return mAmbientDisplayConfiguration.alwaysOnEnabled(UserHandle.USER_CURRENT)
+                && !mBatteryController.isAodPowerSave();
     }
 
     /**
@@ -422,12 +421,6 @@
 
     @Override
     public void onTuningChanged(String key, String newValue) {
-        mDozeAlwaysOn = mAmbientDisplayConfiguration.alwaysOnEnabled(mUserTracker.getUserId());
-
-        if (key.equals(Settings.Secure.DOZE_ALWAYS_ON)) {
-            updateControlScreenOff();
-        }
-
         dispatchAlwaysOnEvent();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index f8eae36..10b6711 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -24,18 +24,30 @@
 import android.app.AlarmManager.AlarmClockInfo;
 import android.app.NotificationManager;
 import android.app.admin.DevicePolicyManager;
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.SharedPreferences;
 import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.PaintFlagsDrawFilter;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
 import android.media.AudioManager;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings.Global;
+import android.provider.Settings.System;
 import android.service.notification.ZenModeConfig;
 import android.telecom.TelecomManager;
 import android.text.format.DateFormat;
@@ -45,12 +57,16 @@
 import androidx.lifecycle.Observer;
 
 import com.android.internal.statusbar.StatusBarIcon;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
+import com.android.settingslib.graph.BluetoothDeviceLayerDrawable;
+import com.android.systemui.Dependency;
 import com.android.systemui.Flags;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.qualifiers.DisplayId;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dagger.qualifiers.UiBackground;
 import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor;
+import com.android.systemui.omni.OmniSettingsService;
 import com.android.systemui.modes.shared.ModesUiIcons;
 import com.android.systemui.privacy.PrivacyItem;
 import com.android.systemui.privacy.PrivacyItemController;
@@ -86,6 +102,8 @@
 import com.android.systemui.util.kotlin.JavaAdapter;
 import com.android.systemui.util.time.DateFormatUtil;
 
+import org.omnirom.omnilib.utils.OmniSettings;
+
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.util.List;
@@ -107,7 +125,8 @@
                 KeyguardStateController.Callback,
                 PrivacyItemController.Callback,
                 LocationController.LocationChangeCallback,
-                RecordingController.RecordingStateChangeCallback {
+                RecordingController.RecordingStateChangeCallback,
+                OmniSettingsService.OmniSettingsObserver {
     private static final String TAG = "PhoneStatusBarPolicy";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
@@ -175,6 +194,9 @@
 
     private BluetoothController mBluetooth;
     private AlarmManager.AlarmClockInfo mNextAlarm;
+    private Context mContext;
+    private boolean mShowAlarm;
+    private boolean mShowBtBattery;
 
     @Inject
     public PhoneStatusBarPolicy(StatusBarIconController iconController,
@@ -198,7 +220,8 @@
             PrivacyLogger privacyLogger,
             ConnectedDisplayInteractor connectedDisplayInteractor,
             ZenModeInteractor zenModeInteractor,
-            JavaAdapter javaAdapter
+            JavaAdapter javaAdapter,
+            Context context
     ) {
         mIconController = iconController;
         mCommandQueue = commandQueue;
@@ -231,6 +254,7 @@
         mPrivacyLogger = privacyLogger;
         mZenModeInteractor = zenModeInteractor;
         mJavaAdapter = javaAdapter;
+        mContext = context;
 
         mSlotCast = resources.getString(com.android.internal.R.string.status_bar_cast);
         mSlotConnectedDisplay = resources.getString(
@@ -265,6 +289,7 @@
         IntentFilter filter = new IntentFilter();
 
         filter.addAction(AudioManager.ACTION_HEADSET_PLUG);
+        filter.addAction(BluetoothDevice.ACTION_BATTERY_LEVEL_CHANGED);
         filter.addAction(Intent.ACTION_SIM_STATE_CHANGED);
         filter.addAction(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED);
         filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
@@ -387,6 +412,8 @@
         }
         mJavaAdapter.alwaysCollectFlow(mConnectedDisplayInteractor.getConnectedDisplayState(),
                 this::onConnectedDisplayAvailabilityChanged);
+        Dependency.get(OmniSettingsService.class).addIntObserver(this, OmniSettings.OMNI_STATUS_BAR_ALARM);
+        Dependency.get(OmniSettingsService.class).addIntObserver(this, OmniSettings.OMNI_STATUS_BAR_BT_BATTERY);
 
         mCommandQueue.addCallback(this);
     }
@@ -438,11 +465,10 @@
     private void updateAlarm() {
         final AlarmClockInfo alarm = mAlarmManager.getNextAlarmClock(mUserTracker.getUserId());
         final boolean hasAlarm = alarm != null && alarm.getTriggerTime() > 0;
-        int zen = mZenController.getZen();
-        final boolean zenNone = zen == Global.ZEN_MODE_NO_INTERRUPTIONS;
+        final boolean zenNone = !zenAllowsAlarm();
         mIconController.setIcon(mSlotAlarmClock, zenNone ? R.drawable.stat_sys_alarm_dim
                 : R.drawable.stat_sys_alarm, buildAlarmContentDescription());
-        mIconController.setIconVisibility(mSlotAlarmClock, mCurrentUserSetup && hasAlarm);
+        mIconController.setIconVisibility(mSlotAlarmClock, mCurrentUserSetup && hasAlarm && mShowAlarm);
     }
 
     private String buildAlarmContentDescription() {
@@ -543,17 +569,48 @@
         String contentDescription =
                 mResources.getString(R.string.accessibility_quick_settings_bluetooth_on);
         boolean bluetoothVisible = false;
+        StatusBarIcon icon = null;
         if (mBluetooth != null) {
             if (mBluetooth.isBluetoothConnected()
                     && (mBluetooth.isBluetoothAudioActive()
                     || !mBluetooth.isBluetoothAudioProfileOnly())) {
                 contentDescription = mResources.getString(
                         R.string.accessibility_bluetooth_connected);
+                }
+
+            if (mBluetooth.isBluetoothConnected()) {
+                final List<CachedBluetoothDevice> devices = mBluetooth.getConnectedDevices();
+                if (mShowBtBattery && devices != null) {
+                    // get battery level for the first device with battery level support
+                    for (CachedBluetoothDevice device : devices) {
+                        // don't get the level if still pairing
+                        int state = device.getMaxConnectionState();
+                        if (state == BluetoothProfile.STATE_CONNECTED) {
+                            int batteryLevel = device.getBatteryLevel();
+                            contentDescription = mResources.getString(R.string.accessibility_bluetooth_connected);
+                            if (batteryLevel != BluetoothDevice.BATTERY_LEVEL_UNKNOWN) {
+                                final int padding = mResources.getDimensionPixelSize(com.android.settingslib.R.dimen.bt_battery_padding);
+                                Drawable d = BluetoothDeviceLayerDrawable.createLayerDrawable(mContext,
+                                        R.drawable.ic_bluetooth_connected, batteryLevel, 1, -padding, padding, 0);
+                                icon = new StatusBarIcon(UserHandle.SYSTEM, mContext.getPackageName(),
+                                        Icon.createWithBitmap(getBitmapFromDrawable(d)), 0, 0, contentDescription,
+                                            StatusBarIcon.Type.SystemIcon);
+                            } else {
+                                iconId = R.drawable.stat_sys_data_bluetooth_connected;
+                            }
+                            break;
+                        }
+                    }
+                }
                 bluetoothVisible = mBluetooth.isBluetoothEnabled();
             }
         }
 
-        mIconController.setIcon(mSlotBluetooth, iconId, contentDescription);
+        if (icon != null) {
+            mIconController.setCustomIcon(mSlotBluetooth, icon);
+        } else {
+            mIconController.setIcon(mSlotBluetooth, iconId, contentDescription);
+        }
         mIconController.setIconVisibility(mSlotBluetooth, bluetoothVisible);
     }
 
@@ -851,6 +908,9 @@
                 case AudioManager.ACTION_HEADSET_PLUG:
                     updateHeadsetPlug(intent);
                     break;
+                case BluetoothDevice.ACTION_BATTERY_LEVEL_CHANGED:
+                    updateBluetooth();
+                    break;
             }
         }
     };
@@ -943,4 +1003,43 @@
 
         mIconController.setIconVisibility(mSlotConnectedDisplay, visible);
     }
+
+    @Override
+    public void onIntSettingChanged(String key, Integer newValue) {
+        mShowAlarm = System.getIntForUser(mContext.getContentResolver(),
+                OmniSettings.OMNI_STATUS_BAR_ALARM, 0, mUserTracker.getUserId()) != 0;
+        updateAlarm();
+        mShowBtBattery = System.getIntForUser(mContext.getContentResolver(),
+                OmniSettings.OMNI_STATUS_BAR_BT_BATTERY, 0, mUserTracker.getUserId()) != 0;
+        updateBluetooth();
+    }
+
+    private boolean zenAllowsAlarm() {
+        int zen = mZenController.getZen();
+        if (zen == Global.ZEN_MODE_OFF) {
+            return true;
+        }
+        if (zen == Global.ZEN_MODE_NO_INTERRUPTIONS) {
+            return false;
+        }
+        if (zen == Global.ZEN_MODE_ALARMS) {
+            return true;
+        }
+        boolean allowAlarms = (mZenController.getConsolidatedPolicy().priorityCategories & NotificationManager.Policy
+                .PRIORITY_CATEGORY_ALARMS) != 0;
+        return allowAlarms;
+    }
+
+    private Bitmap getBitmapFromDrawable(Drawable image) {
+        final Canvas canvas = new Canvas();
+        canvas.setDrawFilter(new PaintFlagsDrawFilter(Paint.ANTI_ALIAS_FLAG,
+                Paint.FILTER_BITMAP_FLAG));
+
+        Bitmap bmResult = Bitmap.createBitmap(image.getIntrinsicWidth(), image.getIntrinsicHeight(),
+                Bitmap.Config.ARGB_8888);
+        canvas.setBitmap(bmResult);
+        image.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+        image.draw(canvas);
+        return bmResult;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/StatusBarIconController.java
index 0459b97..4edc42c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/StatusBarIconController.java
@@ -61,6 +61,11 @@
     void setIcon(String slot, int resourceId, CharSequence contentDescription);
 
     /**
+     * @hide
+     */
+    void setCustomIcon(String slot, StatusBarIcon icon);
+
+    /**
      * Adds or updates an icon for the given slot.
      *
      * @param resPackage the package name containing the resource in question. Can be null if the
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerImpl.java
index e66e8138..f6c06c5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ui/StatusBarIconControllerImpl.java
@@ -293,6 +293,17 @@
     }
 
     @Override
+    public void setCustomIcon(String slot, StatusBarIcon icon) {
+        if (icon == null) {
+            removeAllIconsForSlot(slot, /* fromNewPipeline */ false);
+            return;
+        }
+
+        StatusBarIconHolder holder = StatusBarIconHolder.fromIcon(icon);
+        setIcon(slot, holder);
+    }
+
+    @Override
     public void setNewWifiIcon() {
         String slot = mContext.getString(com.android.internal.R.string.status_bar_wifi);
         StatusBarIconHolder holder = mStatusBarIconList.getIconHolder(slot, /* tag= */ 0);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
index 279e5ef..f7f38aa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
@@ -24,6 +24,7 @@
     void setFlashlight(boolean newState);
     boolean isAvailable();
     boolean isEnabled();
+    void initFlashLight();
 
     @WeaklyReferencedCallback
     public interface FlashlightListener {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightControllerImpl.java
index 615cc74..ca77397 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightControllerImpl.java
@@ -121,6 +121,12 @@
         }
     }
 
+    public synchronized void initFlashLight() {
+        if (mCameraId == null) {
+            tryInitCamera();
+        }
+    }
+
     public void setFlashlight(boolean enabled) {
         if (!mHasFlashlight) return;
         if (mCameraId.get() == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 28cf78f..6df3a5e 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -801,12 +801,6 @@
             mActivityManager.setThemeOverlayReady(currentUser);
         };
 
-        if (colorSchemeIsApplied(managedProfiles)) {
-            Log.d(TAG, "Skipping overlay creation. Theme was already: " + mColorScheme);
-            onCompleteCallback.run();
-            return;
-        }
-
         if (DEBUG) {
             Log.d(TAG, "Applying overlays: " + categoryToPackage.keySet().stream()
                     .map(key -> key + " -> " + categoryToPackage.get(key)).collect(
diff --git a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
index 8a6f79d..35c6de7 100644
--- a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
+++ b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
@@ -88,6 +88,7 @@
                 isTv(context)
                         ? NotificationManager.IMPORTANCE_DEFAULT
                         : NotificationManager.IMPORTANCE_LOW);
+        storage.setBlockable(true);
 
         final NotificationChannel hint = new NotificationChannel(
                 HINTS,
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index a4e46f6..84db887 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -888,18 +888,22 @@
         final LayerDrawable seekbarDrawable =
                 (LayerDrawable) mContext.getDrawable(R.drawable.volume_row_seekbar);
 
+        final LayerDrawable seekbarThumbDrawable =
+                (LayerDrawable) mContext.getDrawable(R.drawable.volume_row_seekbar_thumb);
+
         final LayerDrawable seekbarProgressDrawable = (LayerDrawable)
                 ((RoundedCornerProgressDrawable) seekbarDrawable.findDrawableByLayerId(
                         android.R.id.progress)).getDrawable();
 
         row.sliderProgressSolid = seekbarProgressDrawable.findDrawableByLayerId(
                 R.id.volume_seekbar_progress_solid);
-        final Drawable sliderProgressIcon = seekbarProgressDrawable.findDrawableByLayerId(
+        final Drawable sliderProgressIcon = seekbarThumbDrawable.findDrawableByLayerId(
                         R.id.volume_seekbar_progress_icon);
         row.sliderProgressIcon = sliderProgressIcon != null ? (AlphaTintDrawableWrapper)
                 ((RotateDrawable) sliderProgressIcon).getDrawable() : null;
 
         row.slider.setProgressDrawable(seekbarDrawable);
+        row.slider.setThumb(seekbarThumbDrawable);
 
         row.icon = row.view.findViewById(R.id.volume_row_icon);
 
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index 7ac7859..e0bb98c 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -7444,5 +7444,8 @@
     // ---- End Q Constants, all Q constants go above this line ----
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
+
+    // ACTION: Custom Omni metrics
+    CUSTOM_QUICK_TILES = 9001;
   }
 }
diff --git a/services/Android.bp b/services/Android.bp
index 7298f14..20aa00c 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -323,6 +323,7 @@
         "service-permission.stubs.system_server",
         "service-rkp.stubs.system_server",
         "service-sdksandbox.stubs.system_server",
+        "omnirom.internal",
     ],
 
     soong_config_variables: {
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetXmlUtil.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetXmlUtil.java
index ce9130a..c1bfb7a 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetXmlUtil.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetXmlUtil.java
@@ -117,7 +117,7 @@
         out.attributeInt(null, ATTR_WIDGET_FEATURES, info.widgetFeatures);
         out.attributeInt(null, ATTR_DESCRIPTION_RES, info.descriptionRes);
         out.attributeBoolean(null, ATTR_PROVIDER_INHERITANCE, info.isExtendedFromAppWidgetProvider);
-        out.attribute(null, ATTR_OS_FINGERPRINT, Build.FINGERPRINT);
+        out.attribute(null, ATTR_OS_FINGERPRINT, String.valueOf(Build.TIME));
     }
 
     /**
@@ -128,7 +128,7 @@
             @NonNull final TypedXmlPullParser parser) {
         Objects.requireNonNull(parser);
         final String fingerprint = parser.getAttributeValue(null, ATTR_OS_FINGERPRINT);
-        if (!Build.FINGERPRINT.equals(fingerprint)) {
+        if (!String.valueOf(Build.TIME).equals(fingerprint)) {
             return null;
         }
         final AppWidgetProviderInfo info = new AppWidgetProviderInfo();
diff --git a/services/core/Android.bp b/services/core/Android.bp
index b3d85f8..7a583a4 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -216,6 +216,7 @@
         "icu4j_calendar_astronomer",
         "android.security.aaid_aidl-java",
         "netd-client",
+        "omnirom.internal",
         "overlayable_policy_aidl-java",
         "SurfaceFlingerProperties",
         "com.android.sysprop.watchdog",
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index 4cf17ae..bfd8790 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -82,6 +82,8 @@
 import com.android.server.lights.LightsManager;
 import com.android.server.lights.LogicalLight;
 
+import org.omnirom.omnilib.utils.OmniSettings;
+
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileOutputStream;
@@ -350,6 +352,27 @@
 
     private MetricsLogger mMetricsLogger;
 
+    //Battery light color customization
+    private boolean mLightEnabled = false;
+    private boolean mAllowBatteryLightOnDnd;
+    private boolean mIsDndActive;
+    private boolean mMultiColorLed;
+    private boolean mLightOnlyFullyCharged;
+    private boolean mFastChargingLedSupported;
+    private boolean mFastBatteryLightEnabled;
+    private int mBatteryLowARGB;
+    private int mBatteryMediumARGB;
+    private int mBatteryFullARGB;
+    private int mBatteryReallyFullARGB;
+    private int mFastBatteryARGB;
+    private int mBatteryLowBehavior;
+    private int mBatteryLowBehaviorCustom;
+
+    // TODO - thats a resource constant in SystemUI - maybe better
+    // move those into core context
+    private static final int FAST_CHARGING_ENABLED_THRESHOLD = 7500000;
+    private static final int DEFAULT_CHARGING_VOLTAGE_MICRO_VOLT = 5000000;
+
     private static final int MSG_BROADCAST_BATTERY_CHANGED = 1;
     private static final int MSG_BROADCAST_POWER_CONNECTION_CHANGED = 2;
     private static final int MSG_BROADCAST_BATTERY_LOW_OKAY = 3;
@@ -456,6 +479,8 @@
                 com.android.internal.R.bool.config_shutdownIfNoPower);
         sSystemUiPackage = mContext.getResources().getString(
                 com.android.internal.R.string.config_systemUi);
+        mFastChargingLedSupported = context.getResources().getBoolean(
+                org.omnirom.omnilib.R.bool.config_FastChargingLedSupported);
 
         mBatteryLevelsEventQueue = new ArrayDeque<>();
         mMetricsLogger = new MetricsLogger();
@@ -510,6 +535,114 @@
                         false, obs, UserHandle.USER_ALL);
                 updateBatteryWarningLevelLocked();
             }
+        } else if (phase == PHASE_BOOT_COMPLETED) {
+            SettingsObserver mObserver = new SettingsObserver(new Handler());
+            mObserver.observe();
+        }
+    }
+
+    private synchronized void updateLed() {
+        mLed.updateLightsLocked();
+    }
+
+    class SettingsObserver extends ContentObserver {
+        SettingsObserver(Handler handler) {
+            super(handler);
+        }
+
+        void observe() {
+            ContentResolver resolver = mContext.getContentResolver();
+
+            // Battery light enabled
+            resolver.registerContentObserver(Settings.System.getUriFor(
+                    OmniSettings.OMNI_BATTERY_LIGHT_ENABLED),
+                    false, this, UserHandle.USER_ALL);
+            resolver.registerContentObserver(Settings.System.getUriFor(
+                    OmniSettings.OMNI_BATTERY_LIGHT_ALLOW_ON_DND),
+                    false, this, UserHandle.USER_ALL);
+            resolver.registerContentObserver(
+                    Settings.Global.getUriFor(Settings.Global.ZEN_MODE),
+                    false, this, UserHandle.USER_ALL);
+            resolver.registerContentObserver(Settings.System.getUriFor(
+                    OmniSettings.OMNI_BATTERY_LIGHT_ONLY_FULLY_CHARGED),
+                    false, this, UserHandle.USER_ALL);
+            resolver.registerContentObserver(Settings.System.getUriFor(
+                    OmniSettings.OMNI_LOW_BATTERY_BEHAVIOR),
+                    false, this, UserHandle.USER_ALL);
+            if (mMultiColorLed) {
+                resolver.registerContentObserver(Settings.System.getUriFor(
+                        OmniSettings.OMNI_BATTERY_LIGHT_LOW_COLOR),
+                        false, this, UserHandle.USER_ALL);
+                resolver.registerContentObserver(Settings.System.getUriFor(
+                        OmniSettings.OMNI_BATTERY_LIGHT_MEDIUM_COLOR),
+                        false, this, UserHandle.USER_ALL);
+                resolver.registerContentObserver(Settings.System.getUriFor(
+                        OmniSettings.OMNI_BATTERY_LIGHT_FULL_COLOR),
+                        false, this, UserHandle.USER_ALL);
+                resolver.registerContentObserver(Settings.System.getUriFor(
+                        OmniSettings.OMNI_BATTERY_LIGHT_REALLY_FULL_COLOR),
+                        false, this, UserHandle.USER_ALL);
+
+                if (mFastChargingLedSupported) {
+                    //Fast Charging LED
+                    resolver.registerContentObserver(Settings.System.getUriFor(
+                            OmniSettings.OMNI_FAST_CHARGING_LED_ENABLED), false, this,
+                            UserHandle.USER_ALL);
+                     // Register observer if we have a device that supports fast charging
+                    resolver.registerContentObserver(Settings.System.getUriFor(
+                            OmniSettings.OMNI_FAST_BATTERY_LIGHT_COLOR), false, this,
+                            UserHandle.USER_ALL);
+                }
+            }
+            update();
+        }
+
+        @Override
+        public void onChange(boolean selfChange) {
+            update();
+        }
+
+        public void update() {
+            ContentResolver resolver = mContext.getContentResolver();
+
+            // Battery light enabled
+            mLightEnabled = Settings.System.getIntForUser(resolver,
+                    OmniSettings.OMNI_BATTERY_LIGHT_ENABLED, 1,
+                    UserHandle.USER_CURRENT) != 0;
+            mAllowBatteryLightOnDnd = Settings.System.getIntForUser(resolver,
+                    OmniSettings.OMNI_BATTERY_LIGHT_ALLOW_ON_DND, 0,
+                    UserHandle.USER_CURRENT) == 1;
+            mIsDndActive = Settings.Global.getInt(resolver,
+                    Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF)
+                    != Settings.Global.ZEN_MODE_OFF;
+            mBatteryLowARGB = Settings.System.getIntForUser(resolver,
+                    OmniSettings.OMNI_BATTERY_LIGHT_LOW_COLOR, 0xFFFF0000,
+                    UserHandle.USER_CURRENT);
+            mBatteryMediumARGB = Settings.System.getIntForUser(resolver,
+                    OmniSettings.OMNI_BATTERY_LIGHT_MEDIUM_COLOR, 0xFFFFFF00,
+                    UserHandle.USER_CURRENT);
+            mBatteryFullARGB = Settings.System.getIntForUser(resolver,
+                    OmniSettings.OMNI_BATTERY_LIGHT_FULL_COLOR, 0xFFFFFF00,
+                    UserHandle.USER_CURRENT);
+            mBatteryReallyFullARGB = Settings.System.getIntForUser(resolver,
+                    OmniSettings.OMNI_BATTERY_LIGHT_REALLY_FULL_COLOR, 0xFF00FF00,
+                    UserHandle.USER_CURRENT);
+            mFastBatteryLightEnabled = Settings.System.getIntForUser(resolver,
+                    OmniSettings.OMNI_FAST_CHARGING_LED_ENABLED, 0,
+                    UserHandle.USER_CURRENT) != 0;
+            mFastBatteryARGB = Settings.System.getIntForUser(resolver,
+                    OmniSettings.OMNI_FAST_BATTERY_LIGHT_COLOR,
+                    mContext.getResources().getInteger(
+                        org.omnirom.omnilib.R.integer.config_notificationsFastBatteryARGB),
+                    UserHandle.USER_CURRENT);
+            mLightOnlyFullyCharged = Settings.System.getIntForUser(resolver,
+                    OmniSettings.OMNI_BATTERY_LIGHT_ONLY_FULLY_CHARGED, 0,
+                    UserHandle.USER_CURRENT) != 0;
+            mBatteryLowBehaviorCustom = Settings.System.getIntForUser(resolver,
+                    OmniSettings.OMNI_LOW_BATTERY_BEHAVIOR, 0,
+                    UserHandle.USER_CURRENT);
+
+            updateLed();
         }
     }
 
@@ -998,6 +1131,29 @@
                 mLastBroadcastBatteryCycleCount = mHealthInfo.batteryCycleCount;
                 mLastBroadcastChargingState = mHealthInfo.chargingState;
                 mLastBroadcastBatteryCapacityLevel = mHealthInfo.batteryCapacityLevel;
+
+                final int maxChargingMicroWatt;
+                if (mLastMaxChargingVoltage <= 0) {
+                    mLastMaxChargingVoltage = DEFAULT_CHARGING_VOLTAGE_MICRO_VOLT;
+                }
+                if (mLastMaxChargingCurrent > 0) {
+                    // Calculating muW = muA * muV / (10^6 mu^2 / mu); splitting up the divisor
+                    // to maintain precision equally on both factors.
+                    maxChargingMicroWatt = (mLastMaxChargingCurrent / 1000)
+                            * (mLastMaxChargingVoltage / 1000);
+                } else {
+                    maxChargingMicroWatt = -1;
+                }
+
+                if (DEBUG) {
+                    Slog.d(TAG, "mLastMaxChargingCurrent = " + mLastMaxChargingCurrent +
+                            " mLastMaxChargingVoltage = " + mLastMaxChargingVoltage +
+                            " maxChargingMicroWatt = " + maxChargingMicroWatt);
+                }
+                if (mFastChargingLedSupported) {
+                    // Update the Fast battery LED
+                    mLed.fastCharge(maxChargingMicroWatt);
+                }
             }
         }
     }
@@ -1748,22 +1904,24 @@
 
         private final LogicalLight mBatteryLight;
 
-        private final int mBatteryLowARGB;
-        private final int mBatteryMediumARGB;
-        private final int mBatteryFullARGB;
         private final int mBatteryLedOn;
         private final int mBatteryLedOff;
-        private final int mBatteryLowBehavior;
+        private boolean mIsFastCharging;
+
+        protected void fastCharge(int maxChargingMicroWatt) {
+            mIsFastCharging = maxChargingMicroWatt > FAST_CHARGING_ENABLED_THRESHOLD;
+            if (DEBUG) {
+                Slog.d(TAG, "mIsFastCharging = " + mIsFastCharging);
+            }
+            updateLightsLocked();
+        }
 
         public Led(Context context, LightsManager lights) {
             mBatteryLight = lights.getLight(LightsManager.LIGHT_ID_BATTERY);
 
-            mBatteryLowARGB = context.getResources().getInteger(
-                    com.android.internal.R.integer.config_notificationsBatteryLowARGB);
-            mBatteryMediumARGB = context.getResources().getInteger(
-                    com.android.internal.R.integer.config_notificationsBatteryMediumARGB);
-            mBatteryFullARGB = context.getResources().getInteger(
-                    com.android.internal.R.integer.config_notificationsBatteryFullARGB);
+            // Does the Device support changing battery LED colors?
+            mMultiColorLed = context.getResources().getBoolean(
+                    org.omnirom.omnilib.R.bool.config_multiColorBatteryLed);
             mBatteryLedOn = context.getResources().getInteger(
                     com.android.internal.R.integer.config_notificationsBatteryLedOn);
             mBatteryLedOff = context.getResources().getInteger(
@@ -1781,25 +1939,41 @@
             if (mBatteryLight == null) {
                 return;
             }
+            // mHealthInfo could be null on startup (called by SettingsObserver)
+            if (mHealthInfo == null) {
+                Slog.w(TAG, "updateLightsLocked: mHealthInfo is null; skipping");
+                return;
+            }
             final int level = mHealthInfo.batteryLevel;
             final int status = mHealthInfo.batteryStatus;
-            if (level < mLowBatteryWarningLevel) {
+            boolean fastlightenabled = mFastBatteryLightEnabled & mIsFastCharging;
+            if (!mLightEnabled || (mIsDndActive && !mAllowBatteryLightOnDnd)) {
+                mBatteryLight.turnOff();
+            } else if (level < mLowBatteryWarningLevel) {
+                if (mContext.getResources().getBoolean(
+                            org.omnirom.omnilib.R.bool.config_intrusiveBatteryLed)) {
+                    mBatteryLowBehavior = mBatteryLowBehaviorCustom;
+                }
                 switch (mBatteryLowBehavior) {
                     case LOW_BATTERY_BEHAVIOR_SOLID:
-                        // Solid red when low battery
+                        // Solid color when low battery
                         mBatteryLight.setColor(mBatteryLowARGB);
                         break;
                     case LOW_BATTERY_BEHAVIOR_FLASHING:
-                        // Flash red when battery is low and not charging
+                        // Flash when battery is low and not charging
                         mBatteryLight.setFlashing(mBatteryLowARGB, LogicalLight.LIGHT_FLASH_TIMED,
                                 mBatteryLedOn, mBatteryLedOff);
                         break;
                     default:
-                        if (status == BatteryManager.BATTERY_STATUS_CHARGING) {
-                            // Solid red when battery is charging
+                        if (fastlightenabled) {
+                            //Solid color when battery is fast charging
+                            mBatteryLight.setColor(mFastBatteryARGB);
+                            mLightEnabled = !mLightOnlyFullyCharged;
+                        } else if (status == BatteryManager.BATTERY_STATUS_CHARGING) {
+                            // Solid when battery is charging
                             mBatteryLight.setColor(mBatteryLowARGB);
                         } else {
-                            // Flash red when battery is low and not charging
+                            // Flash when battery is low and not charging
                             mBatteryLight.setFlashing(mBatteryLowARGB,
                                     LogicalLight.LIGHT_FLASH_TIMED, mBatteryLedOn, mBatteryLedOff);
                         }
@@ -1809,11 +1983,23 @@
                     || status == BatteryManager.BATTERY_STATUS_FULL) {
                 if (status == BatteryManager.BATTERY_STATUS_FULL
                         || level >= mBatteryNearlyFullLevel) {
-                    // Solid green when full or charging and nearly full
-                    mBatteryLight.setColor(mBatteryFullARGB);
+                    if (level == 100) {
+                        // Battery is really full
+                        mBatteryLight.setColor(mBatteryReallyFullARGB);
+                    } else {
+                        // Battery is full or charging and nearly full
+                        mBatteryLight.setColor(mBatteryFullARGB);
+                    }
                 } else {
-                    // Solid orange when charging and halfway full
-                    mBatteryLight.setColor(mBatteryMediumARGB);
+                    if (fastlightenabled) {
+                        //Solid color when battery is fast charging
+                        mBatteryLight.setColor(mFastBatteryARGB);
+                        mLightEnabled = !mLightOnlyFullyCharged;
+                    } else {
+                        // Battery is charging and halfway full
+                        mLightEnabled = !mLightOnlyFullyCharged;
+                        mBatteryLight.setColor(mBatteryMediumARGB);
+                    }
                 }
             } else {
                 // No lights if not charging and not low
diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java
index ccc44a4..de0a2b3 100644
--- a/services/core/java/com/android/server/GestureLauncherService.java
+++ b/services/core/java/com/android/server/GestureLauncherService.java
@@ -700,6 +700,14 @@
                 Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_CURRENT) != 0;
     }
 
+    /**
+     * @return true if camera was launched, false otherwise.
+     * @hide
+     */
+    public boolean doCameraLaunchGesture() {
+        return handleCameraGesture(false, StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP);
+    }
+
     private final BroadcastReceiver mUserReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index b7bc4e4..0f1f09c 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -1634,7 +1634,7 @@
 
             // Adoptable public disks are visible to apps, since they meet
             // public API requirement of being in a stable location.
-            if (vol.disk.isAdoptable()) {
+            if (vol.disk.isAdoptable() || vol.disk.isSd()) {
                 vol.mountFlags |= VolumeInfo.MOUNT_FLAG_VISIBLE_FOR_WRITE;
             }
 
diff --git a/services/core/java/com/android/server/dreams/DreamManagerService.java b/services/core/java/com/android/server/dreams/DreamManagerService.java
index 0c04be1..d447a6c 100644
--- a/services/core/java/com/android/server/dreams/DreamManagerService.java
+++ b/services/core/java/com/android/server/dreams/DreamManagerService.java
@@ -1073,6 +1073,18 @@
         }
 
         @Override // Binder call
+        public boolean isDozing() {
+            checkPermission(android.Manifest.permission.READ_DREAM_STATE);
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                return isDozingInternal();
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        @Override // Binder call
         public boolean isDreamingOrInPreview() {
             checkPermission(android.Manifest.permission.READ_DREAM_STATE);
 
@@ -1333,6 +1345,11 @@
         }
 
         @Override
+        public boolean isDozing() {
+            return isDozingInternal();
+        }
+
+        @Override
         public boolean canStartDreaming(boolean isScreenOn) {
             return canStartDreamingInternal(isScreenOn);
         }
diff --git a/services/core/java/com/android/server/logcat/LogcatManagerService.java b/services/core/java/com/android/server/logcat/LogcatManagerService.java
index fee54f5..92ac6e2 100644
--- a/services/core/java/com/android/server/logcat/LogcatManagerService.java
+++ b/services/core/java/com/android/server/logcat/LogcatManagerService.java
@@ -435,6 +435,11 @@
             return;
         }
 
+        if (client.mPackageName.equals("org.omnirom.logcat")) {
+            onAccessApprovedForClient(client);
+            return;
+        }
+
         if (!shouldShowConfirmationDialog(client)) {
             onAccessDeclinedForClient(client);
             return;
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index 0e9ec4d..3028977 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -822,7 +822,8 @@
 
         // Idmaps for immutable RROs targeting "android", i.e. framework-res.apk, are created at
         // boot time in OverlayConfig.createImmutableFrameworkIdmapsInZygote().
-        if (targetPackage != null && !("android".equals(info.getTargetPackageName())
+        if (targetPackage != null && !(("android".equals(info.getTargetPackageName()) ||
+                                        "omnirom.platform".equals(info.getTargetPackageName()))
                 && !isPackageConfiguredMutable(overlayPackage))) {
             idmapStatus = mIdmapManager.createIdmap(targetPackage, overlayPackageState,
                     overlayPackage, updatedOverlayInfo.baseCodePath, overlay.getOverlayName(),
diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java
index be2f58d..c1c263b 100644
--- a/services/core/java/com/android/server/pm/ComputerEngine.java
+++ b/services/core/java/com/android/server/pm/ComputerEngine.java
@@ -169,6 +169,7 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.nio.charset.StandardCharsets;
+import java.security.cert.CertificateException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -440,6 +441,16 @@
         return mLocalAndroidApplication;
     }
 
+    /**
+     * The Google signature faked by microG.
+     */
+    private static final String MICROG_FAKE_SIGNATURE = "308204433082032ba003020102020900c2e08746644a308d300d06092a864886f70d01010405003074310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e205669657731143012060355040a130b476f6f676c6520496e632e3110300e060355040b1307416e64726f69643110300e06035504031307416e64726f6964301e170d3038303832313233313333345a170d3336303130373233313333345a3074310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e205669657731143012060355040a130b476f6f676c6520496e632e3110300e060355040b1307416e64726f69643110300e06035504031307416e64726f696430820120300d06092a864886f70d01010105000382010d00308201080282010100ab562e00d83ba208ae0a966f124e29da11f2ab56d08f58e2cca91303e9b754d372f640a71b1dcb130967624e4656a7776a92193db2e5bfb724a91e77188b0e6a47a43b33d9609b77183145ccdf7b2e586674c9e1565b1f4c6a5955bff251a63dabf9c55c27222252e875e4f8154a645f897168c0b1bfc612eabf785769bb34aa7984dc7e2ea2764cae8307d8c17154d7ee5f64a51a44a602c249054157dc02cd5f5c0e55fbef8519fbe327f0b1511692c5a06f19d18385f5c4dbc2d6b93f68cc2979c70e18ab93866b3bd5db8999552a0e3b4c99df58fb918bedc182ba35e003c1b4b10dd244a8ee24fffd333872ab5221985edab0fc0d0b145b6aa192858e79020103a381d93081d6301d0603551d0e04160414c77d8cc2211756259a7fd382df6be398e4d786a53081a60603551d2304819e30819b8014c77d8cc2211756259a7fd382df6be398e4d786a5a178a4763074310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e205669657731143012060355040a130b476f6f676c6520496e632e3110300e060355040b1307416e64726f69643110300e06035504031307416e64726f6964820900c2e08746644a308d300c0603551d13040530030101ff300d06092a864886f70d010104050003820101006dd252ceef85302c360aaace939bcff2cca904bb5d7a1661f8ae46b2994204d0ff4a68c7ed1a531ec4595a623ce60763b167297a7ae35712c407f208f0cb109429124d7b106219c084ca3eb3f9ad5fb871ef92269a8be28bf16d44c8d9a08e6cb2f005bb3fe2cb96447e868e731076ad45b33f6009ea19c161e62641aa99271dfd5228c5c587875ddb7f452758d661f6cc0cccb7352e424cc4365c523532f7325137593c4ae341f4db41edda0d0b1071a7c440f0fe9ea01cb627ca674369d084bd2fd911ff06cdbf2cfa10dc0f893ae35762919048c7efc64c7144178342f70581c9de573af55b390dd7fdb9418631895d5f759f30112687ff621410c069308a";
+
+    /**
+     * List of packages which require signature spoofing.
+     */
+    private static final List<String> MICROG_FAKE_SIGNATURE_PACKAGES = List.of("com.google.android.gms", "com.android.vending");
+
     ComputerEngine(PackageManagerService.Snapshot args, int version) {
         mVersion = version;
         mSettings = new Settings(args.settings);
@@ -1511,23 +1522,53 @@
             // Compute GIDs only if requested
             final int[] gids = (flags & PackageManager.GET_GIDS) == 0 ? EMPTY_INT_ARRAY
                     : mPermissionManager.getGidsForUid(UserHandle.getUid(userId, ps.getAppId()));
+
+            // Allow microG GmsCore and FakeStore to spoof signature
+            final boolean isMicroG = MICROG_FAKE_SIGNATURE_PACKAGES.contains(p.getPackageName());
+
+            // OmniLib ressources overlay enabled by the ROM_BUILDTYPE MicroG
+            final boolean mUseMicroGBuildType = mContext.getResources().getBoolean(
+                        org.omnirom.omnilib.R.bool.config_useMicroGBuildType);
+
             // Compute installed permissions only if requested
             final Set<String> installedPermissions = ((flags & PackageManager.GET_PERMISSIONS) == 0
                     || ArrayUtils.isEmpty(p.getPermissions())) ? Collections.emptySet()
                     : mPermissionManager.getInstalledPermissions(ps.getPackageName());
             // Compute granted permissions only if package has requested permissions
-            final Set<String> grantedPermissions = ((flags & PackageManager.GET_PERMISSIONS) == 0
-                    || ArrayUtils.isEmpty(p.getRequestedPermissions())) ? Collections.emptySet()
+            // or we matched a microg package
+            final Set<String> grantedPermissions = (((flags & PackageManager.GET_PERMISSIONS) == 0
+                    || ArrayUtils.isEmpty(p.getRequestedPermissions())) && !isMicroG && !mUseMicroGBuildType ) ? Collections.emptySet()
                     : mPermissionManager.getGrantedPermissions(ps.getPackageName(), userId);
 
             PackageInfo packageInfo = PackageInfoUtils.generate(p, gids, flags,
                     state.getFirstInstallTimeMillis(), ps.getLastUpdateTime(), installedPermissions,
                     grantedPermissions, state, userId, ps);
 
+            if (isMicroG && mUseMicroGBuildType) {
+                packageInfo = mayFakeSignature(p, packageInfo, grantedPermissions);
+            }
+
             if (packageInfo == null) {
                 return null;
             }
 
+            if (isMicroG && mUseMicroGBuildType) {
+                if (grantedPermissions.contains("android.permission.FAKE_PACKAGE_SIGNATURE")) {
+                    try {
+                        packageInfo.signingInfo = new SigningInfo(
+                                new SigningDetails(
+                                        packageInfo.signatures,
+                                        SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3,
+                                        SigningDetails.toSigningKeys(packageInfo.signatures),
+                                        null
+                                )
+                        );
+                    } catch (CertificateException e) {
+                        Slog.e(TAG, "Caught an exception when creating signing keys: ", e);
+                    }
+                }
+            }
+
             packageInfo.packageName = packageInfo.applicationInfo.packageName =
                     resolveExternalPackageName(p);
 
@@ -1578,6 +1619,21 @@
         }
     }
 
+    private PackageInfo mayFakeSignature(AndroidPackage p, PackageInfo pi,
+            Set<String> permissions) {
+        try {
+            if (permissions.contains("android.permission.FAKE_PACKAGE_SIGNATURE")) {
+                if (pi != null) {
+                    pi.signatures = new Signature[] {new Signature(MICROG_FAKE_SIGNATURE)};
+                }
+            }
+        } catch (Throwable t) {
+            // We should never die because of any failures, this is system code!
+            Log.w("PackageManagerService.FAKE_PACKAGE_SIGNATURE", t);
+        }
+        return pi;
+    }
+
     public final PackageInfo getPackageInfo(String packageName,
             @PackageManager.PackageInfoFlagsBits long flags, int userId) {
         return getPackageInfoInternal(packageName, PackageManager.VERSION_CODE_HIGHEST,
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index aadf112..24a56b7 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2239,7 +2239,7 @@
             if (mIsUpgrade) {
                 PackageManagerServiceUtils.logCriticalInfo(Log.INFO,
                         "Upgrading from " + ver.fingerprint + " (" + ver.buildFingerprint + ") to "
-                                + PackagePartitions.FINGERPRINT + " (" + Build.FINGERPRINT + ")");
+                                + PackagePartitions.FINGERPRINT + " (" + String.valueOf(Build.TIME) + ")");
             }
             mPriorSdkVersion = mIsUpgrade ? ver.sdkVersion : -1;
             mInitAppsHelper = new InitAppsHelper(this, mApexManager, mInstallPackageHelper,
@@ -2397,7 +2397,7 @@
                                         | Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES);
                     }
                 }
-                ver.buildFingerprint = Build.FINGERPRINT;
+                ver.buildFingerprint = String.valueOf(Build.TIME);
                 ver.fingerprint = PackagePartitions.FINGERPRINT;
             }
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 7af39f7..a297d90 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -1399,9 +1399,7 @@
         // NOTE: When no BUILD_NUMBER is set by the build system, it defaults to a build
         // that starts with "eng." to signify that this is an engineering build and not
         // destined for release.
-        if (isUserDebugBuild && incrementalVersion.startsWith("eng.")) {
-            Slog.w(TAG, "Wiping cache directory because the system partition changed.");
-
+        /*if (isUserDebugBuild && incrementalVersion.startsWith("eng.")) {
             // Heuristic: If the /system directory has been modified recently due to an "adb sync"
             // or a regular make, then blow away the cache. Note that mtimes are *NOT* reliable
             // in general and should not be used for production changes. In this specific case,
@@ -1409,10 +1407,11 @@
             File frameworkDir =
                     new File(Environment.getRootDirectory(), "framework");
             if (cacheDir.lastModified() < frameworkDir.lastModified()) {
+                Slog.w(TAG, "Wiping cache directory because the system partition changed.");
                 FileUtils.deleteContents(cacheBaseDir);
                 cacheDir = FileUtils.createDir(cacheBaseDir, cacheName);
             }
-        }
+        }*/
 
         return cacheDir;
     }
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 485a280..01f9ca8 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -485,7 +485,7 @@
         public void forceCurrent() {
             sdkVersion = Build.VERSION.SDK_INT;
             databaseVersion = CURRENT_DATABASE_VERSION;
-            buildFingerprint = Build.FINGERPRINT;
+            buildFingerprint = String.valueOf(Build.TIME);
             fingerprint = PackagePartitions.FINGERPRINT;
         }
     }
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 1052c94..90555a5 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -5259,7 +5259,7 @@
 
     // Injection point.
     String injectBuildFingerprint() {
-        return Build.FINGERPRINT;
+        return String.valueOf(Build.TIME);
     }
 
     final void wtf(String message) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 8052754..c318eec 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -154,6 +154,10 @@
 import android.hardware.input.InputManager;
 import android.hardware.input.InputSettings;
 import android.hardware.input.KeyGestureEvent;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
 import android.media.AudioManager;
 import android.media.AudioManagerInternal;
 import android.media.AudioSystem;
@@ -217,6 +221,11 @@
 import android.view.animation.AnimationUtils;
 import android.view.autofill.AutofillManagerInternal;
 import android.widget.Toast;
+import org.omnirom.omnilib.utils.DeviceKeyHandler;
+import org.omnirom.omnilib.utils.OmniSettings;
+import org.omnirom.omnilib.utils.OmniUtils;
+
+import dalvik.system.PathClassLoader;
 
 import com.android.internal.R;
 import com.android.internal.accessibility.AccessibilityShortcutController;
@@ -263,6 +272,7 @@
 import java.io.FileReader;
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.lang.reflect.Constructor;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
@@ -281,6 +291,7 @@
     static final boolean localLOGV = false;
     static final boolean DEBUG_INPUT = false;
     static final boolean DEBUG_KEYGUARD = false;
+    static final boolean DEBUG_PROXI_SENSOR = false;
     static final boolean DEBUG_WAKEUP = false;
 
     // Whether to allow dock apps with METADATA_DOCK_HOME to temporarily take over the Home key.
@@ -314,6 +325,7 @@
     static final int LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM = 3;
     static final int LONG_PRESS_POWER_GO_TO_VOICE_ASSIST = 4;
     static final int LONG_PRESS_POWER_ASSISTANT = 5; // Settings.Secure.ASSISTANT
+    static final int LONG_PRESS_POWER_TORCH = 6;
 
     // must match: config_veryLongPresOnPowerBehavior in config.xml
     // The config value can be overridden using Settings.Global.POWER_BUTTON_VERY_LONG_PRESS
@@ -763,6 +775,18 @@
     private static final int MSG_RINGER_TOGGLE_CHORD = 24;
     private static final int MSG_SWITCH_KEYBOARD_LAYOUT = 25;
     private static final int MSG_SET_DEFERRED_KEY_ACTIONS_EXECUTABLE = 27;
+    private static final int MSG_TOGGLE_TORCH = 28;
+
+    // omni additions start
+    private DeviceKeyHandler mDeviceKeyHandler;
+    private boolean mProxyIsNear;
+    private SensorManager mSensorManager;
+    private Sensor mProximitySensor;
+    private boolean mProxiWakeupCheckEnabled;
+    private boolean mProxiListenerEnabled;
+    private boolean mLongPressPowerTorch;
+
+    private static final int KEY_ACTION_TOGGLE_TORCH = 9;
 
     private class PolicyHandler extends Handler {
 
@@ -858,6 +882,9 @@
                     final long downTime = (Long) msg.obj;
                     mDeferredKeyActionExecutor.setActionsExecutable(keyCode, downTime);
                     break;
+                case MSG_TOGGLE_TORCH:
+                    performKeyAction(KEY_ACTION_TOGGLE_TORCH);
+                    break;
             }
         }
     }
@@ -943,6 +970,12 @@
             resolver.registerContentObserver(Settings.Secure.getUriFor(
                     Settings.Secure.NAV_BAR_KIDS_MODE), false, this,
                     UserHandle.USER_ALL);
+            resolver.registerContentObserver(Settings.System.getUriFor(
+                    OmniSettings.OMNI_SYSTEM_PROXI_CHECK_ENABLED), false, this,
+                    UserHandle.USER_ALL);
+            resolver.registerContentObserver(Settings.System.getUriFor(
+                    OmniSettings.OMNI_LONG_PRESS_POWER_TORCH), false, this,
+                    UserHandle.USER_ALL);
             updateSettings();
         }
 
@@ -1099,7 +1132,9 @@
                 || mKeyCombinationManager.isPowerKeyIntercepted();
         if (!mPowerKeyHandled) {
             if (!interactive) {
-                wakeUpFromWakeKey(event);
+                if (!mLongPressPowerTorch) {
+                    wakeUpFromWakeKey(event);
+                }
             }
         } else {
             // handled by another power key policy.
@@ -1199,6 +1234,8 @@
                     break;
                 }
             }
+        } else if (!mProxyIsNear && mLongPressPowerTorch && mSingleKeyGestureDetector.beganFromNonInteractive()) {
+            wakeUpFromWakeKey(eventTime, KEYCODE_POWER, /* isDown= */ false);
         }
     }
 
@@ -1454,6 +1491,17 @@
                 launchAssistAction(null, powerKeyDeviceId, eventTime,
                         AssistUtils.INVOCATION_TYPE_POWER_BUTTON_LONG_PRESS);
                 break;
+            case LONG_PRESS_POWER_TORCH:
+                mPowerKeyHandled = true;
+                performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
+                        "Power - Long Press - Toggle Torch");
+                // Toggle torch state asynchronously to help protect against
+                // a misbehaving cameraservice from blocking systemui.
+                mHandler.removeMessages(MSG_TOGGLE_TORCH);
+                Message msg = mHandler.obtainMessage(MSG_TOGGLE_TORCH);
+                msg.setAsynchronous(true);
+                msg.sendToTarget();
+                break;
         }
     }
 
@@ -1516,6 +1564,9 @@
         if (FactoryTest.isLongPressOnPowerOffEnabled()) {
             return LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM;
         }
+        if (mLongPressPowerTorch && (!isScreenOn() || isDozeMode())) {
+            return LONG_PRESS_POWER_TORCH;
+        }
 
         // If the config indicates the assistant behavior but the device isn't yet provisioned, show
         // global actions instead.
@@ -2492,6 +2543,49 @@
         initKeyGestures();
         mButtonOverridePermissionChecker = injector.getButtonOverridePermissionChecker();
         mSideFpsEventHandler = new SideFpsEventHandler(mContext, mHandler, mPowerManager);
+
+        String deviceKeyHandlerLib = mContext.getResources().getString(
+                org.omnirom.omnilib.R.string.config_deviceKeyHandlerLib);
+
+        String deviceKeyHandlerClass = mContext.getResources().getString(
+                org.omnirom.omnilib.R.string.config_deviceKeyHandlerClass);
+
+        if (!deviceKeyHandlerLib.isEmpty() && !deviceKeyHandlerClass.isEmpty()) {
+            try {
+                PathClassLoader loader =  new PathClassLoader(deviceKeyHandlerLib,
+                        getClass().getClassLoader());
+
+                Class<?> klass = loader.loadClass(deviceKeyHandlerClass);
+                Constructor<?> constructor = klass.getConstructor(Context.class);
+                mDeviceKeyHandler = (DeviceKeyHandler) constructor.newInstance(
+                        mContext);
+                if(DEBUG_INPUT) Slog.d(TAG, "Device key handler loaded");
+            } catch (Exception e) {
+                Slog.w(TAG, "Could not instantiate device key handler "
+                        + deviceKeyHandlerClass + " from class "
+                        + deviceKeyHandlerLib, e);
+            }
+        }
+        boolean supportPowerButtonProxyCheck = mContext.getResources().getBoolean(
+                org.omnirom.omnilib.R.bool.config_proxiSensorWakupCheck);
+        if (supportPowerButtonProxyCheck) {
+            mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
+            if (mDeviceKeyHandler != null && mDeviceKeyHandler.getCustomProxiSensor() != null) {
+                String proxySensor = mDeviceKeyHandler.getCustomProxiSensor();
+                for (Sensor sensor : mSensorManager.getSensorList(Sensor.TYPE_ALL)) {
+                    if (proxySensor.equals(sensor.getStringType())) {
+                        mProximitySensor = sensor;
+                        if (DEBUG_PROXI_SENSOR) Log.i(TAG, "mProximitySensor = " + proxySensor);
+                    }
+                }
+            }
+            if (mProximitySensor == null) {
+                mProximitySensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
+                if (mProximitySensor != null) {
+                    if (DEBUG_PROXI_SENSOR) Log.i(TAG, "mProximitySensor = Sensor.TYPE_PROXIMITY");
+                }
+            }
+        }
     }
 
     private void initKeyCombinationRules() {
@@ -2683,10 +2777,23 @@
 
         @Override
         void onLongPress(long eventTime) {
-            if (mSingleKeyGestureDetector.beganFromNonInteractive()
-                    && !mSupportLongPressPowerWhenNonInteractive) {
-                Slog.v(TAG, "Not support long press power when device is not interactive.");
-                return;
+            if (mSingleKeyGestureDetector.beganFromNonInteractive() || isFlashLightIsOn()) {
+                if (mLongPressPowerTorch) {
+                    if (!mProxyIsNear) {
+                        performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
+                        "Power - Long Press - Torch");
+                        performKeyAction(KEY_ACTION_TOGGLE_TORCH);
+                    }
+                    return;
+                }
+                if (!mSupportLongPressPowerWhenNonInteractive) {
+                    Slog.v(TAG, "Not support long press power when device is not interactive.");
+                    return;
+                }
+                if (mProxyIsNear) {
+                    if (DEBUG_PROXI_SENSOR) Log.i(TAG, "blocked onLongPress because of mProxyIsNear");
+                    return;
+                }
             }
 
             powerLongPress(eventTime);
@@ -3087,6 +3194,13 @@
                 mKidsModeEnabled = kidsModeEnabled;
                 updateKidsModeSettings = true;
             }
+
+            mProxiWakeupCheckEnabled = Settings.System.getIntForUser(resolver,
+                    OmniSettings.OMNI_SYSTEM_PROXI_CHECK_ENABLED, 0,
+                    UserHandle.USER_CURRENT) != 0;
+            mLongPressPowerTorch = Settings.System.getIntForUser(resolver,
+                    OmniSettings.OMNI_LONG_PRESS_POWER_TORCH, 0,
+                    UserHandle.USER_CURRENT) != 0;
         }
         if (updateKidsModeSettings) {
             updateKidsModeSettings(kidsModeEnabled);
@@ -4053,6 +4167,18 @@
             return true;
         }
 
+        // Specific device key handling
+        if (mDeviceKeyHandler != null) {
+            try {
+                // The device only will consume known keys.
+                if (mDeviceKeyHandler.canHandleKeyEvent(event)) {
+                    return true;
+                }
+            } catch (Exception e) {
+                Slog.w(TAG, "Could not dispatch event to device key handler", e);
+            }
+        }
+
         // Reserve all the META modifier combos for system behavior
         return (metaState & KeyEvent.META_META_ON) != 0;
     }
@@ -5320,6 +5446,53 @@
                 && (!isNavBarVirtKey || mNavBarVirtualKeyHapticFeedbackEnabled)
                 && event.getRepeatCount() == 0;
 
+        // Specific device key handling
+        if (mDeviceKeyHandler != null) {
+            try {
+                // The device says if we should ignore this event.
+                if (mDeviceKeyHandler.isDisabledKeyEvent(event)) {
+                    result &= ~ACTION_PASS_TO_USER;
+                    return result;
+                }
+                if (mDeviceKeyHandler.isCameraLaunchEvent(event)) {
+                    if (DEBUG_INPUT) {
+                        Slog.i(TAG, "isCameraLaunchEvent from DeviceKeyHandler");
+                    }
+                    GestureLauncherService gestureService = LocalServices.getService(
+                            GestureLauncherService.class);
+                    if (gestureService != null) {
+                        gestureService.doCameraLaunchGesture();
+                    }
+                    result &= ~ACTION_PASS_TO_USER;
+                    return result;
+                }
+                if (!interactive && mDeviceKeyHandler.isWakeEvent(event)) {
+                    if (DEBUG_INPUT) {
+                        Slog.i(TAG, "isWakeEvent from DeviceKeyHandler");
+                    }
+                    wakeUpFromWakeKey(event);
+                    result &= ~ACTION_PASS_TO_USER;
+                    return result;
+                }
+                final Intent eventLaunchActivity = mDeviceKeyHandler.isActivityLaunchEvent(event);
+                if (!interactive && eventLaunchActivity != null) {
+                    if (DEBUG_INPUT) {
+                        Slog.i(TAG, "isActivityLaunchEvent from DeviceKeyHandler " + eventLaunchActivity);
+                    }
+                    wakeUpFromWakeKey(event);
+                    OmniUtils.launchKeyguardDismissIntent(mContext, UserHandle.CURRENT, eventLaunchActivity);
+                    result &= ~ACTION_PASS_TO_USER;
+                    return result;
+                }
+                if (mDeviceKeyHandler.handleKeyEvent(event)) {
+                    result &= ~ACTION_PASS_TO_USER;
+                    return result;
+                }
+            } catch (Exception e) {
+                Slog.w(TAG, "Could not dispatch event to device key handler", e);
+            }
+        }
+
         // Handle special keys.
         switch (keyCode) {
             case KeyEvent.KEYCODE_BACK: {
@@ -5471,6 +5644,10 @@
                 // Any activity on the power button stops the accessibility shortcut
                 result &= ~ACTION_PASS_TO_USER;
                 isWakeKey = false; // wake-up will be handled separately
+                if (mProxiListenerEnabled && mProxyIsNear) {
+                    if (DEBUG_PROXI_SENSOR) Log.i(TAG, "KeyEvent.KEYCODE_POWER blocked because of mProxyIsNear");
+                    break;
+                }
                 if (down) {
                     interceptPowerKeyDown(event, interactiveAndAwake, isKeyGestureTriggered);
                 } else {
@@ -5833,6 +6010,10 @@
      * is always considered a wake key.
      */
     private boolean isWakeKeyWhenScreenOff(int keyCode) {
+        if (mProxiListenerEnabled && mProxyIsNear) {
+            if (DEBUG_PROXI_SENSOR) Log.i(TAG, "isWakeKeyWhenScreenOff blocked because of mProxyIsNear - keyCode = " + keyCode);
+            return false;
+        }
         switch (keyCode) {
             case KeyEvent.KEYCODE_DPAD_UP:
             case KeyEvent.KEYCODE_DPAD_DOWN:
@@ -5914,7 +6095,7 @@
             IDreamManager dreamManager = getDreamManager();
 
             try {
-                if (dreamManager != null && dreamManager.isDreaming()) {
+                if (dreamManager != null && dreamManager.isDreaming() && !dreamManager.isDozing()) {
                     return true;
                 }
             } catch (RemoteException e) {
@@ -6199,6 +6380,13 @@
         if (mDisplayFoldController != null) {
             mDisplayFoldController.finishedWakingUp();
         }
+
+        if (mProxiWakeupCheckEnabled && mProximitySensor != null) {
+            if (DEBUG_PROXI_SENSOR) Log.i(TAG, "unregisterListener");
+            mSensorManager.unregisterListener(mProximitySensorListener, mProximitySensor);
+            mProxyIsNear = false;
+            mProxiListenerEnabled = false;
+        }
     }
 
     private boolean shouldWakeUpWithHomeIntent() {
@@ -6276,6 +6464,14 @@
             }
             mDefaultDisplayRotation.updateOrientationListener();
             reportScreenStateToVrManager(false);
+
+            if (mProxiWakeupCheckEnabled && mProximitySensor != null && !mProxiListenerEnabled) {
+                mProxyIsNear = false;
+                if (DEBUG_PROXI_SENSOR) Log.i(TAG, "registerListener");
+                mSensorManager.registerListener(mProximitySensorListener, mProximitySensor,
+                        SensorManager.SENSOR_DELAY_NORMAL);
+                mProxiListenerEnabled = true;
+            }
         }
     }
 
@@ -7644,4 +7840,57 @@
         }
         return false;
     }
+
+    // omni additions start
+    private SensorEventListener mProximitySensorListener = new SensorEventListener() {
+        @Override
+        public void onSensorChanged(SensorEvent event) {
+            if (mDeviceKeyHandler != null && mDeviceKeyHandler.getCustomProxiSensor() != null) {
+                mProxyIsNear = mDeviceKeyHandler.getCustomProxiIsNear(event);
+            } else {
+                mProxyIsNear = event.values[0] < mProximitySensor.getMaximumRange();
+            }
+            if (DEBUG_PROXI_SENSOR) Log.i(TAG, "mProxyIsNear = " + mProxyIsNear);
+        }
+
+        @Override
+        public void onAccuracyChanged(Sensor sensor, int accuracy) {
+        }
+    };
+
+    private boolean isFlashLightIsOn() {
+        return Settings.Secure.getInt(mContext.getContentResolver(),
+                Settings.Secure.FLASHLIGHT_ENABLED, 0) != 0;
+    }
+
+     private boolean isDozeMode() {
+        IDreamManager dreamManager = getDreamManager();
+        try {
+            if (dreamManager != null && dreamManager.isDozing()) {
+                return true;
+            }
+        } catch (RemoteException e) {
+            return false;
+        }
+        return false;
+    }
+
+    private void performKeyAction(int behavior) {
+        if (DEBUG_INPUT){
+            Slog.d(TAG, "performKeyAction " + behavior);
+        }
+        switch (behavior) {
+            case KEY_ACTION_TOGGLE_TORCH: {
+                IStatusBarService service = getStatusBarService();
+                if (service != null) {
+                    try {
+                        service.toggleCameraFlash();
+                    } catch (RemoteException e) {
+                        // do nothing.
+                    }
+                }
+                break;
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index cc31bb1..290743d 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -256,6 +256,12 @@
         public void reboot(boolean confirm);
         public void rebootSafeMode(boolean confirm);
 
+        /** @hide */
+        void reboot(String reason, boolean confirm);
+
+        /** @hide */
+        void rebootCustom(String reason, boolean confirm);
+
         /**
          * Return the window manager lock needed to correctly call "Lw" methods.
          */
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 36bc0b9..79d5e1f 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -146,6 +146,8 @@
 
 import dalvik.annotation.optimization.NeverCompile;
 
+import org.omnirom.omnilib.utils.OmniSettings;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
@@ -727,6 +729,10 @@
         }
     }
 
+    // omni additions start
+    // doze on charge
+    private boolean mDozeOnChargeEnabled;
+
     private final class PowerGroupWakefulnessChangeListener implements
             PowerGroup.PowerGroupListener {
         @GuardedBy("mLock")
@@ -1348,6 +1354,10 @@
     }
 
     private void systemReady() {
+        // set initial value
+        Settings.System.putIntForUser(mContext.getContentResolver(),
+                OmniSettings.OMNI_DOZE_ON_CHARGE_NOW, 0, UserHandle.USER_CURRENT);
+
         synchronized (mLock) {
             mSystemReady = true;
             mDreamManager = getLocalService(DreamManagerInternal.class);
@@ -1476,6 +1486,12 @@
         resolver.registerContentObserver(Settings.Global.getUriFor(
                 Settings.Global.DEVICE_DEMO_MODE),
                 false, mSettingsObserver, UserHandle.USER_SYSTEM);
+        resolver.registerContentObserver(Settings.System.getUriFor(
+                OmniSettings.OMNI_DOZE_ON_CHARGE_NOW),
+                false, mSettingsObserver, UserHandle.USER_ALL);
+        resolver.registerContentObserver(Settings.System.getUriFor(
+                OmniSettings.OMNI_DOZE_ON_CHARGE),
+                false, mSettingsObserver, UserHandle.USER_ALL);
 
         // Register for broadcasts from other components of the system.
         IntentFilter filter = new IntentFilter();
@@ -1578,6 +1594,10 @@
         mTheaterModeEnabled = Settings.Global.getInt(mContext.getContentResolver(),
                 Settings.Global.THEATER_MODE_ON, 0) == 1;
         mAlwaysOnEnabled = mAmbientDisplayConfiguration.alwaysOnEnabled(UserHandle.USER_CURRENT);
+        mDozeOnChargeEnabled = Settings.System.getIntForUser(resolver,
+                OmniSettings.OMNI_DOZE_ON_CHARGE, 0, UserHandle.USER_CURRENT) != 0;
+        Settings.System.putIntForUser(resolver, OmniSettings.OMNI_DOZE_ON_CHARGE_NOW,
+                mDozeOnChargeEnabled && mIsPowered ? 1 : 0, UserHandle.USER_CURRENT);
 
         if (mSupportsDoubleTapWakeConfig) {
             boolean doubleTapWakeEnabled = Settings.Secure.getIntForUser(resolver,
@@ -2645,6 +2665,11 @@
                 final boolean dockedOnWirelessCharger = mWirelessChargerDetector.update(
                         mIsPowered, mPlugType);
 
+                if (mDozeOnChargeEnabled) {
+                    Settings.System.putIntForUser(mContext.getContentResolver(),
+                            OmniSettings.OMNI_DOZE_ON_CHARGE_NOW, mIsPowered ? 1 : 0,
+                            UserHandle.USER_CURRENT);
+                }
                 // Treat plugging and unplugging the devices as a user activity.
                 // Users find it disconcerting when they plug or unplug the device
                 // and it shuts off right away.
@@ -4028,7 +4053,7 @@
     }
 
     private void shutdownOrRebootInternal(final @HaltMode int haltMode, final boolean confirm,
-            @Nullable final String reason, boolean wait) {
+            @Nullable final String reason, boolean wait, final boolean custom) {
         if (PowerManager.REBOOT_USERSPACE.equals(reason)) {
             if (!PowerManager.isRebootingUserspaceSupportedImpl()) {
                 throw new UnsupportedOperationException(
@@ -4054,7 +4079,11 @@
                     if (haltMode == HALT_MODE_REBOOT_SAFE_MODE) {
                         ShutdownThread.rebootSafeMode(getUiContext(), confirm);
                     } else if (haltMode == HALT_MODE_REBOOT) {
-                        ShutdownThread.reboot(getUiContext(), reason, confirm);
+                        if (custom) {
+                            ShutdownThread.rebootCustom(getUiContext(), reason, confirm);
+                        } else {
+                            ShutdownThread.reboot(getUiContext(), reason, confirm);
+                        }
                     } else {
                         ShutdownThread.shutdown(getUiContext(), reason, confirm);
                     }
@@ -6695,7 +6724,7 @@
             ShutdownCheckPoints.recordCheckPoint(Binder.getCallingPid(), reason);
             final long ident = Binder.clearCallingIdentity();
             try {
-                shutdownOrRebootInternal(HALT_MODE_REBOOT, confirm, reason, wait);
+                shutdownOrRebootInternal(HALT_MODE_REBOOT, confirm, reason, wait, false);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -6715,7 +6744,29 @@
             ShutdownCheckPoints.recordCheckPoint(Binder.getCallingPid(), reason);
             final long ident = Binder.clearCallingIdentity();
             try {
-                shutdownOrRebootInternal(HALT_MODE_REBOOT_SAFE_MODE, confirm, reason, wait);
+                shutdownOrRebootInternal(HALT_MODE_REBOOT_SAFE_MODE, confirm, reason, wait, false);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        /**
+         * Reboots the device with custom progress message.
+         *
+         * @param confirm If true, shows a reboot confirmation dialog.
+         * @param reason The reason for the reboot, or null if none.
+         * @param wait If true, this call waits for the reboot to complete and does not return.
+         */
+        @Override // Binder call
+        public void rebootCustom(boolean confirm, String reason, boolean wait) {
+            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
+            if (PowerManager.REBOOT_RECOVERY.equals(reason)) {
+                mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
+            }
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                shutdownOrRebootInternal(HALT_MODE_REBOOT, confirm, reason, wait, true);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -6734,7 +6785,7 @@
             ShutdownCheckPoints.recordCheckPoint(Binder.getCallingPid(), reason);
             final long ident = Binder.clearCallingIdentity();
             try {
-                shutdownOrRebootInternal(HALT_MODE_SHUTDOWN, confirm, reason, wait);
+                shutdownOrRebootInternal(HALT_MODE_SHUTDOWN, confirm, reason, wait, false);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index d209ea9..aceac87 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -95,6 +95,7 @@
     private static boolean sIsStarted = false;
 
     private static boolean mReboot;
+    private static boolean mRebootCustom;
     private static boolean mRebootSafeMode;
     private static boolean mRebootHasProgressBar;
     private static String mReason;
@@ -161,6 +162,7 @@
      */
     public static void shutdown(final Context context, String reason, boolean confirm) {
         mReboot = false;
+        mRebootCustom = false;
         mRebootSafeMode = false;
         mReason = reason;
         shutdownInner(context, confirm);
@@ -260,6 +262,22 @@
         mRebootSafeMode = false;
         mRebootHasProgressBar = false;
         mReason = reason;
+        mRebootCustom = false;
+        shutdownInner(context, confirm);
+    }
+
+    /**
+     * Request reboot system, reboot recovery or reboot bootloader
+     *
+     * @param context Context used to display the shutdown progress dialog.
+     * @param reason code to pass to the kernel (e.g. "recovery", "bootloader"), or null.
+     * @param confirm true if user confirmation is needed before rebooting.
+     */
+    public static void rebootCustom(final Context context, String reason, boolean confirm) {
+        mReboot = true;
+        mRebootSafeMode = false;
+        mReason = reason;
+        mRebootCustom = true;
         shutdownInner(context, confirm);
     }
 
@@ -278,6 +296,7 @@
         }
 
         mReboot = true;
+        mRebootCustom = false;
         mRebootSafeMode = true;
         mRebootHasProgressBar = false;
         mReason = null;
@@ -339,20 +358,54 @@
                             com.android.internal.R.string.reboot_to_update_reboot));
             }
         } else if (mReason != null && mReason.equals(PowerManager.REBOOT_RECOVERY)) {
-            if (CrashRecoveryHelper.isRecoveryTriggeredReboot()) {
-                // We're not actually doing a factory reset yet; we're rebooting
-                // to ask the user if they'd like to reset, so give them a less
-                // scary dialog message.
-                pd.setTitle(context.getText(com.android.internal.R.string.power_off));
-                pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));
-                pd.setIndeterminate(true);
-            } else if (showSysuiReboot()) {
-                return null;
-            } else {
-                // Factory reset path. Set the dialog message accordingly.
-                pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_reset_title));
+            if (!mRebootCustom) {
+                if (CrashRecoveryHelper.isRecoveryTriggeredReboot()) {
+                    // We're not actually doing a factory reset yet; we're rebooting
+                    // to ask the user if they'd like to reset, so give them a less
+                    // scary dialog message.
+                    pd.setTitle(context.getText(com.android.internal.R.string.power_off));
+                    pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));
+                    pd.setIndeterminate(true);
+                } else if (showSysuiReboot()) {
+                    return null;
+                } else {
+                    // Factory reset path. Set the dialog message accordingly.
+                    pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_reset_title));
+                    pd.setMessage(context.getText(
+                        com.android.internal.R.string.reboot_to_reset_message));
+                    pd.setIndeterminate(true);
+                }
+            } else if (mReason != null && PowerManager.REBOOT_BOOTLOADER.equals(mReason) && mRebootCustom) {
+                if (showSysuiReboot()) {
+                    return null;
+                }
+                pd.setTitle(context.getText(org.omnirom.omnilib.R.string.reboot_to_bootloader_title));
                 pd.setMessage(context.getText(
-                            com.android.internal.R.string.reboot_to_reset_message));
+                        org.omnirom.omnilib.R.string.reboot_to_bootloader_message));
+                pd.setIndeterminate(true);
+            } else if (mReason != null && PowerManager.REBOOT_FASTBOOT.equals(mReason) && mRebootCustom) {
+                if (showSysuiReboot()) {
+                    return null;
+                }
+                pd.setTitle(context.getText(org.omnirom.omnilib.R.string.reboot_to_fastboot_title));
+                pd.setMessage(context.getText(
+                        org.omnirom.omnilib.R.string.reboot_to_fastboot_message));
+                pd.setIndeterminate(true);
+            } else if (mReason == null && mRebootCustom) {
+                if (showSysuiReboot()) {
+                    return null;
+                }
+                pd.setTitle(context.getText(org.omnirom.omnilib.R.string.reboot_system_title));
+                pd.setMessage(context.getText(
+                        org.omnirom.omnilib.R.string.reboot_system_message));
+                pd.setIndeterminate(true);
+            } else {
+                if (showSysuiReboot()) {
+                    return null;
+                }
+                pd.setTitle(context.getText(org.omnirom.omnilib.R.string.reboot_to_recovery_title));
+                pd.setMessage(context.getText(
+                            org.omnirom.omnilib.R.string.reboot_to_recovery_message));
                 pd.setIndeterminate(true);
             }
         } else {
@@ -377,7 +430,7 @@
         try {
             StatusBarManagerInternal service = LocalServices.getService(
                     StatusBarManagerInternal.class);
-            if (service.showShutdownUi(mReboot, mReason)) {
+            if (service.showShutdownUi(mReboot, mReason, mRebootCustom)) {
                 // Sysui will handle shutdown UI.
                 if (DEBUG) {
                     Log.d(TAG, "SysUI handling shutdown UI");
diff --git a/services/core/java/com/android/server/statusbar/SessionMonitor.java b/services/core/java/com/android/server/statusbar/SessionMonitor.java
index f4356bd..321ee67 100644
--- a/services/core/java/com/android/server/statusbar/SessionMonitor.java
+++ b/services/core/java/com/android/server/statusbar/SessionMonitor.java
@@ -44,6 +44,7 @@
     private final Context mContext;
     private final Map<Integer, Set<ISessionListener>> mSessionToListeners =
             new HashMap<>();
+    private final Map<Integer, Boolean> mSessionStatus = new HashMap<>();
 
     /** */
     public SessionMonitor(Context context) {
@@ -97,6 +98,8 @@
             return;
         }
 
+        mSessionStatus.put(sessionType, true);
+
         synchronized (mSessionToListeners) {
             for (ISessionListener listener : mSessionToListeners.get(sessionType)) {
                 try {
@@ -122,6 +125,8 @@
             return;
         }
 
+        mSessionStatus.put(sessionType, false);
+
         synchronized (mSessionToListeners) {
             for (ISessionListener listener : mSessionToListeners.get(sessionType)) {
                 try {
@@ -133,6 +138,13 @@
         }
     }
 
+    public boolean getSessionStatus(@SessionFlags int sessionType) {
+        if (mSessionStatus.containsKey(sessionType)) {
+            return mSessionStatus.get(sessionType);
+        }
+        return false;
+    }
+
     private boolean isValidSessionType(@SessionFlags int sessionType) {
         return ALL_SESSIONS.contains(sessionType);
     }
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index 83cb72e..ef2158f 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -139,7 +139,7 @@
      */
     void setTopAppHidesStatusBar(int displayId, boolean hidesStatusBar);
 
-    boolean showShutdownUi(boolean isReboot, String requestString);
+    boolean showShutdownUi(boolean isReboot, String requestString, boolean rebootCustom);
 
     /**
      * Notify system UI the immersive prompt should be dismissed as confirmed, and the confirmed
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index f8877ad..87e285c 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -697,14 +697,14 @@
         }
 
         @Override
-        public boolean showShutdownUi(boolean isReboot, String reason) {
+        public boolean showShutdownUi(boolean isReboot, String reason, boolean rebootCustom) {
             if (!mContext.getResources().getBoolean(R.bool.config_showSysuiShutdown)) {
                 return false;
             }
             IStatusBar bar = mBar;
             if (bar != null) {
                 try {
-                    bar.showShutdownUi(isReboot, reason);
+                    bar.showShutdownUi(isReboot, reason, rebootCustom);
                     return true;
                 } catch (RemoteException ex) {}
             }
@@ -1326,6 +1326,26 @@
         return mTracingEnabled;
     }
 
+    @Override
+    public void toggleCameraFlash() {
+        if (mBar != null) {
+            try {
+                mBar.toggleCameraFlash();
+            } catch (RemoteException ex) {
+            }
+        }
+    }
+
+    @Override
+    public void toggleCameraFlashState(boolean enable) {
+        if (mBar != null) {
+            try {
+                mBar.toggleCameraFlashState(enable);
+            } catch (RemoteException ex) {
+            }
+        }
+    }
+
     // TODO(b/117478341): make it aware of multi-display if needed.
     @Override
     public void disable(int what, IBinder token, String pkg) {
@@ -1855,13 +1875,10 @@
      * Allows the status bar to reboot the device.
      */
     @Override
-    public void reboot(boolean safeMode) {
+    public void reboot(boolean safeMode, String reason) {
         enforceStatusBarService();
         enforceValidCallingUser();
 
-        String reason = safeMode
-                ? PowerManager.REBOOT_SAFE_MODE
-                : PowerManager.SHUTDOWN_USER_REQUESTED;
         ShutdownCheckPoints.recordCheckPoint(Binder.getCallingPid(), reason);
         final long identity = Binder.clearCallingIdentity();
         try {
@@ -1871,7 +1888,7 @@
                 if (safeMode) {
                     ShutdownThread.rebootSafeMode(getUiContext(), true);
                 } else {
-                    ShutdownThread.reboot(getUiContext(), reason, false);
+                    ShutdownThread.rebootCustom(getUiContext(), reason, false);
                 }
             });
         } finally {
@@ -2482,6 +2499,11 @@
         mSessionMonitor.unregisterSessionListener(sessionFlags, listener);
     }
 
+    @Override
+    public boolean getSessionStatus(@SessionFlags int sessionType) {
+        return  mSessionMonitor.getSessionStatus(sessionType);
+    }
+
     public String[] getStatusBarIcons() {
         return mContext.getResources().getStringArray(R.array.config_statusBarIcons);
     }
diff --git a/services/core/java/com/android/server/webkit/SystemImpl.java b/services/core/java/com/android/server/webkit/SystemImpl.java
index 1798661..57f9f1f 100644
--- a/services/core/java/com/android/server/webkit/SystemImpl.java
+++ b/services/core/java/com/android/server/webkit/SystemImpl.java
@@ -47,6 +47,7 @@
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
@@ -142,7 +143,9 @@
      * */
     @Override
     public WebViewProviderInfo[] getWebViewPackages() {
-        return mWebViewProviderPackages;
+        return Arrays.stream(mWebViewProviderPackages)
+                .filter(x -> isProviderAvailable(x.packageName))
+                .toArray(WebViewProviderInfo[]::new);
     }
 
     public long getFactoryPackageVersion(String packageName) throws NameNotFoundException {
@@ -151,6 +154,15 @@
                 .getLongVersionCode();
     }
 
+    private boolean isProviderAvailable(String packageName) {
+        try {
+            getFactoryPackageVersion(packageName);
+            return true;
+        } catch (NameNotFoundException e) {
+            return false;
+        }
+    }
+
     /**
      * Reads all signatures at the current depth (within the current provider) from the XML parser.
      */
diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java
index 258a87e..99d8ca4 100644
--- a/services/core/java/com/android/server/wm/DragDropController.java
+++ b/services/core/java/com/android/server/wm/DragDropController.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.content.ClipDescription.EXTRA_HIDE_DRAG_SOURCE_TASK_ID;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.view.View.DRAG_FLAG_GLOBAL;
 import static android.view.View.DRAG_FLAG_GLOBAL_SAME_APPLICATION;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 866798d..ddbbfa9 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3781,6 +3781,18 @@
                 confirm);
     }
 
+    // Called by window manager policy.  Not exposed externally.
+    @Override
+    public void reboot(String reason, boolean confirm) {
+        ShutdownThread.reboot(ActivityThread.currentActivityThread().getSystemUiContext(), reason, confirm);
+    }
+
+    // Called by window manager policy.  Not exposed externally.
+    @Override
+    public void rebootCustom(String reason, boolean confirm) {
+        ShutdownThread.rebootCustom(ActivityThread.currentActivityThread().getSystemUiContext(), reason, confirm);
+    }
+
     public void setCurrentUser(@UserIdInt int newUserId) {
         synchronized (mGlobalLock) {
             final TransitionController controller = mAtmService.getTransitionController();
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 92dbf63..785ea98 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -310,6 +310,9 @@
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.text.SimpleDateFormat;
 import java.util.Arrays;
 import java.util.Date;
@@ -2932,6 +2935,26 @@
         mSystemServiceManager.startService(TracingServiceProxy.class);
         t.traceEnd();
 
+        // OmniRom Services
+        String externalServer = context.getResources().getString(
+                org.omnirom.omnilib.R.string.config_externalSystemServer);
+        final Class<?> serverClazz;
+        try {
+            serverClazz = Class.forName(externalServer);
+            final Constructor<?> constructor = serverClazz.getDeclaredConstructor(Context.class);
+            constructor.setAccessible(true);
+            final Object baseObject = constructor.newInstance(mSystemContext);
+            final Method method = baseObject.getClass().getDeclaredMethod("run");
+            method.setAccessible(true);
+            method.invoke(baseObject);
+        } catch (ClassNotFoundException
+                | IllegalAccessException
+                | InvocationTargetException
+                | InstantiationException
+                | NoSuchMethodException e) {
+            reportWtf("Making " + externalServer + " ready", e);
+        }
+
         // UprobeStats DynamicInstrumentationManager
         if (android.uprobestats.flags.Flags.executableMethodFileOffsets()) {
             t.traceBegin("StartDynamicInstrumentationManager");
diff --git a/services/proguard.flags b/services/proguard.flags
index 0e1f68e..30c4525 100644
--- a/services/proguard.flags
+++ b/services/proguard.flags
@@ -128,3 +128,8 @@
 # CoverageService guards optional jacoco class references with a runtime guard, so we can safely
 # suppress build-time warnings.
 -dontwarn org.jacoco.agent.rt.*
+
+# SDK
+-keep,allowoptimization,allowaccessmodification class omnirom.** { *; }
+-keep,allowoptimization,allowaccessmodification class org.omnirom.** { *; }
+-keep,allowoptimization,allowaccessmodification class vendor.lineage.** { *; }
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 9fb7319..713f8a1 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -2894,8 +2894,9 @@
     for (size_t i = 0; i < basePackageCount; i++) {
         size_t packageId = table.getBasePackageId(i);
         String16 packageName(table.getBasePackageName(i));
-        if (packageId > 0x01 && packageId != 0x7f &&
-                packageName != String16("android")) {
+        if (packageId > 0x01 && packageId != 0x7f && packageId != 0x3f &&
+                packageName != String16("android") &&
+                packageName != String16("omnirom.platform")) {
             libraryPackages.add(sp<Package>(new Package(packageName, packageId)));
         }
     }
diff --git a/tools/aapt2/Configuration.proto b/tools/aapt2/Configuration.proto
index 4883844..a8111a2 100644
--- a/tools/aapt2/Configuration.proto
+++ b/tools/aapt2/Configuration.proto
@@ -213,4 +213,6 @@
   //
 
   string product = 25;
+
+  string stringified = 100;
 }
diff --git a/tools/aapt2/cmd/Convert.h b/tools/aapt2/cmd/Convert.h
index 9452e58..b78029f 100644
--- a/tools/aapt2/cmd/Convert.h
+++ b/tools/aapt2/cmd/Convert.h
@@ -74,6 +74,8 @@
         "Has no effect on APKs where resource names are kept.",
         &table_flattener_options_.deduplicate_entry_values);
     AddOptionalSwitch("-v", "Enables verbose logging", &verbose_);
+    AddOptionalSwitch("--for-adevtool", "This flag exists to prevent using adevtool with "
+            "upstream aapt2 which lacks the Configuration.proto customization.", &for_adevtool_);
   }
 
   int Action(const std::vector<std::string>& args) override;
@@ -91,6 +93,7 @@
   bool force_sparse_encoding_ = false;
   bool enable_compact_entries_ = false;
   std::optional<std::string> resources_config_path_;
+  bool for_adevtool_ = false;
 };
 
 int Convert(IAaptContext* context, LoadedApk* input, IArchiveWriter* output_writer,
diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp
index fcc77d5..12c59c1 100644
--- a/tools/aapt2/format/proto/ProtoSerialize.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize.cpp
@@ -63,6 +63,7 @@
 }
 
 void SerializeConfig(const ConfigDescription& config, pb::Configuration* out_pb_config) {
+  out_pb_config->set_stringified(config.to_string());
   out_pb_config->set_mcc(config.mcc);
   out_pb_config->set_mnc(config.mnc);
   out_pb_config->set_locale(config.GetBcp47LanguageTag());