cmd/tailscale,com/tailscale/ipn: implement QR sign-in for TV devices

This is a cleand up version of #27.

Fixes tailscale/tailscale#1611

Signed-off-by: Elias Naur <mail@eliasnaur.com>
pull/42/head
Elias Naur 2 years ago committed by Brad Fitzpatrick
parent e316f3b1c2
commit 83bfea18bb

@ -11,6 +11,7 @@ import android.app.Fragment;
import android.app.FragmentTransaction;
import android.app.NotificationChannel;
import android.app.PendingIntent;
import android.app.UiModeManager;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.ContentValues;
@ -21,6 +22,7 @@ import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.Signature;
import android.content.res.Configuration;
import android.provider.MediaStore;
import android.provider.Settings;
import android.net.ConnectivityManager;
@ -394,4 +396,9 @@ public class App extends Application {
return sb.toString();
}
boolean isTV() {
UiModeManager mm = (UiModeManager)getSystemService(UI_MODE_SERVICE);
return mm.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION;
}
}

@ -871,8 +871,13 @@ func (a *App) runUI() error {
ui.runningExit = p.AdvertisesExitNode()
ui.exitLAN.Value = p.ExitNodeAllowLANAccess
w.Invalidate()
case state.browseURL = <-a.browseURLs:
case url := <-a.browseURLs:
ui.signinType = noSignin
if a.isTV() {
ui.ShowQRCode(url)
} else {
state.browseURL = url
}
w.Invalidate()
a.updateState(activity, state)
case newState := <-a.netStates:
@ -948,6 +953,21 @@ func (a *App) runUI() error {
}
}
func (a *App) isTV() bool {
var istv bool
err := jni.Do(a.jvm, func(env *jni.Env) error {
cls := jni.GetObjectClass(env, a.appCtx)
m := jni.GetMethodID(env, cls, "isTV", "()Z")
b, err := jni.CallBooleanMethod(env, a.appCtx, m)
istv = b
return err
})
if err != nil {
fatalErr(err)
}
return istv
}
// isReleaseSigned reports whether the app is signed with a release
// signature.
func (a *App) isReleaseSigned() bool {

@ -25,6 +25,7 @@ import (
"gioui.org/unit"
"gioui.org/widget"
"gioui.org/widget/material"
qrcode "github.com/skip2/go-qrcode"
"golang.org/x/exp/shiny/materialdesign/icons"
"inet.af/netaddr"
"tailscale.com/client/tailscale/apitype"
@ -76,6 +77,11 @@ type UI struct {
showDebugMenu bool
runningExit bool // are we an exit node now?
qr struct {
show bool
op paint.ImageOp
}
intro struct {
list layout.List
start widget.Clickable
@ -255,6 +261,8 @@ func (ui *UI) onBack() bool {
func (ui *UI) activeDialog() *bool {
switch {
case ui.qr.show:
return &ui.qr.show
case ui.menu.show:
return &ui.menu.show
case ui.shareDialog.show:
@ -414,6 +422,9 @@ func (ui *UI) layout(gtx layout.Context, sysIns system.Insets, state *clientStat
const numHeaders = 6
n := numHeaders + len(state.Peers)
needsLogin := state.backend.State == ipn.NeedsLogin
if !needsLogin {
ui.qr.show = false
}
rootGtx := gtx
if ui.activeDialog() != nil {
rootGtx.Queue = nil
@ -494,9 +505,20 @@ func (ui *UI) layout(gtx layout.Context, sysIns system.Insets, state *clientStat
ui.layoutMenu(gtx, sysIns, expiry, exitID != "" || len(state.backend.Exits) > 0)
}
if ui.qr.show {
ui.layoutQR(gtx, sysIns)
}
return events
}
func (ui *UI) layoutQR(gtx layout.Context, sysIns system.Insets) layout.Dimensions {
fill{rgb(0x232323)}.Layout(gtx, gtx.Constraints.Max)
return layout.Center.Layout(gtx, func(gtx C) D {
return drawImage(gtx, ui.qr.op, unit.Dp(300))
})
}
func (ui *UI) FillShareDialog(targets []*apitype.FileTarget, err error) {
ui.shareDialog.error = err
ui.shareDialog.loaded = true
@ -527,6 +549,16 @@ func (ui *UI) ShowMessage(msg string) {
ui.message.t0 = time.Now()
}
func (ui *UI) ShowQRCode(url string) {
ui.qr.show = true
q, err := qrcode.New(url, qrcode.Medium)
if err != nil {
fatalErr(err)
return
}
ui.qr.op = paint.NewImageOp(q.Image(512))
}
// Dismiss is a widget that detects pointer presses.
type Dismiss struct {
}

@ -6,6 +6,7 @@ require (
eliasnaur.com/font v0.0.0-20200617114307-e02d32decb4b
gioui.org v0.0.0-20220228171706-79bfd3adbd32
gioui.org/cmd v0.0.0-20210925100615-41f3a7e74ee6
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
golang.org/x/exp v0.0.0-20210722180016-6781d3edade3
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9
golang.zx2c4.com/wireguard v0.0.0-20211116201604-de7c702ace45

@ -369,6 +369,8 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=

Loading…
Cancel
Save