App Shortcuts & Widgets (Java)

Not every entry point into RecipeBox has to go through the launcher icon and main screen. App Shortcuts surface quick actions when a user long-presses the launcher icon, and App Widgets place a small live view of the app right on the home screen. Both give an app a presence outside its own UI.

App Shortcuts: Static vs Dynamic

Long-pressing RecipeBox's launcher icon can pop up a small menu of shortcuts. There are two kinds: static shortcuts, declared once in XML and unchanging until the next app update, and dynamic shortcuts, set and updated at runtime based on user behavior.

Static Shortcuts

A static shortcut is defined in res/xml/shortcuts.xml and referenced from the manifest. This is the natural fit for an action that never changes — like jumping straight to RecipeBox's "add a new recipe" screen:

<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
    <shortcut
        android:shortcutId="add_new_recipe"
        android:enabled="true"
        android:icon="@drawable/ic_shortcut_add"
        android:shortcutShortLabel="@string/shortcut_add_short"
        android:shortcutLongLabel="@string/shortcut_add_long">
        <intent
            android:action="android.intent.action.VIEW"
            android:targetPackage="com.recipebox"
            android:targetClass="com.recipebox.AddRecipeActivity" />
    </shortcut>
</shortcuts>
<activity android:name=".MainActivity">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
    <meta-data
        android:name="android.app.shortcuts"
        android:resource="@xml/shortcuts" />
</activity>

Dynamic Shortcuts

A dynamic shortcut is pushed at runtime through ShortcutManager — perfect for something that changes per user, like offering fast access to the recipe they viewed most recently:

// Called right after the user opens a recipe's detail screen
public void pinRecentRecipeShortcut(Context context, Recipe recipe) {
    ShortcutManager shortcutManager = context.getSystemService(ShortcutManager.class);

    Intent intent = new Intent(context, RecipeDetailActivity.class);
    intent.setAction(Intent.ACTION_VIEW);
    intent.putExtra("recipe_id", recipe.getId());

    ShortcutInfo shortcut = new ShortcutInfo.Builder(context, "recent_recipe")
            .setShortLabel(recipe.getTitle())
            .setIcon(Icon.createWithResource(context, R.drawable.ic_shortcut_recipe))
            .setIntent(intent)
            .build();

    shortcutManager.setDynamicShortcuts(Collections.singletonList(shortcut));
}
Explanation:
  • setDynamicShortcuts() replaces the current dynamic set — call it again whenever the "most recent" recipe changes.
  • Android also allows a user to explicitly pin a dynamic shortcut to their home screen, which then persists independently of your app updating the dynamic list.
  • A device typically limits how many dynamic shortcuts an app may have active at once — keep the list short and relevant.

App Widgets: Glanceable Home Screen UI

A widget is a small, self-updating piece of UI living on the home screen — for RecipeBox, imagine a "Today's Recipe Suggestion" box showing a photo and title without opening the app at all. Widgets are built by extending AppWidgetProvider and overriding onUpdate():

// RecipeSuggestionWidget.java
public class RecipeSuggestionWidget extends AppWidgetProvider {

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        for (int widgetId : appWidgetIds) {
            Recipe suggestion = RecipeRepository.getTodaysSuggestion(context);

            RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_recipe_suggestion);
            views.setTextViewText(R.id.widgetRecipeTitle, suggestion.getTitle());
            views.setImageViewUri(R.id.widgetRecipeImage, Uri.parse(suggestion.getPhotoUri()));

            appWidgetManager.updateAppWidget(widgetId, views);
        }
    }
}

The widget's own layout is a separate, simple XML file:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="12dp">

    <ImageView
        android:id="@+id/widgetRecipeImage"
        android:layout_width="match_parent"
        android:layout_height="80dp" />

    <TextView
        android:id="@+id/widgetRecipeTitle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textStyle="bold" />
</LinearLayout>
RemoteViews is not a normal layout inflater. A widget runs inside the launcher's process, not RecipeBox's own — so RemoteViews can only update a limited, specific subset of Views (things like TextView, ImageView, Button, ProgressBar, and a few container layouts). You cannot drop an arbitrary custom View into a widget's layout the way you can inside your app's own Activities.

Declaring the Widget Provider

The widget needs a small info XML describing its size and update behavior, plus a manifest entry registering the provider:

<!-- res/xml/recipe_suggestion_widget_info.xml -->
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="180dp"
    android:minHeight="110dp"
    android:updatePeriodMillis="1800000"
    android:initialLayout="@layout/widget_recipe_suggestion"
    android:resizeMode="horizontal|vertical" />
<receiver android:name=".RecipeSuggestionWidget"
    android:exported="false">
    <intent-filter>
        <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
    </intent-filter>
    <meta-data
        android:name="android.appwidget.provider"
        android:resource="@xml/recipe_suggestion_widget_info" />
</receiver>
android:updatePeriodMillis requests periodic updates (a minimum of about 30 minutes is enforced by the system) — for anything more time-sensitive, trigger updates manually from your app code instead of relying on this alone.

Both Increase Visibility

Shortcuts and widgets share one goal: making RecipeBox visible and reachable without a user having to open the app first. A well-placed shortcut or widget genuinely increases engagement, because it turns a multi-tap journey into a single glance or tap.

Shortcuts and widgets launch into the app from outside — the next lesson, Deep Links & App Links, covers doing the same from any URI or web URL, opening straight to a specific recipe.