Own application id (.bench suffix) and label ("AI Sessions bench" via a
build-type resValue over the new @string/app_name), release
optimisations, signed with the same key build-apk.sh already generates,
FIXTURE_MODE=true wired through BuildConfig. Its asset source set points
straight at app/bench-fixture/assets rather than a copy under androidApp,
so there is one file to keep in sync with the generator, not two.
build-apk.sh bench builds it; the CA-pinning step is untouched and still
requires a real ca.pem to exist, even though this build never connects --
simplest to let it pin whatever is there rather than special-casing it.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
124 lines
7.2 KiB
XML
124 lines
7.2 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
xmlns:tools="http://schemas.android.com/tools">
|
|
<uses-permission android:name="android.permission.INTERNET" />
|
|
<!-- Android 17 (API 37) made Local Network Protection mandatory: an app
|
|
targeting 37+ needs this runtime permission to reach *any* local
|
|
network address, including a plain socket to a LAN IP literal.
|
|
Without it the traffic is silently dropped, surfacing only as a
|
|
connect timeout. See MainActivity.kt's runtime request, and
|
|
dev-updater's manifest for the full story. -->
|
|
<uses-permission android:name="android.permission.ACCESS_LOCAL_NETWORK" />
|
|
|
|
<!-- Telling somebody a session wants them. POST_NOTIFICATIONS is a
|
|
runtime permission from Android 13; the foreground-service pair
|
|
below is what lets the connection outlive the app being closed,
|
|
which is the entire point (see Notifications.kt). -->
|
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
|
|
|
|
<!-- tools:ignore MissingApplicationIcon: there is no icon yet, and
|
|
that is a decision rather than an oversight. An app with no icon
|
|
of its own is obvious to anyone who opens a launcher, so the
|
|
warning tells nobody here anything they cannot already see, and
|
|
the fix is a judgement about how this app should look. Drop this
|
|
suppression when a real icon lands. -->
|
|
<application
|
|
android:label="@string/app_name"
|
|
android:allowBackup="true"
|
|
android:theme="@android:style/Theme.Material.Light.NoActionBar"
|
|
tools:ignore="MissingApplicationIcon">
|
|
<!-- Lets the phone's own System Tracing see this app's trace sections
|
|
(Compose's phases, and the composable names runtime-tracing
|
|
adds) in a release build, so a frame cost measured on the real
|
|
device can be attributed. shell="true" limits it to profilers
|
|
run from the shell; it grants nothing to other apps. -->
|
|
<profileable android:shell="true" tools:targetApi="q" />
|
|
<!-- adjustResize (not the system's default pan): the layout handles
|
|
the keyboard itself via imePadding(), so the window must resize
|
|
rather than slide the top bar off screen.
|
|
|
|
stateUnchanged: coming back to the app leaves the keyboard as it
|
|
was left. The default, stateUnspecified, lets the system decide,
|
|
and what it decides with a focused message field is to open the
|
|
keyboard, so switching away and back covered half the transcript
|
|
somebody had switched away to compare against. Unchanged rather
|
|
than hidden, because a keyboard that was up when the app was left
|
|
is one somebody was in the middle of typing into. -->
|
|
<activity
|
|
android:name=".MainActivity"
|
|
android:exported="true"
|
|
android:launchMode="singleTop"
|
|
android:windowSoftInputMode="adjustResize|stateUnchanged"
|
|
android:theme="@android:style/Theme.Material.Light.NoActionBar">
|
|
<intent-filter>
|
|
<action android:name="android.intent.action.MAIN" />
|
|
<category android:name="android.intent.category.LAUNCHER" />
|
|
</intent-filter>
|
|
<!-- Enrollment: the server prints its aiapp://enroll QR to the
|
|
terminal. This intent filter is the fallback path for a
|
|
camera app that redirects a scanned aiapp:// URI here
|
|
directly; the Settings screen's own "Scan QR code" button
|
|
(zxing-android-embedded) is the primary path and needs no
|
|
filter, since it decodes the QR itself and hands the URI
|
|
to parseEnrollmentUri in-process. -->
|
|
<intent-filter>
|
|
<action android:name="android.intent.action.VIEW" />
|
|
<category android:name="android.intent.category.DEFAULT" />
|
|
<category android:name="android.intent.category.BROWSABLE" />
|
|
<data android:scheme="aiapp" android:host="enroll" />
|
|
</intent-filter>
|
|
<!-- The share sheet: a file, a photo or some text from another app
|
|
lands here and is attached to a session (see Share.kt). Any
|
|
type, because what a session can be handed is the server's
|
|
decision rather than the sheet's. -->
|
|
<intent-filter>
|
|
<action android:name="android.intent.action.SEND" />
|
|
<action android:name="android.intent.action.SEND_MULTIPLE" />
|
|
<category android:name="android.intent.category.DEFAULT" />
|
|
<data android:mimeType="*/*" />
|
|
</intent-filter>
|
|
</activity>
|
|
|
|
<!-- specialUse rather than dataSync, which is the type this looks
|
|
like: Android 15 caps dataSync at six hours a day, and a
|
|
connection that stops listening after six hours is one that
|
|
misses the overnight run it exists for. The subtype below is
|
|
the reason string that type requires. -->
|
|
<service
|
|
android:name=".NotificationService"
|
|
android:exported="false"
|
|
android:foregroundServiceType="specialUse">
|
|
<property
|
|
android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
|
|
android:value="Holds one connection to the user's own backend so a session
|
|
that needs an answer can be reported while the app is closed. There is no
|
|
push service: the backend is reachable only over the user's WireGuard
|
|
tunnel and never talks to a third party." />
|
|
</service>
|
|
|
|
<!-- The scanner behind Settings' "Scan QR code". Declared here so
|
|
it can drop the library CaptureActivity's landscape pin: the
|
|
code being scanned is usually on a monitor in front of someone
|
|
holding the phone upright. zxing_CaptureTheme is the library's
|
|
own fullscreen theme, which is all the activity needs. -->
|
|
<!-- tools:ignore DiscouragedApi: lint flags every fixed
|
|
screenOrientation, because Android 16 ignores most of them.
|
|
This one is not a pin but its removal. fullSensor is what
|
|
drops the library's landscape lock, so the activity follows
|
|
the phone rather than asking anyone to turn it, and where the
|
|
platform ignores the attribute the behaviour is the one this
|
|
asked for anyway. Scoped to this activity, so a genuine pin
|
|
elsewhere would still be reported. -->
|
|
<activity
|
|
android:name="com.example.wgapplink.EnrollmentScanActivity"
|
|
android:clearTaskOnLaunch="true"
|
|
android:screenOrientation="fullSensor"
|
|
android:stateNotNeeded="true"
|
|
android:theme="@style/zxing_CaptureTheme"
|
|
android:windowSoftInputMode="stateAlwaysHidden"
|
|
tools:ignore="DiscouragedApi" />
|
|
</application>
|
|
</manifest>
|