Java Code
Allows you to write and execute arbitrary Java code. The code is interpreted by the BeanShell interpreter, which uses a syntax similar to older versions of Java (pre-Java 5).
Click the magnifying glass icon next to the code field to get help writing your code. You can use the built-in AI to generate the code for you directly in the editor, or you can copy the system instructions to use with your preferred external AI (like ChatGPT, Gemini, etc.).
Two special variables are always available for you to use in your code: context and tasker.
The context variable is an Android Context object from a Service. Because it is not from an Activity, you must add the flag FLAG_ACTIVITY_NEW_TASK when starting new activities to avoid errors.
The tasker variable is a helper object that provides methods to interact with Tasker and the system. The available methods are:
String getVariable(String name)
Reads a Tasker variable. The name must not include the '%' prefix. Returnsnullif the variable is not set.
Example:String data = tasker.getVariable("http_data");void setVariable(String name, Object value)
Sets a standard Tasker variable. The name must not include the '%' prefix. The value will be converted to a string. The scope (local/global) depends on the capitalization of the name.
Example:tasker.setVariable("LastLocation", "Home");void setJavaVariable(String name, Object value)
Sets a Java object variable that can be accessed by other Java actions. This is for passing complex data. The scope (local/global) depends on the capitalization of the name.
Example:tasker.setJavaVariable("myList", new ArrayList());Object getJavaVariable(String name)
Retrieves a Tasker Java Variable that was set in a previous action. Note that Java variables are automatically available by name at the start of the script, so you rarely need to call this explicitly unless you need to re-fetch a value during execution.Critical: Checking for `null` vs `void`
In BeanShell, a variable that has not been set (e.g., an injected Java variable from a previous action that didn't run) is not `null`. It is a special value: `void`. If you only check `myVar == null`, your script will crash with an 'Undefined variable' error if `myVar` was never set. To safely check for the existence and non-null value of a variable, you MUST check for both conditions.
/* Correct and Safe Example: */ if (myInjectedVar == null || myInjectedVar == void) { /* The variable is either not set or has been explicitly set to null. */ tasker.log("Variable is not available."); } /* Incorrect and Unsafe Example: */ if (myInjectedVar == null) { /* This line will CRASH if the variable was never set. */ }java.util.Map<java.lang.String, java.lang.Object> getJavaVariables()
Gets a Map<String,Object> of both global and local Java variables. If there are variables with the same name, the local variables take precedence.java.util.Map<java.lang.String, java.lang.Object> getLocalJavaVariables()
Gets a Map<String,Object> of the local Java variables available in the current task. These do not include global variables.java.util.Map<java.lang.String, java.lang.Object> getGlobalJavaVariables()
Gets a Map<String,Object> of the global Java variables available that can be accessed in any Task in Tasker. These do not include local task variables.void clearGlobalJavaVariables()
Clears all global Java objects from memory. This is important for managing memory if you use global Java objects extensively.
Example:tasker.clearGlobalJavaVariables();void log(String message, ...)
Writes a debug message to the Tasker log which is sent to the system log or external storage, depending on what you enabled in Tasker Preferences. This is the only correct way to log from your code. Do not useSystem.out.println().
This method has several overrides:log(String message)log(String message, String filePath)log(String message, String filePath, String level)log(String message, String filePath, String level, String tag)
Example:tasker.log("Processing item number " + i);Disposable logAndToast(CharSequence message, ...)
Calls thelog()function followed byshowToast()with the provided text. Useful for debugging when you need immediate on-screen feedback.logAndToast(CharSequence message)logAndToast(CharSequence message, String filePath)
Example:tasker.logAndToast("Operation Complete");Disposable showToast(CharSequence text, ... )
Shows a simple on-screen toast. This method has three available overrides:showToast(CharSequence text): Standard toast.showToast(CharSequence text, CharSequence title): Toast with a title.showToast(CharSequence text, CharSequence title, Drawable icon): Toast with a title and an icon.
Example:tasker.showToast("Hello World");IBinder getShizukuService(String name)
Gets a system service via Shizuku for privileged operations. This will cause an error if Shizuku is not available.
Example:IBinder cs = tasker.getShizukuService("clipboard");NotificationListenerService getNotificationListener()
Gets the bound Notification Listener service to interact with notifications. Returnsnullif the service is not available, so your code must handle this.
Example:if (tasker.getNotificationListener() != null) { ... }Observable<NotificationUpdate> getNotificationUpdates()
Returns an RxJava2 Observable ofcom.joaomgcd.taskerm.helper.NotificationUpdateevents. You can subscribe to this stream to react to notification changes in real-time.
TheNotificationUpdateobject has exactly two methods:boolean getCreated(): Returnstrueif the notification was posted (created), andfalseif the notification was removed.android.service.notification.StatusBarNotification getStatusBarNotification(): Returns theandroid.service.notification.StatusBarNotificationobject that was either posted or removed.
boolean callTask(String taskName, HashMap params)
Runs a Tasker task by name, optionally passing parameters.This method asynchronously starts the specified task. It returns
Parameters:trueif the task was successfully queued to run, andfalseotherwise. It does not wait for the task to complete and does not provide a result from the task.taskName: The exact name of the Tasker task to run.params: AHashMapwhere keys are local variable names (without the '%' prefix) and values are the string values to pass to the task. Can benullif no parameters are needed.
import java.util.HashMap; /* Create a map to hold the parameters. */ params = new HashMap(); params.put("device_name", "Living Room TV"); params.put("command", "volume_up"); /* Call the 'Control Device' task with the specified parameters. */ boolean started = tasker.callTask("Control Device", params); if (started) { tasker.log("Successfully started the 'Control Device' task."); } else { tasker.log("Failed to start the 'Control Device' task."); }String sendCommand(String command)
Sends a command that can trigger the "Command" event in Tasker, allowing you to trigger other profiles or tasks. Equivalent to using the "Command" action.
Example:tasker.sendCommand("my_custom_command=:=value");AccessibilityService getAccessibilityService()
Returns an instance of Tasker's accessibility service if it's running. Returnsnullotherwise.
This service object includes the helper methodList<AccessibilityNodeInfo> getChildrenRecursive(AccessibilityNodeInfo node)to easily retrieve all child elements. You can use it withaccessibilityService.getRootInActiveWindow()to get all elements on the screen.
Example:if (tasker.getAccessibilityService() != null) { ... }Observable<AccessibilityEvent> getAccessibilityEvents()
Returns an RxJava2 Observable of Accessibility events. You can subscribe to this stream to detect and react to UI changes, clicks, and text changes across the system.Example: Creating a background text monitor
This example creates a persistent monitor that toasts any text typed into an EditText field in any app. It uses a global Java variable to handle cleanup so you can stop it later.
import android.view.accessibility.AccessibilityEvent; import io.reactivex.functions.Consumer; import io.reactivex.functions.Predicate; import io.reactivex.functions.Action; import io.reactivex.subjects.CompletableSubject; import java.util.List; import com.joaomgcd.taskerm.action.java.JavaCodeException; /* * Clean up any previous instance of this script by triggering the old signal. * We use getJavaVariable safely to check if the global variable exists. */ oldSignal = tasker.getJavaVariable("accKillSignal"); if (oldSignal != null && oldSignal != void) oldSignal.onComplete(); /* Create a new kill signal subject. */ killSignal = CompletableSubject.create(); /* * Store it as a Global Java Variable. * Another task can retrieve this using 'accKillSignal' and call .onComplete() to stop this monitor. */ tasker.setJavaVariable("accKillSignal", killSignal); /* Get the event stream. */ events = tasker.getAccessibilityEvents(); if (events == null) throw new JavaCodeException("Accessibility Service not available."); /* * Subscribe using takeUntil to handle the stop signal. * Use doFinally to clean up the global variable when the subscription ends. */ disposable = events.takeUntil(killSignal.toObservable()) .doFinally(new Action() { run() { /* Clear the global variables so they don't linger in memory. */ tasker.setJavaVariable("accKillSignal", null); tasker.setJavaVariable("accDisposable", null); } }) .filter(new Predicate() { boolean test(Object obj) { AccessibilityEvent event = (AccessibilityEvent) obj; /* Filter for text changes. */ if (event.getEventType() != AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED) return false; /* Filter for EditText. */ if (event.getClassName() == null) return false; if (!"android.widget.EditText".contentEquals(event.getClassName())) return false; return true; } }).subscribe(new Consumer() { accept(Object obj) { AccessibilityEvent event = (AccessibilityEvent) obj; List textList = event.getText(); /* Check for valid text. */ if (textList == null) return; if (textList.isEmpty()) return; tasker.showToast("Input: " + textList.get(0)); } }); /* CRITICAL: Store the subscription in a global variable so it's not garbage collected */ tasker.setJavaVariable("accDisposable", disposable);Example: Stopping the monitor
Run this code in a separate action (or task) to stop the monitor created above.
import io.reactivex.subjects.CompletableSubject; /* Retrieve the global signal variable. */ killSignal = tasker.getJavaVariable("accKillSignal"); /* Check if it exists and is valid. */ if (killSignal != null && killSignal != void) { /* Trigger completion. This stops the subscription in the other task. */ killSignal.onComplete(); tasker.showToast("Monitor Stopped"); } else { tasker.showToast("Monitor was not running"); }Object implementClass(...)
Dynamically extends or implements any class (concrete or abstract) to intercept its method calls. This is a powerful tool for adding logging, modifying behavior, or handling abstract classes where traditional anonymous classes fail in BeanShell.- How it works: You provide a class to extend (e.g.,
Intent.class) and an implementation of theClassImplementationinterface. Your implementation'srunmethod will be called for every method invoked on the created object. - Handler Interface: Your handler must implement
com.joaomgcd.taskerm.action.java.ClassImplementation. Remember to import this class at the top of your script. - The
runmethod parameters:Callable superCaller: This is the most important parameter. It is a handle to the original method that was called. To execute the original method, you must callsuperCaller.call(). The value returned by.call()is the original method's return value. This allows you to run code before or after the original logic.String methodName: The name of the method being called (e.g.,"putExtra").Object[] args: An array of arguments passed to that method.
- CRITICAL SYNTAX RULE: Due to a BeanShell limitation, you MUST write the
runmethod signature without a return type or access modifier. The line must be written literally asrun(Callable superCaller, String methodName, Object[] args){ ... }.
Signatures
1. Basic Implementation (No-Argument Constructor)
Object implementClass(java.lang.Class<?>, com.joaomgcd.taskerm.action.java.ClassImplementation)2. Implementation with Specific Constructor
Object implementClass(java.lang.Class<?>, com.joaomgcd.taskerm.action.java.ClassImplementation, java.lang.Class<?>[], java.lang.Object[])Example 1: Logging method calls on a concrete class
/* Import the necessary classes. */ import com.joaomgcd.taskerm.action.java.ClassImplementation; import android.content.Intent; import java.util.concurrent.Callable; /* Create a proxied Intent object. */ intent = tasker.implementClass(Intent.class, new ClassImplementation(){ run(Callable superCaller, String methodName, Object[] args){ tasker.log("Method Logger: about to call " + methodName); /* Execute the original method and capture its result. */ Object result = superCaller.call(); tasker.log("Method Logger: finished " + methodName +". Got result: " + result); /* Return the original result to preserve functionality. */ return result; } }); /* * Now, when you use this 'intent' object, every method call will be logged. */ intent.putExtra("aaa","coool"); intent.getStringExtra("aaa");Example 2: Implementing an abstract
BroadcastReceiverimport com.joaomgcd.taskerm.action.java.ClassImplementation; import android.content.BroadcastReceiver; import android.content.IntentFilter; import android.content.Intent; import java.util.concurrent.Callable; import io.reactivex.subjects.CompletableSubject; screenOffSignal = CompletableSubject.create(); filter = new IntentFilter(Intent.ACTION_SCREEN_OFF); screenOffReceiver = tasker.implementClass(BroadcastReceiver.class, new ClassImplementation(){ run(Callable superCaller, String methodName, Object[] args){ /* * Check for the specific abstract method we want to implement. * For any other method, we MUST call superCaller to preserve * the original behavior (e.g., for toString(), equals(), etc.). */ if (!methodName.equals("onReceive")) { return superCaller.call(); } /* This is our custom implementation for the 'onReceive' method. */ tasker.log("Screen just went OFF!"); screenOffSignal.onComplete(); return null; /* onReceive is a void method. */ } }); context.registerReceiver(screenOffReceiver, filter); try { screenOffSignal.blockingAwait(); tasker.log("...Signal received!"); } finally { context.unregisterReceiver(screenOffReceiver); }Example 3: Using a specific constructor
import com.joaomgcd.taskerm.action.java.ClassImplementation; import android.widget.ArrayAdapter; import android.content.Context; import java.util.concurrent.Callable; // We want to call the ArrayAdapter(Context context, int resource, T[] objects) constructor. constructorTypes = new Class[]{ Context.class, int.class, Object[].class }; String[] myItems = new String[]{"Item 1", "Item 2", "Item 3"}; constructorArgs = new Object[]{ context, android.R.layout.simple_list_item_1, myItems }; myAdapter = tasker.implementClass( ArrayAdapter.class, new ClassImplementation(){ run(Callable superCaller, String methodName, Object[] args){ if (methodName.equals("getCount")) { tasker.log("ArrayAdapter.getCount() was called!"); } return superCaller.call(); } }, constructorTypes, constructorArgs ); tasker.log("Adapter count is: " + myAdapter.getCount());- How it works: You provide a class to extend (e.g.,
TaskForHelper getTask()
Gets an object with information about the currently running task.
TheTaskForHelperobject has the following methods:String getName(): Gets the name of the current task.int getTaskId(): Gets the ID of the running task.int getProjectId(): Gets the project ID that contains the task.java.lang.Integer getProfileId(): Gets the eventual profile id of the profile that launched the running task. May be null.List<ActionForHelper> getActions(): Gets a list of all actions in the task.int getActionCount(): Gets the number of actions in this task.int getCurrentActionIndex(): Gets the 0-based index of this Java Code action.ActionForHelper getNextAction(): Gets the next action in the task.ActionForHelper getPreviousAction(): Gets the previous action in the task.
ActionForHelperobject has the following methods:int getCode(): Gets the action's internal code.String getName(): Gets the action's display name.
Bundle getTaskVariables()
Gets a Bundle object containing all of the current task's variables.
Example:Bundle vars = tasker.getTaskVariables();String toJson(Object object, ...)
Converts a Java object into its JSON string representation.toJson(Object object): Converts to a compact, non-pretty JSON string.toJson(Object object, boolean pretty): Ifprettyistrue, the JSON will be formatted for readability.
Example:String prettyJson = tasker.toJson(myObject, true);void doWithActivity(Consumer consumer)
Runs code within a temporary Activity context.This is the solution for running APIs that require an `Activity` and will not work with the default `Service` context. A prime example is showing an `AlertDialog` or any other UI element, which will crash if attempted from a service.
How it works:- You provide a `java.util.function.Consumer` as the argument. You must import this class.
- The function creates a temporary, invisible Activity behind the scenes.
- It then calls your `Consumer`'s `accept(Activity activity)` method, giving you access to the live `Activity` instance.
- Since this function uses a `Consumer`, it does not return a value. Its purpose is to perform an action with the Activity.
Example: Showing a Confirmation Dialog and Waiting for the ResultCRITICAL RULES — READ CAREFULLY
- Your Code Runs on the Main Thread: The code inside your `Consumer` executes on the Android Main (UI) Thread. Any long-running operations will freeze the app's UI. You must use RxJava2 or start a new `Thread` to perform background work.
- You MUST Finish the Activity: You are responsible for closing the Activity. You MUST call
activity.finish()inside your code when you are done. If you don't, the invisible activity will linger in the background. For asynchronous UI like a Dialog, this means callingfinish()inside the dialog's button listeners.
This example correctly demonstrates all the rules: it shows a dialog, pauses the script until the user clicks a button, and safely closes the temporary activity.
import java.util.function.Consumer; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import io.reactivex.subjects.SingleSubject; /* Use a SingleSubject to wait for the dialog's result. */ resultSignal = SingleSubject.create(); /* Create a Consumer to build and show the dialog. */ myActivityConsumer = new Consumer() { accept(Object activity) { final Activity currentActivity = (Activity) activity; onClickListener = new DialogInterface.OnClickListener() { onClick(DialogInterface dialog, int which) { String result = "cancel"; if (which == DialogInterface.BUTTON_POSITIVE) { result = "ok"; } resultSignal.onSuccess(result); currentActivity.finish(); /* CRITICAL: Finish activity here! */ } }; AlertDialog.Builder builder = new AlertDialog.Builder(currentActivity); builder.setTitle("Confirmation"); builder.setMessage("Do you want to proceed?"); builder.setPositiveButton("OK", onClickListener); builder.setNegativeButton("Cancel", onClickListener); builder.setCancelable(false); builder.create().show(); } }; /* Execute the consumer to show the dialog. */ tasker.doWithActivity(myActivityConsumer); /* Block the script and wait for the signal from the button listener. */ userChoice = resultSignal.blockingGet(); return userChoice;Single<Intent> getWithActivityForResult(Intent intent)
Handles the `startActivityForResult` flow, returning a `Single<Intent>`.This is the standard way to get data from other apps that require user interaction, like picking a file, selecting a contact, or choosing an account.
How it works:- You provide an `Intent` that launches an activity designed to return a result (e.g., `new Intent(Intent.ACTION_GET_CONTENT)`).
- The function starts that activity and immediately returns a `Single<Intent>` object.
- This `Single` acts as a placeholder for the result. It will emit the final `Intent` object only after you complete the action in the other activity and it closes.
You must subscribe to the `Single` to get the result. The most common way to do this is by using
Example: Basic Usage (Blocking immediately).blockingGet(), which pauses the script until the result is available.import android.content.Intent; /* Create an intent to pick any file. */ intent = new Intent(Intent.ACTION_GET_CONTENT); intent.setType("*/*"); /* Start the activity and get the Single placeholder. */ resultSingle = tasker.getWithActivityForResult(intent); /* Block the script and wait for the user to pick a file. */ resultIntent = resultSingle.blockingGet(); /* Extract the data (e.g., the file's URI) from the result. */ fileUri = resultIntent.getData(); return fileUri.toString();Example: Advanced Usage (Adding a Timeout)The flexibility of returning a `Single` allows you to add operators like `timeout`.
import android.content.Intent; import java.util.concurrent.TimeUnit; intent = new Intent(Intent.ACTION_GET_CONTENT); intent.setType("*/*"); resultSingle = tasker.getWithActivityForResult(intent); try { /* Wait for the result, but with a 30-second timeout. */ resultIntent = resultSingle.timeout(30, TimeUnit.SECONDS).blockingGet(); return resultIntent.getData().toString(); } catch (Exception e) { tasker.log("User did not pick a file within 30 seconds."); return "timeout"; }String convertToRealFilePath(Uri uri)
Attempts to convert a `content://` URI to a real, direct file path.Use Case: Android's modern security model often provides `content://` URIs instead of direct file paths (e.g., when you pick a file). This function acts as a bridge for tools or code that require a traditional, absolute path like `/storage/emulated/0/Download/MyFile.pdf`.
IMPORTANT: This conversion is not guaranteed to succeed and may return `null`, especially if the URI points to a cloud file (like from Google Drive) or other virtual content. You MUST always check if the result is `null`.
Example: Picking a File and Getting Its Real Pathimport android.content.Intent; import android.net.Uri; /* 1. Get the result Intent from the file picker. */ intent = new Intent(Intent.ACTION_GET_CONTENT); intent.setType("*/*"); resultIntent = tasker.getWithActivityForResult(intent).blockingGet(); if (resultIntent == null) return "User cancelled."; /* 2. Get the content URI from the result. */ contentUri = resultIntent.getData(); if (contentUri == null) return "Could not get file URI."; tasker.log("Got content URI: " + contentUri); /* 3. Attempt to convert the content URI to a real file path. */ realPath = tasker.convertToRealFilePath(contentUri); /* 4. CRITICAL: Check if the conversion succeeded. */ if (realPath != null) { tasker.log("Successfully converted to real path: " + realPath); return realPath; } else { tasker.log("Failed to convert URI to a real path."); return "Could not get real file path."; }
You can also access Java objects that were created and returned by other Tasker Java actions (like Java Function) within your code.
You have access to specific third-party libraries to simplify common tasks without needing manual imports or complex setups.
OkHttp3 (Web Requests)
Use this for all HTTP requests. Since your script runs on a background thread, you should prefer synchronous calls (execute()) over asynchronous callbacks to keep the code linear and readable.
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
client = new OkHttpClient();
request = new Request.Builder()
.url("https://www.example.com")
.build();
/* Execute synchronously. */
response = client.newCall(request).execute();
body = response.body().string();
return body;
Coil (Image Loading)
Use Coil to load images from URLs.
- Loading into an ImageView (Preferred): Use the asynchronous
enqueue()method with.target(imageView). This prevents UI freezes (e.g., in custom Dialogs) by loading images in the background while keeping the UI responsive. - Loading Raw Data: Use the synchronous
execute()method only if you need the actualBitmaporDrawableobject for processing within the script.
Example: Async loading into an ImageView
import coil.Coil;
import coil.request.ImageRequest;
/* Assume 'myImageView' is an existing view in your layout/dialog. */
request = new ImageRequest.Builder(context)
.data("https://www.example.com/image.png")
.target(myImageView)
.build();
/* Load in background without blocking the script or UI. */
Coil.imageLoader(context).enqueue(request);
The RxJava2 library is available for handling asynchronous operations like waiting for events, performing background work, or running code after a delay. The action will automatically wait for your reactive stream to complete before proceeding.
You must end your RxJava chain with a blocking operator (like blockingAwait(), blockingGet(), or blockingFirst()). This is what tells the action to wait for your asynchronous operation to finish.
Waiting for Events with Subjects (Recommended)
To wait for an event from a callback (like in a `BroadcastReceiver` or another listener), the cleanest approach is to use a Subject. You create a subject, use it within your callback implementation to signal that an event has occurred, and then block the script until that signal is received. This is much simpler than using complex operators like Completable.create().
Example: Using a Subject to wait for a signal
import io.reactivex.subjects.CompletableSubject;
/* Create a subject that will act as our signal. */
mySignal = CompletableSubject.create();
/*
* In another part of your code (e.g., inside the 'run' method of an
* implemented BroadcastReceiver), you would signal completion like this:
*
* mySignal.onComplete();
*
* See the `implementClass` BroadcastReceiver example for a practical use case.
*/
/* This line will block and wait until onComplete() is called. */
mySignal.blockingAwait();
tasker.log("Signal received, script can now continue.");
Simple Delays and Timers
For basic delays, using a simple timer is still appropriate.
Example: Wait for 3 seconds
import java.util.concurrent.TimeUnit;
import io.reactivex.Completable;
/* Wait for 3 seconds on a background thread. */
Completable.timer(3, TimeUnit.SECONDS).blockingAwait();
/* This code will run after the 3-second delay. */
tasker.log("3 seconds have passed.");
Example: Get a value after a delay
import java.util.concurrent.TimeUnit;
import io.reactivex.Single;
import io.reactivex.functions.Function;
/* Get the string "Hello" after a 1 second delay. */
result = Single.timer(1, TimeUnit.SECONDS)
.map(new Function() {
apply(Object aLong) {
return "Hello";
}
})
.blockingGet();
return result; /* Returns "Hello" */
The value from your code's return statement will be stored in the output variable specified in the "Return" field. Any variables you declare inside your code are temporary and will be discarded when the action finishes.
The scope (local or global) of the returned value is determined by the capitalization of the variable name you choose:
- Without a % prefix (stores as a Java Object)
This is ideal for passing complex data, like a
Listor custom object, to another Java-based action. The actual Java object is stored in memory.- All lowercase name (e.g.
my_object,resultslist): The object is stored locally and is only available within the current task. - Name contains at least one uppercase letter (e.g.
myGlobalObject,persistentList): The object is stored globally and persists across different tasks.- CRITICAL: The first letter of a global Java object name must be lowercase (e.g.,
myGlobalObjectis valid, butMyGlobalObjectis not).
Important: Global Java objects persist in memory. If you no longer need one, you should manually clear it using the
tasker.clearGlobalJavaVariables()method or the Java Function action to prevent memory leaks. - CRITICAL: The first letter of a global Java object name must be lowercase (e.g.,
- All lowercase name (e.g.
- With a % prefix (stores as a standard Tasker Variable)
The object's
.toString()method is called, and the resulting text is stored in a Tasker variable.- All lowercase name (e.g.
%result,%http_data): The variable is local to the current task. - Name contains at least one uppercase letter (e.g. %Result, %LastLocation): The variable is global and accessible from any task.
- Convention: Avoid using all-uppercase names (e.g.,
%WIFI). These are typically reserved for Tasker's built-in read-only variables.
- Convention: Avoid using all-uppercase names (e.g.,
- All lowercase name (e.g.
BeanShell supports both strong and dynamic typing. You do not need to declare a specific type when creating a variable, and you can reassign values of different types to the same variable without errors—similar to how Tasker handles variables.
Scope inside Functions: The behavior of a variable inside a function depends on how it is initialized:
- With a type declaration: If you specify a type (e.g.,
String i = ...), the variable is local to that function and will not affect variables with the same name outside of it. - Without a type declaration: If you simply assign a value (e.g.,
i = ...), BeanShell will look for that variable in the outer scope and modify it directly.
Example: Local Scope (Returns "1")
i = "1";
test() {
String i = "12"; /* Declared with a type: it's a new local variable. */
}
test();
return i;
Example: Outer Scope (Returns "12")
i = "1";
test() {
i = "12"; /* Assigned without a type: modifies the existing 'i' variable. */
}
test();
return i;
Example
You can use the following code to set the %wifi variable to the name of currently connected Wifi Network.
import android.content.Context;
import android.net.wifi.WifiManager;
import android.net.wifi.WifiInfo;
/* Get the WifiManager service. */
WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
/* If WiFi manager is unavailable or WiFi is disabled, exit. */
if (wifiManager == null || !wifiManager.isWifiEnabled()) return null;
/* Get information about the currently connected WiFi network. */
WifiInfo wifiInfo = wifiManager.getConnectionInfo();
if (wifiInfo == null) return null;
/* Get the raw SSID string. */
String ssid = wifiInfo.getSSID();
if (ssid == null) return null;
/* Remove surrounding quotes from the SSID if they exist. */
if (ssid.startsWith("\"") && ssid.endsWith("\"")) ssid = ssid.substring(1, ssid.length() - 1);
/* Return the cleaned SSID. */
return ssid;
%wifi