MessageOnTap's Plugin Core Architecture - MessageOnTap/MessageOnTap_API GitHub Wiki
MessageOnTap aims to be extensible to support users as much need as possible. To accomplish this, we design MessageOnTap as a framework for developers to create intelligent plugins for instant messaging apps. An IM plugin is just a normal Android app written on top of MessageOnTap API which is mainly used to communicate with the MessageOnTap-core running on the user's phone.
To work with the MessageOnTap framework, an IM plugin would need to set up the following:
- in AndroidManifest.xml.
- in build.gradle.
- extends a MessageOnTapPlugin service.
Add MessageOnTap API dependency to the build.gradle in your local project.
...
compile 'messageontap:api:0.3.2'
...
Your app must declare your plugin service with an intent-filter in its manifest. You can choose your own service name; in the following example, it is "SamplePlugin"
<service android:name=".SamplePlugin"
android:label="@string/plugin_title">
<intent-filter>
<action android:name="edu.cmu.chimps.messageontap_prototype.Plugin" />
</intent-filter>
<meta-data android:name="description"
android:value="@string/plugin_description" />
<meta-data android:name="settingsActivity"
android:value=".SamplePluginSettingsActivity" />
</service>
There are five steps for creating a new MessageOnTapPlugin Service in your plugin:
- Register semantic templates
- Create a session
- Create a task
- Handle task responses
- End a session
/**
* Return the semantic templates of this plugin. This will be called when
* MessageOnTap is started (when this plugin is already enabled) or when
* this plugin is being enabled.
*
* @return semantic templates
*/
@Override
protected Set<SemanticTemplate> semanticTemplates() {
Set<SemanticTemplate> semanticTemplates = new HashSet<>();
/**
* Semantic Template I:
* This template can recognize all the incoming messages with phone numbers.
* Examples: {Mike} just changed his number to {412-100-1000}.
* You can call {412-200-2000} for help.
* An optional tag will be added in the following code.
*/
Set<Tag> phoneNumberTags = new HashSet<>();
phoneNumberTags.add(new Tag(ServiceAttributes.Internal.TAG_PHONE_NUMBER,
new HashSet<String>(), Tag.Type.MANDATORY);
phoneNumberTags.add(new Tag(ServiceAttributes.Internal.TAG_PERSON, new HashSet<>(), TAG_TYPE.OPTIONAL);
semanticTemplates.add(new SemanticTemplate(
.name("phone_number")
.tags(phoneNumberTags)
.direction(Direction.INCOMING);
/**
* Semantic Template II:
* The following code defines a customized tag with four keywords, "number", "phone", "telephone", "cell".
* This template can recognize all the incoming messages that request phone numbers.
* Examples: What is {your} {phone number}?
* Do you have {Mike}'s {telephone number}?
* A customized tag will be added in the following code.
*/
Set<Tag> phoneNumberRequestTags = new HashSet<>();
phoneNumberRequestTags.add(new Tag(ServiceAttributes.Internal.TAG_PERSON, new HashSet<>(), TAG_TYPE.MANDATORY);
phoneNumberRequestTags.add(new Tag("phone_number_keyword",
new HashSet<String>(Arrays.asList({"number", "phone", "telephone", "cell"})),
TAG_TYPE.MANDATORY));
semanticTemplates.add(new SemanticTemplate("phone_number_request",phoneNumberRequestTags, Direction.INCOMING,
Mood.INTERROGTIVE));
return semanticTemplates;
}
Initialize A New Session
@Override
protected void initNewSession(long sid, HashMap<String, Object> params) throws Exception {
Log.e(TAG, "Session created here!");
Log.e(TAG, JSONUtils.hashMapToString(params));
Log.e(TAG, "parse tree: " + ((ParseTree) JSONUtils.jsonToSimpleObject((String) params.get("tree")
, JSONUtils.TYPE_PARSE_TREE)).toString());
HashMap<String, Object> reqParams = new HashMap<>();
reqParams.put("key1", "value1");
reqParams.put("key2", "value2");
reqParams.put("key3", "value3");
// TID is something we might need to implement stateflow inside a plugin.
long tid = createTask(sid, MethodConstants.PMS_TYPE, "test", params);
}
Now Create A New Task
With a task, you can easily connect make:
- User Interface showing on user's phone
- Actions such as making phone call and replying messages
- PersonGraph Search to get multi-source Personal data
//Example of Showing UI
long sid = SESSION_ID;
createTask(sid, MethodConstants.UI_TYPE,
MethodConstants.UI_METHOD_SHOW_BUBBLE, params);
//Example of Action Retrieve
long sid = SESSION_ID;
MethodConstants.ACTION_TYPE,
MethodConstants.ACTION_METHOD_SETTEXT, params)
//Example of Personal Graph Retrieve
long sid = SESSION_ID;
params.put(ServiceAttributes.Graph.SYNTAX_TREE,
JSONUtils.simpleObjectToJson(treeForSearch1.get(sid), JSONUtils.TYPE_PARSE_TREE));
createTask(sid, MethodConstants.GRAPH_TYPE,
MethodConstants.GRAPH_METHOD_RETRIEVE, params);
After a task is finished, the function newTaskResponded() will be called. Developers can choose to create a new task again or end this session.
@Override
protected void newTaskResponded(long sid, long tid, HashMap<String, Object> params) throws Exception {
Log.e(TAG, "Got task response!");
Log.e(TAG, JSONUtils.hashMapToString(params));
Log.e(TAG, "Ending session " + sid);
endSession(sid);
Log.e(TAG, "Session ended");
}
If your plugin finished all the tasks and ready for the next time of trigger match, call endSession(long sid) to end the current session.
long sid = SESSION_ID;
endSession(sid);