Skip to content
Varun Chitre edited this page Aug 26, 2015 · 4 revisions

Custom Tiles

A custom tile is a UI widget you can display to the user outside of your application's normal UI. When you tell the system to issue a custom tile, it will appear as an icon within the status bar panel. The status bar panel is system-controlled areas that the user can view at any time.

Figure 1. A custom tile within the status bar panel

Creating a tile

You specify the UI information and actions for a custom tile in a CustomTile.Builder object. To create the custom tile itself, you call CustomTile.Builder.build(), which returns a CustomTile object containing your specifications. To issue the custom tile, you pass the CustomTile object to the system by calling [CMStatusBarManager.publishTile()](https://cyanogenmod.github.io/cm_platform_sdk/reference/cyanogenmod/app/CMStatusBarManager.html#publishTile(java.lang.String, int, cyanogenmod.app.CustomTile)).

Required Custom Tile contents

A CustomTile object must contain the following:

To use these Custom Tile API, your application must first declare the publish custom tile permission in AndroidManifest.xml:

<uses-permission android:name="cyanogenmod.permission.PUBLISH_CUSTOM_TILE" />

Creating a simple toggle tile

The following snippet illustrates a simple custom tile that specifies an intent to be broadcasted when the user clicks the tile.

From our main activity we can generate a custom tile and publish it.

// Define an intent that has an action of toggling a state
Intent intent = new Intent();
intent.setAction(ACTION_TOGGLE_STATE);
// initialize this state to off
intent.putExtra(MainActivity.STATE, States.STATE_OFF);

// Retrieve a pending intent from the system to be fired when the
// clicks the custom tile
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0,
        intent , PendingIntent.FLAG_UPDATE_CURRENT);

// Instantiate a builder object
CustomTile customTile = new CustomTile.Builder(this)
    .setOnClickIntent(pendingIntent)                      // set the pending intent
    .setContentDescription("Generic content description")
    .setLabel("CustomTile " + States.STATE_OFF)           // display current state
    .shouldCollapsePanel(false)
    .setIcon(R.drawable.ic_launcher)
    .build();                                             // build

//Publish our tile to the status bar panel with CUSTOM_TILE_ID defined elsewhere
CMStatusBarManager.getInstance(this)
        .publishTile(CUSTOM_TILE_ID, customTile);

Then we define our receiver for the broadcast to receive the action and toggle the state of the tile, publishing updates as needed.

public class TileReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {

        if (MainActivity.ACTION_TOGGLE_STATE.equals(intent.getAction())) {
            Intent newIntent = new Intent();
            newIntent.setAction(MainActivity.ACTION_TOGGLE_STATE);
            String label = "CustomTile " + States.STATE_OFF;

            int state = getCurrentState(intent);
            switch (state) {
                case States.STATE_OFF:
                    newIntent.putExtra(MainActivity.STATE, States.STATE_ON);
                    label = "CustomTile " + States.STATE_ON;
                    break;
                case States.STATE_ON:
                    newIntent.putExtra(MainActivity.STATE, States.STATE_OFF);
                    label = "CustomTile " + States.STATE_OFF;
                    break;
            }

            PendingIntent pendingIntent =
                    PendingIntent.getBroadcast(context, 0,
                            newIntent , PendingIntent.FLAG_UPDATE_CURRENT);

            CustomTile customTile = new CustomTile.Builder(context)
                    .setOnClickIntent(pendingIntent)
                    .setContentDescription("Generic content description")
                    .shouldCollapsePanel(false)
                    .setLabel(label)
                    .setIcon(R.drawable.ic_launcher)
                    .build();

            CMStatusBarManager.getInstance(context)
                    .publishTile(MainActivity.CUSTOM_TILE_ID, customTile);
        }
    }

    private int getCurrentState(Intent intent) {
        return intent.getIntExtra(MainActivity.STATE, 0);
    }
}

The effect you get then is a tile that toggles between states!

Publishing a remoteview as an expanded style (Requires > API level 2.0)

The below snippet utilizes the new RemoteExpandedStyle to publish a tile containing a RemoteViews which receives a layout defined by the developer.

// Create a remoteviews object
RemoteViews contentView = new RemoteViews(getPackageName(),
        R.layout.remote_view);

// Create intent for the onclick button
Intent cyngnIntent = new Intent(Intent.ACTION_VIEW)
    .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
    .setData(Uri.parse("http://www.cyngn.com"));

// Get a pending intent for the defined intent
PendingIntent intent = PendingIntent.getActivity(this, 0,
        cyngnIntent, 0);

// Set the pending intent on the button in our layout
contentView.setOnClickPendingIntent(R.id.whats_hot_click, intent);

// Create the new RemoteExpandedStyle
CustomTile.RemoteExpandedStyle remoteExpandedStyle =
        new CustomTile.RemoteExpandedStyle();
remoteExpandedStyle.setRemoteViews(contentView);

// Build the custom tile
CustomTile customTile = new CustomTile.Builder(CMStatusBarTest.this)
    .setLabel("Remote Style From SDK")
    .setIcon(R.drawable.ic_launcher)
    .setExpandedStyle(remoteExpandedStyle)
    .setOnSettingsClickIntent(new Intent(thiis, DummyClass.class)
            .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
    .setContentDescription("Description of content for expanded style")
    .build();

// Publish the custom tile
CMStatusBarManager.getInstance(this)
        .publishTile(CUSTOM_TILE_ID, customTile);

You end up with a remoteviews with a custom button that launches an external site!

For further details about the capabilities for the CustomTile API, see the javadoc for it.