GrayPause 1.4: grayscale color breaks for Android
Timers that switch grayscale off and restore it on their own: presets and custom h/m/s timers, Quick Settings tile, launcher shortcuts, countdown notification, reboot recovery, and optional always-in-color apps via an accessibility service. WRITE_SECURE_SETTINGS is granted once via Shizuku or adb. Gradle project for F-Droid with fastlane metadata and a draft fdroiddata recipe; build.sh keeps the Gradle-free on-phone Termux build. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
64aa7adc99
commit
5d7d84eaca
38 changed files with 2419 additions and 1 deletions
55
tools/ZipAlign.java
Normal file
55
tools/ZipAlign.java
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
/**
|
||||
* Minimal zipalign: copies a zip, padding STORED entries so their data is 4-byte aligned,
|
||||
* and appends any extra files given after the output path (compressed, at the zip root).
|
||||
*/
|
||||
public class ZipAlign {
|
||||
public static void main(String[] a) throws IOException {
|
||||
try (ZipFile in = new ZipFile(a[0]);
|
||||
CountingOut cnt = new CountingOut(new BufferedOutputStream(new FileOutputStream(a[1])));
|
||||
ZipOutputStream out = new ZipOutputStream(cnt)) {
|
||||
for (ZipEntry e : Collections.list(in.entries())) {
|
||||
ZipEntry n = new ZipEntry(e.getName());
|
||||
n.setMethod(e.getMethod());
|
||||
n.setTime(946684800000L); // 2000-01-01, inside the DOS date range (no extra timestamp field)
|
||||
if (e.getMethod() == ZipEntry.STORED) {
|
||||
n.setSize(e.getSize());
|
||||
n.setCompressedSize(e.getSize());
|
||||
n.setCrc(e.getCrc());
|
||||
out.flush();
|
||||
long dataStart = cnt.count + 30 + n.getName().getBytes("UTF-8").length;
|
||||
int pad = (int) ((4 - dataStart % 4) % 4);
|
||||
if (pad > 0) n.setExtra(padExtra(pad));
|
||||
}
|
||||
out.putNextEntry(n);
|
||||
in.getInputStream(e).transferTo(out);
|
||||
out.closeEntry();
|
||||
}
|
||||
for (int i = 2; i < a.length; i++) {
|
||||
File f = new File(a[i]);
|
||||
ZipEntry n = new ZipEntry(f.getName());
|
||||
n.setTime(946684800000L);
|
||||
out.putNextEntry(n);
|
||||
try (InputStream fin = new FileInputStream(f)) { fin.transferTo(out); }
|
||||
out.closeEntry();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// An extra field needs a 4-byte header, so use one field of pad+4 bytes (Android's 0xD935 alignment tag).
|
||||
static byte[] padExtra(int pad) {
|
||||
byte[] x = new byte[pad + 4];
|
||||
x[0] = 0x35; x[1] = (byte) 0xD9; x[2] = (byte) pad;
|
||||
return x;
|
||||
}
|
||||
|
||||
static class CountingOut extends FilterOutputStream {
|
||||
long count;
|
||||
CountingOut(OutputStream o) { super(o); }
|
||||
@Override public void write(int b) throws IOException { out.write(b); count++; }
|
||||
@Override public void write(byte[] b, int off, int len) throws IOException { out.write(b, off, len); count += len; }
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue