feat: 获取加密激活码
This commit is contained in:
@@ -17,8 +17,8 @@ android {
|
||||
minSdkVersion 23
|
||||
targetSdkVersion 29
|
||||
|
||||
versionCode 36
|
||||
versionName "1.3.5"
|
||||
versionCode 39
|
||||
versionName "1.3.8"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
|
||||
@@ -135,7 +135,7 @@ public class ActivationActivity extends BaseMvvmActivity<ActivationViewModel, Ac
|
||||
@Override
|
||||
public void onChanged(Boolean aBoolean) {
|
||||
if (aBoolean) {
|
||||
mViewModel.getActivation();
|
||||
mViewModel.getEncryptedCode();
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -227,7 +227,7 @@ public class ActivationActivity extends BaseMvvmActivity<ActivationViewModel, Ac
|
||||
.observeOn(AndroidSchedulers.mainThread()) // 在主线程处理结果
|
||||
.subscribe(tick -> {
|
||||
// 此处执行轮询任务,例如网络请求
|
||||
mViewModel.getActivation();
|
||||
mViewModel.getEncryptedCode();
|
||||
}, throwable -> {
|
||||
// 处理错误
|
||||
throwable.printStackTrace();
|
||||
|
||||
@@ -8,6 +8,7 @@ import com.hjq.toast.Toaster;
|
||||
import com.tencent.mmkv.MMKV;
|
||||
import com.trello.rxlifecycle4.RxLifecycle;
|
||||
import com.trello.rxlifecycle4.android.ActivityEvent;
|
||||
import com.xwad.os.BuildConfig;
|
||||
import com.xwad.os.base.mvvm.BaseViewModel;
|
||||
import com.xwad.os.bean.BaseResponse;
|
||||
import com.xwad.os.bean.CodeBean;
|
||||
@@ -153,16 +154,19 @@ public class ActivationViewModel extends BaseViewModel<ActivityActivationBinding
|
||||
public void codeActivation(String code) {
|
||||
NetInterfaceManager.getInstance().getCodeActivationControl(code)
|
||||
.compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
|
||||
.subscribe(new Observer<BaseResponse>() {
|
||||
.subscribe(new Observer<BaseResponse<CodeBean>>() {
|
||||
@Override
|
||||
public void onSubscribe(@NonNull Disposable d) {
|
||||
Log.e("codeActivation", "onSubscribe: ");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(@NonNull BaseResponse baseResponse) {
|
||||
public void onNext(@NonNull BaseResponse<CodeBean> baseResponse) {
|
||||
Log.e("codeActivation", "onNext: " + baseResponse);
|
||||
if (baseResponse.code == 200) {
|
||||
CodeBean codeBean = baseResponse.data;
|
||||
ActivationUtil.getInstance().setActivationCode(codeBean.getCode());
|
||||
ActivationUtil.getInstance().setActivation(1);
|
||||
mCodeActivationData.setValue(true);
|
||||
} else {
|
||||
Toaster.show(baseResponse.msg);
|
||||
@@ -183,6 +187,7 @@ public class ActivationViewModel extends BaseViewModel<ActivityActivationBinding
|
||||
|
||||
public MutableLiveData<Boolean> mGetCodeData = new MutableLiveData<>();
|
||||
|
||||
@Deprecated
|
||||
public void getActivation() {
|
||||
NetInterfaceManager.getInstance().getActivationCodeControl()
|
||||
.compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
|
||||
@@ -196,7 +201,7 @@ public class ActivationViewModel extends BaseViewModel<ActivityActivationBinding
|
||||
public void onNext(@NonNull BaseResponse<CodeBean> baseResponse) {
|
||||
if (baseResponse.code == 200) {
|
||||
CodeBean codeBean = baseResponse.data;
|
||||
mMMKV.encode(CommonConfig.ACTIVATIONBEAN_CODE_KEY, codeBean.getCode());
|
||||
ActivationUtil.getInstance().setActivationCode(codeBean.getCode());
|
||||
ActivationUtil.getInstance().setActivation(1);
|
||||
mGetCodeData.setValue(true);
|
||||
} else {
|
||||
@@ -216,6 +221,42 @@ public class ActivationViewModel extends BaseViewModel<ActivityActivationBinding
|
||||
});
|
||||
}
|
||||
|
||||
public void getEncryptedCode() {
|
||||
NetInterfaceManager.getInstance().getEncryptedActivationCodeControl()
|
||||
.compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
|
||||
.subscribe(new Observer<BaseResponse<CodeBean>>() {
|
||||
@Override
|
||||
public void onSubscribe(@NonNull Disposable d) {
|
||||
Log.e("getEncryptedCode", "onSubscribe: ");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(@NonNull BaseResponse<CodeBean> baseResponse) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.e("getEncryptedCode", "onNext: " + baseResponse);
|
||||
}
|
||||
if (baseResponse.code == 200) {
|
||||
CodeBean codeBean = baseResponse.data;
|
||||
ActivationUtil.getInstance().setActivationCode(codeBean.getCode());
|
||||
ActivationUtil.getInstance().setActivation(1);
|
||||
mGetCodeData.setValue(true);
|
||||
} else {
|
||||
ActivationUtil.getInstance().setActivation(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@NonNull Throwable e) {
|
||||
Log.e("getEncryptedCode", "onError: " + e.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
Log.e("getEncryptedCode", "onComplete: ");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public MutableLiveData<Boolean> mCouponsLegalData = new MutableLiveData<>();
|
||||
public MutableLiveData<String> mCouponsData = new MutableLiveData<>();
|
||||
|
||||
|
||||
@@ -264,7 +264,7 @@ public class HomeActivity extends BaseMvvmActivity<HomeViewModel, ActivityHomeBi
|
||||
}
|
||||
}
|
||||
});
|
||||
mViewModel.getActivation();
|
||||
mViewModel.getEncryptedCode();
|
||||
mViewModel.mUserInfoData.observe(this, new Observer<UserInfo>() {
|
||||
@Override
|
||||
public void onChanged(UserInfo userInfo) {
|
||||
|
||||
@@ -114,7 +114,7 @@ public class HomeViewModel extends BaseViewModel<ActivityHomeBinding, ActivityEv
|
||||
ControlManager.getInstance().setSystemSetting(systemSettings);
|
||||
mMMKV.encode(CommonConfig.APP_INSTALLATION, systemSettings.getSetting_other_appInstaller());
|
||||
mSystemSettingsMutableLiveData.setValue(systemSettings);
|
||||
}else {
|
||||
} else {
|
||||
ControlManager.getInstance().setDisableSetting();
|
||||
}
|
||||
}
|
||||
@@ -147,8 +147,8 @@ public class HomeViewModel extends BaseViewModel<ActivityHomeBinding, ActivityEv
|
||||
public void onNext(@NonNull BaseResponse<AppInfo> appUpdateInfoBaseResponse) {
|
||||
Log.e("checkUpdate", "onNext: " + appUpdateInfoBaseResponse);
|
||||
if (appUpdateInfoBaseResponse.code == 200) {
|
||||
AppInfo appUpdateInfo = appUpdateInfoBaseResponse.data;
|
||||
mAppUpdateInfoData.setValue(appUpdateInfo);
|
||||
AppInfo appInfo = appUpdateInfoBaseResponse.data;
|
||||
mAppUpdateInfoData.setValue(appInfo);
|
||||
} else {
|
||||
mAppUpdateInfoData.setValue(null);
|
||||
}
|
||||
@@ -175,12 +175,12 @@ public class HomeViewModel extends BaseViewModel<ActivityHomeBinding, ActivityEv
|
||||
.subscribe(new Observer<BaseResponse<AppUpdateInfo>>() {
|
||||
@Override
|
||||
public void onSubscribe(@NonNull Disposable d) {
|
||||
Log.e("checkUpdate", "onSubscribe: ");
|
||||
Log.e("checkUpdateUiUiOS", "onSubscribe: ");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(@NonNull BaseResponse<AppUpdateInfo> appUpdateInfoBaseResponse) {
|
||||
Log.e("checkUpdate", "onNext: " + appUpdateInfoBaseResponse);
|
||||
Log.e("checkUpdateUiUiOS", "onNext: " + appUpdateInfoBaseResponse);
|
||||
if (appUpdateInfoBaseResponse.code == 200) {
|
||||
AppUpdateInfo appUpdateInfo = appUpdateInfoBaseResponse.data;
|
||||
mAppUpdateInfoUiUiOSData.setValue(appUpdateInfo);
|
||||
@@ -191,13 +191,13 @@ public class HomeViewModel extends BaseViewModel<ActivityHomeBinding, ActivityEv
|
||||
|
||||
@Override
|
||||
public void onError(@NonNull Throwable e) {
|
||||
Log.e("checkUpdate", "onError: ");
|
||||
Log.e("checkUpdateUiUiOS", "onError: ");
|
||||
Toaster.show("网络连接失败");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
Log.e("checkUpdate", "onComplete: ");
|
||||
Log.e("checkUpdateUiUiOS", "onComplete: ");
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -280,6 +280,7 @@ public class HomeViewModel extends BaseViewModel<ActivityHomeBinding, ActivityEv
|
||||
|
||||
public MutableLiveData<Boolean> mGetCodeData = new MutableLiveData<>();
|
||||
|
||||
@Deprecated
|
||||
public void getActivation() {
|
||||
NetInterfaceManager.getInstance().getActivationCodeControl()
|
||||
.compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
|
||||
@@ -293,7 +294,7 @@ public class HomeViewModel extends BaseViewModel<ActivityHomeBinding, ActivityEv
|
||||
public void onNext(@NonNull BaseResponse<CodeBean> baseResponse) {
|
||||
if (baseResponse.code == 200) {
|
||||
CodeBean codeBean = baseResponse.data;
|
||||
mMMKV.encode(CommonConfig.ACTIVATIONBEAN_CODE_KEY, codeBean.getCode());
|
||||
ActivationUtil.getInstance().setActivationCode(codeBean.getCode());
|
||||
mGetCodeData.setValue(true);
|
||||
ActivationUtil.getInstance().setActivation(1);
|
||||
} else {
|
||||
@@ -313,6 +314,42 @@ public class HomeViewModel extends BaseViewModel<ActivityHomeBinding, ActivityEv
|
||||
});
|
||||
}
|
||||
|
||||
public void getEncryptedCode() {
|
||||
NetInterfaceManager.getInstance().getEncryptedActivationCodeControl()
|
||||
.compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
|
||||
.subscribe(new Observer<BaseResponse<CodeBean>>() {
|
||||
@Override
|
||||
public void onSubscribe(@NonNull Disposable d) {
|
||||
Log.e("getEncryptedCode", "onSubscribe: ");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(@NonNull BaseResponse<CodeBean> baseResponse) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.e("getEncryptedCode", "onNext: " + baseResponse);
|
||||
}
|
||||
if (baseResponse.code == 200) {
|
||||
CodeBean codeBean = baseResponse.data;
|
||||
ActivationUtil.getInstance().setActivationCode(codeBean.getCode());
|
||||
ActivationUtil.getInstance().setActivation(1);
|
||||
mGetCodeData.setValue(true);
|
||||
} else {
|
||||
ActivationUtil.getInstance().setActivation(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@NonNull Throwable e) {
|
||||
Log.e("getEncryptedCode", "onError: " + e.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
Log.e("getEncryptedCode", "onComplete: ");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public MutableLiveData<UserInfo> mUserInfoData = new MutableLiveData<>();
|
||||
|
||||
public void getUserInfo() {
|
||||
|
||||
26
app/src/main/java/com/xwad/os/bean/UserExpireInfo.java
Normal file
26
app/src/main/java/com/xwad/os/bean/UserExpireInfo.java
Normal file
@@ -0,0 +1,26 @@
|
||||
package com.xwad.os.bean;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class UserExpireInfo implements Serializable {
|
||||
private static final long serialVersionUID = 2733370887454572840L;
|
||||
|
||||
String expire_at;
|
||||
int year;
|
||||
|
||||
public String getExpire_at() {
|
||||
return expire_at;
|
||||
}
|
||||
|
||||
public void setExpire_at(String expire_at) {
|
||||
this.expire_at = expire_at;
|
||||
}
|
||||
|
||||
public int getYear() {
|
||||
return year;
|
||||
}
|
||||
|
||||
public void setYear(int year) {
|
||||
this.year = year;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.xwad.os.fragment.complex;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
@@ -7,8 +8,11 @@ import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.lifecycle.LifecycleEventObserver;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter;
|
||||
@@ -17,7 +21,9 @@ import androidx.viewpager2.widget.ViewPager2;
|
||||
import com.chad.library.adapter.base.BaseQuickAdapter;
|
||||
import com.chad.library.adapter.base.BaseViewHolder;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonSyntaxException;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.xwad.os.BuildConfig;
|
||||
import com.xwad.os.R;
|
||||
import com.xwad.os.base.mvvm.fragment.BaseMvvmFragment;
|
||||
import com.xwad.os.bean.jxw.TabBean;
|
||||
@@ -32,49 +38,47 @@ import org.greenrobot.eventbus.EventBus;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
import org.greenrobot.eventbus.ThreadMode;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A simple {@link Fragment} subclass.
|
||||
* Use the {@link ComplexFragment#newInstance} factory method to
|
||||
* create an instance of this fragment.
|
||||
* 复合Fragment(包含垂直ViewPager2+侧边Tab列表)
|
||||
* 核心功能:根据年级加载不同的学习阶段Fragment,支持年级切换刷新
|
||||
*/
|
||||
public class ComplexFragment extends BaseMvvmFragment<ComplexViewModel, FragmentComplexBinding> {
|
||||
private static final String TAG = "ComplexFragment";
|
||||
|
||||
private FragmentActivity mContext;
|
||||
|
||||
private MyAdapter adapter;
|
||||
private TabTbxAdapter tabTbxAdapter;
|
||||
private List<TabBean> tabBeanList = new ArrayList<>();
|
||||
private List<Fragment> mFragment = new ArrayList<>();
|
||||
|
||||
|
||||
// TODO: Rename parameter arguments, choose names that match
|
||||
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
|
||||
// 1. 抽取常量,消除硬编码
|
||||
private static final String TAG = ComplexFragment.class.getSimpleName();
|
||||
private static final String ARG_PARAM1 = "param1";
|
||||
private static final String ARG_PARAM2 = "param2";
|
||||
private static final int OFFSCREEN_PAGE_LIMIT = 5; // 预加载页数(保留原有逻辑)
|
||||
private static final String GRADE_PRIMARY_SCHOOL = "小学";
|
||||
private static final String ASSETS_TBX_JSON_PATH = "script/fragment_tbx.json";
|
||||
private static final int COLOR_WHITE = -1;
|
||||
private static final int COLOR_TAB_NORMAL = 1627389951;
|
||||
|
||||
// TODO: Rename and change types of parameters
|
||||
// 2. 优化上下文引用(避免内存泄漏)
|
||||
private WeakReference<FragmentActivity> mContextRef;
|
||||
private StageTabAdapter mStageTabAdapter; // 语义化命名:tabTbxAdapter → mStageTabAdapter
|
||||
private StageFragmentAdapter mStageFragmentAdapter; // 语义化命名:adapter → mStageFragmentAdapter
|
||||
private List<TabBean> mTabBeanList = new ArrayList<>();
|
||||
private int mSelectedTabPosition = -1; // 语义化命名:defSel → mSelectedTabPosition
|
||||
|
||||
// 页面参数(保留原有逻辑)
|
||||
private String mParam1;
|
||||
private String mParam2;
|
||||
|
||||
public ComplexFragment() {
|
||||
// Required empty public constructor
|
||||
Log.e(TAG, "ComplexFragment: ");
|
||||
super();
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.d(TAG, "ComplexFragment: 构造函数");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this factory method to create a new instance of
|
||||
* this fragment using the provided parameters.
|
||||
*
|
||||
* @param param1 Parameter 1.
|
||||
* @param param2 Parameter 2.
|
||||
* @return A new instance of fragment ComplexFragment.
|
||||
* 实例化Fragment(保留原有参数逻辑,增加注释)
|
||||
*/
|
||||
// TODO: Rename and change types and number of parameters
|
||||
public static ComplexFragment newInstance(String param1, String param2) {
|
||||
ComplexFragment fragment = new ComplexFragment();
|
||||
Bundle args = new Bundle();
|
||||
@@ -85,15 +89,24 @@ public class ComplexFragment extends BaseMvvmFragment<ComplexViewModel, Fragment
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (getArguments() != null) {
|
||||
mParam1 = getArguments().getString(ARG_PARAM1);
|
||||
mParam2 = getArguments().getString(ARG_PARAM2);
|
||||
}
|
||||
Log.e(TAG, "onCreate: ");
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.d(TAG, "onCreate: 参数param1=" + mParam1 + ", param2=" + mParam2);
|
||||
}
|
||||
// 3. 基于Lifecycle自动管理EventBus(避免手动解绑遗漏)
|
||||
getLifecycle().addObserver((LifecycleEventObserver) (source, event) -> {
|
||||
if (event == Lifecycle.Event.ON_DESTROY) {
|
||||
if (EventBus.getDefault().isRegistered(ComplexFragment.this)) {
|
||||
EventBus.getDefault().unregister(ComplexFragment.this);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected int getLayoutId() {
|
||||
@@ -102,201 +115,362 @@ public class ComplexFragment extends BaseMvvmFragment<ComplexViewModel, Fragment
|
||||
|
||||
@Override
|
||||
protected void initDataBinding() {
|
||||
mContext = getActivity();
|
||||
FragmentActivity activity = getActivity();
|
||||
if (activity != null) {
|
||||
mContextRef = new WeakReference<>(activity);
|
||||
}
|
||||
mViewModel.setCtx(getCtx());
|
||||
mViewModel.setLifecycle(getLifecycleSubject());
|
||||
mViewModel.setVDBinding(mViewDataBinding);
|
||||
// mViewDataBinding.setClick(new BtnClick());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initView(Bundle savedInstanceState) {
|
||||
// 注册EventBus(Lifecycle已管理解绑)
|
||||
if (!EventBus.getDefault().isRegistered(this)) {
|
||||
EventBus.getDefault().register(this);
|
||||
}
|
||||
|
||||
mViewDataBinding.subjectViewPager.setOffscreenPageLimit(10);
|
||||
mViewDataBinding.subjectViewPager.setUserInputEnabled(false);
|
||||
mViewDataBinding.subjectViewPager.setOrientation(ViewPager2.ORIENTATION_VERTICAL);
|
||||
mViewDataBinding.subjectViewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
mViewDataBinding.rvTitle.smoothScrollToPosition(position);
|
||||
}
|
||||
});
|
||||
|
||||
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext());
|
||||
linearLayoutManager.setOrientation(RecyclerView.VERTICAL);
|
||||
mViewDataBinding.rvTitle.setLayoutManager(linearLayoutManager);
|
||||
|
||||
tabTbxAdapter = new TabTbxAdapter(tabBeanList);
|
||||
adapter = new MyAdapter(mContext);
|
||||
|
||||
initViews();
|
||||
// 初始化ViewPager2(拆分方法,增强可读性)
|
||||
initViewPager2();
|
||||
// 初始化Tab列表RecyclerView
|
||||
initTabRecyclerView();
|
||||
// 初始化核心视图逻辑
|
||||
initStageView();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initData(Bundle savedInstanceState) {
|
||||
|
||||
// 保留原有空实现,增加注释说明
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fetchData() {
|
||||
Log.e(TAG, "fetchData: ");
|
||||
// initViews();
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.d(TAG, "fetchData: 触发数据加载");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
if (EventBus.getDefault().isRegistered(this)) {
|
||||
EventBus.getDefault().unregister(this);
|
||||
// 4. 资源释放优化:清空集合+置空适配器+解除引用
|
||||
if (mViewDataBinding != null) {
|
||||
mViewDataBinding.subjectViewPager.setAdapter(null);
|
||||
}
|
||||
mStageFragmentAdapter = null;
|
||||
mStageTabAdapter = null;
|
||||
mTabBeanList.clear();
|
||||
mContextRef = null;
|
||||
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.d(TAG, "onDestroyView: 视图销毁,资源已释放");
|
||||
}
|
||||
}
|
||||
|
||||
private void initViews() {
|
||||
if (mViewDataBinding == null) {
|
||||
return;
|
||||
// ========== 拆分的初始化方法(单一职责) ==========
|
||||
/**
|
||||
* 初始化ViewPager2配置
|
||||
*/
|
||||
private void initViewPager2() {
|
||||
if (mViewDataBinding == null) return;
|
||||
|
||||
ViewPager2 viewPager2 = mViewDataBinding.subjectViewPager;
|
||||
viewPager2.setOffscreenPageLimit(OFFSCREEN_PAGE_LIMIT);
|
||||
viewPager2.setUserInputEnabled(false);
|
||||
viewPager2.setOrientation(ViewPager2.ORIENTATION_VERTICAL);
|
||||
// 页面切换监听:Tab列表跟随滚动
|
||||
viewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
super.onPageSelected(position);
|
||||
mViewDataBinding.rvTitle.smoothScrollToPosition(position);
|
||||
}
|
||||
if ("小学".equals(Util.checkGrade(SPUtils.getGrade()))) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化Tab列表RecyclerView
|
||||
*/
|
||||
private void initTabRecyclerView() {
|
||||
if (mViewDataBinding == null) return;
|
||||
|
||||
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext());
|
||||
linearLayoutManager.setOrientation(RecyclerView.VERTICAL);
|
||||
mViewDataBinding.rvTitle.setLayoutManager(linearLayoutManager);
|
||||
|
||||
mStageTabAdapter = new StageTabAdapter(mTabBeanList);
|
||||
mViewDataBinding.rvTitle.setAdapter(mStageTabAdapter);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化核心业务视图(原initViews)
|
||||
*/
|
||||
private void initStageView() {
|
||||
if (mViewDataBinding == null) return;
|
||||
|
||||
String currentGrade = SPUtils.getGrade();
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.d(TAG, "initStageView: 当前年级=" + currentGrade);
|
||||
}
|
||||
|
||||
// 小学场景:显示专属布局,隐藏ViewPager2和Tab列表
|
||||
if (GRADE_PRIMARY_SCHOOL.equals(Util.checkGrade(currentGrade))) {
|
||||
mViewDataBinding.rlXx.setVisibility(View.VISIBLE);
|
||||
mViewDataBinding.subjectViewPager.setVisibility(View.GONE);
|
||||
mViewDataBinding.rvTitle.setVisibility(View.GONE);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
// 非小学场景:显示ViewPager2和Tab列表
|
||||
mViewDataBinding.rlXx.setVisibility(View.GONE);
|
||||
mViewDataBinding.subjectViewPager.setVisibility(View.VISIBLE);
|
||||
mViewDataBinding.rvTitle.setVisibility(View.VISIBLE);
|
||||
|
||||
// 获取学习阶段列表(增加空防护)
|
||||
List<LearnStageBean> learnStageList = getLearnStageList(currentGrade);
|
||||
if (learnStageList.isEmpty()) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.w(TAG, "initStageView: 学习阶段列表为空");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
tabBeanList.clear();
|
||||
mFragment.clear();
|
||||
for (LearnStageBean learnStageBean : getLearnStage()) {
|
||||
TabBean tabBean = new TabBean(learnStageBean.getName(),
|
||||
getResources().getIdentifier(learnStageBean.getNormal(), "drawable", mContext.getPackageName()),
|
||||
getResources().getIdentifier(learnStageBean.getPress(), "drawable", mContext.getPackageName()));
|
||||
tabBeanList.add(tabBean);
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString("subject", learnStageBean.getName());
|
||||
bundle.putString("label", learnStageBean.getLabel());
|
||||
bundle.putString("tbsp_tag", learnStageBean.getTbsp_tag());
|
||||
bundle.putBoolean("isBig", learnStageBean.getIsBig());
|
||||
try {
|
||||
Fragment fragment = (Fragment) Class.forName(learnStageBean.getClassName()).newInstance();
|
||||
fragment.setArguments(bundle);
|
||||
mFragment.add(fragment);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Log.e(TAG, "getLearnStage: " + e.getMessage());
|
||||
}
|
||||
// 更新Tab列表
|
||||
updateTabList(learnStageList);
|
||||
// 更新ViewPager2适配器
|
||||
updateViewPager2Adapter(learnStageList);
|
||||
// 设置默认选中项
|
||||
setDefaultSelectedTab();
|
||||
}
|
||||
|
||||
mViewDataBinding.rvTitle.setAdapter(tabTbxAdapter);
|
||||
mViewDataBinding.subjectViewPager.setAdapter(adapter);
|
||||
if (!tabBeanList.isEmpty()) {
|
||||
tabTbxAdapter.setChoosePosition(0);
|
||||
mViewDataBinding.subjectViewPager.setCurrentItem(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
public void onGkNoticeEvent(UpdateGradeEvent updateGradeEvent) {
|
||||
initViews();
|
||||
if (isAdded()) {
|
||||
// getNjId();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private List<LearnStageBean> getLearnStage() {
|
||||
String grade = SPUtils.getGrade();
|
||||
Log.e(TAG, "getLearnStage: grade = " + grade);
|
||||
String jsonString = AssertUtils.getFromAssets(mContext, "script/fragment_tbx.json");
|
||||
Type type = new TypeToken<List<LearnStageBean>>() {
|
||||
}.getType();
|
||||
List<LearnStageBean> arrayList = new Gson().fromJson(jsonString, type);
|
||||
/**
|
||||
* 获取学习阶段列表(原getLearnStage,增强空安全+容错)
|
||||
*/
|
||||
private List<LearnStageBean> getLearnStageList(String grade) {
|
||||
List<LearnStageBean> resultList = new ArrayList<>();
|
||||
for (LearnStageBean learnStageBean : arrayList) {
|
||||
FragmentActivity context = mContextRef != null ? mContextRef.get() : null;
|
||||
if (context == null || grade == null) {
|
||||
return resultList;
|
||||
}
|
||||
|
||||
// 读取Assets文件(增加空判断)
|
||||
String jsonString = AssertUtils.getFromAssets(context, ASSETS_TBX_JSON_PATH);
|
||||
if (jsonString == null || jsonString.isEmpty()) {
|
||||
Log.e(TAG, "getLearnStageList: 读取JSON文件失败");
|
||||
return resultList;
|
||||
}
|
||||
|
||||
// Gson解析(增加异常捕获)
|
||||
Type type = new TypeToken<List<LearnStageBean>>() {}.getType();
|
||||
try {
|
||||
List<LearnStageBean> allStageList = new Gson().fromJson(jsonString, type);
|
||||
if (allStageList == null) {
|
||||
return resultList;
|
||||
}
|
||||
|
||||
// 过滤当前年级的学习阶段
|
||||
for (LearnStageBean stageBean : allStageList) {
|
||||
String learnStage = stageBean.getLearnStage();
|
||||
if (learnStage == null) continue;
|
||||
|
||||
if ("六年级".equals(grade)) {
|
||||
String learnStage = learnStageBean.getLearnStage();
|
||||
if (learnStage.contains("," + grade)) {
|
||||
resultList.add(learnStageBean);
|
||||
resultList.add(stageBean);
|
||||
}
|
||||
} else if (learnStageBean.getLearnStage().contains(grade)) {
|
||||
resultList.add(learnStageBean);
|
||||
} else if (learnStage.contains(grade)) {
|
||||
resultList.add(stageBean);
|
||||
}
|
||||
}
|
||||
} catch (JsonSyntaxException e) {
|
||||
Log.e(TAG, "getLearnStageList: JSON解析失败", e);
|
||||
}
|
||||
return resultList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新Tab列表数据
|
||||
*/
|
||||
private void updateTabList(List<LearnStageBean> learnStageList) {
|
||||
mTabBeanList.clear();
|
||||
FragmentActivity context = mContextRef != null ? mContextRef.get() : null;
|
||||
if (context == null) return;
|
||||
|
||||
public class MyAdapter extends FragmentStateAdapter {
|
||||
MyAdapter(FragmentActivity fragmentActivity) {
|
||||
for (LearnStageBean stageBean : learnStageList) {
|
||||
// 资源ID获取(增加空判断)
|
||||
int normalResId = getDrawableResId(context, stageBean.getNormal());
|
||||
int pressResId = getDrawableResId(context, stageBean.getPress());
|
||||
TabBean tabBean = new TabBean(stageBean.getName(), normalResId, pressResId);
|
||||
mTabBeanList.add(tabBean);
|
||||
}
|
||||
mStageTabAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新ViewPager2适配器
|
||||
*/
|
||||
private void updateViewPager2Adapter(List<LearnStageBean> learnStageList) {
|
||||
FragmentActivity context = mContextRef != null ? mContextRef.get() : null;
|
||||
if (context == null) return;
|
||||
|
||||
if (mStageFragmentAdapter == null) {
|
||||
mStageFragmentAdapter = new StageFragmentAdapter(context, learnStageList);
|
||||
mViewDataBinding.subjectViewPager.setAdapter(mStageFragmentAdapter);
|
||||
} else {
|
||||
mStageFragmentAdapter.updateData(learnStageList);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置默认选中Tab(增加非空判断)
|
||||
*/
|
||||
private void setDefaultSelectedTab() {
|
||||
if (mTabBeanList.isEmpty() || mViewDataBinding == null) return;
|
||||
|
||||
mStageTabAdapter.setSelectedPosition(0);
|
||||
if (mViewDataBinding.subjectViewPager.getCurrentItem() != 0) {
|
||||
mViewDataBinding.subjectViewPager.setCurrentItem(0, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Drawable资源ID(封装重复逻辑,增加容错)
|
||||
*/
|
||||
private int getDrawableResId(Context context, String resName) {
|
||||
if (context == null || resName == null || resName.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
return context.getResources().getIdentifier(resName, "drawable", context.getPackageName());
|
||||
}
|
||||
|
||||
// ========== EventBus事件接收 ==========
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
public void onGradeUpdateEvent(UpdateGradeEvent event) {
|
||||
// 增强Fragment状态判断
|
||||
if (isAdded() && !isDetached() && mViewDataBinding != null) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.d(TAG, "onGradeUpdateEvent: 年级更新,刷新视图");
|
||||
}
|
||||
initStageView();
|
||||
}
|
||||
}
|
||||
|
||||
// ========== ViewPager2适配器(原MyAdapter,优化命名+容错) ==========
|
||||
public class StageFragmentAdapter extends FragmentStateAdapter {
|
||||
private List<LearnStageBean> mLearnStageList;
|
||||
|
||||
public StageFragmentAdapter(@NonNull FragmentActivity fragmentActivity, List<LearnStageBean> learnStageList) {
|
||||
super(fragmentActivity);
|
||||
this.mLearnStageList = learnStageList != null ? learnStageList : new ArrayList<>();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Fragment createFragment(int position) {
|
||||
return mFragment.get(position);
|
||||
if (position < 0 || position >= mLearnStageList.size()) {
|
||||
Log.w(TAG, "createFragment: 位置越界,position=" + position);
|
||||
return new Fragment(); // 兜底避免崩溃
|
||||
}
|
||||
|
||||
LearnStageBean bean = mLearnStageList.get(position);
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString("subject", bean.getName());
|
||||
bundle.putString("label", bean.getLabel());
|
||||
bundle.putString("tbsp_tag", bean.getTbsp_tag());
|
||||
bundle.putBoolean("isBig", bean.getIsBig());
|
||||
|
||||
try {
|
||||
Class<?> fragmentClass = Class.forName(bean.getClassName());
|
||||
Fragment fragment = (Fragment) fragmentClass.getDeclaredConstructor().newInstance();
|
||||
fragment.setArguments(bundle);
|
||||
return fragment;
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "createFragment: 实例化Fragment失败,className=" + bean.getClassName(), e);
|
||||
return new Fragment(); // 兜底
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int i) {
|
||||
return (mFragment.get(i)).hashCode();
|
||||
public long getItemId(int position) {
|
||||
// 优先用label的hashCode(保证唯一性),无label则用position
|
||||
LearnStageBean bean = mLearnStageList.get(position);
|
||||
return bean.getLabel() != null ? bean.getLabel().hashCode() : position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsItem(long itemId) {
|
||||
for (LearnStageBean bean : mLearnStageList) {
|
||||
if (bean.getLabel() != null && bean.getLabel().hashCode() == itemId) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mFragment == null ? 0 : mFragment.size();
|
||||
return mLearnStageList.size();
|
||||
}
|
||||
|
||||
public void updateData(List<LearnStageBean> newList) {
|
||||
this.mLearnStageList = newList != null ? newList : new ArrayList<>();
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public class TabTbxAdapter extends BaseQuickAdapter<TabBean, BaseViewHolder> {
|
||||
private int defSel;
|
||||
// ========== Tab列表适配器(原TabTbxAdapter,优化命名+封装) ==========
|
||||
public class StageTabAdapter extends BaseQuickAdapter<TabBean, BaseViewHolder> {
|
||||
|
||||
public void setChoosePosition(int i) {
|
||||
int i2 = defSel;
|
||||
if (i2 == i) {
|
||||
public StageTabAdapter(List<TabBean> data) {
|
||||
super(R.layout.item_tab_1, data != null ? data : new ArrayList<>());
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置选中的Tab位置(封装状态管理)
|
||||
*/
|
||||
public void setSelectedPosition(int position) {
|
||||
if (position == mSelectedTabPosition || position < 0 || position >= getData().size()) {
|
||||
return;
|
||||
}
|
||||
if (i2 != -1) {
|
||||
getData().get(defSel).setSelect(false);
|
||||
notifyItemChanged(defSel);
|
||||
}
|
||||
defSel = i;
|
||||
if (defSel != -1) {
|
||||
getData().get(defSel).setSelect(true);
|
||||
notifyItemChanged(defSel);
|
||||
}
|
||||
|
||||
// 取消原选中项
|
||||
if (mSelectedTabPosition != -1) {
|
||||
getData().get(mSelectedTabPosition).setSelect(false);
|
||||
notifyItemChanged(mSelectedTabPosition);
|
||||
}
|
||||
|
||||
public TabTbxAdapter(List<TabBean> list) {
|
||||
super(R.layout.item_tab_1, list);
|
||||
defSel = -1;
|
||||
// 设置新选中项
|
||||
mSelectedTabPosition = position;
|
||||
getData().get(mSelectedTabPosition).setSelect(true);
|
||||
notifyItemChanged(mSelectedTabPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void convert(final BaseViewHolder baseViewHolder, TabBean tabBean) {
|
||||
RelativeLayout relativeLayout = baseViewHolder.getView(R.id.rl_root);
|
||||
TextView textView = baseViewHolder.getView(R.id.iv_tab_title);
|
||||
public void convert(@NonNull BaseViewHolder holder, TabBean tabBean) {
|
||||
RelativeLayout rootLayout = holder.getView(R.id.rl_root);
|
||||
TextView titleTv = holder.getView(R.id.iv_tab_title);
|
||||
|
||||
// Tab选中/未选中样式(抽取常量,增强可读性)
|
||||
if (tabBean.isSelect()) {
|
||||
relativeLayout.setBackgroundResource(R.drawable.icon_xk_tab_bg_pre);
|
||||
textView.setTextSize(getResources().getDimension(R.dimen.x12));
|
||||
textView.setTextColor(-1);
|
||||
rootLayout.setBackgroundResource(R.drawable.icon_xk_tab_bg_pre);
|
||||
titleTv.setTextSize(getResources().getDimension(R.dimen.x12));
|
||||
titleTv.setTextColor(COLOR_WHITE);
|
||||
} else {
|
||||
relativeLayout.setBackground(null);
|
||||
textView.setTextSize(getResources().getDimension(R.dimen.x10));
|
||||
textView.setTextColor(1627389951);
|
||||
rootLayout.setBackground(null);
|
||||
titleTv.setTextSize(getResources().getDimension(R.dimen.x10));
|
||||
titleTv.setTextColor(COLOR_TAB_NORMAL);
|
||||
}
|
||||
textView.setText(tabBean.getTab_Title());
|
||||
baseViewHolder.itemView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
setChoosePosition(baseViewHolder.getAdapterPosition());
|
||||
mViewDataBinding.subjectViewPager.setCurrentItem(baseViewHolder.getAdapterPosition(), false);
|
||||
|
||||
titleTv.setText(tabBean.getTab_Title());
|
||||
|
||||
// Tab点击事件(解耦,避免直接依赖外部View)
|
||||
holder.itemView.setOnClickListener(v -> {
|
||||
int currentPos = holder.getAdapterPosition();
|
||||
setSelectedPosition(currentPos);
|
||||
if (mViewDataBinding != null) {
|
||||
mViewDataBinding.subjectViewPager.setCurrentItem(currentPos, false);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -217,6 +217,9 @@ public class MineFragment extends BaseMvvmFragment<MineViewModel, FragmentMineBi
|
||||
} else {
|
||||
mViewDataBinding.tvWlz.setText(getString(R.string.default_class));
|
||||
}
|
||||
} else {
|
||||
String grade = mMMKV.decodeString(CommonConfig.UIUI_USER_GRADE_KEY, getString(R.string.default_grade));
|
||||
mViewDataBinding.tvGrade.setText(grade);
|
||||
}
|
||||
|
||||
|
||||
@@ -400,6 +403,7 @@ public class MineFragment extends BaseMvvmFragment<MineViewModel, FragmentMineBi
|
||||
} else {
|
||||
Utils.exitDesktop(mContext);
|
||||
}
|
||||
|
||||
// OpenApkUtils.getInstance().openJxwApp(mContext, "com.hihonor.android.launcher,com.hihonor.android.launcher.unihome.UniHomeLauncher,,,退出桌面");
|
||||
}
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ public class AccountFragment extends BaseMvvmFragment<AccountViewModel, Fragment
|
||||
// mViewModel.getAppInfo("com.study.flashplayer");
|
||||
// }
|
||||
// mViewModel.getAdminAppDownload();
|
||||
mViewModel.getActivation();
|
||||
mViewModel.getEncryptedCode();
|
||||
} else {
|
||||
mViewDataBinding.tvVipName.setText("学习超人365AI旗舰版");
|
||||
mViewDataBinding.tvVipStatu.setText("点击购买激活");
|
||||
|
||||
@@ -8,6 +8,7 @@ import com.hjq.toast.Toaster;
|
||||
import com.tencent.mmkv.MMKV;
|
||||
import com.trello.rxlifecycle4.RxLifecycle;
|
||||
import com.trello.rxlifecycle4.android.FragmentEvent;
|
||||
import com.xwad.os.BuildConfig;
|
||||
import com.xwad.os.base.mvvm.BaseViewModel;
|
||||
import com.xwad.os.bean.AppInfo;
|
||||
import com.xwad.os.bean.BaseResponse;
|
||||
@@ -78,6 +79,7 @@ public class AccountViewModel extends BaseViewModel<FragmentAccountBinding, Frag
|
||||
});
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void getActivation() {
|
||||
NetInterfaceManager.getInstance().getActivationCodeControl()
|
||||
.compose(RxLifecycle.bindUntilEvent(getLifecycle(), FragmentEvent.DESTROY))
|
||||
@@ -91,7 +93,7 @@ public class AccountViewModel extends BaseViewModel<FragmentAccountBinding, Frag
|
||||
public void onNext(@NonNull BaseResponse<CodeBean> baseResponse) {
|
||||
if (baseResponse.code == 200) {
|
||||
CodeBean codeBean = baseResponse.data;
|
||||
mMMKV.encode(CommonConfig.ACTIVATIONBEAN_CODE_KEY, codeBean.getCode());
|
||||
ActivationUtil.getInstance().setActivationCode( codeBean.getCode());
|
||||
ActivationUtil.getInstance().setActivation(1);
|
||||
ActivationUtil.getInstance().startJxwLauncher();
|
||||
} else {
|
||||
@@ -111,6 +113,42 @@ public class AccountViewModel extends BaseViewModel<FragmentAccountBinding, Frag
|
||||
});
|
||||
}
|
||||
|
||||
public void getEncryptedCode() {
|
||||
NetInterfaceManager.getInstance().getEncryptedActivationCodeControl()
|
||||
.compose(RxLifecycle.bindUntilEvent(getLifecycle(), FragmentEvent.DESTROY))
|
||||
.subscribe(new Observer<BaseResponse<CodeBean>>() {
|
||||
@Override
|
||||
public void onSubscribe(@NonNull Disposable d) {
|
||||
Log.e("getEncryptedCode", "onSubscribe: ");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(@NonNull BaseResponse<CodeBean> baseResponse) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.e("getEncryptedCode", "onNext: " + baseResponse);
|
||||
}
|
||||
if (baseResponse.code == 200) {
|
||||
CodeBean codeBean = baseResponse.data;
|
||||
ActivationUtil.getInstance().setActivationCode( codeBean.getCode());
|
||||
ActivationUtil.getInstance().setActivation(1);
|
||||
ActivationUtil.getInstance().startJxwLauncher();
|
||||
} else {
|
||||
ActivationUtil.getInstance().setActivation(0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@NonNull Throwable e) {
|
||||
Log.e("getEncryptedCode", "onError: " + e.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
Log.e("getEncryptedCode", "onComplete: ");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void getAppInfo(String pkg) {
|
||||
NetInterfaceManager.getInstance().getAdminAppObservable(pkg)
|
||||
.compose(RxLifecycle.bindUntilEvent(getLifecycle(), FragmentEvent.DESTROY))
|
||||
|
||||
@@ -535,13 +535,14 @@ public class NetInterfaceManager {
|
||||
.observeOn(AndroidSchedulers.mainThread());
|
||||
}
|
||||
|
||||
public Observable<BaseResponse> getCodeActivationControl(String code) {
|
||||
public Observable<BaseResponse<CodeBean>> getCodeActivationControl(String code) {
|
||||
return mRetrofit.create(UserApi.class)
|
||||
.codeActivation(getToken(), DeviceSNManager.getDeviceSN(), code)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread());
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public Observable<BaseResponse<CodeBean>> getActivationCodeControl() {
|
||||
return mRetrofit.create(UserApi.class)
|
||||
.getActivationCode(getToken(), DeviceSNManager.getDeviceSN())
|
||||
@@ -549,6 +550,13 @@ public class NetInterfaceManager {
|
||||
.observeOn(AndroidSchedulers.mainThread());
|
||||
}
|
||||
|
||||
public Observable<BaseResponse<CodeBean>> getEncryptedActivationCodeControl() {
|
||||
return mRetrofit.create(UserApi.class)
|
||||
.getEncryptedActivationCode(getToken(), DeviceSNManager.getDeviceSN())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread());
|
||||
}
|
||||
|
||||
public Observable<BaseResponse<PayInfo>> getPayQrcodeControl(String orderSn) {
|
||||
return mRetrofit.create(UserApi.class)
|
||||
.payQrcode(getToken(), DeviceSNManager.getDeviceSN(), orderSn)
|
||||
@@ -593,8 +601,8 @@ public class NetInterfaceManager {
|
||||
|
||||
public Observable<BaseResponse> getOauthTokenObservable() {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("appId", JxwUtils.getAppId());
|
||||
params.put("signature", JxwUtils.getAppSecret());
|
||||
params.put("appId", JgyUtils.getAppId());
|
||||
params.put("signature", JgyUtils.getAppSecret());
|
||||
params.put("timestamp", String.valueOf(System.currentTimeMillis()));
|
||||
params.put("nonce", "zylcpxlj");
|
||||
return mJxwRetrofit.create(JxwApi.class)
|
||||
|
||||
@@ -20,6 +20,8 @@ public class UrlAddress {
|
||||
|
||||
/*用户会员信息(用于判断是否有VIP)*/
|
||||
public static final String USER_INFO = "user/info";
|
||||
/*获取设备过期时间*/
|
||||
public static final String USER_expire_info = "user/expire-info";
|
||||
/*套餐可选列表*/
|
||||
public static final String VIP_LIST = "user/vip-list";
|
||||
/*购买VIP下订单*/
|
||||
@@ -30,7 +32,11 @@ public class UrlAddress {
|
||||
/*激活码激活*/
|
||||
public static final String activation_code = "activation/code";
|
||||
/*获取激活码(激活成功后才有)*/
|
||||
public static final String get_activation_code = "activation/get-code";
|
||||
@Deprecated
|
||||
public static final String GET_ACTIVATION_CODE_DEPRECATED = "activation/get-code";
|
||||
/*获取加密激活码*/
|
||||
public static final String GET_ACTIVATION_CODE = "activation/get-activation-code";
|
||||
|
||||
/*发起支付*/
|
||||
public static final String PAY_QRCODE = "pay/qrcode";
|
||||
/*续费购买(已经是VIP过期或没过期)*/
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.xwad.os.bean.BaseResponse;
|
||||
import com.xwad.os.bean.CodeBean;
|
||||
import com.xwad.os.bean.OrderInfo;
|
||||
import com.xwad.os.bean.PayInfo;
|
||||
import com.xwad.os.bean.UserExpireInfo;
|
||||
import com.xwad.os.bean.UserInfo;
|
||||
import com.xwad.os.bean.VipInfo;
|
||||
import com.xwad.os.network.UrlAddress;
|
||||
@@ -24,6 +25,11 @@ public interface UserApi {
|
||||
@Header("token") String token
|
||||
);
|
||||
|
||||
@GET(UrlAddress.USER_expire_info)
|
||||
Observable<BaseResponse<UserExpireInfo>> getUserExpireInfo(
|
||||
@Header("token") String token
|
||||
);
|
||||
|
||||
@GET(UrlAddress.VIP_LIST)
|
||||
Observable<BaseResponse<List<VipInfo>>> getVipList(
|
||||
@Header("token") String token,
|
||||
@@ -55,18 +61,25 @@ public interface UserApi {
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST(UrlAddress.activation_code)
|
||||
Observable<BaseResponse> codeActivation(
|
||||
Observable<BaseResponse<CodeBean>> codeActivation(
|
||||
@Header("token") String token,
|
||||
@Field("sn") String sn,
|
||||
@Field("code") String code
|
||||
);
|
||||
|
||||
@GET(UrlAddress.get_activation_code)
|
||||
@Deprecated
|
||||
@GET(UrlAddress.GET_ACTIVATION_CODE_DEPRECATED)
|
||||
Observable<BaseResponse<CodeBean>> getActivationCode(
|
||||
@Header("token") String token,
|
||||
@Query("sn") String sn
|
||||
);
|
||||
|
||||
@GET(UrlAddress.GET_ACTIVATION_CODE)
|
||||
Observable<BaseResponse<CodeBean>> getEncryptedActivationCode(
|
||||
@Header("token") String token,
|
||||
@Query("sn") String sn
|
||||
);
|
||||
|
||||
@FormUrlEncoded
|
||||
@POST(UrlAddress.PAY_QRCODE)
|
||||
Observable<BaseResponse<PayInfo>> payQrcode(
|
||||
|
||||
@@ -114,6 +114,11 @@ public class ActivationUtil {
|
||||
return mMMKV.decodeLong(CommonConfig.UIUI_EXPIRE_TIME_KEY, DEFAULT_EXPIRE_TIME);
|
||||
}
|
||||
|
||||
public void setActivationCode(String activationCode) {
|
||||
String code = CryptoUtils.decrypt(activationCode);
|
||||
mMMKV.encode(CommonConfig.ACTIVATIONBEAN_CODE_KEY, code);
|
||||
}
|
||||
|
||||
public String getActivationCode() {
|
||||
return mMMKV.decodeString(CommonConfig.ACTIVATIONBEAN_CODE_KEY, "");
|
||||
}
|
||||
|
||||
168
app/src/main/java/com/xwad/os/utils/CryptoUtils.java
Normal file
168
app/src/main/java/com/xwad/os/utils/CryptoUtils.java
Normal file
@@ -0,0 +1,168 @@
|
||||
package com.xwad.os.utils;
|
||||
|
||||
import android.util.Base64;
|
||||
import android.util.Log;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.spec.AlgorithmParameterSpec;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
/**
|
||||
* Android 对称加密解密工具类
|
||||
* 支持 AES/DES/TripleDES + ECB/CBC/CFB/OFB/CTR + PKCS5Padding 等
|
||||
*/
|
||||
public class CryptoUtils {
|
||||
/**
|
||||
* 简化解密方法:仅需传入待解密字符串
|
||||
*
|
||||
* @param data 待解密的字符串
|
||||
* @return 解密后的原文
|
||||
* @throws Exception 解密异常
|
||||
*/
|
||||
public static String decrypt(String data) {
|
||||
String KEY = JgyUtils.getAesKey();
|
||||
String IV = JgyUtils.getAesIv();
|
||||
|
||||
try {
|
||||
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
||||
|
||||
// 解码密钥
|
||||
byte[] keyBytes = KEY.getBytes(StandardCharsets.UTF_8);
|
||||
SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES");
|
||||
|
||||
// 初始化Cipher
|
||||
// 解码偏移量IV
|
||||
byte[] ivBytes = IV.getBytes(StandardCharsets.UTF_8);
|
||||
AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivBytes);
|
||||
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);
|
||||
|
||||
// 解码待解密数据
|
||||
byte[] dataBytes = Base64.decode(data, Base64.DEFAULT);
|
||||
|
||||
// 执行解密并返回字符串
|
||||
byte[] decryptBytes = cipher.doFinal(dataBytes);
|
||||
return new String(decryptBytes, StandardCharsets.UTF_8);
|
||||
} catch (GeneralSecurityException e) {
|
||||
e.printStackTrace();
|
||||
Log.e("CryptoUtils", "decrypt: " + e.getMessage());
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* 对称解密核心方法
|
||||
*
|
||||
* @param data 待解密的字符串
|
||||
* @param type 加密类型:AES / DES / TRIPLEDES
|
||||
* @param mode 模式:ECB / CBC / CFB / OFB / CTR
|
||||
* @param pad 填充方式:PKCS5Padding / ISO10126Padding / NoPadding
|
||||
* @param key 密钥字符串
|
||||
* @param keyType 密钥编码:Utf8 / Base64 / Hex
|
||||
* @param iv 偏移量(ECB模式无需)
|
||||
* @param ivType 偏移量编码:Utf8 / Base64 / Hex
|
||||
* @param isBase64 待解密数据编码:true=Base64 false=Hex
|
||||
* @return 解密后的原始字符串
|
||||
* @throws Exception 解密异常(密钥长度/算法不支持/数据错误等)
|
||||
*/
|
||||
public static String decrypt(
|
||||
String data,
|
||||
String type,
|
||||
String mode,
|
||||
String pad,
|
||||
String key,
|
||||
String keyType,
|
||||
String iv,
|
||||
String ivType,
|
||||
boolean isBase64
|
||||
) throws Exception {
|
||||
// 1. 拼接算法全称
|
||||
String algorithm = type + "/" + mode + "/" + pad;
|
||||
Cipher cipher = Cipher.getInstance(algorithm);
|
||||
|
||||
// 2. 解码密钥(修复:== 改为 equals() 字符串值比较)
|
||||
byte[] keyBytes;
|
||||
if ("Hex".equals(keyType)) {
|
||||
keyBytes = hex2Bytes(key);
|
||||
} else if ("Base64".equals(keyType)) {
|
||||
keyBytes = Base64.decode(key, Base64.DEFAULT);
|
||||
} else {
|
||||
// 强制指定UTF-8,避免乱码
|
||||
keyBytes = key.getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
SecretKeySpec secretKey = new SecretKeySpec(keyBytes, type);
|
||||
|
||||
// 3. 初始化Cipher(ECB无IV,其他模式需要IV)
|
||||
if ("ECB".equals(mode)) {
|
||||
cipher.init(Cipher.DECRYPT_MODE, secretKey);
|
||||
} else {
|
||||
// 解码偏移量IV
|
||||
byte[] ivBytes;
|
||||
if ("Hex".equals(ivType)) {
|
||||
ivBytes = hex2Bytes(iv);
|
||||
} else if ("Base64".equals(ivType)) {
|
||||
ivBytes = Base64.decode(iv, Base64.DEFAULT);
|
||||
} else {
|
||||
ivBytes = iv.getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivBytes);
|
||||
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);
|
||||
}
|
||||
|
||||
// 4. 解码待解密数据
|
||||
byte[] dataBytes;
|
||||
if (isBase64) {
|
||||
dataBytes = Base64.decode(data, Base64.DEFAULT);
|
||||
} else {
|
||||
dataBytes = hex2Bytes(data);
|
||||
}
|
||||
|
||||
// 5. 执行解密 + 转字符串
|
||||
byte[] decryptBytes = cipher.doFinal(dataBytes);
|
||||
return new String(decryptBytes, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* 全Android版本兼容的 Hex字符串 → 字节数组 解码
|
||||
* 替代Apache Commons-Codec的Hex.decodeHex
|
||||
*/
|
||||
private static byte[] hex2Bytes(String hexStr) {
|
||||
if (hexStr == null || hexStr.length() == 0) return new byte[0];
|
||||
byte[] bytes = new byte[hexStr.length() / 2];
|
||||
for (int i = 0; i < bytes.length; i++) {
|
||||
int high = Character.digit(hexStr.charAt(2 * i), 16);
|
||||
int low = Character.digit(hexStr.charAt(2 * i + 1), 16);
|
||||
bytes[i] = (byte) (high << 4 | low);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
// ------------------- 你的业务调用示例(直接复制到Android Activity/ViewModel中使用) -------------------
|
||||
public static void testDecrypt() {
|
||||
// 你的原始配置参数(完全不变)
|
||||
String data = "88072p8780";
|
||||
String type = "AES";
|
||||
String mode = "CBC";
|
||||
String pad = "PKCS5Padding";
|
||||
String key = "fRW5b5FI4uG32HISvVZ40QFSkyvXYwP8";
|
||||
String keyType = "Utf8";
|
||||
String iv = "7COBgH2wUtJnPPSX";
|
||||
String ivType = "Utf8";
|
||||
boolean isBase64 = true;
|
||||
|
||||
try {
|
||||
// 执行解密
|
||||
String result = decrypt(data, type, mode, pad, key, keyType, iv, ivType, isBase64);
|
||||
// 输出结果(Android中用Log.d,不要用System.out)
|
||||
Log.d("Crypto", "解密结果:" + result);
|
||||
} catch (Exception e) {
|
||||
// 异常捕获(密钥错误/算法不支持/数据被篡改等)
|
||||
e.printStackTrace();
|
||||
Log.e("Crypto", "解密失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -70,7 +70,6 @@ import io.reactivex.rxjava3.disposables.Disposable;
|
||||
|
||||
import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE;
|
||||
|
||||
|
||||
public class JgyUtils {
|
||||
private static final String TAG = "JgyUtils";
|
||||
|
||||
@@ -90,6 +89,19 @@ public class JgyUtils {
|
||||
public static final String LENOVO_TAG = "lenovo";
|
||||
public static final String NATURE_TAG = "Nature";
|
||||
|
||||
static {
|
||||
System.loadLibrary("xuewang"); // 加载 libjniutils.so
|
||||
}
|
||||
|
||||
// 声明为Native方法
|
||||
public static native String getAppId();
|
||||
|
||||
public static native String getAppSecret();
|
||||
|
||||
public static native String getAesKey();
|
||||
|
||||
public static native String getAesIv();
|
||||
|
||||
|
||||
private HashSet<String> ownApp = new HashSet<String>() {{
|
||||
this.add("com.tt.ttutils");
|
||||
|
||||
@@ -5,7 +5,6 @@ import android.util.Log;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
@@ -13,22 +12,13 @@ import java.util.TreeMap;
|
||||
public class JxwUtils {
|
||||
private static final String TAG = "JxwUtils";
|
||||
|
||||
static {
|
||||
System.loadLibrary("xuewang"); // 加载 libjniutils.so
|
||||
}
|
||||
|
||||
// 声明为Native方法
|
||||
public static native String getAppId();
|
||||
|
||||
public static native String getAppSecret();
|
||||
|
||||
public static String getSignature(Map<String, String> paramMap) {
|
||||
long timeStamp = System.currentTimeMillis();
|
||||
//用于获取signature
|
||||
SortedMap<String, String> items = new TreeMap<>();
|
||||
items.put("nonce", "X6SH3YeRTs");
|
||||
items.put("appId", JxwUtils.getAppId());
|
||||
items.put("appsecret", JxwUtils.getAppSecret());
|
||||
items.put("appId", JgyUtils.getAppId());
|
||||
items.put("appsecret", JgyUtils.getAppSecret());
|
||||
items.put("timestamp", String.valueOf(timeStamp));
|
||||
// items.putAll(paramMap);
|
||||
|
||||
|
||||
@@ -13,14 +13,28 @@
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_com_xwad_os_utils_JxwUtils_getAppId(JNIEnv *env, jclass thiz) {
|
||||
Java_com_xwad_os_utils_JgyUtils_getAppId(JNIEnv *env, jclass thiz) {
|
||||
std::string key = "hlhdpb";
|
||||
return env->NewStringUTF(key.c_str());
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_com_xwad_os_utils_JxwUtils_getAppSecret(JNIEnv *env, jclass thiz) {
|
||||
Java_com_xwad_os_utils_JgyUtils_getAppSecret(JNIEnv *env, jclass thiz) {
|
||||
std::string key = "WDNUnYMNL33lqlGIIZB";
|
||||
return env->NewStringUTF(key.c_str());
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_com_xwad_os_utils_JgyUtils_getAesKey(JNIEnv *env, jclass clazz) {
|
||||
std::string key = "fRW5b5FI4uG32HISvVZ40QFSkyvXYwP8";
|
||||
return env->NewStringUTF(key.c_str());
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_com_xwad_os_utils_JgyUtils_getAesIv(JNIEnv *env, jclass clazz) {
|
||||
std::string key = "7COBgH2wUtJnPPSX";
|
||||
return env->NewStringUTF(key.c_str());
|
||||
}
|
||||
BIN
app/src/main/res/drawable-nodpi/icon_read_klxyy.png
Normal file
BIN
app/src/main/res/drawable-nodpi/icon_read_klxyy.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 MiB |
BIN
app/src/main/res/drawable-nodpi/icon_yy_xx_kywtbbdc.png
Normal file
BIN
app/src/main/res/drawable-nodpi/icon_yy_xx_kywtbbdc.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 319 KiB |
@@ -496,9 +496,9 @@
|
||||
<ImageView
|
||||
android:layout_width="169dp"
|
||||
android:layout_height="86dp"
|
||||
android:background="@drawable/icon_yy_xx_lwxfy"
|
||||
android:background="@drawable/icon_yy_xx_kywtbbdc"
|
||||
android:onClick="onClick"
|
||||
android:tag="@string/taf_args_xfy" />
|
||||
android:tag="@string/tag_args_new_bdc" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
|
||||
@@ -274,8 +274,8 @@
|
||||
android:adjustViewBounds="true"
|
||||
android:onClick="onClick"
|
||||
android:scaleType="centerCrop"
|
||||
android:src="@drawable/icon_read_syhbg"
|
||||
android:tag="@string/tag_args_new_zhtsg_syhb" />
|
||||
android:src="@drawable/icon_read_klxyy"
|
||||
android:tag="@string/tag_args_new_klxyy" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user