diff --git a/client/build.gradle b/client/build.gradle
index afe59b6e0833c6e330126def80cd28ac1a9d8696..e94f4b1d0f0bedefa8991c6e1e573490692aab8c 100644
--- a/client/build.gradle
+++ b/client/build.gradle
@@ -1,4 +1,5 @@
 apply plugin: 'com.android.library'
+apply plugin: 'witness'
 
 android {
     compileSdkVersion Integer.parseInt(project.ANDROID_BUILD_SDK_VERSION)
@@ -14,10 +15,20 @@ android {
             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
         }
     }
+    lintOptions {
+        abortOnError false
+    }
 }
 
 dependencies {
     compile project(path: ':routerjars', configuration: 'client')
+    compile 'com.android.support:support-v4:19.1.0'
+}
+
+dependencyVerification {
+    verify = [
+            'com.android.support:support-v4:3f40fa7b3a4ead01ce15dce9453b061646e7fe2e7c51cb75ca01ee1e77037f3f',
+    ]
 }
 
 android.libraryVariants.all { variant ->
diff --git a/client/src/main/java/net/i2p/android/ui/I2PAndroidHelper.java b/client/src/main/java/net/i2p/android/ui/I2PAndroidHelper.java
new file mode 100644
index 0000000000000000000000000000000000000000..9a62c82c7b3dc0475e7dd5715aeb7e52164d4411
--- /dev/null
+++ b/client/src/main/java/net/i2p/android/ui/I2PAndroidHelper.java
@@ -0,0 +1,156 @@
+package net.i2p.android.ui;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import net.i2p.android.lib.client.R;
+import net.i2p.android.router.service.IRouterState;
+
+/**
+ * @author str4d
+ * @since 0.2
+ */
+public class I2PAndroidHelper {
+    public static final String URI_I2P_ANDROID = "net.i2p.android";
+    public static final String URI_I2P_ANDROID_DONATE = "net.i2p.android.donate";
+    public static final String URI_I2P_ANDROID_LEGACY = "net.i2p.android.legacy";
+
+    public static final int REQUEST_START_I2P = 9857;
+
+    private Context mContext;
+    private boolean mTriedBindState;
+    private IRouterState mStateService;
+
+    public I2PAndroidHelper(Context context) {
+        mContext = context;
+    }
+
+    /**
+     * Try to bind to I2P Android. Call this in Activity.onStart()
+     */
+    public void bind() {
+        Intent i2pIntent = new Intent(IRouterState.class.getName());
+        try {
+            mTriedBindState = mContext.bindService(
+                    i2pIntent, mStateConnection, Context.BIND_AUTO_CREATE);
+        } catch (SecurityException e) {
+            // Old version of I2P Android (pre-0.9.13), cannot use
+            mStateService = null;
+            mTriedBindState = false;
+        }
+    }
+
+    /**
+     * Unbind from I2P Android. Call this in Activity.onStop();
+     */
+    public void unbind() {
+        if (mTriedBindState)
+            mContext.unbindService(mStateConnection);
+        mTriedBindState = false;
+    }
+
+    private ServiceConnection mStateConnection = new ServiceConnection() {
+        public void onServiceConnected(ComponentName className,
+                                       IBinder service) {
+            mStateService = IRouterState.Stub.asInterface(service);
+        }
+
+        public void onServiceDisconnected(ComponentName className) {
+            // This is called when the connection with the service has been
+            // unexpectedly disconnected -- that is, its process crashed.
+            mStateService = null;
+        }
+    };
+
+    /**
+     * Check if I2P Android is installed.
+     * @return true if I2P Android is installed, false otherwise.
+     */
+    public boolean isI2PAndroidInstalled() {
+        return isAppInstalled(URI_I2P_ANDROID) ||
+                isAppInstalled(URI_I2P_ANDROID_DONATE) ||
+                isAppInstalled(URI_I2P_ANDROID_LEGACY);
+    }
+
+    private boolean isAppInstalled(String uri) {
+        PackageManager pm = mContext.getPackageManager();
+        boolean installed;
+        try {
+            pm.getPackageInfo(uri, PackageManager.GET_ACTIVITIES);
+            installed = true;
+        } catch (PackageManager.NameNotFoundException e) {
+            installed = false;
+        }
+        return installed;
+    }
+
+    /**
+     * Show dialog - install from market or F-Droid.
+     * @param activity
+     */
+    public void promptToInstall(final Activity activity) {
+        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+        builder.setTitle(R.string.install_i2p_android)
+                .setMessage(R.string.you_must_have_i2p_android)
+                .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
+                    public void onClick(DialogInterface dialogInterface, int i) {
+                        String uriMarket = activity.getString(R.string.market_i2p_android);
+                        Uri uri = Uri.parse(uriMarket);
+                        Intent intent = new Intent(Intent.ACTION_VIEW, uri);
+                        activity.startActivity(intent);
+                    }
+                })
+                .setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
+                    public void onClick(DialogInterface dialogInterface, int i) {
+                    }
+                });
+        builder.show();
+    }
+
+    /**
+     * Check if I2P Android is running. If {@link net.i2p.android.ui.I2PAndroidHelper#bind()}
+     * has not been called previously, this will always return false.
+     * @return true if I2P Android is running, false otherwise.
+     */
+    public boolean isI2PAndroidRunning() {
+        if (mStateService == null)
+            return false;
+
+        try {
+            return mStateService.isStarted();
+        } catch (RemoteException e) {
+            // TODO: log
+            return false;
+        }
+    }
+
+    /**
+     * Show dialog - request that I2P Android be started.
+     * @param activity
+     */
+    public void requestI2PAndroidStart(final Activity activity) {
+        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+        builder.setTitle(R.string.start_i2p_android)
+                .setMessage(R.string.would_you_like_to_start_i2p_android)
+                .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
+                    public void onClick(DialogInterface dialog, int which) {
+                        Intent i = new Intent("net.i2p.android.router.START_I2P");
+                        activity.startActivityForResult(i, REQUEST_START_I2P);
+                    }
+                })
+                .setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
+                    public void onClick(DialogInterface dialog, int which) {
+                    }
+                });
+        builder.show();
+    }
+}
diff --git a/client/src/main/res/values/strings.xml b/client/src/main/res/values/strings.xml
index f00bf74f9364c17995109cdd1eedb4a00f1b8779..37d5b9270cbd67cbb5858d83e7951b1c7f1ff573 100644
--- a/client/src/main/res/values/strings.xml
+++ b/client/src/main/res/values/strings.xml
@@ -1,3 +1,10 @@
 <resources>
-    <string name="app_name">I2P Android client</string>
+    <string name="app_name" translatable="false">I2P Android client</string>
+    <string name="yes">Yes</string>
+    <string name="no">No</string>
+    <string name="install_i2p_android">Install I2P Android?</string>
+    <string name="you_must_have_i2p_android">You must have I2P Android installed and running. Would you like to install it?</string>
+    <string name="market_i2p_android" translatable="false">market://search?q=pname:net.i2p.android</string>
+    <string name="start_i2p_android">Start I2P Android?</string>
+    <string name="would_you_like_to_start_i2p_android">It appears that I2P Android is not running. Would you like to start it?</string>
 </resources>