KIVY not updating UI on phone sleep mode - android

I was again trying kivy gps example from https://github.com/kivy/plyer/blob/master/examples/gps/main.py. But the problem occurs when I press the Start button and put the phone on sleep mode(screen off), after sometimes I came back to screen and the app, only I can see a frozen gui that due to unable to update the label while on standby mode. How do I can overcome this? I want to update the label even my phone is on sleep mode.
from kivy.lang import Builder
from plyer import gps
from kivy.app import App
from kivy.properties import StringProperty
from kivy.clock import Clock
kv = '''
BoxLayout:
orientation: 'vertical'
Label:
text: app.gps_location
Label:
text: app.gps_status
BoxLayout:
size_hint_y: None
height: '48dp'
padding: '4dp'
ToggleButton:
text: 'Start' if self.state == 'normal' else 'Stop'
on_state: app.gps.start() if self.state == 'down' else app.gps.stop()
'''
def mainthread(func):
# This method is now part of Kivy 1.8.0. When it's released, remove it.
def delayed_func(*args, **kwargs):
def callback_func(dt):
func(*args, **kwargs)
Clock.schedule_once(callback_func, 0)
return delayed_func
class GpsTest(App):
def on_pause(self):
# Here you can save data if needed
return True
def on_resume(self):
# Here you can check if any data needs replacing (usually nothing)
pass
gps_location = StringProperty()
gps_status = StringProperty('Click Start to get GPS location updates')
def build(self):
self.gps = gps
try:
self.gps.configure(on_location=self.on_location,
on_status=self.on_status)
except NotImplementedError:
import traceback; traceback.print_exc()
self.gps_status = 'GPS is not implemented for your platform'
return Builder.load_string(kv)
#mainthread
def on_location(self, **kwargs):
self.gps_location = '\n'.join([
'{}={}'.format(k, v) for k, v in kwargs.items()])
#mainthread
def on_status(self, stype, status):
self.gps_status = 'type={}\n{}'.format(stype, status)
if __name__ == '__main__':
GpsTest().run()

You can't ever guarantee that the app will continue operating in sleep mode, so this probably isn't a good way to do things. Better would be to use an android service, which is possible with python-for-android. Here is a blog post about it, and it's documented here.
You can do your gps stuff in the service and sync with the app on on_resume and/or on_start.

Related

kivy + android intent filters

Im very new to kivy and python so I may have thrown myself in at the deep end here but i'm trying to figure out how to get an android intent and use it within a simple kivy app?
So im currently trying to figure out the basic design elements and just how to get stuff working. I want to be able to click on a link (for example) and launch my app and then do stuff, nothing too complicated, it just needs to be able to get the link which is passed to it from android.
I figured out this was to do with android intent filters and added the appropriate "intent_filters.xml" file to make this work.
So clicking on the link will launch my app, which is good.
However I cant figure out then how to parse the information passed to the app in android. So below is a very simple app with a button and I just want to update the button to see if my intent is being picked up or not.
Currently clicking the button causes the app to close. When i test this in the Kivy VM I am using to compile the apk it will close with a message that "platform" is not defined (which makes sense as its not in android) but it doesnt much help with testing or tracking down how to make it work.
I've read some stuff which seems to suggest that this might not be possible with kivy?
Can anyone confirm if this is possible in kivy and if so, how?
(i've tried variations on activity.getIntent(), intent.getData(), Intent.getIntent().getStringExtra(Intent.EXTRA_TEXT), Intent().getData().getPath() all to no avail)
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
class TutorialApp(App):
def build(self):
self.gen_btn = Button(text='Initial',
size_hint=(.90, .10),
pos=(5, 5),
font_size=50)
self.gen_btn.bind(on_press=self.update_tutorialapp)
l = BoxLayout()
l.add_widget(self.gen_btn)
return l
def update_tutorialapp(self, *args):
st = update_button()
st.update_Message(self)
class update_button():
def update_Message(self, source):
source.gen_btn.text = "the event was called"
if platform=="android":
from jnius import cast
from jnius import autoclass
import android
import android.activity
# test for an intent passed to us
PythonActivity = autoclass('org.renpy.android.PythonActivity')
activity = PythonActivity.mActivity
intent = activity.getIntent()
intent_data = intent.getData()
source.gen_btn.text = PythonActivity.getIntent().getStringExtra(Intent.EXTRA_TEXT)
if __name__ == "__main__":
TutorialApp().run()
def build(self):
android.activity.bind(on_new_intent=self.on_new_intent) # add this line in build
def on_new_intent(self, intent):
data = intent.getData() # perform operations on intent

Kivy-Python-Android Torch App

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.

Offline Speech Recognition in qpython3

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

How to perform click/tap operation to the perticular bound/co-ordinates in python script for Android UI using appium

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.

Is "Monkey Runner" useful for testers to prepare test cases directly in Android applications?

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.

Categories

Resources