-
-
Notifications
You must be signed in to change notification settings - Fork 52
5. SDK: Creating a Requirement
Smartspacer's Requirements allow the user to customise when Targets and Complications appear on the Smartspace. Plugins can provide their own Requirements based on their own rules.
Firstly, create a new project or open an existing one. It does not matter if the project uses Compose or Views, since Requirements use neither.
Add the Plugin SDK:
implementation 'com.kieronquinn.smartspacer:sdk-plugin:version'
You can find the latest version here
Requirements at their core are Content Providers, but the Smartspacer SDK handles most of the logic required for a Provider to function.
The basic Requirement class is as follows:
class ExampleRequirement: SmartspacerRequirementProvider() {
override fun isRequirementMet(smartspacerId: String): Boolean {
//Return whether the Requirement is currently met
}
override fun getConfig(smartspacerId: String?): Config {
//Return your configuration
}
override fun onProviderRemoved(smartspacerId: String) {
//Handle removal of the Requirement (optional)
}
}
Since a Requirement is based on ContentProvider, it must be specified as one, with a specific action and permission:
<provider
android:name=".ExampleRequirement"
android:authorities="${applicationId}.requirement.example"
android:permission="com.kieronquinn.app.smartspacer.permission.ACCESS_SMARTSPACER_REQUIREMENTS"
android:exported="true">
<intent-filter>
<action android:name="com.kieronquinn.app.smartspacer.REQUIREMENT" />
</intent-filter>
</provider>
Your Requirement must be exported, and must have the specific action and permission shown above. Without this, they will not work in Smartspacer.
The getConfig
method needs to return some basic information for Smartspacer about your Requirement. The available options are:
Config(
label = // Your Requirement's label to be shown in Smartspacer's settings UI
description = // A short description for your Requirement to be shown in the same UI
icon = // An Icon (android.graphics.drawable.Icon) to show in the same UI
allowAddingMoreThanOnce = // Optional: Whether the Requirement should be able to be added multiple times at once (defaults to true)
configActivity = // Optional: An Intent given as an option to the user in the settings UI after adding
setupActivity = // Optional: An Intent of an Activity presented to the user during setup (see below)
compatibilityState = // Optional: A CompatibilityState object representing whether this Requirement is compatible with the device or not (defaults to always compatible)
)
As a bare minimum, you must specify a label, description and icon. It's also recommended you consider specifying a Compatibility State, checking whether the device is able to add your Requirement or not. For example, you may require another app to load data from, in which case you would return CompatibilityState.Incompatible("App X is not installed")
if the app is not installed, or CompatibilityState.Compatible
if it is.
The setup and configuration activities work much the same as those used for App Widgets by Android. Specify an Intent, with any extras you wish, and Smartspacer will open it during the adding of a Requirement or when the user selects the settings option from the UI respectively. These Intents will also automatically be provided with the extra SmartspacerConstants.EXTRA_SMARTSPACER_ID
, a String containing the unique ID given to this Requirement during setup.
The setup activity must call Activity.setResult(Activity.RESULT_OK)
before finishing to tell Smartspacer setup was successful and to continue adding the Requirement. Otherwise, the Requirement will not be added and the provider's onProviderRemovedMethod
will be called.
The configuration activity may call Activity.setResult(Activity.RESULT_OK)
before finishing to tell Smartspacer to send a change notification to the Requirement, though this is optional.
When specifying a refresh period, please be mindful of battery use. Refreshes are also not guaranteed, the value is a limit to how often the refresh call will be made, not a guaranteed call. Refreshes also are not guaranteed to happen at the top of the minute (:00), so may not be reliable for time-sensitive refreshes such as calendar events or reminders. Enabling the refreshIfNotVisible
option means the refresh call will also be made when your Requirement is not currently in Smartspace, which may be useful if you check for an update to something periodically. Enabling this option can have a severe effect on battery life if combined with refreshing often, so please be extremely careful.
Smartspacer will call isRequirementMet
with the Requirement's ID when required, either due to a refresh request or if a reload is required by Smartspacer itself. You must return true
if the Requirement is met, or false
if not. The ID provided to this method is the same unique ID provided during setup, so you can use it to retreive local data to display in a Requirement, but please do not block the thread. Very simple data loading (eg. reading a row from a database or a JSON file) is usually fine, but making a network request at this state may result in failed loads and your Requirement not working.
When the user removes a Requirement from Smartspacer, the onProviderRemoved
method will be called with your unique Smartspacer ID. You should perform cleanup actions here, such as removing any data from the database related to the Requirement.
Please note that this method will not be called if Smartspacer is uninstalled.
If you wish to notify Smartspacer of a change to your Requirement, and thus a call to isRequirementMet
should be made, you can call one of the two static notifyChange
methods in SmartspacerRequirementProvider
from anywhere you have a context. These are:
-
SmartspacerRequirementProvider.notifyChange(Context, Authority, Smartspacer ID (optional))
: Updates a Requirement with a given provider Authority. If provided, only that with a given Smartspacer ID will be updated (only useful if you are allowing multiple of the same Requirement to be added) -
SmartspacerRequirementProvider.notifyChange(Context, Class<out SmartspacerRequirementProvider>, Smartspacer ID (optional))
: Updates a Requirement with a given Requirement class. If provided, only that with a given Smartspacer ID will be updated (only useful if you are allowing multiple of the same Requirement to be added)
Smartspacer supports an integrated backup system, since it is not available on Google Play. The idea of this is all Targets, Complications and Requirements contribute to a single backup file, which when restored provides the same data back to the plugins for restoration. You should put basic information such as settings in here, but data such as images should not be backed up - and large data will be rejected due to Android's Binder limit of 1MB. Backups are entirely optional - if you do not wish to implement it, the user will simply be presented with your Requirement during restoration and add it as if it were new.
During a backup, the createBackup
method will be called, passing the standard Smartspacer ID:
override fun createBackup(smartspacerId: String): Backup {
val settings = //load settings
return Backup(settings.serialiseToString(), "A short description")
}
You should use the ID to load the settings of your Requirement, and serialise it to a String (consider using GSON or similar libraries to flatten to JSON easily). A short description should also be provided specifying what was in the backup, which will be shown to the user in lieu of the Requirement's description so they know what is being restored.
Similarly, the restoreBackup
method is called during the restoration process:
override fun restoreBackup(smartspacerId: String, backup: Backup): Boolean {
//Handle restoring your backup
notifyChange(smartspacerId)
return true
}
Important note: The Smartspacer ID here will not be the same as your one at the time of backup. Requirements do not keep a static ID between different Smartspacer install instances
The Backup
object here contains the data you sent during the backup process. You should deserialise the data, commit it however you wish, and then call notifyChange(smartspacerId)
to refresh Requirement with this new data. Returning true
tells Smartspacer the restoration was successful, and the setup activity (if specified) does not need to be shown for this Requirement. If you cannot restore the Requirement for whatever reason, return false
and the setup activity will be shown.
Note: If your Requirement requires certain permissions which will not persist across a reinstall, consider returning
false
even if the restore succeeds, so you can make sure the user grants the permission before the Requirement finishes being added.