Skip to content

Commit

Permalink
app, app/internal: [wasm,android] new Option to change navigation/sta…
Browse files Browse the repository at this point in the history
…tus color

Signed-off-by: Inkeliz <inkeliz@inkeliz.com>
  • Loading branch information
inkeliz committed Apr 21, 2021
1 parent 9bf4e55 commit 9522aaf
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 15 deletions.
66 changes: 66 additions & 0 deletions app/internal/wm/GioView.java
Expand Up @@ -29,6 +29,8 @@
import android.view.Surface;
import android.view.SurfaceView;
import android.view.SurfaceHolder;
import android.view.Window;
import android.view.WindowInsetsController;
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
Expand Down Expand Up @@ -132,6 +134,70 @@ private void setCursor(int id) {
setPointerIcon(pointerIcon);
}

private enum Bar {
NAVIGATION,
STATUS,
}

private void setBarColor(Bar t, int color, int luminance) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
return;
}

Window window = ((Activity) this.getContext()).getWindow();

int insetsMask;
int viewMask;

switch (t) {
case STATUS:
insetsMask = WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
viewMask = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
window.setStatusBarColor(color);
break;
case NAVIGATION:
insetsMask = WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
viewMask = View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
window.setNavigationBarColor(color);
break;
default:
throw new RuntimeException("invalid bar type");
}

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
return;
}

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
int flags = this.getSystemUiVisibility();
if (luminance > 128) {
flags |= viewMask;
} else {
flags &= ~viewMask;
}
this.setSystemUiVisibility(flags);
return;
}

WindowInsetsController insetsController = window.getInsetsController();
if (insetsController == null) {
return;
}
if (luminance > 128) {
insetsController.setSystemBarsAppearance(insetsMask, insetsMask);
} else {
insetsController.setSystemBarsAppearance(0, insetsMask);
}
}

private void setStatusColor(int color, int luminance) {
this.setBarColor(Bar.STATUS, color, luminance);
}

private void setNavigationColor(int color, int luminance) {
this.setBarColor(Bar.NAVIGATION, color, luminance);
}

private void dispatchMotionEvent(MotionEvent event) {
for (int j = 0; j < event.getHistorySize(); j++) {
long time = event.getHistoricalEventTime(j);
Expand Down
58 changes: 49 additions & 9 deletions app/internal/wm/os_android.go
Expand Up @@ -42,7 +42,9 @@ import "C"
import (
"errors"
"fmt"
"gioui.org/internal/f32color"
"image"
"image/color"
"reflect"
"runtime"
"runtime/debug"
Expand Down Expand Up @@ -82,18 +84,22 @@ type window struct {
// windowState tracks the View or Activity specific state lost when Android
// re-creates our Activity.
type windowState struct {
cursor *pointer.CursorName
cursor *pointer.CursorName
navigationColor *color.NRGBA
statusColor *color.NRGBA
}

// gioView hold cached JNI methods for GioView.
var gioView struct {
once sync.Once
getDensity C.jmethodID
getFontScale C.jmethodID
showTextInput C.jmethodID
hideTextInput C.jmethodID
postFrameCallback C.jmethodID
setCursor C.jmethodID
once sync.Once
getDensity C.jmethodID
getFontScale C.jmethodID
showTextInput C.jmethodID
hideTextInput C.jmethodID
postFrameCallback C.jmethodID
setCursor C.jmethodID
setNavigationColor C.jmethodID
setStatusColor C.jmethodID
}

// ViewEvent is sent whenever the Window's underlying Android view
Expand Down Expand Up @@ -220,6 +226,8 @@ func Java_org_gioui_GioView_onCreateView(env *C.JNIEnv, class C.jclass, view C.j
m.hideTextInput = getMethodID(env, class, "hideTextInput", "()V")
m.postFrameCallback = getMethodID(env, class, "postFrameCallback", "()V")
m.setCursor = getMethodID(env, class, "setCursor", "(I)V")
m.setNavigationColor = getMethodID(env, class, "setNavigationColor", "(II)V")
m.setStatusColor = getMethodID(env, class, "setStatusColor", "(II)V")
})
view = C.gio_jni_NewGlobalRef(env, view)
wopts := <-mainWindow.out
Expand All @@ -235,6 +243,7 @@ func Java_org_gioui_GioView_onCreateView(env *C.JNIEnv, class C.jclass, view C.j
handle := C.jlong(view)
views[handle] = w
w.loadConfig(env, class)
w.Option(wopts.opts)
applyStateDiff(env, view, windowState{}, w.state)
w.setStage(system.StagePaused)
w.callbacks.Event(ViewEvent{View: uintptr(view)})
Expand Down Expand Up @@ -676,7 +685,18 @@ func (w *window) ReadClipboard() {
})
}

func (w *window) Option(opts *Options) {}
func (w *window) Option(opts *Options) {
if o := opts.NavigationColor; o != nil {
w.setState(func(state *windowState) {
state.navigationColor = o
})
}
if o := opts.StatusColor; o != nil {
w.setState(func(state *windowState) {
state.statusColor = o
})
}
}

func (w *window) SetCursor(name pointer.CursorName) {
w.setState(func(state *windowState) {
Expand All @@ -703,6 +723,12 @@ func applyStateDiff(env *C.JNIEnv, view C.jobject, old, state windowState) {
if state.cursor != nil && old.cursor != state.cursor {
setCursor(env, view, *state.cursor)
}
if state.navigationColor != nil && old.navigationColor != state.navigationColor {
setNavigationColor(env, view, *state.navigationColor)
}
if state.statusColor != nil && old.statusColor != state.statusColor {
setStatusColor(env, view, *state.statusColor)
}
}

func setCursor(env *C.JNIEnv, view C.jobject, name pointer.CursorName) {
Expand All @@ -728,6 +754,20 @@ func setCursor(env *C.JNIEnv, view C.jobject, name pointer.CursorName) {
callVoidMethod(env, view, gioView.setCursor, jvalue(curID))
}

func setStatusColor(env *C.JNIEnv, view C.jobject, color color.NRGBA) {
callVoidMethod(env, view, gioView.setStatusColor,
jvalue(uint32(color.A)<<24|uint32(color.R)<<16|uint32(color.G)<<8|uint32(color.B)),
jvalue(int(f32color.LinearFromSRGB(color).Luminance()*255)),
)
}

func setNavigationColor(env *C.JNIEnv, view C.jobject, color color.NRGBA) {
callVoidMethod(env, view, gioView.setNavigationColor,
jvalue(uint32(color.A)<<24|uint32(color.R)<<16|uint32(color.G)<<8|uint32(color.B)),
jvalue(int(f32color.LinearFromSRGB(color).Luminance()*255)),
)
}

// Close the window. Not implemented for Android.
func (w *window) Close() {}

Expand Down
21 changes: 20 additions & 1 deletion app/internal/wm/os_js.go
Expand Up @@ -3,7 +3,10 @@
package wm

import (
"fmt"
"gioui.org/internal/f32color"
"image"
"image/color"
"strings"
"sync"
"syscall/js"
Expand All @@ -22,6 +25,7 @@ import (
type window struct {
window js.Value
document js.Value
head js.Value
clipboard js.Value
cnv js.Value
tarea js.Value
Expand Down Expand Up @@ -61,6 +65,7 @@ func NewWindow(win Callbacks, opts *Options) error {
document: doc,
tarea: tarea,
window: js.Global().Get("window"),
head: doc.Get("head"),
clipboard: js.Global().Get("navigator").Get("clipboard"),
}
w.requestAnimationFrame = w.window.Get("requestAnimationFrame")
Expand Down Expand Up @@ -486,6 +491,9 @@ func (w *window) Option(opts *Options) {
if o := opts.WindowMode; o != nil {
w.windowMode(*o)
}
if o := opts.NavigationColor; o != nil {
w.navigationColor(*o)
}
}

func (w *window) SetCursor(name pointer.CursorName) {
Expand Down Expand Up @@ -567,7 +575,7 @@ func (w *window) config() (int, int, system.Insets, unit.Metric) {
func (w *window) windowMode(mode WindowMode) {
switch mode {
case Windowed:
if fs := w.document.Get("fullscreenElement"); !fs.Truthy() {
if !w.document.Get("fullscreenElement").Truthy() {
return // Browser is already Windowed.
}
if !w.document.Get("exitFullscreen").Truthy() {
Expand All @@ -583,6 +591,17 @@ func (w *window) windowMode(mode WindowMode) {
}
}

func (w *window) navigationColor(c color.NRGBA) {
theme := w.head.Call("querySelector", `meta[name="theme-color"]`)
if !theme.Truthy() {
theme = w.document.Call("createElement", "meta")
theme.Set("name", "theme-color")
w.head.Call("appendChild", theme)
}
rgba := f32color.NRGBAToLinearRGBA(c)
theme.Set("content", fmt.Sprintf("#%06X", []uint8{rgba.R, rgba.G, rgba.B}))
}

func Main() {
select {}
}
Expand Down
13 changes: 8 additions & 5 deletions app/internal/wm/window.go
Expand Up @@ -6,6 +6,7 @@ package wm

import (
"errors"
"image/color"

"gioui.org/gpu"
"gioui.org/io/event"
Expand All @@ -20,11 +21,13 @@ type Size struct {
}

type Options struct {
Size *Size
MinSize *Size
MaxSize *Size
Title *string
WindowMode *WindowMode
Size *Size
MinSize *Size
MaxSize *Size
Title *string
WindowMode *WindowMode
StatusColor *color.NRGBA
NavigationColor *color.NRGBA
}

type WindowMode uint8
Expand Down
15 changes: 15 additions & 0 deletions app/window.go
Expand Up @@ -6,6 +6,7 @@ import (
"errors"
"fmt"
"image"
"image/color"
"time"

"gioui.org/io/event"
Expand Down Expand Up @@ -525,4 +526,18 @@ func MinSize(w, h unit.Value) Option {
}
}

// StatusColor sets the color of the Android status bar.
func StatusColor(color color.NRGBA) Option {
return func(opts *wm.Options) {
opts.StatusColor = &color
}
}

// NavigationColor sets the color of the navigation bar on Android, or the address bar in browsers.
func NavigationColor(color color.NRGBA) Option {
return func(opts *wm.Options) {
opts.NavigationColor = &color
}
}

func (driverEvent) ImplementsEvent() {}

0 comments on commit 9522aaf

Please sign in to comment.