Documentation
¶
Overview ¶
This file is the transport that binds the sovereign codec (protocol.go) to a live Java host: it dials the host's abstract unix socket, creates and maps the shared framebuffer, hands its descriptor over, paints the go-widgets root into it and posts a frame per damaged rectangle. It is CGO-free — the whole Android side of the process is a socket and an mmap, both of which Go makes on its own — so the application binary stays exactly as sovereign as it is on X11 or Wayland.
Package android implements the application half of the go-widgets Android host protocol, so a go-widgets application runs inside a real Android app exactly as it runs on X11, Wayland, Cocoa or Win32.
Android hands out no drawable surface to a process that is not the app: the whole graphics API is behind JNI, and JNI needs cgo. So the app is split in two. A thin Java host owns the Activity, the SurfaceView and the input stream; the go-widgets application is an ordinary CGO-free executable the host spawns, which paints into a shared mapping and tells the host which rectangle changed. The split is the same one the Linux back-ends already live with — a socket protocol plus a shared pixel buffer — with the Java host standing where the X server or the Wayland compositor stands.
This file is the SOVEREIGN, transport-agnostic codec: the wire messages, the framing, and the input→toolkit.Event mapping, over plain Go values. It carries no syscall and no net dependency, so it builds — and is unit-tested to 100% — on every GOOS. The transport that dials the host socket, maps the buffer and drives a widget tree lives in client.go.
Index ¶
- Constants
- Variables
- func DecodeReady(b []byte) (w, h int, err error)
- func EncodeConfig(c Config) []byte
- func EncodeFrame(r Rect) []byte
- func EncodeInsets(i Insets) []byte
- func EncodeKey(k Key) []byte
- func EncodeReady(w, h int) []byte
- func EncodeTouch(t Touch) []byte
- func FrameMessage(typ uint8, body []byte) []byte
- func MapKey(k Key) []toolkit.Event
- func MapTouch(t Touch, held bool) []toolkit.Event
- func ReadMessage(r io.Reader) (typ uint8, body []byte, err error)
- func WriteMessage(w io.Writer, typ uint8, body []byte) error
- type Client
- func (c *Client) Close() error
- func (c *Client) Density() int
- func (c *Client) Insets() Insets
- func (c *Client) Repaint()
- func (c *Client) Run(root toolkit.Widget) error
- func (c *Client) SetFullBleed(on bool)
- func (c *Client) SetTitle(title string)
- func (c *Client) Size() (int, int)
- func (c *Client) String() string
- type Config
- type Insets
- type Key
- type Rect
- type Touch
Constants ¶
const ( // MsgConfig carries the surface geometry and the shared buffer path. The // host sends it once at start-up and again on every resize or rotation. MsgConfig uint8 = 0x01 // MsgTouch carries one pointer sample in surface pixels. MsgTouch uint8 = 0x02 // MsgKey carries one key event: an Android key code plus the unicode rune // the host's key-character map produced (0 when the key produces none). MsgKey uint8 = 0x03 // MsgLifecycle carries an Activity transition: the app keeps its widget // tree across a pause, but stops painting until it resumes. MsgLifecycle uint8 = 0x04 // MsgClose asks the application to end its Run loop. MsgClose uint8 = 0x05 // MsgInsets carries the area of the surface the system is drawing over. // It is its own message rather than a Config field because insets change // on their own schedule: the soft keyboard opening does not resize the // surface, and a bar auto-hiding does not either. MsgInsets uint8 = 0x06 // MsgReady tells the host the shared buffer is mapped at the announced // size, so the host may map it in turn. Every MsgFrame that follows // refers to this mapping, until the next MsgReady replaces it. MsgReady uint8 = 0x81 // MsgFrame tells the host which surface-local rectangle changed. MsgFrame uint8 = 0x82 // MsgTitle updates the host's window title. MsgTitle uint8 = 0x83 // MsgBye tells the host the application ended. MsgBye uint8 = 0x84 )
Message types. Host→app messages are below 0x80, app→host at or above it, so a misrouted message is a decode error rather than a plausible other message.
const ( TouchDown uint8 = 0 TouchUp uint8 = 1 TouchMove uint8 = 2 )
Touch actions, matching the three MotionEvent actions the host forwards.
const ( KeyDown uint8 = 0 KeyUp uint8 = 1 )
Key actions.
const ( LifecyclePause uint8 = 0 LifecycleResume uint8 = 1 )
Lifecycle states.
const EnvSocket = "GW_ANDROID_SOCKET"
EnvSocket names the environment variable the Java host sets to the abstract socket it is listening on. The host generates a fresh name per launch, so two instances of the app never collide.
const MaxPayload = 1 << 16
MaxPayload bounds one decoded message body. The largest message a host legitimately sends is a Config carrying a filesystem path, so a frame beyond this is a desynchronised stream — refused rather than allocated.
Variables ¶
var ErrShortPayload = errors.New("android: truncated message payload")
ErrShortPayload reports a message whose body is too short for its type.
var ErrUnsupported = errors.New("android: no Android host on this platform")
ErrUnsupported reports an environment with no Android host: every GOOS but Linux, where the abstract socket and the shared mapping the host protocol needs do not exist. A cross-built application gets this from Dial and can report it and exit cleanly, exactly as go-widgets/window does off its supported back-ends.
Functions ¶
func DecodeReady ¶
DecodeReady parses a MsgReady body.
func EncodeFrame ¶
EncodeFrame builds a MsgFrame body naming the damaged rectangle.
func EncodeInsets ¶ added in v0.3.0
EncodeInsets builds a MsgInsets body.
func EncodeReady ¶
EncodeReady builds a MsgReady body: the size the application actually mapped.
func FrameMessage ¶ added in v0.4.0
FrameMessage returns one framed message: a 4-byte big-endian length covering the type byte and the body, then the type byte, then the body. Big-endian keeps the Java host on DataInputStream.readInt with no byte-swapping.
It exists as bytes rather than as writes because a message that carries an ancillary descriptor has to reach the host in ONE sendmsg: split across two writes, the host could attribute the descriptor to the wrong message.
func MapKey ¶
MapKey maps one Android key event to toolkit events, mirroring the wasmbox and X11 mappings: a named key is one EventKeyDown/EventKeyUp; a key that committed a character is an EventKeyDown followed by an EventChar on press, and an EventKeyUp on release. A key that is neither named nor printable reaches the tree as nothing.
func MapTouch ¶
MapTouch maps one pointer sample to toolkit events. It mirrors the wasmbox and X11 mappings: a press is a click, a move with the finger down is a drag. A touch screen has no hover, so a move with no finger down cannot occur and is mapped to a plain move rather than dropped, keeping a synthetic host (a test, a replay) honest.
func ReadMessage ¶
ReadMessage reads one framed message. It returns io.EOF when the stream ends cleanly between messages, so a caller can tell a closed host from a truncated one.
Types ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is an open Android host surface bound to a go-widgets scene. It satisfies window.Backend (Run/Close/Size/String), so a go-widgets app runs through Open→Run unchanged whether the backend is X11, Wayland, Cocoa, Win32, wasmbox or — here — a Java host Activity.
func Dial ¶
Dial connects to the Java host named by $GW_ANDROID_SOCKET and blocks until the host has announced its surface geometry, so the returned Client is ready to paint. It is the Android-environment analogue of openX11/openWayland.
func (*Client) Close ¶
Close ends the session: it tells the host the application is going away, unmaps the framebuffer and ends Run. Idempotent.
func (*Client) Density ¶
Density returns the display density in hundredths, as the host read it from Android's DisplayMetrics (a 3x panel is 300). It is this back-end's spelling of the backing-scale factor.
func (*Client) Insets ¶ added in v0.3.0
Insets returns the margin of the surface the system is drawing over: the status and navigation bars, a display cutout, the soft keyboard. By default the widget tree is laid out inside what they leave; see Client.SetFullBleed.
func (*Client) Repaint ¶
func (c *Client) Repaint()
Repaint asks for a repaint from ANY goroutine, satisfying window.Repainter.
func (*Client) Run ¶
Run binds root, paints the seed frame and blocks while host messages drive the widget tree, until the host closes the surface (or Close ends it). It is the Android analogue of the X11 and Wayland event loops.
func (*Client) SetFullBleed ¶ added in v0.3.0
SetFullBleed lays the widget tree out over the WHOLE surface, insets and all. It is for a root that means to reach under the system bars — a photo, a map, a video — and is then responsible for keeping anything readable out of the area Client.Insets reports.
type Config ¶
type Config struct {
// W and H are the surface size in physical pixels.
W, H int
// Density is the display density in hundredths (Android's
// DisplayMetrics.density × 100, so a 3.0x panel arrives as 300). It is the
// Android spelling of the backing-scale factor the Cocoa back-end reads
// from the screen.
Density int
// BufPath is the file the application maps as its framebuffer. The host
// picks it inside the app's own storage, which both processes share.
BufPath string
}
Config is the host's geometry announcement.
func DecodeConfig ¶
DecodeConfig parses a MsgConfig body.
type Insets ¶ added in v0.3.0
type Insets struct{ Left, Top, Right, Bottom int }
Insets is the margin of the surface the system draws over, in pixels.
An Android window is edge-to-edge from API 35: the surface really is the whole screen, and the status bar, the navigation bar, a display cutout and the soft keyboard are painted ON TOP of it rather than shrinking it. So a widget tree laid out to the full surface is correct in size and wrong in practice — its first and last rows are behind the bars. These are the four edges to keep clear.
func DecodeInsets ¶ added in v0.3.0
DecodeInsets parses a MsgInsets body.
type Key ¶
type Key struct {
Action uint8
// Code is the Android KeyEvent key code.
Code int
// Rune is the character the key produced, or 0 for a key that produces
// none (an arrow, a modifier, the back key).
Rune rune
}
Key is one key event.
type Rect ¶
type Rect struct{ X, Y, W, H int }
Rect is a surface-local rectangle in pixels. It mirrors toolkit.Rect but is kept local so the codec stays a leaf with one toolkit dependency (the event model).
