Quote from alexsmith on September 17, 2016
Hello!
I had a play on Torque Plugin Development and found it a bit difficult to understand all steps. Maybe because I’m new to the Android programming world… So I decided to document my learning process and share with you, hoping to ease the future plugins development.
I used Android Studio 2.1.3 (Linux version) for this. For testing/deploying, I used a Samsung Galaxy S5 with Android 6.0.1 (Marshmallow).
This how-to is a “Hello World!” intended to help developers understand the basics behind Torque plugins development.
First of all, we open Android SDK and:
1. Create new project
1.1 Choose a name, company and project location. Click Next.
1.2 Choose the API version number (API 23, for example). Click Next.
1.3 Choose “Empty Activity”. Click Next.
1.4 Name “Activity Name” as “PluginActivity”. Other names won’t work. Leave “Layout Name” as it is. Click Finish.
2. Edit AndroidManifest.xml to tell you want to attach to torque. Do this by replacing the “<activity>” xml entry like this:
<activity android:name=".PluginActivity">
<intent-filter>
<action android:name="org.prowl.torque.ACTIVITY_PLUGIN" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
At this point, you can deploy your “Hello World” and Torque will see it.
Of course the plugin does nothing and is not yet communicating with Torque. So let’s develop it a little further.
In order to interface with Torque, we need to get Torque’s AIDL file, which will expose Torque’s available API calls. There’s a number of ways you can do that. I’ve chosen to do like this:
1. Create a directory where the AIDL will be saved to.
$ mkdir -p <project_path>/app/src/main/aidl/org/prowl/torque/remote/
2. Get latest Torque AIDL file:
$ wget "http://torque-bhp.com/ITorqueService.aidl" -O <project_path>/app/src/main/aidl/org/prowl/torque/remote/ITorqueService.aidl
Going back to Android SDK, the project will refresh itself and you’ll see a new folder containing the AIDL file.
Now we must bind to Torque to get access to its functions. The following code for PluginActivity.class should be sufficiently documented for you to understand what’s going on.
package com.alexsmithsoftware.alextorquepidscanner;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.Bundle;
import android.widget.TextView;
import org.prowl.torque.remote.ITorqueService;
public class PluginActivity extends Activity {
/**
* Attribute to handle all calls we do to Torque.
*/
private ITorqueService torqueService;
/**
* Method to tell what will be shown when plugin initiates.
*
* @param savedInstanceState
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_plugin);
}
/**
* When application is resumed (first start or comming back from lock screen),
* we try to bind to Torque.
*/
@Override
protected void onResume() {
super.onResume();
try {
// Bind to the torque service
Intent intent = new Intent();
intent.setClassName("org.prowl.torque", "org.prowl.torque.remote.TorqueService");
boolean successfulBind = bindService(intent, connection, 0);
if ( ! successfulBind ) {
throw new Exception("Couldn't connect to Torque");
}
} catch ( Exception e ) {
info("Error: " + e.getMessage());
}
}
/**
* When screen is on pause (on lock screen or when user hit back), we unbind.
*/
@Override
protected void onPause() {
super.onPause();
unbindService(connection);
}
/**
* General method to do what we want to do once connected.
*/
private void displayVersion() {
int torqueVersion = 0;
int minVersion = 26;
try {
if (torqueService != null) {
torqueVersion = torqueService.getVersion();
if (torqueVersion < minVersion) {
throw new Exception("Minimum Torque version for this plugin is " + minVersion + ". You're running " + torqueVersion + ". Please update.");
}
}
} catch ( Exception e ) {
info("Error: " + e.getMessage());
}
TextView t = (TextView) findViewById(R.id.txtTest);
t.setText("Current Torque version: " + torqueVersion);
}
/**
* Auxiliary method to show a message box with an Ok button
*/
private void info(String msg) {
AlertDialog.Builder dlgAlert = new AlertDialog.Builder(this);
dlgAlert.setMessage(msg);
dlgAlert.setTitle(getString(R.string.app_name));
dlgAlert.setCancelable(true);
dlgAlert.setPositiveButton("Ok", null);
dlgAlert.create().show();
}
/**
* Attribute to handle our connection to Torque. Overridden method onServiceConnected
* is called when we bind successfully to Torque. Overriden method onServiceDisconnected
* is called when we unbind the connection.
*/
private ServiceConnection connection = new ServiceConnection() {
/**
* What to do when we get connected to Torque.
*
* @param arg0
* @param service
*/
public void onServiceConnected(ComponentName arg0, IBinder service) {
torqueService = ITorqueService.Stub.asInterface(service);
displayVersion();
};
/**
* What to do when we get disconnected from Torque.
*
* @param name
*/
public void onServiceDisconnected(ComponentName name) {
torqueService = null;
};
};
}
That's it!
In the end, you'll have a working code, which does a call to Torque and get the version number and displays it in a TextView.
Hope this can help someone out there.
Thank you for this. Very helpful!
|