[2/2] OmniControl: Add custom fingerprint icon support
OmniGears: custom fingerprint icon [2/2]
* Create a new entry in the dashbord
* Also move the haptic feedback toggle
[micky387]
* Remove Fp vibration toggle
[maxwen] new API to copy the image into SystemUI settings
To prevent any grant uri issues do it like wallpaper and
copy the image to a file SystemUI can read without issues
Change-Id: I77b2962c5f525d0828193b5871f197bed74becc6
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index fb7f4a8..61a9130 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
- <bytecodeTargetLevel target="11" />
+ <bytecodeTargetLevel target="1.8" />
</component>
</project>
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 95858db..050a237 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -76,7 +76,7 @@
</map>
</option>
</component>
- <component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
+ <component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
diff --git a/Android.bp b/Android.bp
index 405998a..27154ab 100644
--- a/Android.bp
+++ b/Android.bp
@@ -23,7 +23,8 @@
"androidx.recyclerview_recyclerview",
"OmniLib",
"OmniLibCore",
- "OmniPreferenceTheme"
+ "OmniPreferenceTheme",
+ "SystemUISharedLib",
],
kotlincflags: ["-Xjvm-default=enable"],
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index cc17c54..a4ce9b7 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -17,6 +17,8 @@
<uses-permission
android:name="android.permission.CHANGE_OVERLAY_PACKAGES"
tools:ignore="ProtectedPermissions" />
+ <uses-permission
+ android:name="android.permission.READ_MEDIA_IMAGES" />
<application
android:name=".App"
diff --git a/app/src/main/java/org/omnirom/control/FingerprintSettingsFragment.kt b/app/src/main/java/org/omnirom/control/FingerprintSettingsFragment.kt
new file mode 100644
index 0000000..ab573d0
--- /dev/null
+++ b/app/src/main/java/org/omnirom/control/FingerprintSettingsFragment.kt
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2023 The OmniROM Project
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+package org.omnirom.control
+
+import android.app.Activity
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.ServiceConnection
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
+import android.graphics.Color
+import android.graphics.drawable.BitmapDrawable
+import android.graphics.drawable.ColorDrawable
+import android.net.Uri
+import android.os.Bundle
+import android.os.IBinder
+import android.provider.MediaStore
+import android.provider.Settings
+import android.text.TextUtils
+import android.util.Log
+import androidx.activity.result.contract.ActivityResultContract
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.preference.Preference
+import androidx.preference.SwitchPreference
+import com.android.systemui.shared.omni.IOmniSystemUiProxy
+import java.io.File
+import java.io.FileOutputStream
+
+
+class FingerprintSettingsFragment : AbstractSettingsFragment() {
+ private val TAG = "FingerprintSettingsFragment"
+ private val FINGERPRINT_CUSTOM_ICON_SELECT = "custom_fingerprint_icon_select"
+ private val FINGERPRINT_CUSTOM_ICON_ENABLE = "custom_fingerprint_icon_enable"
+ private val UFPSIMAGE_FILE_NAME = "ufpsImage"
+
+ class PickSinglePhotoContract : ActivityResultContract<Void?, Uri?>() {
+ override fun createIntent(context: Context, input: Void?): Intent {
+ return Intent(Intent(MediaStore.ACTION_PICK_IMAGES)).apply { type = "image/*" }
+ }
+
+ override fun parseResult(resultCode: Int, intent: Intent?): Uri? {
+ return intent.takeIf { resultCode == Activity.RESULT_OK }?.data
+ }
+ }
+
+ private val pickImage =
+ registerForActivityResult(PickSinglePhotoContract()) { uri ->
+ Log.d(TAG, "pickImage uri = " + uri)
+ if (uri != null) {
+ // TODO we should do some check if the image is even a useful one eg size
+ try {
+ requireContext().contentResolver.openInputStream(uri).use { inputStream ->
+ val bitmap = BitmapFactory.decodeStream(inputStream)
+ systemUIProxy?.setUfpsImageBitmap(bitmap)
+ savePickerIcon(bitmap)
+ }
+
+ Settings.System.putString(
+ requireContext().contentResolver,
+ Settings.System.OMNI_CUSTOM_FP_ICON_UPDATE,
+ System.currentTimeMillis().toString()
+ )
+ } catch (e: Exception) {
+ Log.d(TAG, "pickImage", e);
+ }
+ }
+ }
+
+
+ private val mSystemUIProxyService: ServiceConnection = object : ServiceConnection {
+ override fun onServiceConnected(name: ComponentName, service: IBinder) {
+ Log.d(
+ TAG,
+ "onServiceConnected $name $service"
+ )
+ systemUIProxy = IOmniSystemUiProxy.Stub.asInterface(service)
+ }
+
+ override fun onServiceDisconnected(name: ComponentName) {
+ Log.d(TAG, "onServiceDisconnected $name")
+ }
+ }
+
+ private var mSystemUIProxyBound = false
+ private var systemUIProxy: IOmniSystemUiProxy? = null
+ private var mFilePicker: Preference? = null
+ private var mEnableCustom: SwitchPreference? = null
+
+
+ private fun bindSystemUIProxyService() {
+ if (!mSystemUIProxyBound) {
+ Log.d(TAG, "bindSystemUIProxyService")
+ val serviceIntent = Intent("android.intent.action.OMNI_SYSTEMUI_SERVICE")
+ .setPackage("com.android.systemui")
+ try {
+ mSystemUIProxyBound = requireActivity().bindService(
+ serviceIntent,
+ mSystemUIProxyService,
+ Context.BIND_AUTO_CREATE
+ )
+ } catch (e: SecurityException) {
+ Log.e(
+ TAG,
+ "Unable to bind because of security error",
+ e
+ )
+ }
+ }
+ }
+
+ private fun unbindSystemUIProxyService() {
+ if (mSystemUIProxyBound) {
+ Log.d(TAG, "unbindSystemUIProxyService")
+ requireActivity().unbindService(mSystemUIProxyService)
+ mSystemUIProxyBound = false
+ }
+ }
+
+ override fun getFragmentTitle(): String {
+ return getString(R.string.fprint_title)
+ }
+
+ override fun getFragmentSummary(): String {
+ return getString(R.string.fprint_summary)
+ }
+
+ override fun getFragmentIcon(): Int {
+ return R.drawable.ic_settings_fingerprint
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ unbindSystemUIProxyService()
+ }
+
+ override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
+ setPreferencesFromResource(R.xml.fingerprint_preferences, rootKey)
+
+ mEnableCustom = findPreference<SwitchPreference>(FINGERPRINT_CUSTOM_ICON_ENABLE)
+ mEnableCustom?.let {
+ it.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue ->
+ if (newValue as Boolean) {
+ if (getCustomImagePath().exists()) {
+ enablePickerIcon()
+ }
+ } else {
+ systemUIProxy?.resetUfpsImage()
+ }
+ true
+ }
+ }
+ mFilePicker = findPreference(FINGERPRINT_CUSTOM_ICON_SELECT)
+ mFilePicker?.let {
+ bindSystemUIProxyService()
+
+ if (getCustomImagePath().exists()) {
+ setPickerIcon()
+ }
+
+ it.onPreferenceClickListener = Preference.OnPreferenceClickListener {
+ pickImage.launch(null)
+ true
+ }
+ }
+ }
+
+ private fun getCustomImagePath(): File {
+ return File(requireContext().filesDir, UFPSIMAGE_FILE_NAME)
+ }
+
+ private fun setPickerIcon() {
+ try {
+ val parcelFileDescriptor = requireContext().contentResolver.openFileDescriptor(
+ Uri.fromFile(getCustomImagePath()),
+ "r"
+ )
+ parcelFileDescriptor?.let { it ->
+ val bitmap = BitmapFactory.decodeFileDescriptor(it.fileDescriptor)
+ it.close()
+ val d = BitmapDrawable(resources, bitmap)
+ mFilePicker?.icon = d
+ }
+ } catch (e: Exception) {
+ Log.e(
+ TAG,
+ "setPickerIcon",
+ e
+ )
+ }
+ }
+
+ private fun enablePickerIcon() {
+ try {
+ val parcelFileDescriptor = requireContext().contentResolver.openFileDescriptor(
+ Uri.fromFile(getCustomImagePath()),
+ "r"
+ )
+ parcelFileDescriptor?.let { it ->
+ val bitmap = BitmapFactory.decodeFileDescriptor(it.fileDescriptor)
+ it.close()
+ systemUIProxy?.setUfpsImageBitmap(bitmap)
+ }
+ } catch (e: Exception) {
+ Log.e(
+ TAG,
+ "setPickerIcon",
+ e
+ )
+ }
+ }
+
+ private fun savePickerIcon(bitmap: Bitmap) {
+ try {
+ val fos = FileOutputStream(getCustomImagePath())
+ bitmap.compress(Bitmap.CompressFormat.PNG, 90, fos)
+ fos.close()
+ val d = BitmapDrawable(resources, bitmap)
+ mFilePicker?.icon = d
+ } catch (e: Exception) {
+ Log.e(
+ TAG,
+ "savePickerIcon",
+ e
+ )
+ }
+ }
+
+ private fun deletePickerIcon() {
+ if (getCustomImagePath().exists()) {
+ getCustomImagePath().delete()
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/omnirom/control/GridViewFragment.kt b/app/src/main/java/org/omnirom/control/GridViewFragment.kt
index 8236e56..81f95e4 100644
--- a/app/src/main/java/org/omnirom/control/GridViewFragment.kt
+++ b/app/src/main/java/org/omnirom/control/GridViewFragment.kt
@@ -27,6 +27,8 @@
import android.widget.*
import androidx.fragment.app.Fragment
+import com.android.internal.util.ArrayUtils;
+
import org.omnirom.omnilibcore.utils.DeviceUtils
class GridViewFragment() : Fragment() {
@@ -84,7 +86,7 @@
AppListFragment()
)
)
- if (getResources().getBoolean(com.android.internal.R.bool.config_intrusiveBatteryLed)) {
+ if (resources.getBoolean(com.android.internal.R.bool.config_intrusiveBatteryLed)) {
gridItems.add(
FragmentGridItem(
R.string.batterylight_title,
@@ -120,6 +122,16 @@
)
)
}
+ if (resources.getBoolean(R.bool.config_has_udfps)) {
+ gridItems.add(
+ FragmentGridItem(
+ R.string.fprint_title,
+ R.string.fprint_summary,
+ R.drawable.ic_settings_fingerprint,
+ FingerprintSettingsFragment()
+ )
+ )
+ }
gridItems.add(
FragmentGridItem(
R.string.lockscreen_item_title,
diff --git a/app/src/main/res/drawable/ic_settings_fingerprint.xml b/app/src/main/res/drawable/ic_settings_fingerprint.xml
new file mode 100644
index 0000000..37eb6f1
--- /dev/null
+++ b/app/src/main/res/drawable/ic_settings_fingerprint.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:height="24dp"
+ android:width="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?android:textColorPrimary">
+
+ <path android:fillColor="@android:color/white"
+ android:pathData="M17.81,4.47C17.73,4.47 17.65,4.45 17.58,4.41C15.66,3.42 14,3 12,3C10.03,3 8.15,3.47 6.44,4.41C6.2,4.54 5.9,4.45 5.76,4.21C5.63,3.97 5.72,3.66 5.96,3.53C7.82,2.5 9.86,2 12,2C14.14,2 16,2.47 18.04,3.5C18.29,3.65 18.38,3.95 18.25,4.19C18.16,4.37 18,4.47 17.81,4.47M3.5,9.72C3.4,9.72 3.3,9.69 3.21,9.63C3,9.47 2.93,9.16 3.09,8.93C4.08,7.53 5.34,6.43 6.84,5.66C10,4.04 14,4.03 17.15,5.65C18.65,6.42 19.91,7.5 20.9,8.9C21.06,9.12 21,9.44 20.78,9.6C20.55,9.76 20.24,9.71 20.08,9.5C19.18,8.22 18.04,7.23 16.69,6.54C13.82,5.07 10.15,5.07 7.29,6.55C5.93,7.25 4.79,8.25 3.89,9.5C3.81,9.65 3.66,9.72 3.5,9.72M9.75,21.79C9.62,21.79 9.5,21.74 9.4,21.64C8.53,20.77 8.06,20.21 7.39,19C6.7,17.77 6.34,16.27 6.34,14.66C6.34,11.69 8.88,9.27 12,9.27C15.12,9.27 17.66,11.69 17.66,14.66A0.5,0.5 0 0,1 17.16,15.16A0.5,0.5 0 0,1 16.66,14.66C16.66,12.24 14.57,10.27 12,10.27C9.43,10.27 7.34,12.24 7.34,14.66C7.34,16.1 7.66,17.43 8.27,18.5C8.91,19.66 9.35,20.15 10.12,20.93C10.31,21.13 10.31,21.44 10.12,21.64C10,21.74 9.88,21.79 9.75,21.79M16.92,19.94C15.73,19.94 14.68,19.64 13.82,19.05C12.33,18.04 11.44,16.4 11.44,14.66A0.5,0.5 0 0,1 11.94,14.16A0.5,0.5 0 0,1 12.44,14.66C12.44,16.07 13.16,17.4 14.38,18.22C15.09,18.7 15.92,18.93 16.92,18.93C17.16,18.93 17.56,18.9 17.96,18.83C18.23,18.78 18.5,18.96 18.54,19.24C18.59,19.5 18.41,19.77 18.13,19.82C17.56,19.93 17.06,19.94 16.92,19.94M14.91,22C14.87,22 14.82,22 14.78,22C13.19,21.54 12.15,20.95 11.06,19.88C9.66,18.5 8.89,16.64 8.89,14.66C8.89,13.04 10.27,11.72 11.97,11.72C13.67,11.72 15.05,13.04 15.05,14.66C15.05,15.73 16,16.6 17.13,16.6C18.28,16.6 19.21,15.73 19.21,14.66C19.21,10.89 15.96,7.83 11.96,7.83C9.12,7.83 6.5,9.41 5.35,11.86C4.96,12.67 4.76,13.62 4.76,14.66C4.76,15.44 4.83,16.67 5.43,18.27C5.53,18.53 5.4,18.82 5.14,18.91C4.88,19 4.59,18.87 4.5,18.62C4,17.31 3.77,16 3.77,14.66C3.77,13.46 4,12.37 4.45,11.42C5.78,8.63 8.73,6.82 11.96,6.82C16.5,6.82 20.21,10.33 20.21,14.65C20.21,16.27 18.83,17.59 17.13,17.59C15.43,17.59 14.05,16.27 14.05,14.65C14.05,13.58 13.12,12.71 11.97,12.71C10.82,12.71 9.89,13.58 9.89,14.65C9.89,16.36 10.55,17.96 11.76,19.16C12.71,20.1 13.62,20.62 15.03,21C15.3,21.08 15.45,21.36 15.38,21.62C15.33,21.85 15.12,22 14.91,22Z" />
+</vector>
diff --git a/app/src/main/res/values/config.xml b/app/src/main/res/values/config.xml
index 08e2d57..9d32956 100644
--- a/app/src/main/res/values/config.xml
+++ b/app/src/main/res/values/config.xml
@@ -12,4 +12,7 @@
<!-- Does devices support fast charging battery led -->
<bool name="config_FastChargingLedSupported">false</bool>
+
+ <!-- udfps support. -->
+ <bool name="config_has_udfps">false</bool>
</resources>
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index b138726..3917599 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -146,4 +146,11 @@
<string name="incall_vibrate_disconnect_summary">Device vibrate on call disconnect</string>
<string name="monet_overlay_enable_title">Enable dynamic colors based on wallpaper - Monet</string>
<string name="system_colors_title">System colors</string>
+
+ <!-- Fingerprint -->
+ <string name="fprint_title">Fingerprint</string>
+ <string name="fprint_summary">Fingerprint Options</string>
+ <string name="fingerprint_category_custom_icon">Custom icon</string>
+ <string name="custom_fp_icon_enable_title">Use custom icon</string>
+ <string name="custom_fp_icon_select_title">Select custom icon</string>
</resources>
diff --git a/app/src/main/res/xml/fingerprint_preferences.xml b/app/src/main/res/xml/fingerprint_preferences.xml
new file mode 100644
index 0000000..408d602
--- /dev/null
+++ b/app/src/main/res/xml/fingerprint_preferences.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2018 The OmniROM Project
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ -->
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+ android:key="fingerprint_p">
+
+ <PreferenceCategory
+ android:key="category_fingerprint_custom_icon"
+ android:title="@string/fingerprint_category_custom_icon">
+ <SwitchPreference
+ android:defaultValue="false"
+ android:key="custom_fingerprint_icon_enable"
+ android:title="@string/custom_fp_icon_enable_title" />
+ <Preference
+ android:dependency="custom_fingerprint_icon_enable"
+ android:key="custom_fingerprint_icon_select"
+ android:title="@string/custom_fp_icon_select_title" />
+ </PreferenceCategory>
+</PreferenceScreen>