Merge d1f428ba5f
into e76a4afd85
commit
09d44f6b0d
|
@ -167,6 +167,10 @@ simulator:
|
||||||
:alt: Software selection app running on the wasp-os simulator
|
:alt: Software selection app running on the wasp-os simulator
|
||||||
:width: 179
|
:width: 179
|
||||||
|
|
||||||
|
.. image:: res/PhoneApp.png
|
||||||
|
:alt: Phone application running on the wasp-os simulator
|
||||||
|
:width: 179
|
||||||
|
|
||||||
|
|
||||||
wasp-os also contains a library of additional applications for you to choose.
|
wasp-os also contains a library of additional applications for you to choose.
|
||||||
These are disabled by default but can be easily enabled using the Software
|
These are disabled by default but can be easily enabled using the Software
|
||||||
|
|
|
@ -36,6 +36,8 @@ Built-in
|
||||||
|
|
||||||
.. automodule:: apps.pager
|
.. automodule:: apps.pager
|
||||||
|
|
||||||
|
.. automodule:: apps.phone
|
||||||
|
|
||||||
Applications
|
Applications
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 8.2 KiB |
Binary file not shown.
After Width: | Height: | Size: 432 B |
Binary file not shown.
After Width: | Height: | Size: 525 B |
|
@ -0,0 +1,150 @@
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
# Copyright (C) 2020 Daniel Thompson
|
||||||
|
# Copyright (C) 2020 Carlos Gil
|
||||||
|
|
||||||
|
"""Phone for GadgetBridge and wasp-os companion
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. figure:: res/PhoneApp.png
|
||||||
|
:width: 179
|
||||||
|
|
||||||
|
Screenshot of the Phone application
|
||||||
|
|
||||||
|
Phone Controller:
|
||||||
|
|
||||||
|
* Touch: answer/end
|
||||||
|
* Event BACK: ignore/close
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import wasp
|
||||||
|
|
||||||
|
import icons
|
||||||
|
import time
|
||||||
|
|
||||||
|
from micropython import const
|
||||||
|
|
||||||
|
DISPLAY_WIDTH = const(240)
|
||||||
|
ICON_SIZE = const(72)
|
||||||
|
CENTER_AT = const((DISPLAY_WIDTH - ICON_SIZE) // 2)
|
||||||
|
|
||||||
|
class PhoneApp(object):
|
||||||
|
""" Phone application."""
|
||||||
|
NAME = 'Phone'
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._anwser = wasp.widgets.GfxButton(24, CENTER_AT, icons.phone)
|
||||||
|
self._end = wasp.widgets.GfxButton(DISPLAY_WIDTH - ICON_SIZE - 24, CENTER_AT, icons.hangup)
|
||||||
|
self._state = "end"
|
||||||
|
self._name = ''
|
||||||
|
self._number = ''
|
||||||
|
self._state_changed = True
|
||||||
|
self._name_changed = True
|
||||||
|
self._number_changed = True
|
||||||
|
|
||||||
|
def _send_cmd(self, cmd):
|
||||||
|
print('\r')
|
||||||
|
for i in range(1):
|
||||||
|
for i in range(0, len(cmd), 20):
|
||||||
|
print(cmd[i: i + 20], end='')
|
||||||
|
time.sleep(0.2)
|
||||||
|
print(' ')
|
||||||
|
print(' ')
|
||||||
|
|
||||||
|
def _fill_space(self, key):
|
||||||
|
if key == 'top':
|
||||||
|
wasp.watch.drawable.fill(
|
||||||
|
x=0, y=0, w=DISPLAY_WIDTH, h=CENTER_AT)
|
||||||
|
elif key == 'down':
|
||||||
|
wasp.watch.drawable.fill(x=0, y=CENTER_AT + ICON_SIZE,
|
||||||
|
w=DISPLAY_WIDTH,
|
||||||
|
h=DISPLAY_WIDTH - (CENTER_AT + ICON_SIZE))
|
||||||
|
|
||||||
|
def foreground(self):
|
||||||
|
"""Activate the application."""
|
||||||
|
number = wasp.system.phonestate.get('number')
|
||||||
|
name = wasp.system.phonestate.get('name')
|
||||||
|
state = wasp.system.phonestate.get('cmd')
|
||||||
|
|
||||||
|
if number:
|
||||||
|
self._number = number
|
||||||
|
if name:
|
||||||
|
self._name = name
|
||||||
|
if state:
|
||||||
|
self._state = state
|
||||||
|
wasp.watch.drawable.fill()
|
||||||
|
self.draw()
|
||||||
|
wasp.system.request_tick(1000)
|
||||||
|
wasp.system.request_event(wasp.EventMask.TOUCH)
|
||||||
|
|
||||||
|
def background(self):
|
||||||
|
"""De-activate the application (without losing state)."""
|
||||||
|
self._state_changed = True
|
||||||
|
self._name_changed = True
|
||||||
|
self._number_changed = True
|
||||||
|
|
||||||
|
def tick(self, ticks):
|
||||||
|
wasp.system.keep_awake()
|
||||||
|
state_now = wasp.system.phonestate.get('cmd')
|
||||||
|
name_now = wasp.system.phonestate.get('name')
|
||||||
|
number_now = wasp.system.phonestate.get('number')
|
||||||
|
if state_now:
|
||||||
|
if state_now != self._state:
|
||||||
|
self._state = state_now
|
||||||
|
self._state_changed = True
|
||||||
|
else:
|
||||||
|
self._state_changed = False
|
||||||
|
if name_now:
|
||||||
|
if name_now != self._name:
|
||||||
|
self._name = name_now
|
||||||
|
self._name_changed = True
|
||||||
|
else:
|
||||||
|
self._name_changed = False
|
||||||
|
if number_now:
|
||||||
|
if number_now != self._number:
|
||||||
|
self._number = number_now
|
||||||
|
self._number_changed = True
|
||||||
|
else:
|
||||||
|
self._number_changed = False
|
||||||
|
wasp.system.phonestate = {}
|
||||||
|
self._update()
|
||||||
|
|
||||||
|
def touch(self, event):
|
||||||
|
if self._anwser.touch(event):
|
||||||
|
self._send_cmd('{"t":"call", "n":"ACCEPT"} ')
|
||||||
|
wasp.system.navigate(wasp.EventType.BACK)
|
||||||
|
elif self._end.touch(event):
|
||||||
|
self._send_cmd('{"t":"call", "n":"REJECT"} ')
|
||||||
|
wasp.system.navigate(wasp.EventType.BACK)
|
||||||
|
|
||||||
|
def draw(self):
|
||||||
|
"""Redraw the display from scratch."""
|
||||||
|
self._draw()
|
||||||
|
|
||||||
|
def _draw(self):
|
||||||
|
"""Redraw the updated zones."""
|
||||||
|
if self._state_changed:
|
||||||
|
self._anwser.draw()
|
||||||
|
if self._name_changed:
|
||||||
|
self._draw_label(self._name, 24 + 144)
|
||||||
|
if self._number_changed:
|
||||||
|
self._draw_label(self._number, 12)
|
||||||
|
self._end.draw()
|
||||||
|
|
||||||
|
def _draw_label(self, label, pos):
|
||||||
|
"""Redraw label info"""
|
||||||
|
if label:
|
||||||
|
draw = wasp.watch.drawable
|
||||||
|
chunks = draw.wrap(label, 240)
|
||||||
|
self._fill_space(pos)
|
||||||
|
for i in range(len(chunks)-1):
|
||||||
|
sub = label[chunks[i]:chunks[i+1]].rstrip()
|
||||||
|
draw.string(sub, 0, pos + 24 * i, 240)
|
||||||
|
|
||||||
|
def _update(self):
|
||||||
|
if(self._state == "start" or self._state == "incoming"):
|
||||||
|
wasp.watch.vibrator.pulse(ms=wasp.system.notify_duration)
|
||||||
|
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
pass
|
|
@ -17,6 +17,7 @@ manifest = (
|
||||||
'apps/launcher.py',
|
'apps/launcher.py',
|
||||||
'apps/pager.py',
|
'apps/pager.py',
|
||||||
'apps/play2048.py',
|
'apps/play2048.py',
|
||||||
|
'apps/phone.py',
|
||||||
'apps/settings.py',
|
'apps/settings.py',
|
||||||
'apps/software.py',
|
'apps/software.py',
|
||||||
'apps/steps.py',
|
'apps/steps.py',
|
||||||
|
|
|
@ -13,6 +13,12 @@ wasp.system.set_music_info({
|
||||||
'artist': 'Dreams of Bamboo',
|
'artist': 'Dreams of Bamboo',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
wasp.system.set_phone_state({
|
||||||
|
'cmd': 'end',
|
||||||
|
'name': '5555555555',
|
||||||
|
'number': 'Unknown Caller',
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
# Increase the display blanking time to avoid spamming the console
|
# Increase the display blanking time to avoid spamming the console
|
||||||
# with backlight activations.
|
# with backlight activations.
|
||||||
|
|
|
@ -11,3 +11,5 @@ settings = 'Default settings icon'
|
||||||
torch = 'Default torch or flashlight icon'
|
torch = 'Default torch or flashlight icon'
|
||||||
up_arrow = 'Small (16x9) up arrow'
|
up_arrow = 'Small (16x9) up arrow'
|
||||||
down_arrow = 'Small (16x9) down arrow'
|
down_arrow = 'Small (16x9) down arrow'
|
||||||
|
phone = 'A phone icon rotated to look as if it is picked up'
|
||||||
|
hangup = 'A phone icon'
|
|
@ -56,6 +56,8 @@ def GB(cmd):
|
||||||
wasp.system.toggle_music(cmd)
|
wasp.system.toggle_music(cmd)
|
||||||
elif task == 'musicinfo':
|
elif task == 'musicinfo':
|
||||||
wasp.system.set_music_info(cmd)
|
wasp.system.set_music_info(cmd)
|
||||||
|
elif task == 'call':
|
||||||
|
wasp.system.set_phone_state(cmd)
|
||||||
else:
|
else:
|
||||||
pass
|
pass
|
||||||
#_info('Command "{}" is not implemented'.format(cmd))
|
#_info('Command "{}" is not implemented'.format(cmd))
|
||||||
|
|
|
@ -303,3 +303,29 @@ checkbox = (
|
||||||
b'Z\xc7X\xe4\x01\xde\x03\xdc\x02'
|
b'Z\xc7X\xe4\x01\xde\x03\xdc\x02'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 2-bit RLE, generated from res/phone.png, 126 bytes
|
||||||
|
phone = (
|
||||||
|
b'\x02'
|
||||||
|
b'HH'
|
||||||
|
b'?\xff\xff\xa8\xc4?\x03\xc7?\x01\xc9>\xcb<\xcc;'
|
||||||
|
b'\xce:\xcf8\xd07\xd26\xd26\xd25\xd44\xd44'
|
||||||
|
b'\xd44\xd35\xd35\xd26\xd17\xcf9\xce:\xcd<'
|
||||||
|
b'\xcc<\xcc<\xcc=\xcb=\xcc<\xcd<\xcc<\xcd<'
|
||||||
|
b"\xcc<\xcd<\xcd<\xcd<\xcd\x0e\xc5(\xce\x0c\xc8'"
|
||||||
|
b'\xce\n\xcb&\xce\x07\xce&\xd0\x03\xd0&\xe3&\xe3&'
|
||||||
|
b"\xe3&\xe2'\xe1(\xe0)\xdf*\xdd,\xdc.\xd90"
|
||||||
|
b'\xd63\xd47\xcf<\xc9?\xff\xff\xa9'
|
||||||
|
)
|
||||||
|
|
||||||
|
# 2-bit RLE, generated from res/hangup.png, 104 bytes
|
||||||
|
hangup = (
|
||||||
|
b'\x02'
|
||||||
|
b'HH'
|
||||||
|
b'?\xff\xff\xff\xff\xff8\xd40\xdc)\xe3"\xe7 \xea'
|
||||||
|
b'\x1c\xee\x19\xf0\x17\xf2\x15\xf4\x13\xf6\x11\xda\x05\xd8\x11\xd4'
|
||||||
|
b'\x10\xd4\x0f\xd2\x15\xd2\x0f\xd1\x17\xd2\x0e\xd1\x17\xd2\r\xd2'
|
||||||
|
b'\x17\xd2\r\xd2\x17\xd2\r\xd2\x17\xd2\r\xd2\x17\xd2\r\xd2'
|
||||||
|
b'\x17\xd2\r\xd2\x17\xd2\r\xd2\x18\xd1\r\xd1\x19\xd1\r\xd1'
|
||||||
|
b'\x1a\xd0\r\xd0\x1d\xce\x0e\xcd!\xcb\x10\xc8?\xff\xff\xff'
|
||||||
|
b'\xff\xff\xff\xffP'
|
||||||
|
)
|
|
@ -30,6 +30,7 @@ from apps.settings import SettingsApp
|
||||||
from apps.steps import StepCounterApp
|
from apps.steps import StepCounterApp
|
||||||
from apps.software import SoftwareApp
|
from apps.software import SoftwareApp
|
||||||
from apps.stopwatch import StopwatchApp
|
from apps.stopwatch import StopwatchApp
|
||||||
|
from apps.phone import PhoneApp
|
||||||
|
|
||||||
class EventType():
|
class EventType():
|
||||||
"""Enumerated interface actions.
|
"""Enumerated interface actions.
|
||||||
|
@ -117,6 +118,8 @@ class Manager():
|
||||||
self.notifications = {}
|
self.notifications = {}
|
||||||
self.musicstate = {}
|
self.musicstate = {}
|
||||||
self.musicinfo = {}
|
self.musicinfo = {}
|
||||||
|
self.call = PhoneApp()
|
||||||
|
self.phonestate = {}
|
||||||
|
|
||||||
self._theme = (
|
self._theme = (
|
||||||
b'\x7b\xef' # ble
|
b'\x7b\xef' # ble
|
||||||
|
@ -320,6 +323,12 @@ class Manager():
|
||||||
def set_music_info(self, info):
|
def set_music_info(self, info):
|
||||||
self.musicinfo = info
|
self.musicinfo = info
|
||||||
|
|
||||||
|
def set_phone_state(self, info):
|
||||||
|
self.phonestate = info
|
||||||
|
if(self.phonestate.get("cmd") == "start" or self.phonestate.get("cmd") == "incoming"):
|
||||||
|
self.wake()
|
||||||
|
self.switch(self.call)
|
||||||
|
|
||||||
def set_alarm(self, time, action):
|
def set_alarm(self, time, action):
|
||||||
"""Queue an alarm.
|
"""Queue an alarm.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue