Skip to content

3. SDK: Creating a Target

Kieron Quinn edited this page Dec 23, 2024 · 5 revisions

Creating a Target

Smartspacer's Targets are pages of information, consisting of at least a title, subtitle and icon. With one of the included Target Templates, you can also include additional information including images, lists and game scores. On this page, we will discuss the process of creating an app with a simple Target, and the additional options available with templates.

Setup

Firstly, create a new project or open an existing one. It does not matter if the project uses Compose or Views, since Targets use neither.

Adding the SDK

Add the Plugin SDK:

implementation 'com.kieronquinn.smartspacer:sdk-plugin:version'

You can find the latest version here

Proguard

If your plugin is going to provide a Target which contains only a title (no subtitle or icon), eg. a Greeting Target, you must also exclude the SDK from your Proguard obfuscation. This is only required for this specific use, other uses are not impacted

-keep class com.kieronquinn.app.smartspacer.sdk.** { *; }

The Target Class

Targets at their core are Content Providers, but the Smartspacer SDK handles most of the logic required for a Provider to function.

The basic Target class is as follows:

class ExampleTarget: SmartspacerTargetProvider() {

    override fun getSmartspaceTargets(smartspacerId: String): List<SmartspaceTarget> {
        //Return a list of SmartspaceTargets
    }

    override fun getConfig(smartspacerId: String?): Config {
        //Return your configuration
    }

    override fun onDismiss(smartspacerId: String, targetId: String): Boolean {
        //Handle dismissal of a Target, returning `true` when dismissed, or `false` if not dismissed
    }

	override fun onProviderRemoved(smartspacerId: String) {
        //Handle removal of the Target (optional)
    }
    
}

Declaring in the Manifest

Since a Target is based on ContentProvider, it must be specified as one, with a specific action and permission:

<provider
	android:name=".ExampleTarget"
	android:authorities="${applicationId}.target.example"
	android:permission="com.kieronquinn.app.smartspacer.permission.ACCESS_SMARTSPACER_TARGETS"
	android:exported="true">
	<intent-filter>
		<action android:name="com.kieronquinn.app.smartspacer.TARGET" />
	</intent-filter>
</provider>

Your Target must be exported, and must have the specific action and permission shown above. Without this, they will not work in Smartspacer.

Configuration

The getConfig method needs to return some basic information for Smartspacer about your Target. The available options are:

Config(
	label = // Your Target's label to be shown in Smartspacer's settings UI
	description = // A short description for your Target to be shown in the same UI
	icon = // An Icon (android.graphics.drawable.Icon) to show in the same UI
	allowAddingMoreThanOnce = // Optional: Whether the Target should be able to be added multiple times at once (defaults to false)
	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)
	refreshPeriodMinutes = // Optional: How often the refresh broadcast for this Target should be called, in minutes (defaults to 0, never)
	refreshIfNotVisible = // Optional: Whether to call the refresh broadcast if the Target did not last return any Targets (defaults to false)
	compatibilityState = // Optional: A CompatibilityState object representing whether this Target is compatible with the device or not (defaults to always compatible)
	widgetProvider = // Optional: The authority of a Widget Provider attached to this Target (see Widget Providers page)
	notificationProvider = // Optional: The authority of a Notification Provider attached to this Target (see Notification Providers page)
	broadcastProvider = // Optional: The authority of a Broadcast Provider attached to this Target (see Broadcast Providers page)
)

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 Target 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 Target 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 Target 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 Target. Otherwise, the Target 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 Target, 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 Target 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.

Returning a Basic Target

The getSmartspaceTargets method expects a list of SmartspaceTargets in return, this can be empty up to containing as many Targets as you wish. 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 Target, 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 Target not updating.

Smartspacer's SDK comes with a number of templates you can choose from to show data in a Target. In this example, we'll use the Basic one, which contains a title, subtitle and icon. More options are explained later in this guide.

TargetTemplate.Basic(
	id ="example_$smartspacerId",
	componentName = ComponentName(provideContext(), ExampleTarget::class.java),
	title = Text("Hello World!"),
	subtitle = Text("Example"),
	icon = Icon(android.graphics.drawable.Icon.createWithResource(provideContext(), R.drawable.ic_example)),
	onClick = TapAction(
		intent = Intent(provideContext(), MainActivity::class.java)
	)
).create().apply { 
    //Apply additional options here (optional)
}

This example Basic Target Template has all the required fields filled as follows:

  • id: The unique ID for this SmartspaceTarget, you don't need to consider other plugins in this ID, but it should be unique across your app. Consider using the provided Smartspacer ID to aid with this. The ID is also used throughout Smartspacer for efficiency and animations, so the same SmartspaceTarget (for example a specific calendar event) should keep the same ID.
  • componentName: The Component Name for this SmartspaceTarget. This isn't actually important, it can be anything, but it's easiest to use the component of this Target. Note here how provideContext() is used - this is the same as requireContext(), but backwards compatible down to API 29.
  • title: The Text object representing this SmartspaceTarget's title. While just content is required, you can also specify justification here. The content is also a CharSequence and thus supports basic Parcelable formatting - colour and style - though both this and justification are not supported by OEM Smartspace.
  • subtitle: The Text object representing this SmartspaceTarget's subtitle. The same options are available as the title.
  • icon: The Icon object representing this SmartspaceTarget's icon. This is a model provided by the SDK, containing an android.graphics.drawable.Icon object, as well as options for whether to automatically tint the icon and an accessibility content description. Due to the duplication of class names, it's recommended to use import aliases to make this easier to understand.
  • onClick: The TapAction object representing this SmartspaceTarget's action to be invoked on click. It contains:
    • intent: An Intent to be invoked on tap (must be an Activity)
    • pendingIntent: A PendingIntent to be be invoked on tap (can be any, takes priority over Intent)
    • shouldShowOnLockScreen: If set, Smartspacer will not try to unlock the device when the action is run. If you start an Activity that can display over the lock screen, or send a PendingIntent which starts a service or sends a broadcast, this can mean no interruption to the user.

In addition to these options, the Basic Template also has options for:

  • featureType: The type of Target this is. SmartspaceTarget contains a small set of options, but most of the time you should leave this as the default (UNDEFINED for basic). Some Targets require a certain feature type, and the SDK will fill that for you, and some will prevent some types from being used by throwing a RuntimeException, in the event that it would cause an invalid Target.
  • subComplication: The Basic Template supports providing a fully formed Complication which will always be attached to it, regardless of other Complications the user has selected. You can specify it here.

Additional Options

After creating a SmartspaceTarget, some fields can be set to modify Smartspacer behaviour. You can set these on a SmartspaceTarget object:

  • sourceNotificationKey: When set to a notification's key, if the Target is the first displayed on Native Smartspace on the lockscreen, the corresponding notification will be hidden. This only happens under these specific circumstances.
  • isSensitive: If set, the Target will be treated as "sensitive" and will be either hidden or its content redacted on the lock screen, depending on the user's setting in Smartspacer.
  • aboutIntent: When specified, this shows an "About this Content" option in the long press popup in Native Smartspace, Smartspace in launchers which have integrated it, and Expanded Smartspace. When selected, the provided activity Intent will be launched.
  • feedbackIntent: When specified, this shows a "Feedback" option in the long press popup in Native Smartspace, Smartspace in launchers which have integrated it, and Expanded Smartspace. When selected, the provided activity Intent will be launched.
  • hideTitleOnAod: If specified, the Target's title will be hidden when displayed on the Always on Display
  • hideSubtitleOnAod: If specified, the Target's subtitle will be hidden when displayed on the Always on Display
  • expandedState: Additional data to show in Expanded Smartspace (see below)
  • canBeDismissed: Whether the Target can be dismissed. This simply prevents the dismiss option from appearing where possible, you should still return false to the onDismiss method call if your Target cannot be dismissed.
  • canTakeTwoComplications: If set, Smartspacer will ignore the subtitle and icon for this Target and replace it with another Complication.
  • hideIfNoComplications: If set, the Target will not be displayed if there are no Complications to place alongside it.
  • limitToSurfaces: An optional set of UI Surfaces (HOMESCREEN and LOCKSCREEN) on which the Target should be shown. If not set, it will be shown on all.

Target Dismissal

It's up to you how you want to handle dismissing of Targets (if you even wish to at all!). The onDismiss method will be called with the same Smartspace ID as before, as well as the ID of the SmartspaceTarget of which the dismiss option has been selected. You should make a change so the SmartspaceTarget would no longer be returned from getSmartspaceTargets, and then call notifyChange(smartspacerId). Once finished, return true from the method so Smartspacer knows the Target was dismissed successfully.

If you do not wish to allow Target dismissal, as well as specifying canBeDismissed = false on the created SmartspaceTarget(s) in the additional options, you should simply return false to the onDismiss call. This means that in the event the user attempts to dismiss the Target, they will automatically be presented with a Toast message stating it is not supported.

Target Removal

When the user removes a Target 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 Target.

Please note that this method will not be called if Smartspacer is uninstalled.

Target Configuration

In the settings UI for your Target within Smartspacer, the user can be presented with a link to your app's settings. Some customisation is available, depending on how you declare the Activity your Intent is linking to in your manifest:

<activity
	android:name=".ConfigurationActivity"
	android:description="A short description to be shown to the user of what they can configure"
	android:exported="true"
	android:icon="@drawable/ic_target_settings"
	android:label="Example Settings" />

Requesting an update to your Target

If you wish to notify Smartspacer of a change to your Target, and thus a call to getSmartspaceTargets should be made, you can call one of the two static notifyChange methods in SmartspacerTargetProvider from anywhere you have a context. These are:

  • SmartspacerTargetProvider.notifyChange(Context, Authority, Smartspacer ID (optional)): Updates a Target 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 Target to be added)

  • SmartspacerTargetProvider.notifyChange(Context, Class<out SmartspacerTargetProvider>, Smartspacer ID (optional)): Updates a Target with a given Target class. If provided, only that with a given Smartspacer ID will be updated (only useful if you are allowing multiple of the same Target to be added)

Receiving Target Refresh Broadcasts

If you specified a refresh period in your config, detailed earlier, your app will receive periodic broadcasts. To receive them, set up a receiver extending from SmartspacerTargetUpdateReceiver:

class ExampleTargetUpdateReceiver: SmartspacerTargetUpdateReceiver() {

    override fun onRequestSmartspaceTargetUpdate(
        context: Context,
        requestTargets: List<RequestTarget>
    ) {
        //Handle updates to the requested targets
    }
}

You must also declare this in your manifest with the required action and permission, since it is a BroadcastReceiver:

<receiver
	android:name=".ExampleTargetUpdateReceiver"
	android:exported="true"
	android:permission="com.kieronquinn.app.smartspacer.permission.SEND_UPDATE_BROADCAST">
	<intent-filter>
		<action android:name="com.kieronquinn.app.smartspacer.REQUEST_TARGET_UPDATE" />
	</intent-filter>
</receiver>

Note: The RequestTarget object contains the authority and Smartspacer ID for each Target an update has been requested for. Updates are batched, so if you have multiple Targets requesting an update at the same minute, the broadcast will only be received once, with multiple requestTargets

Smartspace Visibility

If you wish to receive a broadcast when Smartspace becomes visible, or stops being visible, you can add a receiver for this too. This could be used to pause background updates, or request an update to your data automatically when Smartspace becomes visible. Create a receiver extending from SmartspacerVisibilityChangedReceiver:

class SmartspaceVisibilityReceiver: SmartspacerVisibilityChangedReceiver() {

    override fun onSmartspaceVisibilityChanged(context: Context, visible: Boolean, timestamp: Long) {
	//Run an update?
    }

}

You must also declare this in your manifest with the required action and permission, since it is a BroadcastReceiver:

<receiver android:name=".SmartspaceVisibilityReceiver"
	android:exported="true"
	android:permission="com.kieronquinn.app.smartspacer.permission.SEND_UPDATE_BROADCAST">
	<intent-filter>
		<action android:name="com.kieronquinn.app.smartspacer.SMARTSPACE_VISIBILITY_CHANGED" />
	</intent-filter>
</receiver>

Important note: This option requires the user have Smartspacer v1.3 or above installed. You can use "minimum_smartspacer_version": 130 in your update.json file to enforce this.

Target Backups

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 Target 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 Target, 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 Target's description so they know what is being restored.

Target Restoration

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. Targets 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 update the Target 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 Target. If you cannot restore the Target for whatever reason, return false and the setup activity will be shown.

Note: If your Target 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 Target finishes being added.

Target Templates

There are currently 9 available Target Templates

Basic

Support: All Native Smartspace implementation, Smartspacer Widget, Smartspacer integrated launchers, Expanded Smartspace, OEM Smartspace

Basic Target Template

See above

Head to Head

Support: All Native Smartspace implementations, Smartspacer Widget, Smartspacer integrated launchers, Expanded Smartspace. OEM Smartspace is not supported (will just display as a Basic Target)

Head to Head Template

This Target Template shows two icons, two scores and a header to the left of the title & subtitle. It's intended for sports scores.

It has the following options, in addition to the Basic ones:

  • headToHeadTitle: The Text to show above the teams/scores
  • headToHeadFirstCompetitorIcon: The Icon of the first team
  • headToHeadFirstCompetitorText: A short piece of Text (usually a score) to display to the right of the first team's icon
  • headToHeadSecondCompetitorIcon: The Icon of the second team
  • headToHeadSecondCompetitorText: A short piece of Text (usually a score) to display to the left of the second team's icon

Tip: Use RelativeSizeSpan to shrink text in order to fit in the limited space provided.

Button

Support: All Native Smartspace implementations, Smartspacer Widget, Smartspacer integrated launchers, Expanded Smartspace. OEM Smartspace is not supported (will just display as a Basic Target)

Button Template

This Target Template shows an icon and text to the left of the title & subtitle. It's intended for anything button related, such as deep links to apps

It has the following options, in addition to the Basic ones:

  • buttonIcon: The Icon to show at the top of the button to the left of the title & subtitle
  • buttonText: The Text to show at the bottom of the button to the left of the title & subtitle

List Items

Support: All Native Smartspace implementations, Smartspacer Widget, Smartspacer integrated launchers, Expanded Smartspace. OEM Smartspace is not supported (will just display as a Basic Target)

List Items Template

This Target Template shows a list of up to 3 items, as well as a small icon to the left of the title & subtitle. It's intended for things like shopping lists, but can also be used for short lists of basic data such as ticketing info (eg. seat, flight number)

It has the following options, in addition to the Basic ones:

  • listItems: A list of Text objects, the first three of which will be shown in the list
  • listIcon: The icon to display to the top right of the list. If you do not wish to display an icon, send an empty 1x1 Bitmap Icon.
  • emptyListMessage: A short message to display when the list is empty. This is only used on Android 12, so you should also send it as list item #1 if the list is "empty".

Loyalty Card

Support: All Native Smartspace implementations, Smartspacer Widget, Smartspacer integrated launchers, Expanded Smartspace. OEM Smartspace is not supported (will just display as a Basic Target)

Basically the same as the Button template, but with some additional icon options

Loyalty Card Template

It has the following options, in addition to the Basic ones:

  • cardIcon: The image to display to the left of the title & subtitle
  • cardPrompt: The text to display below the image
  • imageScaleType: The ImageView.ScaleType applied to the image (optional)
  • imageWidth: The width of the image to use (optional)
  • imageHeight: The height of the image to use (optional)

Tip: You can combine the image options to apply an aspect ratio to your image, it does not need to be square.

Image

Support: All Native Smartspace implementations, Smartspacer Widget, Smartspacer integrated launchers, Expanded Smartspace. OEM Smartspace is not supported (will just display as a Basic Target)

Shows a rectangular image to the left of the title & subtitle, with rounded corners. Internally called "Commute Time", but can display any image.

Image Template

It has the following options, in addition to the Basic ones:

  • image: The image to display

Doorbell

Support: Some Native Smartspace implementations (does not display states on Pixel Launcher), Smartspacer Widget (low FPS), Smartspacer integrated launchers, Expanded Smartspace. OEM Smartspace is not supported (will just display as a Basic Target).

The Doorbell Target Template is a complex template with many display options including image sequences and loading states. It was created for use by the Nest app to display a "live" (actually time delayed) feed of a doorbell camera.

The Doorbell template only has one extra option, doorbellState, but it's a sealed class with a number of options.

Loading Indeterminate

Shows a circular indeterminate loading state

Loading Indeterminate State

Options:

  • width: The width of the loading bar (optional)
  • height: The height of the loading bar (optional)
  • ratioWidth: The horizontal aspect ratio component of the loading bar (optional)
  • ratioHeight: The vertical aspect ratio component of the loading bar (optional)

Loading

Shows a small icon, with an optional indeterminate circular progress bar overlayed on top

Loading State (Loading spinner is not enabled in this image)

Options:

  • icon: A Bitmap image to show as the icon
  • showProgressBar: Whether to show an overlayed progress bar
  • width: The width of the loading bar and icon (optional)
  • height: The height of the loading bar and icon (optional)
  • ratioWidth: The horizontal aspect ratio component of the loading bar and icon (optional)
  • ratioHeight: The vertical aspect ratio component of the loading bar and icon (optional)

Videocam

Shows a video camera icon

Videocam State

Options:

  • width: The width of the icon (optional)
  • height: The height of the icon (optional)
  • ratioWidth: The horizontal aspect ratio component of the icon (optional)
  • ratioHeight: The vertical aspect ratio component of the icon (optional)

Videocam Off

Shows a video camera icon with a strikethrough

Videocam Off State

Options:

  • width: The width of the icon (optional)
  • height: The height of the icon (optional)
  • ratioWidth: The horizontal aspect ratio component of the icon (optional)
  • ratioHeight: The vertical aspect ratio component of the icon (optional)

Image Bitmap

Shows a singular bitmap image filling the available area

Image Bitmap State

Options:

  • bitmap: A Bitmap to show
  • imageScaleType: The ImageView.ScaleType applied to the image (optional)
  • imageWidth: The width of the image to use (optional)
  • imageHeight: The height of the image to use (optional)

Tip: You can combine the image options to apply an aspect ratio to your image, it does not need to be square.

Image URI

Shows a sequence of images loaded from specified URIs

Image URI

Options:

  • frameDurationMs: The duration each image should be displayed for, in milliseconds. Please note that the Smartspacer Widget is capped at a frame duration of 500ms, and will skip frames to keep up if required.
  • imageUris: A list of URIs to load images from. These images are loaded sequentially before the Target is displayed, so please be mindful with your frame rate to limit CPU usage.

Important: The Image URIs here MUST be usable with ContentResolver.openInputStream(), and MUST be run through Context.createSmartspacerProxyUri() (provided by the SDK). Other URIs will not be loaded. Please note that these URIs are NOT web URIs, and should NOT block the thread when loading. For an example of loading images, see the SDK Sample's Doorbell Target.

Images

Support: Native Smartspace implementations on Android 13+, Smartspacer Widget (low FPS), Smartspacer integrated launchers, Expanded Smartspace. OEM Smartspace is not supported (will just display as a Basic Target)

Similar to the Doorbell Target's Image URI and Image Bitmap states, shows a sequence of images

Images Template

It has the following options, in addition to the Basic ones:

  • images: A list of Images to show in a sequence. These don't have to be loaded from Uri, they can be any Icon objects.
  • frameDurationMs: The duration each image should be displayed for, in milliseconds. Please note that the Smartspacer Widget is capped at a frame duration of 500ms, and will skip frames to keep up if required.
  • imageDimensionRatio: The dimension ratio applied to the image, matching the spec of ConstraintLayout's ratio attribute
  • imageClickIntent: An Activity Intent to be run when the images are clicked (defaults to the same as the Target's tap action)
  • imageClickPendingIntent: A PendingIntent to be sent when the images are clicked (defaults to the same as the Target's tap action, takes priority over intent)

This Target also supports a Sub Complication, same as the Basic Target Template.

Important: If you use image URIs, they MUST be usable with ContentResolver.openInputStream(), and MUST be run through Context.createSmartspacerProxyUri() (provided by the SDK). Other URIs will not be loaded. Please note that these URIs are NOT web URIs, and should NOT block the thread when loading. For an example of loading images, see the SDK Sample's Images Target.

Carousel

Support: Native Smartspace implementations on Android 13+, Smartspacer Widget, Smartspacer integrated launchers, Expanded Smartspace. OEM Smartspace is not supported (will just display as a Basic Target)

Shows up to four columns of icon, text, icon to the left of the title and subtitle. Intended for a weather forecast.

Carousel Template

It has the following options, in addition to the Basic ones:

  • items: A list of CarouselTemplateData.CarouselItem items, containing:
    • upperText: Short Text to show above the icon
    • lowerText: Short text to show below the icon
    • image: The Icon to show in the carousel item
    • tapAction: The action to run when the item is clicked (defaults to that of the Carousel, and then the Target if not specified)
  • onCarouselClick: The action to run when the carousel is clicked (defaults to that of the Target if not specified)

This Target also supports a Sub Complication, same as the Basic Target Template.

RemoteViews

Experimental: This Target type is experimental. It may change or stop working without warning, and support is limited in Native Smartspace (Android 15 QPR2+ or Android 16+)

Support: Native Smartspace (Android 15 QPR2+ or Android 16+), Smartspacer Widget, Smartspacer integrated launchers, Expanded Smartspace. OEM Smartspace is not supported (Any unsupported space will display the fallback)

This Target type allows you specify RemoteViews to be displayed instead of one of the other templates. It has the same restrictions as RemoteViews in widgets - no custom Views and a limited subset of available Views, with the added restriction of not supporting collections (ListView, GridView and StackView).

RemoteViews Template

Unlike other templates, you must specify a fallback template, which will be displayed in the event that widgets are not supported on the current space. This can be any other template, and you should use it to show the same content in a template, if possible. If this is not possible, include a warning to users in your plugin & its description that a space requiring widgets is required.

Expanded State

When creating a Target, you can also specify an Expanded State. This is shown in Expanded Smartspace, and can contain an number of extra features such as widgets, shortcuts and arbitrary RemoteViews.

Set an Expanded State object in the additional options, after creating a Target:

TargetTemplate.Basic(
	...
	).create().apply { 
        expandedState = ExpandedState(
			...
		)
    }
)

Expanded States can contain four types of options:

Shortcuts

You can specify up to 10 shortcuts, to be displayed below the Target.

Shortcut options:

  • label: A short label for the shortcut (optional)
  • icon: An icon for the shortcut (optional, but either label or icon must be specified)
  • intent: An Activity intent to launch when tapped (optional)
  • pendingIntent: A PendingIntent to send when tapped (optional, takes priority over intent)
  • showWhenLocked: Whether to show these shortcuts while the device is in a locked state (defaults to true)

App Shortcuts

Requires Smartspacer's Enhanced Mode (will not be displayed otherwise). Allows you to specify packages to show App Shortcuts from, with a maximum amount for each package. Up to 10 total shortcuts will be shown, breadth first.

Options:

  • packageNames: A set of package names to show shortcuts from. Packages which are not installed will not be considered.
  • appShortcutCount: The maximum number of shortcuts from each app to be shown
  • showWhenLocked: Whether to show these app shortcuts while the device is in a locked state (defaults to true)

Widget

Allows you to specify an app's widget to be displayed below a Target when it is visible

Options:

  • info: The AppWidgetProviderInfo of the App Widget, you should retrieve this from AppWidgetManager.
  • id: Optional: A static ID for the instance of this widget. If the widget requires customisation, for example a note from Google Keep, keeping this ID the same will bind the same configuration of the widget each time (and thus the same note)
  • showWhenLocked: Whether to show the widget while the device is in a locked state (defaults to true)
  • height: The maximum height of the widget, in pixels. The SDK contains a getRowSpan method to calculate this from widget "rows"
  • width: The maximum width of the widget, in pixels. The SDK contains a getColumnSpan method to calculate this from widget "columns". To fill the available width, specify the device's screen width here.

Tip: If the widget you are showing declares a "configuration" activity, you may be able to set it to null on the info object, and skip the widget's configuration, providing a better UX to the user. Make sure this works first though!

RemoteViews

Allows you to specify arbitrary RemoteViews to be displayed below the Target. These can be any RemoteViews, the same as Widgets, except ones requiring an adapter. Please see the RemoteViews page linked for restrictions of the system itself.

Options:

  • view: The default RemoteViews to display below the Target
  • unlocked: The RemoteViews to display while in an unlocked state only, takes priority over the default
  • locked: The RemoteViews to display while in a locked state only, takes priority over the default