diff --git a/build.sbt b/build.sbt
index c5971f8b..53e74a82 100644
--- a/build.sbt
+++ b/build.sbt
@@ -2,7 +2,7 @@ import android.Keys._
android.Plugin.androidBuild
-platformTarget in Android := "android-23"
+platformTarget in Android := "android-N"
name := "shadowsocks"
diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml
index f931df3a..3250f588 100644
--- a/src/main/AndroidManifest.xml
+++ b/src/main/AndroidManifest.xml
@@ -48,6 +48,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksTileService.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksTileService.scala
new file mode 100644
index 00000000..aebd4006
--- /dev/null
+++ b/src/main/scala/com/github/shadowsocks/ShadowsocksTileService.scala
@@ -0,0 +1,56 @@
+package com.github.shadowsocks
+
+import android.content.Intent
+import android.graphics.drawable.Icon
+import android.service.quicksettings.{Tile, TileService}
+import com.github.shadowsocks.aidl.IShadowsocksServiceCallback
+import com.github.shadowsocks.utils.State
+
+/**
+ * @author Mygod
+ */
+final class ShadowsocksTileService extends TileService with ServiceBoundContext {
+ private lazy val iconIdle = Icon.createWithResource(this, R.drawable.ic_start_idle).setTint(0x80ffffff)
+ private lazy val iconBusy = Icon.createWithResource(this, R.drawable.ic_start_busy)
+ private lazy val iconConnected = Icon.createWithResource(this, R.drawable.ic_start_connected)
+ private lazy val callback = new IShadowsocksServiceCallback.Stub {
+ def trafficUpdated(txRate: Long, rxRate: Long, txTotal: Long, rxTotal: Long) = ()
+ def stateChanged(state: Int, msg: String) {
+ val tile = getQsTile
+ state match {
+ case State.STOPPED =>
+ tile.setIcon(iconIdle)
+ tile.setLabel(getString(R.string.app_name))
+ tile.setState(Tile.STATE_INACTIVE)
+ case State.CONNECTED =>
+ tile.setIcon(iconConnected)
+ tile.setLabel(ShadowsocksApplication.currentProfile match {
+ case Some(profile) => profile.name
+ case None => getString(R.string.app_name)
+ })
+ tile.setState(Tile.STATE_ACTIVE)
+ case _ =>
+ tile.setIcon(iconBusy)
+ tile.setLabel(getString(R.string.app_name))
+ tile.setState(Tile.STATE_UNAVAILABLE)
+ }
+ tile.updateTile
+ }
+ }
+
+ override def onServiceConnected = callback.stateChanged(bgService.getState, null)
+
+ override def onStartListening {
+ super.onStartListening
+ attachService(callback)
+ }
+
+ override def onStopListening {
+ super.onStopListening
+ detachService // just in case the user switches to NAT mode
+ }
+
+ override def onClick = if (isLocked) unlockAndRun(configure) else configure()
+
+ private def configure() = startActivityAndCollapse(new Intent(this, classOf[Shadowsocks]))
+}