Overview
PhoneClaw provides a suite of utility functions that complement the vision-based automation features. These functions handle common tasks like delays, text-to-speech, app launching, and data manipulation.
Delay Functions
delay()
Pause script execution for a specified duration.
Duration to wait in milliseconds (1000ms = 1 second)
Examples:
// Wait 2 seconds
delay(2000);
// Wait for animation to complete
Android.magicClicker("Menu button");
delay(1500);
Android.magicClicker("Settings option");
// Wait between automation steps
Android.launchTikTok();
delay(3000); // Let app fully load
Android.magicClicker("Search icon");
Text-to-Speech
speakText()
Provide voice feedback during automation.
The text to speak aloud via device text-to-speech engine
Examples:
// Simple feedback
Android.speakText("Starting automation");
// Status updates
var battery = Android.magicScraper("battery percentage");
Android.speakText("Battery level is " + battery);
// Error notifications
if (result.startsWith("Error")) {
Android.speakText("Operation failed, please check the device");
}
// Progress tracking
Android.speakText("Step one complete");
delay(1000);
Android.speakText("Moving to step two");
App Launching
launchTikTok()
Launch the TikTok application.
Example:
// Launch and interact with TikTok
Android.launchTikTok();
delay(3000);
Android.magicClicker("Search button");
Package: com.zhiliaoapp.musically
launchGmail()
Launch the Gmail application.
Example:
// Launch Gmail and compose email
Android.launchGmail();
delay(3000);
Android.magicClicker("Compose button in the bottom right corner");
Package: com.google.android.gm
Both launch functions check if the app is installed and provide voice feedback if not found.
Email Automation
sendEmail()
Automated email composition workflow (experimental).
fun sendEmail(to: String, subject: String, body: String)
Example:
Android.sendEmail(
"user@example.com",
"Automation Report",
"The automation completed successfully."
);
This is an experimental function that uses vision-based clicking and may need adjustment based on your Gmail version and layout.
How it works:
- Launches Gmail
- Uses
magicClicker() to find compose button
- Types recipient in editable field
- Types body in text area
- Waits with built-in delays between steps
Data Parsing
While there’s no built-in safeInt() function in the current implementation, you can safely parse integers using JavaScript:
Safe Integer Parsing
function safeInt(value, defaultVal) {
var parsed = parseInt(value);
return isNaN(parsed) ? defaultVal : parsed;
}
// Usage with magicScraper
var battery = Android.magicScraper("battery percentage");
var batteryLevel = safeInt(battery, 0);
if (batteryLevel < 20) {
Android.speakText("Low battery warning");
}
Parsing Scraped Data
// Extract numbers from text
function extractNumber(text) {
var match = text.match(/\d+/);
return match ? parseInt(match[0]) : 0;
}
var notificationText = Android.magicScraper("notification count");
var count = extractNumber(notificationText);
console.log("Notifications: " + count);
// Extract time
function parseTime(timeStr) {
var match = timeStr.match(/(\d{1,2}):(\d{2})\s*(AM|PM)?/);
if (match) {
return {
hour: parseInt(match[1]),
minute: parseInt(match[2]),
period: match[3]
};
}
return null;
}
var currentTime = Android.magicScraper("current time");
var time = parseTime(currentTime);
console.log("Hour: " + time.hour + ", Minute: " + time.minute);
String Utilities
Common String Operations
// Clean scraped text
function cleanText(text) {
return text.trim()
.replace(/\s+/g, ' ')
.replace(/[^a-zA-Z0-9\s]/g, '');
}
// Check if scraped data is valid
function isValidData(data) {
return data &&
!data.startsWith("Error:") &&
data.length > 0 &&
data !== "Not found";
}
// Usage
var appName = Android.magicScraper("current app name");
if (isValidData(appName)) {
var cleaned = cleanText(appName);
console.log("App: " + cleaned);
}
Accessibility Helpers
Direct Click (Coordinate-Based)
For when you know exact coordinates:
// Using AccessibilityService directly
// Note: Requires MyAccessibilityService to be enabled
// Click at specific coordinates
MyAccessibilityService.instance?.simulateClick(430f, 530f);
// Type in editable fields
MyAccessibilityService.instance?.simulateTypeInSecondEditableField("text");
MyAccessibilityService.instance?.simulateTypeInThirdEditableField("more text");
Direct coordinate clicking is less flexible than magicClicker() and may break if UI layout changes.
Get Device Details
While not directly exposed as utility functions, PhoneClaw tracks device information:
// These are tracked internally:
// - Device ID (Android ID)
// - Manufacturer, Model, Brand
// - Android Version, SDK Level
// - Local IP Address
// - Public IP and geolocation
// - Battery status
// - WiFi connection state
To access this data, use magicScraper():
var deviceInfo = {
battery: Android.magicScraper("battery percentage"),
time: Android.magicScraper("current time"),
wifi: Android.magicScraper("WiFi network name"),
app: Android.magicScraper("current app name")
};
console.log(JSON.stringify(deviceInfo));
Logging and Debugging
Console Logging
// Standard JavaScript console
console.log("Automation started");
console.error("Failed to find element");
console.warn("Low battery detected");
// Structured logging
function logAction(action, status, details) {
var timestamp = new Date().toISOString();
console.log(timestamp + " | " + action + " | " + status + " | " + details);
}
logAction("magicClicker", "SUCCESS", "Clicked submit button");
logAction("magicScraper", "SUCCESS", "Battery: 75%");
Voice Logging
// Combine logging with voice feedback
function logAndSpeak(message) {
console.log(message);
Android.speakText(message);
}
logAndSpeak("Automation complete");
Error Handling Utilities
Retry Logic
function retryOperation(operation, maxRetries, delayMs) {
for (var i = 0; i < maxRetries; i++) {
try {
var result = operation();
if (isValidData(result)) {
return result;
}
} catch (e) {
console.error("Attempt " + (i + 1) + " failed: " + e);
}
if (i < maxRetries - 1) {
delay(delayMs);
}
}
return null;
}
// Usage
var battery = retryOperation(
function() {
return Android.magicScraper("battery percentage");
},
3, // Try 3 times
2000 // Wait 2 seconds between attempts
);
Timeout Wrapper
function withTimeout(operation, timeoutMs, timeoutResult) {
var startTime = Date.now();
var result = operation();
var elapsed = Date.now() - startTime;
if (elapsed > timeoutMs) {
console.warn("Operation took " + elapsed + "ms (timeout: " + timeoutMs + "ms)");
return timeoutResult;
}
return result;
}
Best Practices
Use Adequate Delays: Always add delays after navigation, app launches, or UI changes to ensure elements are loaded.
Voice Feedback: Use speakText() for important status updates, especially for long-running automations.
Validate Data: Always check scraped data before using it in conditional logic or calculations.
Recommended Delay Times
- After app launch: 3000ms (3 seconds)
- After button click: 1000-1500ms (1-1.5 seconds)
- After navigation: 2000ms (2 seconds)
- After typing: 500-1000ms (0.5-1 second)
Complete Automation Example
function sendAutomatedEmail(recipient, subject, message) {
try {
// Launch Gmail
Android.speakText("Opening Gmail");
Android.launchGmail();
delay(3000);
// Compose new email
Android.speakText("Composing email");
Android.magicClicker("Compose button in the bottom right corner");
delay(2000);
// Fill in recipient
MyAccessibilityService.instance?.simulateTypeInSecondEditableField(recipient);
delay(1000);
// Click subject field
Android.magicClicker("Subject field");
delay(500);
// Type subject
MyAccessibilityService.instance?.simulateTypeInThirdEditableField(subject);
delay(1000);
// Click body field
Android.magicClicker("Email body area");
delay(500);
// Type message
MyAccessibilityService.instance?.simulateTypeInThirdEditableField(message);
delay(1000);
// Send
Android.magicClicker("Send button");
Android.speakText("Email sent successfully");
return true;
} catch (e) {
Android.speakText("Email sending failed");
console.error("Error: " + e);
return false;
}
}
// Use the function
sendAutomatedEmail(
"contact@example.com",
"Automation Test",
"This email was sent automatically by PhoneClaw."
);
See Also