uidriver/mobile: Implement IsForeground

This adds hooks on resuming/suspending the application, and
switches the foreground state there. This change also updates
the logic to suspend the game loop to be clearer.

Fixes #1037
This commit is contained in:
Hajime Hoshi 2020-01-22 01:58:59 +09:00
parent 38f49c3768
commit 802693fa20
4 changed files with 43 additions and 17 deletions

View File

@ -313,6 +313,7 @@ const objcM = `// Code generated by ebitenmobile. DO NOT EDIT.
@synchronized(self) { @synchronized(self) {
active_ = false; active_ = false;
EbitenmobileviewSuspend();
} }
} }
@ -321,6 +322,7 @@ const objcM = `// Code generated by ebitenmobile. DO NOT EDIT.
@synchronized(self) { @synchronized(self) {
active_ = true; active_ = true;
EbitenmobileviewResume();
} }
} }
@ -402,6 +404,7 @@ public class EbitenView extends ViewGroup {
// Activity's onPause is called. // Activity's onPause is called.
public void suspendGame() { public void suspendGame() {
ebitenSurfaceView_.onPause(); ebitenSurfaceView_.onPause();
Ebitenmobileview.suspend();
} }
// resumeGame resumes the game. // resumeGame resumes the game.
@ -409,6 +412,7 @@ public class EbitenView extends ViewGroup {
// Activity's onResume is called. // Activity's onResume is called.
public void resumeGame() { public void resumeGame() {
ebitenSurfaceView_.onResume(); ebitenSurfaceView_.onResume();
Ebitenmobileview.resume();
} }
// onErrorOnGameUpdate is called on the main thread when an error happens when updating a game. // onErrorOnGameUpdate is called on the main thread when an error happens when updating a game.

File diff suppressed because one or more lines are too long

View File

@ -21,7 +21,6 @@ import (
"fmt" "fmt"
"runtime/debug" "runtime/debug"
"sync" "sync"
"time"
"golang.org/x/mobile/app" "golang.org/x/mobile/app"
"golang.org/x/mobile/event/lifecycle" "golang.org/x/mobile/event/lifecycle"
@ -46,7 +45,9 @@ var (
// renderEndCh receives when updating finishes. // renderEndCh receives when updating finishes.
renderEndCh = make(chan struct{}) renderEndCh = make(chan struct{})
theUI = &UserInterface{} theUI = &UserInterface{
foreground: true,
}
) )
func init() { func init() {
@ -58,6 +59,13 @@ func Get() *UserInterface {
} }
func (u *UserInterface) Update() { func (u *UserInterface) Update() {
u.m.Lock()
fg := u.foreground
u.m.Unlock()
if !fg {
return
}
renderCh <- struct{}{} renderCh <- struct{}{}
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
go func() { go func() {
@ -99,6 +107,7 @@ type UserInterface struct {
scale float64 scale float64
sizeChanged bool sizeChanged bool
foreground bool
// Used for gomobile-build // Used for gomobile-build
gbuildWidthPx int gbuildWidthPx int
@ -130,6 +139,7 @@ func (u *UserInterface) appMain(a app.App) {
case lifecycle.Event: case lifecycle.Event:
switch e.Crosses(lifecycle.StageVisible) { switch e.Crosses(lifecycle.StageVisible) {
case lifecycle.CrossOn: case lifecycle.CrossOn:
u.SetForeground(true)
glctx, _ = e.DrawContext.(gl.Context) glctx, _ = e.DrawContext.(gl.Context)
// Assume that glctx is always a same instance. // Assume that glctx is always a same instance.
// Then, only once initializing should be enough. // Then, only once initializing should be enough.
@ -139,6 +149,7 @@ func (u *UserInterface) appMain(a app.App) {
} }
a.Send(paint.Event{}) a.Send(paint.Event{})
case lifecycle.CrossOff: case lifecycle.CrossOff:
u.SetForeground(false)
glctx = nil glctx = nil
} }
case size.Event: case size.Event:
@ -182,6 +193,18 @@ func (u *UserInterface) appMain(a app.App) {
} }
} }
func (u *UserInterface) SetForeground(foreground bool) {
u.m.Lock()
u.foreground = foreground
u.m.Unlock()
if foreground {
hooks.ResumeAudio()
} else {
hooks.SuspendAudio()
}
}
func (u *UserInterface) Run(context driver.UIContext) error { func (u *UserInterface) Run(context driver.UIContext) error {
// TODO: Remove width/height/scale arguments. They are not used from gomobile-build. // TODO: Remove width/height/scale arguments. They are not used from gomobile-build.
@ -290,18 +313,7 @@ func (u *UserInterface) updateSize(context driver.UIContext) {
} }
func (u *UserInterface) update(context driver.UIContext) error { func (u *UserInterface) update(context driver.UIContext) error {
t := time.NewTimer(500 * time.Millisecond) <-renderCh
defer t.Stop()
select {
case <-renderCh:
case <-t.C:
hooks.SuspendAudio()
<-renderCh
}
hooks.ResumeAudio()
defer func() { defer func() {
renderEndCh <- struct{}{} renderEndCh <- struct{}{}
}() }()
@ -370,8 +382,10 @@ func (u *UserInterface) SetFullscreen(fullscreen bool) {
} }
func (u *UserInterface) IsForeground() bool { func (u *UserInterface) IsForeground() bool {
// TODO: implement this u.m.Lock()
return true fg := u.foreground
u.m.Unlock()
return fg
} }
func (u *UserInterface) IsRunnableInBackground() bool { func (u *UserInterface) IsRunnableInBackground() bool {

View File

@ -80,3 +80,11 @@ func Update() error {
return update() return update()
} }
func Suspend() {
mobile.Get().SetForeground(false)
}
func Resume() {
mobile.Get().SetForeground(true)
}