Commit 257b44f3 authored by Max Lv's avatar Max Lv

Merge pull request #417 from Mygod/master

Some final touches
parents 7d581508 63bc4a57
...@@ -64,7 +64,7 @@ ...@@ -64,7 +64,7 @@
<activity <activity
android:name=".ProfileManagerActivity" android:name=".ProfileManagerActivity"
android:label="@string/app_name" android:label="@string/profiles"
android:parentActivityName=".Shadowsocks" android:parentActivityName=".Shadowsocks"
android:exported="false"> android:exported="false">
<intent-filter> <intent-filter>
...@@ -75,14 +75,8 @@ ...@@ -75,14 +75,8 @@
<activity <activity
android:name=".AppManager" android:name=".AppManager"
android:label="@string/app_name" android:label="@string/proxied_apps"
android:parentActivityName=".Shadowsocks" android:parentActivityName=".Shadowsocks"/>
android:exported="false">
<intent-filter>
<action android:name="com.github.shadowsocks.AppManager"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<service <service
android:name=".ShadowsocksRunnerService" android:name=".ShadowsocksRunnerService"
......
...@@ -5,10 +5,8 @@ import android.os.Parcelable; ...@@ -5,10 +5,8 @@ import android.os.Parcelable;
public class Config implements Parcelable { public class Config implements Parcelable {
public boolean isGlobalProxy = true; public boolean isProxyApps = false;
public boolean isGFWList = true;
public boolean isBypassApps = false; public boolean isBypassApps = false;
public boolean isTrafficStat = false;
public boolean isUdpDns = false; public boolean isUdpDns = false;
public boolean isAuth = false; public boolean isAuth = false;
public boolean isIpv6 = false; public boolean isIpv6 = false;
...@@ -34,13 +32,11 @@ public class Config implements Parcelable { ...@@ -34,13 +32,11 @@ public class Config implements Parcelable {
} }
}; };
public Config(boolean isGlobalProxy, boolean isGFWList, boolean isBypassApps, public Config(boolean isProxyApps, boolean isBypassApps,
boolean isTrafficStat, boolean isUdpDns, boolean isAuth, boolean isIpv6, String profileName, String proxy, String sitekey, boolean isUdpDns, boolean isAuth, boolean isIpv6, String profileName, String proxy, String sitekey,
String encMethod, String proxiedAppString, String route, int remotePort, int localPort) { String encMethod, String proxiedAppString, String route, int remotePort, int localPort) {
this.isGlobalProxy = isGlobalProxy; this.isProxyApps = isProxyApps;
this.isGFWList = isGFWList;
this.isBypassApps = isBypassApps; this.isBypassApps = isBypassApps;
this.isTrafficStat = isTrafficStat;
this.isUdpDns = isUdpDns; this.isUdpDns = isUdpDns;
this.isAuth = isAuth; this.isAuth = isAuth;
this.isIpv6 = isIpv6; this.isIpv6 = isIpv6;
...@@ -59,10 +55,8 @@ public class Config implements Parcelable { ...@@ -59,10 +55,8 @@ public class Config implements Parcelable {
} }
public void readFromParcel(Parcel in) { public void readFromParcel(Parcel in) {
isGlobalProxy = in.readInt() == 1; isProxyApps = in.readInt() == 1;
isGFWList = in.readInt() == 1;
isBypassApps = in.readInt() == 1; isBypassApps = in.readInt() == 1;
isTrafficStat = in.readInt() == 1;
isUdpDns = in.readInt() == 1; isUdpDns = in.readInt() == 1;
isAuth = in.readInt() == 1; isAuth = in.readInt() == 1;
isIpv6 = in.readInt() == 1; isIpv6 = in.readInt() == 1;
...@@ -81,10 +75,8 @@ public class Config implements Parcelable { ...@@ -81,10 +75,8 @@ public class Config implements Parcelable {
} }
@Override public void writeToParcel(Parcel out, int flags) { @Override public void writeToParcel(Parcel out, int flags) {
out.writeInt(isGlobalProxy ? 1 : 0); out.writeInt(isProxyApps ? 1 : 0);
out.writeInt(isGFWList ? 1 : 0);
out.writeInt(isBypassApps ? 1 : 0); out.writeInt(isBypassApps ? 1 : 0);
out.writeInt(isTrafficStat ? 1 : 0);
out.writeInt(isUdpDns ? 1 : 0); out.writeInt(isUdpDns ? 1 : 0);
out.writeInt(isAuth ? 1 : 0); out.writeInt(isAuth ? 1 : 0);
out.writeInt(isIpv6 ? 1 : 0); out.writeInt(isIpv6 ? 1 : 0);
......
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout <LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="fill_parent" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent" android:layout_height="fill_parent"
android:orientation="vertical" android:orientation="vertical"
android:duplicateParentState="false"> android:duplicateParentState="false">
<include layout="@layout/toolbar_light_dark"/> <include layout="@layout/toolbar_light_dark"/>
<LinearLayout <LinearLayout android:layout_width="fill_parent"
android:layout_width="fill_parent" android:layout_height="wrap_content"
android:layout_height="wrap_content" android:paddingLeft="48dp"
android:paddingBottom="8dp" android:paddingStart="48dp"
android:paddingLeft="48dp" android:elevation="1dp"
android:paddingStart="48dp" android:background="@android:color/white"
android:paddingTop="8dp" android:orientation="vertical"
android:background="@android:color/white" tools:ignore="RtlSymmetry">
android:elevation="1dp" tools:ignore="RtlSymmetry"> <LinearLayout
<TextView android:layout_width="fill_parent"
android:id="@+id/bypassLabel" android:layout_height="wrap_content"
android:layout_width="0dp" android:layout_margin="8dp">
android:layout_weight="1" <TextView
android:layout_height="wrap_content" android:layout_width="0dp"
android:padding="3dp" android:layout_weight="1"
android:gravity="center_vertical" android:layout_height="wrap_content"
android:textSize="18sp" android:padding="4dp"
android:text="@string/bypass_apps"/> android:gravity="center_vertical"
android:textSize="18sp"
android:text="@string/on"/>
<Switch android:checked="true"
android:id="@+id/onSwitch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp">
<TextView
android:id="@+id/bypassLabel"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:padding="4dp"
android:gravity="center_vertical"
android:textSize="18sp"
android:text="@string/bypass_apps"/>
<Switch <Switch
android:id="@+id/bypassSwitch" android:id="@+id/bypassSwitch"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"/>
android:layout_marginEnd="6dp" </LinearLayout>
android:layout_marginRight="6dp"/>
</LinearLayout> </LinearLayout>
<FrameLayout android:layout_width="fill_parent" <FrameLayout android:layout_width="fill_parent"
android:layout_height="0dp" android:layout_height="0dp"
......
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:layout_height="fill_parent"
android:stretchColumns="1"> android:background="?android:attr/selectableItemBackground">
<TableRow>
<ImageView <ImageView
android:id="@+id/itemicon" android:id="@+id/itemicon"
android:layout_width="48dp" android:layout_width="60dp"
android:layout_height="48dp" android:layout_height="48dp"
android:scaleType="fitCenter" android:scaleType="fitCenter"
android:padding="3dp"/> android:paddingLeft="8dp"
android:paddingRight="8dp"
android:paddingTop="2dp"
android:paddingBottom="2dp"/>
<TextView <TextView
android:id="@+id/itemtext" android:id="@+id/itemtext"
android:layout_width="wrap_content" android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="fill_parent" android:layout_height="fill_parent"
android:text="uid:packages"
android:gravity="center_vertical" android:gravity="center_vertical"
android:maxLength="25" android:ellipsize="end"
android:textSize="18sp" android:textSize="18sp"/>
android:padding="3dp"/>
<Switch <Switch
android:id="@+id/itemcheck" android:id="@+id/itemcheck"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="fill_parent" android:layout_height="fill_parent"
android:layout_marginRight="6dp"/> android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"/>
</TableRow> </LinearLayout>
</TableLayout>
...@@ -2,9 +2,8 @@ ...@@ -2,9 +2,8 @@
<!--Generated by crowdin.net--> <!--Generated by crowdin.net-->
<resources> <resources>
<string name="app_name">影梭</string> <string name="app_name">影梭</string>
<string name="screen_name">shadowsocks</string>
<string name="global_cat">全局设置</string> <string name="global_cat">全局设置</string>
<string name="misc_cat">杂项</string> <string name="misc_cat">其他</string>
<string name="proxy_cat">服务器设置</string> <string name="proxy_cat">服务器设置</string>
<string name="profile_name">配置名称</string> <string name="profile_name">配置名称</string>
<string name="profile">配置文件</string> <string name="profile">配置文件</string>
...@@ -12,9 +11,9 @@ ...@@ -12,9 +11,9 @@
<string name="proxy">服务器</string> <string name="proxy">服务器</string>
<string name="proxy_summary">远程服务器的地址</string> <string name="proxy_summary">远程服务器的地址</string>
<string name="remote_port">远程端口</string> <string name="remote_port">远程端口</string>
<string name="remote_port_summary">远程服务器的端口号</string> <string name="remote_port_summary">%d(远程服务器的端口号)</string>
<string name="port">本地端口</string> <string name="port">本地端口</string>
<string name="port_summary">本地客户端的端口号</string> <string name="port_summary">%d(本地客户端的端口号)</string>
<string name="sitekey">密码</string> <string name="sitekey">密码</string>
<string name="sitekey_summary">远程服务器的密码</string> <string name="sitekey_summary">远程服务器的密码</string>
<string name="enc_method">加密方法</string> <string name="enc_method">加密方法</string>
...@@ -26,11 +25,9 @@ ...@@ -26,11 +25,9 @@
<string name="auto_set_gfwlist">国内路由</string> <string name="auto_set_gfwlist">国内路由</string>
<string name="auto_set_gfwlist_summary">绕过所有位于中国的网站</string> <string name="auto_set_gfwlist_summary">绕过所有位于中国的网站</string>
<string name="route_list">路由</string> <string name="route_list">路由</string>
<string name="auto_set_proxy">全局代理</string>
<string name="auto_set_proxy_summary">设置系统代理</string>
<string name="proxied_apps">分应用代理</string> <string name="proxied_apps">分应用代理</string>
<string name="proxied_apps_summary">为应用程序分别设置代理</string> <string name="proxied_apps_summary">为应用程序分别设置代理</string>
<string name="proxied_help">分应用代理</string> <string name="on"></string>
<string name="bypass_apps">绕行模式</string> <string name="bypass_apps">绕行模式</string>
<string name="bypass_apps_summary">启用该选项,以使所选应用程序的流量不经过代理</string> <string name="bypass_apps_summary">启用该选项,以使所选应用程序的流量不经过代理</string>
<string name="auto_connect">自动连接</string> <string name="auto_connect">自动连接</string>
...@@ -44,8 +41,6 @@ ...@@ -44,8 +41,6 @@
<string name="stopping">正在关闭……</string> <string name="stopping">正在关闭……</string>
<string name="vpn_error">后台服务启动失败:%s</string> <string name="vpn_error">后台服务启动失败:%s</string>
<string name="close">关闭</string> <string name="close">关闭</string>
<string name="port_alert">本地端口号应大于1024</string>
<string name="port_empty">端口号不能为空</string>
<string name="proxy_empty">代理服务器地址不能为空</string> <string name="proxy_empty">代理服务器地址不能为空</string>
<string name="connect">连接</string> <string name="connect">连接</string>
<string name="initializing">正在初始化……</string> <string name="initializing">正在初始化……</string>
...@@ -59,20 +54,20 @@ ...@@ -59,20 +54,20 @@
<string name="about">关于</string> <string name="about">关于</string>
<string name="about_title">影梭(shadowsocks)%s</string> <string name="about_title">影梭(shadowsocks)%s</string>
<string name="flush_dnscache">刷新 DNS 缓存</string> <string name="flush_dnscache">刷新 DNS 缓存</string>
<string name="flush_dnscache_summary">需要 ROOT 权限</string> <string name="flush_dnscache_summary_disabled">需要 ROOT 权限</string>
<string name="flushing">刷新中……</string> <string name="flushing">刷新中……</string>
<string name="qrcode">二维码</string> <string name="qrcode">二维码</string>
<string name="add_profile">添加配置文件</string> <string name="add_profile">添加配置文件</string>
<string name="nat">NAT 模式 (仅限调试)</string> <string name="nat">NAT 模式 (仅限调试)</string>
<string name="nat_summary">停用 VPN 模式,启用 NAT 模式</string> <string name="nat_summary">从 VPN 模式切换为 NAT 模式</string>
<string name="nat_summary_no_root">NAT 模式已禁用,需要 ROOT 权限</string> <string name="nat_summary_no_root">NAT 模式已禁用,需要 ROOT 权限</string>
<string name="udp_dns">UDP 转发</string> <string name="udp_dns">UDP 转发</string>
<string name="udp_dns_summary">由远程服务器转发 UDP 协议的数据包</string> <string name="udp_dns_summary">由远程服务器转发 UDP 协议的数据包</string>
<string name="onetime_auth">一次性认证</string> <string name="onetime_auth">一次性认证</string>
<string name="onetime_auth_summary">启用一次性认证(实验性)</string> <string name="onetime_auth_summary">启用一次性认证(实验性)</string>
<string name="ipv6">IPv6 路由</string> <string name="ipv6">IPv6 路由</string>
<string name="ipv6_summary">向远程服务器转发 IPv6 流量</string> <string name="ipv6_summary">向远程服务器转发 IPv6 流量</string>
......
...@@ -7,4 +7,8 @@ ...@@ -7,4 +7,8 @@
<attr name="entries" format="reference" /> <attr name="entries" format="reference" />
<attr name="entryValues" format="reference" /> <attr name="entryValues" format="reference" />
</declare-styleable> </declare-styleable>
</resources> <declare-styleable name="NumberPickerPreference">
\ No newline at end of file <attr name="max" format="integer" />
<attr name="min" format="integer" />
</declare-styleable>
</resources>
This diff is collapsed.
...@@ -2,16 +2,16 @@ ...@@ -2,16 +2,16 @@
<resources> <resources>
<string name="app_name">Shadowsocks</string> <string name="app_name">Shadowsocks</string>
<string name="screen_name">shadowsocks</string> <string name="screen_name" translatable="false">shadowsocks</string>
<!-- global/misc category --> <!-- global/misc category -->
<string name="global_cat">Global Settings</string> <string name="global_cat">Global Settings</string>
<string name="misc_cat">Misc</string> <string name="misc_cat">Misc</string>
<string name="profile">Profile</string> <string name="profile">Profile</string>
<string name="profile_summary">Switch to another profile</string> <string name="profile_summary">Switch to another profile or add new profiles</string>
<string name="nat">NAT mode (deprecated)</string> <string name="nat">NAT mode (deprecated)</string>
<string name="nat_summary">Use NAT mode instead of VPN mode.</string> <string name="nat_summary">Use NAT mode instead of VPN mode</string>
<string name="nat_summary_no_root">NAT mode is disabled without root.</string> <string name="nat_summary_no_root">NAT mode is disabled without root</string>
<!-- proxy category --> <!-- proxy category -->
<string name="proxy_cat">Server Settings</string> <string name="proxy_cat">Server Settings</string>
...@@ -19,9 +19,9 @@ ...@@ -19,9 +19,9 @@
<string name="proxy">Server</string> <string name="proxy">Server</string>
<string name="proxy_summary">Hostname or IP of the remote server</string> <string name="proxy_summary">Hostname or IP of the remote server</string>
<string name="remote_port">Remote Port</string> <string name="remote_port">Remote Port</string>
<string name="remote_port_summary">Port number of the remote server</string> <string name="remote_port_summary">%d (port number of the remote server)</string>
<string name="port">Local Port</string> <string name="port">Local Port</string>
<string name="port_summary">Port number of the local server</string> <string name="port_summary">%d (port number of the local server)</string>
<string name="sitekey">Password</string> <string name="sitekey">Password</string>
<string name="sitekey_summary">Password of the remote server</string> <string name="sitekey_summary">Password of the remote server</string>
<string name="enc_method">Encrypt Method</string> <string name="enc_method">Encrypt Method</string>
...@@ -40,11 +40,9 @@ ...@@ -40,11 +40,9 @@
<string name="auto_set_gfwlist_summary">Bypass all sites located in China <string name="auto_set_gfwlist_summary">Bypass all sites located in China
</string> </string>
<string name="route_list">Route</string> <string name="route_list">Route</string>
<string name="auto_set_proxy">Global Proxy</string>
<string name="auto_set_proxy_summary">Set up system-wide proxy</string>
<string name="proxied_apps">Per-App Proxy</string> <string name="proxied_apps">Per-App Proxy</string>
<string name="proxied_apps_summary">Set proxy for selected apps</string> <string name="proxied_apps_summary">Set proxy for selected apps</string>
<string name="proxied_help">Per-App Proxy</string> <string name="on">On</string>
<string name="bypass_apps">Bypass Mode</string> <string name="bypass_apps">Bypass Mode</string>
<string name="bypass_apps_summary">Enable this option to bypass selected apps</string> <string name="bypass_apps_summary">Enable this option to bypass selected apps</string>
<string name="auto_connect">Auto Connect</string> <string name="auto_connect">Auto Connect</string>
...@@ -64,15 +62,11 @@ ...@@ -64,15 +62,11 @@
<!-- alert category --> <!-- alert category -->
<string name="close">Close</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="proxy_empty">Proxy should not be empty</string>
<string name="connect">Connect</string> <string name="connect">Connect</string>
<string name="initializing">Initializing…</string> <string name="initializing">Initializing…</string>
<string name="recovering">Resetting…</string> <string name="recovering">Resetting…</string>
<string name="loading">Loading…</string> <string name="loading">Loading…</string>
<string name="yes">Yes</string>
<string name="no">No</string>
<string name="remove_profile">Remove this profile "%s"?</string> <string name="remove_profile">Remove this profile "%s"?</string>
<!-- menu category --> <!-- menu category -->
...@@ -84,7 +78,7 @@ ...@@ -84,7 +78,7 @@
<string name="about_title">Shadowsocks %s</string> <string name="about_title">Shadowsocks %s</string>
<string name="qrcode">QR Code</string> <string name="qrcode">QR Code</string>
<string name="flush_dnscache">Flush DNS cache</string> <string name="flush_dnscache">Flush DNS cache</string>
<string name="flush_dnscache_summary">Require ROOT permission</string> <string name="flush_dnscache_summary_disabled">Requires ROOT permission</string>
<string name="flushing">Flushing</string> <string name="flushing">Flushing</string>
<string name="add_profile">Add Profile</string> <string name="add_profile">Add Profile</string>
<string name="action_export">Export to Clipboard</string> <string name="action_export">Export to Clipboard</string>
......
...@@ -26,17 +26,19 @@ ...@@ -26,17 +26,19 @@
android:key="proxy" android:key="proxy"
android:summary="@string/proxy_summary" android:summary="@string/proxy_summary"
android:title="@string/proxy"/> android:title="@string/proxy"/>
<com.github.shadowsocks.preferences.SummaryEditTextPreference <com.github.shadowsocks.preferences.NumberPickerPreference
android:inputType="number"
android:defaultValue="443" android:defaultValue="443"
app:min="1"
app:max="65535"
android:key="remotePort" android:key="remotePort"
android:summary="@string/remote_port_summary" app:summary="@string/remote_port_summary"
android:title="@string/remote_port"/> android:title="@string/remote_port"/>
<com.github.shadowsocks.preferences.SummaryEditTextPreference <com.github.shadowsocks.preferences.NumberPickerPreference
android:inputType="number"
android:defaultValue="1080" android:defaultValue="1080"
app:min="1025"
app:max="65535"
android:key="port" android:key="port"
android:summary="@string/port_summary" app:summary="@string/port_summary"
android:title="@string/port"/> android:title="@string/port"/>
<com.github.shadowsocks.preferences.PasswordEditTextPreference <com.github.shadowsocks.preferences.PasswordEditTextPreference
android:inputType="textPassword" android:inputType="textPassword"
...@@ -75,18 +77,10 @@ ...@@ -75,18 +77,10 @@
android:summary="@string/ipv6_summary" android:summary="@string/ipv6_summary"
android:title="@string/ipv6"/> android:title="@string/ipv6"/>
<SwitchPreference <SwitchPreference
android:defaultValue="true" android:key="isProxyApps"
android:key="isGlobalProxy" android:defaultValue="false"
android:disableDependentsState="true"
android:summary="@string/auto_set_proxy_summary"
android:title="@string/auto_set_proxy"/>
<Preference
android:key="proxyedApps"
android:dependency="isGlobalProxy"
android:summary="@string/proxied_apps_summary" android:summary="@string/proxied_apps_summary"
android:title="@string/proxied_apps"> android:title="@string/proxied_apps"/>
<intent android:action="com.github.shadowsocks.AppManager"/>
</Preference>
<SwitchPreference <SwitchPreference
android:key="isUdpDns" android:key="isUdpDns"
android:defaultValue="false" android:defaultValue="false"
...@@ -102,8 +96,7 @@ ...@@ -102,8 +96,7 @@
android:summary="@string/nat_summary"/> android:summary="@string/nat_summary"/>
<Preference android:key="recovery" android:title="@string/recovery" <Preference android:key="recovery" android:title="@string/recovery"
android:summary="@string/recovery_summary"/> android:summary="@string/recovery_summary"/>
<Preference android:key="flush_dnscache" android:title="@string/flush_dnscache" <Preference android:key="flush_dnscache" android:title="@string/flush_dnscache"/>
android:summary="@string/flush_dnscache_summary"/>
<Preference android:key="about" android:title="@string/about"/> <Preference android:key="about" android:title="@string/about"/>
</PreferenceCategory> </PreferenceCategory>
......
...@@ -104,11 +104,12 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC ...@@ -104,11 +104,12 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC
implicit def anyrefarray_tools[T <: AnyRef](a: Array[T]): ObjectArrayTools[T] = new ObjectArrayTools(a) implicit def anyrefarray_tools[T <: AnyRef](a: Array[T]): ObjectArrayTools[T] = new ObjectArrayTools(a)
var apps: Array[ProxiedApp] = null var apps: Array[ProxiedApp] = _
var appListView: ListView = null var appListView: ListView = _
var overlay: TextView = null var loadingView: View = _
var adapter: ListAdapter = null var overlay: TextView = _
var appsLoaded: Boolean = false var adapter: ListAdapter = _
@volatile var appsLoading: Boolean = _
def loadApps(context: Context): Array[ProxiedApp] = { def loadApps(context: Context): Array[ProxiedApp] = {
val proxiedAppString = ShadowsocksApplication.settings.getString(Key.proxied, "") val proxiedAppString = ShadowsocksApplication.settings.getString(Key.proxied, "")
...@@ -133,6 +134,7 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC ...@@ -133,6 +134,7 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC
} }
def loadApps() { def loadApps() {
appsLoading = true
apps = loadApps(this).sortWith((a, b) => { apps = loadApps(this).sortWith((a, b) => {
if (a == null || b == null || a.name == null || b.name == null) { if (a == null || b == null || a.name == null || b.name == null) {
true true
...@@ -154,8 +156,7 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC ...@@ -154,8 +156,7 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC
val switch = convertView.findViewById(R.id.itemcheck).asInstanceOf[Switch] val switch = convertView.findViewById(R.id.itemcheck).asInstanceOf[Switch]
val text = convertView.findViewById(R.id.itemtext).asInstanceOf[TextView] val text = convertView.findViewById(R.id.itemtext).asInstanceOf[TextView]
entry = new ListEntry(switch, text, icon) entry = new ListEntry(switch, text, icon)
entry.text.setOnClickListener(AppManager.this) convertView.setOnClickListener(AppManager.this)
entry.text.setOnClickListener(AppManager.this)
convertView.setTag(entry) convertView.setTag(entry)
entry.switch.setOnCheckedChangeListener(AppManager.this) entry.switch.setOnCheckedChangeListener(AppManager.this)
} else { } else {
...@@ -173,7 +174,6 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC ...@@ -173,7 +174,6 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC
convertView convertView
} }
} }
appsLoaded = true
} }
/** Called an application is check/unchecked */ /** Called an application is check/unchecked */
...@@ -186,7 +186,7 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC ...@@ -186,7 +186,7 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC
} }
def onClick(v: View) { def onClick(v: View) {
val switch = v.getTag.asInstanceOf[Switch] val switch = v.getTag.asInstanceOf[ListEntry].switch
val app: ProxiedApp = switch.getTag.asInstanceOf[ProxiedApp] val app: ProxiedApp = switch.getTag.asInstanceOf[ProxiedApp]
if (app != null) { if (app != null) {
app.proxied = !app.proxied app.proxied = !app.proxied
...@@ -230,9 +230,9 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC ...@@ -230,9 +230,9 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC
prefs.edit.putString(Key.proxied, apps).apply() prefs.edit.putString(Key.proxied, apps).apply()
Toast.makeText(this, R.string.action_import_msg, Toast.LENGTH_SHORT).show() Toast.makeText(this, R.string.action_import_msg, Toast.LENGTH_SHORT).show()
// Restart activity // Restart activity
val intent = getIntent appListView.setVisibility(View.GONE)
finish() loadingView.setVisibility(View.VISIBLE)
startActivity(intent) if (appsLoading) appsLoading = false else loadAppsAsync()
return true return true
} }
} }
...@@ -251,7 +251,7 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC ...@@ -251,7 +251,7 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC
this.setContentView(R.layout.layout_apps) this.setContentView(R.layout.layout_apps)
val toolbar = findViewById(R.id.toolbar).asInstanceOf[Toolbar] val toolbar = findViewById(R.id.toolbar).asInstanceOf[Toolbar]
toolbar.setTitle(R.string.proxied_help) toolbar.setTitle(R.string.proxied_apps)
toolbar.setNavigationIcon(R.drawable.abc_ic_ab_back_mtrl_am_alpha) toolbar.setNavigationIcon(R.drawable.abc_ic_ab_back_mtrl_am_alpha)
toolbar.setNavigationOnClickListener((v: View) => { toolbar.setNavigationOnClickListener((v: View) => {
val intent = getParentActivityIntent val intent = getParentActivityIntent
...@@ -267,11 +267,18 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC ...@@ -267,11 +267,18 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, PixelFormat.TRANSLUCENT)) WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, PixelFormat.TRANSLUCENT))
findViewById(R.id.onSwitch).asInstanceOf[Switch]
.setOnCheckedChangeListener((button: CompoundButton, checked: Boolean) => {
ShadowsocksApplication.settings.edit().putBoolean(Key.isProxyApps, checked).apply()
finish()
})
val bypassSwitch = findViewById(R.id.bypassSwitch).asInstanceOf[Switch] val bypassSwitch = findViewById(R.id.bypassSwitch).asInstanceOf[Switch]
bypassSwitch.setOnCheckedChangeListener((button: CompoundButton, checked: Boolean) => bypassSwitch.setOnCheckedChangeListener((button: CompoundButton, checked: Boolean) =>
ShadowsocksApplication.settings.edit().putBoolean(Key.isBypassApps, checked).apply()) ShadowsocksApplication.settings.edit().putBoolean(Key.isBypassApps, checked).apply())
bypassSwitch.setChecked(ShadowsocksApplication.settings.getBoolean(Key.isBypassApps, false)) bypassSwitch.setChecked(ShadowsocksApplication.settings.getBoolean(Key.isBypassApps, false))
loadingView = findViewById(R.id.loading)
appListView = findViewById(R.id.applistview).asInstanceOf[ListView] appListView = findViewById(R.id.applistview).asInstanceOf[ListView]
appListView.setOnScrollListener(new AbsListView.OnScrollListener { appListView.setOnScrollListener(new AbsListView.OnScrollListener {
var visible = false var visible = false
...@@ -294,15 +301,16 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC ...@@ -294,15 +301,16 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC
} }
} }
}) })
loadAppsAsync()
} }
protected override def onResume() { def loadAppsAsync() {
super.onResume()
Future { Future {
if (!appsLoaded) loadApps() while (!appsLoading) loadApps()
appsLoading = false
handler.post(() => { handler.post(() => {
appListView.setAdapter(adapter) appListView.setAdapter(adapter)
Utils.crossFade(AppManager.this, findViewById(R.id.loading), appListView) Utils.crossFade(AppManager.this, loadingView, appListView)
}) })
} }
} }
......
...@@ -60,7 +60,7 @@ import android.widget._ ...@@ -60,7 +60,7 @@ import android.widget._
import com.github.jorgecastilloprz.FABProgressCircle import com.github.jorgecastilloprz.FABProgressCircle
import com.github.shadowsocks.aidl.{IShadowsocksService, IShadowsocksServiceCallback} import com.github.shadowsocks.aidl.{IShadowsocksService, IShadowsocksServiceCallback}
import com.github.shadowsocks.database._ import com.github.shadowsocks.database._
import com.github.shadowsocks.preferences.{DropDownPreference, PasswordEditTextPreference, SummaryEditTextPreference} import com.github.shadowsocks.preferences.{NumberPickerPreference, DropDownPreference, PasswordEditTextPreference, SummaryEditTextPreference}
import com.github.shadowsocks.utils._ import com.github.shadowsocks.utils._
import com.google.android.gms.ads.{AdRequest, AdSize, AdView} import com.google.android.gms.ads.{AdRequest, AdSize, AdView}
...@@ -96,8 +96,9 @@ object Shadowsocks { ...@@ -96,8 +96,9 @@ object Shadowsocks {
val REQUEST_CONNECT = 1 val REQUEST_CONNECT = 1
val PREFS_NAME = "Shadowsocks" val PREFS_NAME = "Shadowsocks"
val PROXY_PREFS = Array(Key.profileName, Key.proxy, Key.remotePort, Key.localPort, Key.sitekey, Key.encMethod) val PROXY_PREFS = Array(Key.profileName, Key.proxy, Key.remotePort, Key.localPort, Key.sitekey, Key.encMethod,
val FEATURE_PREFS = Array(Key.route, Key.isGlobalProxy, Key.proxyedApps, Key.isUdpDns, Key.isAuth, Key.isIpv6) Key.isAuth)
val FEATURE_PREFS = Array(Key.route, Key.isProxyApps, Key.isUdpDns, Key.isIpv6)
val EXECUTABLES = Array(Executable.PDNSD, Executable.REDSOCKS, Executable.SS_TUNNEL, Executable.SS_LOCAL, val EXECUTABLES = Array(Executable.PDNSD, Executable.REDSOCKS, Executable.SS_TUNNEL, Executable.SS_LOCAL,
Executable.TUN2SOCKS) Executable.TUN2SOCKS)
...@@ -111,6 +112,10 @@ object Shadowsocks { ...@@ -111,6 +112,10 @@ object Shadowsocks {
pref.asInstanceOf[PasswordEditTextPreference].setText(value) pref.asInstanceOf[PasswordEditTextPreference].setText(value)
} }
def updateNumberPickerPreference(pref: Preference, value: Int): Unit = {
pref.asInstanceOf[NumberPickerPreference].setValue(value)
}
def updateSummaryEditTextPreference(pref: Preference, value: String) { def updateSummaryEditTextPreference(pref: Preference, value: String) {
pref.setSummary(value) pref.setSummary(value)
pref.asInstanceOf[SummaryEditTextPreference].setText(value) pref.asInstanceOf[SummaryEditTextPreference].setText(value)
...@@ -124,12 +129,12 @@ object Shadowsocks { ...@@ -124,12 +129,12 @@ object Shadowsocks {
name match { name match {
case Key.profileName => updateSummaryEditTextPreference(pref, profile.name) case Key.profileName => updateSummaryEditTextPreference(pref, profile.name)
case Key.proxy => updateSummaryEditTextPreference(pref, profile.host) case Key.proxy => updateSummaryEditTextPreference(pref, profile.host)
case Key.remotePort => updateSummaryEditTextPreference(pref, profile.remotePort.toString) case Key.remotePort => updateNumberPickerPreference(pref, profile.remotePort)
case Key.localPort => updateSummaryEditTextPreference(pref, profile.localPort.toString) case Key.localPort => updateNumberPickerPreference(pref, profile.localPort)
case Key.sitekey => updatePasswordEditTextPreference(pref, profile.password) case Key.sitekey => updatePasswordEditTextPreference(pref, profile.password)
case Key.encMethod => updateDropDownPreference(pref, profile.method) case Key.encMethod => updateDropDownPreference(pref, profile.method)
case Key.route => updateDropDownPreference(pref, profile.route) case Key.route => updateDropDownPreference(pref, profile.route)
case Key.isGlobalProxy => updateSwitchPreference(pref, profile.global) case Key.isProxyApps => updateSwitchPreference(pref, profile.proxyApps)
case Key.isUdpDns => updateSwitchPreference(pref, profile.udpdns) case Key.isUdpDns => updateSwitchPreference(pref, profile.udpdns)
case Key.isAuth => updateSwitchPreference(pref, profile.auth) case Key.isAuth => updateSwitchPreference(pref, profile.auth)
case Key.isIpv6 => updateSwitchPreference(pref, profile.ipv6) case Key.isIpv6 => updateSwitchPreference(pref, profile.ipv6)
...@@ -315,8 +320,6 @@ class Shadowsocks ...@@ -315,8 +320,6 @@ class Shadowsocks
def isReady: Boolean = { def isReady: Boolean = {
if (!checkText(Key.proxy)) return false if (!checkText(Key.proxy)) return false
if (!checkText(Key.sitekey)) 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 if (bgService == null) return false
true true
} }
...@@ -347,15 +350,6 @@ class Shadowsocks ...@@ -347,15 +350,6 @@ class Shadowsocks
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.layout_main)
if (ShadowsocksApplication.proxy == "198.199.101.152") {
val adView = new AdView(this)
adView.setAdUnitId("ca-app-pub-9097031975646651/7760346322")
adView.setAdSize(AdSize.SMART_BANNER)
preferences.getView.asInstanceOf[ViewGroup].addView(adView, 0)
adView.loadAd(new AdRequest.Builder().build())
}
// Update the profile // Update the profile
if (!ShadowsocksApplication.settings.getBoolean(ShadowsocksApplication.getVersionName, false)) { if (!ShadowsocksApplication.settings.getBoolean(ShadowsocksApplication.getVersionName, false)) {
currentProfile = ShadowsocksApplication.profileManager.create() currentProfile = ShadowsocksApplication.profileManager.create()
...@@ -365,6 +359,16 @@ class Shadowsocks ...@@ -365,6 +359,16 @@ class Shadowsocks
currentProfile = { currentProfile = {
ShadowsocksApplication.currentProfile getOrElse currentProfile ShadowsocksApplication.currentProfile getOrElse currentProfile
} }
ShadowsocksApplication.profileManager.load(currentProfile.id)
setContentView(R.layout.layout_main)
if (ShadowsocksApplication.proxy == "198.199.101.152") {
val adView = new AdView(this)
adView.setAdUnitId("ca-app-pub-9097031975646651/7760346322")
adView.setAdSize(AdSize.SMART_BANNER)
preferences.getView.asInstanceOf[ViewGroup].addView(adView, 0)
adView.loadAd(new AdRequest.Builder().build())
}
// Initialize action bar // Initialize action bar
val toolbar = findViewById(R.id.toolbar).asInstanceOf[Toolbar] val toolbar = findViewById(R.id.toolbar).asInstanceOf[Toolbar]
...@@ -501,8 +505,7 @@ class Shadowsocks ...@@ -501,8 +505,7 @@ class Shadowsocks
for (name <- Shadowsocks.FEATURE_PREFS) { for (name <- Shadowsocks.FEATURE_PREFS) {
val pref = preferences.findPreference(name) val pref = preferences.findPreference(name)
if (pref != null) { if (pref != null) {
if (Seq(Key.isGlobalProxy, Key.proxyedApps) if (name == Key.isProxyApps) {
.contains(name)) {
pref.setEnabled(enabled && (Utils.isLollipopOrAbove || !ShadowsocksApplication.isVpnEnabled)) pref.setEnabled(enabled && (Utils.isLollipopOrAbove || !ShadowsocksApplication.isVpnEnabled))
} else { } else {
pref.setEnabled(enabled) pref.setEnabled(enabled)
...@@ -602,25 +605,6 @@ class Shadowsocks ...@@ -602,25 +605,6 @@ class Shadowsocks
!isTextEmpty(text, getString(R.string.proxy_empty)) !isTextEmpty(text, getString(R.string.proxy_empty))
} }
def checkNumber(key: String, low: Boolean): Boolean = {
val text = ShadowsocksApplication.settings.getString(key, "")
if (isTextEmpty(text, getString(R.string.port_empty))) return false
try {
val port: Int = Integer.valueOf(text)
if (!low && port <= 1024) {
Snackbar.make(getWindow.getDecorView.findViewById(android.R.id.content), R.string.port_alert,
Snackbar.LENGTH_LONG).show
return false
}
} catch {
case ex: Exception =>
Snackbar.make(getWindow.getDecorView.findViewById(android.R.id.content), R.string.port_alert,
Snackbar.LENGTH_LONG).show
return false
}
true
}
/** Called when connect button is clicked. */ /** Called when connect button is clicked. */
def serviceStart() { def serviceStart() {
bgService.start(ConfigUtils.load(ShadowsocksApplication.settings)) bgService.start(ConfigUtils.load(ShadowsocksApplication.settings))
......
...@@ -390,10 +390,10 @@ class ShadowsocksNatService extends Service with BaseService { ...@@ -390,10 +390,10 @@ class ShadowsocksNatService extends Service with BaseService {
init_sb.append(Utils.getIptables init_sb.append(Utils.getIptables
+ " -t nat -A OUTPUT -p udp --dport 53 -j DNAT --to-destination 127.0.0.1:" + 8153) + " -t nat -A OUTPUT -p udp --dport 53 -j DNAT --to-destination 127.0.0.1:" + 8153)
if (config.isGlobalProxy || config.isBypassApps) { if (!config.isProxyApps || config.isBypassApps) {
http_sb.append(Utils.getIptables + CMD_IPTABLES_DNAT_ADD_SOCKS) http_sb.append(Utils.getIptables + CMD_IPTABLES_DNAT_ADD_SOCKS)
} }
if (!config.isGlobalProxy) { if (config.isProxyApps) {
if (apps == null || apps.length <= 0) { if (apps == null || apps.length <= 0) {
apps = AppManager.getProxiedApps(this, config.proxiedAppString) apps = AppManager.getProxiedApps(this, config.proxiedAppString)
} }
......
...@@ -5,8 +5,8 @@ import java.util.Locale ...@@ -5,8 +5,8 @@ import java.util.Locale
import android.app.AlertDialog import android.app.AlertDialog
import android.content.{DialogInterface, Intent} import android.content.{DialogInterface, Intent}
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.{Build, Bundle}
import android.preference.{Preference, PreferenceFragment} import android.preference.{SwitchPreference, Preference, PreferenceFragment}
import android.webkit.{WebViewClient, WebView} import android.webkit.{WebViewClient, WebView}
import com.github.shadowsocks.utils.Key import com.github.shadowsocks.utils.Key
...@@ -14,10 +14,18 @@ import com.github.shadowsocks.utils.Key ...@@ -14,10 +14,18 @@ import com.github.shadowsocks.utils.Key
class ShadowsocksSettings extends PreferenceFragment { class ShadowsocksSettings extends PreferenceFragment {
private lazy val activity = getActivity.asInstanceOf[Shadowsocks] private lazy val activity = getActivity.asInstanceOf[Shadowsocks]
private var isProxyApps: SwitchPreference = _
override def onCreate(savedInstanceState: Bundle) { override def onCreate(savedInstanceState: Bundle) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
addPreferencesFromResource(R.xml.pref_all) addPreferencesFromResource(R.xml.pref_all)
isProxyApps = findPreference(Key.isProxyApps).asInstanceOf[SwitchPreference]
isProxyApps.setOnPreferenceChangeListener((preference: Preference, newValue: Any) => {
startActivity(new Intent(activity, classOf[AppManager]))
newValue.asInstanceOf[Boolean] // keep it ON
})
findPreference(Key.isNAT).setOnPreferenceChangeListener((preference: Preference, newValue: Any) => findPreference(Key.isNAT).setOnPreferenceChangeListener((preference: Preference, newValue: Any) =>
if (ShadowsocksApplication.isRoot) activity.handler.post(() => { if (ShadowsocksApplication.isRoot) activity.handler.post(() => {
activity.deattachService() activity.deattachService()
...@@ -30,7 +38,11 @@ class ShadowsocksSettings extends PreferenceFragment { ...@@ -30,7 +38,11 @@ class ShadowsocksSettings extends PreferenceFragment {
true true
}) })
findPreference("flush_dnscache").setOnPreferenceClickListener((preference: Preference) => { val flush = findPreference("flush_dnscache")
if (Build.VERSION.SDK_INT >= 17 && !ShadowsocksApplication.isRoot) {
flush.setEnabled(false)
flush.setSummary(R.string.flush_dnscache_summary_disabled)
} else flush.setOnPreferenceClickListener((preference: Preference) => {
ShadowsocksApplication.track(Shadowsocks.TAG, "flush_dnscache") ShadowsocksApplication.track(Shadowsocks.TAG, "flush_dnscache")
activity.flushDnsCache() activity.flushDnsCache()
true true
...@@ -58,4 +70,9 @@ class ShadowsocksSettings extends PreferenceFragment { ...@@ -58,4 +70,9 @@ class ShadowsocksSettings extends PreferenceFragment {
true true
}) })
} }
override def onResume = {
super.onResume
isProxyApps.setChecked(ShadowsocksApplication.settings.getBoolean(Key.isProxyApps, false)) // update
}
} }
...@@ -394,7 +394,7 @@ class ShadowsocksVpnService extends VpnService with BaseService { ...@@ -394,7 +394,7 @@ class ShadowsocksVpnService extends VpnService with BaseService {
if (Utils.isLollipopOrAbove) { if (Utils.isLollipopOrAbove) {
if (!config.isGlobalProxy) { if (config.isProxyApps) {
val apps = AppManager.getProxiedApps(this, config.proxiedAppString) val apps = AppManager.getProxiedApps(this, config.proxiedAppString)
val pkgSet: mutable.HashSet[String] = new mutable.HashSet[String] val pkgSet: mutable.HashSet[String] = new mutable.HashSet[String]
for (app <- apps) { for (app <- apps) {
......
...@@ -39,19 +39,19 @@ ...@@ -39,19 +39,19 @@
package com.github.shadowsocks.database package com.github.shadowsocks.database
import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper
import android.content.Context import android.content.Context
import android.database.sqlite.SQLiteDatabase import android.database.sqlite.SQLiteDatabase
import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper
import com.j256.ormlite.dao.Dao
import com.j256.ormlite.support.ConnectionSource import com.j256.ormlite.support.ConnectionSource
import com.j256.ormlite.table.TableUtils import com.j256.ormlite.table.TableUtils
import com.j256.ormlite.dao.Dao
object DBHelper { object DBHelper {
val PROFILE = "profile.db" val PROFILE = "profile.db"
} }
class DBHelper(val context: Context) class DBHelper(val context: Context)
extends OrmLiteSqliteOpenHelper(context, DBHelper.PROFILE, null, 11) { extends OrmLiteSqliteOpenHelper(context, DBHelper.PROFILE, null, 12) {
lazy val profileDao: Dao[Profile, Int] = getDao(classOf[Profile]) lazy val profileDao: Dao[Profile, Int] = getDao(classOf[Profile])
...@@ -63,21 +63,31 @@ class DBHelper(val context: Context) ...@@ -63,21 +63,31 @@ class DBHelper(val context: Context)
newVersion: Int) { newVersion: Int) {
if (oldVersion != newVersion) { if (oldVersion != newVersion) {
if (oldVersion < 7) { if (oldVersion < 7) {
profileDao.executeRaw("DROP TABLE IF EXISTS 'profile';") profileDao.executeRawNoArgs("DROP TABLE IF EXISTS 'profile';")
onCreate(database, connectionSource) onCreate(database, connectionSource)
} else { } else {
if (oldVersion < 8) { if (oldVersion < 8) {
profileDao.executeRaw("ALTER TABLE `profile` ADD COLUMN udpdns SMALLINT;") profileDao.executeRawNoArgs("ALTER TABLE `profile` ADD COLUMN udpdns SMALLINT;")
profileDao.executeRaw("ALTER TABLE `profile` ADD COLUMN route VARCHAR;") profileDao.executeRawNoArgs("ALTER TABLE `profile` ADD COLUMN route VARCHAR;")
} }
if (oldVersion < 9) { if (oldVersion < 9) {
profileDao.executeRaw("ALTER TABLE `profile` ADD COLUMN route VARCHAR;") profileDao.executeRawNoArgs("ALTER TABLE `profile` ADD COLUMN route VARCHAR;")
} }
if (oldVersion < 10) { if (oldVersion < 10) {
profileDao.executeRaw("ALTER TABLE `profile` ADD COLUMN auth SMALLINT;") profileDao.executeRawNoArgs("ALTER TABLE `profile` ADD COLUMN auth SMALLINT;")
} }
if (oldVersion < 11) { if (oldVersion < 11) {
profileDao.executeRaw("ALTER TABLE `profile` ADD COLUMN ipv6 SMALLINT;") profileDao.executeRawNoArgs("ALTER TABLE `profile` ADD COLUMN ipv6 SMALLINT;")
}
if (oldVersion < 12) {
profileDao.executeRawNoArgs("ALTER TABLE `profile` RENAME TO `tmp`;")
onCreate(database, connectionSource)
profileDao.executeRawNoArgs(
"INSERT INTO `profile`(id, name, host, localPort, remotePort, password, method, route, proxyApps, bypass," +
" udpdns, auth, ipv6, individual) " +
"SELECT id, name, host, localPort, remotePort, password, method, route, 1 - global, bypass, udpdns, auth," +
" ipv6, individual FROM `tmp`;")
profileDao.executeRawNoArgs("DROP TABLE `tmp`;")
} }
} }
} }
......
...@@ -63,30 +63,15 @@ class Profile { ...@@ -63,30 +63,15 @@ class Profile {
@DatabaseField @DatabaseField
var method: String = "rc4" var method: String = "rc4"
@DatabaseField
var date: String = ""
@DatabaseField @DatabaseField
var route: String = "all" var route: String = "all"
@DatabaseField @DatabaseField
var upload: Int = 0 var proxyApps: Boolean = false
@DatabaseField
var download: Int = 0
@DatabaseField
var chnroute: Boolean = true
@DatabaseField
var global: Boolean = true
@DatabaseField @DatabaseField
var bypass: Boolean = false var bypass: Boolean = false
@DatabaseField
var traffic: Boolean = false
@DatabaseField @DatabaseField
var udpdns: Boolean = false var udpdns: Boolean = false
...@@ -98,7 +83,4 @@ class Profile { ...@@ -98,7 +83,4 @@ class Profile {
@DatabaseField(dataType = DataType.LONG_STRING) @DatabaseField(dataType = DataType.LONG_STRING)
var individual: String = "" var individual: String = ""
@DatabaseField(dataType = DataType.LONG_STRING)
var description: String = ""
} }
...@@ -117,10 +117,8 @@ class ProfileManager(settings: SharedPreferences, dbHelper: DBHelper) { ...@@ -117,10 +117,8 @@ class ProfileManager(settings: SharedPreferences, dbHelper: DBHelper) {
} }
val edit = settings.edit() val edit = settings.edit()
edit.putBoolean(Key.isGlobalProxy, profile.global) edit.putBoolean(Key.isProxyApps, profile.proxyApps)
edit.putBoolean(Key.isGFWList, profile.chnroute)
edit.putBoolean(Key.isBypassApps, profile.bypass) edit.putBoolean(Key.isBypassApps, profile.bypass)
edit.putBoolean(Key.isTrafficStat, profile.traffic)
edit.putBoolean(Key.isUdpDns, profile.udpdns) edit.putBoolean(Key.isUdpDns, profile.udpdns)
edit.putBoolean(Key.isAuth, profile.auth) edit.putBoolean(Key.isAuth, profile.auth)
edit.putBoolean(Key.isIpv6, profile.ipv6) edit.putBoolean(Key.isIpv6, profile.ipv6)
...@@ -128,8 +126,8 @@ class ProfileManager(settings: SharedPreferences, dbHelper: DBHelper) { ...@@ -128,8 +126,8 @@ class ProfileManager(settings: SharedPreferences, dbHelper: DBHelper) {
edit.putString(Key.proxy, profile.host) edit.putString(Key.proxy, profile.host)
edit.putString(Key.sitekey, profile.password) edit.putString(Key.sitekey, profile.password)
edit.putString(Key.encMethod, profile.method) edit.putString(Key.encMethod, profile.method)
edit.putString(Key.remotePort, profile.remotePort.toString) edit.putInt(Key.remotePort, profile.remotePort)
edit.putString(Key.localPort, profile.localPort.toString) edit.putInt(Key.localPort, profile.localPort)
edit.putString(Key.proxied, profile.individual) edit.putString(Key.proxied, profile.individual)
edit.putInt(Key.profileId, profile.id) edit.putInt(Key.profileId, profile.id)
edit.putString(Key.route, profile.route) edit.putString(Key.route, profile.route)
...@@ -143,10 +141,8 @@ class ProfileManager(settings: SharedPreferences, dbHelper: DBHelper) { ...@@ -143,10 +141,8 @@ class ProfileManager(settings: SharedPreferences, dbHelper: DBHelper) {
profile.id = settings.getInt(Key.profileId, -1) profile.id = settings.getInt(Key.profileId, -1)
profile.global = settings.getBoolean(Key.isGlobalProxy, false) profile.proxyApps = settings.getBoolean(Key.isProxyApps, false)
profile.chnroute = settings.getBoolean(Key.isGFWList, false)
profile.bypass = settings.getBoolean(Key.isBypassApps, false) profile.bypass = settings.getBoolean(Key.isBypassApps, false)
profile.traffic = settings.getBoolean(Key.isTrafficStat, false)
profile.udpdns = settings.getBoolean(Key.isUdpDns, false) profile.udpdns = settings.getBoolean(Key.isUdpDns, false)
profile.auth = settings.getBoolean(Key.isAuth, false) profile.auth = settings.getBoolean(Key.isAuth, false)
profile.ipv6 = settings.getBoolean(Key.isIpv6, false) profile.ipv6 = settings.getBoolean(Key.isIpv6, false)
...@@ -155,18 +151,8 @@ class ProfileManager(settings: SharedPreferences, dbHelper: DBHelper) { ...@@ -155,18 +151,8 @@ class ProfileManager(settings: SharedPreferences, dbHelper: DBHelper) {
profile.password = settings.getString(Key.sitekey, "default") profile.password = settings.getString(Key.sitekey, "default")
profile.method = settings.getString(Key.encMethod, "table") profile.method = settings.getString(Key.encMethod, "table")
profile.route = settings.getString(Key.route, "all") profile.route = settings.getString(Key.route, "all")
profile.remotePort = try { profile.remotePort = settings.getInt(Key.remotePort, 1984)
Integer.valueOf(settings.getString(Key.remotePort, "1984")) profile.localPort = settings.getInt(Key.localPort, 1984)
} catch {
case ex: NumberFormatException =>
1984
}
profile.localPort = try {
Integer.valueOf(settings.getString(Key.localPort, "1984"))
} catch {
case ex: NumberFormatException =>
1984
}
profile.individual = settings.getString(Key.proxied, "") profile.individual = settings.getString(Key.proxied, "")
profile profile
......
...@@ -14,7 +14,6 @@ import android.widget.{AdapterView, ArrayAdapter} ...@@ -14,7 +14,6 @@ import android.widget.{AdapterView, ArrayAdapter}
import com.github.shadowsocks.R import com.github.shadowsocks.R
/** /**
* Based on: https://github.com/Mygod/mygod-lib-android/blob/683c41cb86d10e99ab0f457d41a218c6915fccc8/lib/src/main/scala/tk/mygod/preference/DropDownPreference.scala
* @author Mygod * @author Mygod
*/ */
final class DropDownPreference(private val mContext: Context, attrs: AttributeSet = null) final class DropDownPreference(private val mContext: Context, attrs: AttributeSet = null)
......
...@@ -14,14 +14,13 @@ final class NatSwitchPreference(context: Context, attrs: AttributeSet) extends S ...@@ -14,14 +14,13 @@ final class NatSwitchPreference(context: Context, attrs: AttributeSet) extends S
private var disabled = false private var disabled = false
override def isEnabled = super.isEnabled && !disabled override def isEnabled = super.isEnabled && !disabled
override def setEnabled(b: Boolean) = super.setEnabled(b && !disabled)
override def onGetDefaultValue(a: TypedArray, index: Int) = { if (!ShadowsocksApplication.isRoot) {
val result = ShadowsocksApplication.isVpnEnabled disabled = true
if (!ShadowsocksApplication.isRoot) { setEnabled(false)
disabled = true setSummary(R.string.nat_summary_no_root)
setEnabled(false)
setSummary(R.string.nat_summary_no_root)
}
result.asInstanceOf[AnyRef]
} }
override def onGetDefaultValue(a: TypedArray, index: Int) = ShadowsocksApplication.isVpnEnabled.asInstanceOf[AnyRef]
} }
package com.github.shadowsocks.preferences
import android.content.Context
import android.content.res.TypedArray
import android.preference.DialogPreference
import android.util.AttributeSet
import android.view.ViewGroup
import android.widget.NumberPicker
import com.github.shadowsocks.R
/**
* @author Mygod
*/
final class NumberPickerPreference(context: Context, attrs: AttributeSet = null)
extends DialogPreference(context, attrs) with SummaryPreference {
private val picker = new NumberPicker(context)
private var value: Int = _
{
val a: TypedArray = context.obtainStyledAttributes(attrs, R.styleable.NumberPickerPreference)
setMin(a.getInt(R.styleable.NumberPickerPreference_min, 0))
setMax(a.getInt(R.styleable.NumberPickerPreference_max, Int.MaxValue - 1))
a.recycle
}
initSummary(context, attrs)
def getValue = value
def getMin = if (picker == null) 0 else picker.getMinValue
def getMax = picker.getMaxValue
def setValue(i: Int) {
if (i == getValue || !callChangeListener(i)) return
picker.setValue(i)
value = picker.getValue
persistInt(value)
notifyChanged
}
def setMin(value: Int) = picker.setMinValue(value)
def setMax(value: Int) = picker.setMaxValue(value)
override protected def onCreateDialogView = {
val parent = picker.getParent.asInstanceOf[ViewGroup]
if (parent != null) parent.removeView(picker)
picker
}
override protected def onDialogClosed(positiveResult: Boolean) {
picker.clearFocus // commit changes
super.onDialogClosed(positiveResult) // forward compatibility
if (positiveResult) setValue(picker.getValue) else picker.setValue(value)
}
override protected def onGetDefaultValue(a: TypedArray, index: Int) = a.getInt(index, getMin).asInstanceOf[AnyRef]
override protected def onSetInitialValue(restorePersistedValue: Boolean, defaultValue: Any) {
val default = defaultValue.asInstanceOf[Int]
setValue(if (restorePersistedValue) getPersistedInt(default) else default)
}
protected def getSummaryValue: AnyRef = getValue.asInstanceOf[AnyRef]
}
...@@ -7,7 +7,6 @@ import com.github.shadowsocks.R ...@@ -7,7 +7,6 @@ import com.github.shadowsocks.R
/** /**
* Make your preference support %s in summary. Override getSummaryValue to customize what to put in. * Make your preference support %s in summary. Override getSummaryValue to customize what to put in.
* Based on: https://github.com/Mygod/mygod-lib-android/blob/eb20c57a0da70bb5dbc27104002f20fb1eb31d76/lib/src/main/scala/tk/mygod/preference/SummaryPreference.scala
* @author Mygod * @author Mygod
*/ */
trait SummaryPreference extends Preference { trait SummaryPreference extends Preference {
......
...@@ -241,16 +241,13 @@ object ConfigUtils { ...@@ -241,16 +241,13 @@ object ConfigUtils {
val password = proxy(2).trim val password = proxy(2).trim
val method = proxy(3).trim val method = proxy(3).trim
new Config(config.isGlobalProxy, config.isGFWList, config.isBypassApps, config.isTrafficStat, new Config(config.isProxyApps, config.isBypassApps, config.isUdpDns, config.isAuth, config.isIpv6,
config.isUdpDns, config.isAuth, config.isIpv6, config.profileName, host, password, method, config.proxiedAppString, config.route, port, config.profileName, host, password, method, config.proxiedAppString, config.route, port, config.localPort)
config.localPort)
} }
def load(settings: SharedPreferences): Config = { def load(settings: SharedPreferences): Config = {
val isGlobalProxy = settings.getBoolean(Key.isGlobalProxy, false) val isProxyApps = settings.getBoolean(Key.isProxyApps, false)
val isGFWList = settings.getBoolean(Key.isGFWList, false)
val isBypassApps = settings.getBoolean(Key.isBypassApps, false) val isBypassApps = settings.getBoolean(Key.isBypassApps, false)
val isTrafficStat = settings.getBoolean(Key.isTrafficStat, false)
val isUdpDns = settings.getBoolean(Key.isUdpDns, false) val isUdpDns = settings.getBoolean(Key.isUdpDns, false)
val isAuth = settings.getBoolean(Key.isAuth, false) val isAuth = settings.getBoolean(Key.isAuth, false)
val isIpv6 = settings.getBoolean(Key.isIpv6, false) val isIpv6 = settings.getBoolean(Key.isIpv6, false)
...@@ -261,21 +258,11 @@ object ConfigUtils { ...@@ -261,21 +258,11 @@ object ConfigUtils {
val encMethod = settings.getString(Key.encMethod, "table") val encMethod = settings.getString(Key.encMethod, "table")
val route = settings.getString(Key.route, "all") val route = settings.getString(Key.route, "all")
val remotePort: Int = try { val remotePort = settings.getInt(Key.remotePort, 1984)
settings.getString(Key.remotePort, "1984").toInt val localPort = settings.getInt(Key.localPort, 1984)
} catch {
case ex: NumberFormatException =>
1984
}
val localPort: Int = try {
settings.getString(Key.localPort, "1984").toInt
} catch {
case ex: NumberFormatException =>
1984
}
val proxiedAppString = settings.getString(Key.proxied, "") val proxiedAppString = settings.getString(Key.proxied, "")
new Config(isGlobalProxy, isGFWList, isBypassApps, isTrafficStat, isUdpDns, isAuth, isIpv6, profileName, proxy, new Config(isProxyApps, isBypassApps, isUdpDns, isAuth, isIpv6, profileName, proxy, sitekey, encMethod,
sitekey, encMethod, proxiedAppString, route, remotePort, localPort) proxiedAppString, route, remotePort, localPort)
} }
} }
...@@ -67,16 +67,13 @@ object Key { ...@@ -67,16 +67,13 @@ object Key {
val profiles = "profiles" val profiles = "profiles"
val isNAT = "isNAT" val isNAT = "isNAT"
val proxyedApps = "proxyedApps"
val route = "route" val route = "route"
val isRunning = "isRunning" val isRunning = "isRunning"
val isAutoConnect = "isAutoConnect" val isAutoConnect = "isAutoConnect"
val isGlobalProxy = "isGlobalProxy" val isProxyApps = "isProxyApps"
val isGFWList = "isGFWList"
val isBypassApps = "isBypassApps" val isBypassApps = "isBypassApps"
val isTrafficStat = "isTrafficStat"
val isUdpDns = "isUdpDns" val isUdpDns = "isUdpDns"
val isAuth= "isAuth" val isAuth= "isAuth"
val isIpv6= "isIpv6" val isIpv6= "isIpv6"
......
...@@ -55,7 +55,7 @@ import android.util.{DisplayMetrics, Base64, Log} ...@@ -55,7 +55,7 @@ import android.util.{DisplayMetrics, Base64, Log}
import android.view.View.MeasureSpec import android.view.View.MeasureSpec
import android.view.{Gravity, View, Window} import android.view.{Gravity, View, Window}
import android.widget.Toast import android.widget.Toast
import com.github.shadowsocks.BuildConfig import com.github.shadowsocks.{ShadowsocksApplication, BuildConfig}
import org.xbill.DNS._ import org.xbill.DNS._
...@@ -155,24 +155,13 @@ object Utils { ...@@ -155,24 +155,13 @@ object Utils {
// Blocked > 3 seconds // Blocked > 3 seconds
def toggleAirplaneMode(context: Context) { def toggleAirplaneMode(context: Context) {
if (Build.VERSION.SDK_INT >= 17) { if (ShadowsocksApplication.isRoot) {
toggleAboveApiLevel17() Console.runRootCommand(Array("ndc resolver flushdefaultif", "ndc resolver flushif wlan0"))
} else { } else if (Build.VERSION.SDK_INT < 17) {
toggleBelowApiLevel17(context) toggleBelowApiLevel17(context)
} }
} }
private def toggleAboveApiLevel17() {
// Android 4.2 and above
Console.runRootCommand(Array("ndc resolver flushdefaultif", "ndc resolver flushif wlan0"))
//Utils.runRootCommand("settings put global airplane_mode_on 1\n"
// + "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state true\n"
// + "settings put global airplane_mode_on 0\n"
// + "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state false\n")
}
//noinspection ScalaDeprecation //noinspection ScalaDeprecation
private def toggleBelowApiLevel17(context: Context) { private def toggleBelowApiLevel17(context: Context) {
// Android 4.2 below // Android 4.2 below
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment