Compare commits

...
16 Commits
Author SHA1 Message Date
Max Lv fa083a8eca fix #295 2015-05-08 08:57:40 +08:00
Max Lv ef2ff23cd0 fix the style on lolipop 2015-05-02 22:51:26 +08:00
Max Lv c1e208737c Merge pull request #287 from vmlinz/master
Update sbt and sbt-android-plugin
2015-05-01 14:00:35 +08:00
Zaicheng Qi 75bb00593a Add jcenter resolver and update sbt to 0.13.8 2015-05-01 11:38:30 +08:00
Zaicheng Qi 15f25b95a0 Update sbt-android plugin to latest 2015-05-01 10:55:29 +08:00
Max Lv cc9fa4c4a6 refine the drawer indicator 2015-04-30 17:29:40 +08:00
Max Lv 9041404f42 add partial material design 2015-04-30 16:44:27 +08:00
Max Lv 5aae822cdd add qr code 2015-04-29 13:06:27 +08:00
Max Lv 33ed5c65c5 fix #279 2015-04-22 16:52:02 +08:00
Max Lv 1424e056ac disable IPv6 resolver in all route mode. #275 2015-04-09 17:32:00 +08:00
Max Lv ed79e0090e Update README.md 2015-04-08 17:34:10 +08:00
Max Lv 304113ce97 Update README.md 2015-04-08 14:52:21 +08:00
Max Lv 290bf8cb31 Delete .travis.yml 2015-04-08 14:31:45 +08:00
Max Lv fcb0e2ace3 Update README.md 2015-04-08 14:31:30 +08:00
Max Lv f240d5d202 bump version 2015-03-19 16:43:38 +08:00
Max Lv ea85bbd83d refine DNS on Kitkat 2015-03-19 16:34:22 +08:00
22 changed files with 290 additions and 86 deletions
-28
View File
@@ -1,28 +0,0 @@
language: android
android:
components:
- tools
- platform-tools
- build-tools-21.1.1
- android-21
- extra-google-m2repository
- extra-android-m2repository
cache:
- apt
before_install:
- echo "deb https://dl.bintray.com/sbt/debian /" | sudo tee -a /etc/apt/sources.list.d/sbt.list
- sudo apt-get update
install:
- sudo apt-get install -y --force-yes sbt 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/ndk/android-ndk-r10d-linux-${ARCH}.bin
- chmod +x android-ndk-r10d-linux-${ARCH}.bin
- ./android-ndk-r10d-linux-${ARCH}.bin -y | grep gcc
- export ANDROID_NDK_HOME=`pwd`/android-ndk-r10d
- export PATH=${PATH}:${ANDROID_NDK_HOME}:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools
script:
- cp local.properties.travis local.properties
- ./build.sh
- sbt android:package-release
- exit 0
+4 -4
View File
@@ -6,14 +6,14 @@ Help to translate shadowsocks: http://crowdin.net/project/shadowsocks/invite
[![Google Play](http://developer.android.com/images/brand/en_generic_rgb_wo_45.png)](https://play.google.com/store/apps/details?id=com.github.shadowsocks)
### TRAVIS CI STATUS
### CI STATUS
[![Build Status](https://secure.travis-ci.org/shadowsocks/shadowsocks-android.png)](http://travis-ci.org/shadowsocks/shadowsocks-android)
[![Build Status](https://drone.io/github.com/shadowsocks/shadowsocks-android/status.png)](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+
+6 -3
View File
@@ -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.**")
+1 -1
View File
@@ -1 +1 @@
sbt.version=0.13.5
sbt.version=0.13.8
+1 -1
View File
@@ -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")
+2 -2
View File
@@ -1,7 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.github.shadowsocks"
android:versionCode="103"
android:versionName="2.6.5">
android:versionCode="104"
android:versionName="2.6.6">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

+1 -1
View File
@@ -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"
+96
View File
@@ -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>
+3 -1
View File
@@ -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>
+3 -1
View File
@@ -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>
+4 -2
View File
@@ -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>
+1 -1
View File
@@ -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>
@@ -280,6 +280,7 @@ class AppManager extends Activity with OnCheckedChangeListener with OnClickListe
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._
@@ -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) {
@@ -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() {
@@ -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)