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
1887c6ff
Commit
1887c6ff
authored
Jan 13, 2017
by
Mygod
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Initial commit for plugin library
See spec at #1073.
parent
5ead55d6
Changes
11
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
522 additions
and
45 deletions
+522
-45
mobile/src/main/java/com/github/shadowsocks/utils/Commandline.java
...c/main/java/com/github/shadowsocks/utils/Commandline.java
+146
-0
mobile/src/main/scala/com/github/shadowsocks/utils/Utils.scala
...e/src/main/scala/com/github/shadowsocks/utils/Utils.scala
+1
-45
plugin/src/main/java/com/github/shadowsocks/plugin/PluginInterface.java
...n/java/com/github/shadowsocks/plugin/PluginInterface.java
+82
-0
plugin/src/main/java/com/github/shadowsocks/plugin/PluginOptions.java
...ain/java/com/github/shadowsocks/plugin/PluginOptions.java
+78
-0
plugin/src/main/res/layout/toolbar_light_dark.xml
plugin/src/main/res/layout/toolbar_light_dark.xml
+0
-0
plugin/src/main/scala/com/github/shadowsocks/plugin/ConfigurationActivity.scala
...com/github/shadowsocks/plugin/ConfigurationActivity.scala
+39
-0
plugin/src/main/scala/com/github/shadowsocks/plugin/HelpActivity.scala
...in/scala/com/github/shadowsocks/plugin/HelpActivity.scala
+25
-0
plugin/src/main/scala/com/github/shadowsocks/plugin/HelpCallback.scala
...in/scala/com/github/shadowsocks/plugin/HelpCallback.scala
+18
-0
plugin/src/main/scala/com/github/shadowsocks/plugin/NativePluginProvider.scala
.../com/github/shadowsocks/plugin/NativePluginProvider.scala
+65
-0
plugin/src/main/scala/com/github/shadowsocks/plugin/OptionsCapableActivity.scala
...om/github/shadowsocks/plugin/OptionsCapableActivity.scala
+32
-0
plugin/src/main/scala/com/github/shadowsocks/plugin/PathProvider.scala
...in/scala/com/github/shadowsocks/plugin/PathProvider.scala
+36
-0
No files found.
mobile/src/main/java/com/github/shadowsocks/utils/Commandline.java
0 → 100644
View file @
1887c6ff
package
com.github.shadowsocks.utils
;
import
java.util.ArrayList
;
import
java.util.StringTokenizer
;
/**
* Commandline objects help handling command lines specifying processes to
* execute.
*
* The class can be used to define a command line as nested elements or as a
* helper to define a command line by an application.
* <p>
* <code>
* <someelement><br>
* <acommandline executable="/executable/to/run"><br>
* <argument value="argument 1" /><br>
* <argument line="argument_1 argument_2 argument_3" /><br>
* <argument value="argument 4" /><br>
* </acommandline><br>
* </someelement><br>
* </code>
*
* Based on: https://github.com/apache/ant/blob/588ce1f/src/main/org/apache/tools/ant/types/Commandline.java
*
* Adds support for escape character '\'.
*
* @author Mygod
*/
public
final
class
Commandline
{
private
Commandline
()
{
}
/**
* Quote the parts of the given array in way that makes them
* usable as command line arguments.
* @param line the list of arguments to quote.
* @return empty string for null or no command, else every argument split
* by spaces and quoted by quoting rules.
*/
public
static
String
toString
(
String
[]
line
)
{
// empty path return empty string
if
(
line
==
null
||
line
.
length
==
0
)
{
return
""
;
}
// path containing one or more elements
final
StringBuilder
result
=
new
StringBuilder
();
for
(
int
i
=
0
;
i
<
line
.
length
;
i
++)
{
if
(
i
>
0
)
{
result
.
append
(
' '
);
}
for
(
int
j
=
0
;
j
<
line
[
i
].
length
();
++
j
)
{
char
ch
=
line
[
i
].
charAt
(
j
);
switch
(
ch
)
{
case
' '
:
case
'\\'
:
case
'"'
:
case
'\''
:
result
.
append
(
'\\'
);
// intentionally no break
default
:
result
.
append
(
ch
);
}
}
}
return
result
.
toString
();
}
/**
* Crack a command line.
* @param toProcess the command line to process.
* @return the command line broken into strings.
* An empty or null toProcess parameter results in a zero sized array.
*/
public
static
String
[]
translateCommandline
(
String
toProcess
)
{
if
(
toProcess
==
null
||
toProcess
.
length
()
==
0
)
{
//no command? no string
return
new
String
[
0
];
}
// parse with a simple finite state machine
final
int
normal
=
0
;
final
int
inQuote
=
1
;
final
int
inDoubleQuote
=
2
;
int
state
=
normal
;
final
StringTokenizer
tok
=
new
StringTokenizer
(
toProcess
,
"\\\"\' "
,
true
);
final
ArrayList
<
String
>
result
=
new
ArrayList
<>();
final
StringBuilder
current
=
new
StringBuilder
();
boolean
lastTokenHasBeenQuoted
=
false
;
boolean
lastTokenIsSlash
=
false
;
while
(
tok
.
hasMoreTokens
())
{
String
nextTok
=
tok
.
nextToken
();
switch
(
state
)
{
case
inQuote:
if
(
"\'"
.
equals
(
nextTok
))
{
lastTokenHasBeenQuoted
=
true
;
state
=
normal
;
}
else
{
current
.
append
(
nextTok
);
}
break
;
case
inDoubleQuote:
if
(
"\""
.
equals
(
nextTok
))
{
if
(
lastTokenIsSlash
)
{
current
.
append
(
nextTok
);
lastTokenIsSlash
=
false
;
}
else
{
lastTokenHasBeenQuoted
=
true
;
state
=
normal
;
}
}
else
if
(
"\\"
.
equals
(
nextTok
))
{
if
(
lastTokenIsSlash
)
{
current
.
append
(
nextTok
);
lastTokenIsSlash
=
false
;
}
else
lastTokenIsSlash
=
true
;
}
else
{
if
(
lastTokenIsSlash
)
{
current
.
append
(
"\\"
);
// unescaped
lastTokenIsSlash
=
false
;
}
current
.
append
(
nextTok
);
}
break
;
default
:
if
(
lastTokenIsSlash
)
{
current
.
append
(
nextTok
);
lastTokenIsSlash
=
false
;
}
else
if
(
"\\"
.
equals
(
nextTok
))
lastTokenIsSlash
=
true
;
else
if
(
"\'"
.
equals
(
nextTok
))
{
state
=
inQuote
;
}
else
if
(
"\""
.
equals
(
nextTok
))
{
state
=
inDoubleQuote
;
}
else
if
(
" "
.
equals
(
nextTok
))
{
if
(
lastTokenHasBeenQuoted
||
current
.
length
()
!=
0
)
{
result
.
add
(
current
.
toString
());
current
.
setLength
(
0
);
}
}
else
{
current
.
append
(
nextTok
);
}
lastTokenHasBeenQuoted
=
false
;
break
;
}
}
if
(
lastTokenHasBeenQuoted
||
current
.
length
()
!=
0
)
{
result
.
add
(
current
.
toString
());
}
if
(
state
==
inQuote
||
state
==
inDoubleQuote
)
{
throw
new
IllegalArgumentException
(
"unbalanced quotes in "
+
toProcess
);
}
if
(
lastTokenIsSlash
)
throw
new
IllegalArgumentException
(
"escape character following nothing in "
+
toProcess
);
return
result
.
toArray
(
new
String
[
result
.
size
()]);
}
}
mobile/src/main/scala/com/github/shadowsocks/utils/Utils.scala
View file @
1887c6ff
...
...
@@ -23,9 +23,8 @@ package com.github.shadowsocks.utils
import
java.io.File
import
java.net._
import
java.security.MessageDigest
import
java.util.
{
Scanner
,
StringTokenizer
}
import
java.util.
Scanner
import
android.animation.
{
Animator
,
AnimatorListenerAdapter
}
import
android.content.pm.PackageManager
import
android.content.
{
Context
,
Intent
}
import
android.graphics._
...
...
@@ -39,7 +38,6 @@ import com.github.shadowsocks.{BuildConfig, ShadowsocksRunnerService}
import
org.xbill.DNS._
import
scala.collection.JavaConversions._
import
scala.collection.mutable.ArrayBuffer
import
scala.concurrent.ExecutionContext.Implicits.global
import
scala.concurrent.Future
import
scala.util.
{
Failure
,
Try
}
...
...
@@ -98,48 +96,6 @@ object Utils {
}
}
/**
* Crack a command line.
* Based on: https://github.com/apache/ant/blob/588ce1f/src/main/org/apache/tools/ant/types/Commandline.java#L471
* @param toProcess the command line to process.
* @return the command line broken into strings.
* An empty or null toProcess parameter results in a zero sized ArrayBuffer.
*/
def
translateCommandline
(
toProcess
:
String
)
:
ArrayBuffer
[
String
]
=
{
if
(
toProcess
==
null
||
toProcess
.
length
==
0
)
return
ArrayBuffer
[
String
]()
val
tok
=
new
StringTokenizer
(
toProcess
,
"\"' "
,
true
)
val
result
=
ArrayBuffer
[
String
]()
val
current
=
new
StringBuilder
()
var
quote
=
' '
var
last
=
" "
while
(
tok
.
hasMoreTokens
)
{
val
nextTok
=
tok
.
nextToken
quote
match
{
case
'\''
=>
nextTok
match
{
case
"'"
=>
quote
=
' '
case
_
=>
current
.
append
(
nextTok
)
}
case
'"'
=>
nextTok
match
{
case
"\""
=>
quote
=
' '
case
_
=>
current
.
append
(
nextTok
)
}
case
_
=>
nextTok
match
{
case
"'"
=>
quote
=
'\''
case
"\""
=>
quote
=
'"'
case
" "
=>
if
(
last
!=
" "
)
{
result
.
append
(
current
.
toString
)
current
.
setLength
(
0
)
}
case
_
=>
current
.
append
(
nextTok
)
}
}
last
=
nextTok
}
if
(
current
.
nonEmpty
)
result
.
append
(
current
.
toString
)
if
(
quote
==
'\''
||
quote
==
'"'
)
throw
new
Exception
(
"Unbalanced quotes in "
+
toProcess
)
result
}
def
resolve
(
host
:
String
,
addrType
:
Int
)
:
Option
[
String
]
=
{
try
{
val
lookup
=
new
Lookup
(
host
,
addrType
)
...
...
plugin/src/main/java/com/github/shadowsocks/plugin/PluginInterface.java
0 → 100644
View file @
1887c6ff
package
com.github.shadowsocks.plugin
;
/**
* This class provides String constants that will be used in plugin interfaces.
*
* This class is written in Java to keep Java interoperability.
*
* @author Mygod
*/
public
final
class
PluginInterface
{
private
PluginInterface
()
{
}
/**
* Should be a NativePluginProvider.
*
* Constant Value: "com.github.shadowsocks.plugin.CATEGORY_NATIVE_PLUGIN"
*/
public
static
final
String
CATEGORY_NATIVE_PLUGIN
=
"com.github.shadowsocks.plugin.CATEGORY_NATIVE_PLUGIN"
;
/**
* The lookup key for a string that provides the whole command as a string.
*
* Example: "obfs=http;obfs-host=www.baidu.com"
*
* Constant Value: "com.github.shadowsocks.plugin.EXTRA_OPTIONS"
*/
public
static
final
String
EXTRA_OPTIONS
=
"com.github.shadowsocks.plugin.EXTRA_OPTIONS"
;
/**
* The lookup key for a CharSequence that provides user relevant help message.
*
* Example: "obfs=<http|tls> Enable obfuscating: HTTP or TLS (Experimental).
* obfs-host=<host_name> Hostname for obfuscating (Experimental)."
*
* Constant Value: "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 default configuration. Default value is empty.
*
* Constant Value: "com.github.shadowsocks.plugin.default_config"
*/
public
static
final
String
METADATA_KEY_DEFAULT_CONFIG
=
"com.github.shadowsocks.plugin.default_config"
;
/**
* Relative to the file to be copied. This column is required.
*
* Example: "kcptun", "doc/help.txt"
*
* Type: String
*/
public
static
final
String
COLUMN_PATH
=
"path"
;
/**
* Authority to use for native plugin ContentProvider.
*
* @param pluginId Plugin ID.
* @return com.github.shadowsocks.plugin.$PLUGIN_ID
*/
public
static
String
getAuthority
(
String
pluginId
)
{
return
"com.github.shadowsocks.plugin."
+
pluginId
;
}
/**
* Activity Action: Used for ConfigurationActivity.
*
* @param pluginId Plugin ID.
* @return com.github.shadowsocks.plugin.$PLUGIN_ID.ACTION_CONFIGURE
*/
public
static
String
ACTION_CONFIGURE
(
String
pluginId
)
{
return
getAuthority
(
pluginId
)
+
".ACTION_CONFIGURE"
;
}
/**
* Activity Action: Used for HelpActivity or HelpCallback.
*
* @param pluginId Plugin ID.
* @return com.github.shadowsocks.plugin.$PLUGIN_ID.ACTION_HELP
*/
public
static
String
ACTION_HELP
(
String
pluginId
)
{
return
getAuthority
(
pluginId
)
+
".ACTION_HELP"
;
}
}
plugin/src/main/java/com/github/shadowsocks/plugin/PluginOptions.java
0 → 100644
View file @
1887c6ff
package
com.github.shadowsocks.plugin
;
import
android.text.TextUtils
;
import
java.util.HashMap
;
import
java.util.StringTokenizer
;
/**
* Helper class for processing plugin options.
*
* Based on: https://github.com/apache/ant/blob/588ce1f/src/main/org/apache/tools/ant/types/Commandline.java
*
* @author Mygod
*/
public
final
class
PluginOptions
extends
HashMap
<
String
,
String
>
{
public
PluginOptions
()
{
super
();
}
public
PluginOptions
(
int
initialCapacity
)
{
super
(
initialCapacity
);
}
public
PluginOptions
(
int
initialCapacity
,
float
loadFactor
)
{
super
(
initialCapacity
,
loadFactor
);
}
public
PluginOptions
(
String
options
)
throws
IllegalArgumentException
{
if
(
TextUtils
.
isEmpty
(
options
))
return
;
final
StringTokenizer
tokenizer
=
new
StringTokenizer
(
options
,
"\\=;"
,
true
);
final
StringBuilder
current
=
new
StringBuilder
();
String
key
=
null
;
boolean
firstEntry
=
true
;
while
(
tokenizer
.
hasMoreTokens
())
{
String
nextToken
=
tokenizer
.
nextToken
();
if
(
"\\"
.
equals
(
nextToken
))
current
.
append
(
tokenizer
.
nextToken
());
else
if
(
"="
.
equals
(
nextToken
))
{
if
(
key
!=
null
)
throw
new
IllegalArgumentException
(
"Duplicate keys in "
+
options
);
key
=
current
.
toString
();
current
.
setLength
(
0
);
}
else
if
(
";"
.
equals
(
nextToken
))
{
if
(
current
.
length
()
>
0
)
put
(
key
,
current
.
toString
());
else
if
(
firstEntry
)
id
=
key
;
else
throw
new
IllegalArgumentException
(
"Value missing in "
+
options
);
firstEntry
=
false
;
}
}
}
public
PluginOptions
(
String
id
,
String
options
)
throws
IllegalArgumentException
{
this
(
options
);
this
.
id
=
id
;
}
public
String
id
;
private
static
void
append
(
StringBuilder
result
,
String
str
)
{
for
(
int
i
=
0
;
i
<
str
.
length
();
++
i
)
{
char
ch
=
str
.
charAt
(
i
);
switch
(
ch
)
{
case
'\\'
:
case
'='
:
case
';'
:
result
.
append
(
'\\'
);
// intentionally no break
default
:
result
.
append
(
ch
);
}
}
}
public
String
toString
(
boolean
trimId
)
{
final
StringBuilder
result
=
new
StringBuilder
();
if
(!
trimId
&&
!
TextUtils
.
isEmpty
(
id
))
append
(
result
,
id
);
for
(
Entry
<
String
,
String
>
entry
:
entrySet
())
if
(
entry
.
getValue
()
!=
null
)
{
if
(
result
.
length
()
>
0
)
result
.
append
(
';'
);
append
(
result
,
entry
.
getKey
());
result
.
append
(
'='
);
append
(
result
,
entry
.
getValue
());
}
return
result
.
toString
();
}
@Override
public
String
toString
()
{
return
toString
(
false
);
}
}
mobile
/src/main/res/layout/toolbar_light_dark.xml
→
plugin
/src/main/res/layout/toolbar_light_dark.xml
View file @
1887c6ff
File moved
plugin/src/main/scala/com/github/shadowsocks/plugin/ConfigurationActivity.scala
0 → 100644
View file @
1887c6ff
package
com.github.shadowsocks.plugin
import
android.app.Activity
import
android.content.Intent
/**
* Base class for configuration activity. A configuration activity is started when user wishes to configure the
* selected plugin. To create a configuration activity, extend this class, implement abstract methods, invoke
* `saveChanges(options)` and `discardChanges()` when appropriate, and add it to your manifest like this:
*
* <pre class="prettyprint"><manifest>
* ...
* <application>
* ...
* <activity android:name="com.github.shadowsocks.$PLUGIN_ID.ConfigureActivity">
* <intent-filter>
* <action android:name="com.github.shadowsocks.plugin.$PLUGIN_ID.ACTION_CONFIGURE" />
* </intent-filter>
* </activity>
* ...
* </application>
*</manifest></pre>
*
* @author Mygod
*/
trait
ConfigurationActivity
extends
OptionsCapableActivity
{
/**
* Equivalent to setResult(RESULT_CANCELED).
*/
final
def
discardChanges
()
:
Unit
=
setResult
(
Activity
.
RESULT_CANCELED
)
/**
* Equivalent to setResult(RESULT_OK, args_with_correct_format).
*
* @param options PluginOptions to save.
*/
final
def
saveChanges
(
options
:
PluginOptions
)
:
Unit
=
setResult
(
Activity
.
RESULT_OK
,
new
Intent
().
putExtra
(
PluginInterface
.
EXTRA_OPTIONS
,
options
.
toString
))
}
plugin/src/main/scala/com/github/shadowsocks/plugin/HelpActivity.scala
0 → 100644
View file @
1887c6ff
package
com.github.shadowsocks.plugin
/**
* Base class for a help activity. A help activity is started when user taps help when configuring options for your
* plugin. To create a help activity, just extend this class, and add it to your manifest like this:
*
* <pre class="prettyprint"><manifest>
* ...
* <application>
* ...
* <activity android:name="com.github.shadowsocks.$PLUGIN_ID.HelpActivity">
* <intent-filter>
* <action android:name="com.github.shadowsocks.plugin.$PLUGIN_ID.ACTION_HELP" />
* </intent-filter>
* </activity>
* ...
* </application>
*</manifest></pre>
*
* @author Mygod
*/
trait
HelpActivity
extends
OptionsCapableActivity
{
// HelpActivity can choose to ignore options
override
protected
def
onInitializePluginOptions
(
options
:
PluginOptions
)
:
Unit
=
()
}
plugin/src/main/scala/com/github/shadowsocks/plugin/HelpCallback.scala
0 → 100644
View file @
1887c6ff
package
com.github.shadowsocks.plugin
import
android.app.Activity
import
android.content.Intent
/**
* HelpCallback is an HelpActivity but you just need to produce a CharSequence help message instead of having to
* provide UI. To create a help callback, just extend this class, implement abstract methods, and add it to your
* manifest following the same procedure as adding a HelpActivity.
*
* @author Mygod
*/
trait
HelpCallback
extends
HelpActivity
{
def
produceHelpMessage
(
options
:
PluginOptions
)
:
CharSequence
override
protected
def
onInitializePluginOptions
(
options
:
PluginOptions
)
:
Unit
=
setResult
(
Activity
.
RESULT_OK
,
new
Intent
().
putExtra
(
PluginInterface
.
EXTRA_HELP_MESSAGE
,
produceHelpMessage
(
options
)))
}
plugin/src/main/scala/com/github/shadowsocks/plugin/NativePluginProvider.scala
0 → 100644
View file @
1887c6ff
package
com.github.shadowsocks.plugin
import
android.content.
{
ContentProvider
,
ContentValues
}
import
android.database.
{
Cursor
,
MatrixCursor
}
import
android.net.Uri
import
android.os.ParcelFileDescriptor
/**
* Base class for a native plugin provider. A native plugin provider offers read-only access to files that are required
* to run a plugin, such as binary files and other configuration files. To create a native plugin provider, extend this
* class, implement the abstract methods, and add it to your manifest like this:
*
* <pre class="prettyprint"><manifest>
* ...
* <application>
* ...
* <provider android:name="com.github.shadowsocks.$PLUGIN_ID.PluginProvider"
* android:authorities="com.github.shadowsocks.$PLUGIN_ID">
* <intent-filter>
* <category android:name="com.github.shadowsocks.plugin.CATEGORY_NATIVE_PLUGIN" />
* </intent-filter>
* </provider>
* ...
* </application>
*</manifest></pre>
*
* @author Mygod
*/
abstract
class
NativePluginProvider
extends
ContentProvider
{
/**
* @inheritdoc
*
* NativePluginProvider returns application/x-elf by default. It's implementer's responsibility to change this to
* correct type.
*/
override
def
getType
(
uri
:
Uri
)
:
String
=
"application/x-elf"
override
def
onCreate
()
:
Boolean
=
true
/**
* Provide all files needed for native plugin.
*
* @param provider A helper object to use to add files.
*/
protected
def
populateFiles
(
provider
:
PathProvider
)
override
def
query
(
uri
:
Uri
,
projection
:
Array
[
String
],
selection
:
String
,
selectionArgs
:
Array
[
String
],
sortOrder
:
String
)
:
Cursor
=
{
if
(
selection
!=
null
||
selectionArgs
!=
null
||
sortOrder
!=
null
)
???
val
result
=
new
MatrixCursor
(
projection
.
filter
(
_
==
PluginInterface
.
COLUMN_PATH
))
populateFiles
(
new
PathProvider
(
uri
,
result
))
result
}
def
openFile
(
uri
:
Uri
)
:
ParcelFileDescriptor
override
def
openFile
(
uri
:
Uri
,
mode
:
String
)
:
ParcelFileDescriptor
=
{
if
(
mode
!=
"r"
)
???
openFile
(
uri
)
}
// Methods that should not be used
override
def
update
(
uri
:
Uri
,
values
:
ContentValues
,
selection
:
String
,
selectionArgs
:
Array
[
String
])
:
Int
=
???
override
def
insert
(
uri
:
Uri
,
values
:
ContentValues
)
:
Uri
=
???
override
def
delete
(
uri
:
Uri
,
selection
:
String
,
selectionArgs
:
Array
[
String
])
:
Int
=
???
}
plugin/src/main/scala/com/github/shadowsocks/plugin/OptionsCapableActivity.scala
0 → 100644
View file @
1887c6ff
package
com.github.shadowsocks.plugin
import
android.app.Activity
import
android.content.Intent
import
android.os.Bundle
import
android.widget.Toast
/**
* Activity that's capable of getting EXTRA_OPTIONS input.
*
* @author Mygod
*/
trait
OptionsCapableActivity
extends
Activity
{
protected
def
pluginOptions
(
intent
:
Intent
=
getIntent
)
:
PluginOptions
=
try
new
PluginOptions
(
intent
.
getStringExtra
(
PluginInterface
.
EXTRA_OPTIONS
))
catch
{
case
exc
:
IllegalArgumentException
=>
Toast
.
makeText
(
this
,
exc
.
getMessage
,
Toast
.
LENGTH_SHORT
).
show
()
null
}
/**
* Populate args to your user interface.
*
* @param options PluginOptions parsed.
*/
protected
def
onInitializePluginOptions
(
options
:
PluginOptions
=
pluginOptions
())
:
Unit
override
protected
def
onPostCreate
(
savedInstanceState
:
Bundle
)
{
super
.
onPostCreate
(
savedInstanceState
)
if
(
savedInstanceState
==
null
)
onInitializePluginOptions
()
}
}
plugin/src/main/scala/com/github/shadowsocks/plugin/PathProvider.scala
0 → 100644
View file @
1887c6ff
package
com.github.shadowsocks.plugin
import
java.io.File
import
android.database.MatrixCursor
import
android.net.Uri
/**
* Helper class to provide relative paths of files to copy.
*
* @author Mygod
*/
final
class
PathProvider
private
[
plugin
](
baseUri
:
Uri
,
cursor
:
MatrixCursor
)
{
private
val
basePath
=
baseUri
.
getPath
match
{
case
null
=>
""
case
p
=>
p
.
stripPrefix
(
"/"
).
stripSuffix
(
"/"
)
}
def
addPath
(
path
:
String
)
:
PathProvider
=
{
val
stripped
=
path
.
stripPrefix
(
"/"
).
stripSuffix
(
"/"
)
if
(
stripped
.
startsWith
(
basePath
))
cursor
.
newRow
().
add
(
PluginInterface
.
COLUMN_PATH
,
stripped
)
this
}
def
addTo
(
file
:
File
,
to
:
String
=
""
)
:
PathProvider
=
{
var
sub
=
to
+
file
.
getName
if
(
basePath
.
startsWith
(
sub
))
if
(
file
.
isDirectory
)
{
sub
+=
'/'
file
.
listFiles
().
foreach
(
addTo
(
_
,
sub
))
}
else
addPath
(
sub
)
this
}
def
addAt
(
file
:
File
,
at
:
String
=
""
)
:
PathProvider
=
{
if
(
basePath
.
startsWith
(
at
))
if
(
file
.
isDirectory
)
file
.
listFiles
().
foreach
(
addTo
(
_
,
at
))
else
addPath
(
at
)
this
}
}
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