Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
com.ccwangluo.accelerator
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
sheteng
com.ccwangluo.accelerator
Commits
04ec29c9
Commit
04ec29c9
authored
Mar 12, 2016
by
Max Lv
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #603 from Mygod/master
Import/export one/all ss urls
parents
86da4f53
16e39f8b
Changes
10
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
105 additions
and
84 deletions
+105
-84
src/main/res/menu/app_manager_menu.xml
src/main/res/menu/app_manager_menu.xml
+9
-5
src/main/res/menu/profile_manager_menu.xml
src/main/res/menu/profile_manager_menu.xml
+8
-0
src/main/res/values-zh/strings.xml
src/main/res/values-zh/strings.xml
+1
-0
src/main/res/values/strings.xml
src/main/res/values/strings.xml
+1
-0
src/main/scala/com/github/shadowsocks/AppManager.scala
src/main/scala/com/github/shadowsocks/AppManager.scala
+16
-20
src/main/scala/com/github/shadowsocks/ParserActivity.scala
src/main/scala/com/github/shadowsocks/ParserActivity.scala
+5
-7
src/main/scala/com/github/shadowsocks/ProfileManagerActivity.scala
...scala/com/github/shadowsocks/ProfileManagerActivity.scala
+34
-18
src/main/scala/com/github/shadowsocks/ShadowsocksNotification.scala
...cala/com/github/shadowsocks/ShadowsocksNotification.scala
+6
-2
src/main/scala/com/github/shadowsocks/utils/Constants.scala
src/main/scala/com/github/shadowsocks/utils/Constants.scala
+2
-0
src/main/scala/com/github/shadowsocks/utils/Parser.scala
src/main/scala/com/github/shadowsocks/utils/Parser.scala
+23
-32
No files found.
src/main/res/menu/app_manager_menu.xml
View file @
04ec29c9
<menu
xmlns:android=
"http://schemas.android.com/apk/res/android"
>
<item
android:id=
"@+id/action_export"
android:title=
"@string/action_export"
android:showAsAction=
"never"
/>
<item
android:id=
"@+id/action_import"
android:title=
"@string/action_import"
android:showAsAction=
"never"
/>
android:showAsAction=
"never"
android:alphabeticShortcut=
"i"
android:numericShortcut=
"1"
/>
<item
android:id=
"@+id/action_export"
android:title=
"@string/action_export"
android:showAsAction=
"never"
android:alphabeticShortcut=
"e"
android:numericShortcut=
"2"
/>
</menu>
src/main/res/menu/profile_manager_menu.xml
View file @
04ec29c9
...
...
@@ -15,6 +15,14 @@
android:title=
"@string/add_profile_methods_manual_settings"
android:alphabeticShortcut=
"m"
android:numericShortcut=
"2"
/>
<item
android:id=
"@+id/action_import"
android:title=
"@string/action_import"
android:alphabeticShortcut=
"i"
android:numericShortcut=
"3"
/>
<item
android:id=
"@+id/action_export"
android:title=
"@string/action_export"
android:alphabeticShortcut=
"e"
android:numericShortcut=
"4"
/>
</menu>
</item>
</menu>
src/main/res/values-zh/strings.xml
View file @
04ec29c9
...
...
@@ -90,6 +90,7 @@
<string
name=
"profile_manager_dialog_content"
>
•
点击选择配置文件;\n
•
滑动删除;\n
•
长按拖动改变顺序。
</string>
<string
name=
"gotcha"
>
好的
</string>
<string
name=
"copy_url"
>
复制 URL
</string>
<string
name=
"add_profile_dialog"
>
为影梭添加此配置文件?
</string>
<string
name=
"add_profile_methods_scan_qr_code"
>
扫描二维码
</string>
<string
name=
"add_profile_methods_manual_settings"
>
手动设置
</string>
...
...
src/main/res/values/strings.xml
View file @
04ec29c9
...
...
@@ -113,6 +113,7 @@
<string
name=
"add_profile_dialog"
>
Add this Shadowsocks Profile?
</string>
<string
name=
"add_profile_methods_scan_qr_code"
>
Scan QR code
</string>
<string
name=
"add_profile_methods_manual_settings"
>
Manual Settings
</string>
<string
name=
"copy_url"
>
Copy URL
</string>
<plurals
name=
"removed"
>
<item
quantity=
"one"
>
Removed
</item>
<item
quantity=
"other"
>
%d items removed
</item>
...
...
src/main/scala/com/github/shadowsocks/AppManager.scala
View file @
04ec29c9
...
...
@@ -154,10 +154,7 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC
return
true
case
R
.
id
.
action_import
=>
if
(
clipboard
.
hasPrimaryClip
)
{
val
clipdata
=
clipboard
.
getPrimaryClip
val
label
=
clipdata
.
getDescription
.
getLabel
if
(
label
==
Key
.
proxied
)
{
val
proxiedAppSequence
=
clipdata
.
getItemAt
(
0
).
getText
val
proxiedAppSequence
=
clipboard
.
getPrimaryClip
.
getItemAt
(
0
).
getText
if
(
proxiedAppSequence
!=
null
)
{
val
proxiedAppString
=
proxiedAppSequence
.
toString
if
(!
proxiedAppString
.
isEmpty
)
{
...
...
@@ -176,7 +173,6 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC
}
}
}
}
Toast
.
makeText
(
this
,
R
.
string
.
action_import_err
,
Toast
.
LENGTH_SHORT
).
show
()
return
false
}
...
...
src/main/scala/com/github/shadowsocks/ParserActivity.scala
View file @
04ec29c9
...
...
@@ -50,9 +50,8 @@ import com.github.shadowsocks.utils.Parser
class
ParserActivity
extends
AppCompatActivity
{
override
def
onCreate
(
savedInstanceState
:
Bundle
)
{
super
.
onCreate
(
savedInstanceState
)
val
data
=
getIntent
.
getData
.
toString
val
profile
=
Parser
.
parse
(
data
)
if
(
profile
.
isEmpty
)
{
// ignore
val
profiles
=
Parser
.
findAll
(
getIntent
.
getData
.
toString
)
if
(
profiles
.
isEmpty
)
{
// ignore
finish
()
return
}
...
...
@@ -60,11 +59,10 @@ class ParserActivity extends AppCompatActivity {
val
dialog
=
new
AlertDialog
.
Builder
(
this
)
.
setTitle
(
R
.
string
.
add_profile_dialog
)
.
setCancelable
(
false
)
.
setPositiveButton
(
android
.
R
.
string
.
yes
,
((
dialog
:
DialogInterface
,
id
:
Int
)
=>
{
ShadowsocksApplication
.
profileManager
.
createProfile
(
profile
.
get
)
})
:
DialogInterface.OnClickListener
)
.
setPositiveButton
(
android
.
R
.
string
.
yes
,
((
_
,
_
)
=>
profiles
.
foreach
(
ShadowsocksApplication
.
profileManager
.
createProfile
))
:
DialogInterface.OnClickListener
)
.
setNegativeButton
(
android
.
R
.
string
.
no
,
null
)
.
setMessage
(
data
)
.
setMessage
(
profiles
.
mkString
(
"\n"
)
)
.
create
()
dialog
.
setOnDismissListener
((
dialog
:
DialogInterface
)
=>
finish
())
// builder method was added in API 17
dialog
.
show
()
...
...
src/main/scala/com/github/shadowsocks/ProfileManagerActivity.scala
View file @
04ec29c9
package
com.github.shadowsocks
import
android.content.
Intent
import
android.content.
_
import
android.os.
{
Bundle
,
Handler
}
import
android.support.v7.app.
{
AlertDialog
,
AppCompatActivity
}
import
android.support.v7.widget.RecyclerView.ViewHolder
...
...
@@ -14,7 +14,7 @@ import android.view.{LayoutInflater, MenuItem, View, ViewGroup}
import
android.widget.
{
CheckedTextView
,
ImageView
,
LinearLayout
,
Toast
}
import
com.github.shadowsocks.aidl.IShadowsocksServiceCallback
import
com.github.shadowsocks.database.Profile
import
com.github.shadowsocks.utils.
{
Parser
,
TrafficMonitor
,
Utils
}
import
com.github.shadowsocks.utils.
{
Key
,
Parser
,
TrafficMonitor
,
Utils
}
import
com.github.shadowsocks.widget.UndoSnackbarManager
import
com.google.zxing.integration.android.IntentIntegrator
import
net.glxn.qrgen.android.QRCode
...
...
@@ -24,13 +24,7 @@ import scala.collection.mutable.ArrayBuffer
/**
* @author Mygod
*/
object
ProfileManagerActivity
{
private
final
val
profileTip
=
"profileTip"
}
class
ProfileManagerActivity
extends
AppCompatActivity
with
OnMenuItemClickListener
with
ServiceBoundContext
{
import
ProfileManagerActivity._
private
class
ProfileViewHolder
(
val
view
:
View
)
extends
RecyclerView
.
ViewHolder
(
view
)
with
View
.
OnClickListener
{
var
item
:
Profile
=
_
private
val
text
=
itemView
.
findViewById
(
android
.
R
.
id
.
text1
).
asInstanceOf
[
CheckedTextView
]
...
...
@@ -38,17 +32,20 @@ class ProfileManagerActivity extends AppCompatActivity with OnMenuItemClickListe
{
val
qrcode
=
itemView
.
findViewById
(
R
.
id
.
qrcode
)
qrcode
.
setOnClickListener
((
v
:
View
)
=>
{
qrcode
.
setOnClickListener
(
_
=>
{
val
url
=
Parser
.
generate
(
item
)
val
image
=
new
ImageView
(
ProfileManagerActivity
.
this
)
image
.
setLayoutParams
(
new
LinearLayout
.
LayoutParams
(-
1
,
-
1
))
val
qrcode
=
QRCode
.
from
(
Parser
.
generate
(
item
)
)
val
qrcode
=
QRCode
.
from
(
url
)
.
withSize
(
Utils
.
dpToPx
(
ProfileManagerActivity
.
this
,
250
),
Utils
.
dpToPx
(
ProfileManagerActivity
.
this
,
250
))
.
asInstanceOf
[
QRCode
].
bitmap
()
image
.
setImageBitmap
(
qrcode
)
new
AlertDialog
.
Builder
(
ProfileManagerActivity
.
this
)
.
setCancelable
(
true
)
.
setNegativeButton
(
R
.
string
.
close
,
null
)
.
setPositiveButton
(
R
.
string
.
close
,
null
)
.
setNegativeButton
(
R
.
string
.
copy_url
,
((
_
,
_
)
=>
clipboard
.
setPrimaryClip
(
ClipData
.
newPlainText
(
null
,
url
)))
:
DialogInterface.OnClickListener
)
.
setView
(
image
)
.
create
()
.
show
()
...
...
@@ -150,6 +147,8 @@ class ProfileManagerActivity extends AppCompatActivity with OnMenuItemClickListe
private
lazy
val
profilesAdapter
=
new
ProfilesAdapter
private
var
undoManager
:
UndoSnackbarManager
[
Profile
]
=
_
private
lazy
val
clipboard
=
getSystemService
(
Context
.
CLIPBOARD_SERVICE
).
asInstanceOf
[
ClipboardManager
]
override
def
onCreate
(
savedInstanceState
:
Bundle
)
{
super
.
onCreate
(
savedInstanceState
)
setContentView
(
R
.
layout
.
layout_profiles
)
...
...
@@ -193,8 +192,8 @@ class ProfileManagerActivity extends AppCompatActivity with OnMenuItemClickListe
if
(
selectedItem
!=
null
)
selectedItem
.
updateText
(
txTotal
,
rxTotal
)
})
if
(
ShadowsocksApplication
.
settings
.
getBoolean
(
profileTip
,
true
))
{
ShadowsocksApplication
.
settings
.
edit
.
putBoolean
(
profileTip
,
false
).
commit
if
(
ShadowsocksApplication
.
settings
.
getBoolean
(
Key
.
profileTip
,
true
))
{
ShadowsocksApplication
.
settings
.
edit
.
putBoolean
(
Key
.
profileTip
,
false
).
commit
new
AlertDialog
.
Builder
(
this
).
setTitle
(
R
.
string
.
profile_manager_dialog
)
.
setMessage
(
R
.
string
.
profile_manager_dialog_content
).
setPositiveButton
(
R
.
string
.
gotcha
,
null
).
create
.
show
}
...
...
@@ -218,13 +217,11 @@ class ProfileManagerActivity extends AppCompatActivity with OnMenuItemClickListe
override
def
onActivityResult
(
requestCode
:
Int
,
resultCode
:
Int
,
data
:
Intent
)
{
val
scanResult
=
IntentIntegrator
.
parseActivityResult
(
requestCode
,
resultCode
,
data
)
if
(
scanResult
!=
null
)
Parser
.
parse
(
scanResult
.
getContents
)
match
{
case
Some
(
profile
)
=>
ShadowsocksApplication
.
profileManager
.
createProfile
(
profile
)
case
_
=>
// ignore
}
if
(
scanResult
!=
null
)
Parser
.
findAll
(
scanResult
.
getContents
).
foreach
(
ShadowsocksApplication
.
profileManager
.
createProfile
)
}
def
onMenuItemClick
(
item
:
MenuItem
)
=
item
.
getItemId
match
{
def
onMenuItemClick
(
item
:
MenuItem
)
:
Boolean
=
item
.
getItemId
match
{
case
R
.
id
.
scan_qr_code
=>
val
integrator
=
new
IntentIntegrator
(
this
)
val
list
=
new
java
.
util
.
ArrayList
(
IntentIntegrator
.
TARGET_ALL_KNOWN
)
...
...
@@ -237,6 +234,25 @@ class ProfileManagerActivity extends AppCompatActivity with OnMenuItemClickListe
ShadowsocksApplication
.
switchProfile
(
ShadowsocksApplication
.
profileManager
.
save
.
id
)
finish
true
case
R
.
id
.
action_import
=>
if
(
clipboard
.
hasPrimaryClip
)
{
val
profiles
=
Parser
.
findAll
(
clipboard
.
getPrimaryClip
.
getItemAt
(
0
).
getText
)
if
(
profiles
.
nonEmpty
)
{
profiles
.
foreach
(
ShadowsocksApplication
.
profileManager
.
createProfile
)
Toast
.
makeText
(
this
,
R
.
string
.
action_import_msg
,
Toast
.
LENGTH_SHORT
).
show
return
true
}
}
Toast
.
makeText
(
this
,
R
.
string
.
action_import_err
,
Toast
.
LENGTH_SHORT
).
show
true
case
R
.
id
.
action_export
=>
ShadowsocksApplication
.
profileManager
.
getAllProfiles
match
{
case
Some
(
profiles
)
=>
clipboard
.
setPrimaryClip
(
ClipData
.
newPlainText
(
null
,
profiles
.
map
(
Parser
.
generate
).
mkString
(
"\n"
)))
Toast
.
makeText
(
this
,
R
.
string
.
action_export_msg
,
Toast
.
LENGTH_SHORT
).
show
case
_
=>
Toast
.
makeText
(
this
,
R
.
string
.
action_export_err
,
Toast
.
LENGTH_SHORT
).
show
}
true
case
_
=>
false
}
}
src/main/scala/com/github/shadowsocks/ShadowsocksNotification.scala
View file @
04ec29c9
...
...
@@ -41,8 +41,12 @@ class ShadowsocksNotification(private val service: BaseService, profileName: Str
.
setSmallIcon
(
R
.
drawable
.
ic_stat_shadowsocks
)
.
addAction
(
android
.
R
.
drawable
.
ic_menu_close_clear_cancel
,
service
.
getString
(
R
.
string
.
stop
),
PendingIntent
.
getBroadcast
(
service
,
0
,
new
Intent
(
Action
.
CLOSE
),
0
))
.
addAction
(
android
.
R
.
drawable
.
ic_menu_manage
,
service
.
getString
(
R
.
string
.
quick_switch
),
ShadowsocksApplication
.
profileManager
.
getAllProfiles
match
{
case
Some
(
profiles
)
=>
if
(
profiles
.
length
>
1
)
builder
.
addAction
(
android
.
R
.
drawable
.
ic_menu_manage
,
service
.
getString
(
R
.
string
.
quick_switch
),
PendingIntent
.
getActivity
(
service
,
0
,
new
Intent
(
Action
.
QUICK_SWITCH
),
0
))
case
_
=>
}
private
lazy
val
style
=
new
BigTextStyle
(
builder
)
private
val
showOnUnlock
=
visible
&&
Utils
.
isLollipopOrAbove
private
var
isVisible
=
true
...
...
src/main/scala/com/github/shadowsocks/utils/Constants.scala
View file @
04ec29c9
...
...
@@ -80,6 +80,8 @@ object Key {
val
encMethod
=
"encMethod"
val
remotePort
=
"remotePortNum"
val
localPort
=
"localPortNum"
val
profileTip
=
"profileTip"
}
object
Scheme
{
...
...
src/main/scala/com/github/shadowsocks/utils/Parser.scala
View file @
04ec29c9
...
...
@@ -39,44 +39,35 @@
package
com.github.shadowsocks.utils
import
com.github.shadowsocks.database.Profile
import
java.util.Locale
import
android.net.Uri
import
android.util.
{
Log
,
Base64
}
import
android.util.
{
Base64
,
Log
}
import
com.github.shadowsocks.database.Profile
object
Parser
{
val
TAG
=
"ShadowParser"
private
val
pattern
=
"(?i)ss://([A-Za-z0-9+-/=_]+)"
.
r
def
generate
(
profile
:
Profile
)
:
String
=
"ss://"
+
Base64
.
encodeToString
(
"%s:%s@%s:%d"
.
formatLocal
(
Locale
.
ENGLISH
,
profile
.
method
,
profile
.
password
,
profile
.
host
,
profile
.
remotePort
).
getBytes
,
Base64
.
NO_PADDING
)
profile
.
method
,
profile
.
password
,
profile
.
host
,
profile
.
remotePort
).
getBytes
,
Base64
.
NO_PADDING
|
Base64
.
NO_WRAP
)
def
parse
(
data
:
String
)
:
Option
[
Profile
]
=
{
try
{
Log
.
d
(
TAG
,
data
)
val
uri
=
Uri
.
parse
(
data
.
trim
)
if
(
uri
.
getScheme
==
Scheme
.
SS
)
{
val
encoded
=
data
.
replace
(
Scheme
.
SS
+
"://"
,
""
)
val
content
=
new
String
(
Base64
.
decode
(
encoded
,
Base64
.
NO_PADDING
),
"UTF-8"
)
def
findAll
(
data
:
CharSequence
)
=
pattern
.
findAllMatchIn
(
data
).
map
(
m
=>
try
{
val
content
=
new
String
(
Base64
.
decode
(
m
.
group
(
1
),
Base64
.
NO_PADDING
),
"UTF-8"
)
val
methodIdx
=
content
.
indexOf
(
':'
)
val
passwordIdx
=
content
.
lastIndexOf
(
'@'
)
val
hostIdx
=
content
.
lastIndexOf
(
':'
)
val
method
=
content
.
substring
(
0
,
methodIdx
)
val
password
=
content
.
substring
(
methodIdx
+
1
,
passwordIdx
)
val
host
=
content
.
substring
(
passwordIdx
+
1
,
hostIdx
)
val
port
=
content
.
substring
(
hostIdx
+
1
)
val
profile
=
new
Profile
profile
.
name
=
host
profile
.
host
=
host
profile
.
remotePort
=
port
.
toInt
profile
.
localPort
=
1080
profile
.
method
=
method
.
toLowerCase
profile
.
password
=
password
return
Some
(
profile
)
}
profile
.
remotePort
=
content
.
substring
(
hostIdx
+
1
).
toInt
profile
.
method
=
content
.
substring
(
0
,
methodIdx
).
toLowerCase
profile
.
password
=
content
.
substring
(
methodIdx
+
1
,
passwordIdx
)
profile
}
catch
{
case
ex
:
Exception
=>
Log
.
e
(
TAG
,
"parser error"
,
ex
)
// Ignore
}
None
}
case
ex
:
Exception
=>
Log
.
e
(
TAG
,
"parser error: "
+
m
.
source
,
ex
)
// Ignore
null
}
).
filter
(
_
!=
null
)
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment