Delete patches_treble_td/platform_frameworks_base/0032-FOD-support-for-Asus-ZF8-and-Samsung-devices.patch

This commit is contained in:
Talmid of Levi 2023-12-15 16:11:42 -05:00
parent 4631b08a2e
commit f85f2186f9

View File

@ -1,566 +0,0 @@
From 9608e159585b0fad82cede7fd9dca5e50a71672b Mon Sep 17 00:00:00 2001
From: Pierre-Hugues Husson <phh@phh.me>
Date: Sun, 18 Dec 2022 18:20:40 -0500
Subject: [PATCH 32/40] FOD support for Asus ZF8 and Samsung devices
Thanks Asus for providing a free device to make this support
And thanks @davigamer987 for donating enough to get a Samsung FOD device
to make this
Change-Id: Ib328f39217c3f9b42e13e186496b3f6391643637
---
packages/SystemUI/Android.bp | 1 +
packages/SystemUI/res/values/config.xml | 2 +-
.../biometrics/UdfpsControllerOverlay.kt | 7 +-
.../android/systemui/biometrics/UdfpsView.kt | 138 ++++++++++
services/core/Android.bp | 7 +-
.../server/biometrics/AuthService.java | 238 +++++++++++++++++-
6 files changed, 388 insertions(+), 5 deletions(-)
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index b4027197344d..0637dd4b4471 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -178,6 +178,7 @@ android_library {
"LowLightDreamLib",
"motion_tool_lib",
"vendor.lineage.powershare-V1.0-java",
+ "vendor.goodix.hardware.biometrics.fingerprint-V2.1-java",
],
manifest: "AndroidManifest.xml",
additional_manifests: ["LineageManifest.xml"],
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 0743bcdde621..99f21ed21d15 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -585,7 +585,7 @@
<!-- The radius of the enrollment progress bar, in dp -->
<integer name="config_udfpsEnrollProgressBar" translatable="false">
- 70
+ 50
</integer>
<!-- The time (in ms) needed to trigger the lock icon view's long-press affordance -->
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
index b6b5d26b398c..88c2976d81ab 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
@@ -120,7 +120,9 @@ class UdfpsControllerOverlay @JvmOverloads constructor(
gravity = android.view.Gravity.TOP or android.view.Gravity.LEFT
layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
flags = (Utils.FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS or
- WindowManager.LayoutParams.FLAG_SPLIT_TOUCH)
+ WindowManager.LayoutParams.FLAG_SPLIT_TOUCH) or
+ WindowManager.LayoutParams.FLAG_DIM_BEHIND
+ dimAmount = 0.0f
privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY
// Avoid announcing window title.
accessibilityTitle = " "
@@ -189,6 +191,9 @@ class UdfpsControllerOverlay @JvmOverloads constructor(
windowManager.addView(this, coreLayoutParams.updateDimensions(animation))
sensorRect = sensorBounds
touchExplorationEnabled = accessibilityManager.isTouchExplorationEnabled
+ dimUpdate = {
+ windowManager.updateViewLayout(this, coreLayoutParams.updateDimensions(animation).apply { dimAmount = it })
+ }
overlayTouchListener = TouchExplorationStateChangeListener {
if (accessibilityManager.isTouchExplorationEnabled) {
setOnHoverListener { v, event -> onTouch(v, event, true) }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.kt
index e61c614f0292..cdaad81b9222 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsView.kt
@@ -19,18 +19,27 @@ import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
+import android.graphics.PixelFormat
import android.graphics.PointF
import android.graphics.Rect
import android.graphics.RectF
+import android.os.FileObserver
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
+import android.view.SurfaceHolder
+import android.view.SurfaceView
+import android.view.ViewGroup
import android.widget.FrameLayout
import com.android.systemui.R
import com.android.systemui.doze.DozeReceiver
+import java.io.File
+
+import vendor.goodix.hardware.biometrics.fingerprint.V2_1.IGoodixFingerprintDaemon
private const val TAG = "UdfpsView"
+
/**
* The main view group containing all UDFPS animations.
*/
@@ -38,6 +47,54 @@ class UdfpsView(
context: Context,
attrs: AttributeSet?
) : FrameLayout(context, attrs), DozeReceiver {
+ private var currentOnIlluminatedRunnable: Runnable? = null
+ private val mySurfaceView = SurfaceView(context)
+ init {
+ mySurfaceView.setVisibility(INVISIBLE)
+ mySurfaceView.setZOrderOnTop(true)
+ addView(mySurfaceView, FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT))
+ mySurfaceView.holder.addCallback(object: SurfaceHolder.Callback{
+ override fun surfaceCreated(p0: SurfaceHolder) {
+ Log.d("PHH", "Surface created!")
+ val paint = Paint(0 /* flags */);
+ paint.setAntiAlias(true);
+ paint.setStyle(Paint.Style.FILL);
+ val colorStr = android.os.SystemProperties.get("persist.sys.phh.fod_color", "00ff00");
+ try {
+ val parsedColor = Color.parseColor("#" + colorStr);
+ val r = (parsedColor shr 16) and 0xff;
+ val g = (parsedColor shr 8) and 0xff;
+ val b = (parsedColor shr 0) and 0xff;
+ paint.setARGB(255, r, g, b);
+ } catch(t: Throwable) {
+ Log.d("PHH", "Failed parsing color #" + colorStr, t);
+ }
+ var canvas: Canvas? = null
+ try {
+ canvas = p0.lockCanvas();
+Log.d("PHH", "Surface dimensions ${canvas.getWidth()*1.0f} ${canvas.getHeight()*1.0f}")
+ canvas.drawOval(RectF(0.0f, 0.0f, canvas.getWidth()*1.0f, canvas.getHeight()*1.0f), paint);
+ } finally {
+ // Make sure the surface is never left in a bad state.
+ if (canvas != null) {
+ p0.unlockCanvasAndPost(canvas);
+ }
+ }
+
+ currentOnIlluminatedRunnable?.run()
+ }
+
+ override fun surfaceChanged(p0: SurfaceHolder, p1: Int, p2: Int, p3: Int) {
+Log.d("PHH", "Got surface size $p1 $p2 $p3")
+ }
+
+ override fun surfaceDestroyed(p0: SurfaceHolder) {
+Log.d("PHH", "Surface destroyed!")
+ }
+ })
+ mySurfaceView.holder.setFormat(PixelFormat.RGBA_8888)
+
+ }
// Use expanded overlay when feature flag is true, set by UdfpsViewController
var useExpandedOverlay: Boolean = false
@@ -66,6 +123,8 @@ class UdfpsView(
/** Parameters that affect the position and size of the overlay. */
var overlayParams = UdfpsOverlayParams()
+ var dimUpdate: (Float) -> Unit = {}
+
/** Debug message. */
var debugMessage: String? = null
set(value) {
@@ -146,15 +205,94 @@ class UdfpsView(
!(animationViewController?.shouldPauseAuth() ?: false)
}
+ fun goodixCmd(id: Int) {
+ val goodixSvc = IGoodixFingerprintDaemon.getService()
+ if(goodixSvc != null) {
+ goodixSvc.sendCommand(id, ArrayList(), { returnCode, resultData -> {
+ Log.e("PHH-Enroll", "Goodix send command returned code "+ returnCode);
+ }});
+ }
+ }
+
+ val asusGhbmOnAchieved = "/sys/class/drm/ghbm_on_achieved"
+ var hasAsusGhbm = File(asusGhbmOnAchieved).exists()
+ var samsungActualMaskBrightness = "/sys/class/lcd/panel/actual_mask_brightness"
+ val hasSamsungMask = File(samsungActualMaskBrightness).exists()
+ var fodFileObserver: FileObserver? = null
+
fun configureDisplay(onDisplayConfigured: Runnable) {
isDisplayConfigured = true
animationViewController?.onDisplayConfiguring()
mUdfpsDisplayMode?.enable(onDisplayConfigured)
+
+ mySurfaceView.setVisibility(VISIBLE)
+ Log.d("PHH", "setting surface visible!")
+
+ val brightness = File("/sys/class/backlight/panel0-backlight/brightness").readText().toDouble()
+ val maxBrightness = File("/sys/class/backlight/panel0-backlight/max_brightness").readText().toDouble()
+
+ // Assume HBM is max brightness
+ val dim = 1.0 - Math.pow( (brightness / maxBrightness), 1/2.3);
+ Log.d("PHH-Enroll", "Brightness is $brightness / $maxBrightness, setting dim to $dim")
+ if (hasAsusGhbm) {
+ dimUpdate(dim.toFloat())
+ }
+ if (hasSamsungMask) {
+ dimUpdate(dim.toFloat())
+ }
+
+ if(android.os.SystemProperties.get("ro.vendor.build.fingerprint").contains("ASUS")) {
+ goodixCmd(200001)
+ }
}
fun unconfigureDisplay() {
isDisplayConfigured = false
animationViewController?.onDisplayUnconfigured()
mUdfpsDisplayMode?.disable(null /* onDisabled */)
+
+ if (hasAsusGhbm) {
+ fodFileObserver = object: FileObserver(asusGhbmOnAchieved, FileObserver.MODIFY) {
+ override fun onEvent(event: Int, path: String): Unit {
+ Log.d("PHH-Enroll", "Asus ghbm event")
+ try {
+ val spotOn = File(asusGhbmOnAchieved).readText().toInt()
+ if(spotOn == 0) {
+ dimUpdate(0.0f)
+ fodFileObserver?.stopWatching()
+ fodFileObserver = null
+ }
+ } catch(e: Exception) {
+ Log.d("PHH-Enroll", "Failed dimpdate off", e)
+ }
+ }
+ };
+ fodFileObserver?.startWatching();
+ } else if (hasSamsungMask) {
+ fodFileObserver = object: FileObserver(asusGhbmOnAchieved, FileObserver.MODIFY) {
+ override fun onEvent(event: Int, path: String): Unit {
+ Log.d("PHH-Enroll", "samsung mask brightness event")
+ try {
+ val spotOn = File(samsungActualMaskBrightness).readText().toInt()
+ if(spotOn == 0) {
+ dimUpdate(0.0f)
+ fodFileObserver?.stopWatching()
+ fodFileObserver = null
+ }
+ } catch(e: Exception) {
+ Log.d("PHH-Enroll", "Failed dimpdate off", e)
+ }
+ }
+ };
+ fodFileObserver?.startWatching();
+ } else {
+ dimUpdate(0.0f)
+ }
+
+ mySurfaceView.setVisibility(INVISIBLE)
+ Log.d("PHH", "setting surface invisible!")
+ if(android.os.SystemProperties.get("ro.vendor.build.fingerprint").contains("ASUS")) {
+ goodixCmd(200003)
+ }
}
}
diff --git a/services/core/Android.bp b/services/core/Android.bp
index ebd4373e25c1..c4c8ee1f565a 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -174,7 +174,12 @@ java_library_static {
"motorola.hardware.health-V1.0-java",
"overlayable_policy_aidl-java",
"com.android.sysprop.watchdog",
- "vendor.samsung.hardware.sysinput-V1.2-java", // HIDL
+ // HIDL
+ "vendor.samsung.hardware.sysinput-V1.2-java",
+ "vendor.goodix.hardware.biometrics.fingerprint-V2.1-java",
+ "vendor.samsung.hardware.biometrics.fingerprint-V3.0-java",
+ "vendor.oplus.hardware.biometrics.fingerprint-V2.1-java",
+ "vendor.oppo.hardware.biometrics.fingerprint-V2.1-java",
],
javac_shard_size: 50,
}
diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java
index 7e6f35acc398..063e3599d6cd 100644
--- a/services/core/java/com/android/server/biometrics/AuthService.java
+++ b/services/core/java/com/android/server/biometrics/AuthService.java
@@ -77,6 +77,22 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import android.hardware.display.DisplayManager;
+
+import android.graphics.Point;
+import android.util.DisplayMetrics;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.PrintWriter;
+
+import android.os.FileObserver;
+import android.os.Build;
+
+import vendor.samsung.hardware.biometrics.fingerprint.V3_0.ISehBiometricsFingerprint;
+import vendor.goodix.hardware.biometrics.fingerprint.V2_1.IGoodixFingerprintDaemon;
+import vendor.samsung.hardware.sysinput.V1_0.ISehSysInputDev;
+
/**
* System service that provides an interface for authenticating with biometrics and
* PIN/pattern/password to BiometricPrompt and lock screen.
@@ -95,6 +111,9 @@ public class AuthService extends SystemService {
@VisibleForTesting
final IAuthService.Stub mImpl;
+ private FileObserver fodFileObserver = null;
+ private ISehBiometricsFingerprint mSamsungFingerprint = null;
+
/**
* Class for injecting dependencies into AuthService.
* TODO(b/141025588): Replace with a dependency injection framework (e.g. Guice, Dagger).
@@ -652,6 +671,72 @@ public class AuthService extends SystemService {
registerAuthenticators(hidlConfigs);
mInjector.publishBinderService(this, mImpl);
+ try {
+ mSamsungFingerprint = ISehBiometricsFingerprint.getService();
+ android.util.Log.e("PHH", "Got samsung fingerprint HAL");
+ } catch(Exception e) {
+ android.util.Log.e("PHH", "Failed getting Samsung fingerprint HAL", e);
+ }
+ if(samsungHasCmd("fod_enable") && mSamsungFingerprint != null) {
+ samsungCmd("fod_enable,1,1,0");
+ String actualMaskBrightnessPath = "/sys/class/lcd/panel/actual_mask_brightness";
+ android.util.Log.e("PHH-Enroll", "Reading actual brightness file gives " + readFile(actualMaskBrightnessPath));
+ fodFileObserver = new FileObserver(actualMaskBrightnessPath, FileObserver.MODIFY) {
+ @Override
+ public void onEvent(int event, String path) {
+ String actualMask = readFile(actualMaskBrightnessPath);
+ try {
+ mSamsungFingerprint = ISehBiometricsFingerprint.getService();
+ } catch(Exception e) {}
+ Slog.d("PHH-Enroll", "New actual mask brightness is " + actualMask);
+ try {
+ int eventReq = 0;
+ if("0".equals(actualMask)) {
+ eventReq = 1; //released
+ } else {
+ eventReq = 2; //pressed
+ }
+ if(mSamsungFingerprint != null) {
+ mSamsungFingerprint.sehRequest(22 /* SEM_FINGER_STATE */, eventReq, new java.util.ArrayList<Byte>(),
+ (int retval, java.util.ArrayList<Byte> out) -> {} );
+ }
+ } catch(Exception e) {
+ Slog.d("PHH-Enroll", "Failed setting samsung event for mask observer", e);
+ }
+ }
+ };
+ fodFileObserver.startWatching();
+ }
+
+ String asusGhbmOnAchieved = "/sys/class/drm/ghbm_on_achieved";
+ if( (new File(asusGhbmOnAchieved)).exists()) {
+ fodFileObserver = new FileObserver(asusGhbmOnAchieved, FileObserver.MODIFY) {
+ boolean wasOn = false;
+ @Override
+ public void onEvent(int event, String path) {
+ String spotOn = readFile(asusGhbmOnAchieved);
+ if("1".equals(spotOn)) {
+ if(!wasOn) {
+ try {
+ IGoodixFingerprintDaemon goodixDaemon = IGoodixFingerprintDaemon.getService();
+
+ //Send UI ready
+ goodixDaemon.sendCommand(200002, new java.util.ArrayList<Byte>(), (returnCode, resultData) -> {
+ Slog.e(TAG, "Goodix send command touch pressed returned code "+ returnCode);
+ });
+ } catch(Throwable t) {
+ Slog.d("PHH-Enroll", "Failed sending goodix command", t);
+ }
+ }
+ wasOn = true;
+ } else {
+ wasOn = false;
+ }
+ }
+ };
+ fodFileObserver.startWatching();
+ }
+
}
/**
@@ -775,18 +860,104 @@ public class AuthService extends SystemService {
? modality : (modality & ~BiometricAuthenticator.TYPE_CREDENTIAL);
}
+ private int[] dynamicUdfpsProps() {
+ DisplayManager mDM = (DisplayManager) getContext().getSystemService(Context.DISPLAY_SERVICE);
+ Point displayRealSize = new Point();
+ DisplayMetrics displayMetrics = new DisplayMetrics();
+ mDM.getDisplay(0).getRealSize(displayRealSize);
+ mDM.getDisplay(0).getMetrics(displayMetrics);
+
+ if(readFile("/sys/class/fingerprint/fingerprint/position") != null) {
+ try {
+ ISehSysInputDev s = ISehSysInputDev.getService();
+ s.getTspFodInformation(0, (a, b) -> {
+ Slog.d("PHH-Enroll", "TspFod info " + a + ", " + b);
+ });
+ s.getTspFodPosition(0, (a, b) -> {
+ Slog.d("PHH-Enroll", "TspFod info " + a + ", " + b);
+ });
+ }catch(Throwable t) {
+ Slog.d("PHH-Enroll", "heya ", t);
+ }
+
+
+ android.util.Log.d("PHH", "Samsung fingerprint");
+ String[] fodPositionArray = readFile("/sys/class/fingerprint/fingerprint/position").split(",");
+ float bottomMM = Float.parseFloat(fodPositionArray[0]);
+ float areaSizeMM = Float.parseFloat(fodPositionArray[5]);
+ float heightMM = Float.parseFloat(fodPositionArray[2]);
+ float bottomInch = bottomMM * 0.0393700787f;
+ float areaSizeInch = areaSizeMM * 0.0393700787f;
+ float heightInch = heightMM * 0.0393700787f;
+ int bottomPx = (int)(bottomInch * displayMetrics.ydpi);
+ int areaSizePx = (int)(areaSizeInch * displayMetrics.ydpi);
+ int midDistPx = (int)(areaSizeInch * displayMetrics.ydpi / 2.0f);
+
+ float mW = areaSizePx/2;
+ float mH = areaSizePx/2;
+ float mX = displayRealSize.x/2;
+ //float mY = displayRealSize.y - bottomPx - midDistPx;
+ float mY = displayRealSize.y - (bottomInch * displayMetrics.ydpi) - (areaSizeInch * displayMetrics.ydpi / 2.0f);
+
+ samsungCmd(String.format("fod_rect,%d,%d,%d,%d", (int)(mX - mW/2), (int)(mY - mW/2), (int)(mX + mW/2), (int)(mY + mW/2)));
+ Slog.d("PHH-Enroll", "Display real size is " + displayRealSize.y + ", dpy " + displayMetrics.ydpi);
+
+ int udfpsProps[] = new int[3];
+ udfpsProps[0] = (int)mX;
+ udfpsProps[1] = (int)mY;
+ udfpsProps[2] = (int)mW;
+
+ try {
+ mSamsungFingerprint = ISehBiometricsFingerprint.getService();
+ Slog.d("PHH-Enroll", "Samsung ask for sensor status");
+ mSamsungFingerprint.sehRequest(6, 0, new java.util.ArrayList(), (int retval, java.util.ArrayList<Byte> out) -> {
+ Slog.d("PHH-Enroll", "Result is " + retval);
+ for(int i=0; i<out.size(); i++) {
+ Slog.d("PHH-Enroll", "\t" + i + ":" + out.get(i));
+ }
+ } );
+ Slog.d("PHH-Enroll", "Samsung ask for sensor brightness value");
+ mSamsungFingerprint.sehRequest(32, 0, new java.util.ArrayList(), (int retval, java.util.ArrayList<Byte> out) -> {
+ Slog.d("PHH-Enroll", "Result is " + retval);
+ for(int i=0; i<out.size(); i++) {
+ Slog.d("PHH-Enroll", "\t" + i + ":" + out.get(i));
+ }
+ } );
+
+ } catch(Exception e) {
+ Slog.d("PHH-Enroll", "Failed setting samsung3.0 fingerprint recognition", e);
+ }
+ return udfpsProps;
+ }
+
+ if(android.os.SystemProperties.get("ro.vendor.build.fingerprint").contains("ASUS_I006D")) {
+ int udfpsProps[] = new int[3];
+ udfpsProps[0] = displayRealSize.x/2;
+ udfpsProps[1] = 1741;
+ udfpsProps[2] = 110;
+ return udfpsProps;
+ }
+
+ return new int[0];
+ }
private FingerprintSensorPropertiesInternal getHidlFingerprintSensorProps(int sensorId,
@BiometricManager.Authenticators.Types int strength) {
// The existence of config_udfps_sensor_props indicates that the sensor is UDFPS.
- final int[] udfpsProps = getContext().getResources().getIntArray(
+ int[] udfpsProps = getContext().getResources().getIntArray(
com.android.internal.R.array.config_udfps_sensor_props);
// Non-empty workaroundLocations indicates that the sensor is SFPS.
final List<SensorLocationInternal> workaroundLocations =
getWorkaroundSensorProps(getContext());
- final boolean isUdfps = !ArrayUtils.isEmpty(udfpsProps);
+ boolean isUdfps = !ArrayUtils.isEmpty(udfpsProps);
+ if(!isUdfps) udfpsProps = dynamicUdfpsProps();
+ isUdfps = !ArrayUtils.isEmpty(udfpsProps);
+
+ if(udfpsProps.length > 0) {
+ Slog.d("PHH-Enroll", "Got udfps infos " + udfpsProps[0] + ", " + udfpsProps[1] + ", " + udfpsProps[2]);
+ }
// config_is_powerbutton_fps indicates whether device has a power button fingerprint sensor.
final boolean isPowerbuttonFps = getContext().getResources().getBoolean(
@@ -854,4 +1025,67 @@ public class AuthService extends SystemService {
componentInfo, resetLockoutRequiresHardwareAuthToken,
resetLockoutRequiresChallenge);
}
+
+ private static boolean samsungHasCmd(String cmd) {
+ try {
+ File f = new File("/sys/devices/virtual/sec/tsp/cmd_list");
+ if(!f.exists()) return false;
+
+ android.util.Log.d("PHH", "Managed to grab cmd list, checking...");
+ BufferedReader b = new BufferedReader(new FileReader(f));
+ String line = null;
+ while( (line = b.readLine()) != null) {
+ if(line.equals(cmd)) return true;
+ }
+ android.util.Log.d("PHH", "... nope");
+ return false;
+ } catch(Exception e) {
+ android.util.Log.d("PHH", "Failed reading cmd_list", e);
+ return false;
+ }
+ }
+
+ public static void samsungCmd(String cmd) {
+ try {
+ writeFile("/sys/devices/virtual/sec/tsp/cmd", cmd);
+
+ String status = readFile("/sys/devices/virtual/sec/tsp/cmd_status");
+ String ret = readFile("/sys/devices/virtual/sec/tsp/cmd_result");
+
+ android.util.Log.d("PHH", "Sending command " + cmd + " returned " + ret + ":" + status);
+ } catch(Exception e) {
+ android.util.Log.d("PHH", "Failed sending command " + cmd, e);
+ }
+ }
+
+ private static void writeFile(String path, String value) {
+ try {
+ PrintWriter writer = new PrintWriter(path, "UTF-8");
+ writer.println(value);
+ writer.close();
+ } catch(Exception e) {
+ android.util.Log.d("PHH", "Failed writing to " + path + ": " + value);
+ }
+ }
+
+ private static void writeFile(File file, String value) {
+ try {
+ PrintWriter writer = new PrintWriter(file, "UTF-8");
+ writer.println(value);
+ writer.close();
+ } catch(Exception e) {
+ android.util.Log.d("PHH", "Failed writing to " + file + ": " + value);
+ }
+ }
+
+ private static String readFile(String path) {
+ try {
+ File f = new File(path);
+
+ BufferedReader b = new BufferedReader(new FileReader(f));
+ return b.readLine();
+ } catch(Exception e) {
+ return null;
+ }
+ }
}
--
2.34.1