Commit 1907ac2f authored by Max Lv's avatar Max Lv

support scaning QR code

parent aae95df4
...@@ -4,7 +4,8 @@ libraryDependencies ++= Seq( ...@@ -4,7 +4,8 @@ libraryDependencies ++= Seq(
"com.google.android" % "admob" % "6.4.1", "com.google.android" % "admob" % "6.4.1",
"dnsjava" % "dnsjava" % "2.1.5", "dnsjava" % "dnsjava" % "2.1.5",
"org.scalaj" %% "scalaj-http" % "0.3.10", "org.scalaj" %% "scalaj-http" % "0.3.10",
"commons-net" % "commons-net" % "3.3" "commons-net" % "commons-net" % "3.3",
"com.google.zxing" % "android-integration" % "2.2"
) )
libraryDependencies ++= Seq( libraryDependencies ++= Seq(
......
...@@ -66,4 +66,11 @@ ...@@ -66,4 +66,11 @@
<string name="flush_dnscache">刷新 DNS 缓存</string> <string name="flush_dnscache">刷新 DNS 缓存</string>
<string name="flushing">刷新中...</string> <string name="flushing">刷新中...</string>
<string name="add_profile">添加配置文件</string> <string name="add_profile">添加配置文件</string>
<!-- profile -->
<string-array name="add_profile_methods">
<item>扫描二维码</item>
<item>手动设置</item>
</string-array>
</resources> </resources>
...@@ -83,4 +83,10 @@ ...@@ -83,4 +83,10 @@
<string name="flushing">Flushing</string> <string name="flushing">Flushing</string>
<string name="add_profile">Add Profile</string> <string name="add_profile">Add Profile</string>
<!-- profile -->
<string-array name="add_profile_methods">
<item>Scan QR code</item>
<item>Manually Setting</item>
</string-array>
</resources> </resources>
...@@ -72,6 +72,7 @@ import com.github.shadowsocks.database.Category ...@@ -72,6 +72,7 @@ import com.github.shadowsocks.database.Category
import com.github.shadowsocks.utils._ import com.github.shadowsocks.utils._
import com.github.shadowsocks.database.Item import com.github.shadowsocks.database.Item
import com.github.shadowsocks.database.Category import com.github.shadowsocks.database.Category
import com.google.zxing.integration.android.IntentIntegrator
class ProfileIconDownloader(context: Context, connectTimeout: Int, readTimeout: Int) class ProfileIconDownloader(context: Context, connectTimeout: Int, readTimeout: Int)
extends BaseImageDownloader(context, connectTimeout, readTimeout) { extends BaseImageDownloader(context, connectTimeout, readTimeout) {
...@@ -569,6 +570,50 @@ class Shadowsocks ...@@ -569,6 +570,50 @@ class Shadowsocks
drawer.setActiveView(v, pos) drawer.setActiveView(v, pos)
} }
def newProfile(id: Int) {
val builder = new AlertDialog.Builder(this)
builder.setTitle(R.string.add_profile)
.setItems(R.array.add_profile_methods, new DialogInterface.OnClickListener() {
def onClick(dialog: DialogInterface, which: Int) {
which match {
case 0 => {
val integrator = new IntentIntegrator(Shadowsocks.this)
integrator.initiateScan()
}
case 1 => addProfile(id)
case _ =>
}
}
})
builder.create().show()
}
def addProfile(profile: Profile) {
drawer.closeMenu(true)
val h = showProgress(getString(R.string.loading))
handler.postDelayed(new Runnable {
def run() {
currentProfile = profile
profileManager.createOrUpdateProfile(currentProfile)
profileManager.reload(currentProfile.id)
menuAdapter.updateList(getMenuList, currentProfile.id)
if (!isSinglePane) {
sendBroadcast(new Intent(Action.UPDATE_FRAGMENT))
} else {
updatePreferenceScreen()
}
h.sendEmptyMessage(0)
}
}, 600)
}
def addProfile(id: Int) { def addProfile(id: Int) {
drawer.closeMenu(true) drawer.closeMenu(true)
...@@ -665,7 +710,7 @@ class Shadowsocks ...@@ -665,7 +710,7 @@ class Shadowsocks
buf ++= getProfileList buf ++= getProfileList
buf += buf +=
new Item(-400, getString(R.string.add_profile), android.R.drawable.ic_menu_add, addProfile) new Item(-400, getString(R.string.add_profile), android.R.drawable.ic_menu_add, newProfile)
buf += new Category(getString(R.string.settings)) buf += new Category(getString(R.string.settings))
...@@ -827,16 +872,24 @@ class Shadowsocks ...@@ -827,16 +872,24 @@ class Shadowsocks
} }
override def onActivityResult(requestCode: Int, resultCode: Int, data: Intent) { override def onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
resultCode match { val scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data)
case Activity.RESULT_OK => { if (scanResult != null) {
prepared = true ShadowParser.parse(scanResult.getContents) match {
if (!serviceStart) { case Some(profile) => addProfile(profile)
switchButton.setChecked(false) case _ => // ignore
}
} }
case _ => { } else {
clearDialog() resultCode match {
Log.e(Shadowsocks.TAG, "Failed to start VpnService") case Activity.RESULT_OK => {
prepared = true
if (!serviceStart) {
switchButton.setChecked(false)
}
}
case _ => {
clearDialog()
Log.e(Shadowsocks.TAG, "Failed to start VpnService")
}
} }
} }
} }
......
package com.github.shadowsocks.utils
import com.github.shadowsocks.database.Profile
import android.net.Uri
import android.util.{Log, Base64}
object ShadowParser {
val TAG = "ShadowParser"
def parse (data: String): Option[Profile] = {
try {
Log.d(TAG, data)
val uri = Uri.parse(data.trim)
if (uri.isOpaque && uri.getScheme == "shadow") {
val encoded = data.replace("shadow:", "")
val content = new String(Base64.decode(encoded, Base64.NO_PADDING), "UTF-8")
val info = content.split('@')
val encinfo = info(0).split(':')
val serverinfo = info(1).split(':')
val profile = new Profile
profile.name = serverinfo(0)
profile.host = serverinfo(0)
profile.remotePort = serverinfo(1).toInt
profile.localPort = 1080
profile.method = encinfo(0)
profile.password = encinfo(1)
return Some(profile)
}
} catch {
case ex : Exception => Log.e(TAG, "parser error", ex)// Ignore
}
None
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment