5 Commits

Author SHA1 Message Date
91fd515d39 android: Cleaner shutdown still.
All checks were successful
Build Tilde Friends / Build-All (push) Successful in 31m38s
2025-08-27 20:23:02 -04:00
be6e841d3d android: This order seems more sensible.
Some checks failed
Build Tilde Friends / Build-All (push) Has been cancelled
2025-08-27 20:12:20 -04:00
af6afa6903 android: Don't log from the main thread. It might block?
Some checks failed
Build Tilde Friends / Build-All (push) Has been cancelled
2025-08-27 19:20:02 -04:00
6ab5d2a28d build: Start work on 0.2025.9.
Some checks failed
Build Tilde Friends / Build-All (push) Has been cancelled
2025-08-27 18:55:24 -04:00
4be033f288 build: Do the nix dance. 2025-08-27 18:54:41 -04:00
8 changed files with 77 additions and 41 deletions

View File

@@ -16,9 +16,9 @@ MAKEFLAGS += --no-builtin-rules
## LD := Linker. ## LD := Linker.
## ANDROID_SDK := Path to the Android SDK. ## ANDROID_SDK := Path to the Android SDK.
VERSION_CODE := 42 VERSION_CODE := 43
VERSION_CODE_IOS := 16 VERSION_CODE_IOS := 17
VERSION_NUMBER := 0.2025.8 VERSION_NUMBER := 0.2025.9-wip
VERSION_NAME := This program kills fascists. VERSION_NAME := This program kills fascists.
IPHONEOS_VERSION_MIN=14.0 IPHONEOS_VERSION_MIN=14.0

View File

@@ -25,14 +25,14 @@
}: }:
pkgs.stdenv.mkDerivation rec { pkgs.stdenv.mkDerivation rec {
pname = "tildefriends"; pname = "tildefriends";
version = "0.0.33"; version = "0.2025.8";
src = pkgs.fetchFromGitea { src = pkgs.fetchFromGitea {
domain = "dev.tildefriends.net"; domain = "dev.tildefriends.net";
owner = "cory"; owner = "cory";
repo = "tildefriends"; repo = "tildefriends";
rev = "v${version}"; rev = "v${version}";
hash = "sha256-9D28gmaBTRVyXhY3zZd/W9PsXA1YZt/K69hz41aVP04="; hash = "sha256-N/5lp8RL19B6Z43kRxx7c01WVJkK44a/wwNgRJPk5uI=";
fetchSubmodules = true; fetchSubmodules = true;
}; };

6
flake.lock generated
View File

@@ -20,11 +20,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1753749649, "lastModified": 1756217674,
"narHash": "sha256-+jkEZxs7bfOKfBIk430K+tK9IvXlwzqQQnppC2ZKFj4=", "narHash": "sha256-TH1SfSP523QI7kcPiNtMAEuwZR3Jdz0MCDXPs7TS8uo=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "1f08a4df998e21f4e8be8fb6fbf61d11a1a5076a", "rev": "4e7667a90c167f7a81d906e5a75cba4ad8bee620",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.unprompted.tildefriends" package="com.unprompted.tildefriends"
android:versionCode="42" android:versionCode="43"
android:versionName="0.2025.8"> android:versionName="0.2025.9-wip">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.INTERNET"/>
<application <application

View File

@@ -19,7 +19,6 @@ import android.os.RemoteException;
import android.os.StrictMode; import android.os.StrictMode;
import android.text.InputType; import android.text.InputType;
import android.util.Base64; import android.util.Base64;
import android.util.Log;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
@@ -44,6 +43,7 @@ import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.FileReader; import java.io.FileReader;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
public class TildeFriendsActivity extends Activity { public class TildeFriendsActivity extends Activity {
@@ -53,8 +53,10 @@ public class TildeFriendsActivity extends Activity {
String port_file_path; String port_file_path;
Thread create_thread; Thread create_thread;
Thread server_thread; Thread server_thread;
Thread log_thread;
ServiceConnection service_connection; ServiceConnection service_connection;
FileObserver observer; FileObserver observer;
LinkedBlockingQueue<String> log_queue = new LinkedBlockingQueue<String>();
private ValueCallback<Uri[]> upload_message; private ValueCallback<Uri[]> upload_message;
private final static int FILECHOOSER_RESULT = 1; private final static int FILECHOOSER_RESULT = 1;
@@ -63,19 +65,29 @@ public class TildeFriendsActivity extends Activity {
private boolean loaded = false; private boolean loaded = false;
static { static {
Log.w("tildefriends", "Calling system.loadLibrary()."); log("Calling system.loadLibrary().");
System.loadLibrary("tildefriends"); System.loadLibrary("tildefriends");
Log.w("tildefriends", "system.loadLibrary() completed."); log("system.loadLibrary() completed.");
} }
public static native int tf_server_main(String files_dir, String apk_path, String out_port_file_path, ConnectivityManager connectivity_manager); public static native int tf_server_main(String files_dir, String apk_path, String out_port_file_path, ConnectivityManager connectivity_manager);
public static native int tf_sandbox_main(int pipe_fd); public static native int tf_sandbox_main(int pipe_fd);
public static void log(String message) {
if (s_activity != null && s_activity.log_queue != null && message != null) {
try {
s_activity.log_queue.put(message);
} catch (InterruptedException e) {
android.util.Log.w("tildefriends", message);
}
}
}
private void createThread() { private void createThread() {
web_view = (TildeFriendsWebView)findViewById(R.id.web); web_view = (TildeFriendsWebView)findViewById(R.id.web);
Log.w("tildefriends", String.format("getFilesDir() is %s", getFilesDir().toString())); log(String.format("getFilesDir() is %s", getFilesDir().toString()));
Log.w("tildefriends", String.format("getPackageResourcePath() is %s", getPackageResourcePath().toString())); log(String.format("getPackageResourcePath() is %s", getPackageResourcePath().toString()));
Log.w("tildefriends", String.format("nativeLibraryDir is %s", getApplicationInfo().nativeLibraryDir)); log(String.format("nativeLibraryDir is %s", getApplicationInfo().nativeLibraryDir));
port_file_path = getFilesDir().toString() + "/port.txt"; port_file_path = getFilesDir().toString() + "/port.txt";
new File(port_file_path).delete(); new File(port_file_path).delete();
@@ -86,17 +98,17 @@ public class TildeFriendsActivity extends Activity {
server_thread = new Thread(new Runnable() { server_thread = new Thread(new Runnable() {
@Override @Override
public void run() { public void run() {
Log.w("tildefriends", "Watching for changes in: " + getFilesDir().toString()); log("Watching for changes in: " + getFilesDir().toString());
observer = make_file_observer(getFilesDir().toString(), port_file_path); observer = make_file_observer(getFilesDir().toString(), port_file_path);
observer.startWatching(); observer.startWatching();
Log.w("tildefriends", "Calling tf_server_main."); log("Calling tf_server_main.");
int result = tf_server_main( int result = tf_server_main(
getFilesDir().toString(), getFilesDir().toString(),
getPackageResourcePath().toString(), getPackageResourcePath().toString(),
port_file_path, port_file_path,
(ConnectivityManager)getApplicationContext().getSystemService(CONNECTIVITY_SERVICE)); (ConnectivityManager)getApplicationContext().getSystemService(CONNECTIVITY_SERVICE));
Log.w("tildefriends", "tf_server_main returned " + result + "."); log("tf_server_main returned " + result + ".");
} }
}); });
server_thread.start(); server_thread.start();
@@ -110,17 +122,17 @@ public class TildeFriendsActivity extends Activity {
web_view.setDownloadListener(new DownloadListener() { web_view.setDownloadListener(new DownloadListener() {
public void onDownloadStart(String url, String userAgent, String content_disposition, String mime_type, long content_length) { public void onDownloadStart(String url, String userAgent, String content_disposition, String mime_type, long content_length) {
Log.w("tildefriends", "Let's download: " + url + " (" + content_disposition + ")"); log("Let's download: " + url + " (" + content_disposition + ")");
String file_name = URLUtil.guessFileName(url, content_disposition, mime_type); String file_name = URLUtil.guessFileName(url, content_disposition, mime_type);
if (url.startsWith("data:") && url.indexOf(',') != -1) { if (url.startsWith("data:") && url.indexOf(',') != -1) {
String b64 = url.substring(url.indexOf(',') + 1); String b64 = url.substring(url.indexOf(',') + 1);
byte[] data = Base64.decode(b64, Base64.DEFAULT); byte[] data = Base64.decode(b64, Base64.DEFAULT);
Log.w("tildefriends", "Downloaded " + data.length + " bytes."); log("Downloaded " + data.length + " bytes.");
File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS); File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
try (OutputStream stream = new FileOutputStream(new File(path, file_name))) { try (OutputStream stream = new FileOutputStream(new File(path, file_name))) {
stream.write(data); stream.write(data);
} catch (java.io.IOException e) { } catch (java.io.IOException e) {
Log.w("tildefriends", "IOException: " + e.toString()); log("IOException: " + e.toString());
} }
Toast.makeText(getApplicationContext(), "Downloaded File", Toast.LENGTH_LONG).show(); Toast.makeText(getApplicationContext(), "Downloaded File", Toast.LENGTH_LONG).show();
} else { } else {
@@ -228,7 +240,7 @@ public class TildeFriendsActivity extends Activity {
@Override @Override
public boolean onConsoleMessage(android.webkit.ConsoleMessage consoleMessage) { public boolean onConsoleMessage(android.webkit.ConsoleMessage consoleMessage) {
Log.d("tildefriends", consoleMessage.message() + " -- From line " + consoleMessage.lineNumber() + " of " + consoleMessage.sourceId()); log(consoleMessage.message() + " -- From line " + consoleMessage.lineNumber() + " of " + consoleMessage.sourceId());
return true; return true;
} }
}); });
@@ -259,6 +271,23 @@ public class TildeFriendsActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
s_activity = this; s_activity = this;
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
log_thread = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
String message = log_queue.take();
if (message != null) {
android.util.Log.w("tildefriends", message);
} else {
break;
}
} catch (InterruptedException e) {
}
}
}
});
log_thread.start();
StrictMode.setThreadPolicy( StrictMode.setThreadPolicy(
new StrictMode.ThreadPolicy.Builder() new StrictMode.ThreadPolicy.Builder()
.detectAll() .detectAll()
@@ -305,8 +334,16 @@ public class TildeFriendsActivity extends Activity {
@Override @Override
protected void onDestroy() protected void onDestroy()
{ {
super.onDestroy(); try {
if (log_queue != null) {
log_queue.put(null);
}
log_thread.join();
} catch (InterruptedException e) {
}
log_thread = null;
s_activity = null; s_activity = null;
super.onDestroy();
} }
@Override @Override
@@ -399,32 +436,32 @@ public class TildeFriendsActivity extends Activity {
} }
public static void start_sandbox(int pipe_fd) { public static void start_sandbox(int pipe_fd) {
Log.w("tildefriends", "starting service with fd: " + pipe_fd); log("starting service with fd: " + pipe_fd);
Intent intent = new Intent(s_activity, TildeFriendsSandboxService.class); Intent intent = new Intent(s_activity, TildeFriendsSandboxService.class);
s_activity.service_connection = new ServiceConnection() { s_activity.service_connection = new ServiceConnection() {
@Override @Override
public void onBindingDied(ComponentName name) { public void onBindingDied(ComponentName name) {
Log.w("tildefriends", "onBindingDied"); log("onBindingDied");
} }
@Override @Override
public void onNullBinding(ComponentName name) { public void onNullBinding(ComponentName name) {
Log.w("tildefriends", "onNullBinding"); log("onNullBinding");
} }
@Override @Override
public void onServiceConnected(ComponentName name, IBinder binder) { public void onServiceConnected(ComponentName name, IBinder binder) {
Log.w("tildefriends", "onServiceConnected"); log("onServiceConnected");
Parcel data = Parcel.obtain(); Parcel data = Parcel.obtain();
try (ParcelFileDescriptor pfd = ParcelFileDescriptor.fromFd(pipe_fd)) { try (ParcelFileDescriptor pfd = ParcelFileDescriptor.fromFd(pipe_fd)) {
data.writeParcelable(pfd, 0); data.writeParcelable(pfd, 0);
} catch (java.io.IOException e) { } catch (java.io.IOException e) {
Log.w("tildefriends", "IOException: " + e); log("IOException: " + e);
} }
try { try {
binder.transact(TildeFriendsSandboxService.START_CALL, data, null, IBinder.FLAG_ONEWAY); binder.transact(TildeFriendsSandboxService.START_CALL, data, null, IBinder.FLAG_ONEWAY);
} catch (RemoteException e) { } catch (RemoteException e) {
Log.w("tildefriends", "RemoteException"); log("RemoteException");
} finally { } finally {
data.recycle(); data.recycle();
} }
@@ -432,14 +469,14 @@ public class TildeFriendsActivity extends Activity {
@Override @Override
public void onServiceDisconnected(ComponentName name) { public void onServiceDisconnected(ComponentName name) {
Log.w("tildefriends", "onServiceDisconnected"); log("onServiceDisconnected");
} }
}; };
s_activity.bindService(intent, s_activity.service_connection, BIND_AUTO_CREATE | BIND_NOT_FOREGROUND); s_activity.bindService(intent, s_activity.service_connection, BIND_AUTO_CREATE | BIND_NOT_FOREGROUND);
} }
public static void stop_sandbox() { public static void stop_sandbox() {
Log.w("tildefriends", "stop_sandbox"); log("stop_sandbox");
if (s_activity.service_connection != null) { if (s_activity.service_connection != null) {
s_activity.unbindService(s_activity.service_connection); s_activity.unbindService(s_activity.service_connection);
s_activity.service_connection = null; s_activity.service_connection = null;

View File

@@ -6,7 +6,6 @@ import android.os.Binder;
import android.os.IBinder; import android.os.IBinder;
import android.os.Parcel; import android.os.Parcel;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
import android.util.Log;
public class TildeFriendsSandboxService extends Service { public class TildeFriendsSandboxService extends Service {
public static final int START_CALL = IBinder.FIRST_CALL_TRANSACTION; public static final int START_CALL = IBinder.FIRST_CALL_TRANSACTION;
@@ -14,12 +13,12 @@ public class TildeFriendsSandboxService extends Service {
Thread thread; Thread thread;
public int onStartCommand(Intent intent, int flags, int start_id) { public int onStartCommand(Intent intent, int flags, int start_id) {
Log.w("tildefriends", "TildeFriendsSandboxService: onStartCommand"); TildeFriendsActivity.log("TildeFriendsSandboxService: onStartCommand");
return super.onStartCommand(intent, flags, start_id); return super.onStartCommand(intent, flags, start_id);
} }
public void onDestroy() { public void onDestroy() {
Log.w("tildefriends", "TildeFriendsSandboxService: onDestroy"); TildeFriendsActivity.log("TildeFriendsSandboxService: onDestroy");
super.onDestroy(); super.onDestroy();
} }
@@ -27,9 +26,9 @@ public class TildeFriendsSandboxService extends Service {
thread = new Thread(new Runnable() { thread = new Thread(new Runnable() {
@Override @Override
public void run() { public void run() {
Log.w("tildefriends", "Calling tf_sandbox_main."); TildeFriendsActivity.log("Calling tf_sandbox_main.");
int result = TildeFriendsActivity.tf_sandbox_main(pipe_fd); int result = TildeFriendsActivity.tf_sandbox_main(pipe_fd);
Log.w("tildefriends", "tf_sandbox_main returned " + result + "."); TildeFriendsActivity.log("tf_sandbox_main returned " + result + ".");
} }
}); });
thread.start(); thread.start();
@@ -43,7 +42,7 @@ public class TildeFriendsSandboxService extends Service {
if (code == START_CALL) { if (code == START_CALL) {
ParcelFileDescriptor pfd = read_pfd(data); ParcelFileDescriptor pfd = read_pfd(data);
if (pfd != null) { if (pfd != null) {
Log.w("tildefriends", "fd is " + pfd.getFd()); TildeFriendsActivity.log("fd is " + pfd.getFd());
start_thread(pfd.detachFd()); start_thread(pfd.detachFd());
try { try {
pfd.close(); pfd.close();

View File

@@ -13,13 +13,13 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>0.2025.8</string> <string>0.2025.9</string>
<key>CFBundleSupportedPlatforms</key> <key>CFBundleSupportedPlatforms</key>
<array> <array>
<string>iPhoneOS</string> <string>iPhoneOS</string>
</array> </array>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>16</string> <string>17</string>
<key>DTPlatformName</key> <key>DTPlatformName</key>
<string>iphoneos</string> <string>iphoneos</string>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>

View File

@@ -1,2 +1,2 @@
#define VERSION_NUMBER "0.2025.8" #define VERSION_NUMBER "0.2025.9-wip"
#define VERSION_NAME "This program kills fascists." #define VERSION_NAME "This program kills fascists."