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
a2848ce5
Commit
a2848ce5
authored
Sep 29, 2013
by
Max Lv
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
update UI
parent
6f55861d
Changes
12
Show whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
375 additions
and
120 deletions
+375
-120
src/main/res/layout/layout_switch.xml
src/main/res/layout/layout_switch.xml
+2
-1
src/main/res/values/strings.xml
src/main/res/values/strings.xml
+3
-0
src/main/res/xml/pref_proxy.xml
src/main/res/xml/pref_proxy.xml
+6
-0
src/main/scala/com/github/shadowsocks/AppManager.scala
src/main/scala/com/github/shadowsocks/AppManager.scala
+2
-3
src/main/scala/com/github/shadowsocks/Shadowsocks.scala
src/main/scala/com/github/shadowsocks/Shadowsocks.scala
+193
-67
src/main/scala/com/github/shadowsocks/ShadowsocksApplication.scala
...scala/com/github/shadowsocks/ShadowsocksApplication.scala
+0
-1
src/main/scala/com/github/shadowsocks/ShadowsocksService.scala
...ain/scala/com/github/shadowsocks/ShadowsocksService.scala
+2
-12
src/main/scala/com/github/shadowsocks/Utils.scala
src/main/scala/com/github/shadowsocks/Utils.scala
+46
-3
src/main/scala/com/github/shadowsocks/database/DBHelper.scala
...main/scala/com/github/shadowsocks/database/DBHelper.scala
+1
-1
src/main/scala/com/github/shadowsocks/database/MenuAdapter.scala
...n/scala/com/github/shadowsocks/database/MenuAdapter.scala
+31
-17
src/main/scala/com/github/shadowsocks/database/Profile.scala
src/main/scala/com/github/shadowsocks/database/Profile.scala
+14
-8
src/main/scala/com/github/shadowsocks/database/ProfileManager.scala
...cala/com/github/shadowsocks/database/ProfileManager.scala
+75
-7
No files found.
src/main/res/layout/layout_switch.xml
View file @
a2848ce5
...
...
@@ -9,7 +9,7 @@
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:gravity=
"center_vertical"
android:textSize=
"2
2
sp"
android:textSize=
"2
4
sp"
android:textColor=
"@color/title"
android:text=
"@string/app_name"
android:layout_alignParentLeft=
"true"
...
...
@@ -20,6 +20,7 @@
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_alignParentRight=
"true"
android:layout_marginRight =
"10dp"
android:layout_centerVertical=
"true"
/>
</RelativeLayout>
src/main/res/values/strings.xml
View file @
a2848ce5
...
...
@@ -10,6 +10,8 @@
<!-- proxy category -->
<string
name=
"proxy_cat"
>
Server Settings
</string>
<string
name=
"profile"
>
Profile
</string>
<string
name=
"profile_summary"
>
Profile name
</string>
<string
name=
"proxy"
>
Server
</string>
<string
name=
"proxy_summary"
>
Hostname or IP Address of your Shadowsocks server
</string>
<string
name=
"remote_port"
>
Remote Port
</string>
...
...
@@ -73,5 +75,6 @@
<string
name=
"about_title"
>
Shadowsocks %s
</string>
<string
name=
"flush_dnscache"
>
Flush DNS Cache
</string>
<string
name=
"flushing"
>
Flushing
</string>
<string
name=
"add_profile"
>
Add Profile
</string>
</resources>
src/main/res/xml/pref_proxy.xml
View file @
a2848ce5
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
xmlns:android=
"http://schemas.android.com/apk/res/android"
>
<com.github.shadowsocks.preferences.SummaryEditTextPreference
android:defaultValue=
"Default"
android:key=
"profileName"
android:summary=
"@string/profile_summary"
android:title=
"@string/profile"
>
</com.github.shadowsocks.preferences.SummaryEditTextPreference>
<com.github.shadowsocks.preferences.SummaryEditTextPreference
android:defaultValue=
"198.199.101.152"
android:key=
"proxy"
...
...
src/main/scala/com/github/shadowsocks/AppManager.scala
View file @
a2848ce5
...
...
@@ -109,7 +109,6 @@ class AppManager extends SherlockActivity with OnCheckedChangeListener with OnCl
val
MSG_LOAD_START
=
1
val
MSG_LOAD_FINISH
=
2
val
SCHEME
=
"app://"
val
STUB
=
android
.
R
.
drawable
.
sym_def_app_icon
implicit
def
anyrefarray_tools
[
T
<:
AnyRef
](
a
:
Array
[
T
])
=
new
ObjectArrayTools
(
a
)
...
...
@@ -184,7 +183,7 @@ class AppManager extends SherlockActivity with OnCheckedChangeListener with OnCl
.
cacheOnDisc
()
.
displayer
(
new
FadeInBitmapDisplayer
(
300
))
.
build
()
ImageLoader
.
getInstance
().
displayImage
(
"app://"
+
app
.
uid
,
entry
.
icon
,
options
)
ImageLoader
.
getInstance
().
displayImage
(
Scheme
.
APP
+
app
.
uid
,
entry
.
icon
,
options
)
entry
.
text
.
setText
(
app
.
name
)
val
box
:
CheckBox
=
entry
.
box
...
...
@@ -327,7 +326,7 @@ class AppManager extends SherlockActivity with OnCheckedChangeListener with OnCl
}
override
def
getStreamFromOtherSource
(
imageUri
:
String
,
extra
:
AnyRef
)
:
InputStream
=
{
val
uid
=
imageUri
.
substring
(
S
CHEME
.
length
).
toInt
val
uid
=
imageUri
.
substring
(
S
cheme
.
APP
.
length
).
toInt
val
drawable
=
Utils
.
getAppIcon
(
getBaseContext
,
uid
)
val
bitmap
=
Utils
.
drawableToBitmap
(
drawable
)
...
...
src/main/scala/com/github/shadowsocks/Shadowsocks.scala
View file @
a2848ce5
...
...
@@ -41,21 +41,16 @@ package com.github.shadowsocks
import
android.app.
{
Activity
,
AlertDialog
,
ProgressDialog
}
import
android.content._
import
android.content.res.AssetManager
import
android.graphics.
Typeface
import
android.graphics.
{
Color
,
Bitmap
,
Typeface
}
import
android.os._
import
android.preference.
{
Preference
,
PreferenceManager
}
import
android.preference.
_
import
android.util.Log
import
android.view.
{
View
Group
,
Gravity
,
ViewParent
,
KeyEvent
}
import
android.view.
{
View
,
ViewGroup
,
ViewParent
,
KeyEvent
}
import
android.widget._
import
com.actionbarsherlock.view.Menu
import
com.actionbarsherlock.view.MenuItem
import
com.google.analytics.tracking.android.EasyTracker
import
de.keyboardsurfer.android.widget.crouton.Crouton
import
de.keyboardsurfer.android.widget.crouton.Style
import
java.io.FileOutputStream
import
java.io.IOException
import
java.io.InputStream
import
java.io.OutputStream
import
java.io._
import
java.util.Hashtable
import
net.saik0.android.unifiedpreference.UnifiedPreferenceFragment
import
net.saik0.android.unifiedpreference.UnifiedSherlockPreferenceActivity
...
...
@@ -71,21 +66,107 @@ import net.simonvt.menudrawer.MenuDrawer
import
com.github.shadowsocks.database._
import
scala.collection.mutable.ListBuffer
import
com.github.shadowsocks.database.Profile
import
com.nostra13.universalimageloader.core.
{
ImageLoader
,
ImageLoaderConfiguration
}
import
com.nostra13.universalimageloader.core.download.BaseImageDownloader
import
com.github.shadowsocks.database.Item
import
com.github.shadowsocks.database.Category
import
com.actionbarsherlock.view.MenuItem
import
com.github.shadowsocks.preferences.
{
PasswordEditTextPreference
,
SummaryEditTextPreference
}
import
com.github.shadowsocks.database.Item
import
com.github.shadowsocks.database.Profile
import
com.github.shadowsocks.database.Category
import
scala.Option
class
ProfileIconDownloader
(
context
:
Context
,
connectTimeout
:
Int
,
readTimeout
:
Int
)
extends
BaseImageDownloader
(
context
,
connectTimeout
,
readTimeout
)
{
def
this
(
context
:
Context
)
{
this
(
context
,
0
,
0
)
}
override
def
getStreamFromOtherSource
(
imageUri
:
String
,
extra
:
AnyRef
)
:
InputStream
=
{
val
text
=
imageUri
.
substring
(
Scheme
.
PROFILE
.
length
)
val
size
=
Utils
.
dpToPx
(
context
,
16
).
toInt
val
idx
=
text
.
getBytes
.
last
%
6
val
color
=
Seq
(
Color
.
MAGENTA
,
Color
.
GREEN
,
Color
.
YELLOW
,
Color
.
BLUE
,
Color
.
DKGRAY
,
Color
.
CYAN
)(
idx
)
val
bitmap
=
Utils
.
getBitmap
(
text
,
size
,
size
,
color
)
val
os
=
new
ByteArrayOutputStream
()
bitmap
.
compress
(
Bitmap
.
CompressFormat
.
PNG
,
100
,
os
)
new
ByteArrayInputStream
(
os
.
toByteArray
)
}
}
object
Typefaces
{
def
get
(
c
:
Context
,
assetPath
:
String
)
:
Typeface
=
{
cache
synchronized
{
if
(!
cache
.
containsKey
(
assetPath
))
{
try
{
val
t
:
Typeface
=
Typeface
.
createFromAsset
(
c
.
getAssets
,
assetPath
)
cache
.
put
(
assetPath
,
t
)
}
catch
{
case
e
:
Exception
=>
{
Log
.
e
(
TAG
,
"Could not get typeface '"
+
assetPath
+
"' because "
+
e
.
getMessage
)
return
null
}
}
}
return
cache
.
get
(
assetPath
)
}
}
private
final
val
TAG
:
String
=
"Typefaces"
private
final
val
cache
:
Hashtable
[
String
,
Typeface
]
=
new
Hashtable
[
String
,
Typeface
]
}
object
Shadowsocks
{
val
PREFS_NAME
=
"Shadowsocks"
val
PROXY_PREFS
=
Array
(
Key
.
proxy
,
Key
.
remotePort
,
Key
.
localPort
,
Key
.
sitekey
,
Key
.
encMethod
)
val
FEATRUE_PREFS
=
Array
(
Key
.
isGFWList
,
Key
.
isGlobalProxy
,
Key
.
proxyedApps
,
Key
.
is
TrafficStat
,
Key
.
is
AutoConnect
)
val
PROXY_PREFS
=
Array
(
Key
.
pro
fileName
,
Key
.
pro
xy
,
Key
.
remotePort
,
Key
.
localPort
,
Key
.
sitekey
,
Key
.
encMethod
)
val
FEATRUE_PREFS
=
Array
(
Key
.
isGFWList
,
Key
.
isGlobalProxy
,
Key
.
proxyedApps
,
Key
.
isTrafficStat
,
Key
.
isAutoConnect
)
val
TAG
=
"Shadowsocks"
val
REQUEST_CONNECT
=
1
private
var
vpnEnabled
=
-
1
var
currentProfile
:
Profile
=
null
def
updateListPreference
(
pref
:
Preference
,
value
:
String
)
{
pref
.
setSummary
(
value
)
pref
.
asInstanceOf
[
ListPreference
].
setValue
(
value
)
}
def
updatePasswordEditTextPreference
(
pref
:
Preference
,
value
:
String
)
{
pref
.
setSummary
(
value
)
pref
.
asInstanceOf
[
PasswordEditTextPreference
].
setText
(
value
)
}
def
updateSummaryEditTextPreference
(
pref
:
Preference
,
value
:
String
)
{
pref
.
setSummary
(
value
)
pref
.
asInstanceOf
[
SummaryEditTextPreference
].
setText
(
value
)
}
def
updateCheckBoxPreference
(
pref
:
Preference
,
value
:
Boolean
)
{
pref
.
asInstanceOf
[
CheckBoxPreference
].
setChecked
(
value
)
}
def
updatePreference
(
pref
:
Preference
,
name
:
String
,
profile
:
Profile
)
{
name
match
{
case
Key
.
profileName
=>
updateSummaryEditTextPreference
(
pref
,
profile
.
name
)
case
Key
.
proxy
=>
updateSummaryEditTextPreference
(
pref
,
profile
.
host
)
case
Key
.
remotePort
=>
updateSummaryEditTextPreference
(
pref
,
profile
.
remotePort
.
toString
)
case
Key
.
localPort
=>
updateSummaryEditTextPreference
(
pref
,
profile
.
localPort
.
toString
)
case
Key
.
sitekey
=>
updatePasswordEditTextPreference
(
pref
,
profile
.
password
)
case
Key
.
encMethod
=>
updateListPreference
(
pref
,
profile
.
method
)
case
Key
.
isGFWList
=>
updateCheckBoxPreference
(
pref
,
profile
.
chnroute
)
case
Key
.
isGlobalProxy
=>
updateCheckBoxPreference
(
pref
,
profile
.
global
)
case
Key
.
isTrafficStat
=>
updateCheckBoxPreference
(
pref
,
profile
.
traffic
)
case
_
=>
}
}
def
isServiceStarted
(
context
:
Context
)
:
Boolean
=
{
ShadowsocksService
.
isServiceStarted
(
context
)
||
ShadowVpnService
.
isServiceStarted
(
context
)
}
...
...
@@ -105,6 +186,13 @@ object Shadowsocks {
}
}
private
def
updatePreferenceScreen
()
{
for
(
name
<-
Shadowsocks
.
PROXY_PREFS
)
{
val
pref
=
findPreference
(
name
)
Shadowsocks
.
updatePreference
(
pref
,
name
,
Shadowsocks
.
currentProfile
)
}
}
override
def
onCreate
(
bundle
:
Bundle
)
{
super
.
onCreate
(
bundle
)
val
filter
=
new
IntentFilter
()
...
...
@@ -112,6 +200,7 @@ object Shadowsocks {
receiver
=
new
BroadcastReceiver
{
def
onReceive
(
p1
:
Context
,
p2
:
Intent
)
{
setPreferenceEnabled
()
updatePreferenceScreen
()
}
}
getActivity
.
getApplicationContext
.
registerReceiver
(
receiver
,
filter
)
...
...
@@ -132,7 +221,7 @@ object Shadowsocks {
}
}
class
FeatureFragment
extends
UnifiedPreferenceFragment
with
OnSharedPreferenceChangeListener
{
class
FeatureFragment
extends
UnifiedPreferenceFragment
{
var
receiver
:
BroadcastReceiver
=
null
...
...
@@ -144,8 +233,8 @@ object Shadowsocks {
if
(
pref
!=
null
)
{
val
status
=
getActivity
.
getSharedPreferences
(
Key
.
status
,
Context
.
MODE_PRIVATE
)
val
isRoot
=
status
.
getBoolean
(
Key
.
isRoot
,
false
)
if
(
Seq
(
Key
.
isAutoConnect
,
Key
.
isGlobalProxy
,
Key
.
isTrafficStat
,
Key
.
proxyedApps
)
.
contains
(
name
))
{
if
(
Seq
(
Key
.
isAutoConnect
,
Key
.
isGlobalProxy
,
Key
.
isTrafficStat
,
Key
.
proxyedApps
)
.
contains
(
name
))
{
pref
.
setEnabled
(
enabled
&&
isRoot
)
}
else
{
pref
.
setEnabled
(
enabled
)
...
...
@@ -154,6 +243,13 @@ object Shadowsocks {
}
}
private
def
updatePreferenceScreen
()
{
for
(
name
<-
Shadowsocks
.
FEATRUE_PREFS
)
{
val
pref
=
findPreference
(
name
)
Shadowsocks
.
updatePreference
(
pref
,
name
,
Shadowsocks
.
currentProfile
)
}
}
override
def
onCreate
(
bundle
:
Bundle
)
{
super
.
onCreate
(
bundle
)
val
filter
=
new
IntentFilter
()
...
...
@@ -161,6 +257,7 @@ object Shadowsocks {
receiver
=
new
BroadcastReceiver
{
def
onReceive
(
p1
:
Context
,
p2
:
Intent
)
{
setPreferenceEnabled
()
updatePreferenceScreen
()
}
}
getActivity
.
getApplicationContext
.
registerReceiver
(
receiver
,
filter
)
...
...
@@ -179,40 +276,15 @@ object Shadowsocks {
override
def
onPause
()
{
super
.
onPause
()
}
def
onSharedPreferenceChanged
(
prefs
:
SharedPreferences
,
key
:
String
)
{
if
(
key
==
Key
.
isGlobalProxy
)
setPreferenceEnabled
()
}
}
}
object
Typefaces
{
def
get
(
c
:
Context
,
assetPath
:
String
)
:
Typeface
=
{
cache
synchronized
{
if
(!
cache
.
containsKey
(
assetPath
))
{
try
{
val
t
:
Typeface
=
Typeface
.
createFromAsset
(
c
.
getAssets
,
assetPath
)
cache
.
put
(
assetPath
,
t
)
}
catch
{
case
e
:
Exception
=>
{
Log
.
e
(
TAG
,
"Could not get typeface '"
+
assetPath
+
"' because "
+
e
.
getMessage
)
return
null
}
}
}
return
cache
.
get
(
assetPath
)
}
}
private
final
val
TAG
:
String
=
"Typefaces"
private
final
val
cache
:
Hashtable
[
String
,
Typeface
]
=
new
Hashtable
[
String
,
Typeface
]
}
class
Shadowsocks
extends
UnifiedSherlockPreferenceActivity
with
CompoundButton
.
OnCheckedChangeListener
with
OnSharedPreferenceChangeListener
{
with
OnSharedPreferenceChangeListener
with
MenuAdapter
.
MenuListener
{
private
val
MSG_CRASH_RECOVER
:
Int
=
1
private
val
MSG_INITIAL_FINISH
:
Int
=
2
...
...
@@ -227,9 +299,9 @@ class Shadowsocks
lazy
val
status
=
getSharedPreferences
(
Key
.
status
,
Context
.
MODE_PRIVATE
)
lazy
val
receiver
=
new
StateBroadcastReceiver
lazy
val
drawer
=
MenuDrawer
.
attach
(
this
)
lazy
val
listView
=
new
ListView
(
this
)
lazy
val
menuAdapter
=
new
MenuAdapter
(
this
,
getMenuList
)
lazy
val
profileManager
=
getApplication
.
asInstanceOf
[
ShadowsocksApplication
].
profileManager
lazy
val
listView
=
new
ListView
(
this
)
lazy
val
profileManager
=
new
ProfileManager
(
settings
,
getApplication
.
asInstanceOf
[
ShadowsocksApplication
].
dbHelper
)
private
val
handler
:
Handler
=
new
Handler
{
override
def
handleMessage
(
msg
:
Message
)
{
...
...
@@ -291,10 +363,10 @@ class Shadowsocks
}
}
def
onSharedPreferenceChanged
(
prefs
:
SharedPreferences
,
key
:
String
)
{
if
(
key
==
Key
.
isGlobalProxy
)
{
val
enabled
=
state
!=
State
.
CONNECTED
&&
state
!=
State
.
CONNECTING
setPreferenceEnabled
(
enable
d
)
override
def
onSharedPreferenceChanged
(
prefs
:
SharedPreferences
,
key
:
String
)
{
if
(
key
==
Key
.
profileName
)
{
profileManager
.
save
()
menuAdapter
.
updateList
(
getMenuList
,
Shadowsocks
.
currentProfile
.
i
d
)
}
}
...
...
@@ -407,6 +479,10 @@ class Shadowsocks
setHeaderRes
(
R
.
xml
.
shadowsocks_headers
)
super
.
onCreate
(
savedInstanceState
)
Shadowsocks
.
currentProfile
=
{
profileManager
.
getProfile
(
settings
.
getInt
(
Key
.
profileId
,
-
1
))
getOrElse
new
Profile
()
}
listView
.
setAdapter
(
menuAdapter
)
drawer
.
setMenuView
(
listView
)
...
...
@@ -422,7 +498,6 @@ class Shadowsocks
getSupportActionBar
.
setDisplayShowTitleEnabled
(
false
)
getSupportActionBar
.
setDisplayShowCustomEnabled
(
true
)
// getSupportActionBar.setDisplayShowHomeEnabled(false)
val
title
:
TextView
=
switchLayout
.
findViewById
(
R
.
id
.
title
).
asInstanceOf
[
TextView
]
val
tf
:
Typeface
=
Typefaces
.
get
(
this
,
"fonts/Iceland.ttf"
)
if
(
tf
!=
null
)
title
.
setTypeface
(
tf
)
...
...
@@ -445,16 +520,49 @@ class Shadowsocks
handler
.
sendEmptyMessage
(
MSG_INITIAL_FINISH
)
}
}
}
override
def
onActiveViewChanged
(
v
:
View
,
pos
:
Int
)
{
drawer
.
setActiveView
(
v
,
pos
)
}
def
updateProfile
(
id
:
Int
)
{
drawer
.
closeMenu
(
true
)
handler
.
postDelayed
(
new
Runnable
{
def
run
()
{
Shadowsocks
.
currentProfile
=
profileManager
.
load
(
id
)
updatePreferenceScreen
()
}
},
600
)
if
(!
isSinglePane
)
sendBroadcast
(
new
Intent
(
Action
.
UPDATE_FRAGMENT
))
}
def
delProfile
(
id
:
Int
)
:
Boolean
=
{
drawer
.
closeMenu
(
true
)
handler
.
postDelayed
(
new
Runnable
{
def
run
()
{
profileManager
.
delProfile
(
id
)
val
profileId
=
{
val
profiles
=
profileManager
.
getAllProfiles
.
getOrElse
(
List
[
Profile
]())
if
(
profiles
.
isEmpty
)
-
1
else
profiles
(
0
).
id
}
Shadowsocks
.
currentProfile
=
profileManager
.
load
(
profileId
)
updatePreferenceScreen
()
menuAdapter
.
updateList
(
getMenuList
,
Shadowsocks
.
currentProfile
.
id
)
}
},
600
)
if
(!
isSinglePane
)
sendBroadcast
(
new
Intent
(
Action
.
UPDATE_FRAGMENT
))
true
}
def
getProfileList
:
List
[
Item
]
=
{
val
list
=
profileManager
.
getAllProfiles
getOrElse
List
[
Profile
]()
list
.
map
(
p
=>
new
Item
(
p
.
id
,
p
.
name
,
-
1
,
updateProfile
))
list
.
map
(
p
=>
new
Item
(
p
.
id
,
p
.
name
,
-
1
,
updateProfile
,
delProfile
))
}
def
getMenuList
:
List
[
Any
]
=
{
...
...
@@ -465,28 +573,31 @@ class Shadowsocks
buf
++=
getProfileList
buf
+=
new
Item
(-
1
,
getString
(
R
.
string
.
add_profile
),
android
.
R
.
drawable
.
ic_menu_add
,
_
=>
{
updateProfile
(-
1
)
profileManager
.
save
()
menuAdapter
.
updateList
(
getMenuList
,
Shadowsocks
.
currentProfile
.
id
)
})
buf
+=
new
Category
(
"Settings"
)
buf
+=
new
Item
(-
1
,
getString
(
R
.
string
.
recovery
),
android
.
R
.
drawable
.
ic_menu_revert
,
_
=>
{
buf
+=
new
Item
(-
100
,
getString
(
R
.
string
.
recovery
),
android
.
R
.
drawable
.
ic_menu_revert
,
_
=>
{
EasyTracker
.
getTracker
.
sendEvent
(
Shadowsocks
.
TAG
,
"reset"
,
getVersionName
,
0L
)
recovery
()
})
buf
+=
new
Item
(-
2
,
getString
(
R
.
string
.
flush_dnscache
),
android
.
R
.
drawable
.
ic_menu_delete
,
_
=>
{
buf
+=
new
Item
(-
200
,
getString
(
R
.
string
.
flush_dnscache
),
android
.
R
.
drawable
.
ic_menu_delete
,
_
=>
{
EasyTracker
.
getTracker
.
sendEvent
(
Shadowsocks
.
TAG
,
"flush_dnscache"
,
getVersionName
,
0L
)
flushDnsCache
()
})
buf
+=
new
Item
(-
3
,
getString
(
R
.
string
.
about
),
android
.
R
.
drawable
.
ic_menu_info_details
,
_
=>
{
buf
+=
new
Item
(-
300
,
getString
(
R
.
string
.
about
),
android
.
R
.
drawable
.
ic_menu_info_details
,
_
=>
{
EasyTracker
.
getTracker
.
sendEvent
(
Shadowsocks
.
TAG
,
"about"
,
getVersionName
,
0L
)
showAbout
()
})
buf
.
toList
}
override
def
onKeyDown
(
keyCode
:
Int
,
event
:
KeyEvent
)
:
Boolean
=
{
...
...
@@ -516,6 +627,7 @@ class Shadowsocks
protected
override
def
onPause
()
{
super
.
onPause
()
prepared
=
false
settings
.
unregisterOnSharedPreferenceChangeListener
(
this
)
}
protected
override
def
onResume
()
{
...
...
@@ -549,6 +661,8 @@ class Shadowsocks
}
switchButton
.
setOnCheckedChangeListener
(
this
)
settings
.
registerOnSharedPreferenceChangeListener
(
this
)
}
private
def
setPreferenceEnabled
(
enabled
:
Boolean
)
{
...
...
@@ -562,8 +676,8 @@ class Shadowsocks
for
(
name
<-
Shadowsocks
.
FEATRUE_PREFS
)
{
val
pref
=
findPreference
(
name
)
if
(
pref
!=
null
)
{
if
(
Seq
(
Key
.
isAutoConnect
,
Key
.
isGlobalProxy
,
Key
.
isTrafficStat
,
Key
.
proxyedApps
)
.
contains
(
name
))
{
if
(
Seq
(
Key
.
isAutoConnect
,
Key
.
isGlobalProxy
,
Key
.
isTrafficStat
,
Key
.
proxyedApps
)
.
contains
(
name
))
{
pref
.
setEnabled
(
enabled
&&
isRoot
)
}
else
{
pref
.
setEnabled
(
enabled
)
...
...
@@ -572,6 +686,18 @@ class Shadowsocks
}
}
private
def
updatePreferenceScreen
()
{
val
profile
=
Shadowsocks
.
currentProfile
for
(
name
<-
Shadowsocks
.
PROXY_PREFS
)
{
val
pref
=
findPreference
(
name
)
Shadowsocks
.
updatePreference
(
pref
,
name
,
profile
)
}
for
(
name
<-
Shadowsocks
.
FEATRUE_PREFS
)
{
val
pref
=
findPreference
(
name
)
Shadowsocks
.
updatePreference
(
pref
,
name
,
profile
)
}
}
override
def
onStart
()
{
super
.
onStart
()
EasyTracker
.
getInstance
.
activityStart
(
this
)
...
...
@@ -790,7 +916,7 @@ class Shadowsocks
setPreferenceEnabled
(
enabled
=
true
)
}
}
sendBroadcast
(
new
Intent
(
Action
.
UPDATE_FRAGMENT
))
if
(!
isSinglePane
)
sendBroadcast
(
new
Intent
(
Action
.
UPDATE_FRAGMENT
))
}
}
...
...
src/main/scala/com/github/shadowsocks/ShadowsocksApplication.scala
View file @
a2848ce5
...
...
@@ -44,7 +44,6 @@ import com.github.shadowsocks.database.{ProfileManager, DBHelper}
class
ShadowsocksApplication
extends
Application
{
lazy
val
dbHelper
=
new
DBHelper
(
this
)
lazy
val
profileManager
=
new
ProfileManager
(
dbHelper
)
override
def
onCreate
()
{
EasyTracker
.
getInstance
.
setContext
(
this
)
...
...
src/main/scala/com/github/shadowsocks/ShadowsocksService.scala
View file @
a2848ce5
...
...
@@ -324,18 +324,8 @@ class ShadowsocksService extends Service {
val
icon
=
getResources
.
getDrawable
(
R
.
drawable
.
ic_stat_shadowsocks
)
if
(
rate
>=
0
)
{
val
bitmap
=
Bitmap
.
createBitmap
(
icon
.
getIntrinsicWidth
*
4
,
icon
.
getIntrinsicHeight
*
4
,
Bitmap
.
Config
.
ARGB_8888
)
val
r
=
rate
.
toString
val
size
=
bitmap
.
getHeight
/
4
val
canvas
=
new
Canvas
(
bitmap
)
val
paint
=
new
Paint
()
paint
.
setColor
(
Color
.
WHITE
)
paint
.
setTextSize
(
size
)
val
bounds
=
new
Rect
()
paint
.
getTextBounds
(
r
,
0
,
r
.
length
,
bounds
)
canvas
.
drawText
(
r
,
(
bitmap
.
getWidth
-
bounds
.
width
())
/
2
,
bitmap
.
getHeight
-
(
bitmap
.
getHeight
-
bounds
.
height
())
/
2
,
paint
)
val
bitmap
=
Utils
.
getBitmap
(
rate
.
toString
,
icon
.
getIntrinsicWidth
*
4
,
icon
.
getIntrinsicHeight
*
4
,
Color
.
TRANSPARENT
)
builder
.
setLargeIcon
(
bitmap
)
if
(
rate
<
1000
)
{
...
...
src/main/scala/com/github/shadowsocks/Utils.scala
View file @
a2848ce5
...
...
@@ -49,10 +49,11 @@ import org.apache.http.conn.util.InetAddressUtils
import
scala.collection.mutable.ArrayBuffer
import
org.xbill.DNS._
import
scala.Some
import
android.graphics.
{
Canvas
,
Bitmap
}
import
android.graphics.
_
import
android.app.ActivityManager
import
android.os.Build
import
android.provider.Settings
import
scala.Some
object
Config
{
val
SHADOWSOCKS
=
"{\"server\": [%s], \"server_port\": %d, \"local_port\": %d, \"password\": %s, \"timeout\": %d}"
...
...
@@ -112,10 +113,13 @@ object Config {
}
case
class
Config
(
isGlobalProxy
:
Boolean
,
isGFWList
:
Boolean
,
isBypassApps
:
Boolean
,
isTrafficStat
:
Boolean
,
var
proxy
:
String
,
sitekey
:
String
,
encMethod
:
String
,
remotePort
:
Int
,
profileName
:
String
,
var
proxy
:
String
,
sitekey
:
String
,
encMethod
:
String
,
remotePort
:
Int
,
localPort
:
Int
,
proxiedAppString
:
String
)
object
Key
{
val
profileId
=
"profileId"
val
profileName
=
"profileName"
val
proxied
=
"Proxyed"
val
isRoot
=
"isRoot"
...
...
@@ -137,6 +141,11 @@ object Key {
val
localPort
=
"port"
}
object
Scheme
{
val
APP
=
"app://"
val
PROFILE
=
"profile://"
}
object
State
{
val
INIT
=
0
val
CONNECTING
=
1
...
...
@@ -162,6 +171,7 @@ object Extra {
edit
.
putBoolean
(
Key
.
isBypassApps
,
config
.
isBypassApps
)
edit
.
putBoolean
(
Key
.
isTrafficStat
,
config
.
isTrafficStat
)
edit
.
putString
(
Key
.
profileName
,
config
.
profileName
)
edit
.
putString
(
Key
.
proxy
,
config
.
proxy
)
edit
.
putString
(
Key
.
sitekey
,
config
.
sitekey
)
edit
.
putString
(
Key
.
encMethod
,
config
.
encMethod
)
...
...
@@ -177,6 +187,7 @@ object Extra {
val
isBypassApps
=
intent
.
getBooleanExtra
(
Key
.
isBypassApps
,
false
)
val
isTrafficStat
=
intent
.
getBooleanExtra
(
Key
.
isTrafficStat
,
false
)
val
profileName
=
intent
.
getStringExtra
(
Key
.
profileName
)
val
proxy
=
intent
.
getStringExtra
(
Key
.
proxy
)
val
sitekey
=
intent
.
getStringExtra
(
Key
.
sitekey
)
val
encMethod
=
intent
.
getStringExtra
(
Key
.
encMethod
)
...
...
@@ -184,7 +195,7 @@ object Extra {
val
localPort
=
intent
.
getIntExtra
(
Key
.
localPort
,
1984
)
val
proxiedString
=
intent
.
getStringExtra
(
Key
.
proxied
)
new
Config
(
isGlobalProxy
,
isGFWList
,
isBypassApps
,
isTrafficStat
,
proxy
,
sitekey
,
encMethod
,
remotePort
,
new
Config
(
isGlobalProxy
,
isGFWList
,
isBypassApps
,
isTrafficStat
,
pro
fileName
,
pro
xy
,
sitekey
,
encMethod
,
remotePort
,
localPort
,
proxiedString
)
}
...
...
@@ -194,6 +205,7 @@ object Extra {
val
isBypassApps
=
settings
.
getBoolean
(
Key
.
isBypassApps
,
false
)
val
isTrafficStat
=
settings
.
getBoolean
(
Key
.
isTrafficStat
,
false
)
val
profileName
=
settings
.
getString
(
Key
.
profileName
,
"default"
)
val
proxy
=
settings
.
getString
(
Key
.
proxy
,
"127.0.0.1"
)
match
{
case
"198.199.101.152"
=>
BuildConfig
.
SERVER
case
s
:
String
=>
s
...
...
@@ -232,6 +244,7 @@ object Extra {
intent
.
putExtra
(
Key
.
isBypassApps
,
isBypassApps
)
intent
.
putExtra
(
Key
.
isTrafficStat
,
isTrafficStat
)
intent
.
putExtra
(
Key
.
profileName
,
profileName
)
intent
.
putExtra
(
Key
.
proxy
,
proxy
)
intent
.
putExtra
(
Key
.
sitekey
,
sitekey
)
intent
.
putExtra
(
Key
.
encMethod
,
encMethod
)
...
...
@@ -265,6 +278,36 @@ object Utils {
var
data_path
:
String
=
null
var
rootTries
=
0
/*
* round or floor depending on whether you are using offsets(floor) or
* widths(round)
*/
def
dpToPx
(
context
:
Context
,
dp
:
Float
)
:
Float
=
{
val
density
=
context
.
getResources
.
getDisplayMetrics
.
density
dp
*
density
}
def
pxToDp
(
context
:
Context
,
px
:
Float
)
:
Float
=
{
val
density
=
context
.
getResources
.
getDisplayMetrics
.
density
px
/
density
}
def
getBitmap
(
text
:
String
,
width
:
Int
,
height
:
Int
,
background
:
Int
)
:
Bitmap
=
{
val
bitmap
=
Bitmap
.
createBitmap
(
width
,
height
,
Bitmap
.
Config
.
ARGB_8888
)
val
size
=
bitmap
.
getHeight
/
4
val
canvas
=
new
Canvas
(
bitmap
)
canvas
.
drawColor
(
background
)
val
paint
=
new
Paint
()
paint
.
setColor
(
Color
.
WHITE
)
paint
.
setTextSize
(
size
)
val
bounds
=
new
Rect
()
paint
.
getTextBounds
(
text
,
0
,
text
.
length
,
bounds
)
canvas
.
drawText
(
text
,
(
bitmap
.
getWidth
-
bounds
.
width
())
/
2
,
bitmap
.
getHeight
-
(
bitmap
.
getHeight
-
bounds
.
height
())
/
2
,
paint
)
bitmap
}
// Blocked > 3 seconds
def
toggleAirplaneMode
(
context
:
Context
)
{
if
(
Build
.
VERSION
.
SDK_INT
>=
17
)
{
...
...
src/main/scala/com/github/shadowsocks/database/DBHelper.scala
View file @
a2848ce5
...
...
@@ -46,7 +46,7 @@ import com.j256.ormlite.support.ConnectionSource
import
com.j256.ormlite.table.TableUtils
import
com.j256.ormlite.dao.Dao
class
DBHelper
(
val
context
:
Context
)
extends
OrmLiteSqliteOpenHelper
(
context
,
"profile.db"
,
null
,
3
)
{
class
DBHelper
(
val
context
:
Context
)
extends
OrmLiteSqliteOpenHelper
(
context
,
"profile.db"
,
null
,
7
)
{
lazy
val
profileDao
:
Dao
[
Profile
,
Int
]
=
getDao
(
classOf
[
Profile
])
...
...
src/main/scala/com/github/shadowsocks/database/MenuAdapter.scala
View file @
a2848ce5
...
...
@@ -39,39 +39,39 @@
package
com.github.shadowsocks.database
import
android.content.
{
DialogInterface
,
Context
}
import
android.content.
Context
import
android.view.LayoutInflater
import
android.view.View
import
android.view.ViewGroup
import
android.widget.BaseAdapter
import
android.widget.TextView
import
com.github.shadowsocks.
R
import
android.view.View.
OnClickListener
import
com.github.shadowsocks.
{
Shadowsocks
,
R
}
import
android.view.View.
{
OnLongClickListener
,
OnClickListener
}
case
class
Item
(
id
:
Int
,
title
:
String
,
iconRes
:
Int
,
action
:
Int
=>
Unit
)
case
class
Item
(
id
:
Int
,
title
:
String
,
iconRes
:
Int
,
click
:
Int
=>
Unit
,
longClick
:
Int
=>
Boolean
=
_
=>
false
)
case
class
Category
(
title
:
String
)
case
class
Category
(
title
:
String
)
object
MenuAdapter
{
trait
MenuListener
{
def
onActiveViewChanged
(
v
:
View
)
def
onActiveViewChanged
(
v
:
View
,
pos
:
Int
)
}
val
UNDEFINED
=
-
1
val
CATEGORY
=
0
val
ITEM
=
1
}
class
MenuAdapter
(
context
:
Context
,
var
items
:
List
[
Any
])
extends
BaseAdapter
{
class
MenuAdapter
(
context
:
Context
,
var
items
:
List
[
Any
])
extends
BaseAdapter
{
def
setListener
(
listener
:
MenuAdapter.MenuListener
)
{
mL
istener
=
listener
this
.
l
istener
=
listener
}
def
setActivePosition
(
activePosition
:
Int
)
{
mA
ctivePosition
=
activePosition
this
.
a
ctivePosition
=
activePosition
}
@Override
def
getCount
:
Int
=
{
...
...
@@ -121,32 +121,46 @@ class MenuAdapter (context: Context, var items: List[Any]) extends BaseAdapter {
}
val
tv
:
TextView
=
v
.
asInstanceOf
[
TextView
]
tv
.
setText
(
value
.
title
)
if
(
value
.
iconRes
!=
-
1
)
{
tv
.
setCompoundDrawablesWithIntrinsicBounds
(
value
.
iconRes
,
0
,
0
,
0
)
}
tv
.
setOnClickListener
(
new
OnClickListener
{
def
onClick
(
view
:
View
)
{
val
item
=
view
.
getTag
(
R
.
id
.
mdItem
).
asInstanceOf
[
Item
]
item
.
action
(
item
.
id
)
item
.
click
(
item
.
id
)
}
})
tv
.
setOnLongClickListener
(
new
OnLongClickListener
{
def
onLongClick
(
view
:
View
)
:
Boolean
=
{
val
item
=
view
.
getTag
(
R
.
id
.
mdItem
).
asInstanceOf
[
Item
]
item
.
longClick
(
item
.
id
)
}
})
v
.
setTag
(
R
.
id
.
mdItem
,
value
)
case
_
=>
}
v
.
setTag
(
R
.
id
.
mdActiveViewPosition
,
position
)
if
(
position
==
mA
ctivePosition
)
{
if
(
mListener
!=
null
)
mListener
.
onActiveViewChanged
(
v
)
if
(
position
==
a
ctivePosition
)
{
if
(
listener
!=
null
)
listener
.
onActiveViewChanged
(
v
,
position
)
}
v
}
def
updateList
(
list
:
List
[
Any
])
{
def
updateList
(
list
:
List
[
Any
]
,
activeId
:
Int
)
{
items
=
list
activePosition
=
items
.
indexWhere
{
case
item
:
Item
=>
item
.
id
==
activeId
case
_
=>
false
}
notifyDataSetChanged
()
}
private
var
mL
istener
:
MenuAdapter.MenuListener
=
null
private
var
mActivePosition
:
Int
=
0
private
var
l
istener
:
MenuAdapter.MenuListener
=
null
private
var
activePosition
:
Int
=
-
1
}
src/main/scala/com/github/shadowsocks/database/Profile.scala
View file @
a2848ce5
...
...
@@ -42,14 +42,14 @@ package com.github.shadowsocks.database
import
com.j256.ormlite.field.
{
DataType
,
DatabaseField
}
class
Profile
{
@DatabaseField
(
i
d
=
true
)
@DatabaseField
(
generatedI
d
=
true
)
var
id
:
Int
=
0
@DatabaseField
var
name
:
String
=
null
var
name
:
String
=
"Untitled"
@DatabaseField
var
host
:
String
=
null
var
host
:
String
=
""
@DatabaseField
var
localPort
:
Int
=
0
...
...
@@ -58,13 +58,13 @@ class Profile {
var
remotePort
:
Int
=
0
@DatabaseField
var
password
:
String
=
null
var
password
:
String
=
""
@DatabaseField
var
method
:
String
=
null
var
method
:
String
=
""
@DatabaseField
var
date
:
String
=
null
var
date
:
String
=
""
@DatabaseField
var
upload
:
Int
=
0
...
...
@@ -78,9 +78,15 @@ class Profile {
@DatabaseField
var
global
:
Boolean
=
false
@DatabaseField
var
bypass
:
Boolean
=
false
@DatabaseField
var
traffic
:
Boolean
=
false
@DatabaseField
(
dataType
=
DataType
.
LONG_STRING
)
var
individual
:
String
=
null
var
individual
:
String
=
""
@DatabaseField
(
dataType
=
DataType
.
LONG_STRING
)
var
description
:
String
=
null
var
description
:
String
=
""
}
src/main/scala/com/github/shadowsocks/database/ProfileManager.scala
View file @
a2848ce5
...
...
@@ -40,18 +40,20 @@
package
com.github.shadowsocks.database
import
android.util.Log
import
com.github.shadowsocks.Shadowsocks
import
com.github.shadowsocks._
import
android.content.
{
SharedPreferences
,
Context
}
class
ProfileManager
(
dbHelper
:
DBHelper
)
{
def
addProfile
(
profile
:
Profile
)
:
Boolean
=
{
class
ProfileManager
(
settings
:
SharedPreferences
,
dbHelper
:
DBHelper
)
{
def
createOrUpdateProfile
(
profile
:
Profile
)
:
Boolean
=
{
try
{
dbHelper
.
profileDao
.
createOrUpdate
(
profile
)
true
}
catch
{
case
ex
:
Exception
=>
Log
.
e
(
Shadowsocks
.
TAG
,
"addProfile"
,
ex
)
return
false
false
}
true
}
def
getProfile
(
id
:
Int
)
:
Option
[
Profile
]
=
{
...
...
@@ -70,12 +72,12 @@ class ProfileManager(dbHelper: DBHelper) {
def
delProfile
(
id
:
Int
)
:
Boolean
=
{
try
{
dbHelper
.
profileDao
.
deleteById
(
id
)
true
}
catch
{
case
ex
:
Exception
=>
Log
.
e
(
Shadowsocks
.
TAG
,
"delProfile"
,
ex
)
return
false
false
}
true
}
def
getAllProfiles
:
Option
[
List
[
Profile
]]
=
{
...
...
@@ -88,4 +90,70 @@ class ProfileManager(dbHelper: DBHelper) {
None
}
}
def
load
(
id
:
Int
)
:
Profile
=
{
Log
.
d
(
Shadowsocks
.
TAG
,
id
+
" "
)
save
()
val
profile
=
getProfile
(
id
)
getOrElse
{
val
p
=
new
Profile
()
createOrUpdateProfile
(
p
)
p
}
Log
.
d
(
Shadowsocks
.
TAG
,
"load "
+
profile
.
id
+
" "
+
profile
.
name
)
val
edit
=
settings
.
edit
()
edit
.
putBoolean
(
Key
.
isGlobalProxy
,
profile
.
global
)
edit
.
putBoolean
(
Key
.
isGFWList
,
profile
.
chnroute
)
edit
.
putBoolean
(
Key
.
isBypassApps
,
profile
.
bypass
)
edit
.
putBoolean
(
Key
.
isTrafficStat
,
profile
.
traffic
)
edit
.
putString
(
Key
.
profileName
,
profile
.
name
)
edit
.
putString
(
Key
.
proxy
,
profile
.
host
)
edit
.
putString
(
Key
.
sitekey
,
profile
.
password
)
edit
.
putString
(
Key
.
encMethod
,
profile
.
method
)
edit
.
putString
(
Key
.
remotePort
,
profile
.
remotePort
.
toString
)
edit
.
putString
(
Key
.
localPort
,
profile
.
localPort
.
toString
)
edit
.
putString
(
Key
.
proxied
,
profile
.
individual
)
edit
.
putInt
(
Key
.
profileId
,
profile
.
id
)
edit
.
commit
()
profile
}
def
save
()
{
val
profile
=
new
Profile
()
profile
.
global
=
settings
.
getBoolean
(
Key
.
isGlobalProxy
,
false
)
profile
.
chnroute
=
settings
.
getBoolean
(
Key
.
isGFWList
,
false
)
profile
.
bypass
=
settings
.
getBoolean
(
Key
.
isBypassApps
,
false
)
profile
.
traffic
=
settings
.
getBoolean
(
Key
.
isTrafficStat
,
false
)
profile
.
name
=
settings
.
getString
(
Key
.
profileName
,
"default"
)
profile
.
host
=
settings
.
getString
(
Key
.
proxy
,
"127.0.0.1"
)
profile
.
password
=
settings
.
getString
(
Key
.
sitekey
,
"default"
)
profile
.
method
=
settings
.
getString
(
Key
.
encMethod
,
"table"
)
profile
.
remotePort
=
try
{
Integer
.
valueOf
(
settings
.
getString
(
Key
.
remotePort
,
"1984"
))
}
catch
{
case
ex
:
NumberFormatException
=>
{
1984
}
}
profile
.
localPort
=
try
{
Integer
.
valueOf
(
settings
.
getString
(
Key
.
localPort
,
"1984"
))
}
catch
{
case
ex
:
NumberFormatException
=>
{
1984
}
}
profile
.
individual
=
settings
.
getString
(
Key
.
proxied
,
""
)
profile
.
id
=
settings
.
getInt
(
Key
.
profileId
,
-
1
)
Log
.
d
(
Shadowsocks
.
TAG
,
"save "
+
profile
.
id
+
" "
+
profile
.
name
)
createOrUpdateProfile
(
profile
)
}
}
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