From 62fa007695cdeddfecb97bccdd799c95f4cb16f9 Mon Sep 17 00:00:00 2001 From: Fanhuitong <981964879@qq.com> Date: Tue, 31 Oct 2023 10:27:03 +0800 Subject: [PATCH] =?UTF-8?q?version:1.0.8=20fix:=20update:=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E7=AE=A1=E6=8E=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AndroidManifest-common.xml | 1 + build.gradle | 49 +- iconloaderlib/build.gradle | 14 +- .../com/uiuipad/os/icons/BaseIconFactory.java | 2 +- res/xml/default_workspace_6x4.xml | 16 +- res/xml/device_profiles.xml | 4 +- src/com/uiuipad/os/Launcher.java | 100 +- src/com/uiuipad/os/LauncherModel.java | 7 +- src/com/uiuipad/os/base/BaseApplication.java | 13 + src/com/uiuipad/os/base/BasePresenter.java | 7 + src/com/uiuipad/os/base/BaseView.java | 4 + .../folder/ClippedFolderIconLayoutRule.java | 2 +- src/com/uiuipad/os/gson/GsonUtils.java | 144 ++ .../os/gson/IntegerDefault0Adapter.java | 35 + .../gson/NullStringToEmptyAdapterFactory.java | 45 + src/com/uiuipad/os/icons/IconCache.java | 3 +- .../uiuipad/os/manager/AppUsedTimeUtils.java | 47 + .../uiuipad/os/manager/MyAppUsageBean.java | 73 + .../uiuipad/os/manager/RunningAppManager.java | 1491 +++++++++++++++++ .../os/manager/TimeControlManager.java | 191 +++ .../os/manager/bean/AppRunTimeBean.java | 75 + .../uiuipad/os/manager/bean/AppUsageTime.java | 50 + .../uiuipad/os/manager/bean/RemainTime.java | 88 + src/com/uiuipad/os/model/LoaderTask.java | 11 + .../os/network/NetInterfaceManager.java | 31 +- src/com/uiuipad/os/network/UrlAddress.java | 1 + .../os/network/api/CloudLessonAppApi.java | 2 +- .../os/network/api/CloudLessonSettingApi.java | 2 +- .../os/network/api/TimeManageAppApi.java | 4 +- .../os/network/api/TimeManageSnApi.java | 2 +- .../os/network/api/UploadAppUseLogApi.java | 10 +- .../os/network/bean/TimeManageApp.java | 50 +- .../os/network/bean/TimeManagePart.java | 34 +- .../uiuipad/os/network/bean/TimeManageSn.java | 17 +- .../interceptor/RepeatRequestInterceptor.java | 2 +- src/com/uiuipad/os/service/MainSContact.java | 17 + .../uiuipad/os/service/MainSPresenter.java | 131 ++ src/com/uiuipad/os/service/MainService.java | 93 +- .../uiuipad/os/touch/ItemClickHandler.java | 5 + .../{APKUtils.java => ApkUtils.java} | 2 +- src/com/uiuipad/os/uiuiutils/GsonUtils.java | 29 - src/doc/iPlay50SE.keystore | Bin 0 -> 2717 bytes 42 files changed, 2733 insertions(+), 171 deletions(-) create mode 100644 src/com/uiuipad/os/base/BasePresenter.java create mode 100644 src/com/uiuipad/os/base/BaseView.java create mode 100644 src/com/uiuipad/os/gson/GsonUtils.java create mode 100644 src/com/uiuipad/os/gson/IntegerDefault0Adapter.java create mode 100644 src/com/uiuipad/os/gson/NullStringToEmptyAdapterFactory.java create mode 100644 src/com/uiuipad/os/manager/AppUsedTimeUtils.java create mode 100644 src/com/uiuipad/os/manager/MyAppUsageBean.java create mode 100644 src/com/uiuipad/os/manager/RunningAppManager.java create mode 100644 src/com/uiuipad/os/manager/TimeControlManager.java create mode 100644 src/com/uiuipad/os/manager/bean/AppRunTimeBean.java create mode 100644 src/com/uiuipad/os/manager/bean/AppUsageTime.java create mode 100644 src/com/uiuipad/os/manager/bean/RemainTime.java create mode 100644 src/com/uiuipad/os/service/MainSContact.java create mode 100644 src/com/uiuipad/os/service/MainSPresenter.java rename src/com/uiuipad/os/uiuiutils/{APKUtils.java => ApkUtils.java} (99%) delete mode 100644 src/com/uiuipad/os/uiuiutils/GsonUtils.java create mode 100644 src/doc/iPlay50SE.keystore diff --git a/AndroidManifest-common.xml b/AndroidManifest-common.xml index e61e138..a0608b2 100644 --- a/AndroidManifest-common.xml +++ b/AndroidManifest-common.xml @@ -55,6 +55,7 @@ + + + + + + + - \ No newline at end of file diff --git a/res/xml/device_profiles.xml b/res/xml/device_profiles.xml index 29790f4..73b1e28 100644 --- a/res/xml/device_profiles.xml +++ b/res/xml/device_profiles.xml @@ -135,8 +135,8 @@ launcher:name="Large Phone" launcher:minWidthDps="406" launcher:minHeightDps="694" - launcher:iconImageSize="90" - launcher:iconTextSize="16" + launcher:iconImageSize="80" + launcher:iconTextSize="14.4" launcher:canBeDefault="true" /> diff --git a/src/com/uiuipad/os/Launcher.java b/src/com/uiuipad/os/Launcher.java index 6f5b54e..e182a8f 100644 --- a/src/com/uiuipad/os/Launcher.java +++ b/src/com/uiuipad/os/Launcher.java @@ -34,8 +34,8 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.IntentSender; +import android.content.ServiceConnection; import android.content.SharedPreferences; -import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Configuration; @@ -45,8 +45,8 @@ import android.graphics.Point; import android.graphics.Rect; import android.os.Build; import android.os.Bundle; -import android.os.Environment; import android.os.Handler; +import android.os.IBinder; import android.os.Parcelable; import android.os.Process; import android.os.StrictMode; @@ -69,13 +69,14 @@ import android.view.animation.OvershootInterpolator; import android.widget.Toast; import androidx.annotation.Nullable; -import androidx.core.content.ContextCompat; import com.alibaba.sdk.android.push.CloudPushService; import com.alibaba.sdk.android.push.CommonCallback; import com.alibaba.sdk.android.push.noonesdk.PushServiceFactory; import com.uiuipad.os.DropTarget.DragObject; -import com.uiuipad.os.uiuiutils.APKUtils; +import com.uiuipad.os.network.bean.TimeManageApp; +import com.uiuipad.os.network.bean.TimeManageSn; +import com.uiuipad.os.uiuiutils.ApkUtils; import com.uiuipad.os.uiuiutils.Utils; import com.uiuipad.os.accessibility.LauncherAccessibilityDelegate; import com.uiuipad.os.allapps.AllAppsContainerView; @@ -106,7 +107,6 @@ import com.uiuipad.os.model.ModelWriter; import com.uiuipad.os.network.bean.AppPasswdBean; import com.uiuipad.os.network.bean.BaseResponse; import com.uiuipad.os.network.NetInterfaceManager; -import com.uiuipad.os.network.bean.NewestAppUpdateResult; import com.uiuipad.os.notification.NotificationListener; import com.uiuipad.os.pageindicators.PageIndicatorDots; import com.uiuipad.os.popup.PopupContainerWithArrow; @@ -152,12 +152,10 @@ import com.uiuipad.os.widget.WidgetHostViewLoader; import com.uiuipad.os.widget.WidgetListRowEntry; import com.uiuipad.os.widget.WidgetsFullSheet; import com.uiuipad.os.widget.custom.CustomWidgetParser; -import com.arialyy.aria.core.Aria; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import com.tencent.mmkv.MMKV; -import java.io.File; import java.io.FileDescriptor; import java.io.IOException; import java.io.PrintWriter; @@ -167,18 +165,18 @@ import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import java.util.function.Consumer; import java.util.function.Predicate; -import io.reactivex.Observable; -import io.reactivex.ObservableEmitter; -import io.reactivex.ObservableOnSubscribe; -import io.reactivex.Observer; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.disposables.Disposable; -import io.reactivex.schedulers.Schedulers; +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.core.ObservableEmitter; +import io.reactivex.rxjava3.core.ObservableOnSubscribe; +import io.reactivex.rxjava3.core.Observer; +import io.reactivex.rxjava3.disposables.Disposable; +import okhttp3.RequestBody; import static android.content.pm.ActivityInfo.CONFIG_LOCALE; import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION; @@ -344,7 +342,11 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, Observable.create(updateSubscribe) .throttleFirst(6, TimeUnit.HOURS) .subscribe(updateObserver); - startService(new Intent(Launcher.this, MainService.class)); + + Intent intent = new Intent(Launcher.this, MainService.class); + bindService(intent, serviceConnect, BIND_AUTO_CREATE); + startService(intent); + if (DEBUG_STRICT_MODE) { StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() .detectDiskReads() @@ -426,7 +428,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, if (!isDefaultHome()) { // setDefaultL(); -// setRoleHolderAsUser(this, BuildConfig.APPLICATION_ID); + setRoleHolderAsUser(this, BuildConfig.APPLICATION_ID); } SharedPreferences sharedPref = getPreferences(MODE_PRIVATE); int i = sharedPref.getInt("SetWallPaper", 0); @@ -521,6 +523,23 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, }); } + MainService.MainBinder mMainBinder; + private ServiceConnect serviceConnect = new ServiceConnect(); + + private class ServiceConnect implements ServiceConnection { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + Log.e(TAG, "onServiceConnected: "); + mMainBinder = (MainService.MainBinder) service; + } + + @Override + public void onServiceDisconnected(ComponentName name) { + Log.e(TAG, "onServiceDisconnected: "); + mMainBinder = null; + } + } + private void SetWallPaper() { //利用WallpaparManager,添加权限set_wallpaper WallpaperManager wallpaperManager = WallpaperManager.getInstance(this); @@ -1150,8 +1169,47 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, Log.e("onStart", "app = null" + packageName); return; } + sendAppUsageRecord(packageName); + } + private void sendAppUsageRecord(String packageName) { + Log.e("sendAppUsageRecord", "packageName: " + packageName); + String app_name = ApkUtils.getAppNameByPackage(Launcher.this, packageName); + long openTime = TimeUtils.getInstance().getStartTime() / 1000; + long closeTime = TimeUtils.getInstance().getEndTime() / 1000; + Map params = new HashMap<>(); + params.put("sn", NetInterfaceManager.convertToRequestBody(Utils.getSerial(this))); + params.put("app_name", NetInterfaceManager.convertToRequestBody(app_name)); + params.put("app_package", NetInterfaceManager.convertToRequestBody(packageName)); + params.put("open_time", NetInterfaceManager.convertToRequestBody(openTime)); + params.put("close_time", NetInterfaceManager.convertToRequestBody(closeTime)); + NetInterfaceManager.getInstance() + .getUploadAppUseLogObservable(params) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + Log.e("sendAppUsageRecord", "onSubscribe: "); + } + + @Override + public void onNext(BaseResponse baseResponse) { + Log.e("sendAppUsageRecord", "onNext: " + baseResponse); + } + + @Override + public void onError(Throwable e) { + Log.e("sendAppUsageRecord", "onError: " + e.getMessage()); + } + + @Override + public void onComplete() { + Log.e("sendAppUsageRecord", "onComplete: "); + } + }); + } + + private void handleDeferredResume() { if (hasBeenResumed() && !mStateManager.getState().disableInteraction) { getUserEventDispatcher().logActionCommand(Action.Command.RESUME, @@ -1223,7 +1281,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, /*打开霸屏应用*/ String always_top_packagename = Settings.System.getString(getContentResolver(), "always_top_packagename"); if (!TextUtils.isEmpty(always_top_packagename)) { - APKUtils.openPackage(Launcher.this, always_top_packagename); + ApkUtils.openPackage(Launcher.this, always_top_packagename); } mUpdate.checkUpdate(System.currentTimeMillis()); mPasswd.getPassword(System.currentTimeMillis()); @@ -1231,6 +1289,14 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, JGYUtils.getInstance().wakeUpAppstore(); JGYUtils.getInstance().wakeUpDeviceInfo(); checkIsRest(); + + if (mMainBinder != null) { + mMainBinder.getService().mPresenter.getTimeManageSn(); + }else { + Log.e(TAG, "onResume: mMainBinder is null" ); + Intent intent = new Intent(Launcher.this, MainService.class); + bindService(intent, serviceConnect, BIND_AUTO_CREATE); + } } private void checkIsRest() { diff --git a/src/com/uiuipad/os/LauncherModel.java b/src/com/uiuipad/os/LauncherModel.java index 5ee2adc..b078359 100644 --- a/src/com/uiuipad/os/LauncherModel.java +++ b/src/com/uiuipad/os/LauncherModel.java @@ -303,14 +303,13 @@ public class LauncherModel extends BroadcastReceiver } else if (IS_DOGFOOD_BUILD && LauncherAppState.ACTION_FORCE_ROLOAD.equals(action)) { Launcher l = (Launcher) getCallback(); l.reload(); - }else if (Intent.ACTION_DATE_CHANGED.equals(action) //日历更新 + } else if (Intent.ACTION_DATE_CHANGED.equals(action) //日历更新 || Intent.ACTION_TIMEZONE_CHANGED.equals(action) || Intent.ACTION_TIME_CHANGED.equals(action)) { UserHandle myUser = Process.myUserHandle(); changedData(myUser); changedTime(myUser); - } else if (Intent.ACTION_TIME_TICK.equals(action)//时钟更新 - ) { + } else if (Intent.ACTION_TIME_TICK.equals(action)) {//时钟更新 UserHandle myUser = Process.myUserHandle(); changedTime(myUser); } @@ -336,6 +335,8 @@ public class LauncherModel extends BroadcastReceiver new PackageUpdatedTask(PackageUpdatedTask.OP_UPDATE, user, deskclock)); } + + public void forceReload() { forceReload(-1); } diff --git a/src/com/uiuipad/os/base/BaseApplication.java b/src/com/uiuipad/os/base/BaseApplication.java index 50df785..798f102 100644 --- a/src/com/uiuipad/os/base/BaseApplication.java +++ b/src/com/uiuipad/os/base/BaseApplication.java @@ -3,7 +3,11 @@ package com.uiuipad.os.base; import android.app.Application; import android.util.Log; +import com.tencent.bugly.crashreport.CrashReport; +import com.uiuipad.os.manager.AppUsedTimeUtils; import com.uiuipad.os.manager.ConnectManager; +import com.uiuipad.os.manager.RunningAppManager; +import com.uiuipad.os.manager.TimeControlManager; import com.uiuipad.os.network.NetInterfaceManager; import com.uiuipad.os.push.PushManager; import com.uiuipad.os.uiuiutils.JGYUtils; @@ -11,6 +15,7 @@ import com.uiuipad.os.uiuiutils.TimeUtils; import com.uiuipad.os.uiuiutils.ToastUtil; import com.arialyy.aria.core.Aria; import com.tencent.mmkv.MMKV; +import com.uiuipad.os.uiuiutils.Utils; public class BaseApplication extends Application { private static final String TAG = BaseApplication.class.getSimpleName(); @@ -28,5 +33,13 @@ public class BaseApplication extends Application { NetInterfaceManager.init(this); ToastUtil.init(this); ConnectManager.init(this); + + AppUsedTimeUtils.init(this); + RunningAppManager.init(this); + TimeControlManager.init(this); + + CrashReport.initCrashReport(getApplicationContext(), "55d55ba689", false); + CrashReport.setDeviceId(this, Utils.getSerial(this)); + xcrash.XCrash.init(this); } } diff --git a/src/com/uiuipad/os/base/BasePresenter.java b/src/com/uiuipad/os/base/BasePresenter.java new file mode 100644 index 0000000..be05cc1 --- /dev/null +++ b/src/com/uiuipad/os/base/BasePresenter.java @@ -0,0 +1,7 @@ +package com.uiuipad.os.base; + +public interface BasePresenter { + void attachView(V view); + + void detachView(); +} diff --git a/src/com/uiuipad/os/base/BaseView.java b/src/com/uiuipad/os/base/BaseView.java new file mode 100644 index 0000000..dbe502e --- /dev/null +++ b/src/com/uiuipad/os/base/BaseView.java @@ -0,0 +1,4 @@ +package com.uiuipad.os.base; + +public interface BaseView { +} diff --git a/src/com/uiuipad/os/folder/ClippedFolderIconLayoutRule.java b/src/com/uiuipad/os/folder/ClippedFolderIconLayoutRule.java index 018f661..b52084b 100644 --- a/src/com/uiuipad/os/folder/ClippedFolderIconLayoutRule.java +++ b/src/com/uiuipad/os/folder/ClippedFolderIconLayoutRule.java @@ -6,7 +6,7 @@ public class ClippedFolderIconLayoutRule { static final int MAX_NUM_ITEMS_IN_PREVIEW = Integer.MAX_VALUE; private static final int MIN_NUM_ITEMS_IN_PREVIEW = 2; - private static final float MIN_SCALE = 0.22f; + private static final float MIN_SCALE = 0.20f; private static final float MAX_SCALE = 0.58f; private static final float MAX_RADIUS_DILATION = 0.15f; private static final float ITEM_RADIUS_SCALE_FACTOR = 1.33f; diff --git a/src/com/uiuipad/os/gson/GsonUtils.java b/src/com/uiuipad/os/gson/GsonUtils.java new file mode 100644 index 0000000..a2270f4 --- /dev/null +++ b/src/com/uiuipad/os/gson/GsonUtils.java @@ -0,0 +1,144 @@ +package com.uiuipad.os.gson; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.reflect.TypeToken; + +import java.lang.reflect.Type; +import java.util.List; +import java.util.Map; +import java.util.Objects; + + +public class GsonUtils { + //https://blog.csdn.net/zte1055889498/article/details/122400299 + + public static JsonObject getJsonObject(String jsonString) { + JsonObject jsonObject = JsonParser.parseString(jsonString).getAsJsonObject(); + return jsonObject; + } + + private static final Gson gson; + + static { + GsonBuilder builder = new GsonBuilder(); + builder.registerTypeAdapterFactory(new NullStringToEmptyAdapterFactory()); + builder.registerTypeAdapter(Integer.class, new IntegerDefault0Adapter()); + builder.registerTypeAdapter(int.class, new IntegerDefault0Adapter()); + builder.disableHtmlEscaping(); + builder.enableComplexMapKeySerialization(); + // builder.excludeFieldsWithoutExposeAnnotation(); + builder.setDateFormat("yyyy-MM-dd HH:mm:ss"); + gson = builder.create(); + } + + public static Type makeJavaType(Type rawType, Type... typeArguments) { + return TypeToken.getParameterized(rawType, typeArguments).getType(); + } + + public static String toString(Object value) { + if (Objects.isNull(value)) { + return null; + } + if (value instanceof String) { + return (String) value; + } + return toJSONString(value); + } + + public static String toJSONString(Object value) { + return gson.toJson(value); + } + + public static String toPrettyString(Object value) { + return gson.newBuilder().setPrettyPrinting().create().toJson(value); + } + + public static JsonElement fromJavaObject(Object value) { + JsonElement result = null; + if (Objects.nonNull(value) && (value instanceof String)) { + result = parseObject((String) value); + } else { + result = gson.toJsonTree(value); + } + return result; + } + + public static JsonElement parseObject(String content) { + return JsonParser.parseString(content); + } + + public static JsonElement getJsonElement(JsonObject node, String name) { + return node.get(name); + } + + public static JsonElement getJsonElement(JsonArray node, int index) { + return node.get(index); + } + + public static T toJavaObject(JsonElement node, Class clazz) { + return gson.fromJson(node, clazz); + } + + public static T toJavaObject(JsonElement node, Type type) { + return gson.fromJson(node, type); + } + + public static T toJavaObject(JsonElement node, TypeToken typeToken) { + return toJavaObject(node, typeToken.getType()); + } + + public static List toJavaList(JsonElement node, Class clazz) { + return toJavaObject(node, makeJavaType(List.class, clazz)); + } + + public static List toJavaList(JsonElement node) { + return toJavaObject(node, new TypeToken>() { + }.getType()); + } + + public static Map toJavaMap(JsonElement node, Class clazz) { + return toJavaObject(node, makeJavaType(Map.class, String.class, clazz)); + } + + public static Map toJavaMap(JsonElement node) { + return toJavaObject(node, new TypeToken>() { + }.getType()); + } + + public static T toJavaObject(String content, Class clazz) { + JsonObject jsonObject = getJsonObject(content); + String jsonString = jsonObject.toString(); + return gson.fromJson(jsonString, clazz); + } + + public static T toJavaObject(String content, Type type) { + return gson.fromJson(content, type); + } + + public static T toJavaObject(String content, TypeToken typeToken) { + return toJavaObject(content, typeToken.getType()); + } + + public static List toJavaList(String content, Class clazz) { + return toJavaObject(content, makeJavaType(List.class, clazz)); + } + + public static List toJavaList(String content) { + return toJavaObject(content, new TypeToken>() { + }.getType()); + } + + public static Map toJavaMap(String content, Class clazz) { + return toJavaObject(content, makeJavaType(Map.class, String.class, clazz)); + } + + public static Map toJavaMap(String content) { + return toJavaObject(content, new TypeToken>() { + }.getType()); + } +} diff --git a/src/com/uiuipad/os/gson/IntegerDefault0Adapter.java b/src/com/uiuipad/os/gson/IntegerDefault0Adapter.java new file mode 100644 index 0000000..2036d94 --- /dev/null +++ b/src/com/uiuipad/os/gson/IntegerDefault0Adapter.java @@ -0,0 +1,35 @@ +package com.uiuipad.os.gson; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import com.google.gson.JsonSyntaxException; + +import java.lang.reflect.Type; + +public class IntegerDefault0Adapter implements JsonSerializer, JsonDeserializer { + @Override + public Integer deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + try { + if (json.getAsString().equals("")) { + return 0; + } + } catch (Exception ignore) { + } + try { + return json.getAsInt(); + } catch (NumberFormatException e) { + throw new JsonSyntaxException(e); + } + } + + @Override + public JsonElement serialize(Integer src, Type typeOfSrc, JsonSerializationContext context) { + return new JsonPrimitive(src); + } +} \ No newline at end of file diff --git a/src/com/uiuipad/os/gson/NullStringToEmptyAdapterFactory.java b/src/com/uiuipad/os/gson/NullStringToEmptyAdapterFactory.java new file mode 100644 index 0000000..519b885 --- /dev/null +++ b/src/com/uiuipad/os/gson/NullStringToEmptyAdapterFactory.java @@ -0,0 +1,45 @@ +package com.uiuipad.os.gson; + +import com.google.gson.Gson; +import com.google.gson.TypeAdapter; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonToken; +import com.google.gson.stream.JsonWriter; + +import java.io.IOException; + +public class NullStringToEmptyAdapterFactory implements TypeAdapterFactory { + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + + Class rawType = (Class) type.getRawType(); + if (rawType != String.class) { + return null; + } + return (TypeAdapter) new StringAdapter(); + } + + public static class StringAdapter extends TypeAdapter { + @Override + public String read(JsonReader reader) throws IOException { + if (reader.peek() == JsonToken.NULL) { + reader.nextNull(); + return ""; + } + return reader.nextString(); + } + + @Override + public void write(JsonWriter writer, String value) throws IOException { + if (value == null) { + writer.nullValue(); + return; + } + writer.value(value); + } + } + +} + diff --git a/src/com/uiuipad/os/icons/IconCache.java b/src/com/uiuipad/os/icons/IconCache.java index 7858f46..f9e6855 100644 --- a/src/com/uiuipad/os/icons/IconCache.java +++ b/src/com/uiuipad/os/icons/IconCache.java @@ -322,7 +322,8 @@ public class IconCache extends BaseIconCache { String name = info.getComponentName().getClassName(); Log.e("getFullResIcon", "getDeskClockIcon: " + name); if (appClassNameList.indexOf(info.getComponentName().getClassName()) == -1) { - icon = BitmapUtils.getRoundedBitmap(mIconProvider.getIcon(info, mIconDpi, flattenDrawable), mContext); + icon = mIconProvider.getIcon(info, mIconDpi, flattenDrawable); +// icon = BitmapUtils.getRoundedBitmap(mIconProvider.getIcon(info, mIconDpi, flattenDrawable), mContext); } else { // if ("com.android.calendar.AllInOneActivity".equals(name)) { // icon = BitmapUtils.createCalendarIconBitmap(mContext.getResources().getDrawable(R.drawable.mask), mContext); diff --git a/src/com/uiuipad/os/manager/AppUsedTimeUtils.java b/src/com/uiuipad/os/manager/AppUsedTimeUtils.java new file mode 100644 index 0000000..7247205 --- /dev/null +++ b/src/com/uiuipad/os/manager/AppUsedTimeUtils.java @@ -0,0 +1,47 @@ +package com.uiuipad.os.manager; + +import android.annotation.SuppressLint; +import android.content.Context; + +public class AppUsedTimeUtils { + private static final String TAG = AppUsedTimeUtils.class.getSimpleName(); + + @SuppressLint("StaticFieldLeak") + private static AppUsedTimeUtils sInstance; + private Context mContext; + private String app_package; + private long start_time; + + private AppUsedTimeUtils(Context context) { + this.mContext = context; + } + + public static void init(Context context) { + if (sInstance == null) { + sInstance = new AppUsedTimeUtils(context); + } + } + + public static AppUsedTimeUtils getInstance() { + if (sInstance == null) { + throw new IllegalStateException("You must be init AppUsedTimeUtils first"); + } + return sInstance; + } + + public String getApp_package() { + return app_package; + } + + public void setApp_package(String app_package) { + this.app_package = app_package; + } + + public long getStart_time() { + return start_time; + } + + public void setStart_time(long start_time) { + this.start_time = start_time; + } +} diff --git a/src/com/uiuipad/os/manager/MyAppUsageBean.java b/src/com/uiuipad/os/manager/MyAppUsageBean.java new file mode 100644 index 0000000..77c9948 --- /dev/null +++ b/src/com/uiuipad/os/manager/MyAppUsageBean.java @@ -0,0 +1,73 @@ +package com.uiuipad.os.manager; + +import androidx.annotation.NonNull; + +import com.google.gson.Gson; +import com.google.gson.JsonParser; + +import java.io.Serializable; + +public class MyAppUsageBean implements Serializable { + private static final long serialVersionUID = 5340688429095924160L; + + int id; + String app_name; + String app_package; + String app_img; + String class_name; + long use_time;//s + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getApp_name() { + return app_name; + } + + public void setApp_name(String app_name) { + this.app_name = app_name; + } + + public String getApp_package() { + return app_package; + } + + public void setApp_package(String app_package) { + this.app_package = app_package; + } + + public String getApp_img() { + return app_img; + } + + public void setApp_img(String app_img) { + this.app_img = app_img; + } + + public String getClass_name() { + return class_name; + } + + public void setClass_name(String class_name) { + this.class_name = class_name; + } + + public long getUse_time() { + return use_time; + } + + public void setUse_time(long use_time) { + this.use_time = use_time; + } + + @NonNull + @Override + public String toString() { + return JsonParser.parseString(new Gson().toJson(this)).getAsJsonObject().toString(); + } +} diff --git a/src/com/uiuipad/os/manager/RunningAppManager.java b/src/com/uiuipad/os/manager/RunningAppManager.java new file mode 100644 index 0000000..72b2267 --- /dev/null +++ b/src/com/uiuipad/os/manager/RunningAppManager.java @@ -0,0 +1,1491 @@ +package com.uiuipad.os.manager; + +import android.annotation.SuppressLint; +import android.app.ActivityManager; +import android.app.ActivityManagerNative; +import android.app.ActivityTaskManager; +import android.app.usage.UsageStats; +import android.app.usage.UsageStatsManager; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.pm.UserInfo; +import android.os.Build; +import android.os.PowerManager; +import android.os.RemoteException; +import android.provider.Settings; +import android.text.TextUtils; +import android.util.Log; + +import androidx.annotation.NonNull; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import com.tencent.mmkv.MMKV; +import com.uiuipad.os.BuildConfig; +import com.uiuipad.os.comm.CommonConfig; +import com.uiuipad.os.gson.GsonUtils; +import com.uiuipad.os.manager.bean.AppRunTimeBean; +import com.uiuipad.os.manager.bean.AppUsageTime; +import com.uiuipad.os.manager.bean.RemainTime; +import com.uiuipad.os.network.bean.TimeManageApp; +import com.uiuipad.os.network.bean.TimeManagePart; +import com.uiuipad.os.network.bean.TimeManageSn; +import com.uiuipad.os.uiuiutils.CmdUtil; +import com.uiuipad.os.uiuiutils.ToastUtil; + +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Comparator; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.functions.Consumer; +import io.reactivex.rxjava3.schedulers.Schedulers; + +import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE; + +public class RunningAppManager { + private static final String TAG = RunningAppManager.class.getSimpleName(); + + @SuppressLint("StaticFieldLeak") + private static RunningAppManager mRunningAppManager; + private Context mContext; + private MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE); + + public static final String RemainingTimeMap = "RemainingTimeMap_KEY"; + + public static final String GlobalUsageTimeMap = "GlobalUsageTimeMap_KEY"; + + public static final String AllApplUsageTimeMap = "AllAppUsageTimeMap_KEY"; + + //剩余时间 + private long globalRemainingTime; + private String GLOBAL_REMAINING_TIME_KEY = "GLOBAL_REMAINING_TIME_KEY"; + + //存储每个单独有配置app剩余时间 + private HashMap mRemainingTimeMap = new HashMap<>(); + //存储整机配置app使用时间 + private HashMap mGlobalUsageTime = new HashMap<>(); + //存储所有app使用时间 + private HashMap mAllAppUsageTime = new HashMap<>(); + + public static final long minuteTime = 60 * 1000; + public static final long dayTime = minuteTime * 60 * 24; + + //日期格式化 + private static DateFormat dateFormat = new SimpleDateFormat("HH:mm"); + + /*当前时间*/ + private static final long END_TIME = System.currentTimeMillis(); + /*一周的时间*/ + private static final long TIME_INTERVAL = 7 * 24 * 60 * 60 * 1000L; + /*查询一周的记录*/ + private static final long START_TIME = END_TIME - TIME_INTERVAL; + + private RunningAppManager(Context context) { + if (context == null) { + throw new RuntimeException("Context is NULL"); + } + this.mContext = context; + registerTimeReceiver(mContext); + + globalRemainingTime = mMMKV.decodeLong(GLOBAL_REMAINING_TIME_KEY, 0); + String remainsTimeJson = mMMKV.decodeString(RemainingTimeMap, ""); + Log.i(TAG, "remainsTimeJson: " + remainsTimeJson); + Gson gson = new Gson(); + Type remainsTimeType = new TypeToken>() { + }.getType(); + HashMap remainingTimeMap = gson.fromJson(remainsTimeJson, remainsTimeType); + if (remainingTimeMap != null) { + mRemainingTimeMap = remainingTimeMap; + } + + String globalUsageTimeJson = mMMKV.decodeString(GlobalUsageTimeMap, ""); + Log.i(TAG, "globalUsageTimeJson: " + globalUsageTimeJson); + Type globalUsageTimeType = new TypeToken>() { + }.getType(); + HashMap appUsageTimeHashMap = gson.fromJson(globalUsageTimeJson, globalUsageTimeType); + if (appUsageTimeHashMap != null) { + mGlobalUsageTime = appUsageTimeHashMap; + } + + String allAppUsageTimeJson = mMMKV.decodeString(AllApplUsageTimeMap, ""); + Log.i(TAG, "allAppUsageTimeJson: " + globalUsageTimeJson); + Type allAppUsageTimeType = new TypeToken>() { + }.getType(); + HashMap allAppUsageTimeHashMap = gson.fromJson(allAppUsageTimeJson, allAppUsageTimeType); + if (allAppUsageTimeHashMap != null) { + mAllAppUsageTime = allAppUsageTimeHashMap; + } + + inInterval(); + } + + public static void init(Context context) { + if (mRunningAppManager == null) { + mRunningAppManager = new RunningAppManager(context); + } + } + + public static RunningAppManager getInstance() { + if (mRunningAppManager == null) { + throw new IllegalStateException("You must be init RunningAppManager first"); + } + return mRunningAppManager; + } + + /** + * 初始化计时 + */ + 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.i(TAG, "accept: " + aLong); + PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); + boolean isScreenOn = pm.isScreenOn(); + if (!isScreenOn) { + return; + } + checkForegroundAppName(); + } + }); + } + + /** + * 检查前台app + */ + private void checkForegroundAppName() { + String topPackage = getTopActivityInfo(); + if ("org.chromium.browser".equals(topPackage)) { + killPackage("org.chromium.browser"); + } + Log.i(TAG, "checkForegroundAppName: topPackage = " + topPackage); + String appPackageName = getAppPackageName(); + Log.d(TAG, "checkForegroundAppName: appPackageName = " + appPackageName); + if (allowPackage.contains(topPackage)) {//排除在外的包名都写入空值 + if (!TextUtils.isEmpty(appPackageName)) { + if (!topPackage.equals(appPackageName)) { + //切换出去了 + Log.i(TAG, "checkForegroundAppName: 切换应用1:" + topPackage); +// NetInterfaceManager.getInstance().sendCloseApp(appPackageName, new NetInterfaceManager.CompleteCallback() { +// @Override +// public void onComplete() { +// Log.i(TAG, "onComplete: "); +// } +// }); +// NetInterfaceManager.getInstance().getMyAppList(new NetInterfaceManager.MyAppListCallback() { +// @Override +// public void setMyAppList(List myAppList) { +// syncAllAppUsageTime(myAppList); +// } +// }); + AppUsedTimeUtils.getInstance().setApp_package(topPackage); + AppUsedTimeUtils.getInstance().setStart_time(System.currentTimeMillis() / 1000); + } + } + mMMKV.encode(RUNNING_APP_PACKAGENAME, ""); + Log.d(TAG, "checkForegroundAppName: allow: " + topPackage); + return; + } + //如果appPackageName 为空则topPackage是才打开 + if (TextUtils.isEmpty(appPackageName)) { + Log.d(TAG, "checkForegroundAppName: open: " + topPackage); + recordPackageOpenTime(topPackage); + AppUsedTimeUtils.getInstance().setApp_package(topPackage); + AppUsedTimeUtils.getInstance().setStart_time(System.currentTimeMillis() / 1000); + return; + } + long onClickTime = getOnClickTime(); + Log.i(TAG, "checkForegroundAppName: getAppPackageName = " + appPackageName); + if (appPackageName.equals(topPackage)) { + Log.i(TAG, "checkForegroundAppName: 没有切换应用"); + if (inControlTime(appPackageName)) { + removeTask(topPackage); + killApp(); + gotoLauncher(); + } else { + Log.i(TAG, "checkForegroundAppName: 没有管控"); + reduceAppRemainingTime(topPackage, 1); + } + } else { + Log.i(TAG, "checkForegroundAppName: 切换应用2:" + topPackage); +// NetInterfaceManager.getInstance().sendCloseApp(appPackageName, new NetInterfaceManager.CompleteCallback() { +// @Override +// public void onComplete() { +// } +// }); + + reduceAppRemainingTime(topPackage, 1); + appPackageName = topPackage; + AppUsedTimeUtils.getInstance().setApp_package(appPackageName); + onClickTime = System.currentTimeMillis() / 1000; + AppUsedTimeUtils.getInstance().setStart_time(onClickTime); + if (inControlTime(appPackageName)) { + Log.i(TAG, "checkForegroundAppName: 没有剩余时间2"); + removeTask(topPackage); + killApp(); + gotoLauncher(); + } else { + recordPackageOpenTime(topPackage); + Log.i(TAG, "checkForegroundAppName: 没有管控2"); + } + } + saveAppRemainingTime(); + } + + private void killApp() { + PackageManager pm = mContext.getPackageManager(); + Intent intent = new Intent(Intent.ACTION_MAIN); + intent.addCategory(Intent.CATEGORY_LAUNCHER); + List launcherApp = pm.queryIntentActivities(intent, 0); + List appList = launcherApp.stream().map(resolveInfo -> resolveInfo.activityInfo.packageName).collect(Collectors.toList()); + Log.e(TAG, "killApp: " + appList); + for (String pkg : appList) { + if (BuildConfig.APPLICATION_ID.equals(pkg) + || "com.android.settings".equals(pkg) + ) { + continue; + } + killBackgroundProcesses(pkg); + } + } + + private TimeChangedReceiver mTimeChangedReceiver; + + /** + * 监听时间和日期变化 + */ + private void registerTimeReceiver(Context context) { + 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); + context.registerReceiver(mTimeChangedReceiver, filter); + } + + @SuppressLint("SimpleDateFormat") + private SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); + + private class TimeChangedReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + Log.i(TAG, "TimeChangedReceiver:" + action); + long time = System.currentTimeMillis(); + String finaWayDate = sdf.format(time); + if ("00:00:00".equals(finaWayDate)) { + //清除数据保证及时性 + mMMKV.encode(RemainingTimeMap, ""); + mMMKV.encode(GlobalUsageTimeMap, ""); + mMMKV.encode(AllApplUsageTimeMap, ""); + mRemainingTimeMap.clear(); + mGlobalUsageTime.clear(); + mAllAppUsageTime.clear(); + } + } + } + + public void killBackgroundProcesses(String processName) { +// gotoLauncher(); + // mIsScanning = true; + removeTask(processName); + ActivityManager activityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); + String packageName = null; + try { + if (processName.indexOf(":") == -1) { + packageName = processName; + } else { + packageName = processName.split(":")[0]; + } + activityManager.killBackgroundProcesses(packageName); + // + Method forceStopPackage = activityManager.getClass() + .getDeclaredMethod("forceStopPackage", String.class); + forceStopPackage.setAccessible(true); + forceStopPackage.invoke(activityManager, packageName); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 清除所有最近记录 + */ + public void removeAllTask(Context context) { + List list = getRecentTasks(ActivityManager.getMaxRecentTasksStatic(), getCurrentUserId()); + + for (ActivityManager.RecentTaskInfo info : list) { + if (info.realActivity != null) { + Log.i(TAG, "removeAllTask: " + info.realActivity.getPackageName()); + //排除自身 + if (BuildConfig.APPLICATION_ID.equals(info.realActivity.getPackageName())) { + continue; + } + } + try { + ActivityManagerNative.getDefault().removeTask(info.id); + } catch (RemoteException e) { + e.printStackTrace(); + Log.i(TAG, "removeAllTask: " + e.getMessage()); + } + } + } + + public void removeTask(String packageName) { + List list = getRecentTasks(ActivityManager.getMaxRecentTasksStatic(), getCurrentUserId()); + HashMap taskMap = new HashMap<>(); + for (ActivityManager.RecentTaskInfo info : list) { + taskMap.put(info.realActivity.getPackageName(), info.id); + } + try { + ActivityManagerNative.getDefault().removeTask(taskMap.get(packageName)); + } catch (RemoteException e) { + e.printStackTrace(); + Log.i(TAG, "removeTask: " + e.getMessage()); + } catch (NullPointerException e) { + Log.i(TAG, "removeTask: " + e.getMessage()); + } + } + + /** + * 如果界面正在最近任务列表,有些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); + } + + /** + * @return a list of the recents tasks. + * 获取近期任务列表 + */ + public List getRecentTasks(int numTasks, int userId) { + try { + return ActivityTaskManager.getService().getRecentTasks(numTasks, + RECENT_IGNORE_UNAVAILABLE, userId).getList(); + } catch (RemoteException e) { + Log.i(TAG, "Failed to get recent tasks " + e); + return new ArrayList<>(); + } + } + + /** + * @return the current user's id. + * 获取userId + */ + public int getCurrentUserId() { + UserInfo ui; + try { + ui = ActivityManager.getService().getCurrentUser(); + return ui != null ? ui.id : 0; + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + //缓存正在运行包名 + private static final String RUNNING_APP_PACKAGENAME = "running_app_package_name"; + //缓存app运行时间 + private static final String RUNNING_APP_RUN_TIME = "running_app_run_time"; + //缓存app起始运行时间 + private static final String RUNNING_APP_ONCLICK_TIME = "running_app_on_click_time"; + + /** + * 同时在前台运行的就只有一个 + * + * @param packageName + */ + public void recordPackageOpenTime(String packageName) { + mMMKV.encode(RUNNING_APP_PACKAGENAME, packageName); + mMMKV.encode(RUNNING_APP_ONCLICK_TIME, System.currentTimeMillis() / 1000); + } + + public String getAppPackageName() { + String packageName = mMMKV.decodeString(RUNNING_APP_PACKAGENAME, ""); + return packageName; + } + + public long getOnClickTime() { + long onClickTime = mMMKV.decodeLong(RUNNING_APP_ONCLICK_TIME, 0L); + return onClickTime; + } + + public void setAppRunTime(long time) { + mMMKV.encode(RUNNING_APP_RUN_TIME, time); + } + + public long getAppRunTime() { + long appRunTime = mMMKV.decodeLong(RUNNING_APP_RUN_TIME, 0L); + return appRunTime; + } + + public void setGlobalUsageTime(long time) { + this.globalRemainingTime = time; + if (globalRemainingTime < 0) { + globalRemainingTime = 0; + } + mMMKV.encode(GLOBAL_REMAINING_TIME_KEY, globalRemainingTime); + } + + /** + * 同步剩余时间 + * + * @param appTimeControls + */ + public void syncAppRemainingTime(List appTimeControls) { + mRemainingTimeMap.clear(); + for (TimeManageApp appTimeControl : appTimeControls) { +// if (appTimeControl.getUse_type() != 3) { +// continue; +// } + AppRunTimeBean appRunTimeBean = new AppRunTimeBean(appTimeControl.getApp_package()); + appRunTimeBean.setAppRunTime(appTimeControl.getToday_time()); + mRemainingTimeMap.put(appTimeControl.getApp_package(), appRunTimeBean); + } + Log.i(TAG, "syncAppRemainingTime: Finish" + mRemainingTimeMap); + } + + /*同步所有应用使用时间*/ + public void syncAllAppUsageTime(List myAppList) { + if (myAppList == null || myAppList.size() == 0) { + mAllAppUsageTime.clear(); + } else { +// mAllAppUsageTime.clear(); + for (MyAppUsageBean bean : myAppList) { + if (TextUtils.isEmpty(bean.getApp_package())) { + continue; + } + AppUsageTime appUsageTime = new AppUsageTime(); + appUsageTime.setPkg(bean.getApp_package()); + appUsageTime.setAppName(bean.getApp_name()); + appUsageTime.setUsageTime(bean.getUse_time()); + mAllAppUsageTime.put(bean.getApp_package(), appUsageTime); + } + } + String singleString = GsonUtils.toJSONString(mAllAppUsageTime); + mMMKV.encode(AllApplUsageTimeMap, singleString); + Log.e(TAG, "syncAllAppUsageTime: " + mAllAppUsageTime); + } + + /** + * 保存剩余时间到缓存 + */ + public void saveAppRemainingTime() { + String jsonString = GsonUtils.toJSONString(mRemainingTimeMap); + mMMKV.encode(RemainingTimeMap, jsonString); + String timeString = GsonUtils.toJSONString(mGlobalUsageTime); + mMMKV.encode(GlobalUsageTimeMap, timeString); + String singleString = GsonUtils.toJSONString(mAllAppUsageTime); + mMMKV.encode(AllApplUsageTimeMap, singleString); + } + + /** + * 获取剩余时间 + * + * @param pkg + * @return + */ + public long getAppRemainingTime(String pkg) { + AppRunTimeBean timeBean = mRemainingTimeMap.get(pkg); + if (timeBean == null) { + return 0; + } else { + return timeBean.getAppRunTime(); + } + } + + /** + * 减少剩余时间 + * + * @param pkg + * @param time + */ + public void reduceAppRemainingTime(String pkg, long time) { + if (allowPackage.contains(pkg)) { + return; + } + int isControl = Settings.Global.getInt(mContext.getContentResolver(), "is_control", 0); + Log.i(TAG, "reduceAppRemainingTime: isControl = " + isControl); + //家长管控关闭始终可用 + if (isControl == 0) { + return; + } + boolean havaConfigure = TimeControlManager.getInstance().havaConfigure(pkg); + TimeManageSn machineControl = TimeControlManager.getInstance().getGlobalMachineControl(); + + Log.e(TAG, "inControlTime: globalRemainingTime = " + globalRemainingTime); + if (globalRemainingTime <= 0) { + if (machineControl != null) { +// if (machineControl.getIs_part() == 0 && machineControl.getIs_quota() == 0) { +// return; +// } + } else { + ToastUtil.show("今日可使用时间已用完"); + return; + } + } + if (havaConfigure) { + TimeManageApp appTimeControl = TimeControlManager.getInstance().getAppTimeControl(pkg); + //全局配置的 + if (appTimeControl.getUse_type() == 2) { + AppUsageTime appUsageTime; + if (mGlobalUsageTime.get(pkg) == null) { + appUsageTime = new AppUsageTime(); + appUsageTime.setPkg(pkg); + appUsageTime.setAppName(getAppName(pkg)); + appUsageTime.setUsageTime(1); + } else { + appUsageTime = mGlobalUsageTime.get(pkg); + appUsageTime.setAppName(getAppName(pkg)); + appUsageTime.setUsageTime(appUsageTime.getUsageTime() + 1); + } + mGlobalUsageTime.put(pkg, appUsageTime); + } else if (appTimeControl.getUse_type() == 0) { + return; + } else { + mGlobalUsageTime.remove(pkg); + } + //单个app的 + AppUsageTime singleAppUsageTime; + if (mAllAppUsageTime.get(pkg) == null) { + singleAppUsageTime = new AppUsageTime(); + singleAppUsageTime.setPkg(pkg); + singleAppUsageTime.setAppName(getAppName(pkg)); + singleAppUsageTime.setUsageTime(1); + } else { + singleAppUsageTime = mAllAppUsageTime.get(pkg); + singleAppUsageTime.setAppName(getAppName(pkg)); + long singleTime = singleAppUsageTime.getUsageTime(); + Log.e(TAG, "reduceAppRemainingTime: " + singleTime); + singleAppUsageTime.setUsageTime(singleTime + 1); + } + mAllAppUsageTime.put(pkg, singleAppUsageTime); + Log.e(TAG, "reduceAppRemainingTime: mAllAppUsageTime = " + mAllAppUsageTime.toString()); + Log.i(TAG, "reduceAppRemainingTime: " + appTimeControl.getToday_time()); + long remainingTime = appTimeControl.getToday_time() - time; + if (remainingTime < 0) { + remainingTime = 0; + } + AppRunTimeBean timeBean = mRemainingTimeMap.get(pkg); + timeBean.setAppRunTime(remainingTime); + mRemainingTimeMap.put(pkg, timeBean); + appTimeControl.setToday_time(remainingTime); + TimeControlManager.getInstance().setAppTimeControl(pkg, appTimeControl); + setGlobalUsageTime(globalRemainingTime - time); + } else { + if (machineControl == null) { + return; + } + Log.i(TAG, "reduceAppRemainingTime: " + machineControl.getToday_time()); + long remainingTime = machineControl.getToday_time() - time; + if (remainingTime < 0) { + remainingTime = 0; + } + machineControl.setToday_time(remainingTime); + TimeControlManager.getInstance().setGlobalMachineControl(machineControl); + } + } + + private String getAppName(String pkg) { + if (TextUtils.isEmpty(pkg)) { + return "未知"; + } +// String jsonString = mMMKV.decodeString(UrlAddress.GET_ALL_PACKAGE, ""); +// if (!TextUtils.isEmpty(jsonString)) { +// Type type = new TypeToken>() { +// }.getType(); +// Gson gson = new Gson(); +// List appInfoList = gson.fromJson(jsonString, type); +// if (appInfoList != null && appInfoList.size() != 0) { +// List temp = appInfoList.stream().filter(new Predicate() { +// @Override +// public boolean test(AppInfo appInfo) { +// return pkg.equals(appInfo.getApp_package()); +// } +// }).collect(Collectors.toList()); +// if (temp.size() != 0) { +// return temp.get(0).getApp_name(); +// } +// } +// } + PackageManager pm = mContext.getPackageManager(); + PackageInfo info = null; + try { + info = pm.getPackageInfo(pkg, 0); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } + if (info != null) { + return info.applicationInfo.loadLabel(pm).toString(); + } + return "未知"; + } + + 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("com.sprd.engineermode"); + this.add("com.teclast.update"); + this.add("com.incar.update"); + }}; + + /** + * 可用返回false,不可用返回true + * + * @param pkg + * @return + */ + public boolean inControlTime(String pkg) { + if (allowPackage.contains(pkg)) { + return false; + } + Log.i(TAG, "inControlTime: pkg = " + pkg); + int isControl = Settings.Global.getInt(mContext.getContentResolver(), "is_control", 0); + Log.i(TAG, "inControlTime: isControl = " + isControl); + //家长管控关闭始终可用 + if (isControl == 0) { + return false; + } + boolean havaConfigure = TimeControlManager.getInstance().havaConfigure(pkg); + TimeManageSn machineControl = TimeControlManager.getInstance().getGlobalMachineControl(); + + if (havaConfigure) { + //有单独设置 不管是分类整机还是其他都是这个设置 + TimeManageApp appTimeControl = TimeControlManager.getInstance().getAppTimeControl(pkg); +// if (appTimeControl.getIs_control() == 0) { +// ToastUtil.show("应用已被禁用"); +// Log.e(TAG, "inControlTime: " + "应用已被禁用"); +// return true; +// } + if (appTimeControl.getUse_type() == 0) { + Log.e(TAG, "inControlTime: " + "应用始终可用"); + return false; + } + + Log.e(TAG, "inControlTime: globalRemainingTime = " + globalRemainingTime); + if (appTimeControl.getUse_type() != 3) { + if (globalRemainingTime <= 0) { +// if (machineControl != null) { +// if (machineControl.getIs_part() == 0 && machineControl.getIs_quota() == 0) { +// Log.e(TAG, "inControlTime: is_part = 0 is_quota = 0"); +// //整机额度和时间段关闭不管控 +// return false; +// } +// } else { + ToastUtil.show("今日可使用时间已用完"); + return true; +// } + } + } + //打开时间段管控 + if (appTimeControl.getTime_part() != null && appTimeControl.getTime_part().size() != 0) { + boolean inControlTime = inControlTime(machineControl, appTimeControl); + //判断是否在时间段内 + if (inControlTime) { + Log.i(TAG, "inControlTime: " + "应用在管控时间段不能打开" + appTimeControl.getTime_part().toString()); + ToastUtil.show("该应用" + partTime2String(appTimeControl)); + Log.e(TAG, "inControlTime: " + "该应用" + partTime2String(appTimeControl)); + return true; + } else { +// if (appTimeControl.getIs_quota() == 0) { +// //要求设置了管控时间段没有设置使用额度也可以使用 +// return false; +// } + if (getAppRemainingTime(pkg) <= 0) { + //没有剩余时间 + ToastUtil.show("该应用今日可使用时间已用完"); + Log.e(TAG, "inControlTime: " + "该应用今日可使用时间已用完"); + + return true; + } else { + return false; + } + } + } else { + //关闭时间段管控关闭额度开关为不管控 +// if (appTimeControl.getIs_quota() == 0) { +// Log.e(TAG, "inControlTime: " + "没有使用额度"); +// return false; +// } + if (getAppRemainingTime(pkg) <= 0) { + //没有剩余时间 + ToastUtil.show("该应用今日可使用时间已用完"); + Log.e(TAG, "inControlTime: " + "该应用今日可使用时间已用完"); + return true; + } else { + return false; + } + } + } else { + //没有配置可以直接使用 + return false; +// //根据整机 +// if (machineControl == null) { +// return false; +// } +// if (globalRemainingTime <= 0) { +//// if (machineControl.getIs_part() == 0 && machineControl.getIs_quota() == 0) { +//// Log.e(TAG, "inControlTime: is_part = 0 is_quota = 0"); +//// //整机额度和时间段关闭不管控 +//// return false; +//// } +// } +//// if (machineControl.is_quota == 1) { +// if (isControl == 1) { +// if (haveUseTime(machineControl.getWork_time(), machineControl.getRest_time(), machineControl.getToday_time())) { +// return false; +// } else { +// boolean inControlTime = inControlTime(machineControl); +// if (inControlTime) { +// Log.i(TAG, "inControlTime: " + "应用在管控时间段不能打开" + machineControl.getTime_part().toString()); +// ToastUtil.show("该应用" + partTime2String(machineControl)); +// } +// return inControlTime; +// } +// } else { +// //关闭整机额度开关 始终可用 +// return false; +// } + } + } + + private String partTime2String(TimeManageApp appTimeControl) { + List partTimes = appTimeControl.getTime_part(); + if (partTimes == null || partTimes.size() == 0) { + return "没有设置管控时段"; + } + StringBuilder stringBuilder = new StringBuilder(); + for (TimeManagePart partTime : partTimes) { + if (getDayType() != partTime.getDay_type()) { + continue; + } + if (stringBuilder.length() == 0) { + if (appTimeControl.getTime_part() != null && appTimeControl.getTime_part().size() != 0) { + stringBuilder.append("仅限"); + } + } else { + stringBuilder.append(";"); + } + stringBuilder.append(partTime.getStart_time()) + .append("-").append(partTime.getEnd_time()); + } + if (appTimeControl.getTime_part() != null && appTimeControl.getTime_part().size() != 0) { + stringBuilder.append("使用"); + } else { + stringBuilder.append("禁止使用"); + } + return stringBuilder.toString(); + } + + private String partTime2String(TimeManageSn machineControl) { + List partTimes = machineControl.getTime_part(); + if (partTimes == null || partTimes.size() == 0) { + return "没有设置管控时段"; + } + StringBuilder stringBuilder = new StringBuilder(); + for (TimeManagePart partTime : partTimes) { + if (stringBuilder.length() > 0) { + stringBuilder.append(";"); + } + stringBuilder.append(partTime.getStart_time()) + .append("-").append(partTime.getEnd_time()); + if (machineControl.getTime_part() != null && machineControl.getTime_part().size() != 0) { + stringBuilder.append("可以使用"); + } else { + stringBuilder.append("禁止使用"); + } + } + return stringBuilder.toString(); + } + + + /** + * @param pkg + * @return json数据 + */ + public String getDisableContent(String pkg) { + RemainTime remainTime = new RemainTime(); + remainTime.setPkg(pkg); + + boolean havaConfigure = TimeControlManager.getInstance().havaConfigure(pkg); + TimeManageSn machineControl = TimeControlManager.getInstance().getGlobalMachineControl(); + + Log.e(TAG, "inControlTime: globalRemainingTime = " + globalRemainingTime); + + if (havaConfigure) { + //有单独设置 不管是分类整机还是其他都是这个设置 + TimeManageApp appTimeControl = TimeControlManager.getInstance().getAppTimeControl(pkg); + if (inWeekDay()) { + remainTime.setTotalTime(appTimeControl.getWork_time()); + } else { + remainTime.setTotalTime(appTimeControl.getRest_time()); + } +// if (appTimeControl.getIs_control() == 0) { +// remainTime.setDisableType(1); +// remainTime.setContent("应用已被禁用"); +// return remainTime.toString(); +// } +// if (appTimeControl.getUse_type() == 0) { +// return ""; +// } + //打开时间段管控 + if (appTimeControl.getTime_part() != null && appTimeControl.getTime_part().size() != 0) { + boolean inControlTime = inControlTime(machineControl, appTimeControl); + //判断是否在时间段内 + if (inControlTime) { + remainTime.setDisableType(3); + remainTime.setContent("该应用" + partTime2String(appTimeControl)); + return remainTime.getContent(); + } else { +// if (appTimeControl.getIs_quota() == 0) { +// //要求设置了管控时间段没有设置使用额度也可以使用 +// return ""; +// } + if (getAppRemainingTime(pkg) <= 0) { + //没有剩余时间 + if (inWeekDay()) { + remainTime.setAvailableTime(appTimeControl.getWork_time()); + } else { + remainTime.setAvailableTime(appTimeControl.getRest_time()); + } + remainTime.setContent("该应用今日可使用时间已用完"); + //分类没有时间 + if (appTimeControl.getUse_type() == 1) { + remainTime.setDisableType(5); + remainTime.setAppUsageTimes(getClassAppUsageTime(appTimeControl.getClass_id())); + } else if (appTimeControl.getUse_type() == 2) { + remainTime.setDisableType(4); + remainTime.setAppUsageTimes(getMachineTime()); + } else { + remainTime.setDisableType(2); + } + return remainTime.getContent(); + } else { + return ""; + } + } + } else { +// if (appTimeControl.getIs_quota() == 0) { +// return ""; +// } + if (getAppRemainingTime(pkg) <= 0) { + //没有剩余时间 + if (appTimeControl.getUse_type() == 1) { + remainTime.setDisableType(5); + remainTime.setAppUsageTimes(getClassAppUsageTime(appTimeControl.getClass_id())); + } else if (appTimeControl.getUse_type() == 2) { + remainTime.setDisableType(4); + remainTime.setAppUsageTimes(getMachineTime()); + } else { + remainTime.setDisableType(2); + } + remainTime.setContent("该应用今日可使用时间已用完"); + return remainTime.getContent(); + } + return ""; + } + } else { + //根据整机 + if (machineControl == null) { + return ""; + } + if (inWeekDay()) { + remainTime.setTotalTime(machineControl.getWork_time()); + } else { + remainTime.setTotalTime(machineControl.getRest_time()); + } +// if (machineControl.is_quota == 1) { + if (haveUseTime(machineControl.getWork_time(), machineControl.getRest_time(), machineControl.getToday_time())) { + return ""; + } else { + boolean inControlTime = inControlTime(machineControl); + if (inControlTime) { + remainTime.setDisableType(3); + remainTime.setContent("该应用" + partTime2String(machineControl)); + return remainTime.getContent(); + } else { + return ""; + } + } +// } else { +// //关闭整机额度开关 始终可用 +// return ""; +// } + } + } + + /** + * 获取id对应分类每个app的时间 + * + * @param id + * @return + */ + private List getClassAppUsageTime(int id) { + List appUsageTimes = new ArrayList<>(); + HashMap appTimeControlHashMap = TimeControlManager.getInstance().getAppTimeControlMap(); + if (appTimeControlHashMap == null || appTimeControlHashMap.size() == 0) { + return appUsageTimes; + } + appTimeControlHashMap.entrySet().stream().forEach((entry) -> { + if (entry.getValue().getClass_id() == id) { + String pkg = entry.getKey(); + if (TextUtils.isEmpty(pkg)) { + return; + } + AppUsageTime appUsageTime = mAllAppUsageTime.get(pkg); + if (appUsageTime != null) { + appUsageTimes.add(appUsageTime); + } + } + }); + if (appUsageTimes.size() == 0) { + return appUsageTimes; + } + //时间补偿 防止以后每个应用加起来时间不对的问题 + TimeManageApp appTimeControl = TimeControlManager.getInstance().getAppTimeControl(appUsageTimes.get(0).getPkg()); + long allTime = 0; + if (inWeekDay()) { + allTime = appTimeControl.getWork_time(); + } else { + allTime = appTimeControl.getRest_time(); + } + long tempTime = 0; + for (AppUsageTime appUsageTime : appUsageTimes) { + tempTime += appUsageTime.getUsageTime(); + } + appUsageTimes.sort(new Comparator() { + @Override + public int compare(AppUsageTime o1, AppUsageTime o2) { + if (o1.getUsageTime() > o2.getUsageTime()) { + return 1; + } else if (o1.getUsageTime() == o2.getUsageTime()) { + return 0; + } else if (o1.getUsageTime() < o2.getUsageTime()) { + return -1; + } + return 1; + } + }); + if (tempTime < allTime) { + AppUsageTime lastAppUsageTime = appUsageTimes.get(appUsageTimes.size() - 1); + appUsageTimes.get(appUsageTimes.size() - 1).setUsageTime(lastAppUsageTime.getUsageTime() + (allTime - tempTime)); + } else if (tempTime > allTime) { + AppUsageTime lastAppUsageTime = appUsageTimes.get(appUsageTimes.size() - 1); + appUsageTimes.get(appUsageTimes.size() - 1).setUsageTime(lastAppUsageTime.getUsageTime() - (tempTime - allTime)); + } + return appUsageTimes; + } + + private List getAppClassificationTime(int id) { + List appUsageTimes = new ArrayList<>(); + HashMap appTimeControlHashMap = TimeControlManager.getInstance().getAppTimeControlMap(); + if (appTimeControlHashMap == null || appTimeControlHashMap.size() == 0) { + return appUsageTimes; + } + appTimeControlHashMap.entrySet().stream().forEach((entry) -> { + if (entry.getValue().getClass_id() == id) { + String pkg = entry.getKey(); + if (TextUtils.isEmpty(pkg)) { + return; + } + AppUsageTime appUsageTime = new AppUsageTime(); + appUsageTime.setPkg(pkg); + appUsageTime.setAppName(getAppName(pkg)); + AppRunTimeBean appRunTimeBean = mRemainingTimeMap.get(pkg); + long usageTime = appRunTimeBean.getAppRunTime(); + Log.e(TAG, "getAppClassificationTime: " + pkg + ": usageTime = " + usageTime); + long time; + if (inWeekDay()) { + time = entry.getValue().getWork_time() - usageTime; + } else { + time = entry.getValue().getRest_time() - usageTime; + } + appUsageTime.setUsageTime(time); + if (time > 0) { + appUsageTimes.add(appUsageTime); + } + } + }); + return appUsageTimes; + } + + private List getMachineTime() { + List appUsageTimes = new ArrayList<>(); + if (mGlobalUsageTime == null) { + return appUsageTimes; + } + mGlobalUsageTime.entrySet().stream().forEach((entry) -> { + if (entry.getValue().getUsageTime() > 0) { + appUsageTimes.add(entry.getValue()); + } + }); + return appUsageTimes; + } + + private boolean haveUseTime(long workTime, long restTime, long todayTime) { + //不用去管工作日还是休息日,后台返回的就是剩余时间 +// if (inWeekDay()) { +// return workTime - todayTime <= 0; +// } else { +// return restTime - todayTime <= 0; +// } + Log.i(TAG, "haveUseTime: " + globalRemainingTime); + return (globalRemainingTime > 0); + } + + + /** + * 整机使用额度 + * + * @param machineControl + * @return + */ + public boolean inControlTime(TimeManageSn machineControl) { + //整机使用时段开关 开启时 +// if (machineControl.getIs_part() == 1) { +// int partType = machineControl.getPart_type(); + if (machineControl.getTime_part() != null && machineControl.getTime_part().size() != 0) { + int partType = 1; + HashSet weekdayPart = machineControl.getTime_part().stream().filter(partTime -> partTime.getDay_type() == 0).collect(Collectors.toCollection(HashSet::new)); + HashSet holidayPart = machineControl.getTime_part().stream().filter(partTime -> partTime.getDay_type() == 1).collect(Collectors.toCollection(HashSet::new)); + //工作日 + if (inWeekDay()) { + return inControlTime(partType, weekdayPart); + } else {//休息日 + return inControlTime(partType, holidayPart); + } + } else { + return false; + } + } + + public boolean inControlTime(HashSet partTimeHashSet) { + //没有设置管控时段的情况 + if (partTimeHashSet == null || partTimeHashSet.size() == 0) { + return false; + } else { + for (TimeManagePart partTime : partTimeHashSet) { + if (inControlTime(partTime)) { + return true; + } + } + return false; + } + } + + /** + * 通过tc_use_type判断配置 + * + * @param machineControl + * @param appTimeControl + * @return + */ + public boolean inControlTime(TimeManageSn machineControl, TimeManageApp appTimeControl) { + //使用控制方式 0始终可用 1分类 2整机 3自由 + switch (appTimeControl.getUse_type()) { + case 0: + return false; + case 1: + case 3: + return isControlTime(appTimeControl); + case 2: + return inControlTime(machineControl); + default: + return true; + } + } + + /** + * 是否在禁用时间段内 + * + * @param appTimeControl + * @return + */ + public boolean isControlTime(TimeManageApp appTimeControl) { + //整机使用时段开关 开启时 +// if (appTimeControl.getIs_part() == 1) { +// int partType = appTimeControl.getPart_type(); + if (appTimeControl.getTime_part() != null && appTimeControl.getTime_part().size() != 0) { + int partType = 1; + HashMap> partTimeMap = new HashMap(); + HashSet weekdayPart = new HashSet(appTimeControl.getTime_part().stream().filter(partTime -> partTime.getDay_type() == 0).collect(Collectors.toList())); + HashSet holidayPart = new HashSet(appTimeControl.getTime_part().stream().filter(partTime -> partTime.getDay_type() == 1).collect(Collectors.toList())); + partTimeMap.put(0, weekdayPart); + partTimeMap.put(1, holidayPart); + if (inWeekDay()) { + //工作日 + Set partTimeHashSet = partTimeMap.get(0); + //使用时间段-开放 + return inControlTime(partType, partTimeHashSet); + } else { + //休息日 + Set partTimeHashSet = partTimeMap.get(1); + return inControlTime(partType, partTimeHashSet); + } + } else { + if (inWeekDay()) { + //工作日 + + } else { + //休息日 + + } + //关闭的时候都可以运行 + return false; + } + } + + /** + * @param partType 使用时间段类型 0禁用 1开放 + * @param partTimeHashSet + * @return + */ + private boolean inControlTime(int partType, Set partTimeHashSet) { + if (partTimeHashSet != null) { + if (partType == 0) { + List inPartTimes = new ArrayList<>(); + for (TimeManagePart partTime : partTimeHashSet) { + inPartTimes.add(inControlTime(partTime)); + } + //禁用时段需要满足所有 + boolean inPartTime = inPartTimes.indexOf(true) >= 0; + return inPartTime; + } else if (partType == 1) { + //开放时段只需要满足一个就行 + for (TimeManagePart partTime : partTimeHashSet) { + if (inControlTime(partTime)) { + return false; + } + } + } + } + return true; + } + + private boolean inControlTime(TimeManagePart partTime) { + String startTime = partTime.getStart_time(); + String endTime = partTime.getEnd_time(); + ContralTime contralTime = new ContralTime(startTime, endTime); + boolean inControlTime = contralTime.inControlTime(); + Log.i(TAG, "inControlTime: " + inControlTime); + return inControlTime; + } + + public static class ContralTime { + //format HH:mm + String startTime; + String endTime; + + public ContralTime() { + + } + + public ContralTime(String startT, String endT) { + this.startTime = startT; + this.endTime = endT; + } + + public String getStartTime() { + return startTime; + } + + + public void setStartTime(String startT) { + this.startTime = startT; + } + + public String getEndTime() { + return endTime; + } + + public void setEndTime(String endT) { + this.endTime = endT; + } + + public static DateFormat getDf() { + return dateFormat; + } + + public static void setDf(DateFormat d) { + dateFormat = d; + } + + public String getNowTimeString(long time) { + return dateFormat.format(new Date(time)); + } + + /*在时间段内返回 true,没有返回false*/ + public boolean inControlTime() { + long time = System.currentTimeMillis(); + return inControlTime(time); + } + + public boolean inControlTime(long time) { + return inControlTime(dateFormat.format(new Date(time))); + } + + public boolean inControlTime(String time) { + if (TextUtils.isEmpty(time)) { + throw new RuntimeException("Time is empty"); + } else { + if (!time.contains(":")) { + throw new RuntimeException("Time format error"); + } + } + try { + Date startDate = dateFormat.parse(startTime); + Date endDate = dateFormat.parse(endTime); + Date nowDate = dateFormat.parse(time); + if (startDate.getTime() > endDate.getTime()) { + //开始时间大于结束时间 列 16:00-01:00 + endDate.setTime(endDate.getTime() + dayTime); + } + Log.i(TAG, "inControlTime: " + (startDate.getTime() - minuteTime)); + assert nowDate != null; +// if (nowDate.getTime() <= startDate.getTime() - minuteTime || nowDate.getTime() >= endDate.getTime()) { + if (nowDate.getTime() >= startDate.getTime() && nowDate.getTime() <= endDate.getTime()) { + return true; + } else { + return false; + } + } catch (ParseException e) { + e.printStackTrace(); + } + return false; + } + + @NonNull + @Override + public String toString() { + return startTime + "\t-\t" + endTime; + } + } + + + /** + * 获取格式化后的时间 + * + * @param time 时间戳 + * @return 时间戳格式化文本 + */ + public String getDate(long time) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + String finaWayDate = sdf.format(time); + Log.i(TAG, "getDate: " + finaWayDate); + return finaWayDate; + } + + /** + * 获取周几 + * + * @return 周几的数字 + */ + public int getWeekDay() { + long time = System.currentTimeMillis(); + Log.i(TAG, "getWeekDay: " + time); + return getWeekDay(time); + } + + /** + * 获取周几 + * + * @param time 时间戳 + * @return 周几的数字 1-7 + */ + public int getWeekDay(long time) { + getDate(time); + Calendar now = Calendar.getInstance(); + now.setTimeInMillis(time); + //一周第一天是否为星期天 + boolean isFirstSunday = (now.getFirstDayOfWeek() == Calendar.SUNDAY); + //获取周几 + int weekDay = now.get(Calendar.DAY_OF_WEEK); + //若一周第一天为星期天,则-1 + if (isFirstSunday) { + weekDay = weekDay - 1; + if (weekDay == 0) { + weekDay = 7; + } + } + return weekDay; + } + + private String[] weekDays = {"星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"}; + + /** + * 获取星期几 + * + * @return 星期的文本 + */ + public String getWeekDayString() { + return weekDays[getWeekDay() - 1]; + } + + /** + * 获取星期几 + * + * @param time 时间戳 + * @return 星期的文本 + */ + public String getWeekDayString(long time) { + return weekDays[getWeekDay(time) - 1]; + } + + /** + * 是否未周末 + * + * @return 周末返回false 工作日返回true + */ + public boolean inWeekDay() { + long time = System.currentTimeMillis(); + return inWeekDay(time); + } + + public int getDayType() { + long time = System.currentTimeMillis(); + if (inWeekDay(time)) { + return 0; + } else { + return 1; + } + } + + /** + * 是否未周末 + * + * @param time 时间戳 + * @return 周末返回false 工作日返回true + */ + public boolean inWeekDay(long time) { + int weekDay = getWeekDay(time); + if (weekDay > 5) { + return false; + } else { + return true; + } + } + + private String getTopActivityInfo() { + ActivityManager manager = (ActivityManager) mContext.getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE); + String currentClassName = manager.getRunningTasks(1).get(0).topActivity.getPackageName(); + return currentClassName; + } + + /** + * 获取栈顶的应用包名 + */ + public String getForegroundActivityName() { + String currentClassName = ""; + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { + ActivityManager manager = (ActivityManager) mContext.getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE); + currentClassName = manager.getRunningTasks(1).get(0).topActivity.getPackageName(); + } else { + UsageStats initStat = getForegroundUsageStats(START_TIME, System.currentTimeMillis()); + if (initStat != null) { + currentClassName = initStat.getPackageName(); + } + } + Log.i(TAG, "getForegroundActivityName: " + currentClassName); + return currentClassName; + } + + /** + * 获取记录前台应用的UsageStats对象 + */ + private UsageStats getForegroundUsageStats(long startTime, long endTime) { + UsageStats usageStatsResult = null; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + List usageStatses = getUsageStatsList(startTime, endTime); + if (usageStatses == null || usageStatses.isEmpty()) { + return null; + } + for (UsageStats usageStats : usageStatses) { + if (usageStatsResult == null || usageStatsResult.getLastTimeUsed() < usageStats.getLastTimeUsed()) { + usageStatsResult = usageStats; + } + } + } + return usageStatsResult; + } + + /** + * 获取记录当前应用的UsageStats对象 + */ + public UsageStats getCurrentUsageStats(long startTime, long endTime) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + List usageStatses = getUsageStatsList(startTime, endTime); + if (usageStatses == null || usageStatses.isEmpty()) { + return null; + } + for (UsageStats usageStats : usageStatses) { + if (TextUtils.equals(usageStats.getPackageName(), mContext.getPackageName())) { + return usageStats; + } + } + } + return null; + } + + /** + * 通过UsageStatsManager获取List集合 + */ + public List getUsageStatsList(long startTime, long endTime) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + UsageStatsManager manager = (UsageStatsManager) mContext.getApplicationContext().getSystemService(Context.USAGE_STATS_SERVICE); + //UsageStatsManager.INTERVAL_WEEKLY,UsageStatsManager的参数定义了5个,具体查阅源码 + List usageStatses = manager.queryUsageStats(UsageStatsManager.INTERVAL_BEST, startTime, endTime); + if (usageStatses == null || usageStatses.size() == 0) {// 没有权限,获取不到数据 + Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + // TODO: 2022/6/27 每次都会弹出来 +// mContext.getApplicationContext().startActivity(intent); + return null; + } + return usageStatses; + } + return null; + } + + + public void killPackage(String pkg) { + ActivityManager manager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE); + manager.killBackgroundProcesses(pkg); + CmdUtil.execute("am force-stop " + pkg); + } +} diff --git a/src/com/uiuipad/os/manager/TimeControlManager.java b/src/com/uiuipad/os/manager/TimeControlManager.java new file mode 100644 index 0000000..d8d8ca5 --- /dev/null +++ b/src/com/uiuipad/os/manager/TimeControlManager.java @@ -0,0 +1,191 @@ +package com.uiuipad.os.manager; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.text.TextUtils; +import android.util.Log; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import com.tencent.mmkv.MMKV; +import com.uiuipad.os.comm.CommonConfig; +import com.uiuipad.os.disklrucache.CacheHelper; +import com.uiuipad.os.network.UrlAddress; +import com.uiuipad.os.network.bean.TimeManageApp; +import com.uiuipad.os.network.bean.TimeManageSn; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.stream.Collectors; + +public class TimeControlManager { + private static final String TAG = TimeControlManager.class.getSimpleName(); + + @SuppressLint("StaticFieldLeak") + private static TimeControlManager mTimeControlManager; + private Context mContext; + private MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE); + + private HashMap mClassifyTimeControlHashMap = new HashMap<>(); + /*分类的所有包名列表*/ + private HashMap mAppTimeControlMap = new HashMap<>(); + /*整机分类*/ + private TimeManageSn mGlobalMachineControl; + + private TimeControlManager(Context context) { + if (context == null) { + throw new RuntimeException("Context is NULL"); + } + this.mContext = context; + String appTimeControlJson = mMMKV.decodeString(UrlAddress.GET_TIME_MANAGE_APP, ""); + if (!TextUtils.isEmpty(appTimeControlJson)) { + Gson gson = new Gson(); + Type type = new TypeToken>() { + }.getType(); + try { + List appTimeControls = gson.fromJson(appTimeControlJson, type); + setAppTimeControlMap(appTimeControls); + } catch (Exception e) { + Log.e(TAG, "TimeControlManager: " + e.getMessage()); + } + } + } + + public static void init(Context context) { + if (mTimeControlManager == null) { + mTimeControlManager = new TimeControlManager(context); + } + } + + public static TimeControlManager getInstance() { + if (mTimeControlManager == null) { + throw new IllegalStateException("You must be init TimeControlManager first"); + } + return mTimeControlManager; + } + + public HashMap getAppTimeControlMap() { + return mAppTimeControlMap; + } + + /** + * 判断是否有配置存在 + * + * @param pkg + * @return + */ + public boolean havaConfigure(String pkg) { + TimeManageApp appTimeControl = mAppTimeControlMap.get(pkg); + if (appTimeControl == null) { + Log.e(TAG, "havaConfigure: not"); + return false; + } else { + if (appTimeControl.getUse_type() == 1) { + //根据分类 + Log.e(TAG, "havaConfigure: classify"); + return mClassifyTimeControlHashMap.get(appTimeControl.getClass_id()) != null; + } + Log.e(TAG, "havaConfigure: hava"); + return true; + } + } + + /** + * 获取整机配置 + * + * @return + */ + public TimeManageSn getGlobalMachineControl() { + if (mGlobalMachineControl == null) { + String jsonString = mMMKV.decodeString(UrlAddress.GET_TIME_MANAGE_SN, ""); + //为 "" 是已经请求成功的 + if (jsonString == null) { + return null; + } else { + Gson gson = new Gson(); + Type Type = new TypeToken() { + }.getType(); + TimeManageSn machineControl = gson.fromJson(jsonString, Type); + return machineControl; + } + } else { + return mGlobalMachineControl; + } + } + + public void setGlobalMachineControl(TimeManageSn machineControl) { + this.mGlobalMachineControl = machineControl; + if (machineControl != null) { + RunningAppManager.getInstance().setGlobalUsageTime(machineControl.getToday_time()); + } + } + + /** + * 获取app的配置 + * + * @param pkg + * @return + */ + public TimeManageApp getAppTimeControl(String pkg) { + TimeManageApp temp = mAppTimeControlMap.get(pkg); + if (temp == null) { + String jsonString = mMMKV.decodeString(UrlAddress.GET_TIME_MANAGE_APP, ""); + //为 "" 是已经请求成功的 + if (jsonString == null) { + return null; + } else { + Gson gson = new Gson(); + Type Type = new TypeToken>() { + }.getType(); + List appTimeControlList = gson.fromJson(jsonString, Type); + if (appTimeControlList == null) { + return null; + } + HashMap appTimeControlMap = new HashMap<>(); + for (TimeManageApp appTimeControl : appTimeControlList) { + appTimeControlMap.put(appTimeControl.getApp_package(), appTimeControl); + } + setAppTimeControlMap(appTimeControlList); + return appTimeControlMap.get(pkg); + } + } else { + return temp; + } + } + + public void setAppTimeControl(String pkg, TimeManageApp appTimeControl) { + this.mAppTimeControlMap.put(pkg, appTimeControl); + } + + + /** + * 设置app的配置 + * + * @param appTimeControlList + */ + public void setAppTimeControlMap(List appTimeControlList) { + if (appTimeControlList == null || appTimeControlList.size() == 0) { + return; + } + HashMap classifyTimeControlHashMap = new HashMap<>(); + List filterAppTimeControlList = appTimeControlList.stream().filter(appTimeControl -> { + //tc_use_type == 1 时用的是分类配置,配置都是一样的 + return appTimeControl.getUse_type() == 1; + }).collect(Collectors.toList()); + for (TimeManageApp appTimeControl : filterAppTimeControlList) { + classifyTimeControlHashMap.put(appTimeControl.getClass_id(), appTimeControl); + } + this.mClassifyTimeControlHashMap = classifyTimeControlHashMap; + + HashMap appTimeControlMap = new HashMap<>(); + List appTimeControls = new ArrayList<>(); + for (TimeManageApp appTimeControl : appTimeControlList) { + appTimeControlMap.put(appTimeControl.getApp_package(), appTimeControl); + appTimeControls.add(appTimeControl); + } + RunningAppManager.getInstance().syncAppRemainingTime(appTimeControls); + this.mAppTimeControlMap = appTimeControlMap; + } +} diff --git a/src/com/uiuipad/os/manager/bean/AppRunTimeBean.java b/src/com/uiuipad/os/manager/bean/AppRunTimeBean.java new file mode 100644 index 0000000..74d7ffe --- /dev/null +++ b/src/com/uiuipad/os/manager/bean/AppRunTimeBean.java @@ -0,0 +1,75 @@ +package com.uiuipad.os.manager.bean; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import java.io.Serializable; + +public class AppRunTimeBean implements Serializable { + private static final long serialVersionUID = 3699088127005434759L; + + String packageName; + Long appRunTime; + + AppRunTimeBean() { + this.appRunTime = 0L; + } + + public AppRunTimeBean(String pkg) { + this.packageName = pkg; + this.appRunTime = 0L; + } + + AppRunTimeBean(String pkg, long time) { + this.packageName = pkg; + this.appRunTime = time; + } + + public String getPackageName() { + return packageName; + } + + public void setPackageName(String packageName) { + this.packageName = packageName; + } + + public void reduceTime(Long time) { + this.appRunTime -= time; + } + + public Long getAppRunTime() { + return appRunTime; + } + + public void setAppRunTime(Long appRunTime) { + this.appRunTime = appRunTime; + } + + @NonNull + @Override + public String toString() { + Gson gson = new Gson(); + JsonObject jsonObject = JsonParser.parseString(gson.toJson(this)).getAsJsonObject(); + return jsonObject.toString(); + } + + @Override + public int hashCode() { + return super.hashCode(); + } + + @Override + public boolean equals(@Nullable Object obj) { + if (obj instanceof AppRunTimeBean) { + AppRunTimeBean appRunTimeBean = (AppRunTimeBean) obj; + return appRunTimeBean.packageName.equals(packageName) + && appRunTimeBean.appRunTime.equals(appRunTime); + } else { + return false; + } + } +} diff --git a/src/com/uiuipad/os/manager/bean/AppUsageTime.java b/src/com/uiuipad/os/manager/bean/AppUsageTime.java new file mode 100644 index 0000000..f0f135c --- /dev/null +++ b/src/com/uiuipad/os/manager/bean/AppUsageTime.java @@ -0,0 +1,50 @@ +package com.uiuipad.os.manager.bean; + +import androidx.annotation.NonNull; + +import com.google.gson.Gson; +import com.google.gson.JsonParser; + +import java.io.Serializable; + +public class AppUsageTime implements Serializable { + private static final long serialVersionUID = -2981074385838909527L; + + /*包名*/ + String pkg; + /*应用名*/ + String appName; + /*使用时间*/ + long usageTime; + + + public String getPkg() { + return pkg; + } + + public void setPkg(String pkg) { + this.pkg = pkg; + } + + public String getAppName() { + return appName; + } + + public void setAppName(String appName) { + this.appName = appName; + } + + public long getUsageTime() { + return usageTime; + } + + public void setUsageTime(long usageTime) { + this.usageTime = usageTime; + } + + @NonNull + @Override + public String toString() { + return JsonParser.parseString(new Gson().toJson(this)).getAsJsonObject().toString(); + } +} diff --git a/src/com/uiuipad/os/manager/bean/RemainTime.java b/src/com/uiuipad/os/manager/bean/RemainTime.java new file mode 100644 index 0000000..aace546 --- /dev/null +++ b/src/com/uiuipad/os/manager/bean/RemainTime.java @@ -0,0 +1,88 @@ +package com.uiuipad.os.manager.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 RemainTime implements Serializable { + private static final long serialVersionUID = 5651493620850107410L; + + /*包名*/ + String pkg; + /** + * 禁用类型 + * 1 应用已被禁用 + * 2 该应用今日可使用时间已用完 + * 3 APP设置了禁用时间段 + * 4 该应用跟随整机使用,整机剩余时间不足 + * 5 该应用跟随分类使用,分类剩余时间不足 + */ + int disableType; + /*禁用提示*/ + String content; + /*总时间*/ + long totalTime; + /*应用设置的可用时间*/ + long availableTime; + /*app使用时间*/ + List mAppUsageTimes; + + + public String getPkg() { + return pkg; + } + + public void setPkg(String pkg) { + this.pkg = pkg; + } + + public int getDisableType() { + return disableType; + } + + public void setDisableType(int disableType) { + this.disableType = disableType; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public long getTotalTime() { + return totalTime; + } + + public void setTotalTime(long totalTime) { + this.totalTime = totalTime; + } + + public long getAvailableTime() { + return availableTime; + } + + public void setAvailableTime(long availableTime) { + this.availableTime = availableTime; + } + + public List getAppUsageTimes() { + return mAppUsageTimes; + } + + public void setAppUsageTimes(List appUsageTimes) { + this.mAppUsageTimes = appUsageTimes; + } + + @NonNull + @Override + public String toString() { + return JsonParser.parseString(new Gson().toJson(this)).getAsJsonObject().toString(); + } +} diff --git a/src/com/uiuipad/os/model/LoaderTask.java b/src/com/uiuipad/os/model/LoaderTask.java index 824a789..a952da4 100644 --- a/src/com/uiuipad/os/model/LoaderTask.java +++ b/src/com/uiuipad/os/model/LoaderTask.java @@ -307,6 +307,8 @@ public class LoaderTask implements Runnable { Log.e("verifyApplications", "whiteList: " + whiteList); int aihuaUnlock = Settings.System.getInt(context.getContentResolver(), "Aihua_unlock_state", 0); Log.e(TAG, "verifyApplications: aihuaUnlock = " + aihuaUnlock); + int is_control = Settings.Global.getInt(crv, "is_control", 0); + Log.e(TAG, "verifyApplications: is_control = " + is_control); for (UserHandle user : profiles) { final List apps = mLauncherApps.getActivityList(null, user); ArrayList added = new ArrayList(); @@ -315,8 +317,17 @@ public class LoaderTask implements Runnable { Log.e("verifyApplications", "AllAPP: " + app.getApplicationInfo().packageName); if (BuildConfig.APPLICATION_ID.equals(app.getApplicationInfo().packageName) || "com.ygyb.yischool".equals(app.getApplicationInfo().packageName) + || "com.cube.setlauncherdef".equals(app.getApplicationInfo().packageName) + || "com.iflytek.speechcloud".equals(app.getApplicationInfo().packageName) + || "com.oirsdfg89.flg".equals(app.getApplicationInfo().packageName) ) continue; + if (is_control == 1) { + if ("org.chromium.chrome".equals(app.getApplicationInfo().packageName) + || "org.chromium.webview_shell".equals(app.getApplicationInfo().packageName)) { + continue; + } + } /*系统应用*/ // if (JGYUtils.getInstance().getDeviceIsLocked() && aihuaUnlock != 1) { // if ((app.getApplicationFlags() & ApplicationInfo.FLAG_SYSTEM) == 1) { diff --git a/src/com/uiuipad/os/network/NetInterfaceManager.java b/src/com/uiuipad/os/network/NetInterfaceManager.java index 1052cfa..ff9eee4 100644 --- a/src/com/uiuipad/os/network/NetInterfaceManager.java +++ b/src/com/uiuipad/os/network/NetInterfaceManager.java @@ -21,13 +21,15 @@ import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; -import io.reactivex.Observable; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.schedulers.Schedulers; +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; +import io.reactivex.rxjava3.schedulers.Schedulers; import okhttp3.Cache; +import okhttp3.MediaType; import okhttp3.OkHttpClient; +import okhttp3.RequestBody; import retrofit2.Retrofit; -import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; +import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory; import retrofit2.converter.gson.GsonConverterFactory; public class NetInterfaceManager { @@ -73,7 +75,7 @@ public class NetInterfaceManager { .client(okHttpClient) .baseUrl(ROOT_URL) .addConverterFactory(GsonConverterFactory.create()) - .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) + .addCallAdapterFactory(RxJava3CallAdapterFactory.create()) .build(); } } @@ -94,6 +96,21 @@ public class NetInterfaceManager { return sInstance; } + public static RequestBody convertToRequestBody(String param) { + RequestBody requestBody = RequestBody.create(MediaType.parse("text/plain"), param); + return requestBody; + } + + public static RequestBody convertToRequestBody(int param) { + RequestBody requestBody = RequestBody.create(MediaType.parse("text/plain"), String.valueOf(param)); + return requestBody; + } + + public static RequestBody convertToRequestBody(long param) { + RequestBody requestBody = RequestBody.create(MediaType.parse("text/plain"), String.valueOf(param)); + return requestBody; + } + public Observable getCloudLessonSettingObservable() { return mRetrofit.create(CloudLessonSettingApi.class) .getCloudLessonSetting(Utils.getSerial(mContext)) @@ -108,7 +125,7 @@ public class NetInterfaceManager { .observeOn(AndroidSchedulers.mainThread()); } - public Observable getUploadAppUseLogObservable(Map params) { + public Observable getUploadAppUseLogObservable(Map params) { return mRetrofit.create(UploadAppUseLogApi.class) .uploadAppUseLog(params) .subscribeOn(Schedulers.io()) @@ -124,7 +141,7 @@ public class NetInterfaceManager { public Observable>> getTimeManageAppObservable() { return mRetrofit.create(TimeManageAppApi.class) - .getTimeManageSn(Utils.getSerial(mContext)) + .getTimeManageApp(Utils.getSerial(mContext)) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()); } diff --git a/src/com/uiuipad/os/network/UrlAddress.java b/src/com/uiuipad/os/network/UrlAddress.java index d75ea1f..a52292a 100644 --- a/src/com/uiuipad/os/network/UrlAddress.java +++ b/src/com/uiuipad/os/network/UrlAddress.java @@ -3,6 +3,7 @@ package com.uiuipad.os.network; public class UrlAddress { public static final String ROOT_URL = "https://kxapi.uiuios.com/android/"; + /*上传应用使用记录*/ public static final String UPLOAD_APP_USE_LOG = "app/app/uploadAppUseLog"; diff --git a/src/com/uiuipad/os/network/api/CloudLessonAppApi.java b/src/com/uiuipad/os/network/api/CloudLessonAppApi.java index 70553ba..26d4a8c 100644 --- a/src/com/uiuipad/os/network/api/CloudLessonAppApi.java +++ b/src/com/uiuipad/os/network/api/CloudLessonAppApi.java @@ -3,7 +3,7 @@ package com.uiuipad.os.network.api; import com.uiuipad.os.network.UrlAddress; import com.uiuipad.os.network.bean.BaseResponse; -import io.reactivex.Observable; +import io.reactivex.rxjava3.core.Observable; import retrofit2.http.GET; import retrofit2.http.Query; diff --git a/src/com/uiuipad/os/network/api/CloudLessonSettingApi.java b/src/com/uiuipad/os/network/api/CloudLessonSettingApi.java index 9b73dc8..84a1591 100644 --- a/src/com/uiuipad/os/network/api/CloudLessonSettingApi.java +++ b/src/com/uiuipad/os/network/api/CloudLessonSettingApi.java @@ -3,7 +3,7 @@ package com.uiuipad.os.network.api; import com.uiuipad.os.network.UrlAddress; import com.uiuipad.os.network.bean.BaseResponse; -import io.reactivex.Observable; +import io.reactivex.rxjava3.core.Observable; import retrofit2.http.GET; import retrofit2.http.Query; diff --git a/src/com/uiuipad/os/network/api/TimeManageAppApi.java b/src/com/uiuipad/os/network/api/TimeManageAppApi.java index 9861737..872f1b4 100644 --- a/src/com/uiuipad/os/network/api/TimeManageAppApi.java +++ b/src/com/uiuipad/os/network/api/TimeManageAppApi.java @@ -6,13 +6,13 @@ import com.uiuipad.os.network.bean.TimeManageApp; import java.util.List; -import io.reactivex.Observable; +import io.reactivex.rxjava3.core.Observable; import retrofit2.http.GET; import retrofit2.http.Query; public interface TimeManageAppApi { @GET(UrlAddress.GET_TIME_MANAGE_APP) - Observable>> getTimeManageSn( + Observable>> getTimeManageApp( @Query("sn") String sn ); } diff --git a/src/com/uiuipad/os/network/api/TimeManageSnApi.java b/src/com/uiuipad/os/network/api/TimeManageSnApi.java index b727339..1c0349d 100644 --- a/src/com/uiuipad/os/network/api/TimeManageSnApi.java +++ b/src/com/uiuipad/os/network/api/TimeManageSnApi.java @@ -4,7 +4,7 @@ import com.uiuipad.os.network.UrlAddress; import com.uiuipad.os.network.bean.BaseResponse; import com.uiuipad.os.network.bean.TimeManageSn; -import io.reactivex.Observable; +import io.reactivex.rxjava3.core.Observable; import retrofit2.http.GET; import retrofit2.http.Query; diff --git a/src/com/uiuipad/os/network/api/UploadAppUseLogApi.java b/src/com/uiuipad/os/network/api/UploadAppUseLogApi.java index 425fe4c..d3bd322 100644 --- a/src/com/uiuipad/os/network/api/UploadAppUseLogApi.java +++ b/src/com/uiuipad/os/network/api/UploadAppUseLogApi.java @@ -5,16 +5,16 @@ import com.uiuipad.os.network.bean.BaseResponse; import java.util.Map; -import io.reactivex.Observable; -import retrofit2.http.Field; -import retrofit2.http.FormUrlEncoded; +import io.reactivex.rxjava3.core.Observable; +import okhttp3.RequestBody; +import retrofit2.http.Multipart; import retrofit2.http.POST; import retrofit2.http.PartMap; public interface UploadAppUseLogApi { - @FormUrlEncoded + @Multipart @POST(UrlAddress.UPLOAD_APP_USE_LOG) Observable uploadAppUseLog( - @PartMap Map params + @PartMap Map params ); } diff --git a/src/com/uiuipad/os/network/bean/TimeManageApp.java b/src/com/uiuipad/os/network/bean/TimeManageApp.java index a8077b6..30d40e9 100644 --- a/src/com/uiuipad/os/network/bean/TimeManageApp.java +++ b/src/com/uiuipad/os/network/bean/TimeManageApp.java @@ -1,18 +1,16 @@ package com.uiuipad.os.network.bean; -import java.io.Serializable; -import java.util.List; +import androidx.annotation.NonNull; -public class TimeManageApp implements Serializable { +import com.google.gson.Gson; +import com.google.gson.JsonParser; + +public class TimeManageApp extends TimeManageSn { private static final long serialVersionUID = 8994636991878020624L; String app_package; - int class_id; - int use_type; - long work_time; - long rest_time; - long today_time; - List time_part; + int class_id;//分类id + int use_type;//控制方式 0 始终可用 1分类 2整机 3自由 public String getApp_package() { return app_package; @@ -38,35 +36,9 @@ public class TimeManageApp implements Serializable { this.use_type = use_type; } - 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 long getToday_time() { - return today_time; - } - - public void setToday_time(long today_time) { - this.today_time = today_time; - } - - public List getTime_part() { - return time_part; - } - - public void setTime_part(List time_part) { - this.time_part = time_part; + @NonNull + @Override + public String toString() { + return JsonParser.parseString(new Gson().toJson(this)).getAsJsonObject().toString(); } } diff --git a/src/com/uiuipad/os/network/bean/TimeManagePart.java b/src/com/uiuipad/os/network/bean/TimeManagePart.java index 720bc61..4b70deb 100644 --- a/src/com/uiuipad/os/network/bean/TimeManagePart.java +++ b/src/com/uiuipad/os/network/bean/TimeManagePart.java @@ -1,5 +1,12 @@ package com.uiuipad.os.network.bean; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + import java.io.Serializable; public class TimeManagePart implements Serializable { @@ -7,7 +14,7 @@ public class TimeManagePart implements Serializable { String start_time; String end_time; - int day_type; + int day_type;//0上学日 1休息日 public String getStart_time() { return start_time; @@ -32,4 +39,29 @@ public class TimeManagePart implements Serializable { public void setDay_type(int day_type) { this.day_type = day_type; } + + @NonNull + @Override + public String toString() { + Gson gson = new Gson(); + JsonObject jsonObject = JsonParser.parseString(gson.toJson(this)).getAsJsonObject(); + return jsonObject.toString(); + } + + @Override + public int hashCode() { + return super.hashCode(); + } + + @Override + public boolean equals(@Nullable Object obj) { + if (obj instanceof TimeManagePart) { + TimeManagePart partTime = (TimeManagePart) obj; + return start_time.equals(partTime.start_time) + && end_time.equals(partTime.end_time) + && day_type == partTime.day_type; + } else { + return false; + } + } } diff --git a/src/com/uiuipad/os/network/bean/TimeManageSn.java b/src/com/uiuipad/os/network/bean/TimeManageSn.java index c8ebc8e..1334150 100644 --- a/src/com/uiuipad/os/network/bean/TimeManageSn.java +++ b/src/com/uiuipad/os/network/bean/TimeManageSn.java @@ -1,14 +1,19 @@ package com.uiuipad.os.network.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 TimeManageSn implements Serializable { private static final long serialVersionUID = 7571406354160374162L; - long work_time; - long rest_time; - long today_time; + long work_time;//上学日额度 单位秒 + long rest_time;//休息日额度 单位秒 + long today_time;//今日剩余时间 单位秒 List time_part; public long getWork_time() { @@ -42,4 +47,10 @@ public class TimeManageSn implements Serializable { public void setTime_part(List time_part) { this.time_part = time_part; } + + @NonNull + @Override + public String toString() { + return JsonParser.parseString(new Gson().toJson(this)).getAsJsonObject().toString(); + } } diff --git a/src/com/uiuipad/os/network/interceptor/RepeatRequestInterceptor.java b/src/com/uiuipad/os/network/interceptor/RepeatRequestInterceptor.java index 492fbde..d0602fe 100644 --- a/src/com/uiuipad/os/network/interceptor/RepeatRequestInterceptor.java +++ b/src/com/uiuipad/os/network/interceptor/RepeatRequestInterceptor.java @@ -39,7 +39,7 @@ public class RepeatRequestInterceptor implements Interceptor { // Response copy = response.newBuilder().body(responseBody).build(); ResponseBody copy = ResponseBody.create(responseBody.contentType(), content); if (BuildConfig.DEBUG) { - Log.e(TAG, "请求体返回:| Response: " + request.url().encodedPath() + "\t body: " + content); + Log.e(TAG, "请求体返回:| Response: " + request.url() + "\t body: " + content); } //相同的请求 String requestKey = MD5Util.getUpperMD5Str(request.method() + request.url().toString() + requestBodyToString(request.body())); diff --git a/src/com/uiuipad/os/service/MainSContact.java b/src/com/uiuipad/os/service/MainSContact.java new file mode 100644 index 0000000..554383d --- /dev/null +++ b/src/com/uiuipad/os/service/MainSContact.java @@ -0,0 +1,17 @@ +package com.uiuipad.os.service; + +import com.uiuipad.os.base.BasePresenter; +import com.uiuipad.os.base.BaseView; + + +public class MainSContact { + interface Presenter extends BasePresenter { + void getTimeManageSn(); + void getTimeManageApp(); + } + + public interface MainView extends BaseView { + void getTimeManageSnFinish(); + void getTimeManageAppFinish(); + } +} diff --git a/src/com/uiuipad/os/service/MainSPresenter.java b/src/com/uiuipad/os/service/MainSPresenter.java new file mode 100644 index 0000000..c011a85 --- /dev/null +++ b/src/com/uiuipad/os/service/MainSPresenter.java @@ -0,0 +1,131 @@ +package com.uiuipad.os.service; + +import android.content.Context; +import android.util.Log; + +import com.tencent.mmkv.MMKV; + +import com.trello.rxlifecycle4.RxLifecycle; +import com.trello.rxlifecycle4.android.ActivityEvent; +import com.uiuipad.os.comm.CommonConfig; +import com.uiuipad.os.gson.GsonUtils; +import com.uiuipad.os.manager.TimeControlManager; +import com.uiuipad.os.network.NetInterfaceManager; +import com.uiuipad.os.network.UrlAddress; +import com.uiuipad.os.network.bean.BaseResponse; +import com.uiuipad.os.network.bean.TimeManageApp; +import com.uiuipad.os.network.bean.TimeManageSn; + +import java.util.List; + +import io.reactivex.rxjava3.core.Observer; +import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.subjects.BehaviorSubject; + +/** + * @author fanhuitong + */ +public class MainSPresenter implements MainSContact.Presenter { + private static final String TAG = MainSPresenter.class.getSimpleName(); + + private MainSContact.MainView mView; + private Context mContext; + + private MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE); + + public MainSPresenter(Context context) { + this.mContext = context; + } + + private BehaviorSubject lifecycle; + + public void setLifecycle(BehaviorSubject lifecycle) { + this.lifecycle = lifecycle; + } + + public BehaviorSubject getLifecycle() { + return lifecycle; + } + + @Override + public void attachView(MainSContact.MainView view) { + this.mView = view; + } + + @Override + public void detachView() { + this.mView = null; + } + + @Override + public void getTimeManageSn() { + NetInterfaceManager.getInstance().getTimeManageSnObservable() + .compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY)) + .safeSubscribe(new Observer>() { + @Override + public void onSubscribe(Disposable d) { + Log.e("getTimeManageSn", "onSubscribe: "); + } + + @Override + public void onNext(BaseResponse timeManageSnBaseResponse) { + Log.e("getTimeManageSn", "onNext: " + timeManageSnBaseResponse); + if (timeManageSnBaseResponse.code == 200) { + TimeManageSn timeManageSn = timeManageSnBaseResponse.data; + TimeControlManager.getInstance().setGlobalMachineControl(timeManageSn); + mMMKV.encode(UrlAddress.GET_TIME_MANAGE_SN, GsonUtils.toJSONString(timeManageSn)); + } else { + mMMKV.encode(UrlAddress.GET_TIME_MANAGE_SN, GsonUtils.toJSONString("")); + } + } + + @Override + public void onError(Throwable e) { + Log.e("getTimeManageSn", "onError: " + e.getMessage()); + onComplete(); + } + + @Override + public void onComplete() { + Log.e("getTimeManageSn", "onComplete: "); + mView.getTimeManageSnFinish(); + } + }); + } + + @Override + public void getTimeManageApp() { + NetInterfaceManager.getInstance().getTimeManageAppObservable() + .compose(RxLifecycle.bindUntilEvent(getLifecycle(), ActivityEvent.DESTROY)) + .subscribe(new Observer>>() { + @Override + public void onSubscribe(Disposable d) { + Log.e("getTimeManageApp", "onSubscribe: "); + } + + @Override + public void onNext(BaseResponse> listBaseResponse) { + Log.e("getTimeManageApp", "onNext: " + listBaseResponse); + if (listBaseResponse.code == 200) { + List timeManageApps = listBaseResponse.data; + TimeControlManager.getInstance().setAppTimeControlMap(timeManageApps); + mMMKV.encode(UrlAddress.GET_TIME_MANAGE_APP, GsonUtils.toJSONString(timeManageApps)); + } else { + mMMKV.encode(UrlAddress.GET_TIME_MANAGE_APP, GsonUtils.toJSONString("")); + } + } + + @Override + public void onError(Throwable e) { + Log.e("getTimeManageApp", "onError: " + e.getMessage()); + onComplete(); + } + + @Override + public void onComplete() { + Log.e("getTimeManageApp", "onComplete: "); + mView.getTimeManageAppFinish(); + } + }); + } +} diff --git a/src/com/uiuipad/os/service/MainService.java b/src/com/uiuipad/os/service/MainService.java index c0d7ee6..885b8e6 100644 --- a/src/com/uiuipad/os/service/MainService.java +++ b/src/com/uiuipad/os/service/MainService.java @@ -5,55 +5,82 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.os.Binder; import android.os.IBinder; -import android.os.PowerManager; -import android.text.TextUtils; import android.util.Log; -import com.uiuipad.os.BuildConfig; -import com.uiuipad.os.network.NetInterfaceManager; -import com.uiuipad.os.network.bean.BaseResponse; -import com.uiuipad.os.uiuiutils.APKUtils; -import com.uiuipad.os.uiuiutils.CmdUtil; -import com.uiuipad.os.uiuiutils.ForegroundAppUtil; -import com.uiuipad.os.uiuiutils.TimeUtils; -import com.uiuipad.os.uiuiutils.Utils; +import com.blankj.utilcode.util.NetworkUtils; +import com.trello.rxlifecycle4.LifecycleProvider; +import com.trello.rxlifecycle4.LifecycleTransformer; +import com.trello.rxlifecycle4.RxLifecycle; +import com.trello.rxlifecycle4.android.ActivityEvent; +import com.trello.rxlifecycle4.android.RxLifecycleAndroid; +import com.uiuipad.os.uiuiutils.ApkUtils; import com.arialyy.annotations.Download; import com.arialyy.aria.core.Aria; import com.arialyy.aria.core.task.DownloadTask; -import java.io.File; -import java.util.HashMap; -import java.util.Map; +import org.jetbrains.annotations.NotNull; -import io.reactivex.Observable; -import io.reactivex.ObservableEmitter; -import io.reactivex.ObservableOnSubscribe; -import io.reactivex.Observer; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.disposables.Disposable; -import io.reactivex.schedulers.Schedulers; -import okhttp3.MediaType; -import okhttp3.MultipartBody; -import okhttp3.RequestBody; +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.subjects.BehaviorSubject; -public class MainService extends Service { +public class MainService extends Service implements MainSContact.MainView , LifecycleProvider { private String TAG = MainService.class.getSimpleName(); + + + public MainSPresenter mPresenter; + + public MainService() { } + private BehaviorSubject lifecycleSubject = BehaviorSubject.create(); + + @NotNull + @Override + public Observable lifecycle() { + return lifecycleSubject.hide(); + } + + @NotNull + @Override + public LifecycleTransformer bindUntilEvent(@NotNull ActivityEvent event) { + return RxLifecycle.bindUntilEvent(lifecycleSubject, event); + } + + @NotNull + @Override + public LifecycleTransformer bindToLifecycle() { + return RxLifecycleAndroid.bindActivity(lifecycleSubject); + } + @Override public IBinder onBind(Intent intent) { - return null; + return mMainBinder; + } + + public MainBinder mMainBinder = new MainBinder(); + + public class MainBinder extends Binder { + public MainService getService() { + return MainService.this; + } } @Override public void onCreate() { + super.onCreate(); Log.e(TAG, "onCreate: "); registerTimeReceiver(); Aria.download(this).register(); - super.onCreate(); + + lifecycleSubject.onNext(ActivityEvent.CREATE); + mPresenter = new MainSPresenter(this); + mPresenter.setLifecycle(lifecycleSubject); + mPresenter.attachView(this); + mPresenter.getTimeManageSn(); } @Override @@ -75,6 +102,16 @@ public class MainService extends Service { private TimeChangedReceiver mTimeChangedReceiver; + @Override + public void getTimeManageSnFinish() { + mPresenter.getTimeManageApp(); + } + + @Override + public void getTimeManageAppFinish() { + + } + private class TimeChangedReceiver extends BroadcastReceiver { @Override @@ -96,6 +133,8 @@ public class MainService extends Service { @Override public void onDestroy() { super.onDestroy(); + lifecycleSubject.onNext(ActivityEvent.DESTROY); + mPresenter.detachView(); if (mTimeChangedReceiver != null) { unregisterReceiver(mTimeChangedReceiver); } @@ -108,7 +147,7 @@ public class MainService extends Service { @Download.onTaskComplete void taskComplete(DownloadTask task) { - APKUtils.installApp(MainService.this, task.getFilePath()); + ApkUtils.installApp(MainService.this, task.getFilePath()); Aria.download(this).load(task.getDownloadEntity().getId()).cancel(); } diff --git a/src/com/uiuipad/os/touch/ItemClickHandler.java b/src/com/uiuipad/os/touch/ItemClickHandler.java index b639160..2d768ca 100644 --- a/src/com/uiuipad/os/touch/ItemClickHandler.java +++ b/src/com/uiuipad/os/touch/ItemClickHandler.java @@ -44,6 +44,7 @@ import com.uiuipad.os.ItemInfo; import com.uiuipad.os.Launcher; import com.uiuipad.os.LauncherAppWidgetInfo; import com.uiuipad.os.LauncherAppWidgetProviderInfo; +import com.uiuipad.os.manager.RunningAppManager; import com.uiuipad.os.uiuiutils.CustomDialog; import com.uiuipad.os.uiuiutils.JGYUtils; import com.uiuipad.os.uiuiutils.ToastUtil; @@ -112,6 +113,10 @@ public class ItemClickHandler { // if (is_forbid(v.getContext(), packageName)) { // return; // } + if (RunningAppManager.getInstance().inControlTime(packageName)){ + ToastUtil.show(RunningAppManager.getInstance().getDisableContent(packageName)); + return; + } //获取本地密码 String ApplicationLock = MMKV.defaultMMKV().decodeString("ApplicationLock"); Log.e("onClick", "onClick: " + ApplicationLock); diff --git a/src/com/uiuipad/os/uiuiutils/APKUtils.java b/src/com/uiuipad/os/uiuiutils/ApkUtils.java similarity index 99% rename from src/com/uiuipad/os/uiuiutils/APKUtils.java rename to src/com/uiuipad/os/uiuiutils/ApkUtils.java index 035e8e7..2200efe 100644 --- a/src/com/uiuipad/os/uiuiutils/APKUtils.java +++ b/src/com/uiuipad/os/uiuiutils/ApkUtils.java @@ -26,7 +26,7 @@ import java.io.InputStreamReader; import java.io.OutputStream; import java.util.List; -public class APKUtils { +public class ApkUtils { public static boolean openPackage(Context context, String packageName) { Context pkgContext = getPackageContext(context, packageName); Intent intent = getAppOpenIntentByPackageName(context, packageName); diff --git a/src/com/uiuipad/os/uiuiutils/GsonUtils.java b/src/com/uiuipad/os/uiuiutils/GsonUtils.java deleted file mode 100644 index b20fe92..0000000 --- a/src/com/uiuipad/os/uiuiutils/GsonUtils.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.uiuipad.os.uiuiutils; - -import com.google.gson.Gson; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.google.gson.reflect.TypeToken; - -import java.lang.reflect.Type; - - -public class GsonUtils { - public static JsonObject getJsonObject(String jsonString) { - JsonObject jsonObject = JsonParser.parseString(jsonString).getAsJsonObject(); - return jsonObject; - } - - // TODO: 2022/3/31 暂时没有实现 - public static E getJsonFromType(String jsonString) { - Gson gson = new Gson(); - Type Type = new TypeToken() { - }.getType(); - E e = gson.fromJson(jsonString, Type); - return e; - } - - public static String toJsonString(Object o) { - return new Gson().toJson(o); - } -} diff --git a/src/doc/iPlay50SE.keystore b/src/doc/iPlay50SE.keystore new file mode 100644 index 0000000000000000000000000000000000000000..57f25214373c57f853a55218da54d97b8db56ff9 GIT binary patch literal 2717 zcmY+EX*d*&8ir@a7>u>ZGNde7nlSdUON1Ix_HAlJW6e4;*@t8qd$Pos3|X>AmSL

bvkAc=6`>&K!G4K0epxcfOip+5a@sKX*oZbODyY; zP8Evz>XC%KN8-vYi@@V9T@W3h!vstK_XKY!ndJM|i3N*?a}Vs=Em%UuZ#j>-LC227 zpG6{1nv|9v^X-DC(BnxiL)6sdsNa!MUgbo4vI!}oB=_ybgJ$d~%L6lumN{K@LIMcN zZsRw<{L|9=4XRoL7JSRYW-svKHadfn2t}yzK7Z<1t8>HrMYJ`Owd{EKI~iiu@}^UL zgaJ+kB$Hm=zG@%;rD*p^XYeN{^X!sC#(DY{#VbNggUf}!Uj6uV`>O@;RmZPy`=EAoC9V&31hxopAb`K! z#mhdHDwyoy7p&l`qtg&u-l>ecdgn>7m(#uYHSfeXEUE`1Mz*Ljp74#n9O zUzN>==Ch$3mD3a2;*HM^jnMP{DVG#Vtyk7opU@a-`c~G3IS*IDMMBaIFt1HIim%W0 z3@1&H=2P&PUaR^l7M`2Rh-k|prA=qk_g70_X8R$tg}XA}wJkr7BoRIZOGK9Xd4^>s zhunXB7k6^khBvlke-Txlc64q#i>lmGizTO$tE=CrcO0Fu!FceZk2%I?HLWuA#KRz5UXm~aWO|WBB>rEN<-O9|IzSwOMbR*4hgI%&KSF1c8H}nz|Tz(NmMHQ zz6ZPPhdOqr!|+MgQvm>h@jyyOoHg29;6lD#;Z^;y7w62KNk6YVPGT)VzAA01F5V0B z+}fyF7aJ_j3{QKQxb;aEmN)6wo_mPv#bflPn{6UDgyS0HAo@$+pw7TsjM2IbKFMX^ z5gRLKl|R(ab|b~SbV!b>|tj~|B2cLmGMeVKL-@AGfHFv~r` zN13SRwTNiT!B>s>*wuA63mTC2vlD-okdC6XA(%_-rqTQY-WD(|YSti|&FP80T8n<@ z@JiUt&?{Q=EuUqs{7$x7H>=mNNl-Wnw9JGX*8IM02*Oh+rMX9P-1TL}X66UeuX=A; zY&1Da%5qjjNmU_Ln!y@xW$v^871R0tTPxK++6hKi?{)bo;vV;UEUmOQZj5bfUy}^a z??Z(0(Ew|k=D;#;Ik3+1o=!h5G@MkJtlRgo89hFZ%1zAlT? zs8O4bP1MVQ2MjLBuxmzA&1N+&q4j3;SyRNuz8fzY>ri+-Z%b*HooP_Lw(Ik}71v#K zfz1w1%XN5yWw1{Cvm7flmMQExHENVEQvfDx7|cACAgcQWthAffB(10wZb{p^t6g#w zmBKe|mg#*yS8>24#6BiezWpWu?6t*0tz3#DD}A|nd6Md%Z7_o6F8LHOTCMKh16vf? zAX!Aj48k!jjWw?p1J}wcTUb#A7VLcWVizQmj7IGH*$fg*9w~aXX`M}Q>5jruXMs0^kd9`rngtvRvS^W-cC17iE={l~fdz)3b#=mARuipCxJ1qYm8?qFENlSCjwc z*)Rgw>)KviH=X@ixm!h;k$@gcbe-^m*~YI+CGVLiCgD7wVV=K$2Mm|we=@lbSte8S zkvjvEfaQ>sl1c7sL;N#ZZeuFN-dlOB+s=_AuTHuim?JVw16zB!szcQ^KO@!Q8n_i& zNhH^=io_kwT{DNmR5(#$vo4%4C)d^+6|6VBAT(A+uh_0&H*U(fmL2*o!+HL2pBpxL z(EaszW#G~E+oUEX;{n2Ur~DC*QSlm5?%aM0`pw(&$q<={5GAnC(lup zMCvoHQh`p`qdh0Sal8mv``w}&y9^{KF!<}w(!HC!JBwZ4DT zDAX4FvAr!lVnlw^aCTrsF}b$FQ&SS{8@xJBJJ{VGV+L?)c;CcpOsGUBpt+p@2u?Y+ zA+lU{%1?crP(}vMV+;I4EUmz^FVID6VsbdxU~-Sa*fS+DofoUVeFIfHXD?VE9q8e~ z>?-Ss`DQyzPA@@NVRt0+(E~rI)T8(czDZ8k32neZj=8^scS4o{6InrMmO&#I%7k+prGE zy!pJIWOF?J^`E<4cODN#5Q*9Pb`1j&G`f$?)xDamxZWt&JoCcd^NK2nfkRZsu9J_d zNHde7N~S>3uu0H__n4Vc$w_7!BQPl^k{NGc_?rS+G%f|D2oi*Rd~Y8$IyKDMmoaDh z=tQ3cYz8>}vW@?mOY?$gfzNBQQST#Rmvc#~XKPJ&3e(J*Z`_}k2}Nf*^m=4p))u%j zs5c-#^*JU!1U#D{4`)=c5L`F(Un?Q;1i2WcVx<^YIkFx#lN~qFrBGjVp9f@_D*NMu zJc}->RMf#d+$si)|G-TuriFMQqa_WVdfSWa(`u&{W51-Th@i1o=*wsQANORakA)(fQZ7ZKg1OW&b%JKal>>3e zpNf5u0R2Y|Vz!+6t)A)wIT!_^(IMC#xcmV5oMpGjRd2NU*%iqJ*DvD7#sTYDFUF3^ z!qLyO=DvKX^LoJt8FmSowx;*y)277O7DHzN)-S1dEQLE&WD$Wg zopxuEyuUK5I$9T5E-?44Yy;B4P{_1&UX35)xw-nG43mPJ?>Z#{G=4XcTUD@>lDeog zJlE%?hqAGE_80j1{UTjS}Em3LMCisHNmKy{4foKqnSk80=RrI~9L} zD<8L8wjagwu=a+GdcGCqd7!(^Gd6b1FG(B|k(z|^!X>xxWS!sGicO!it`dYMLI}YG zp@*~4fnf9iFqhq^#Zy+XlXr(f9}Etpe&^2}V5GrZ1RMrz<@SndRj^O@DZSRNgQx#K Jhz=M<{s*yh`NseN literal 0 HcmV?d00001