소스 검색

add bluetooth agent,now device can paired,remembered after disconnect

cuu 5 년 전
부모
커밋
c225aa7dde
3개의 변경된 파일364개의 추가작업 그리고 17개의 파일을 삭제
  1. 100 17
      Menu/GameShell/10_Settings/Bluetooth/__init__.py
  2. 217 0
      Menu/GameShell/10_Settings/Bluetooth/agent.py
  3. 47 0
      sys.py/libs/bluezutils/__init__.py

+ 100 - 17
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)

+ 217 - 0
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()
+        
+    
+    

+ 47 - 0
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")