Customization
Functionality
CaptureStandaloneActivity
Configuration
The behaviour of CaptureStandaloneActivity can be configured by passing a CaptureConfig configuration object as a Intent Extra with the tag CaptureStandaloneActivity.EXTRA_CAPTURE_CONFIG
.
The configurable properties and their effects are below:
Name | Description | Type | Default Value |
---|---|---|---|
defaultFlashMode | Sets the default flash mode that will be used by the camera. | .models.FlashMode * |
FLASH_MODE_AUTO |
enableAutoCapture | Enables the auto-capture feature. | Boolean | true |
initialAutoCaptureState | Sets the initial state of the auto-capture functionality (true represents ON).Note: This flag only has an effect if enableAutoCapture is set to true . |
Boolean | true |
enableBlurDetection | Enables the blur detection feature. When enabled, the capture flow will attempt to determine if a captured image is blurry and display a warning tothe user if so, prompting them to retake the blurry image. |
Boolean | true |
enableFeedbackToast | Enables a feedback toast message on the capture screen. | Boolean | true |
enableGalleryImport | Enables the ability for a user to select an image from their device’s image gallery. | Boolean | true |
enableMultiPageCapture | Allows the user to capture multiple distinct images in a single capture flow. | Boolean | true |
maxPages | Determines the maximum number of distinct images that can be captured in a single capture flow. Note: This value is only used if enableMultiPageCapture is set to true |
Int | 3 |
enableLongCapture | Enables the long receipt feature. When enabled, the user is able to select a mode in which they can take a receipt image as two different parts: a top and a bottom. The images will then be stitched together. |
Boolean | true |
enableCrop | Enables the user to manually crop, or adjust the existing cropping on a captured image. | Boolean | true |
enableSecureWindow | Enables Android’s secure window feature for the capture flow. When enabled, the user will be unable to take screenshots or record the screen. | Boolean | false |
attachLocationData | Enables attaching GPS location data via EXIF to captured images. In order for this feature to function properly, the consumer of this module must first request location permissions from the user before launching the capture activity. Permissions Required: - android.Manifest.permission.ACCESS_COARSE_LOCATION - android.Manifest.permission.ACCESS_FINE_LOCATION See the EXIF Data section for more detailed information on recorded EXIF data |
Boolean | false |
compressForSensibillApi | This flag only has an effect if using the Standalone Capture module directly Enables built-in compression for captured images in order to make them compatible with the Sensibill APIs. If using the standalone capture module to capture images to be used with the Sensibill SDK, or images to be otherwise uploaded to the Sensibill APIs please ensure this flag is set to true. When set to false, captured images will be returned at full size with no compression. Default value: true |
Boolean |
*(base module package: com.getsensibill.capturestandalone
)
Example usage: Configuring and launching standalone capture such that the flash is always off, 5 images can be taken, long receipt capture is disabled, and the secure window feature is enabled, otherwise default behaviour is used. Kotlin
val config = CaptureConfig(
allowFlashToggling = false,
defaultFlashMode = FlashMode.FLASH_MODE_OFF,
maxPages = 5,
enableLongCapture = false,
enableSecureWindow = true
)
val intent = Intent(this, CaptureStandaloneActivity::class.java).apply {
putExtra(CaptureStandaloneActivity.EXTRA_CAPTURE_CONFIG, config)
}
startActivityForResult(intent, 0x05)
Java
CaptureConfig config = new CaptureConfig(
false, // Allow flash toggling
FlashMode.FLASH_MODE_OFF, // Initial flash state
true, // Auto-capture enabled
true, // Initially auto-capture is enabled
true, // Blur detection enabled
true, // Feedback toasts enabled
true, // Gallery import enabled
true, // Multi-page capture is enabled
5, // 5 pages will be captured
false, // Long receipt capture disabled
true, // Crop feature enabled
true, // Secure window feature will be enabled
true // Attach location data will be enabled
);
Intent intent = new Intent(this, CaptureStandaloneActivity.class);
intent.putExtra(CaptureStandaloneActivity.EXTRA_CAPTURE_CONFIG, config);
startActivityForResult(intent, 0x05);
EXIF Data
Captured Data
The Capture Standalone module records and attaches some EXIF data to the images that it outputs. The recorded data, as well as any applicable configurations are as follows.
When using the camera to capture an image:
- The device make and model are always attached
- If the
attachLocationData
flag is set totrue
and the host app has already acquired location permissions, GPS data will be attached
When using gallery import:
- All existing EXIF data from the source image is preserved
Location Data Setup
In order for the Capture Standalone module to record location data, the following steps must be taken.
AndroidManifest.xml
Permission Request
The integrating app’s AndroidManifest
will automaticall inherit the permissions requested by the Capture Standalone module, but for verbosity it is recommended that you add the following permissions to your own AndroidManifest
:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
Note: If you do not wish to use the location data section of the standalone capture module, and your app did not previously request location permissions, the permissions can be removed from the manifest by adding the following to your AndroidManifest
:
<!-- Integrators can remove the permissions by including the following: -->
<!-- Prevent the Sensibill SDK from causing the host app to require the location permission -->
<uses-permission
android:name="android.permission.ACCESS_FINE_LOCATION"
tools:node="remove" />
<uses-permission
android:name="android.permission.ACCESS_COARSE_LOCATION"
tools:node="remove" />
Runtime Permission Request
Before attempting to launch the Capture Standalone module, the integrating app must independently request the user for locaiton permissions. The Capture Standalone module will not make the location permission request itself, and will only gather location data if both the CaptureConfig.attachLocationData
flag is set to true
and the required location permissions are already granted.
See below for an example implementation. Kotlin:
class IntegratorActivity : AppCompatActivity() {
// ...
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// ...
if (savedInstanceState == null) {
// Array of required permissions
val permissions = arrayOf(
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION
)
val hasPermissions = permissions
// Check each permission
.map { ContextCompat.checkSelfPermission(baseContext, it) == PackageManager.PERMISSION_GRANTED }
// We have required permissions if every check resolves to `true`
.all { it }
if (!hasPermissions) {
ActivityCompat.requestPermissions(this, permissions, REQUEST_CODE_LOCATION_PERMISSION)
}
// ...
}
// ...
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
when (requestCode) {
REQUEST_CODE_LOCATION_PERMISSION -> {
if (grantResults.any { it == PackageManager.PERMISSION_DENIED }) {
Timber.d("Location permission request denied")
}
}
else -> super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
}
// ...
}
Java:
public class IntegratorActivity extends AppCompatActivity {
// ...
@Override
public void onCreate(Bundle savedInstanceState) {
if (savedInstanceState == null) {
String[] permissions = {
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION
};
boolean hasPermissions = true;
for (String permission : permissions) {
boolean hasPermission = ActivityCompat.checkSelfPermission(getBaseContext(), permission) == PackageManager.PERMISSION_GRANTED;
if (!hasPermission) {
hasPermissions = false;
break;
}
}
if (!hasPermissions) {
ActivityCompat.requestPermissions(this, permissions, REQUEST_CODE_LOCATION_PERMISSION);
}
}
}
// ...
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
switch (requestCode) {
case REQUEST_CODE_LOCATION_PERMISSION:
boolean requestsGranted = true;
for (int grantResult : grantResults) {
if (grantResult == PackageManager.PERMISSION_DENIED) {
requestsGranted = false;
break;
}
}
if (!requestsGranted) {
Log.d("TAG", "Permission request denied");
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
// ...
}
Configuration Flag
When creating the CaptureConfig
object, the CaptureConfig.attachLocationData
flag must be set to true
Styling
Theme Customization
Colour Attributes
Coloured components of the theme used in the standalone capture module can be customized. This can be achieved by creating a new style object in your app’s resources folder declaring a style named New.Theme.Sensibill
, extending LegacyIntegration.New.Theme.Sensibill
Example: NOTE: It is very important that the stlye’s name and parent name match the example
<style name="New.Theme.Sensibill" parent="LegacyIntegration.New.Theme.Sensibill" >
<item name="sb__brandPrimaryBackground">@color/your_colour_here</item>
<item name="sb__brandPrimaryBackground2">@color/your_colour_here</item>
<item name="sb__brandPrimaryForeground">@color/your_colour_here</item>
<item name="sb__brandSecondaryBackground">@color/your_colour_here</item>
<item name="sb__brandSecondaryForeground">@color/your_colour_here</item>
<item name="sb__uiPrimaryBackground">@color/your_colour_here</item>
<item name="sb__uiPrimaryForeground">@color/your_colour_here</item>
<item name="sb__uiSecondaryBackground">@color/your_colour_here</item>
<item name="sb__uiSecondaryForeground">@color/your_colour_here</item>
<item name="sb__surfaceBackground">@color/your_colour_here</item>
<item name="sb__surfaceForeground">@color/your_colour_here</item>
<item name="sb__stateErrorBackground">@color/your_colour_here</item>
<item name="sb__stateErrorForeground">@color/your_colour_here</item>
<item name="sb__stateDisabledBackground">@color/your_colour_here</item>
<item name="sb__stateDisabledForeground">@color/your_colour_here</item>
</style>
Text Appearances
The set of text appearances used by this module can be customized by overriding any or all the following text appearance styles:
NOTE: As above, it is important that both the style name
and parent
exactly match those defined here
<style name="TextAppearance.Sensibill" parent="Base.TextAppearance.Sensibill" />
<style name="TextAppearance.Sensibill.H1" parent="Base.TextAppearance.Sensibill.H1" />
<style name="TextAppearance.Sensibill.H2" parent="Base.TextAppearance.Sensibill.H2" />
<style name="TextAppearance.Sensibill.H3" parent="Base.TextAppearance.Sensibill.H3" />
<style name="TextAppearance.Sensibill.H4" parent="Base.TextAppearance.Sensibill.H4" />
<style name="TextAppearance.Sensibill.Headline" parent="Base.TextAppearance.Sensibill.Headline" />
<style name="TextAppearance.Sensibill.Body1" parent="Base.TextAppearance.Sensibill.Body1" />
<style name="TextAppearance.Sensibill.Body2" parent="Base.TextAppearance.Sensibill.Body2" />
<style name="TextAppearance.Sensibill.Button" parent="Base.TextAppearance.Sensibill.Button" />
<style name="TextAppearance.Sensibill.Subtitle" parent="Base.TextAppearance.Sensibill.Subtitle" />
<style name="TextAppearance.Sensibill.Caption" parent="Base.TextAppearance.Sensibill.Caption" />
<style name="TextAppearance.Sensibill.Badge" parent="Base.TextAppearance.Sensibill.Badge" />
Component Styles
The base component styles used by this module can be customized by overriding any or all the following component styles:
NOTE: As above, it is important that both the style name
and parent
exactly match those defined here
<!--===== Buttons =====-->
<!-- This shape appearance is used to define the background shape of Primary and Error buttons -->
<style name="ShapeAppearance.Sensibill.RoundedButton" parent="Base.ShapeAppearance.Sensibill.RoundedButton" />
<style name="Widget.Sensibill.Button.Primary" parent="Base.Widget.Sensibill.Button.Primary" />
<style name="Widget.Sensibill.Button.Error" parent="Base.Widget.Sensibill.Button.Error" />
<style name="Widget.Sensibill.Button.TextButton" parent="Base.Widget.Sensibill.Button.TextButton" />
<style name="Widget.Sensibill.Button.TextButton.Small" parent="Base.Widget.Sensibill.Button.TextButton.Small" />
<style name="Widget.Sensibill.Button.IconButton" parent="Base.Widget.Sensibill.Button.IconButton" />
<!--===== AlertDialog =====-->
<style name="AlertDialog.Sensibill.Theme" parent="Base.AlertDialog.Sensibill.Theme" />
<style name="Widget.Sensibill.AlertDialog.TextButton" parent="Base.Widget.Sensibill.AlertDialog.TextButton" />
Additional Customization of Specific UI Elements
Additionally, style customizations can be applied to individual views in the standalone capture flow in a manner similar to what is defined above.
For example, the Preview page “Continue” button can be styled like so:
<style name="Widget.Sensibill.ReceiptPreview.Button.Continue" parent="Base.Widget.Sensibill.ReceiptPreview.Button.Continue">
<item name="android:text">Finish</item>
<item name="backgroundTint">#444</item>
</style>
This customization would change the the button to have a gray background, and read “Finish” instead of “Continue”.
Overriding OpenCV Libraries
Only available on v1.26.1+
We allow overriding the OpenCV libraries used within the standalone capture, in case there is an existing version used within the application. A new loadOpenCvBlock
can be overridden before the OpenCvAnalyzer is initialized, allowing the integrator to load their own OpenCV libraries.
If you plan to use your own OpenCV libraries, exclude the opencv-for-capture
module when importing the sensibill dependencies.
For example:
implementation"com.getsensibill:sensibill-capture-standalone:X.X.X" {
exclude group: 'com.getsensibill', module: 'opencv-for-capture'
}
Then load your own libraries using the OpenCvLoader.loadOpenCvBlock
. This must be set prior to loading the standalone capture:
OpenCvLoader.loadOpenCvBlock = {
System.loadLibrary("openCvLib")
}
Replace the "openCvLib"
with the name of your OpenCV’s .so
file(s). You may need to look into your generated project files to find them by name.
Note: this method does not guarantee compatibility with every OpenCV version, but exists to help resolve conflicts if different OpenCV versions are being used.