Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa083a8eca | ||
|
|
ef2ff23cd0 | ||
|
|
c1e208737c | ||
|
|
75bb00593a | ||
|
|
15f25b95a0 | ||
|
|
cc9fa4c4a6 | ||
|
|
9041404f42 | ||
|
|
5aae822cdd | ||
|
|
33ed5c65c5 | ||
|
|
1424e056ac | ||
|
|
ed79e0090e | ||
|
|
304113ce97 | ||
|
|
290bf8cb31 | ||
|
|
fcb0e2ace3 | ||
|
|
f240d5d202 | ||
|
|
ea85bbd83d | ||
|
|
d3018fc090 | ||
|
|
f1f585b4d9 | ||
|
|
3653f73e0b | ||
|
|
d648910aac | ||
|
|
1e2f8c3bd3 | ||
|
|
b94c16c725 | ||
|
|
a03a6af5ba | ||
|
|
b9414c6b0a | ||
|
|
0d54d9cd9b | ||
|
|
8611a66cdc | ||
|
|
740dcc3ca9 | ||
|
|
730efbafc0 | ||
|
|
8b05476823 | ||
|
|
50b890423a | ||
|
|
fb63268895 | ||
|
|
41934f8909 | ||
|
|
bedc7a0443 | ||
|
|
537f790386 | ||
|
|
62afcf51d7 | ||
|
|
6c1ae68931 | ||
|
|
2703e91bbe | ||
|
|
8fba319db2 |
-23
@@ -1,23 +0,0 @@
|
||||
language: scala
|
||||
scala:
|
||||
- 2.10.4
|
||||
before_install:
|
||||
- sudo apt-get update
|
||||
install:
|
||||
- sudo apt-get install -y libc6-dev-i386 lib32ncurses5-dev libx11-dev g++-multilib lib32z1-dev ccache
|
||||
- export NDK_CCACHE=ccache
|
||||
- export ARCH=`uname -m`
|
||||
- wget http://dl.google.com/android/android-sdk_r23.0.2-linux.tgz
|
||||
- tar xf android-sdk_r23.0.2-linux.tgz
|
||||
- wget http://dl.google.com/android/ndk/android-ndk-r9d-linux-${ARCH}.tar.bz2
|
||||
- tar xf android-ndk-r9d-linux-${ARCH}.tar.bz2
|
||||
- export ANDROID_NDK_HOME=`pwd`/android-ndk-r9d
|
||||
- export ANDROID_HOME=`pwd`/android-sdk-linux
|
||||
- export PATH=${PATH}:${ANDROID_NDK_HOME}:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools
|
||||
- echo "y" | android update sdk --filter tools,platform-tools,build-tools-21.0.1,android-21,extra-google-m2repository --no-ui --no-https -a
|
||||
- echo "y" | android update sdk --filter extra-android-m2repository --no-ui --no-https -a
|
||||
script:
|
||||
- cp local.properties.travis local.properties
|
||||
- ./build.sh
|
||||
- sbt android:package-release
|
||||
- exit 0
|
||||
@@ -6,14 +6,14 @@ Help to translate shadowsocks: http://crowdin.net/project/shadowsocks/invite
|
||||
|
||||
[](https://play.google.com/store/apps/details?id=com.github.shadowsocks)
|
||||
|
||||
### TRAVIS CI STATUS
|
||||
### CI STATUS
|
||||
|
||||
[](http://travis-ci.org/shadowsocks/shadowsocks-android)
|
||||
[](https://drone.io/github.com/shadowsocks/shadowsocks-android/latest)
|
||||
|
||||
### PREREQUISITES
|
||||
|
||||
* JDK 1.6+
|
||||
* SBT 0.12.3
|
||||
* JDK 1.7+
|
||||
* SBT 0.13.0+
|
||||
* Android SDK r21+
|
||||
* Android NDK r9+
|
||||
|
||||
@@ -40,6 +40,7 @@ Help to translate shadowsocks: http://crowdin.net/project/shadowsocks/invite
|
||||
|
||||
* Install Android SDK and NDK by run `brew install android-ndk android-sdk`
|
||||
* Add `export ANDROID_HOME=/usr/local/Cellar/android-sdk/$version` to your .bashrc , then reopen the shell to load it.
|
||||
* Add `export ANDROID_NDK_HOME=/usr/local/Cellar/android-ndk/$version` to your .bashrc , then reopen the shell to load it.
|
||||
* echo "y" | android update sdk --filter tools,platform-tools,build-tools-21.0.1,android-21,extra-google-m2repository --no-ui --no-https -a
|
||||
* echo "y" | android update sdk --filter extra-android-m2repository --no-ui --no-https -a
|
||||
* Create your key following the instructions at http://developer.android.com/guide/publishing/app-signing.html#cert
|
||||
|
||||
@@ -16,18 +16,20 @@ ndkBuild in Android := List()
|
||||
|
||||
typedResources in Android := false
|
||||
|
||||
resolvers += Resolver.jcenterRepo
|
||||
|
||||
resolvers += "JRAF" at "http://JRAF.org/static/maven/2"
|
||||
|
||||
resolvers += "madeye private releases" at "http://madeye-maven-repository.googlecode.com/git/"
|
||||
|
||||
libraryDependencies ++= Seq(
|
||||
"dnsjava" % "dnsjava" % "2.1.5",
|
||||
"dnsjava" % "dnsjava" % "2.1.7",
|
||||
"com.github.kevinsawicki" % "http-request" % "5.6",
|
||||
"commons-net" % "commons-net" % "3.3",
|
||||
"com.google.zxing" % "android-integration" % "3.1.0"
|
||||
)
|
||||
|
||||
libraryDependencies ++= Seq(
|
||||
"com.joanzapata.android" % "android-iconify" % "1.0.9",
|
||||
"net.glxn.qrgen" % "android" % "2.0",
|
||||
"net.simonvt.menudrawer" % "menudrawer" % "3.0.6",
|
||||
"com.google.android.gms" % "play-services-base" % "6.5.87",
|
||||
"com.google.android.gms" % "play-services-ads" % "6.5.87",
|
||||
@@ -48,6 +50,7 @@ proguardOptions in Android ++= Seq("-keep class android.support.v4.app.** { *; }
|
||||
"-keep class org.jraf.android.backport.** { *; }",
|
||||
"-keep class com.github.shadowsocks.** { *; }",
|
||||
"-keep class * extends com.j256.ormlite.** { *; }",
|
||||
"-keep class com.joanzapata.** { *; }",
|
||||
"-keepattributes *Annotation*",
|
||||
"-dontwarn org.xbill.**",
|
||||
"-dontwarn com.actionbarsherlock.**")
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
-4488
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1 +1 @@
|
||||
sbt.version=0.13.5
|
||||
sbt.version=0.13.8
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
resolvers += Resolver.url("scalasbt releases", new URL("http://scalasbt.artifactoryonline.com/scalasbt/sbt-plugin-snapshots"))(Resolver.ivyStylePatterns)
|
||||
|
||||
addSbtPlugin("com.hanhuy.sbt" % "android-sdk-plugin" % "1.3.10")
|
||||
addSbtPlugin("com.hanhuy.sbt" % "android-sdk-plugin" % "1.3.22")
|
||||
|
||||
resolvers += Resolver.sbtPluginRepo("snapshots")
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.github.shadowsocks"
|
||||
android:versionCode="101"
|
||||
android:versionName="2.6.3">
|
||||
android:versionCode="104"
|
||||
android:versionName="2.6.6">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
@@ -65,7 +65,8 @@
|
||||
<activity
|
||||
android:name=".AppManager"
|
||||
android:theme="@style/Theme.AppManager"
|
||||
android:label="@string/app_name">
|
||||
android:label="@string/app_name"
|
||||
android:parentActivityName=".Shadowsocks">
|
||||
<intent-filter>
|
||||
<action android:name="com.github.shadowsocks.AppManager"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
|
||||
Submodule src/main/jni/shadowsocks-libev updated: 77d3ecabdd...02050e49e7
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 2.9 KiB |
@@ -9,7 +9,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:textSize="24sp"
|
||||
android:textSize="26sp"
|
||||
android:textColor="@color/title"
|
||||
android:text="@string/screen_name"
|
||||
android:layout_alignParentLeft="true"
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- File created by the Android Action Bar Style Generator
|
||||
|
||||
Copyright (C) 2011 The Android Open Source Project
|
||||
Copyright (C) 2012 readyState Software Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
|
||||
<style name="Theme.Shadow" parent="@android:style/Theme.Material.Light.DarkActionBar">
|
||||
<item name="android:actionBarItemBackground">@drawable/selectable_background_shadow</item>
|
||||
<item name="android:popupMenuStyle">@style/PopupMenu.Shadow</item>
|
||||
<item name="android:dropDownListViewStyle">@style/DropDownListView.Shadow</item>
|
||||
<item name="android:actionBarTabStyle">@style/ActionBarTabStyle.Shadow</item>
|
||||
<item name="android:actionDropDownStyle">@style/DropDownNav.Shadow</item>
|
||||
<item name="android:actionBarStyle">@style/ActionBar.Solid.Shadow</item>
|
||||
<item name="android:actionModeBackground">@drawable/cab_background_top_shadow</item>
|
||||
<item name="android:actionModeSplitBackground">@drawable/cab_background_bottom_shadow</item>
|
||||
<!-- Light.DarkActionBar specific -->
|
||||
<item name="android:actionBarWidgetTheme">@style/Theme.Shadow.Widget</item>
|
||||
<item name="android:textAppearanceLargePopupMenu">@style/m_textAppearanceLargePopupMenu</item>
|
||||
<item name="android:textAppearanceSmallPopupMenu" >@style/m_textAppearanceSmallPopupMenu</item>
|
||||
</style>
|
||||
|
||||
<style name="ActionBar.Solid.Shadow" parent="@android:style/Widget.Material.ActionBar">
|
||||
<item name="android:background">@drawable/ab_background_textured_shadow</item>
|
||||
<item name="android:backgroundStacked">@drawable/ab_stacked_solid_shadow</item>
|
||||
<item name="android:backgroundSplit">@drawable/ab_background_textured_shadow</item>
|
||||
</style>
|
||||
|
||||
<style name="ActionBar.Transparent.Shadow" parent="@android:style/Widget.Material.ActionBar">
|
||||
<item name="android:background">@drawable/ab_transparent_shadow</item>
|
||||
</style>
|
||||
|
||||
<style name="PopupMenu.Shadow" parent="@android:style/Widget.Material.ListPopupWindow">
|
||||
<item name="android:popupBackground">@drawable/menu_dropdown_panel_shadow</item>
|
||||
</style>
|
||||
|
||||
<style name="m_textAppearanceSmallPopupMenu" parent="@android:style/TextAppearance.Material.Widget.PopupMenu.Small">
|
||||
<item name="android:textColor">@android:color/black</item>
|
||||
</style>
|
||||
|
||||
<style name="m_textAppearanceLargePopupMenu" parent="@android:style/TextAppearance.Material.Widget.PopupMenu.Large">
|
||||
<item name="android:textColor">@android:color/black</item>
|
||||
</style>
|
||||
|
||||
<style name="DropDownListView.Shadow" parent="@android:style/Widget.Material.ListView.DropDown">
|
||||
<item name="android:listSelector">@drawable/selectable_background_shadow</item>
|
||||
</style>
|
||||
|
||||
<style name="ActionBarTabStyle.Shadow" parent="@android:style/Widget.Material.ActionBar.TabView">
|
||||
<item name="android:background">@drawable/tab_indicator_ab_shadow</item>
|
||||
</style>
|
||||
|
||||
<style name="DropDownNav.Shadow" parent="@android:style/Widget.Material.Spinner">
|
||||
<item name="android:background">@drawable/spinner_background_ab_shadow</item>
|
||||
<item name="android:popupBackground">@drawable/menu_dropdown_panel_shadow</item>
|
||||
<item name="android:dropDownSelector">@drawable/selectable_background_shadow</item>
|
||||
</style>
|
||||
|
||||
<!-- this style is only referenced in a Light.DarkActionBar based theme -->
|
||||
<style name="Theme.Shadow.Widget" parent="@android:style/Theme.Material">
|
||||
<item name="android:popupMenuStyle">@style/PopupMenu.Shadow</item>
|
||||
<item name="android:dropDownListViewStyle">@style/DropDownListView.Shadow</item>
|
||||
<item name="android:textColor">@android:color/white</item>
|
||||
<item name="android:textAppearanceLargePopupMenu">@style/m_textAppearanceLargePopupMenu</item>
|
||||
<item name="android:textAppearanceSmallPopupMenu" >@style/m_textAppearanceSmallPopupMenu</item>
|
||||
</style>
|
||||
|
||||
<style name="PopupTheme" parent="@android:style/Theme.Material.Light">
|
||||
<item name="android:windowActionBar">false</item>
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
<item name="android:windowFrame">@null</item>
|
||||
<item name="android:windowIsFloating">false</item>
|
||||
<item name="android:windowContentOverlay">@null</item>
|
||||
<item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
|
||||
<item name="android:windowSoftInputMode">stateAlwaysHidden</item>
|
||||
<item name="android:windowActionModeOverlay">true</item>
|
||||
<item name="android:colorBackgroundCacheHint">@null</item>
|
||||
<item name="android:windowCloseOnTouchOutside">true</item>
|
||||
<item name="android:windowIsTranslucent">true</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
@@ -49,7 +49,8 @@
|
||||
<string name="stopping">正在关闭...</string>
|
||||
<string name="vpn_error">后台服务启动失败:%s</string>
|
||||
<string name="ok_iknow">确定</string>
|
||||
<string name="port_alert">端口号应大于1024</string>
|
||||
<string name="close">关闭</string>
|
||||
<string name="port_alert">本地端口号应大于1024</string>
|
||||
<string name="port_empty">端口号不能为空</string>
|
||||
<string name="proxy_empty">代理服务器地址不能为空</string>
|
||||
<string name="crash_alert">检测到意外退出,状态已被重置。</string>
|
||||
@@ -67,6 +68,7 @@
|
||||
<string name="about_title">影梭(shadowsocks)%s</string>
|
||||
<string name="flush_dnscache">刷新 DNS 缓存</string>
|
||||
<string name="flushing">刷新中...</string>
|
||||
<string name="qrcode">二维码</string>
|
||||
<string name="add_profile">添加配置文件</string>
|
||||
|
||||
<string name="enable_nat">启用 NAT 模式.</string>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Executable → Regular
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Executable → Regular
+3
-1
@@ -65,7 +65,8 @@
|
||||
|
||||
<!-- alert category -->
|
||||
<string name="ok_iknow">OK</string>
|
||||
<string name="port_alert">The port number should be greater than 1024</string>
|
||||
<string name="close">Close</string>
|
||||
<string name="port_alert">The local port number should be greater than 1024</string>
|
||||
<string name="port_empty">Port should not be empty</string>
|
||||
<string name="proxy_empty">Proxy should not be empty</string>
|
||||
<string name="crash_alert">An unexpected exit detected, the context has been reset.
|
||||
@@ -84,6 +85,7 @@
|
||||
<string name="recovery">Reset</string>
|
||||
<string name="about">About</string>
|
||||
<string name="about_title">Shadowsocks %s</string>
|
||||
<string name="qrcode">QR Code</string>
|
||||
<string name="flush_dnscache">Flush DNS Cache</string>
|
||||
<string name="flushing">Flushing</string>
|
||||
<string name="add_profile">Add Profile</string>
|
||||
|
||||
@@ -19,7 +19,9 @@
|
||||
<style name="Theme.AppManager" parent="@style/Theme.Shadow">
|
||||
</style>
|
||||
|
||||
<style name="PopupTheme" parent="@android:style/Theme.Translucent.NoTitleBar">
|
||||
<style name="PopupTheme" parent="@android:style/Theme.Holo.Light">
|
||||
<item name="android:windowActionBar">false</item>
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
<item name="android:windowFrame">@null</item>
|
||||
<item name="android:windowIsFloating">false</item>
|
||||
<item name="android:windowContentOverlay">@null</item>
|
||||
@@ -72,4 +74,4 @@
|
||||
<item name="mdMenuSize">250dp</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
</resources>
|
||||
|
||||
Executable → Regular
+1
-1
@@ -35,7 +35,7 @@
|
||||
<item name="android:textAppearanceSmallPopupMenu" >@style/m_textAppearanceSmallPopupMenu</item>
|
||||
</style>
|
||||
|
||||
<style name="ActionBar.Solid.Shadow" parent="@android:style/Widget.Holo.Light.ActionBar.Solid.Inverse">
|
||||
<style name="ActionBar.Solid.Shadow" parent="@android:style/Widget.Holo.ActionBar">
|
||||
<item name="android:background">@drawable/ab_background_textured_shadow</item>
|
||||
<item name="android:backgroundStacked">@drawable/ab_stacked_solid_shadow</item>
|
||||
<item name="android:backgroundSplit">@drawable/ab_background_textured_shadow</item>
|
||||
|
||||
@@ -259,6 +259,9 @@ class AppManager extends Activity with OnCheckedChangeListener with OnClickListe
|
||||
}
|
||||
Toast.makeText(this, R.string.action_import_err, Toast.LENGTH_SHORT).show()
|
||||
return false
|
||||
case android.R.id.home =>
|
||||
navigateUpTo(getParentActivityIntent)
|
||||
return true
|
||||
}
|
||||
super.onOptionsItemSelected(item)
|
||||
}
|
||||
@@ -274,7 +277,10 @@ class AppManager extends Activity with OnCheckedChangeListener with OnClickListe
|
||||
|
||||
handler = new Handler()
|
||||
|
||||
getActionBar.setTitle(R.string.proxied_help)
|
||||
val actionBar = getActionBar()
|
||||
actionBar.setTitle(R.string.proxied_help)
|
||||
actionBar.setDisplayHomeAsUpEnabled(true)
|
||||
actionBar.setDisplayShowHomeEnabled(false)
|
||||
this.setContentView(R.layout.layout_apps)
|
||||
this.overlay = View.inflate(this, R.layout.overlay, null).asInstanceOf[TextView]
|
||||
getWindowManager.addView(overlay, new
|
||||
|
||||
@@ -41,6 +41,7 @@ package com.github.shadowsocks
|
||||
import java.util
|
||||
import java.io.{OutputStream, InputStream, ByteArrayInputStream, ByteArrayOutputStream, IOException, FileOutputStream}
|
||||
import java.util.Locale
|
||||
import java.lang.Math
|
||||
|
||||
import android.app.backup.BackupManager
|
||||
import android.app.{Activity, AlertDialog, ProgressDialog}
|
||||
@@ -66,6 +67,10 @@ import com.google.android.gms.analytics.HitBuilders
|
||||
import com.google.zxing.integration.android.IntentIntegrator
|
||||
import com.nostra13.universalimageloader.core.download.BaseImageDownloader
|
||||
import net.simonvt.menudrawer.MenuDrawer
|
||||
import com.joanzapata.android.iconify.Iconify
|
||||
import com.joanzapata.android.iconify.Iconify.IconValue
|
||||
import com.joanzapata.android.iconify.IconDrawable
|
||||
import net.glxn.qrgen.android.QRCode
|
||||
|
||||
import scala.collection.mutable.{ArrayBuffer, ListBuffer}
|
||||
import scala.concurrent.ops._
|
||||
@@ -321,7 +326,7 @@ class Shadowsocks
|
||||
}
|
||||
}
|
||||
|
||||
private def crash_recovery() {
|
||||
private def crashRecovery() {
|
||||
val cmd = new ArrayBuffer[String]()
|
||||
|
||||
for (task <- Array("ss-local", "ss-tunnel", "pdnsd", "redsocks", "tun2socks")) {
|
||||
@@ -366,19 +371,29 @@ class Shadowsocks
|
||||
|
||||
def isTextEmpty(s: String, msg: String): Boolean = {
|
||||
if (s == null || s.length <= 0) {
|
||||
new SnackBar.Builder(this).withMessage(msg).withStyle(SnackBar.Style.ALERT).show()
|
||||
new SnackBar.Builder(this)
|
||||
.withMessage(msg)
|
||||
.withActionMessageId(R.string.error)
|
||||
.withStyle(SnackBar.Style.ALERT)
|
||||
.withDuration(SnackBar.LONG_SNACK)
|
||||
.show()
|
||||
return true
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
def cancelStart() {
|
||||
handler.postDelayed(new Runnable {
|
||||
override def run() {
|
||||
clearDialog()
|
||||
changeSwitch(checked = false)
|
||||
}
|
||||
}, 1000)
|
||||
clearDialog()
|
||||
changeSwitch(checked = false)
|
||||
}
|
||||
|
||||
def isReady(): Boolean = {
|
||||
if (!checkText(Key.proxy)) return false
|
||||
if (!checkText(Key.sitekey)) return false
|
||||
if (!checkNumber(Key.localPort, low = false)) return false
|
||||
if (!checkNumber(Key.remotePort, low = true)) return false
|
||||
if (bgService == null) return false
|
||||
true
|
||||
}
|
||||
|
||||
def prepareStartService() {
|
||||
@@ -392,9 +407,7 @@ class Shadowsocks
|
||||
onActivityResult(Shadowsocks.REQUEST_CONNECT, Activity.RESULT_OK, null)
|
||||
}
|
||||
} else {
|
||||
if (!serviceStart) {
|
||||
cancelStart()
|
||||
}
|
||||
serviceStart()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -403,7 +416,10 @@ class Shadowsocks
|
||||
if (compoundButton eq switchButton) {
|
||||
checked match {
|
||||
case true =>
|
||||
prepareStartService()
|
||||
if (isReady)
|
||||
prepareStartService()
|
||||
else
|
||||
changeSwitch(checked = false)
|
||||
case false =>
|
||||
serviceStop()
|
||||
}
|
||||
@@ -479,10 +495,16 @@ class Shadowsocks
|
||||
menuAdapter.setListener(this)
|
||||
listView.setAdapter(menuAdapter)
|
||||
drawer.setMenuView(listView)
|
||||
// The drawable that replaces the up indicator in the action bar
|
||||
drawer.setSlideDrawable(R.drawable.ic_drawer)
|
||||
// Whether the previous drawable should be shown
|
||||
drawer.setDrawerIndicatorEnabled(true)
|
||||
|
||||
if (Utils.isLollipopOrAbove) {
|
||||
drawer.setDrawerIndicatorEnabled(false)
|
||||
} else {
|
||||
// The drawable that replaces the up indicator in the action bar
|
||||
drawer.setSlideDrawable(R.drawable.ic_drawer)
|
||||
// Whether the previous drawable should be shown
|
||||
drawer.setDrawerIndicatorEnabled(true)
|
||||
}
|
||||
|
||||
if (!isSinglePane) {
|
||||
drawer.openMenu(false)
|
||||
}
|
||||
@@ -498,7 +520,14 @@ class Shadowsocks
|
||||
getActionBar.setCustomView(switchLayout)
|
||||
getActionBar.setDisplayShowTitleEnabled(false)
|
||||
getActionBar.setDisplayShowCustomEnabled(true)
|
||||
getActionBar.setIcon(R.drawable.ic_stat_shadowsocks)
|
||||
if (Utils.isLollipopOrAbove) {
|
||||
getWindow.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
|
||||
getWindow.setStatusBarColor(getResources().getColor(R.color.grey3));
|
||||
getActionBar.setDisplayHomeAsUpEnabled(true)
|
||||
getActionBar.setHomeAsUpIndicator(R.drawable.ic_drawer)
|
||||
} else {
|
||||
getActionBar.setIcon(R.drawable.ic_stat_shadowsocks)
|
||||
}
|
||||
title.setOnLongClickListener(new OnLongClickListener {
|
||||
override def onLongClick(v: View): Boolean = {
|
||||
if (Utils.isLollipopOrAbove && bgService != null
|
||||
@@ -609,6 +638,25 @@ class Shadowsocks
|
||||
builder.create().show()
|
||||
}
|
||||
|
||||
def reloadProfile() {
|
||||
drawer.closeMenu(true)
|
||||
|
||||
val h = showProgress(getString(R.string.loading))
|
||||
|
||||
handler.postDelayed(new Runnable {
|
||||
def run() {
|
||||
currentProfile = {
|
||||
profileManager.getProfile(settings.getInt(Key.profileId, -1)) getOrElse currentProfile
|
||||
}
|
||||
menuAdapter.updateList(getMenuList, currentProfile.id)
|
||||
|
||||
updatePreferenceScreen()
|
||||
|
||||
h.sendEmptyMessage(0)
|
||||
}
|
||||
}, 600)
|
||||
}
|
||||
|
||||
def addProfile(profile: Profile) {
|
||||
drawer.closeMenu(true)
|
||||
|
||||
@@ -700,7 +748,7 @@ class Shadowsocks
|
||||
|
||||
def getProfileList: List[Item] = {
|
||||
val list = profileManager.getAllProfiles getOrElse List[Profile]()
|
||||
list.map(p => new Item(p.id, p.name, -1, updateProfile, delProfile))
|
||||
list.map(p => new IconItem(p.id, p.name, -1, updateProfile, delProfile))
|
||||
}
|
||||
|
||||
def getMenuList: List[Any] = {
|
||||
@@ -712,11 +760,13 @@ class Shadowsocks
|
||||
buf ++= getProfileList
|
||||
|
||||
buf +=
|
||||
new Item(-400, getString(R.string.add_profile), android.R.drawable.ic_menu_add, newProfile)
|
||||
new DrawableItem(-400, getString(R.string.add_profile), new IconDrawable(this, IconValue.fa_plus_circle)
|
||||
.colorRes(android.R.color.darker_gray).sizeDp(26), newProfile)
|
||||
|
||||
buf += new Category(getString(R.string.settings))
|
||||
|
||||
buf += new Item(-100, getString(R.string.recovery), android.R.drawable.ic_menu_revert, _ => {
|
||||
buf += new DrawableItem(-100, getString(R.string.recovery), new IconDrawable(this, IconValue.fa_recycle)
|
||||
.colorRes(android.R.color.darker_gray).sizeDp(26), _ => {
|
||||
// send event
|
||||
application.tracker.send(new HitBuilders.EventBuilder()
|
||||
.setCategory(Shadowsocks.TAG)
|
||||
@@ -727,7 +777,8 @@ class Shadowsocks
|
||||
})
|
||||
|
||||
buf +=
|
||||
new Item(-200, getString(R.string.flush_dnscache), android.R.drawable.ic_menu_delete, _ => {
|
||||
new DrawableItem(-200, getString(R.string.flush_dnscache), new IconDrawable(this, IconValue.fa_refresh)
|
||||
.colorRes(android.R.color.darker_gray).sizeDp(26), _ => {
|
||||
// send event
|
||||
application.tracker.send(new HitBuilders.EventBuilder()
|
||||
.setCategory(Shadowsocks.TAG)
|
||||
@@ -737,7 +788,20 @@ class Shadowsocks
|
||||
flushDnsCache()
|
||||
})
|
||||
|
||||
buf += new Item(-300, getString(R.string.about), android.R.drawable.ic_menu_info_details, _ => {
|
||||
buf +=
|
||||
new DrawableItem(-300, getString(R.string.qrcode), new IconDrawable(this, IconValue.fa_qrcode)
|
||||
.colorRes(android.R.color.darker_gray).sizeDp(26), _ => {
|
||||
// send event
|
||||
application.tracker.send(new HitBuilders.EventBuilder()
|
||||
.setCategory(Shadowsocks.TAG)
|
||||
.setAction("qrcode")
|
||||
.setLabel(getVersionName)
|
||||
.build())
|
||||
showQrCode()
|
||||
})
|
||||
|
||||
buf += new DrawableItem(-400, getString(R.string.about), new IconDrawable(this, IconValue.fa_info_circle)
|
||||
.colorRes(android.R.color.darker_gray).sizeDp(26), _ => {
|
||||
// send event
|
||||
application.tracker.send(new HitBuilders.EventBuilder()
|
||||
.setCategory(Shadowsocks.TAG)
|
||||
@@ -781,6 +845,10 @@ class Shadowsocks
|
||||
switchButton.setOnCheckedChangeListener(Shadowsocks.this)
|
||||
}
|
||||
ConfigUtils.refresh(this)
|
||||
|
||||
// Check if profile list changed
|
||||
if (currentProfile.id != settings.getInt(Key.profileId, -1))
|
||||
reloadProfile()
|
||||
}
|
||||
|
||||
private def setPreferenceEnabled(enabled: Boolean) {
|
||||
@@ -849,7 +917,7 @@ class Shadowsocks
|
||||
|
||||
def reset() {
|
||||
|
||||
crash_recovery()
|
||||
crashRecovery()
|
||||
|
||||
copyAssets(System.getABI)
|
||||
|
||||
@@ -870,6 +938,31 @@ class Shadowsocks
|
||||
}
|
||||
}
|
||||
|
||||
private def dp2px(dp: Int): Int = {
|
||||
val displayMetrics = getBaseContext.getResources.getDisplayMetrics()
|
||||
Math.round(dp * (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT))
|
||||
}
|
||||
|
||||
private def showQrCode() {
|
||||
val image = new ImageView(this)
|
||||
image.setPadding(0, dp2px(20), 0, dp2px(20))
|
||||
image.setLayoutParams(new LinearLayout.LayoutParams(-1, -1))
|
||||
val qrcode = QRCode.from(Parser.generate(currentProfile))
|
||||
.withSize(dp2px(250), dp2px(250)).asInstanceOf[QRCode]
|
||||
image.setImageBitmap(qrcode.bitmap())
|
||||
|
||||
new AlertDialog.Builder(this)
|
||||
.setCancelable(true)
|
||||
.setNegativeButton(getString(R.string.close), new DialogInterface.OnClickListener() {
|
||||
override def onClick(dialog: DialogInterface, id: Int) {
|
||||
dialog.cancel()
|
||||
}
|
||||
})
|
||||
.setView(image)
|
||||
.create()
|
||||
.show()
|
||||
}
|
||||
|
||||
private def flushDnsCache() {
|
||||
val h = showProgress(getString(R.string.flushing))
|
||||
spawn {
|
||||
@@ -889,9 +982,7 @@ class Shadowsocks
|
||||
resultCode match {
|
||||
case Activity.RESULT_OK =>
|
||||
prepared = true
|
||||
if (!serviceStart) {
|
||||
cancelStart()
|
||||
}
|
||||
serviceStart()
|
||||
case _ =>
|
||||
cancelStart()
|
||||
Log.e(Shadowsocks.TAG, "Failed to start VpnService")
|
||||
@@ -925,33 +1016,34 @@ class Shadowsocks
|
||||
try {
|
||||
val port: Int = Integer.valueOf(text)
|
||||
if (!low && port <= 1024) {
|
||||
new SnackBar.Builder(this).withMessageId(R.string.port_alert).withStyle(SnackBar.Style.ALERT).show()
|
||||
new SnackBar.Builder(this)
|
||||
.withMessageId(R.string.port_alert)
|
||||
.withActionMessageId(R.string.error)
|
||||
.withStyle(SnackBar.Style.ALERT)
|
||||
.withDuration(SnackBar.LONG_SNACK)
|
||||
.show()
|
||||
return false
|
||||
}
|
||||
} catch {
|
||||
case ex: Exception =>
|
||||
new SnackBar.Builder(this).withMessageId(R.string.port_alert).withStyle(SnackBar.Style.ALERT).show()
|
||||
new SnackBar.Builder(this)
|
||||
.withMessageId(R.string.port_alert)
|
||||
.withActionMessageId(R.string.error)
|
||||
.withStyle(SnackBar.Style.ALERT)
|
||||
.withDuration(SnackBar.LONG_SNACK)
|
||||
.show()
|
||||
return false
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
/** Called when connect button is clicked. */
|
||||
def serviceStart: Boolean = {
|
||||
|
||||
if (!checkText(Key.proxy)) return false
|
||||
if (!checkText(Key.sitekey)) return false
|
||||
if (!checkNumber(Key.localPort, low = false)) return false
|
||||
if (!checkNumber(Key.remotePort, low = true)) return false
|
||||
|
||||
if (bgService == null) return false
|
||||
|
||||
def serviceStart() {
|
||||
bgService.start(ConfigUtils.load(settings))
|
||||
|
||||
if (isVpnEnabled) {
|
||||
changeSwitch(checked = false)
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
private def showAbout() {
|
||||
|
||||
@@ -348,7 +348,7 @@ class ShadowsocksNatService extends Service with BaseService {
|
||||
actionIntent)
|
||||
|
||||
if (visible)
|
||||
builder.setPriority(NotificationCompat.PRIORITY_MAX)
|
||||
builder.setPriority(NotificationCompat.PRIORITY_DEFAULT)
|
||||
else
|
||||
builder.setPriority(NotificationCompat.PRIORITY_MIN)
|
||||
|
||||
|
||||
@@ -58,7 +58,9 @@ class ShadowsocksRunnerActivity extends Activity {
|
||||
override def onServiceConnected(name: ComponentName, service: IBinder) {
|
||||
bgService = IShadowsocksService.Stub.asInterface(service)
|
||||
handler.postDelayed(new Runnable() {
|
||||
override def run() = startBackgroundService()
|
||||
override def run() {
|
||||
if (bgService != null) startBackgroundService()
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
override def onServiceDisconnected(name: ComponentName) {
|
||||
|
||||
@@ -153,7 +153,7 @@ class ShadowsocksVpnService extends VpnService with BaseService {
|
||||
|
||||
def startDnsDaemon() {
|
||||
val conf = {
|
||||
if (Utils.isLollipopOrAbove && config.route == Route.BYPASS_CHN) {
|
||||
if (config.route == Route.BYPASS_CHN) {
|
||||
val reject = ConfigUtils.getRejectList(getContext, application)
|
||||
val blackList = ConfigUtils.getBlackList(getContext, application)
|
||||
ConfigUtils.PDNSD_DIRECT.formatLocal(Locale.ENGLISH, "0.0.0.0", 8153,
|
||||
|
||||
@@ -45,11 +45,24 @@ import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.BaseAdapter
|
||||
import android.widget.TextView
|
||||
import android.graphics.drawable.Drawable
|
||||
import com.github.shadowsocks.{R}
|
||||
import android.view.View.{OnLongClickListener, OnClickListener}
|
||||
|
||||
case class Item(id: Int, title: String, iconRes: Int,
|
||||
abstract class Item {
|
||||
def id: Int
|
||||
def title: String
|
||||
def click: Int => Unit
|
||||
def longClick: Int => Boolean
|
||||
}
|
||||
|
||||
case class IconItem(id: Int, title: String, iconRes: Int,
|
||||
click: Int => Unit, longClick: Int => Boolean = _ => false)
|
||||
extends Item
|
||||
|
||||
case class DrawableItem(id: Int, title: String, iconRes: Drawable,
|
||||
click: Int => Unit, longClick: Int => Boolean = _ => false)
|
||||
extends Item
|
||||
|
||||
case class Category(title: String)
|
||||
|
||||
@@ -89,7 +102,8 @@ class MenuAdapter(context: Context, var items: List[Any]) extends BaseAdapter {
|
||||
@Override override def getItemViewType(position: Int): Int = {
|
||||
getItem(position) match {
|
||||
case Category => MenuAdapter.CATEGORY
|
||||
case Item => MenuAdapter.ITEM
|
||||
case IconItem => MenuAdapter.ITEM
|
||||
case DrawableItem => MenuAdapter.ITEM
|
||||
case _ => MenuAdapter.UNDEFINED
|
||||
}
|
||||
}
|
||||
@@ -121,9 +135,18 @@ 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)
|
||||
|
||||
value match {
|
||||
case iconItem: IconItem =>
|
||||
if (iconItem.iconRes != -1) {
|
||||
tv.setCompoundDrawablesWithIntrinsicBounds(iconItem.iconRes, 0, 0, 0)
|
||||
}
|
||||
case drawableItem: DrawableItem =>
|
||||
if (drawableItem.iconRes != null) {
|
||||
tv.setCompoundDrawablesWithIntrinsicBounds(drawableItem.iconRes, null, null, null)
|
||||
}
|
||||
}
|
||||
|
||||
tv.setOnClickListener(new OnClickListener {
|
||||
def onClick(view: View) {
|
||||
val item = view.getTag(R.id.mdItem).asInstanceOf[Item]
|
||||
|
||||
@@ -82,6 +82,9 @@ object ConfigUtils {
|
||||
| label = "local";
|
||||
| ip = 127.0.0.1;
|
||||
| port = %d;
|
||||
| reject = ::/0;
|
||||
| reject_policy = negate;
|
||||
| reject_recursively = on;
|
||||
| timeout = 5;
|
||||
|}
|
||||
|
|
||||
|
||||
@@ -40,11 +40,19 @@
|
||||
package com.github.shadowsocks.utils
|
||||
|
||||
import com.github.shadowsocks.database.Profile
|
||||
import java.util.Locale
|
||||
import android.net.Uri
|
||||
import android.util.{Log, Base64}
|
||||
|
||||
object Parser {
|
||||
val TAG = "ShadowParser"
|
||||
|
||||
def generate (profile: Profile): String = {
|
||||
val path = "%s:%s@%s:%d".formatLocal(Locale.ENGLISH,
|
||||
profile.method, profile.password, profile.host, profile.remotePort)
|
||||
return "ss://" + Base64.encodeToString(path.getBytes, Base64.NO_PADDING)
|
||||
}
|
||||
|
||||
def parse (data: String): Option[Profile] = {
|
||||
try {
|
||||
Log.d(TAG, data)
|
||||
@@ -65,7 +73,7 @@ object Parser {
|
||||
profile.host = host
|
||||
profile.remotePort = port.toInt
|
||||
profile.localPort = 1080
|
||||
profile.method = method
|
||||
profile.method = method.toLowerCase
|
||||
profile.password = password
|
||||
return Some(profile)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user