# Mobile App Development in PicoLisp - VI:  Intents and the Java Interface

As we already learned, the PilBox is a tool providing an interface to the Android Java runtime environment. Specifically, we are able to use most of the classes that are listed in the official Android documentation: https://developer.android.com/reference/classes.html

Often, the interesting part of a smartphone app needs to acces smartphone-specific resources (like camera, GPS..). In this case, we need to leave our PicoLisp environment and send an **intent** to an app which provides the needed resources. This post will cover a general explanation of intents and how we can call them from PicoLisp using the Java Interface.

---

### Android Intents

[**Intents**](https://developer.android.com/guide/components/intents-filters) are messaging objects that can be used to request an action from another app component such as camera, GPS, contacts and so on. There are three fundamental uses cases:

- **starting an activity**, which is represented by a single screen in an app,
- **services**, which run in the background, 
- or **broadcast deliveries**: messages that any app can receive.

There are two types of intents:

- **Explicit intents** specify which application will satisfy the intent, by supplying either the target app's package name or a fully-qualified component class name. 
- **Implicit intents** do not name a specific component, but instead declare a general action to perform, which allows a component from another app to handle it.

Obviously, implicit intents are inherently less secure because there is no control from developer side which app will accept the intent. The Android system will simply find all appropriate components based on the *intent filters* in the manifest files of other apps.  

![intents.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1645707558824/KOkwIouO2.png)

*From the [android docs](https://developer.android.com/guide/components/intents-filters): 1. How an implicit intent is delivered through the system to start another activity: [1] Activity A creates an Intent with an action description and passes it to startActivity(). [2] The Android System searches all apps for an intent filter that matches the intent. When a match is found, [3] the system starts the matching activity (Activity B) by invoking its onCreate() method and passing it the Intent.*

Now let's see how we can call intents from our PicoLisp app.


---


### Example: Camera ``takePictureIntent`` as per Android docs

A typical intent is a call to take a picture from the smartphone app. Let's look at the example Java code from the [Android documentation](https://developer.android.com/training/camera/photobasics#java).

First, we need to check if the camera is available: 

```undefined
getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)
```

Then we can call the **intent**, which involves three pieces: The Intent itself, a call to start the external Activity, and some code to handle the image data when focus returns to your activity. 

```undefined
static final int REQUEST_IMAGE_CAPTURE = 1;

private void dispatchTakePictureIntent() {
    Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
    try {
        startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
    } catch (ActivityNotFoundException e) {
        // display error state to the user
    }
}
```

Now let's see how we can call this from PicoLisp.

---

### The ``java`` function

Let's take a look at ``lib/android.l`` in your local pil21-installation (or in the PilBox source code). Here we find the definition how to access the Java environment from PicoLisp in line 37 to 45:

```undefined
# Java I/O
# (java "cls" 'T ['any ..]) -> obj         New object
# (java 'obj ['n] 'msg ['any ..]) -> any   Send message to object
# (java 'obj "fld" ['any]) -> any          Value of object field
# (java "cls" ['n] 'msg ['any ..]) -> any  Call method in class
# (java "cls" "fld" ['any]) -> any         Value of class field
# (java T "cls" ["cls" ..]) -> obj         Define interface
# (java 'obj) -> [lst ..]                  Reflect object
# (java "cls") -> cls                      Get class
```

What does this tell us. The types of the arguments to ``java`` specify the type of the call. These types may be

- symbols (transient, internal or external),
- short numbers,
- or ``T``.

(read [here](https://picolisp-explored.com/concepts-and-data-types) for data types of PicoLisp).

Then a transient symbol ``cls`` denotes a **Java class name**, and ``fld`` a **field** in a class:

- An external symbol ``obj`` denotes a Java object
- An internal symbol ``msg`` denotes a message (method call)

The following ``any`` arguments may be of any type (numbers, symbols (normally strings) or lists (e. g., arrays in Java).

---

Now let's "translate"  the line of code which checks the camera permissions: 

```undefined
getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)
```

``hasSystemFeature`` is a method of the Android [PackageManager abstract class](https://developer.android.com/reference/android/content/pm/PackageManager) and ``getPackageManager`` is a method of the abstract [``Context`` class](https://developer.android.com/reference/android/content/Context). So this means, the line above is actually a short form of:

```undefined
context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)
```

Now in PicoLisp: we can express ``context.getPackageManager()`` by 

```undefined
(let PM (java CONTEXT 'getPackageManager))
``` 

where ``CONTEXT`` is a pre-defined database object describing the android context (more on this later) and ``'getPackageManager`` is the message. This corresponds to the syntax:

```undefined
# (java 'obj ['n] 'msg ['any ..]) -> any   Send message to object
```
 
Then we call the``hasSystemFeature`` method of the package manager class:

```undefined
(java PM 'hasSystemFeature "android.hardware.camera")
```

---

Now let's look at the ``takePictureIntent`` in Java and PicoLisp:

```undefined
# Java
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

# PicoLisp
(let Intent (java "android.content.Intent" T "android.media.action.IMAGE_CAPTURE"))
```

---

Next, the Java code

```undefined
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
```

can be mapped to the PicoLisp function ``startActivityForResult`` which is defined in ``lib/android.l``. Note that the intent is already defined within in the PicoLisp function ``startActivityForResult``:

```undefined
(de startActivityForResult (Fun Action . @)
   (let Intent (java "android.content.Intent" T Action)
      (catch '("ActivityNotFound")
         ...
```

where ``Fun`` is the function that should be handled and ``Action`` is the activity, in this case ``"android.media.action.IMAGE_CAPTURE"``. It generates a new object by calling the ``new()`` function in Java.

The complete example: 

```undefined
# Java (try-catch removed)
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(takePictureIntent, 1);

# PicoLisp
(startActivityForResult Fun "android.media.action.IMAGE_CAPTURE")
```

where ``Fun`` defines what to do with the picture. We will see an example of this in the next post, where the picture will be saved in a temporary directory.

---

### The CONTEXT object

In the example above, we used the ``CONTEXT`` object in ``(java CONTEXT 'getPackageManager)`` without explaining what is actually is. So let's do that now: ``CONTEXT`` is defined in ``lib/android.l`` as

```undefined
# Android Context
(local) (CONTEXT GUI Config javaExt)
(de CONTEXT . {H@@@40000000000})  # file 32768, obj (hex "100000000")
```

where ``{H@@@40000000000}`` is the external database object. We can inspect it in the PilBox Repl or from your local pty-connection:

```undefined
android: (show CONTEXT)
{H@@@40000000000} ({H@@@1404477010} . "de.software_lab.pilbox.PicoLisp")
   GUI {H@@@1725467726}
   Home "/data/user/0/de.software_lab.pilbox/files"
   Pid {H@@@27043500604}
   Port "8081"
    <...>
   Uuid "de1958ea-d909-44a7-83f7-cd4d750a68ca"
   Loaded T
-> {H@@@40000000000}
```

As  you can see, the object's class is ``"de.software_lab.pilbox.PicoLisp"``. Let's check that one:

```undefined
android: (show '{H@@@1404477010})
{H@@@1404477010} ({H@@@1114542263} . "android.app.Service")
   NIL
   mActivityManager
   mApplication
   <...>
-> {H@@@1404477010}
```

and we find that the superclass is ``"android.app.Service"`` which shows that PicoLisp is actually running as a **service**. Apps have activities and services - the PilBox **activity** can be inspected in the ``GUI`` property of ``CONTEXT``:


```undefined
android: (show  (get CONTEXT 'GUI))
{H@@@1725467726} ({H@@@1233152210} . "de.software_lab.pilbox.PilBoxActivity")
   PilView {H@@@46020644}
   <...>
   Config {H@@@1565731746}
   <...>
   Home "/data/user/0/de.software_lab.pilbox/files/"
   <...>
-> {H@@@1725467726}
```

From here, you could check the ``Config`` component with ``(show (get CONTEXT 'GUI 'Config)`` or ``PilView`` with ``(show (get CONTEXT 'GUI 'PilView))``, and so on.

---

This post showed a quick (and rather superficial) introduction to how to map Java and PicoLisp code in order to access smartphone components. In the next posts, we will study some examples from the demo applications.


---

### Sources

- https://developer.android.com


