Launch on Android
Overview
CaptureStandaloneActivity
is the entry point to Stnadalone Capture. The Activity optionally takes a CaptureConfig
for configuration as an intent extras. If none is provided, it will use the default - CaptureConfig.defaultConfig
.
Our ActivityResultContract
implementation for the capture is CaptureImages
.
As Android has recently deprecated startActivityForResult
, the example below will include both the classic startActivityForResult
as well as the registerForActivityResult
methods of starting the capture activity.
Example
class MyActivity : AppCompatActivity() {
// ...
// ---------- Using `startActivityForResult` ----------
private fun launchCapture() {
// Create configuration object if required
val config = CaptureConfig(
allowFlashToggling = false,
defaultFlashMode = FlashMode.FLASH_MODE_OFF,
maxPages = 5,
enableLongCapture = false,
enableSecureWindow = true
)
// Create intent and attach config
val intent = Intent(this, CaptureStandaloneActivity::class.java).apply {
putExtra(CaptureStandaloneActivity.EXTRA_CAPTURE_CONFIG, config)
}
// Start the capture activity
startActivityForResult(intent, REQUEST_CODE_TO_CAPTURE)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when (requestCode) {
REQUEST_CODE_TO_CAPTURE -> {
// See next section for handling the result
}
else -> super.onActivityResult(requestCode, resultCode, data)
}
}
companion object {
private const val REQUEST_CODE_TO_CAPTURE = 0x123
}
// ---------- Using `registerForActivityResult` ----------
private lateinit var launcher: ActivityResultLauncher<CaptureConfig>
private fun registerForCaptureResult() {
val contract = CaptureImages()
launcher = registerForActivityResult(contract) { result ->
// See next section for handling the result
}
}
private fun launchCaptureWithRegistration() {
launcher.launch(CaptureConfig())
}
}
public class MyActivity extends AppCompatActivity {
private static final int REQUEST_CODE_TO_CAPTURE = 0x123;
// ...
// ---------- Using `startActivityForResult` ----------
private void launchCapture() {
// Create configuration object if required
final CaptureConfig captureConfig = new CaptureConfig(
true,
true,
FlashMode.FLASH_MODE_OFF,
true,
true,
false,
true,
3,
false,
true,
false,
true,
true,
true,
DocumentTypeStrings.Companion.getDefaultReceiptStrings(),
CaptureDocumentType.RECEIPT
);
// Create intent and attach config
final Intent intent = new Intent(this, CaptureStandaloneActivity.class);
intent.putExtra(CaptureStandaloneActivity.EXTRA_CAPTURE_CONFIG, config);
// Start the capture activity
startActivityForResult(intent, REQUEST_CODE_TO_CAPTURE);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable @org.jetbrains.annotations.Nullable Intent data) {
if (requestCode == REQUEST_CODE_TO_CAPTURE) {
// See next section for handling the result
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
// ---------- Using `registerForActivityResult` ----------
private ActivityResultLauncher<CaptureConfig> launcher;
private void registerForCaptureResult() {
CaptureImages contract = new CaptureImages();
launcher = registerForActivityResult(contract, new ActivityResultCallback<BareCapturedReceiptData[]>() {
@Override
public void onActivityResult(BareCapturedReceiptData[] result) {
// See next section for handling the result
}
});
}
private void launchCaptureWithRegistration() {
launcher.launch(new CaptureConfig());
}
// ...
}
Using Captured Images
Upon completion, the CaptureStandaloneActivity
will provide the calling activity an array of BareCapturedReceiptData
, objects representing the captured receipt images. The BareCapturedReceiptData
array will be attached to the activity result data
Intent
as a Serializable
with the key CaptureStandaloneActivity.EXTRA_CAPTURED_RECEIPTS
.
If the user cancels the flow or the flow ends unexpectedly, the resultCode
will be Activity.RESULT_CANCELED
, or the returned data will be null
.
The examples below provide both, the deprecated startActivityForResult
method, as well as the registerForActivityResult
flow.
// ---------- Using `startActivityForResult` ----------
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when (requestCode) {
REQUEST_CODE_TO_CAPTURE -> {
// Result is OK when the flow was completed and images were captured
if (resultCode == Activity.RESULT_OK && data != null) {
// Retrieve captured images
val capturedImages = data.getSerializableExtra(CaptureStandaloneActivity.EXTRA_CAPTURED_RECEIPTS)
as Array<BareCapturedReceiptData>
// Process images
// ...
// *Important* clean up images
capturedImages.forEach { it.cleanup() }
} else {
// Capture flow was cancelled
Toast.makeText(this, "No images captured", Toast.LENGTH_LONG).show()
}
}
else -> super.onActivityResult(requestCode, resultCode, data)
}
}
// ---------- Using `registerForActivityResult` ----------
private fun registerForCaptureResult() {
val contract = CaptureImages()
launcher = registerForActivityResult(contract) { capturedImages ->
if (capturedImages != null) {
// Process images
// ...
// *Important* clean up images
capturedImages.forEach { it.cleanup() }
} else {
// The user cancelled the capture flow
Toast.makeText(this, "No images captured", Toast.LENGTH_LONG).show()
}
}
}
// ---------- Using `startActivityForResult` ----------
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
if (requestCode == REQUEST_CODE_TO_CAPTURE) {
if (resultCode == Activity.RESULT_OK && data != null) {
// Retrieve captured images
BareCapturedReceiptData[] capturedImages = (BareCapturedReceiptData[]) data.getSerializableExtra(CaptureStandaloneActivity.EXTRA_CAPTURED_RECEIPTS);
// Process images
// ...
// *Important* clean up images
for (BareCapturedReceiptData capturedImage : capturedImages) {
capturedImage.cleanup();
}
} else {
// Capture flow was cancelled
Toast.makeText(this, "No images captured", Toast.LENGTH_LONG).show();
}
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
// ---------- Using `registerForActivityResult` ----------
private void registerForCaptureResult() {
CaptureImages contract = new CaptureImages();
launcher = registerForActivityResult(contract, new ActivityResultCallback<BareCapturedReceiptData[]>() {
@Override
public void onActivityResult(BareCapturedReceiptData[] result) {
if (result != null) {
// Process images
// ...
// *Important* clean up images
for (BareCapturedReceiptData capturedImage : result) {
capturedImage.cleanup();
}
} else {
// Capture flow was cancelled
Toast.makeText(MyActivity.this, "No images captured", Toast.LENGTH_LONG).show();
}
}
});
}
Branding
In addition to standard color constants, described on Branding page, there is an additional set of colours that is used by the Standalone Capture and can be customized as well.
In order to customize these colours, please create an additional style
element with the name New.Theme.Sensibill.CaptureStandalone
and parent Base.New.Theme.Sensibill.CaptureStandalone
. The available colours to customize will be shown in the example below.
<style name="New.Theme.Sensibill.CaptureStandalone" parent="Base.New.Theme.Sensibill.CaptureStandalone">
<item name="sb__colourCaptureBackground">#000000 by default</item>
<item name="sb__colourOnCaptureBackground">#FFFFFF by default</item>
<item name="sb__colourOnCaptureBackgroundDisabled">#99FFFFFF by default</item>
</style>