1// Copyright 2015 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// Package lifecycle defines an event for an app's lifecycle.
6//
7// The app lifecycle consists of moving back and forth between an ordered
8// sequence of stages. For example, being at a stage greater than or equal to
9// StageVisible means that the app is visible on the screen.
10//
11// A lifecycle event is a change from one stage to another, which crosses every
12// intermediate stage. For example, changing from StageAlive to StageFocused
13// implicitly crosses StageVisible.
14//
15// Crosses can be in a positive or negative direction. A positive crossing of
16// StageFocused means that the app has gained the focus. A negative crossing
17// means it has lost the focus.
18//
19// See the golang.org/x/mobile/app package for details on the event model.
20package lifecycle // import "golang.org/x/mobile/event/lifecycle"
21
22import (
23	"fmt"
24)
25
26// Cross is whether a lifecycle stage was crossed.
27type Cross uint32
28
29func (c Cross) String() string {
30	switch c {
31	case CrossOn:
32		return "on"
33	case CrossOff:
34		return "off"
35	}
36	return "none"
37}
38
39const (
40	CrossNone Cross = 0
41	CrossOn   Cross = 1
42	CrossOff  Cross = 2
43)
44
45// Event is a lifecycle change from an old stage to a new stage.
46type Event struct {
47	From, To Stage
48
49	// DrawContext is the state used for painting, if any is valid.
50	//
51	// For OpenGL apps, a non-nil DrawContext is a gl.Context.
52	//
53	// TODO: make this an App method if we move away from an event channel?
54	DrawContext interface{}
55}
56
57func (e Event) String() string {
58	return fmt.Sprintf("lifecycle.Event{From:%v, To:%v, DrawContext:%v}", e.From, e.To, e.DrawContext)
59}
60
61// Crosses reports whether the transition from From to To crosses the stage s:
62// 	- It returns CrossOn if it does, and the lifecycle change is positive.
63// 	- It returns CrossOff if it does, and the lifecycle change is negative.
64//	- Otherwise, it returns CrossNone.
65// See the documentation for Stage for more discussion of positive and negative
66// crosses.
67func (e Event) Crosses(s Stage) Cross {
68	switch {
69	case e.From < s && e.To >= s:
70		return CrossOn
71	case e.From >= s && e.To < s:
72		return CrossOff
73	}
74	return CrossNone
75}
76
77// Stage is a stage in the app's lifecycle. The values are ordered, so that a
78// lifecycle change from stage From to stage To implicitly crosses every stage
79// in the range (min, max], exclusive on the low end and inclusive on the high
80// end, where min is the minimum of From and To, and max is the maximum.
81//
82// The documentation for individual stages talk about positive and negative
83// crosses. A positive lifecycle change is one where its From stage is less
84// than its To stage. Similarly, a negative lifecycle change is one where From
85// is greater than To. Thus, a positive lifecycle change crosses every stage in
86// the range (From, To] in increasing order, and a negative lifecycle change
87// crosses every stage in the range (To, From] in decreasing order.
88type Stage uint32
89
90// TODO: how does iOS map to these stages? What do cross-platform mobile
91// abstractions do?
92
93const (
94	// StageDead is the zero stage. No lifecycle change crosses this stage,
95	// but:
96	//	- A positive change from this stage is the very first lifecycle change.
97	//	- A negative change to this stage is the very last lifecycle change.
98	StageDead Stage = iota
99
100	// StageAlive means that the app is alive.
101	//	- A positive cross means that the app has been created.
102	//	- A negative cross means that the app is being destroyed.
103	// Each cross, either from or to StageDead, will occur only once.
104	// On Android, these correspond to onCreate and onDestroy.
105	StageAlive
106
107	// StageVisible means that the app window is visible.
108	//	- A positive cross means that the app window has become visible.
109	//	- A negative cross means that the app window has become invisible.
110	// On Android, these correspond to onStart and onStop.
111	// On Desktop, an app window can become invisible if e.g. it is minimized,
112	// unmapped, or not on a visible workspace.
113	StageVisible
114
115	// StageFocused means that the app window has the focus.
116	//	- A positive cross means that the app window has gained the focus.
117	//	- A negative cross means that the app window has lost the focus.
118	// On Android, these correspond to onResume and onFreeze.
119	StageFocused
120)
121
122func (s Stage) String() string {
123	switch s {
124	case StageDead:
125		return "StageDead"
126	case StageAlive:
127		return "StageAlive"
128	case StageVisible:
129		return "StageVisible"
130	case StageFocused:
131		return "StageFocused"
132	default:
133		return fmt.Sprintf("lifecycle.Stage(%d)", s)
134	}
135}
136