From 73f12ad5eb71b89b2e631e3af30a76c6245527c3 Mon Sep 17 00:00:00 2001 From: Alberto Ponces Date: Mon, 14 Oct 2024 13:58:46 +0100 Subject: [PATCH] feat: bump to android-15.0 --- .github/workflows/build.yml | 2 +- README.md | 2 +- build.sh | 21 +- build/aosp.mk | 2 +- build/default.xml | 10 +- build/remove.xml | 33 +- .../0001-Import-vendor-gapps.patch | 15 +- .../0002-Rework-securize-tweak.patch | 2 +- ...OKEN_MISSING_REQUIRED_MODULES-to-tru.patch | 21 - .../0001-Remove-su-from-vanilla-builds.patch | 6 +- ...clude-AOSP-apn-list-on-custom-builds.patch | 8 +- ...-attestation-and-instrumentation-to-.patch | 22 +- ...pat-Spoof-Pixel-XL-for-Google-Photos.patch | 6 +- ...03-monet-Use-Style.SPRITZ-by-default.patch | 12 +- ...d.version.incremental-to-signal-OTA-.patch | 173 +- ...Add-left-padding-for-keyguard-slices.patch | 45 + .../0005-SystemUI-fix-SliceView-layout.patch | 29 - ...mission.READ_PHONE_STATE-to-manifest.patch | 6 +- ...Pre-grant-google-restore-permissions.patch | 10 +- ...Lockscreen-Weather-with-OmniJaws-1-2.patch | 613 ++-- ...d-Face-Unlock-with-ParanoidSense-1-2.patch | 2943 ----------------- ...tly-monet-theme-the-new-volume-panel.patch | 85 - ...Lockscreen-Weather-with-OmniJaws-2-2.patch | 726 +--- ...d-Face-Unlock-with-ParanoidSense-2-2.patch | 30 - ...uired-libraries-between-the-build-sy.patch | 30 + ...sing-background-location-permission-.patch | 47 + ...pdate-default-provider-to-MET-Norway.patch | 51 + sync.sh | 4 +- 28 files changed, 661 insertions(+), 4293 deletions(-) delete mode 100644 patches/personal/device_phh_treble/0003-a64-Set-BUILD_BROKEN_MISSING_REQUIRED_MODULES-to-tru.patch create mode 100644 patches/personal/platform_frameworks_base/0005-SystemUI-Add-left-padding-for-keyguard-slices.patch delete mode 100644 patches/personal/platform_frameworks_base/0005-SystemUI-fix-SliceView-layout.patch delete mode 100644 patches/personal/platform_frameworks_base/0009-feat-Add-Face-Unlock-with-ParanoidSense-1-2.patch delete mode 100644 patches/personal/platform_frameworks_base/0010-SystemUI-Correctly-monet-theme-the-new-volume-panel.patch delete mode 100644 patches/personal/platform_packages_apps_Settings/0002-feat-Add-Face-Unlock-with-ParanoidSense-2-2.patch create mode 100644 patches/personal/platform_packages_services_OmniJaws/0001-OmniJaws-Fix-required-libraries-between-the-build-sy.patch create mode 100644 patches/personal/platform_packages_services_OmniJaws/0002-OmniJaws-Add-missing-background-location-permission-.patch create mode 100644 patches/personal/platform_packages_services_OmniJaws/0003-OmniJaws-update-default-provider-to-MET-Norway.patch diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2dd99cb9..c7833f06 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,7 +10,7 @@ on: type: string push: branches: - - android-14.0 + - android-15.0 paths-ignore: - '.github/**' - 'config/**' diff --git a/README.md b/README.md index 7921c4bd..3f2be1b8 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ To get started with building AOSP GSI, you'll need to get familiar with [Git and ``` - Clone this repo: ``` - git clone https://github.com/ponces/treble_aosp -b android-14.0 + git clone https://github.com/ponces/treble_aosp -b android-15.0 ``` - Finally, start the build script: ``` diff --git a/build.sh b/build.sh index 1609d257..6b1c6b2a 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ echo echo "--------------------------------------" -echo " AOSP 14.0 Buildbot " +echo " AOSP 15.0 Buildbot " echo " by " echo " ponces " echo "--------------------------------------" @@ -16,7 +16,7 @@ BV=$1 initRepos() { echo "--> Initializing workspace" - repo init -u https://android.googlesource.com/platform/manifest -b android-14.0.0_r55 --git-lfs + repo init -u https://android.googlesource.com/platform/manifest -b android-15.0.0_r1 --git-lfs echo echo "--> Preparing local manifest" @@ -67,7 +67,7 @@ buildTrebleApp() { buildVariant() { echo "--> Building $1" - lunch "$1"-ap2a-userdebug + lunch "$1"-ap3a-userdebug make -j$(nproc --all) installclean make -j$(nproc --all) systemimage make -j$(nproc --all) target-files-package otatools @@ -79,9 +79,8 @@ buildVariant() { buildVndkliteVariant() { echo "--> Building $1-vndklite" - [[ "$1" == *"a64"* ]] && arch="32" || arch="64" cd treble_adapter - sudo bash lite-adapter.sh "$arch" $BD/system-"$1".img + sudo bash lite-adapter.sh "64" $BD/system-"$1".img mv s.img $BD/system-"$1"-vndklite.img sudo rm -rf d tmp cd .. @@ -89,12 +88,8 @@ buildVndkliteVariant() { } buildVariants() { - buildVariant treble_a64_bvN - buildVariant treble_a64_bgN buildVariant treble_arm64_bvN buildVariant treble_arm64_bgN - buildVndkliteVariant treble_a64_bvN - buildVndkliteVariant treble_a64_bgN buildVndkliteVariant treble_arm64_bvN buildVndkliteVariant treble_arm64_bgN } @@ -104,10 +99,9 @@ generatePackages() { buildDate="$(date +%Y%m%d)" find $BD/ -name "system-treble_*.img" | while read file; do filename="$(basename $file)" - [[ "$filename" == *"_a64"* ]] && arch="arm32_binder64" || arch="arm64" [[ "$filename" == *"_bvN"* ]] && variant="vanilla" || variant="gapps" [[ "$filename" == *"-vndklite"* ]] && vndk="-vndklite" || vndk="" - name="aosp-${arch}-ab-${variant}${vndk}-14.0-$buildDate" + name="aosp-arm64-ab-${variant}${vndk}-15.0-$buildDate" xz -cv "$file" -T0 > $BD/"$name".img.xz done rm -rf $BD/system-*.img @@ -120,13 +114,12 @@ generateOta() { buildDate="$(date +%Y%m%d)" timestamp="$START" json="{\"version\": \"$version\",\"date\": \"$timestamp\",\"variants\": [" - find $BD/ -name "aosp-*-14.0-$buildDate.img.xz" | sort | { + find $BD/ -name "aosp-*-15.0-$buildDate.img.xz" | sort | { while read file; do filename="$(basename $file)" - [[ "$filename" == *"-arm32"* ]] && arch="a64" || arch="arm64" [[ "$filename" == *"-vanilla"* ]] && variant="v" || variant="g" [[ "$filename" == *"-vndklite"* ]] && vndk="-vndklite" || vndk="" - name="treble_${arch}_b${variant}N${vndk}" + name="treble_arm64_b${variant}N${vndk}" size=$(wc -c $file | awk '{print $1}') url="https://github.com/ponces/treble_aosp/releases/download/$version/$filename" json="${json} {\"name\": \"$name\",\"size\": \"$size\",\"url\": \"$url\"}," diff --git a/build/aosp.mk b/build/aosp.mk index 6493ba44..1b071e46 100644 --- a/build/aosp.mk +++ b/build/aosp.mk @@ -1,4 +1,4 @@ $(call inherit-product, vendor/ponces/config/common.mk) PRODUCT_SYSTEM_DEFAULT_PROPERTIES += \ - ro.system.ota.json_url=https://raw.githubusercontent.com/ponces/treble_aosp/android-14.0/config/ota.json + ro.system.ota.json_url=https://raw.githubusercontent.com/ponces/treble_aosp/android-15.0/config/ota.json diff --git a/build/default.xml b/build/default.xml index 1b6ec68d..0e0cffbe 100644 --- a/build/default.xml +++ b/build/default.xml @@ -4,20 +4,20 @@ - + - + - - + + - + diff --git a/build/remove.xml b/build/remove.xml index b2d25de9..b4e6701d 100644 --- a/build/remove.xml +++ b/build/remove.xml @@ -1,22 +1,27 @@ - - + + - + - - - + + + + + + + + - + @@ -24,31 +29,33 @@ - + - + - + - - + - + + + + diff --git a/patches/personal/device_phh_treble/0001-Import-vendor-gapps.patch b/patches/personal/device_phh_treble/0001-Import-vendor-gapps.patch index 6b0bf461..87482c5d 100644 --- a/patches/personal/device_phh_treble/0001-Import-vendor-gapps.patch +++ b/patches/personal/device_phh_treble/0001-Import-vendor-gapps.patch @@ -1,23 +1,22 @@ -From 2bf85c385f0e9c41ab6c33cfab114457275db967 Mon Sep 17 00:00:00 2001 +From 990e22c107d7144f41c83b39a6e48f2f89248e10 Mon Sep 17 00:00:00 2001 From: Alberto Ponces Date: Tue, 21 Feb 2023 22:51:12 +0000 -Subject: [PATCH 1/3] Import vendor/gapps +Subject: [PATCH 1/2] Import vendor/gapps --- - generate.sh | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) + generate.sh | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generate.sh b/generate.sh -index 461eff1..4c7690a 100644 +index 9c20eb5..8fbb16b 100644 --- a/generate.sh +++ b/generate.sh -@@ -26,7 +26,8 @@ for part in a ab;do +@@ -26,7 +26,7 @@ for part in a ab;do optional_base="" if [ "$apps" == "gapps" ];then apps_suffix="g" - apps_script='$(call inherit-product, device/phh/treble/gapps.mk)' -+ [[ "$arch" == "a64" ]] && base="arm" || base="arm64" -+ apps_script="\$(call inherit-product, vendor/gapps/$base/$base-vendor.mk)" ++ apps_script='$(call inherit-product, vendor/gapps/common/common-vendor.mk)' apps_name="with GApps" fi if [ "$apps" == "gapps-go" ];then diff --git a/patches/personal/device_phh_treble/0002-Rework-securize-tweak.patch b/patches/personal/device_phh_treble/0002-Rework-securize-tweak.patch index 49966eb4..8ac9348f 100644 --- a/patches/personal/device_phh_treble/0002-Rework-securize-tweak.patch +++ b/patches/personal/device_phh_treble/0002-Rework-securize-tweak.patch @@ -1,7 +1,7 @@ From 1423a40a59b5d849e6161a3e7cdf0de003dcbad9 Mon Sep 17 00:00:00 2001 From: Alberto Ponces Date: Wed, 25 Dec 2019 12:34:05 +0200 -Subject: [PATCH 2/3] Rework securize tweak +Subject: [PATCH 2/2] Rework securize tweak --- base.mk | 1 - diff --git a/patches/personal/device_phh_treble/0003-a64-Set-BUILD_BROKEN_MISSING_REQUIRED_MODULES-to-tru.patch b/patches/personal/device_phh_treble/0003-a64-Set-BUILD_BROKEN_MISSING_REQUIRED_MODULES-to-tru.patch deleted file mode 100644 index 941410ba..00000000 --- a/patches/personal/device_phh_treble/0003-a64-Set-BUILD_BROKEN_MISSING_REQUIRED_MODULES-to-tru.patch +++ /dev/null @@ -1,21 +0,0 @@ -From f122a0b9671501c0b45c4251d7217f607e8f8509 Mon Sep 17 00:00:00 2001 -From: Alberto Ponces -Date: Fri, 12 Apr 2024 23:59:25 +0000 -Subject: [PATCH 3/3] a64: Set BUILD_BROKEN_MISSING_REQUIRED_MODULES to true - ---- - tdgsi_a64_ab/BoardConfig.mk | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/tdgsi_a64_ab/BoardConfig.mk b/tdgsi_a64_ab/BoardConfig.mk -index f131e88..72c4c73 100644 ---- a/tdgsi_a64_ab/BoardConfig.mk -+++ b/tdgsi_a64_ab/BoardConfig.mk -@@ -8,3 +8,4 @@ ifeq ($(BOARD_SYSTEMIMAGE_PARTITION_RESERVED_SIZE),) - BOARD_SYSTEMIMAGE_PARTITION_SIZE := 1572864000 - endif - TARGET_USES_64_BIT_BINDER := true -+BUILD_BROKEN_MISSING_REQUIRED_MODULES := true --- -2.34.1 - diff --git a/patches/personal/platform_build/0001-Remove-su-from-vanilla-builds.patch b/patches/personal/platform_build/0001-Remove-su-from-vanilla-builds.patch index 481ab55e..365bb2df 100644 --- a/patches/personal/platform_build/0001-Remove-su-from-vanilla-builds.patch +++ b/patches/personal/platform_build/0001-Remove-su-from-vanilla-builds.patch @@ -1,4 +1,4 @@ -From c046f10027f788fc6645a7d377f0c9e90ce399e6 Mon Sep 17 00:00:00 2001 +From c690eeb44a8d7fda7522b8681decb07ac861313f Mon Sep 17 00:00:00 2001 From: Victor Bo Date: Sat, 14 Dec 2019 23:46:34 +0200 Subject: [PATCH 1/2] Remove su from vanilla builds @@ -8,10 +8,10 @@ Subject: [PATCH 1/2] Remove su from vanilla builds 1 file changed, 1 deletion(-) diff --git a/target/product/base_system.mk b/target/product/base_system.mk -index c6ca3dda2c..58d9629a92 100644 +index 4f21c3ed63..c54b6f7ba4 100644 --- a/target/product/base_system.mk +++ b/target/product/base_system.mk -@@ -436,7 +436,6 @@ PRODUCT_PACKAGES_DEBUG := \ +@@ -471,7 +471,6 @@ PRODUCT_PACKAGES_DEBUG := \ ss \ start_with_lockagent \ strace \ diff --git a/patches/personal/platform_build/0002-product-Exclude-AOSP-apn-list-on-custom-builds.patch b/patches/personal/platform_build/0002-product-Exclude-AOSP-apn-list-on-custom-builds.patch index 7736a2f0..4d899d3c 100644 --- a/patches/personal/platform_build/0002-product-Exclude-AOSP-apn-list-on-custom-builds.patch +++ b/patches/personal/platform_build/0002-product-Exclude-AOSP-apn-list-on-custom-builds.patch @@ -1,4 +1,4 @@ -From 32bd5279405b2013c1152338ab79dca6585983b7 Mon Sep 17 00:00:00 2001 +From e38da8c1aa80ac5ec327cb6fa3aba867caa11871 Mon Sep 17 00:00:00 2001 From: Alberto Ponces Date: Tue, 26 Dec 2023 17:01:46 +0000 Subject: [PATCH 2/2] product: Exclude AOSP apn list on custom builds @@ -10,13 +10,13 @@ Change-Id: I76c8d5ef67de73d4558d350a87a9bc317aaad792 2 files changed, 6 deletions(-) diff --git a/target/product/aosp_product.mk b/target/product/aosp_product.mk -index f72f2dfec4..05bcaefcea 100644 +index 3a5b622f99..26070b7f2b 100644 --- a/target/product/aosp_product.mk +++ b/target/product/aosp_product.mk -@@ -35,8 +35,3 @@ PRODUCT_PACKAGES += \ +@@ -34,8 +34,3 @@ PRODUCT_PACKAGES += \ + PhotoTable \ preinstalled-packages-platform-aosp-product.xml \ ThemePicker \ - WallpaperPicker \ - -# Telephony: -# Provide a APN configuration to GSI product diff --git a/patches/personal/platform_frameworks_base/0001-gmscompat-Change-attestation-and-instrumentation-to-.patch b/patches/personal/platform_frameworks_base/0001-gmscompat-Change-attestation-and-instrumentation-to-.patch index e6a4af40..acaf159c 100644 --- a/patches/personal/platform_frameworks_base/0001-gmscompat-Change-attestation-and-instrumentation-to-.patch +++ b/patches/personal/platform_frameworks_base/0001-gmscompat-Change-attestation-and-instrumentation-to-.patch @@ -1,8 +1,8 @@ -From 2804e0c5f6443f0ab18056c86ed4e50faa60af92 Mon Sep 17 00:00:00 2001 +From 6bb6ae865746aa6cf8258396daa95edbca434f8e Mon Sep 17 00:00:00 2001 From: Alberto Ponces Date: Thu, 9 Nov 2023 12:33:55 +0100 -Subject: [PATCH 01/10] gmscompat: Change attestation and instrumentation to - pass SafetyNet and Play Integrity API. +Subject: [PATCH 1/8] gmscompat: Change attestation and instrumentation to pass + SafetyNet and Play Integrity API. Original work by @kdrag0n. Updated by many people like @dereference23, @Stallix, @dyneteve, @neobuddy89 and @jhenrique09. @@ -16,7 +16,7 @@ Adapted by @ponces based on the work of @chiteroman to pass newest Play Integrit create mode 100644 core/java/com/android/internal/gmscompat/AttestationHooks.java diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java -index db216b1a..9445bc1b 100644 +index db216b1af..9445bc1b5 100644 --- a/core/java/android/app/Instrumentation.java +++ b/core/java/android/app/Instrumentation.java @@ -63,6 +63,8 @@ import android.view.WindowManagerGlobal; @@ -46,7 +46,7 @@ index db216b1a..9445bc1b 100644 diff --git a/core/java/com/android/internal/gmscompat/AttestationHooks.java b/core/java/com/android/internal/gmscompat/AttestationHooks.java new file mode 100644 -index 00000000..cff1250c +index 000000000..eb59bed82 --- /dev/null +++ b/core/java/com/android/internal/gmscompat/AttestationHooks.java @@ -0,0 +1,100 @@ @@ -116,13 +116,13 @@ index 00000000..cff1250c + } + + private static void spoofBuildGms() { -+ setBuildField("PRODUCT", "akita_beta"); -+ setBuildField("DEVICE", "akita"); ++ setBuildField("PRODUCT", "oriole_beta"); ++ setBuildField("DEVICE", "oriole"); + setBuildField("MANUFACTURER", "Google"); + setBuildField("BRAND", "google"); -+ setBuildField("MODEL", "Pixel 8a"); -+ setBuildField("FINGERPRINT", "google/akita_beta/akita:15/AP31.240617.015/12207491:user/release-keys"); -+ setVersionField("SECURITY_PATCH", "2024-08-05"); ++ setBuildField("MODEL", "Pixel 6"); ++ setBuildField("FINGERPRINT", "google/oriole_beta/oriole:15/AP41.240823.009/12329489:user/release-keys"); ++ setVersionField("SECURITY_PATCH", "2024-09-05"); + setVersionField("DEVICE_INITIAL_SDK_INT", Build.VERSION_CODES.LOLLIPOP); + } + @@ -151,7 +151,7 @@ index 00000000..cff1250c + } +} diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java -index e6a63b9c..6a80c14c 100644 +index e6a63b9c4..6a80c14c9 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java @@ -48,6 +48,7 @@ import android.system.keystore2.ResponseCode; diff --git a/patches/personal/platform_frameworks_base/0002-gmscompat-Spoof-Pixel-XL-for-Google-Photos.patch b/patches/personal/platform_frameworks_base/0002-gmscompat-Spoof-Pixel-XL-for-Google-Photos.patch index 4500e67c..ef13de12 100644 --- a/patches/personal/platform_frameworks_base/0002-gmscompat-Spoof-Pixel-XL-for-Google-Photos.patch +++ b/patches/personal/platform_frameworks_base/0002-gmscompat-Spoof-Pixel-XL-for-Google-Photos.patch @@ -1,7 +1,7 @@ -From 482bc6f508e57d21199ee466af827b8e675606a4 Mon Sep 17 00:00:00 2001 +From 3ca70b42c7f24ce1138f2c3a78ef00bf720cb22a Mon Sep 17 00:00:00 2001 From: vladsendrix <83285656+vladsendrix@users.noreply.github.com> Date: Fri, 31 Dec 2021 03:18:04 +0100 -Subject: [PATCH 02/10] gmscompat: Spoof Pixel XL for Google Photos +Subject: [PATCH 2/8] gmscompat: Spoof Pixel XL for Google Photos Change-Id: I905e40625b07ebf500cbb3ce1deadedee2e624c5 --- @@ -9,7 +9,7 @@ Change-Id: I905e40625b07ebf500cbb3ce1deadedee2e624c5 1 file changed, 14 insertions(+) diff --git a/core/java/com/android/internal/gmscompat/AttestationHooks.java b/core/java/com/android/internal/gmscompat/AttestationHooks.java -index cff1250c..dfbf69a0 100644 +index eb59bed82..563bad8a8 100644 --- a/core/java/com/android/internal/gmscompat/AttestationHooks.java +++ b/core/java/com/android/internal/gmscompat/AttestationHooks.java @@ -32,6 +32,7 @@ public final class AttestationHooks { diff --git a/patches/personal/platform_frameworks_base/0003-monet-Use-Style.SPRITZ-by-default.patch b/patches/personal/platform_frameworks_base/0003-monet-Use-Style.SPRITZ-by-default.patch index 23deb370..2048417e 100644 --- a/patches/personal/platform_frameworks_base/0003-monet-Use-Style.SPRITZ-by-default.patch +++ b/patches/personal/platform_frameworks_base/0003-monet-Use-Style.SPRITZ-by-default.patch @@ -1,7 +1,7 @@ -From 927bb5d5daa4ae48011f9701abb2bbd3b05007a9 Mon Sep 17 00:00:00 2001 +From cdb439e3ef319cd3ec2817a69b5da7f7e9255b9d Mon Sep 17 00:00:00 2001 From: Alberto Ponces Date: Sun, 26 Feb 2023 22:13:35 +0000 -Subject: [PATCH 03/10] monet: Use Style.SPRITZ by default +Subject: [PATCH 3/8] monet: Use Style.SPRITZ by default Change-Id: Ia44ba56c8daa07033b290de89bb300bda9d39d86 --- @@ -9,11 +9,11 @@ Change-Id: Ia44ba56c8daa07033b290de89bb300bda9d39d86 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java -index 44c684c3..4869ec42 100644 +index 4963aae08..9c67b44fc 100644 --- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java +++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java -@@ -153,7 +153,7 @@ public class ThemeOverlayController implements CoreStartable, Dumpable { - private float mContrast = 0; +@@ -146,7 +146,7 @@ public class ThemeOverlayController implements CoreStartable, Dumpable { + private double mContrast = 0.0; // Theme variant: Vibrant, Tonal, Expressive, etc @VisibleForTesting - protected Style mThemeStyle = Style.TONAL_SPOT; @@ -21,7 +21,7 @@ index 44c684c3..4869ec42 100644 // Accent colors overlay private FabricatedOverlay mSecondaryOverlay; // Neutral system colors overlay -@@ -862,11 +862,11 @@ public class ThemeOverlayController implements CoreStartable, Dumpable { +@@ -831,11 +831,11 @@ public class ThemeOverlayController implements CoreStartable, Dumpable { style = Style.valueOf( object.getString(ThemeOverlayApplier.OVERLAY_CATEGORY_THEME_STYLE)); if (!validStyles.contains(style)) { diff --git a/patches/personal/platform_frameworks_base/0004-fw-b-Use-ro.build.version.incremental-to-signal-OTA-.patch b/patches/personal/platform_frameworks_base/0004-fw-b-Use-ro.build.version.incremental-to-signal-OTA-.patch index 6be2478b..ed14ffce 100644 --- a/patches/personal/platform_frameworks_base/0004-fw-b-Use-ro.build.version.incremental-to-signal-OTA-.patch +++ b/patches/personal/platform_frameworks_base/0004-fw-b-Use-ro.build.version.incremental-to-signal-OTA-.patch @@ -1,75 +1,28 @@ -From a293f31f6f239099222ff3e93e9d80da44a0c4ca Mon Sep 17 00:00:00 2001 +From 22a165579df84085b3e18608264c616159b21bfe Mon Sep 17 00:00:00 2001 From: dhacker29 Date: Tue, 24 Nov 2015 01:53:47 -0500 -Subject: [PATCH 04/10] fw/b: Use ro.build.version.incremental to signal OTA +Subject: [PATCH 4/8] fw/b: Use ro.build.version.incremental to signal OTA upgrades -[PeterCxy]: On T, there is a new class PackagePartitions that is -responsible for detecting updates to not just the system, but also other -partitions. Most of the fingerprint detection were moved there, and thus -modifications were made there to use the -ro..build.version.incremental property. - -Squash of: - -Author: dhacker29 -Date: Tue Nov 24 01:53:47 2015 -0500 - Core: Use ro.build.date to signal mIsUpgrade - - M: We use a static fingerprint that is only changed when a new OEM build is released, so - every flash shows Android is starting instead of upgrading. This will fix that. - N: even though we dont have the dexopt sceen on N, this is still needed to delete the - correct caches, and grant/deny specific runtime permissions like a true oem update - would do. - Updated for Nougat By: BeansTown106 - - Change-Id: I0e3ed5c8f0351e48944432ae6a0c5194ddeff1fa - -Author: Sam Mortimer -Date: Fri Sep 28 13:45:00 2018 -0700 - fw/b UserManagerService: Use ro.build.date to signal upgrades - - *) We changed PackageManagerService to use Build.DATE instead of - Build.FINGERPRINT to detect upgrade. Do the same for - UserManagerService. - *) Affects generation of preboot intent and app data migration. - - Change-Id: I56887b7ca842afdcf3cf84b27b4c04667cf43307 - -Author: Wang Han <416810799@qq.com> -Date: Sat Dec 29 23:33:20 2018 +0800 - ShortcutService: Use ro.build.date to signal package scanning - - * Affects system apps scanning. - - Change-Id: I5f6d6647929f5b5ae7e820b18e95bf5ed2ec8d1c - -Author: maxwen -Date: Tue Nov 19 01:02:01 2019 +0100 - base: Use ro.build.date to clear cache dirs on update - - instead of using ro.build.fingerprint we explictly need to use ro.build.date - - Change-Id: Ib3e80e58eb8c9a21c108e9f5cd2dbdb7ada8e3a4 - -Author: maxwen -Date: Wed Oct 28 07:07:10 2020 -0400 - One more Build.FINGERPRINT to Build.DATE change - - Change-Id: I13dbf3d7f6587d3fcd6591cc0f861b34b6d5561c - +Co-authored-by: maxwen +Co-authored-by: Sam Mortimer +Co-authored-by: Wang Han <416810799@qq.com> Change-Id: If0eb969ba509981f9209ffa37a949d9042ef4c2a --- - core/java/android/app/admin/SystemUpdateInfo.java | 4 ++-- - core/java/android/content/pm/PackagePartitions.java | 4 ++-- - services/core/java/com/android/server/pm/ShortcutService.java | 2 +- - 3 files changed, 5 insertions(+), 5 deletions(-) + core/java/android/app/admin/SystemUpdateInfo.java | 4 ++-- + core/java/android/content/pm/PackagePartitions.java | 2 +- + .../java/com/android/server/appwidget/AppWidgetXmlUtil.java | 4 ++-- + .../java/com/android/server/pm/PackageManagerService.java | 5 +++-- + .../com/android/server/pm/PackageManagerServiceUtils.java | 3 +-- + services/core/java/com/android/server/pm/Settings.java | 2 +- + .../core/java/com/android/server/pm/ShortcutService.java | 2 +- + 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/core/java/android/app/admin/SystemUpdateInfo.java b/core/java/android/app/admin/SystemUpdateInfo.java -index 9e6c91f4..7459b0e0 100644 +index 9e6c91f4ec313..7459b0e05e3af 100644 --- a/core/java/android/app/admin/SystemUpdateInfo.java +++ b/core/java/android/app/admin/SystemUpdateInfo.java -@@ -133,7 +133,7 @@ public final class SystemUpdateInfo implements Parcelable { +@@ -133,7 +133,7 @@ public void writeToXml(TypedXmlSerializer out, String tag) throws IOException { out.startTag(null, tag); out.attributeLong(null, ATTR_RECEIVED_TIME, mReceivedTime); out.attributeInt(null, ATTR_SECURITY_PATCH_STATE, mSecurityPatchState); @@ -78,7 +31,7 @@ index 9e6c91f4..7459b0e0 100644 out.endTag(null, tag); } -@@ -142,7 +142,7 @@ public final class SystemUpdateInfo implements Parcelable { +@@ -142,7 +142,7 @@ public void writeToXml(TypedXmlSerializer out, String tag) throws IOException { 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 ); @@ -88,26 +41,102 @@ index 9e6c91f4..7459b0e0 100644 } try { diff --git a/core/java/android/content/pm/PackagePartitions.java b/core/java/android/content/pm/PackagePartitions.java -index ff80e614..8bf0d5ff 100644 +index ff80e614be58b..da3b68ecf789f 100644 --- a/core/java/android/content/pm/PackagePartitions.java +++ b/core/java/android/content/pm/PackagePartitions.java -@@ -129,9 +129,9 @@ public class PackagePartitions { - final String[] digestProperties = new String[SYSTEM_PARTITIONS.size() + 1]; - for (int i = 0; i < SYSTEM_PARTITIONS.size(); i++) { +@@ -131,7 +131,7 @@ private static String getFingerprint() { final String partitionName = SYSTEM_PARTITIONS.get(i).getName(); -- digestProperties[i] = "ro." + partitionName + ".build.fingerprint"; -+ digestProperties[i] = "ro." + partitionName + ".build.version.incremental"; + digestProperties[i] = "ro." + partitionName + ".build.fingerprint"; } - digestProperties[SYSTEM_PARTITIONS.size()] = "ro.build.fingerprint"; // build fingerprint -+ digestProperties[SYSTEM_PARTITIONS.size()] = "ro.build.version.incremental"; // build fingerprint ++ digestProperties[SYSTEM_PARTITIONS.size()] = "ro.build.version.incremental"; return SystemProperties.digestOf(digestProperties); } +diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetXmlUtil.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetXmlUtil.java +index d781cd8d58d89..c1b2c5824b519 100644 +--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetXmlUtil.java ++++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetXmlUtil.java +@@ -100,7 +100,7 @@ public static void writeAppWidgetProviderInfoLocked(@NonNull final TypedXmlSeria + 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, Build.VERSION.INCREMENTAL); + } + + /** +@@ -111,7 +111,7 @@ public static AppWidgetProviderInfo readAppWidgetProviderInfoLocked( + @NonNull final TypedXmlPullParser parser) { + Objects.requireNonNull(parser); + final String fingerprint = parser.getAttributeValue(null, ATTR_OS_FINGERPRINT); +- if (!Build.FINGERPRINT.equals(fingerprint)) { ++ if (!Build.VERSION.INCREMENTAL.equals(fingerprint)) { + return null; + } + final AppWidgetProviderInfo info = new AppWidgetProviderInfo(); +diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java +index c0b8034b9a562..dd7d5cea82a83 100644 +--- a/services/core/java/com/android/server/pm/PackageManagerService.java ++++ b/services/core/java/com/android/server/pm/PackageManagerService.java +@@ -2229,7 +2229,8 @@ public Set getInstallConstraintsAllowlist() { + if (mIsUpgrade) { + PackageManagerServiceUtils.logCriticalInfo(Log.INFO, + "Upgrading from " + ver.fingerprint + " (" + ver.buildFingerprint + ") to " +- + PackagePartitions.FINGERPRINT + " (" + Build.FINGERPRINT + ")"); ++ + PackagePartitions.FINGERPRINT ++ + " (" + Build.VERSION.INCREMENTAL + ")"); + } + mPriorSdkVersion = mIsUpgrade ? ver.sdkVersion : -1; + mInitAppsHelper = new InitAppsHelper(this, mApexManager, mInstallPackageHelper, +@@ -2387,7 +2388,7 @@ public Set getInstallConstraintsAllowlist() { + | Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES); + } + } +- ver.buildFingerprint = Build.FINGERPRINT; ++ ver.buildFingerprint = Build.VERSION.INCREMENTAL; + 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 ff8abf8794874..0babd99a511ba 100644 +--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java ++++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java +@@ -1399,8 +1399,6 @@ public static void enforceSystemOrRoot(String message) { + // 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."); +- + // 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, +@@ -1408,6 +1406,7 @@ public static void enforceSystemOrRoot(String message) { + 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); + } +diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java +index 39565526f33ee..d410f237fd07c 100644 +--- a/services/core/java/com/android/server/pm/Settings.java ++++ b/services/core/java/com/android/server/pm/Settings.java +@@ -484,7 +484,7 @@ public static class VersionInfo { + public void forceCurrent() { + sdkVersion = Build.VERSION.SDK_INT; + databaseVersion = CURRENT_DATABASE_VERSION; +- buildFingerprint = Build.FINGERPRINT; ++ buildFingerprint = Build.VERSION.INCREMENTAL; + 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 c1ab3f9e..1b0c9917 100644 +index 1cd77ffcedaa2..b918cfa56f40d 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java -@@ -5230,7 +5230,7 @@ public class ShortcutService extends IShortcutService.Stub { +@@ -5248,7 +5248,7 @@ void injectRestoreCallingIdentity(long token) { // Injection point. String injectBuildFingerprint() { diff --git a/patches/personal/platform_frameworks_base/0005-SystemUI-Add-left-padding-for-keyguard-slices.patch b/patches/personal/platform_frameworks_base/0005-SystemUI-Add-left-padding-for-keyguard-slices.patch new file mode 100644 index 00000000..47ec6e3a --- /dev/null +++ b/patches/personal/platform_frameworks_base/0005-SystemUI-Add-left-padding-for-keyguard-slices.patch @@ -0,0 +1,45 @@ +From 37f057dcbb2c09130fd745170f3e83eb46535884 Mon Sep 17 00:00:00 2001 +From: LuK1337 +Date: Fri, 27 May 2022 01:13:39 +0200 +Subject: [PATCH 5/8] SystemUI: Add left padding for keyguard slices + +Fixes: https://gitlab.com/LineageOS/issues/android/-/issues/4620 +Change-Id: I2735028472aa46bad412c69948936fb30c5fa36c +--- + .../src/com/android/keyguard/KeyguardSliceView.java | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java +index 7b5325d4e..d8be862e1 100644 +--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java ++++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java +@@ -49,6 +49,7 @@ import com.android.internal.annotations.VisibleForTesting; + import com.android.internal.graphics.ColorUtils; + import com.android.settingslib.Utils; + import com.android.systemui.res.R; ++import com.android.systemui.keyguard.KeyguardSliceProvider; + import com.android.systemui.util.wakelock.KeepAwakeAnimationListener; + + import java.io.PrintWriter; +@@ -445,13 +446,15 @@ public class KeyguardSliceView extends LinearLayout { + + private void updatePadding() { + boolean hasText = !TextUtils.isEmpty(getText()); ++ boolean isDate = Uri.parse(KeyguardSliceProvider.KEYGUARD_DATE_URI).equals(getTag()); + int padding = (int) getContext().getResources() + .getDimension(R.dimen.widget_horizontal_padding) / 2; ++ int iconPadding = (int) mContext.getResources() ++ .getDimension(R.dimen.widget_icon_padding); + // orientation is vertical, so add padding to top & bottom +- setPadding(0, padding, 0, hasText ? padding : 0); ++ setPadding(!isDate ? iconPadding : 0, padding, 0, hasText ? padding : 0); + +- setCompoundDrawablePadding((int) mContext.getResources() +- .getDimension(R.dimen.widget_icon_padding)); ++ setCompoundDrawablePadding(iconPadding); + } + + @Override +-- +2.34.1 + diff --git a/patches/personal/platform_frameworks_base/0005-SystemUI-fix-SliceView-layout.patch b/patches/personal/platform_frameworks_base/0005-SystemUI-fix-SliceView-layout.patch deleted file mode 100644 index 5b46c5c1..00000000 --- a/patches/personal/platform_frameworks_base/0005-SystemUI-fix-SliceView-layout.patch +++ /dev/null @@ -1,29 +0,0 @@ -From e69cdc79b594a26c7eb42564a5a1fcbb8afca848 Mon Sep 17 00:00:00 2001 -From: Anay Wadhera -Date: Sun, 13 Nov 2022 10:42:03 -0500 -Subject: [PATCH 05/10] SystemUI: fix SliceView layout - -Before: https://imgur.com/a/wIwyMJS -After: https://imgur.com/a/dJPVMxS - -Change-Id: Ib5fb2e3b9c0f3948bc3e88c2333df816bde265f8 ---- - packages/SystemUI/res-keyguard/layout/keyguard_slice_view.xml | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_slice_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_slice_view.xml -index 7c5dbc24..64657547 100644 ---- a/packages/SystemUI/res-keyguard/layout/keyguard_slice_view.xml -+++ b/packages/SystemUI/res-keyguard/layout/keyguard_slice_view.xml -@@ -38,7 +38,7 @@ - android:id="@+id/row" - android:layout_width="match_parent" - android:layout_height="wrap_content" -- android:orientation="horizontal" -+ android:orientation="vertical" - android:gravity="start" - /> - --- -2.34.1 - diff --git a/patches/personal/platform_frameworks_base/0006-Add-android.permission.READ_PHONE_STATE-to-manifest.patch b/patches/personal/platform_frameworks_base/0006-Add-android.permission.READ_PHONE_STATE-to-manifest.patch index ae2864f2..c9d56193 100644 --- a/patches/personal/platform_frameworks_base/0006-Add-android.permission.READ_PHONE_STATE-to-manifest.patch +++ b/patches/personal/platform_frameworks_base/0006-Add-android.permission.READ_PHONE_STATE-to-manifest.patch @@ -1,7 +1,7 @@ -From 1d4828950852f5cdbaa1f52ba01c745512d1ca3f Mon Sep 17 00:00:00 2001 +From fd9ded0e5692e15d1b97c582f546c962441271a5 Mon Sep 17 00:00:00 2001 From: Janson Kang Date: Mon, 14 Dec 2015 11:13:24 +0800 -Subject: [PATCH 06/10] Add "android.permission.READ_PHONE_STATE" to manifest +Subject: [PATCH 6/8] Add "android.permission.READ_PHONE_STATE" to manifest Change-Id: I78d90166635bbdf6b74e2a02efc1029387b4ad8d --- @@ -9,7 +9,7 @@ Change-Id: I78d90166635bbdf6b74e2a02efc1029387b4ad8d 1 file changed, 1 insertion(+) diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml -index 12e8f574..774d6cbc 100644 +index 666d93925..e47dde0c1 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -68,6 +68,7 @@ diff --git a/patches/personal/platform_frameworks_base/0007-permissions-Pre-grant-google-restore-permissions.patch b/patches/personal/platform_frameworks_base/0007-permissions-Pre-grant-google-restore-permissions.patch index 7e2cd384..f1f72c14 100644 --- a/patches/personal/platform_frameworks_base/0007-permissions-Pre-grant-google-restore-permissions.patch +++ b/patches/personal/platform_frameworks_base/0007-permissions-Pre-grant-google-restore-permissions.patch @@ -1,7 +1,7 @@ -From 7b5640f84acfd11a19c49156a7eb2bcd24eeafc7 Mon Sep 17 00:00:00 2001 +From 6aee610201ab3e34f39a7160950a024b25d01d78 Mon Sep 17 00:00:00 2001 From: Alberto Ponces Date: Sun, 5 Mar 2023 17:54:25 +0000 -Subject: [PATCH 07/10] permissions: Pre-grant google restore permissions +Subject: [PATCH 7/8] permissions: Pre-grant google restore permissions Change-Id: I241886b63e0660ef01e7801b273045c3c91d44ea --- @@ -9,10 +9,10 @@ Change-Id: I241886b63e0660ef01e7801b273045c3c91d44ea 1 file changed, 19 insertions(+) diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java -index f7f76aaa..03ec8f7d 100644 +index 5eda6deb0..748e5a2c5 100644 --- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java +++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java -@@ -210,6 +210,15 @@ final class DefaultPermissionGrantPolicy { +@@ -217,6 +217,15 @@ final class DefaultPermissionGrantPolicy { SENSORS_PERMISSIONS.add(Manifest.permission.BODY_SENSORS_BACKGROUND); } @@ -28,7 +28,7 @@ index f7f76aaa..03ec8f7d 100644 private static final Set STORAGE_PERMISSIONS = new ArraySet<>(); static { STORAGE_PERMISSIONS.add(Manifest.permission.READ_EXTERNAL_STORAGE); -@@ -932,6 +941,16 @@ final class DefaultPermissionGrantPolicy { +@@ -939,6 +948,16 @@ final class DefaultPermissionGrantPolicy { String commonServiceAction = "android.adservices.AD_SERVICES_COMMON_SERVICE"; grantPermissionsToSystemPackage(pm, getDefaultSystemHandlerServicePackage(pm, commonServiceAction, userId), userId, NOTIFICATION_PERMISSIONS); diff --git a/patches/personal/platform_frameworks_base/0008-feat-Add-Lockscreen-Weather-with-OmniJaws-1-2.patch b/patches/personal/platform_frameworks_base/0008-feat-Add-Lockscreen-Weather-with-OmniJaws-1-2.patch index e74006fb..0fa12c70 100644 --- a/patches/personal/platform_frameworks_base/0008-feat-Add-Lockscreen-Weather-with-OmniJaws-1-2.patch +++ b/patches/personal/platform_frameworks_base/0008-feat-Add-Lockscreen-Weather-with-OmniJaws-1-2.patch @@ -1,7 +1,7 @@ -From b68c5d1ed8e863c5b567e481b0801c55bac30741 Mon Sep 17 00:00:00 2001 +From 98586827d510de79eac63c1fdeece3c81409605e Mon Sep 17 00:00:00 2001 From: maxwen Date: Fri, 22 Oct 2021 14:55:26 +0200 -Subject: [PATCH 08/10] feat: Add Lockscreen Weather with OmniJaws (1/2) +Subject: [PATCH 8/8] feat: Add Lockscreen Weather with OmniJaws (1/2) Based on OmniROM's implementation, updated by @maxwen and adapted by @neobuddy89. @@ -9,25 +9,20 @@ Change-Id: I138c0dc94f08142f6614659037a501d6ae8909b1 Co-authored-by: maxwen Co-authored-by: Pranav Vashi --- - core/java/android/provider/Settings.java | 10 + - .../internal/util/crdroid/OmniJawsClient.java | 437 ++++++++++++++++++ + core/java/android/provider/Settings.java | 5 + + .../internal/util/crdroid/OmniJawsClient.java | 441 ++++++++++++++++++ data/etc/com.android.systemui.xml | 1 + packages/SystemUI/AndroidManifest.xml | 4 + - .../layout/current_weather_view.xml | 59 +++ - .../layout/keyguard_clock_switch.xml | 6 + - .../KeyguardClockSwitchController.java | 52 ++- - .../KeyguardStatusViewController.java | 1 + - .../systemui/crdroid/CurrentWeatherView.java | 163 +++++++ - 9 files changed, 732 insertions(+), 1 deletion(-) + .../android/keyguard/KeyguardSliceView.java | 13 + + .../keyguard/KeyguardSliceProvider.java | 103 +++- + 6 files changed, 566 insertions(+), 1 deletion(-) create mode 100644 core/java/com/android/internal/util/crdroid/OmniJawsClient.java - create mode 100644 packages/SystemUI/res-keyguard/layout/current_weather_view.xml - create mode 100644 packages/SystemUI/src/com/android/systemui/crdroid/CurrentWeatherView.java diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java -index 51585af1..f8e86e0f 100644 +index 5c392ae6b..e9f87249f 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java -@@ -6201,6 +6201,16 @@ public final class Settings { +@@ -6249,6 +6249,11 @@ public final class Settings { * the setting value. See an example above. */ @@ -35,21 +30,16 @@ index 51585af1..f8e86e0f 100644 + * @hide + */ + public static final String LOCKSCREEN_WEATHER_ENABLED = "lockscreen_weather_enabled"; -+ -+ /** -+ * @hide -+ */ -+ public static final String LOCKSCREEN_WEATHER_LOCATION = "lockscreen_weather_location"; + /** * Keys we no longer back up under the current schema, but want to continue to * process when restoring historical backup datasets. diff --git a/core/java/com/android/internal/util/crdroid/OmniJawsClient.java b/core/java/com/android/internal/util/crdroid/OmniJawsClient.java new file mode 100644 -index 00000000..26437e03 +index 000000000..2bbd51ffa --- /dev/null +++ b/core/java/com/android/internal/util/crdroid/OmniJawsClient.java -@@ -0,0 +1,437 @@ +@@ -0,0 +1,441 @@ +/* +* Copyright (C) 2021 The OmniROM Project +* @@ -106,7 +96,7 @@ index 00000000..26437e03 + = Uri.parse("content://org.omnirom.omnijaws.provider/control"); + + private static final String ICON_PACKAGE_DEFAULT = "org.omnirom.omnijaws"; -+ private static final String ICON_PREFIX_DEFAULT = "google"; ++ private static final String ICON_PREFIX_DEFAULT = "google_new_light"; + private static final String ICON_PREFIX_OUTLINE = "outline"; + private static final String EXTRA_ERROR = "error"; + public static final int EXTRA_ERROR_NETWORK = 0; @@ -406,21 +396,25 @@ index 00000000..26437e03 + if (!isOmniJawsServiceInstalled()) { + return false; + } ++ boolean enabled = false; + try { + final Cursor c = mContext.getContentResolver().query(SETTINGS_URI, SETTINGS_PROJECTION, + null, null, null); + if (c != null) { -+ int count = c.getCount(); -+ if (count == 1) { -+ c.moveToPosition(0); -+ boolean enabled = c.getInt(0) == 1; -+ return enabled; ++ try { ++ int count = c.getCount(); ++ if (count == 1) { ++ c.moveToPosition(0); ++ enabled = c.getInt(0) == 1; ++ } ++ } finally { ++ c.close(); + } + } + } catch (Exception e) { + Log.e(TAG, "isOmniJawsEnabled", e); + } -+ return false; ++ return enabled; + } + + private String getTemperatureUnit() { @@ -488,7 +482,7 @@ index 00000000..26437e03 + } +} diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml -index ce2543a4..ef330da9 100644 +index a115c659d..d001b0329 100644 --- a/data/etc/com.android.systemui.xml +++ b/data/etc/com.android.systemui.xml @@ -16,6 +16,7 @@ @@ -500,352 +494,237 @@ index ce2543a4..ef330da9 100644 diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml -index 774d6cbc..86a8a2a0 100644 +index e47dde0c1..ef993a447 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml -@@ -364,6 +364,10 @@ - - +@@ -383,6 +383,10 @@ + + + + + + - - - -diff --git a/packages/SystemUI/res-keyguard/layout/current_weather_view.xml b/packages/SystemUI/res-keyguard/layout/current_weather_view.xml -new file mode 100644 -index 00000000..502df830 ---- /dev/null -+++ b/packages/SystemUI/res-keyguard/layout/current_weather_view.xml -@@ -0,0 +1,59 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml -index fc9c917c..5b26e314 100644 ---- a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml -+++ b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml -@@ -56,6 +56,12 @@ - android:layout_width="match_parent" - android:layout_height="wrap_content" /> - -+ -+ - -- implements Dumpable { -+ implements Dumpable, TunerService.Tunable { - private static final String TAG = "KeyguardClockSwitchController"; - -+ private static final String LOCKSCREEN_WEATHER_ENABLED = -+ "system:" + Settings.System.LOCKSCREEN_WEATHER_ENABLED; -+ - private final StatusBarStateController mStatusBarStateController; - private final ClockRegistry mClockRegistry; - private final KeyguardSliceViewController mKeyguardSliceViewController; -@@ -94,6 +101,7 @@ public class KeyguardClockSwitchController extends ViewController { -+ final ContentResolver resolver = getContext().getContentResolver(); -+ mShowWeather = Settings.System.getIntForUser(resolver, -+ Settings.System.LOCKSCREEN_WEATHER_ENABLED, 0, -+ UserHandle.USER_CURRENT) != 0; -+ if (mCurrentWeatherView != null) { -+ if (mShowWeather && !mOnlyClock) { -+ mCurrentWeatherView.enableUpdates(); -+ mCurrentWeatherView.setVisibility(View.VISIBLE); -+ } else { -+ mCurrentWeatherView.disableUpdates(); -+ mCurrentWeatherView.setVisibility(View.GONE); -+ } -+ } -+ }); -+ } -+ - void onLocaleListChanged() { - if (mSmartspaceController.isEnabled()) { - removeViewsFromStatusArea(); -diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java -index c0ae4a1f..9f71ed70 100644 ---- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java -+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java -@@ -436,6 +436,7 @@ public class KeyguardStatusViewController extends ViewController -Date: Tue, 1 Nov 2022 17:27:48 -0400 -Subject: [PATCH 09/10] feat: Add Face Unlock with ParanoidSense (1/2) - -Based on AOSPA's implementation and adapted by @ghostrider-reborn - -Co-authored-by: Chris Crump -Co-authored-by: Adithya R -Change-Id: I05fa784d9f7f978be9f5944900a97ad7df19f59e ---- - .../privacy/AppOpsPrivacyItemMonitor.kt | 8 + - .../phone/BiometricUnlockController.java | 2 +- - .../phone/KeyguardBypassController.kt | 11 +- - services/core/Android.bp | 1 + - .../biometrics/sensors/face/FaceService.java | 34 +- - .../face/sense/BiometricTestSessionImpl.java | 229 ++++ - .../face/sense/FaceAuthenticationClient.java | 228 ++++ - .../sensors/face/sense/FaceEnrollClient.java | 138 ++ - .../sense/FaceGenerateChallengeClient.java | 111 ++ - .../face/sense/FaceGetFeatureClient.java | 101 ++ - .../face/sense/FaceInternalCleanupClient.java | 70 ++ - .../sense/FaceInternalEnumerateClient.java | 58 + - .../sensors/face/sense/FaceRemovalClient.java | 63 + - .../face/sense/FaceResetLockoutClient.java | 82 ++ - .../face/sense/FaceRevokeChallengeClient.java | 55 + - .../face/sense/FaceSetFeatureClient.java | 93 ++ - .../sense/FaceUpdateActiveUserClient.java | 84 ++ - .../sensors/face/sense/SenseProvider.java | 1110 +++++++++++++++++ - .../sensors/face/sense/SenseUtils.java | 61 + - .../sensors/face/sense/TestHal.java | 144 +++ - 20 files changed, 2667 insertions(+), 16 deletions(-) - create mode 100644 services/core/java/com/android/server/biometrics/sensors/face/sense/BiometricTestSessionImpl.java - create mode 100644 services/core/java/com/android/server/biometrics/sensors/face/sense/FaceAuthenticationClient.java - create mode 100644 services/core/java/com/android/server/biometrics/sensors/face/sense/FaceEnrollClient.java - create mode 100644 services/core/java/com/android/server/biometrics/sensors/face/sense/FaceGenerateChallengeClient.java - create mode 100644 services/core/java/com/android/server/biometrics/sensors/face/sense/FaceGetFeatureClient.java - create mode 100644 services/core/java/com/android/server/biometrics/sensors/face/sense/FaceInternalCleanupClient.java - create mode 100644 services/core/java/com/android/server/biometrics/sensors/face/sense/FaceInternalEnumerateClient.java - create mode 100644 services/core/java/com/android/server/biometrics/sensors/face/sense/FaceRemovalClient.java - create mode 100644 services/core/java/com/android/server/biometrics/sensors/face/sense/FaceResetLockoutClient.java - create mode 100644 services/core/java/com/android/server/biometrics/sensors/face/sense/FaceRevokeChallengeClient.java - create mode 100644 services/core/java/com/android/server/biometrics/sensors/face/sense/FaceSetFeatureClient.java - create mode 100644 services/core/java/com/android/server/biometrics/sensors/face/sense/FaceUpdateActiveUserClient.java - create mode 100644 services/core/java/com/android/server/biometrics/sensors/face/sense/SenseProvider.java - create mode 100644 services/core/java/com/android/server/biometrics/sensors/face/sense/SenseUtils.java - create mode 100644 services/core/java/com/android/server/biometrics/sensors/face/sense/TestHal.java - -diff --git a/packages/SystemUI/src/com/android/systemui/privacy/AppOpsPrivacyItemMonitor.kt b/packages/SystemUI/src/com/android/systemui/privacy/AppOpsPrivacyItemMonitor.kt -index fedbdec1..cc4ce05a 100644 ---- a/packages/SystemUI/src/com/android/systemui/privacy/AppOpsPrivacyItemMonitor.kt -+++ b/packages/SystemUI/src/com/android/systemui/privacy/AppOpsPrivacyItemMonitor.kt -@@ -95,6 +95,10 @@ class AppOpsPrivacyItemMonitor @Inject constructor( - if (code in OPS_LOCATION && !locationAvailable) { - return - } -+ // Hide incoming chip from sense caller package -+ if (packageName == "co.aospa.sense") { -+ return -+ } - if (userTracker.userProfiles.any { it.id == UserHandle.getUserId(uid) } || - code in USER_INDEPENDENT_OPS) { - logger.logUpdatedItemFromAppOps(code, uid, packageName, active) -@@ -219,6 +223,10 @@ class AppOpsPrivacyItemMonitor @Inject constructor( - AppOpsManager.OP_RECORD_AUDIO -> PrivacyType.TYPE_MICROPHONE - else -> return null - } -+ // Hide incoming chip from sense caller package -+ if (appOpItem.packageName == "co.aospa.sense") { -+ return null -+ } - val app = PrivacyApplication(appOpItem.packageName, appOpItem.uid) - return PrivacyItem(type, app, appOpItem.timeStartedElapsed, appOpItem.isDisabled) - } -diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java -index 97fc35a0..1d4069ae 100644 ---- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java -+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java -@@ -618,7 +618,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp - final boolean unlockingAllowed = - mUpdateMonitor.isUnlockingWithBiometricAllowed(isStrongBiometric); - final boolean deviceDreaming = mUpdateMonitor.isDreaming(); -- final boolean bypass = mKeyguardBypassController.getBypassEnabled() -+ final boolean bypass = mKeyguardBypassController.getBypassEnabledBiometric() - || mAuthController.isUdfpsFingerDown(); - - logCalculateModeForPassiveAuth(unlockingAllowed, deviceInteractive, isKeyguardShowing, -diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt -index a3d316b6..866bc590 100644 ---- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt -+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBypassController.kt -@@ -107,6 +107,8 @@ open class KeyguardBypassController : Dumpable, StackScrollAlgorithm.BypassContr - notifyListeners() - } - -+ var bypassEnabledBiometric: Boolean = false -+ - var bouncerShowing: Boolean = false - var altBouncerShowing: Boolean = false - var launchingAffordance: Boolean = false -@@ -163,7 +165,7 @@ open class KeyguardBypassController : Dumpable, StackScrollAlgorithm.BypassContr - com.android.internal.R.bool.config_faceAuthDismissesKeyguard)) 1 else 0 - - tunerService.addTunable({ key, _ -> -- bypassEnabled = tunerService.getValue(key, dismissByDefault) != 0 -+ bypassEnabledBiometric = tunerService.getValue(key, dismissByDefault) != 0 - }, Settings.Secure.FACE_UNLOCK_DISMISSES_KEYGUARD) - - lockscreenUserManager.addUserChangedListener( -@@ -200,8 +202,8 @@ open class KeyguardBypassController : Dumpable, StackScrollAlgorithm.BypassContr - biometricSourceType: BiometricSourceType, - isStrongBiometric: Boolean - ): Boolean { -- if (biometricSourceType == BiometricSourceType.FACE && bypassEnabled) { -- val can = canBypass() -+ if (bypassEnabledBiometric) { -+ val can = biometricSourceType != BiometricSourceType.FACE || canBypass() - if (!can && (isPulseExpanding || qsExpanded)) { - pendingUnlock = PendingUnlock(biometricSourceType, isStrongBiometric) - } -@@ -225,7 +227,7 @@ open class KeyguardBypassController : Dumpable, StackScrollAlgorithm.BypassContr - * If keyguard can be dismissed because of bypass. - */ - fun canBypass(): Boolean { -- if (bypassEnabled) { -+ if (bypassEnabledBiometric) { - return when { - bouncerShowing -> true - altBouncerShowing -> true -@@ -258,6 +260,7 @@ open class KeyguardBypassController : Dumpable, StackScrollAlgorithm.BypassContr - pw.println(" mPendingUnlock: $pendingUnlock") - } - pw.println(" bypassEnabled: $bypassEnabled") -+ pw.println(" bypassEnabledBiometric: $bypassEnabledBiometric") - pw.println(" canBypass: ${canBypass()}") - pw.println(" bouncerShowing: $bouncerShowing") - pw.println(" altBouncerShowing: $altBouncerShowing") -diff --git a/services/core/Android.bp b/services/core/Android.bp -index 69089d3a..680669ff 100644 ---- a/services/core/Android.bp -+++ b/services/core/Android.bp -@@ -263,6 +263,7 @@ java_library_static { - "vendor.oplus.hardware.biometrics.fingerprint-V2.1-java", - "vendor.oppo.hardware.biometrics.fingerprint-V2.1-java", - "vendor.xiaomi.hardware.fingerprintextension-V1.0-java", -+ "vendor.aospa.biometrics.face", - - //AIDL - "vendor.samsung.hardware.sysinput-V1-java", -diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java -index 7ee2a7ab..6ada92b5 100644 ---- a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java -+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java -@@ -26,6 +26,7 @@ import android.app.ActivityManager; - import android.content.Context; - import android.hardware.biometrics.AuthenticationStateListener; - import android.hardware.biometrics.BiometricsProtoEnums; -+import android.hardware.biometrics.SensorProperties; - import android.hardware.biometrics.IBiometricSensorReceiver; - import android.hardware.biometrics.IBiometricService; - import android.hardware.biometrics.IBiometricServiceLockoutResetCallback; -@@ -39,6 +40,7 @@ import android.hardware.face.Face; - import android.hardware.face.FaceAuthenticateOptions; - import android.hardware.face.FaceEnrollOptions; - import android.hardware.face.FaceSensorConfigurations; -+import android.hardware.face.FaceSensorProperties; - import android.hardware.face.FaceSensorPropertiesInternal; - import android.hardware.face.FaceServiceReceiver; - import android.hardware.face.IFaceAuthenticatorsRegisteredCallback; -@@ -73,6 +75,8 @@ import com.android.server.biometrics.sensors.LockoutResetDispatcher; - import com.android.server.biometrics.sensors.LockoutTracker; - import com.android.server.biometrics.sensors.face.aidl.FaceProvider; - import com.android.server.biometrics.sensors.face.hidl.Face10; -+import com.android.server.biometrics.sensors.face.sense.SenseProvider; -+import com.android.server.biometrics.sensors.face.sense.SenseUtils; - - import com.google.android.collect.Lists; - -@@ -692,24 +696,32 @@ public class FaceService extends SystemService { - return providers; - } - -+ private List getSenseProviders() { -+ final List providers = new ArrayList<>(); -+ if (SenseUtils.canUseProvider()) { -+ FaceSensorPropertiesInternal props = new FaceSensorPropertiesInternal( -+ SenseProvider.DEVICE_ID, -+ SensorProperties.STRENGTH_WEAK, -+ 1, /** maxEnrollmentsPerUser **/ -+ new ArrayList(), -+ FaceSensorProperties.TYPE_RGB, -+ false, /** supportsFaceDetection **/ -+ false, /** supportsSelfIllumination **/ -+ false); /** resetLockoutRequiresChallenge **/ -+ SenseProvider provider = new SenseProvider(getContext(), mBiometricStateCallback, props, mLockoutResetDispatcher); -+ providers.add(provider); -+ } -+ return providers; -+ } -+ - @android.annotation.EnforcePermission(android.Manifest.permission.USE_BIOMETRIC_INTERNAL) - public void registerAuthenticators( - @NonNull List hidlSensors) { - super.registerAuthenticators_enforcePermission(); - - mRegistry.registerAll(() -> { -- List aidlSensors = new ArrayList<>(); -- final String[] instances = mAidlInstanceNameSupplier.get(); -- if (instances != null) { -- aidlSensors.addAll(Lists.newArrayList(instances)); -- } -- -- final Pair, List> -- filteredInstances = filterAvailableHalInstances(hidlSensors, aidlSensors); -- - final List providers = new ArrayList<>(); -- providers.addAll(getHidlProviders(filteredInstances.first)); -- providers.addAll(getAidlProviders(filteredInstances.second)); -+ providers.addAll(getSenseProviders()); - return providers; - }); - } -diff --git a/services/core/java/com/android/server/biometrics/sensors/face/sense/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/face/sense/BiometricTestSessionImpl.java -new file mode 100644 -index 00000000..c1122a20 ---- /dev/null -+++ b/services/core/java/com/android/server/biometrics/sensors/face/sense/BiometricTestSessionImpl.java -@@ -0,0 +1,229 @@ -+/* -+ * Copyright (C) 2020 The Android Open Source Project -+ * Copyright (C) 2023 Paranoid Android -+ * -+ * 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.server.biometrics.sensors.face.sense; -+ -+import android.annotation.NonNull; -+import android.content.Context; -+import android.hardware.biometrics.ITestSession; -+import android.hardware.biometrics.ITestSessionCallback; -+import android.hardware.face.Face; -+import android.hardware.face.FaceAuthenticationFrame; -+import android.hardware.face.FaceEnrollFrame; -+import android.hardware.face.FaceEnrollOptions; -+import android.hardware.face.IFaceServiceReceiver; -+import android.os.Binder; -+import android.os.RemoteException; -+import android.util.Slog; -+ -+import com.android.server.biometrics.sensors.BaseClientMonitor; -+import com.android.server.biometrics.sensors.BiometricStateCallback; -+import com.android.server.biometrics.sensors.ClientMonitorCallback; -+import com.android.server.biometrics.sensors.face.FaceUtils; -+ -+import java.util.List; -+import java.util.Random; -+ -+/** -+ * A test session implementation for {@link SenseProvider}. See -+ * {@link android.hardware.biometrics.BiometricTestSession}. -+ */ -+public class BiometricTestSessionImpl extends ITestSession.Stub { -+ -+ private static final String TAG = "face/sense/BiometricTestSessionImpl"; -+ -+ @NonNull private final Context mContext; -+ private final int mSensorId; -+ @NonNull private final ITestSessionCallback mCallback; -+ @NonNull private final Random mRandom; -+ -+ @NonNull private final SenseProvider.HalResultController mHalResultController; -+ @NonNull private final SenseProvider mSenseProvider; -+ -+ /** -+ * Internal receiver currently only used for enroll. Results do not need to be forwarded to the -+ * test, since enrollment is a platform-only API. The authentication path is tested through -+ * the public BiometricPrompt APIs and does not use this receiver. -+ */ -+ private final IFaceServiceReceiver mReceiver = new IFaceServiceReceiver.Stub() { -+ @Override -+ public void onEnrollResult(Face face, int remaining) { -+ -+ } -+ -+ @Override -+ public void onAcquired(int acquireInfo, int vendorCode) { -+ -+ } -+ -+ @Override -+ public void onAuthenticationSucceeded(Face face, int userId, boolean isStrongBiometric) { -+ -+ } -+ -+ @Override -+ public void onFaceDetected(int sensorId, int userId, boolean isStrongBiometric) { -+ -+ } -+ -+ @Override -+ public void onAuthenticationFailed() { -+ -+ } -+ -+ @Override -+ public void onError(int error, int vendorCode) { -+ -+ } -+ -+ @Override -+ public void onRemoved(Face face, int remaining) { -+ -+ } -+ -+ @Override -+ public void onFeatureSet(boolean success, int feature) { -+ -+ } -+ -+ @Override -+ public void onFeatureGet(boolean success, int[] features, boolean[] featureState) { -+ -+ } -+ -+ @Override -+ public void onChallengeGenerated(int sensorId, int userId, long challenge) { -+ -+ } -+ -+ @Override -+ public void onAuthenticationFrame(FaceAuthenticationFrame frame) { -+ -+ } -+ -+ @Override -+ public void onEnrollmentFrame(FaceEnrollFrame frame) { -+ -+ } -+ }; -+ -+ BiometricTestSessionImpl(@NonNull Context context, int sensorId, -+ @NonNull ITestSessionCallback callback, @NonNull SenseProvider provider, -+ @NonNull SenseProvider.HalResultController halResultController) { -+ mContext = context; -+ mSensorId = sensorId; -+ mCallback = callback; -+ mSenseProvider = provider; -+ mHalResultController = halResultController; -+ mRandom = new Random(); -+ } -+ -+ @android.annotation.EnforcePermission(android.Manifest.permission.TEST_BIOMETRIC) -+ @Override -+ public void setTestHalEnabled(boolean enabled) { -+ super.setTestHalEnabled_enforcePermission(); -+ -+ mSenseProvider.setTestHalEnabled(enabled); -+ } -+ -+ @android.annotation.EnforcePermission(android.Manifest.permission.TEST_BIOMETRIC) -+ @Override -+ public void startEnroll(int userId) { -+ super.startEnroll_enforcePermission(); -+ -+ mSenseProvider.scheduleEnroll(mSensorId, new Binder(), new byte[69], userId, mReceiver, -+ mContext.getOpPackageName(), new int[0] /* disabledFeatures */, -+ null /* previewSurface */, false /* debugConsent */, -+ (new FaceEnrollOptions.Builder()).build()); -+ } -+ -+ @android.annotation.EnforcePermission(android.Manifest.permission.TEST_BIOMETRIC) -+ @Override -+ public void finishEnroll(int userId) { -+ super.finishEnroll_enforcePermission(); -+ -+ mHalResultController.onEnrollResult(1, userId, 0); -+ } -+ -+ @android.annotation.EnforcePermission(android.Manifest.permission.TEST_BIOMETRIC) -+ @Override -+ public void acceptAuthentication(int userId) { -+ super.acceptAuthentication_enforcePermission(); -+ -+ // Fake authentication with any of the existing faces -+ List faces = FaceUtils.getInstance(mSensorId) -+ .getBiometricsForUser(mContext, userId); -+ if (faces.isEmpty()) { -+ Slog.w(TAG, "No faces, returning"); -+ return; -+ } -+ final int fid = faces.get(0).getBiometricId(); -+ byte[] hat = {0}; -+ mHalResultController.onAuthenticated(0 /* deviceId */, userId, hat); -+ } -+ -+ @android.annotation.EnforcePermission(android.Manifest.permission.TEST_BIOMETRIC) -+ @Override -+ public void rejectAuthentication(int userId) { -+ super.rejectAuthentication_enforcePermission(); -+ -+ mHalResultController.onAuthenticated(0 /* deviceId */, userId, null); -+ } -+ -+ @android.annotation.EnforcePermission(android.Manifest.permission.TEST_BIOMETRIC) -+ @Override -+ public void notifyAcquired(int userId, int acquireInfo) { -+ super.notifyAcquired_enforcePermission(); -+ -+ mHalResultController.onAcquired(userId, 0 /* deviceId */, 0 /* vendorCode */); -+ } -+ -+ @android.annotation.EnforcePermission(android.Manifest.permission.TEST_BIOMETRIC) -+ @Override -+ public void notifyError(int userId, int errorCode) { -+ super.notifyError_enforcePermission(); -+ -+ mHalResultController.onError(0 /* deviceId */, 0 /* vendorCode */); -+ } -+ -+ @android.annotation.EnforcePermission(android.Manifest.permission.TEST_BIOMETRIC) -+ @Override -+ public void cleanupInternalState(int userId) { -+ super.cleanupInternalState_enforcePermission(); -+ -+ mSenseProvider.scheduleInternalCleanup(mSensorId, userId, new ClientMonitorCallback() { -+ @Override -+ public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) { -+ try { -+ mCallback.onCleanupStarted(clientMonitor.getTargetUserId()); -+ } catch (RemoteException e) { -+ Slog.e(TAG, "Remote exception", e); -+ } -+ } -+ -+ @Override -+ public void onClientFinished(@NonNull BaseClientMonitor clientMonitor, -+ boolean success) { -+ try { -+ mCallback.onCleanupFinished(clientMonitor.getTargetUserId()); -+ } catch (RemoteException e) { -+ Slog.e(TAG, "Remote exception", e); -+ } -+ } -+ }); -+ } -+} -diff --git a/services/core/java/com/android/server/biometrics/sensors/face/sense/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/sense/FaceAuthenticationClient.java -new file mode 100644 -index 00000000..118970dc ---- /dev/null -+++ b/services/core/java/com/android/server/biometrics/sensors/face/sense/FaceAuthenticationClient.java -@@ -0,0 +1,228 @@ -+/* -+ * Copyright (C) 2020 The Android Open Source Project -+ * Copyright (C) 2023 Paranoid Android -+ * -+ * 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.server.biometrics.sensors.face.sense; -+ -+import android.annotation.NonNull; -+import android.content.Context; -+import android.content.res.Resources; -+import android.hardware.SensorPrivacyManager; -+import android.hardware.biometrics.BiometricAuthenticator; -+import android.hardware.biometrics.BiometricConstants; -+import android.hardware.biometrics.BiometricFaceConstants; -+import android.hardware.biometrics.BiometricManager.Authenticators; -+import android.hardware.biometrics.face.V1_0.IBiometricsFace; -+import android.hardware.face.FaceAuthenticateOptions; -+import android.hardware.face.FaceManager; -+import android.os.IBinder; -+import android.os.RemoteException; -+import android.util.Slog; -+ -+import com.android.internal.R; -+import com.android.server.biometrics.Utils; -+import com.android.server.biometrics.log.BiometricContext; -+import com.android.server.biometrics.log.BiometricLogger; -+import com.android.server.biometrics.sensors.AuthenticationClient; -+import com.android.server.biometrics.sensors.BiometricNotificationUtils; -+import com.android.server.biometrics.sensors.ClientMonitorCallback; -+import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; -+import com.android.server.biometrics.sensors.ClientMonitorCompositeCallback; -+import com.android.server.biometrics.sensors.LockoutTracker; -+import com.android.server.biometrics.sensors.PerformanceTracker; -+import com.android.server.biometrics.sensors.face.UsageStats; -+ -+import java.util.ArrayList; -+import java.util.function.Supplier; -+ -+import vendor.aospa.biometrics.face.ISenseService; -+ -+/** -+ * Face-specific authentication client supporting the {@link android.hardware.biometrics.face.V1_0} -+ * HIDL interface. -+ */ -+class FaceAuthenticationClient -+ extends AuthenticationClient { -+ -+ private static final String TAG = "FaceAuthenticationClient"; -+ -+ private final UsageStats mUsageStats; -+ -+ private final int[] mBiometricPromptIgnoreList; -+ private final int[] mBiometricPromptIgnoreListVendor; -+ private final int[] mKeyguardIgnoreList; -+ private final int[] mKeyguardIgnoreListVendor; -+ -+ private int mLastAcquire; -+ -+ FaceAuthenticationClient(@NonNull Context context, -+ @NonNull Supplier lazyDaemon, -+ @NonNull IBinder token, long requestId, -+ @NonNull ClientMonitorCallbackConverter listener, long operationId, -+ boolean restricted, @NonNull FaceAuthenticateOptions options, int cookie, -+ boolean requireConfirmation, -+ @NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext, -+ boolean isStrongBiometric, @NonNull LockoutTracker lockoutTracker, -+ @NonNull UsageStats usageStats, boolean allowBackgroundAuthentication, -+ @Authenticators.Types int sensorStrength) { -+ super(context, lazyDaemon, token, listener, operationId, restricted, -+ options, cookie, requireConfirmation, logger, biometricContext, -+ isStrongBiometric, null /* taskStackListener */, -+ lockoutTracker, allowBackgroundAuthentication, true /* shouldVibrate */, -+ sensorStrength); -+ setRequestId(requestId); -+ mUsageStats = usageStats; -+ -+ final Resources resources = getContext().getResources(); -+ mBiometricPromptIgnoreList = resources.getIntArray( -+ R.array.config_face_acquire_biometricprompt_ignorelist); -+ mBiometricPromptIgnoreListVendor = resources.getIntArray( -+ R.array.config_face_acquire_vendor_biometricprompt_ignorelist); -+ mKeyguardIgnoreList = resources.getIntArray( -+ R.array.config_face_acquire_keyguard_ignorelist); -+ mKeyguardIgnoreListVendor = resources.getIntArray( -+ R.array.config_face_acquire_vendor_keyguard_ignorelist); -+ } -+ -+ @Override -+ public void start(@NonNull ClientMonitorCallback callback) { -+ super.start(callback); -+ mState = STATE_STARTED; -+ } -+ -+ @NonNull -+ @Override -+ protected ClientMonitorCallback wrapCallbackForStart(@NonNull ClientMonitorCallback callback) { -+ return new ClientMonitorCompositeCallback( -+ getLogger().getAmbientLightProbe(true /* startWithClient */), callback); -+ } -+ -+ @Override -+ protected void startHalOperation() { -+ try { -+ getFreshDaemon().authenticate(mOperationId); -+ } catch (RemoteException e) { -+ Slog.e(TAG, "Remote exception when requesting auth", e); -+ onError(BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */); -+ mCallback.onClientFinished(this, false /* success */); -+ } -+ } -+ -+ @Override -+ protected void stopHalOperation() { -+ try { -+ getFreshDaemon().cancel(); -+ } catch (RemoteException e) { -+ Slog.e(TAG, "Remote exception when requesting cancel", e); -+ onError(BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */); -+ mCallback.onClientFinished(this, false /* success */); -+ } -+ } -+ -+ @Override -+ public boolean wasUserDetected() { -+ // Do not provide haptic feedback if the user was not detected, and an error (usually -+ // ERROR_TIMEOUT) is received. -+ return mLastAcquire != FaceManager.FACE_ACQUIRED_NOT_DETECTED -+ && mLastAcquire != FaceManager.FACE_ACQUIRED_SENSOR_DIRTY; -+ } -+ -+ @Override -+ protected void handleLifecycleAfterAuth(boolean authenticated) { -+ // For face, the authentication lifecycle ends either when -+ // 1) Authenticated == true -+ // 2) Error occurred -+ // 3) Authenticated == false -+ mCallback.onClientFinished(this, true /* success */); -+ } -+ -+ @Override -+ public @LockoutTracker.LockoutMode int handleFailedAttempt(int userId) { -+ @LockoutTracker.LockoutMode final int lockoutMode = -+ getLockoutTracker().getLockoutModeForUser(userId); -+ final PerformanceTracker performanceTracker = -+ PerformanceTracker.getInstanceForSensorId(getSensorId()); -+ if (lockoutMode == LockoutTracker.LOCKOUT_PERMANENT) { -+ performanceTracker.incrementPermanentLockoutForUser(userId); -+ } else if (lockoutMode == LockoutTracker.LOCKOUT_TIMED) { -+ performanceTracker.incrementTimedLockoutForUser(userId); -+ } -+ -+ return lockoutMode; -+ } -+ -+ @Override -+ public void onAuthenticated(BiometricAuthenticator.Identifier identifier, -+ boolean authenticated, ArrayList token) { -+ super.onAuthenticated(identifier, authenticated, token); -+ -+ mState = STATE_STOPPED; -+ mUsageStats.addEvent(new UsageStats.AuthenticationEvent( -+ getStartTimeMs(), -+ System.currentTimeMillis() - getStartTimeMs() /* latency */, -+ authenticated, -+ 0 /* error */, -+ 0 /* vendorError */, -+ getTargetUserId())); -+ } -+ -+ @Override -+ public void onError(@BiometricConstants.Errors int error, int vendorCode) { -+ mUsageStats.addEvent(new UsageStats.AuthenticationEvent( -+ getStartTimeMs(), -+ System.currentTimeMillis() - getStartTimeMs() /* latency */, -+ false /* authenticated */, -+ error, -+ vendorCode, -+ getTargetUserId())); -+ -+ super.onError(error, vendorCode); -+ } -+ -+ private int[] getAcquireIgnorelist() { -+ return isBiometricPrompt() ? mBiometricPromptIgnoreList : mKeyguardIgnoreList; -+ } -+ -+ private int[] getAcquireVendorIgnorelist() { -+ return isBiometricPrompt() ? mBiometricPromptIgnoreListVendor : mKeyguardIgnoreListVendor; -+ } -+ -+ private boolean shouldSend(int acquireInfo, int vendorCode) { -+ if (acquireInfo == FaceManager.FACE_ACQUIRED_VENDOR) { -+ return !Utils.listContains(getAcquireVendorIgnorelist(), vendorCode); -+ } else { -+ return !Utils.listContains(getAcquireIgnorelist(), acquireInfo); -+ } -+ } -+ -+ @Override -+ public void onAcquired(int acquireInfo, int vendorCode) { -+ mLastAcquire = acquireInfo; -+ -+ if (acquireInfo == FaceManager.FACE_ACQUIRED_RECALIBRATE) { -+ BiometricNotificationUtils.showReEnrollmentNotification(getContext()); -+ } -+ @LockoutTracker.LockoutMode final int lockoutMode = -+ getLockoutTracker().getLockoutModeForUser(getTargetUserId()); -+ if (lockoutMode == LockoutTracker.LOCKOUT_NONE) { -+ PerformanceTracker pt = PerformanceTracker.getInstanceForSensorId(getSensorId()); -+ pt.incrementAcquireForUser(getTargetUserId(), isCryptoOperation()); -+ } -+ -+ final boolean shouldSend = shouldSend(acquireInfo, vendorCode); -+ onAcquiredInternal(acquireInfo, vendorCode, shouldSend); -+ } -+} -diff --git a/services/core/java/com/android/server/biometrics/sensors/face/sense/FaceEnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/face/sense/FaceEnrollClient.java -new file mode 100644 -index 00000000..3b4e21f7 ---- /dev/null -+++ b/services/core/java/com/android/server/biometrics/sensors/face/sense/FaceEnrollClient.java -@@ -0,0 +1,138 @@ -+/* -+ * Copyright (C) 2020 The Android Open Source Project -+ * Copyright (C) 2023 Paranoid Android -+ * -+ * 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.server.biometrics.sensors.face.sense; -+ -+import android.annotation.NonNull; -+import android.annotation.Nullable; -+import android.content.Context; -+import android.hardware.biometrics.BiometricFaceConstants; -+import android.hardware.face.Face; -+import android.hardware.face.FaceEnrollOptions; -+import android.hardware.face.FaceManager; -+import android.os.IBinder; -+import android.os.RemoteException; -+import android.util.Slog; -+import android.view.Surface; -+ -+import com.android.internal.R; -+import com.android.server.biometrics.Utils; -+import com.android.server.biometrics.log.BiometricContext; -+import com.android.server.biometrics.log.BiometricLogger; -+import com.android.server.biometrics.sensors.BiometricUtils; -+import com.android.server.biometrics.sensors.ClientMonitorCallback; -+import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; -+import com.android.server.biometrics.sensors.ClientMonitorCompositeCallback; -+import com.android.server.biometrics.sensors.EnrollClient; -+ -+import java.util.ArrayList; -+import java.util.Arrays; -+import java.util.function.Supplier; -+ -+import vendor.aospa.biometrics.face.ISenseService; -+ -+public class FaceEnrollClient extends EnrollClient { -+ -+ private static final String TAG = "FaceEnrollClient"; -+ -+ @NonNull private final int[] mDisabledFeatures; -+ @NonNull private final int[] mEnrollIgnoreList; -+ @NonNull private final int[] mEnrollIgnoreListVendor; -+ -+ FaceEnrollClient(@NonNull Context context, @NonNull Supplier lazyDaemon, -+ @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId, -+ @NonNull byte[] hardwareAuthToken, @NonNull String owner, long requestId, -+ @NonNull BiometricUtils utils, @NonNull int[] disabledFeatures, int timeoutSec, -+ @Nullable Surface previewSurface, int sensorId, -+ @NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext, -+ @NonNull FaceEnrollOptions options) { -+ super(context, lazyDaemon, token, listener, userId, hardwareAuthToken, owner, utils, -+ timeoutSec, sensorId, false /* shouldVibrate */, logger, biometricContext, -+ BiometricFaceConstants.reasonToMetric(options.getEnrollReason())); -+ setRequestId(requestId); -+ mDisabledFeatures = Arrays.copyOf(disabledFeatures, disabledFeatures.length); -+ mEnrollIgnoreList = getContext().getResources() -+ .getIntArray(R.array.config_face_acquire_enroll_ignorelist); -+ mEnrollIgnoreListVendor = getContext().getResources() -+ .getIntArray(R.array.config_face_acquire_vendor_enroll_ignorelist); -+ -+ Slog.w(TAG, "EnrollOptions " -+ + FaceEnrollOptions.enrollReasonToString(options.getEnrollReason())); -+ } -+ -+ @NonNull -+ @Override -+ protected ClientMonitorCallback wrapCallbackForStart(@NonNull ClientMonitorCallback callback) { -+ return new ClientMonitorCompositeCallback( -+ getLogger().getAmbientLightProbe(true /* startWithClient */), callback); -+ } -+ -+ @Override -+ protected boolean hasReachedEnrollmentLimit() { -+ final int limit = getContext().getResources().getInteger( -+ com.android.internal.R.integer.config_faceMaxTemplatesPerUser); -+ final int enrolled = mBiometricUtils.getBiometricsForUser(getContext(), getTargetUserId()) -+ .size(); -+ if (enrolled >= limit) { -+ Slog.w(TAG, "Too many faces registered, user: " + getTargetUserId()); -+ return true; -+ } -+ return false; -+ } -+ -+ @Override -+ public void onAcquired(int acquireInfo, int vendorCode) { -+ final boolean shouldSend; -+ if (acquireInfo == FaceManager.FACE_ACQUIRED_VENDOR) { -+ shouldSend = !Utils.listContains(mEnrollIgnoreListVendor, vendorCode); -+ } else { -+ shouldSend = !Utils.listContains(mEnrollIgnoreList, acquireInfo); -+ } -+ onAcquiredInternal(acquireInfo, vendorCode, shouldSend); -+ } -+ -+ @Override -+ protected void startHalOperation() { -+ final ArrayList token = new ArrayList<>(); -+ for (byte b : mHardwareAuthToken) { -+ token.add(Byte.valueOf(b)); -+ } -+ final ArrayList disabledFeatures = new ArrayList<>(); -+ for (int disabledFeature : mDisabledFeatures) { -+ disabledFeatures.add(disabledFeature); -+ } -+ -+ try { -+ getFreshDaemon().enroll(SenseUtils.toByteArray(token), mTimeoutSec, SenseUtils.toIntArray(disabledFeatures)); -+ } catch (RemoteException e) { -+ Slog.e(TAG, "Remote exception when requesting enroll", e); -+ onError(BiometricFaceConstants.FACE_ERROR_UNABLE_TO_PROCESS, 0 /* vendorCode */); -+ mCallback.onClientFinished(this, false /* success */); -+ } -+ } -+ -+ @Override -+ protected void stopHalOperation() { -+ try { -+ getFreshDaemon().cancel(); -+ } catch (RemoteException e) { -+ Slog.e(TAG, "Remote exception when requesting cancel", e); -+ onError(BiometricFaceConstants.FACE_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */); -+ mCallback.onClientFinished(this, false /* success */); -+ } -+ } -+} -diff --git a/services/core/java/com/android/server/biometrics/sensors/face/sense/FaceGenerateChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/face/sense/FaceGenerateChallengeClient.java -new file mode 100644 -index 00000000..9a9414ff ---- /dev/null -+++ b/services/core/java/com/android/server/biometrics/sensors/face/sense/FaceGenerateChallengeClient.java -@@ -0,0 +1,111 @@ -+/* -+ * Copyright (C) 2020 The Android Open Source Project -+ * Copyright (C) 2023 Paranoid Android -+ * -+ * 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.server.biometrics.sensors.face.sense; -+ -+import android.annotation.NonNull; -+import android.content.Context; -+import android.hardware.face.IFaceServiceReceiver; -+import android.os.IBinder; -+import android.os.RemoteException; -+import android.util.Slog; -+ -+import com.android.internal.util.Preconditions; -+import com.android.server.biometrics.log.BiometricContext; -+import com.android.server.biometrics.log.BiometricLogger; -+import com.android.server.biometrics.sensors.ClientMonitorCallback; -+import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; -+import com.android.server.biometrics.sensors.GenerateChallengeClient; -+ -+import java.util.ArrayList; -+import java.util.List; -+import java.util.function.Supplier; -+ -+import vendor.aospa.biometrics.face.ISenseService; -+ -+public class FaceGenerateChallengeClient extends GenerateChallengeClient { -+ -+ private static final String TAG = "FaceGenerateChallengeClient"; -+ static final int CHALLENGE_TIMEOUT_SEC = 600; // 10 minutes -+ private static final ClientMonitorCallback EMPTY_CALLBACK = new ClientMonitorCallback() { -+ }; -+ -+ private final long mCreatedAt; -+ private List mWaiting; -+ private Long mChallengeResult; -+ -+ FaceGenerateChallengeClient(@NonNull Context context, -+ @NonNull Supplier lazyDaemon, @NonNull IBinder token, -+ @NonNull ClientMonitorCallbackConverter listener, int userId, @NonNull String owner, -+ int sensorId, @NonNull BiometricLogger logger, -+ @NonNull BiometricContext biometricContext, long now) { -+ super(context, lazyDaemon, token, listener, userId, owner, sensorId, logger, -+ biometricContext); -+ mCreatedAt = now; -+ mWaiting = new ArrayList<>(); -+ } -+ -+ @Override -+ protected void startHalOperation() { -+ mChallengeResult = null; -+ try { -+ mChallengeResult = Long.valueOf(getFreshDaemon().generateChallenge(CHALLENGE_TIMEOUT_SEC)); -+ // send the result to the original caller via mCallback and any waiting callers -+ // that called reuseResult -+ sendChallengeResult(getListener(), mCallback); -+ for (IFaceServiceReceiver receiver : mWaiting) { -+ sendChallengeResult(new ClientMonitorCallbackConverter(receiver), EMPTY_CALLBACK); -+ } -+ } catch (RemoteException e) { -+ Slog.e(TAG, "generateChallenge failed", e); -+ mCallback.onClientFinished(this, false /* success */); -+ } finally { -+ mWaiting = null; -+ } -+ } -+ -+ /** @return An arbitrary time value for caching provided to the constructor. */ -+ public long getCreatedAt() { -+ return mCreatedAt; -+ } -+ -+ /** -+ * Reuse the result of this operation when it is available. The receiver will be notified -+ * immediately if a challenge has already been generated. -+ * -+ * @param receiver receiver to be notified of challenge result -+ */ -+ public void reuseResult(@NonNull IFaceServiceReceiver receiver) { -+ if (mWaiting != null) { -+ mWaiting.add(receiver); -+ } else { -+ sendChallengeResult(new ClientMonitorCallbackConverter(receiver), EMPTY_CALLBACK); -+ } -+ } -+ -+ private void sendChallengeResult(@NonNull ClientMonitorCallbackConverter receiver, -+ @NonNull ClientMonitorCallback ownerCallback) { -+ Preconditions.checkState(mChallengeResult != null, "result not available"); -+ try { -+ receiver.onChallengeGenerated(getSensorId(), getTargetUserId(), mChallengeResult); -+ ownerCallback.onClientFinished(this, true /* success */); -+ } catch (RemoteException e) { -+ Slog.e(TAG, "Remote exception", e); -+ ownerCallback.onClientFinished(this, false /* success */); -+ } -+ } -+} -diff --git a/services/core/java/com/android/server/biometrics/sensors/face/sense/FaceGetFeatureClient.java b/services/core/java/com/android/server/biometrics/sensors/face/sense/FaceGetFeatureClient.java -new file mode 100644 -index 00000000..fc3b8223 ---- /dev/null -+++ b/services/core/java/com/android/server/biometrics/sensors/face/sense/FaceGetFeatureClient.java -@@ -0,0 +1,101 @@ -+/* -+ * Copyright (C) 2020 The Android Open Source Project -+ * Copyright (C) 2023 Paranoid Android -+ * -+ * 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.server.biometrics.sensors.face.sense; -+ -+import android.annotation.NonNull; -+import android.annotation.Nullable; -+import android.content.Context; -+import android.os.IBinder; -+import android.os.RemoteException; -+import android.util.Slog; -+ -+import com.android.server.biometrics.BiometricsProto; -+import com.android.server.biometrics.log.BiometricContext; -+import com.android.server.biometrics.log.BiometricLogger; -+import com.android.server.biometrics.sensors.ClientMonitorCallback; -+import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; -+import com.android.server.biometrics.sensors.HalClientMonitor; -+ -+import java.util.function.Supplier; -+ -+import vendor.aospa.biometrics.face.ISenseService; -+ -+public class FaceGetFeatureClient extends HalClientMonitor { -+ -+ private static final String TAG = "FaceGetFeatureClient"; -+ -+ private final int mFeature; -+ private final int mFaceId; -+ private boolean mValue; -+ -+ FaceGetFeatureClient(@NonNull Context context, @NonNull Supplier lazyDaemon, -+ @NonNull IBinder token, @Nullable ClientMonitorCallbackConverter listener, int userId, -+ @NonNull String owner, int sensorId, -+ @NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext, -+ int feature, int faceId) { -+ super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId, -+ logger, biometricContext); -+ mFeature = feature; -+ mFaceId = faceId; -+ } -+ -+ @Override -+ public void unableToStart() { -+ try { -+ if (getListener() != null) { -+ getListener().onFeatureGet(false /* success */, new int[0], new boolean[0]); -+ } -+ } catch (RemoteException e) { -+ Slog.e(TAG, "Unable to send error", e); -+ } -+ } -+ -+ @Override -+ public void start(@NonNull ClientMonitorCallback callback) { -+ super.start(callback); -+ startHalOperation(); -+ } -+ -+ @Override -+ protected void startHalOperation() { -+ try { -+ final boolean result = getFreshDaemon().getFeature(mFeature, mFaceId); -+ int[] features = new int[1]; -+ features[0] = mFeature; -+ boolean[] featureState = {result}; -+ mValue = result; -+ -+ if (getListener() != null) { -+ getListener().onFeatureGet(result, features, featureState); -+ } -+ mCallback.onClientFinished(this, true /* success */); -+ } catch (RemoteException e) { -+ Slog.e(TAG, "Unable to getFeature", e); -+ mCallback.onClientFinished(this, false /* success */); -+ } -+ } -+ -+ boolean getValue() { -+ return mValue; -+ } -+ -+ @Override -+ public int getProtoEnum() { -+ return BiometricsProto.CM_GET_FEATURE; -+ } -+} -diff --git a/services/core/java/com/android/server/biometrics/sensors/face/sense/FaceInternalCleanupClient.java b/services/core/java/com/android/server/biometrics/sensors/face/sense/FaceInternalCleanupClient.java -new file mode 100644 -index 00000000..bd696fd6 ---- /dev/null -+++ b/services/core/java/com/android/server/biometrics/sensors/face/sense/FaceInternalCleanupClient.java -@@ -0,0 +1,70 @@ -+/* -+ * Copyright (C) 2020 The Android Open Source Project -+ * Copyright (C) 2023 Paranoid Android -+ * -+ * 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.server.biometrics.sensors.face.sense; -+ -+import android.annotation.NonNull; -+import android.content.Context; -+import android.hardware.face.Face; -+import android.os.IBinder; -+ -+import com.android.server.biometrics.log.BiometricContext; -+import com.android.server.biometrics.log.BiometricLogger; -+import com.android.server.biometrics.sensors.BiometricUtils; -+import com.android.server.biometrics.sensors.InternalCleanupClient; -+import com.android.server.biometrics.sensors.InternalEnumerateClient; -+import com.android.server.biometrics.sensors.RemovalClient; -+ -+import java.util.List; -+import java.util.Map; -+import java.util.function.Supplier; -+ -+import vendor.aospa.biometrics.face.ISenseService; -+ -+class FaceInternalCleanupClient extends InternalCleanupClient { -+ -+ FaceInternalCleanupClient(@NonNull Context context, -+ @NonNull Supplier lazyDaemon, int userId, @NonNull String owner, -+ int sensorId, @NonNull BiometricLogger logger, -+ @NonNull BiometricContext biometricContext, -+ @NonNull BiometricUtils utils, @NonNull Map authenticatorIds) { -+ super(context, lazyDaemon, userId, owner, sensorId, logger, biometricContext, -+ utils, authenticatorIds); -+ } -+ -+ @Override -+ protected InternalEnumerateClient getEnumerateClient(Context context, -+ Supplier lazyDaemon, IBinder token, int userId, String owner, -+ List enrolledList, BiometricUtils utils, int sensorId, -+ @NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext) { -+ return new FaceInternalEnumerateClient(context, lazyDaemon, token, userId, owner, -+ enrolledList, utils, sensorId, logger, biometricContext); -+ } -+ -+ @Override -+ protected RemovalClient getRemovalClient(Context context, -+ Supplier lazyDaemon, IBinder token, -+ int biometricId, int userId, String owner, BiometricUtils utils, int sensorId, -+ @NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext, -+ Map authenticatorIds) { -+ // Internal remove does not need to send results to anyone. Cleanup (enumerate + remove) -+ // is all done internally. -+ return new FaceRemovalClient(context, lazyDaemon, token, -+ null /* ClientMonitorCallbackConverter */, biometricId, userId, owner, utils, -+ sensorId, logger, biometricContext, authenticatorIds); -+ } -+} -diff --git a/services/core/java/com/android/server/biometrics/sensors/face/sense/FaceInternalEnumerateClient.java b/services/core/java/com/android/server/biometrics/sensors/face/sense/FaceInternalEnumerateClient.java -new file mode 100644 -index 00000000..c9f0a028 ---- /dev/null -+++ b/services/core/java/com/android/server/biometrics/sensors/face/sense/FaceInternalEnumerateClient.java -@@ -0,0 +1,58 @@ -+/* -+ * Copyright (C) 2020 The Android Open Source Project -+ * Copyright (C) 2023 Paranoid Android -+ * -+ * 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.server.biometrics.sensors.face.sense; -+ -+import android.annotation.NonNull; -+import android.content.Context; -+import android.hardware.face.Face; -+import android.os.IBinder; -+import android.os.RemoteException; -+import android.util.Slog; -+ -+import com.android.server.biometrics.log.BiometricContext; -+import com.android.server.biometrics.log.BiometricLogger; -+import com.android.server.biometrics.sensors.BiometricUtils; -+import com.android.server.biometrics.sensors.InternalEnumerateClient; -+ -+import java.util.List; -+import java.util.function.Supplier; -+ -+import vendor.aospa.biometrics.face.ISenseService; -+ -+class FaceInternalEnumerateClient extends InternalEnumerateClient { -+ private static final String TAG = "FaceInternalEnumerateClient"; -+ -+ FaceInternalEnumerateClient(@NonNull Context context, -+ @NonNull Supplier lazyDaemon, @NonNull IBinder token, int userId, -+ @NonNull String owner, @NonNull List enrolledList, -+ @NonNull BiometricUtils utils, int sensorId, -+ @NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext) { -+ super(context, lazyDaemon, token, userId, owner, enrolledList, utils, sensorId, -+ logger, biometricContext); -+ } -+ -+ @Override -+ protected void startHalOperation() { -+ try { -+ getFreshDaemon().enumerate(); -+ } catch (RemoteException e) { -+ Slog.e(TAG, "Remote exception when requesting enumerate", e); -+ mCallback.onClientFinished(this, false /* success */); -+ } -+ } -+} -diff --git a/services/core/java/com/android/server/biometrics/sensors/face/sense/FaceRemovalClient.java b/services/core/java/com/android/server/biometrics/sensors/face/sense/FaceRemovalClient.java -new file mode 100644 -index 00000000..93e72863 ---- /dev/null -+++ b/services/core/java/com/android/server/biometrics/sensors/face/sense/FaceRemovalClient.java -@@ -0,0 +1,63 @@ -+/* -+ * Copyright (C) 2020 The Android Open Source Project -+ * Copyright (C) 2023 Paranoid Android -+ * -+ * 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.server.biometrics.sensors.face.sense; -+ -+import android.annotation.NonNull; -+import android.content.Context; -+import android.hardware.face.Face; -+import android.os.IBinder; -+import android.os.RemoteException; -+import android.util.Slog; -+ -+import com.android.server.biometrics.log.BiometricContext; -+import com.android.server.biometrics.log.BiometricLogger; -+import com.android.server.biometrics.sensors.BiometricUtils; -+import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; -+import com.android.server.biometrics.sensors.RemovalClient; -+ -+import java.util.Map; -+import java.util.function.Supplier; -+ -+import vendor.aospa.biometrics.face.ISenseService; -+ -+class FaceRemovalClient extends RemovalClient { -+ private static final String TAG = "FaceRemovalClient"; -+ -+ private final int mBiometricId; -+ -+ FaceRemovalClient(@NonNull Context context, @NonNull Supplier lazyDaemon, -+ @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, -+ int biometricId, int userId, @NonNull String owner, @NonNull BiometricUtils utils, -+ int sensorId, @NonNull BiometricLogger logger, -+ @NonNull BiometricContext biometricContext, -+ @NonNull Map authenticatorIds) { -+ super(context, lazyDaemon, token, listener, userId, owner, utils, sensorId, logger, -+ biometricContext, authenticatorIds); -+ mBiometricId = biometricId; -+ } -+ -+ @Override -+ protected void startHalOperation() { -+ try { -+ getFreshDaemon().remove(mBiometricId); -+ } catch (RemoteException e) { -+ Slog.e(TAG, "Remote exception when requesting remove", e); -+ mCallback.onClientFinished(this, false /* success */); -+ } -+ } -+} -diff --git a/services/core/java/com/android/server/biometrics/sensors/face/sense/FaceResetLockoutClient.java b/services/core/java/com/android/server/biometrics/sensors/face/sense/FaceResetLockoutClient.java -new file mode 100644 -index 00000000..ab791d0b ---- /dev/null -+++ b/services/core/java/com/android/server/biometrics/sensors/face/sense/FaceResetLockoutClient.java -@@ -0,0 +1,82 @@ -+/* -+ * Copyright (C) 2020 The Android Open Source Project -+ * Copyright (C) 2023 Paranoid Android -+ * -+ * 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.server.biometrics.sensors.face.sense; -+ -+import android.annotation.NonNull; -+import android.content.Context; -+import android.os.RemoteException; -+import android.util.Slog; -+ -+import com.android.server.biometrics.BiometricsProto; -+import com.android.server.biometrics.log.BiometricContext; -+import com.android.server.biometrics.log.BiometricLogger; -+import com.android.server.biometrics.sensors.ClientMonitorCallback; -+import com.android.server.biometrics.sensors.HalClientMonitor; -+ -+import java.util.ArrayList; -+import java.util.function.Supplier; -+ -+import vendor.aospa.biometrics.face.ISenseService; -+ -+public class FaceResetLockoutClient extends HalClientMonitor { -+ -+ private static final String TAG = "FaceResetLockoutClient"; -+ -+ private final byte[] mHardwareAuthToken; -+ -+ FaceResetLockoutClient(@NonNull Context context, -+ @NonNull Supplier lazyDaemon, int userId, String owner, int sensorId, -+ @NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext, -+ @NonNull byte[] hardwareAuthToken) { -+ super(context, lazyDaemon, null /* token */, null /* listener */, userId, owner, -+ 0 /* cookie */, sensorId, logger, biometricContext); -+ -+ mHardwareAuthToken = (byte[]) hardwareAuthToken.clone(); -+ } -+ -+ @Override -+ public void unableToStart() { -+ // Nothing to do here -+ } -+ -+ @Override -+ public void start(@NonNull ClientMonitorCallback callback) { -+ super.start(callback); -+ startHalOperation(); -+ } -+ -+ public boolean interruptsPrecedingClients() { -+ return true; -+ } -+ -+ @Override -+ protected void startHalOperation() { -+ try { -+ getFreshDaemon().resetLockout(mHardwareAuthToken); -+ mCallback.onClientFinished(this, true /* success */); -+ } catch (RemoteException e) { -+ Slog.e(TAG, "Unable to reset lockout", e); -+ mCallback.onClientFinished(this, false /* success */); -+ } -+ } -+ -+ @Override -+ public int getProtoEnum() { -+ return BiometricsProto.CM_RESET_LOCKOUT; -+ } -+} -diff --git a/services/core/java/com/android/server/biometrics/sensors/face/sense/FaceRevokeChallengeClient.java b/services/core/java/com/android/server/biometrics/sensors/face/sense/FaceRevokeChallengeClient.java -new file mode 100644 -index 00000000..7f42df49 ---- /dev/null -+++ b/services/core/java/com/android/server/biometrics/sensors/face/sense/FaceRevokeChallengeClient.java -@@ -0,0 +1,55 @@ -+/* -+ * Copyright (C) 2020 The Android Open Source Project -+ * Copyright (C) 2023 Paranoid Android -+ * -+ * 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.server.biometrics.sensors.face.sense; -+ -+import android.annotation.NonNull; -+import android.content.Context; -+import android.os.IBinder; -+import android.os.RemoteException; -+import android.util.Slog; -+ -+import com.android.server.biometrics.log.BiometricContext; -+import com.android.server.biometrics.log.BiometricLogger; -+import com.android.server.biometrics.sensors.RevokeChallengeClient; -+ -+import java.util.function.Supplier; -+ -+import vendor.aospa.biometrics.face.ISenseService; -+ -+public class FaceRevokeChallengeClient extends RevokeChallengeClient { -+ -+ private static final String TAG = "FaceRevokeChallengeClient"; -+ -+ FaceRevokeChallengeClient(@NonNull Context context, -+ @NonNull Supplier lazyDaemon, @NonNull IBinder token, -+ int userId, @NonNull String owner, int sensorId, -+ @NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext) { -+ super(context, lazyDaemon, token, userId, owner, sensorId, logger, biometricContext); -+ } -+ -+ @Override -+ protected void startHalOperation() { -+ try { -+ getFreshDaemon().revokeChallenge(); -+ mCallback.onClientFinished(this, true /* success */); -+ } catch (RemoteException e) { -+ Slog.e(TAG, "revokeChallenge failed", e); -+ mCallback.onClientFinished(this, false /* success */); -+ } -+ } -+} -diff --git a/services/core/java/com/android/server/biometrics/sensors/face/sense/FaceSetFeatureClient.java b/services/core/java/com/android/server/biometrics/sensors/face/sense/FaceSetFeatureClient.java -new file mode 100644 -index 00000000..65f17d5a ---- /dev/null -+++ b/services/core/java/com/android/server/biometrics/sensors/face/sense/FaceSetFeatureClient.java -@@ -0,0 +1,93 @@ -+/* -+ * Copyright (C) 2020 The Android Open Source Project -+ * Copyright (C) 2023 Paranoid Android -+ * -+ * 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.server.biometrics.sensors.face.sense; -+ -+import android.annotation.NonNull; -+import android.content.Context; -+import android.os.IBinder; -+import android.os.RemoteException; -+import android.util.Slog; -+ -+import com.android.server.biometrics.BiometricsProto; -+import com.android.server.biometrics.log.BiometricContext; -+import com.android.server.biometrics.log.BiometricLogger; -+import com.android.server.biometrics.sensors.ClientMonitorCallback; -+import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; -+import com.android.server.biometrics.sensors.HalClientMonitor; -+ -+import java.util.ArrayList; -+import java.util.function.Supplier; -+ -+import vendor.aospa.biometrics.face.ISenseService; -+ -+public class FaceSetFeatureClient extends HalClientMonitor { -+ -+ private static final String TAG = "FaceSetFeatureClient"; -+ -+ private final int mFeature; -+ private final boolean mEnabled; -+ private final byte[] mHardwareAuthToken; -+ private final int mFaceId; -+ -+ FaceSetFeatureClient(@NonNull Context context, @NonNull Supplier lazyDaemon, -+ @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId, -+ @NonNull String owner, int sensorId, -+ @NonNull BiometricLogger logger, @NonNull BiometricContext biometricContext, -+ int feature, boolean enabled, byte[] hardwareAuthToken, int faceId) { -+ super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId, -+ logger, biometricContext); -+ mFeature = feature; -+ mEnabled = enabled; -+ mFaceId = faceId; -+ -+ mHardwareAuthToken = (byte[]) hardwareAuthToken.clone(); -+ } -+ -+ @Override -+ public void unableToStart() { -+ try { -+ getListener().onFeatureSet(false /* success */, mFeature); -+ } catch (RemoteException e) { -+ Slog.e(TAG, "Unable to send error", e); -+ } -+ } -+ -+ @Override -+ public void start(@NonNull ClientMonitorCallback callback) { -+ super.start(callback); -+ -+ startHalOperation(); -+ } -+ -+ @Override -+ protected void startHalOperation() { -+ try { -+ getFreshDaemon().setFeature(mFeature, mEnabled, mHardwareAuthToken, mFaceId); -+ getListener().onFeatureSet(true, mFeature); -+ mCallback.onClientFinished(this, true /* success */); -+ } catch (RemoteException e) { -+ Slog.e(TAG, "Unable to set feature: " + mFeature + " to enabled: " + mEnabled, e); -+ mCallback.onClientFinished(this, false /* success */); -+ } -+ } -+ -+ @Override -+ public int getProtoEnum() { -+ return BiometricsProto.CM_SET_FEATURE; -+ } -+} -diff --git a/services/core/java/com/android/server/biometrics/sensors/face/sense/FaceUpdateActiveUserClient.java b/services/core/java/com/android/server/biometrics/sensors/face/sense/FaceUpdateActiveUserClient.java -new file mode 100644 -index 00000000..08c07506 ---- /dev/null -+++ b/services/core/java/com/android/server/biometrics/sensors/face/sense/FaceUpdateActiveUserClient.java -@@ -0,0 +1,84 @@ -+/* -+ * Copyright (C) 2020 The Android Open Source Project -+ * Copyright (C) 2023 Paranoid Android -+ * -+ * 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.server.biometrics.sensors.face.sense; -+ -+import android.annotation.NonNull; -+import android.content.Context; -+import android.os.Environment; -+import android.os.RemoteException; -+import android.util.Slog; -+ -+import com.android.server.biometrics.BiometricsProto; -+import com.android.server.biometrics.log.BiometricContext; -+import com.android.server.biometrics.log.BiometricLogger; -+import com.android.server.biometrics.sensors.ClientMonitorCallback; -+import com.android.server.biometrics.sensors.HalClientMonitor; -+ -+import java.io.File; -+import java.util.Map; -+import java.util.function.Supplier; -+ -+import vendor.aospa.biometrics.face.ISenseService; -+ -+public class FaceUpdateActiveUserClient extends HalClientMonitor { -+ private static final String TAG = "FaceUpdateActiveUserClient"; -+ private static final String FACE_DATA_DIR = "facedata"; -+ -+ private final boolean mHasEnrolledBiometrics; -+ @NonNull private final Map mAuthenticatorIds; -+ -+ FaceUpdateActiveUserClient(@NonNull Context context, -+ @NonNull Supplier lazyDaemon, int userId, @NonNull String owner, -+ int sensorId, @NonNull BiometricLogger logger, -+ @NonNull BiometricContext biometricContext, boolean hasEnrolledBiometrics, -+ @NonNull Map authenticatorIds) { -+ super(context, lazyDaemon, null /* token */, null /* listener */, userId, owner, -+ 0 /* cookie */, sensorId, logger, biometricContext); -+ mHasEnrolledBiometrics = hasEnrolledBiometrics; -+ mAuthenticatorIds = authenticatorIds; -+ } -+ -+ @Override -+ public void start(@NonNull ClientMonitorCallback callback) { -+ super.start(callback); -+ startHalOperation(); -+ } -+ -+ @Override -+ public void unableToStart() { -+ // Nothing to do here -+ } -+ -+ @Override -+ protected void startHalOperation() { -+ try { -+ final ISenseService daemon = getFreshDaemon(); -+ mAuthenticatorIds.put(getTargetUserId(), -+ mHasEnrolledBiometrics ? daemon.getAuthenticatorId() : 0L); -+ mCallback.onClientFinished(this, true /* success */); -+ } catch (RemoteException e) { -+ Slog.e(TAG, "Failed to setActiveUser: " + e); -+ mCallback.onClientFinished(this, false /* success */); -+ } -+ } -+ -+ @Override -+ public int getProtoEnum() { -+ return BiometricsProto.CM_UPDATE_ACTIVE_USER; -+ } -+} -diff --git a/services/core/java/com/android/server/biometrics/sensors/face/sense/SenseProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/sense/SenseProvider.java -new file mode 100644 -index 00000000..3f899c69 ---- /dev/null -+++ b/services/core/java/com/android/server/biometrics/sensors/face/sense/SenseProvider.java -@@ -0,0 +1,1110 @@ -+/* -+ * Copyright (C) 2020 The Android Open Source Project -+ * Copyright (C) 2023 Paranoid Android -+ * -+ * 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.server.biometrics.sensors.face.sense; -+ -+import android.annotation.NonNull; -+import android.annotation.Nullable; -+import android.app.ActivityManager; -+import android.app.SynchronousUserSwitchObserver; -+import android.app.UserSwitchObserver; -+import android.content.ComponentName; -+import android.content.Context; -+import android.content.Intent; -+import android.content.ServiceConnection; -+import android.content.pm.PackageManager; -+import android.content.pm.ResolveInfo; -+import android.content.pm.UserInfo; -+import android.hardware.biometrics.BiometricConstants; -+import android.hardware.biometrics.BiometricFaceConstants; -+import android.hardware.biometrics.BiometricsProtoEnums; -+import android.hardware.biometrics.ITestSession; -+import android.hardware.biometrics.ITestSessionCallback; -+import android.hardware.biometrics.face.V1_0.IBiometricsFace; -+import android.hardware.face.Face; -+import android.hardware.face.FaceAuthenticateOptions; -+import android.hardware.face.FaceEnrollOptions; -+import android.hardware.face.FaceSensorPropertiesInternal; -+import android.hardware.face.IFaceServiceReceiver; -+import android.os.Binder; -+import android.os.Handler; -+import android.os.IBinder; -+import android.os.Looper; -+import android.os.RemoteException; -+import android.os.UserHandle; -+import android.os.UserManager; -+import android.provider.Settings; -+import android.util.Slog; -+import android.util.SparseArray; -+import android.util.proto.ProtoOutputStream; -+import android.view.Surface; -+ -+import com.android.internal.annotations.VisibleForTesting; -+import com.android.server.biometrics.AuthenticationStatsBroadcastReceiver; -+import com.android.server.biometrics.AuthenticationStatsCollector; -+import com.android.server.biometrics.SensorServiceStateProto; -+import com.android.server.biometrics.SensorStateProto; -+import com.android.server.biometrics.UserStateProto; -+import com.android.server.biometrics.Utils; -+import com.android.server.biometrics.log.BiometricContext; -+import com.android.server.biometrics.log.BiometricLogger; -+import com.android.server.biometrics.sensors.AcquisitionClient; -+import com.android.server.biometrics.sensors.AuthenticationConsumer; -+import com.android.server.biometrics.sensors.BaseClientMonitor; -+import com.android.server.biometrics.sensors.BiometricNotificationUtils; -+import com.android.server.biometrics.sensors.BiometricScheduler; -+import com.android.server.biometrics.sensors.BiometricStateCallback; -+import com.android.server.biometrics.sensors.ClientMonitorCallback; -+import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; -+import com.android.server.biometrics.sensors.ClientMonitorCompositeCallback; -+import com.android.server.biometrics.sensors.EnumerateConsumer; -+import com.android.server.biometrics.sensors.ErrorConsumer; -+import com.android.server.biometrics.sensors.LockoutResetDispatcher; -+import com.android.server.biometrics.sensors.LockoutTracker; -+import com.android.server.biometrics.sensors.PerformanceTracker; -+import com.android.server.biometrics.sensors.RemovalConsumer; -+import com.android.server.biometrics.sensors.face.FaceUtils; -+import com.android.server.biometrics.sensors.face.LockoutHalImpl; -+import com.android.server.biometrics.sensors.face.ServiceProvider; -+import com.android.server.biometrics.sensors.face.UsageStats; -+ -+import org.json.JSONArray; -+import org.json.JSONException; -+import org.json.JSONObject; -+ -+import java.io.FileDescriptor; -+import java.io.PrintWriter; -+import java.time.Clock; -+import java.util.ArrayList; -+import java.util.HashMap; -+import java.util.List; -+import java.util.Map; -+import java.util.concurrent.atomic.AtomicLong; -+import java.util.function.Supplier; -+ -+import vendor.aospa.biometrics.face.ISenseService; -+import vendor.aospa.biometrics.face.ISenseServiceReceiver; -+ -+public class SenseProvider implements ServiceProvider { -+ -+ private static final String TAG = "SenseProvider"; -+ -+ private static final String BIND_SENSE_ACTION = "co.aospa.sense.BIND"; -+ private static final String PACKAGE_NAME = "co.aospa.sense"; -+ private static final String SERVICE_NAME = "co.aospa.sense.SenseService"; -+ -+ public static final int DEVICE_ID = 1008; -+ private static final int ENROLL_TIMEOUT_SEC = 75; -+ private static final int GENERATE_CHALLENGE_REUSE_INTERVAL_MILLIS = 60 * 1000; -+ private static final int GENERATE_CHALLENGE_COUNTER_TTL_MILLIS = -+ FaceGenerateChallengeClient.CHALLENGE_TIMEOUT_SEC * 1000; -+ @VisibleForTesting -+ public static Clock sSystemClock = Clock.systemUTC(); -+ -+ private boolean mIsBinding; -+ private boolean mTestHalEnabled; -+ -+ @NonNull private final FaceSensorPropertiesInternal mSensorProperties; -+ @NonNull private final BiometricStateCallback mBiometricStateCallback; -+ @NonNull private final Context mContext; -+ @NonNull private final BiometricScheduler mScheduler; -+ @NonNull private final Handler mHandler; -+ @NonNull private final Supplier mLazyDaemon; -+ @NonNull private final LockoutHalImpl mLockoutTracker; -+ @NonNull private final UsageStats mUsageStats; -+ @NonNull private final Map mAuthenticatorIds; -+ @Nullable private IBiometricsFace mDaemon; -+ @NonNull private final HalResultController mHalResultController; -+ @NonNull private final BiometricContext mBiometricContext; -+ @Nullable -+ private AuthenticationStatsCollector mAuthenticationStatsCollector; -+ SparseArray mServices; -+ // for requests that do not use biometric prompt -+ @NonNull private final AtomicLong mRequestCounter = new AtomicLong(0); -+ private int mCurrentUserId = UserHandle.USER_NULL; -+ private final int mSensorId; -+ private final List mGeneratedChallengeCount = new ArrayList<>(); -+ private FaceGenerateChallengeClient mGeneratedChallengeCache = null; -+ -+ private final UserSwitchObserver mUserSwitchObserver = new SynchronousUserSwitchObserver() { -+ @Override -+ public void onUserSwitching(int newUserId) { -+ mCurrentUserId = newUserId; -+ ISenseService service = getDaemon(); -+ if (service == null) { -+ bindService(mCurrentUserId); -+ } -+ } -+ }; -+ -+ public static class HalResultController extends ISenseServiceReceiver.Stub { -+ /** -+ * Interface to sends results to the HalResultController's owner. -+ */ -+ public interface Callback { -+ /** -+ * Invoked when the HAL sends ERROR_HW_UNAVAILABLE. -+ */ -+ void onHardwareUnavailable(); -+ } -+ -+ private final int mSensorId; -+ @NonNull private final Context mContext; -+ @NonNull private final Handler mHandler; -+ @NonNull private final BiometricScheduler mScheduler; -+ @Nullable private Callback mCallback; -+ @NonNull private final LockoutHalImpl mLockoutTracker; -+ @NonNull private final LockoutResetDispatcher mLockoutResetDispatcher; -+ -+ -+ HalResultController(int sensorId, @NonNull Context context, @NonNull Handler handler, -+ @NonNull BiometricScheduler scheduler, @NonNull LockoutHalImpl lockoutTracker, -+ @NonNull LockoutResetDispatcher lockoutResetDispatcher) { -+ mSensorId = sensorId; -+ mContext = context; -+ mHandler = handler; -+ mScheduler = scheduler; -+ mLockoutTracker = lockoutTracker; -+ mLockoutResetDispatcher = lockoutResetDispatcher; -+ } -+ -+ public void setCallback(@Nullable Callback callback) { -+ mCallback = callback; -+ } -+ -+ @Override -+ public void onEnrollResult(int faceId, int userId, int remaining) { -+ mHandler.post(() -> { -+ final CharSequence name = FaceUtils.getLegacyInstance(mSensorId) -+ .getUniqueName(mContext, userId); -+ final Face face = new Face(name, faceId, Long.valueOf(DEVICE_ID)); -+ -+ final BaseClientMonitor client = mScheduler.getCurrentClient(); -+ if (!(client instanceof FaceEnrollClient)) { -+ Slog.e(TAG, "onEnrollResult for non-enroll client: " -+ + Utils.getClientName(client)); -+ return; -+ } -+ -+ final FaceEnrollClient enrollClient = (FaceEnrollClient) client; -+ enrollClient.onEnrollResult(face, remaining); -+ }); -+ } -+ -+ @Override -+ public void onAuthenticated(int faceId, int userId, byte[] token) { -+ mHandler.post(() -> { -+ final BaseClientMonitor client = mScheduler.getCurrentClient(); -+ if (!(client instanceof AuthenticationConsumer)) { -+ Slog.e(TAG, "onAuthenticated for non-authentication consumer: " -+ + Utils.getClientName(client)); -+ return; -+ } -+ -+ final AuthenticationConsumer authenticationConsumer = -+ (AuthenticationConsumer) client; -+ final boolean authenticated = faceId != 0; -+ final Face face = new Face("", faceId, DEVICE_ID); -+ authenticationConsumer.onAuthenticated(face, authenticated, SenseUtils.toByteArrayList(token)); -+ }); -+ } -+ -+ @Override -+ public void onAcquired(int userId, int acquiredInfo, int vendorCode) { -+ mHandler.post(() -> { -+ final BaseClientMonitor client = mScheduler.getCurrentClient(); -+ if (!(client instanceof AcquisitionClient)) { -+ Slog.e(TAG, "onAcquired for non-acquire client: " -+ + Utils.getClientName(client)); -+ return; -+ } -+ -+ final AcquisitionClient acquisitionClient = -+ (AcquisitionClient) client; -+ acquisitionClient.onAcquired(acquiredInfo, vendorCode); -+ }); -+ } -+ -+ @Override -+ public void onError(int error, int vendorCode) { -+ mHandler.post(() -> { -+ final BaseClientMonitor client = mScheduler.getCurrentClient(); -+ Slog.d(TAG, "handleError" -+ + ", client: " + (client != null ? client.getOwnerString() : null) -+ + ", error: " + error -+ + ", vendorCode: " + vendorCode); -+ if (!(client instanceof ErrorConsumer)) { -+ Slog.e(TAG, "onError for non-error consumer: " + Utils.getClientName( -+ client)); -+ return; -+ } -+ -+ final ErrorConsumer errorConsumer = (ErrorConsumer) client; -+ errorConsumer.onError(error, vendorCode); -+ -+ if (error == BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE) { -+ Slog.e(TAG, "Got ERROR_HW_UNAVAILABLE"); -+ if (mCallback != null) { -+ mCallback.onHardwareUnavailable(); -+ } -+ } -+ }); -+ } -+ -+ @Override -+ public void onRemoved(int[] faceIds, int userId) { -+ mHandler.post(() -> { -+ final BaseClientMonitor client = mScheduler.getCurrentClient(); -+ if (!(client instanceof RemovalConsumer)) { -+ Slog.e(TAG, "onRemoved for non-removal consumer: " -+ + Utils.getClientName(client)); -+ return; -+ } -+ -+ final RemovalConsumer removalConsumer = (RemovalConsumer) client; -+ -+ if (faceIds.length > 0) { -+ // Convert to old fingerprint-like behavior, where remove() receives -+ // one removal at a time. This way, remove can share some more common code. -+ for (int i = 0; i < faceIds.length; i++) { -+ final int id = faceIds[i]; -+ final Face face = new Face("", id, Long.valueOf(DEVICE_ID)); -+ final int remaining = (faceIds.length - i) - 1; -+ Slog.d(TAG, "Removed, faceId: " + id + ", remaining: " + remaining); -+ removalConsumer.onRemoved(face, remaining); -+ } -+ } else { -+ removalConsumer.onRemoved(null, 0 /* remaining */); -+ } -+ -+ Settings.Secure.putIntForUser(mContext.getContentResolver(), -+ Settings.Secure.FACE_UNLOCK_RE_ENROLL, 0, UserHandle.USER_CURRENT); -+ }); -+ } -+ -+ @Override -+ public void onEnumerate(int[] faceIds, int userId) { -+ mHandler.post(() -> { -+ final BaseClientMonitor client = mScheduler.getCurrentClient(); -+ if (!(client instanceof EnumerateConsumer)) { -+ Slog.e(TAG, "onEnumerate for non-enumerate consumer: " -+ + Utils.getClientName(client)); -+ return; -+ } -+ -+ final EnumerateConsumer enumerateConsumer = (EnumerateConsumer) client; -+ -+ if (faceIds.length > 0) { -+ // Convert to old fingerprint-like behavior, where enumerate() receives one -+ // template at a time. This way, enumerate can share some more common code. -+ for (int i = 0; i < faceIds.length; i++) { -+ final Face face = new Face("", faceIds[i], Long.valueOf(DEVICE_ID)); -+ enumerateConsumer.onEnumerationResult(face, (faceIds.length - i) - 1); -+ } -+ } else { -+ // For face, the HIDL contract is to receive an empty list when there are no -+ // templates enrolled. Send a null identifier since we don't consume them -+ // anywhere, and send remaining == 0 so this code can be shared with Face@1.1 -+ enumerateConsumer.onEnumerationResult(null /* identifier */, 0); -+ } -+ }); -+ } -+ -+ @Override -+ public void onLockoutChanged(long duration) { -+ mHandler.post(() -> { -+ Slog.d(TAG, "onLockoutChanged: " + duration); -+ final @LockoutTracker.LockoutMode int lockoutMode; -+ if (duration == 0) { -+ lockoutMode = LockoutTracker.LOCKOUT_NONE; -+ } else if (duration == -1 || duration == Long.MAX_VALUE) { -+ lockoutMode = LockoutTracker.LOCKOUT_PERMANENT; -+ } else { -+ lockoutMode = LockoutTracker.LOCKOUT_TIMED; -+ } -+ -+ mLockoutTracker.setCurrentUserLockoutMode(lockoutMode); -+ -+ if (duration == 0) { -+ mLockoutResetDispatcher.notifyLockoutResetCallbacks(mSensorId); -+ } -+ }); -+ } -+ } -+ -+ @VisibleForTesting -+ public SenseProvider(@NonNull Context context, -+ @NonNull BiometricStateCallback biometricStateCallback, -+ @NonNull FaceSensorPropertiesInternal sensorProps, -+ @NonNull LockoutResetDispatcher lockoutResetDispatcher, -+ @NonNull BiometricScheduler scheduler) { -+ mServices = new SparseArray<>(); -+ mIsBinding = false; -+ mSensorProperties = sensorProps; -+ mContext = context; -+ mBiometricStateCallback = biometricStateCallback; -+ mSensorId = sensorProps.sensorId; -+ mScheduler = scheduler; -+ mHandler = new Handler(Looper.getMainLooper()); -+ mBiometricContext = BiometricContext.getInstance(context); -+ mUsageStats = new UsageStats(context); -+ mAuthenticatorIds = new HashMap<>(); -+ mLazyDaemon = SenseProvider.this::getDaemon; -+ mLockoutTracker = new LockoutHalImpl(); -+ mHalResultController = new HalResultController(sensorProps.sensorId, context, mHandler, -+ mScheduler, mLockoutTracker, lockoutResetDispatcher); -+ mHalResultController.setCallback(() -> { -+ mDaemon = null; -+ mCurrentUserId = UserHandle.USER_NULL; -+ }); -+ mCurrentUserId = ActivityManager.getCurrentUser(); -+ -+ AuthenticationStatsBroadcastReceiver mBroadcastReceiver = -+ new AuthenticationStatsBroadcastReceiver( -+ mContext, -+ BiometricsProtoEnums.MODALITY_FACE, -+ (AuthenticationStatsCollector collector) -> { -+ Slog.d(TAG, "Initializing AuthenticationStatsCollector"); -+ mAuthenticationStatsCollector = collector; -+ }); -+ -+ try { -+ ActivityManager.getService().registerUserSwitchObserver(mUserSwitchObserver, TAG); -+ } catch (RemoteException e) { -+ Slog.e(TAG, "Unable to register user switch observer"); -+ } -+ } -+ -+ public SenseProvider(Context context, BiometricStateCallback biometricStateCallback, FaceSensorPropertiesInternal sensorProps, LockoutResetDispatcher lockoutResetDispatcher) { -+ this(context, biometricStateCallback, sensorProps, lockoutResetDispatcher, new BiometricScheduler(0, null)); -+ } -+ -+ private synchronized ISenseService getDaemon() { -+ if (mTestHalEnabled) { -+ final TestHal testHal = new TestHal(mContext, mSensorId); -+ testHal.setCallback(mHalResultController); -+ return testHal; -+ } -+ -+ ISenseService service = getService(mCurrentUserId); -+ if (service == null) { -+ bindService(mCurrentUserId); -+ } -+ return service; -+ } -+ -+ @Override -+ public boolean containsSensor(int sensorId) { -+ return mSensorId == sensorId; -+ } -+ -+ @Override -+ @NonNull -+ public List getSensorProperties() { -+ final List properties = new ArrayList<>(); -+ properties.add(mSensorProperties); -+ return properties; -+ } -+ -+ @NonNull -+ @Override -+ public FaceSensorPropertiesInternal getSensorProperties(int sensorId) { -+ return mSensorProperties; -+ } -+ -+ @Override -+ @NonNull -+ public List getEnrolledFaces(int sensorId, int userId) { -+ return FaceUtils.getLegacyInstance(mSensorId).getBiometricsForUser(mContext, userId); -+ } -+ -+ @Override -+ public boolean hasEnrollments(int sensorId, int userId) { -+ return !getEnrolledFaces(sensorId, userId).isEmpty(); -+ } -+ -+ @Override -+ @LockoutTracker.LockoutMode -+ public int getLockoutModeForUser(int sensorId, int userId) { -+ return mLockoutTracker.getLockoutModeForUser(userId); -+ } -+ -+ @Override -+ public long getAuthenticatorId(int sensorId, int userId) { -+ return mAuthenticatorIds.getOrDefault(userId, 0L); -+ } -+ -+ @Override -+ public boolean isHardwareDetected(int sensorId) { -+ return getDaemon() != null; -+ } -+ -+ private boolean isGeneratedChallengeCacheValid() { -+ return mGeneratedChallengeCache != null -+ && sSystemClock.millis() - mGeneratedChallengeCache.getCreatedAt() -+ < GENERATE_CHALLENGE_REUSE_INTERVAL_MILLIS; -+ } -+ -+ private void incrementChallengeCount() { -+ mGeneratedChallengeCount.add(0, sSystemClock.millis()); -+ } -+ -+ private int decrementChallengeCount() { -+ final long now = sSystemClock.millis(); -+ // ignore values that are old in case generate/revoke calls are not matched -+ // this doesn't ensure revoke if calls are mismatched but it keeps the list from growing -+ mGeneratedChallengeCount.removeIf(x -> now - x > GENERATE_CHALLENGE_COUNTER_TTL_MILLIS); -+ if (!mGeneratedChallengeCount.isEmpty()) { -+ mGeneratedChallengeCount.remove(0); -+ } -+ return mGeneratedChallengeCount.size(); -+ } -+ -+ /** -+ * {@link IBiometricsFace} only supports a single in-flight challenge but there are cases where -+ * two callers both need challenges (e.g. resetLockout right before enrollment). -+ */ -+ @Override -+ public void scheduleGenerateChallenge(int sensorId, int userId, @NonNull IBinder token, -+ @NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName) { -+ mHandler.post(() -> { -+ if (getDaemon() == null) { -+ bindService(mCurrentUserId); -+ try { -+ receiver.onChallengeGenerated(sensorId, userId, 0L); -+ return; -+ } catch (RemoteException e) { -+ e.printStackTrace(); -+ return; -+ } -+ } -+ incrementChallengeCount(); -+ -+ if (isGeneratedChallengeCacheValid()) { -+ Slog.d(TAG, "Current challenge is cached and will be reused"); -+ mGeneratedChallengeCache.reuseResult(receiver); -+ return; -+ } -+ -+ scheduleUpdateActiveUserWithoutHandler(userId); -+ -+ final FaceGenerateChallengeClient client = new FaceGenerateChallengeClient(mContext, -+ mLazyDaemon, token, new ClientMonitorCallbackConverter(receiver), userId, -+ opPackageName, mSensorId, -+ createLogger(BiometricsProtoEnums.ACTION_UNKNOWN, -+ BiometricsProtoEnums.CLIENT_UNKNOWN), -+ mBiometricContext, sSystemClock.millis()); -+ mGeneratedChallengeCache = client; -+ mScheduler.scheduleClientMonitor(client, new ClientMonitorCallback() { -+ @Override -+ public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) { -+ if (client != clientMonitor) { -+ Slog.e(TAG, "scheduleGenerateChallenge onClientStarted, mismatched client." -+ + " Expecting: " + client + ", received: " + clientMonitor); -+ } -+ } -+ }); -+ }); -+ } -+ -+ @Override -+ public void scheduleRevokeChallenge(int sensorId, int userId, @NonNull IBinder token, -+ @NonNull String opPackageName, long challenge) { -+ mHandler.post(() -> { -+ if (getDaemon() == null) { -+ bindService(mCurrentUserId); -+ return; -+ } -+ final boolean shouldRevoke = decrementChallengeCount() == 0; -+ if (!shouldRevoke) { -+ Slog.w(TAG, "scheduleRevokeChallenge skipped - challenge still in use: " -+ + mGeneratedChallengeCount); -+ return; -+ } -+ -+ Slog.d(TAG, "scheduleRevokeChallenge executing - no active clients"); -+ mGeneratedChallengeCache = null; -+ -+ final FaceRevokeChallengeClient client = new FaceRevokeChallengeClient(mContext, -+ mLazyDaemon, token, userId, opPackageName, mSensorId, -+ createLogger(BiometricsProtoEnums.ACTION_UNKNOWN, -+ BiometricsProtoEnums.CLIENT_UNKNOWN), -+ mBiometricContext); -+ mScheduler.scheduleClientMonitor(client, new ClientMonitorCallback() { -+ @Override -+ public void onClientFinished(@NonNull BaseClientMonitor clientMonitor, -+ boolean success) { -+ if (client != clientMonitor) { -+ Slog.e(TAG, "scheduleRevokeChallenge, mismatched client." -+ + "Expecting: " + client + ", received: " + clientMonitor); -+ } -+ } -+ }); -+ }); -+ } -+ -+ @Override -+ public long scheduleEnroll(int sensorId, @NonNull IBinder token, -+ @NonNull byte[] hardwareAuthToken, int userId, @NonNull IFaceServiceReceiver receiver, -+ @NonNull String opPackageName, @NonNull int[] disabledFeatures, -+ @Nullable Surface previewSurface, boolean debugConsent, -+ @NonNull FaceEnrollOptions options) { -+ final long id = mRequestCounter.incrementAndGet(); -+ mHandler.post(() -> { -+ if (getDaemon() == null) { -+ bindService(mCurrentUserId); -+ try { -+ receiver.onError(2, 0); -+ return; -+ } catch (RemoteException e) { -+ e.printStackTrace(); -+ return; -+ } -+ } -+ scheduleUpdateActiveUserWithoutHandler(userId); -+ -+ BiometricNotificationUtils.cancelFaceReEnrollNotification(mContext); -+ -+ final FaceEnrollClient client = new FaceEnrollClient(mContext, mLazyDaemon, token, -+ new ClientMonitorCallbackConverter(receiver), userId, hardwareAuthToken, -+ opPackageName, id, FaceUtils.getLegacyInstance(mSensorId), disabledFeatures, -+ ENROLL_TIMEOUT_SEC, previewSurface, mSensorId, -+ createLogger(BiometricsProtoEnums.ACTION_ENROLL, -+ BiometricsProtoEnums.CLIENT_UNKNOWN), -+ mBiometricContext, options); -+ -+ mScheduler.scheduleClientMonitor(client, new ClientMonitorCallback() { -+ @Override -+ public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) { -+ mBiometricStateCallback.onClientStarted(clientMonitor); -+ } -+ -+ @Override -+ public void onBiometricAction(int action) { -+ mBiometricStateCallback.onBiometricAction(action); -+ } -+ -+ @Override -+ public void onClientFinished(@NonNull BaseClientMonitor clientMonitor, -+ boolean success) { -+ mBiometricStateCallback.onClientFinished(clientMonitor, success); -+ if (success) { -+ // Update authenticatorIds -+ scheduleUpdateActiveUserWithoutHandler(client.getTargetUserId()); -+ } -+ } -+ }); -+ }); -+ return id; -+ } -+ -+ @Override -+ public void cancelEnrollment(int sensorId, @NonNull IBinder token, long requestId) { -+ mHandler.post(() -> mScheduler.cancelEnrollment(token, requestId)); -+ } -+ -+ @Override -+ public long scheduleFaceDetect(@NonNull IBinder token, -+ @NonNull ClientMonitorCallbackConverter callback, -+ @NonNull FaceAuthenticateOptions options, int statsClient) { -+ throw new IllegalStateException("Face detect not supported by IBiometricsFace@1.0. Did you" -+ + "forget to check the supportsFaceDetection flag?"); -+ } -+ -+ @Override -+ public void cancelFaceDetect(int sensorId, @NonNull IBinder token, long requestId) { -+ throw new IllegalStateException("Face detect not supported by IBiometricsFace@1.0. Did you" -+ + "forget to check the supportsFaceDetection flag?"); -+ } -+ -+ @Override -+ public void scheduleAuthenticate(@NonNull IBinder token, long operationId, -+ int cookie, @NonNull ClientMonitorCallbackConverter receiver, -+ @NonNull FaceAuthenticateOptions options, long requestId, boolean restricted, -+ int statsClient, boolean allowBackgroundAuthentication) { -+ mHandler.post(() -> { -+ final int userId = options.getUserId(); -+ if (getDaemon() == null) { -+ bindService(mCurrentUserId); -+ try { -+ receiver.onError(1008, 0, 1, 0); -+ return; -+ } catch (RemoteException e) { -+ e.printStackTrace(); -+ return; -+ } -+ } -+ scheduleUpdateActiveUserWithoutHandler(userId); -+ -+ final boolean isStrongBiometric = Utils.isStrongBiometric(mSensorId); -+ final FaceAuthenticationClient client = new FaceAuthenticationClient(mContext, -+ mLazyDaemon, token, requestId, receiver, operationId, restricted, -+ options, cookie, false /* requireConfirmation */, -+ createLogger(BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient), -+ mBiometricContext, isStrongBiometric, mLockoutTracker, -+ mUsageStats, allowBackgroundAuthentication, -+ Utils.getCurrentStrength(mSensorId)); -+ mScheduler.scheduleClientMonitor(client); -+ }); -+ } -+ -+ @Override -+ public long scheduleAuthenticate(@NonNull IBinder token, long operationId, -+ int cookie, @NonNull ClientMonitorCallbackConverter receiver, -+ @NonNull FaceAuthenticateOptions options, boolean restricted, -+ int statsClient, boolean allowBackgroundAuthentication) { -+ final long id = mRequestCounter.incrementAndGet(); -+ -+ scheduleAuthenticate(token, operationId, cookie, receiver, -+ options, id, restricted, statsClient, allowBackgroundAuthentication); -+ -+ return id; -+ } -+ -+ @Override -+ public void cancelAuthentication(int sensorId, @NonNull IBinder token, long requestId) { -+ mHandler.post(() -> mScheduler.cancelAuthenticationOrDetection(token, requestId)); -+ } -+ -+ @Override -+ public void scheduleRemove(int sensorId, @NonNull IBinder token, int faceId, int userId, -+ @NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName) { -+ mHandler.post(() -> { -+ if (getDaemon() == null) { -+ bindService(mCurrentUserId); -+ try { -+ receiver.onError(1, 0); -+ return; -+ } catch (RemoteException e) { -+ e.printStackTrace(); -+ return; -+ } -+ } -+ scheduleUpdateActiveUserWithoutHandler(userId); -+ -+ final FaceRemovalClient client = new FaceRemovalClient(mContext, mLazyDaemon, token, -+ new ClientMonitorCallbackConverter(receiver), faceId, userId, opPackageName, -+ FaceUtils.getLegacyInstance(mSensorId), mSensorId, -+ createLogger(BiometricsProtoEnums.ACTION_REMOVE, -+ BiometricsProtoEnums.CLIENT_UNKNOWN), -+ mBiometricContext, mAuthenticatorIds); -+ mScheduler.scheduleClientMonitor(client, mBiometricStateCallback); -+ }); -+ } -+ -+ @Override -+ public void scheduleRemoveAll(int sensorId, @NonNull IBinder token, int userId, -+ @NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName) { -+ mHandler.post(() -> { -+ if (getDaemon() == null) { -+ bindService(mCurrentUserId); -+ try { -+ receiver.onError(1, 0); -+ return; -+ } catch (RemoteException e) { -+ e.printStackTrace(); -+ return; -+ } -+ } -+ scheduleUpdateActiveUserWithoutHandler(userId); -+ -+ // For IBiometricsFace@1.0, remove(0) means remove all enrollments -+ final FaceRemovalClient client = new FaceRemovalClient(mContext, mLazyDaemon, token, -+ new ClientMonitorCallbackConverter(receiver), 0 /* faceId */, userId, -+ opPackageName, -+ FaceUtils.getLegacyInstance(mSensorId), mSensorId, -+ createLogger(BiometricsProtoEnums.ACTION_REMOVE, -+ BiometricsProtoEnums.CLIENT_UNKNOWN), -+ mBiometricContext, mAuthenticatorIds); -+ mScheduler.scheduleClientMonitor(client, mBiometricStateCallback); -+ }); -+ } -+ -+ @Override -+ public void scheduleResetLockout(int sensorId, int userId, @NonNull byte[] hardwareAuthToken) { -+ mHandler.post(() -> { -+ if (getDaemon() == null) { -+ bindService(mCurrentUserId); -+ } -+ if (getEnrolledFaces(sensorId, userId).isEmpty()) { -+ Slog.w(TAG, "Ignoring lockout reset, no templates enrolled for user: " + userId); -+ return; -+ } -+ -+ scheduleUpdateActiveUserWithoutHandler(userId); -+ -+ final FaceResetLockoutClient client = new FaceResetLockoutClient(mContext, -+ mLazyDaemon, userId, mContext.getOpPackageName(), mSensorId, -+ createLogger(BiometricsProtoEnums.ACTION_UNKNOWN, -+ BiometricsProtoEnums.CLIENT_UNKNOWN), -+ mBiometricContext, hardwareAuthToken); -+ mScheduler.scheduleClientMonitor(client, mBiometricStateCallback); -+ }); -+ } -+ -+ @Override -+ public void scheduleSetFeature(int sensorId, @NonNull IBinder token, int userId, int feature, -+ boolean enabled, @NonNull byte[] hardwareAuthToken, -+ @NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName) { -+ mHandler.post(() -> { -+ if (getDaemon() == null) { -+ bindService(mCurrentUserId); -+ return; -+ } -+ final List faces = getEnrolledFaces(sensorId, userId); -+ if (faces.isEmpty()) { -+ Slog.w(TAG, "Ignoring setFeature, no templates enrolled for user: " + userId); -+ return; -+ } -+ -+ scheduleUpdateActiveUserWithoutHandler(userId); -+ -+ final int faceId = faces.get(0).getBiometricId(); -+ final FaceSetFeatureClient client = new FaceSetFeatureClient(mContext, -+ mLazyDaemon, token, new ClientMonitorCallbackConverter(receiver), userId, -+ opPackageName, mSensorId, BiometricLogger.ofUnknown(mContext), -+ mBiometricContext, -+ feature, enabled, hardwareAuthToken, faceId); -+ mScheduler.scheduleClientMonitor(client, mBiometricStateCallback); -+ }); -+ } -+ -+ @Override -+ public void scheduleGetFeature(int sensorId, @NonNull IBinder token, int userId, int feature, -+ @Nullable ClientMonitorCallbackConverter listener, @NonNull String opPackageName) { -+ mHandler.post(() -> { -+ if (getDaemon() == null) { -+ bindService(mCurrentUserId); -+ if (listener != null) { -+ try { -+ listener.onError(1008, 0, 1, 0); -+ return; -+ } catch (RemoteException e) { -+ e.printStackTrace(); -+ return; -+ } -+ } -+ return; -+ } -+ final List faces = getEnrolledFaces(sensorId, userId); -+ if (faces.isEmpty()) { -+ Slog.w(TAG, "Ignoring getFeature, no templates enrolled for user: " + userId); -+ return; -+ } -+ -+ scheduleUpdateActiveUserWithoutHandler(userId); -+ -+ final int faceId = faces.get(0).getBiometricId(); -+ final FaceGetFeatureClient client = new FaceGetFeatureClient(mContext, mLazyDaemon, -+ token, listener, userId, opPackageName, mSensorId, -+ BiometricLogger.ofUnknown(mContext), mBiometricContext, -+ feature, faceId); -+ mScheduler.scheduleClientMonitor(client, new ClientMonitorCallback() { -+ @Override -+ public void onClientFinished( -+ @NonNull BaseClientMonitor clientMonitor, boolean success) { -+ if (success && feature == BiometricFaceConstants.FEATURE_REQUIRE_ATTENTION) { -+ final int settingsValue = client.getValue() ? 1 : 0; -+ Slog.d(TAG, "Updating attention value for user: " + userId -+ + " to value: " + settingsValue); -+ Settings.Secure.putIntForUser(mContext.getContentResolver(), -+ Settings.Secure.FACE_UNLOCK_ATTENTION_REQUIRED, -+ settingsValue, userId); -+ } -+ } -+ }); -+ }); -+ } -+ -+ private void scheduleInternalCleanup(int userId, -+ @Nullable ClientMonitorCallback callback) { -+ mHandler.post(() -> { -+ scheduleUpdateActiveUserWithoutHandler(userId); -+ -+ final FaceInternalCleanupClient client = new FaceInternalCleanupClient(mContext, -+ mLazyDaemon, userId, mContext.getOpPackageName(), mSensorId, -+ createLogger(BiometricsProtoEnums.ACTION_ENUMERATE, -+ BiometricsProtoEnums.CLIENT_UNKNOWN), -+ mBiometricContext, -+ FaceUtils.getLegacyInstance(mSensorId), mAuthenticatorIds); -+ mScheduler.scheduleClientMonitor(client, new ClientMonitorCompositeCallback(callback, -+ mBiometricStateCallback)); -+ }); -+ } -+ -+ @Override -+ public void scheduleInternalCleanup(int sensorId, int userId, -+ @Nullable ClientMonitorCallback callback) { -+ scheduleInternalCleanup(userId, mBiometricStateCallback); -+ } -+ -+ @Override -+ public void scheduleInternalCleanup(int sensorId, int userId, -+ @Nullable ClientMonitorCallback callback, boolean favorHalEnrollments) { -+ scheduleInternalCleanup(userId, mBiometricStateCallback); -+ } -+ -+ @Override -+ public void startPreparedClient(int sensorId, int cookie) { -+ mHandler.post(() -> { -+ mScheduler.startPreparedClient(cookie); -+ }); -+ } -+ -+ @Override -+ public void dumpProtoState(int sensorId, ProtoOutputStream proto, -+ boolean clearSchedulerBuffer) { -+ final long sensorToken = proto.start(SensorServiceStateProto.SENSOR_STATES); -+ -+ proto.write(SensorStateProto.SENSOR_ID, mSensorProperties.sensorId); -+ proto.write(SensorStateProto.MODALITY, SensorStateProto.FACE); -+ proto.write(SensorStateProto.CURRENT_STRENGTH, -+ Utils.getCurrentStrength(mSensorProperties.sensorId)); -+ proto.write(SensorStateProto.SCHEDULER, mScheduler.dumpProtoState(clearSchedulerBuffer)); -+ -+ for (UserInfo user : UserManager.get(mContext).getUsers()) { -+ final int userId = user.getUserHandle().getIdentifier(); -+ -+ final long userToken = proto.start(SensorStateProto.USER_STATES); -+ proto.write(UserStateProto.USER_ID, userId); -+ proto.write(UserStateProto.NUM_ENROLLED, FaceUtils.getLegacyInstance(mSensorId) -+ .getBiometricsForUser(mContext, userId).size()); -+ proto.end(userToken); -+ } -+ -+ proto.write(SensorStateProto.RESET_LOCKOUT_REQUIRES_HARDWARE_AUTH_TOKEN, -+ mSensorProperties.resetLockoutRequiresHardwareAuthToken); -+ proto.write(SensorStateProto.RESET_LOCKOUT_REQUIRES_CHALLENGE, -+ mSensorProperties.resetLockoutRequiresChallenge); -+ -+ proto.end(sensorToken); -+ } -+ -+ @Override -+ public void dumpProtoMetrics(int sensorId, FileDescriptor fd) { -+ } -+ -+ @Override -+ public void dumpInternal(int sensorId, PrintWriter pw) { -+ PerformanceTracker performanceTracker = -+ PerformanceTracker.getInstanceForSensorId(mSensorId); -+ -+ JSONObject dump = new JSONObject(); -+ try { -+ dump.put("service", TAG); -+ -+ JSONArray sets = new JSONArray(); -+ for (UserInfo user : UserManager.get(mContext).getUsers()) { -+ final int userId = user.getUserHandle().getIdentifier(); -+ final int c = FaceUtils.getLegacyInstance(mSensorId) -+ .getBiometricsForUser(mContext, userId).size(); -+ JSONObject set = new JSONObject(); -+ set.put("id", userId); -+ set.put("count", c); -+ set.put("accept", performanceTracker.getAcceptForUser(userId)); -+ set.put("reject", performanceTracker.getRejectForUser(userId)); -+ set.put("acquire", performanceTracker.getAcquireForUser(userId)); -+ set.put("lockout", performanceTracker.getTimedLockoutForUser(userId)); -+ set.put("permanentLockout", performanceTracker.getPermanentLockoutForUser(userId)); -+ // cryptoStats measures statistics about secure face transactions -+ // (e.g. to unlock password storage, make secure purchases, etc.) -+ set.put("acceptCrypto", performanceTracker.getAcceptCryptoForUser(userId)); -+ set.put("rejectCrypto", performanceTracker.getRejectCryptoForUser(userId)); -+ set.put("acquireCrypto", performanceTracker.getAcquireCryptoForUser(userId)); -+ sets.put(set); -+ } -+ -+ dump.put("prints", sets); -+ } catch (JSONException e) { -+ Slog.e(TAG, "dump formatting failure", e); -+ } -+ pw.println(dump); -+ pw.println("HAL deaths since last reboot: " + performanceTracker.getHALDeathCount()); -+ -+ mScheduler.dump(pw); -+ mUsageStats.print(pw); -+ } -+ -+ private void scheduleLoadAuthenticatorIds() { -+ // Note that this can be performed on the scheduler (as opposed to being done immediately -+ // when the HAL is (re)loaded, since -+ // 1) If this is truly the first time it's being performed (e.g. system has just started), -+ // this will be run very early and way before any applications need to generate keys. -+ // 2) If this is being performed to refresh the authenticatorIds (e.g. HAL crashed and has -+ // just been reloaded), the framework already has a cache of the authenticatorIds. This -+ // is safe because authenticatorIds only change when A) new template has been enrolled, -+ // or B) all templates are removed. -+ mHandler.post(() -> { -+ for (UserInfo user : UserManager.get(mContext).getAliveUsers()) { -+ final int targetUserId = user.id; -+ if (!mAuthenticatorIds.containsKey(targetUserId)) { -+ scheduleUpdateActiveUserWithoutHandler(targetUserId); -+ } -+ } -+ }); -+ } -+ -+ /** -+ * Schedules the {@link FaceUpdateActiveUserClient} without posting the work onto the handler. -+ * Many/most APIs are user-specific. However, the HAL requires explicit "setActiveUser" -+ * invocation prior to authenticate/enroll/etc. Thus, internally we usually want to schedule -+ * this operation on the same lambda/runnable as those operations so that the ordering is -+ * correct. -+ */ -+ private void scheduleUpdateActiveUserWithoutHandler(int targetUserId) { -+ final boolean hasEnrolled = !getEnrolledFaces(mSensorId, targetUserId).isEmpty(); -+ final FaceUpdateActiveUserClient client = new FaceUpdateActiveUserClient(mContext, -+ mLazyDaemon, targetUserId, mContext.getOpPackageName(), mSensorId, -+ createLogger(BiometricsProtoEnums.ACTION_UNKNOWN, -+ BiometricsProtoEnums.CLIENT_UNKNOWN), -+ mBiometricContext, hasEnrolled, mAuthenticatorIds); -+ mScheduler.scheduleClientMonitor(client, new ClientMonitorCallback() { -+ @Override -+ public void onClientFinished(@NonNull BaseClientMonitor clientMonitor, -+ boolean success) { -+ if (success) { -+ mCurrentUserId = targetUserId; -+ } else { -+ Slog.w(TAG, "Failed to change user, still: " + mCurrentUserId); -+ } -+ } -+ }); -+ } -+ -+ public class SenseServiceConnection implements ServiceConnection { -+ private int mUserId; -+ -+ public SenseServiceConnection(int userId) { -+ mUserId = userId; -+ } -+ -+ @Override -+ public void onServiceConnected(ComponentName className, IBinder service) { -+ Slog.d(TAG, "Service connected : " + mUserId); -+ ISenseService senseService = ISenseService.Stub.asInterface(service); -+ if (senseService != null) { -+ synchronized (mServices) { -+ try { -+ senseService.setCallback(mHalResultController); -+ mServices.put(mUserId, senseService); -+ mHandler.post(() -> { -+ updateSchedule(); -+ }); -+ } catch (RemoteException e) { -+ e.printStackTrace(); -+ } -+ mIsBinding = false; -+ } -+ } -+ } -+ -+ public void updateSchedule() { -+ scheduleInternalCleanup(mUserId, null); -+ scheduleGetFeature(mSensorId, new Binder(), mUserId, 1, null, mContext.getOpPackageName()); -+ } -+ -+ @Override -+ public void onServiceDisconnected(ComponentName className) { -+ Slog.d(TAG, "Service disconnected : " + mUserId); -+ mServices.remove(mUserId); -+ mIsBinding = false; -+ if (mUserId == mCurrentUserId) { -+ mHandler.post(() -> { -+ updateResetSchedule(); -+ }); -+ } -+ mContext.unbindService(this); -+ } -+ -+ public void updateResetSchedule() { -+ BaseClientMonitor client = mScheduler.getCurrentClient(); -+ if (client != null && (client instanceof ErrorConsumer)) { -+ ErrorConsumer errorConsumer = (ErrorConsumer) client; -+ errorConsumer.onError(5, 0); -+ } -+ bindService(mUserId); -+ mScheduler.recordCrashState(); -+ mScheduler.reset(); -+ } -+ } -+ -+ private boolean isServiceEnabled() { -+ PackageManager pm = mContext.getPackageManager(); -+ Intent intent = new Intent(BIND_SENSE_ACTION); -+ intent.setClassName(PACKAGE_NAME, SERVICE_NAME); -+ ResolveInfo info = pm.resolveService(intent, 131072); -+ if (info != null && info.serviceInfo.isEnabled()) { -+ return true; -+ } -+ return false; -+ } -+ -+ private ISenseService getService(int userId) { -+ if (userId == -10000) { -+ scheduleUpdateActiveUserWithoutHandler(ActivityManager.getCurrentUser()); -+ } -+ return mServices.get(mCurrentUserId); -+ } -+ -+ public boolean bindService(int userId) { -+ Slog.d(TAG, "bindService " + userId); -+ if (!isServiceEnabled()) { -+ Slog.d(TAG, "Service disabled"); -+ return false; -+ } else if (mIsBinding) { -+ Slog.d(TAG, "Service is binding"); -+ return true; -+ } else { -+ if (userId != -10000 && getService(userId) == null) { -+ try { -+ Intent intent = new Intent(BIND_SENSE_ACTION); -+ intent.setClassName(PACKAGE_NAME, SERVICE_NAME); -+ boolean result = mContext.bindServiceAsUser(intent, new SenseServiceConnection(userId), 1, UserHandle.of(userId)); -+ if (result) { -+ mIsBinding = true; -+ } -+ return result; -+ } catch (SecurityException e) { -+ e.printStackTrace(); -+ } -+ } -+ return false; -+ } -+ } -+ -+ private BiometricLogger createLogger(int statsAction, int statsClient) { -+ return new BiometricLogger(mContext, BiometricsProtoEnums.MODALITY_FACE, -+ statsAction, statsClient, mAuthenticationStatsCollector); -+ } -+ -+ /** -+ * Sends a debug message to the HAL with the provided FileDescriptor and arguments. -+ */ -+ public void dumpHal(int sensorId, @NonNull FileDescriptor fd, @NonNull String[] args) { } -+ -+ void setTestHalEnabled(boolean enabled) { -+ mTestHalEnabled = enabled; -+ } -+ -+ @NonNull -+ @Override -+ public ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback, -+ @NonNull String opPackageName) { -+ return new BiometricTestSessionImpl(mContext, mSensorId, callback, this, -+ mHalResultController); -+ } -+} -diff --git a/services/core/java/com/android/server/biometrics/sensors/face/sense/SenseUtils.java b/services/core/java/com/android/server/biometrics/sensors/face/sense/SenseUtils.java -new file mode 100644 -index 00000000..9e49fa1e ---- /dev/null -+++ b/services/core/java/com/android/server/biometrics/sensors/face/sense/SenseUtils.java -@@ -0,0 +1,61 @@ -+/* -+ * Copyright (C) 2023 Paranoid Android -+ * -+ * 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.server.biometrics.sensors.face.sense; -+ -+import android.os.SystemProperties; -+ -+import java.util.ArrayList; -+ -+public class SenseUtils { -+ -+ public static boolean canUseProvider() { -+ return SystemProperties.getBoolean("ro.face.sense_service", false); -+ } -+ -+ public static ArrayList toByteArrayList(byte[] in) { -+ if (in == null) { -+ return null; -+ } -+ ArrayList out = new ArrayList<>(in.length); -+ for (byte c : in) { -+ out.add(Byte.valueOf(c)); -+ } -+ return out; -+ } -+ -+ public static byte[] toByteArray(ArrayList in) { -+ if (in == null) { -+ return null; -+ } -+ byte[] out = new byte[in.size()]; -+ for (int i = 0; i < in.size(); i++) { -+ out[i] = in.get(i).byteValue(); -+ } -+ return out; -+ } -+ -+ public static int[] toIntArray(ArrayList in) { -+ if (in == null) { -+ return null; -+ } -+ int[] out = new int[in.size()]; -+ for (int i = 0; i < in.size(); i++) { -+ out[i] = in.get(i).intValue(); -+ } -+ return out; -+ } -+} -\ No newline at end of file -diff --git a/services/core/java/com/android/server/biometrics/sensors/face/sense/TestHal.java b/services/core/java/com/android/server/biometrics/sensors/face/sense/TestHal.java -new file mode 100644 -index 00000000..0499bc51 ---- /dev/null -+++ b/services/core/java/com/android/server/biometrics/sensors/face/sense/TestHal.java -@@ -0,0 +1,144 @@ -+/* -+ * Copyright (C) 2020 The Android Open Source Project -+ * Copyright (C) 2023 Paranoid Android -+ * -+ * 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.server.biometrics.sensors.face.sense; -+ -+import android.annotation.NonNull; -+import android.annotation.Nullable; -+import android.content.Context; -+import android.hardware.biometrics.face.V1_0.FaceError; -+import android.hardware.biometrics.face.V1_0.OptionalBool; -+import android.hardware.biometrics.face.V1_0.OptionalUint64; -+import android.hardware.biometrics.face.V1_0.Status; -+import android.hardware.face.Face; -+import android.os.RemoteException; -+import android.util.Slog; -+ -+import com.android.server.biometrics.sensors.face.FaceUtils; -+ -+import java.util.ArrayList; -+import java.util.Collections; -+import java.util.List; -+ -+import vendor.aospa.biometrics.face.ISenseService; -+import vendor.aospa.biometrics.face.ISenseServiceReceiver; -+ -+public class TestHal extends ISenseService.Stub { -+ private static final String TAG = "face.hidl.TestHal"; -+ -+ @NonNull -+ private final Context mContext; -+ private final int mSensorId; -+ -+ @Nullable -+ private ISenseServiceReceiver mCallback; -+ private int mUserId; -+ -+ TestHal(@NonNull Context context, int sensorId) { -+ mContext = context; -+ mSensorId = sensorId; -+ } -+ -+ @Override -+ public void setCallback(ISenseServiceReceiver clientCallback) { -+ mCallback = clientCallback; -+ } -+ -+ @Override -+ public long generateChallenge(int challengeTimeoutSec) { -+ Slog.w(TAG, "generateChallenge"); -+ return 0L; -+ } -+ -+ @Override -+ public void enroll(byte[] hat, int timeoutSec, int[] disabledFeatures) { -+ Slog.w(TAG, "enroll"); -+ } -+ -+ @Override -+ public int revokeChallenge() { -+ return 0; -+ } -+ -+ @Override -+ public void setFeature(int feature, boolean enabled, byte[] token, int faceId) { } -+ -+ @Override -+ public boolean getFeature(int feature, int faceId) { -+ return false; -+ } -+ -+ @Override -+ public int getFeatureCount() throws RemoteException { -+ return 0; -+ } -+ -+ @Override -+ public int getAuthenticatorId() { -+ return 0; -+ } -+ -+ @Override -+ public void cancel() throws RemoteException { -+ if (mCallback != null) { -+ mCallback.onError(0 /* deviceId */, 0 /* vendorCode */); -+ } -+ } -+ -+ @Override -+ public int enumerate() throws RemoteException { -+ Slog.w(TAG, "enumerate"); -+ if (mCallback != null) { -+ mCallback.onEnumerate(new int[0], 0 /* userId */); -+ } -+ return 0; -+ } -+ -+ @Override -+ public void remove(int faceId) throws RemoteException { -+ Slog.w(TAG, "remove"); -+ if (mCallback != null) { -+ if (faceId == 0) { -+ List faces = FaceUtils.getInstance(mSensorId).getBiometricsForUser(mContext, mUserId); -+ if (faces.size() <= 0) { -+ mCallback.onError(6, 0); -+ return; -+ } -+ int[] faceIds = new int[faces.size()]; -+ for (int i = 0; i < faces.size(); i++) { -+ Face face = faces.get(i); -+ faceIds[i] = face.getBiometricId(); -+ } -+ -+ mCallback.onRemoved(faceIds, mUserId); -+ } else { -+ mCallback.onRemoved(new int[]{faceId}, mUserId); -+ } -+ } -+ } -+ -+ @Override -+ public void authenticate(long operationId) { -+ Slog.w(TAG, "authenticate"); -+ } -+ -+ @Override -+ public void resetLockout(byte[] hat) { -+ Slog.w(TAG, "resetLockout"); -+ } -+ -+} --- -2.34.1 - diff --git a/patches/personal/platform_frameworks_base/0010-SystemUI-Correctly-monet-theme-the-new-volume-panel.patch b/patches/personal/platform_frameworks_base/0010-SystemUI-Correctly-monet-theme-the-new-volume-panel.patch deleted file mode 100644 index d35a0f4a..00000000 --- a/patches/personal/platform_frameworks_base/0010-SystemUI-Correctly-monet-theme-the-new-volume-panel.patch +++ /dev/null @@ -1,85 +0,0 @@ -From 117afed975ebfb70a916c3f5c8a64da0eaa2f208 Mon Sep 17 00:00:00 2001 -From: Ido Ben-Hur -Date: Wed, 19 Jun 2024 20:44:06 +0300 -Subject: [PATCH 10/10] SystemUI: Correctly monet theme the new volume panel - ---- - .../src/com/android/compose/PlatformSlider.kt | 16 ++++++++-------- - .../button/ui/composable/ButtonComponent.kt | 6 +++--- - .../ui/composable/ToggleButtonComponent.kt | 8 ++++---- - 3 files changed, 15 insertions(+), 15 deletions(-) - -diff --git a/packages/SystemUI/compose/core/src/com/android/compose/PlatformSlider.kt b/packages/SystemUI/compose/core/src/com/android/compose/PlatformSlider.kt -index ef15c846..5ed83805 100644 ---- a/packages/SystemUI/compose/core/src/com/android/compose/PlatformSlider.kt -+++ b/packages/SystemUI/compose/core/src/com/android/compose/PlatformSlider.kt -@@ -300,10 +300,10 @@ object PlatformSliderDefaults { - @Composable - private fun lightThemePlatformSliderColors() = - PlatformSliderColors( -- trackColor = MaterialTheme.colorScheme.tertiaryContainer, -- indicatorColor = LocalAndroidColorScheme.current.tertiaryFixedDim, -- iconColor = MaterialTheme.colorScheme.onTertiaryContainer, -- labelColor = MaterialTheme.colorScheme.onTertiaryContainer, -+ trackColor = MaterialTheme.colorScheme.primaryContainer, -+ indicatorColor = LocalAndroidColorScheme.current.primaryFixedDim, -+ iconColor = MaterialTheme.colorScheme.onPrimaryContainer, -+ labelColor = MaterialTheme.colorScheme.onPrimaryContainer, - disabledTrackColor = MaterialTheme.colorScheme.surfaceContainerHighest, - disabledIndicatorColor = MaterialTheme.colorScheme.surfaceContainerHighest, - disabledIconColor = MaterialTheme.colorScheme.outline, -@@ -314,10 +314,10 @@ private fun lightThemePlatformSliderColors() = - @Composable - private fun darkThemePlatformSliderColors() = - PlatformSliderColors( -- trackColor = MaterialTheme.colorScheme.onTertiary, -- indicatorColor = LocalAndroidColorScheme.current.onTertiaryFixedVariant, -- iconColor = MaterialTheme.colorScheme.onTertiaryContainer, -- labelColor = MaterialTheme.colorScheme.onTertiaryContainer, -+ trackColor = MaterialTheme.colorScheme.onPrimary, -+ indicatorColor = LocalAndroidColorScheme.current.onPrimaryFixedVariant, -+ iconColor = MaterialTheme.colorScheme.onPrimaryContainer, -+ labelColor = MaterialTheme.colorScheme.onPrimaryContainer, - disabledTrackColor = MaterialTheme.colorScheme.surfaceContainerHighest, - disabledIndicatorColor = MaterialTheme.colorScheme.surfaceContainerHighest, - disabledIconColor = MaterialTheme.colorScheme.outline, -diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ButtonComponent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ButtonComponent.kt -index 5f7bd47f..68ff0a88 100644 ---- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ButtonComponent.kt -+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ButtonComponent.kt -@@ -60,10 +60,10 @@ class ButtonComponent( - ) { - Expandable( - modifier = Modifier.height(64.dp).fillMaxWidth(), -- color = MaterialTheme.colorScheme.primaryContainer, -+ color = MaterialTheme.colorScheme.primary, - shape = RoundedCornerShape(28.dp), -- contentColor = MaterialTheme.colorScheme.onPrimaryContainer, -- borderStroke = BorderStroke(8.dp, MaterialTheme.colorScheme.surface), -+ contentColor = MaterialTheme.colorScheme.onPrimary, -+ borderStroke = BorderStroke(8.dp, MaterialTheme.colorScheme.primary), - onClick = onClick, - ) { - Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { -diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt -index dfee684c..8991426e 100644 ---- a/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt -+++ b/packages/SystemUI/compose/features/src/com/android/systemui/volume/panel/component/button/ui/composable/ToggleButtonComponent.kt -@@ -62,10 +62,10 @@ class ToggleButtonComponent( - shape = RoundedCornerShape(28.dp), - colors = - IconButtonDefaults.outlinedIconToggleButtonColors( -- containerColor = MaterialTheme.colorScheme.surface, -- contentColor = MaterialTheme.colorScheme.onSurfaceVariant, -- checkedContainerColor = MaterialTheme.colorScheme.primaryContainer, -- checkedContentColor = MaterialTheme.colorScheme.onPrimaryContainer, -+ containerColor = MaterialTheme.colorScheme.primary, -+ contentColor = MaterialTheme.colorScheme.onPrimary, -+ checkedContainerColor = MaterialTheme.colorScheme.secondary, -+ checkedContentColor = MaterialTheme.colorScheme.onSecondary, - ), - border = BorderStroke(8.dp, MaterialTheme.colorScheme.surface), - ) { --- -2.34.1 - diff --git a/patches/personal/platform_packages_apps_Settings/0001-feat-Add-Lockscreen-Weather-with-OmniJaws-2-2.patch b/patches/personal/platform_packages_apps_Settings/0001-feat-Add-Lockscreen-Weather-with-OmniJaws-2-2.patch index 6c64aa1e..672945aa 100644 --- a/patches/personal/platform_packages_apps_Settings/0001-feat-Add-Lockscreen-Weather-with-OmniJaws-2-2.patch +++ b/patches/personal/platform_packages_apps_Settings/0001-feat-Add-Lockscreen-Weather-with-OmniJaws-2-2.patch @@ -1,7 +1,7 @@ -From 40d398a214a711e648a10cb7310ce3f17606675b Mon Sep 17 00:00:00 2001 +From 2bf82017a069a3f440919cbc1dee8d24911d3d13 Mon Sep 17 00:00:00 2001 From: Alberto Ponces Date: Sun, 12 Nov 2023 11:24:17 +0000 -Subject: [PATCH 1/2] feat: Add Lockscreen Weather with OmniJaws (2/2) +Subject: [PATCH] feat: Add Lockscreen Weather with OmniJaws (2/2) Based on OmniROM's implementation, updated by @maxwen and adapted by @neobuddy89. @@ -9,106 +9,55 @@ Change-Id: I138c0dc94f08142f6614659037a501d6ae8909b1 Co-authored-by: maxwen Co-authored-by: Pranav Vashi --- - res/values/attrs.xml | 13 + - res/values/strings.xml | 10 + - res/xml/security_lockscreen_settings.xml | 25 + - .../custom/preference/ConstraintsHelper.java | 430 ++++++++++++++++++ - .../SelfRemovingSwitchPreference.java | 104 +++++ - .../SystemSettingSwitchPreference.java | 53 +++ - .../security/LockscreenDashboardFragment.java | 26 ++ - 7 files changed, 661 insertions(+) - create mode 100644 src/com/android/settings/custom/preference/ConstraintsHelper.java - create mode 100644 src/com/android/settings/custom/preference/SelfRemovingSwitchPreference.java - create mode 100644 src/com/android/settings/custom/preference/SystemSettingSwitchPreference.java + res/values/strings.xml | 5 ++ + res/xml/security_lockscreen_settings.xml | 7 ++ + ...LockScreenWeatherPreferenceController.java | 79 +++++++++++++++++++ + .../security/LockscreenDashboardFragment.java | 25 +++++- + 4 files changed, 115 insertions(+), 1 deletion(-) + create mode 100644 src/com/android/settings/omnijaws/LockScreenWeatherPreferenceController.java -diff --git a/res/values/attrs.xml b/res/values/attrs.xml -index 200253a..5289822 100644 ---- a/res/values/attrs.xml -+++ b/res/values/attrs.xml -@@ -203,4 +203,17 @@ - - - -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ - diff --git a/res/values/strings.xml b/res/values/strings.xml -index 0622daa..48d68fc 100644 +index f92fd2a..39e8134 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml -@@ -12056,6 +12056,16 @@ +@@ -12411,6 +12411,11 @@ %1$s, %2$s + -+ Weather -+ Weather settings -+ Setup icon pack and weather service -+ Weather condition -+ Display current weather condition and temperature ++ Weather update ++ Display current weather update + Requires weather service to be enabled -+ Weather location -+ Display current weather location + diff --git a/res/xml/security_lockscreen_settings.xml b/res/xml/security_lockscreen_settings.xml -index cb1ce44..b968908 100644 +index 15d5303..3712b41 100644 --- a/res/xml/security_lockscreen_settings.xml +++ b/res/xml/security_lockscreen_settings.xml -@@ -79,6 +79,31 @@ +@@ -81,6 +81,13 @@ android:title="@string/lockscreen_double_line_clock_setting_toggle" android:summary="@string/lockscreen_double_line_clock_summary" settings:controller="com.android.settings.display.LockscreenClockPreferenceController" /> + -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ ++ + = 0 && (tv.data & mask) == 0)) { -+ return false; -+ } -+ } -+ } -+ -+ // Check a system service -+ String rService = a.getString( -+ R.styleable.lineage_SelfRemovingPreference_requiresService); -+ if (rService != null) { -+ boolean negated = isNegated(rService); -+ if (negated) { -+ rService = rService.substring(1); -+ } -+ IBinder value = ServiceManager.getService(rService); -+ boolean available = value != null; -+ if (available == negated) { -+ return false; -+ } -+ } -+ } finally { -+ a.recycle(); -+ } -+ -+ return true; -+ } -+ -+ /** -+ * Returns whether the device supports a particular feature -+ */ -+ public static boolean hasSystemFeature(Context context, String feature) { -+ return context.getPackageManager().hasSystemFeature(feature); -+ } -+ -+ /** -+ * Returns whether the device is voice-capable (meaning, it is also a phone). -+ */ -+ public static boolean isVoiceCapable(Context context) { -+ TelephonyManager telephony = -+ (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); -+ return telephony != null && telephony.isVoiceCapable(); -+ } -+ -+ /** -+ * Checks if a package is installed. Set the ignoreState argument to true if you don't -+ * care if the package is enabled/disabled. -+ */ -+ public static boolean isPackageInstalled(Context context, String pkg, boolean ignoreState) { -+ if (pkg != null) { -+ try { -+ PackageInfo pi = context.getPackageManager().getPackageInfo(pkg, 0); -+ if (!pi.applicationInfo.enabled && !ignoreState) { -+ return false; -+ } -+ } catch (PackageManager.NameNotFoundException e) { -+ return false; -+ } -+ } -+ -+ return true; -+ } -+ -+ /** -+ * Checks if a package is available to handle the given action. -+ */ -+ public static boolean resolveIntent(Context context, Intent intent) { -+ if (DEBUG) Log.d(TAG, "resolveIntent " + Objects.toString(intent)); -+ // check whether the target handler exist in system -+ PackageManager pm = context.getPackageManager(); -+ List results = pm.queryIntentActivitiesAsUser(intent, -+ PackageManager.MATCH_SYSTEM_ONLY, -+ UserHandle.myUserId()); -+ for (ResolveInfo resolveInfo : results) { -+ // check is it installed in system.img, exclude the application -+ // installed by user -+ if (DEBUG) Log.d(TAG, "resolveInfo: " + Objects.toString(resolveInfo)); -+ if ((resolveInfo.activityInfo.applicationInfo.flags & -+ ApplicationInfo.FLAG_SYSTEM) != 0) { -+ return true; -+ } -+ } -+ return false; -+ } -+ -+ public static boolean resolveIntent(Context context, String action) { -+ return resolveIntent(context, new Intent(action)); -+ } -+ -+ public static int getAttr(Context context, int attr, int fallbackAttr) { -+ TypedValue value = new TypedValue(); -+ context.getTheme().resolveAttribute(attr, value, true); -+ if (value.resourceId != 0) { -+ return attr; -+ } -+ return fallbackAttr; -+ } -+ -+ public void onAttached() { -+ checkIntent(); -+ -+ if (isAvailable() && mReplacesKey != null) { -+ Graveyard.get(mContext).addTombstones(mReplacesKey); -+ } -+ -+ Graveyard.get(mContext).summonReaper(mPref.getPreferenceManager()); -+ } -+ -+ public void onBindViewHolder(PreferenceViewHolder holder) { -+ if (!isAvailable()) { -+ return; -+ } -+ -+ if (mSummaryMinLines > 0) { -+ TextView textView = (TextView) holder.itemView.findViewById(android.R.id.summary); -+ if (textView != null) { -+ textView.setMinLines(mSummaryMinLines); -+ } -+ } -+ } -+ -+ /** -+ * If we want to keep this at the preference level vs the fragment level, we need to -+ * collate all the preferences that need to be removed when attached to the -+ * hierarchy, then purge them all when loading is complete. The Graveyard keeps track -+ * of this, and will reap the dead when onAttached is called. -+ */ -+ private static class Graveyard { -+ -+ private Set mDeathRow = new ArraySet<>(); -+ -+ private static Graveyard sInstance; -+ -+ private final Context mContext; -+ -+ private Graveyard(Context context) { -+ mContext = context; -+ } -+ -+ public synchronized static Graveyard get(Context context) { -+ if (sInstance == null) { -+ sInstance = new Graveyard(context); -+ } -+ return sInstance; -+ } -+ -+ public void addTombstone(String pref) { -+ synchronized (mDeathRow) { -+ mDeathRow.add(pref); -+ } -+ } -+ -+ public void addTombstones(String[] prefs) { -+ synchronized (mDeathRow) { -+ mDeathRow.addAll(Arrays.asList(prefs)); -+ } -+ } -+ -+ private PreferenceGroup getParent(Preference p1, Preference p2) { -+ return getParent(p1.getPreferenceManager().getPreferenceScreen(), p2); -+ } -+ -+ private PreferenceGroup getParent(PreferenceGroup root, Preference preference) { -+ for (int i = 0; i < root.getPreferenceCount(); i++) { -+ Preference p = root.getPreference(i); -+ if (p == preference) -+ return root; -+ if (PreferenceGroup.class.isInstance(p)) { -+ PreferenceGroup parent = getParent((PreferenceGroup) p, preference); -+ if (parent != null) -+ return parent; -+ } -+ } -+ return null; -+ } -+ -+ private void hidePreference(PreferenceManager mgr, Preference pref) { -+ pref.setVisible(false); -+ // Hide the group if nothing is visible -+ final PreferenceGroup group = getParent(pref, pref); -+ boolean allHidden = true; -+ for (int i = 0; i < group.getPreferenceCount(); i++) { -+ if (group.getPreference(i).isVisible()) { -+ allHidden = false; -+ break; -+ } -+ } -+ if (allHidden) { -+ group.setVisible(false); -+ } -+ } -+ -+ public void summonReaper(PreferenceManager mgr) { -+ synchronized (mDeathRow) { -+ Set notReadyForReap = new ArraySet<>(); -+ for (String dead : mDeathRow) { -+ Preference deadPref = mgr.findPreference(dead); -+ if (deadPref != null) { -+ hidePreference(mgr, deadPref); -+ } else { -+ notReadyForReap.add(dead); -+ } -+ } -+ mDeathRow = notReadyForReap; -+ } -+ } -+ } -+} -diff --git a/src/com/android/settings/custom/preference/SelfRemovingSwitchPreference.java b/src/com/android/settings/custom/preference/SelfRemovingSwitchPreference.java -new file mode 100644 -index 0000000..5ba32e5 ---- /dev/null -+++ b/src/com/android/settings/custom/preference/SelfRemovingSwitchPreference.java -@@ -0,0 +1,104 @@ -+/* -+ * Copyright (C) 2016 The CyanogenMod Project -+ * Copyright (C) 2018 The LineageOS Project -+ * -+ * Licensed under the Apache License, Version 2.0 (the "License"); -+ * you may not use this file except in compliance with the License. -+ * You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+package com.android.settings.custom.preference; + -+import android.content.Context; -+import android.util.AttributeSet; ++import com.android.settings.core.TogglePreferenceController; + -+import androidx.preference.PreferenceDataStore; -+import androidx.preference.PreferenceViewHolder; -+import androidx.preference.SwitchPreference; ++/** Controller to update the lockscreen weather widget state */ ++public class LockScreenWeatherPreferenceController extends TogglePreferenceController { ++ private static final int ON = 1; ++ private static final int OFF = 0; ++ private static final int DEFAULT = OFF; + -+/** -+ * A SwitchPreference which can automatically remove itself from the hierarchy -+ * based on constraints set in XML. -+ */ -+public abstract class SelfRemovingSwitchPreference extends SwitchPreference { -+ -+ private final ConstraintsHelper mConstraints; -+ -+ public SelfRemovingSwitchPreference(Context context, AttributeSet attrs, int defStyle) { -+ super(context, attrs, defStyle); -+ mConstraints = new ConstraintsHelper(context, attrs, this); -+ setPreferenceDataStore(new DataStore()); -+ } -+ -+ public SelfRemovingSwitchPreference(Context context, AttributeSet attrs) { -+ super(context, attrs); -+ mConstraints = new ConstraintsHelper(context, attrs, this); -+ setPreferenceDataStore(new DataStore()); -+ } -+ -+ public SelfRemovingSwitchPreference(Context context) { -+ super(context); -+ mConstraints = new ConstraintsHelper(context, null, this); -+ setPreferenceDataStore(new DataStore()); ++ public LockScreenWeatherPreferenceController(Context context, String preferenceKey) { ++ super(context, preferenceKey); + } + + @Override -+ public void onAttached() { -+ super.onAttached(); -+ mConstraints.onAttached(); ++ public int getAvailabilityStatus() { ++ return AVAILABLE; + } + + @Override -+ public void onBindViewHolder(PreferenceViewHolder holder) { -+ super.onBindViewHolder(holder); -+ mConstraints.onBindViewHolder(holder); ++ public boolean isChecked() { ++ return Settings.System.getIntForUser(mContext.getContentResolver(), ++ Settings.System.LOCKSCREEN_WEATHER_ENABLED, DEFAULT, UserHandle.USER_CURRENT) == ON; + } + -+ public void setAvailable(boolean available) { -+ mConstraints.setAvailable(available); -+ } -+ -+ public boolean isAvailable() { -+ return mConstraints.isAvailable(); -+ } -+ -+ protected abstract boolean isPersisted(); -+ protected abstract void putBoolean(String key, boolean value); -+ protected abstract boolean getBoolean(String key, boolean defaultValue); -+ + @Override -+ protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) { -+ final boolean checked; -+ if (!restorePersistedValue || !isPersisted()) { -+ boolean defValue = defaultValue == null ? false : (boolean) defaultValue; -+ checked = getBoolean(getKey(), defValue); -+ if (shouldPersist()) { -+ persistBoolean(checked); -+ } -+ } else { -+ // Note: the default is not used because to have got here -+ // isPersisted() must be true. -+ checked = getBoolean(getKey(), false /* not used */); -+ } -+ setChecked(checked); -+ } -+ -+ private class DataStore extends PreferenceDataStore { -+ @Override -+ public void putBoolean(String key, boolean value) { -+ SelfRemovingSwitchPreference.this.putBoolean(key, value); -+ } -+ -+ @Override -+ public boolean getBoolean(String key, boolean defaultValue) { -+ return SelfRemovingSwitchPreference.this.getBoolean(key, defaultValue); -+ } -+ } -+} -diff --git a/src/com/android/settings/custom/preference/SystemSettingSwitchPreference.java b/src/com/android/settings/custom/preference/SystemSettingSwitchPreference.java -new file mode 100644 -index 0000000..b6a4654 ---- /dev/null -+++ b/src/com/android/settings/custom/preference/SystemSettingSwitchPreference.java -@@ -0,0 +1,53 @@ -+/* -+ * Copyright (C) 2013 The CyanogenMod Project -+ * Copyright (C) 2018 The LineageOS Project -+ * -+ * Licensed under the Apache License, Version 2.0 (the "License"); -+ * you may not use this file except in compliance with the License. -+ * You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+package com.android.settings.custom.preference; -+ -+import android.content.Context; -+import android.provider.Settings; -+import android.os.UserHandle; -+import android.util.AttributeSet; -+ -+public class SystemSettingSwitchPreference extends SelfRemovingSwitchPreference { -+ -+ public SystemSettingSwitchPreference(Context context, AttributeSet attrs, int defStyle) { -+ super(context, attrs, defStyle); -+ } -+ -+ public SystemSettingSwitchPreference(Context context, AttributeSet attrs) { -+ super(context, attrs); -+ } -+ -+ public SystemSettingSwitchPreference(Context context) { -+ super(context); ++ public boolean setChecked(boolean isChecked) { ++ return Settings.System.putIntForUser(mContext.getContentResolver(), ++ Settings.System.LOCKSCREEN_WEATHER_ENABLED, isChecked ? ON : OFF, UserHandle.USER_CURRENT); + } + + @Override -+ protected boolean isPersisted() { -+ return Settings.System.getString(getContext().getContentResolver(), getKey()) != null; ++ public boolean handlePreferenceTreeClick(Preference preference) { ++ if (getPreferenceKey().equals(preference.getKey())) { ++ Intent intent = new Intent(Intent.ACTION_MAIN); ++ intent.setClassName(SERVICE_PACKAGE, SERVICE_PACKAGE + ".SettingsActivity"); ++ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); ++ mContext.startActivity(intent); ++ return true; ++ } ++ return super.handlePreferenceTreeClick(preference); + } + + @Override -+ protected void putBoolean(String key, boolean value) { -+ Settings.System.putIntForUser(getContext().getContentResolver(), key, value ? 1 : 0, UserHandle.USER_CURRENT); ++ public final boolean isSliceable() { ++ return false; + } + + @Override -+ protected boolean getBoolean(String key, boolean defaultValue) { -+ return Settings.System.getIntForUser(getContext().getContentResolver(), -+ key, defaultValue ? 1 : 0, UserHandle.USER_CURRENT) != 0; ++ public int getSliceHighlightMenuRes() { ++ // not needed since it's not sliceable ++ return NO_RES; + } +} diff --git a/src/com/android/settings/security/LockscreenDashboardFragment.java b/src/com/android/settings/security/LockscreenDashboardFragment.java -index 2e4a1f2..320ce9f 100644 +index 2e4a1f2..499fc2c 100644 --- a/src/com/android/settings/security/LockscreenDashboardFragment.java +++ b/src/com/android/settings/security/LockscreenDashboardFragment.java -@@ -30,6 +30,9 @@ import android.os.Looper; - import android.provider.Settings; +@@ -31,6 +31,8 @@ import android.provider.Settings; import androidx.annotation.VisibleForTesting; -+import androidx.preference.Preference; -+ -+import com.android.internal.util.crdroid.OmniJawsClient; ++import com.android.internal.util.crdroid.OmniJawsClient; ++ import com.android.settings.R; import com.android.settings.dashboard.DashboardFragment; -@@ -70,12 +73,16 @@ public class LockscreenDashboardFragment extends DashboardFragment + import com.android.settings.display.AmbientDisplayAlwaysOnPreferenceController; +@@ -40,6 +42,7 @@ import com.android.settings.gestures.PickupGesturePreferenceController; + import com.android.settings.notification.LockScreenNotificationPreferenceController; + import com.android.settings.search.BaseSearchIndexProvider; + import com.android.settings.security.screenlock.LockScreenPreferenceController; ++import com.android.settingslib.PrimarySwitchPreference; + import com.android.settingslib.core.AbstractPreferenceController; + import com.android.settingslib.core.lifecycle.Lifecycle; + import com.android.settingslib.search.SearchIndexable; +@@ -69,13 +72,16 @@ public class LockscreenDashboardFragment extends DashboardFragment + @VisibleForTesting static final String KEY_ADD_USER_FROM_LOCK_SCREEN = "security_lockscreen_add_users_when_locked"; - -+ private static final String KEY_WEATHER = "lockscreen_weather_enabled"; +- ++ static final String KEY_WEATHER = "lockscreen_weather_enabled"; private AmbientDisplayConfiguration mConfig; private OwnerInfoPreferenceController mOwnerInfoPreferenceController; @VisibleForTesting ContentObserver mControlsContentObserver; -+ private Preference mWeather; ++ private PrimarySwitchPreference mWeather; + private OmniJawsClient mWeatherClient; + @Override public int getMetricsCategory() { return SettingsEnums.SETTINGS_LOCK_SCREEN_PREFERENCES; -@@ -94,6 +101,10 @@ public class LockscreenDashboardFragment extends DashboardFragment +@@ -94,6 +100,9 @@ public class LockscreenDashboardFragment extends DashboardFragment R.string.locked_work_profile_notification_title); replaceEnterpriseStringTitle("security_setting_lock_screen_notif_work_header", WORK_PROFILE_NOTIFICATIONS_SECTION_HEADER, R.string.profile_section_header); -+ -+ mWeather = (Preference) findPreference(KEY_WEATHER); ++ mWeather = (PrimarySwitchPreference) findPreference(KEY_WEATHER); + mWeatherClient = new OmniJawsClient(getContext()); + updateWeatherSettings(); } @Override -@@ -193,4 +204,19 @@ public class LockscreenDashboardFragment extends DashboardFragment +@@ -193,4 +202,18 @@ public class LockscreenDashboardFragment extends DashboardFragment .isAvailable(); } }; + + private void updateWeatherSettings() { + if (mWeatherClient == null || mWeather == null) return; -+ + boolean weatherEnabled = mWeatherClient.isOmniJawsEnabled(); -+ mWeather.setEnabled(weatherEnabled); ++ mWeather.setSwitchEnabled(weatherEnabled); + mWeather.setSummary(weatherEnabled ? R.string.lockscreen_weather_summary : + R.string.lockscreen_weather_enabled_info); + } diff --git a/patches/personal/platform_packages_apps_Settings/0002-feat-Add-Face-Unlock-with-ParanoidSense-2-2.patch b/patches/personal/platform_packages_apps_Settings/0002-feat-Add-Face-Unlock-with-ParanoidSense-2-2.patch deleted file mode 100644 index 4b724848..00000000 --- a/patches/personal/platform_packages_apps_Settings/0002-feat-Add-Face-Unlock-with-ParanoidSense-2-2.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 56b2c38a22681db6ad2caec74506beb0cff4856d Mon Sep 17 00:00:00 2001 -From: Chris Crump -Date: Fri, 17 Mar 2023 20:48:46 +0100 -Subject: [PATCH 2/2] feat: Add Face Unlock with ParanoidSense (2/2) - -Based on AOSPA's implementation and adapted by @ghostrider-reborn - -Co-authored-by: Chris Crump -Co-authored-by: Adithya R -Change-Id: I05fa784d9f7f978be9f5944900a97ad7df19f59e ---- - AndroidManifest.xml | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/AndroidManifest.xml b/AndroidManifest.xml -index aed51f3..52eeeab 100644 ---- a/AndroidManifest.xml -+++ b/AndroidManifest.xml -@@ -2663,7 +2663,7 @@ - android:screenOrientation="portrait"/> - - - - +Date: Fri, 13 Sep 2024 23:25:45 -0400 +Subject: [PATCH 1/3] OmniJaws: Fix required libraries between the build system + and the manifest + +https: //android.googlesource.com/platform/build/+/main/Changes.md#dexpreopt-starts-enforcing-checks-for-java-modules +Change-Id: Ic01b3b2ff8878af5a7b7a0599de4e1a3120dc2ca +--- + Android.bp | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/Android.bp b/Android.bp +index c2be871..8c5c81a 100644 +--- a/Android.bp ++++ b/Android.bp +@@ -8,6 +8,10 @@ android_app { + "org.apache.http.legacy", + ], + ++ optional_uses_libs: [ ++ "org.apache.http.legacy", ++ ], ++ + srcs: [ + "app/src/main/**/*.java", + ], +-- +2.34.1 + diff --git a/patches/personal/platform_packages_services_OmniJaws/0002-OmniJaws-Add-missing-background-location-permission-.patch b/patches/personal/platform_packages_services_OmniJaws/0002-OmniJaws-Add-missing-background-location-permission-.patch new file mode 100644 index 00000000..ebbb29fd --- /dev/null +++ b/patches/personal/platform_packages_services_OmniJaws/0002-OmniJaws-Add-missing-background-location-permission-.patch @@ -0,0 +1,47 @@ +From 0af65aaf4bd507b52bef9dfc06189f3a0090c51c Mon Sep 17 00:00:00 2001 +From: Alberto Ponces +Date: Mon, 23 Sep 2024 15:50:58 +0100 +Subject: [PATCH 2/3] OmniJaws: Add missing background location permission + request and validation + +--- + .../org/omnirom/omnijaws/SettingsFragment.java | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/app/src/main/java/org/omnirom/omnijaws/SettingsFragment.java b/app/src/main/java/org/omnirom/omnijaws/SettingsFragment.java +index b1dd733..dadcc2c 100644 +--- a/app/src/main/java/org/omnirom/omnijaws/SettingsFragment.java ++++ b/app/src/main/java/org/omnirom/omnijaws/SettingsFragment.java +@@ -114,6 +114,17 @@ public class SettingsFragment extends PreferenceFragmentCompat implements OnPref + } + ); + ++ ActivityResultLauncher requestBackgroundPermissionLauncher = ++ registerForActivityResult(new ActivityResultContracts ++ .RequestMultiplePermissions(), result -> { ++ Boolean backgroundLocationGranted = result.getOrDefault( ++ Manifest.permission.ACCESS_BACKGROUND_LOCATION, false); ++ if ((backgroundLocationGranted != null && backgroundLocationGranted)) { ++ forceRefreshWeatherSettings(); ++ } ++ } ++ ); ++ + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + mPrefs = PreferenceManager.getDefaultSharedPreferences(getContext()); +@@ -323,6 +334,11 @@ public class SettingsFragment extends PreferenceFragmentCompat implements OnPref + Manifest.permission.ACCESS_FINE_LOCATION, + Manifest.permission.ACCESS_COARSE_LOCATION + }); ++ } else if (getContext().checkSelfPermission(Manifest.permission.ACCESS_BACKGROUND_LOCATION) ++ != PackageManager.PERMISSION_GRANTED) { ++ requestBackgroundPermissionLauncher.launch(new String[]{ ++ Manifest.permission.ACCESS_BACKGROUND_LOCATION ++ }); + } else { + if (force) { + forceRefreshWeatherSettings(); +-- +2.34.1 + diff --git a/patches/personal/platform_packages_services_OmniJaws/0003-OmniJaws-update-default-provider-to-MET-Norway.patch b/patches/personal/platform_packages_services_OmniJaws/0003-OmniJaws-update-default-provider-to-MET-Norway.patch new file mode 100644 index 00000000..f73c4499 --- /dev/null +++ b/patches/personal/platform_packages_services_OmniJaws/0003-OmniJaws-update-default-provider-to-MET-Norway.patch @@ -0,0 +1,51 @@ +From 792b17f180e40713f348148a7853ef69c82d7019 Mon Sep 17 00:00:00 2001 +From: Alberto Ponces +Date: Mon, 9 Sep 2024 11:45:41 +0100 +Subject: [PATCH 3/3] OmniJaws: update default provider to MET Norway + +--- + app/src/main/java/org/omnirom/omnijaws/Config.java | 4 ++-- + app/src/main/java/org/omnirom/omnijaws/SettingsFragment.java | 4 ++-- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/app/src/main/java/org/omnirom/omnijaws/Config.java b/app/src/main/java/org/omnirom/omnijaws/Config.java +index b09c750..b9f9bb2 100644 +--- a/app/src/main/java/org/omnirom/omnijaws/Config.java ++++ b/app/src/main/java/org/omnirom/omnijaws/Config.java +@@ -44,7 +44,7 @@ public static AbstractWeatherProvider getProvider(Context context) { + SharedPreferences prefs = PreferenceManager + .getDefaultSharedPreferences(context); + +- switch (prefs.getString(PREF_KEY_PROVIDER, "0")) { ++ switch (prefs.getString(PREF_KEY_PROVIDER, "1")) { + case "0": + return new OpenWeatherMapProvider(context); + case "1": +@@ -58,7 +58,7 @@ public static String getProviderId(Context context) { + SharedPreferences prefs = PreferenceManager + .getDefaultSharedPreferences(context); + +- String provider = prefs.getString(PREF_KEY_PROVIDER, "0"); ++ String provider = prefs.getString(PREF_KEY_PROVIDER, "1"); + switch (provider) { + case "0": + return "OpenWeatherMap"; +diff --git a/app/src/main/java/org/omnirom/omnijaws/SettingsFragment.java b/app/src/main/java/org/omnirom/omnijaws/SettingsFragment.java +index b1dd733..b7f9925 100644 +--- a/app/src/main/java/org/omnirom/omnijaws/SettingsFragment.java ++++ b/app/src/main/java/org/omnirom/omnijaws/SettingsFragment.java +@@ -134,9 +134,9 @@ private void doLoadPreferences() { + + mProvider = (ListPreference) findPreference(Config.PREF_KEY_PROVIDER); + mProvider.setOnPreferenceChangeListener(this); +- int idx = mProvider.findIndexOfValue(mPrefs.getString(Config.PREF_KEY_PROVIDER, "0")); ++ int idx = mProvider.findIndexOfValue(mPrefs.getString(Config.PREF_KEY_PROVIDER, "1")); + if (idx == -1) { +- idx = 0; ++ idx = 1; + } + mProvider.setValueIndex(idx); + mProvider.setSummary(mProvider.getEntries()[idx]); +-- +2.34.1 + diff --git a/sync.sh b/sync.sh index e6b7e307..85ef3d4a 100755 --- a/sync.sh +++ b/sync.sh @@ -2,7 +2,7 @@ echo echo "--------------------------------------" -echo " AOSP 14.0 Syncbot " +echo " AOSP 15.0 Syncbot " echo " by " echo " ponces " echo "--------------------------------------" @@ -11,7 +11,7 @@ echo set -e BL=$PWD/treble_aosp -TD="android-14.0" +TD="android-15.0" initRepos() { echo "--> Getting latest upstream version"