support scaning QR code
This commit is contained in:
@@ -4,7 +4,8 @@ libraryDependencies ++= Seq(
|
||||
"com.google.android" % "admob" % "6.4.1",
|
||||
"dnsjava" % "dnsjava" % "2.1.5",
|
||||
"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(
|
||||
|
||||
@@ -66,4 +66,11 @@
|
||||
<string name="flush_dnscache">刷新 DNS 缓存</string>
|
||||
<string name="flushing">刷新中...</string>
|
||||
<string name="add_profile">添加配置文件</string>
|
||||
|
||||
<!-- profile -->
|
||||
<string-array name="add_profile_methods">
|
||||
<item>扫描二维码</item>
|
||||
<item>手动设置</item>
|
||||
</string-array>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -83,4 +83,10 @@
|
||||
<string name="flushing">Flushing</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>
|
||||
|
||||
@@ -72,6 +72,7 @@ import com.github.shadowsocks.database.Category
|
||||
import com.github.shadowsocks.utils._
|
||||
import com.github.shadowsocks.database.Item
|
||||
import com.github.shadowsocks.database.Category
|
||||
import com.google.zxing.integration.android.IntentIntegrator
|
||||
|
||||
class ProfileIconDownloader(context: Context, connectTimeout: Int, readTimeout: Int)
|
||||
extends BaseImageDownloader(context, connectTimeout, readTimeout) {
|
||||
@@ -569,6 +570,50 @@ class Shadowsocks
|
||||
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) {
|
||||
drawer.closeMenu(true)
|
||||
|
||||
@@ -665,7 +710,7 @@ class Shadowsocks
|
||||
buf ++= getProfileList
|
||||
|
||||
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))
|
||||
|
||||
@@ -827,16 +872,24 @@ class Shadowsocks
|
||||
}
|
||||
|
||||
override def onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
|
||||
resultCode match {
|
||||
case Activity.RESULT_OK => {
|
||||
prepared = true
|
||||
if (!serviceStart) {
|
||||
switchButton.setChecked(false)
|
||||
}
|
||||
val scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data)
|
||||
if (scanResult != null) {
|
||||
ShadowParser.parse(scanResult.getContents) match {
|
||||
case Some(profile) => addProfile(profile)
|
||||
case _ => // ignore
|
||||
}
|
||||
case _ => {
|
||||
clearDialog()
|
||||
Log.e(Shadowsocks.TAG, "Failed to start VpnService")
|
||||
} else {
|
||||
resultCode match {
|
||||
case Activity.RESULT_OK => {
|
||||
prepared = true
|
||||
if (!serviceStart) {
|
||||
switchButton.setChecked(false)
|
||||
}
|
||||
}
|
||||
case _ => {
|
||||
clearDialog()
|
||||
Log.e(Shadowsocks.TAG, "Failed to start VpnService")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user