You are browsing as a guest. Sign up (or log in) to start making projects!

Android Desktop

Hardware
  • 4 Devlogs
  • 19 Total hours

As a replacement for my broken Android Auto device, I'm using a capture card as an alternate display on desktop mode and working on a script that will pass my touchscreen input through to the phone.

Open comments for this post

1h 49m 44s logged

android-desktop is live!

Just published my second npm package, this time for working with app windows on android’s desktop mode for external displays.

Now that this is polished I’ll officially be moving on to the hardware stage, I’ll just need to get funding for a monitor, stereo amplifier, 12V to 20V booster, and I should be good to start building.

Usage

parseDisplayInfo(data)

Parses a DisplayInfo object to JSON. This is mainly intended to be used internally by getDisplays().

  • data: A string containing DisplayInfo data. See the DisplayInfo source (especially the toString() function) for more info.

getDisplays()

Returns an array of DisplayInfo objects. See https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/view/DisplayInfo.java for more info on what’s included. To avoid issues when translationg to a JSON structure, any entries that were singular values rather than key/value pairs are put inside a _flags array, since most are intended to be flags. However, as you can see in the toString() function of the DisplayInfo source linked above, the first value entered is always the name of the device, so this will always be the first item in _flags.

getDensity(displayId)

Returns the dpi of a given display.

  • displayId: The id of the display

setDensity(displayId)

Sets the dpi of a given display. This can be useful for scaling app content.

  • displayId: The id of the display

startActivity(displayId, pkg, forceStart)

Starts an activity on a given display. If forceStart is set to true

  • displayId: The id of the display
  • pkg: The package name of the app to start. Some apps may require you to include an intent as well.
  • forceStart: If true, the app is closed and reopened, which can help with stability. Set to true by default.

getTaskId(displayId, pkg)

Returns the task id of an app on a given display. Returns null if it couldn’t be found.

  • displayId: The id of the display.
  • pkg: The package name of the app.

resizeTask(taskId, x1, y1, x2, y2)

Sets the position and size of an app window on external displays in desktop mode.

  • taskId: The task id of the app.
  • x1: The x coordinate to move the top left corner to.
  • y1: The y coordinate to move the top left corner to.
  • x2: The x coordinate to move the bottom right corner to.
  • y2: The y coordinate to move the bottom right corner to.
0
0
4
Open comments for this post

2h 25m 43s logged

Apps are working!

I’m using adb to spawn in windows for the apps I want and resize them to fill a grid on the screen. This is all fully customizable in config.json.

I changed up a lot of my plan for this project, instead of connecting my laptop to the display and forwarding the touch events to my phone I’m now just connecting my phone to a usb c hub that supports alt display to connect it directly to the monitor while also having a data cable connected to my laptop for adb.

This unfortunately means that showing my laptop’s display on the screen wil now be much less convenient… and that I completely wasted my time writing evdevlib. I was kinda excited to use my own package for a project, but it just isn’t worth the noticeable latency when forwarding inputs and using a capture card. I’ll probably look into plugging the phone and laptop into some sort of splitter to toggle which usb c is forwarded to the monitor, or worst-case scenario I could just leave the monitor input on auto and unplug the hdmi from my laptop when I’m not using it, since I doubt I’ll need it very often.

Either way I’m very happy with how this is turning out so far, the last major hurtle will be connecting the audio to my car. The monitor does have an aux output so I’ll just have to go buy an amplifier at some point, as well as the usb c hub. Until then I’ll just smooth some things out until I’m comfortable posting the code publicly.

0
0
3
Open comments for this post

10h 9m 24s logged

Since I’ll be using an alternate display on desktop mode, I’ll need to pass the displayId when I forward input so that it doesn’t input on my phone’s builtin screen. The id of the builtin one is conveniently always 0, but the id of the external display changes every time I plug my phone into the display card, so I decided to automate the process by parsing the output of adb shell cmd display get-displays whenever the script starts. This tuned out to be way more of a pain than I expected, especially since the syntax isn’t consistent across the entire output, but I’m happy with how it turned out, even if I never use it again. I might make another npm package for this one in the future, but I haven’t really done enough testing to be confident enough in its reliability yet. It seems to work fine for the display info at least, so I’ll move on for now.

0
0
2
Open comments for this post

5h 1m 35s logged

Just published the evdevlib package on npm!

Usage

listDevices([options])

Lists available character devices.

  • options: An object used to provide optional arguments.
    • info: Automatically fetches the device name from /sys/class/input.
    • path: Which directory to scan for devices (default: /dev/input).

Example:

import { listDevices } from 'evdevlib';

console.log(listDevices()); // Prints: [ { path: '/dev/input/event0' }]
console.log(listDevices({ info: true })); // Prints: [ { path: '/dev/input/event0', name: 'Mouse' }]

Class: DeviceListener

Listens to a device’s input stream

  • constructor(path, […args]):
    • path: The path of the interface to listen to (e.g. /dev/input/event0)
    • args: Args to pass to the EventEmitter constructor
  • stop(): Destroys the read stream and stops listening for input.
  • events
    • data: Emitted when input is received from the device.
    • error: Emitted when an ‘error’ event is received from the read stream.
      • error
    • close: Emitted when a ‘close’ event is received from the read stream.
    • end: Emitted after stop() or when an ‘end’ event is received from the read stream.

Example:

import { DeviceListener } from 'evdevlib';

let listener = new DeviceListener('/dev/input/event0');
listener.on('data', input => console.log(input));
listener.on('error', error => console.log('Error reading device input:', error));
console.log('Listening for input...');
// ...
listener.stop();
console.log('Stopped listening for input.');

An input event for relative mouse movement would look something like this:

{
    tv_sec: 1783887711n,
    tv_usec: 338192n,
    type: 'REL',
    code: 'REL_X',
    value: 1
}

See https://docs.kernel.org/input/event-codes.html#input-event-codes for all event types.

0
0
2

Delete project?

Are you sure you want to permanently delete this project? This action cannot be undone.

All devlogs, followers, and associated data will be removed.

Followers

Loading…