exp/sensor: don't enable a sensor on a sender

The underlying implementation was not enabling the sensors on a
particular sender even though the Enable signature accepts different
instances of Sender to enable.

Consider the following program:

  type A struct{}
  func (a A) Send(ev interface{}) {}

  type B struct{}
  func (b B) Send(ev interface{}) {}

  sensor.Enable(A{}, sensor.Gyroscope, time.Millisecond)
  sensor.Enable(B{}, sensor.Accelerometer, time.Millisecond)

is going to compile but only A will be notified when there are new
gyroscope and accelerometer events.

In order to improve the misleading APIs, this CL introduces a
Notify function that users can register a Sender implementation to
listen the changes. If set nil, the sensor package will keep
reading the events but will won't notify.

  sensor.Notify(A{})
  sensor.Enable(sensor.Gyroscope, time.Millisecond)
  sensor.Enable(sensor.Accelerometer, time.Millisecond)

Change-Id: I25e43349e4ae682930baa2d32430f46f24b588b7
Reviewed-on: https://go-review.googlesource.com/15650
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
This commit is contained in:
Burcu Dogan
2015-10-09 11:30:18 -07:00
parent f1034a4131
commit 1b12574c99
4 changed files with 56 additions and 14 deletions

View File

@ -101,8 +101,10 @@ func init() {
}() }()
} }
func enable(s Sender, t Type, delay time.Duration) error { // enable enables the sensor t on sender. A non-nil sender is
startCollecting(s) // required before calling enable.
func enable(t Type, delay time.Duration) error {
startCollecting()
var err error var err error
done := make(chan struct{}) done := make(chan struct{})
@ -114,7 +116,7 @@ func enable(s Sender, t Type, delay time.Duration) error {
return err return err
} }
func startCollecting(s Sender) { func startCollecting() {
collectingMu.Lock() collectingMu.Lock()
defer collectingMu.Unlock() defer collectingMu.Unlock()
@ -135,7 +137,7 @@ func startCollecting(s Sender) {
} }
<-done <-done
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
s.Send(ev[i]) sender.Send(ev[i])
} }
} }
}() }()

View File

@ -60,7 +60,9 @@ func init() {
const minDelay = 10 * time.Millisecond const minDelay = 10 * time.Millisecond
func enable(s Sender, t Type, delay time.Duration) error { // enable enables the sensor t on sender. A non-nil sender is
// required before calling enable.
func enable(t Type, delay time.Duration) error {
channels.Lock() channels.Lock()
defer channels.Unlock() defer channels.Unlock()
@ -82,7 +84,7 @@ func enable(s Sender, t Type, delay time.Duration) error {
case Magnetometer: case Magnetometer:
C.GoIOS_startMagneto(interval) C.GoIOS_startMagneto(interval)
} }
go pollSensor(s, t, delay, channels.done[t]) go pollSensor(t, delay, channels.done[t])
return nil return nil
} }
@ -107,7 +109,7 @@ func disable(t Type) error {
return nil return nil
} }
func pollSensor(s Sender, t Type, d time.Duration, done chan struct{}) { func pollSensor(t Type, d time.Duration, done chan struct{}) {
var lastTimestamp int64 var lastTimestamp int64
var timestamp C.int64_t var timestamp C.int64_t
@ -133,7 +135,7 @@ func pollSensor(s Sender, t Type, d time.Duration, done chan struct{}) {
if ts > lastTimestamp { if ts > lastTimestamp {
// TODO(jbd): Do we need to convert the values to another unit? // TODO(jbd): Do we need to convert the values to another unit?
// How does iOS units compare to the Android units. // How does iOS units compare to the Android units.
s.Send(Event{ sender.Send(Event{
Sensor: t, Sensor: t,
Timestamp: ts, Timestamp: ts,
Data: []float64{float64(ev[0]), float64(ev[1]), float64(ev[2])}, Data: []float64{float64(ev[0]), float64(ev[1]), float64(ev[2])},

View File

@ -11,7 +11,7 @@ import (
"time" "time"
) )
func enable(s Sender, t Type, delay time.Duration) error { func enable(t Type, delay time.Duration) error {
return errors.New("sensor: no sensors available") return errors.New("sensor: no sensors available")
} }

View File

@ -7,6 +7,7 @@ package sensor // import "golang.org/x/mobile/exp/sensor"
import ( import (
"errors" "errors"
"sync"
"time" "time"
) )
@ -66,20 +67,47 @@ type Event struct {
// TODO(jbd): Move Sender interface definition to a top-level package. // TODO(jbd): Move Sender interface definition to a top-level package.
var (
// senderMu protects sender.
senderMu sync.Mutex
// sender is notified with the sensor data each time a new event is available.
sender Sender
)
// Sender sends an event. // Sender sends an event.
type Sender interface { type Sender interface {
Send(event interface{}) Send(event interface{})
} }
// Notify registers a Sender and sensor events will be sent to s.
// A typical example of Sender implementations is app.App.
// Once you call Notify, you are not allowed to call it again.
// You cannot call Notify with a nil Sender.
func Notify(s Sender) {
senderMu.Lock()
defer senderMu.Unlock()
if s == nil {
panic("sensor: cannot set a nil sender")
}
if sender != nil {
panic("sensor: another sender is being notified, cannot set s as the sender")
}
sender = s
}
// Enable enables the specified sensor type with the given delay rate. // Enable enables the specified sensor type with the given delay rate.
// Sensor events will be sent to s, a typical example of Sender // Users must set a non-nil Sender via Notify before enabling a sensor,
// implementations is app.App. // otherwise an error will be returned.
// Enable is not safe for concurrent use. func Enable(t Type, delay time.Duration) error {
func Enable(s Sender, t Type, delay time.Duration) error {
if t < 0 || int(t) >= len(sensorNames) { if t < 0 || int(t) >= len(sensorNames) {
return errors.New("sensor: unknown sensor type") return errors.New("sensor: unknown sensor type")
} }
return enable(s, t, delay) if err := validSender(); err != nil {
return err
}
return enable(t, delay)
} }
// Disable disables to feed the manager with the specified sensor. // Disable disables to feed the manager with the specified sensor.
@ -90,3 +118,13 @@ func Disable(t Type) error {
} }
return disable(t) return disable(t)
} }
func validSender() error {
senderMu.Lock()
defer senderMu.Unlock()
if sender == nil {
return errors.New("sensor: no senders to be notified; cannot enable the sensor")
}
return nil
}