Hello Tracker

This chapter describes how to create a simple tracker provider with the SDK. Create a new Android application project and follow the basic steps below.

  • Importing Libraries

  • Connection to Samsung Health

  • Initialization

  • Feature Availability

  • Posting Your App's Tracker

Detailed descriptions are below.

Importing Libraries

Not only the SDK's Health Service, but also Health Data are required to use the tracker feature. Add the following libraries to the "libs" folder in your created application project.

  • samsung-health-data-a.b.c.jar

  • samsung-health-service-va.b.c.jar

  • sdk-v1.0.0.jar

Connection to Samsung Health

Samsung Health SDK works with Samsung Health 4.0 or above. Samsung Health installation and the installed Samsung Health‘s version need to be checked before calling the Health Service's APIs.

See the related FAQ or Health Data's Programing Guide's 4.2 for more information.

Initialization

Initializing the Health Service with the following API is needed to use its other APIs.

  • initialize(Context)of the com.samsung.android.sdk.shealth.Shealth class.

import com.samsung.android.sdk.shealth.Shealth;

import android.app.Application;
import android.content.Context;
import android.util.Log;

public class PluginTracker extends Application {

    private static final String APP_TAG = "PluginTracker";

    @Override
    public void onCreate() {
        super.onCreate();
        Shealth shealth = new Shealth();
        try {
            shealth.initialize(mContext);
        } catch (Exception e1) {
            Log.d(APP_TAG, "Samsung Health Service Initialization failed." + e.toString());
        }
    }
}

Feature Availability

A certain Health Service's feature works on the specific Samsung Health's version or above because the tracker feature is deeply integrated to Samsung Health. E.g., FEATURE_TRACKER_LAUNCH works on Samsung Health 4.8 or above.

Check the feature availability of your desired feature in Health Service. If any feature is not available, upgrade Samsung Health to the latest version.

// Check the feature availability for all wanted features.
    if (mShealth.isFeatureEnabled(Shealth.FEATURE_TRACKER, Shealth.FEATURE_TRACKER_LAUNCH)) {

        // All wanted features are available.
        // You can use all APIs of the "com.samsung.android.sdk.shealth" package.

    } else {
        // If any feature is not available, Samsung Health should be upgraded.
        Log.d(APP_TAG, "Samsung Health should be upgraded");

        // Let the user upgrade Samsung Health to the latest version.
        Intent intent;
        intent = new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=com.sec.android.app.shealth"));
        this.startActivity(intent);
    }
Posting Your App's Tracker

If you cannot find a wanted tracker on Samsung Health, you can define your app's own tracker.

Manifest for Tracker Definition

A new tracker can be defined in the manifest file as shown below. An ID, displayed name, icon and controller are required for the tracker definition. For more information, refer to Tracker Definition.

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="testtracker_manifest">
{
    \"tracker\" : {
        \"id\" : \"tracker.test\",
        \"display-name\" : \"tracker_display_name\",
        \"icon\" : \"tracker_icon\",
        \"controller\" : \"com.samsung.android.app.plugintracker.MyTracker\"
    }
}
    </string>
</resources>
Registration of Plugin Service

The tracker of your application is installed as plugin for Samsung Health by registering it for the plugin service with your defined tracker ID and its resource name in AndroidManifest.xml of your application project.

<service
    android:name="com.samsung.android.sdk.shealth.PluginService"
    android:exported="true" >
    <meta-data
        android:name="tracker.test" android:value="@string/testtracker_manifest"/>
</service>
  • android:name - the tracker ID of the tracker manifest file.

  • android:value - the resource name of the tracker manifest file.

Handling Event from Samsung Health

Samsung Health sends its events to your application through TrackerEventListener and your app can handle them by implementing TrackerEventListener.

TrackerEventListener can be implemented basically as shown below.

public class MyTracker implements TrackerEventListener {

    private TrackerTileManager mTrackerTileManager;

    public MyTracker() {
        // A default constructor has to be created.
    }

    @Override
    public void onCreate(Context context, String trackerId) {
        Log.d(APP_TAG, "onCreate(" + trackerId + ")");

        if (mTrackerTileManager == null) {
            try {
                mTrackerTileManager = new TrackerTileManager(context);
            } catch (IllegalArgumentException e) {
                Log.d(APP_TAG, "MyTracker onCreate() - IllegalArgumentException");
            }
        }
    }

    @Override
    public void onSubscribed(Context context, String trackerId) {
        Log.d(APP_TAG, "onSubscribed(" + trackerId + ")");
        // User changed the subscription state of your tracker to subscribe.

        // Post your tracker tile here to show it on the Samsung Health's main screen
        // right after user subscribed your tracker.

        // If you miss posting your tracker tile here and post it in onTileRequested(),
        // your tracker tile will not be shown on the main screen
        // until onTileRequested() is called.

        // TRACKER_TILE_TYPE_1 is used generally if there is no data yet.
    }

    @Override
    public void onUnsubscribed(Context context, String trackerId) {
        Log.d(APP_TAG, "onUnsubscribed(" + trackerId + ")");
        // User changed the subscription state of your tracker to unsubscribe.
    }

    @Override
    public void onPaused(Context context, String trackerId) {
        Log.d(APP_TAG, "onPaused(" + trackerId + ")");
        // Samsung Health went to the background.
        // Stop posting tracker tiles.
    }

    @Override
    public void onTileRequested(Context context, String trackerId, String tileId) {
        Log.d(APP_TAG, "onTileRequested(" + trackerId + ", " + tileId + ")");
        // Samsung Health has been resumed on the foreground.

        // If tileId is null, it means there is no posted tracker tile successfully on the main screen.
        // Set the tracker ID if it's null.

        // Post your tracker tile here.
        // TRACKER_TILE_TYPE_1 is used generally if there is no data yet.

        // Or you can update the posted tracker tile with updated data here.
    }

    @Override
    public void onTileRemoved(Context context, String trackerId, String tileId) {
        Log.d(APP_TAG, "onTileRemoved(" + trackerId + ", " + tileId + ")");
        // User removed your posted tracker tile from the main screen.
    }
}

When you implement TrackerEventListener, the implemented class's default constructor is mandatory. E.g. if implemented class name is 'MyTracker', create its default constructor as shown below. Or your application won't receive Samsung Health‘s events well.

public class MyTracker implements TrackerEventListener {

    public MyTracker() {
        // An empty constructor should be created.
    }
}
Creating a TrackerTileManager's Instance

TrackerTileManager enables your application to post or remove your tracker's tile.

public class MyTracker implements TrackerEventListener {

    private TrackerTileManager mTrackerTileManager;

    public MyTracker(Context context) {
        if (mTrackerTileManager == null) {
            try {
                mTrackerTileManager = new TrackerTileManager(context);
            } catch (IllegalArgumentException e) {
                Log.d(APP_TAG, "MyTracker Constructor - " + e.toString());
            }
        }
    }
}
Creating Tracker Tile's Intent

If you want to add service intent for a tile's button to be performed in background, the service intent can be defined as the following example.

final public class MyTrackerService extends IntentService {

    private static final String APP_TAG = "PluginTracker";

    private static final String SHARED_PREFERENCE_NAME = "tile_content";
    private static final String SHARED_PREFERENCE_CONTENT_VALUE_KEY = "content_value";
    private static final String VALIDATION_KEY = "validation_key";

    @Override
    protected void onHandleIntent(Intent intent) {

        if (intent == null) {
            return;
        }

        String trackerId = intent.getStringExtra(TrackerTileManager.EXTRA_TRACKER_ID);
        if (trackerId == null) {
            return;
        }

        String tileId = intent.getStringExtra(TrackerTileManager.EXTRA_TILE_ID);
        if (tileId == null) {
            return;
        }

        String validationValue = intent.getStringExtra(VALIDATION_KEY);
        SharedPreferences sp = getSharedPreferences(SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE);
        String validationSavedValue = sp.getString(VALIDATION_KEY, "");

        if (validationValue.isEmpty() || !validationValue.equals(validationSavedValue)) {
            Log.d(APP_TAG, "invalid validation value");
            return;
        }

        int tileContent = sp.getInt(SHARED_PREFERENCE_CONTENT_VALUE_KEY, 0) + 1;
        Log.d(APP_TAG, "content value : " + String.valueOf(tileContent));
        sp.edit().putInt(SHARED_PREFERENCE_CONTENT_VALUE_KEY, tileContent).apply();

        MyTracker tracker = new MyTracker(this);
        tracker.updateTile(this, trackerId, tileId);
    }
}
Posting a Tracker Tile

If the user subscribes to your tracker on the Samsung Health's tracker item list, Samsung Health sends an event to onSubscribed() of your application. Post your tracker tile in this event handler to show your tracker tile on the Samsung Health's main screen right after the user subscribes to your tracker. Keep in mind that a tracker tile will not be posted if the Samsung Health‘s main screen is in pause state.

public class MyTracker implements TrackerEventListener {

    private static final String MY_TILE_ID = "hello_tile";

    @Override
    public void onSubscribed(Context context, String trackerId) {
        // Your tracker is subscribed.
        Log.d(APP_TAG, "onSubscribed(" + trackerId + ")");

        postDefaultTile(context, trackerId, MY_TILE_ID);
    }
}

In case that there is no data for your tracker, use TRACKER_TILE_TYPE_1 with an icon, title and button. See 7.2 for more information. The following code shows how to post a TRACKER_TILE_TYPE_1 tracker tile.

public class MyTracker implements TrackerEventListener {

    private int mTemplate = TrackerTile.TRACKER_TILE_TYPE_1;

private void postDefaultTile(Context context, String trackerId, String tileId) {
        TrackerTile myTrackerTile;
        Intent launchIntent;

        // Your tracker tile is not posted successfully on the main screen of Samsung Health.
        // Set the tile ID. Or the tile will not be shown though you call TrackerTileManager.post().
        if (tileId == null) {
            tileId = MY_TILE_ID;
        }

        try {
            // Create Intent to do an action
            // when the tracker tile is clicked
            launchIntent = new Intent(context, MainActivity.class);

            // Create Intent to do an action
            // when the button on this tile is clicked
            Intent serviceIntent = new Intent(context, MyTrackerService.class);

            // Create TrackerTile with type 1 and set each values and intents
            myTrackerTile = new TrackerTile(context, trackerId, tileId, mTemplate);

            // Set Title
            myTrackerTile
                    .setTitle(R.string.tracker_test_display_name)
                    // Set Icon resource
                    .setIcon(R.drawable.tracker_icon)
                    // Set content color
                    .setContentColor(context.getResources().getColor(R.color.tracker_content_color))
                    // Set content intent
                    .setContentIntent(TrackerTile.INTENT_TYPE_ACTIVITY, launchIntent)
                    // Set button intent
                    .setButtonIntent("START", TrackerTile.INTENT_TYPE_SERVICE, serviceIntent);

            if (mTrackerTileManager != null) {
                mTrackerTileManager.post(myTrackerTile);
            }

        } catch (IllegalArgumentException e) {
            Log.d(APP_TAG, "MyTracker postDefaultTile(" + trackerId + ", " + tileId + ") " + e.toString());
        } catch (NotFoundException e) {
            Log.d(APP_TAG, "MyTracker postDefaultTile(" + trackerId + ", " + tileId + ") " + e.toString());
        }
    }
}

Make sure that Samsung Health is on the developer mode before installing your application. Samsung Health will suggest your new tracker on its main screen and you can add tracker easily by tapping the suggestion tile as Figure 4.

Figure 4: Posted tracker tile on Samsung Health Figure 4: Posted tracker tile on Samsung Health
Updating the Posted Tracker Tile

When the main screen is resumed on the foreground, implemented
TrackerEventListener.onTileRequested() of your application receives an event from Samsung Health. You can post a tracker tile or update the posted tile here.

public class MyTracker implements TrackerEventListener {

    @Override
    public void onTileRequested(Context context, String trackerId, String tileId) {
        // The main screen requested the tracker tile.
        Log.d(APP_TAG, "onTileRequested(" + trackerId + ", " + tileId + ")");

        // Update your tracker tile.
        updateTile(context, trackerId, tileId);
    }
}

If the application has health related data to show it on the tracker tile, use the TRACKER_TILE_TYPE_2 or TRACKER_TILE_TYPE_3 tracker tile type.

If there is no posted tracker tile on the main screen, the tile ID is received as null in the event handler above. To post a tracker tile on the main screen, the tile ID must be specified.

The following code shows how to update the posted tracker tile with TRACKER_TILE_TYPE_3.

public class MyTracker implements TrackerEventListener {

    public void updateTile(Context context, String trackerId, String tileId) {

        TrackerTile myTrackerTile = null;
        Intent launchIntent;

        // Set the measured value of the data
        int tileContentValue;
        // Set the measured time of the data
        int tileDate;

        // Your tracker tile is not posted successfully on the main screen of Samsung Health.
        // Set the tile ID. Or the tile will not be shown though you call TrackerTileManager.post().
        if (tileId == null) {
            tileId = MY_TILE_ID;
        }

        try {
            // Create Intent to do an action
            // when the tracker tile is clicked
            launchIntent = new Intent(context, MainActivity.class);

            // Create Intent to do an action
            // when the button on this tile is clicked
            Intent serviceIntent = new Intent(context, MyTrackerService.class);

            // Set template
            mTemplate = TrackerTile.TRACKER_TILE_TYPE_3;

            // Create TrackerTile and set each values and intents
            myTrackerTile = new TrackerTile(context, trackerId, tileId, mTemplate);

            // Set Title
            myTrackerTile
                    .setTitle(R.string.tracker_display_name)
                    // Set Icon resource
                    .setIcon(R.drawable.tracker_icon_30x30)
                    // Set content value
                    .setContentValue(String.valueOf(tileContentValue))
                    // Set content unit
                    .setContentUnit("LBS")
                    // Set Date text
                    .setDate(tileDate)
                    // Set content color
                    .setContentColor(Color.parseColor("#7CB342"))
                    // Set content intent
                    .setContentIntent(TrackerTile.INTENT_TYPE_ACTIVITY, launchIntent)
                    // Set button intent
                    .setButtonIntent("UPDATE", TrackerTile.INTENT_TYPE_SERVICE, serviceIntent);

            if (mTrackerTileManager != null) {
                mTrackerTileManager.post(myTrackerTile);
            }

        } catch (IllegalArgumentException e) {
            Log.d(APP_TAG, "MyTracker updateTile(" + trackerId + ", " + tileId + " " + e.toString());
        } catch (NotFoundException e) {
            Log.d(APP_TAG, "MyTracker updateTile(" + trackerId + ", " + tileId + " " + e.toString());
        }
    }
}

If you use the same tile ID with the posted tracker tile and update the tile, the updated tracker tile will be shown in the same position of the main screen as Figure 5 where the tracker tile has been posted. Otherwise, the updated tracker tile will be shown as the last tile on the main screen.

Figure 5: Updated tracker tile on Samsung Health Figure 5: Updated tracker tile on Samsung Health

Launching Samsung Health's Tracker

You can launch the Samsung Health's available tracker with the SDK's Health Service.

Creating a TrackerManager's Instance

Create a TrackerManager's instance first. Launching the Samsung Health's tracker is supported in Samsung Health 4.8 or above.

public class MainActivity extends Activity {

    private static final String APP_TAG = "PluginTracker";

    private TrackerManager mTrackerManager;

    private TrackerInfo getSpecificTrackerInfo(String trackerId) {

        // Construct a TrackerManager's instance
        try {
            mTrackerManager = new TrackerManager(this);
        } catch (IllegalArgumentException e) {
            Log.d(APP_TAG, "TrackerManager Constructor - " + e.toString());
        }

        // ...

    }
Getting Samsung Health's Tracker Info

The interesting tracker's information can be retrieved by TrackerManager. Check the tracker's availability also.

private TrackerInfo getSpecificTrackerInfo(String trackerId) {

		// ...

		// Get the tracker's info
		TrackerInfo trackerInfo = mTrackerManager.getTrackerInfo(TrackerManager.TRACKER_RUNNING);
		if(trackerInfo == null) {
				Log.d(APP_TAG, "trackerInfo == null");
				return null;
		}
		if(trackerInfo.isAvailable() == false) {
				Log.d(APP_TAG, "trackerInfo is not available.");
				return null;
		}

		return trackerInfo;
}
Launching the Available Tracker

If the tracker is available, you can launch it.

private void launchRunningTracker() {
		if(mTrackerManager == null) {
				Log.d(APP_TAG, "mTrackerManager == null");
				return;
		}

		// Get the wanted tracker's info
		TrackerInfo trackerInfo = getSpecificTrackerInfo(TrackerManager.TRACKER_RUNNING);
		if (trackerInfo == null) {
				Log.d(APP_TAG, "trackerInfo == null");
				return;
		}

		// Launch the tracker
		try {
				mTrackerManager.startActivity(this, trackerInfo.getId());
		} catch (IllegalArgumentException e) {
				Log.d(APP_TAG, "startActivity() - " + e.toString());
		} catch (IllegalStateException e) {
				Log.d(APP_TAG, "startActivity() - " + e.toString());
		}
}