Linux copy all mounted USB upon insertion - including android + apple devices - android

Ubuntu user here. I am looking for a way to copy all flash drive and phone/tablet data to a specified folder whenever they are inserted. The python code below works great for flash drives but for some reason it will not work on my android phone or tablet. Additionally, I would like to only copy picture and video file extensions. My intention is to come home after a day of filming and plug in all my devices and have the pictures and video copy over. Thanks!
import subprocess
import time
import shutil
#--
target_folder = "/path/to/target_folder"
excluded = ["media_extern"]
#--
def get_mountedlist():
return [(item.split()[0].replace("├─", "").replace("└─", ""),
item[item.find("/"):]) for item in subprocess.check_output(
["/bin/bash", "-c", "lsblk"]).decode("utf-8").split("\n") if "/" in item]
def identify(disk):
command = "find /dev/disk -ls | grep /"+disk
output = subprocess.check_output(["/bin/bash", "-c", command]).decode("utf-8")
if "usb" in output:
return True
else:
return False
done = []
while True:
mounted = get_mountedlist()
new_paths = [dev for dev in get_mountedlist() if not dev in done and not dev[1] == "/"]
valid = [dev for dev in new_paths if (identify(dev[0]), dev[1].split("/")[-1] in excluded) == (True, False)]
for item in valid:
target = target_folder+"/"+item[1].split("/")[-1]
try:
shutil.rmtree(target)
except FileNotFoundError:
pass
shutil.copytree(item[1], target)
done = mounted
time.sleep(4)here

Related

Talking clock on old laptop or an Android app

I want to program a "talking clock" for my blind father and I have an very old laptop, 768 RAM. I have tried many different things, from making an app on android with kivy, without any success, because on my laptop (a different one) seems to work like a charm but when I'm "buildoze" it just doesn't play any mp3. I've tried some answers provided on SO with no success. Now I thought to try to install different things, like Python libraries for 2.79 and even Java on my old laptop, but seems that because Linux Mint 2.0 it's no longer supported can't install anything...
Does anyone have any suggestion if I can use that old laptop for such a thing or I can make an app for Android that plays mp3's?
I quite a noobie 😛
Thanks
Quick, dirty, and simple: install espeak and run something like the following in a cron job as often as you like:
dt=$(date +'%A, %B %d, %Y. The time is %l %M %p.'); espeak "Today is $dt"
EDIT: On reflection, It might be better to write a shell script and call that from cron. Assuming your father's only challenge is blindness, he probably doesn't need to be reminded of the date every, say, fifteen minutes. A script could speak the date every eight hours, perhaps, and the time as often as is useful.
EDIT AGAIN: Here's a script I threw together for fun. Give it a try.
#!/bin/bash
# If espeak isn't installed, complain and quit
command -v espeak > /dev/null 2>&1 ||\
{ echo -e "$0 requires espeak to be installed. Exiting..." ; exit 1; }
# ** Set variables
date_now=$(date +'%A, %B %d, %Y')
military_time=$(date +'%R') # 24-hour time
minute=$(date +'%M')
# We don't need espeak to say "zero zero" for the minutes
if [ $minute = "00" ]; then
time_now=$(date +'%l %p')
else
time_now=$(date +'%l %M %p')
fi
# Speak the date only if it's 9am or 5pm
[[ $military_time = "09:00" || $military_time = "17:00" ]] && espeak "Today is $date_now."
espeak "The time is $time_now."
Here's a speaking-clock in JS - just load it into a WebView or something - but you don't even need to package an app: just put it in a HTML page with a PWA manifest and save that as a home-screen icon so it will work while offline.
Click "Run code snippet" and then the button.
It will work in any modern web-browser available for Android and Linux desktops (except Opera and the stock (non-Chrome) Android Browser - it will also work in any modern Linux desktop environment - or any desktop OS, really.
I hope the code is self-explanatory.
It uses the Web Speech Synthesis API which is widely supported (except by the not-Google-Chrome Android Browser for some reason).
Note that it is not possible to make it play automatically or on-load (so need to click the button first to make speech synthesis work), as most browsers (including Chrome) block scripts from auto-playing sounds without user-interaction; the same applies to <video>, <audio>, etc.
Eta voila:
function sayTime() {
if( window.speechSynthesis.speaking ) return;
const now = new Date();
var tts = new SpeechSynthesisUtterance();
tts.text = "The time is now " + now.toLocaleTimeString();
window.speechSynthesis.speak( tts );
}
let timerId = null;
function toggleSpeakingClock() {
if( timerId ) {
window.speechSynthesis.cancel();
window.clearInterval( timerId );
timerId = null;
btn.textContent = "Click me to start";
}
else {
timerId = window.setInterval( sayTime, 1000 );
const btn = document.getElementById('btn');
btn.textContent = "Click me to stop";
}
}
document.addEventListener( 'DOMContentLoaded', function() {
const btn = document.getElementById('btn');
btn.disabled = !( typeof window.speechSynthesis === 'object' ) && ( window.speechSynthesis !== null );
if( btn.disabled ) btn.textContent = "Your browser doesn't support TTS";
} );
<button id="btn" onclick="toggleSpeakingClock()" disabled>Please wait...</button>

Kivy on Android get bluetooth state

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

ADB command from macOS application with special characters

I want to pull a file from my android device through an adb command from my macOS application.
Everything works perfect with the code below, except when the name of the file I want to pull contains special characters like german umlauts (äöüÄÖÜ).
I get this error:
adb: error: failed to stat remote object '/storage/emulated/0/Download/Böse': No such file or directory.
But when I use the command adb pull /storage/emulated/0/Download/Böse ~/Desktop from within the Terminal.app, the file will be pulled to my computer.
The strange thing here is that if I copy the substring /storage/emulated/0/Download/Böse from the Xcode console output, the command is also not working within the Terminal.app until I delete the ö and replace it with an ö from my keyboard input.
I tried replacing the ö with the unicode representation \u{00f6}, but this has no effect (but the console output still shows an ö but the 'wrong' encoded one.
// Configure task.
let task = Process()
task.launchPath = "~/Library/Android/sdk/platform-tools/adb"
task.arguments = ["pull", "/storage/emulated/0/Download/Böse", "~/Desktop"]
// Configure pipe.
let pipe = Pipe()
task.standardOutput = pipe
task.standardError = pipe
task.launch()
// Run task.
let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output = String(data: data, encoding: .utf8)
task.waitUntilExit()
// adb: error: failed to stat remote object '/storage/emulated/0/Download/Böse': No such file or directory
print(output)
I found the following in the documentation, how the Process handles the arguments that I provide:
The NSTask object converts both path and the strings in arguments to appropriate C-style strings (using fileSystemRepresentation) before passing them to the task via argv[] . The strings in arguments do not undergo shell expansion, so you do not need to do special quoting, and shell variables, such as $PWD, are not resolved.
It seems like I am not the only one with this problem, and I found this workaround:
How to work around NSTask calling -[NSString fileSystemRepresentation] for arguments, but I was not able to make it work with Swift.
As a workaround I am now writing my adb command to a file and execute it from a bash command in my application.
let source = "/storage/emulated/0/Download/Böse"
let destination = "~/Desktop"
guard let uniqueURL = URL(string: destination + "/" + ProcessInfo.processInfo.globallyUniqueString) else { return }
// Write command to file
let scriptContent = "#!/bin/bash\n~/Library/Android/sdk/platform-tools/adb pull -a \"" + source + "\" \"" + destination + "\""
try? scriptContent.write(to: uniqueURL, atomically: false, encoding: .utf8)
// Configure task.
let task = Process()
task.environment = ["LC_ALL": "de_DE.UTF-8", "LANG": "de_DE.UTF-8"]
task.launchPath = "/bin/bash"
task.arguments = [uniqueURL.path]
// Configure pipe.
let pipe = Pipe()
task.standardOutput = pipe
task.standardError = pipe
try? task.run()
// Run task.
let data = pipe.fileHandleForReading.readDataToEndOfFile()
let output = String(data: data, encoding: .utf8)
task.waitUntilExit()
print(output)
Even though this is working for now, it is not a satisfactory solution as it is not very elegant and not efficient too, so any improvements or better answers are welcome.

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

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