From 6de0c1f016c7a9533c4e24b1c9d07bec5cb544fc Mon Sep 17 00:00:00 2001
From: Fanhuitong <981964879@qq.com>
Date: Thu, 28 Sep 2023 15:01:45 +0800
Subject: [PATCH] =?UTF-8?q?version:6.4.6=20fix:=20update:=E5=A2=9E?=
=?UTF-8?q?=E5=8A=A0=E6=8A=A4=E7=9C=BC=E6=A8=A1=E5=BC=8F,=E5=A2=9E?=
=?UTF-8?q?=E5=8A=A0=E9=9D=99=E9=BB=98=E6=8B=8D=E7=85=A7,=E5=A2=9E?=
=?UTF-8?q?=E5=8A=A0=E6=97=B6=E9=97=B4=E7=AE=A1=E6=8E=A7=E5=92=8C=E4=B8=93?=
=?UTF-8?q?=E6=B3=A8=E6=A8=A1=E5=BC=8F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
app/build.gradle | 5 +-
app/src/main/AndroidManifest.xml | 15 +
.../sn/activity/EyeProtectionActivity.java | 99 +++
.../sn/activity/main/MainAContact.java | 10 +-
.../sn/activity/main/MainAPresenter.java | 41 +-
.../sn/activity/main/MainActivity.java | 12 +-
.../com/aoleyun/sn/base/BaseApplication.java | 2 +
.../com/aoleyun/sn/bean/AdminAppInfo.java | 197 ++++++
.../java/com/aoleyun/sn/bean/SnSetting.java | 62 ++
.../com/aoleyun/sn/comm/CommonConfig.java | 5 +-
.../sn/network/NetInterfaceManager.java | 136 ++++-
.../com/aoleyun/sn/network/UrlAddress.java | 13 +-
.../api/aolelearn/ExclusiveAdminAppApi.java | 15 +
.../sn/network/api/get/SnSettingApi.java | 16 +
.../sn/network/api/post/MACAddressApi.java | 3 +-
.../java/com/aoleyun/sn/push/PushManager.java | 76 ++-
.../aoleyun/sn/service/main/MainSContact.java | 8 +-
.../sn/service/main/MainSPresenter.java | 56 +-
.../aoleyun/sn/service/main/MainService.java | 19 +-
.../sn/utils/Camera2BackgroundUtil.java | 568 ++++++++++++++++++
.../java/com/aoleyun/sn/utils/JGYUtils.java | 41 ++
.../java/com/aoleyun/sn/utils/TimeUtils.java | 7 +
.../main/java/com/aoleyun/sn/utils/Utils.java | 19 +-
.../com/aoleyun/sn/view/ToggleButton.java | 347 +++++++++++
app/src/main/res/drawable-hdpi/back.png | Bin 0 -> 3643 bytes
.../res/drawable-hdpi/com_system_huyan.png | Bin 0 -> 10527 bytes
.../main/res/drawable/item_eye_background.xml | 18 +
.../main/res/layout-land/activity_main.xml | 4 +-
.../res/layout/activity_eye_protection.xml | 275 +++++++++
app/src/main/res/values/attrs.xml | 12 +
30 files changed, 2049 insertions(+), 32 deletions(-)
create mode 100644 app/src/main/java/com/aoleyun/sn/activity/EyeProtectionActivity.java
create mode 100644 app/src/main/java/com/aoleyun/sn/bean/AdminAppInfo.java
create mode 100644 app/src/main/java/com/aoleyun/sn/bean/SnSetting.java
create mode 100644 app/src/main/java/com/aoleyun/sn/network/api/aolelearn/ExclusiveAdminAppApi.java
create mode 100644 app/src/main/java/com/aoleyun/sn/network/api/get/SnSettingApi.java
create mode 100644 app/src/main/java/com/aoleyun/sn/utils/Camera2BackgroundUtil.java
create mode 100644 app/src/main/java/com/aoleyun/sn/view/ToggleButton.java
create mode 100644 app/src/main/res/drawable-hdpi/back.png
create mode 100644 app/src/main/res/drawable-hdpi/com_system_huyan.png
create mode 100644 app/src/main/res/drawable/item_eye_background.xml
create mode 100644 app/src/main/res/layout/activity_eye_protection.xml
create mode 100644 app/src/main/res/values/attrs.xml
diff --git a/app/build.gradle b/app/build.gradle
index 837dff7..3e23499 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -29,8 +29,8 @@ android {
defaultConfig {
applicationId "com.aoleyun.sn"
- versionCode 84
- versionName "6.4.4"
+ versionCode 86
+ versionName "6.4.6"
//There are no CERT files because If the mini sdk version is 23+, the AGP will ignore the V1 scheme signature.
minSdkVersion 24
@@ -436,6 +436,7 @@ dependencies {
// // kotlin扩展(可选)
// implementation 'com.gyf.immersionbar:immersionbar-ktx:3.0.0'
implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.24'
+ implementation 'com.facebook.rebound:rebound:0.3.8'
}
preBuild {
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index ad41f6d..ec1fd8c 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -149,6 +149,21 @@
+
+
+
+
+
+
+
+
diff --git a/app/src/main/java/com/aoleyun/sn/activity/EyeProtectionActivity.java b/app/src/main/java/com/aoleyun/sn/activity/EyeProtectionActivity.java
new file mode 100644
index 0000000..ea4f3be
--- /dev/null
+++ b/app/src/main/java/com/aoleyun/sn/activity/EyeProtectionActivity.java
@@ -0,0 +1,99 @@
+package com.aoleyun.sn.activity;
+
+import android.provider.Settings;
+import android.view.View;
+
+import androidx.constraintlayout.widget.ConstraintLayout;
+
+import com.aoleyun.sn.R;
+import com.aoleyun.sn.base.BaseActivity;
+import com.aoleyun.sn.utils.ToastUtil;
+import com.aoleyun.sn.view.ToggleButton;
+
+import butterknife.BindView;
+import butterknife.ButterKnife;
+
+public class EyeProtectionActivity extends BaseActivity {
+
+ @BindView(R.id.cl_exit)
+ ConstraintLayout cl_exit;
+ @BindView(R.id.toggleButton1)
+ ToggleButton toggleButton1;
+ @BindView(R.id.toggleButton2)
+ ToggleButton toggleButton2;
+ @BindView(R.id.toggleButton3)
+ ToggleButton toggleButton3;
+ @BindView(R.id.toggleButton4)
+ ToggleButton toggleButton4;
+ @BindView(R.id.toggleButton5)
+ ToggleButton toggleButton5;
+
+ @Override
+ public int getLayoutId() {
+ return R.layout.activity_eye_protection;
+ }
+
+
+ @Override
+ public void initView() {
+ ButterKnife.bind(this);
+ int nightDisplay = Settings.Secure.getInt(getContentResolver(), Settings.Secure.NIGHT_DISPLAY_ACTIVATED, 0);
+ if (nightDisplay == 1) {
+ toggleButton1.setToggleOn();
+ } else {
+ toggleButton1.setToggleOff();
+ }
+ toggleButton1.setOnToggleChanged(new ToggleButton.OnToggleChanged() {
+ @Override
+ public void onToggle(boolean on) {
+ Settings.Secure.putInt(getContentResolver(), Settings.Secure.NIGHT_DISPLAY_ACTIVATED, on ? 1 : 0);
+ }
+ });
+
+ int accessibilityDisplay = Settings.Secure.getInt(getContentResolver(), Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, 0);
+ if (accessibilityDisplay == 1) {
+ toggleButton2.setToggleOn();
+ } else {
+ toggleButton2.setToggleOff();
+ }
+ toggleButton2.setOnToggleChanged(new ToggleButton.OnToggleChanged() {
+ @Override
+ public void onToggle(boolean on) {
+ Settings.Secure.putInt(getContentResolver(), Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, on ? 1 : 0);
+ }
+ });
+ toggleButton3.setDisable(true);
+ toggleButton3.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ ToastUtil.show("此功能暂未开放");
+ }
+ });
+ toggleButton4.setDisable(true);
+ toggleButton4.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ ToastUtil.show("此功能暂未开放");
+ }
+ });
+ toggleButton5.setDisable(true);
+ toggleButton5.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ ToastUtil.show("此功能暂未开放");
+ }
+ });
+
+ cl_exit.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ finish();
+ }
+ });
+ }
+
+ @Override
+ public void initData() {
+
+ }
+}
diff --git a/app/src/main/java/com/aoleyun/sn/activity/main/MainAContact.java b/app/src/main/java/com/aoleyun/sn/activity/main/MainAContact.java
index fc13562..0c12755 100644
--- a/app/src/main/java/com/aoleyun/sn/activity/main/MainAContact.java
+++ b/app/src/main/java/com/aoleyun/sn/activity/main/MainAContact.java
@@ -16,8 +16,10 @@ public class MainAContact {
void getQrCode(boolean loocked);
/*获取学生信息*/
void getStudesInfo();
- //获取电子书包激活码
+ /*获取电子书包激活码*/
void getEBagCode();
+ /*获取学习应用*/
+ void getExclusiveAdminApp();
/*获取公网ip*/
void getPublicIp();
/*手动获取设备信息更新*/
@@ -37,8 +39,10 @@ public class MainAContact {
void setQrCode(Bitmap qrcode);
/*获取学生信息*/
void setStudesInfo(StudentsInfo studesInfo);
- //获取电子书包激活码
- void getEBagCodeFinish();
+ /*获取电子书包激活码*/
+ void getEBagCodeFinish(boolean activation);
+ /*获取学习应用*/
+ void getExclusiveAdminAppFinish();
/*获取公网ip*/
void setPublicIp(String ip);
/*手动获取设备信息更新*/
diff --git a/app/src/main/java/com/aoleyun/sn/activity/main/MainAPresenter.java b/app/src/main/java/com/aoleyun/sn/activity/main/MainAPresenter.java
index 956c481..45b1f16 100644
--- a/app/src/main/java/com/aoleyun/sn/activity/main/MainAPresenter.java
+++ b/app/src/main/java/com/aoleyun/sn/activity/main/MainAPresenter.java
@@ -9,6 +9,7 @@ import android.util.Log;
import android.view.View;
import com.aoleyun.sn.BuildConfig;
+import com.aoleyun.sn.bean.AdminAppInfo;
import com.aoleyun.sn.bean.AppUpdateInfo;
import com.aoleyun.sn.bean.BaseResponse;
import com.aoleyun.sn.bean.StudentsInfo;
@@ -24,6 +25,8 @@ import com.google.gson.JsonParser;
import com.trello.rxlifecycle4.RxLifecycle;
import com.trello.rxlifecycle4.android.ActivityEvent;
+import java.util.List;
+
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.annotations.NonNull;
import io.reactivex.rxjava3.core.Observer;
@@ -114,11 +117,47 @@ public class MainAPresenter implements MainAContact.Presenter {
NetInterfaceManager.getInstance().getEBagCode(true, getLifecycle(), new NetInterfaceManager.onCompleteCallback() {
@Override
public void onComplete() {
- mView.getEBagCodeFinish();
+ mView.getEBagCodeFinish(Settings.Global.getInt(mContext.getContentResolver(), CommonConfig.UIUI_ACTIVATION_KEY, 0) == 1);
}
});
}
+
+ @Override
+ public void getExclusiveAdminApp() {
+ NetInterfaceManager.getInstance().getExclusiveAdminAppObservable()
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
+ .subscribe(new Observer>>() {
+ @Override
+ public void onSubscribe(@NonNull Disposable d) {
+ Log.e("getAdminApp", "onSubscribe: ");
+ }
+
+ @Override
+ public void onNext(@NonNull BaseResponse> listBaseResponse) {
+ Log.e("getAdminApp", "onNext: " + listBaseResponse);
+ if (listBaseResponse.code == 200) {
+ List adminAppInfos = listBaseResponse.data;
+ JGYUtils.getInstance().installAdminApp(adminAppInfos);
+ }
+ }
+
+ @Override
+ public void onError(@NonNull Throwable e) {
+ Log.e("getAdminApp", "onError: " + e.getMessage());
+ onComplete();
+ }
+
+ @Override
+ public void onComplete() {
+ Log.e("getAdminApp", "onComplete: ");
+ mView.getExclusiveAdminAppFinish();
+ }
+ });
+ }
+
@Override
public void getPublicIp() {
NetInterfaceManager.getInstance().getPublicIp(lifecycle, ip -> mView.setPublicIp(ip));
diff --git a/app/src/main/java/com/aoleyun/sn/activity/main/MainActivity.java b/app/src/main/java/com/aoleyun/sn/activity/main/MainActivity.java
index f8f462f..7ef5d54 100644
--- a/app/src/main/java/com/aoleyun/sn/activity/main/MainActivity.java
+++ b/app/src/main/java/com/aoleyun/sn/activity/main/MainActivity.java
@@ -429,8 +429,18 @@ public class MainActivity extends BaseActivity implements MainAContact.MainView,
}
@Override
- public void getEBagCodeFinish() {
+ public void getEBagCodeFinish(boolean activation) {
+ if (activation){
+ mMainAPresenter.getExclusiveAdminApp();
+ Log.e(TAG, "getEBagCodeFinish: "+"已激活" );
+ }else {
+ Log.e(TAG, "getEBagCodeFinish: "+"未激活" );
+ }
+ }
+ @Override
+ public void getExclusiveAdminAppFinish() {
+ Log.e(TAG, "getAdminAppFinish: " );
}
@Override
diff --git a/app/src/main/java/com/aoleyun/sn/base/BaseApplication.java b/app/src/main/java/com/aoleyun/sn/base/BaseApplication.java
index 2c51190..f0b765c 100644
--- a/app/src/main/java/com/aoleyun/sn/base/BaseApplication.java
+++ b/app/src/main/java/com/aoleyun/sn/base/BaseApplication.java
@@ -204,8 +204,10 @@ public class BaseApplication extends MultiDexApplication {
switch (code){
case "PUSH_20101":
aliyunPushInit();
+ break;
default:
setAlias();
+ break;
}
}
diff --git a/app/src/main/java/com/aoleyun/sn/bean/AdminAppInfo.java b/app/src/main/java/com/aoleyun/sn/bean/AdminAppInfo.java
new file mode 100644
index 0000000..906bb48
--- /dev/null
+++ b/app/src/main/java/com/aoleyun/sn/bean/AdminAppInfo.java
@@ -0,0 +1,197 @@
+package com.aoleyun.sn.bean;
+
+import java.io.Serializable;
+
+public class AdminAppInfo implements Serializable {
+ private static final long serialVersionUID = -4152412763486673833L;
+
+ int id;
+ String app_name;
+ String app_img;
+ String app_developer;
+ long app_size;
+ String app_package;
+ String app_version_name;
+ long app_version_code;
+ String app_md5;
+ float app_score;
+ String app_preview1;
+ String app_preview2;
+ String app_preview3;
+ String app_url;
+ String app_remarks;
+ String app_desc;
+ int is_promote;
+ int weight;
+ String discount;
+ String use_type;
+ int is_autodown;
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public String getApp_name() {
+ return app_name;
+ }
+
+ public void setApp_name(String app_name) {
+ this.app_name = app_name;
+ }
+
+ public String getApp_img() {
+ return app_img;
+ }
+
+ public void setApp_img(String app_img) {
+ this.app_img = app_img;
+ }
+
+ public String getApp_developer() {
+ return app_developer;
+ }
+
+ public void setApp_developer(String app_developer) {
+ this.app_developer = app_developer;
+ }
+
+ public long getApp_size() {
+ return app_size;
+ }
+
+ public void setApp_size(long app_size) {
+ this.app_size = app_size;
+ }
+
+ public String getApp_package() {
+ return app_package;
+ }
+
+ public void setApp_package(String app_package) {
+ this.app_package = app_package;
+ }
+
+ public String getApp_version_name() {
+ return app_version_name;
+ }
+
+ public void setApp_version_name(String app_version_name) {
+ this.app_version_name = app_version_name;
+ }
+
+ public long getApp_version_code() {
+ return app_version_code;
+ }
+
+ public void setApp_version_code(long app_version_code) {
+ this.app_version_code = app_version_code;
+ }
+
+ public String getApp_md5() {
+ return app_md5;
+ }
+
+ public void setApp_md5(String app_md5) {
+ this.app_md5 = app_md5;
+ }
+
+ public float getApp_score() {
+ return app_score;
+ }
+
+ public void setApp_score(float app_score) {
+ this.app_score = app_score;
+ }
+
+ public String getApp_preview1() {
+ return app_preview1;
+ }
+
+ public void setApp_preview1(String app_preview1) {
+ this.app_preview1 = app_preview1;
+ }
+
+ public String getApp_preview2() {
+ return app_preview2;
+ }
+
+ public void setApp_preview2(String app_preview2) {
+ this.app_preview2 = app_preview2;
+ }
+
+ public String getApp_preview3() {
+ return app_preview3;
+ }
+
+ public void setApp_preview3(String app_preview3) {
+ this.app_preview3 = app_preview3;
+ }
+
+ public String getApp_url() {
+ return app_url;
+ }
+
+ public void setApp_url(String app_url) {
+ this.app_url = app_url;
+ }
+
+ public String getApp_remarks() {
+ return app_remarks;
+ }
+
+ public void setApp_remarks(String app_remarks) {
+ this.app_remarks = app_remarks;
+ }
+
+ public String getApp_desc() {
+ return app_desc;
+ }
+
+ public void setApp_desc(String app_desc) {
+ this.app_desc = app_desc;
+ }
+
+ public int getIs_promote() {
+ return is_promote;
+ }
+
+ public void setIs_promote(int is_promote) {
+ this.is_promote = is_promote;
+ }
+
+ public int getWeight() {
+ return weight;
+ }
+
+ public void setWeight(int weight) {
+ this.weight = weight;
+ }
+
+ public String getDiscount() {
+ return discount;
+ }
+
+ public void setDiscount(String discount) {
+ this.discount = discount;
+ }
+
+ public String getUse_type() {
+ return use_type;
+ }
+
+ public void setUse_type(String use_type) {
+ this.use_type = use_type;
+ }
+
+ public int getIs_autodown() {
+ return is_autodown;
+ }
+
+ public void setIs_autodown(int is_autodown) {
+ this.is_autodown = is_autodown;
+ }
+}
diff --git a/app/src/main/java/com/aoleyun/sn/bean/SnSetting.java b/app/src/main/java/com/aoleyun/sn/bean/SnSetting.java
new file mode 100644
index 0000000..16fb22a
--- /dev/null
+++ b/app/src/main/java/com/aoleyun/sn/bean/SnSetting.java
@@ -0,0 +1,62 @@
+package com.aoleyun.sn.bean;
+
+import java.io.Serializable;
+
+public class SnSetting implements Serializable {
+ private static final long serialVersionUID = -1984636328774813651L;
+
+ int id;
+ int is_timecontrol;
+ String timecontrol_start;
+ String timecontrol_end;
+ int is_storeinstall;
+ int is_usb;
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public int getIs_timecontrol() {
+ return is_timecontrol;
+ }
+
+ public void setIs_timecontrol(int is_timecontrol) {
+ this.is_timecontrol = is_timecontrol;
+ }
+
+ public String getTimecontrol_start() {
+ return timecontrol_start;
+ }
+
+ public void setTimecontrol_start(String timecontrol_start) {
+ this.timecontrol_start = timecontrol_start;
+ }
+
+ public String getTimecontrol_end() {
+ return timecontrol_end;
+ }
+
+ public void setTimecontrol_end(String timecontrol_end) {
+ this.timecontrol_end = timecontrol_end;
+ }
+
+ public int getIs_storeinstall() {
+ return is_storeinstall;
+ }
+
+ public void setIs_storeinstall(int is_storeinstall) {
+ this.is_storeinstall = is_storeinstall;
+ }
+
+ public int getIs_usb() {
+ return is_usb;
+ }
+
+ public void setIs_usb(int is_usb) {
+ this.is_usb = is_usb;
+ }
+}
diff --git a/app/src/main/java/com/aoleyun/sn/comm/CommonConfig.java b/app/src/main/java/com/aoleyun/sn/comm/CommonConfig.java
index 71ab810..8604223 100644
--- a/app/src/main/java/com/aoleyun/sn/comm/CommonConfig.java
+++ b/app/src/main/java/com/aoleyun/sn/comm/CommonConfig.java
@@ -60,7 +60,10 @@ public class CommonConfig {
public final static String DEVICES_TAG = "Aoleyun_devices_tpush_tag";
/*上次获取标签的时间*/
public final static String GET_DEVICES_TAG_LASTTIME = "Aoleyun_devices_tag_last_time";
-
+ /*专注模式刷新*/
+ public static final String FOCUS_MODE_REFRESH_KEY = "AOLEYUN_FOCUS_MODE_REFRESH";
+ /*应用市场允许安装*/
+ public static final String AOLEYUN_APPSTORE_INSTALL = "AOLEYUN_APPSTORE_INSTALL_KEY";
/**
diff --git a/app/src/main/java/com/aoleyun/sn/network/NetInterfaceManager.java b/app/src/main/java/com/aoleyun/sn/network/NetInterfaceManager.java
index 802d0ca..917515b 100644
--- a/app/src/main/java/com/aoleyun/sn/network/NetInterfaceManager.java
+++ b/app/src/main/java/com/aoleyun/sn/network/NetInterfaceManager.java
@@ -19,6 +19,7 @@ import com.alibaba.sdk.android.push.CommonCallback;
import com.alibaba.sdk.android.push.noonesdk.PushServiceFactory;
import com.aoleyun.sn.BuildConfig;
import com.aoleyun.sn.base.BaseApplication;
+import com.aoleyun.sn.bean.AdminAppInfo;
import com.aoleyun.sn.bean.AppAttr;
import com.aoleyun.sn.bean.AppDateInfo;
import com.aoleyun.sn.bean.AppID;
@@ -41,6 +42,7 @@ import com.aoleyun.sn.bean.NetAndLaunchBean;
import com.aoleyun.sn.bean.PoweroffBean;
import com.aoleyun.sn.bean.ScreenLockState;
import com.aoleyun.sn.bean.SnRunLog;
+import com.aoleyun.sn.bean.SnSetting;
import com.aoleyun.sn.bean.SnTimeControl;
import com.aoleyun.sn.bean.StudentsInfo;
import com.aoleyun.sn.bean.TopApp;
@@ -55,6 +57,7 @@ import com.aoleyun.sn.gson.NullStringToEmptyAdapterFactory;
import com.aoleyun.sn.manager.ConnectManager;
import com.aoleyun.sn.manager.ConnectMode;
import com.aoleyun.sn.network.api.GetWhoisApi;
+import com.aoleyun.sn.network.api.aolelearn.ExclusiveAdminAppApi;
import com.aoleyun.sn.network.api.get.CheckTestUpdateApi;
import com.aoleyun.sn.network.api.get.DefaultAppApi;
import com.aoleyun.sn.network.api.get.DesktopsDiyUpdateApi;
@@ -67,6 +70,7 @@ import com.aoleyun.sn.network.api.get.GetWiFiAliasApi;
import com.aoleyun.sn.network.api.get.LogoImgApi;
import com.aoleyun.sn.network.api.get.ScreenLockStateApi;
import com.aoleyun.sn.network.api.get.SnAppAttrApi;
+import com.aoleyun.sn.network.api.get.SnSettingApi;
import com.aoleyun.sn.network.api.get.SnTimeControlApi;
import com.aoleyun.sn.network.api.get.TopAppControlApi;
import com.aoleyun.sn.network.api.post.AppLimitApi;
@@ -181,6 +185,10 @@ public class NetInterfaceManager {
private Context mContext;
private Retrofit mRetrofit;
private OkHttpClient okHttpClient;
+
+ private Retrofit mAolelearnRetrofit;
+ private OkHttpClient mAolelearnOkHttpClient;
+
private MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE);
private CacheHelper cacheHelper;
@@ -318,6 +326,29 @@ public class NetInterfaceManager {
.addCallAdapterFactory(RxJava3CallAdapterFactory.create())
.build();
}
+
+ if (mAolelearnOkHttpClient == null) {
+ //如果无法生存缓存文件目录,检测权限使用已经加上,检测手机是否把文件读写权限禁止了
+ OkHttpClient.Builder builder = new OkHttpClient.Builder();
+ builder.connectTimeout(timeOut, TimeUnit.SECONDS); // 设置连接超时时间
+ builder.writeTimeout(timeOut, TimeUnit.SECONDS);// 设置写入超时时间
+ builder.readTimeout(timeOut, TimeUnit.SECONDS);// 设置读取数据超时时间
+ builder.retryOnConnectionFailure(true);// 设置进行连接失败重试
+ builder.addInterceptor(new RepeatRequestInterceptor());
+ // 设置缓存文件路径
+ String cacheDirectory = mContext.getExternalCacheDir().getAbsolutePath() + "/OkHttpCache";
+ Cache cache = new Cache(new File(cacheDirectory), cacheSize);
+ builder.cache(cache);// 设置缓存
+ mAolelearnOkHttpClient = builder.build();
+ }
+ if (mAolelearnRetrofit == null) {
+ mAolelearnRetrofit = new Retrofit.Builder()
+ .client(mAolelearnOkHttpClient)
+ .baseUrl(UrlAddress.AOLELEARN_ROOT)
+ .addConverterFactory(GsonConverterFactory.create())
+ .addCallAdapterFactory(RxJava3CallAdapterFactory.create())
+ .build();
+ }
}
public static void init(Context context) {
@@ -340,6 +371,18 @@ public class NetInterfaceManager {
return okHttpClient;
}
+ /**
+ * 获取学习软件
+ *
+ * @return
+ */
+ public Observable>> getExclusiveAdminAppObservable() {
+ return mAolelearnRetrofit.create(ExclusiveAdminAppApi.class)
+ .getAdminApp()
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread());
+ }
+
/**
* 通过sn获取设备的信息
*
@@ -390,7 +433,8 @@ public class NetInterfaceManager {
mMMKV.decodeString(WHOIS_ADDR, "未知"),
NetworkUtils.getNetworkType(mContext),
NetworkUtils.getOperators(mContext),
- NetworkUtils.getPhoneNumber(mContext)
+ NetworkUtils.getPhoneNumber(mContext),
+ Utils.getDensityDpi(mContext)
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
@@ -618,6 +662,13 @@ public class NetInterfaceManager {
.observeOn(AndroidSchedulers.mainThread());
}
+ public Observable> getSnSettingObservable() {
+ return mRetrofit.create(SnSettingApi.class)
+ .getSnSetting(Utils.getSerial(mContext))
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread());
+ }
+
/*
*
* API
@@ -3150,7 +3201,7 @@ public class NetInterfaceManager {
.subscribe(getSnTimeObserver(null));
}
- private Observer getSnTimeObserver(onCompleteCallback callback) {
+ private Observer> getSnTimeObserver(onCompleteCallback callback) {
return new Observer>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
@@ -3858,4 +3909,85 @@ public class NetInterfaceManager {
}
});
}
+
+ public void getSnSetting(BehaviorSubject lifecycle, onCompleteCallback callback) {
+ getSnSettingObservable()
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .compose(RxLifecycle.bindUntilEvent(lifecycle, ActivityEvent.DESTROY))
+ .subscribe(getSnSettingObserver(callback));
+ }
+
+ public void getSnSetting(onCompleteCallback callback) {
+ getSnSettingObservable()
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(getSnSettingObserver(callback));
+ }
+
+ public void getSnSetting() {
+ getSnSettingObservable()
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(getSnSettingObserver(null));
+ }
+
+ public Observer> getSnSettingObserver(onCompleteCallback callback) {
+ return new Observer>() {
+ @Override
+ public void onSubscribe(@NonNull Disposable d) {
+ Log.e("getSnSetting", "onSubscribe: ");
+ }
+
+ @Override
+ public void onNext(@NonNull BaseResponse snSettingBaseResponse) {
+ Log.e("getSnSetting", "onNext: " + snSettingBaseResponse);
+ if (snSettingBaseResponse.code == OK) {
+ SnSetting snSetting = snSettingBaseResponse.data;
+ int is_timecontrol = snSetting.getIs_timecontrol();
+ int is_storeinstall = snSetting.getIs_storeinstall();
+ Settings.Global.putInt(mContext.getContentResolver(), CommonConfig.AOLEYUN_APPSTORE_INSTALL, is_storeinstall);
+ if (is_timecontrol == 0) {
+ TimeUtils.setEmpty(mContext);
+ TimeUtils.ContralTime c = TimeUtils.getDefaltContralTime(mContext);
+ if (null != c) {
+ Log.e("getTimeControl", c.toString());
+ }
+ } else {
+ String start_time = snSetting.getTimecontrol_start();
+ String end_time = snSetting.getTimecontrol_end();
+ TimeUtils.ContralTime c = TimeUtils.String2ContralTime(mContext, start_time + "-" + end_time);
+ if (null != c) {
+ Log.e("getTimeControl", "OK:" + c.toString());
+ }
+ }
+ } else {
+ TimeUtils.setEmpty(mContext);
+ TimeUtils.ContralTime c = TimeUtils.getDefaltContralTime(mContext);
+ if (null != c) {
+ Log.e("getTimeControl", c.toString());
+ }
+ }
+ }
+
+ @Override
+ public void onError(@NonNull Throwable e) {
+ Log.e("getSnSetting", "onError: " + e.getMessage());
+ onComplete();
+ }
+
+ @Override
+ public void onComplete() {
+ Log.e("getSnSetting", "onComplete: ");
+ Intent intent = new Intent();
+ intent.setAction(MainService.TimeChangedReceiver.ACTION_UPDATE);
+ mContext.sendBroadcast(intent);
+ if (callback != null) {
+ callback.onComplete();
+ }
+ }
+ };
+ }
+
+
}
diff --git a/app/src/main/java/com/aoleyun/sn/network/UrlAddress.java b/app/src/main/java/com/aoleyun/sn/network/UrlAddress.java
index 6db25b3..06a5b2a 100644
--- a/app/src/main/java/com/aoleyun/sn/network/UrlAddress.java
+++ b/app/src/main/java/com/aoleyun/sn/network/UrlAddress.java
@@ -4,6 +4,10 @@ package com.aoleyun.sn.network;
* @author Administrator
*/
public class UrlAddress {
+ /*学习机*/
+ public static final String AOLELEARN_ROOT = "https://led.aolelearn.com/android/";
+ /*获取专属应用*/
+ public static final String GET_EXCLUSIVE_ADMIN_APP = "getExclusiveAdminApp";
/**
* 设备管控信息
@@ -32,6 +36,8 @@ public class UrlAddress {
public static final String GET_ALL_APP = "recommend/index";
/*强制安装应用*/
public static final String GET_FORCE_INSTALL_LIST = "forceinstall/index";
+ /**/
+
/*通过固件名获取内置应用*/
public static final String GET_ROM_APP = "And/getFirmwareApp";
/*获取应用升级自启*/
@@ -78,7 +84,8 @@ public class UrlAddress {
public static final String SEND_BATTERY_INFO = "And/sn/updateBatteryInfo";
/*上传联网时间*/
public static final String NETWORK_CONNECT = "And/network";
-
+ /*获取设备时间管控*/
+ public static final String GET_SN_SETTING = "And/control/getSnSetting";
/**
@@ -113,9 +120,8 @@ public class UrlAddress {
public static final String GET_LOGO_IMG = "Sn/getLogoImg";
/*获取默认桌面升级*/
public static final String GET_DESKTOP = "Sn/getSnDesktop";
- /*获取DIY桌面升级*/
+ /*获取自定义桌面升级*/
public static final String GET_DESKTOPS_DIY_UPDATE = "Sn/getDesktopsDiyUpdate";
-
/*获取系统默认程序*/
public static final String GET_DEFAULT_APP = "app/getDefaultApp";
@@ -138,7 +144,6 @@ public class UrlAddress {
public static final String UPLOAD_IS_LOG_FILE = "And/sn/uploadIsLogFile";
-
/*通过ip获取信息*/
public static final String PCONLINE_WHOIS = "http://whois.pconline.com.cn/";
public static final String WHOIS = "ipJson.jsp";
diff --git a/app/src/main/java/com/aoleyun/sn/network/api/aolelearn/ExclusiveAdminAppApi.java b/app/src/main/java/com/aoleyun/sn/network/api/aolelearn/ExclusiveAdminAppApi.java
new file mode 100644
index 0000000..2c8b1e5
--- /dev/null
+++ b/app/src/main/java/com/aoleyun/sn/network/api/aolelearn/ExclusiveAdminAppApi.java
@@ -0,0 +1,15 @@
+package com.aoleyun.sn.network.api.aolelearn;
+
+import com.aoleyun.sn.bean.AdminAppInfo;
+import com.aoleyun.sn.bean.BaseResponse;
+import com.aoleyun.sn.network.UrlAddress;
+
+import java.util.List;
+
+import io.reactivex.rxjava3.core.Observable;
+import retrofit2.http.GET;
+
+public interface ExclusiveAdminAppApi {
+ @GET(UrlAddress.GET_EXCLUSIVE_ADMIN_APP)
+ Observable>> getAdminApp();
+}
diff --git a/app/src/main/java/com/aoleyun/sn/network/api/get/SnSettingApi.java b/app/src/main/java/com/aoleyun/sn/network/api/get/SnSettingApi.java
new file mode 100644
index 0000000..26b0559
--- /dev/null
+++ b/app/src/main/java/com/aoleyun/sn/network/api/get/SnSettingApi.java
@@ -0,0 +1,16 @@
+package com.aoleyun.sn.network.api.get;
+
+import com.aoleyun.sn.bean.BaseResponse;
+import com.aoleyun.sn.bean.SnSetting;
+import com.aoleyun.sn.network.UrlAddress;
+
+import io.reactivex.rxjava3.core.Observable;
+import retrofit2.http.GET;
+import retrofit2.http.Query;
+
+public interface SnSettingApi {
+ @GET(UrlAddress.GET_SN_SETTING)
+ Observable> getSnSetting(
+ @Query("sn") String sn
+ );
+}
diff --git a/app/src/main/java/com/aoleyun/sn/network/api/post/MACAddressApi.java b/app/src/main/java/com/aoleyun/sn/network/api/post/MACAddressApi.java
index 325fcf9..eb8c684 100644
--- a/app/src/main/java/com/aoleyun/sn/network/api/post/MACAddressApi.java
+++ b/app/src/main/java/com/aoleyun/sn/network/api/post/MACAddressApi.java
@@ -31,6 +31,7 @@ public interface MACAddressApi {
@Field("wifi_operator") String wifi_operator,
@Field("network_type") String network_type,
@Field("network_operator") String network_operator,
- @Field("sn_phone") String sn_phone
+ @Field("sn_phone") String sn_phone,
+ @Field("dpi") int dpi
);
}
diff --git a/app/src/main/java/com/aoleyun/sn/push/PushManager.java b/app/src/main/java/com/aoleyun/sn/push/PushManager.java
index 57e5ee7..22cdceb 100644
--- a/app/src/main/java/com/aoleyun/sn/push/PushManager.java
+++ b/app/src/main/java/com/aoleyun/sn/push/PushManager.java
@@ -8,6 +8,8 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.BatteryManager;
@@ -37,12 +39,14 @@ import com.aoleyun.sn.service.main.MainService;
import com.aoleyun.sn.utils.ApkUtils;
import com.aoleyun.sn.utils.BatteryUtils;
import com.aoleyun.sn.utils.CacheUtils;
+import com.aoleyun.sn.utils.Camera2BackgroundUtil;
import com.aoleyun.sn.utils.CmdUtil;
import com.aoleyun.sn.utils.ForegroundAppUtil;
import com.aoleyun.sn.utils.JGYUtils;
import com.aoleyun.sn.utils.MySQLData;
import com.aoleyun.sn.utils.SPUtils;
import com.aoleyun.sn.utils.ServiceAliveUtils;
+import com.aoleyun.sn.utils.TimeUtils;
import com.aoleyun.sn.utils.ToastUtil;
import com.aoleyun.sn.utils.Utils;
import com.arialyy.aria.core.Aria;
@@ -204,6 +208,14 @@ public class PushManager {
private static final String INFO_BATTERY_INFO = "53";
/*判断是否更新桌面*/
private static final String UPDATE_DESKTOP = "56";
+ /*前置拍照*/
+ private static final String TAKE_FRONT_PICTURE = "58";
+ /*时间管控*/
+ private static final String TIME_CONTROL2 = "59";
+ /*usb传输*/
+ private static final String USB_CONTROL = "61";
+ /*专注模式*/
+ private static final String FOCUS_MODE = "62";
public void setPushContent(String title, String extras) {
switch (title) {
@@ -436,9 +448,9 @@ public class PushManager {
break;
case LOCK_SCREEN:
ToastUtil.betaShow("收到管控:屏幕锁定");
- JsonObject lockJSONObject = GsonUtils.getJsonObject(extras);
- String name = lockJSONObject.get("name").getAsString();
- setLock_screen(1, name);
+// JsonObject lockJSONObject = GsonUtils.getJsonObject(extras);
+// String name = lockJSONObject.get("name").getAsString();
+ setLock_screen(1, "锁屏管控中");
break;
case UNLOCK_SCREEN:
ToastUtil.betaShow("收到管控:屏幕解锁");
@@ -535,10 +547,68 @@ public class PushManager {
case UPDATE_DESKTOP:
NetInterfaceManager.getInstance().getDefaultDesktop();
break;
+ case TAKE_FRONT_PICTURE:
+ ToastUtil.betaShow("收到推送消息: 截图");
+ long createTime = System.currentTimeMillis() / 1000;
+ Camera2BackgroundUtil camera2BackgroundUtil = new Camera2BackgroundUtil(mContext, new Camera2BackgroundUtil.CameraCallBack() {
+ @Override
+ public void onErr(String msg) {
+ Log.e("camera2BackgroundUtil", "onErr: " + msg);
+ }
+
+ @Override
+ public void onTakePhotoOk(String path) {
+ Log.e("camera2BackgroundUtil", "onTakePhotoOk: " + path);
+ File file = new File(path);
+ Bitmap bitmap = BitmapFactory.decodeFile(path);
+ MediaType mediaType = MediaType.Companion.parse("image/png");
+ RequestBody fileBody = RequestBody.Companion.create(file, mediaType);
+ //设置一个file文件
+ MultipartBody.Part body = MultipartBody.Part.createFormData("file", file.getName(), fileBody);
+ Map params = new HashMap<>();
+ params.put("sn", Utils.getSerial(mContext));
+ params.put("createtime", String.valueOf(createTime));
+ Call call = NetInterfaceManager.getInstance().getScreenshotCall().sendScreenshot(params, body);
+ call.enqueue(new RetryCallback(call, 10, 30 * 1000) {
+ @Override
+ public void onRequestResponse(Call call, Response response) {
+ Log.e(TAG, "onRequestResponse: " + response.body().toString());
+ }
+
+ @Override
+ public void onRequestFail(Call call, Throwable t) {
+ Log.e(TAG, "onRequestFail: ");
+ }
+
+ @Override
+ public void onStartRetry() {
+ Log.e(TAG, "onStartRetry: ");
+ }
+ });
+
+ }
+ });
+ camera2BackgroundUtil.startTakePicture(mContext.getExternalCacheDir().getAbsolutePath() + File.separator + TimeUtils.getPhotoDate() + ".jpg");
+ break;
+ case TIME_CONTROL2:
+ case USB_CONTROL:
+ NetInterfaceManager.getInstance().getSnSetting();
+ break;
+ case FOCUS_MODE:
+ refreshFocusMode();
+ break;
default:
}
}
+ private void refreshFocusMode() {
+ Intent intent = new Intent();
+// ComponentName componentName = new ComponentName("com.aoleyunos.dop6", "com.aoleyunos.dop6.service.main.MainService");
+// intent.setComponent(componentName);
+ intent.setAction(CommonConfig.FOCUS_MODE_REFRESH_KEY);
+ mContext.sendBroadcast(intent);
+ }
+
private void deleteApp(String extras) {
if (!TextUtils.isEmpty(extras)) {
JsonObject jsonObject = GsonUtils.getJsonObject(extras);
diff --git a/app/src/main/java/com/aoleyun/sn/service/main/MainSContact.java b/app/src/main/java/com/aoleyun/sn/service/main/MainSContact.java
index cb073af..35bdcf3 100644
--- a/app/src/main/java/com/aoleyun/sn/service/main/MainSContact.java
+++ b/app/src/main/java/com/aoleyun/sn/service/main/MainSContact.java
@@ -80,8 +80,11 @@ public class MainSContact {
void getPoweroffTime();
/*获取时间管控*/
void getSnTimeControl();
+ void getSnSetting();
/*获取电子书包激活码*/
void getEbagCode();
+ /*获取学习应用*/
+ void getExclusiveAdminApp();
/*获取wifi密码*/
void getWiFiPasswd();
}
@@ -154,8 +157,11 @@ public class MainSContact {
void setPoweroffTime();
/*获取时间管控*/
void getSnTimeControlFinish();
+ void getSnSettingFinish();
/*获取电子书包激活码*/
- void getEbagCodeFinish();
+ void getEbagCodeFinish(boolean activation);
+ /*获取学习应用*/
+ void getExclusiveAdminAppFinish();
/*获取wifi密码结束*/
void setWiFiPasswd();
diff --git a/app/src/main/java/com/aoleyun/sn/service/main/MainSPresenter.java b/app/src/main/java/com/aoleyun/sn/service/main/MainSPresenter.java
index b9a49ac..f175960 100644
--- a/app/src/main/java/com/aoleyun/sn/service/main/MainSPresenter.java
+++ b/app/src/main/java/com/aoleyun/sn/service/main/MainSPresenter.java
@@ -9,6 +9,7 @@ import android.util.Log;
import com.alibaba.sdk.android.push.CloudPushService;
import com.alibaba.sdk.android.push.CommonCallback;
import com.alibaba.sdk.android.push.noonesdk.PushServiceFactory;
+import com.aoleyun.sn.bean.AdminAppInfo;
import com.aoleyun.sn.bean.BaseResponse;
import com.aoleyun.sn.bean.StudentsInfo;
import com.aoleyun.sn.comm.CommonConfig;
@@ -31,9 +32,11 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.annotations.NonNull;
import io.reactivex.rxjava3.core.Observer;
import io.reactivex.rxjava3.disposables.Disposable;
+import io.reactivex.rxjava3.schedulers.Schedulers;
import io.reactivex.rxjava3.subjects.BehaviorSubject;
/**
@@ -355,12 +358,12 @@ public class MainSPresenter implements MainSContact.Presenter {
public void getDefaultDesktop() {
Log.e(TAG, "getDefaultDesktop: ");
if (JGYUtils.isOfficialVersion() || !JGYUtils.getInstance().getDeviceIsLocked()) {
- Log.e(TAG, "getDefaultDesktop: "+"Device unLocked");
+ Log.e(TAG, "getDefaultDesktop: " + "Device unLocked");
mView.getDefaultDesktopFinish();
} else {
int aihuaUnlock = Settings.System.getInt(mContext.getContentResolver(), CommonConfig.AIHUA_UNLOCK, 0);
if (JGYUtils.getInstance().isAihuaFramwwork() && aihuaUnlock == 1) {
- Log.e(TAG, "getDefaultDesktop: "+"Device aihua");
+ Log.e(TAG, "getDefaultDesktop: " + "Device aihua");
mView.getDefaultDesktopFinish();
} else {
NetInterfaceManager.getInstance()
@@ -420,7 +423,7 @@ public class MainSPresenter implements MainSContact.Presenter {
@Override
public void getDesktopIcon() {
NetInterfaceManager.getInstance()
- .getDesktopIcon( getLifecycle(), new NetInterfaceManager.onCompleteCallback() {
+ .getDesktopIcon(getLifecycle(), new NetInterfaceManager.onCompleteCallback() {
@Override
public void onComplete() {
Log.e("getDesktopIcon", "onComplete: ");
@@ -539,13 +542,58 @@ public class MainSPresenter implements MainSContact.Presenter {
}
}
+ @Override
+ public void getSnSetting() {
+ NetInterfaceManager.getInstance().getSnSetting(getLifecycle(), new NetInterfaceManager.onCompleteCallback() {
+ @Override
+ public void onComplete() {
+ mView.getSnSettingFinish();
+ }
+ });
+ }
+
@Override
public void getEbagCode() {
NetInterfaceManager.getInstance()
.getEBagCode(true, getLifecycle(), new NetInterfaceManager.onCompleteCallback() {
@Override
public void onComplete() {
- mView.getEbagCodeFinish();
+ mView.getEbagCodeFinish(Settings.Global.getInt(mContext.getContentResolver(), CommonConfig.UIUI_ACTIVATION_KEY, 0) == 1);
+ }
+ });
+ }
+
+ @Override
+ public void getExclusiveAdminApp() {
+ NetInterfaceManager.getInstance().getExclusiveAdminAppObservable()
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY))
+ .subscribe(new Observer>>() {
+ @Override
+ public void onSubscribe(@NonNull Disposable d) {
+ Log.e("getAdminApp", "onSubscribe: ");
+ }
+
+ @Override
+ public void onNext(@NonNull BaseResponse> listBaseResponse) {
+ Log.e("getAdminApp", "onNext: " + listBaseResponse);
+ if (listBaseResponse.code == 200) {
+ List adminAppInfos = listBaseResponse.data;
+ JGYUtils.getInstance().installAdminApp(adminAppInfos);
+ }
+ }
+
+ @Override
+ public void onError(@NonNull Throwable e) {
+ Log.e("getAdminApp", "onError: " + e.getMessage());
+ onComplete();
+ }
+
+ @Override
+ public void onComplete() {
+ Log.e("getAdminApp", "onComplete: ");
+ mView.getExclusiveAdminAppFinish();
}
});
}
diff --git a/app/src/main/java/com/aoleyun/sn/service/main/MainService.java b/app/src/main/java/com/aoleyun/sn/service/main/MainService.java
index bbfb24c..adad8bc 100644
--- a/app/src/main/java/com/aoleyun/sn/service/main/MainService.java
+++ b/app/src/main/java/com/aoleyun/sn/service/main/MainService.java
@@ -1133,11 +1133,28 @@ public class MainService extends Service implements MainSContact.MainView, Netwo
@Override
public void getSnTimeControlFinish() {
+ mPresenter.getSnSetting();
+ }
+
+ @Override
+ public void getSnSettingFinish() {
mPresenter.getEbagCode();
}
@Override
- public void getEbagCodeFinish() {
+ public void getEbagCodeFinish(boolean activation) {
+ if (activation){
+ mPresenter.getExclusiveAdminApp();
+ Log.e(TAG, "getEBagCodeFinish: "+"已激活" );
+ }else {
+ mPresenter.getWiFiPasswd();
+ Log.e(TAG, "getEBagCodeFinish: "+"未激活" );
+ }
+ }
+
+ @Override
+ public void getExclusiveAdminAppFinish() {
+ Log.e(TAG, "getAdminAppFinish: " );
mPresenter.getWiFiPasswd();
}
diff --git a/app/src/main/java/com/aoleyun/sn/utils/Camera2BackgroundUtil.java b/app/src/main/java/com/aoleyun/sn/utils/Camera2BackgroundUtil.java
new file mode 100644
index 0000000..e6e578c
--- /dev/null
+++ b/app/src/main/java/com/aoleyun/sn/utils/Camera2BackgroundUtil.java
@@ -0,0 +1,568 @@
+package com.aoleyun.sn.utils;
+
+import android.Manifest;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.graphics.ImageFormat;
+import android.graphics.SurfaceTexture;
+import android.hardware.Camera;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CameraCaptureSession;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.TotalCaptureResult;
+import android.hardware.camera2.params.StreamConfigurationMap;
+import android.media.Image;
+import android.media.ImageReader;
+import android.media.MediaRecorder;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.util.Size;
+
+import androidx.annotation.NonNull;
+import androidx.core.app.ActivityCompat;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.stream.Collectors;
+
+/**
+ * @作者 Liushihua
+ * @创建时间 2021-2-3 10:54
+ * @描述
+ */
+public class Camera2BackgroundUtil {
+ private static final String TAG = Camera2BackgroundUtil.class.getSimpleName();
+
+ private Context context;
+ private CameraCallBack cameraCallBack;
+ private CameraManager cameraManager;
+ // 默认相机id是0 LENS_FACING_FRONT,LENS_FACING_BACK
+ private int cameraId = CameraCharacteristics.LENS_FACING_FRONT;
+ private CameraDevice mCameraDevice;
+ private String savePath;
+
+ private CaptureRequest.Builder mPreviewRequestBuilder;
+ private CameraCaptureSession mCameraCaptureSession;
+ private CaptureRequest request;
+ private ExecutorService service;
+ private boolean isTakedPicture = false;//是否已经拍照
+
+ private int needSetOrientation = 0;// 设置默认的拍照方向
+ private boolean isInitOk = false;// 是否初始化成功
+ private boolean isSessionClosed = true;// captureSession是否被关闭
+ private boolean isCameraDoing = false;// 是否正在使用相机
+ private final long CAPTURE_DELAY_TIME_LONG = 1200;// 延时拍照——聚焦需要时间
+
+ private final int HANDLER_ERR = 3;// 拍照失败
+ private final int HANDLER_TAKE_PHOTO_SUCCESS = 5;// 拍照成功
+ private List enableCameraList;//可用摄像头列表
+ private boolean mFlashSupported = false;//是否支持闪光灯
+ private List recordSizeList;// 录制尺寸
+ private Size mPreviewOutputSize;// 预览尺寸
+ private List imgOutputSizes;// 拍照尺寸
+
+ private final int PREVIEW_TYPE_NORMAL = 0;// 默认预览
+ private final int PREVIEW_TYPE_RECORD = 1;// 录屏预览
+ private final int PREVIEW_TYPE_TAKE_PHOTO = 2;// 拍照预览
+ private int previewType = 0;//默认预览
+
+ private boolean mTakePictureFinish = false;
+
+ private long lastSaveFileTime = 0;
+
+ public interface CameraCallBack {
+ void onErr(String msg);
+
+ void onTakePhotoOk(String path);
+ }
+
+ /**
+ * 处理静态图片的输出
+ */
+ private ImageReader imageReader;
+
+ private Handler handler = new Handler(Looper.getMainLooper()) {
+ @Override
+ public void handleMessage(Message msg) {
+ super.handleMessage(msg);
+ switch (msg.what) {
+ case HANDLER_ERR:
+ cameraCallBack.onErr("" + msg.obj);
+ isCameraDoing = false;
+ break;
+ case HANDLER_TAKE_PHOTO_SUCCESS:
+ if (!mTakePictureFinish) {
+ cameraCallBack.onTakePhotoOk(savePath);
+ mTakePictureFinish = true;
+ }
+ break;
+ default:
+ }
+ }
+ };
+
+ /**
+ * 当相机设备的状态发生改变的时候,将会回调。
+ */
+ protected final CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
+ /**
+ * 当相机打开的时候,调用
+ * @param cameraDevice
+ */
+ @Override
+ public void onOpened(@NonNull CameraDevice cameraDevice) {
+ Log.e(TAG, "onOpened");
+ mCameraDevice = cameraDevice;
+ startPreview();
+ }
+
+ @Override
+ public void onDisconnected(@NonNull CameraDevice cameraDevice) {
+ Log.e(TAG, "onDisconnected");
+ cameraDevice.close();
+ mCameraDevice = null;
+ Message message = new Message();
+ message.what = HANDLER_ERR;
+ message.obj = "后台相机断开连接";
+ handler.sendMessage(message);
+ }
+
+ /**
+ * 发生异常的时候调用
+ *
+ * 这里释放资源,然后关闭界面
+ * @param cameraDevice
+ * @param error
+ */
+ @Override
+ public void onError(@NonNull CameraDevice cameraDevice, int error) {
+ Log.e(TAG, "onError 相机设备异常,请重启!");
+ cameraDevice.close();
+ mCameraDevice = null;
+ Message messagef = new Message();
+ messagef.what = HANDLER_ERR;
+ messagef.obj = "相机设备异常,请重启!";
+ handler.sendMessage(messagef);
+ }
+
+ /**
+ *当相机被关闭的时候
+ */
+ @Override
+ public void onClosed(@NonNull CameraDevice camera) {
+ super.onClosed(camera);
+ Log.e(TAG, "onClosed");
+ mCameraDevice = null;
+ isCameraDoing = false;
+ }
+ };
+
+ /**
+ * 相机状态回调
+ */
+ private CameraManager.AvailabilityCallback callback = new CameraManager.AvailabilityCallback() {
+ @Override
+ public void onCameraAvailable(@NonNull String cameraId) {// 相机可用
+ super.onCameraAvailable(cameraId);
+ Log.e(TAG, "相机可用");
+ }
+
+ @Override
+ public void onCameraUnavailable(@NonNull String cameraId) {// 相机不可用
+ super.onCameraUnavailable(cameraId);
+ Log.e(TAG, "相机不可用");
+ }
+ };
+
+
+ /**
+ * 初始化
+ *
+ * @param activity
+ * @param cameraCallBack 回调
+ */
+ public Camera2BackgroundUtil(Context activity, @NonNull CameraCallBack cameraCallBack) {
+ this.context = activity;
+ this.cameraCallBack = cameraCallBack;
+ cameraManager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
+ // 对于静态图片,使用可用的最大值来拍摄。
+ if (cameraManager != null) {
+ isInitOk = true;
+ cameraManager.registerAvailabilityCallback(callback, null);
+ getCameraInfo();
+ setupImageReader();
+ service = Executors.newSingleThreadExecutor();
+ }
+ }
+
+ private void setupImageReader() {
+// Size size = getOutputSize(imgOutputSizes);
+ //前三个参数分别是需要的尺寸和格式,最后一个参数代表每次最多获取几帧数据,本例的3代表ImageReader中最多可以获取2帧图像流
+ imageReader = ImageReader.newInstance(1600, 1200, ImageFormat.JPEG, 1);
+ //监听ImageReader的事件,当有图像流数据可用时会回调onImageAvailable方法,它的参数就是预览帧数据,可以对这帧数据进行处理
+ imageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
+ @Override
+ public void onImageAvailable(ImageReader reader) {
+ Image image = reader.acquireLatestImage();
+ //我们可以将这帧数据转成字节数组,类似于Camera1的PreviewCallback回调的预览帧数据
+ ByteBuffer buffer = image.getPlanes()[0].getBuffer();
+ byte[] data = new byte[buffer.remaining()];
+ buffer.get(data);
+ image.close();
+ saveFile(data, savePath);
+ }
+ }, null);
+ }
+
+ /**
+ * 打开相机
+ */
+ private void openCamera() {
+ cameraId = getFrontCameraId();
+ Log.e(TAG, "openCamera: getFrontCameraId = " + getFrontCameraId());
+ Log.e(TAG, "openCamera:" + cameraId);
+ isCameraDoing = true;
+ // 设置TextureView的缓冲区大小
+ // 获取Surface显示预览数据
+ if (ActivityCompat.checkSelfPermission(context, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
+ Message message = new Message();
+ message.what = HANDLER_ERR;
+ message.obj = "权限不足";
+ handler.sendMessage(message);
+ return;
+ }
+ try {
+ cameraManager.openCamera(Integer.toString(cameraId), stateCallback, null);
+ Log.e(TAG, "打开相机成功!");
+ } catch (Exception e) {
+ Log.e(TAG, "打开相机失败-Exception:" + e.getMessage());
+ e.printStackTrace();
+ Message messagef = new Message();
+ messagef.what = HANDLER_ERR;
+ messagef.obj = "打开相机失败";
+ handler.sendMessage(messagef);
+ }
+ }
+
+ private int getFrontCameraId() {
+ int numberOfCameras = Camera.getNumberOfCameras();
+ for (int i = 0; i < numberOfCameras; i++) {
+ Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
+ Camera.getCameraInfo(i, cameraInfo);
+ if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
+ return i;
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * 开始视频录制预览
+ */
+ private void startPreview() {
+ Log.e(TAG, "startPreview");
+ // CaptureRequest添加imageReaderSurface,不加的话就会导致ImageReader的onImageAvailable()方法不会回调
+ // 创建CaptureSession时加上imageReaderSurface,如下,这样预览数据就会同时输出到previewSurface和imageReaderSurface了
+ try {
+ // 创建CaptureRequestBuilder,TEMPLATE_PREVIEW比表示预览请求
+ mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
+ mPreviewRequestBuilder.addTarget(imageReader.getSurface());// 设置Surface作为预览数据的显示界面
+ // 创建相机捕获会话,第一个参数是捕获数据的输出Surface列表,第二个参数是CameraCaptureSession的状态回调接口,当它创建好后会回调onConfigured方法,第三个参数用来确定Callback在哪个线程执行,为null的话就在当前线程执行
+ mCameraDevice.createCaptureSession(Arrays.asList(imageReader.getSurface()), captureSessionStateCallBack, null);
+ } catch (CameraAccessException e) {
+ e.printStackTrace();
+ Message messagef = new Message();
+ messagef.what = HANDLER_ERR;
+ messagef.obj = "捕获帧失败";
+ handler.sendMessage(messagef);
+ Log.e(TAG, "Camera获取成功,创建录制请求或捕获Session失败" + e.getMessage());
+ }
+ }
+
+ /**
+ * 捕获图片数据
+ */
+ private CameraCaptureSession.StateCallback captureSessionStateCallBack = new CameraCaptureSession.StateCallback() {
+ @Override
+ public void onConfigured(CameraCaptureSession session) {
+ try {
+ mCameraCaptureSession = session;
+ isSessionClosed = false;
+ request = mPreviewRequestBuilder.build();
+ // 设置反复捕获数据的请求,这样预览界面就会一直有数据显示
+ mCameraCaptureSession.setRepeatingRequest(request, null, null);
+ } catch (Exception e) {
+ e.printStackTrace();
+ Message messagef = new Message();
+ messagef.what = HANDLER_ERR;
+ messagef.obj = "开启图像预览失败";
+ handler.sendMessage(messagef);
+ }
+ if (!isTakedPicture) {
+ isTakedPicture = true;
+ handler.postDelayed(() -> takePicture(), CAPTURE_DELAY_TIME_LONG);
+ }
+ }
+
+ @Override
+ public void onConfigureFailed(CameraCaptureSession session) {
+ Log.e(TAG, "onConfigureFailed");
+ }
+ };
+
+
+ public void startTakePicture(String savePath) {
+ Log.e(TAG, "拍照:" + savePath);
+ this.savePath = savePath;
+ if (isCameraDoing) {
+ Log.e(TAG, "相机使用中...");
+ } else {
+ isTakedPicture = false;
+ openCamera();
+ }
+ }
+
+ /**
+ * 拍照
+ */
+ private void takePicture() {
+ Log.e(TAG, "takePicture");
+ try {
+ if (mCameraDevice == null || mPreviewRequestBuilder == null) return;
+ mPreviewRequestBuilder.addTarget(imageReader.getSurface());
+ //设置拍照方向
+ mPreviewRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, this.needSetOrientation);
+ //这个回调接口用于拍照结束时重启预览,因为拍照会导致预览停止
+ CameraCaptureSession.CaptureCallback mImageSavedCallback = new CameraCaptureSession.CaptureCallback() {
+ @Override
+ public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) {
+ Log.e(TAG, "拍照完成");
+ onStop();
+ }
+ };
+ //开始拍照,然后回调上面的接口重启预览,因为mCaptureBuilder设置ImageReader作为target,所以会自动回调ImageReader的onImageAvailable()方法保存图片
+ mCameraCaptureSession.capture(mPreviewRequestBuilder.build(), mImageSavedCallback, null);
+ } catch (CameraAccessException e) {
+ Log.e(TAG, "takePhoto CameraAccessException:" + e.getMessage());
+ e.printStackTrace();
+ Message messagef = new Message();
+ messagef.what = HANDLER_ERR;
+ messagef.obj = "拍照失败";
+ handler.sendMessage(messagef);
+ }
+ }
+
+ /**
+ * 停止预览,释放资源
+ */
+ public void stopRecord() {
+ Log.e(TAG, "停止预览,释放资源");
+ try {
+ if (mCameraCaptureSession != null && !isSessionClosed) {
+ mCameraCaptureSession.stopRepeating();
+ mCameraCaptureSession.abortCaptures();
+ mCameraCaptureSession.close();
+ isSessionClosed = true;
+ imageReader.close();
+ imageReader = null;
+ }
+ if (mCameraDevice != null)
+ mCameraDevice.close();
+ isCameraDoing = false;
+ } catch (Exception e) {
+ e.printStackTrace();
+ Log.e(TAG, "stopRecord-Exception:" + e.getMessage());
+ }
+ }
+
+ /**
+ * 重置后,开始预览
+ */
+ public void reset() {
+ previewType = PREVIEW_TYPE_NORMAL;
+ stopRecord();
+ openCamera();
+ }
+
+ /**
+ * 在 activity,fragment的onStop中调用
+ */
+ public void onStop() {
+ stopRecord();
+ }
+
+ /**
+ * 注销 回调
+ */
+ public void onDestroy() {
+ this.cameraCallBack = null;
+ if (cameraManager != null)
+ cameraManager.unregisterAvailabilityCallback(callback);
+ }
+
+ /**
+ * 获得可用的摄像头
+ *
+ * @return SparseArray of available cameras ids。key为摄像头方位,见CameraCharacteristics#LENS_FACING,value为对应的摄像头id
+ */
+ public void getCameras() {
+ if (cameraManager == null) return;
+ enableCameraList = new ArrayList<>();
+ try {
+ String[] camerasAvailable = cameraManager.getCameraIdList();
+ CameraCharacteristics cam;
+ Integer characteristic;
+ Log.e(TAG, "-------------------------------------");
+ for (String id : camerasAvailable) {
+ Log.e(TAG, "getCameras:" + id);
+ try {
+ enableCameraList.add(Integer.parseInt(id));
+ } catch (NumberFormatException e) {
+ e.printStackTrace();
+ }
+ }
+ Log.e(TAG, "-------------------------------------");
+ } catch (CameraAccessException e) {
+ Log.e(TAG, "getCameras CameraAccessException:" + e.getMessage());
+ }
+ }
+
+ /**
+ * 设置输出数据尺寸选择器,在selectCamera之前设置有效
+ * (一般手机支持多种输出尺寸,请用户根据自身需要选择最合适的一种)
+ * 举例:
+ * SizeSelector maxPreview = SizeSelectors.and(SizeSelectors.maxWidth(720), SizeSelectors.maxHeight(480));
+ * SizeSelector minPreview = SizeSelectors.and(SizeSelectors.minWidth(320), SizeSelectors.minHeight(240));
+ * camera.setmOutputSizeSelector(SizeSelectors.or(
+ * SizeSelectors.and(maxPreview, minPreview)//先在最大和最小中寻找
+ * , SizeSelectors.and(maxPreview, SizeSelectors.biggest())//找不到则按不超过最大尺寸的那个选择
+ * ));
+ */
+ public void getOutputSizeSelector() {
+
+ }
+
+
+ /**
+ * 获取摄像头信息
+ */
+ public void getCameraInfo() {
+ if (enableCameraList == null) {
+ getCameras();
+ }
+ try {
+ CameraCharacteristics mCameraCharacteristics = cameraManager.getCameraCharacteristics(String.valueOf(cameraId));
+ // 设置是否支持闪光灯
+ Boolean available = mCameraCharacteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
+ mFlashSupported = available == null ? false : available;
+ StreamConfigurationMap map = mCameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+ if (map == null) {
+ Log.e(TAG, "Could not get configuration map.");
+ return;
+ }
+ int mSensorOrientation = mCameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);//这个方法来获取CameraSensor的方向。
+ Log.e(TAG, "camera sensor orientation:" + mSensorOrientation + ",display rotation=" + context.getDisplay().getRotation());
+
+ int[] formats = map.getOutputFormats();//获得手机支持的输出格式,其中jpeg是一定会支持的,yuv_420_888是api21才开始支持的
+ for (int format : formats) {
+ Log.e(TAG, "手机格式支持: " + format);
+ }
+ Size[] yuvOutputSizes = map.getOutputSizes(ImageFormat.YUV_420_888);
+ Size[] mediaOutputSizes = map.getOutputSizes(MediaRecorder.class);
+ Size[] previewOutputSizes = map.getOutputSizes(SurfaceTexture.class);
+ Size[] jpegOutputSizes = map.getOutputSizes(ImageFormat.JPEG);
+
+ recordSizeList = new ArrayList<>();
+ imgOutputSizes = new ArrayList<>();
+
+ Log.e(TAG, "---------------------------------------------------");
+ for (Size size : mediaOutputSizes) {
+ recordSizeList.add(new Size(size.getWidth(), size.getHeight()));
+ Log.e(TAG, "mediaOutputSizes: " + size.toString());
+ }
+ for (Size size : jpegOutputSizes) {
+ imgOutputSizes.add(new Size(size.getWidth(), size.getHeight()));
+ Log.e(TAG, "jpegOutputSizes: " + size.toString());
+ }
+ for (Size size : previewOutputSizes) {
+ Log.e(TAG, "previewOutputSizes: " + size.toString());
+ }
+ for (Size size : yuvOutputSizes) {
+ Log.e(TAG, "yuvOutputSizes: " + size.toString());
+ }
+ Log.e(TAG, "---------------------------------------------------");
+ } catch (Exception e) {
+ Log.e(TAG, "selectCamera Exception:" + e.getMessage());
+ }
+ }
+
+ private Size getOutputSize(List sizes) {
+ DisplayMetrics dm = context.getResources().getDisplayMetrics();
+ int screenWidth = dm.widthPixels;
+ int screenHeight = dm.heightPixels;
+ Log.e(TAG, "getOutputSize: screenWidth = " + screenWidth);
+ Log.e(TAG, "getOutputSize: screenHeight = " + screenHeight);
+ List sorted = sizes.stream().sorted(new Comparator() {
+ @Override
+ public int compare(Size o1, Size o2) {
+ return Long.compare(o1.getHeight() * o1.getWidth(), o2.getHeight() * o2.getWidth());
+ }
+ }).collect(Collectors.toList());
+ for (Size size : sorted) {
+ if (size.getWidth() > screenHeight && size.getHeight() > screenWidth) {
+ return size;
+ }
+ }
+ return new Size(1600, 1200);
+ }
+
+ //覆盖性保存
+ private void saveFile(final byte[] data, final String savePath) {
+ if (data == null || data.length == 0) return;
+ if (System.currentTimeMillis() - lastSaveFileTime > 1000)
+ service.execute(() -> {
+ File file = new File(savePath);
+ File parent = file.getParentFile();
+ if (parent != null && !parent.exists()) {
+ parent.mkdirs();
+ }
+ if (file.exists()) {
+ file.delete();
+ }
+ try {
+ file.createNewFile();
+ FileOutputStream fos = new FileOutputStream(file);
+ fos.write(data);
+ fos.flush();
+ fos.close();
+ lastSaveFileTime = System.currentTimeMillis();
+ Message message = new Message();
+ message.what = HANDLER_TAKE_PHOTO_SUCCESS;
+ message.obj = savePath;
+ handler.sendMessage(message);
+ } catch (IOException e) {
+ e.printStackTrace();
+ Log.e(TAG, "图片保存-IOException:" + e.getMessage());
+ Message messagef = new Message();
+ messagef.what = HANDLER_ERR;
+ messagef.obj = "图片保存失败";
+ handler.sendMessage(messagef);
+ }
+ });
+ }
+}
+
diff --git a/app/src/main/java/com/aoleyun/sn/utils/JGYUtils.java b/app/src/main/java/com/aoleyun/sn/utils/JGYUtils.java
index 5630640..d548129 100644
--- a/app/src/main/java/com/aoleyun/sn/utils/JGYUtils.java
+++ b/app/src/main/java/com/aoleyun/sn/utils/JGYUtils.java
@@ -38,6 +38,7 @@ import androidx.annotation.RequiresApi;
import androidx.core.content.ContextCompat;
import com.aoleyun.sn.BuildConfig;
+import com.aoleyun.sn.bean.AdminAppInfo;
import com.aoleyun.sn.bean.AppListInfo;
import com.aoleyun.sn.bean.Appground;
import com.aoleyun.sn.bean.BaseResponse;
@@ -2491,4 +2492,44 @@ public class JGYUtils {
}
cacheHelper.put(CONNECTED_TIME_KEY, GsonUtils.toJSONString(connectedTime));
}
+
+
+ public void installAdminApp(List adminAppInfos) {
+ for (AdminAppInfo adminAppInfo : adminAppInfos) {
+ String app_name = adminAppInfo.getApp_name();
+ String app_package = adminAppInfo.getApp_package();
+ String app_url = adminAppInfo.getApp_url();
+ String app_md5 = adminAppInfo.getApp_md5();
+ int app_id = adminAppInfo.getId();
+ long app_version_code = adminAppInfo.getApp_version_code();
+ JsonObject jsonObject = new JsonObject();
+ jsonObject.addProperty("app_name", app_name);
+ jsonObject.addProperty("app_package", app_package);
+ jsonObject.addProperty("app_id", app_id);
+ jsonObject.addProperty("MD5", app_md5);
+ PackageInfo packageInfo = null;
+ try {
+ packageInfo = mContext.getPackageManager().getPackageInfo(app_package, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ }
+ if (packageInfo == null) {
+ Log.e(TAG, "installAdminApp: " + app_package + " 未安装");
+ Utils.ariaDownload(mContext, app_url, jsonObject);
+ } else {
+ long appVersionCode;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+ appVersionCode = packageInfo.getLongVersionCode();
+ } else {
+ appVersionCode = packageInfo.versionCode;
+ }
+ if (app_version_code > appVersionCode) {
+ Log.e(TAG, "installAdminApp: " + app_package + " 更新");
+ Utils.ariaDownload(mContext, app_url, jsonObject);
+ } else {
+ Log.e(TAG, "installAdminApp: " + app_package + "已安装最新版");
+ }
+ }
+ }
+ }
}
diff --git a/app/src/main/java/com/aoleyun/sn/utils/TimeUtils.java b/app/src/main/java/com/aoleyun/sn/utils/TimeUtils.java
index 8fff4db..55855ca 100644
--- a/app/src/main/java/com/aoleyun/sn/utils/TimeUtils.java
+++ b/app/src/main/java/com/aoleyun/sn/utils/TimeUtils.java
@@ -73,6 +73,13 @@ public class TimeUtils {
return zeroTime;
}
+ public static String getPhotoDate() {
+ long millisecond = System.currentTimeMillis();
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
+ Date date = new Date(millisecond);
+ return sdf.format(date);
+ }
+
@RequiresApi(api = Build.VERSION_CODES.O)
public static boolean isTodayTime(long timeStamp) {
String time = transferLongToDate(timeStamp);
diff --git a/app/src/main/java/com/aoleyun/sn/utils/Utils.java b/app/src/main/java/com/aoleyun/sn/utils/Utils.java
index 9e69311..e5be1ea 100644
--- a/app/src/main/java/com/aoleyun/sn/utils/Utils.java
+++ b/app/src/main/java/com/aoleyun/sn/utils/Utils.java
@@ -1322,15 +1322,22 @@ public class Utils {
int screenWidth = (int) (width / density); // 屏幕宽度(dp)
int screenHeight = (int) (height / density);// 屏幕高度(dp)
-// Log.e("h_bl", "屏幕宽度(像素):" + width);
-// Log.e("h_bl", "屏幕高度(像素):" + height);
-// Log.e("h_bl", "屏幕密度(0.75 / 1.0 / 1.5):" + density);
-// Log.e("h_bl", "屏幕密度dpi(120 / 160 / 240):" + densityDpi);
-// Log.e("h_bl", "屏幕宽度(dp):" + screenWidth);
-// Log.e("h_bl", "屏幕高度(dp):" + screenHeight);
+ Log.e("getAndroiodScreenProperty", "屏幕宽度(像素):" + width);
+ Log.e("getAndroiodScreenProperty", "屏幕高度(像素):" + height);
+ Log.e("getAndroiodScreenProperty", "屏幕密度(0.75 / 1.0 / 1.5):" + density);
+ Log.e("getAndroiodScreenProperty", "屏幕密度dpi(120 / 160 / 240):" + densityDpi);
+ Log.e("getAndroiodScreenProperty", "屏幕宽度(dp):" + screenWidth);
+ Log.e("getAndroiodScreenProperty", "屏幕高度(dp):" + screenHeight);
return width + "×" + height;
}
+ public static int getDensityDpi(Context context) {
+ WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+ DisplayMetrics dm = new DisplayMetrics();
+ wm.getDefaultDisplay().getRealMetrics(dm);
+ return dm.densityDpi;
+ }
+
public static String getMacAddress() {
List interfaces = null;
try {
diff --git a/app/src/main/java/com/aoleyun/sn/view/ToggleButton.java b/app/src/main/java/com/aoleyun/sn/view/ToggleButton.java
new file mode 100644
index 0000000..76d9c5a
--- /dev/null
+++ b/app/src/main/java/com/aoleyun/sn/view/ToggleButton.java
@@ -0,0 +1,347 @@
+package com.aoleyun.sn.view;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.RectF;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.View;
+
+import com.aoleyun.sn.R;
+import com.facebook.rebound.SimpleSpringListener;
+import com.facebook.rebound.Spring;
+import com.facebook.rebound.SpringConfig;
+import com.facebook.rebound.SpringSystem;
+import com.facebook.rebound.SpringUtil;
+
+public class ToggleButton extends View {
+ private SpringSystem springSystem;
+ private Spring spring;
+ /**
+ *
+ */
+ private float radius;
+ /**
+ * 开启颜色
+ */
+ private int onColor = Color.parseColor("#00d56b");
+ /**
+ * 关闭颜色
+ */
+ private int offBorderColor = Color.parseColor("#e7e4e4");
+ /**
+ * 灰色带颜色
+ */
+ private int offColor = Color.parseColor("#ffffff");
+ /**
+ * 手柄颜色
+ */
+ private int spotColor = Color.parseColor("#ffffff");
+ /**
+ * 边框颜色
+ */
+ private int borderColor = offBorderColor;
+ /**
+ * 画笔
+ */
+ private Paint paint;
+ /**
+ * 开关状态
+ */
+ private boolean toggleOn = false;
+ /**
+ * 边框大小
+ */
+ private int borderWidth = 2;
+ /**
+ * 垂直中心
+ */
+ private float centerY;
+ /**
+ * 按钮的开始和结束位置
+ */
+ private float startX, endX;
+ /**
+ * 手柄X位置的最小和最大值
+ */
+ private float spotMinX, spotMaxX;
+ /**
+ * 手柄大小
+ */
+ private int spotSize;
+ /**
+ * 手柄X位置
+ */
+ private float spotX;
+ /**
+ * 关闭时内部灰色带高度
+ */
+ private float offLineWidth;
+ /**
+ *
+ */
+ private RectF rect = new RectF();
+ /**
+ * 默认使用动画
+ */
+ private boolean defaultAnimate = true;
+ /**
+ * 是否默认处于打开状态
+ */
+ private boolean isDefaultOn = false;
+ /**
+ * 禁止点击
+ */
+ private boolean disable = false;
+
+ private OnToggleChanged listener;
+
+ public void setDisable(boolean dis) {
+ this.disable = dis;
+ }
+
+ private ToggleButton(Context context) {
+ super(context);
+ }
+
+ public ToggleButton(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ setup(attrs);
+ }
+
+ public ToggleButton(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ setup(attrs);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ spring.removeListener(springListener);
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ spring.addListener(springListener);
+ }
+
+ public void setup(AttributeSet attrs) {
+ paint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ paint.setStyle(Paint.Style.FILL);
+ paint.setStrokeCap(Paint.Cap.ROUND);
+ springSystem = SpringSystem.create();
+ spring = springSystem.createSpring();
+ spring.setSpringConfig(SpringConfig.fromOrigamiTensionAndFriction(50, 7));
+ this.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View arg0) {
+ if (disable) {
+
+ } else {
+ toggle(defaultAnimate);
+ }
+ }
+ });
+ TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.ToggleButton);
+ offBorderColor = typedArray.getColor(R.styleable.ToggleButton_tbOffBorderColor, offBorderColor);
+ onColor = typedArray.getColor(R.styleable.ToggleButton_tbOnColor, onColor);
+ spotColor = typedArray.getColor(R.styleable.ToggleButton_tbSpotColor, spotColor);
+ offColor = typedArray.getColor(R.styleable.ToggleButton_tbOffColor, offColor);
+ borderWidth = typedArray.getDimensionPixelSize(R.styleable.ToggleButton_tbBorderWidth, borderWidth);
+ defaultAnimate = typedArray.getBoolean(R.styleable.ToggleButton_tbAnimate, defaultAnimate);
+ isDefaultOn = typedArray.getBoolean(R.styleable.ToggleButton_tbAsDefaultOn, isDefaultOn);
+ typedArray.recycle();
+ borderColor = offBorderColor;
+ if (isDefaultOn) {
+ toggleOn();
+ }
+ }
+
+ public void toggle() {
+ toggle(true);
+ }
+
+ public void toggle(boolean animate) {
+ toggleOn = !toggleOn;
+ takeEffect(animate);
+ if (listener != null) {
+ listener.onToggle(toggleOn);
+ }
+ }
+
+ public void toggleOn() {
+ setToggleOn();
+ if (listener != null) {
+ listener.onToggle(toggleOn);
+ }
+ }
+
+ public void toggleOff() {
+ setToggleOff();
+ if (listener != null) {
+ listener.onToggle(toggleOn);
+ }
+ }
+
+ /**
+ * 设置显示成打开样式,不会触发toggle事件
+ */
+ public void setToggleOn() {
+ setToggleOn(true);
+ }
+
+ /**
+ * @param animate asd
+ */
+ public void setToggleOn(boolean animate) {
+ toggleOn = true;
+ takeEffect(animate);
+ }
+
+ /**
+ * 设置显示成关闭样式,不会触发toggle事件
+ */
+ public void setToggleOff() {
+ setToggleOff(true);
+ }
+
+ public void setToggleOff(boolean animate) {
+ toggleOn = false;
+ takeEffect(animate);
+ }
+
+ public int isToggleOn() {
+ return toggleOn ? 1 : 0;
+ }
+
+ private void takeEffect(boolean animate) {
+ if (animate) {
+ spring.setEndValue(toggleOn ? 1 : 0);
+ } else {
+//这里没有调用spring,所以spring里的当前值没有变更,这里要设置一下,同步两边的当前值
+ spring.setCurrentValue(toggleOn ? 1 : 0);
+ calculateEffect(toggleOn ? 1 : 0);
+ }
+ }
+
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+ final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+ int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+ int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+ Resources r = Resources.getSystem();
+ if (widthMode == MeasureSpec.UNSPECIFIED || widthMode == MeasureSpec.AT_MOST) {
+ widthSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, r.getDisplayMetrics());
+ widthMeasureSpec = MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY);
+ }
+ if (heightMode == MeasureSpec.UNSPECIFIED || heightSize == MeasureSpec.AT_MOST) {
+ heightSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 30, r.getDisplayMetrics());
+ heightMeasureSpec = MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.EXACTLY);
+ }
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right,
+ int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ final int width = getWidth();
+ final int height = getHeight();
+ radius = Math.min(width, height) * 0.5f;
+ centerY = radius;
+ startX = radius;
+ endX = width - radius;
+ spotMinX = startX + borderWidth;
+ spotMaxX = endX - borderWidth;
+ spotSize = height - 4 * borderWidth;
+ spotX = toggleOn ? spotMaxX : spotMinX;
+ offLineWidth = 0;
+ }
+
+ SimpleSpringListener springListener = new SimpleSpringListener() {
+ @Override
+ public void onSpringUpdate(Spring spring) {
+ final double value = spring.getCurrentValue();
+ calculateEffect(value);
+ }
+ };
+
+ private int clamp(int value, int low, int high) {
+ return Math.min(Math.max(value, low), high);
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+//
+ super.draw(canvas);
+ rect.set(0, 0, getWidth(), getHeight());
+ paint.setColor(borderColor);
+ canvas.drawRoundRect(rect, radius, radius, paint);
+ if (offLineWidth > 0) {
+ final float cy = offLineWidth * 0.5f;
+ rect.set(spotX - cy, centerY - cy, endX + cy, centerY + cy);
+// paint.setColor(offColor);
+ canvas.drawRoundRect(rect, cy, cy, paint);
+ }
+ rect.set(spotX - 1 - radius, centerY - radius, spotX + 1.1f + radius, centerY + radius);
+ paint.setColor(borderColor);
+ canvas.drawRoundRect(rect, radius, radius, paint);
+ final float spotR = spotSize * 0.5f;
+ rect.set(spotX - spotR, centerY - spotR, spotX + spotR, centerY + spotR);
+ paint.setColor(spotColor);
+ canvas.drawRoundRect(rect, spotR, spotR, paint);
+ }
+
+ /**
+ * @param value
+ */
+ private void calculateEffect(final double value) {
+ final float mapToggleX = (float) SpringUtil.mapValueFromRangeToRange(value, 0, 1, spotMinX, spotMaxX);
+ spotX = mapToggleX;
+ float mapOffLineWidth = (float) SpringUtil.mapValueFromRangeToRange(1 - value, 0, 1, 10, spotSize);
+ offLineWidth = mapOffLineWidth;
+ final int fb = Color.blue(onColor);
+ final int fr = Color.red(onColor);
+ final int fg = Color.green(onColor);
+ final int tb = Color.blue(offBorderColor);
+ final int tr = Color.red(offBorderColor);
+ final int tg = Color.green(offBorderColor);
+ int sb = (int) SpringUtil.mapValueFromRangeToRange(1 - value, 0, 1, fb, tb);
+ int sr = (int) SpringUtil.mapValueFromRangeToRange(1 - value, 0, 1, fr, tr);
+ int sg = (int) SpringUtil.mapValueFromRangeToRange(1 - value, 0, 1, fg, tg);
+ sb = clamp(sb, 0, 255);
+ sr = clamp(sr, 0, 255);
+ sg = clamp(sg, 0, 255);
+ borderColor = Color.rgb(sr, sg, sb);
+ postInvalidate();
+ }
+
+ /**
+ * @author ThinkPad
+ */
+ public interface OnToggleChanged {
+ /**
+ * @param on = =
+ */
+ public void onToggle(boolean on);
+ }
+
+ public void setOnToggleChanged(OnToggleChanged onToggleChanged) {
+ listener = onToggleChanged;
+ }
+
+ public boolean isAnimate() {
+ return defaultAnimate;
+ }
+
+ public void setAnimate(boolean animate) {
+ this.defaultAnimate = animate;
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable-hdpi/back.png b/app/src/main/res/drawable-hdpi/back.png
new file mode 100644
index 0000000000000000000000000000000000000000..b9e3ed0557aea0dee2bd4799746deadd007b6704
GIT binary patch
literal 3643
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
N002ovPDHLkV1mdD)kpvU
literal 0
HcmV?d00001
diff --git a/app/src/main/res/drawable-hdpi/com_system_huyan.png b/app/src/main/res/drawable-hdpi/com_system_huyan.png
new file mode 100644
index 0000000000000000000000000000000000000000..d81a835a1da1d47a5ae51015ca2617d6d3aeadec
GIT binary patch
literal 10527
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
literal 0
HcmV?d00001
diff --git a/app/src/main/res/drawable/item_eye_background.xml b/app/src/main/res/drawable/item_eye_background.xml
new file mode 100644
index 0000000..83c3ff9
--- /dev/null
+++ b/app/src/main/res/drawable/item_eye_background.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout-land/activity_main.xml b/app/src/main/res/layout-land/activity_main.xml
index d7aae11..a4e5677 100644
--- a/app/src/main/res/layout-land/activity_main.xml
+++ b/app/src/main/res/layout-land/activity_main.xml
@@ -189,7 +189,7 @@
app:layout_constraintStart_toEndOf="@+id/constraintLayout5" />
+ app:layout_constraintStart_toEndOf="@+id/cl_student" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml
new file mode 100644
index 0000000..2a19fbc
--- /dev/null
+++ b/app/src/main/res/values/attrs.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file