diff --git a/app/build.gradle b/app/build.gradle index 4668fa8..9c35a2f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -15,7 +15,7 @@ android { buildToolsVersion "29.0.3" defaultConfig { - minSdkVersion 24 + minSdkVersion 26 targetSdkVersion 29 multiDexEnabled true @@ -63,8 +63,8 @@ android { official { flavorDimensions "default" - versionCode 88 - versionName "3.4.8" + versionCode 89 + versionName "3.4.9" applicationId "com.fuying.sn" buildConfigField "String", "ROOT_URL", '"https://as.fuyingy.com/android/"' @@ -570,6 +570,22 @@ project.afterEvaluate { } } +tasks.register('deleteAppSourceWhiteList', Exec) { + // Windows 系统使用 cmd /c, Mac/Linux 使用 sh -c + if (System.properties['os.name'].toLowerCase().contains('windows')) { + commandLine 'cmd', '/c', 'adb', 'shell', 'settings', 'delete', 'system', 'app_source_white_list' + } else { + commandLine 'adb', 'shell', 'settings', 'delete', 'system', 'app_source_white_list' + } + + // 即使命令执行失败也不中断构建(可选,防止因为没连手机导致编译失败) + ignoreExitValue = true + + doLast { + println "ADB command executed: settings delete system app_source_white_list" + } +} + //preBuild { // doLast { // def imlFile = file(project.name + ".iml") diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 31ef4eb..a804d45 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -214,7 +214,7 @@ mStringAppTimeControlInfoMap; + private Map mAppTimeControlMap = new HashMap<>(); - // 剩余时间 + /** + * 记录整机(SN)当前剩余可用时长(秒) + */ 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() { + /** + * 免管控白名单,包含系统核心组件及特定工具应用 + */ + public final 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"); + add(BuildConfig.APPLICATION_ID); + add("com.fuying.sn"); + add("com.fuying.appstore"); + add("com.android.launcher3"); + add("com.android.packageinstaller"); + add("com.android.systemui"); + add("com.android.settings"); + add("com.android.permissioncontroller"); + add("com.uiui.os"); + add("com.uiui.store"); + add("com.uiui.info"); + add("com.tt.ttutils"); + add(JgyUtils.fuxiaoying); + add("com.sprd.engineermode"); + add("com.teclast.update"); + add("com.incar.update"); + add("com.adups.fota"); } }; - public TimeManager(Context context) { + private 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(); + initActivityController(); + initUidImportanceListener(); + loadLocalConfig(); - 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(); + getTimeControl(); // 异步同步服务端配置 + startInIntervalTask(); // 启动每秒检测任务 } public static void init(Context context) { - Log.e(TAG, "init: "); if (sInstance == null) { sInstance = new TimeManager(context); } @@ -189,697 +140,468 @@ public class TimeManager { public static TimeManager getInstance() { if (sInstance == null) { - throw new IllegalStateException("You must be init TimeManager first"); + throw new IllegalStateException("TimeManager must be initialized first. Call init(context)."); } 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 或空数组。 + * 初始化 Activity 控制器,用于拦截 Activity 切换(底层管控手段) */ - 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]; + private void initActivityController() { + try { + IActivityManager activityManager = ActivityManagerNative.getDefault(); + activityManager.setActivityController(new FuyingActivityController(), false); + } catch (RemoteException e) { + Log.e(TAG, "setActivityController failed: " + e.getMessage()); } - return null; } /** - * 初始化计时 + * 监听 UID 重要性变化,用于精确记录应用在前台的使用时长。 + * 优化点:通过 synchronized 锁和状态校验,解决应用切换时 foreground 和 background 事件顺序不确定导致的记录丢失或重复上传问题。 */ - private void inInterval() { + private void initUidImportanceListener() { + ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); + am.addOnUidImportanceListener((uid, importance) -> { + String packageName = getFirstPackageNameForUid(uid); + if (TextUtils.isEmpty(packageName)) { + return; + } + + long nowTime = System.currentTimeMillis() / 1000; + + synchronized (this) { + String recordedPackage = AppUsedTimeUtils.getInstance().getApp_package(); + // 判断当前 UID 是否进入了前台(或者处于更高优先级状态) + boolean enteringForeground = (importance <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND); + + if (enteringForeground) { + // 情况 1: 某个应用进入前台 + if (!packageName.equals(recordedPackage)) { + // 如果之前有正在记录的应用(且不是当前这个),说明发生了应用切换 + // 先结算并上传上一个应用的记录 + if (!TextUtils.isEmpty(recordedPackage)) { + Log.d(TAG, "Detect app switch. Finishing record for: " + recordedPackage); + NetInterfaceManager.getInstance().sendAppUsageRecord(recordedPackage, nowTime, this::getTimeControl); + } + + // 开启对新进入应用的记录(排除系统应用及白名单应用) + if (!ApkUtils.isSystemApp(mContext, packageName) && !isPackageExempted(packageName)) { + Log.d(TAG, "New foreground app: " + packageName + ". Start recording."); + AppUsedTimeUtils.getInstance().setApp_package(packageName); + AppUsedTimeUtils.getInstance().setStart_time(nowTime); + } else { + // 如果是系统应用或豁免应用,则重置记录状态,暂不跟踪 + AppUsedTimeUtils.getInstance().setApp_package(""); + AppUsedTimeUtils.getInstance().setStart_time(0); + } + } + } else { + // 情况 2: 某个应用离开前台 + // 仅当我们当前正在记录该应用时,才触发结算并上传 + if (packageName.equals(recordedPackage)) { + Log.d(TAG, "App moved to background: " + packageName + ". Uploading usage record."); + NetInterfaceManager.getInstance().sendAppUsageRecord(packageName, nowTime, this::getTimeControl); + // 结算后清空记录状态,防止后续重复触发 + AppUsedTimeUtils.getInstance().setApp_package(""); + AppUsedTimeUtils.getInstance().setStart_time(0); + } + } + } + }, ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND); + } + + /** + * 从 MMKV 加载本地缓存的管控配置,保证离线可用性 + */ + private void loadLocalConfig() { + String jsonString = mMMKV.decodeString(SN_TIME_CONTROL_INFO, ""); + if (!TextUtils.isEmpty(jsonString)) { + try { + Type type = new TypeToken() { + }.getType(); + mSnTimeControlInfo = new Gson().fromJson(jsonString, type); + } catch (Exception e) { + Log.e(TAG, "Failed to load local config: " + e.getMessage()); + mMMKV.remove(SN_TIME_CONTROL_INFO); + } + } + mGlobalRemainingTime = mMMKV.decodeLong(GLOBAL_REMAINING_TIME_KEY, 0); + } + + /** + * 核心检测循环:每秒执行一次管控校验 + */ + private void startInIntervalTask() { 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; - } + .subscribe(aLong -> { + if (JgyUtils.getInstance().isScreenOn()) { checkForegroundAppName(); } - }); + }, throwable -> Log.e(TAG, "Interval task error: " + throwable.getMessage())); } + /** + * 检测当前活跃应用的状态,并处理时长扣减或强制退出 + */ 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; - } + String pkg = getTopActivityPackageName(); + if (TextUtils.isEmpty(pkg)) return; + + // 1. 豁免条件:白名单或家长管控总开关已关闭 + if (isPackageExempted(pkg)) return; + + // 2. 检查基本配置是否就绪 if (mSnTimeControlInfo == null) { - if (!GetSnTimeControlInfoSuccessful) { - getSnTimeControl(); - } - Log.e(TAG, "checkForegroundAppName: no SnTimeControlInfo"); + if (!mGetSnTimeControlInfoSuccessful) getSnTimeControl(); return; } - int snControlType = mSnTimeControlInfo.getControl_type(); - AppTimeControlInfo appTimeControlInfo = mStringAppTimeControlInfoMap.get(foregroundPackage); - if (appTimeControlInfo == null) { - // TODO: 2026/3/16 无配置实现逻辑再讨论 + + // 3. 运行权限动态校验 + if (!appCanRun(pkg)) { 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"); + return; + } - 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); - } - } - } + // 4. 时长扣减(仅在允许运行的情况下执行) + decrementUsageTime(pkg); + } - } 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 boolean isPackageExempted(String pkg) { + if (allowPackage.contains(pkg)) return true; + int isControl = Settings.System.getInt(mContext.getContentResolver(), CommonConfig.KEY_IS_CONTROL, 1); + return isControl == 0; + } + + /** + * 校验指定应用在当前状态下是否允许运行 + * + * @param pkg 应用包名 + * @return true 允许运行,false 触发拦截 + */ + public boolean appCanRun(String pkg) { + if (isPackageExempted(pkg)) return true; + if (mSnTimeControlInfo == null) return false; + + AppTimeControlInfo appInfo = mAppTimeControlMap.get(pkg); + if (appInfo == null) { + Log.w(TAG, "appCanRun: Application [" + pkg + "] is not in the controlled list. Blocking by default."); + Toaster.show("应用已被禁用"); + return false; + } + + // 应用是否被手动禁用 (is_control == 0) + if (appInfo.getIs_control() == 0) { + Toaster.show("应用已被禁用"); + return false; + } + + // A. 校验整机(SN)层级的限制 + if (!checkSnLevelControl()) return false; + + // B. 校验应用(App)自身的独立限制 + return checkAppLevelControl(pkg, appInfo); + } + + /** + * 整机(SN)级别管控逻辑:时长模式或时间段模式 + */ + private boolean checkSnLevelControl() { + int snType = mSnTimeControlInfo.getControl_type(); + switch (snType) { + case 1: // 整机限时:如果整机时间耗尽,则拦截(无论应用是否开启独立时长) + if (mGlobalRemainingTime <= 0) { + Toaster.show("今日整机使用时长已超限"); + return false; } + break; + case 2: // 整机限时间段:当前时间需在整机允许的时间段内 + List snParts = mSnTimeControlInfo.getTime_part(); + if (!isDefaultTimePeriod(snParts) && !inOpenTimePeriod(snParts)) { + Toaster.show("当前时间不在设备的可使用时间段内"); + return false; + } + break; + } + return true; + } + + /** + * 应用(App)级别管控逻辑:独立时长或独立时间段 + */ + private boolean checkAppLevelControl(String pkg, AppTimeControlInfo appInfo) { + switch (appInfo.getControl_type()) { + case 1: // 应用时长限制:检查该应用剩余时长 + Long remain = mRemainingTimeMap.get(pkg); + if (remain == null || remain <= 0) { + Toaster.show("今日该应用使用时长已超限"); + return false; + } + break; + case 2: // 应用时间段限制:检查当前是否在应用允许的时间段 + if (!inOpenTimePeriod(appInfo.getTime_part())) { + Toaster.show("当前时间不在应用的可使用时间段内"); + return false; + } + break; + } + return true; + } + + /** + * 时长扣减逻辑:根据当前整机模式和应用模式,扣减相应的计数器。 + * 优化点:只要整机开启了限时模式,所有管控应用的使用都会扣减整机时长。 + */ + private void decrementUsageTime(String pkg) { + AppTimeControlInfo appInfo = mAppTimeControlMap.get(pkg); + if (appInfo == null) return; + + int snType = mSnTimeControlInfo.getControl_type(); + int appType = appInfo.getControl_type(); + + // 1. 扣减整机时长(如果整机是限时模式) + if (snType == 1) { + if (mGlobalRemainingTime > 0) { + mGlobalRemainingTime--; + mMMKV.encode(GLOBAL_REMAINING_TIME_KEY, mGlobalRemainingTime); + } + } + + // 2. 扣减应用独立时长(如果应用是限时模式) + if (appType == 1) { + Long remain = mRemainingTimeMap.get(pkg); + if (remain != null && remain > 0) { + mRemainingTimeMap.put(pkg, remain - 1); } } } - 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; - } + /** + * 获取最顶层的应用包名 + */ + private String getTopActivityPackageName() { + ActivityManager manager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); + List tasks = manager.getRunningTasks(1); + if (tasks != null && !tasks.isEmpty()) { + ComponentName top = tasks.get(0).topActivity; + return top != null ? top.getPackageName() : ""; } return ""; } /** - * @param pkg - * @return true为可运行,false为禁止运行 + * 获取指定 UID 的第一个包名 */ - 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; + public String getFirstPackageNameForUid(int uid) { + String[] packages = mPackageManager.getPackagesForUid(uid); + return (packages != null && packages.length > 0) ? packages[0] : null; } /** - * 单个应用限制 - * - * @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); + Intent intent = new Intent(Intent.ACTION_MAIN); + intent.addCategory(Intent.CATEGORY_HOME); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); + + // 优先定位到当前的默认桌面应用,避免在存在多个桌面时弹出系统选择框 + ResolveInfo resolveInfo = mPackageManager.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY); + if (resolveInfo != null && resolveInfo.activityInfo != null && !resolveInfo.activityInfo.packageName.equals("android")) { + intent.setComponent(new ComponentName(resolveInfo.activityInfo.packageName, resolveInfo.activityInfo.name)); + } + + try { + mContext.startActivity(intent); + } catch (Exception e) { + Log.e(TAG, "gotoLauncher failed: " + e.getMessage()); + // 如果精准跳转失败,则使用基础的 Home Intent + Intent fallback = new Intent(Intent.ACTION_MAIN); + fallback.addCategory(Intent.CATEGORY_HOME); + fallback.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + mContext.startActivity(fallback); + } + } + + // --- 日期与时间管控工具方法 --- + + public boolean isWorkday() { + DayOfWeek day = LocalDate.now().getDayOfWeek(); + return day != DayOfWeek.SATURDAY && day != DayOfWeek.SUNDAY; } /** - * 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 boolean inOpenTimePeriod(List partTimes) { + if (partTimes == null || partTimes.isEmpty()) { + return false; } + for (PartTime pt : partTimes) { + if (inOpenTimePeriod(pt)) return true; + } + return false; } - 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(); + public boolean inOpenTimePeriod(PartTime pt) { + boolean isWeekday = isWorkday(); + // day_type: 0-仅工作日生效, 1-仅休息日生效 + if ((pt.getDay_type() == 0 && !isWeekday) || (pt.getDay_type() == 1 && isWeekday)) { + return false; } - 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); + if (isDefaultTimePeriod(pt)) { + return true; + } - switch (action) { - case Intent.ACTION_DATE_CHANGED: - case Intent.ACTION_TIME_CHANGED: - case Intent.ACTION_TIMEZONE_CHANGED: - case Intent.ACTION_TIME_TICK: - // checkTimePeriod(); - break; + LocalTime now = LocalTime.now(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm"); + try { + LocalTime start = LocalTime.parse(pt.getStart_time(), formatter); + // 处理 24:00 情况,LocalTime 不支持 24:00 + if ("24:00".equals(pt.getEnd_time())) { + return !now.isBefore(start); } - + LocalTime end = LocalTime.parse(pt.getEnd_time(), formatter); + return !now.isBefore(start) && !now.isAfter(end); + } catch (Exception e) { + Log.e(TAG, "Time parse error for: " + pt.getStart_time() + " - " + pt.getEnd_time()); + return false; } } + /** + * 是否为全天开放(00:00 - 24:00) + * 且满足当日生效条件 + */ + public boolean isDefaultTimePeriod(PartTime pt) { + boolean isWeekday = isWorkday(); + // day_type: 0-仅工作日生效, 1-仅休息日生效 + if ((pt.getDay_type() == 0 && !isWeekday) || (pt.getDay_type() == 1 && isWeekday)) { + return false; + } + return "00:00".equals(pt.getStart_time()) && "24:00".equals(pt.getEnd_time()); + } + + public boolean isDefaultTimePeriod(List list) { + if (list == null || list.isEmpty()) return false; + return list.stream().anyMatch(this::isDefaultTimePeriod); + } + + // --- 网络接口请求 --- + + public void getTimeControl() { + Log.d(TAG, "Syncing time control config from server..."); + getSnTimeControl(); + getAppTimeControlInfo(); + } + 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(); + mGetSnTimeControlInfoSuccessful = true; + if (response.code == 200 && response.data != null) { + mSnTimeControlInfo = response.data; + mMMKV.encode(SN_TIME_CONTROL_INFO, GsonUtils.toJSONString(mSnTimeControlInfo)); + mGlobalRemainingTime = mSnTimeControlInfo.getToday_time(); mMMKV.encode(GLOBAL_REMAINING_TIME_KEY, mGlobalRemainingTime); - } else { - } } @Override public void onError(@NonNull Throwable e) { - Log.e("getSnTimeControl", "onError: " + e.getMessage()); + Log.e(TAG, "getSnTimeControl failed: " + e.getMessage()); } @Override public void onComplete() { - Log.e("getSnTimeControl", "onComplete: "); } }); } - public void getAppTimeControlInfo() { + private 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)); + if (response.code == 200 && response.data != null) { + List list = response.data; + mAppTimeControlMap = list.stream().collect(Collectors.toMap(AppTimeControlInfo::getApp_package, Function.identity(), (v1, v2) -> v1)); + mRemainingTimeMap = list.stream().collect(Collectors.toMap(AppTimeControlInfo::getApp_package, AppTimeControlInfo::getToday_time, (v1, v2) -> v1)); } } @Override public void onError(@NonNull Throwable e) { - Log.e("getAppTimeControlInfo", "onError: " + e.getMessage()); + Log.e(TAG, "getAppTimeControlInfo failed: " + e.getMessage()); } @Override public void onComplete() { - Log.e("getAppTimeControlInfo", "onComplete: "); } }); } + // --- 广播监听 --- + + private void registerTimeReceiver() { + IntentFilter filter = new IntentFilter(); + 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(new TimeChangedReceiver(), filter); + } + + private static class TimeChangedReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + Log.d(TAG, "System time/date changed: " + intent.getAction()); + } + } + + public void onDestroy() { + // 必要时清理资源 + } + + // --- Getters & Setters --- + + public SnTimeControlInfo getSnTimeControlInfo() { + return mSnTimeControlInfo; + } + + public void setSnTimeControlInfo(SnTimeControlInfo snTimeControlInfo) { + this.mSnTimeControlInfo = snTimeControlInfo; + if (snTimeControlInfo != null) { + this.mGlobalRemainingTime = snTimeControlInfo.getToday_time(); + mMMKV.encode(GLOBAL_REMAINING_TIME_KEY, mGlobalRemainingTime); + } + } + + public boolean isGetSnTimeControlInfoSuccessful() { + return mGetSnTimeControlInfoSuccessful; + } + + public void setGetSnTimeControlInfoSuccessful(boolean successful) { + this.mGetSnTimeControlInfoSuccessful = successful; + } } 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 dd700d4..3722c56 100644 --- a/app/src/main/java/com/fuying/sn/network/NetInterfaceManager.java +++ b/app/src/main/java/com/fuying/sn/network/NetInterfaceManager.java @@ -813,54 +813,54 @@ public class NetInterfaceManager { */ public void SendAppInstallInfo() { Observable.create(new ObservableOnSubscribe() { - @Override - public void subscribe(@NonNull ObservableEmitter emitter) throws Throwable { - PackageManager pm = mContext.getPackageManager(); - List list = pm.getInstalledPackages(0); - List uploadInfos = new ArrayList<>(); - Intent intent = new Intent(Intent.ACTION_MAIN); - intent.addCategory(Intent.CATEGORY_LAUNCHER); - List appsWithLauncher = pm.queryIntentActivities(intent, 0); - List pkgs = new ArrayList<>(); - for (ResolveInfo info : appsWithLauncher) { - pkgs.add(info.activityInfo.packageName); - } - Log.e("SendAppInstallInfo", "pkgs: " + pkgs); - Set showPkg = getShowPackages(); - Log.e("SendAppInstallInfo", "showPkg: " + showPkg); - for (PackageInfo info : list) { - //排除掉部分系统应用 - if (ApkUtils.isSystemApp(mContext, info.packageName)) { - if (!showPkg.contains(info.packageName)) { - continue; + @Override + public void subscribe(@NonNull ObservableEmitter emitter) throws Throwable { + PackageManager pm = mContext.getPackageManager(); + List list = pm.getInstalledPackages(0); + List uploadInfos = new ArrayList<>(); + Intent intent = new Intent(Intent.ACTION_MAIN); + intent.addCategory(Intent.CATEGORY_LAUNCHER); + List appsWithLauncher = pm.queryIntentActivities(intent, 0); + List pkgs = new ArrayList<>(); + for (ResolveInfo info : appsWithLauncher) { + pkgs.add(info.activityInfo.packageName); } - } else { - if (!showPkg.contains(info.packageName)) { - //排除掉没有图标的应用 - if (!pkgs.contains(info.packageName)) { - continue; + Log.e("SendAppInstallInfo", "pkgs: " + pkgs); + Set showPkg = getShowPackages(); + Log.e("SendAppInstallInfo", "showPkg: " + showPkg); + for (PackageInfo info : list) { + //排除掉部分系统应用 + if (ApkUtils.isSystemApp(mContext, info.packageName)) { + if (!showPkg.contains(info.packageName)) { + continue; + } + } else { + if (!showPkg.contains(info.packageName)) { + //排除掉没有图标的应用 + if (!pkgs.contains(info.packageName)) { + continue; + } + } } + AppUploadInfo uploadInfo = new AppUploadInfo(); + uploadInfo.setApp_name(info.applicationInfo.loadLabel(pm).toString()); + uploadInfo.setApp_package(info.packageName); + uploadInfo.setApp_version_name(info.versionName); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + uploadInfo.setApp_version_code(info.getLongVersionCode()); + } else { + uploadInfo.setApp_version_code(info.versionCode); + } + uploadInfo.setFirstInstallTime(info.firstInstallTime / 1000); + uploadInfo.setLastUpdateTime(info.lastUpdateTime / 1000); + uploadInfo.setApp_size(getPackageSize(mContext, info.applicationInfo.publicSourceDir)); + uploadInfos.add(uploadInfo); } + String json = GsonUtils.toJSONString(uploadInfos); + Log.e("SendAppInstallInfo", "subscribe: json = " + json); + emitter.onNext(json); } - AppUploadInfo uploadInfo = new AppUploadInfo(); - uploadInfo.setApp_name(info.applicationInfo.loadLabel(pm).toString()); - uploadInfo.setApp_package(info.packageName); - uploadInfo.setApp_version_name(info.versionName); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { - uploadInfo.setApp_version_code(info.getLongVersionCode()); - } else { - uploadInfo.setApp_version_code(info.versionCode); - } - uploadInfo.setFirstInstallTime(info.firstInstallTime / 1000); - uploadInfo.setLastUpdateTime(info.lastUpdateTime / 1000); - uploadInfo.setApp_size(getPackageSize(mContext, info.applicationInfo.publicSourceDir)); - uploadInfos.add(uploadInfo); - } - String json = GsonUtils.toJSONString(uploadInfos); - Log.e("SendAppInstallInfo", "subscribe: json = " + json); - emitter.onNext(json); - } - }) + }) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .concatMap(new Function>() { @@ -909,20 +909,20 @@ public class NetInterfaceManager { public void getElderlyUsersApp() { Observable.zip(getUpdateObservable(JgyUtils.AIHealth), - getUpdateObservable(JgyUtils.ElderlyDesktop), - new BiFunction, BaseResponse, List>() { - @Override - public List apply(BaseResponse appInfoBaseResponse, BaseResponse appInfoBaseResponse2) throws Throwable { - List appInfoList = new ArrayList<>(); - if (appInfoBaseResponse.code == 200) { - appInfoList.add(appInfoBaseResponse.data); - } - if (appInfoBaseResponse2.code == 200) { - appInfoList.add(appInfoBaseResponse2.data); - } - return appInfoList; - } - }) + getUpdateObservable(JgyUtils.ElderlyDesktop), + new BiFunction, BaseResponse, List>() { + @Override + public List apply(BaseResponse appInfoBaseResponse, BaseResponse appInfoBaseResponse2) throws Throwable { + List appInfoList = new ArrayList<>(); + if (appInfoBaseResponse.code == 200) { + appInfoList.add(appInfoBaseResponse.data); + } + if (appInfoBaseResponse2.code == 200) { + appInfoList.add(appInfoBaseResponse2.data); + } + return appInfoList; + } + }) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer>() { @@ -1017,19 +1017,19 @@ public class NetInterfaceManager { public void checkAllAppUpdate(BehaviorSubject lifecycle, CompleteCallback callback) { Observable.zip( - getUpdateObservable(BuildConfig.APPLICATION_ID), - getUpdateObservable(JgyUtils.PACKAGE_APPSTORE), + getUpdateObservable(BuildConfig.APPLICATION_ID), + getUpdateObservable(JgyUtils.PACKAGE_APPSTORE), // getUpdateObservable(JGYUtils.PACKAGE_OS), // getUpdateObservable(JGYUtils.PACKAGE_BROWSER), // getUpdateObservable(JGYUtils.Notifications), - (appInfoBaseResponse, appInfoBaseResponse2) -> { - List appInfoList = new ArrayList<>(); - if (appInfoBaseResponse.code == 200) { - appInfoList.add(appInfoBaseResponse.data); - } - if (appInfoBaseResponse2.code == 200) { - appInfoList.add(appInfoBaseResponse2.data); - } + (appInfoBaseResponse, appInfoBaseResponse2) -> { + List appInfoList = new ArrayList<>(); + if (appInfoBaseResponse.code == 200) { + appInfoList.add(appInfoBaseResponse.data); + } + if (appInfoBaseResponse2.code == 200) { + appInfoList.add(appInfoBaseResponse2.data); + } // if (appInfoBaseResponse3.code == 200) { // appInfoList.add(appInfoBaseResponse3.data); // } @@ -1039,8 +1039,8 @@ public class NetInterfaceManager { // if (appInfoBaseResponse5.code == 200) { // appInfoList.add(appInfoBaseResponse5.data); // } - return appInfoList; - }) + return appInfoList; + }) .compose(RxLifecycle.bindUntilEvent(lifecycle, ActivityEvent.DESTROY)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) @@ -1098,46 +1098,46 @@ public class NetInterfaceManager { public void checkFXYAppUpdate(BehaviorSubject lifecycle, CompleteCallback callback) { Observable.zip( - getUpdateObservable(JgyUtils.gkwxhd), - getUpdateObservable(JgyUtils.fuxiaoying), - getUpdateObservable(JgyUtils.moshujia), - getUpdateObservable(JgyUtils.english), - getUpdateObservable(JgyUtils.zhiduoke), - getUpdateObservable(JgyUtils.aobama), - getUpdateObservable(JgyUtils.growthspace), - getUpdateObservable(JgyUtils.pandaabc), - getUpdateObservable(JgyUtils.qibenyi), - (appInfoBaseResponse, appInfoBaseResponse2, appInfoBaseResponse3, appInfoBaseResponse4, appInfoBaseResponse5, appInfoBaseResponse6, appInfoBaseResponse7, appInfoBaseResponse8, appInfoBaseResponse9) -> { - List appInfoList = new ArrayList<>(); - if (appInfoBaseResponse.code == 200) { - appInfoList.add(appInfoBaseResponse.data); - } - if (appInfoBaseResponse2.code == 200) { - appInfoList.add(appInfoBaseResponse2.data); - } - if (appInfoBaseResponse3.code == 200) { - appInfoList.add(appInfoBaseResponse3.data); - } - if (appInfoBaseResponse4.code == 200) { - appInfoList.add(appInfoBaseResponse4.data); - } - if (appInfoBaseResponse5.code == 200) { - appInfoList.add(appInfoBaseResponse5.data); - } - if (appInfoBaseResponse6.code == 200) { - appInfoList.add(appInfoBaseResponse6.data); - } - if (appInfoBaseResponse7.code == 200) { - appInfoList.add(appInfoBaseResponse7.data); - } - if (appInfoBaseResponse8.code == 200) { - appInfoList.add(appInfoBaseResponse7.data); - } - if (appInfoBaseResponse9.code == 200) { - appInfoList.add(appInfoBaseResponse7.data); - } - return appInfoList; - }) + getUpdateObservable(JgyUtils.gkwxhd), + getUpdateObservable(JgyUtils.fuxiaoying), + getUpdateObservable(JgyUtils.moshujia), + getUpdateObservable(JgyUtils.english), + getUpdateObservable(JgyUtils.zhiduoke), + getUpdateObservable(JgyUtils.aobama), + getUpdateObservable(JgyUtils.growthspace), + getUpdateObservable(JgyUtils.pandaabc), + getUpdateObservable(JgyUtils.qibenyi), + (appInfoBaseResponse, appInfoBaseResponse2, appInfoBaseResponse3, appInfoBaseResponse4, appInfoBaseResponse5, appInfoBaseResponse6, appInfoBaseResponse7, appInfoBaseResponse8, appInfoBaseResponse9) -> { + List appInfoList = new ArrayList<>(); + if (appInfoBaseResponse.code == 200) { + appInfoList.add(appInfoBaseResponse.data); + } + if (appInfoBaseResponse2.code == 200) { + appInfoList.add(appInfoBaseResponse2.data); + } + if (appInfoBaseResponse3.code == 200) { + appInfoList.add(appInfoBaseResponse3.data); + } + if (appInfoBaseResponse4.code == 200) { + appInfoList.add(appInfoBaseResponse4.data); + } + if (appInfoBaseResponse5.code == 200) { + appInfoList.add(appInfoBaseResponse5.data); + } + if (appInfoBaseResponse6.code == 200) { + appInfoList.add(appInfoBaseResponse6.data); + } + if (appInfoBaseResponse7.code == 200) { + appInfoList.add(appInfoBaseResponse7.data); + } + if (appInfoBaseResponse8.code == 200) { + appInfoList.add(appInfoBaseResponse7.data); + } + if (appInfoBaseResponse9.code == 200) { + appInfoList.add(appInfoBaseResponse7.data); + } + return appInfoList; + }) .compose(RxLifecycle.bindUntilEvent(lifecycle, ActivityEvent.DESTROY)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) @@ -1339,27 +1339,27 @@ public class NetInterfaceManager { public void setBrowserWhiteList() { Observable.zip(getLabelControl(), getBrowserControl(), new BiFunction, BaseResponse, HashSet>() { - @Override - public HashSet apply(BaseResponse