diff --git a/Menu/GameShell/10_Settings/Bluetooth/__init__.py b/Menu/GameShell/10_Settings/Bluetooth/__init__.py index 3d161d7..c413441 100644 --- a/Menu/GameShell/10_Settings/Bluetooth/__init__.py +++ b/Menu/GameShell/10_Settings/Bluetooth/__init__.py @@ -28,9 +28,12 @@ from UI.info_page_list_item import InfoPageListItem from UI.multilabel import MultiLabel from UI.lang_manager import MyLangManager +from UI.keyboard import Keyboard from net_item import NetItem +from agent import BleAgent,BleAgentPairPage + class BleForgetConfirmPage(ConfirmPage): _ConfirmText = MyLangManager.Tr("ConfirmForgetQ") @@ -189,9 +192,16 @@ class BleInfoPage(Page): try: adapter.RemoveDevice(dev) except Exception,e: - print(str(e)) + err_name = e.get_dbus_name() + if err_name == "org.freedesktop.DBus.Error.NoReply": + self._Screen._MsgBox.SetText("DBus noreply") + else: + self._Screen._MsgBox.SetText("Forget failed") + + self._Screen._MsgBox.Draw() + self._Screen.SwapAndShow() - pygame.time.delay(400) + pygame.time.delay(500) self.ReturnToUpLevelPage() self._Screen.Draw() @@ -215,9 +225,15 @@ class BleInfoPage(Page): try: dev.Disconnect() except Exception,e: - print(str(e)) + err_name = e.get_dbus_name() + if err_name == "org.freedesktop.DBus.Error.NoReply": + self._Screen._MsgBox.SetText("DBus noreply") + else: + self._Screen._MsgBox.SetText("Disconnect failed") + self._Screen._MsgBox.Draw() + self._Screen.SwapAndShow() - pygame.time.delay(300) + pygame.time.delay(500) self.ReturnToUpLevelPage() self._Screen.Draw() self._Screen.SwapAndShow() @@ -372,6 +388,8 @@ class BluetoothPage(Page): _Offline = False + _Leader = None + def __init__(self): Page.__init__(self) self._MyList = [] @@ -480,7 +498,7 @@ class BluetoothPage(Page): self._Screen.SwapAndShow() def ShutDownConnecting(self): - print("Shutdownconnecting...") + print("Bluetooth Shutdown connecting...") def AbortedAndReturnToUpLevel(self): self.HideBox() @@ -512,13 +530,18 @@ class BluetoothPage(Page): self._Screen._FootBar.UpdateNavText("Connecting") self.ShowBox(MyLangManager.Tr("Connecting")) + self._Leader._MyAgent.device_obj = dev + self._Leader._MyAgent.dev_path = cur_li._Path + try: - dev.Connect() + dev.Pair(reply_handler=self._Leader._MyAgent.pair_reply, + error_handler=self._Leader._MyAgent.pair_error,timeout=60000) except Exception,e: print(str(e)) - self.HideBox() - self._Screen._FootBar.ResetNavText() + + #self.HideBox() + #self._Screen._FootBar.ResetNavText() def RefreshDevices(self): global devices @@ -577,7 +600,7 @@ class BluetoothPage(Page): proxy_obj = self._Dbus.get_object("org.bluez", "/org/bluez/" + self._ADAPTER_DEV) adapter_props = dbus.Interface(proxy_obj,"org.freedesktop.DBus.Properties") discoverying = adapter_props.Get("org.bluez.Adapter1", "Discovering") - print(discoverying) + print("discoverying", discoverying) if self._Adapter!= None: @@ -589,7 +612,11 @@ class BluetoothPage(Page): try: self._Adapter.StartDiscovery() except Exception,e: - print(str(e)) + err_name = e.get_dbus_name() + if err_name == "org.freedesktop.DBus.Error.NoReply": + print("start discovery timeout") + else: + print("start discovery unknown err: ", str(e)) def OnReturnBackCb(self): self.RefreshDevices() @@ -688,17 +715,59 @@ class BluetoothPage(Page): - - - - +BUS_NAME = 'org.bluez' +AGENT_INTERFACE = 'org.bluez.Agent1' +AGENT_PATH = "/gameshell/bleagent" class APIOBJ(object): _Page = None - def __init__(self): - pass + _PairPage = None + _Page3 = None + _Prompts = {} # string key,string value + _PromptType = None + _MyAgent = None + def __init__(self): + self._Prompts["PIN"]="" + self._Prompts["PASS"]="" + + def OnKbdReturnBackCb(self): + if self._PromptType == None: + return + else: + if self._PromptType in self._Prompts: + inputed = "".join(self._Page3._Textarea._MyWords) + self._Prompts[self._PromptType] = inputed + + self._PromptType = None ##clear + + + def Ask(self,prompt,prompt_type=None): + + self._Screen.PushPage(self._Page3) + self._Page3.SetPassword("") + self._Page3._Name = prompt + self._Page3._Caller = self + + self._Screen.Draw() + self._Screen.SwapAndShow() + + if prompt_type != None: + self._PromptType = prompt_type + + def RegisterMyAgent(self): + global AGENT_PATH, bus,devices,adapter + + capability = "KeyboardDisplay" + self._MyAgent = BleAgent(bus, AGENT_PATH) + self._MyAgent._Leader = self + + obj = bus.get_object(BUS_NAME, "/org/bluez"); + manager = dbus.Interface(obj, "org.bluez.AgentManager1") + manager.RegisterAgent(AGENT_PATH, capability) + print("BleAgent %s registered" % AGENT_PATH) + def Init(self,main_screen): global bus,devices,adapter @@ -710,14 +779,28 @@ class APIOBJ(object): self._Page._Screen = main_screen self._Page._Name ="Bluetooth" + self._Page._Leader = self + self._Page.Init() + self._PairPage = BleAgentPairPage() + self._PairPage._Screen = main_screen + self._PairPage._Name = "Bluetooth" + self._PairPage.Init() + + self._Page3= Keyboard() + self._Page3._Name = "Enter" + self._Page3._Screen = main_screen + self._Page3.Init() + bus.add_signal_receiver(self._Page.DbusPropertiesChanged, dbus_interface = "org.freedesktop.DBus.Properties", signal_name = "PropertiesChanged", arg0 = "org.bluez.Device1", path_keyword = "path") - + + self.RegisterMyAgent() + def API(self,main_screen): if main_screen !=None: main_screen.PushPage(self._Page) diff --git a/Menu/GameShell/10_Settings/Bluetooth/agent.py b/Menu/GameShell/10_Settings/Bluetooth/agent.py new file mode 100644 index 0000000..8f11647 --- /dev/null +++ b/Menu/GameShell/10_Settings/Bluetooth/agent.py @@ -0,0 +1,217 @@ +# -*- coding: utf-8 -*- + +import pygame +#import math +#import commands +import dbus +#from beeprint import pp +from libs.roundrects import aa_round_rect +from UI.page import Page,PageSelector +from UI.keys_def import CurKeys +from libs.DBUS import bus, adapter,devices + + +BUS_NAME = 'org.bluez' +AGENT_INTERFACE = 'org.bluez.Agent1' +AGENT_PATH = "/gameshell/bleagent" + +class Rejected(dbus.DBusException): + _dbus_error_name = "org.bluez.Error.Rejected" + +class BleAgent(dbus.service.Object): + device_obj = None + _Leader = None + dev_path = "" + + def set_trusted(self,path): + global BUS_NAME + props = dbus.Interface(bus.get_object(BUS_NAME, path), + "org.freedesktop.DBus.Properties") + props.Set("org.bluez.Device1", "Trusted", True) + + def dev_connect(self,path): + global BUS_NAME + dev = dbus.Interface(bus.get_object(BUS_NAME, path), + "org.bluez.Device1") + dev.Connect() + + @dbus.service.method(AGENT_INTERFACE,in_signature="", out_signature="") + def Release(self): + print("Agent release") + + + @dbus.service.method(AGENT_INTERFACE,in_signature="os", out_signature="") + def AuthorizeService(self, device, uuid): + print("AuthorizeService (%s, %s)" % (device, uuid)) ## directly authrized + return + + @dbus.service.method(AGENT_INTERFACE,in_signature="o", out_signature="s") + def RequestPinCode(self, device): + print("RequestPinCode (%s)" % (device)) + set_trusted(device) + return "0000" + + @dbus.service.method(AGENT_INTERFACE,in_signature="o", out_signature="u") + def RequestPasskey(self, device): + print("RequestPasskey (%s)" % (device)) + set_trusted(device) + passkey = "000000" + return dbus.UInt32(passkey) + + @dbus.service.method(AGENT_INTERFACE,in_signature="ouq", out_signature="") + def DisplayPasskey(self, device, passkey, entered): + print("DisplayPasskey (%s, %06u entered %u)" % (device, passkey, entered)) + self._Leader._PairPage.ShowPassKey(device,passkey,entered) + + @dbus.service.method(AGENT_INTERFACE,in_signature="os", out_signature="") + def DisplayPinCode(self, device, pincode): + print("DisplayPinCode (%s, %s)" % (device, pincode)) + self._Leader._PairPage.ShowPinCode(device,pincode) + + @dbus.service.method(AGENT_INTERFACE,in_signature="ou", out_signature="") + def RequestConfirmation(self, device, passkey): + print("RequestConfirmation (%s, %06d)" % (device, passkey)) + set_trusted(device) + return + + @dbus.service.method(AGENT_INTERFACE,in_signature="o", out_signature="") + def RequestAuthorization(self, device): + print("RequestAuthorization (%s)" % (device)) + + return + + @dbus.service.method(AGENT_INTERFACE,in_signature="", out_signature="") + def Cancel(self): + print("Cancel") + + + def pair_reply(self): + print("Device paired under Agent") + self.set_trusted(self.dev_path) + self.dev_connect(self.dev_path) + + self._Leader._PairPage._dev_obj = self.device_obj + self._Leader._PairPage.PairReplyCb() + + def pair_error(self,error): + global adapter + err_msg = "" + err_name = error.get_dbus_name() + print(err_name) + if err_name == "org.freedesktop.DBus.Error.NoReply" and self.device_obj: + err_msg = "Timed out. Cancelling pairing" + print(err_msg) + self.device_obj.CancelPairing() + elif err_name == "org.bluez.Error.AuthenticationCanceled": + err_msg = "Authentication Canceled" + elif err_name == "org.bluez.Error.ConnectionAttemptFailed": + err_msg = "Page Timeout" + elif err_name == "org.bluez.Error.AlreadyExists": + err_msg ="Already Exists" + try: + adapter.RemoveDevice(self.device_obj) + except Exception,e: + print("pair_error forget err:",str(e)) + + elif err_name == "org.bluez.Error.AuthenticationFailed": + err_msg = "Authentication Failed" + else: + err_msg = "Pair error" + print( err_name,str(error) ) + + self.device_obj = None + self._Leader._PairPage.PairErrorCb(err_msg) + +class BleAgentPairPage(Page): + + ##show pin/password + ##show prompt + _Pin = "" + _Pass = "" + _dev_obj = None + + def Init(self): + self._PosX = self._Index * self._Screen._Width + self._Width = self._Screen._Width + self._Height = self._Screen._Height + + #self._CanvasHWND = pygame.Surface((self._Width,self._Height)) + self._CanvasHWND = self._Screen._CanvasHWND + + def ShowPinCode(self,device,pincode): + print("ShowPinCode %s %d" % (pincode)) + if self._Screen.CurPage() != self: + self._Screen.PushPage(self) + self.ClearCanvas() + self._Screen.Draw() + self._Screen.SwapAndShow() + + self._Pin = "%s" % pincode + if len(self._Pin) > 0: + txt = "Pin code: %s" % self._Pin + self._Screen._MsgBox.SetText(txt) + self._Screen._MsgBox.Draw() + self._Screen.SwapAndShow() + + def ShowPassKey(self,device,passkey,entered): + print("ShowPassKey %s %d" % (passkey,entered)) + if self._Screen.CurPage() != self: + self._Screen.PushPage(self) + self.ClearCanvas() + self._Screen.Draw() + self._Screen.SwapAndShow() + + self._Pass = "%s" % passkey + if len(self._Pass) > 0: + txt = "Pair code: %s" % self._Pass + self._Screen._MsgBox.SetText(txt) + self._Screen._MsgBox.Draw() + self._Screen.SwapAndShow() + + def PairReplyCb(self): + self.ClearCanvas() + self._Screen.Draw() + self._Screen.SwapAndShow() + + self._Screen._MsgBox.SetText("Device paired") + self._Screen._MsgBox.Draw() + self._Screen.SwapAndShow() + pygame.time.delay(1500) + self.ReturnToUpLevelPage() + self._Screen.Draw() + self._Screen.SwapAndShow() + self._Screen._FootBar.ResetNavText() + + def PairErrorCb(self,error=None): + self.ClearCanvas() + self._Screen.Draw() + self._Screen.SwapAndShow() + + self._Screen._MsgBox.SetText(error) + self._Screen._MsgBox.Draw() + self._Screen.SwapAndShow() + pygame.time.delay(1500) + self.ReturnToUpLevelPage() + self._Screen.Draw() + self._Screen.SwapAndShow() + self._Screen._FootBar.ResetNavText() + + def KeyDown(self,event): + if event.key == CurKeys["A"] or event.key == CurKeys["Menu"]: + if self._dev_obj != None: + try: + self._dev_obj.CancelPairing() + except Exception,e: + print(str(e)) + + self.ReturnToUpLevelPage() + self._Screen.Draw() + self._Screen.SwapAndShow() + + + def Draw(self): + pass + #self.ClearCanvas() + + + diff --git a/sys.py/libs/bluezutils/__init__.py b/sys.py/libs/bluezutils/__init__.py new file mode 100644 index 0000000..de08cbd --- /dev/null +++ b/sys.py/libs/bluezutils/__init__.py @@ -0,0 +1,47 @@ +import dbus + +SERVICE_NAME = "org.bluez" +ADAPTER_INTERFACE = SERVICE_NAME + ".Adapter1" +DEVICE_INTERFACE = SERVICE_NAME + ".Device1" + +def get_managed_objects(): + bus = dbus.SystemBus() + manager = dbus.Interface(bus.get_object("org.bluez", "/"), + "org.freedesktop.DBus.ObjectManager") + return manager.GetManagedObjects() + +def find_adapter(pattern=None): + return find_adapter_in_objects(get_managed_objects(), pattern) + +def find_adapter_in_objects(objects, pattern=None): + bus = dbus.SystemBus() + for path, ifaces in objects.iteritems(): + adapter = ifaces.get(ADAPTER_INTERFACE) + if adapter is None: + continue + if not pattern or pattern == adapter["Address"] or \ + path.endswith(pattern): + obj = bus.get_object(SERVICE_NAME, path) + return dbus.Interface(obj, ADAPTER_INTERFACE) + raise Exception("Bluetooth adapter not found") + +def find_device(device_address, adapter_pattern=None): + return find_device_in_objects(get_managed_objects(), device_address, + adapter_pattern) + +def find_device_in_objects(objects, device_address, adapter_pattern=None): + bus = dbus.SystemBus() + path_prefix = "" + if adapter_pattern: + adapter = find_adapter_in_objects(objects, adapter_pattern) + path_prefix = adapter.object_path + for path, ifaces in objects.iteritems(): + device = ifaces.get(DEVICE_INTERFACE) + if device is None: + continue + if (device["Address"] == device_address and + path.startswith(path_prefix)): + obj = bus.get_object(SERVICE_NAME, path) + return dbus.Interface(obj, DEVICE_INTERFACE) + + raise Exception("Bluetooth device not found")