add intent filter for shadowsocks URI #51
This commit is contained in:
@@ -1,85 +1,97 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.github.shadowsocks">
|
||||
package="com.github.shadowsocks">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_SUPERUSER"/>
|
||||
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_SUPERUSER"/>
|
||||
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
|
||||
|
||||
<uses-feature
|
||||
android:name="android.hardware.touchscreen"
|
||||
android:required="false"/>
|
||||
<uses-feature
|
||||
android:name="android.hardware.touchscreen"
|
||||
android:required="false"/>
|
||||
|
||||
<uses-sdk
|
||||
android:minSdkVersion="9"
|
||||
android:targetSdkVersion="16"/>
|
||||
<uses-sdk
|
||||
android:minSdkVersion="9"
|
||||
android:targetSdkVersion="16"/>
|
||||
|
||||
<application
|
||||
android:name=".ShadowsocksApplication"
|
||||
android:hardwareAccelerated="true"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:backupAgent=".ShadowsocksBackupAgent"
|
||||
android:label="@string/app_name">
|
||||
<application
|
||||
android:name=".ShadowsocksApplication"
|
||||
android:hardwareAccelerated="true"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:backupAgent=".ShadowsocksBackupAgent"
|
||||
android:label="@string/app_name">
|
||||
|
||||
<meta-data android:name="com.google.android.backup.api_key"
|
||||
android:value="AEdPqrEAAAAI_zVxZthz2HDuz9toTvkYvL0L5GA-OjeUIfBeXg"/>
|
||||
<meta-data android:name="com.google.android.backup.api_key"
|
||||
android:value="AEdPqrEAAAAI_zVxZthz2HDuz9toTvkYvL0L5GA-OjeUIfBeXg"/>
|
||||
|
||||
<activity
|
||||
android:name="com.google.ads.AdActivity"
|
||||
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"/>
|
||||
<activity
|
||||
android:name="com.google.ads.AdActivity"
|
||||
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize"/>
|
||||
|
||||
<activity
|
||||
android:name=".Shadowsocks"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.Shadowsocks"
|
||||
android:launchMode="singleTask">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".Shadowsocks"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.Shadowsocks"
|
||||
android:launchMode="singleTask">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN"/>
|
||||
<category android:name="android.intent.category.LAUNCHER"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".ShadowVpnActivity"
|
||||
android:theme="@android:style/Theme.Translucent.NoTitleBar"
|
||||
android:launchMode="singleTask">
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".ParserActivity"
|
||||
android:theme="@style/PopupTheme"
|
||||
android:launchMode="singleTask">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
<category android:name="android.intent.category.BROWSABLE"/>
|
||||
<data android:scheme="ss"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".AppManager"
|
||||
android:theme="@style/Theme.AppManager"
|
||||
android:label="@string/app_name">
|
||||
<intent-filter>
|
||||
<action android:name="com.github.shadowsocks.AppManager"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".ShadowVpnActivity"
|
||||
android:theme="@style/PopupTheme"
|
||||
android:launchMode="singleTask">
|
||||
</activity>
|
||||
|
||||
<service
|
||||
android:name=".ShadowsocksService"
|
||||
android:process=":proxy"
|
||||
android:exported="false"/>
|
||||
<activity
|
||||
android:name=".AppManager"
|
||||
android:theme="@style/Theme.AppManager"
|
||||
android:label="@string/app_name">
|
||||
<intent-filter>
|
||||
<action android:name="com.github.shadowsocks.AppManager"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<service
|
||||
android:name=".ShadowVpnService"
|
||||
android:label="@string/app_name"
|
||||
android:process=":vpn"
|
||||
android:permission="android.permission.BIND_VPN_SERVICE"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="android.net.VpnService"/>
|
||||
</intent-filter>
|
||||
</service>
|
||||
<service
|
||||
android:name=".ShadowsocksService"
|
||||
android:process=":proxy"
|
||||
android:exported="false"/>
|
||||
|
||||
<receiver android:name=".ShadowsocksReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED"/>
|
||||
<action android:name="com.github.shadowsocks.ACTION_UPDATE_STATE"/>
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<service
|
||||
android:name=".ShadowVpnService"
|
||||
android:label="@string/app_name"
|
||||
android:process=":vpn"
|
||||
android:permission="android.permission.BIND_VPN_SERVICE"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="android.net.VpnService"/>
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
</application>
|
||||
<receiver android:name=".ShadowsocksReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED"/>
|
||||
<action android:name="com.github.shadowsocks.ACTION_UPDATE_STATE"/>
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
||||
@@ -19,6 +19,15 @@
|
||||
|
||||
<resources>
|
||||
|
||||
<style name="PopupTheme" parent="@android:style/Theme.Holo.Light.Dialog.NoActionBar">
|
||||
<item name="android:windowIsFloating">false</item>
|
||||
<item name="android:windowContentOverlay">@null</item>
|
||||
<item name="android:windowSoftInputMode">stateAlwaysHidden</item>
|
||||
<item name="android:windowActionModeOverlay">true</item>
|
||||
<item name="android:windowIsTranslucent">true</item>
|
||||
</style>
|
||||
|
||||
|
||||
<style name="Theme.Shadow" parent="@style/Theme.Sherlock.Light.DarkActionBar">
|
||||
<item name="android:actionBarItemBackground">@drawable/selectable_background_shadow</item>
|
||||
<item name="android:popupMenuStyle">@style/PopupMenu.Shadow</item>
|
||||
|
||||
@@ -68,6 +68,7 @@
|
||||
<string name="add_profile">添加配置文件</string>
|
||||
|
||||
<!-- profile -->
|
||||
<string name="add_profile_dialog">为影梭添加此配置文件?</string>
|
||||
<string-array name="add_profile_methods">
|
||||
<item>扫描二维码</item>
|
||||
<item>手动设置</item>
|
||||
|
||||
@@ -84,6 +84,7 @@
|
||||
<string name="add_profile">Add Profile</string>
|
||||
|
||||
<!-- profile -->
|
||||
<string name="add_profile_dialog">Add this Shadowsocks Profile?</string>
|
||||
<string-array name="add_profile_methods">
|
||||
<item>Scan QR code</item>
|
||||
<item>Manually Setting</item>
|
||||
|
||||
@@ -19,7 +19,20 @@
|
||||
|
||||
<resources>
|
||||
|
||||
<style name="Theme.Shadow" parent="@style/Theme.Sherlock.Light.DarkActionBar">
|
||||
<style name="PopupTheme" parent="@android:style/Theme.Translucent.NoTitleBar">
|
||||
<item name="android:windowFrame">@null</item>
|
||||
<item name="android:windowIsFloating">false</item>
|
||||
<item name="android:windowContentOverlay">@null</item>
|
||||
<item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
|
||||
<item name="android:windowSoftInputMode">stateAlwaysHidden</item>
|
||||
<item name="android:windowActionModeOverlay">true</item>
|
||||
<item name="android:colorBackgroundCacheHint">@null</item>
|
||||
<item name="android:windowCloseOnTouchOutside">true</item>
|
||||
<item name="android:windowIsTranslucent">true</item>
|
||||
<item name="windowContentOverlay">@null</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Shadow" parent="@style/Theme.Sherlock.Light.DarkActionBar">
|
||||
<item name="actionBarItemBackground">@drawable/selectable_background_shadow</item>
|
||||
<item name="popupMenuStyle">@style/PopupMenu.Shadow</item>
|
||||
<item name="dropDownListViewStyle">@style/DropDownListView.Shadow</item>
|
||||
@@ -30,7 +43,7 @@
|
||||
<item name="actionModeSplitBackground">@drawable/cab_background_bottom_shadow</item>
|
||||
<item name="actionModeCloseButtonStyle">@style/ActionButton.CloseMode.Shadow</item>
|
||||
|
||||
<!-- Light.DarkActionBar specific -->
|
||||
<!-- Light.DarkActionBar specific -->
|
||||
<item name="actionBarWidgetTheme">@style/Theme.Shadow.Widget</item>
|
||||
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.github.shadowsocks
|
||||
|
||||
import android.os.{Message, Handler, Bundle}
|
||||
import android.app.{ProgressDialog, AlertDialog, Activity}
|
||||
import android.content.{Intent, DialogInterface}
|
||||
import com.github.shadowsocks.database.{ProfileManager, Profile}
|
||||
import com.github.shadowsocks.utils.{Parser, Action}
|
||||
import android.preference.PreferenceManager
|
||||
import android.view.WindowManager
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
|
||||
class ParserActivity extends Activity {
|
||||
override def onCreate(savedInstanceState: Bundle) {
|
||||
super.onCreate(savedInstanceState)
|
||||
showAsPopup(this)
|
||||
val data = getIntent.getData.toString
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle(R.string.add_profile_dialog)
|
||||
.setCancelable(false)
|
||||
.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
|
||||
override def onClick(dialog: DialogInterface, id: Int) {
|
||||
Parser.parse(data) match {
|
||||
case Some(profile) => addProfile(profile)
|
||||
case _ => // ignore
|
||||
}
|
||||
dialog.dismiss()
|
||||
}
|
||||
})
|
||||
.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
|
||||
override def onClick(dialog: DialogInterface, id: Int) {
|
||||
dialog.dismiss()
|
||||
finish()
|
||||
}
|
||||
})
|
||||
.setMessage(data)
|
||||
.create()
|
||||
.show()
|
||||
}
|
||||
|
||||
def showAsPopup(activity: Activity) {
|
||||
activity.getWindow.setFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND,
|
||||
WindowManager.LayoutParams.FLAG_DIM_BEHIND)
|
||||
val params = activity.getWindow.getAttributes
|
||||
params.alpha = 1.0f
|
||||
params.dimAmount = 0.5f
|
||||
activity.getWindow.setAttributes(params.asInstanceOf[android.view.WindowManager.LayoutParams])
|
||||
activity.getWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT))
|
||||
}
|
||||
|
||||
def addProfile(profile: Profile) {
|
||||
|
||||
val h = showProgress(getString(R.string.loading))
|
||||
|
||||
h.postDelayed(new Runnable {
|
||||
def run() {
|
||||
val profileManager =
|
||||
new ProfileManager(PreferenceManager.getDefaultSharedPreferences(getBaseContext),
|
||||
getApplication.asInstanceOf[ShadowsocksApplication].dbHelper)
|
||||
profileManager.createOrUpdateProfile(profile)
|
||||
profileManager.reload(profile.id)
|
||||
h.sendEmptyMessage(0)
|
||||
}
|
||||
}, 600)
|
||||
}
|
||||
|
||||
private def showProgress(msg: String): Handler = {
|
||||
val progressDialog = ProgressDialog.show(this, "", msg, true, false)
|
||||
new Handler {
|
||||
override def handleMessage(msg: Message) {
|
||||
progressDialog.dismiss()
|
||||
finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -46,6 +46,7 @@ import android.content.Intent
|
||||
import android.util.Log
|
||||
import android.preference.PreferenceManager
|
||||
import com.github.shadowsocks.utils.Extra
|
||||
import com.actionbarsherlock.app.SherlockActivity
|
||||
|
||||
class ShadowVpnActivity extends Activity {
|
||||
|
||||
|
||||
@@ -579,10 +579,20 @@ class Shadowsocks
|
||||
def onClick(dialog: DialogInterface, which: Int) {
|
||||
which match {
|
||||
case 0 => {
|
||||
val integrator = new IntentIntegrator(Shadowsocks.this)
|
||||
integrator.initiateScan()
|
||||
dialog.dismiss()
|
||||
val h = showProgress(getString(R.string.loading))
|
||||
h.postDelayed(new Runnable() {
|
||||
def run() {
|
||||
val integrator = new IntentIntegrator(Shadowsocks.this)
|
||||
integrator.initiateScan()
|
||||
h.sendEmptyMessage(0)
|
||||
}
|
||||
}, 600)
|
||||
}
|
||||
case 1 => {
|
||||
dialog.dismiss()
|
||||
addProfile(id)
|
||||
}
|
||||
case 1 => addProfile(id)
|
||||
case _ =>
|
||||
}
|
||||
}
|
||||
@@ -874,7 +884,7 @@ class Shadowsocks
|
||||
override def onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
|
||||
val scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data)
|
||||
if (scanResult != null) {
|
||||
ShadowParser.parse(scanResult.getContents) match {
|
||||
Parser.parse(scanResult.getContents) match {
|
||||
case Some(profile) => addProfile(profile)
|
||||
case _ => // ignore
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ object Key {
|
||||
object Scheme {
|
||||
val APP = "app://"
|
||||
val PROFILE = "profile://"
|
||||
val SHADOW = "shadow:"
|
||||
val SS = "ss"
|
||||
}
|
||||
|
||||
object State {
|
||||
|
||||
+3
-3
@@ -4,14 +4,14 @@ import com.github.shadowsocks.database.Profile
|
||||
import android.net.Uri
|
||||
import android.util.{Log, Base64}
|
||||
|
||||
object ShadowParser {
|
||||
object Parser {
|
||||
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:", "")
|
||||
if (uri.isOpaque && uri.getScheme == Scheme.SS) {
|
||||
val encoded = data.replace(Scheme.SS + ":", "")
|
||||
val content = new String(Base64.decode(encoded, Base64.NO_PADDING), "UTF-8")
|
||||
val info = content.split('@')
|
||||
val encinfo = info(0).split(':')
|
||||
Reference in New Issue
Block a user