集成aTrust SDK

master
wenfei 8 months ago
parent e72a10ed74
commit 90f5155d42

@ -75,6 +75,8 @@ dependencies {
// implementation files('libs/ksoap2-android-assembly-3.6.0-jar-with-dependencies.jar')
implementation files('libs/badgeview.jar')
implementation files('libs/TbsFileSdk_base_arm64_release_1.0.5.6000030.20231109143447.aar')
//SDK
implementation files('libs/SangforSDK.aar')
implementation libs.androidx.core.ktx

Binary file not shown.

@ -81,6 +81,12 @@
tools:ignore="GoogleAppIndexingWarning"
tools:replace="android:allowBackup"
tools:targetApi="s">
<activity
android:name=".ui.activity.AuthSuccessActivity"
android:exported="false" />
<activity
android:name=".ui.activity.VpnAuthActivity"
android:exported="false" />
<meta-data
android:name="design_width"
@ -109,6 +115,14 @@
android:name=".ui.activity.Main2Activity"
android:configChanges="orientation|screenSize|keyboardHidden"
android:screenOrientation="portrait" />
<activity
android:name=".ui.activity.PrimarySmsLoginActivity"
android:configChanges="orientation|screenSize|keyboardHidden"
android:screenOrientation="portrait" />
<activity
android:name=".ui.activity.PrimaryAuthActivity"
android:configChanges="orientation|screenSize|keyboardHidden"
android:screenOrientation="portrait" />
<activity
android:name=".ui.activity.DownloadActivity"
android:configChanges="orientation|screenSize|keyboardHidden"
@ -1218,6 +1232,12 @@
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths_public" />
</provider>
<service
android:name="com.sangfor.atrust.sdp_tunnel.SdpVpnService"
android:enabled="true"
android:exported="false"
android:permission="android.permission.BIND_VPN_SERVICE" />
</application>
</manifest>

@ -1,20 +1,16 @@
package com.rehome.zhdcoa;
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Process;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.emoji.bundled.BundledEmojiCompatConfig;
import androidx.emoji.text.EmojiCompat;
import androidx.multidex.BuildConfig;
import androidx.multidex.MultiDex;
//import com.blankj.utilcode.util.Utils;
@ -25,9 +21,18 @@ import com.github.mikephil.charting.utils.Utils;
//import com.hjq.http.model.HttpHeaders;
//import com.hjq.http.model.HttpParams;
import com.rehome.zhdcoa.bean.UserInfoBean;
import com.rehome.zhdcoa.ui.activity.VpnAuthActivity;
import com.rehome.zhdcoa.utils.DpPxSpTransformUtil;
import com.rehome.zhdcoa.utils.SPUtils;
//import com.squareup.leakcanary.LeakCanary;
//import com.squareup.leakcanary.RefWatcher;
import com.rehome.zhdcoa.vpn.GlobalListenerManager;
import com.sangfor.sdk.SFUemSDK;
import com.sangfor.sdk.base.SFBaseMessage;
import com.sangfor.sdk.base.SFSDKFlags;
import com.sangfor.sdk.base.SFSDKMode;
import com.sangfor.sdk.base.SFSetSpaConfigListener;
import com.sangfor.sdk.utils.SFLogN;
import com.tencent.bugly.crashreport.CrashReport;
import com.xuexiang.xui.XUI;
import com.yolanda.nohttp.NoHttp;
@ -35,11 +40,6 @@ import com.zhy.autolayout.config.AutoLayoutConifg;
import org.litepal.LitePalApplication;
import java.util.HashMap;
import java.util.List;
import okhttp3.OkHttpClient;
public class App extends LitePalApplication {
private UserInfoBean.UserInfo userInfo;
@ -60,6 +60,8 @@ public class App extends LitePalApplication {
private int activityAount = 0;
private boolean isForeground = false;
public static Context mContext;
public static App getInstance() {
return mInstance;
@ -152,6 +154,37 @@ public class App extends LitePalApplication {
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
mContext = base;
/**
* sdk,attachBaseContextsdksdk
*
* dpsppx
*/
if (isApkInDebug(base)) {
showLog("attachBaseContext base");
initSdk(base);
GlobalListenerManager.getInstance().init(base);
DpPxSpTransformUtil.init(getResources().getDisplayMetrics().density);
// String config = "{\"loginAddress\":\"https://vpn.zhp.geg.com.cn:55420\", \"spaSecret\":\"7FFQ-rWE5-V6xX\"}";
// SFUemSDK.setSpaConfig(config, new SFSetSpaConfigListener() {
// @Override
// public void onSetSpaConfig(String result, SFBaseMessage error) {
// SFLogN.info("app", "spa result:"+ result + ", error:" + error);
// Log.i("app", "spa result:"+ result + ", error:" + error);
// if (error.mErrCode != 0) {
// Toast.makeText(mContext,
// "SPA设置失败"+ ", Error Message:" + error.toString(),
// Toast.LENGTH_SHORT)
// .show();
// } else {
// Toast.makeText(mContext, "SPA设置成功 result:" + result,
// Toast.LENGTH_SHORT)
// .show();
// }
// }
// });
}
}
public void clearUser() {
@ -211,5 +244,45 @@ public class App extends LitePalApplication {
}
}
public void showLog(String logText) {
if (isApkInDebug(mContext)) {
if (TextUtils.isEmpty(logText)) {
Log.i("app", "logText is null");
} else {
Log.i("app", logText);
}
}
}
void initSdk(Context context) {
SFSDKMode sdkMode = SFSDKMode.MODE_SUPPORT_MUTABLE; // 表明启用可变授权功能,详情参考集成指导文档
switch (sdkMode) {
case MODE_SUPPORT_MUTABLE:{
int sdkFlags = SFSDKFlags.FLAGS_HOST_APPLICATION; //表明是单应用或者是主应用
sdkFlags |= SFSDKFlags.FLAGS_VPN_MODE_TCP; //表明使用VPN功能中的TCP模式
SFUemSDK.getInstance().initSDK(this, sdkMode,sdkFlags,null);
break;
}
case MODE_VPN: { //只使用VPN功能场景
int sdkFlags = SFSDKFlags.FLAGS_HOST_APPLICATION; //表明是单应用或者是主应用
sdkFlags |= SFSDKFlags.FLAGS_VPN_MODE_TCP; //表明使用VPN功能中的TCP模式
SFUemSDK.getInstance().initSDK(this, sdkMode,sdkFlags,null);
break;
}
case MODE_SANDBOX: { //只使用安全沙箱功能场景
int sdkFlags = SFSDKFlags.FLAGS_HOST_APPLICATION; //表明是单应用或者是主应用
SFUemSDK.getInstance().initSDK(this, sdkMode,sdkFlags,null);
break;
}
case MODE_VPN_SANDBOX: { //同时使用VPN功能+安全沙箱功能场景
int sdkFlags = SFSDKFlags.FLAGS_HOST_APPLICATION; //表明是单应用或者是主应用
sdkFlags |= SFSDKFlags.FLAGS_VPN_MODE_TCP; //表明使用VPN功能中的TCP模式
SFUemSDK.getInstance().initSDK(this, sdkMode,sdkFlags,null);
break;
}
default: {
Toast.makeText(context, "SDK模式错误", Toast.LENGTH_LONG).show();
}
}
}
}

@ -93,6 +93,9 @@ public class Contans {
/********************广播字段(唯一性)********************************/
public static final String ACTION_REFLASH_PRODUCE_FRAGMENT = "ACTION_REFLASH_PRODUCE_FRAGMENT";
public static final String USER_NAME_VPN = "usernameVpn";//vpn用户名
public static final String PASS_WORD_VPN = "pwdVpn";//vpn密码
public class KEY {
public static final String SELECT_PERSON = "select_person";//选择的人数
public static final String SELECT_ADDR = "select_addr";//选择的乘车地址

@ -0,0 +1,679 @@
package com.rehome.zhdcoa.ui.activity;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.net.http.SslError;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.webkit.DownloadListener;
import android.webkit.SslErrorHandler;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.sangfor.sdk.SFUemSDK;
import com.sangfor.sdk.base.SFBaseMessage;
import com.sangfor.sdk.base.SFTunnelStatus;
import com.sangfor.sdk.base.SFTunnelStatusListener;
import com.sangfor.sdk.utils.SFLogN;
//import com.sangfor.sdkdemo.BuildConfig;
import com.rehome.zhdcoa.R;
//import com.sangfor.sdkdemo.primary.L3VPNPrimaryAuthActivity;
import com.rehome.zhdcoa.vpn.SignatureUtils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.ref.WeakReference;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLDecoder;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.security.cert.X509Certificate;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class AuthSuccessActivity extends AppCompatActivity implements View.OnClickListener, SFTunnelStatusListener {
private static final String TAG = "app";
private static String sTestURL = "https://mobile.zhp.geg.com.cn:7082/ApkUpdate/GetData.aspx";
private final int TEST_URL_TIMEOUT_MILLIS = 8 * 1000;// 测试vpn资源的超时时间
private EditText mEtUrl;
private FrameLayout mWebViewContainer = null;
private WebView mWebView = null;
private RadioGroup mRadioGroup_authMethod = null;
private RadioButton mRadioButton_selected_authMethod = null;
private AutoCompleteTextView mAutoCompleteTextView = null;
//L3VPN全局vpn模式才需要关注的处理逻辑
private boolean mIsFromL3vpn = false;
private static ThreadPoolExecutor sBackupExecutor =
new ThreadPoolExecutor(3, 3, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "downloadfile thread #" + mCount.getAndIncrement());
}
});
static {
sBackupExecutor.allowCoreThreadTimeOut(true);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "onCreate...");
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_auth_success);
initView();
initClickEvents();
}
private void initView() {
mEtUrl = findViewById(R.id.et_url);
mRadioGroup_authMethod = findViewById(R.id.svpn_resource_tabheader);
mAutoCompleteTextView = findViewById(R.id.autoComTextView_url);
mWebViewContainer = findViewById(R.id.web_view_container);
mWebView = new WebView(getApplicationContext());
mWebViewContainer.addView(mWebView);
setWebViewSettings(); //设置webview配置参数
String[] str_extraResource_url = getResources().getStringArray(R.array.extra_resource_url);
ArrayAdapter<String> arrayAdapter =
new ArrayAdapter<String>(AuthSuccessActivity.this, R.layout.simple_spinner_item,
str_extraResource_url);
mAutoCompleteTextView.setAdapter(arrayAdapter);
mEtUrl.setText(sTestURL);
Intent intent = getIntent();
mIsFromL3vpn = true;
Button startTunnelBtn = findViewById(R.id.btn_start_tunnel);
Button stopTunnelBtn = findViewById(R.id.btn_stop_tunnel);
//L3VPN模式才显示隧道启动停止按钮和注册隧道状态回调
if (mIsFromL3vpn) {
startTunnelBtn.setVisibility(View.VISIBLE);
stopTunnelBtn.setVisibility(View.VISIBLE);
startTunnelBtn.setOnClickListener(this);
stopTunnelBtn.setOnClickListener(this);
SFUemSDK.getInstance().getSFTunnel().registerTunnelStatusListener(this);
} else {
startTunnelBtn.setVisibility(View.INVISIBLE);
stopTunnelBtn.setVisibility(View.INVISIBLE);
}
}
//注册监听事件
private void initClickEvents() {
findViewById(R.id.btn_file).setOnClickListener(this);
findViewById(R.id.btn_log).setOnClickListener(this);
findViewById(R.id.btn_master_slave).setOnClickListener(this);
findViewById(R.id.btn_modify_psw).setOnClickListener(this);
//资源展示按钮变动监听
mRadioGroup_authMethod.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
//监听认证按钮,动态改变布局显示
if(mRadioGroup_authMethod.getCheckedRadioButtonId()==R.id.svpn_intraResource_tabheader){
findViewById(R.id.et_url).setVisibility(View.VISIBLE);
findViewById(R.id.autoComTextView_url).setVisibility(View.GONE);
}
if(mRadioGroup_authMethod.getCheckedRadioButtonId()==R.id.svpn_extraResource_tabheader){
findViewById(R.id.et_url).setVisibility(View.GONE);
findViewById(R.id.autoComTextView_url).setVisibility(View.VISIBLE);
}
// switch (mRadioGroup_authMethod.getCheckedRadioButtonId()) {
// case R.id.svpn_intraResource_tabheader:
// findViewById(R.id.et_url).setVisibility(View.VISIBLE);
// findViewById(R.id.autoComTextView_url).setVisibility(View.GONE);
// break;
// case R.id.svpn_extraResource_tabheader:
// findViewById(R.id.et_url).setVisibility(View.GONE);
// findViewById(R.id.autoComTextView_url).setVisibility(View.VISIBLE);
// break;
// default:
// break;
// }
}
});
//AutoCompleteTextView控件获取焦点时展示提示资源
mAutoCompleteTextView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
((AutoCompleteTextView) v).showDropDown();
}
}
});
//内部测试代码,不需要,可以删除
Intent intent = getIntent();
if (intent != null && intent.getBooleanExtra("inner_test",false)) {
findViewById(R.id.btn_udp).setOnClickListener(this);
} else {
findViewById(R.id.btn_udp).setVisibility(View.GONE);
}
if (intent != null && intent.getBooleanExtra("inner_test",false)) {
findViewById(R.id.btn_atrust_auth).setOnClickListener(this);
} else {
findViewById(R.id.btn_atrust_auth).setVisibility(View.GONE);
}
}
@Override
public void onClick(View v) {
if(v.getId()==R.id.btn_test_res){
doTestResource();
}
if(v.getId()==R.id.btn_logout){
doVPNLogout();
}
if(v.getId()==R.id.btn_file){
entryFileTestPage();
}
if(v.getId()==R.id.btn_udp){
entryUdpPage();
}
if(v.getId()==R.id.btn_atrust_auth){
entryAtrustAuthPage();
}
if(v.getId()==R.id.btn_log){
entryLogTestPage();
}
if(v.getId()==R.id.btn_start_tunnel){
SFUemSDK.getInstance().getSFTunnel().startTunnel();
showLog(String.valueOf(SFUemSDK.getInstance().getAuthStatus()));
}
if(v.getId()==R.id.btn_stop_tunnel){
SFUemSDK.getInstance().getSFTunnel().stopTunnel();
}
if(v.getId()==R.id.btn_master_slave){
//startActivity(new Intent(this, MasterSlaveTestActivity.class));
}
if(v.getId()==R.id.btn_modify_psw){
if (!SFUemSDK.getInstance().allowResetPassword()) {
Toast.makeText(AuthSuccessActivity.this, "当前不支持修改密码", Toast.LENGTH_SHORT).show();
return;
}
//startActivity(new Intent(this, ModifyPswActivity.class));
}
}
private void entryUdpPage() {
//内部测试代码,不需要可以删除
}
private void entryAtrustAuthPage() {
//startActivity(new Intent(this, ThirdCodeAuthInnerTestActivity.class));
}
private void entryLogTestPage() {
//startActivity(new Intent(this, LogTestActivity.class));
}
private void entryFileTestPage() {
//startActivity(new Intent(this, FileTestActivtiy.class));
}
private void doTestProxyDomain() {
// 获取选定的认证方式
mRadioButton_selected_authMethod = (RadioButton) findViewById(mRadioGroup_authMethod.getCheckedRadioButtonId());
String resourceType = mRadioButton_selected_authMethod.getText().toString().trim();
final EditText editText = mEtUrl;
int port = (int) SFUemSDK.getInstance().getSocks5ProxyPort();
SFLogN.info(TAG, "Access the domain " + editText.getText().toString() + " through port " + port + " via a proxy");
showLog( "Access the domain " + editText.getText().toString() + " through port " + port + " via a proxy");
// 设置代理
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", port));
/**
*
* TrustManager
*/
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) {
// 不进行客户端证书校验
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) {
// 不进行服务器证书校验
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
};
// 创建 SSLContext
SSLContext sslContext;
try {
sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
} catch (Exception e) {
SFLogN.error2(TAG, "Failed to create SSL context: ", e.toString());
return;
}
OkHttpClient client = new OkHttpClient.Builder()
.proxy(proxy)
.sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager) trustAllCerts[0])
.hostnameVerifier((hostname, session) -> true) // 关闭主机名验证
.build();
// 使用 AsyncTask 执行网络请求
new ProxyAsyncTask(this, client, editText.getText().toString()).execute();
}
private static class ProxyAsyncTask extends AsyncTask<Void, Void, String> {
private WeakReference<AuthSuccessActivity> activityReference;
private OkHttpClient client;
private String url;
ProxyAsyncTask(AuthSuccessActivity context, OkHttpClient client, String url) {
activityReference = new WeakReference<>(context);
this.client = client;
this.url = url;
}
@Override
protected String doInBackground(Void... voids) {
// 创建请求对象
Request request = new Request.Builder()
.url(url)
.header("Proxy-Connection", "Keep-Alive")
.build();
// 发送请求并获取响应
Response response = null;
try {
response = client.newCall(request).execute();
if (response.isSuccessful()) {
return response.body().string(); // 获取响应体内容
} else {
SFLogN.info(TAG, "The request was failed, and the response code is " + response.code());
return null;
}
} catch (IOException e) {
SFLogN.error2(TAG, "An exception occurred, and the exception message is: ", e.toString());
if (response != null) {
response.body().close();
}
return null;
}
}
@Override
protected void onPostExecute(String responseBody) {
AuthSuccessActivity activity = activityReference.get();
if (activity == null || activity.isFinishing()) {
return; // Activity 已经被销毁,直接返回
}
if (responseBody != null) {
SFLogN.info(TAG, "The request " + url + " was successful.");
activity.mWebView.loadDataWithBaseURL(url, responseBody, "text/html", "utf-8", null);
} else {
SFLogN.info(TAG, "The request " + url + " was failed.");
}
}
}
/**
*
*/
private void doTestResource() {
//获取选定的认证方式
mRadioButton_selected_authMethod = (RadioButton) findViewById(mRadioGroup_authMethod.getCheckedRadioButtonId());
String resourceType = mRadioButton_selected_authMethod.getText().toString().trim();
if(resourceType.equals(getString(R.string.str_proxy_domain))) {
SFLogN.info(TAG, "begin to test proxy domain");
doTestProxyDomain();
return;
}
final EditText editText =
resourceType.equals(getString(R.string.str_intranet_resource)) ? mEtUrl : mAutoCompleteTextView;
LoadPageByWebView(editText.getText().toString());
}
/**
*
*/
private void doVPNLogout() {
// 注销VPN登录.
SFUemSDK.getInstance().logout();
Toast.makeText(AuthSuccessActivity.this, R.string.str_vpn_logout, Toast.LENGTH_SHORT).show();
}
@SuppressLint("SetJavaScriptEnabled")
public void LoadPageByWebView(String url) {
if (url == null || url.equals("")) {
SFLogN.info(TAG, "LoadPageByWebView url is wrong!");
return;
}
if (!url.contains("http")) {
url = "http://" + url;
}
showLog(url);
mWebView.loadUrl(url);
}
/**
*
*
* @param packageName
* @return
*/
private String getSafeAppSignature(String packageName) {
PackageManager packageManager = getPackageManager();
ApplicationInfo applicationInfo;
try {
applicationInfo = packageManager.getApplicationInfo(packageName, 0);
} catch (PackageManager.NameNotFoundException e) {
SFLogN.warn2(TAG, "getSafeAppSignature failed", "application not found: " + packageName, e);
return "";
}
String pubkeyInfo = SignatureUtils.getPubKeyInfo(applicationInfo, this);
if (TextUtils.isEmpty(pubkeyInfo)) {
SFLogN.warn2(TAG, "getSafeAppSignature failed", "get pubkeyInfo failed: " + packageName);
return "";
}
SFLogN.info(TAG, "pubKeyInfo: " + pubkeyInfo + ",packageName: " + packageName);
return pubkeyInfo;
}
private boolean downloadFile(String url, File dir) {
try {
SFLogN.info(TAG, "run startDownload");
long start = SystemClock.elapsedRealtime();
URL url1 = new URL(url);
String decodeUrl = URLDecoder.decode(url1.getFile(), "utf-8");
SFLogN.info(TAG, "downloadFile decodeUrl:" + decodeUrl);
File dstFile = new File(dir, decodeUrl);
try {
if (!dstFile.exists()) {
dstFile.getParentFile().mkdirs();
dstFile.createNewFile();
}
} catch (Exception e) {
SFLogN.error(TAG, "downloadFile failed.", e);
}
SFLogN.info(TAG, "downloadFile dstFile:" + dstFile.getAbsolutePath() + " exist:" + dstFile.exists());
URLConnection connection = url1.openConnection();
connection.connect();
long contentLen = 0;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
contentLen = connection.getContentLengthLong();
} else {
contentLen = connection.getContentLength();
}
SFLogN.info(TAG, "downloadFile content len:" + contentLen);
InputStream inputStream = connection.getInputStream();
OutputStream outputStream = new FileOutputStream(dstFile);
byte[] buf = new byte[2048];
int len = 0;
long totlen = 0;
long percent = 1;
long lastCount = 0, lastTime = SystemClock.elapsedRealtime();
while ((len = inputStream.read(buf)) >= 0) {
totlen += len;
outputStream.write(buf, 0, len);
if (contentLen > 0 && totlen * 100 > contentLen * percent) {
percent++;
SFLogN.info(TAG, "downloadFile %d%% speed: %.2fMB/s",
(totlen * 100 / contentLen),
(totlen - lastCount) / 1024.0 / 1024 * 1000 / (SystemClock.elapsedRealtime() - lastTime));
lastCount = totlen;
lastTime = SystemClock.elapsedRealtime();
}
}
inputStream.close();
outputStream.close();
SFLogN.info(TAG, "downloadFile over,totlen:" + totlen);
long cost = SystemClock.elapsedRealtime() - start;
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(AuthSuccessActivity.this, "下載完成!", Toast.LENGTH_SHORT).show();
}
});
SFLogN.info(TAG, "downloadFile cost:%.2fs, speed:%.2fMB/s", (cost / 1000.0f),
(totlen / 1024.0 / 1024.0 / cost * 1000));
return true;
} catch (Exception e) {
SFLogN.error(TAG, "downloadFile failed.", e);
}
return false;
}
private void setWebViewSettings() {
mWebView.setWebViewClient(new MyWebViewClient());
WebSettings webSettings = mWebView.getSettings();
// 不使用缓存,只从网络获取数据。
webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);
// 开启 DOM storage API 功能
webSettings.setDomStorageEnabled(true);
// 开启 database storage API 功能
webSettings.setDatabaseEnabled(true);
// 设置可以支持缩放
webSettings.setSupportZoom(true);
// 设置出现缩放工具
webSettings.setBuiltInZoomControls(true);
// 设置可在大视野范围内上下左右拖动,并且可以任意比例缩放
webSettings.setUseWideViewPort(true);
// 设置默认加载的可视范围是大视野范围
webSettings.setLoadWithOverviewMode(true);
// 网页中包含JavaScript内容需调用以下方法参数为true
webSettings.setJavaScriptEnabled(true);
mWebView.setDownloadListener(new DownloadListener() {
@Override
public void onDownloadStart(final String url, String userAgent, String contentDisposition, String mimetype,
long contentLength) {
SFLogN.info(TAG, "onDownloadStart url:" + url + " len:" + contentLength);
SFLogN.info(TAG, "onDownloadStart download dir:" + getExternalFilesDir(null).getAbsolutePath());
Toast.makeText(AuthSuccessActivity.this, String.format("下载地址Url:%s 下载文件路径:%s",
url, getExternalFilesDir(null).getAbsolutePath()), Toast.LENGTH_LONG).show();
sBackupExecutor.submit(new Runnable() {
@Override
public void run() {
SFLogN.info(TAG, "run startDownload");
boolean ret = downloadFile(url, new File(getExternalFilesDir(null) + "/download/"));
SFLogN.info(TAG, "run downloadFile ret:" + ret);
}
});
}
});
}
private class MyWebViewClient extends WebViewClient {
public MyWebViewClient() {
}
@Override
// 覆盖WebView默认使用第三方或系统默认浏览器打开网页的行为使网页用WebView打开
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;// 返回值是true的时候控制去WebView打开为false调用系统浏览器或第三方浏览器
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
SFLogN.info(TAG, "onPageStarted url = " + url);
}
@Override
public void onPageFinished(WebView view, String url) {
//清除缓存
mWebView.clearCache(true);
mWebView.clearHistory();
super.onPageFinished(view, url);
}
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
handler.proceed();// 忽略证书错误
}
}
/**
* WebView
*/
private void destroyWebView() {
mWebViewContainer.removeAllViews();
if (mWebView != null) {
mWebView.clearHistory();
mWebView.clearCache(true);
mWebView.loadUrl("about:blank");
mWebView.freeMemory();
// mWebView.pauseTimers();
mWebView.destroy();
}
}
@Override
protected void onResume() {
Log.i(TAG, "onResume...");
super.onResume();
}
@Override
protected void onNewIntent(Intent intent) {
Log.i(TAG, "onNewIntent...");
super.onNewIntent(intent);
}
@Override
protected void onDestroy() {
destroyWebView();
if (mIsFromL3vpn) {
SFUemSDK.getInstance().getSFTunnel().unRegisterTunnelStatusListener(this);
}
super.onDestroy();
}
@Override
public void onTunnelStatusChanged(SFTunnelStatus curStatus) {
SFLogN.info(TAG, "onTunnelStatusChanged called: curStatus: " + curStatus);
}
@Override
public void onTunnelStarted(SFBaseMessage msg) {
SFLogN.info(TAG, "onTunnelStarted, msg: " + msg.mErrStr + ",errCode: " + msg.mErrCode);
if (msg.mErrCode != 0) {
SFLogN.warn2(TAG, "start Tunnel failed", msg.mErrStr);
showToast("L3VPN隧道启动失败 " + msg.mErrStr);
return;
}
SFLogN.info(TAG, "startTunnel finished");
showToast("L3VPN隧道启动成功");
}
@Override
public void onTunnelStoped() {
SFLogN.info(TAG, "onTunnelStoped");
showToast("隧道已经关闭");
}
//封装Toast
public void showToast(final String text) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(AuthSuccessActivity.this, text, Toast.LENGTH_SHORT).show();
}
});
}
public void showLog(String logText) {
if (isApkInDebug(AuthSuccessActivity.this)) {
if(TextUtils.isEmpty(logText)){
Log.i("app", "logText is null");
}else{
Log.i("app", logText);
}
}
}
/**
* debug
*/
public static boolean isApkInDebug(Context context) {
try {
ApplicationInfo info = context.getApplicationInfo();
return (info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
} catch (Exception e) {
return false;
}
}
}

@ -18,6 +18,8 @@ import android.view.View
import android.widget.CompoundButton
import android.widget.RadioGroup
import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import com.google.gson.Gson
import com.rehome.zhdcoa.App
@ -29,6 +31,7 @@ import com.rehome.zhdcoa.bean.UserInfoBean
import com.rehome.zhdcoa.databinding.ActivityLoginBinding
import com.rehome.zhdcoa.ui.toastview.toastviewbymyself
import com.rehome.zhdcoa.utils.*
import com.sangfor.sdk.SFUemSDK
import com.tencent.bugly.crashreport.CrashReport
import com.yolanda.nohttp.NoHttp
import com.yolanda.nohttp.RequestMethod
@ -43,6 +46,10 @@ class LoginActivity : BaseActivityOaToolbarViewBinding<ActivityLoginBinding>() {
private lateinit var networkCheckType: String
private var usernameVpn = ""
private var pwdVpn = ""
private lateinit var launcherResultVpn: ActivityResultLauncher<Intent>
override fun getViewBinding() = ActivityLoginBinding.inflate(layoutInflater)
override fun getToolbar() = binding.toolbarView.toolbar
@ -50,6 +57,7 @@ class LoginActivity : BaseActivityOaToolbarViewBinding<ActivityLoginBinding>() {
override fun initView() {
StatusBarUtil.transparencyBar(this)
launcherResultVpn = createActivityResultLauncherVpn()
val wifi = SPUtils.get(context, Contans.YX_WIFI_IP, "") as String
val mob = SPUtils.get(context, Contans.YX_4G_IP, "") as String
if (wifi == "" && mob == "") {
@ -101,6 +109,15 @@ class LoginActivity : BaseActivityOaToolbarViewBinding<ActivityLoginBinding>() {
Contans.BASE_URL_AI_3D_SERVER =
Contans.BASE_URL_AI_3D_SERVER_EXTRANET //AI三维可视化安防平台登录 电厂外网
}
if (networkCheckType == "aTrust") {
binding.rg.check(R.id.rb3)
Contans.IP = Contans.IP_INTRANET //运行IP内网
Contans.BASE_URL = Contans.BASE_URL_INTRANET //行政IP内网
Contans.BASE_URL_COMPANY_SERVER =
Contans.BASE_URL_COMPANY_SERVER_INTRANET //智慧安防平台登录 电厂内网
Contans.BASE_URL_AI_3D_SERVER =
Contans.BASE_URL_AI_3D_SERVER_INTRANET //AI三维可视化安防平台登录 电厂外网
}
} else {
binding.rg.check(R.id.rb2)
SPUtils.put(this, Contans.NETWORK_CHECK_TYPE, "外网")
@ -133,6 +150,16 @@ class LoginActivity : BaseActivityOaToolbarViewBinding<ActivityLoginBinding>() {
Contans.BASE_URL_AI_3D_SERVER =
Contans.BASE_URL_AI_3D_SERVER_EXTRANET //AI三维可视化安防平台登录 电厂外网
}
R.id.rb3 -> {
SPUtils.put(this, Contans.NETWORK_CHECK_TYPE, "aTrust")
Contans.IP = Contans.IP_INTRANET //运行IP内网
Contans.BASE_URL = Contans.BASE_URL_INTRANET //行政IP内网
Contans.BASE_URL_COMPANY_SERVER =
Contans.BASE_URL_COMPANY_SERVER_INTRANET //智慧安防平台登录 电厂内网
Contans.BASE_URL_AI_3D_SERVER =
Contans.BASE_URL_AI_3D_SERVER_INTRANET //AI三维可视化安防平台登录 电厂外网
}
}
})
binding.cbAgreement.setOnCheckedChangeListener(CompoundButton.OnCheckedChangeListener { buttonView, isChecked ->
@ -145,14 +172,25 @@ class LoginActivity : BaseActivityOaToolbarViewBinding<ActivityLoginBinding>() {
binding.tvServiceAgreement.setOnClickListener {
val intent = Intent(this, ServiceAgreementActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
startActivity(intent)
}
binding.tvPrivacy.setOnClickListener {
val intent = Intent(this, PrivacyAgreementActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
startActivity(intent)
}
//vpn登录
binding.tvVpn.setOnClickListener {
goToVpnLogin()
}
//vpn注销
binding.tvVpnLogout.setOnClickListener {
// 注销VPN登录.
SFUemSDK.getInstance().logout()
showToast(R.string.str_vpn_logout)
}
}
@SuppressLint("SetTextI18n")
@ -174,8 +212,8 @@ class LoginActivity : BaseActivityOaToolbarViewBinding<ActivityLoginBinding>() {
if (isApkInDebug(context)) {
// 管理员
// binding.etUsername.setText("ZHPS_Admin")
// binding.etPassword.setText("Rehome.zhps@996")
binding.etUsername.setText("ZHPS_Admin")
binding.etPassword.setText("Rehome.zhps@996")
//公司内网215管理员
@ -256,6 +294,7 @@ class LoginActivity : BaseActivityOaToolbarViewBinding<ActivityLoginBinding>() {
this,
WjmmGetVerificationCodeActivity::class.java
)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
startActivity(intent)
})
@ -560,6 +599,75 @@ class LoginActivity : BaseActivityOaToolbarViewBinding<ActivityLoginBinding>() {
System.exit(0)
}
private fun checkInput(): Boolean{
if (TextUtils.isEmpty(binding.etUsername.text.toString())) {
showToast("用户名不能为空")
return false
}
if (TextUtils.isEmpty(binding.etPassword.text.toString())) {
showToast("密码不能为空")
return false
}
return true;
}
private fun goToVpnLogin() {
val usernameVpnTemp = SPUtils.get(context, Contans.USER_NAME_VPN, "") as String
val pwdVpnTemp = SPUtils.get(context, Contans.PASS_WORD_VPN, "") as String
if ((!TextUtils.isEmpty(usernameVpnTemp)) && (!TextUtils.isEmpty(pwdVpnTemp))) {
usernameVpn = RSAUtils.decryptBASE64StrLocal(usernameVpnTemp)
pwdVpn = RSAUtils.decryptBASE64StrLocal(pwdVpnTemp)
}
//val intent = Intent(context, VpnLoginActivity::class.java)
val intent = Intent(context, VpnAuthActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
if ((!TextUtils.isEmpty(usernameVpn)) && (!TextUtils.isEmpty(pwdVpn))) {
intent.putExtra("usernameVpn",usernameVpn)
intent.putExtra("pwdVpn",pwdVpn)
}
launcherResultVpn.launch(intent)
}
//创建一个ActivityResultLauncher
private fun createActivityResultLauncherVpn(): ActivityResultLauncher<Intent> {
//kotlin写法
return registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
val data = it.data
val resultCode = it.resultCode
if (resultCode == RESULT_OK) {
if (data != null) {
usernameVpn = data.getStringExtra("usernameVpn").toString()
pwdVpn = data.getStringExtra("pwdVpn").toString()
showLog(usernameVpn)
showLog(pwdVpn)
SPUtils.put(
context,
Contans.USER_NAME_VPN,
RSAUtils.encryptBASE64StrLocal(usernameVpn)
)
SPUtils.put(
context,
Contans.PASS_WORD_VPN,
RSAUtils.encryptBASE64StrLocal(pwdVpn)
)
if(checkInput()){
//登录
appLogin()
// val intent = Intent(context, AuthSuccessActivity::class.java)
// intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
// startActivity(intent)
// finish()
}
}
}
}
}
}

@ -0,0 +1,490 @@
package com.rehome.zhdcoa.ui.activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.sangfor.sdk.SFUemSDK;
import com.sangfor.sdk.base.SFAuthResultListener;
import com.sangfor.sdk.base.SFAuthType;
import com.sangfor.sdk.base.SFBaseMessage;
import com.sangfor.sdk.base.SFChangePswMessage;
import com.sangfor.sdk.base.SFConstants;
import com.sangfor.sdk.base.SFSetSpaConfigListener;
import com.sangfor.sdk.base.SFSmsMessage;
import com.sangfor.sdk.utils.SFLogN;
import com.rehome.zhdcoa.R;
import com.rehome.zhdcoa.vpn.Constants;
//import com.rehome.zhdcoa.activity.AuthSuccessActivity;
import com.rehome.zhdcoa.vpn.SFDialogHelper;
import java.util.HashMap;
import java.util.Map;
public class PrimaryAuthActivity extends AppCompatActivity implements SFAuthResultListener {
private static final String TAG = "app";
private String mServerAddress = "https://vpn.zhp.geg.com.cn:55420"; //服务器地址
private String mUserName = "rehome5"; //用户名
private String mUserPassword = "452131wW,./"; //密码
private EditText mServerAddressEditText = null;
private EditText mUserNameEditView = null;
private EditText mUserPasswordEditView = null;
private Button mLoginButton = null;
private AlertDialog mAuthDialog = null;
private ProgressDialog mProgressDialog = null; // 进度条对话框
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.i(TAG, "onCreate...");
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_primary_auth);
//加载UI
initView();
//SPA初始化设置安全码
String config = "{\"loginAddress\":\"https://vpn.zhp.geg.com.cn:55420\", \"spaSecret\":\"7FFQ-rWE5-V6xX\"}";
SFUemSDK.setSpaConfig(config, new SFSetSpaConfigListener() {
@Override
public void onSetSpaConfig(String result, SFBaseMessage error) {
SFLogN.info(TAG, "spa result:"+ result + ", error:" + error);
Log.i(TAG, "spa result:"+ result + ", error:" + error);
if (error.mErrCode != 0) {
Toast.makeText(PrimaryAuthActivity.this,
"SPA设置失败"+ ", Error Message:" + error.toString(),
Toast.LENGTH_SHORT)
.show();
} else {
Toast.makeText(PrimaryAuthActivity.this, "SPA设置成功 result:" + result,
Toast.LENGTH_SHORT)
.show();
}
}
});
//加载上次登录信息
setLoginInfo();
/**
* ,SFAuthResultListeneronAuthSuccessonAuthFailedonAuthProgress
*
*/
SFUemSDK.getInstance().setAuthResultListener(this);
//免密认证
startAutoTicket();
}
private void startAutoTicket() {
/**
* true访
* false,
*/
if (SFUemSDK.getInstance().startAutoTicket()){
showToast("免密成功");
// startActivity(new Intent(PrimaryAuthActivity.this, AuthSuccessActivity.class));
// finish();
}
}
@Override
protected void onResume() {
Log.i(TAG,"onResume... ");
super.onResume();
}
@Override
protected void onNewIntent(Intent intent) {
Log.i(TAG, "onNewIntent...");
super.onNewIntent(intent);
}
@Override
protected void onPause() {
super.onPause();
//只有走回收流程的时候的那种onPauseisFinishing才为true
if (isFinishing()) {
//取消认证回调
SFLogN.info(TAG,"SFUemSDK setAuthResultListener null");
/**
* onPause()onDestroy()
* onDestroy()onCreate()onCreateonDestory
*/
SFUemSDK.getInstance().setAuthResultListener(null);
}
}
// 初始化界面元素
private void initView() {
mServerAddressEditText = findViewById(R.id.vpn_addr_editView);
mUserNameEditView = findViewById(R.id.svpn_username_editView);
mUserPasswordEditView = findViewById(R.id.svpn_userPassword_editView);
//登录按钮
mLoginButton = findViewById(R.id.svpn_login_button);
mLoginButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mServerAddress = mServerAddressEditText.getText().toString();
mUserName = mUserNameEditView.getText().toString();
mUserPassword = mUserPasswordEditView.getText().toString();
//开始主认证
startPrimaryAuth();
}
});
}
//开始用户名密码认证
private void startPrimaryAuth() {
if (TextUtils.isEmpty(mServerAddress)) {
showToast("VPN服务器地址不能为空");
return;
}
if (TextUtils.isEmpty(mUserName)) {
showToast("用户名不能为空");
return;
}
showWaitingDialog(false);
/**
* onAuthSuccess,onAuthFailed,onAuthProgress
*/
SFUemSDK.getInstance().startPasswordAuth(mServerAddress, mUserName, mUserPassword);
}
/**
*
*
* @param message
*/
@Override
public void onAuthSuccess(final SFBaseMessage message) {
SFLogN.info(TAG, "auth success");
//关闭进度框
dismissWaitingDialog();
saveLoginInfo(); //保存登录信息
//认证完成,跳转认证成功界面,可以开始访问资源
runOnUiThread(new Runnable() {
@Override
public void run() {
showToast(getString(R.string.auth_success));
// startActivity(new Intent(PrimaryAuthActivity.this, AuthSuccessActivity.class));
// finish();
}
});
}
/**
*
*
* @param message
*/
@Override
public void onAuthFailed(final SFBaseMessage message) {
SFLogN.error2(TAG, "auth failed", "errMsg: " + message.mErrStr);
//关闭进度框
dismissWaitingDialog();
//认证失败
runOnUiThread(new Runnable() {
@Override
public void run() {
showErrorMessage(message.mErrStr);
}
});
}
/**
*
*
* @param nextAuthType
* @param message
*/
@Override
public void onAuthProgress(SFAuthType nextAuthType, SFBaseMessage message) {
SFLogN.info(TAG, "need next auth, authType: " + nextAuthType.name());
dismissWaitingDialog();
/**
* 1. onAuthProgress, ;
* "首次登录强制修改密码", onAuthProgress;
* , , onAuthProgress.
*
* 2. , :
* , ,
* , .
*/
if (nextAuthType == SFAuthType.AUTH_TYPE_RENEW_PASSWORD) {
//显示下一步认证UI界面
showAuthDialog(nextAuthType, message);
return;
}
showErrorMessage("暂不支持此种认证类型(" + nextAuthType.toString() + ")");
}
//显示“请稍候...”提示框
public void showWaitingDialog(final boolean isCancelable) {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (mProgressDialog == null || !mProgressDialog.isShowing()) {
mProgressDialog = new ProgressDialog(PrimaryAuthActivity.this);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
mProgressDialog.setTitle("");
mProgressDialog.setMessage(PrimaryAuthActivity.this.getString(R.string.waiting));
mProgressDialog.setCancelable(isCancelable);
mProgressDialog.show();
}
}
});
}
//取消“请稍候...”提示框
public void dismissWaitingDialog() {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (mProgressDialog != null && mProgressDialog.isShowing()) {
mProgressDialog.dismiss();
mProgressDialog = null;
}
}
});
}
//显示错误提示对话框
public void showErrorMessage(final String errMsg) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Dialog messageDialog = new AlertDialog.Builder(PrimaryAuthActivity.this)
.setTitle(PrimaryAuthActivity.this.getString(R.string.info))
.setMessage(errMsg)
.setIcon(android.R.drawable.ic_dialog_alert)
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
})
.create();
messageDialog.show();
}
});
}
//封装Toast
public void showToast(final String text) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(PrimaryAuthActivity.this, text, Toast.LENGTH_SHORT).show();
}
});
}
//恢复登录信息,重启应用后记录原来的登陆信息
private void setLoginInfo() {
SharedPreferences sharedPreferences = getSharedPreferences(Constants.PREF_FILE_NAME, MODE_PRIVATE);
mServerAddress = sharedPreferences.getString(Constants.KEY_VPN_ADDRESS, mServerAddress);
mUserName = sharedPreferences.getString(Constants.KEY_USER_NAME, mUserName);
mUserPassword = sharedPreferences.getString(Constants.KEY_USER_PASSWORD, mUserPassword);
mServerAddressEditText.setText(mServerAddress);
mUserNameEditView.setText(mUserName);
mUserPasswordEditView.setText(mUserPassword);
}
//更新保存的登录信息
private void saveLoginInfo() {
SharedPreferences sharedPreferences = getSharedPreferences(Constants.PREF_FILE_NAME, MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(Constants.KEY_VPN_ADDRESS, mServerAddress);
//保存用户名和密码,真实场景请加密存储
editor.putString(Constants.KEY_USER_NAME, mUserName);
editor.putString(Constants.KEY_USER_PASSWORD, mUserPassword);
editor.apply();
}
/**
* UI
*/
private void showAuthDialog(final SFAuthType authType, final SFBaseMessage message) {
runOnUiThread(new Runnable() {
@Override
public void run() {
closeDialog();
//获取认证类型对应的标题
String dialogTitle = SFDialogHelper.getDialogTitle(authType);
if (TextUtils.isEmpty(dialogTitle)) {
showErrorMessage("暂不支持此种认证类型(" + authType.toString() + ")");
return;
}
//获取认证类型对应的layout布局
int viewLayoutId = SFDialogHelper.getAuthDialogViewId(authType);
handlerSecondAuth(dialogTitle, viewLayoutId, authType, message);
}
});
}
/**
*
*/
private void closeDialog() {
if (mAuthDialog != null && mAuthDialog.isShowing()) {
mAuthDialog.dismiss();
mAuthDialog = null;
}
}
/**
*
* @param dialogTitle
* @param viewLayoutId
* @param authType
* @param message
*/
private void handlerSecondAuth(String dialogTitle, int viewLayoutId, SFAuthType authType, SFBaseMessage message) {
//创建认证类型对应的对话框显示视图
final View dialogView = createDialogView(authType, viewLayoutId, message);
mAuthDialog = new AlertDialog.Builder(PrimaryAuthActivity.this)
.setTitle(dialogTitle)
.setView(dialogView)
.setCancelable(false)
.setPositiveButton(R.string.str_commit, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
closeDialog();
//构建辅助认证类型所需参数
Map<String, String> authParams = new HashMap<String, String>();
String errorMsg = buildAuthParams(authType, dialogView, authParams);
//检查参数构建是否成功
if (TextUtils.isEmpty(errorMsg)) {
showWaitingDialog(false);
//开始辅助认证
SFUemSDK.getInstance().doSecondaryAuth(authType, authParams);
} else {
//参数构建失败,进行提示
showErrorMessage(errorMsg);
}
return;
}
})
.setNegativeButton(R.string.str_cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//放弃继续认证
closeDialog();
return;
}
})
.create();
//显示认证对话框
mAuthDialog.show();
}
/**
*
*
* @param sfAuthType
* @param layoutId ID
* @param message
* @return
*/
private View createDialogView(SFAuthType sfAuthType, int layoutId, final SFBaseMessage message) {
LayoutInflater inflater = getLayoutInflater();
View dialogView = inflater.inflate(layoutId, null);
switch (sfAuthType) {
case AUTH_TYPE_RENEW_PASSWORD: {
TextView tvPolicy = (TextView) dialogView.findViewById(R.id.tv_policy);
String policy = "";
//获取密码策略
if (message instanceof SFChangePswMessage) {
policy = ((SFChangePswMessage) message).policyMsg;
}
if (TextUtils.isEmpty(policy)) {
tvPolicy.setText(R.string.str_no_policy);
} else {
tvPolicy.setText(getString(R.string.str_policy_hint) + "\n" + policy);
}
break;
}
default:
break;
}
return dialogView;
}
/**
*
*
* @param sfAuthType
* @param dialogView
* @param authParams
* @return
*/
private String buildAuthParams(SFAuthType sfAuthType, View dialogView, Map<String, String> authParams) {
String errorMsg = "";
switch (sfAuthType) {
case AUTH_TYPE_RENEW_PASSWORD: {
EditText etNewPwd = dialogView.findViewById(R.id.et_newpwd);
EditText etOldPwd = dialogView.findViewById(R.id.et_oldpwd);
EditText etReNewPwd = dialogView.findViewById(R.id.et_renewpwd);
String oldPwd = etOldPwd.getText().toString();
String newPwd = etNewPwd.getText().toString();
String reNewPwd = etReNewPwd.getText().toString();
if (TextUtils.isEmpty(newPwd) || TextUtils.isEmpty(reNewPwd)) {
errorMsg = "新密码不能为空";
break;
}
if (!newPwd.equals(reNewPwd)) {
errorMsg = "新密码与确认密码不一致";
break;
}
authParams.put(SFConstants.AUTH_KEY_RENEW_OLD_PASSWORD, oldPwd);
authParams.put(SFConstants.AUTH_KEY_REWNEW_NEW_PASSWORD, newPwd);
break;
}
default:
errorMsg = "暂不支持的认证类型";
break;
}
return errorMsg;
}
}

@ -0,0 +1,719 @@
package com.rehome.zhdcoa.ui.activity;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.Process;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.RadioGroup;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import com.sangfor.sdk.SFUemSDK;
import com.sangfor.sdk.base.SFAuthResultListener;
import com.sangfor.sdk.base.SFAuthType;
import com.sangfor.sdk.base.SFBaseMessage;
import com.sangfor.sdk.base.SFChangePswMessage;
import com.sangfor.sdk.base.SFConstants;
import com.sangfor.sdk.base.SFRegetRandCodeListener;
import com.sangfor.sdk.base.SFRegetSmsListener;
import com.sangfor.sdk.base.SFSetSpaConfigListener;
import com.sangfor.sdk.base.SFSmsMessage;
import com.sangfor.sdk.utils.SFLogN;
import com.rehome.zhdcoa.R;
import com.rehome.zhdcoa.vpn.CertUtils;
import com.rehome.zhdcoa.vpn.Constants;
import com.rehome.zhdcoa.vpn.PermissionUtil;
import com.rehome.zhdcoa.vpn.SFDialogHelper;
import java.io.ByteArrayInputStream;
import java.security.MessageDigest;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
public class PrimarySmsLoginActivity extends AppCompatActivity implements SFAuthResultListener, SFRegetSmsListener,
SFRegetRandCodeListener {
private static final String TAG = "app";
private static final int PERMISSON_REQUEST_CODE = 32; //动态权限请求码
private static final int CERTFILE_REQUEST_CODE = 33; //当证书认证是主认证时获取证书路径请求码
private static final int DIALOG_CERTFILE_REQUEST_CODE = 34; //当证书认证是辅助认证时获取证书路径请求码
private static final int DEFAULT_SMS_COUN_TDOWN_TIME = 30; //短信验证码默认倒计时时间, 以秒为单位
private String mVpnAddress = "https://vpn.zhp.geg.com.cn:55420";
// enum SERVER_MODE {
// VPN,
// SDP
// }
//private SERVER_MODE mServerMode = SERVER_MODE.SDP;
//private String mSdpAddress = "https://10.242.4.235:443";
private String mPhoneNumber = "15307858521";
//View
private AlertDialog mAuthDialog = null;
private EditText mVpnAddressEditText = null;
private EditText mPhoneNumberEditView = null;
private Button mLoginButton = null;
private View mRandCodeDialogView = null; //图形校验码对话框视图
private View mSmsCodeDialogView = null; //短信验证码对话框视图
private EditText mCertPathDialogEditView = null;//证书路径输入框
private ProgressDialog mProgressDialog = null; // 对话框对象
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_vpn_auth);
//加载UI
initView();
//SPA初始化设置安全码
String config = "{\"loginAddress\":\"https://vpn.zhp.geg.com.cn:55420\", \"spaSecret\":\"7FFQ-rWE5-V6xX\"}";
SFUemSDK.setSpaConfig(config, new SFSetSpaConfigListener() {
@Override
public void onSetSpaConfig(String result, SFBaseMessage error) {
SFLogN.info(TAG, "spa result:"+ result + ", error:" + error);
Log.i(TAG, "spa result:"+ result + ", error:" + error);
if (error.mErrCode != 0) {
Toast.makeText(PrimarySmsLoginActivity.this,
"SPA设置失败"+ ", Error Message:" + error.toString(),
Toast.LENGTH_SHORT)
.show();
} else {
Toast.makeText(PrimarySmsLoginActivity.this, "SPA设置成功 result:" + result,
Toast.LENGTH_SHORT)
.show();
}
}
});
// SFUemSDK.setSpaConfig(config, new SFSetSpaConfigListener() {
// @Override
// public void onSetSpaConfig(String result, SFBaseMessage error) {
// Log.i(TAG, "spa result:"+ result + ", error:" + error);
// if (error.mErrCode != 0) {
// Toast.makeText(PrimarySmsLoginActivity.this,
// "SPA设置失败"+ ", Error Message:" + error.toString(),
// Toast.LENGTH_SHORT)
// .show();
// } else {
// Toast.makeText(PrimarySmsLoginActivity.this, "SPA设置成功 result:" + result,
// Toast.LENGTH_SHORT)
// .show();
//
// }
// }
// });
//加载上次登录信息
setLoginInfo();
/**
* ,SFAuthResultListeneronAuthSuccessonAuthFailedonAuthProgress
*
*/
SFUemSDK.getInstance().setAuthResultListener(this);
if (SFUemSDK.getInstance().startAutoTicket()){
showToast("免密成功");
//startActivity(new Intent(PrimarySmsLoginActivity.this, AuthSuccessActivity.class));
}
}
@Override
protected void onResume() {
super.onResume();
}
@Override
protected void onDestroy() {
super.onDestroy();
//取消认证回调
SFLogN.info(TAG,"SFUemSDK setAuthResultListener ");
SFUemSDK.getInstance().setAuthResultListener(null);
}
/**
*
*/
private void initView() {
mVpnAddressEditText = findViewById(R.id.vpn_addr_editView);
mPhoneNumberEditView = findViewById(R.id.svpn_username_editView);
//登录按钮
mLoginButton = findViewById(R.id.svpn_login_button);
mLoginButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//开始主认证,用户名密码或者证书认证,在认证回调中返回认证结果
startPrimaryAuth();
}
});
}
/**
*
*/
private void startPrimaryAuth() {
mVpnAddress = mVpnAddressEditText.getText().toString();
mPhoneNumber = mPhoneNumberEditView.getText().toString();
if (TextUtils.isEmpty(mVpnAddress)) {
showToast("VPN服务器地址不能为空");
return;
}
if (TextUtils.isEmpty(mPhoneNumber)) {
showToast("手机号码不能为空");
return;
}
showWaitingDialog(false);
SFUemSDK.getInstance().startPrimarySmsAuth(mVpnAddress, mPhoneNumber);
}
/**
*
*
* @param message
*/
@Override
public void onAuthSuccess(final SFBaseMessage message) {
SFLogN.info(TAG, "auth success");
dismissWaitingDialog();
saveLoginInfo(); //保存登录信息
//认证完成,跳转认证成功界面,可以开始访问资源
runOnUiThread(new Runnable() {
@Override
public void run() {
showToast(getString(R.string.auth_success));
//startActivity(new Intent(PrimarySmsLoginActivity.this, AuthSuccessActivity.class));
}
});
}
/**
*
*
* @param message
*/
@Override
public void onAuthFailed(final SFBaseMessage message) {
SFLogN.error2(TAG, "auth failed", "errMsg: " + message.mErrStr);
dismissWaitingDialog();
//认证失败
runOnUiThread(new Runnable() {
@Override
public void run() {
showErrorMessage(message.mErrStr);
}
});
}
/**
*
*
* @param nextAuthType
* @param message
*/
@Override
public void onAuthProgress(SFAuthType nextAuthType, SFBaseMessage message) {
SFLogN.info(TAG, "need next auth, authType: " + nextAuthType.name());
dismissWaitingDialog();
//显示下一步认证UI界面
showAuthDialog(nextAuthType, message);
}
/**
* UI
*/
public void showAuthDialog(final SFAuthType authType, final SFBaseMessage message) {
runOnUiThread(new Runnable() {
@Override
public void run() {
closeDialog();
//获取认证类型对应的标题
String dialogTitle = SFDialogHelper.getDialogTitle(authType);
if (TextUtils.isEmpty(dialogTitle)) {
showErrorMessage("暂不支持此种认证类型(" + authType.toString() + ")");
return;
}
//获取认证类型对应的layout布局
int viewLayoutId = SFDialogHelper.getAuthDialogViewId(authType);
//创建认证类型对应的对话框显示视图
final View dialogView = createDialogView(authType, viewLayoutId, message);
mAuthDialog = new AlertDialog.Builder(PrimarySmsLoginActivity.this)
.setTitle(dialogTitle)
.setView(dialogView)
.setCancelable(false)
.setPositiveButton(R.string.str_commit, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
closeDialog();
//构建辅助认证类型所需参数
Map<String, String> authParams = new HashMap<String, String>();
String errorMsg = buildAuthParams(authType, dialogView, authParams);
//检查参数构建是否成功
if (TextUtils.isEmpty(errorMsg)) {
showWaitingDialog(false);
//开始辅助认证
SFUemSDK.getInstance().doSecondaryAuth(authType, authParams);
} else {
//参数构建失败,进行提示
showErrorMessage(errorMsg);
}
return;
}
})
.setNegativeButton(R.string.str_cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//放弃继续认证
closeDialog();
return;
}
})
.create();
//显示认证对话框
mAuthDialog.show();
}
});
}
/**
*
*
* @param sfAuthType
* @param layoutId ID
* @param message
* @return
*/
private View createDialogView(SFAuthType sfAuthType, int layoutId, final SFBaseMessage message) {
LayoutInflater inflater = getLayoutInflater();
View dialogView = inflater.inflate(layoutId, null);
switch (sfAuthType) {
case AUTH_TYPE_SMS:
case AUTH_TYPE_PRIMARY_SMS: {
mSmsCodeDialogView = dialogView;
TextView tvTel = dialogView.findViewById(R.id.tv_tel);
Button btnGetVerficationCode = dialogView.findViewById(R.id.bt_getVerficationCode);
btnGetVerficationCode.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
v.setEnabled(false);
//调用重新获取短信接口
SFUemSDK.getInstance().getSFAuth().regetSmsCode(PrimarySmsLoginActivity.this);
}
});
SFSmsMessage smsMessage = ((SFSmsMessage) message);
//获取手机号码
String smsPhoneNum = smsMessage.getPhoneNum();
if (TextUtils.isEmpty(smsPhoneNum)) {
tvTel.setText(R.string.get_phone_number_failed);
} else {
tvTel.setText(getString(R.string.phone_number) + smsPhoneNum);
}
//上次发送的短信验证码是否在有效期
if (smsMessage.isStillValid()) {
showToast("上次发送的短信验证码仍在有效期");
}
//开启短信码倒计时
smsCountDownTimer(btnGetVerficationCode, smsMessage.getCountDown());
break;
}
case AUTH_TYPE_RENEW_PASSWORD: {
TextView tvPolicy = (TextView) dialogView.findViewById(R.id.tv_policy);
String policy = "";
//获取密码策略
if (message instanceof SFChangePswMessage) {
policy = ((SFChangePswMessage) message).policyMsg;
}
if (TextUtils.isEmpty(policy)) {
tvPolicy.setText(R.string.str_no_policy);
} else {
tvPolicy.setText(getString(R.string.str_policy_hint) + "\n" + policy);
}
break;
}
case AUTH_TYPE_RAND: {
mRandCodeDialogView = dialogView;// 保存一份图形校验码对话框视图
final ImageView imgError = dialogView.findViewById(R.id.randcode_imgError);
final ImageView imgRandCode = dialogView.findViewById(R.id.iv_graphCode);
// 按图片刷新校验码
View.OnClickListener refreshListener = new View.OnClickListener() {
public void onClick(View v) {
long lastRefresh = (Long) imgRandCode.getTag();
//检查更新间隔暂定间隔3秒
if (System.currentTimeMillis() - lastRefresh >= 3 * 1000) {
// 启动刷新任务
SFUemSDK.getInstance().getSFAuth().regetRandCode(PrimarySmsLoginActivity.this);
imgRandCode.setTag(System.currentTimeMillis());
}
}
};
imgError.setOnClickListener(refreshListener);
imgRandCode.setOnClickListener(refreshListener);
SFUemSDK.getInstance().getSFAuth().regetRandCode(PrimarySmsLoginActivity.this); //首次自动触发获取校验码
imgRandCode.setTag(System.currentTimeMillis());// 记录上次更新时间到imgChecksum控件的tag里初始化为0即没有上次更新
break;
}
default:
break;
}
return dialogView;
}
/**
*
*
* @param button
*/
private void smsCountDownTimer(final Button button, final int countDown) {
int smsRefreshTime = countDown < 0 ? DEFAULT_SMS_COUN_TDOWN_TIME : countDown;
//开启短信验证码倒计时,第一个参数为倒计时时间(毫秒),第二个为时间间隔
new CountDownTimer(smsRefreshTime * 1000, 1000) {
@Override
public void onTick(long millisUntilFinished) {
button.setText(millisUntilFinished / 1000 + getString(R.string.after_time_resend));
button.setTextColor(Color.parseColor("#708090"));
button.setEnabled(false);
}
@Override
public void onFinish() {
button.setText(R.string.str_resend);
button.setTextColor(Color.parseColor("#000000"));
button.setEnabled(true);
}
}.start();
}
/**
*
*
* @param sfAuthType
* @param dialogView
* @param authParams
* @return
*/
private String buildAuthParams(SFAuthType sfAuthType, View dialogView, Map<String, String> authParams) {
String errorMsg = "";
switch (sfAuthType) {
case AUTH_TYPE_SMS: {
EditText etSmsCode = dialogView.findViewById(R.id.et_verficationCode);
String smsCode = etSmsCode.getText().toString();
if (TextUtils.isEmpty(smsCode)) {
errorMsg = "短信验证码不能为空";
break;
}
authParams.put(SFConstants.AUTH_KEY_SMS, smsCode);
break;
}
case AUTH_TYPE_PRIMARY_SMS: {
EditText etSmsCode = dialogView.findViewById(R.id.et_verficationCode);
String smsCode = etSmsCode.getText().toString();
if (TextUtils.isEmpty(smsCode)) {
errorMsg = "短信验证码不能为空";
break;
}
authParams.put(SFConstants.AUTH_KEY_PRIMARYSMS_CODE, smsCode);
break;
}
case AUTH_TYPE_RADIUS: {
EditText etRadiusAnswer = dialogView.findViewById(R.id.et_authAnswer);
String radiusAnswer = etRadiusAnswer.getText().toString();
if (TextUtils.isEmpty(radiusAnswer)) {
errorMsg = "认证答案不能为空";
break;
}
authParams.put(SFConstants.AUTH_KEY_RADIUS_CODE, radiusAnswer);
break;
}
case AUTH_TYPE_TOKEN: {
EditText etDynamicToken = dialogView.findViewById(R.id.et_dynamicToken);
String dynamicToken = etDynamicToken.getText().toString();
if (TextUtils.isEmpty(dynamicToken)) {
errorMsg = "动态口令不能为空";
break;
}
authParams.put(SFConstants.AUTH_KEY_TOKEN, dynamicToken);
break;
}
case AUTH_TYPE_RENEW_PASSWORD: {
EditText etNewPwd = dialogView.findViewById(R.id.et_newpwd);
EditText etOldPwd = dialogView.findViewById(R.id.et_oldpwd);
EditText etReNewPwd = dialogView.findViewById(R.id.et_renewpwd);
String oldPwd = etOldPwd.getText().toString();
String newPwd = etNewPwd.getText().toString();
String reNewPwd = etReNewPwd.getText().toString();
if (TextUtils.isEmpty(newPwd) || TextUtils.isEmpty(reNewPwd)) {
errorMsg = "新密码不能为空";
break;
}
if (!newPwd.equals(reNewPwd)) {
errorMsg = "新密码与确认密码不一致";
break;
}
authParams.put(SFConstants.AUTH_KEY_RENEW_OLD_PASSWORD, oldPwd);
authParams.put(SFConstants.AUTH_KEY_REWNEW_NEW_PASSWORD, newPwd);
break;
}
default:
errorMsg = "暂不支持的认证类型";
break;
}
return errorMsg;
}
/**
*
*/
private void closeDialog() {
// if (mAuthDialog != null && mAuthDialog.isShowing()) {
// mAuthDialog.dismiss();
// mAuthDialog = null;
// }
}
/**
* @param success true: , false:
* @param bytes successtrue
* @param byteLength successtrue
* @brief SFRegetRandCodeListener
*/
@Override
public void onRegetRandCode(boolean success, byte[] bytes, int byteLength) {
Drawable randCode = null;
if (success) {
randCode = Drawable.createFromStream(new ByteArrayInputStream(bytes), "rand_code");
} else {
SFLogN.error2(TAG, "get RandCode failed", "maybe network is wrong");
}
final Drawable drawable = randCode;
//显示图形校验码
runOnUiThread(new Runnable() {
@Override
public void run() {
if (mRandCodeDialogView == null) {
showToast("图形校验码对话框视图未加载");
return;
}
final ImageView imgError = mRandCodeDialogView.findViewById(R.id.randcode_imgError);
final ImageView imgRandCode = mRandCodeDialogView.findViewById(R.id.iv_graphCode);
imgError.setVisibility(drawable == null ? View.VISIBLE : View.GONE);
imgRandCode.setVisibility(drawable == null ? View.GONE : View.VISIBLE);
// 显示图形校验码
imgRandCode.setImageDrawable(drawable);
// 更新刷新时间
imgRandCode.setTag(System.currentTimeMillis());
}
});
}
/**
*
*
* @param success truefalse
* @param message
*/
@Override
public void onRegetSmsCode(final boolean success, final SFSmsMessage message) {
SFLogN.info(TAG, "onRegetSmsCode result: " + success + ", msg: " + message.mErrStr);
//更新短信验证码信息
runOnUiThread(new Runnable() {
@Override
public void run() {
if (mSmsCodeDialogView == null) {
showToast("短信验证码对话框视图未加载");
return;
}
final Button btnGetVerficationCode = mSmsCodeDialogView.findViewById(R.id.bt_getVerficationCode);
if (success) {
//更新倒计时
smsCountDownTimer(btnGetVerficationCode, message.getCountDown());
showToast(getString(R.string.reget_sms_code_success));
} else {
btnGetVerficationCode.setEnabled(true);
showToast(getString(R.string.reget_sms_code_failed) + message.mErrStr);
}
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
//登录界面证书选择
case CERTFILE_REQUEST_CODE: {
//获取证书选择器结果
String certPath = "";
if (resultCode == Activity.RESULT_OK) {
certPath = CertUtils.fromUriGetRealPath(this, data.getData()).trim();
}
break;
}
case DIALOG_CERTFILE_REQUEST_CODE: {
//当证书认证是辅助认证时获取证书选择器结果
String certPathDialog = "";
if (resultCode == Activity.RESULT_OK) {
certPathDialog = CertUtils.fromUriGetRealPath(this, data.getData()).trim();
}
mCertPathDialogEditView.setText(certPathDialog);
break;
}
}
super.onActivityResult(requestCode, resultCode, data);
}
//显示“请稍候...”提示框
public void showWaitingDialog(final boolean isCancelable) {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (mProgressDialog == null || !mProgressDialog.isShowing()) {
mProgressDialog = new ProgressDialog(PrimarySmsLoginActivity.this);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
mProgressDialog.setTitle("");
mProgressDialog.setMessage(PrimarySmsLoginActivity.this.getString(R.string.waiting));
mProgressDialog.setCancelable(isCancelable);
mProgressDialog.show();
}
}
});
}
//取消“请稍候...”提示框
public void dismissWaitingDialog() {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (mProgressDialog != null && mProgressDialog.isShowing()) {
mProgressDialog.dismiss();
mProgressDialog = null;
}
}
});
}
//显示错误提示对话框
public void showErrorMessage(final String errMsg) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Dialog messageDialog = new AlertDialog.Builder(PrimarySmsLoginActivity.this)
.setTitle(PrimarySmsLoginActivity.this.getString(R.string.info))
.setMessage(errMsg)
.setIcon(android.R.drawable.ic_dialog_alert)
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
})
.create();
messageDialog.show();
}
});
}
//封装Toast
public void showToast(final String text) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(PrimarySmsLoginActivity.this, text, Toast.LENGTH_SHORT).show();
}
});
}
/**
*
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] paramArrayOfInt) {
super.onRequestPermissionsResult(requestCode, permissions, paramArrayOfInt);
if (requestCode == PERMISSON_REQUEST_CODE) {
//处理权限申请结果
// do nothing
}
}
/**
*
*/
private void setLoginInfo() {
SharedPreferences sharedPreferences = getSharedPreferences(Constants.PREF_FILE_NAME, MODE_PRIVATE);
mVpnAddress = sharedPreferences.getString(Constants.KEY_VPN_ADDRESS, mVpnAddress);
mPhoneNumber = sharedPreferences.getString(Constants.KEY_PHONE_NUMBER, mPhoneNumber);
mVpnAddressEditText.setText(mVpnAddress);
mPhoneNumberEditView.setText(mPhoneNumber);
}
/**
*
*/
private void saveLoginInfo() {
SharedPreferences sharedPreferences = getSharedPreferences(Constants.PREF_FILE_NAME, MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(Constants.KEY_VPN_ADDRESS, mVpnAddress);
//保存手机号码,真实场景请加密存储
editor.putString(Constants.KEY_PHONE_NUMBER, mPhoneNumber);
editor.apply();
}
}

@ -57,7 +57,7 @@ class TrainInfoMoreActivity : BaseActivityOaToolbarViewBinding<ActivityTrainInfo
private val filedataBeans: MutableList<PxinfomoreBean.ResultsBean.FilesBean> = mutableListOf()
private val dialogDatas: MutableList<String> = mutableListOf()
private lateinit var launcherResult: ActivityResultLauncher<Intent>
private var launcherResult: ActivityResultLauncher<Intent>? = null
override fun getViewBinding() = ActivityTrainInfoMoreBinding.inflate(layoutInflater)
@ -166,7 +166,7 @@ class TrainInfoMoreActivity : BaseActivityOaToolbarViewBinding<ActivityTrainInfo
intent.putExtra("Skrrid", Skrrid)
intent.putExtra("ysssc", ysssc)
intent.putExtra("ysssc_s", ysssc_s)
launcherResult.launch(intent)
launcherResult?.launch(intent)
})
}
@ -198,7 +198,7 @@ class TrainInfoMoreActivity : BaseActivityOaToolbarViewBinding<ActivityTrainInfo
intent.putExtra("Skrrid", Skrrid)
intent.putExtra("ysssc", ysssc)
intent.putExtra("ysssc_s", ysssc_s)
launcherResult.launch(intent)
launcherResult?.launch(intent)
}
} else if (filedataBeans[position].filetype == ".pdf" || filedataBeans[position].filetype == ".doc" || filedataBeans[position].filetype == ".docx" || filedataBeans[position].filetype == ".xls" || filedataBeans[position].filetype == ".xlsx" || filedataBeans[position].filetype == ".ppt" || filedataBeans[position].filetype == ".pptx") {
docName = FileUtils.getFileNameByPath(filedataBeans[position].filepath)
@ -237,7 +237,7 @@ class TrainInfoMoreActivity : BaseActivityOaToolbarViewBinding<ActivityTrainInfo
intent.putExtra("ysssc", ysssc)
intent.putExtra("ysssc_s", ysssc_s)
intent.putExtra("party", false)
launcherResult.launch(intent)
launcherResult?.launch(intent)
Log.i("app", URL + filedataBeans[position].filepath)
// val intent = Intent(
@ -285,7 +285,7 @@ class TrainInfoMoreActivity : BaseActivityOaToolbarViewBinding<ActivityTrainInfo
intent.putExtra("ysssc", ysssc)
intent.putExtra("ysssc_s", ysssc_s)
intent.putExtra("party", false)
launcherResult.launch(intent)
launcherResult?.launch(intent)
// val intent = Intent(
// this, NetOfficeViewActivity::class.java

@ -0,0 +1,659 @@
package com.rehome.zhdcoa.ui.activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.rehome.zhdcoa.R;
import com.rehome.zhdcoa.base.BaseActivity;
import com.sangfor.sdk.SFUemSDK;
import com.sangfor.sdk.base.SFAuthResultListener;
import com.sangfor.sdk.base.SFAuthType;
import com.sangfor.sdk.base.SFBaseMessage;
import com.sangfor.sdk.base.SFChangePswMessage;
import com.sangfor.sdk.base.SFConstants;
import com.sangfor.sdk.base.SFSetSpaConfigListener;
import com.sangfor.sdk.base.SFSmsMessage;
import com.sangfor.sdk.base.SFTunnelStatus;
import com.sangfor.sdk.base.SFTunnelStatusListener;
import com.sangfor.sdk.utils.SFLogN;
import com.rehome.zhdcoa.vpn.Constants;
//import com.rehome.zhdcoa.ui.activity.vpn.AuthSuccessActivity;
import com.rehome.zhdcoa.vpn.SFDialogHelper;
import java.util.HashMap;
import java.util.Map;
public class VpnAuthActivity extends BaseActivity implements SFAuthResultListener, View.OnClickListener, SFTunnelStatusListener {
private static final String TAG = "app";
// private String mServerAddress = "https://10.242.4.236"; //服务器地址
// private String mUserName = "xxb"; //用户名
// private String mUserPassword = "test@1234"; //密码
//服务器地址
//private String mServerAddress = "https://vpn.dywzhny.com.cn:8443";
private String mServerAddress = "https://vpn.zhp.geg.com.cn:55420";
//用户名
private String mUserName = "rehome5";
//密码
private String mUserPassword = "452131wW,./";
private EditText mServerAddressEditText = null;
private EditText mUserNameEditView = null;
private EditText mUserPasswordEditView = null;
private Button mLoginButton = null;
private AlertDialog mAuthDialog = null;
private ProgressDialog mProgressDialog = null; // 进度条对话框
// @Override
// public int getContentViewID() {
// return R.layout.activity_primary_auth;<include layout="@layout/layout_base"/>
// }
@Override
public int getLayoutId() {
return R.layout.activity_vpn_auth;
}
private void startAutoTicket() {
/**
* true访
* false,
*/
if (SFUemSDK.getInstance().startAutoTicket()){
showToast("vpn免密登录认证成功");
//startActivity(new Intent(PrimaryAuthActivity.this, AuthSuccessActivity.class));
/**
* L3VPNonTunnelStarted访
*/
SFUemSDK.getInstance().getSFTunnel().startTunnel();
Intent intent = new Intent();
intent.putExtra("usernameVpn", mUserName);
intent.putExtra("pwdVpn", mUserPassword);
setResult(RESULT_OK, intent);
finish();
}
}
@Override
protected void onResume() {
Log.i(TAG,"onResume... ");
super.onResume();
}
@Override
protected void onNewIntent(Intent intent) {
Log.i(TAG, "onNewIntent...");
super.onNewIntent(intent);
}
// 初始化界面元素
@Override
public void initView() {
mServerAddressEditText = findViewById(R.id.vpn_addr_editView);
mUserNameEditView = findViewById(R.id.svpn_username_editView);
mUserPasswordEditView = findViewById(R.id.svpn_userPassword_editView);
//登录按钮
mLoginButton = findViewById(R.id.svpn_login_button);
mLoginButton.setOnClickListener(this);
initToolbar("VPN登录", "", new View.OnClickListener() {
@Override
public void onClick(View v) {
}
});
//SPA初始化设置安全码
String config = "{\"loginAddress\":\"https://vpn.zhp.geg.com.cn:55420\", \"spaSecret\":\"7FFQ-rWE5-V6xX\"}";
SFUemSDK.setSpaConfig(config, new SFSetSpaConfigListener() {
@Override
public void onSetSpaConfig(String result, SFBaseMessage error) {
SFLogN.info(TAG, "spa result:"+ result + ", error:" + error);
Log.i(TAG, "spa result:"+ result + ", error:" + error);
if (error.mErrCode != 0) {
Toast.makeText(VpnAuthActivity.this,
"SPA设置失败"+ ", Error Message:" + error.toString(),
Toast.LENGTH_SHORT)
.show();
} else {
Toast.makeText(VpnAuthActivity.this, "SPA设置成功 result:" + result,
Toast.LENGTH_SHORT)
.show();
}
}
});
//加载上次登录信息
setLoginInfo();
mUserNameEditView.setText("rehome5");
mUserPasswordEditView.setText("452131wW,./");
/**
* ,SFAuthResultListeneronAuthSuccessonAuthFailedonAuthProgress
*
*/
SFUemSDK.getInstance().setAuthResultListener(this);
/**
* SFTunnelStatusListeneronTunnelStarted
* onTunnelStopedonTunnelStatusChanged
*/
SFUemSDK.getInstance().getSFTunnel().registerTunnelStatusListener(this);
//免密认证
startAutoTicket();
}
@Override
public void initData() {
}
@Override
protected void onPause() {
super.onPause();
//只有走回收流程的时候的那种onPauseisFinishing才为true
if (isFinishing()) {
//取消认证回调
SFLogN.info(TAG,"SFUemSDK setAuthResultListener null");
/**
* onPause()onDestroy()
* onDestroy()onCreate()onCreateonDestory
*/
SFUemSDK.getInstance().setAuthResultListener(null);
SFUemSDK.getInstance().getSFTunnel().unRegisterTunnelStatusListener(this);
}
}
@Override
public void onClick(View v) {
if(v.getId()==R.id.svpn_login_button){
mServerAddress = mServerAddressEditText.getText().toString();
mUserName = mUserNameEditView.getText().toString();
mUserPassword = mUserPasswordEditView.getText().toString();
//开始主认证
startPrimaryAuth();
}
// switch (v.getId()) {
// case R.id.svpn_login_button: {
// mServerAddress = mServerAddressEditText.getText().toString();
// mUserName = mUserNameEditView.getText().toString();
// mUserPassword = mUserPasswordEditView.getText().toString();
//
// //开始主认证
// startPrimaryAuth();
// break;
// }
// default:
// break;
// }
}
//开始用户名密码认证
private void startPrimaryAuth() {
if (TextUtils.isEmpty(mServerAddress)) {
showToast("VPN服务器地址不能为空");
return;
}
if (TextUtils.isEmpty(mUserName)) {
showToast("vpn帐号必填");
return;
}
if (TextUtils.isEmpty(mUserName)) {
showToast("vpn密码必填");
return;
}
showWaitingDialog(false);
/**
* onAuthSuccess,onAuthFailed,onAuthProgress
*/
SFUemSDK.getInstance().startPasswordAuth(mServerAddress, mUserName, mUserPassword);
}
/**
*
*
* @param message
*/
@Override
public void onAuthSuccess(final SFBaseMessage message) {
showLog("auth success");
//关闭进度框
dismissWaitingDialog();
saveLoginInfo(); //保存登录信息
/**
* L3VPNonTunnelStarted访
*/
SFUemSDK.getInstance().getSFTunnel().startTunnel();
showLog(String.valueOf(SFUemSDK.getInstance().getAuthStatus()));
//认证完成,跳转认证成功界面,可以开始访问资源
runOnUiThread(new Runnable() {
@Override
public void run() {
showToast(getString(R.string.auth_success));
//startActivity(new Intent(PrimaryAuthActivity.this, AuthSuccessActivity.class));
Intent intent = new Intent();
intent.putExtra("usernameVpn", mUserName);
intent.putExtra("pwdVpn", mUserPassword);
setResult(RESULT_OK, intent);
finish();
}
});
}
/**
*
*
* @param message
*/
@Override
public void onAuthFailed(final SFBaseMessage message) {
SFLogN.error2(TAG, "auth failed", "errMsg: " + message.mErrStr);
//关闭进度框
dismissWaitingDialog();
//认证失败
runOnUiThread(new Runnable() {
@Override
public void run() {
showErrorMessage(message.mErrStr);
}
});
}
/**
*
*
* @param nextAuthType
* @param message
*/
@Override
public void onAuthProgress(SFAuthType nextAuthType, SFBaseMessage message) {
SFLogN.info(TAG, "need next auth, authType: " + nextAuthType.name());
dismissWaitingDialog();
/**
* 1. onAuthProgress, ;
* "首次登录强制修改密码", onAuthProgress;
* , , onAuthProgress.
*
* 2. , :
* , ,
* , .
*/
if (nextAuthType == SFAuthType.AUTH_TYPE_RENEW_PASSWORD) {
//显示下一步认证UI界面
showAuthDialog(nextAuthType, message);
return;
}
if (nextAuthType == SFAuthType.AUTH_TYPE_SMS) {
//显示下一步认证UI界面
showAuthDialog(nextAuthType, message);
return;
}
showErrorMessage("暂不支持此种认证类型(" + nextAuthType.toString() + ")");
}
//显示“请稍候...”提示框
public void showWaitingDialog(final boolean isCancelable) {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (mProgressDialog == null || !mProgressDialog.isShowing()) {
mProgressDialog = new ProgressDialog(VpnAuthActivity.this);
mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
mProgressDialog.setTitle("");
mProgressDialog.setMessage(VpnAuthActivity.this.getString(R.string.waiting));
mProgressDialog.setCancelable(isCancelable);
mProgressDialog.show();
}
}
});
}
//取消“请稍候...”提示框
public void dismissWaitingDialog() {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (mProgressDialog != null && mProgressDialog.isShowing()) {
mProgressDialog.dismiss();
mProgressDialog = null;
}
}
});
}
//显示错误提示对话框
public void showErrorMessage(final String errMsg) {
runOnUiThread(new Runnable() {
@Override
public void run() {
AlertDialog messageDialog = new AlertDialog.Builder(VpnAuthActivity.this)
.setTitle(VpnAuthActivity.this.getString(R.string.info))
.setMessage(errMsg)
.setIcon(android.R.drawable.ic_dialog_alert)
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
})
.create();
messageDialog.show();
//确定按钮
Button btnPos = messageDialog.getButton(DialogInterface.BUTTON_POSITIVE);
//取消按钮
Button btnNeg = messageDialog.getButton(DialogInterface.BUTTON_NEGATIVE);
btnPos.setTextColor(Color.BLACK);
btnNeg.setTextColor(Color.BLACK);
}
});
}
//封装Toast
public void showToast(final String text) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(VpnAuthActivity.this, text, Toast.LENGTH_SHORT).show();
}
});
}
//恢复登录信息,重启应用后记录原来的登陆信息
private void setLoginInfo() {
// SharedPreferences sharedPreferences = getSharedPreferences(Constants.PREF_FILE_NAME, MODE_PRIVATE);
// mServerAddress = sharedPreferences.getString(Constants.KEY_VPN_ADDRESS, mServerAddress);
// mUserName = sharedPreferences.getString(Constants.KEY_USER_NAME, mUserName);
// mUserPassword = sharedPreferences.getString(Constants.KEY_USER_PASSWORD, mUserPassword);
Intent intent = getIntent();
mUserName = intent.getStringExtra("usernameVpn");
mUserPassword = intent.getStringExtra("pwdVpn");
mServerAddressEditText.setText(mServerAddress);
if(TextUtils.isEmpty(mUserName)){
mUserNameEditView.setText("");
}else{
mUserNameEditView.setText(mUserName);
}
if(TextUtils.isEmpty(mUserPassword)){
mUserPasswordEditView.setText("");
}else{
mUserPasswordEditView.setText(mUserPassword);
}
}
//更新保存的登录信息
private void saveLoginInfo() {
SharedPreferences sharedPreferences = getSharedPreferences(Constants.PREF_FILE_NAME, MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(Constants.KEY_VPN_ADDRESS, mServerAddress);
//保存用户名和密码,真实场景请加密存储
editor.putString(Constants.KEY_USER_NAME, mUserName);
editor.putString(Constants.KEY_USER_PASSWORD, mUserPassword);
editor.apply();
}
/**
* UI
*/
private void showAuthDialog(final SFAuthType authType, final SFBaseMessage message) {
runOnUiThread(new Runnable() {
@Override
public void run() {
closeDialog();
//获取认证类型对应的标题
String dialogTitle = SFDialogHelper.getDialogTitle(authType);
if (TextUtils.isEmpty(dialogTitle)) {
showErrorMessage("暂不支持此种认证类型(" + authType.toString() + ")");
return;
}
//获取认证类型对应的layout布局
int viewLayoutId = SFDialogHelper.getAuthDialogViewId(authType);
handlerSecondAuth(dialogTitle, viewLayoutId, authType, message);
}
});
}
/**
*
*/
private void closeDialog() {
if (mAuthDialog != null && mAuthDialog.isShowing()) {
mAuthDialog.dismiss();
mAuthDialog = null;
}
}
/**
*
* @param dialogTitle
* @param viewLayoutId
* @param authType
* @param message
*/
private void handlerSecondAuth(String dialogTitle, int viewLayoutId, SFAuthType authType, SFBaseMessage message) {
//创建认证类型对应的对话框显示视图
final View dialogView = createDialogView(authType, viewLayoutId, message);
mAuthDialog = new AlertDialog.Builder(VpnAuthActivity.this)
.setTitle(dialogTitle)
.setView(dialogView)
.setCancelable(false)
.setPositiveButton(R.string.str_commit, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
closeDialog();
//构建辅助认证类型所需参数
Map<String, String> authParams = new HashMap<String, String>();
String errorMsg = buildAuthParams(authType, dialogView, authParams);
//检查参数构建是否成功
if (TextUtils.isEmpty(errorMsg)) {
showWaitingDialog(false);
//开始辅助认证
SFUemSDK.getInstance().doSecondaryAuth(authType, authParams);
} else {
//参数构建失败,进行提示
showErrorMessage(errorMsg);
}
return;
}
})
.setNegativeButton(R.string.str_cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//放弃继续认证
closeDialog();
return;
}
})
.create();
//显示认证对话框
mAuthDialog.show();
//确定按钮
Button btnPos = mAuthDialog.getButton(DialogInterface.BUTTON_POSITIVE);
//取消按钮
Button btnNeg = mAuthDialog.getButton(DialogInterface.BUTTON_NEGATIVE);
btnPos.setTextColor(Color.BLACK);
btnNeg.setTextColor(Color.BLACK);
}
/**
*
*
* @param sfAuthType
* @param layoutId ID
* @param message
* @return
*/
private View createDialogView(SFAuthType sfAuthType, int layoutId, final SFBaseMessage message) {
LayoutInflater inflater = getLayoutInflater();
View dialogView = inflater.inflate(layoutId, null);
switch (sfAuthType) {
case AUTH_TYPE_RENEW_PASSWORD: {
TextView tvPolicy = (TextView) dialogView.findViewById(R.id.tv_policy);
String policy = "";
//获取密码策略
if (message instanceof SFChangePswMessage) {
policy = ((SFChangePswMessage) message).policyMsg;
}
if (TextUtils.isEmpty(policy)) {
tvPolicy.setText(R.string.str_no_policy);
} else {
tvPolicy.setText(getString(R.string.str_policy_hint) + "\n" + policy);
}
break;
}
default:
break;
}
return dialogView;
}
/**
*
*
* @param sfAuthType
* @param dialogView
* @param authParams
* @return
*/
private String buildAuthParams(SFAuthType sfAuthType, View dialogView, Map<String, String> authParams) {
String errorMsg = "";
switch (sfAuthType) {
case AUTH_TYPE_RENEW_PASSWORD: {
EditText etNewPwd = dialogView.findViewById(R.id.et_newpwd);
EditText etOldPwd = dialogView.findViewById(R.id.et_oldpwd);
EditText etReNewPwd = dialogView.findViewById(R.id.et_renewpwd);
String oldPwd = etOldPwd.getText().toString();
String newPwd = etNewPwd.getText().toString();
String reNewPwd = etReNewPwd.getText().toString();
if (TextUtils.isEmpty(newPwd) || TextUtils.isEmpty(reNewPwd)) {
errorMsg = "新密码不能为空";
break;
}
if (!newPwd.equals(reNewPwd)) {
errorMsg = "新密码与确认密码不一致";
break;
}
authParams.put(SFConstants.AUTH_KEY_RENEW_OLD_PASSWORD, oldPwd);
authParams.put(SFConstants.AUTH_KEY_REWNEW_NEW_PASSWORD, newPwd);
break;
}
case AUTH_TYPE_SMS: {
EditText etSmsCode = dialogView.findViewById(R.id.et_verficationCode);
String smsCode = etSmsCode.getText().toString().trim();
if (TextUtils.isEmpty(smsCode)) {
errorMsg = "短信验证码不能为空";
break;
}
showLog("-------smsCode---------");
showLog(smsCode);
authParams.put(SFConstants.AUTH_KEY_SMS, smsCode);
break;
}
default:
errorMsg = "暂不支持的认证类型";
break;
}
return errorMsg;
}
/**
*
* @param curStatus
*/
@Override
public void onTunnelStatusChanged(SFTunnelStatus curStatus) {
showLog("onTunnelStatusChanged called: curStatus: " + curStatus);
}
/**
* msg
* @param msg
*/
@Override
public void onTunnelStarted(SFBaseMessage msg) {
//隧道启动完成,跳转认证成功界面,可以开始访问资源
showLog( "onTunnelStarted, msg: " + msg.mErrStr + ",errCode: " + msg.mErrCode);
if (msg.mErrCode != 0) {
showLog("start Tunnel failed" + msg.mErrStr);
showLog( "L3VPN隧道启动失败 " + msg.mErrStr);
showToast(msg.mErrStr);
showToast("L3VPN隧道启动失败 " + msg.mErrStr);
return;
}
showLog( "startTunnel finished");
showLog( "L3VPN隧道启动成功");
showToast("L3VPN隧道启动成功");
}
/**
*
*/
@Override
public void onTunnelStoped() {
showLog( "onTunnelStoped");
showLog( "隧道已经关闭");
showToast("隧道已经关闭");
}
}

@ -91,6 +91,7 @@ import retrofit2.Call
import retrofit2.Response
import java.text.SimpleDateFormat
import java.util.Calendar
import androidx.core.view.isVisible
/**
@ -146,7 +147,10 @@ class HomeFragment : BaseViewBindingFragment<FragmentHomeBinding>() {
Handler(Looper.getMainLooper()).postDelayed({ // 在指定时间后要执行的代码
//隐藏掉 本平台为非涉密平台,严禁处理、传输国家秘密、工作秘密、商业秘密、敏感信息
//showLog("隐藏掉 本平台为非涉密平台,严禁处理、传输国家秘密、工作秘密、商业秘密、敏感信息")
binding.llTip.visibility=View.GONE;
if(binding!=null){
binding.llTip.visibility=View.GONE;
}
}, 5000)
}
}
@ -170,13 +174,15 @@ class HomeFragment : BaseViewBindingFragment<FragmentHomeBinding>() {
override fun onResume() {
super.onResume()
showLog("onResume")
if (this.isAdded && this.isVisible&&binding.llTip.visibility==View.VISIBLE) {
if (this.isAdded && this.isVisible) {
showLog("this.isAdded && this.isVisible&&binding.llTip.visibility==View.VISIBLE")
// Fragment存在且可见可以安全访问
Handler(Looper.getMainLooper()).postDelayed({ // 在指定时间后要执行的代码
//隐藏掉 本平台为非涉密平台,严禁处理、传输国家秘密、工作秘密、商业秘密、敏感信息
//showLog("隐藏掉 本平台为非涉密平台,严禁处理、传输国家秘密、工作秘密、商业秘密、敏感信息")
binding.llTip.visibility=View.GONE;
if(binding!=null&&binding.llTip.isVisible){
binding.llTip.visibility=View.GONE
}
}, 5000)
}
}

@ -0,0 +1,47 @@
package com.rehome.zhdcoa.utils;
/**
* @ProjectName: SDKDemo
* @Package: com.sangfor.sdkdemo.utils
* @ClassName: DpPxSpTransformUtil
* @Description: java
* @Author: yanghua
* @CreateDate: 2022/9/21 6:11
*/
public class DpPxSpTransformUtil {
private static float scale;
/**
*
* @return
*/
public static void init(float scale){
DpPxSpTransformUtil.scale=scale;
}
/**
* dp px()
*/
public static int dip2px(float dpValue) {
return (int)(dpValue * scale + 0.5f);
}
/**
* px() dp
*/
public static int px2dip(float pxValue) {
return (int)(pxValue / scale + 0.5f);
}
/**
* pxsp
* @return
*/
public static int px2sp(float pxValue) {
return (int) (pxValue / scale + 0.5f);
}
/**
* sppx
* @return
*/
public static int sp2px(float spValue) {
return (int) (spValue * scale + 0.5f);
}
}

@ -0,0 +1,67 @@
package com.rehome.zhdcoa.vpn;
import android.app.Activity;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.text.TextUtils;
import android.util.Log;
/**
* app
*/
public class AppInfoUtils {
private static String TAG = "AppInfoUtils";
/**
*
*
* @param activity
* @return
*/
public static String getApplicationName(Activity activity) {
PackageManager packageManager;
ApplicationInfo applicationInfo;
try {
packageManager = activity.getApplicationContext().getPackageManager();
applicationInfo = packageManager.getApplicationInfo(activity.getPackageName(), 0);
} catch (PackageManager.NameNotFoundException e) {
Log.i(TAG,"PackageManager.NameNotFoundException");
return "";
}
String applicationName = (String) packageManager.getApplicationLabel(applicationInfo);
if (TextUtils.isEmpty(applicationName)) {
Log.i(TAG,"applicationName is Empty");
return "";
} else {
return applicationName;
}
}
/**
*
*
* @param activity
* @return
*/
public static String getApplicationName(Activity activity, String packAgeName) {
PackageManager packageManager;
ApplicationInfo applicationInfo;
try {
packageManager = activity.getApplicationContext().getPackageManager();
applicationInfo = packageManager.getApplicationInfo(packAgeName, 0);
} catch (PackageManager.NameNotFoundException e) {
Log.i(TAG,"PackageManager.NameNotFoundException");
return "";
}
String applicationName = (String) packageManager.getApplicationLabel(applicationInfo);
if (TextUtils.isEmpty(applicationName)) {
Log.i(TAG,"applicationName is Empty");
return "";
} else {
return applicationName;
}
}
}

@ -0,0 +1,47 @@
package com.rehome.zhdcoa.vpn;
import android.content.Context;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class AssetFileUtil {
/**
* assert
* @param context
* @param fileName
* @return
*/
public static String getAssertFileContent(Context context, String fileName){
StringBuffer stringBuffer = new StringBuffer();
InputStream inputStream = null;
try {
inputStream = context.getAssets().open(fileName);
InputStreamReader inputreader = new InputStreamReader(inputStream);
BufferedReader buffreader = new BufferedReader(inputreader);
String line;
// 分行读取
while ((line = buffreader.readLine()) != null) {
stringBuffer.append(line);
}
buffreader.close();
inputreader.close();
} catch (IOException e) {
e.printStackTrace();
}
if(inputStream != null){
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return stringBuffer.toString();
}
}

@ -0,0 +1,89 @@
package com.rehome.zhdcoa.vpn;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import com.rehome.zhdcoa.R;
import com.sangfor.sdk.entry.SFLaunchInfo;
/**
*
*/
public class AuthSessionDialog {
private Activity mActivity;
private DialogClickListener mClickListener;
private AlertDialog mDialog;
private SFLaunchInfo mSFLaunchInfo;
public void setClickListener(DialogClickListener clickListener) {
mClickListener = clickListener;
}
public AuthSessionDialog(Activity activity, SFLaunchInfo launchInfo) {
mActivity = activity;
mSFLaunchInfo = launchInfo;
}
public void show() {
if (mDialog == null) {
String hostAppName = AppInfoUtils.getApplicationName(mActivity);
String subAppName = AppInfoUtils.getApplicationName(mActivity, mSFLaunchInfo.getPackageName());
String dialogMessage = String.format(mActivity.getString(R.string.request_session_can_you_agree), subAppName, hostAppName);
mDialog = new AlertDialog.Builder(mActivity)
.setMessage(dialogMessage)
.setCancelable(false)
.setPositiveButton(mActivity.getString(R.string.agree), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dismiss();
if (mClickListener != null) {
mClickListener.onPositiveClick(mSFLaunchInfo);
}
}
})
.setNegativeButton(mActivity.getString(R.string.disagree), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dismiss();
if (mClickListener != null) {
mClickListener.onNegativeClick(mSFLaunchInfo);
}
}
})
.create();
}
mDialog.show();
}
public void dismiss() {
if (mDialog != null && mDialog.isShowing()) {
mDialog.dismiss();
}
}
public boolean isShowing() {
if (mDialog != null) {
return mDialog.isShowing();
}
return false;
}
public SFLaunchInfo getSFLaunchInfo() {
return mSFLaunchInfo;
}
public interface DialogClickListener {
void onPositiveClick(SFLaunchInfo launchInfo);
void onNegativeClick(SFLaunchInfo launchInfo);
}
}

@ -0,0 +1,212 @@
package com.rehome.zhdcoa.vpn;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.FileUtils;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.provider.OpenableColumns;
import androidx.annotation.RequiresApi;
import com.sangfor.sdk.utils.SFLogN;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* Created by sangfor on 17-9-28.
*/
public class CertUtils {
private static final String TAG = "CertUtils";
/**
* UriScheme
* @param context
* @param uri
* @return Uri
*/
@TargetApi(19)
public static String fromUriGetRealPath(Context context, Uri uri) {
if (uri == null) {
return "";
}
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider
if (isKitKat && Build.VERSION.SDK_INT < Build.VERSION_CODES.Q && DocumentsContract.isDocumentUri(context, uri) ) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/" + split[1];
}
// TODO handle non-primary volumes
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
final Uri contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
}
// MediaProvider
else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[]{split[1]};
return getDataColumn(context, contentUri, selection, selectionArgs);
}
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
return uriToFileApiQ(context, uri);
}
// MediaStore (and general)
else if ("content".equalsIgnoreCase(uri.getScheme())) {
// Return the remote address
if (isGooglePhotosUri(uri))
return uri.getLastPathSegment();
SFLogN.info(TAG, "uri authority is "+uri.getAuthority());
if (isHuaWeiUri(uri)) {
String uriPath = uri.getPath();
// content://com.huawei.filemanager.share.fileprovider/root/storage/emulated/0/hbz1.p12
if (uriPath != null && uriPath.startsWith("/root")) {
return uriPath.replaceAll("/root", "");
}
}
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return "";
}
/**
* Android 10
* @param context
* @param uri
* @return
*/
@RequiresApi(api = Build.VERSION_CODES.Q)
private static String uriToFileApiQ(Context context, Uri uri) {
File file = null;
//android10以上转换
if (uri.getScheme().equals(ContentResolver.SCHEME_FILE)) {
file = new File(uri.getPath());
} else if (uri.getScheme().equals(ContentResolver.SCHEME_CONTENT)) {
//把文件复制到沙盒目录
ContentResolver contentResolver = context.getContentResolver();
Cursor cursor = contentResolver.query(uri, null, null, null, null);
if (cursor.moveToFirst()) {
@SuppressLint("Range")
String displayName = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
try {
InputStream is = contentResolver.openInputStream(uri);
File file1 = new File(context.getExternalCacheDir().getAbsolutePath()+"/"+System.currentTimeMillis());
if (!file1.exists())
{
file1.mkdir();
}
File cache = new File(file1.getPath(), displayName);
FileOutputStream fos = new FileOutputStream(cache);
FileUtils.copy(is, fos);
file = cache;
fos.close();
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return file.getAbsolutePath();
}
public static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = {column};
try {
cursor = context.getContentResolver().query(uri, null, selection, selectionArgs, null);
if (cursor != null && cursor.moveToFirst()) {
final int index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(index);
}
} finally {
if (cursor != null)
cursor.close();
}
return "";
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
*/
public static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
*/
public static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is MediaProvider.
*/
public static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is Google Photos.
*/
public static boolean isGooglePhotosUri(Uri uri) {
return "com.google.android.apps.photos.content".equals(uri.getAuthority());
}
/**
*
* @param uri
* @return
*/
public static boolean isHuaWeiUri(Uri uri) {
return "com.huawei.filemanager.share.fileprovider".equals(uri.getAuthority());
}
}

@ -0,0 +1,12 @@
package com.rehome.zhdcoa.vpn;
public class Constants {
public final static String PREF_FILE_NAME = "loginConfig";
public final static String KEY_VPN_ADDRESS = "vpnAddress";
public final static String KEY_USER_NAME = "userName";
public final static String KEY_USER_PASSWORD = "userPassword";
public final static String KEY_CERT_PATH = "certPath";
public final static String KEY_CERT_PASSWORD = "certPassword";
public final static String KEY_PHONE_NUMBER = "phoneNumber";
public final static String KEY_SUB_APP_PKG_NAME = "subAppPkgName";
}

@ -0,0 +1,140 @@
package com.rehome.zhdcoa.vpn;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
import com.sangfor.sdk.SFUemSDK;
import com.sangfor.sdk.base.SFAuthStatus;
import com.sangfor.sdk.base.SFBaseMessage;
import com.sangfor.sdk.base.SFLaunchReason;
import com.sangfor.sdk.base.SFLogoutListener;
import com.sangfor.sdk.base.SFLogoutType;
import com.sangfor.sdk.entry.SFLaunchEntry;
import com.sangfor.sdk.entry.SFLaunchInfo;
import com.sangfor.sdk.utils.SFLogN;
public class GlobalListenerManager {
private static final String TAG = "GlobalListenerManager";
private Context mAppContext;
private AuthSessionDialog mAuthSessionDialog = null;
public static GlobalListenerManager getInstance() {
return SingletonHolder.INSTANCE;
}
public void init(Context context) {
mAppContext = context.getApplicationContext() == null ? context : context.getApplicationContext();
addSFListener();
}
/**
* sdk
*/
private void addSFListener() {
/**
* Application,
*/
SFUemSDK.getInstance().registerLogoutListener(new SFLogoutListener() {
@Override
public void onLogout(SFLogoutType type, SFBaseMessage message) {
SFLogN.info(TAG, "onLogout, message: " + message);
/**
* demo
*/
// Intent intent = new Intent(mAppContext, EntryActivity.class);
// intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// mAppContext.startActivity(intent);
}
});
/**
*
* 使Application
*/
SFUemSDK.getInstance().getSFLaunch().setAppLaunchListener(new SFLaunchEntry.SFAppLaunchListener() {
@Override
public void onAppLaunched(SFLaunchInfo launchInfo) {
SFLogN.info(TAG, "setAppLaunchListener onAppLaunched, launchInfo is :" + launchInfo);
if (!SFLaunchEntry.isSubApp()) {
/**
*
*/
if (launchInfo.getLaunchReason() == SFLaunchReason.Launch_HOSTAPP_AUTH_AUTHORIZATION) {
/**
*
*/
if (SFUemSDK.getInstance().getAuthStatus() != SFAuthStatus.AuthStatusAuthOk) {
SFLogN.info(TAG, "host app not auth ok, igore it");
Toast.makeText(mAppContext, "主应用尚未认证成功,请先认证", Toast.LENGTH_SHORT).show();
return;
}
String subAppPkgName = launchInfo.getSubAppInfo().getSubAppPackageName();
if (!SFUemSDK.getInstance().getSFLaunch().checkAppAuthorized(launchInfo)) {
SFLogN.info(TAG, "sub app not Authorized, igore it");
Toast.makeText(mAppContext, "管理员未授权该应用", Toast.LENGTH_SHORT).show();
return;
}
/**
* sdkonAppLaunched,launchInfoactivity
* 便使activity
*/
Activity activity = launchInfo.getForegroundActivity();
/**
*
* launcherSubApp
*/
showAuthSessionDialog(activity, launchInfo);
}
}
}
});
}
private void showAuthSessionDialog(Activity activity, SFLaunchInfo sfLaunchInfo) {
if (mAuthSessionDialog != null) {
mAuthSessionDialog.dismiss();
mAuthSessionDialog = null;
}
mAuthSessionDialog = new AuthSessionDialog(activity, sfLaunchInfo);
mAuthSessionDialog.setClickListener(new AuthSessionDialog.DialogClickListener() {
@Override
public void onPositiveClick(SFLaunchInfo launchInfo) {
SFLogN.info(TAG, "AuthSessionDialog positiveClick.");
/**
*
*/
SubAppManager.getInstance().launcherSubApp(mAppContext, launchInfo);
}
@Override
public void onNegativeClick(SFLaunchInfo launchInfo) {
SFLogN.info(TAG, "AuthSessionDialog negativeClick.");
}
});
SFLogN.info(TAG, "showAuthSessionDialog.");
mAuthSessionDialog.show();
}
private GlobalListenerManager() {
}
private final static class SingletonHolder {
private static final GlobalListenerManager INSTANCE = new GlobalListenerManager();
}
}

@ -0,0 +1,88 @@
package com.rehome.zhdcoa.vpn;
import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.Settings;
import android.widget.Toast;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import com.sangfor.sdk.utils.SFLogN;
import java.util.ArrayList;
import java.util.List;
public class PermissionUtil {
private static final String TAG = "PermissionUtil";
public static boolean isNeedRequestSDCardPermission(Context context) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
return false;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
// 先判断有没有权限
//context.checkSelfPermission(Manifest.permission.MANAGE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
if (!Environment.isExternalStorageManager()) {
return true;
}
} else {
if (context.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
return true;
}
if (context.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
return true;
}
}
return false;
}
public static void requestSDCardPermissions(Activity activity, int requestCode) {
if (activity == null) {
return;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
//android 11
Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
intent.setData(Uri.parse("package:" + activity.getPackageName()));
activity.startActivityForResult(intent, requestCode);
Toast.makeText(activity, "请授予所有文件管理权限~", Toast.LENGTH_SHORT).show();
} else {
List<String> permissionsList = new ArrayList<String>();
if (ContextCompat.checkSelfPermission(activity.getBaseContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
SFLogN.info(TAG,"No WRITE_EXTERNAL_STORAGE permission");
permissionsList.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
if (ContextCompat.checkSelfPermission(activity.getBaseContext(), Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
SFLogN.info(TAG,"No READ_EXTERNAL_STORAGE permission");
permissionsList.add(Manifest.permission.READ_EXTERNAL_STORAGE);
}
if (permissionsList.isEmpty()) {
return;
}
String[] permissions = permissionsList.toArray(new String[permissionsList.size()]);
ActivityCompat.requestPermissions(activity, permissions, requestCode);
}
}
/**
*
* @param context
*/
public static void gotoAppPermissionManageActivity(Context context) {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.parse("package:" + context.getPackageName()));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
}

@ -0,0 +1,68 @@
package com.rehome.zhdcoa.vpn;
import com.sangfor.sdk.SFMobileSecuritySDK;
import com.sangfor.sdk.SFUemSDK;
import com.sangfor.sdk.base.SFAuthType;
import com.rehome.zhdcoa.R;
public class SFDialogHelper {
/**
*
*
* @param authType
* @return
*/
public static String getDialogTitle(SFAuthType authType) {
switch (authType) {
case AUTH_TYPE_PASSWORD:
return "密码认证";
case AUTH_TYPE_CERTIFICATE:
return "证书认证";
case AUTH_TYPE_SMS:
case AUTH_TYPE_PRIMARY_SMS:
return "短信认证";
case AUTH_TYPE_RADIUS:
return "挑战认证";
case AUTH_TYPE_TOKEN:
case AUTH_TYPE_TOKEN_RADIUS:
case AUTH_TYPE_TOKEN_TOTP:
case AUTH_TYPE_TOKEN_HTTPS:
return "令牌认证";
case AUTH_TYPE_RAND:
return "图形校验码";
case AUTH_TYPE_RENEW_PASSWORD:
return "修改密码";
default:
return "";
}
}
public static int getAuthDialogViewId(SFAuthType authType) {
switch (authType) {
case AUTH_TYPE_PASSWORD:
return R.layout.dialog_pwd;
case AUTH_TYPE_CERTIFICATE:
return R.layout.dialog_certificate;
case AUTH_TYPE_SMS:
case AUTH_TYPE_PRIMARY_SMS:
return R.layout.dialog_sms;
case AUTH_TYPE_RADIUS:
return R.layout.dialog_challenge;
case AUTH_TYPE_TOKEN:
case AUTH_TYPE_TOKEN_RADIUS:
case AUTH_TYPE_TOKEN_TOTP:
case AUTH_TYPE_TOKEN_HTTPS:
return R.layout.dialog_token;
case AUTH_TYPE_RAND:
if (SFUemSDK.getInstance().isSDPServce()) {
//sdp服务器图形验证码返回当前layout
return R.layout.dialog_graph_check_sdp;
}
return R.layout.dialog_graph_check;
case AUTH_TYPE_RENEW_PASSWORD:
return R.layout.dialog_force_update_pwd;
default:
return -1;
}
}
}

@ -0,0 +1,74 @@
package com.rehome.zhdcoa.vpn;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
import android.text.TextUtils;
import com.sangfor.sdk.utils.SFLogN;
import java.io.ByteArrayInputStream;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class SignatureUtils {
private static final String TAG = "SignatureUtils";
/**
*
* @param appInfo
* @return
*/
public static String getPubKeyInfo(ApplicationInfo appInfo, Context context) {
PackageManager mPackageManager = context.getPackageManager();
if (mPackageManager != null){
try {
PackageInfo packageInfo = mPackageManager.getPackageInfo(appInfo.packageName, mPackageManager.GET_SIGNATURES);
Signature[] signatures = packageInfo.signatures;
Signature signature = signatures[0];
byte[] signatureBytes = signature.toByteArray();
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) certFactory.generateCertificate(new ByteArrayInputStream(signatureBytes));
String pubKeyStr = cert.getPublicKey().toString();
return parsePubKey(pubKeyStr);
} catch (PackageManager.NameNotFoundException e) {
SFLogN.error(TAG, "failed to get packageInfo ", e);
} catch (CertificateException e) {
SFLogN.error(TAG, "failed to get cert", e);
}
}
return null;
}
/**
* apk
* OpenSSLRSAPublicKey{modulus=98cfceafd123bc2d480af0bf31d41ca542736f8353031b01efad25dcef2dd566491635f23c0fbc950c93624dff4436c0910b0cdfe85bf6a86bcd7e42d790110ef4eec3eb8d3fb279734e71c6afd715f33712207101fa40ed0d196ad7c499bbc55d096de61f94117efaea996eed3a3a7c5bb875164bcb890439f6ccd2c0b2acb5,publicExponent=10001}";
* @param info
* @return
*/
private static String parsePubKey(String info) {
if (TextUtils.isEmpty(info)) {
return null;
}
String indexStr = "modulus=";
int index = info.indexOf(indexStr);
if (index != -1) {
int startIndex = index + indexStr.length();
indexStr = info.substring(startIndex);
String pubkey = indexStr.split(",")[0];
//因为解析出来的公钥信息中可能含有空格,换行等干扰信息,因此需要对其进行去杂处理,方便后续的字符串比较
if (pubkey != null) {
Pattern pattern = Pattern.compile("\\s*|\t|\r|\n");
Matcher matcher = pattern.matcher(pubkey);
pubkey = matcher.replaceAll("");
}
return pubkey;
}
return null;
}
}

@ -0,0 +1,69 @@
package com.rehome.zhdcoa.vpn;
import android.content.Context;
import com.sangfor.sdk.SFSecuritySDKFactory;
import com.sangfor.sdk.SFUemSDK;
import com.sangfor.sdk.base.SFLaunchReason;
import com.sangfor.sdk.entry.SFLaunchInfo;
import com.sangfor.sdk.utils.SFLogN;
/**
* 便
*/
public class SubAppManager {
private static final String TAG = "SubAppManager";
private SFLaunchInfo mSubAppLaunchInfo;
private static volatile SubAppManager sInstance;
private SubAppManager() {
}
public static SubAppManager getInstance() {
if (sInstance == null) {
synchronized (SubAppManager.class) {
if (sInstance == null) {
sInstance = new SubAppManager();
}
}
}
return sInstance;
}
public void setSubAppLaunchInfo(SFLaunchInfo subAppLaunchInfo) {
this.mSubAppLaunchInfo = subAppLaunchInfo;
}
public SFLaunchInfo getSubAppLaunchInfo() {
return mSubAppLaunchInfo;
}
/**
*
* @param context
*/
public void launcherSubApp(Context context, SFLaunchInfo launchInfo) {
if (context == null) {
SFLogN.error2(TAG, "cannot launcherSubApp", "context=null");
return;
}
SFLogN.info(TAG, "will launcherSubApp..." + launchInfo.getSubAppInfo().getSubAppPackageName());
if (launchInfo != null) {
SFLogN.info(TAG, "will start sub app...");
SFUemSDK.getInstance().getSFLaunch().launchSubApp(context, launchInfo);
} else {
SFLogN.warn2(TAG, "can not start sub app...", "launchInfo is null");
}
// 子应用被拉起后,表示一个流程执行完成,需要清空数据(主应用被子应用拉起-->主应用拉回子应用)
clearCache();
}
public void clearCache() {
this.mSubAppLaunchInfo = null;
}
}

@ -0,0 +1,53 @@
package com.rehome.zhdcoa.weiget;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.rehome.zhdcoa.R;
/**
* SDPview
* author yanghua
* date 20220915
*/
public class RandCodeCircleView extends RelativeLayout {
private Context context;
private View view;
private SangforTextView tvNum;
private RandCodeLayout.ClickPoint mPoint;
public RandCodeCircleView(Context context) {
super(context);
}
public RandCodeCircleView(Context context, RandCodeLayout.ClickPoint point) {
super(context);
this.context = context;
this.mPoint = point;
initViews();
}
/**
*
**/
protected void initViews() {
view = LayoutInflater.from(context).inflate(R.layout.randcode_cricle_view, this, true);
tvNum = view.findViewById(R.id.tvNum);
tvNum.setText(mPoint.getNum() + "");
}
public int getNum() {
return mPoint.getNum();
}
public void setPoint(RandCodeLayout.ClickPoint point) {
this.mPoint = point;
tvNum.setText(mPoint.getNum() + "");
}
}

@ -0,0 +1,358 @@
package com.rehome.zhdcoa.weiget;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import com.sangfor.sdk.base.SFAuthType;
import com.sangfor.sdk.utils.SFLogN;
import java.util.ArrayList;
/**
* SDP
* author yanghua
* date 20220915
*/
@SuppressLint("NewApi")
public class RandCodeLayout extends RelativeLayout implements OnTouchListener {
private final String TAG = "RandCodeLayout";
private final int LIMT_NUM = 3;
private Context mContext;
private RandCodeCircleView mTouchView;
private int mStartX;
private int mStartY;
private int mChildHeight;
private int mChildWidth;
private int mlayoutWith;
private int mlayoutHeight;
private String user_position;
private ArrayList<ClickPoint> mPoints;
private OnFinishClickListener mFinishClickCallback;
private boolean isCheckCodeing = false;
public void setOnFinishClickListener(OnFinishClickListener callback) {
this.mFinishClickCallback = callback;
}
public RandCodeLayout(Context context) {
super(context, null);
}
public RandCodeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
this.mContext = context;
init();
}
private void init() {
this.setOnTouchListener(this);
mPoints = new ArrayList<ClickPoint>();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
SFLogN.info(TAG, "onSizeChanged:" + w + "/" + h);
//缓存原来的大小
float cacheOriWith = mlayoutWith;
float cacheOriHeight = mlayoutHeight;
//保存新view大小
mlayoutWith = w;
mlayoutHeight = h;
ArrayList<ClickPoint> cachePoints = new ArrayList<>();
if (mPoints == null || mPoints.size() == 0) {
return;
}
//处理数据,计算新的布局,点的位置
int size = mPoints.size();
for (int i = 0; i < size; i++) {
ClickPoint clickPoint = mPoints.get(i);
int cacheX = (int) ((clickPoint.clickX/cacheOriWith) * w);
int cacheY = (int) ((clickPoint.clickY/cacheOriHeight) * h);
cachePoints.add(new ClickPoint(cacheX,cacheY, i+1));
}
//清除数据
clearView();
//重新添加数据
if (cachePoints.size() > 0) {
for (int i = 0; i < size; i++) {
ClickPoint cachePoint = cachePoints.get(i);
addPopup(cachePoint.clickX, cachePoint.clickY);
}
}
}
//开始的位置小于结束的位置 向左滑动
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
if (isCheckCodeing) {
SFLogN.info(TAG, "onTouch is checking" );
break;
}
mStartX = (int) event.getX();
mStartY = (int) event.getY();
if (!hasView(mStartX, mStartY) && isClickableRect(mStartX, mStartY)) {
//如果点击位置没有点击过,并且点击的位置在可点击的返回内
addPopup(mStartX, mStartY);
} else {
//点击的位置包含已经存在的view则移除当前的view
removePopup();
}
break;
}
return true;
}
/**
*
*/
private void removePopup() {
if (mTouchView != null) {
int num = mTouchView.getNum();
removeAllViews();
mTouchView = null;
user_position = "";
//移除数据
for (int i = 0; i < mPoints.size(); i++) {
ClickPoint point = mPoints.get(i);
if (point.getNum() == num) {
mPoints.remove(i);
}
}
//更新数据
for (int i = 0; i < mPoints.size(); i++) {
mPoints.get(i).setNum(i + 1);
}
//更新UI
for (int i = 0; i < mPoints.size(); i++) {
this.addView(mPoints.get(i).getRandCdoeView());
}
}
}
/**
*
*/
public void addPopup(int x, int y) {
SFLogN.info(TAG, "cricle num:" + mPoints.size());
if (mPoints.size() < LIMT_NUM) {
addData(x, y);
}
}
public void addData(int clickX, int clickY) {
SFLogN.info(TAG, "click x:" + clickX + "/y:" + clickY);
if (mPoints != null) {
addItem(clickX, clickY);
if (mPoints.size() == LIMT_NUM && !isCheckCodeing) {
if (mFinishClickCallback != null) {
mFinishClickCallback.onFinishClick(getRondCode(), SFAuthType.AUTH_TYPE_RAND);
}
//记录当前正在校验code中
isCheckCodeing = true;
}
} else {
SFLogN.warn2(TAG, "addData is fail", "points list is null");
}
}
private void addItem(int x, int y) {
//添加元素
int num = mPoints.size() + 1;
ClickPoint point = new ClickPoint(x, y, num);
LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
//第一次点击添加标签是 PictureTagView.Direction.Measure 让TagView自己测量方向
RandCodeCircleView view = new RandCodeCircleView(getContext(), point);
view.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT));
int w = MeasureSpec.makeMeasureSpec(0,
MeasureSpec.UNSPECIFIED);
int h = MeasureSpec.makeMeasureSpec(0,
MeasureSpec.UNSPECIFIED);
view.measure(w, h);
mChildHeight = view.getMeasuredHeight();
mChildWidth = view.getMeasuredWidth();
//标签在右面 点击位置 x-标签宽度 右边的标签并不是以圆点开始的 而是以左边的wei
params.leftMargin = x - mChildWidth / 2;
params.topMargin = y - mChildHeight / 2;
//上下位置在视图内
if (params.topMargin <= 0) {
params.topMargin = 0;
} else if ((params.topMargin + mChildHeight) > getHeight()) {
params.topMargin = getHeight() - mChildHeight;
}
if (params.leftMargin <= 0) {
params.leftMargin = 0;
}
if (params.rightMargin >= getWidth()) {
params.rightMargin = getWidth();
}
point.setRandCdoeView(view);
mPoints.add(point);
this.addView(view, params);
}
private boolean isClickableRect(int clickX, int clickY) {
if (mlayoutHeight <= 0 || mlayoutWith <= 0) {
return false;
}
int clickHeight = (int) (mlayoutHeight - 32 * getResources().getDisplayMetrics().density);
Rect rect = new Rect(0, 0, mlayoutWith, clickHeight);
return rect.contains(clickX, clickY);
}
private boolean hasView(int x, int y) {
//循环获取子view判断xy是否在子view上即判断是否按住了子view
for (int index = 0; index < this.getChildCount(); index++) {
View view = this.getChildAt(index);
int left = (int) view.getX();
int top = (int) view.getY();
int right = view.getRight();
int bottom = view.getBottom();
Rect rect = new Rect(left, top, right, bottom);
boolean contains = rect.contains(x, y);
//如果是与子view重叠则返回真,表示已经有了view不需要添加新view了
if (contains) {
mTouchView = (RandCodeCircleView) view;
return true;
}
}
return false;
}
/**
* string
* json{"coordinates":[[125,196],[255,93],[555,246]],"width":816,"height":576}
*
* @return
*/
private String getRondCode() {
for (int i = 0 ; i < mPoints.size(); i++) {
ClickPoint point = mPoints.get(i);
if (i == 0) {
user_position = "[" + point.getClickX() + "," + point.getClickY() + "]";
} else {
user_position = user_position + ",[" + point.getClickX() + "," + point.getClickY() + "]";
}
}
String json = "{\"coordinates\"" + ":" + "[" + user_position + "]," + "\"width\":" + mlayoutWith + ",\"height\":" + mlayoutHeight + "}";
return json;
}
/**
*
*/
public void clearView() {
removeAllViews();
if (mPoints != null && mPoints.size() > 0) {
mPoints.clear();
}
}
/**
*
* @param checkCodeing
*/
public void setCheckCodeing(boolean checkCodeing) {
isCheckCodeing = checkCodeing;
}
/**
*
* @return
*/
public boolean getCheckCodeing() {
return isCheckCodeing;
}
/**
*
*/
public interface OnFinishClickListener {
void onFinishClick(String authJson, SFAuthType authType);
}
/**
*
*/
class ClickPoint {
private int clickX;
private int clickY;
private int num;
private RandCodeCircleView mRandCodeview;
public ClickPoint(int x, int y, int num) {
this.clickX = x;
this.clickY = y;
this.num = num;
}
public int getClickX() {
return clickX;
}
public void setClickX(int clickX) {
this.clickX = clickX;
}
public int getClickY() {
return clickY;
}
public void setClickY(int clickY) {
this.clickY = clickY;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
mRandCodeview.setPoint(this);
}
public void setRandCdoeView(RandCodeCircleView view) {
this.mRandCodeview = view;
}
public RandCodeCircleView getRandCdoeView() {
return mRandCodeview;
}
}
}

@ -0,0 +1,149 @@
package com.rehome.zhdcoa.weiget;
import android.content.Context;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import androidx.appcompat.widget.AppCompatEditText;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.MotionEvent;
public class SFEditText extends AppCompatEditText implements TextWatcher {
private Drawable leftDrawable = null;
private Drawable rightDrawable = null;
// 控件是否有焦点
private boolean hasFocus;
private IMyRightDrawableClick mRightDrawableClick;
public SFEditText(Context context) {
super(context);
}
public SFEditText(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public SFEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, android.R.attr.editTextStyle);
init();
}
private void init() {
//获取RadioButton的图片集合
Drawable[] drawables = getCompoundDrawables();
leftDrawable = drawables[0];
rightDrawable = drawables[2];
setCompoundDrawablesWithIntrinsicBounds(leftDrawable, null, null, null);
//设置输入框里面内容发生改变的监听
addTextChangedListener(this);
}
//设置显示图片的大小
public void setCompoundDrawablesWithIntrinsicBounds(Drawable left, Drawable top, Drawable right, Drawable bottom) {
super.setCompoundDrawablesWithIntrinsicBounds(left, top, right, bottom);
//这里只要改后面两个参数就好了,一个宽一个是高,如果想知道为什么可以查找源码
if (left != null) {
left.setBounds(0, 0, 50, 50);
}
if (right != null) {
right.setBounds(0, 0, 50, 50);
}
if (top != null) {
top.setBounds(0, 0, 100, 100);
}
if (bottom != null) {
bottom.setBounds(0, 0, 100, 100);
}
setCompoundDrawables(left, top, right, bottom);
}
//光标选中时判断
@Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
super.onFocusChanged(focused, direction, previouslyFocusedRect);
this.hasFocus = focused;
if (focused)
setImageVisible(getText().length() > 0);
else
setImageVisible(false);
}
//设置清除图标的显示与隐藏调用setCompoundDrawables为EditText绘制上去
protected void setImageVisible(boolean flag) {
if (getCompoundDrawables()[2] != null) {
rightDrawable = getCompoundDrawables()[2];
}
if (flag) {
setCompoundDrawables(getCompoundDrawables()[0], null, rightDrawable, null);
} else {
setCompoundDrawables(getCompoundDrawables()[0], null, null, null);
}
}
//文本框监听事件
@Override
public void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
if (hasFocus) {
if (text.length() > 0)
setImageVisible(true);
else
setImageVisible(false);
}
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
public void afterTextChanged(Editable s) {
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
if (getCompoundDrawables()[2] != null) {
boolean touchable = event.getX() > (getWidth() - getTotalPaddingRight())
&& (event.getX() < ((getWidth() - getPaddingRight())));
if (touchable) {
if (mRightDrawableClick != null) {
//调用点击事件
mRightDrawableClick.rightDrawableClick();
}
}
}
}
return super.onTouchEvent(event);
}
public void setDrawableClick(IMyRightDrawableClick mMightDrawableClick) {
this.mRightDrawableClick = mMightDrawableClick;
}
public void setRightDrawable(Drawable drawable) {
rightDrawable = drawable;
setCompoundDrawablesWithIntrinsicBounds(leftDrawable, null, rightDrawable, null);
}
//自定义接口(实现右边图片点击事件)
public interface IMyRightDrawableClick {
void rightDrawableClick();
}
}

@ -0,0 +1,93 @@
package com.rehome.zhdcoa.weiget;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.AppCompatTextView;
import com.rehome.zhdcoa.R;
import com.rehome.zhdcoa.utils.DpPxSpTransformUtil;
/**
* @ProjectName: SDKDemo
* @Package: com.sangfor.sdkdemo.utils
* @ClassName: SangforTextView
* @Description: java
* @Author: yanghua
* @CreateDate: 2022/9/21 5:40
*/
public class SangforTextView extends View {
String mText;
public void setText(String text) {
mText = text;
invalidate();
}
//构造方法
public SangforTextView(@NonNull Context context) {
super(context);
}
public SangforTextView(@NonNull Context context, AttributeSet attrs) {
super(context, attrs);
}
public SangforTextView(@NonNull Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onDraw(Canvas canvas) {
//super.onDraw(canvas);
//画水平中心线和垂直中心线
//drawCenterLineX(canvas);
//drawCenterLineY(canvas);
//画底层黑色
drawTextCenter(canvas);
}
//将文字写到中央
private void drawTextCenter(Canvas canvas){
//创建画笔
Paint paint = new Paint();
paint.setTextSize(DpPxSpTransformUtil.sp2px(12));
paint.setColor(getResources().getColor(R.color.white));
//让他垂直居中
Paint.FontMetrics fontMetrics = paint.getFontMetrics();
float baseLine = getHeight()/2 -(fontMetrics.descent + fontMetrics.ascent)/2;
//让他水平居中
float x = getWidth()/2 - paint.measureText(mText)/2;
canvas.drawText(mText,x,baseLine,paint);
}
//画x轴的中心线
private void drawCenterLineX(final Canvas canvas){
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.RED);
paint.setStrokeWidth(3);
canvas.drawLine(getWidth()/2,0,getWidth()/2,getHeight(),paint);
}
//画y轴的中心线
private void drawCenterLineY(final Canvas canvas){
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.RED);
paint.setStrokeWidth(3);
canvas.drawLine(0,getHeight()/2,getWidth(),getHeight()/2,paint);
}
}

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<solid android:color="#029AFF"/>
<corners android:radius="5dp"/>
</shape>
</item>
</selector>

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:color="@android:color/holo_blue_dark" />
<item android:color="#808080"/>
</selector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 614 B

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<padding
android:left="10dp"
android:top="10dp"
android:right="10dp"
android:bottom="10dp"
/>
<stroke
android:width="1px"
android:color="#969696"/>
<!--背景色-->
<solid android:color="#FFF"></solid>
</shape>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 794 B

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#FFFFE9E9"/>
<stroke
android:width="2dp"
android:color="@color/red" />
<corners
android:bottomLeftRadius="10dp"
android:bottomRightRadius="10dp"/>
</shape>

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#D0CDCD"/>
<corners
android:bottomLeftRadius="10dp"
android:bottomRightRadius="10dp"/>
</shape>

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval"
android:useLevel="false">
<solid android:color="@color/blue"/>
<stroke
android:width="2dp"
android:color="@color/white" />
</shape>

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<stroke
android:width="0.5dp"
android:color="#aaaaaa"/>
<corners android:radius="4dp" />
<solid android:color="@color/white"/>
</shape>

@ -0,0 +1,193 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="true"
android:focusableInTouchMode="true"
android:orientation="vertical"
tools:context=".ui.activity.AuthSuccessActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<LinearLayout
android:layout_width="wrap_content"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="20dp"
android:gravity="center_vertical"
android:orientation="vertical">
<Button
android:id="@+id/btn_file"
android:layout_width="wrap_content"
android:layout_height="42dp"
android:layout_marginTop="10dp"
android:text="@string/file_test" />
<Button
android:id="@+id/btn_udp"
android:layout_width="wrap_content"
android:layout_height="42dp"
android:layout_marginTop="10dp"
android:text="@string/udp_test" />
<Button
android:id="@+id/btn_log"
android:layout_width="wrap_content"
android:layout_height="42dp"
android:layout_marginTop="10dp"
android:text="@string/log_test" />
<Button
android:id="@+id/btn_modify_psw"
android:layout_width="wrap_content"
android:layout_height="42dp"
android:layout_marginTop="10dp"
android:text="@string/modify_psw" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginRight="10dp"
android:layout_marginTop="20dp"
android:gravity="right"
android:orientation="vertical">
<Button
android:id="@+id/btn_start_tunnel"
android:layout_width="wrap_content"
android:layout_height="42dp"
android:layout_marginTop="10dp"
android:layout_marginRight="10dp"
android:text="@string/start_tunnel" />
<Button
android:id="@+id/btn_stop_tunnel"
android:layout_width="wrap_content"
android:layout_height="42dp"
android:layout_marginTop="10dp"
android:layout_marginRight="10dp"
android:text="@string/stop_tunnel" />
<Button
android:id="@+id/btn_master_slave"
android:layout_width="wrap_content"
android:layout_height="42dp"
android:layout_marginTop="10dp"
android:layout_marginRight="10dp"
android:text="@string/master_slave" />
<Button
android:id="@+id/btn_atrust_auth"
android:layout_width="wrap_content"
android:layout_height="42dp"
android:layout_marginTop="10dp"
android:layout_marginRight="10dp"
android:text="@string/atrust_auth" />
</LinearLayout>
</LinearLayout>
<Button
android:id="@+id/btn_logout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:layout_marginTop="5dp"
android:layout_marginRight="5dp"
android:layout_marginBottom="10dp"
android:background="@android:color/transparent"
android:onClick="onClick"
android:text="注销VPN"
android:textColor="@android:color/holo_blue_dark"
android:textSize="20sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:orientation="horizontal"
android:paddingLeft="5dp"
android:paddingRight="5dp"
tools:layout_editor_absoluteX="8dp"
tools:layout_editor_absoluteY="0dp">
<EditText
android:id="@+id/et_url"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.7"
android:hint="内网资源地址"
android:inputType="textUri" />
<AutoCompleteTextView
android:id="@+id/autoComTextView_url"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.7"
android:hint="外网资源地址"
android:inputType="textUri"
android:visibility="gone" />
<Button
android:id="@+id/btn_test_res"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="测试"
android:textSize="18sp" />
</LinearLayout>
<FrameLayout
android:id="@+id/web_view_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<RadioGroup
android:id="@+id/svpn_resource_tabheader"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:orientation="horizontal"
android:paddingLeft="20dp"
android:paddingTop="0dp"
android:paddingRight="20dp"
android:paddingBottom="0dp">
<RadioButton
android:id="@+id/svpn_intraResource_tabheader"
style="@style/VPNSourceButtonIndicator"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:checked="true"
android:text="@string/str_intranet_resource" />
<RadioButton
android:id="@+id/svpn_extraResource_tabheader"
style="@style/VPNSourceButtonIndicator"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/str_extranet_resource" />
<RadioButton
android:id="@+id/svpn_proxyDomain_tabheader"
style="@style/VPNSourceButtonIndicator"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/str_proxy_domain" />
</RadioGroup>
</LinearLayout>

@ -83,6 +83,7 @@
</LinearLayout>
<LinearLayout
android:id="@+id/ll_left_right"
android:layout_width="match_parent"
@ -97,30 +98,34 @@
android:gravity="center_vertical"
android:text=""
android:textSize="35px" />
<TextView
style="@style/serviceAgreement"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/serviceAgreement"
android:text="已阅读并同意"/>
android:text="已阅读并同意" />
<TextView
android:id="@+id/tv_service_agreement"
style="@style/serviceAgreement"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/colorPrimaryDark"
style="@style/serviceAgreement"
android:text="服务协议"/>
android:text="服务协议"
android:textColor="@color/colorPrimaryDark" />
<TextView
style="@style/serviceAgreement"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/serviceAgreement"
android:text="和"/>
android:text="和" />
<TextView
android:id="@+id/tv_privacy"
style="@style/serviceAgreement"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/colorPrimaryDark"
style="@style/serviceAgreement"
android:text="隐私保护"/>
android:text="隐私保护"
android:textColor="@color/colorPrimaryDark" />
</LinearLayout>
@ -128,10 +133,10 @@
android:id="@+id/sw_remember_pwd"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:checked="true"
android:shadowColor="@color/gray"
android:switchMinWidth="40dp"
android:switchPadding="10dp"
android:checked="true"
android:text="@string/remember_me"
android:textSize="14sp"
android:thumb="@drawable/thumb"
@ -161,9 +166,18 @@
style="@style/Widget.AppCompat.CompoundButton.RadioButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="10dp"
android:checked="true"
android:text="外网" />
<RadioButton
android:id="@+id/rb3"
style="@style/Widget.AppCompat.CompoundButton.RadioButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:text="aTrust" />
</RadioGroup>
</LinearLayout>
@ -175,19 +189,48 @@
android:gravity="center"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center|end"
android:layout_marginBottom="10dp"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_vpn_logout"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginStart="15dp"
android:layout_marginEnd="15dp"
android:gravity="center|start"
android:text="VPN注销>>"
android:textColor="@color/colorPrimaryDark"
android:textSize="16sp" />
<TextView
android:id="@+id/tv_vpn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="15dp"
android:gravity="center"
android:text="VPN登录>>"
android:textColor="@color/colorPrimaryDark"
android:textSize="16sp" />
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="#DAA520"
android:text="本平台为非涉密平台,严禁处理、传输"
android:textColor="#DAA520"
android:textSize="16sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="#DAA520"
android:text="国家秘密、工作秘密、商业秘密、敏感信息"
android:textColor="#DAA520"
android:textSize="16sp" />
</LinearLayout>
@ -202,10 +245,10 @@
android:id="@+id/text_wjmm"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/colorPrimaryDark"
android:layout_weight="1"
android:gravity="center"
android:text="忘记密码"
android:textColor="@color/colorPrimaryDark"
android:textSize="16sp" />
</LinearLayout>
@ -220,6 +263,7 @@
android:text="版本号2.0.6"
android:textSize="12sp"
android:textStyle="normal" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -234,19 +278,21 @@
android:gravity="center"
android:text="ICP备案号"
android:textSize="12sp" />
<TextView
android:id="@+id/tv_beiAn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="@color/colorPrimaryDark"
android:text="粤ICP备2024215982号"
android:textColor="@color/colorPrimaryDark"
android:textSize="12sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_marginStart="5dp"
android:gravity="center"
android:text=">"
android:textSize="12sp" />

@ -0,0 +1,81 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_login"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
android:paddingBottom="30dp"
android:paddingLeft="30dp"
android:paddingRight="30dp"
android:focusable="true"
android:focusableInTouchMode="true"
tools:context=".ui.activity.PrimaryAuthActivity">
<LinearLayout
android:id="@+id/svpn_url_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:layout_marginRight="30dp"
android:layout_marginTop="50dp"
android:layout_gravity="center_vertical"
android:orientation="vertical">
<TextView
android:id="@+id/svpn_ip_textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="VPN地址"
android:textSize="18sp"
android:textColor="@android:color/black"
android:padding="5dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp">
<EditText
android:id="@+id/vpn_addr_editView"
android:background="@drawable/shape_corner"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent"
android:hint="@string/str_svpn_ip"
android:textSize="18sp"
android:textColor="@android:color/black"
android:singleLine="true"
android:padding="5dp" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/svpn_auth_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:layout_marginRight="30dp"
android:layout_below="@id/svpn_url_layout"
android:layout_marginTop="30dp">
<include layout="@layout/auth_layout"/>
</LinearLayout>
<Button
android:id="@+id/svpn_login_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/svpn_auth_layout"
android:layout_marginLeft="30dp"
android:layout_marginRight="30dp"
android:background="@drawable/auth_button_login"
android:text="登 录"
android:textColor="#ffffff"
android:layout_marginTop="10dp"
android:textSize="20sp" />
</RelativeLayout>

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_login"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
android:paddingBottom="30dp"
android:paddingStart="30dp"
android:paddingEnd="16dp"
android:focusable="true"
android:focusableInTouchMode="true" >
<LinearLayout
android:id="@+id/svpn_url_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:layout_marginRight="30dp"
android:layout_marginTop="50dp"
android:layout_gravity="center_vertical"
android:orientation="vertical">
<TextView
android:id="@+id/svpn_ip_textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="VPN地址"
android:textSize="18sp"
android:textColor="@android:color/black"
android:padding="5dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp">
<EditText
android:id="@+id/vpn_addr_editView"
android:background="@drawable/shape_corner"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="match_parent"
android:hint="@string/str_svpn_ip"
android:textSize="18sp"
android:textColor="@android:color/black"
android:singleLine="true"
android:padding="5dp" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/svpn_auth_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:layout_marginRight="30dp"
android:layout_below="@id/svpn_url_layout"
android:layout_marginTop="30dp">
<include layout="@layout/sms_auth_layout"/>
</LinearLayout>
<Button
android:id="@+id/svpn_login_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/svpn_auth_layout"
android:layout_marginLeft="30dp"
android:layout_marginRight="30dp"
android:background="@drawable/auth_button_login"
android:text="登 录"
android:textColor="#ffffff"
android:layout_marginTop="10dp"
android:textSize="20sp" />
</RelativeLayout>

@ -0,0 +1,93 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
android:orientation="vertical"
tools:context=".ui.activity.VpnAuthActivity">
<include
android:id="@+id/toolbarView"
layout="@layout/layout_base" />
<RelativeLayout
android:id="@+id/activity_login"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
android:focusable="true"
android:focusableInTouchMode="true"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:paddingBottom="16dp">
<LinearLayout
android:id="@+id/svpn_url_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="30dp"
android:layout_marginTop="50dp"
android:layout_marginRight="30dp"
android:visibility="invisible"
android:orientation="vertical">
<TextView
android:id="@+id/svpn_ip_textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
android:text="VPN地址"
android:textColor="@android:color/black"
android:textSize="18sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp">
<EditText
android:id="@+id/vpn_addr_editView"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/shape_corner"
android:enabled="false"
android:hint="@string/str_svpn_ip"
android:padding="5dp"
android:singleLine="true"
android:textColor="@android:color/black"
android:textSize="15sp" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/svpn_auth_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/svpn_url_layout"
android:layout_marginLeft="30dp"
android:layout_marginTop="30dp"
android:layout_marginRight="30dp">
<include layout="@layout/auth_layout" />
</LinearLayout>
<Button
android:id="@+id/svpn_login_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/svpn_auth_layout"
android:layout_marginLeft="30dp"
android:layout_marginTop="20dp"
android:layout_marginRight="30dp"
android:background="@drawable/auth_button_login"
android:text="登 录"
android:textColor="#ffffff"
android:textSize="20sp" />
</RelativeLayout>
</LinearLayout>

@ -0,0 +1,138 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:tools="http://schemas.android.com/tools"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android">
<RadioGroup
android:id="@+id/svpn_auth_tabheader"
android:layout_gravity="center_horizontal"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:orientation="horizontal"
android:paddingBottom="0dp"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:paddingTop="0dp">
<RadioButton
style="@style/AuthTabHeaderIndicator"
android:id="@+id/svpn_userAuth_tabheader"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_width="0dp"
android:text="@string/str_tab_password"
android:checked="true"/>
</RadioGroup>
<LinearLayout
android:background="@drawable/shape_corner"
android:id="@+id/svpn_userAuth_layout"
android:layout_gravity="center_vertical"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:orientation="vertical">
<com.rehome.zhdcoa.weiget.SFEditText
android:id="@+id/svpn_username_editView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@null"
android:drawableLeft="@mipmap/icon_user"
android:drawablePadding="15dp"
android:hint="用户名"
android:textSize="16dp"
android:paddingBottom="10dp"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:paddingTop="10dp"
android:singleLine="true"/>
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="#999999"/>
<com.rehome.zhdcoa.weiget.SFEditText
android:id="@+id/svpn_userPassword_editView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@null"
android:drawableLeft="@mipmap/icon_psw"
android:drawablePadding="15dp"
android:hint="密码"
android:textSize="16dp"
android:inputType="textPassword"
android:paddingBottom="10dp"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:paddingTop="10dp"
android:singleLine="true"/>
</LinearLayout>
<LinearLayout
android:background="@drawable/shape_corner"
android:id="@+id/svpn_certAuth_layout"
android:layout_gravity="center_vertical"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:orientation="vertical"
android:visibility="gone">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.rehome.zhdcoa.weiget.SFEditText
android:id="@+id/svpn_certPath_editView"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@null"
android:drawableLeft="@mipmap/icon_user"
android:drawablePadding="15dp"
android:hint="证书路径"
android:textSize="16dp"
android:paddingBottom="10dp"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:paddingTop="10dp"
android:singleLine="true" />
<ImageView
android:background="@mipmap/icon_folder"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="10dp"
android:layout_gravity="center"/>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="#999999"/>
<com.rehome.zhdcoa.weiget.SFEditText
android:id="@+id/svpn_certPassword_editView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@null"
android:drawableLeft="@mipmap/icon_psw"
android:drawablePadding="15dp"
android:hint="证书密码"
android:textSize="16dp"
android:inputType="textPassword"
android:paddingBottom="10dp"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:paddingTop="10dp"
android:singleLine="true" />
</LinearLayout>
</LinearLayout>

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="5dp"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="5dp"
>
<LinearLayout
android:layout_marginTop="5dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/edit_bg"
android:orientation="horizontal">
<EditText
android:id="@+id/et_certPath"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@null"
android:drawablePadding="15dp"
android:hint="证书路径"
android:singleLine="true" />
<TextView
android:id="@+id/tv_certPath"
android:layout_marginLeft="10dp"
android:layout_gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="选择"
android:textSize="18sp"
android:textStyle="bold"
android:textColor="@android:color/holo_blue_light"/>
</LinearLayout>
<EditText
android:id="@+id/et_certPwd"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:background="@drawable/edit_bg"
android:drawablePadding="15dp"
android:hint="证书密码"
android:inputType="textPassword"
android:singleLine="true" />
</LinearLayout>
</LinearLayout>

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="10dp"
>
<TextView
android:id="@+id/tv_reminder"
android:layout_marginLeft="5dp"
android:padding="5dp"
android:text="提示hello"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<LinearLayout
android:layout_marginLeft="5dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="5dp">
<EditText
android:id="@+id/et_authAnswer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/edit_bg"
android:hint="认证答案"
android:singleLine="true" />
</LinearLayout>
</LinearLayout>

@ -0,0 +1,66 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="10dp"
>
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="10dp">
<TextView
android:id="@+id/tv_policy"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="密码策略">
</TextView>
<LinearLayout
android:layout_marginLeft="5dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginTop="5dp"
android:padding="5dp">
<EditText
android:id="@+id/et_oldpwd"
android:layout_marginTop="5dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/edit_bg"
android:hint="旧密码"
android:singleLine="true" />
<EditText
android:id="@+id/et_newpwd"
android:layout_marginTop="5dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/edit_bg"
android:hint="新密码"
android:singleLine="true" />
<EditText
android:id="@+id/et_renewpwd"
android:layout_marginTop="5dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/edit_bg"
android:hint="确认密码"
android:singleLine="true" />
</LinearLayout>
</LinearLayout>
</ScrollView>
</LinearLayout>

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="10dp">
<TextView
android:layout_marginLeft="5dp"
android:padding="5dp"
android:text="请输入图形校验码(点击图片刷新):"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<LinearLayout
android:layout_marginLeft="5dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:padding="5dp">
<EditText
android:id="@+id/et_graphCode"
android:layout_width="1dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:background="@drawable/edit_bg"
android:hint="验证码"
android:singleLine="true" />
<ImageView
android:id="@+id/randcode_imgError"
android:layout_marginLeft="6dp"
android:layout_width="1dp"
android:layout_weight="1"
android:gravity="center"
android:layout_height="40dp"
android:src="@android:drawable/ic_delete"
android:visibility="gone"/>
<ImageView
android:id="@+id/iv_graphCode"
android:layout_marginLeft="6dp"
android:layout_width="1dp"
android:layout_weight="1"
android:gravity="center"
android:layout_height="40dp" />
</LinearLayout>
</LinearLayout>

@ -0,0 +1,107 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:layout_marginLeft="20dp"
android:id="@+id/back"
android:layout_marginTop="10dp"
android:background="@drawable/randcode_back"
android:layout_width="25dp"
android:layout_height="25dp" />
<LinearLayout
android:layout_gravity="center_horizontal"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:textColor="@color/bg_font_normal"
android:layout_marginTop="20dp"
android:textSize="25sp"
android:text="图形验证码(非SDK)"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:layout_marginBottom="10dp"
android:layout_marginTop="10dp"
android:text="选择图片中的文字,来进行安全校验"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<FrameLayout
android:id="@+id/rand_flayout"
android:layout_width="326dp"
android:layout_height="230dp"
android:orientation="horizontal"
android:gravity="center_vertical">
<ImageView
android:id="@+id/randcode_imgError"
android:layout_width="1dp"
android:layout_weight="1"
android:gravity="center"
android:layout_height="40dp"
android:src="@android:drawable/ic_delete"
android:visibility="gone"/>
<com.rehome.zhdcoa.weiget.RandCodeLayout
android:id="@+id/iv_graphCode"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.rehome.zhdcoa.weiget.RandCodeLayout>
<ImageView
android:layout_margin="3dp"
android:id="@+id/fresh_randcode"
android:background="@drawable/fresh_button"
android:layout_gravity="right"
android:layout_width="30dp"
android:layout_height="30dp"/>
<FrameLayout
android:visibility="gone"
android:background="@drawable/shape_check_fl"
android:id="@+id/check_code_fl"
android:layout_gravity="bottom|center_horizontal"
android:layout_width="match_parent"
android:layout_height="45dp">
<ProgressBar
android:visibility="gone"
android:id="@+id/check_code_progress"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<LinearLayout
android:visibility="gone"
android:background="@drawable/shape_check_fail"
android:id="@+id/check_code_fail"
android:gravity="center"
android:layout_gravity="center_horizontal"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:src="@drawable/check_fail"
android:layout_width="16dp"
android:layout_height="16dp"/>
<TextView
android:textSize="18sp"
android:textColor="@color/red"
android:layout_gravity="center"
android:text="验证失败,请重试"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
</FrameLayout>
</FrameLayout>
</LinearLayout>
</LinearLayout>

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="10dp"
>
<LinearLayout
android:layout_marginLeft="5dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="5dp">
<EditText
android:id="@+id/et_username"
android:layout_marginTop="5dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/edit_bg"
android:hint="用户名"
android:drawablePadding="15dp"
android:singleLine="true" />
<EditText
android:id="@+id/et_password"
android:layout_marginTop="5dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/edit_bg"
android:drawablePadding="15dp"
android:hint="密码"
android:singleLine="true" />
</LinearLayout>
</LinearLayout>

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="10dp"
>
<TextView
android:layout_marginLeft="5dp"
android:padding="5dp"
android:id="@+id/tv_tel"
android:text="手机号:"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<LinearLayout
android:layout_marginLeft="5dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:padding="5dp">
<EditText
android:id="@+id/et_verficationCode"
android:layout_weight="0.55"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@drawable/edit_bg"
android:hint="验证码"
android:maxLength="6"
android:singleLine="true" />
<Button
android:layout_marginLeft="10dp"
android:id="@+id/bt_getVerficationCode"
android:text="30s后重新发送"
android:layout_weight="0.45"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center"/>
</LinearLayout>
</LinearLayout>

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:padding="10dp"
>
<TextView
android:layout_marginLeft="5dp"
android:padding="5dp"
android:text="请输入动态口令:"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<LinearLayout
android:layout_marginLeft="5dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="5dp">
<EditText
android:id="@+id/et_dynamicToken"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/edit_bg"
android:hint="动态口令"
android:singleLine="true" />
</LinearLayout>
</LinearLayout>

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<LinearLayout
android:layout_width="21dp"
android:layout_height="21dp"
android:layout_gravity="center"
android:background="@drawable/shape_circle_select"
android:gravity="center"
android:orientation="horizontal">
<com.rehome.zhdcoa.weiget.SangforTextView
android:id="@+id/tvNum"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/* //device/apps/common/assets/res/any/layout/simple_spinner_item.xml
**
** Copyright 2006, The Android Open Source Project
**
** 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.
*/
-->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1"
style="?android:attr/spinnerItemStyle"
android:singleLine="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="marquee"
android:textAlignment="inherit"/>

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:tools="http://schemas.android.com/tools"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android">
<RadioGroup
android:id="@+id/svpn_auth_tabheader"
android:layout_gravity="center_horizontal"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:orientation="horizontal"
android:paddingBottom="0dp"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:paddingTop="0dp">
<RadioButton
style="@style/AuthTabHeaderIndicator"
android:id="@+id/svpn_userAuth_tabheader"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_width="0dp"
android:text="@string/str_tab_sms"
android:checked="true"/>
</RadioGroup>
<LinearLayout
android:background="@drawable/shape_corner"
android:id="@+id/svpn_userAuth_layout"
android:layout_gravity="center_vertical"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:orientation="vertical">
<com.rehome.zhdcoa.weiget.SFEditText
android:id="@+id/svpn_username_editView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@null"
android:drawableLeft="@mipmap/icon_user"
android:drawablePadding="15dp"
android:hint="手机号"
android:textSize="16dp"
android:paddingBottom="10dp"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:paddingTop="10dp"
android:singleLine="true"/>
</LinearLayout>
</LinearLayout>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

@ -36,6 +36,15 @@
<item>新增信息</item>
</string-array>
<string-array name="extra_resource_url">
<item>https://www.test-ipv6.com</item>
<item>https://www.baidu.com</item>
<item>https://www.taobao.com</item>
<item>https://www.qq.com</item>
<item>https://www.sina.com.cn</item>
<item>https://vpn.zhp.geg.com.cn</item>
</string-array>
<declare-styleable name="CanBanScrollViewPager">
<attr name="isScroll" format="boolean" />
</declare-styleable>

@ -76,5 +76,8 @@
<color name="e3">#24B56C</color>
<color name="e4">#2479E4</color>
<color name="lightgray">#90505050</color>
<color name="lightred">#90FF0000</color>
</resources>

@ -54,5 +54,46 @@
<string name="shanke_sign">签到</string>
<string name="shan_please_sign">请扫描二维码进行签到</string>
<string name="agree">同意</string>
<string name="disagree">拒绝</string>
<string name="request_session_can_you_agree">"'%s'申请获取'%s'的网关登录信息,是否同意?"</string>
<string name="str_svpn_ip">IP</string>
<string name="str_svpn_port">443</string>
<string name="str_tab_sms">短信主认证</string>
<string name="auth_success">认证成功</string>
<string name="str_commit">提交</string>
<string name="str_cancel">取消</string>
<string name="get_phone_number_failed">手机号:无法获取</string>
<string name="phone_number">手机号:</string>
<string name="str_no_policy">暂无相关密码策略</string>
<string name="str_policy_hint">密码策略:</string>
<string name="str_after_time_resend">秒后重新发送</string>
<string name="str_resend">重新发送</string>
<string name="after_time_resend">秒后重新发送</string>
<string name="reget_sms_code_success">重新获取短信验证码成功</string>
<string name="reget_sms_code_failed">重新获取短信验证码失败,失败信息: </string>
<string name="waiting">请稍候...</string>
<string name="info">提示</string>
<string name="update_app_ok">确认</string>
<string name="ok">确定</string>
<string name="str_tab_password">账号登录</string>
<string name="str_vpn_logout">注销vpn登录成功</string>
<string name="file_test">文件测试</string>
<string name="start_tunnel">启动隧道</string>
<string name="stop_tunnel">关闭隧道</string>
<string name="master_slave">主从测试</string>
<string name="atrust_auth">拉起aTrust认证测试</string>
<string name="launch_sub_app">启动子应用</string>
<string name="sub_app_pkg_name">请输入子应用包名</string>
<string name="use_user_intent">使用应用自定义的intent</string>
<string name="default_subapp_pkg_name">com.example.testapp</string>
<string name="udp_test">udp测试</string>
<string name="log_test">日志测试</string>
<string name="directory">目录</string>
<string name="modify_psw">修改密码</string>
<string name="str_intranet_resource">内网资源</string>
<string name="str_extranet_resource">外网资源</string>
<string name="str_proxy_domain">代理域名</string>
</resources>

@ -176,4 +176,20 @@
<item name="buttonCompat">?attr/listChoiceIndicatorSingleAnimated</item>
<item name="android:background">?attr/controlBackground</item>
</style>
<style name="AuthTabHeaderIndicator">
<item name="android:button">@android:color/transparent</item>
<item name="android:gravity">center</item>
<item name="android:textColor">@drawable/auth_tab_header_text</item>
<item name="android:textSize">20sp</item>
<item name="android:padding">10dp</item>
<item name="android:drawablePadding">8dp</item>
</style>
<style name="VPNSourceButtonIndicator">
<item name="android:button">@color/lightgray</item>
<item name="android:gravity">center</item>
<item name="android:textColor">@drawable/auth_tab_header_text</item>
<item name="android:textSize">20sp</item>
<item name="android:padding">10dp</item>
<item name="android:drawablePadding">8dp</item>
</style>
</resources>

Loading…
Cancel
Save