Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/workflows/phone.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,13 @@ jobs:
bash ../tools/check-shell-graph.sh -p octosense-home
- name: Verify the single runtime graph
run: python3 tools/setup.py --check --cargo
- name: Build Home, App Hub admission and runtime policy tests
working-directory: phone
timeout-minutes: 60
run: cargo test --locked --features mobile-apps -p octosense-shell -p octosense-home -p octosense-app-policy -p octosense-app-hub -p octosense-news -p octosense-appcard -p octosense-ai-host --no-run
- name: Test Home, App Hub admission and runtime policy
working-directory: phone
timeout-minutes: 30
run: |
# octosense-app-hub-app is App Hub's shared shell crate, a git
# dependency with dev-dependencies: cargo cannot test it from here;
Expand Down
40 changes: 32 additions & 8 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 8 additions & 8 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -77,16 +77,16 @@ octoscript-makepad = { git = "https://github.com/OctoSense-org/Octoscript-Makepa
octoscript-node = { git = "https://github.com/OctoSense-org/Octoscript-Makepad.git", rev = "6351524b77a49a382c96373d7bfe6a105f142dbc" }
# --- App Hub: the shells' store/Card runner/system apps crate and the host
# service registry the Mail and llm services register into. One revision.
octosense-app-hub-app = { git = "https://github.com/OctoSense-org/OctoSense-App-Hub", rev = "46d67e51b62827a1224b1aacddc2a7b9e69185fc" }
octosense-appstore = { git = "https://github.com/OctoSense-org/OctoSense-App-Hub", rev = "46d67e51b62827a1224b1aacddc2a7b9e69185fc" }
octosense-app-hub-app = { git = "https://github.com/OctoSense-org/OctoSense-App-Hub", rev = "e8601b80ce104db2e48208094714bdcffdce6b5a" }
octosense-appstore = { git = "https://github.com/OctoSense-org/OctoSense-App-Hub", rev = "e8601b80ce104db2e48208094714bdcffdce6b5a" }
# --- octos: ONE source for every octos crate (octos-org/octos main at the
# merge of octos#2585). Move octos-core and octos-cli together; the Android
# kernel artifact (liboctos.so) is built from this same revision.
octos-core = { git = "https://github.com/octos-org/octos.git", rev = "7bec0918c497b99671c9e882b7a465e6737cfd83" }
octos-cli = { git = "https://github.com/octos-org/octos.git", rev = "7bec0918c497b99671c9e882b7a465e6737cfd83", default-features = false }
# --- Rinx (Matrix chats, Moments, articles, mini apps) as a hosted module:
# the library only, never its standalone entry or its own kernel (Rinx ADR 0007).
rinx = { git = "https://github.com/hagency-org/Rinx.git", rev = "a72e4b003a05ebcb31bc86c346d7dd06cdffbceb", default-features = false, features = ["octosense-module"] }
rinx = { git = "https://github.com/hagency-org/Rinx.git", rev = "68afcf796d303aaf646eeb832d65c450a56c92b5", default-features = false, features = ["octosense-module"] }
# --- AppCard's inline renderers.
streaming-markdown-kit = { git = "https://github.com/Project-Robius-China/streaming-markdown-kit.git", branch = "main" }
makepad-diagram-kit = { git = "https://github.com/Project-Robius-China/makepad-diagram-kit.git", branch = "main" }
Expand Down Expand Up @@ -211,12 +211,12 @@ octoscript-makepad = { path = ".sources/octoscript-makepad/crates/octoscript-mak
octoscript-widgets = { path = ".sources/octoscript-makepad/crates/octoscript-widgets" }
octoscript-node = { path = ".sources/octoscript-makepad/crates/octoscript-node" }

# Rinx still takes the app-peers contract by git from OctoSense-System-Apps
# (archived; it was imported into this repository): that code lives here
# now, so these are the same crates this workspace links — one broker
# contract and one kernel.
[patch."https://github.com/OctoSense-org/OctoSense-System-Apps.git"]
# Rinx takes the app-peers contract from this repository by git. Redirect
# it to the same local workspace crates, so the host and module share one
# broker contract and one kernel.
[patch."https://github.com/OctoSense-org/OctoSense.git"]
octosense-app-peers = { path = "crates/app-peers" }
octosense-kernel = { path = "crates/kernel" }
octosense-llm-config = { path = "apps/ai-providers/config" }

# Rinx's Matrix stack: the patched ruma its own workspace uses (Rinx's
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
/** Public launcher client and asynchronous bridge adapter in the Home process. */
public final class MakepadAppExtension implements MakepadActivity.ApplicationExtension {
private final MakepadActivity activity;
private Runnable unregisterSystemBack;
private final ObscuredTouchGuard touchGuard=new ObscuredTouchGuard();
@Override public boolean filterTouchEvent(android.view.MotionEvent event) {return touchGuard.accept(event);}
private final Handler main=new Handler(Looper.getMainLooper());
Expand Down Expand Up @@ -231,6 +232,21 @@ public MakepadAppExtension(MakepadActivity activity) {
});
refreshCatalog();
onIntent(activity.getIntent());
// This activity opts into predictive Back. Its legacy callback alone
// cannot prevent Android 13+ from finishing the shell.
if(android.os.Build.VERSION.SDK_INT>=33) {
unregisterSystemBack=SystemBack.register(activity,activity::onBackPressed);
}
}
@android.annotation.TargetApi(33)
private static final class SystemBack {
static Runnable register(MakepadActivity activity,Runnable action) {
android.window.OnBackInvokedDispatcher dispatcher=activity.getOnBackInvokedDispatcher();
android.window.OnBackInvokedCallback callback=action::run;
// DEFAULT leaves the IME's Back dismissal ahead of app navigation.
dispatcher.registerOnBackInvokedCallback(android.window.OnBackInvokedDispatcher.PRIORITY_DEFAULT,callback);
return () -> dispatcher.unregisterOnBackInvokedCallback(callback);
}
}
/** A native dialog in the shell's appearance rather than the device default. */
private AlertDialog.Builder dialog(boolean dark) {
Expand Down Expand Up @@ -1540,7 +1556,15 @@ private void bridgeCommand(JSONObject command) throws Exception {
offer(() -> {if(soundsSettings!=null)soundsSettings.invalidate();if(appNotificationsSettings!=null)appNotificationsSettings.invalidate();if(rolesSettings!=null)rolesSettings.invalidate();if(permissionsSettings!=null)permissionsSettings.invalidate();if(dndSettings!=null)dndSettings.invalidate();if(appNetworkSettings!=null)appNetworkSettings.invalidate();if(appBatterySettings!=null)appBatterySettings.invalidate();if(appStorageSettings!=null)appStorageSettings.invalidate();if(appLanguageSettings!=null)appLanguageSettings.invalidate();if(captionLanguageSettings!=null)captionLanguageSettings.invalidate();if(systemLanguageSettings!=null)systemLanguageSettings.invalidate();if(keyboardSettings!=null)keyboardSettings.invalidate();emitUiMode();});
}
@Override public boolean onActivityResult(int request,int result,Intent data) {return widgets.onActivityResult(request,result,data);}
@Override public boolean onBackPressed() {return replyComposer.close()||widgets.hide();}
@Override public boolean usesSystemBackCallback() {return unregisterSystemBack!=null;}
@Override public boolean onBackPressed() {
if(replyComposer.close()||widgets.hide()) return true;
// The shell offers Back to its foreground module, then returns to
// its launcher. Do not let Activity's fallback finish the shell
// before that asynchronous Rust event is handled.
dev.makepad.android.MakepadNative.onBackPressed();
return true;
}
private void sendSettingsEntry(SettingsEntryContract.Entry entry) {
if(entry!=null) {
JSONObject packet=json("schema",1,"id",entry.id,"route",entry.route);
Expand Down Expand Up @@ -1592,6 +1616,7 @@ private void sendSettingsEntry(SettingsEntryContract.Entry entry) {
if(intent!=null && intent.hasCategory(Intent.CATEGORY_HOME)) {replyComposer.close();widgets.hide();homeGeometry.invalidate();}
}
@Override public void onDestroy() {
if(unregisterSystemBack!=null) {unregisterSystemBack.run();unregisterSystemBack=null;}
QrImagePickActivity.setListener(null);
offer(()->{if(captionLanguageSettings!=null)captionLanguageSettings.invalidate();if(systemLanguageSettings!=null)systemLanguageSettings.invalidate();if(keyboardSettings!=null)keyboardSettings.invalidate();});
if(captionCustomSettings!=null)captionCustomSettings.retireInBackground();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ JSONObject json() {
}
private ThemeCatalog(Context context) throws Exception {
byte[] bytes;
try(InputStream stream=context.getAssets().open("makepad/octosense/resources/themes/mobile-presets.json");
try(InputStream stream=context.getAssets().open("makepad/octosense_shell/resources/themes/mobile-presets.json");
ByteArrayOutputStream buffer=new ByteArrayOutputStream()) {
byte[] part=new byte[4096]; int n;
while((n=stream.read(part))!=-1) buffer.write(part,0,n);
Expand Down
11 changes: 9 additions & 2 deletions runtime-patches.lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,17 @@
"base_revision": "b0cbc9bcfb204ade5d8ceecb66e0a58e972c70f1",
"patch": "tools/runtime-patches/makepad-settings.patch",
"sha256": "ba59081fb600b022844db5882f969712275be7a7976be8cb5ced7eac1bfa26a5",
"tree": "be911970c65d202ad997983f8f2ea226c08b7922",
"tree": "ad2f8b693414b260d5d10dcb8895f863da5d29dc",
"product_fixes": [
"Settings integration: Android IME synchronization, accessibility and reduced motion, GLES program-cache validation, obscured-gesture cancellation and scroll-position observation.",
"Contained-app isolation and secret-input restrictions come from the pinned upstream runtime; the Settings overlay preserves those gates."
"Contained-app isolation and secret-input restrictions come from the pinned upstream runtime; the Settings overlay preserves those gates.",
"System Back callback owners suppress compatibility Back keys to avoid duplicate navigation on Android 13+."
],
"stacked": [
{
"patch": "tools/runtime-patches/makepad-system-back.patch",
"sha256": "3268cb486bbd05db7bb6920c26007e437017b6234a4d9f045a99a7d1954b7427"
}
]
}
}
34 changes: 34 additions & 0 deletions tools/runtime-patches/makepad-system-back.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
diff --git a/tools/cargo_makepad/src/android/java/dev/makepad/android/MakepadActivity.java b/tools/cargo_makepad/src/android/java/dev/makepad/android/MakepadActivity.java
index 274d922..ede68f2 100644
--- a/tools/cargo_makepad/src/android/java/dev/makepad/android/MakepadActivity.java
+++ b/tools/cargo_makepad/src/android/java/dev/makepad/android/MakepadActivity.java
@@ -1180,6 +1180,8 @@ public class MakepadActivity
void onDestroy();
default boolean onActivityResult(int requestCode, int resultCode, Intent data) { return false; }
default boolean onBackPressed() { return false; }
+ /** The extension owns Android 13+ Back through its system dispatcher. */
+ default boolean usesSystemBackCallback() { return false; }
/** Runs before native views or the renderer receive a touch. */
default boolean filterTouchEvent(MotionEvent event) { return true; }
}
@@ -1811,6 +1813,12 @@ public class MakepadActivity
// key (BACK included) and forwards it to Rust, so onBackPressed never runs.
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
+ // System Back invokes the registered callback separately. Forwarding
+ // its compatibility key to the surface would navigate twice.
+ if (android.os.Build.VERSION.SDK_INT >= 33 && event.getKeyCode() == KeyEvent.KEYCODE_BACK
+ && mApplicationExtension != null && mApplicationExtension.usesSystemBackCallback()) {
+ return true;
+ }
if (mQrScanning && event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
if (event.getAction() == KeyEvent.ACTION_UP) closeQrScanner("cancelled");
return true;
@@ -1821,6 +1829,7 @@ public class MakepadActivity
@Override
@SuppressWarnings("deprecation")
public void onBackPressed() {
+ if (mQrScanning) { closeQrScanner("cancelled"); return; }
if (mApplicationExtension != null && mApplicationExtension.onBackPressed()) return;
super.onBackPressed();
MakepadNative.onBackPressed();
Loading