I have been trying to make a qpython program that uses sl4a.Android.recognizeSpeech function. The functionality works fine online.
In my phone settings, I turned on and downloaded offline speech recognition and google now works fine offline, but the python speech does not work at all, asking me to try again every single time.
Sample Code:
import sl4a
import time
droid = sl4a.Android()
def speak(text):
droid.ttsSpeak(text)
while droid.ttsIsSpeaking()[1] == True:
time.sleep(1)
def listen():
return droid.recognizeSpeech('Speak Now',None,None)
def login():
speak('Passphrase, please')
try:
phrase = listen().result.lower()
except:
phrase = droid.dialogGetPassword('Passphrase').result
print(phrase)
if phrase == 'pork chops':
speak('Welcome')
else:
speak('Access Denied')
exit(0)
login()
droid.recognizeSpeech("foo", None, None)
returns an Array with the recognized Speech in Index number 1. So if you want to access it, you have to type
return droid.recognizeSpeech("foo", None, None)[1]
Actually none of the above worked for me. So I solved that this way:
x, result, error = droid.recognizeSpeech("Speak")
The result variable stores the speech recognized from the user
Example:
import sl4a
import time
droid = sl4a.Android()
def Speak(talk):
try:
droid.ttsSpeak(talk)
while droid.ttsIsSpeaking()[1] == True:
time.sleep(2)
except:
droid.ttsSpeak("nothing to say")
def listen():
global result,error
time.sleep(1)
x, result, error = droid.recognizeSpeech("Speak")
while True:
try:
listen()
except:
print(error)
try:
if len(str(result)) > 0:
print(result)
if result == "how old are you":
Speak("I'm 1 year old")
elif result is None:
break
else:
Speak("I heard " + result)
except Exception as e:
print(e)
break
Related
I am trying to get my app to get all paired devices after programmatically enabling the bluetooth. The thing is Android only allows you getting all paired devices if the bluetooth state is on. Now I already have a pop up that pops up if there is no bluetooth which has an option to enable bluetooth successfully calling BluetoothAdapter.getDefaultAdapter().enable().
The thing is this enable call runs slow and if my subsequent line code checks for enabled state, it over runs before getting all paired devices:
if BluetoothAdapter.getDefaultAdapter().isEnabled():
this.root.get_devices()
Therefore I tried the broadcast receiver implementation from the p4a docs :
def __init__(self, **kwargs):
super().__init__(**kwargs)
if platform == 'android':
self.intent_bltooth = IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED)
self.br = BroadcastReceiver(self.on_broadcast, actions=['state_changed'])
self.stream = Stream()
self.br.start()
def on_broadcast(self, context, intent):
print(intent.getAction(), 'see intent action')
listen = intent.getExtras()
bltooth_state = bool(listen.get('state'))
if bltooth_state:
this.root.get_devices()
print('bluetooth connected')
else:
print('bluetooth not connected')
But this gives me a constant ACTION_STATE_CHANGED intent does not exist.
So to overcome this I decided to use a more pure kivy solution in the form of a trigger that checks the bluetooth state until enabled:
def enable_bluetooth(self, *args):
this = App.get_running_app()
if platform == 'android':
blueAdapt = BluetoothAdapter.getDefaultAdapter()
blueAdapt.enable()
this.root.dialog_with_action.remove_action_button()
self.bluet_ticker() # this line gives the error TypeError: Argument 'obj' has incorrect type (expected kivy._event.EventDispatcher, got BluetoothHelper)
def bluet_ticker(self):
print('one tick')
self.bluet_tme = 1000
print('two tick')
self.bluet_tick = Clock.create_trigger(lambda dt: self.run_bluet_ticker(), 0)
print('three tick')
self.bluet_tick()
def run_bluet_ticker(self):
this = App.get_running_app()
blueAdapt = BluetoothAdapter.getDefaultAdapter()
if self.bluet_tme > 0:
if blueAdapt.isEnabled() == False:
print('not ennnnnnnnnnnnnnnnnnnnnnnnbled')
self.bluet_tme -= 1
self.bluet_tick()
else:
this.root.get_devices()
print('ennnnnnnnnnnnnnnnnnnnnnnnnnabling bbluuuuuuuuuuuuuuuuuutoottttttth')
self.bluet_tick.cancel()
else:
self.bluet_ticker()
But when the trigger function bluet_trigger() is called I get the following error: TypeError: Argument 'obj' has incorrect type (expected kivy._event.EventDispatcher, got BluetoothHelper)
Can someone please assist in either helping to point me in the right direction to find a solution to use a BroadcastReceiver or the trigger?
I am posting the answer I found from user with alias AdyWizard on discord and his project wifiscan
So the off the shelf p4a broadcast receiver does not have the bluetooth state broadcast receiver built in. You have to amend the source and add support for BluetoothAdapter state.
After my first build of the kivy app using buildozer android debug deploy. I go to the following directory /.buildozer/android/platform/python-for-android/pythonforandroid/recipes/android/src/android/broadcast.py and amend the code with the following:
def _expand_partial_name(partial_name):
if '.' in partial_name:
return partial_name # Its actually a full dotted name
else:
name = 'ACTION_{}'.format(partial_name.upper())
if hasattr(Intent, name):
return getattr(Intent, name)
elif hasattr(BluetoothAdapter, name):
return getattr(BluetoothAdapter, name)
else:
raise Exception('The intent {} doesnt exist'.format(name))
# resolve actions/categories first
Intent = autoclass('android.content.Intent')
BluetoothAdapter = autoclass('android.bluetooth.BluetoothAdapter')
I then run the command buildozer android clean and run the build command again. The p4a broadcast receiver then works as is. Here is a working example
There is this torch app example available online. It uses a 'Switch' to turn flashlight on. It works. I've been trying/struggling to get a 'message' output on the device when the flashlight is turned on and off and I cannot seem to get the right code. Can anyone provide a hint. Here's the working torch app code (somehow, the text 'enlightme' never appears):
from kivy.app import App
from kivy.uix.switch import Switch
from jnius import autoclass
Camera = autoclass('android.hardware.Camera')
Parameters = autoclass('android.hardware.Camera$Parameters')
__version__ = '0.1'
class FlashApp(App):
def build(self):
self.root = Switch(text='enlightenme')
self.root.bind(active=self.toggle_flash)
self.camera = None
return self.root
def toggle_flash(self, *args):
if self.camera == None:
self.camera = Camera.open()
p = self.camera.getParameters()
if self.root.active:
p.setFlashMode(Parameters.FLASH_MODE_TORCH)
self.camera.setParameters(p)
self.camera.startPreview()
else:
p.setFlashMode(Parameters.FLASH_MODE_OFF)
self.camera.stopPreview()
self.camera.setParameters(p)
self.camera.release()
self.camera = None
if __name__ == '__main__':
FlashApp().run()
Switch doesn't have a text property, and due to a quirk of Kivy's argument parsing you don't get an error due to the unused kwarg.
You should instead add a Label with your desired text.
I am writing testcases in python script for android application using appium. I want to perform click/tap operation in a particular bounds/co-ordinates. but I am not able to perform it.Can any one tell me how to do it.
class firstTest(unittest.TestCase):
def tearDown(self):
"Tear down the test"
self.driver.quit()
def test_single_player_mode(self):
time.sleep(5)
element = self.driver.find_element_by_name("Enter your Email ID or User name")
element.send_keys("username")
element = self.driver.find_element_by_name("Let's get started!")
element.click()
time.sleep(5)
Till 'Lets get started it is working fine. After it in UI, I don't have any element name or id. I have only particular bound to click the element. I want to click on bound [918,154][1086,324] resource ID for above bound is "com.abc.android.cap:id/friends_selection_list" Please tell me how to do after it.
I hope you have content-description for this element. In that case you can tap on it by using it and tap method in TouchAction class.
ele = self.driver.find_element_by_accessibility_id('content-description of your element')
action = TouchAction(self.driver)
action.tap(ele).perform()
U can use Xpath of that element, for finding xpath u will need appium inspector, which is supported in MAC OSX only, so you have to use an mac and configure Android SDK and Appium on MAC in order to get it working.
Code will be like this :
#-*- coding: utf-8 -*-
__author__ = 'chetan.krishna'
import os
import time
import unittest
from time import sleep
from appium import webdriver
from pylab import *
from teamcity import is_running_under_teamcity
from teamcity.unittestpy import TeamcityTestRunner
import logging
# Returns absolute path relative to this file
PATH = lambda p: os.path.abspath(
os.path.join(os.path.dirname(__file__), p)
)
class AvavntiAndroidTests(unittest.TestCase):
def setUp(self):
desired_caps = {}
# Specify platform below(Android, iOS)
desired_caps['platformName'] = 'Android'
# Specify OS version(Settings->About phone -> android version)
desired_caps['platformVersion'] = '4.4.4'
# Obtain the Device name from Adb[For Android](Terminal Command: "adb devices")
desired_caps['deviceName'] = '4d0081004c8741a9'
desired_caps['noReset'] = False
# Specify the path to Application
desired_caps["app"] = PATH('AvantiMarket_v1.4.apk')
# Wait for email login activity to appear
desired_caps["appWaitActivity"]= ('com.android.avantimarket.ui.activity.EmailLoginActivity')
self.driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
def tearDown(self):
# end the session
self.driver.quit()
def test_Avanti(self):
# wait for the login screen to appear
self.driver.implicitly_wait(20)
# set values for plotting pass and fail results
nPass = 0
nFail = 0
print('Checking login for registered user')
# Logging in as indiaone#avantilab.org
elf.driver.implicitly_wait('20')
print('Trying to login with abc#abc.org')
self.driver.find_element_by_xpath('//UIAApplication[1]/UIAWindow[2]/UIATextField[1]').send_keys('abc#abc.org.org')
self.driver.find_element_by_xpath('//UIAApplication[1]/UIAWindow[2]/UIASecureTextField[1]').send_keys('12345678')
self.driver.hide_keyboard()
self.driver.implicitly_wait(10)
self.driver.find_element_by_xpath('//UIAApplication[1]/UIAWindow[2]/UIAButton[3]').click()
time.sleep(20)
self.driver.implicitly_wait(99)
try:
self.driver.find_element_by_xpath('//UIAApplication[1]/UIAWindow[2]/UIASecureTextField[1]')
except :
print('Login failed, please check credentials and network')
else:
print('Login successful, creating pin')
self.driver.find_element_by_xpath('//UIAApplication[1]/UIAWindow[2]/UIASecureTextField[1]').send_keys('1')
self.driver.find_element_by_xpath('//UIAApplication[1]/UIAWindow[2]/UIASecureTextField[2]').send_keys('1')
self.driver.find_element_by_xpath('//UIAApplication[1]/UIAWindow[2]/UIASecureTextField[3]').send_keys('1')
self.driver.find_element_by_xpath('//UIAApplication[1]/UIAWindow[2]/UIASecureTextField[4]').send_keys('1')
self.driver.find_element_by_xpath('//UIAApplication[1]/UIAWindow[2]/UIASecureTextField[5]').send_keys('1')
self.driver.find_element_by_id('com.android.avantimarket:id/m_emailTextField').send_keys('abc#abc.org.org')
self.driver.back()
nPass= nPass+1
self.driver.implicitly_wait(20)
self.driver.find_element_by_id('com.android.avantimarket:id/m_passwordTextField').send_keys('12345678')
nPass= nPass+1
self.driver.back()
self.driver.implicitly_wait(10)
self.driver.find_element_by_name('SIGN IN').click()
self.driver.implicitly_wait(30)
time.sleep(5)
# validating for successful login
try:
self.driver.find_element_by_id('com.android.avantimarket:id/create_pin_fields_container')
print('Login successful')
nPass= nPass+1
except:
print('Login failed')
nFail = nFail + 1
else:
# Creating pin required for login
print('Creating Pin for user')
self.driver.find_element_by_id('com.android.avantimarket:id/create_pin_fields_container').send_keys('1111')
self.driver.find_element_by_id('com.android.avantimarket:id/reEnter_pin_fields_container').send_keys('1111')
self.driver.back()
self.driver.implicitly_wait(20)
self.driver.find_element_by_id('com.android.avantimarket:id/m_saveButton').click()
self.driver.implicitly_wait(10)
self.driver.find_element_by_id('com.android.avantimarket:id/btn_cominsoon_Yes').click()
self.driver.implicitly_wait(10)
time.sleep(8)
You can achieve this with Touch Actions.
action = TouchAction(self.driver)
action.tap(element=None, x=100, y=600, count=2).perform()
Or like this:
self.driver.tap([(100,600)], 500)
Where the first variable is a list of up to 5 x,y coordinates(e.g. self.driver.tap([(495,757), (200,500)], 500). The last number is duration of the tap.
Here's what I need to do. I have 2 devices which I need to test using monkeyrunner. It is an automated test using python and monkeyrunner. I want to execute the test simultaneously for the 2 devices so I thought of using thread.
here's the code
import threading
import datetime import os, sys
import ConfigParser from com.android.monkeyrunner
import MonkeyRunner, MonkeyDevice,MonkeyImage from datetime
import datetime import hashlib from java.net
import SocketException from com.ziclix.python.sql
import zxJDBC
def UseThread(data1, data2, data3, devID, Code, ScreenshotRef,
logFile):
device = MonkeyRunner.waitForConnection(10, devID)
'threaded code'
'initialization'
file = open(os.path.dirname(os.path.realpath(file)) +
'\Samples.txt','r') while 1:
while 1:
line = file.readline()
if not line:
print 'Done!'
break
else:
line
val=line.split('\t')
data1 = val[0]
data2 = val[1]
data3 = val[2]
threads = []
for Code in cp.options('p'):
devID = cp.get('product',Code).strip()
ScreenshotRef = cp.get('source','ScreenshotRef') + '\\' + prodCode.upper()
logFile = outputFolder + '\\' + prodCode.upper() + '\\logs.txt'
t=threading.Thread(target=UseThread,args=(data1, data2, data3, devID, prodCode, ScreenshotRef, logFile))
threads.append(t)
t.start()
for i in range(0,len(threads)):
threads[i].join()
The problem is this. When the while loops finish one run and proceed to 2nd run, the code hangs in the part when monkeyrunner is waiting for connection. To be exact, this is the part where it stops
device = MonkeyRunner.waitForConnection(10, devID)
the message says "Monkey command wake".
I assume that the problem has something to do with the connection, not with the thread because I tried to print something before that line which makes a connection and it works.
Is there an issue making a connection when you have already made one? do I need to close the previous connection first?
MonkeyRunner waitForConnection works only for one device. You cannot run this twice. You can run from another instance
I have gone through the "Monkey Runner" for the following link
http://developer.android.com/guide/topics/testing/testing_android.html
It has so much Java code. I am not able to under stand the code to create test cases. Is it only for developers, or the testers to test the application thoroughly. Is there any other pattern for creating test cases through code? Can any one suggest me about the same.
Thank you.
Have a look at my MonkeyRunner code. Should be easier then Java. Change path to save file, and replace phone number. I had only 1 problem. Cant Hangup a call.
#! /usr/bin/env monkeyrunner
'''
Created on Apr 1, 2011
#author: sj
'''
import sys
# import the MonkeyRunners modules used by this program
from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice, MonkeyImage
def browse(d):
d.broadcastIntent("http://www.google.com/", "ACTION_MAIN")
#d.startActivity(component="com.android.browser/.BrowserActivity")
def debug(device):
print" package:%s" % device.getProperty('am.current.package')
print" action:%s" % device.getProperty('am.current.action')
print" comp.class:%s" % device.getProperty('am.current.comp.class')
print" comp.package:%s" % device.getProperty('am.current.comp.package')
print device.getProperty('display.width'), device.getProperty('display.height')
def screenshot(d):
MonkeyRunner.sleep(1.0)
result = d.takeSnapshot()
MonkeyRunner.sleep(1.0)
result.writeToFile('/yourPath/device.png', 'png')
def call(d):
d.startActivity(component="com.android.contacts/.TwelveKeyDialer")
print "Start Activity"
MonkeyRunner.sleep(1.0)
d.type("+XXXXXXXX")
# Call number.
print "Call"
d.touch(190, 800, 'DOWN_AND_UP');
# not working device.press('KEYCODE_CALL', 'DOWN_AND_UP')
print "Wait 10 sec"
MonkeyRunner.sleep(10.0)
# HangUp Call
#device.press('KEYCODE_ENDCALL', 'DOWN_AND_UP')
print "Hang Up"
#x1 = 215
#x2 = 230
#y = 700
#start = (x1,y)
#end = (x2, y)
#steps = 2
#pause = 0.2
#device.drag(start, end, pause, steps)
d.startActivity(component="com.android.phone/.InCallScreen")
#device.touch(230, 700, "DOWN");
MonkeyRunner.sleep(1.0)
#device.touch(230, 700, "UP");
d.touch(230, 700, 'DOWN_AND_UP');
#device.touch(270, 650, 'DOWN_AND_UP');
def main():
print "Start"
# Connect to the current device returning the MonkeyDevice object
device = MonkeyRunner.waitForConnection()
#MonkeyRunner.alert("Starting Activity", "monkeyrunner", "OK")
if not device:
print "Couldn't get connection"
sys.exit()
print "Found device"
#call(device)
browse(device)
debug(device)
screenshot(device)
device.press('KEYCODE_ENDCALL', 'DOWN_AND_UP')
MonkeyRunner.sleep(10.0)
if __name__ == '__main__':
main()
I have learned monkeyrunner via this small guide.
http://antoine-merle.com/introduction-to-the-monkey-runner-tool-2/
You do not have to use java, but to start low on python. For the ide you can use pycharm, which will give you a better start when creating classes in python.
As of the code which #Boris_Ivanov showed, this is a good start, but I would delete the "MonkeyImage" - as you are not using it also pushing the test cases into different files would add to speed if required to use.
One thing to talk about:
Connect to the current device returning the MonkeyDevice object
device = MonkeyRunner.waitForConnection()
#MonkeyRunner.alert("Starting Activity", "monkeyrunner", "OK")
I am using something like this and it does work all the way:
device = MonkeyRunner.waitForConnection(60)
if not device:
raise Exception('Can not connect to device')
Best luck.