diff --git a/app/build.gradle b/app/build.gradle
index b19725c..7364729 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -27,7 +27,6 @@ android {
buildToolsVersion "29.0.3"
defaultConfig {
- applicationId "com.fuying.sn"
minSdkVersion 24
targetSdkVersion 29
@@ -59,26 +58,31 @@ android {
enabled true
}
- manifestPlaceholders = [
- XG_ACCESS_ID : "1500031216",
- XG_ACCESS_KEY: "A1HBG2922B9Z",
- ]
- buildConfigField "String", "SCREEN_URL", '"https://as.fuyingy.com:3018/wm/is_online"'
- buildConfigField "String", "WEBSOCKET_URL", '"wss://47.111.23.154:3018"'
}
//多版本
productFlavors {
-// beta {
-// flavorDimensions "default"
-// versionCode 33
-// versionName "4.2"
-// }
+ beta {
+ flavorDimensions "default"
+ versionCode 89
+ versionName "4.3"
+// applicationId "com.fuying.sn"
+ applicationId "com.fying.sntest"
+
+ buildConfigField "String", "ROOT_URL", '"https://fxyapi.17hxg.com/android/"'
+ buildConfigField "String", "SCREEN_URL", '"https://fxyapi.17hxg.com:3018/wm/is_online"'
+// buildConfigField "String", "WEBSOCKET_URL", '"wss://47.111.23.154:3018"'
+ }
official {
flavorDimensions "default"
versionCode 88
versionName "3.4.8"
+ applicationId "com.fuying.sn"
+
+ buildConfigField "String", "ROOT_URL", '"https://as.fuyingy.com/android/"'
+ buildConfigField "String", "SCREEN_URL", '"https://as.fuyingy.com:3018/wm/is_online"'
+// buildConfigField "String", "WEBSOCKET_URL", '"wss://47.111.23.154:3018"'
}
}
@@ -555,7 +559,7 @@ dependencies {
// //腾讯移动推送 TPNS
// implementation 'com.tencent.tpns:tpns:1.4.4.2-release'
//阿里云推送
- implementation 'com.aliyun.ams:alicloud-android-push:3.8.0'
+ implementation 'com.aliyun.ams:alicloud-android-push:3.9.3'
// //百度地图
// implementation 'com.baidu.lbsyun:BaiduMapSDK_Location:9.1.8'
//高德地图定位
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a066575..31ef4eb 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -11,6 +11,8 @@
+
+
@@ -46,7 +48,7 @@
-
+
@@ -239,19 +241,19 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -267,10 +269,12 @@
+ android:value="335685739" />
+
+ android:value="713e04b35a6249fc979e3d1f74ad59fd" />
+
\ No newline at end of file
diff --git a/app/src/main/java/com/fuying/sn/activity/home/HomeActivity.java b/app/src/main/java/com/fuying/sn/activity/home/HomeActivity.java
index cda04e7..1bc77ef 100644
--- a/app/src/main/java/com/fuying/sn/activity/home/HomeActivity.java
+++ b/app/src/main/java/com/fuying/sn/activity/home/HomeActivity.java
@@ -2,6 +2,7 @@ package com.fuying.sn.activity.home;
import android.content.Intent;
import android.os.SystemClock;
+import android.provider.Settings;
import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
@@ -13,6 +14,7 @@ import androidx.fragment.app.FragmentManager;
import androidx.viewpager.widget.ViewPager;
import com.blankj.utilcode.util.NetworkUtils;
+import com.fuying.sn.BuildConfig;
import com.fuying.sn.R;
import com.fuying.sn.base.mvvm.BaseMvvmActivity;
import com.fuying.sn.bean.BaseResponse;
@@ -24,6 +26,7 @@ import com.fuying.sn.fragment.BaseFragmentPagerAdapter;
import com.fuying.sn.fragment.device.DeviceFragment;
import com.fuying.sn.manager.ControlManager;
import com.fuying.sn.manager.DeviceManager;
+import com.fuying.sn.manager.time.TimeManager;
import com.fuying.sn.network.NetInterfaceManager;
import com.fuying.sn.utils.SPUtils;
import com.fuying.sn.utils.ToastUtil;
@@ -87,6 +90,12 @@ public class HomeActivity extends BaseMvvmActivity>() {
@Override
public void onChanged(BaseResponse snInfoBaseResponse) {
@@ -186,6 +195,11 @@ public class HomeActivity extends BaseMvvmActivity time_part;
+ long today_time;
+
+ public String getApp_name() {
+ return app_name;
+ }
+
+ public void setApp_name(String app_name) {
+ this.app_name = app_name;
+ }
+
+ public String getApp_package() {
+ return app_package;
+ }
+
+ public void setApp_package(String app_package) {
+ this.app_package = app_package;
+ }
+
+ public int getControl_type() {
+ return control_type;
+ }
+
+ public void setControl_type(int control_type) {
+ this.control_type = control_type;
+ }
+
+ public int getIs_control() {
+ return is_control;
+ }
+
+ public void setIs_control(int is_control) {
+ this.is_control = is_control;
+ }
+
+ public long getWork_time() {
+ return work_time;
+ }
+
+ public void setWork_time(long work_time) {
+ this.work_time = work_time;
+ }
+
+ public long getRest_time() {
+ return rest_time;
+ }
+
+ public void setRest_time(long rest_time) {
+ this.rest_time = rest_time;
+ }
+
+ public List getTime_part() {
+ return time_part;
+ }
+
+ public void setTime_part(List time_part) {
+ this.time_part = time_part;
+ }
+
+ public long getToday_time() {
+ return today_time;
+ }
+
+ public void setToday_time(long today_time) {
+ this.today_time = today_time;
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ return JsonParser.parseString(new Gson().toJson(this)).getAsJsonObject().toString();
+ }
+}
diff --git a/app/src/main/java/com/fuying/sn/bean/SnTimeControlInfo.java b/app/src/main/java/com/fuying/sn/bean/SnTimeControlInfo.java
new file mode 100644
index 0000000..8c6e21d
--- /dev/null
+++ b/app/src/main/java/com/fuying/sn/bean/SnTimeControlInfo.java
@@ -0,0 +1,133 @@
+package com.fuying.sn.bean;
+
+import androidx.annotation.NonNull;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonParser;
+
+import java.io.Serializable;
+import java.util.List;
+
+public class SnTimeControlInfo implements Serializable {
+ private static final long serialVersionUID = -3814696589100564944L;
+
+ int id;
+ /**
+ * 0 不限制,1 限制时长,2限制时间段
+ */
+ int control_type;
+ /**/
+ int is_quota;
+ int is_part;
+ int work_time;
+ int rest_time;
+ int part_type;
+ int today_time;
+ int today_time_update;
+ List time_part;
+ /*今日使用时间*/
+ int sn_use_time_part;
+ int is_set;
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public int getControl_type() {
+ return control_type;
+ }
+
+ public void setControl_type(int control_type) {
+ this.control_type = control_type;
+ }
+
+ public int getIs_quota() {
+ return is_quota;
+ }
+
+ public void setIs_quota(int is_quota) {
+ this.is_quota = is_quota;
+ }
+
+ public int getIs_part() {
+ return is_part;
+ }
+
+ public void setIs_part(int is_part) {
+ this.is_part = is_part;
+ }
+
+ public int getWork_time() {
+ return work_time;
+ }
+
+ public void setWork_time(int work_time) {
+ this.work_time = work_time;
+ }
+
+ public int getRest_time() {
+ return rest_time;
+ }
+
+ public void setRest_time(int rest_time) {
+ this.rest_time = rest_time;
+ }
+
+ public int getPart_type() {
+ return part_type;
+ }
+
+ public void setPart_type(int part_type) {
+ this.part_type = part_type;
+ }
+
+ public int getToday_time() {
+ return today_time;
+ }
+
+ public void setToday_time(int today_time) {
+ this.today_time = today_time;
+ }
+
+ public int getToday_time_update() {
+ return today_time_update;
+ }
+
+ public void setToday_time_update(int today_time_update) {
+ this.today_time_update = today_time_update;
+ }
+
+ public List getTime_part() {
+ return time_part;
+ }
+
+ public void setTime_part(List time_part) {
+ this.time_part = time_part;
+ }
+
+ public int getSn_use_time_part() {
+ return sn_use_time_part;
+ }
+
+ public void setSn_use_time_part(int sn_use_time_part) {
+ this.sn_use_time_part = sn_use_time_part;
+ }
+
+ public int getIs_set() {
+ return is_set;
+ }
+
+ public void setIs_set(int is_set) {
+ this.is_set = is_set;
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ return JsonParser.parseString(new Gson().toJson(this)).getAsJsonObject().toString();
+ }
+}
diff --git a/app/src/main/java/com/fuying/sn/config/CommonConfig.java b/app/src/main/java/com/fuying/sn/config/CommonConfig.java
index f1d75cd..2cb3986 100644
--- a/app/src/main/java/com/fuying/sn/config/CommonConfig.java
+++ b/app/src/main/java/com/fuying/sn/config/CommonConfig.java
@@ -69,9 +69,9 @@ public class CommonConfig {
public static final String AOLE_APP_WEB_WHITE_LIST = "app_web_white_list";
/*内部黑名单*/
public static final String AOLE_APP_WEB_BLACK_LIST = "app_web_black_list";
- /*应用白名单安装总开关*/
- public static final String AOLE_ACTION_APP_FORBID = "aole_app_forbid";
/*应用安装白名单*/
+ public static final String AOLE_ACTION_APP_FORBID = "aole_app_forbid";
+ /*应用白名单安装总开关*/
public static final String AOLE_APP_ALLOW_INSTALL = "aole_app_allow_install";
/*指定应用安装源 非指定包名不能安装apk*/
public static final String APP_SOURCE_WHITE_LIST = "app_source_white_list";
diff --git a/app/src/main/java/com/fuying/sn/desktop/RunningAppManager.java b/app/src/main/java/com/fuying/sn/desktop/RunningAppManager.java
index 4186794..ac9ea71 100644
--- a/app/src/main/java/com/fuying/sn/desktop/RunningAppManager.java
+++ b/app/src/main/java/com/fuying/sn/desktop/RunningAppManager.java
@@ -75,7 +75,7 @@ public class RunningAppManager {
private static final String TAG = "RunningAppManager";
@SuppressLint("StaticFieldLeak")
- private static RunningAppManager mRunningAppManager;
+ private static RunningAppManager sInstance;
private Context mContext;
private MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE);
@@ -149,16 +149,17 @@ public class RunningAppManager {
}
public static void init(Context context) {
- if (mRunningAppManager == null) {
- mRunningAppManager = new RunningAppManager(context);
+ Log.e(TAG, "init: " );
+ if (sInstance == null) {
+ sInstance = new RunningAppManager(context);
}
}
public static RunningAppManager getInstance() {
- if (mRunningAppManager == null) {
+ if (sInstance == null) {
throw new IllegalStateException("You must be init RunningAppManager first");
}
- return mRunningAppManager;
+ return sInstance;
}
/**
@@ -221,7 +222,7 @@ public class RunningAppManager {
public void onComplete() {
Log.i(TAG, "onComplete: ");
NetInterfaceManager.getInstance().getAppTimeControl();
- NetInterfaceManager.getInstance().getSnTimeControl();
+ NetInterfaceManager.getInstance().getMachineTimeControl();
}
});
NetInterfaceManager.getInstance().getMyAppList(new NetInterfaceManager.MyAppListCallback() {
@@ -254,7 +255,7 @@ public class RunningAppManager {
Log.i(TAG, "checkForegroundAppName: 没有剩余时间1");
// removeTask(topPackage);
NetInterfaceManager.getInstance().getAppTimeControl();
- NetInterfaceManager.getInstance().getSnTimeControl();
+ NetInterfaceManager.getInstance().getMachineTimeControl();
JgyUtils.getInstance().killPackage(appPackageName);
killApp();
gotoLauncher();
@@ -268,7 +269,7 @@ public class RunningAppManager {
@Override
public void onComplete() {
NetInterfaceManager.getInstance().getAppTimeControl();
- NetInterfaceManager.getInstance().getSnTimeControl();
+ NetInterfaceManager.getInstance().getMachineTimeControl();
}
});
@@ -285,7 +286,7 @@ public class RunningAppManager {
JgyUtils.getInstance().killPackage(appPackageName);
gotoLauncher();
NetInterfaceManager.getInstance().getAppTimeControl();
- NetInterfaceManager.getInstance().getSnTimeControl();
+ NetInterfaceManager.getInstance().getMachineTimeControl();
} else {
recordPackageOpenTime(topPackage);
Log.i(TAG, "checkForegroundAppName: 没有管控2");
@@ -370,7 +371,7 @@ public class RunningAppManager {
mGlobalUsageTime.clear();
mAllAppUsageTime.clear();
NetInterfaceManager.getInstance().getAppTimeControl();
- NetInterfaceManager.getInstance().getSnTimeControl();
+ NetInterfaceManager.getInstance().getMachineTimeControl();
}
@Override
diff --git a/app/src/main/java/com/fuying/sn/desktop/TimeControlManager.java b/app/src/main/java/com/fuying/sn/desktop/TimeControlManager.java
index c5a594b..598c9ed 100644
--- a/app/src/main/java/com/fuying/sn/desktop/TimeControlManager.java
+++ b/app/src/main/java/com/fuying/sn/desktop/TimeControlManager.java
@@ -5,6 +5,7 @@ import android.content.Context;
import android.text.TextUtils;
import android.util.Log;
+import com.fuying.sn.BuildConfig;
import com.fuying.sn.disklrucache.CacheHelper;
import com.fuying.sn.network.UrlAddress;
import com.google.gson.Gson;
@@ -20,7 +21,7 @@ public class TimeControlManager {
private static final String TAG = "TimeControlManager";
@SuppressLint("StaticFieldLeak")
- private static TimeControlManager mTimeControlManager;
+ private static TimeControlManager sInstance;
private Context mContext;
private CacheHelper mCacheHelper;
@@ -47,16 +48,16 @@ public class TimeControlManager {
}
public static void init(Context context) {
- if (mTimeControlManager == null) {
- mTimeControlManager = new TimeControlManager(context);
+ if (sInstance == null) {
+ sInstance = new TimeControlManager(context);
}
}
public static TimeControlManager getInstance() {
- if (mTimeControlManager == null) {
+ if (sInstance == null) {
throw new IllegalStateException("You must be init TimeControlManager first");
}
- return mTimeControlManager;
+ return sInstance;
}
public HashMap getAppTimeControlMap() {
@@ -111,7 +112,9 @@ public class TimeControlManager {
public void setGlobalMachineControl(MachineControl machineControl) {
this.mGlobalMachineControl = machineControl;
if (machineControl != null) {
- RunningAppManager.getInstance().setGlobalUsageTime(machineControl.getToday_time());
+ if (BuildConfig.VERSION_CODE < 88) {
+ RunningAppManager.getInstance().setGlobalUsageTime(machineControl.getToday_time());
+ }
}
}
@@ -183,7 +186,9 @@ public class TimeControlManager {
appTimeControls.add(appTimeControl);
// }
}
- RunningAppManager.getInstance().syncAppRemainingTime(appTimeControls);
+ if (BuildConfig.VERSION_CODE < 88) {
+ RunningAppManager.getInstance().syncAppRemainingTime(appTimeControls);
+ }
this.mAppTimeControlMap = appTimeControlMap;
}
}
diff --git a/app/src/main/java/com/fuying/sn/fragment/device/DeviceFragment.java b/app/src/main/java/com/fuying/sn/fragment/device/DeviceFragment.java
index 3969339..ddbc492 100644
--- a/app/src/main/java/com/fuying/sn/fragment/device/DeviceFragment.java
+++ b/app/src/main/java/com/fuying/sn/fragment/device/DeviceFragment.java
@@ -74,6 +74,7 @@ public class DeviceFragment extends BaseMvvmFragment mStringAppTimeControlInfoMap;
+
+ // 剩余时间
+ private long mGlobalRemainingTime;
+ private String GLOBAL_REMAINING_TIME_KEY = "GLOBAL_REMAINING_TIME_KEY";
+
+ // 存储每个单独有配置app剩余时间,会改变时间
+ // TODO: 2026/3/16 工作日和休息日时间不同需要同步或重新请求接口
+ private Map mRemainingTimeMap = new HashMap<>();
+
+ public HashSet allowPackage = new HashSet() {
+ {
+ this.add(BuildConfig.APPLICATION_ID);
+ this.add("com.android.launcher3");
+ this.add("com.android.packageinstaller");
+ this.add("com.android.systemui");
+ this.add("com.android.settings");
+ this.add("com.android.permissioncontroller");
+
+ this.add("com.fuying.sn");
+ this.add("com.uiui.os");
+ this.add("com.uiui.store");
+ this.add("com.uiui.info");
+ this.add("com.tt.ttutils");
+ this.add(JgyUtils.fuxiaoying);
+ this.add("com.sprd.engineermode");
+ this.add("com.teclast.update");
+ this.add("com.incar.update");
+ this.add("com.adups.fota");
+ }
+ };
+
+ public TimeManager(Context context) {
+ if (context == null) {
+ throw new RuntimeException("Context is NULL");
+ }
+ this.mContext = context.getApplicationContext();
+ this.mUsageStatsManager = (UsageStatsManager) mContext.getSystemService(Context.USAGE_STATS_SERVICE);
+ this.mPackageManager = mContext.getPackageManager();
+ this.mStringAppTimeControlInfoMap = new HashMap<>();
+ registerTimeReceiver();
+
+ IActivityManager activityManager = ActivityManagerNative.getDefault();
+ try {
+ activityManager.setActivityController(new FuyingActivityController(), false);
+ } catch (RemoteException e) {
+ Log.e(TAG, "setActivityController: " + e.getMessage());
+ e.printStackTrace();
+ }
+
+ ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
+ am.addOnUidImportanceListener(new ActivityManager.OnUidImportanceListener() {
+ @Override
+ public void onUidImportance(int uid, int importance) {
+ String foregroundPackage = getFirstPackageNameForUid(uid);
+ if (!TextUtils.isEmpty(foregroundPackage)) {
+ if (ApkUtils.isSystemApp(mContext, foregroundPackage)) {
+ return;
+ }
+ String previousPackage = AppUsedTimeUtils.getInstance().getApp_package();
+ Log.e(TAG, "onUidImportance: previousPackage = " + previousPackage);
+ long nowTime = System.currentTimeMillis() / 1000;
+ if (importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
+ // 该 UID 切到了前台
+ Log.e(TAG, "onUidImportance: " + foregroundPackage + " foreground");
+
+ AppUsedTimeUtils.getInstance().setApp_package(foregroundPackage);
+ AppUsedTimeUtils.getInstance().setStart_time(nowTime);
+
+ } else {
+ // 该 UID 切到了后台
+ Log.e(TAG, "onUidImportance: " + foregroundPackage + " background");
+ if (foregroundPackage.equals(previousPackage)) {
+ NetInterfaceManager.getInstance().sendAppUsageRecord(foregroundPackage, nowTime,
+ new NetInterfaceManager.CompleteCallback() {
+ @Override
+ public void onComplete() {
+ getTimeControl();
+ }
+ });
+ }
+ }
+ }
+ }
+ }, ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND);
+
+ Type type = new TypeToken() {
+ }.getType();
+ Gson gson = new Gson();
+ String jsonString = mMMKV.decodeString(SN_TIME_CONTROL_INFO, "");
+ try {
+ mSnTimeControlInfo = gson.fromJson(jsonString, type);
+ } catch (Exception e) {
+ Log.e(TAG, "TimeManager: " + e.getMessage());
+ mMMKV.remove(SN_TIME_CONTROL_INFO);
+ }
+
+ mGlobalRemainingTime = mMMKV.decodeLong(GLOBAL_REMAINING_TIME_KEY, 0);
+
+ getTimeControl();
+ inInterval();
+ }
+
+ public static void init(Context context) {
+ Log.e(TAG, "init: ");
+ if (sInstance == null) {
+ sInstance = new TimeManager(context);
+ }
+ }
+
+ public static TimeManager getInstance() {
+ if (sInstance == null) {
+ throw new IllegalStateException("You must be init TimeManager first");
+ }
+ return sInstance;
+ }
+
+ public void getTimeControl() {
+ Log.e(TAG, "getTimeControl: ");
+ getSnTimeControl();
+ getAppTimeControlInfo();
+ }
+
+ public SnTimeControlInfo getSnTimeControlInfo() {
+ return mSnTimeControlInfo;
+ }
+
+ public void setSnTimeControlInfo(SnTimeControlInfo snTimeControlInfo) {
+ mSnTimeControlInfo = snTimeControlInfo;
+ }
+
+ public boolean isGetSnTimeControlInfoSuccessful() {
+ return GetSnTimeControlInfoSuccessful;
+ }
+
+ public void setGetSnTimeControlInfoSuccessful(boolean getSnTimeControlInfoSuccessful) {
+ GetSnTimeControlInfoSuccessful = getSnTimeControlInfoSuccessful;
+ }
+
+ /**
+ * 通过应用的 UID 获取其包名列表。
+ * 注意:由于可能存在多用户或共享 UID 的情况,一个 UID 可能对应多个包名。
+ *
+ * @param uid 要查询的应用 UID
+ * @return 对应 UID 的包名数组。如果未找到,则返回 null 或空数组。
+ */
+ public String[] getPackagesForUid(int uid) {
+ String[] packageNames = mPackageManager.getPackagesForUid(uid);
+ return packageNames; // 可能为 null
+ }
+
+ /**
+ * 便捷方法:获取 UID 对应的第一个包名(通常也是最常用的一个)。
+ *
+ * @param uid 要查询的应用 UID
+ * @return 第一个包名。如果未找到,返回 null。
+ */
+ public String getFirstPackageNameForUid(int uid) {
+ String[] packageNames = getPackagesForUid(uid);
+ if (packageNames != null && packageNames.length > 0) {
+ return packageNames[0];
+ }
+ return null;
+ }
+
+ /**
+ * 初始化计时
+ */
+ private void inInterval() {
+ Observable.interval(1, TimeUnit.SECONDS)
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(new Consumer() {
+ @Override
+ public void accept(Long aLong) throws Throwable {
+ // Log.e(TAG, "inInterval accept: " + aLong);
+ boolean isScreenOn = JgyUtils.getInstance().isScreenOn();
+ if (!isScreenOn) {
+ return;
+ }
+ checkForegroundAppName();
+ }
+ });
+ }
+
+ private void checkForegroundAppName() {
+ String foregroundPackage = getTopActivityInfo();
+ Log.v(TAG, "checkForegroundAppName: foregroundPackage = " + foregroundPackage);
+ // if (mRemainingTimeMap.get(topPackage) != null) {
+ // long remainTime = mRemainingTimeMap.get(topPackage);
+ // }
+ // if (mSnTimeControlInfo != null) {
+ // if (mSnTimeControlInfo.getControl_type() == 1 && mCountdownDisposable ==
+ // null) {
+ // startCountdown();
+ // }
+ // }
+ if (allowPackage.contains(foregroundPackage)) {
+ Log.v(TAG, "checkForegroundAppName: skip");
+ return;
+ }
+ int isControl = Settings.System.getInt(mContext.getContentResolver(), CommonConfig.KEY_IS_CONTROL, 1);
+ Log.e(TAG, "checkForegroundAppName: isControl = " + isControl);
+ // 只要关闭家长管控开关,相关内容需无效
+ if (isControl == 0) {
+ Log.e(TAG, "checkForegroundAppName: 家长管控开关关闭");
+ return;
+ }
+ if (mSnTimeControlInfo == null) {
+ if (!GetSnTimeControlInfoSuccessful) {
+ getSnTimeControl();
+ }
+ Log.e(TAG, "checkForegroundAppName: no SnTimeControlInfo");
+ return;
+ }
+ int snControlType = mSnTimeControlInfo.getControl_type();
+ AppTimeControlInfo appTimeControlInfo = mStringAppTimeControlInfoMap.get(foregroundPackage);
+ if (appTimeControlInfo == null) {
+ // TODO: 2026/3/16 无配置实现逻辑再讨论
+ gotoLauncher();
+ } else {
+ if (snControlType == 0) {// 不限制整机
+ if (!singleApplicationLimit(foregroundPackage)) {
+ gotoLauncher();
+ }
+ } else if (snControlType == 1) {// 整机限制时长
+ if (timeLimit(foregroundPackage)) {
+ Long appRemainingTime = mRemainingTimeMap.get(foregroundPackage);
+ if (appRemainingTime != null) {
+ Log.e(TAG, "checkForegroundAppName: " + foregroundPackage + " appRemainingTime = "
+ + appRemainingTime);
+ //
+ if (appTimeControlInfo.getControl_type() == 0
+ || appTimeControlInfo.getControl_type() == 2) {
+ if (mGlobalRemainingTime <= 0) {
+ gotoLauncher();
+ } else {
+ mGlobalRemainingTime -= 1;
+ }
+ } else {
+ if (appRemainingTime <= 0) {
+ gotoLauncher();
+ } else {
+ long time = appRemainingTime - 1;
+ mRemainingTimeMap.put(foregroundPackage, time);
+ }
+ }
+ } else {
+ gotoLauncher();
+ }
+ } else {
+ gotoLauncher();
+ }
+ } else if (snControlType == 2) {// 整机限制时间段
+ // 应用被禁用
+ if (appTimeControlInfo.getIs_control() == 0) {
+ Toaster.show("应用已被禁用");
+ gotoLauncher();
+ return;
+ }
+ List partTimes = mSnTimeControlInfo.getTime_part();
+ // 是否为默认时间段
+ if (isDefaultTimePeriod(partTimes)) {
+ Log.e(TAG, "checkForegroundAppName: isDefaultTimePeriod true");
+
+ if (appTimeControlInfo.getControl_type() == 1) {
+ Log.e(TAG, "checkForegroundAppName: control_type = 1");
+ Long appRemainTime = mRemainingTimeMap.get(foregroundPackage);
+ if (appRemainTime == null) {
+ Log.e(TAG, "checkForegroundAppName: appRemainTime is null");
+ gotoLauncher();
+ } else {
+ if (appRemainTime <= 0) {
+ gotoLauncher();
+ Toaster.show("今日该应用使用时长已超限");
+ } else {
+ mRemainingTimeMap.put(foregroundPackage, appRemainTime - 1);
+ }
+ }
+ }
+
+ } else {
+ boolean inTime = inOpenTimePeriod(partTimes);
+ Log.e(TAG, "timePeriodLimit: inTime = " + inTime);
+ if (inTime) {
+ if (timePeriodLimit(foregroundPackage)) {
+ Long appRemainTime = mRemainingTimeMap.get(foregroundPackage);
+ if (appRemainTime == null) {
+ Log.e(TAG, "checkForegroundAppName: appRemainTime is null");
+ gotoLauncher();
+ } else {
+ Log.e(TAG, "checkForegroundAppName: appRemainTime = " + appRemainTime);
+ if (appTimeControlInfo.getControl_type() == 0) {
+ Log.e(TAG, "checkForegroundAppName: control_type = 0 allow running");
+ } else if (appTimeControlInfo.getControl_type() == 2) {
+ Log.e(TAG, "checkForegroundAppName: control_type = 2");
+ } else {
+ if (appRemainTime <= 0) {
+ gotoLauncher();
+ Toaster.show("今日该应用使用时长已超限");
+ } else {
+ mRemainingTimeMap.put(foregroundPackage, appRemainTime - 1);
+ }
+ }
+ }
+ } else {
+ gotoLauncher();
+ Toaster.show("当前时间不在应用的可使用时间段内,请前往家长守护查看可用时间段");
+ Log.e(TAG, "timePeriodLimit: Outside of the app's usable time period");
+ }
+ } else {
+ Toaster.show("当前时间不在设备的可使用时间段内,请前往家长守护查看可用时间段");
+ Log.e(TAG, "timePeriodLimit: Outside of the device's usable time period");
+ }
+ }
+ }
+ }
+ }
+
+ private String getTopActivityInfo() {
+ ActivityManager manager = (ActivityManager) mContext.getApplicationContext()
+ .getSystemService(Context.ACTIVITY_SERVICE);
+ List runningTaskInfos = manager.getRunningTasks(1);
+ if (runningTaskInfos != null && !runningTaskInfos.isEmpty()) {
+ ComponentName componentName = runningTaskInfos.get(0).topActivity;
+ if (componentName != null) {
+ String currentClassName = componentName.getPackageName();
+ return currentClassName;
+ }
+ }
+ return "";
+ }
+
+ /**
+ * @param pkg
+ * @return true为可运行,false为禁止运行
+ */
+ public boolean appCanRun(String pkg) {
+ Log.e(TAG, "appCanRun: " + pkg);
+ if (allowPackage.contains(pkg)) {
+ return true;
+ }
+
+ int isControl = Settings.System.getInt(mContext.getContentResolver(), CommonConfig.KEY_IS_CONTROL, 1);
+ Log.e(TAG, "appCanRun: isControl = " + isControl);
+ // 只要关闭家长管控开关,相关内容需无效
+ if (isControl == 0) {
+ Log.e(TAG, "appCanRun: 家长管控开关关闭");
+ return true;
+ }
+ if (mSnTimeControlInfo == null) {
+ if (!GetSnTimeControlInfoSuccessful) {
+ getSnTimeControl();
+ }
+ return false;
+ }
+ int controlType = mSnTimeControlInfo.getControl_type();
+ switch (controlType) {
+ case 0:
+ return singleApplicationLimit(pkg);
+ case 1:
+ return timeLimit(pkg);
+ case 2:
+ return timePeriodLimit(pkg);
+ default:
+ }
+
+ return false;
+ }
+
+ /**
+ * 单个应用限制
+ *
+ * @return
+ */
+ private boolean singleApplicationLimit(String pkg) {
+ AppTimeControlInfo appTimeControlInfo = mStringAppTimeControlInfoMap.get(pkg);
+ if (appTimeControlInfo != null) {
+ Log.e(TAG, "singleApplicationLimit: " + appTimeControlInfo);
+ if (appTimeControlInfo.getIs_control() == 0) {
+ Toaster.show("应用已被禁用");
+ return false;
+ }
+ int control_type = appTimeControlInfo.getControl_type();
+ switch (control_type) {
+ case 0:
+ return true;
+ case 1:
+ return appTimeLimit(pkg);
+ case 2:
+ boolean inTime = inOpenTimePeriod(appTimeControlInfo.getTime_part());
+ if (!inTime) {
+ Toaster.show("当前时间不在应用的可使用时间段内,请前往家长守护查看可用时间段");
+ }
+ return inTime;
+ }
+ } else {
+ Log.e(TAG, "singleApplicationLimit: " + pkg + " not configure");
+ }
+ return false;
+ }
+
+ private Disposable mCountdownDisposable;
+
+ /**
+ * 整机限制时长
+ *
+ * @param pkg
+ * @return
+ */
+ private boolean timeLimit(String pkg) {
+ Log.e(TAG, "timeLimit: remainTime = " + mGlobalRemainingTime);
+ if (mGlobalRemainingTime <= 0) {
+ Toaster.show("今日整机使用时长已超限");
+ return false;
+ } else {
+ boolean canRun = singleApplicationLimit(pkg);
+ if (canRun) {
+ // startSnCountdown();
+ } else {
+ Log.e(TAG, "timeLimit: canRun = " + canRun);
+ }
+ return canRun;
+ }
+ }
+
+ // 在类成员变量区域添加
+ private boolean isSnCountdownRunning = false;
+
+ // 替换 startSnCountdown 方法
+ private void startSnCountdown() {
+ Log.e(TAG, "startCountdown: ");
+
+ // 1. 如果已经在运行,直接返回,避免重复生成
+ if (isSnCountdownRunning) {
+ if (mCountdownDisposable != null && !mCountdownDisposable.isDisposed()) {
+ Log.e(TAG, "startCountdown: already running, skip");
+ return;
+ } else {
+ // 如果标志位是true但Disposable已销毁,重置标志位
+ isSnCountdownRunning = false;
+ }
+ }
+
+ // 2. 清理可能存在的旧连接
+ if (mCountdownDisposable != null && !mCountdownDisposable.isDisposed()) {
+ mCountdownDisposable.dispose();
+ }
+
+ // 3. 检查剩余时间
+ if (mGlobalRemainingTime <= 0) {
+ gotoLauncher();
+ return;
+ }
+
+ // 4. 设置标志位
+ isSnCountdownRunning = true;
+
+ // 5. 创建新的倒计时
+ // 注意:这里使用当前的 mGlobalRemainingTime 作为总时长
+ final long duration = mGlobalRemainingTime;
+
+ mCountdownDisposable = Observable.intervalRange(0, duration, 0, 1, TimeUnit.SECONDS)
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(
+ new Consumer() {
+ @Override
+ public void accept(Long aLong) throws Throwable {
+ // 倒计时进行中,可以在这里更新UI或日志
+ // 注意:不要在这里再次扣减 mGlobalRemainingTime,因为 checkForegroundAppName 可能也在做
+ // 如果希望由这个定时器全权负责扣减,需要修改 checkForegroundAppName
+ Log.e(TAG, "startCountdown tick: " + aLong);
+ }
+ },
+ new Consumer() {
+ @Override
+ public void accept(Throwable throwable) throws Throwable {
+ Log.e(TAG, "startCountdown error: " + throwable.getMessage());
+ isSnCountdownRunning = false;
+ }
+ },
+ new io.reactivex.rxjava3.functions.Action() {
+ @Override
+ public void run() throws Throwable {
+ Log.e(TAG, "startCountdown finished");
+ mGlobalRemainingTime = 0;
+ mMMKV.encode(GLOBAL_REMAINING_TIME_KEY, mGlobalRemainingTime);
+ isSnCountdownRunning = false; // 重置标志
+ gotoLauncher();
+ }
+ });
+ }
+
+ /**
+ * 整机时间段限制
+ *
+ * @param pkg
+ * @return
+ */
+ private boolean timePeriodLimit(String pkg) {
+ List partTimes = mSnTimeControlInfo.getTime_part();
+ if (partTimes == null || partTimes.isEmpty()) {
+ Log.e(TAG, "timePeriodLimit: partTimes is empty");
+ return true;
+ }
+ boolean inTime = inOpenTimePeriod(partTimes);
+ Log.e(TAG, "timePeriodLimit: inTime = " + inTime);
+ if (inTime) {
+ return singleApplicationLimit(pkg);
+ } else {
+ Toaster.show("当前时间不在设备的可使用时间段内,请前往家长守护查看可用时间段");
+ Log.e(TAG, "timePeriodLimit: Outside of the device's usable time period");
+ return false;
+ }
+ }
+
+ private boolean appTimeLimit(String pkg) {
+ AppTimeControlInfo appTimeControlInfo = mStringAppTimeControlInfoMap.get(pkg);
+ if (appTimeControlInfo == null) {
+ Log.e(TAG, "appTimeLimit: " + pkg + " appTimeControlInfo not found");
+ return false;
+ } else {
+ // 不限制时长直接返回
+ if (appTimeControlInfo.getControl_type() == 0) {
+ Log.e(TAG, "appTimeLimit: " + pkg + " not limit");
+ return true;
+ }
+
+ long usageTime = getAppTodayUsageTime(pkg);
+ Log.e(TAG, "appTimeLimit: usageTime = " + usageTime);
+ Long aLong = mRemainingTimeMap.get(pkg);
+ if (aLong != null) {
+ long remainTime = aLong;
+ Log.e(TAG, "appTimeLimit: remainTime = " + remainTime);
+ boolean usedUp = remainTime <= 0;
+ if (usedUp) {
+ Toaster.show("今日该应用使用时长已超限");
+ mRemainingTimeMap.put(pkg, 0L);
+ }
+ return !usedUp;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ /**
+ * 判断时间戳对应日期是否为工作日(周一至周五)。
+ *
+ * @param timestamp 毫秒级时间戳(自1970-01-01T00:00:00Z)
+ * @return true表示工作日,false表示休息日
+ */
+ public static boolean isWorkday(long timestamp) {
+ // 将时间戳转换为Instant,然后根据默认时区获取日期时间
+ Instant instant = Instant.ofEpochMilli(timestamp);
+ ZonedDateTime dateTime = instant.atZone(ZoneId.systemDefault());
+
+ // 获取星期几
+ DayOfWeek dayOfWeek = dateTime.getDayOfWeek();
+
+ // 判断是否为工作日:周一至周五
+ return dayOfWeek != DayOfWeek.SATURDAY && dayOfWeek != DayOfWeek.SUNDAY;
+ }
+
+ public static boolean isWorkday() {
+ long timestamp = System.currentTimeMillis();
+ // 将时间戳转换为Instant,然后根据默认时区获取日期时间
+ Instant instant = Instant.ofEpochMilli(timestamp);
+ ZonedDateTime dateTime = instant.atZone(ZoneId.systemDefault());
+
+ // 获取星期几
+ DayOfWeek dayOfWeek = dateTime.getDayOfWeek();
+
+ // 判断是否为工作日:周一至周五
+ return dayOfWeek != DayOfWeek.SATURDAY && dayOfWeek != DayOfWeek.SUNDAY;
+ }
+
+ /**
+ * 是否在禁用时间段内,只有开放时间段
+ *
+ * @param partTimes
+ * @return
+ */
+ public boolean inOpenTimePeriod(List partTimes) {
+ for (PartTime partTime : partTimes) {
+ if (inOpenTimePeriod(partTime)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public boolean inOpenTimePeriod(PartTime partTime) {
+ int dayType = partTime.getDay_type();
+ if (isDefaultTimePeriod(partTime)) {
+ Log.e(TAG, "inOpenTimePeriod: default settings");
+ return true;
+ }
+
+ String startTimeStr = partTime.getStart_time();
+ String endTimeStr = partTime.getEnd_time();
+
+ // 获取当前日期和时间
+ LocalDate currentDate = LocalDate.now();
+ LocalTime currentTime = LocalTime.now();
+
+ // 判断当前日期是工作日还是周末
+ boolean isWeekday = currentDate.getDayOfWeek() != DayOfWeek.SATURDAY &&
+ currentDate.getDayOfWeek() != DayOfWeek.SUNDAY;
+ boolean dayTypeMatch = (dayType == 0 && isWeekday) || (dayType == 1 && !isWeekday);
+ Log.e(TAG, "inOpenTimePeriod: dayTypeMatch = " + dayTypeMatch);
+
+ if (!dayTypeMatch) {
+ return false; // 日期类型不匹配
+ }
+
+ // 解析时间并比较
+ DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm");
+ LocalTime startTime = LocalTime.parse(startTimeStr, formatter);
+ LocalTime endTime = LocalTime.parse(endTimeStr, formatter);
+
+ boolean inTime = !currentTime.isBefore(startTime) && !currentTime.isAfter(endTime);
+ return inTime;
+ }
+
+ private boolean isDefaultTimePeriod(List partTimeList) {
+ if (partTimeList == null || partTimeList.isEmpty()) {
+ return false; // 或者根据你的业务需求返回 true/false
+ }
+
+ return partTimeList.stream()
+ .allMatch(
+ partTime -> "00:00".equals(partTime.getStart_time()) && "24:00".equals(partTime.getEnd_time()));
+ }
+
+ private boolean isDefaultTimePeriod(PartTime partTime) {
+ String startTimeStr = partTime.getStart_time();
+ String endTimeStr = partTime.getEnd_time();
+
+ if ("00:00".equals(startTimeStr) && "24:00".equals(endTimeStr)) {
+ Log.e(TAG, "isDefaultTimePeriod: default settings");
+ return true;
+ } else {
+ Log.e(TAG, "isDefaultTimePeriod: startTimeStr = " + startTimeStr + "\tendTimeStr = " + endTimeStr);
+ return false;
+ }
+ }
+
+ @Deprecated
+ private void checkTimePeriod() {
+ int controlType = mSnTimeControlInfo.getControl_type();
+ if (controlType == 2) {
+ List partTimes = mSnTimeControlInfo.getTime_part();
+ boolean inTime = inOpenTimePeriod(partTimes);
+ if (!inTime) {
+ gotoLauncher();
+ }
+ }
+ }
+
+ /**
+ * 如果界面正在最近任务列表,有些app可能不会被清理
+ */
+ private void gotoLauncher() {
+ Intent i = new Intent(Intent.ACTION_MAIN);
+ i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // android123提示如果是服务里调用,必须加入new task标识
+ i.addCategory(Intent.CATEGORY_HOME);
+ mContext.startActivity(i);
+ }
+
+ /**
+ * getTotalTimeInForeground 需要应用返回后台才会更新使用时间
+ */
+ private long getAppTodayUsageTime(String pkgName) {
+ Calendar calendar = Calendar.getInstance();
+ calendar.set(Calendar.HOUR_OF_DAY, 0);
+ calendar.set(Calendar.MINUTE, 0);
+ calendar.set(Calendar.SECOND, 0);
+ long startTime = calendar.getTimeInMillis(); // 当天0点
+ long endTime = System.currentTimeMillis(); // 当前时间
+ Map stats = mUsageStatsManager.queryAndAggregateUsageStats(startTime, endTime);
+ UsageStats usageStats = stats.get(pkgName);
+ if (usageStats != null) {
+ long usageTime = usageStats.getTotalTimeInForeground();
+ Log.e(TAG, "getAppUsageTime: " + pkgName + " getTotalTimeInForeground = " + usageTime);
+ return usageTime / 1000;
+ } else {
+ return 0;
+ }
+ }
+
+ public void onDestroy() {
+ if (mCountdownDisposable != null && !mCountdownDisposable.isDisposed()) {
+ mCountdownDisposable.dispose();
+ mCountdownDisposable = null;
+ }
+ if (mTimeChangedReceiver != null) {
+ mContext.unregisterReceiver(mTimeChangedReceiver);
+ }
+ }
+
+ private TimeChangedReceiver mTimeChangedReceiver;
+
+ /**
+ * 监听时间和日期变化
+ */
+ private void registerTimeReceiver() {
+ if (mTimeChangedReceiver == null) {
+ mTimeChangedReceiver = new TimeChangedReceiver();
+ }
+ IntentFilter filter = new IntentFilter();
+ filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+ filter.addAction(Intent.ACTION_DATE_CHANGED);
+ filter.addAction(Intent.ACTION_TIME_CHANGED);
+ filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
+ filter.addAction(Intent.ACTION_TIME_TICK);
+ mContext.registerReceiver(mTimeChangedReceiver, filter);
+ }
+
+ private class TimeChangedReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ Log.e(TAG, "TimeChangedReceiver:" + action);
+
+ switch (action) {
+ case Intent.ACTION_DATE_CHANGED:
+ case Intent.ACTION_TIME_CHANGED:
+ case Intent.ACTION_TIMEZONE_CHANGED:
+ case Intent.ACTION_TIME_TICK:
+ // checkTimePeriod();
+ break;
+ }
+
+ }
+ }
+
+ private void getSnTimeControl() {
+ NetInterfaceManager.getInstance().getSnTimeControlObservable()
+ .subscribe(new Observer>() {
+ @Override
+ public void onSubscribe(@NonNull Disposable d) {
+ Log.e("getSnTimeControl", "onSubscribe: ");
+ }
+
+ @Override
+ public void onNext(@NonNull BaseResponse response) {
+ Log.e("getSnTimeControl", "onNext: " + response);
+ GetSnTimeControlInfoSuccessful = true;
+ if (response.code == 200) {
+ SnTimeControlInfo snTimeControlInfo = response.data;
+ mSnTimeControlInfo = snTimeControlInfo;
+ mMMKV.encode(SN_TIME_CONTROL_INFO, GsonUtils.toJSONString(snTimeControlInfo));
+ mGlobalRemainingTime = snTimeControlInfo.getToday_time();
+ mMMKV.encode(GLOBAL_REMAINING_TIME_KEY, mGlobalRemainingTime);
+ } else {
+
+ }
+ }
+
+ @Override
+ public void onError(@NonNull Throwable e) {
+ Log.e("getSnTimeControl", "onError: " + e.getMessage());
+ }
+
+ @Override
+ public void onComplete() {
+ Log.e("getSnTimeControl", "onComplete: ");
+ }
+ });
+ }
+
+ public void getAppTimeControlInfo() {
+ NetInterfaceManager.getInstance().getAppTimeControlInfoObservable()
+ .subscribe(new Observer>>() {
+ @Override
+ public void onSubscribe(@NonNull Disposable d) {
+ Log.e("getAppTimeControlInfo", "onSubscribe: ");
+ }
+
+ @Override
+ public void onNext(@NonNull BaseResponse> response) {
+ Log.e("getAppTimeControlInfo", "onNext: " + response);
+ if (response.code == 200) {
+ List appTimeControlInfos = response.data;
+ mStringAppTimeControlInfoMap = appTimeControlInfos.stream()
+ .collect(Collectors.toMap(AppTimeControlInfo::getApp_package, Function.identity()));
+ mRemainingTimeMap = appTimeControlInfos.stream().collect(Collectors
+ .toMap(AppTimeControlInfo::getApp_package, AppTimeControlInfo::getToday_time));
+ }
+ }
+
+ @Override
+ public void onError(@NonNull Throwable e) {
+ Log.e("getAppTimeControlInfo", "onError: " + e.getMessage());
+ }
+
+ @Override
+ public void onComplete() {
+ Log.e("getAppTimeControlInfo", "onComplete: ");
+ }
+ });
+ }
+
+}
diff --git a/app/src/main/java/com/fuying/sn/network/NetInterfaceManager.java b/app/src/main/java/com/fuying/sn/network/NetInterfaceManager.java
index 2d926ff..dd700d4 100644
--- a/app/src/main/java/com/fuying/sn/network/NetInterfaceManager.java
+++ b/app/src/main/java/com/fuying/sn/network/NetInterfaceManager.java
@@ -25,6 +25,7 @@ import com.fuying.sn.bean.AppAndWhiteBean;
import com.fuying.sn.bean.AppInfo;
import com.fuying.sn.bean.AppJump;
import com.fuying.sn.bean.AppStart;
+import com.fuying.sn.bean.AppTimeControlInfo;
import com.fuying.sn.bean.AppUploadInfo;
import com.fuying.sn.bean.AppletQRCode;
import com.fuying.sn.bean.BaseResponse;
@@ -39,6 +40,7 @@ import com.fuying.sn.bean.SnBindState;
import com.fuying.sn.bean.SnInfo;
import com.fuying.sn.bean.SnRunLog;
import com.fuying.sn.bean.SnTag;
+import com.fuying.sn.bean.SnTimeControlInfo;
import com.fuying.sn.bean.SystemSettingsSet;
import com.fuying.sn.bean.UserAvatarInfo;
import com.fuying.sn.bean.browser.BrowserApiData;
@@ -53,6 +55,7 @@ import com.fuying.sn.gson.GsonUtils;
import com.fuying.sn.manager.ConnectManager;
import com.fuying.sn.manager.ConnectMode;
import com.fuying.sn.manager.ControlManager;
+import com.fuying.sn.manager.time.TimeManager;
import com.fuying.sn.network.api.AppApi;
import com.fuying.sn.network.api.CommonApi;
import com.fuying.sn.network.api.FileApi;
@@ -63,6 +66,7 @@ import com.fuying.sn.network.api.SnApi;
import com.fuying.sn.network.api.SnControlApi;
import com.fuying.sn.network.api.SnInfoApi;
import com.fuying.sn.network.api.SnLogApi;
+import com.fuying.sn.network.api.newly.ControlApi;
import com.fuying.sn.network.interceptor.RepeatRequestInterceptor;
import com.fuying.sn.service.LogcatService;
import com.fuying.sn.utils.ApkUtils;
@@ -161,7 +165,7 @@ public class NetInterfaceManager {
}
mRetrofit = new Retrofit.Builder()
.client(okHttpClient)
- .baseUrl(UrlAddress.ROOT_URL)
+ .baseUrl(BuildConfig.ROOT_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava3CallAdapterFactory.create())
.build();
@@ -249,7 +253,9 @@ public class NetInterfaceManager {
return mRetrofit.create(ScreenStateApi.class);
}
-
+ public ControlApi getControlApi() {
+ return mRetrofit.create(ControlApi.class);
+ }
/*
@@ -469,7 +475,19 @@ public class NetInterfaceManager {
.observeOn(AndroidSchedulers.mainThread());
}
+ public Observable> getSnTimeControlObservable() {
+ return getControlApi()
+ .getSnTimeControl(Utils.getSerial())
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread());
+ }
+ public Observable>> getAppTimeControlInfoObservable() {
+ return getControlApi()
+ .getAppTimeControl(Utils.getSerial())
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread());
+ }
/*
*
@@ -2443,18 +2461,18 @@ public class NetInterfaceManager {
}
- public void getSnTimeControl(boolean refresh, BehaviorSubject lifecycle, CompleteCallback callback) {
+ public void getMachineTimeControl(boolean refresh, BehaviorSubject lifecycle, CompleteCallback callback) {
ConnectMode connectMode = ConnectMode.DEFAULT;
if (refresh) {
connectMode = ConnectMode.DEFAULT;
}
if (ConnectManager.getInstance().isNeedConnect(UrlAddress.GET_SN_TIME_CONTROL, connectMode)) {
- getSnTimeControl(lifecycle, callback);
+ getMachineTimeControl(lifecycle, callback);
} else {
String jsonString = mCacheHelper.getAsString(UrlAddress.GET_SN_TIME_CONTROL);
//为 "" 是已经请求成功的
if (jsonString == null) {
- getSnTimeControl(lifecycle, callback);
+ getMachineTimeControl(lifecycle, callback);
} else {
// Gson gson = new Gson();
// Type type = new TypeToken() {
@@ -2469,32 +2487,32 @@ public class NetInterfaceManager {
return mCacheHelper.getAsString(UrlAddress.GET_SN_TIME_CONTROL);
}
- public void getSnTimeControl(BehaviorSubject lifecycle, CompleteCallback callback) {
+ public void getMachineTimeControl(BehaviorSubject lifecycle, CompleteCallback callback) {
getMachineTimeControlObservable()
.compose(RxLifecycle.bindUntilEvent(lifecycle, ActivityEvent.DESTROY))
- .subscribe(getSnTimeControlObserver(callback));
+ .subscribe(getMachineTimeControlObserver(callback));
}
- public void getSnTimeControl(CompleteCallback callback) {
+ public void getMachineTimeControl(CompleteCallback callback) {
getMachineTimeControlObservable()
- .subscribe(getSnTimeControlObserver(callback));
+ .subscribe(getMachineTimeControlObserver(callback));
}
- public void getSnTimeControl() {
+ public void getMachineTimeControl() {
getMachineTimeControlObservable()
- .subscribe(getSnTimeControlObserver(null));
+ .subscribe(getMachineTimeControlObserver(null));
}
- public Observer> getSnTimeControlObserver(CompleteCallback callback) {
+ public Observer> getMachineTimeControlObserver(CompleteCallback callback) {
return new Observer>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
- Log.e("getSnTimeControlObserver", "onSubscribe: ");
+ Log.e("getMachineTimeControlObserver", "onSubscribe: ");
}
@Override
public void onNext(@NonNull BaseResponse machineControlBaseResponse) {
- Log.e("getSnTimeControlObserver", "onNext: " + machineControlBaseResponse);
+ Log.e("getMachineTimeControlObserver", "onNext: " + machineControlBaseResponse);
if (machineControlBaseResponse.code == 200) {
MachineControl machineControl = machineControlBaseResponse.data;
TimeControlManager.getInstance().setGlobalMachineControl(machineControl);
@@ -2509,13 +2527,13 @@ public class NetInterfaceManager {
@Override
public void onError(@NonNull Throwable e) {
- Log.e("getSnTimeControlObserver", "onError: " + e.getMessage());
+ Log.e("getMachineTimeControlObserver", "onError: " + e.getMessage());
onComplete();
}
@Override
public void onComplete() {
- Log.e("getSnTimeControlObserver", "onComplete: ");
+ Log.e("getMachineTimeControlObserver", "onComplete: ");
if (callback != null) {
callback.onComplete();
}
@@ -2523,6 +2541,43 @@ public class NetInterfaceManager {
};
}
+ public void sendAppUsageRecord(String packageName, long closeTime, CompleteCallback completeCallback) {
+ int isLogined = (int) SPUtils.get(mContext, CommonConfig.isLogined, 2);
+ if (isLogined != 1) {
+ Log.e(TAG, "sendAppUsageRecord: 没有绑定");
+ // TODO: 2025/6/13 延迟获取不了数据
+// return;
+ }
+
+ String label = ApkUtils.getAppLable(mContext, packageName);
+ long openTime = AppUsedTimeUtils.getInstance().getStart_time();
+
+ NetInterfaceManager.getInstance().getAppUsageRecordObservable(packageName, label, openTime, closeTime)
+ .subscribe(new Observer() {
+ @Override
+ public void onSubscribe(@NonNull Disposable d) {
+ Log.e("sendAppUsageRecord", "onSubscribe: ");
+ }
+
+ @Override
+ public void onNext(@NonNull BaseResponse baseResponse) {
+ Log.e("sendAppUsageRecord", "onNext: " + baseResponse);
+ }
+
+ @Override
+ public void onError(@NonNull Throwable e) {
+ Log.e("sendAppUsageRecord", "onError: " + e.getMessage());
+ onComplete();
+ }
+
+ @Override
+ public void onComplete() {
+ Log.e("sendAppUsageRecord", "onComplete: ");
+ completeCallback.onComplete();
+ }
+ });
+ }
+
public void sendCloseApp(String packageName, CompleteCallback completeCallback) {
int isLogined = (int) SPUtils.get(mContext, CommonConfig.isLogined, 2);
if (isLogined != 1) {
@@ -2539,7 +2594,12 @@ public class NetInterfaceManager {
}
if (null != appInfo) {
String label = appInfo.applicationInfo.loadLabel(pm).toString();
- long openTime = RunningAppManager.getInstance().getOnClickTime();
+ long openTime = 0;
+ if (BuildConfig.VERSION_CODE < 88) {
+ openTime = RunningAppManager.getInstance().getOnClickTime();
+ } else {
+
+ }
long closeTime = System.currentTimeMillis() / 1000;
NetInterfaceManager.getInstance().getAppUsageRecordObservable(packageName, label, openTime, closeTime)
.subscribe(new Observer() {
@@ -3049,17 +3109,18 @@ public class NetInterfaceManager {
@Override
public void onNext(@NonNull BaseResponse screenPasswordBaseResponse) {
- Log.e("onNext", "onSubscribe: ");
+ Log.e("onNext", "onNext: ");
if (screenPasswordBaseResponse.code == 200) {
ScreenPassword screenPassword = screenPasswordBaseResponse.data;
if (screenPassword == null || TextUtils.isEmpty(screenPassword.getPwd())) {
mCacheHelper.put(UrlAddress.LOCK_SCREEN_PWD, "");
} else {
mCacheHelper.put(UrlAddress.LOCK_SCREEN_PWD, GsonUtils.toJSONString(screenPassword));
- SPUtils.put(mContext, UrlAddress.LOCK_SCREEN_PWD, screenPassword.getPwd());
+ mMMKV.encode(UrlAddress.LOCK_SCREEN_PWD, screenPassword.getPwd());
}
} else {
mCacheHelper.put(UrlAddress.LOCK_SCREEN_PWD, "");
+ mMMKV.remove(UrlAddress.LOCK_SCREEN_PWD);
}
}
@@ -3252,4 +3313,53 @@ public class NetInterfaceManager {
}
});
}
+
+ public void getSnTimeControl(BehaviorSubject lifecycle, CompleteCallback callback) {
+ getSnTimeControlObservable()
+ .compose(RxLifecycle.bindUntilEvent(lifecycle, ActivityEvent.DESTROY))
+ .subscribe(getSnTimeControlObserver(callback));
+ }
+
+ public void getSnTimeControl(CompleteCallback callback) {
+ getSnTimeControlObservable()
+ .subscribe(getSnTimeControlObserver(callback));
+ }
+
+ public void getSnTimeControl() {
+ getSnTimeControlObservable()
+ .subscribe(getSnTimeControlObserver(null));
+ }
+
+ public Observer> getSnTimeControlObserver(CompleteCallback callback) {
+ return new Observer>() {
+ @Override
+ public void onSubscribe(@NonNull Disposable d) {
+ Log.e("getSnTimeControlObserver", "onSubscribe: ");
+ }
+
+ @Override
+ public void onNext(@NonNull BaseResponse snTimeControlInfoBaseResponse) {
+ Log.e("getSnTimeControlObserver", "onNext: ");
+ if (snTimeControlInfoBaseResponse.code == 200) {
+ SnTimeControlInfo snTimeControlInfo = snTimeControlInfoBaseResponse.data;
+ TimeManager.getInstance().setSnTimeControlInfo(snTimeControlInfo);
+ mMMKV.encode(TimeManager.SN_TIME_CONTROL_INFO, GsonUtils.toJSONString(snTimeControlInfo));
+ } else {
+ TimeManager.getInstance().setSnTimeControlInfo(null);
+ }
+ TimeManager.getInstance().setGetSnTimeControlInfoSuccessful(true);
+ }
+
+ @Override
+ public void onError(@NonNull Throwable e) {
+ Log.e("getSnTimeControlObserver", "onError: ");
+ }
+
+ @Override
+ public void onComplete() {
+ Log.e("getSnTimeControlObserver", "onComplete: ");
+ }
+ };
+ }
+
}
diff --git a/app/src/main/java/com/fuying/sn/network/UrlAddress.java b/app/src/main/java/com/fuying/sn/network/UrlAddress.java
index a70ce1b..430867a 100644
--- a/app/src/main/java/com/fuying/sn/network/UrlAddress.java
+++ b/app/src/main/java/com/fuying/sn/network/UrlAddress.java
@@ -2,7 +2,7 @@ package com.fuying.sn.network;
public class UrlAddress {
/*主页接口*/
- static final String ROOT_URL = "http://47.111.23.154/android/";
+// static final String ROOT_URL = "http://47.111.23.154/android/";
/*设备信息接口*/
public static final String SN_INFO = "sn/getSnInfo";
diff --git a/app/src/main/java/com/fuying/sn/network/api/newly/ControlApi.java b/app/src/main/java/com/fuying/sn/network/api/newly/ControlApi.java
index 0d2ab50..22695b0 100644
--- a/app/src/main/java/com/fuying/sn/network/api/newly/ControlApi.java
+++ b/app/src/main/java/com/fuying/sn/network/api/newly/ControlApi.java
@@ -1,20 +1,24 @@
package com.fuying.sn.network.api.newly;
+import com.fuying.sn.bean.AppTimeControlInfo;
import com.fuying.sn.bean.BaseResponse;
+import com.fuying.sn.bean.SnTimeControlInfo;
import com.fuying.sn.network.UrlAddress;
+import java.util.List;
+
import io.reactivex.rxjava3.core.Observable;
import retrofit2.http.GET;
import retrofit2.http.Query;
public interface ControlApi {
@GET(UrlAddress.SN_TIME_CONTROL)
- Observable getSnTimeControl(
+ Observable> getSnTimeControl(
@Query("sn") String sn
);
@GET(UrlAddress.APP_TIME_CONTROL)
- Observable getAppTimeControl(
+ Observable>> getAppTimeControl(
@Query("sn") String sn
);
}
diff --git a/app/src/main/java/com/fuying/sn/push/PushManager.java b/app/src/main/java/com/fuying/sn/push/PushManager.java
index 481fa79..8e53dc8 100644
--- a/app/src/main/java/com/fuying/sn/push/PushManager.java
+++ b/app/src/main/java/com/fuying/sn/push/PushManager.java
@@ -29,6 +29,7 @@ import com.fuying.sn.disklrucache.CacheHelper;
import com.fuying.sn.gson.GsonUtils;
import com.fuying.sn.manager.ControlManager;
import com.fuying.sn.manager.DeviceManager;
+import com.fuying.sn.manager.time.TimeManager;
import com.fuying.sn.network.NetInterfaceManager;
import com.fuying.sn.receiver.BootReceiver;
import com.fuying.sn.service.LogcatService;
@@ -575,7 +576,10 @@ public class PushManager {
NetInterfaceManager.getInstance().getSnInfo();
NetInterfaceManager.getInstance().getSystemSettings();
NetInterfaceManager.getInstance().getAppTimeControl();
+ NetInterfaceManager.getInstance().getMachineTimeControl();
NetInterfaceManager.getInstance().getSnTimeControl();
+ TimeManager.getInstance().getTimeControl();
+
}
}, 2345);
}
diff --git a/app/src/main/java/com/fuying/sn/service/ManagerService.java b/app/src/main/java/com/fuying/sn/service/ManagerService.java
index 9388bd2..36c3180 100644
--- a/app/src/main/java/com/fuying/sn/service/ManagerService.java
+++ b/app/src/main/java/com/fuying/sn/service/ManagerService.java
@@ -21,6 +21,7 @@ import android.widget.LinearLayout;
import android.widget.TextView;
import com.blankj.utilcode.util.NetworkUtils;
+import com.fuying.sn.BuildConfig;
import com.fuying.sn.R;
import com.fuying.sn.bean.BaseResponse;
import com.fuying.sn.config.CommonConfig;
@@ -33,6 +34,7 @@ import com.fuying.sn.utils.SPUtils;
import com.fuying.sn.utils.TimeUtils;
import com.fuying.sn.utils.Utils;
import com.google.gson.JsonObject;
+import com.tencent.mmkv.MMKV;
import com.tuo.customview.VerificationCodeView;
import java.util.concurrent.TimeUnit;
@@ -53,6 +55,8 @@ import io.reactivex.rxjava3.schedulers.Schedulers;
public class ManagerService extends Service implements NetworkUtils.OnNetworkStatusChangedListener {
private static final String TAG = "ManagerService";
+ private MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE);
+
public static final String ACTION_LOCK = "LockScreenReceiver_lockscreen";
public static final String ACTION_UNLOCK = "LockScreenReceiver_unlockscreen";
public static final String ACTION_UPDATE = "TimeChangedReceiver_update";
@@ -204,6 +208,10 @@ public class ManagerService extends Service implements NetworkUtils.OnNetworkSta
public static final String LOCK_STATE = "SCRENN_LOOCKED_STATE";
private void showFloatingWindow(String name) {
+ if (BuildConfig.DEBUG) {
+ Log.e(TAG, "showFloatingWindow: debug mode skip");
+ return;
+ }
if (Settings.canDrawOverlays(this)) {
// 获取WindowManager服务
if (null == windowManager) {
@@ -324,17 +332,10 @@ public class ManagerService extends Service implements NetworkUtils.OnNetworkSta
return;
}
Log.e(TAG, "inputComplete: " + content);
- String password = (String) SPUtils.get(ManagerService.this, UrlAddress.LOCK_SCREEN_PWD, "");
- if ((!TextUtils.isEmpty(content) && !TextUtils.isEmpty(password))) {
- if (password.equals(content)) {
- hide();
- }else {
- tv_hint.setText("密码错误");
- }
- } else if (DEFAULT_PASSWORD.equals(content)){
+ String password = mMMKV.decodeString(UrlAddress.LOCK_SCREEN_PWD, DEFAULT_PASSWORD);
+ if (content.equals(password)) {
hide();
- } else{
-// ToastUtil.show("密码错误");
+ } else {
tv_hint.setText("密码错误");
}
}
diff --git a/app/src/main/java/com/fuying/sn/service/RemoteService.java b/app/src/main/java/com/fuying/sn/service/RemoteService.java
index e761b02..2fb60f1 100644
--- a/app/src/main/java/com/fuying/sn/service/RemoteService.java
+++ b/app/src/main/java/com/fuying/sn/service/RemoteService.java
@@ -51,18 +51,26 @@ public class RemoteService extends Service {
@Override
public boolean inControl(String pkg) throws RemoteException {
- boolean control = RunningAppManager.getInstance().inControlTime(pkg);
- Log.e(TAG, "inControl: " + control);
- return control;
+ if (BuildConfig.VERSION_CODE < 88) {
+ boolean control = RunningAppManager.getInstance().inControlTime(pkg);
+ Log.e(TAG, "inControl: " + control);
+ return control;
+ } else {
+ return false;
+ }
}
@Override
public String getDisableContent(String pkg) throws RemoteException {
- String content = RunningAppManager.getInstance().getDisableContent(pkg);
- if (BuildConfig.DEBUG) {
- Log.e(TAG, "getDisableContent: " + content);
+ if (BuildConfig.VERSION_CODE < 88) {
+ String content = RunningAppManager.getInstance().getDisableContent(pkg);
+ if (BuildConfig.DEBUG) {
+ Log.e(TAG, "getDisableContent: " + content);
+ }
+ return content;
+ } else {
+ return "新版本测试";
}
- return content;
}
};
}
diff --git a/app/src/main/java/com/fuying/sn/service/main/MainSPresenter.java b/app/src/main/java/com/fuying/sn/service/main/MainSPresenter.java
index 5d947ec..e60c8ba 100644
--- a/app/src/main/java/com/fuying/sn/service/main/MainSPresenter.java
+++ b/app/src/main/java/com/fuying/sn/service/main/MainSPresenter.java
@@ -5,6 +5,7 @@ import android.content.Intent;
import android.provider.Settings;
import android.util.Log;
+import com.fuying.sn.BuildConfig;
import com.fuying.sn.bean.AppStart;
import com.fuying.sn.bean.BaseResponse;
import com.fuying.sn.bean.MyAppUsageBean;
@@ -329,7 +330,7 @@ public class MainSPresenter implements MainSContact.Presenter {
@Override
public void getSnTimeControl() {
- NetInterfaceManager.getInstance().getSnTimeControl(getLifecycle(), new NetInterfaceManager.CompleteCallback() {
+ NetInterfaceManager.getInstance().getMachineTimeControl(getLifecycle(), new NetInterfaceManager.CompleteCallback() {
@Override
public void onComplete() {
mView.setSnTimeControl();
@@ -342,7 +343,9 @@ public class MainSPresenter implements MainSContact.Presenter {
NetInterfaceManager.getInstance().getMyAppList(new NetInterfaceManager.MyAppListCallback() {
@Override
public void setMyAppList(List myAppList) {
- RunningAppManager.getInstance().syncAllAppUsageTime(myAppList);
+ if (BuildConfig.VERSION_CODE < 88) {
+ RunningAppManager.getInstance().syncAllAppUsageTime(myAppList);
+ }
mView.setMyAppList();
}
});
diff --git a/app/src/main/java/com/fuying/sn/service/main/MainService.java b/app/src/main/java/com/fuying/sn/service/main/MainService.java
index 3ae7dcb..e08862a 100644
--- a/app/src/main/java/com/fuying/sn/service/main/MainService.java
+++ b/app/src/main/java/com/fuying/sn/service/main/MainService.java
@@ -444,7 +444,9 @@ public class MainService extends BaseRxService implements MainSContact.MainView,
Log.e(TAG, "getAppControl: requests have been made today");
} else {
Log.e(TAG, "getAppControl: getConfig");
- RunningAppManager.getInstance().getConfig();
+ if (BuildConfig.VERSION_CODE < 88) {
+ RunningAppManager.getInstance().getConfig();
+ }
}
}
diff --git a/app/src/main/java/com/fuying/sn/utils/ApkUtils.java b/app/src/main/java/com/fuying/sn/utils/ApkUtils.java
index 8847bb3..0d29ad1 100644
--- a/app/src/main/java/com/fuying/sn/utils/ApkUtils.java
+++ b/app/src/main/java/com/fuying/sn/utils/ApkUtils.java
@@ -1033,5 +1033,19 @@ public class ApkUtils {
}
}
+ public static String getAppLable(Context context,String pkgName){
+ PackageManager pm = context.getPackageManager();
+ PackageInfo appInfo = null;
+ try {
+ appInfo = pm.getPackageInfo(pkgName, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ }
+ if (null != appInfo) {
+ String label = appInfo.applicationInfo.loadLabel(pm).toString();
+ return label;
+ }
+ return "unknown";
+ }
}
diff --git a/app/src/main/java/com/fuying/sn/utils/Utils.java b/app/src/main/java/com/fuying/sn/utils/Utils.java
index 99cdcaa..b400fda 100644
--- a/app/src/main/java/com/fuying/sn/utils/Utils.java
+++ b/app/src/main/java/com/fuying/sn/utils/Utils.java
@@ -948,7 +948,7 @@ public class Utils {
// IMEI = TelephonyMgr.getDeviceId();
// } else {//9.0到10.0获取
- IMEI = Settings.System.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
+ IMEI = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
}
// Log.e("IMEI:", "IMEI: " + IMEI);
if (null == IMEI) {
diff --git a/build.gradle b/build.gradle
index 56b0369..f863ec5 100644
--- a/build.gradle
+++ b/build.gradle
@@ -6,6 +6,7 @@ buildscript {
// mavenCentral()
maven { url "https://jitpack.io" }
maven { url 'https://developer.huawei.com/repo/' }
+ maven { url 'https://developer.hihonor.com/repo' }
maven { url 'https://maven.aliyun.com/repository/central' }
maven { url "https://maven.aliyun.com/repository/jcenter" }
maven { url 'https://maven.aliyun.com/repository/public' }
@@ -25,6 +26,7 @@ allprojects {
// mavenCentral()
maven { url "https://jitpack.io" }
maven { url 'https://developer.huawei.com/repo/' }
+ maven { url 'https://developer.hihonor.com/repo' }
maven { url 'https://maven.aliyun.com/repository/central' }
maven { url "https://maven.aliyun.com/repository/jcenter" }
maven { url 'https://maven.aliyun.com/repository/public' }