# Application Operations

In this chapter, you will learn how to install, start, and close apps, grant or revoke app permissions, disable or enable apps, and replay **any** Activity (schemes, Activities) including unexported ones.

## Installing Apps

You need to prepare an APK file for installation. Single Android APK and Split APK (e.g., xapk) are supported.

### Single APK

For a single APK file, use the following procedure:

```python
>>> session = d.create_install_session()
>>> session.write("/path/to/file.apk")
session: 2033102247
name: "base.apk"
writtenBytes: 5130176
totalBytes: 5130176

>>> session.commit()
session: 2033102247
package: "com.example.apk"
legacyStatus: 1
statusMessage: "INSTALL_SUCCEEDED: Session installed"
finished: true
committed: true
progress: 1
success: true

>>>
```

### Split APK (e.g., XAPK)

For multi‑APK apps, you may need to first extract the bundle. After extraction, you will typically see a file set like the following:

```bash
➜  apk_temp/ $ ls -l
total 350720
-rw-rw-r--  1 root  root    86M  1 26  1970 com.some.package.apk
-rw-rw-r--  1 root  root   772K  1 26  1970 config.ar.apk
-rw-rw-r--  1 root  root    68M  1 26  1970 config.arm64_v8a.apk
-rw-rw-r--  1 root  root   676K  1 26  1970 config.de.apk
-rw-rw-r--  1 root  root   478K  1 26  1970 config.en.apk
```

Then install them as follows. Usually you need to install the base APK, language packs, and native library APKs.

```python
>>> session = d.create_install_session()
>>> session.write("com.example.app.apk", name="com.example.app.apk")

session: 1137194135
name: "com.example.app.apk"
writtenBytes: 89661970
totalBytes: 89661970

>>> session.write("config.de.apk", name="config.de.apk")
session: 1137194135
name: "config.de.apk"
writtenBytes: 692633
totalBytes: 90354603

>>> session.write("config.arm64_v8a.apk", name="config.arm64_v8a.apk")
session: 1137194135
name: "config.arm64_v8a.apk"
writtenBytes: 70978318
totalBytes: 161332921

>>> session.write("config.xxhdpi.apk", name="config.xxhdpi.apk")
session: 1137194135
name: "config.xxhdpi.apk"
writtenBytes: 6266292
totalBytes: 167599213

>>> session.commit()
session: 1137194135
package: "com.example.app"
legacyStatus: 1
statusMessage: "INSTALL_SUCCEEDED: Session installed"
finished: true
committed: true
progress: 0.900000036
success: true

>>>
```

If any error occurs during installation, an exception will be raised directly, for example when no base APK is provided for a split APK install:

```python
>>> session = d.create_install_session()
>>> session.write("config.de.apk", name="config.de.apk")
session: 1658145271
name: "config.de.apk"
writtenBytes: 692633
totalBytes: 692633

>>> session.commit()
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  ....
  raise self.remote_exception(exception)
lamda.exceptions.InstallPackageFailed: INSTALL_FAILED_INVALID_APK: Full install must include a base package
```

### Session Parameters

Use specific session creation parameters to enable overwrite install, downgrade install, auto-grant permissions, installation to a specific user, etc.

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `user` | `int` | `0` | Install to the specified user ID |
| `package` | `str` | `None` | Package name to be installed; may be omitted |
| `request_downgrade` | `bool` | `False` | Whether to allow downgrade installation |
| `grant_runtime_permissions` | `bool` | `False` | Whether to grant runtime permissions |
| `installer_package_name` | `str` | `None` | Custom installer name (e.g., `com.android.vending`) |
| `dont_kill_app` | `bool` | `False` | Do not kill the app during installation |
| `replace_existing` | `bool` | `True` | Replace an already installed app (in root mode always `True`, even if set to `False`) |
| `allow_test` | `bool` | `False` | Whether to allow installing test apps |

You can use these parameters when creating a session as shown below:

```python
session = d.create_install_session(request_downgrade=True)
```

### Other Cases

Some systems may intercept the installation process or pop up app‑scanning dialogs such as Google Play Protect. In such cases you may want to automate the handling to complete the installation. You can do that.
`commit` provides a background installation mode, where you can continue without waiting and manually query the installation status.

```python
>>> session = d.create_install_session()
>>> session.write("/path/to/file.apk")
session: 1079135981
name: "base.apk"
writtenBytes: 5130176
totalBytes: 5130176

>>> session.commit(wait=False)
session: 1079135981
status: -2147483648
legacyStatus: -2147483648
statusMessage: "Commit sent"
committed: true
progress: 0.8

>>> session.status()
session: 1079135981
package: "com.example.app"
status: -2147483648
legacyStatus: -2147483648
statusMessage: "Commit sent"
committed: true
progress: 0.900000036

>>> session.status()
session: 1079135981
package: "com.example.app"
legacyStatus: 1
statusMessage: "INSTALL_SUCCEEDED: Session installed"
finished: true
committed: true
progress: 1
success: true
```

This way, after installation starts, you can use other code to handle dialogs that appear during installation. Using a [Watcher](./ui-watcher.md) for automatic clicking is also a feasible approach.

## List Installed Apps

Get information about all apps installed on the device.

```python
d.enumerate_installed_apps()
```

```python
>>> d.enumerate_installed_apps()
[packageName: "com.android.uwb.resources"
label: "System UWB Resources"
uid: 10110
enabled: true
system: true
versionName: "T-initial"
, packageName: "com.android.adservices.api"
label: "Android System"
uid: 10105
enabled: true
system: true
versionName: "14"
...
```

## List Running Apps

Get information about currently running processes on the system.

```python
d.enumerate_running_processes()
```

```python
>>> d.enumerate_running_processes()
[packages: "com.android.launcher3"
processName: "com.android.launcher3"
uid: 10084
pid: 2360
label: "Quickstep"
, packages: "com.google.android.gms"
processName: "com.google.android.gms.persistent"
uid: 10123
pid: 2765
label: "Google Play services"
, packages: "com.instagram.android"
processName: "com.instagram.android"
uid: 10150
pid: 5529
label: "Instagram"
...
```

```python
>>> result = d.enumerate_running_processes()
>>> print(result[0].processName)
com.android.launcher3
```

## Get App by Name

Get an app instance by its common name (without knowing the package ID).

```python
app = d.get_application_by_name("微信")
```

## Get App by Package Name

Get an app instance using its package ID.

```python
app = d.application("com.tencent.mm")
```

## Get Foreground App

Get the app instance currently running in the foreground.

```python
app = d.current_application()
```

## Get Multi‑Profile App

Get an instance of an app installed under a separate user profile (typically distinguished by `user` and with uid 999).

```python
app = d.application("com.my.app", user=999)
```

## Start App

Start this app.

```python
app.start()
```

## Stop App

Force‑stop this app.

```python
app.stop()
```

## Check Foreground Status

Check whether the app is currently in the foreground.

```python
app.is_foreground()
```

## Get App Information

Retrieve information about the app, such as version, etc.

```python
app.info()
```

```python
>>> app.info()
packageName: "com.android.settings"
uid: 1000
enabled: true
processName: "com.android.settings"
sourceDir: "/system/product/priv-app/Settings/Settings.apk"
dataDir: "/data/user_de/0/com.android.settings"
firstInstallTime: 1230739200000
lastUpdateTime: 1230768000000
versionCode: 1276
versionName: "10"
```

```python
>>> result = app.info()
>>> print(result.processName)
'com.android.settings'
```

## Check if Installed

Check whether the app is already installed on the device.

```python
app.is_installed()
```

## Uninstall App

Uninstall the app from the device.

```python
app.uninstall()
```

## Launch an Activity

You can replay system‑level Activities to start any Activity of any application. Available parameters are shown below. Note that extras support only `boolean`, `int`, `short`, `long`, `double`, `float`, and `string` types.  
For the definition of flags, refer to the documentation [developer.android.com/reference/android/content/Intent](https://developer.android.com/reference/android/content/Intent#FLAG_ACTIVITY_BROUGHT_TO_FRONT).

```python
from lamda.const import *
d.start_activity(action="*", category="*", component="*", extras={"boolean": False, "int": 1, "string": "abc", "float": 1.123}, flags=FLAG_ACTIVITY_NEW_TASK|FLAG_ACTIVITY_CLEAR_TASK, data="*", debug=False)
```

Now, using the “get recent activities” API as an example, you can replay the last system Activity directly with:

```python
activity = d.get_last_activities(count=5)[-1]
d.start_activity(**activity)
```

If you want to launch an activity in a multi‑profile app, the following call will replay the Activity into the user 999 profile:

```python
d.start_activity(**activity, user=999)
```

Some examples for reference: the following call will dial the 10000 customer service number.

```python
d.start_activity(action="android.intent.action.CALL", data="tel:10000")
```

The following call will launch the Settings app, which is essentially equivalent to starting the app directly.

```python
d.start_activity(action="android.intent.action.MAIN", category="android.intent.category.LAUNCHER", component="com.android.settings/.Settings")
```

The next call launches the Settings app in debug mode. If you have ever seen `Waiting for debugger`, this may be useful to you. Of course, your device or app must be debuggable. The only difference from the previous call is the extra `debug` parameter.

```python
d.start_activity(action="android.intent.action.MAIN", category="android.intent.category.LAUNCHER", component="com.android.settings/.Settings", debug=True)
```

This call will take you directly to the certificate settings page.

```python
d.start_activity(action="com.android.settings.TRUSTED_CREDENTIALS")
```

## List App Permissions

This API lists all permission names declared by the app.

```python
app.permissions()
```

```python
>>> app.permissions()
['android.permission.REQUEST_NETWORK_SCORES', 'android.permission.WRITE_MEDIA_STORAGE', 'android.permission.WRITE_EXTERNAL_STORAGE', 'android.permission.READ_EXTERNAL_STORAGE', 'android.permission.WRITE_SETTINGS',...]
```

## Grant App Permission

This API grants a system permission to the app. You should use it before the app is started; granting permissions while the app is running and requesting them will not automatically take effect.

```python
from lamda.const import *
app.grant(PERMISSION_READ_PHONE_STATE, mode=GrantType.GRANT_ALLOW)
```
This is equivalent to providing the full permission string directly:
```python
app.grant("android.permission.READ_PHONE_STATE", mode=GrantType.GRANT_ALLOW)
```

The `mode` parameter of the `grant` method also supports `GrantType.GRANT_DENY`, which explicitly denies the permission, and `GrantType.GRANT_IGNORE`. `GRANT_IGNORE` is special: it grants the permission to the app but the app cannot actually use it; for example, if an app requests the camera and you use this parameter, the camera preview may remain black.

## Revoke App Permission

This API revokes a granted permission. You should also call it before the app starts.

```python
from lamda.const import *
app.revoke(PERMISSION_READ_PHONE_STATE)
```

## Check if Granted

This API checks whether a certain permission has been properly granted to the app.

```python
from lamda.const import *
app.is_permission_granted(PERMISSION_READ_PHONE_STATE)
```

## Clear App Cache

This API clears the app’s cache data, usually without adverse effects.

```python
app.clear_cache()
```

## Clear App Data

This API clears the app’s data. Note that this will erase all app data, causing account information etc. to be lost.

```python
app.reset()
```

## Get Launch Activity

You can query the launch Activity (entry Activity) of the app with this API.

```python
app.query_launch_activity()
```

```python
>>> app.query_launch_activity()
{'action': 'android.intent.action.MAIN', 'component': 'com.android.settings/com.android.settings.Settings', 'categories': ['android.intent.category.LAUNCHER']}
```

## Enable App

This API enables a previously disabled app. Once enabled, you can use the app normally again.

```python
app.enable()
```

## Disable App

This API disables an app. A disabled app will not appear in the app list and cannot be used until enabled. This can temporarily or permanently freeze the app; it cannot auto‑start. When many apps are installed on the device, you can appropriately disable those you currently do not need to reduce system resource usage.

```python
app.disable()
```