Secondary Display SDK
The Secondary Display SDK lets Android applications display content on the customer-facing screen of supported Dejavoo dual-display terminals. Integrators can initialize the display, show images or custom Android views, clear the screen, and release the display when it is no longer needed.
Prerequisites
Before using the Secondary Display SDK, ensure you have the following:
- A supported Dejavoo dual-display terminal: P8 Dual (opens in a new tab) or P8 Dual Go (opens in a new tab)
- An Android application with minimum SDK 21 or later
- The supplied
peripheral_sdk_v5.0.aarfile - An image with an absolute, readable file path when using
showImage() - The host application should be listed on DvStore
- Login credential to iPOSpays (opens in a new tab)
For Sandbox (UAT)
Users should be onboarded on the iPOSpays sandbox (UAT) environment as a merchant and have a valid TPN.
For Production (Live)
Users should be onboarded on the iPOSpays production environment as a merchant and have a valid TPN.
If you do not have a TPN, contact your ISO or devsupport@dejavoo.io.
The peripheral_sdk_v5.0.aar file is provided with the kit. Download from here (opens in a new tab)
Downloading the Secondary Display SDK
- Locate the peripheral_sdk_v5.0.aar (opens in a new tab) file provided with your Secondary Display SDK kit.
- Copy the file to your Android project.
- Place the file in the project's
libsfolder.
Configuring Gradle Dependencies
Open your module-level build.gradle file and add the SDK inside the dependencies block:
implementation files "libs/peripheral_sdk_v5.0.aar"Synchronize Gradle
In Android Studio, select Sync Project with Gradle Files.
This loads the Secondary Display SDK and makes its APIs available to your application.
Initialize the Secondary Display
Create one SecondaryDisplay instance and keep it for the screen or application lifecycle.
Initialization is asynchronous. Wait for the initialization callback to confirm that the display is ready before calling showImage(), showView(), or clear().
private val secondaryDisplay = SecondaryDisplay()
secondaryDisplay.init(applicationContext) { code, message ->
runOnUiThread {
if (code == 0 && secondaryDisplay.isReady) {
// Ready to show an image or view
} else {
Log.e("SecondaryDisplay", "Init failed: $code $message")
}
}
}Do not call isReady() immediately after init(). Wait for the initialization callback and confirm that code == 0 and the display is ready.
Display an Image
Use showImage() to display a PNG or GIF image on the secondary display. The method requires an absolute file path to the image.
Storage Permissions
No storage permission is required when using app-owned files, such as files stored in filesDir or cacheDir.
If the application reads images directly from shared storage, declare and request the permission appropriate for the Android version:
<uses-permission
android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />For better compatibility with Android scoped storage, copy packaged assets or user-selected content into an app-owned file and pass the absolute path to showImage().
val imagePath = File(filesDir, "customer_ad.gif").absolutePath
val code = secondaryDisplay.showImage(imagePath)
if (code != 0) {
Log.e("SecondaryDisplay", "showImage failed: $code")
}Recommended image size: Match the physical resolution of the secondary display. For the P8 integration sample, use 378 × 172 pixels to avoid unexpected scaling or cropping.
Display a Custom View
Use showView() to display a custom Android view hierarchy on the secondary display. The SDK measures and lays out the view based on the detected secondary-display resolution. Create and submit views on the main thread.
private fun showWelcomeView() {
val root = LinearLayout(this).apply {
orientation = LinearLayout.VERTICAL
gravity = Gravity.CENTER
setBackgroundColor(Color.WHITE)
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
}
root.addView(TextView(this).apply {
text = "Welcome"
textSize = 26f
gravity = Gravity.CENTER
setTextColor(Color.BLACK)
setTypeface(typeface, Typeface.BOLD)
})
root.addView(TextView(this).apply {
text = "Thank you for shopping with us"
textSize = 14f
gravity = Gravity.CENTER
setTextColor(Color.DKGRAY)
})
val code = secondaryDisplay.showView(root)
if (code != 0) {
Log.e("SecondaryDisplay", "showView failed: $code")
}
}Clear the Display
Use clear() to replace the currently displayed image or view with a blank screen.
val code = secondaryDisplay.clear()
if (code != 0) {
Log.e("SecondaryDisplay", "clear failed: $code")
}Calling clear() does not make the SDK instance unusable. You can continue using the instance after clearing the display.
Release Resources
Use release() when the hardware connection is no longer needed. This releases the secondary-display service and associated resources.
Release the SDK when the lifecycle that owns the display ends or when the application intentionally stops using the secondary display.
override fun onDestroy() {
secondaryDisplay.release()
super.onDestroy()
}After calling release(), you must initialize the SDK again and wait for the initialization callback before displaying new content.
secondaryDisplay.release()
secondaryDisplay.init(applicationContext) { code, message ->
if (code == 0 && secondaryDisplay.isReady) {
secondaryDisplay.showImage(imagePath)
}
}Lifecycle rule: Do not call showImage(), showView(), or clear() after release() until a new initialization callback confirms that the display is ready.
Complete Integration Example
The following examples show how to initialize the SDK, display content, clear the display, and release resources.
class CustomerDisplayActivity : AppCompatActivity() {
private val display = SecondaryDisplay()
private var pendingAction: (() -> Unit)? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
initializeDisplay()
}
private fun initializeDisplay() {
display.init(applicationContext) { code, message ->
runOnUiThread {
val action = pendingAction
pendingAction = null
if (code == 0 && display.isReady) {
action?.invoke()
} else {
Log.e("SecondaryDisplay", "Init failed: $code $message")
}
}
}
}
private fun whenDisplayReady(action: () -> Unit) {
if (display.isReady) {
action()
} else {
pendingAction = action
initializeDisplay()
}
}
fun showImage(path: String) = whenDisplayReady {
val code = display.showImage(path)
if (code != 0) Log.e("SecondaryDisplay", "showImage: $code")
}
fun showView(view: View) = whenDisplayReady {
val code = display.showView(view)
if (code != 0) Log.e("SecondaryDisplay", "showView: $code")
}
fun clearAndRelease() {
if (display.isReady) {
display.clear()
display.release()
}
}
override fun onDestroy() {
pendingAction = null
if (display.isReady) display.release()
super.onDestroy()
}
}API Methods
| Method | Description |
|---|---|
init(Context) | Starts asynchronous initialization of the secondary display without a result callback. |
init(Context, InitCallback) | Starts asynchronous initialization and provides a callback when initialization completes. This is the preferred overload. |
isReady() | Returns true when the secondary display is initialized and ready to receive display commands. |
showImage(String) | Displays a PNG or GIF image using an absolute file path. |
showView(View) | Displays a custom Android view hierarchy on the secondary display. |
clear() | Clears the current content and displays a blank screen. |
release() | Releases the secondary-display service and associated resources. |
Error Codes
| Code | Meaning | Action |
|---|---|---|
| 0 | Request accepted successfully. | No action required. |
| -1 | Invalid input or general operation failure. | Check the context, file path, view, and device logs. |
| -2 | Unsupported image extension. | Use a PNG or GIF image. |
| -10 | SDK is not initialized or the display is not ready. | Call init() and wait for the successful initialization callback. |
| Other non-zero | Device- or driver-specific failure. | Record the error code and collect Logcat output. |