新增:Telegram通过socks5/HTTP代理转发

pull/86/head v2.3.0
pppscn 3 years ago
parent c6a6d5d6df
commit 09c6ed0022

@ -32,7 +32,6 @@ import java.util.Map;
import java.util.Set;
@SuppressWarnings("SpellCheckingInspection")
public class AboutActivity extends AppCompatActivity {
private final String TAG = "AboutActivity";
private Context context;

@ -59,6 +59,7 @@ import com.idormy.sms.forwarder.sender.SenderUtil;
import com.idormy.sms.forwarder.sender.SenderWebNotifyMsg;
import com.umeng.analytics.MobclickAgent;
import java.net.Proxy;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
@ -751,7 +752,6 @@ public class SenderActivity extends AppCompatActivity {
}
//企业微信群机器人
@SuppressWarnings("SpellCheckingInspection")
@SuppressLint("SimpleDateFormat")
private void setQYWXGroupRobot(final SenderModel senderModel) {
QYWXGroupRobotSettingVo qywxGroupRobotSettingVo = null;
@ -836,7 +836,6 @@ public class SenderActivity extends AppCompatActivity {
}
//企业微信应用
@SuppressWarnings("SpellCheckingInspection")
@SuppressLint({"SimpleDateFormat", "SetTextI18n"})
private void setQYWXApp(final SenderModel senderModel) {
QYWXAppSettingVo QYWXAppSettingVo = null;
@ -975,13 +974,64 @@ public class SenderActivity extends AppCompatActivity {
final EditText editTextTelegramName = view1.findViewById(R.id.editTextTelegramName);
if (senderModel != null) editTextTelegramName.setText(senderModel.getName());
final EditText editTextTelegramApiToken = view1.findViewById(R.id.editTextTelegramApiToken);
if (telegramSettingVo != null)
editTextTelegramApiToken.setText(telegramSettingVo.getApiToken());
final EditText editTextTelegramChatId = view1.findViewById(R.id.editTextTelegramChatId);
if (telegramSettingVo != null)
final RadioGroup radioGroupProxyType = view1.findViewById(R.id.radioGroupProxyType);
final EditText editTextProxyHost = view1.findViewById(R.id.editTextProxyHost);
final EditText editTextProxyPort = view1.findViewById(R.id.editTextProxyPort);
@SuppressLint("UseSwitchCompatOrMaterialCode") final Switch switchProxyAuthenticator = view1.findViewById(R.id.switchProxyAuthenticator);
final EditText editTextProxyUsername = view1.findViewById(R.id.editTextProxyUsername);
final EditText editTextProxyPassword = view1.findViewById(R.id.editTextProxyPassword);
final LinearLayout layoutProxyHost = view1.findViewById(R.id.layoutProxyHost);
final LinearLayout layoutProxyPort = view1.findViewById(R.id.layoutProxyPort);
final LinearLayout layoutProxyAuthenticator = view1.findViewById(R.id.layoutProxyAuthenticator);
switchProxyAuthenticator.setOnCheckedChangeListener((buttonView, isChecked) -> {
Log.d(TAG, "onCheckedChanged:" + isChecked);
layoutProxyAuthenticator.setVisibility(isChecked ? View.VISIBLE : View.GONE);
});
radioGroupProxyType.setOnCheckedChangeListener((group, checkedId) -> {
if (group != null && checkedId > 0) {
if (checkedId == R.id.btnProxyNone) {
layoutProxyHost.setVisibility(View.GONE);
layoutProxyPort.setVisibility(View.GONE);
layoutProxyAuthenticator.setVisibility(View.GONE);
} else {
layoutProxyHost.setVisibility(View.VISIBLE);
layoutProxyPort.setVisibility(View.VISIBLE);
layoutProxyAuthenticator.setVisibility(switchProxyAuthenticator.isChecked() ? View.VISIBLE : View.GONE);
}
group.check(checkedId);
}
});
if (telegramSettingVo != null) {
editTextTelegramApiToken.setText(telegramSettingVo.getApiToken());
editTextTelegramChatId.setText(telegramSettingVo.getChatId());
radioGroupProxyType.check(telegramSettingVo.getProxyTypeCheckId());
layoutProxyAuthenticator.setVisibility(telegramSettingVo.getProxyAuthenticator() ? View.VISIBLE : View.GONE);
switchProxyAuthenticator.setChecked(telegramSettingVo.getProxyAuthenticator());
if (Proxy.Type.DIRECT == telegramSettingVo.getProxyType()) {
layoutProxyHost.setVisibility(View.GONE);
layoutProxyPort.setVisibility(View.GONE);
} else {
layoutProxyHost.setVisibility(View.VISIBLE);
layoutProxyPort.setVisibility(View.VISIBLE);
}
editTextProxyHost.setText(telegramSettingVo.getProxyHost());
editTextProxyPort.setText(telegramSettingVo.getProxyPort());
editTextProxyUsername.setText(telegramSettingVo.getProxyUsername());
editTextProxyPassword.setText(telegramSettingVo.getProxyPassword());
}
Button buttonTelegramOk = view1.findViewById(R.id.buttonTelegramOk);
Button buttonTelegramDel = view1.findViewById(R.id.buttonTelegramDel);
Button buttonTelegramTest = view1.findViewById(R.id.buttonTelegramTest);
@ -1001,7 +1051,14 @@ public class SenderActivity extends AppCompatActivity {
newSenderModel.setStatus(STATUS_ON);
TelegramSettingVo telegramSettingVoNew = new TelegramSettingVo(
editTextTelegramApiToken.getText().toString().trim(),
editTextTelegramChatId.getText().toString().trim()
editTextTelegramChatId.getText().toString().trim(),
radioGroupProxyType.getCheckedRadioButtonId(),
editTextProxyHost.getText().toString().trim(),
editTextProxyPort.getText().toString().trim(),
switchProxyAuthenticator.isChecked(),
editTextProxyUsername.getText().toString().trim(),
editTextProxyPassword.getText().toString().trim()
);
newSenderModel.setJsonSetting(JSON.toJSONString(telegramSettingVoNew));
SenderUtil.addSender(newSenderModel);
@ -1013,7 +1070,13 @@ public class SenderActivity extends AppCompatActivity {
senderModel.setStatus(STATUS_ON);
TelegramSettingVo telegramSettingVoNew = new TelegramSettingVo(
editTextTelegramApiToken.getText().toString().trim(),
editTextTelegramChatId.getText().toString().trim()
editTextTelegramChatId.getText().toString().trim(),
radioGroupProxyType.getCheckedRadioButtonId(),
editTextProxyHost.getText().toString().trim(),
editTextProxyPort.getText().toString().trim(),
switchProxyAuthenticator.isChecked(),
editTextProxyUsername.getText().toString().trim(),
editTextProxyPassword.getText().toString().trim()
);
senderModel.setJsonSetting(JSON.toJSONString(telegramSettingVoNew));
SenderUtil.updateSender(senderModel);
@ -1037,7 +1100,17 @@ public class SenderActivity extends AppCompatActivity {
String chatId = editTextTelegramChatId.getText().toString().trim();
if (!apiToken.isEmpty() && !chatId.isEmpty()) {
try {
SenderTelegramMsg.sendMsg(0, handler, apiToken, chatId, getString(R.string.test_phone_num), getString(R.string.test_sms));
TelegramSettingVo telegramSettingVoNew = new TelegramSettingVo(
apiToken,
chatId,
radioGroupProxyType.getCheckedRadioButtonId(),
editTextProxyHost.getText().toString().trim(),
editTextProxyPort.getText().toString().trim(),
switchProxyAuthenticator.isChecked(),
editTextProxyUsername.getText().toString().trim(),
editTextProxyPassword.getText().toString().trim()
);
SenderTelegramMsg.sendMsg(0, handler, telegramSettingVoNew, getString(R.string.test_phone_num), getString(R.string.test_sms));
} catch (Exception e) {
Toast.makeText(SenderActivity.this, getString(R.string.failed_to_fwd) + e.getMessage(), Toast.LENGTH_LONG).show();
e.printStackTrace();

@ -1,6 +1,9 @@
package com.idormy.sms.forwarder.model.vo;
import com.idormy.sms.forwarder.R;
import java.io.Serializable;
import java.net.Proxy;
import lombok.Data;
@ -8,6 +11,12 @@ import lombok.Data;
public class TelegramSettingVo implements Serializable {
private String apiToken;
private String chatId;
private Proxy.Type proxyType = Proxy.Type.DIRECT;
private String proxyHost;
private String proxyPort;
private Boolean proxyAuthenticator = false;
private String proxyUsername;
private String proxyPassword;
public TelegramSettingVo() {
}
@ -15,5 +24,33 @@ public class TelegramSettingVo implements Serializable {
public TelegramSettingVo(String apiToken, String chatId) {
this.apiToken = apiToken;
this.chatId = chatId;
this.proxyType = Proxy.Type.DIRECT;
}
public TelegramSettingVo(String apiToken, String chatId, int proxyTypeId, String proxyHost, String proxyPort, boolean proxyAuthenticator, String proxyUsername, String proxyPassword) {
this.apiToken = apiToken;
this.chatId = chatId;
if (proxyTypeId == R.id.btnProxyHttp) {
this.proxyType = Proxy.Type.HTTP;
} else if (proxyTypeId == R.id.btnProxySocks) {
this.proxyType = Proxy.Type.SOCKS;
} else {
this.proxyType = Proxy.Type.DIRECT;
}
this.proxyHost = proxyHost;
this.proxyPort = proxyPort;
this.proxyAuthenticator = proxyAuthenticator;
this.proxyUsername = proxyUsername;
this.proxyPassword = proxyPassword;
}
public int getProxyTypeCheckId() {
if (proxyType == Proxy.Type.HTTP) {
return R.id.btnProxyHttp;
} else if (proxyType == Proxy.Type.SOCKS) {
return R.id.btnProxySocks;
} else {
return R.id.btnProxyNone;
}
}
}

@ -225,7 +225,7 @@ public class SendUtil {
TelegramSettingVo telegramSettingVo = JSON.parseObject(senderModel.getJsonSetting(), TelegramSettingVo.class);
if (telegramSettingVo != null) {
try {
SenderTelegramMsg.sendMsg(logId, handError, telegramSettingVo.getApiToken(), telegramSettingVo.getChatId(), smsVo.getMobile(), smsVo.getSmsVoForSend(smsTemplate, regexReplace));
SenderTelegramMsg.sendMsg(logId, handError, telegramSettingVo, smsVo.getMobile(), smsVo.getSmsVoForSend(smsTemplate, regexReplace));
} catch (Exception e) {
LogUtil.updateLog(logId, 0, e.getMessage());
Log.e(TAG, "senderSendMsg: SenderTelegramMsg error " + e.getMessage());

@ -1,15 +1,19 @@
package com.idormy.sms.forwarder.sender;
import android.os.Handler;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.NonNull;
import com.alibaba.fastjson.JSON;
import com.idormy.sms.forwarder.model.vo.TelegramSettingVo;
import com.idormy.sms.forwarder.utils.LogUtil;
import com.idormy.sms.forwarder.utils.SettingUtil;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
@ -17,8 +21,11 @@ import java.util.concurrent.TimeUnit;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.core.ObservableEmitter;
import okhttp3.Authenticator;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.ConnectionPool;
import okhttp3.Credentials;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
@ -30,9 +37,11 @@ public class SenderTelegramMsg extends SenderBaseMsg {
static final String TAG = "SenderTelegramMsg";
public static void sendMsg(final long logId, final Handler handError, String apiToken, String chatId, String from, String text) throws Exception {
Log.i(TAG, "sendMsg apiToken:" + apiToken + " chatId:" + chatId + " text:" + text);
public static void sendMsg(final long logId, final Handler handError, TelegramSettingVo telegramSettingVo, String from, String text) throws Exception {
Log.i(TAG, "sendMsg telegramSettingVo:" + telegramSettingVo.toString() + " text:" + text);
String apiToken = telegramSettingVo.getApiToken();
String chatId = telegramSettingVo.getChatId();
if (apiToken == null || apiToken.isEmpty()) {
return;
}
@ -54,42 +63,87 @@ public class SenderTelegramMsg extends SenderBaseMsg {
final String requestMsg = JSON.toJSONString(bodyMap);
Log.i(TAG, "requestMsg:" + requestMsg);
//代理相关
final Proxy.Type proxyType = telegramSettingVo.getProxyType();
final String proxyHost = telegramSettingVo.getProxyHost();
final String proxyPort = telegramSettingVo.getProxyPort();
final Boolean needProxyAuthenticator = telegramSettingVo.getProxyAuthenticator();
final String proxyUsername = telegramSettingVo.getProxyUsername();
final String proxyPassword = telegramSettingVo.getProxyPassword();
Observable
.create((ObservableEmitter<Object> emitter) -> {
Toast(handError, TAG, "开始请求接口...");
OkHttpClient client = new OkHttpClient();
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json;charset=utf-8"), requestMsg);
final Request request = new Request.Builder()
.url(requestUrl)
.addHeader("Content-Type", "application/json; charset=utf-8")
.post(requestBody)
.build();
Call call = client.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull final IOException e) {
LogUtil.updateLog(logId, 0, e.getMessage());
Toast(handError, TAG, "发送失败:" + e.getMessage());
emitter.onError(new RuntimeException("请求接口异常..."));
}
try {
Proxy proxy = null;
Authenticator proxyAuthenticator = null;
if ((proxyType == Proxy.Type.HTTP || proxyType == Proxy.Type.SOCKS) && !TextUtils.isEmpty(proxyHost) && !TextUtils.isEmpty(proxyPort)) {
proxy = new Proxy(proxyType, new InetSocketAddress(proxyHost, Integer.parseInt(proxyPort)));
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
final String responseStr = Objects.requireNonNull(response.body()).string();
Log.d(TAG, "Response" + response.code() + "" + responseStr);
Toast(handError, TAG, "发送状态:" + responseStr);
//TODO:粗略解析是否发送成功
if (responseStr.contains("\"ok\":true")) {
LogUtil.updateLog(logId, 2, responseStr);
} else {
LogUtil.updateLog(logId, 0, responseStr);
if (needProxyAuthenticator && (!TextUtils.isEmpty(proxyUsername) || !TextUtils.isEmpty(proxyPassword))) {
proxyAuthenticator = (route, response) -> {
String credential = Credentials.basic("jesse", "password1");
return response.request().newBuilder()
.header("Authorization", credential)
.build();
};
}
}
});
OkHttpClient client;
if (proxy != null && proxyAuthenticator != null) {
client = new OkHttpClient().newBuilder().proxy(proxy).proxyAuthenticator(proxyAuthenticator)
.connectTimeout(120, TimeUnit.SECONDS).readTimeout(120, TimeUnit.SECONDS)
.connectionPool(new ConnectionPool(5, 1, TimeUnit.SECONDS)).build();
} else if (proxy != null) {
client = new OkHttpClient().newBuilder().proxy(proxy)
.connectTimeout(120, TimeUnit.SECONDS).readTimeout(120, TimeUnit.SECONDS)
.connectionPool(new ConnectionPool(5, 1, TimeUnit.SECONDS)).build();
} else {
client = new OkHttpClient().newBuilder()
.connectTimeout(120, TimeUnit.SECONDS).readTimeout(120, TimeUnit.SECONDS)
.connectionPool(new ConnectionPool(5, 1, TimeUnit.SECONDS)).build();
}
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json;charset=utf-8"), requestMsg);
final Request request = new Request.Builder()
.url(requestUrl)
.addHeader("Content-Type", "application/json; charset=utf-8")
.post(requestBody)
.build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull final IOException e) {
LogUtil.updateLog(logId, 0, e.getMessage());
Toast(handError, TAG, "发送失败:" + e.getMessage());
emitter.onError(new RuntimeException("请求接口异常..."));
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
final String responseStr = Objects.requireNonNull(response.body()).string();
Log.d(TAG, "Response" + response.code() + "" + responseStr);
Toast(handError, TAG, "发送状态:" + responseStr);
//TODO:粗略解析是否发送成功
if (responseStr.contains("\"ok\":true")) {
LogUtil.updateLog(logId, 2, responseStr);
} else {
LogUtil.updateLog(logId, 0, responseStr);
}
}
});
} catch (Exception e) {
LogUtil.updateLog(logId, 0, e.getMessage());
Log.e(TAG, e.getMessage(), e);
Toast(handError, TAG, "发送失败:" + e.getMessage());
emitter.onError(new RuntimeException("请求接口异常..."));
}
}).retryWhen((Observable<Throwable> errorObservable) -> errorObservable
.zipWith(Observable.just(
SettingUtil.getRetryDelayTime(1),

@ -89,7 +89,7 @@ public class LogUtil {
public static void updateLog(Long id, int forward_status, String forward_response) {
if (id == null || id <= 0) return;
String sql = new StringBuilder().append("UPDATE ").append(LogTable.LogEntry.TABLE_NAME)
@SuppressWarnings("StringBufferReplaceableByString") String sql = new StringBuilder().append("UPDATE ").append(LogTable.LogEntry.TABLE_NAME)
.append(" SET ").append(LogTable.LogEntry.COLUMN_NAME_FORWARD_STATUS).append(" = ? , ")
.append(LogTable.LogEntry.COLUMN_NAME_FORWARD_RESPONSE)
.append(" = CASE WHEN ").append(LogTable.LogEntry.COLUMN_NAME_FORWARD_STATUS).append(" = 1 THEN ? ELSE ")

@ -577,7 +577,6 @@ public class PhoneUtils {
/**
* SIM
*/
@SuppressWarnings("SpellCheckingInspection")
public static class SimInfo {
/**
*

@ -29,6 +29,7 @@
android:autofillHints=""
android:ems="11"
android:inputType="text"
android:maxLines="1"
android:text=""
tools:ignore="LabelFor,TextFields" />
</LinearLayout>
@ -63,6 +64,7 @@
android:autofillHints=""
android:ems="14"
android:inputType="textEmailAddress"
android:maxLines="1"
android:text=""
tools:ignore="LabelFor" />
</LinearLayout>
@ -87,6 +89,7 @@
android:autofillHints=""
android:ems="14"
android:inputType="textPassword"
android:maxLines="1"
android:text=""
tools:ignore="LabelFor,TextFields" />
</LinearLayout>
@ -111,6 +114,7 @@
android:autofillHints=""
android:ems="14"
android:inputType="text"
android:maxLines="1"
android:text=""
tools:ignore="LabelFor,TextFields" />
</LinearLayout>
@ -184,6 +188,7 @@
android:autofillHints=""
android:ems="14"
android:inputType="text"
android:maxLines="1"
android:text=""
tools:ignore="LabelFor,TextFields" />
</LinearLayout>
@ -207,7 +212,8 @@
android:layout_marginStart="3dp"
android:autofillHints=""
android:ems="5"
android:inputType="text"
android:inputType="number"
android:maxLines="1"
android:text=""
tools:ignore="LabelFor,TextFields" />
@ -254,6 +260,7 @@
android:autofillHints=""
android:ems="14"
android:inputType="textEmailAddress"
android:maxLines="1"
android:text=""
tools:ignore="LabelFor" />
</LinearLayout>

@ -19,7 +19,8 @@
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/set_name" />
android:text="@string/set_name"
android:textStyle="bold" />
<EditText
android:id="@+id/editTextTelegramName"
@ -43,7 +44,8 @@
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/TelegramApiToken" />
android:text="@string/TelegramApiToken"
android:textStyle="bold" />
<EditText
android:id="@+id/editTextTelegramApiToken"
@ -66,7 +68,8 @@
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/TelegramChatId" />
android:text="@string/TelegramChatId"
android:textStyle="bold" />
<EditText
android:id="@+id/editTextTelegramChatId"
@ -79,6 +82,152 @@
tools:ignore="LabelFor" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="5dp"
android:layout_marginTop="5dp"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:text="@string/proxy_settings"
android:textStyle="bold" />
<RadioGroup
android:id="@+id/radioGroupProxyType"
style="@style/rg_style"
android:orientation="horizontal">
<RadioButton
android:id="@+id/btnProxyNone"
style="@style/rg_rb_style"
android:checked="true"
android:text="@string/proxy_none" />
<RadioButton
android:id="@+id/btnProxyHttp"
style="@style/rg_rb_style"
android:text="@string/proxy_http" />
<RadioButton
android:id="@+id/btnProxySocks"
style="@style/rg_rb_style"
android:text="@string/proxy_socks" />
</RadioGroup>
</LinearLayout>
<LinearLayout
android:id="@+id/layoutProxyHost"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:orientation="horizontal"
android:visibility="gone">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hostname" />
<EditText
android:id="@+id/editTextProxyHost"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="3dp"
android:autofillHints=""
android:ems="14"
android:inputType="text"
android:text=""
tools:ignore="LabelFor,TextFields" />
</LinearLayout>
<LinearLayout
android:id="@+id/layoutProxyPort"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:orientation="horizontal"
android:visibility="gone">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/port" />
<EditText
android:id="@+id/editTextProxyPort"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="3dp"
android:autofillHints=""
android:ems="5"
android:inputType="number"
android:maxLines="1"
android:text=""
tools:ignore="LabelFor,TextFields" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:text="@string/proxy_authenticator" />
<Switch
android:id="@+id/switchProxyAuthenticator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:ignore="UseSwitchCompatOrMaterialXml" />
</LinearLayout>
<LinearLayout
android:id="@+id/layoutProxyAuthenticator"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:orientation="horizontal"
android:visibility="gone">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/username" />
<EditText
android:id="@+id/editTextProxyUsername"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="3dp"
android:autofillHints=""
android:ems="7"
android:inputType="text"
android:text=""
tools:ignore="LabelFor" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/password" />
<EditText
android:id="@+id/editTextProxyPassword"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="3dp"
android:autofillHints=""
android:ems="7"
android:inputType="textPassword"
android:text=""
tools:ignore="LabelFor,TextFields" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"

@ -254,4 +254,13 @@
<string name="zero">0</string>
<string name="monitor_battery_status_changes">Monitor battery status changes</string>
<string name="battery_status_changes_tips">Notify when charging status changes (charging/discharging/uncharged/fully charged)</string>
<string name="proxy_settings">Proxy Settings</string>
<string name="proxy_none">None</string>
<string name="proxy_http">HTTP</string>
<string name="proxy_socks">SOCKS</string>
<string name="hostname">Hostname</string>
<string name="port">Port</string>
<string name="proxy_authenticator">Proxy Authenticator</string>
<string name="username">Username</string>
<string name="password">Password</string>
</resources>

@ -253,4 +253,13 @@
<string name="zero">0</string>
<string name="monitor_battery_status_changes">监听电池状态变化</string>
<string name="battery_status_changes_tips">充电状态改变(充电中/放电中/未充电/已充满)时发出通知</string>
<string name="proxy_settings">代理设置</string>
<string name="proxy_none">无代理</string>
<string name="proxy_http">HTTP</string>
<string name="proxy_socks">SOCKS</string>
<string name="hostname">主机名</string>
<string name="port">端口号</string>
<string name="proxy_authenticator">代理身份验证</string>
<string name="username">用户</string>
<string name="password">密码</string>
</resources>

Loading…
Cancel
Save