add activity-login: 增加登录模块,可成功从welcome跳转到登录页面

This commit is contained in:
free will committed 2021-06-28 20:53:03 +08:00
1 parent 34d3d506b6
commit fa47d323be
25 files changed
+989 -20

No files matched your search

+2 -1
View File
@@ -75,6 +75,7 @@ android {
}
dependencies {
implementation files('libs\\gmhelper.jar')
// testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
@@ -110,7 +111,7 @@ dependencies {
api project(path: ':locallib_quick_android:quick_android_custom_view')
api project(path: ':locallib_quick_android:quick_android_easy_bar')
api project(path: ':locallib_quick_android:quick_android_mvp')
api project(path: ':locallib_quick_android:quick_android_rx_permission')
// api project(path: ':locallib_quick_android:quick_android_rx_permission')
// api project(path: ':locallib_quick_android/quick_android_qrcode')
// api project(path: ':locallib_quick_android/quick_android_image_picker')
// api project(path: ':locallib_quick_android/quick_android_file_picker')
Binary file not shown.
+3
View File
@@ -21,6 +21,9 @@
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity
android:name=".activity.login.LoginActivity"
android:launchMode="singleTask" />
</application>
<!-- 以下为copy旧版本VPN的权限定义部分 -->
@@ -0,0 +1,5 @@
package com.pkusz.min_vpn_client;
public class GlobalSetting {
public static boolean openBiometric = false;
}
@@ -0,0 +1,253 @@
package com.pkusz.min_vpn_client.activity.login;
/*
* @Author: Wang Feng
* @Description:
* @Version: 1.0.0
* @Date: 19:45 2021/6/25
* @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
*/
import android.animation.Animator;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.google.android.material.checkbox.MaterialCheckBox;
import com.pkusz.min_vpn_client.GlobalSetting;
import com.pkusz.min_vpn_client.R;
import com.pkusz.min_vpn_client.activity.base.MINVpnBaseActivity;
import com.pkusz.min_vpn_client.activity.welcome.WelcomeActivity;
import com.pkusz.min_vpn_client.model.MINVpnAPI;
import com.pkusz.min_vpn_client.model.request.LoginRequest;
import com.pkusz.min_vpn_client.utils.AccountValidatorRegexUtil;
import com.pkusz.min_vpn_client.utils.Base64Util;
import com.pkusz.min_vpn_client.utils.DigestUtilKt;
import com.pkusz.min_vpn_client.utils.KeyManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
import br.com.simplepass.loadingbutton.customViews.CircularProgressButton;
import cn.qjm253.min_vpn.extensions.ActivityExtensionsKt;
import cn.qjm253.quick_android_base.GlideApp;
import cn.qjm253.quick_android_base.extensions.ContextExtensionKt;
import cn.qjm253.quick_android_base.extensions.ViewExtensionKt;
import cn.qjm253.quick_android_base.util.DisplayUtils;
import cn.qjm253.quick_android_custom_view.other.ClearAbleEditText;
import cn.qjm253.quick_android_easy_bar.EasyBar;
import cn.qjm253.quick_android_easy_bar.EasyBarExtensionsKt;
import kotlin.Unit;
import kotlin.jvm.functions.Function1;
public class LoginActivity extends MINVpnBaseActivity<LoginActivityPresenter>
implements LoginActivityContract.View{
// 常规变量区
private String username="";
private String password="";
// 界面变量区
private EasyBar easyBar;
private ImageView imageView_imgLogo;
private MaterialCheckBox savePasswordBox;
private TextView tvLoginWithSMS;
private TextView tvRegisterNow;
private TextView tvResetNow;
private ClearAbleEditText etUsername;
private CircularProgressButton btnLogin;
private ClearAbleEditText etPassword;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
// 初始化各个组件
easyBar=findViewById(R.id.easyBar);
imageView_imgLogo=findViewById(R.id.imgLogo);
savePasswordBox=findViewById(R.id.savePasswordBox);
tvLoginWithSMS = findViewById(R.id.tvLoginWithSMS);
tvRegisterNow=findViewById(R.id.tvRegisterNow);
tvResetNow=findViewById(R.id.tvResetNow);
etUsername=findViewById(R.id.etUsername);
btnLogin=findViewById(R.id.btnLogin);
etPassword=findViewById(R.id.etPassword);
initView();
}
private void initView(){
// 初始化bar
EasyBarExtensionsKt.init(easyBar, EasyBar.Mode.ICON, String.valueOf(R.string.login),
(Function1<View, Unit>) view -> {
System.out.println("假装跳转到扫码界面");
// ContextExtensionKt.jumpTo(LoginActivity.this, QRcodeScanActivity.class);
return null;
},
(Function1<View, Unit>) view -> {
System.out.println("假装跳转到设置界面");
// ContextExtensionKt.jumpTo(LoginActivity.this, SettingActivity.class);
return null;
},
R.drawable.scan, R.drawable.setting, "", "", -1,
true, R.color.white);
// glideapp
GlideApp.with(this)
.load(R.drawable.logo)
.circleCrop()
.into(imageView_imgLogo);
// 判断是否已登录
if(MINVpnAPI.INSTANCE.isLogin()){
savePasswordBox.setChecked(true);
}else{
savePasswordBox.setChecked(false);
}
// 监听是否验证码登录
tvLoginWithSMS.setOnClickListener(v -> {
System.out.println("假装跳转到验证码界面");
// ContextExtensionKt.jumpTo(this, LoginSMSActivity.class);
});
// 监听注册按钮
tvRegisterNow.setOnClickListener(v -> {
System.out.println("假装跳转到注册界面");
// ContextExtensionKt.jumpTo(this, LoginSMSActivity.class);
});
// 监听重置密码按钮
tvResetNow.setOnClickListener(v -> {
System.out.println("假装跳转到重置界面");
// ContextExtensionKt.jumpTo(this, LoginSMSActivity.class);
});
// 显示账号
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
etUsername.setText(Base64Util.Base64PlusDecode(MINVpnAPI.INSTANCE.getUsername()));
}else{
System.out.println("Base64Util.Base64PlusDecode error");
}
// 如果设置了密码保存,则显示密码
if(savePasswordBox.isChecked()){
etPassword.setText(MINVpnAPI.INSTANCE.getPassword());
}
// 登录按钮
btnLogin.setBackgroundResource(R.drawable.button_shape_default);
btnLogin.setOnClickListener(v->{
ContextExtensionKt.hideSoftKeyboard(this,btnLogin);
btnLogin.startAnimation();
this.username= Objects.requireNonNull(etUsername.getText()).toString();
this.password= Objects.requireNonNull(etPassword.getText()).toString();
if(username.isEmpty()||password.isEmpty()){
showWarning("请将信息填写完整");
btnLogin.revertAnimation();
return;
}
if(!AccountValidatorRegexUtil.INSTANCE.isPassword(password)){
showWarning("请输入有效的密码,密码为8-16位,必须包含大小写字母和特殊符号");
btnLogin.revertAnimation();
return;
}
if(!AccountValidatorRegexUtil.INSTANCE.isUsername(username)){
showWarning("请输入有效的用户名,用户名长度需要大于0小于20");
btnLogin.revertAnimation();
return;
}
// 账号转base64
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
username=Base64Util.Base64PlusEncode(username);
}else{
System.out.println("Base64Util.Base64PlusDecode error");
}
// 初始化keymanager
KeyManager.INSTANCE.initKeyChain("/"+username);
// 登录server(密码转md5)
LoginRequest loginRequest=new LoginRequest();
loginRequest.Prefix="/"+username;
loginRequest.Password= DigestUtilKt.encodeToMD5(password);
if(GlobalSetting.openBiometric){
// 第一种模式,人脸识别登录,暂时废弃
// mPresenter.downloadRegisterFacePicture(username,loginRequest,this);
}else{
mPresenter.login(loginRequest);
}
});
// 监听键盘是否弹起
ActivityExtensionsKt.listenKeyboardVisible(this,(isOpen)->{
if(isOpen){
ViewExtensionKt.animer(imageView_imgLogo,
ViewExtensionKt.scaleXAnimation(imageView_imgLogo,1f, 0.5f),
ViewExtensionKt.scaleYAnimation(imageView_imgLogo,1f, 0.5f),
ViewExtensionKt.transYAnimation(imageView_imgLogo,
0f, -DisplayUtils.dp2px(this, 40)),
ViewExtensionKt.transYAnimation(etUsername,
0f, -DisplayUtils.dp2px(this, 90)),
ViewExtensionKt.transYAnimation(etPassword,
0f, -DisplayUtils.dp2px(this, 90)),
ViewExtensionKt.transYAnimation(btnLogin,
0f, -DisplayUtils.dp2px(this, 90)));
}else{
ViewExtensionKt.animer(imageView_imgLogo,
ViewExtensionKt.scaleXAnimation(imageView_imgLogo,0.5f, 1f),
ViewExtensionKt.scaleYAnimation(imageView_imgLogo,0.5f, 1f),
ViewExtensionKt.transYAnimation(imageView_imgLogo,
0f, -DisplayUtils.dp2px(this, 40),0f),
ViewExtensionKt.transYAnimation(etUsername,
0f, -DisplayUtils.dp2px(this, 90),0f),
ViewExtensionKt.transYAnimation(etPassword,
0f, -DisplayUtils.dp2px(this, 90),0f),
ViewExtensionKt.transYAnimation(btnLogin,
0f, -DisplayUtils.dp2px(this, 90),0f));
}
return null;
});
}
@NotNull
@Override
public LoginActivityPresenter onCreatePresenter() {
return new LoginActivityPresenter(this);
}
@Override
public void loginSuccess() {
loginSuccess("登录成功");
}
@Override
public void loginSuccess(String successMsg) {
showSuccess(successMsg);
MINVpnAPI.INSTANCE.updateUsername(username);
if(savePasswordBox.isChecked()){
MINVpnAPI.INSTANCE.updatePassword(password);
}else{
MINVpnAPI.INSTANCE.updatePassword("");
}
btnLogin.revertAnimation();
System.out.println("假装跳转到了Main");
// ContextExtensionKt.jumpTo(this, .class);
finish();
}
@Override
public void loginFailed(String errMsg) {
showWarning("登录失败: "+errMsg);
btnLogin.revertAnimation();
}
}
@@ -0,0 +1,39 @@
package com.pkusz.min_vpn_client.activity.login;
/*
* @Author: Wang Feng
* @Description:
* @Version: 1.0.0
* @Date: 16:28 2021/6/28
* @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
*/
import android.content.Context;
import com.pkusz.min_vpn_client.activity.base.MINVpnBaseView;
import com.pkusz.min_vpn_client.model.request.LoginRequest;
import cn.qjm253.quick_android_mvp.base.mvp.BaseModel;
import cn.qjm253.quick_android_mvp.base.mvp.BasePresenter;
public interface LoginActivityContract {
interface View extends MINVpnBaseView {
void loginSuccess();
void loginSuccess(String successMsg);
void loginFailed(String errMsg);
}
interface Model extends BaseModel {
void login(LoginRequest loginRequest);
void loginWithSafetyInfo(LoginRequest loginRequest, Context context);
void downloadRegisterFacePicture(String username,LoginRequest loginRequest, Context context);
}
abstract class Presenter extends BasePresenter<LoginActivityContract.View, LoginActivityContract.Model> {
void loginSuccess(){};
void loginSuccess(String successMsg){};
void loginFailed(String errMsg){};
void login(LoginRequest loginRequest){};
void loginWithSafetyInfo(LoginRequest loginRequest, Context context){};
void downloadRegisterFacePicture(String username,LoginRequest loginRequest, Context context){};
}
}
@@ -0,0 +1,52 @@
package com.pkusz.min_vpn_client.activity.login;
/*
* @Author: Wang Feng
* @Description:
* @Version: 1.0.0
* @Date: 16:37 2021/6/28
* @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
*/
import android.content.Context;
import com.pkusz.min_vpn_client.model.Request_API;
import com.pkusz.min_vpn_client.model.request.LoginRequest;
import common.LoggerHelper;
public class LoginActivityModel implements LoginActivityContract.Model{
private LoginActivityPresenter mPresenter;
public LoginActivityModel(LoginActivityPresenter presenter){
this.mPresenter=presenter;
}
@Override
public void login(LoginRequest loginRequest) {
// 与MIS通信,获取返回信息
// Request_API.INSTANCE.login()
// 假定成功登录,则执行下面语句
boolean flag=true;
if(flag){
mPresenter.loginSuccess();
}else{
mPresenter.loginFailed("测试登录失败...");
}
}
@Override
public void loginWithSafetyInfo(LoginRequest loginRequest, Context context) {
// 内含百度定位、mac地址等信息
boolean flag=true;
if(flag){
mPresenter.loginSuccess();
}else{
mPresenter.loginFailed("测试登录失败...");
}
}
@Override
public void downloadRegisterFacePicture(String username, LoginRequest loginRequest, Context context) {
LoggerHelper.warning("model.downloadRegisterFacePicture: 暂停人脸识别登录功能");
}
}
@@ -0,0 +1,49 @@
package com.pkusz.min_vpn_client.activity.login;
/*
* @Author: Wang Feng
* @Description:
* @Version: 1.0.0
* @Date: 16:35 2021/6/28
* @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
*/
import android.content.Context;
import com.pkusz.min_vpn_client.model.request.LoginRequest;
public class LoginActivityPresenter extends LoginActivityContract.Presenter{
public LoginActivityPresenter(LoginActivity loginActivity){
mView=loginActivity;
mModel=new LoginActivityModel(this);
}
@Override
void loginSuccess() {
mView.loginSuccess();
}
@Override
void loginSuccess(String successMsg) {
mView.loginSuccess(successMsg);
}
@Override
void loginFailed(String errMsg) {
mView.loginFailed(errMsg);
}
@Override
void login(LoginRequest loginRequest) {
mModel.login(loginRequest);
}
@Override
void loginWithSafetyInfo(LoginRequest loginRequest, Context context) {
mModel.loginWithSafetyInfo(loginRequest, context);
}
@Override
void downloadRegisterFacePicture(String username, LoginRequest loginRequest, Context context) {
mModel.downloadRegisterFacePicture(username, loginRequest, context);
}
}
@@ -8,28 +8,34 @@ package com.pkusz.min_vpn_client.activity.welcome;
*/
import android.os.Bundle;
import android.os.PersistableBundle;
import android.widget.ImageView;
import androidx.annotation.Nullable;
import com.pkusz.min_vpn_client.R;
import com.pkusz.min_vpn_client.activity.base.MINVpnBaseActivity;
import com.pkusz.min_vpn_client.extensions.FileUtilsExtensions;
import com.pkusz.min_vpn_client.activity.login.LoginActivity;
import org.jetbrains.annotations.NotNull;
import cn.qjm253.min_vpn.extensions.FileUtilsExtensionsKt;
import cn.qjm253.quick_android_base.GlideApp;
import cn.qjm253.quick_android_base.QuickAndroid;
import cn.qjm253.quick_android_base.extensions.ContextExtensionKt;
import cn.qjm253.quick_android_base.util.FileUtils;
import cn.qjm253.quick_android_mvp.base.mvp.BaseView;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.plugins.RxJavaPlugins;
public class WelcomeActivity extends MINVpnBaseActivity<WelcomeActivityPresenter>
implements WelcomeActivityContract.View{
ImageView imageView_imgLogo;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_welcome);
imageView_imgLogo=findViewById(R.id.imgLogo);
}
@Override
@@ -48,7 +54,45 @@ public class WelcomeActivity extends MINVpnBaseActivity<WelcomeActivityPresenter
}
public void fingerprintAuthenticate(){
System.out.println("指纹验证...");
System.out.println("指纹验证 ing...");
// todo: 指纹验证
System.out.println("指纹验证 success");
initView();
}
private void initView(){
GlideApp.with(this)
.load(R.drawable.logo)
.circleCrop()
.into(imageView_imgLogo);
imageView_imgLogo.setScaleX(0.5f);
imageView_imgLogo.setScaleY(1.1f);
String[] premissions= new String[]{
android.Manifest.permission.WRITE_EXTERNAL_STORAGE,
android.Manifest.permission.READ_EXTERNAL_STORAGE,
android.Manifest.permission.FOREGROUND_SERVICE,
android.Manifest.permission.ACCESS_FINE_LOCATION,
android.Manifest.permission.READ_PHONE_STATE,
android.Manifest.permission.ACCESS_WIFI_STATE,
android.Manifest.permission.INTERNET,
android.Manifest.permission.ACCESS_COARSE_LOCATION,
android.Manifest.permission.CAMERA
};
boolean b = imageView_imgLogo.postDelayed(() -> {
Disposable disp = QuickAndroid.INSTANCE.createRxPermission(WelcomeActivity.this)
.request(premissions, "请求权限")
.subscribe(quickAndroidRxPermissionItem -> {
if (quickAndroidRxPermissionItem.getGranted()) {
System.out.println("开始跳转");
ContextExtensionKt.jumpTo(WelcomeActivity.this,LoginActivity.class);
finish();
} else {
System.out.println("无跳转权限");
finish();
}
});
},600);
System.out.println("jump to login result: "+b);
}
@NotNull
@@ -0,0 +1,34 @@
package com.pkusz.min_vpn_client.model;
/*
* @Author: Wang Feng
* @Description:
* @Version: 1.0.0
* @Date: 17:23 2021/6/28
* @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
*/
public enum MINVpnAPI {
INSTANCE;
private String username="";
public boolean isLogin(){
return !username.equals("");
}
public String getUsername(){
return username;
}
public String getPassword(){
return "";
}
public void updateUsername(String username){
}
public void updatePassword(String password){
}
}
@@ -24,9 +24,10 @@ import logicface.LogicFace;
import logicface.LogicFaceException;
import packet.Interest;
public class Request_API {
public enum Request_API {
INSTANCE;
private boolean isConnected = false;
public LogicFace face = null;
private LogicFace face = null;
private String globalPrefix="/mis";
private boolean tcpTestFinished=false;
@@ -7,7 +7,7 @@ package com.pkusz.min_vpn_client.model.request;
* @Copyright: MIN-Group;国家重大科技基础设施——未来网络北大实验室;深圳市信息论与未来网络重点实验室
*/
public class LoginRequest {
public class LoginRequest extends BaseRequest{
// 继承属性
public String Type = BaseRequest.Type;
public String Command = "Login";
@@ -0,0 +1,176 @@
package com.pkusz.min_vpn_client.utils
import java.util.regex.Pattern
/**
* 账户相关属性验证工具
*/
object AccountValidatorRegexUtil {
/**
* 正则表达式:验证用户名
*/
val REGEX_USERNAME = "^[a-zA-Z]\\w{5,20}$"
/**
* 正则表达式:验证密码
*/
val REGEX_PASSWORD = "^(?=.*[A-Za-z])(?=.*\\d)(?=.*[\$@\$!%*.#?&])[A-Za-z\\d\$@\$!%*.#?&]{8,20}\$"
/* val REGEX_PASSWORD1 = "^((?![a-z]+$)(?![A-Z]+$)(?!\\d+$)(?![!@#$%^&*._-]+$)(?![a-zA-Z\\d]+$)(?![a-zA-Z!@#$%^&*._-]+$)(?![\\d!@#$%^&*._-]+$)[a-zA-Z\\d!@#$%^&*._-]+){8,20}$"
val REGEX_PASSWORD2 = ".*[A-Z]+.*"
val REGEX_PASSWORD3 = ".*[a-z]+.*"*/
/**
* 正则表达式:验证手机号
*/
val REGEX_MOBILE = "^1[3-9]\\d{9}\$"
/**
* 正则表达式:验证邮箱
*/
val REGEX_EMAIL = "^([a-z0-9A-Z]+[-|\\.]?)+[a-z0-9A-Z]@([a-z0-9A-Z]+(-[a-z0-9A-Z]+)?\\.)+[a-zA-Z]{2,}$"
/**
* 正则表达式:验证汉字
*/
val REGEX_CHINESE = "^[\u4e00-\u9fa5],{0,}$"
/**
* 正则表达式:验证身份证
*/
val REGEX_ID_CARD = "(^\\d{18}$)|(^\\d{15}$)"
/**
* 正则表达式:验证URL
*/
val REGEX_URL = "http(s)?://([\\w-]+\\.)+[\\w-]+(/[\\w- ./?%&=]*)?"
/**
* 正则表达式:验证IP地址
*/
val REGEX_IP_ADDR = "^(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[1-9])\\." + "(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\." + "(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\." + "(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)$"
/**
* 正则表达式:验证NDN前缀
*/
val REGEX_NDN_PREFIX = "(/([a-z]|[A-Z]|[0-9]|-|_){1,40}){1,10}"
/**
* 正则表达式:验证NDN前缀
*/
val REGEX_PORT = "([0-9]|[1-9]\\d{1,3}|[1-5]\\d{4}|6[0-4]\\d{3}|65[0-4]\\d{2}|655[0-2]\\d|6553[0-5])"
/**
* 校验用户名
*
* @param username
* @return 校验通过返回true,否则返回false
*/
fun isUsername(username: String): Boolean {
//return Pattern.matches(REGEX_USERNAME, username)
return username.length > 0 && username.length < 20
}
/**
* 校验密码
*
* @param password
* @return 校验通过返回true,否则返回false
*/
fun isPassword(password: String): Boolean {
/* return Pattern.matches(REGEX_PASSWORD1, password) && Pattern.matches(REGEX_PASSWORD2, password)
&& Pattern.matches(REGEX_PASSWORD3, password)*/
return Pattern.matches(REGEX_PASSWORD, password)
}
/**
* 校验手机号
*
* @param mobile
* @return 校验通过返回true,否则返回false
*/
fun isMobile(mobile: String): Boolean {
return Pattern.matches(REGEX_MOBILE, mobile)
}
/**
* 校验邮箱
*
* @param email
* @return 校验通过返回true,否则返回false
*/
fun isEmail(email: String): Boolean {
return Pattern.matches(REGEX_EMAIL, email)
}
/**
* 校验汉字
*
* @param chinese
* @return 校验通过返回true,否则返回false
*/
fun isChinese(chinese: String): Boolean {
return Pattern.matches(REGEX_CHINESE, chinese)
}
/**
* 校验身份证
*
* @param idCard
* @return 校验通过返回true,否则返回false
*/
fun isIDCard(idCard: String): Boolean {
return Pattern.matches(REGEX_ID_CARD, idCard)
}
/**
* 校验URL
*
* @param url
* @return 校验通过返回true,否则返回false
*/
fun isUrl(url: String): Boolean {
return Pattern.matches(REGEX_URL, url)
}
/**
* 校验IP地址
*
* @param ipAddr
* @return
*/
fun isIPAddr(ipAddr: String): Boolean {
return Pattern.matches(REGEX_IP_ADDR, ipAddr)
}
/**
* 校验NDN前缀
*
* @param ndnPrefix
* @return
*/
fun isndnPrefix(ndnPrefix: String): Boolean {
return Pattern.matches(REGEX_NDN_PREFIX, ndnPrefix)
}
/**
* 校验端口号
*
* @param ndnPrefix
* @return
*/
fun isPort(port: String): Boolean {
return Pattern.matches(REGEX_PORT, port)
}
/**
* 校验端口号
*
* @param ndnPrefix
* @return
*/
fun isInviteCode(invitecode: String): Boolean {
return invitecode.length > 0 && invitecode.length < 20
}
}
@@ -0,0 +1,47 @@
package com.pkusz.min_vpn_client.utils;
import android.os.Build;
import androidx.annotation.RequiresApi;
import java.io.UnsupportedEncodingException;
import java.util.Base64;
public class Base64Util {
@RequiresApi(api = Build.VERSION_CODES.O)
public static String Base64PlusEncode(String srcStr){
String dstStr = "" ;
try {
dstStr = Base64.getMimeEncoder().encodeToString(srcStr.getBytes("utf-8"));
} catch (UnsupportedEncodingException e) {
return dstStr ;
}
dstStr = dstStr.replaceAll("=","-").replaceAll("/","_") ;
return dstStr;
}
@RequiresApi(api = Build.VERSION_CODES.O)
public static String Base64PlusDecode(String srcStr){
srcStr = srcStr.replaceAll("_","/").replaceAll("-","=") ;
byte[] dstStrByte = null;
try {
dstStrByte = Base64.getMimeDecoder().decode(srcStr.getBytes("utf-8"));
} catch (UnsupportedEncodingException e) {
return new String(dstStrByte) ;
}
return new String(dstStrByte);
}
public static String BlocChainEncode(String srcStr) {
String dstStr = "" ;
try {
//dstStr = Base64.getMimeEncoder().encodeToString(srcStr.getBytes("utf-8"));
dstStr = android.util.Base64.encodeToString(srcStr.getBytes("utf-8"),
android.util.Base64.NO_WRAP | android.util.Base64.NO_PADDING | android.util.Base64.URL_SAFE);
} catch (UnsupportedEncodingException e) {
return dstStr ;
}
return dstStr;
}
}
@@ -0,0 +1,69 @@
package com.pkusz.min_vpn_client.utils
import org.zz.gmhelper.SM3Util
import java.security.MessageDigest
import java.security.NoSuchAlgorithmException
object DigestUtil {
fun md5(message: String) {
val digest = MessageDigest.getInstance("MD5")
digest.update(message.toByte())
digest.digest()
}
}
fun String.encodeToMD5(): String {
try {
//获取md5加密对象
val instance: MessageDigest = MessageDigest.getInstance("MD5")
//对字符串加密,返回字节数组
val digest: ByteArray = instance.digest(this.toByteArray())
val sb = StringBuffer()
for (b in digest) {
//获取低八位有效值
val i: Int = b.toInt() and 0xff
//将整数转化为16进制
var hexString = Integer.toHexString(i)
if (hexString.length < 2) {
//如果是一位的话,补0
hexString = "0$hexString"
}
sb.append(hexString)
}
return sb.toString()
} catch (e: NoSuchAlgorithmException) {
e.printStackTrace()
}
return ""
}
fun String.encodeToSM3(): String {
try {
// //获取md5加密对象
// val instance: MessageDigest = MessageDigest.getInstance("MD5")
// //对字符串加密,返回字节数组
val digest:ByteArray = SM3Util.hash(this.toByteArray())
//val digest: ByteArray = instance.digest(this.toByteArray())
val sb = StringBuffer()
for (b in digest) {
//获取低八位有效值
val i: Int = b.toInt() and 0xff
//将整数转化为16进制
var hexString = Integer.toHexString(i)
if (hexString.length < 2) {
//如果是一位的话,补0
hexString = "0$hexString"
}
sb.append(hexString)
}
return sb.toString()
} catch (e: NoSuchAlgorithmException) {
e.printStackTrace()
}
return ""
}
+1 -1
View File
@@ -5,7 +5,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="cn.qjm253.min_vpn.activity.login.LoginActivity">
tools:context=".activity.login.LoginActivity">
<include
android:id="@+id/include"
layout="@layout/bar_item" />
@@ -36,6 +36,7 @@ android {
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "androidx.appcompat:appcompat:${appcompact_version}"
// implementation project(path: ':locallib_quick_android:quick_android_rx_permission')
testImplementation "junit:junit:${junit_version}"
implementation "androidx.constraintlayout:constraintlayout:${constraintlayout_version}"
androidTestImplementation "androidx.test:runner:${test_runner_version}"
@@ -2,6 +2,8 @@ package cn.qjm253.quick_android_base
import android.app.Application
import android.content.Context
import androidx.fragment.app.FragmentActivity
import cn.qjm253.quick_android_rx_permission.QuickAndroidRxPermission
import com.github.anzewei.parallaxbacklayout.ParallaxHelper
import com.orhanobut.logger.AndroidLogAdapter
import com.orhanobut.logger.Logger
@@ -38,4 +40,8 @@ object QuickAndroid {
enableParallaxBack = true
return this
}
fun createRxPermission(activity: FragmentActivity): QuickAndroidRxPermission {
return QuickAndroidRxPermission.create(activity)
}
}
@@ -39,15 +39,22 @@ fun Context.jumpTo(cls: Class<*>, vararg flags: Int) {
startActivity(intent)
}
//fun jumpTo(vararg cls: Class<*>) {
// val intent = Intent(this, cls)
// flags.forEach {
// intent.addFlags(it)
// }
// startActivity(intent)
//}
fun Context.jumpTo(cls: Class<*>, intentParam: IntentParam? = null, vararg flags: Int) {
val intent = Intent(this, cls)
flags.forEach {
intent.addFlags(it)
}
intentParam?.applyParam(intent)
startActivity(intent)
}
//fun Context.jumpTo(cls: Class<*>, intentParam: IntentParam? = null, vararg flags: Int) {
// val intent = Intent(this, cls)
// flags.forEach {
// intent.addFlags(it)
// }
// intentParam?.applyParam(intent)
// startActivity(intent)
//}
fun Activity.jumpForResult(cls: Class<*>, requestCode: Int = 0, intentParam: IntentParam? = null) {
val intent = Intent(this, cls)
@@ -146,4 +153,3 @@ fun Context.checkMyPermission(permission: String, granted: () -> Unit = {}, deny
private fun autoGenericCode(code: String, num: Int): String {
return String.format("%0" + num + "d", Integer.parseInt(code))
}
@@ -37,7 +37,7 @@ private fun <T: Fragment> getFragment(tag: String, clazz: Class<T>, fragmentMana
fragmentManager
.beginTransaction()
.add(fragment, tag)
.commitNow()
.commitNowAllowingStateLoss()
}
return fragment!!
}
@@ -108,7 +108,28 @@ fun View.animer(vararg animations: ObjectAnimator, duration: Long, listener: Ani
if (listener != null)
animatorSet.addListener(listener)
animatorSet.start()
}
fun View.animer(vararg animations: ObjectAnimator, duration: Long) {
if (animations.isEmpty())
return
val animatorSet = AnimatorSet()
val builder = animatorSet.setDuration(duration)
.play(animations[0])
animations.filterIndexed { index, _ -> index != 0 }
.forEach { builder.with(it) }
animatorSet.start()
}
fun View.animer(vararg animations: ObjectAnimator) {
if (animations.isEmpty())
return
val animatorSet = AnimatorSet()
val builder = animatorSet.setDuration(200)
.play(animations[0])
animations.filterIndexed { index, _ -> index != 0 }
.forEach { builder.with(it) }
animatorSet.start()
}
/**
@@ -120,4 +141,4 @@ fun View.transRotateAlpha(transX: FloatArray = floatArrayOf(0f, 0f), transY: Flo
listener: Animator.AnimatorListener? = null) {
this.animer(transXAnimation(*transX), transYAnimation(*transY), rotationAnimation(*rotation),
alphaAnimation(*alpha), duration = duration, listener = listener)
}
}
@@ -0,0 +1,69 @@
package cn.qjm253.quick_android_rx_permission
// 迁移过来代码
import androidx.annotation.StringRes
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import cn.qjm253.quick_android_base.QuickAndroid
import cn.qjm253.quick_android_base.extensions.getLazySingleton
import cn.qjm253.quick_android_base.util.RxSchedulersHelper
import io.reactivex.Observable
/**
* @author SunnyQjm
* @date 19-7-8 上午9:03
*/
class QuickAndroidRxPermission {
companion object {
const val TAG = "QuickAndroidRxPermission"
fun create(activity: FragmentActivity): QuickAndroidRxPermission {
return QuickAndroidRxPermission(activity)
}
fun create(fragment: Fragment): QuickAndroidRxPermission {
return QuickAndroidRxPermission(fragment)
}
}
private var mRxPermissionFragment: Lazy<QuickAndroidRxPermissionFragment>
private var requestCode = 0
constructor(activity: FragmentActivity) {
mRxPermissionFragment = activity.supportFragmentManager
.getLazySingleton(TAG, QuickAndroidRxPermissionFragment::class.java)
}
constructor(fragment: Fragment) {
mRxPermissionFragment = fragment.childFragmentManager
.getLazySingleton(TAG, QuickAndroidRxPermissionFragment::class.java)
}
fun request(permissions: Array<String>, @StringRes tip: Int): Observable<QuickAndroidRxPermissionItem> {
requestCode++
return mRxPermissionFragment.value.requestPermissions(permissions, tip, requestCode)
.compose(RxSchedulersHelper.io_main())
}
fun request(permissions: Array<String>, tip: String = "请求权限"): Observable<QuickAndroidRxPermissionItem> {
requestCode++
return mRxPermissionFragment.value.requestPermissions(permissions, tip, requestCode)
.compose(RxSchedulersHelper.io_main())
}
// fun request(strings: Array<String>): Any {
//
// }
}
//////////////////////////////////////////////////////////
////////// QuickAndroid 扩展
//////////////////////////////////////////////////////////
fun QuickAndroid.createRxPermission(activity: FragmentActivity): QuickAndroidRxPermission {
return QuickAndroidRxPermission.create(activity)
}
fun QuickAndroid.createRxPermission(fragment: Fragment): QuickAndroidRxPermission {
return QuickAndroidRxPermission.create(fragment)
}
@@ -0,0 +1,77 @@
package cn.qjm253.quick_android_rx_permission
import android.os.Bundle
import androidx.annotation.StringRes
import androidx.fragment.app.Fragment
import io.reactivex.Observable
import io.reactivex.ObservableEmitter
import pub.devrel.easypermissions.EasyPermissions
/**
* @author SunnyQjm
* @date 19-7-8 上午9:13
*/
class QuickAndroidRxPermissionFragment : Fragment(), EasyPermissions.PermissionCallbacks {
private val permissionsMap =
mutableMapOf<Int, ObservableEmitter<QuickAndroidRxPermissionItem>>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
retainInstance = true
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this)
}
/**
* 授权成功
*/
override fun onPermissionsGranted(requestCode: Int, perms: MutableList<String>) {
permissionsMap[requestCode]?.let {
it.onNext(QuickAndroidRxPermissionItem(true, requestCode, perms))
it.onComplete()
permissionsMap.remove(requestCode)
}
}
/**
* 授权失败
*/
override fun onPermissionsDenied(requestCode: Int, perms: MutableList<String>) {
permissionsMap[requestCode]?.let {
it.onNext(QuickAndroidRxPermissionItem(false, requestCode, perms))
it.onComplete()
permissionsMap.remove(requestCode)
}
}
/**
* 请求权限
*/
fun requestPermissions(permissions: Array<String>, @StringRes tip: Int, requestCode: Int)
: Observable<QuickAndroidRxPermissionItem> {
return requestPermissions(permissions, getString(tip), requestCode)
}
fun requestPermissions(permissions: Array<String>, tip: String, requestCode: Int)
: Observable<QuickAndroidRxPermissionItem> {
return Observable.create { emitter ->
permissionsMap[requestCode] = emitter
activity?.let {
if (EasyPermissions.hasPermissions(it, *permissions)) {
onPermissionsGranted(requestCode, permissions.toMutableList())
} else {
EasyPermissions.requestPermissions(this, tip, requestCode, *permissions)
}
}
}
}
}
@@ -0,0 +1,12 @@
package cn.qjm253.quick_android_rx_permission
/**
* @author SunnyQjm
* @date 19-7-8 上午9:34
*/
class QuickAndroidRxPermissionItem(
val granted: Boolean,
val requestCode: Int,
val perms: MutableList<String>
)
@@ -51,6 +51,10 @@ class QuickAndroidRxPermission {
return mRxPermissionFragment.value.requestPermissions(permissions, tip, requestCode)
.compose(RxSchedulersHelper.io_main())
}
// fun request(strings: Array<String>): Any {
//
// }
}
//////////////////////////////////////////////////////////