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
99d97d1d
Commit
99d97d1d
authored
Jan 20, 2017
by
Mygod
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix launching plugin
parent
b78c10e8
Changes
21
Show whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
213 additions
and
159 deletions
+213
-159
mobile/build.sbt
mobile/build.sbt
+0
-6
mobile/src/main/res/values/dimen.xml
mobile/src/main/res/values/dimen.xml
+1
-1
mobile/src/main/scala/com/github/shadowsocks/ProfileConfigFragment.scala
.../scala/com/github/shadowsocks/ProfileConfigFragment.scala
+33
-19
mobile/src/main/scala/com/github/shadowsocks/plugin/NativePlugin.scala
...in/scala/com/github/shadowsocks/plugin/NativePlugin.scala
+12
-9
mobile/src/main/scala/com/github/shadowsocks/plugin/Plugin.scala
...src/main/scala/com/github/shadowsocks/plugin/Plugin.scala
+1
-0
mobile/src/main/scala/com/github/shadowsocks/plugin/PluginConfiguration.scala
...a/com/github/shadowsocks/plugin/PluginConfiguration.scala
+6
-2
mobile/src/main/scala/com/github/shadowsocks/plugin/PluginManager.scala
...n/scala/com/github/shadowsocks/plugin/PluginManager.scala
+41
-31
mobile/src/main/scala/com/github/shadowsocks/plugin/ProviderPlugin.scala
.../scala/com/github/shadowsocks/plugin/ProviderPlugin.scala
+0
-16
mobile/src/main/scala/com/github/shadowsocks/plugin/ResolvedPlugin.scala
.../scala/com/github/shadowsocks/plugin/ResolvedPlugin.scala
+22
-0
mobile/src/main/scala/com/github/shadowsocks/preference/BottomSheetPreferenceDialogFragment.scala
...ocks/preference/BottomSheetPreferenceDialogFragment.scala
+32
-17
mobile/src/main/scala/com/github/shadowsocks/preference/IconListPreference.scala
...om/github/shadowsocks/preference/IconListPreference.scala
+1
-0
mobile/src/main/scala/com/github/shadowsocks/preference/PluginConfigurationDialogFragment.scala
...wsocks/preference/PluginConfigurationDialogFragment.scala
+4
-4
mobile/src/main/scala/com/github/shadowsocks/utils/IOUtils.scala
...src/main/scala/com/github/shadowsocks/utils/IOUtils.scala
+1
-1
plugin/src/main/java/com/github/shadowsocks/plugin/PluginContract.java
...in/java/com/github/shadowsocks/plugin/PluginContract.java
+34
-29
plugin/src/main/java/com/github/shadowsocks/plugin/PluginOptions.java
...ain/java/com/github/shadowsocks/plugin/PluginOptions.java
+9
-11
plugin/src/main/scala/com/github/shadowsocks/plugin/ConfigurationActivity.scala
...com/github/shadowsocks/plugin/ConfigurationActivity.scala
+1
-1
plugin/src/main/scala/com/github/shadowsocks/plugin/HelpCallback.scala
...in/scala/com/github/shadowsocks/plugin/HelpCallback.scala
+1
-1
plugin/src/main/scala/com/github/shadowsocks/plugin/NativePluginProvider.scala
.../com/github/shadowsocks/plugin/NativePluginProvider.scala
+2
-2
plugin/src/main/scala/com/github/shadowsocks/plugin/OptionsCapableActivity.scala
...om/github/shadowsocks/plugin/OptionsCapableActivity.scala
+1
-1
plugin/src/main/scala/com/github/shadowsocks/plugin/PathProvider.scala
...in/scala/com/github/shadowsocks/plugin/PathProvider.scala
+10
-7
project/plugins.sbt
project/plugins.sbt
+1
-1
No files found.
mobile/build.sbt
View file @
99d97d1d
...
@@ -6,12 +6,6 @@ version := "4.0.0"
...
@@ -6,12 +6,6 @@ version := "4.0.0"
versionCode
:=
Some
(
174
)
versionCode
:=
Some
(
174
)
proguardOptions
++=
proguardOptions
++=
"-keep class android.support.v14.preference.SwitchPreference { <init>(...); }"
::
"-keep class android.support.v7.preference.DropDownPreference { <init>(...); }"
::
"-keep class android.support.v7.preference.PreferenceScreen { <init>(...); }"
::
"-keep class be.mygod.preference.EditTextPreference { <init>(...); }"
::
"-keep class be.mygod.preference.NumberPickerPreference { <init>(...); }"
::
"-keep class be.mygod.preference.PreferenceCategory { <init>(...); }"
::
"-keep class com.github.shadowsocks.System { *; }"
::
"-keep class com.github.shadowsocks.System { *; }"
::
"-dontwarn com.google.android.gms.internal.**"
::
"-dontwarn com.google.android.gms.internal.**"
::
"-dontwarn com.j256.ormlite.**"
::
"-dontwarn com.j256.ormlite.**"
::
...
...
mobile/src/main/res/values/dimen.xml
View file @
99d97d1d
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<resources>
<dimen
name=
"profile_item_max_width"
>
480dp
</dimen>
<dimen
name=
"profile_item_max_width"
>
480dp
</dimen>
<dimen
name=
"icon_list_item_padding"
>
8
dp
</dimen>
<dimen
name=
"icon_list_item_padding"
>
16
dp
</dimen>
<!-- TODO: Remove when this issue is fixed: https://github.com/JorgeCastilloPrz/FABProgressCircle/issues/19 -->
<!-- TODO: Remove when this issue is fixed: https://github.com/JorgeCastilloPrz/FABProgressCircle/issues/19 -->
<dimen
name=
"fab_margin_top"
>
-44dp
</dimen>
<dimen
name=
"fab_margin_top"
>
-44dp
</dimen>
</resources>
</resources>
mobile/src/main/scala/com/github/shadowsocks/ProfileConfigFragment.scala
View file @
99d97d1d
...
@@ -20,8 +20,9 @@
...
@@ -20,8 +20,9 @@
package
com.github.shadowsocks
package
com.github.shadowsocks
import
android.app.Activity
import
android.content.SharedPreferences.OnSharedPreferenceChangeListener
import
android.content.SharedPreferences.OnSharedPreferenceChangeListener
import
android.content.
{
DialogInterface
,
Intent
,
SharedPreferences
}
import
android.content.
_
import
android.os.
{
Build
,
Bundle
,
UserManager
}
import
android.os.
{
Build
,
Bundle
,
UserManager
}
import
android.support.design.widget.Snackbar
import
android.support.design.widget.Snackbar
import
android.support.v14.preference.SwitchPreference
import
android.support.v14.preference.SwitchPreference
...
@@ -33,7 +34,7 @@ import android.view.MenuItem
...
@@ -33,7 +34,7 @@ import android.view.MenuItem
import
be.mygod.preference.
{
EditTextPreference
,
PreferenceFragment
}
import
be.mygod.preference.
{
EditTextPreference
,
PreferenceFragment
}
import
com.github.shadowsocks.ShadowsocksApplication.app
import
com.github.shadowsocks.ShadowsocksApplication.app
import
com.github.shadowsocks.database.Profile
import
com.github.shadowsocks.database.Profile
import
com.github.shadowsocks.plugin.
{
PluginConfiguration
,
PluginInterface
,
PluginManager
,
PluginOptions
}
import
com.github.shadowsocks.plugin.
_
import
com.github.shadowsocks.preference.
{
IconListPreference
,
PluginConfigurationDialogFragment
}
import
com.github.shadowsocks.preference.
{
IconListPreference
,
PluginConfigurationDialogFragment
}
import
com.github.shadowsocks.utils.
{
Action
,
Key
,
Utils
}
import
com.github.shadowsocks.utils.
{
Action
,
Key
,
Utils
}
...
@@ -79,29 +80,21 @@ class ProfileConfigFragment extends PreferenceFragment with OnMenuItemClickListe
...
@@ -79,29 +80,21 @@ class ProfileConfigFragment extends PreferenceFragment with OnMenuItemClickListe
pluginConfiguration
=
new
PluginConfiguration
(
pluginConfiguration
.
pluginsOptions
,
selected
)
pluginConfiguration
=
new
PluginConfiguration
(
pluginConfiguration
.
pluginsOptions
,
selected
)
app
.
editor
.
putString
(
Key
.
plugin
,
pluginConfiguration
.
toString
).
putBoolean
(
Key
.
dirty
,
true
).
apply
()
app
.
editor
.
putString
(
Key
.
plugin
,
pluginConfiguration
.
toString
).
putBoolean
(
Key
.
dirty
,
true
).
apply
()
pluginConfigure
.
setEnabled
(!
TextUtils
.
isEmpty
(
selected
))
pluginConfigure
.
setEnabled
(!
TextUtils
.
isEmpty
(
selected
))
pluginConfigure
.
setText
(
pluginConfiguration
.
selectedOptions
.
toString
)
true
true
})
})
pluginConfigure
.
setOnPreferenceChangeListener
((
_
,
value
)
=>
try
{
pluginConfigure
.
setOnPreferenceChangeListener
(
onPluginConfigureChanged
)
val
selected
=
pluginConfiguration
.
selected
pluginConfiguration
=
new
PluginConfiguration
(
pluginConfiguration
.
pluginsOptions
+
(
pluginConfiguration
.
selected
->
new
PluginOptions
(
selected
,
value
.
asInstanceOf
[
String
])),
selected
)
app
.
editor
.
putString
(
Key
.
plugin
,
pluginConfiguration
.
toString
).
putBoolean
(
Key
.
dirty
,
true
).
apply
()
true
}
catch
{
case
exc
:
IllegalArgumentException
=>
Snackbar
.
make
(
getActivity
.
findViewById
(
R
.
id
.
snackbar
),
exc
.
getLocalizedMessage
,
Snackbar
.
LENGTH_LONG
).
show
()
false
})
initPlugins
()
initPlugins
()
app
.
listenForPackageChanges
(
i
f
(
getView
!=
null
)
getView
.
post
(
initPlugins
))
app
.
listenForPackageChanges
(
i
nitPlugins
(
))
app
.
settings
.
registerOnSharedPreferenceChangeListener
(
this
)
app
.
settings
.
registerOnSharedPreferenceChangeListener
(
this
)
}
}
def
initPlugins
()
{
def
initPlugins
()
{
val
plugins
=
PluginManager
.
fetchPlugins
()
val
plugins
=
PluginManager
.
fetchPlugins
()
plugin
.
setEntries
(
plugins
.
map
(
_
.
label
))
plugin
.
setEntries
(
plugins
.
map
(
_
.
_2
.
label
).
toArray
)
plugin
.
setEntryValues
(
plugins
.
map
(
_
.
id
.
asInstanceOf
[
CharSequence
]))
plugin
.
setEntryValues
(
plugins
.
map
(
_
.
_2
.
id
.
asInstanceOf
[
CharSequence
]).
toArray
)
plugin
.
setEntryIcons
(
plugins
.
map
(
_
.
icon
))
plugin
.
setEntryIcons
(
plugins
.
map
(
_
.
_2
.
icon
).
toArray
)
plugin
.
entryPackageNames
=
plugins
.
map
(
_
.
_2
.
packageName
).
toArray
pluginConfiguration
=
new
PluginConfiguration
(
app
.
settings
.
getString
(
Key
.
plugin
,
null
))
pluginConfiguration
=
new
PluginConfiguration
(
app
.
settings
.
getString
(
Key
.
plugin
,
null
))
plugin
.
setValue
(
pluginConfiguration
.
selected
)
plugin
.
setValue
(
pluginConfiguration
.
selected
)
plugin
.
checkSummary
()
plugin
.
checkSummary
()
...
@@ -109,6 +102,18 @@ class ProfileConfigFragment extends PreferenceFragment with OnMenuItemClickListe
...
@@ -109,6 +102,18 @@ class ProfileConfigFragment extends PreferenceFragment with OnMenuItemClickListe
pluginConfigure
.
setText
(
pluginConfiguration
.
selectedOptions
.
toString
)
pluginConfigure
.
setText
(
pluginConfiguration
.
selectedOptions
.
toString
)
}
}
private
def
onPluginConfigureChanged
(
p
:
Preference
,
value
:
Any
)
=
try
{
val
selected
=
pluginConfiguration
.
selected
pluginConfiguration
=
new
PluginConfiguration
(
pluginConfiguration
.
pluginsOptions
+
(
pluginConfiguration
.
selected
->
new
PluginOptions
(
selected
,
value
.
asInstanceOf
[
String
])),
selected
)
app
.
editor
.
putString
(
Key
.
plugin
,
pluginConfiguration
.
toString
).
putBoolean
(
Key
.
dirty
,
true
).
apply
()
true
}
catch
{
case
exc
:
IllegalArgumentException
=>
Snackbar
.
make
(
getActivity
.
findViewById
(
R
.
id
.
snackbar
),
exc
.
getLocalizedMessage
,
Snackbar
.
LENGTH_LONG
).
show
()
false
}
override
def
onSharedPreferenceChanged
(
sharedPreferences
:
SharedPreferences
,
key
:
String
)
:
Unit
=
override
def
onSharedPreferenceChanged
(
sharedPreferences
:
SharedPreferences
,
key
:
String
)
:
Unit
=
if
(
key
!=
Key
.
proxyApps
&&
findPreference
(
key
)
!=
null
)
app
.
editor
.
putBoolean
(
Key
.
dirty
,
true
).
apply
()
if
(
key
!=
Key
.
proxyApps
&&
findPreference
(
key
)
!=
null
)
app
.
editor
.
putBoolean
(
Key
.
dirty
,
true
).
apply
()
...
@@ -124,9 +129,9 @@ class ProfileConfigFragment extends PreferenceFragment with OnMenuItemClickListe
...
@@ -124,9 +129,9 @@ class ProfileConfigFragment extends PreferenceFragment with OnMenuItemClickListe
override
def
onDisplayPreferenceDialog
(
preference
:
Preference
)
:
Unit
=
if
(
preference
eq
pluginConfigure
)
{
override
def
onDisplayPreferenceDialog
(
preference
:
Preference
)
:
Unit
=
if
(
preference
eq
pluginConfigure
)
{
val
selected
=
pluginConfiguration
.
selected
val
selected
=
pluginConfiguration
.
selected
val
intent
=
new
Intent
(
PluginInterface
.
ACTION_CONFIGURE
(
selected
)
)
val
intent
=
PluginManager
.
buildIntent
(
selected
,
PluginContract
.
ACTION_CONFIGURE
)
if
(
intent
.
resolveActivity
(
getActivity
.
getPackageManager
)
!=
null
)
if
(
intent
.
resolveActivity
(
getActivity
.
getPackageManager
)
!=
null
)
startActivityForResult
(
intent
.
putExtra
(
Plugin
Interface
.
EXTRA_OPTIONS
,
startActivityForResult
(
intent
.
putExtra
(
Plugin
Contract
.
EXTRA_OPTIONS
,
pluginConfiguration
.
selectedOptions
.
toString
),
REQUEST_CODE_CONFIGURE
)
else
{
pluginConfiguration
.
selectedOptions
.
toString
),
REQUEST_CODE_CONFIGURE
)
else
{
val
bundle
=
new
Bundle
()
val
bundle
=
new
Bundle
()
bundle
.
putString
(
PluginConfigurationDialogFragment
.
PLUGIN_ID_FRAGMENT_TAG
,
selected
)
bundle
.
putString
(
PluginConfigurationDialogFragment
.
PLUGIN_ID_FRAGMENT_TAG
,
selected
)
...
@@ -134,6 +139,15 @@ class ProfileConfigFragment extends PreferenceFragment with OnMenuItemClickListe
...
@@ -134,6 +139,15 @@ class ProfileConfigFragment extends PreferenceFragment with OnMenuItemClickListe
}
}
}
else
super
.
onDisplayPreferenceDialog
(
preference
)
}
else
super
.
onDisplayPreferenceDialog
(
preference
)
override
def
onActivityResult
(
requestCode
:
Int
,
resultCode
:
Int
,
data
:
Intent
)
:
Unit
=
requestCode
match
{
case
REQUEST_CODE_CONFIGURE
=>
if
(
resultCode
==
Activity
.
RESULT_OK
)
{
val
options
=
data
.
getStringExtra
(
PluginContract
.
EXTRA_OPTIONS
)
pluginConfigure
.
setText
(
options
)
onPluginConfigureChanged
(
null
,
options
)
}
case
_
=>
super
.
onActivityResult
(
requestCode
,
resultCode
,
data
)
}
override
def
onMenuItemClick
(
item
:
MenuItem
)
:
Boolean
=
item
.
getItemId
match
{
override
def
onMenuItemClick
(
item
:
MenuItem
)
:
Boolean
=
item
.
getItemId
match
{
case
R
.
id
.
action_delete
=>
case
R
.
id
.
action_delete
=>
new
AlertDialog
.
Builder
(
getActivity
)
new
AlertDialog
.
Builder
(
getActivity
)
...
...
mobile/src/main/scala/com/github/shadowsocks/plugin/NativePlugin.scala
View file @
99d97d1d
package
com.github.shadowsocks.plugin
package
com.github.shadowsocks.plugin
import
android.content.pm.
{
PackageManager
,
ProviderInfo
}
import
android.content.ContentResolver
import
android.content.pm.
{
PackageManager
,
ResolveInfo
}
import
android.net.Uri
import
android.os.Bundle
/**
/**
* @author Mygod
* @author Mygod
*/
*/
class
NativePlugin
(
providerInfo
:
Provider
Info
,
packageManager
:
PackageManager
)
final
class
NativePlugin
(
resolveInfo
:
Resolve
Info
,
packageManager
:
PackageManager
)
extends
ResolvedPlugin
(
provider
Info
,
packageManager
)
{
extends
ResolvedPlugin
(
resolve
Info
,
packageManager
)
{
assert
(
providerInfo
!=
null
)
assert
(
resolveInfo
.
providerInfo
!=
null
)
assert
(
providerInfo
.
authority
.
startsWith
(
PluginInterface
.
AUTHORITY_BASE
))
override
protected
def
metaData
:
Bundle
=
resolveInfo
.
providerInfo
.
metaData
override
final
lazy
val
id
:
String
=
providerInfo
.
authority
.
substring
(
PluginInterface
.
AUTHORITY_BASE
.
length
)
private
lazy
val
uriBuilder
:
Uri.Builder
=
new
Uri
.
Builder
(
)
override
final
lazy
val
defaultConfig
:
String
=
.
scheme
(
ContentResolver
.
SCHEME_CONTENT
)
providerInfo
.
metaData
.
getString
(
PluginInterface
.
METADATA_KEY_DEFAULT_CONFIG
)
.
authority
(
resolveInfo
.
providerInfo
.
authority
)
}
}
mobile/src/main/scala/com/github/shadowsocks/plugin/Plugin.scala
View file @
99d97d1d
...
@@ -10,4 +10,5 @@ abstract class Plugin {
...
@@ -10,4 +10,5 @@ abstract class Plugin {
def
label
:
CharSequence
def
label
:
CharSequence
def
icon
:
Drawable
=
null
def
icon
:
Drawable
=
null
def
defaultConfig
:
String
=
null
def
defaultConfig
:
String
=
null
def
packageName
:
String
=
null
}
}
mobile/src/main/scala/com/github/shadowsocks/plugin/PluginConfiguration.scala
View file @
99d97d1d
...
@@ -19,7 +19,7 @@ class PluginConfiguration(val pluginsOptions: Map[String, PluginOptions], val se
...
@@ -19,7 +19,7 @@ class PluginConfiguration(val pluginsOptions: Map[String, PluginOptions], val se
val
args
=
mutable
.
Queue
(
Commandline
.
translateCommandline
(
line
)
:
_
*
)
val
args
=
mutable
.
Queue
(
Commandline
.
translateCommandline
(
line
)
:
_
*
)
args
.
dequeue
()
args
.
dequeue
()
while
(
args
.
nonEmpty
)
args
.
dequeue
()
match
{
while
(
args
.
nonEmpty
)
args
.
dequeue
()
match
{
case
"--nocomp"
=>
opt
.
put
(
"nocomp"
,
"1"
)
case
"--nocomp"
=>
opt
.
put
(
"nocomp"
,
null
)
case
option
if
option
.
startsWith
(
"--"
)
=>
opt
.
put
(
option
.
substring
(
2
),
args
.
dequeue
())
case
option
if
option
.
startsWith
(
"--"
)
=>
opt
.
put
(
option
.
substring
(
2
),
args
.
dequeue
())
case
option
=>
throw
new
IllegalArgumentException
(
"Unknown kcptun parameter: "
+
option
)
case
option
=>
throw
new
IllegalArgumentException
(
"Unknown kcptun parameter: "
+
option
)
}
}
...
@@ -30,7 +30,10 @@ class PluginConfiguration(val pluginsOptions: Map[String, PluginOptions], val se
...
@@ -30,7 +30,10 @@ class PluginConfiguration(val pluginsOptions: Map[String, PluginOptions], val se
case
line
=>
new
PluginOptions
(
line
)
case
line
=>
new
PluginOptions
(
line
)
})
})
def
getOptions
(
id
:
String
)
:
PluginOptions
=
if
(
id
.
isEmpty
)
new
PluginOptions
()
else
pluginsOptions
(
id
)
def
getOptions
(
id
:
String
)
:
PluginOptions
=
if
(
id
.
isEmpty
)
new
PluginOptions
()
else
pluginsOptions
.
get
(
id
)
match
{
case
Some
(
options
)
=>
options
case
None
=>
new
PluginOptions
(
id
,
PluginManager
.
fetchPlugins
()(
id
).
defaultConfig
)
}
def
selectedOptions
:
PluginOptions
=
getOptions
(
selected
)
def
selectedOptions
:
PluginOptions
=
getOptions
(
selected
)
override
def
toString
:
String
=
{
override
def
toString
:
String
=
{
...
@@ -39,6 +42,7 @@ class PluginConfiguration(val pluginsOptions: Map[String, PluginOptions], val se
...
@@ -39,6 +42,7 @@ class PluginConfiguration(val pluginsOptions: Map[String, PluginOptions], val se
case
this
.
selected
=>
result
.
prepend
(
opt
)
case
this
.
selected
=>
result
.
prepend
(
opt
)
case
_
=>
result
.
append
(
opt
)
case
_
=>
result
.
append
(
opt
)
}
}
if
(!
pluginsOptions
.
contains
(
selected
))
result
.
prepend
(
selectedOptions
)
result
.
map
(
_
.
toString
(
false
)).
mkString
(
"\n"
)
result
.
map
(
_
.
toString
(
false
)).
mkString
(
"\n"
)
}
}
}
}
mobile/src/main/scala/com/github/shadowsocks/plugin/PluginManager.scala
View file @
99d97d1d
...
@@ -5,36 +5,43 @@ import java.io.{File, FileNotFoundException, FileOutputStream, IOException}
...
@@ -5,36 +5,43 @@ import java.io.{File, FileNotFoundException, FileOutputStream, IOException}
import
android.content.pm.PackageManager
import
android.content.pm.PackageManager
import
android.content.
{
BroadcastReceiver
,
ContentResolver
,
Intent
}
import
android.content.
{
BroadcastReceiver
,
ContentResolver
,
Intent
}
import
android.net.Uri
import
android.net.Uri
import
android.text.TextUtils
import
com.github.shadowsocks.ShadowsocksApplication.app
import
com.github.shadowsocks.ShadowsocksApplication.app
import
com.github.shadowsocks.utils.CloseUtils.autoClose
import
com.github.shadowsocks.utils.CloseUtils.autoClose
import
com.github.shadowsocks.utils.IOUtils
import
com.github.shadowsocks.utils.
{
Commandline
,
IOUtils
}
import
eu.chainfire.libsuperuser.Shell
import
scala.collection.JavaConver
ter
s._
import
scala.collection.JavaConver
sion
s._
/**
/**
* @author Mygod
* @author Mygod
*/
*/
object
PluginManager
{
object
PluginManager
{
private
var
receiver
:
BroadcastReceiver
=
_
private
var
receiver
:
BroadcastReceiver
=
_
private
var
cachedPlugins
:
Array
[
Plugin
]
=
_
private
var
cachedPlugins
:
Map
[
String
,
Plugin
]
=
_
def
fetchPlugins
()
:
Array
[
Plugin
]
=
{
def
fetchPlugins
()
:
Map
[
String
,
Plugin
]
=
{
if
(
receiver
==
null
)
receiver
=
app
.
listenForPackageChanges
(
synchronized
(
cachedPlugins
=
null
))
if
(
receiver
==
null
)
receiver
=
app
.
listenForPackageChanges
(
synchronized
(
cachedPlugins
=
null
))
synchronized
(
if
(
cachedPlugins
==
null
)
{
synchronized
(
if
(
cachedPlugins
==
null
)
{
val
pm
=
app
.
getPackageManager
val
pm
=
app
.
getPackageManager
cachedPlugins
=
(
NoPlugin
+:
cachedPlugins
=
(
pm
.
query
ContentProviders
(
null
,
0
,
PackageManager
.
GET_META_DATA
).
asScala
pm
.
query
IntentContentProviders
(
new
Intent
(
PluginContract
.
ACTION_NATIVE_PLUGIN
),
PackageManager
.
GET_META_DATA
)
.
filter
(
_
!=
null
)
.
map
(
new
NativePlugin
(
_
,
pm
))
:+
.
filter
(
_
.
authority
.
startsWith
(
PluginInterface
.
AUTHORITY_BASE
))
NoPlugin
.
map
(
new
NativePlugin
(
_
,
pm
))).
toArray
).
map
(
plugin
=>
plugin
.
id
->
plugin
).
toMap
})
})
cachedPlugins
cachedPlugins
}
}
private
def
buildUri
(
id
:
String
)
=
new
Uri
.
Builder
()
.
scheme
(
PluginContract
.
SCHEME
)
.
authority
(
PluginContract
.
AUTHORITY
)
.
path
(
'/'
+
id
)
.
build
()
def
buildIntent
(
id
:
String
,
action
:
String
)
:
Intent
=
new
Intent
(
action
,
buildUri
(
id
))
// the following parts are meant to be used by :bg
// the following parts are meant to be used by :bg
@throws
[
Throwable
]
@throws
[
Throwable
]
def
initPlugin
(
id
:
String
)
:
String
=
{
def
initPlugin
(
id
:
String
)
:
String
=
{
if
(
TextUtils
.
isEmpty
(
id
)
)
return
null
if
(
id
.
isEmpty
)
return
null
var
throwable
:
Throwable
=
null
var
throwable
:
Throwable
=
null
try
initNativePlugin
(
id
)
match
{
try
initNativePlugin
(
id
)
match
{
...
@@ -56,32 +63,35 @@ object PluginManager {
...
@@ -56,32 +63,35 @@ object PluginManager {
@throws
[
IndexOutOfBoundsException
]
@throws
[
IndexOutOfBoundsException
]
@throws
[
AssertionError
]
@throws
[
AssertionError
]
private
def
initNativePlugin
(
id
:
String
)
:
String
=
{
private
def
initNativePlugin
(
id
:
String
)
:
String
=
{
val
providers
=
app
.
getPackageManager
.
queryIntentContentProviders
(
new
Intent
(
PluginContract
.
ACTION_NATIVE_PLUGIN
,
buildUri
(
id
)),
0
)
assert
(
providers
.
length
==
1
)
val
builder
=
new
Uri
.
Builder
()
val
builder
=
new
Uri
.
Builder
()
.
scheme
(
ContentResolver
.
SCHEME_CONTENT
)
.
scheme
(
ContentResolver
.
SCHEME_CONTENT
)
.
authority
(
PluginInterface
.
getAuthority
(
id
)
)
.
authority
(
providers
(
0
).
providerInfo
.
authority
)
val
cr
=
app
.
getContentResolver
val
cr
=
app
.
getContentResolver
val
cursor
=
cr
.
query
(
builder
.
build
(),
Array
(
PluginInterface
.
COLUMN_PATH
),
null
,
null
,
null
)
val
cursor
=
cr
.
query
(
builder
.
build
(),
Array
(
PluginContract
.
COLUMN_PATH
,
PluginContract
.
COLUMN_MODE
),
null
,
null
,
null
)
if
(
cursor
!=
null
)
{
if
(
cursor
!=
null
)
{
var
initialized
=
false
var
initialized
=
false
val
pluginDir
=
new
File
(
app
.
getFilesDir
,
"plugin"
)
val
pluginDir
=
new
File
(
app
.
getFilesDir
,
"plugin"
)
if
(
cursor
.
moveToFirst
())
{
def
entryNotFound
()
=
throw
new
IndexOutOfBoundsException
(
"Plugin entry binary not found"
)
try
{
if
(!
cursor
.
moveToFirst
())
entryNotFound
()
IOUtils
.
deleteRecursively
(
pluginDir
)
IOUtils
.
deleteRecursively
(
pluginDir
)
}
catch
{
case
ex
:
IOException
=>
// Ignore
}
if
(!
pluginDir
.
mkdirs
())
throw
new
FileNotFoundException
(
"Unable to create plugin directory"
)
if
(!
pluginDir
.
mkdirs
())
throw
new
FileNotFoundException
(
"Unable to create plugin directory"
)
val
pluginDirPath
=
pluginDir
.
getAbsolutePath
+
'/'
val
pluginDirPath
=
pluginDir
.
getAbsolutePath
+
'/'
var
list
:
List
[
String
]
=
Nil
do
{
do
{
val
path
=
cursor
.
getString
(
0
)
val
path
=
cursor
.
getString
(
0
)
val
file
=
new
File
(
pluginDir
,
path
)
val
file
=
new
File
(
pluginDir
,
path
)
assert
(
file
.
getAbsolutePath
.
startsWith
(
pluginDirPath
))
assert
(
file
.
getAbsolutePath
.
startsWith
(
pluginDirPath
))
autoClose
(
cr
.
openInputStream
(
builder
.
path
(
path
).
build
()))(
in
=>
autoClose
(
cr
.
openInputStream
(
builder
.
path
(
path
).
build
()))(
in
=>
autoClose
(
new
FileOutputStream
(
file
))(
out
=>
IOUtils
.
copy
(
in
,
out
)))
autoClose
(
new
FileOutputStream
(
file
))(
out
=>
IOUtils
.
copy
(
in
,
out
)))
list
+:=
Commandline
.
toString
(
Array
(
"chmod"
,
cursor
.
getString
(
1
),
file
.
getAbsolutePath
))
if
(
path
==
id
)
initialized
=
true
if
(
path
==
id
)
initialized
=
true
}
while
(
cursor
.
moveToNext
())
}
while
(
cursor
.
moveToNext
())
}
if
(!
initialized
)
entryNotFound
()
if
(!
initialized
)
throw
new
IndexOutOfBoundsException
(
"Plugin entry binary not found"
)
Shell
.
SH
.
run
(
list
)
new
File
(
pluginDir
,
id
).
getAbsolutePath
new
File
(
pluginDir
,
id
).
getAbsolutePath
}
else
null
}
else
null
}
}
...
...
mobile/src/main/scala/com/github/shadowsocks/plugin/ProviderPlugin.scala
deleted
100644 → 0
View file @
b78c10e8
package
com.github.shadowsocks.plugin
import
android.content.pm.
{
PackageManager
,
ProviderInfo
}
import
android.graphics.drawable.Drawable
import
com.github.shadowsocks.ShadowsocksApplication.app
/**
* Base class for any kind of plugin that can be used.
*
* @author Mygod
*/
abstract
class
ResolvedPlugin
(
providerInfo
:
ProviderInfo
,
packageManager
:
PackageManager
=
app
.
getPackageManager
)
extends
Plugin
{
override
final
lazy
val
label
:
CharSequence
=
packageManager
.
getApplicationLabel
(
providerInfo
.
applicationInfo
)
override
final
lazy
val
icon
:
Drawable
=
packageManager
.
getApplicationIcon
(
providerInfo
.
applicationInfo
)
}
mobile/src/main/scala/com/github/shadowsocks/plugin/ResolvedPlugin.scala
0 → 100644
View file @
99d97d1d
package
com.github.shadowsocks.plugin
import
android.content.pm.
{
PackageManager
,
ResolveInfo
}
import
android.graphics.drawable.Drawable
import
android.os.Bundle
import
com.github.shadowsocks.ShadowsocksApplication.app
/**
* Base class for any kind of plugin that can be used.
*
* @author Mygod
*/
abstract
class
ResolvedPlugin
(
resolveInfo
:
ResolveInfo
,
packageManager
:
PackageManager
=
app
.
getPackageManager
)
extends
Plugin
{
protected
def
metaData
:
Bundle
override
final
lazy
val
id
:
String
=
metaData
.
getString
(
PluginContract
.
METADATA_KEY_ID
)
override
final
lazy
val
label
:
CharSequence
=
resolveInfo
.
loadLabel
(
packageManager
)
override
final
lazy
val
icon
:
Drawable
=
resolveInfo
.
loadIcon
(
packageManager
)
override
final
lazy
val
defaultConfig
:
String
=
metaData
.
getString
(
PluginContract
.
METADATA_KEY_DEFAULT_CONFIG
)
override
final
def
packageName
:
String
=
resolveInfo
.
resolvePackageName
}
mobile/src/main/scala/com/github/shadowsocks/preference/BottomSheetPreferenceDialogFragment.scala
View file @
99d97d1d
package
com.github.shadowsocks.preference
package
com.github.shadowsocks.preference
import
android.content.
{
ActivityNotFoundException
,
Intent
}
import
android.graphics.Typeface
import
android.graphics.Typeface
import
android.graphics.drawable.Drawable
import
android.graphics.drawable.Drawable
import
android.net.Uri
import
android.os.Bundle
import
android.os.Bundle
import
android.provider.Settings
import
android.support.design.widget.BottomSheetDialog
import
android.support.design.widget.BottomSheetDialog
import
android.support.v14.preference.PreferenceDialogFragment
import
android.support.v14.preference.PreferenceDialogFragment
import
android.support.v7.widget.RecyclerView.ViewHolder
import
android.support.v7.widget.RecyclerView.ViewHolder
import
android.support.v7.widget.
{
LinearLayoutManager
,
RecyclerView
}
import
android.support.v7.widget.
{
LinearLayoutManager
,
RecyclerView
}
import
android.view.ViewGroup.LayoutParams
import
android.view.ViewGroup.LayoutParams
import
android.view.
{
LayoutInflater
,
View
,
ViewGroup
}
import
android.view.
{
LayoutInflater
,
View
,
ViewGroup
}
import
android.widget.
TextView
import
android.widget.
{
ImageView
,
TextView
}
import
com.github.shadowsocks.R
import
com.github.shadowsocks.R
/**
/**
...
@@ -19,6 +22,7 @@ final class BottomSheetPreferenceDialogFragment extends PreferenceDialogFragment
...
@@ -19,6 +22,7 @@ final class BottomSheetPreferenceDialogFragment extends PreferenceDialogFragment
private
lazy
val
preference
=
getPreference
.
asInstanceOf
[
IconListPreference
]
private
lazy
val
preference
=
getPreference
.
asInstanceOf
[
IconListPreference
]
private
lazy
val
index
:
Int
=
preference
.
selectedEntry
private
lazy
val
index
:
Int
=
preference
.
selectedEntry
private
lazy
val
entries
:
Array
[
CharSequence
]
=
preference
.
getEntries
private
lazy
val
entries
:
Array
[
CharSequence
]
=
preference
.
getEntries
private
lazy
val
entryValues
:
Array
[
CharSequence
]
=
preference
.
getEntryValues
private
lazy
val
entryIcons
:
Array
[
Drawable
]
=
preference
.
getEntryIcons
private
lazy
val
entryIcons
:
Array
[
Drawable
]
=
preference
.
getEntryIcons
private
var
clickedIndex
=
-
1
private
var
clickedIndex
=
-
1
...
@@ -39,30 +43,41 @@ final class BottomSheetPreferenceDialogFragment extends PreferenceDialogFragment
...
@@ -39,30 +43,41 @@ final class BottomSheetPreferenceDialogFragment extends PreferenceDialogFragment
if
(
preference
.
callChangeListener
(
value
))
preference
.
setValue
(
value
)
if
(
preference
.
callChangeListener
(
value
))
preference
.
setValue
(
value
)
}
}
private
final
class
IconListViewHolder
(
val
dialog
:
BottomSheetDialog
,
v
al
view
:
Text
View
)
extends
ViewHolder
(
view
)
private
final
class
IconListViewHolder
(
val
dialog
:
BottomSheetDialog
,
v
iew
:
View
)
extends
ViewHolder
(
view
)
with
View
.
OnClickListener
{
with
View
.
OnClickListener
with
View
.
OnLongClickListener
{
private
var
index
:
Int
=
_
private
var
index
:
Int
=
_
private
val
text1
=
view
.
findViewById
(
android
.
R
.
id
.
text1
).
asInstanceOf
[
TextView
]
{
private
val
text2
=
view
.
findViewById
(
android
.
R
.
id
.
text2
).
asInstanceOf
[
TextView
]
val
padding
=
getResources
.
getDimension
(
R
.
dimen
.
icon_list_item_padding
).
toInt
private
val
icon
=
view
.
findViewById
(
android
.
R
.
id
.
icon
).
asInstanceOf
[
ImageView
]
view
.
setPadding
(
padding
,
padding
,
padding
,
padding
)
view
.
setCompoundDrawablePadding
(
padding
)
view
.
setOnClickListener
(
this
)
view
.
setOnClickListener
(
this
)
val
typedArray
=
dialog
.
getContext
.
obtainStyledAttributes
(
Array
(
android
.
R
.
attr
.
selectableItemBackground
))
view
.
setOnLongClickListener
(
this
)
view
.
setBackgroundResource
(
typedArray
.
getResourceId
(
0
,
0
))
typedArray
.
recycle
()
}
def
bind
(
i
:
Int
,
selected
:
Boolean
=
false
)
{
def
bind
(
i
:
Int
,
selected
:
Boolean
=
false
)
{
view
.
setText
(
entries
(
i
))
text1
.
setText
(
entries
(
i
))
view
.
setCompoundDrawablesWithIntrinsicBounds
(
entryIcons
(
i
),
null
,
null
,
null
)
text2
.
setText
(
entryValues
(
i
))
view
.
setTypeface
(
null
,
if
(
selected
)
Typeface
.
BOLD
else
Typeface
.
NORMAL
)
val
typeface
=
if
(
selected
)
Typeface
.
BOLD
else
Typeface
.
NORMAL
text1
.
setTypeface
(
null
,
typeface
)
text2
.
setTypeface
(
null
,
typeface
)
text2
.
setVisibility
(
if
(
entryValues
(
i
).
length
>
0
)
View
.
VISIBLE
else
View
.
GONE
)
icon
.
setImageDrawable
(
entryIcons
(
i
))
index
=
i
index
=
i
}
}
def
onClick
(
v
:
View
)
{
def
onClick
(
v
:
View
)
{
clickedIndex
=
index
clickedIndex
=
index
dialog
.
dismiss
()
dialog
.
dismiss
()
}
}
override
def
onLongClick
(
v
:
View
)
:
Boolean
=
preference
.
entryPackageNames
(
index
)
match
{
case
null
=>
false
case
pn
=>
try
{
startActivity
(
new
Intent
(
Settings
.
ACTION_APPLICATION_DETAILS_SETTINGS
,
new
Uri
.
Builder
()
.
authority
(
Settings
.
AUTHORITY
)
.
opaquePart
(
pn
)
.
build
()))
true
}
catch
{
case
_:
ActivityNotFoundException
=>
false
}
}
}
}
private
final
class
IconListAdapter
(
dialog
:
BottomSheetDialog
)
extends
RecyclerView
.
Adapter
[
IconListViewHolder
]
{
private
final
class
IconListAdapter
(
dialog
:
BottomSheetDialog
)
extends
RecyclerView
.
Adapter
[
IconListViewHolder
]
{
def
getItemCount
:
Int
=
entries
.
length
def
getItemCount
:
Int
=
entries
.
length
...
@@ -72,6 +87,6 @@ final class BottomSheetPreferenceDialogFragment extends PreferenceDialogFragment
...
@@ -72,6 +87,6 @@ final class BottomSheetPreferenceDialogFragment extends PreferenceDialogFragment
case
_
=>
vh
.
bind
(
i
-
1
)
case
_
=>
vh
.
bind
(
i
-
1
)
}
}
def
onCreateViewHolder
(
vg
:
ViewGroup
,
i
:
Int
)
:
IconListViewHolder
=
new
IconListViewHolder
(
dialog
,
def
onCreateViewHolder
(
vg
:
ViewGroup
,
i
:
Int
)
:
IconListViewHolder
=
new
IconListViewHolder
(
dialog
,
LayoutInflater
.
from
(
vg
.
getContext
).
inflate
(
android
.
R
.
layout
.
simple_list_item_1
,
vg
,
false
).
asInstanceOf
[
TextView
]
)
LayoutInflater
.
from
(
vg
.
getContext
).
inflate
(
R
.
layout
.
icon_list_item_2
,
vg
,
false
)
)
}
}
}
}
mobile/src/main/scala/com/github/shadowsocks/preference/IconListPreference.scala
View file @
99d97d1d
...
@@ -19,6 +19,7 @@ class IconListPreference(context: Context, attrs: AttributeSet = null) extends L
...
@@ -19,6 +19,7 @@ class IconListPreference(context: Context, attrs: AttributeSet = null) extends L
def
selectedEntry
:
Int
=
getEntryValues
.
indexOf
(
getValue
)
def
selectedEntry
:
Int
=
getEntryValues
.
indexOf
(
getValue
)
var
unknownValueSummary
:
String
=
_
var
unknownValueSummary
:
String
=
_
var
entryPackageNames
:
Array
[
String
]
=
_
private
var
listener
:
OnPreferenceChangeListener
=
_
private
var
listener
:
OnPreferenceChangeListener
=
_
override
def
getOnPreferenceChangeListener
:
OnPreferenceChangeListener
=
listener
override
def
getOnPreferenceChangeListener
:
OnPreferenceChangeListener
=
listener
...
...
mobile/src/main/scala/com/github/shadowsocks/preference/PluginConfigurationDialogFragment.scala
View file @
99d97d1d
...
@@ -23,7 +23,7 @@ package com.github.shadowsocks.preference
...
@@ -23,7 +23,7 @@ package com.github.shadowsocks.preference
import
android.app.
{
Activity
,
AlertDialog
}
import
android.app.
{
Activity
,
AlertDialog
}
import
android.content.
{
DialogInterface
,
Intent
}
import
android.content.
{
DialogInterface
,
Intent
}
import
be.mygod.preference.EditTextPreferenceDialogFragment
import
be.mygod.preference.EditTextPreferenceDialogFragment
import
com.github.shadowsocks.plugin.
PluginInterface
import
com.github.shadowsocks.plugin.
{
PluginContract
,
PluginManager
}
/**
/**
* @author Mygod
* @author Mygod
...
@@ -38,9 +38,9 @@ class PluginConfigurationDialogFragment extends EditTextPreferenceDialogFragment
...
@@ -38,9 +38,9 @@ class PluginConfigurationDialogFragment extends EditTextPreferenceDialogFragment
override
def
onPrepareDialogBuilder
(
builder
:
AlertDialog.Builder
)
{
override
def
onPrepareDialogBuilder
(
builder
:
AlertDialog.Builder
)
{
super
.
onPrepareDialogBuilder
(
builder
)
super
.
onPrepareDialogBuilder
(
builder
)
val
intent
=
new
Intent
(
PluginInterface
.
ACTION_HELP
(
getArguments
.
getString
(
PLUGIN_ID_FRAGMENT_TAG
))
)
val
intent
=
PluginManager
.
buildIntent
(
getArguments
.
getString
(
PLUGIN_ID_FRAGMENT_TAG
),
PluginContract
.
ACTION_HELP
)
if
(
intent
.
resolveActivity
(
getActivity
.
getPackageManager
)
!=
null
)
builder
.
setNeutralButton
(
"?"
,
((
_
,
_
)
=>
if
(
intent
.
resolveActivity
(
getActivity
.
getPackageManager
)
!=
null
)
builder
.
setNeutralButton
(
"?"
,
((
_
,
_
)
=>
startActivityForResult
(
intent
.
putExtra
(
Plugin
Interface
.
EXTRA_OPTIONS
,
editText
.
getText
.
toString
),
startActivityForResult
(
intent
.
putExtra
(
Plugin
Contract
.
EXTRA_OPTIONS
,
editText
.
getText
.
toString
),
REQUEST_CODE_HELP
))
:
DialogInterface.OnClickListener
)
REQUEST_CODE_HELP
))
:
DialogInterface.OnClickListener
)
}
}
...
@@ -48,7 +48,7 @@ class PluginConfigurationDialogFragment extends EditTextPreferenceDialogFragment
...
@@ -48,7 +48,7 @@ class PluginConfigurationDialogFragment extends EditTextPreferenceDialogFragment
case
REQUEST_CODE_HELP
=>
requestCode
match
{
case
REQUEST_CODE_HELP
=>
requestCode
match
{
case
Activity
.
RESULT_OK
=>
new
AlertDialog
.
Builder
(
getContext
)
case
Activity
.
RESULT_OK
=>
new
AlertDialog
.
Builder
(
getContext
)
.
setTitle
(
"?"
)
.
setTitle
(
"?"
)
.
setMessage
(
data
.
getCharSequenceExtra
(
Plugin
Interface
.
EXTRA_HELP_MESSAGE
))
.
setMessage
(
data
.
getCharSequenceExtra
(
Plugin
Contract
.
EXTRA_HELP_MESSAGE
))
.
show
()
.
show
()
case
_
=>
case
_
=>
}
}
...
...
mobile/src/main/scala/com/github/shadowsocks/utils/IOUtils.scala
View file @
99d97d1d
...
@@ -41,7 +41,7 @@ object IOUtils {
...
@@ -41,7 +41,7 @@ object IOUtils {
autoClose
(
new
FileWriter
(
file
))(
writer
=>
writer
.
write
(
content
))
autoClose
(
new
FileWriter
(
file
))(
writer
=>
writer
.
write
(
content
))
@throws
[
FileNotFoundException
]
@throws
[
FileNotFoundException
]
def
deleteRecursively
(
file
:
File
)
{
def
deleteRecursively
(
file
:
File
)
:
Unit
=
if
(
file
.
exists
())
{
if
(
file
.
isDirectory
)
file
.
listFiles
().
foreach
(
deleteRecursively
)
if
(
file
.
isDirectory
)
file
.
listFiles
().
foreach
(
deleteRecursively
)
if
(!
file
.
delete
())
throw
new
FileNotFoundException
(
"Failed to delete: "
+
file
.
getAbsolutePath
)
if
(!
file
.
delete
())
throw
new
FileNotFoundException
(
"Failed to delete: "
+
file
.
getAbsolutePath
)
}
}
...
...
plugin/src/main/java/com/github/shadowsocks/plugin/Plugin
Interface
.java
→
plugin/src/main/java/com/github/shadowsocks/plugin/Plugin
Contract
.java
View file @
99d97d1d
package
com.github.shadowsocks.plugin
;
package
com.github.shadowsocks.plugin
;
/**
/**
* Th
is class provides String constants that will be used in plugin interfaces
.
* Th
e contract between the plugin provider and host. Contains definitions for the supported actions, extras, etc
.
*
*
* This class is written in Java to keep Java interoperability.
* This class is written in Java to keep Java interoperability.
*
*
* @author Mygod
* @author Mygod
*/
*/
public
final
class
Plugin
Interface
{
public
final
class
Plugin
Contract
{
private
Plugin
Interface
()
{
}
private
Plugin
Contract
()
{
}
/**
/**
*
Should be a
NativePluginProvider.
*
ContentProvider Action: Used for
NativePluginProvider.
*
*
* Constant Value: "com.github.shadowsocks.plugin.
CATEGORY
_NATIVE_PLUGIN"
* Constant Value: "com.github.shadowsocks.plugin.
ACTION
_NATIVE_PLUGIN"
*/
*/
public
static
final
String
CATEGORY_NATIVE_PLUGIN
=
"com.github.shadowsocks.plugin.CATEGORY_NATIVE_PLUGIN"
;
public
static
final
String
ACTION_NATIVE_PLUGIN
=
"com.github.shadowsocks.plugin.ACTION_NATIVE_PLUGIN"
;
/**
* Activity Action: Used for ConfigurationActivity.
*
* Constant Value: "com.github.shadowsocks.plugin.ACTION_CONFIGURE"
*/
public
static
final
String
ACTION_CONFIGURE
=
"com.github.shadowsocks.plugin.ACTION_CONFIGURE"
;
/**
* Activity Action: Used for HelpActivity or HelpCallback.
*
* Constant Value: "com.github.shadowsocks.plugin.ACTION_CONFIGURE"
*/
public
static
final
String
ACTION_HELP
=
"com.github.shadowsocks.plugin.ACTION_HELP"
;
/**
/**
* The lookup key for a string that provides the whole command as a string.
* The lookup key for a string that provides the whole command as a string.
...
@@ -35,6 +48,12 @@ public final class PluginInterface {
...
@@ -35,6 +48,12 @@ public final class PluginInterface {
*/
*/
public
static
final
String
EXTRA_HELP_MESSAGE
=
"com.github.shadowsocks.plugin.EXTRA_HELP_MESSAGE"
;
public
static
final
String
EXTRA_HELP_MESSAGE
=
"com.github.shadowsocks.plugin.EXTRA_HELP_MESSAGE"
;
/**
* The metadata key to retrieve plugin id. Required for plugins.
*
* Constant Value: "com.github.shadowsocks.plugin.id"
*/
public
static
final
String
METADATA_KEY_ID
=
"com.github.shadowsocks.plugin.id"
;
/**
/**
* The metadata key to retrieve default configuration. Default value is empty.
* The metadata key to retrieve default configuration. Default value is empty.
*
*
...
@@ -50,35 +69,21 @@ public final class PluginInterface {
...
@@ -50,35 +69,21 @@ public final class PluginInterface {
* Type: String
* Type: String
*/
*/
public
static
final
String
COLUMN_PATH
=
"path"
;
public
static
final
String
COLUMN_PATH
=
"path"
;
static
final
String
AUTHORITY_BASE
=
"com.github.shadowsocks.plugin."
;
/**
/**
* Authority to use for native plugin ContentProvider.
* File mode bits. Default value is "644".
*
* Example: "755"
*
*
* @param pluginId Plugin ID.
* Type: String
* @return com.github.shadowsocks.plugin.$PLUGIN_ID
*/
*/
public
static
String
getAuthority
(
String
pluginId
)
{
public
static
final
String
COLUMN_MODE
=
"mode"
;
return
AUTHORITY_BASE
+
pluginId
;
}
/**
/**
* Activity Action: Used for ConfigurationActivity.
* The scheme for general plugin actions.
*
* @param pluginId Plugin ID.
* @return com.github.shadowsocks.plugin.$PLUGIN_ID.ACTION_CONFIGURE
*/
*/
public
static
String
ACTION_CONFIGURE
(
String
pluginId
)
{
public
static
final
String
SCHEME
=
"plugin"
;
return
getAuthority
(
pluginId
)
+
".ACTION_CONFIGURE"
;
}
/**
/**
* Activity Action: Used for HelpActivity or HelpCallback.
* The authority for general plugin actions.
*
* @param pluginId Plugin ID.
* @return com.github.shadowsocks.plugin.$PLUGIN_ID.ACTION_HELP
*/
*/
public
static
String
ACTION_HELP
(
String
pluginId
)
{
public
static
final
String
AUTHORITY
=
"com.github.shadowsocks"
;
return
getAuthority
(
pluginId
)
+
".ACTION_HELP"
;
}
}
}
plugin/src/main/java/com/github/shadowsocks/plugin/PluginOptions.java
View file @
99d97d1d
...
@@ -25,8 +25,9 @@ public final class PluginOptions extends HashMap<String, String> {
...
@@ -25,8 +25,9 @@ public final class PluginOptions extends HashMap<String, String> {
}
}
private
PluginOptions
(
String
options
,
boolean
parseId
)
{
private
PluginOptions
(
String
options
,
boolean
parseId
)
{
this
();
if
(
TextUtils
.
isEmpty
(
options
))
return
;
if
(
TextUtils
.
isEmpty
(
options
))
return
;
final
StringTokenizer
tokenizer
=
new
StringTokenizer
(
options
,
"\\=;"
,
true
);
final
StringTokenizer
tokenizer
=
new
StringTokenizer
(
options
+
';'
,
"\\=;"
,
true
);
final
StringBuilder
current
=
new
StringBuilder
();
final
StringBuilder
current
=
new
StringBuilder
();
String
key
=
null
;
String
key
=
null
;
while
(
tokenizer
.
hasMoreTokens
())
{
while
(
tokenizer
.
hasMoreTokens
())
{
...
@@ -35,18 +36,15 @@ public final class PluginOptions extends HashMap<String, String> {
...
@@ -35,18 +36,15 @@ public final class PluginOptions extends HashMap<String, String> {
else
if
(
"="
.
equals
(
nextToken
)
&&
key
==
null
)
{
else
if
(
"="
.
equals
(
nextToken
)
&&
key
==
null
)
{
key
=
current
.
toString
();
key
=
current
.
toString
();
current
.
setLength
(
0
);
current
.
setLength
(
0
);
}
else
if
(
";"
.
equals
(
nextToken
))
}
else
if
(
";"
.
equals
(
nextToken
))
{
if
(
key
!=
null
)
{
if
(
key
!=
null
)
{
put
(
key
,
current
.
toString
());
put
(
key
,
current
.
toString
());
key
=
null
;
key
=
null
;
}
else
if
(
parseId
)
{
}
else
if
(
current
.
length
()
>
0
)
id
=
current
.
toString
();
if
(
parseId
)
id
=
current
.
toString
();
else
put
(
current
.
toString
(),
null
);
parseId
=
false
;
}
else
{
put
(
current
.
toString
(),
null
);
current
.
setLength
(
0
);
current
.
setLength
(
0
);
}
parseId
=
false
;
else
current
.
append
(
nextToken
);
}
else
current
.
append
(
nextToken
);
}
}
}
}
public
PluginOptions
(
String
options
)
{
public
PluginOptions
(
String
options
)
{
...
@@ -57,7 +55,7 @@ public final class PluginOptions extends HashMap<String, String> {
...
@@ -57,7 +55,7 @@ public final class PluginOptions extends HashMap<String, String> {
this
.
id
=
id
;
this
.
id
=
id
;
}
}
public
String
id
;
public
String
id
=
""
;
private
static
void
append
(
StringBuilder
result
,
String
str
)
{
private
static
void
append
(
StringBuilder
result
,
String
str
)
{
for
(
int
i
=
0
;
i
<
str
.
length
();
++
i
)
{
for
(
int
i
=
0
;
i
<
str
.
length
();
++
i
)
{
...
...
plugin/src/main/scala/com/github/shadowsocks/plugin/ConfigurationActivity.scala
View file @
99d97d1d
...
@@ -35,5 +35,5 @@ trait ConfigurationActivity extends OptionsCapableActivity {
...
@@ -35,5 +35,5 @@ trait ConfigurationActivity extends OptionsCapableActivity {
* @param options PluginOptions to save.
* @param options PluginOptions to save.
*/
*/
final
def
saveChanges
(
options
:
PluginOptions
)
:
Unit
=
final
def
saveChanges
(
options
:
PluginOptions
)
:
Unit
=
setResult
(
Activity
.
RESULT_OK
,
new
Intent
().
putExtra
(
Plugin
Interface
.
EXTRA_OPTIONS
,
options
.
toString
))
setResult
(
Activity
.
RESULT_OK
,
new
Intent
().
putExtra
(
Plugin
Contract
.
EXTRA_OPTIONS
,
options
.
toString
))
}
}
plugin/src/main/scala/com/github/shadowsocks/plugin/HelpCallback.scala
View file @
99d97d1d
...
@@ -14,5 +14,5 @@ trait HelpCallback extends HelpActivity {
...
@@ -14,5 +14,5 @@ trait HelpCallback extends HelpActivity {
def
produceHelpMessage
(
options
:
PluginOptions
)
:
CharSequence
def
produceHelpMessage
(
options
:
PluginOptions
)
:
CharSequence
override
protected
def
onInitializePluginOptions
(
options
:
PluginOptions
)
:
Unit
=
setResult
(
Activity
.
RESULT_OK
,
override
protected
def
onInitializePluginOptions
(
options
:
PluginOptions
)
:
Unit
=
setResult
(
Activity
.
RESULT_OK
,
new
Intent
().
putExtra
(
Plugin
Interface
.
EXTRA_HELP_MESSAGE
,
produceHelpMessage
(
options
)))
new
Intent
().
putExtra
(
Plugin
Contract
.
EXTRA_HELP_MESSAGE
,
produceHelpMessage
(
options
)))
}
}
plugin/src/main/scala/com/github/shadowsocks/plugin/NativePluginProvider.scala
View file @
99d97d1d
...
@@ -17,7 +17,7 @@ import android.os.ParcelFileDescriptor
...
@@ -17,7 +17,7 @@ import android.os.ParcelFileDescriptor
* <provider android:name="com.github.shadowsocks.$PLUGIN_ID.BinaryProvider"
* <provider android:name="com.github.shadowsocks.$PLUGIN_ID.BinaryProvider"
* android:authorities="com.github.shadowsocks.plugin.$PLUGIN_ID">
* android:authorities="com.github.shadowsocks.plugin.$PLUGIN_ID">
* <intent-filter>
* <intent-filter>
* <category android:name="com.github.shadowsocks.plugin.
CATEGORY
_NATIVE_PLUGIN" />
* <category android:name="com.github.shadowsocks.plugin.
ACTION
_NATIVE_PLUGIN" />
* </intent-filter>
* </intent-filter>
* </provider>
* </provider>
* ...
* ...
...
@@ -47,7 +47,7 @@ abstract class NativePluginProvider extends ContentProvider {
...
@@ -47,7 +47,7 @@ abstract class NativePluginProvider extends ContentProvider {
override
def
query
(
uri
:
Uri
,
projection
:
Array
[
String
],
selection
:
String
,
selectionArgs
:
Array
[
String
],
override
def
query
(
uri
:
Uri
,
projection
:
Array
[
String
],
selection
:
String
,
selectionArgs
:
Array
[
String
],
sortOrder
:
String
)
:
Cursor
=
{
sortOrder
:
String
)
:
Cursor
=
{
assert
(
selection
==
null
&&
selectionArgs
==
null
&&
sortOrder
==
null
)
assert
(
selection
==
null
&&
selectionArgs
==
null
&&
sortOrder
==
null
)
val
result
=
new
MatrixCursor
(
projection
.
filter
(
_
==
PluginInterface
.
COLUMN_PATH
)
)
val
result
=
new
MatrixCursor
(
projection
)
populateFiles
(
new
PathProvider
(
uri
,
result
))
populateFiles
(
new
PathProvider
(
uri
,
result
))
result
result
}
}
...
...
plugin/src/main/scala/com/github/shadowsocks/plugin/OptionsCapableActivity.scala
View file @
99d97d1d
...
@@ -12,7 +12,7 @@ import android.widget.Toast
...
@@ -12,7 +12,7 @@ import android.widget.Toast
*/
*/
trait
OptionsCapableActivity
extends
Activity
{
trait
OptionsCapableActivity
extends
Activity
{
protected
def
pluginOptions
(
intent
:
Intent
=
getIntent
)
:
PluginOptions
=
protected
def
pluginOptions
(
intent
:
Intent
=
getIntent
)
:
PluginOptions
=
try
new
PluginOptions
(
intent
.
getStringExtra
(
Plugin
Interface
.
EXTRA_OPTIONS
))
catch
{
try
new
PluginOptions
(
intent
.
getStringExtra
(
Plugin
Contract
.
EXTRA_OPTIONS
))
catch
{
case
exc
:
IllegalArgumentException
=>
case
exc
:
IllegalArgumentException
=>
Toast
.
makeText
(
this
,
exc
.
getMessage
,
Toast
.
LENGTH_SHORT
).
show
()
Toast
.
makeText
(
this
,
exc
.
getMessage
,
Toast
.
LENGTH_SHORT
).
show
()
null
null
...
...
plugin/src/main/scala/com/github/shadowsocks/plugin/PathProvider.scala
View file @
99d97d1d
...
@@ -16,21 +16,24 @@ final class PathProvider private[plugin](baseUri: Uri, cursor: MatrixCursor) {
...
@@ -16,21 +16,24 @@ final class PathProvider private[plugin](baseUri: Uri, cursor: MatrixCursor) {
case
p
=>
p
.
stripPrefix
(
"/"
).
stripSuffix
(
"/"
)
case
p
=>
p
.
stripPrefix
(
"/"
).
stripSuffix
(
"/"
)
}
}
def
addPath
(
path
:
String
)
:
PathProvider
=
{
def
addPath
(
path
:
String
,
mode
:
String
=
"644"
)
:
PathProvider
=
{
val
stripped
=
path
.
stripPrefix
(
"/"
).
stripSuffix
(
"/"
)
val
stripped
=
path
.
stripPrefix
(
"/"
).
stripSuffix
(
"/"
)
if
(
stripped
.
startsWith
(
basePath
))
cursor
.
newRow
().
add
(
PluginInterface
.
COLUMN_PATH
,
stripped
)
if
(
stripped
.
startsWith
(
basePath
))
cursor
.
newRow
()
.
add
(
PluginContract
.
COLUMN_PATH
,
stripped
)
.
add
(
PluginContract
.
COLUMN_MODE
,
mode
)
this
this
}
}
def
addTo
(
file
:
File
,
to
:
String
=
""
)
:
PathProvider
=
{
def
addTo
(
file
:
File
,
to
:
String
=
""
,
mode
:
String
=
"644"
)
:
PathProvider
=
{
var
sub
=
to
+
file
.
getName
var
sub
=
to
+
file
.
getName
if
(
basePath
.
startsWith
(
sub
))
if
(
file
.
isDirectory
)
{
if
(
basePath
.
startsWith
(
sub
))
if
(
file
.
isDirectory
)
{
sub
+=
'/'
sub
+=
'/'
file
.
listFiles
().
foreach
(
addTo
(
_
,
sub
))
file
.
listFiles
().
foreach
(
addTo
(
_
,
sub
,
mode
))
}
else
addPath
(
sub
)
}
else
addPath
(
sub
,
mode
)
this
this
}
}
def
addAt
(
file
:
File
,
at
:
String
=
""
)
:
PathProvider
=
{
def
addAt
(
file
:
File
,
at
:
String
=
""
,
mode
:
String
=
"644"
)
:
PathProvider
=
{
if
(
basePath
.
startsWith
(
at
))
if
(
file
.
isDirectory
)
file
.
listFiles
().
foreach
(
addTo
(
_
,
at
))
else
addPath
(
at
)
if
(
basePath
.
startsWith
(
at
))
if
(
file
.
isDirectory
)
file
.
listFiles
().
foreach
(
addTo
(
_
,
at
,
mode
))
else
addPath
(
at
,
mode
)
this
this
}
}
}
}
project/plugins.sbt
View file @
99d97d1d
addSbtPlugin
(
"org.scala-android"
%
"sbt-android"
%
"1.7.
2
"
)
addSbtPlugin
(
"org.scala-android"
%
"sbt-android"
%
"1.7.
3
"
)
addSbtPlugin
(
"com.timushev.sbt"
%
"sbt-updates"
%
"0.1.10"
)
addSbtPlugin
(
"com.timushev.sbt"
%
"sbt-updates"
%
"0.1.10"
)
...
...
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