requestIdsMap = new ConcurrentHashMap<>();
+ //超时时间
+ private static int timeOut = 30;
+ // 缓存文件最大限制大小20M
+ private static long cacheSize = 1024 * 1024 * 64;
+
+ public static final String HTTP_KEY = "YTM3YTAxNTJmMmZmNzkyM2E2YzIwZjlhZTc0NzNmMGI=";
+ public static final String CUSTOM_REPEAT_REQ_PROTOCOL = "MY_CUSTOM_REPEAT_REQ_PROTOCOL";
+
+ private NetInterfaceManager(Context context) {
+ this.mContext = context;
+ if (okHttpClient == null) {
+ Interceptor interceptor = new Interceptor() {
+ @NotNull
+ @Override
+ public Response intercept(@NotNull Chain chain) throws IOException {
+ Request request = chain.request();
+ //相同的请求
+ String requestKey = MD5Util.getUpperMD5Str(request.method() + request.url().toString());
+ long time = System.currentTimeMillis();//请求时间
+ try {
+ if (requestIdsMap.size() > 0 && requestIdsMap.containsKey(requestKey)) {
+ Log.e("REPEAT-REQUEST", "重复请求:" + requestKey + " Method @" + request.method() + " --- " + " URL = " + request.url());
+ chain.call().cancel();
+ return new Response.Builder()
+ .protocol(Protocol.get(CUSTOM_REPEAT_REQ_PROTOCOL))
+ .request(request) //multi thread
+ .build();
+ }
+ requestIdsMap.put(requestKey, time);
+ Log.e("REPEAT-REQUEST", "注册请求:" + requestKey + " Method @" + request.method() + " --- " + " URL = " + request.url());
+// Request.Builder builder = request.newBuilder();
+// builder.addHeader("header", jsonObject.toString());
+ return chain.proceed(request);
+ } catch (IOException e) {
+ throw e;
+ } finally {
+ if (requestIdsMap.containsKey(requestKey) && requestIdsMap.containsValue(time)) {//请求任务完成删除map中的数据
+ requestIdsMap.remove(requestKey);
+ Log.e("REPEAT-REQUEST", "移除请求:" + requestKey + " Method @" + request.method() + " --- " + " URL = " + request.url());
+ }
+ }
+ }
+ };
+
+ //如果无法生存缓存文件目录,检测权限使用已经加上,检测手机是否把文件读写权限禁止了
+ OkHttpClient.Builder builder = new OkHttpClient.Builder();
+ builder.connectTimeout(timeOut, TimeUnit.SECONDS); // 设置连接超时时间
+ builder.writeTimeout(timeOut, TimeUnit.SECONDS);// 设置写入超时时间
+ builder.readTimeout(timeOut, TimeUnit.SECONDS);// 设置读取数据超时时间
+ builder.retryOnConnectionFailure(true);// 设置进行连接失败重试
+ builder.addInterceptor(interceptor);
+
+ // 设置缓存文件路径
+ String cacheDirectory = mContext.getExternalCacheDir().getAbsolutePath() + "/OkHttpCache";
+ Cache cache = new Cache(new File(cacheDirectory), cacheSize);
+ builder.cache(cache);// 设置缓存
+ okHttpClient = builder.build();
+ }
+
+ if (mRetrofit == null) {
+ mRetrofit = new Retrofit.Builder()
+ .client(okHttpClient)
+ .baseUrl(URLAddress.ROOT_URL)
+ .addConverterFactory(GsonConverterFactory.create())
+ .addCallAdapterFactory(RxJava3CallAdapterFactory.create())
+ .build();
+ }
+ }
+
+ /**
+ * 打印全局统一拦截添加的Http Headers
+ *
+ * 全局拦截的http 没法在配置中直接打印处理,因为先http 请求然后打印然后拦截添加的
+ *
+ * @param request
+ */
+ private static void logRequestHeaders(Request request) {
+ Log.e("OKhttp ", " 开始打印HTTP请求 Headers \n");
+ Headers headers = request.headers();
+ for (int i = 0, count = headers.size(); i < count; i++) {
+ String name = headers.name(i);
+ // Skip headers from the request body as they are explicitly logged above.
+ if (!"Content-Type".equalsIgnoreCase(name) && !"Content-Length".equalsIgnoreCase(name)) {
+ Log.e("OKhttp: " + i + " ", name + ": " + headers.value(i));
+ }
+ }
+ Log.e("OKhttp ", " 打印HTTP请求完成 Headers \n");
+ }
+
+ public static void init(Context context) {
+ if (INSTANCE == null) {
+ INSTANCE = new NetInterfaceManager(context);
+ }
+ }
+
+ public static NetInterfaceManager getInstance() {
+ if (INSTANCE == null) {
+ throw new IllegalStateException("You must be init NetworkManager first");
+ }
+ return INSTANCE;
+ }
+
+ public OkHttpClient getOkHttpClient() {
+ return okHttpClient;
+ }
+
+ /**
+ * 通过sn获取设备的信息
+ *
+ * @return
+ */
+ public Observable>> getAlarmClockApiObservable() {
+ return mRetrofit
+ .create(AlarmClockApi.class)
+ .getAlarmClockApiApi(Utils.getSerial())
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread());
+ }
+
+ public Observable getRunningAppObservable(String json) {
+ return mRetrofit.create(RunNewApp.class)
+ .sendRunningInfo(Utils.getSerial(), json)
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread());
+ }
+
+ public AppUsageRecordApi getAppUsageRecordControl() {
+ return mRetrofit.create(AppUsageRecordApi.class);
+ }
+
+ public SendScreenshotApi getScreenshotApi() {
+ return mRetrofit.create(SendScreenshotApi.class);
+ }
+}
diff --git a/app/src/main/java/com/uiui/os/network/URLAddress.java b/app/src/main/java/com/uiui/os/network/URLAddress.java
new file mode 100644
index 0000000..d8fa067
--- /dev/null
+++ b/app/src/main/java/com/uiui/os/network/URLAddress.java
@@ -0,0 +1,13 @@
+package com.uiui.os.network;
+
+public class URLAddress {
+ public static final String ROOT_URL = "https://led.aolelearn.cn/android/";
+ //获取闹钟
+ public static final String GET_ALARM_CLOCK = "getAlarmClock";
+ //应用使用记录
+ public static final String APP_USAGE_RECORD = "appUsageRecord";
+ //正在运行的应用
+ public static final String RUN_NEW_APP = "app/runNewApp";
+ //上传截图
+ public static final String SEND_SCREENSHOT = "sn/uploadScreenshot";
+}
diff --git a/app/src/main/java/com/uiui/os/network/api/AlarmClockApi.java b/app/src/main/java/com/uiui/os/network/api/AlarmClockApi.java
new file mode 100644
index 0000000..75bc53f
--- /dev/null
+++ b/app/src/main/java/com/uiui/os/network/api/AlarmClockApi.java
@@ -0,0 +1,18 @@
+package com.uiui.os.network.api;
+
+import com.uiui.os.bean.AlarmClockData;
+import com.uiui.os.bean.BaseResponse;
+import com.uiui.os.network.URLAddress;
+
+import java.util.List;
+
+import io.reactivex.rxjava3.core.Observable;
+import retrofit2.http.GET;
+import retrofit2.http.Query;
+
+public interface AlarmClockApi {
+ @GET(URLAddress.GET_ALARM_CLOCK)
+ Observable>> getAlarmClockApiApi(
+ @Query("sn") String sn
+ );
+}
diff --git a/app/src/main/java/com/uiui/os/network/api/AppUsageRecordApi.java b/app/src/main/java/com/uiui/os/network/api/AppUsageRecordApi.java
new file mode 100644
index 0000000..d159756
--- /dev/null
+++ b/app/src/main/java/com/uiui/os/network/api/AppUsageRecordApi.java
@@ -0,0 +1,21 @@
+package com.uiui.os.network.api;
+
+import com.uiui.os.bean.BaseResponse;
+import com.uiui.os.network.URLAddress;
+
+import io.reactivex.rxjava3.core.Observable;
+import retrofit2.http.Field;
+import retrofit2.http.FormUrlEncoded;
+import retrofit2.http.POST;
+
+public interface AppUsageRecordApi {
+ @FormUrlEncoded
+ @POST(URLAddress.APP_USAGE_RECORD)
+ Observable sendappUsageRecord(
+ @Field("sn") String sn,
+ @Field("app_name") String app_name,
+ @Field("app_package") String app_package,
+ @Field("open_time") long open_time,
+ @Field("close_time") long close_time
+ );
+}
diff --git a/app/src/main/java/com/uiui/os/network/api/RunNewApp.java b/app/src/main/java/com/uiui/os/network/api/RunNewApp.java
new file mode 100644
index 0000000..9b2a14c
--- /dev/null
+++ b/app/src/main/java/com/uiui/os/network/api/RunNewApp.java
@@ -0,0 +1,18 @@
+package com.uiui.os.network.api;
+
+import com.uiui.os.bean.BaseResponse;
+import com.uiui.os.network.URLAddress;
+
+import io.reactivex.rxjava3.core.Observable;
+import retrofit2.http.Field;
+import retrofit2.http.FormUrlEncoded;
+import retrofit2.http.POST;
+
+public interface RunNewApp {
+ @FormUrlEncoded
+ @POST(URLAddress.RUN_NEW_APP)
+ Observable sendRunningInfo(
+ @Field("sn") String sn,
+ @Field("app") String app
+ );
+}
diff --git a/app/src/main/java/com/uiui/os/network/api/SendScreenshotApi.java b/app/src/main/java/com/uiui/os/network/api/SendScreenshotApi.java
new file mode 100644
index 0000000..7a93163
--- /dev/null
+++ b/app/src/main/java/com/uiui/os/network/api/SendScreenshotApi.java
@@ -0,0 +1,23 @@
+package com.uiui.os.network.api;
+
+
+import com.uiui.os.bean.BaseResponse;
+import com.uiui.os.network.URLAddress;
+
+import java.util.Map;
+
+import io.reactivex.rxjava3.core.Observable;
+import okhttp3.MultipartBody;
+import retrofit2.http.Multipart;
+import retrofit2.http.POST;
+import retrofit2.http.Part;
+import retrofit2.http.Query;
+
+public interface SendScreenshotApi {
+ @Multipart
+ @POST(URLAddress.SEND_SCREENSHOT)
+ Observable sendScreenshot(
+ @Query("sn") String sn,
+ @Part MultipartBody.Part file
+ );
+}
diff --git a/app/src/main/java/com/uiui/os/receiver/BootReceiver.java b/app/src/main/java/com/uiui/os/receiver/BootReceiver.java
new file mode 100644
index 0000000..a8412bd
--- /dev/null
+++ b/app/src/main/java/com/uiui/os/receiver/BootReceiver.java
@@ -0,0 +1,88 @@
+package com.uiui.os.receiver;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.SystemClock;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.uiui.os.service.MainService;
+
+import java.util.concurrent.TimeUnit;
+
+import io.reactivex.rxjava3.core.Observable;
+import io.reactivex.rxjava3.core.ObservableOnSubscribe;
+import io.reactivex.rxjava3.core.Observer;
+import io.reactivex.rxjava3.disposables.Disposable;
+
+public class BootReceiver extends BroadcastReceiver {
+ private static String TAG = BootReceiver.class.getSimpleName();
+ public static final String BOOT_COMPLETED = "zuoyeos.action.BOOT_COMPLETED";
+
+ static {
+ getLockedState();
+ }
+
+ private static void getLockedState() {
+ Observable.create((ObservableOnSubscribe) emitter -> start = emitter::onNext)
+ .throttleLast(1, TimeUnit.HOURS)
+ .subscribe(new Observer() {
+ @Override
+ public void onSubscribe(Disposable d) {
+ Log.e("getLockedState", "onSubscribe: ");
+ }
+
+ @Override
+ public void onNext(Long aLong) {
+
+ }
+
+ @Override
+ public void onError(Throwable e) {
+ Log.e("getLockedState", "onError: " + e.getMessage());
+ }
+
+ @Override
+ public void onComplete() {
+ Log.e("getLockedState", "onComplete: ");
+ }
+ });
+ }
+
+ private interface Start {
+ void onstar(long time);
+ }
+
+ private static Start start;
+
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ Log.e(TAG, "action:" + action);
+ if (TextUtils.isEmpty(action)) {
+ return;
+ }
+ switch (action) {
+ default:
+ break;
+ case BOOT_COMPLETED:
+ MainService.mPresenter.getAlarmClock();
+ case Intent.ACTION_BOOT_COMPLETED:
+
+ break;
+ case Intent.ACTION_BATTERY_CHANGED:
+ case Intent.ACTION_BATTERY_LOW:
+ case Intent.ACTION_BATTERY_OKAY:
+ case Intent.ACTION_POWER_CONNECTED:
+ case Intent.ACTION_POWER_DISCONNECTED:
+ case Intent.ACTION_DATE_CHANGED:
+ case Intent.ACTION_TIME_TICK:
+ case Intent.ACTION_USER_PRESENT:
+ case Intent.ACTION_SCREEN_OFF:
+ case Intent.ACTION_SCREEN_ON:
+ break;
+ }
+ }
+}
diff --git a/app/src/main/java/com/uiui/os/service/AlarmService.java b/app/src/main/java/com/uiui/os/service/AlarmService.java
new file mode 100644
index 0000000..7128b79
--- /dev/null
+++ b/app/src/main/java/com/uiui/os/service/AlarmService.java
@@ -0,0 +1,17 @@
+package com.uiui.os.service;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+public class AlarmService extends Service {
+ public AlarmService() {
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+
+
+}
diff --git a/app/src/main/java/com/uiui/os/service/MainService.java b/app/src/main/java/com/uiui/os/service/MainService.java
new file mode 100644
index 0000000..3917ae1
--- /dev/null
+++ b/app/src/main/java/com/uiui/os/service/MainService.java
@@ -0,0 +1,318 @@
+package com.uiui.os.service;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.IBinder;
+import android.os.PowerManager;
+import android.text.TextUtils;
+import android.text.format.Formatter;
+import android.util.Log;
+
+import com.arialyy.annotations.Download;
+import com.arialyy.aria.core.Aria;
+import com.arialyy.aria.core.task.DownloadTask;
+import com.blankj.utilcode.util.ImageUtils;
+import com.blankj.utilcode.util.NetworkUtils;
+import com.uiui.os.activity.MainContact;
+import com.uiui.os.activity.MainPresenter;
+import com.uiui.os.activity.NoticeActivity;
+import com.uiui.os.base.BaseService;
+import com.uiui.os.bean.AlarmClockData;
+import com.uiui.os.bean.BaseResponse;
+import com.uiui.os.network.NetInterfaceManager;
+import com.uiui.os.utils.CmdUtil;
+import com.uiui.os.utils.ForegroundAppUtil;
+import com.uiui.os.utils.TimeUtils;
+import com.uiui.os.utils.ToastUtil;
+import com.uiui.os.utils.Utils;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
+import io.reactivex.rxjava3.core.Observable;
+import io.reactivex.rxjava3.core.ObservableEmitter;
+import io.reactivex.rxjava3.core.ObservableOnSubscribe;
+import io.reactivex.rxjava3.core.ObservableSource;
+import io.reactivex.rxjava3.core.Observer;
+import io.reactivex.rxjava3.disposables.Disposable;
+import io.reactivex.rxjava3.functions.Function;
+import io.reactivex.rxjava3.schedulers.Schedulers;
+import okhttp3.MediaType;
+import okhttp3.MultipartBody;
+import okhttp3.RequestBody;
+
+
+public class MainService extends BaseService implements MainContact.MainView, NetworkUtils.OnNetworkStatusChangedListener {
+ private static final String TAG = MainService.class.getSimpleName();
+ public static MainPresenter mPresenter;
+
+ public MainService() {
+
+ }
+
+ @Override
+ public void onDisconnected() {
+
+ }
+
+ @Override
+ public void onConnected(NetworkUtils.NetworkType networkType) {
+
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ Log.e(TAG, "onBind: ");
+ return null;
+ }
+
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ Log.e(TAG, "onCreate: ");
+ Aria.init(this);
+ Aria.download(this).register();
+ mPresenter = new MainPresenter(this);
+ mPresenter.attachView(this);
+ mPresenter.setLifecycle(lifecycleSubject);
+ NetworkUtils.registerNetworkStatusChangedListener(this);
+ mPresenter.getAlarmClock();
+ registerAlarmReceiver();
+ registerTimeReceiver();
+ }
+
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ Log.e(TAG, "onStartCommand: ");
+ return START_STICKY;
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ mPresenter.detachView();
+ NetworkUtils.unregisterNetworkStatusChangedListener(this);
+ if (alarmReceiver != null) {
+ unregisterReceiver(alarmReceiver);
+ }
+ if (mTimeChangedReceiver != null) {
+ unregisterReceiver(mTimeChangedReceiver);
+ }
+ }
+
+ @Override
+ public void setAlarmClock(List dataList) {
+
+ }
+
+ public static final String ALARMWAKEUP = "ALARM_WAKEUP";
+
+ private void registerAlarmReceiver() {
+ if (alarmReceiver == null) {
+ alarmReceiver = new AlarmReceiver();
+ }
+ IntentFilter filter = new IntentFilter();
+ filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+ filter.addAction(ALARMWAKEUP);
+ registerReceiver(alarmReceiver, filter);
+ }
+
+ private AlarmReceiver alarmReceiver = new AlarmReceiver();
+
+ private class AlarmReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (TextUtils.isEmpty(action)) return;
+ Log.e(TAG, "onReceive: " + action);
+ String title = intent.getStringExtra("title");
+ int code = intent.getIntExtra("id", -1);
+ Log.e(TAG, "onReceive: title = " + title);
+ if (ALARMWAKEUP.equals(action)) {
+ Intent noticeIntent = new Intent();
+ noticeIntent.putExtra("id", code);
+ noticeIntent.setClass(MainService.this, NoticeActivity.class);
+ noticeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(noticeIntent);
+ }
+ }
+ }
+
+ //监听时间和日期变化
+ public void registerTimeReceiver() {
+ 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);
+ registerReceiver(mTimeChangedReceiver, filter);
+ }
+
+ private TimeChangedReceiver mTimeChangedReceiver;
+
+ private class TimeChangedReceiver extends BroadcastReceiver {
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (Intent.ACTION_DATE_CHANGED.equals(intent.getAction())) {
+ Log.e(TAG, "TimeChangedReceiver:" + "data changed");
+ } else if (Intent.ACTION_TIME_CHANGED.equals(intent.getAction())) {
+ Log.e(TAG, "TimeChangedReceiver:" + "time changed");
+ } else if (Intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
+ Log.e(TAG, "TimeChangedReceiver:" + "timezone changed");
+ } else if (Intent.ACTION_TIME_TICK.equals(intent.getAction())) {
+ Log.e(TAG, "TimeChangedReceiver:" + "time tick");
+ isScreenshot();
+ }
+ }
+ }
+
+ private final static long ONE_HOURS_TIME = 60 * 60 * 1000;
+ private final static long TEN_MINUTES_TIME = 60 * 10 * 1000;
+
+
+ private void isScreenshot() {
+ //1、检测应用使用情况,如果设备长时间运行一个应用,超过1小时,启动截屏一次。
+ //2、检测设备在非正常时间使用时,使用第三方应用,在运行10分钟后,启动截屏功能一次
+ //屏幕未点亮时不用截图
+ // TODO: 2021/12/20 计算当前app打开时间
+ String topPackageName = ForegroundAppUtil.getForegroundPackageName(MainService.this);
+ Log.e(TAG, "isScreenshot: " + topPackageName);
+ String pkg = TimeUtils.getInstance().getAppPackageName();
+ if (TextUtils.isEmpty(pkg)) {
+ return;
+ }
+
+ PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
+ //true为打开,false为关闭
+ boolean screenOn = powerManager.isInteractive();
+ Log.e(TAG, "isScreenshot: screenOn = " + screenOn);
+ if (!screenOn) return;
+
+ long startTime = TimeUtils.getInstance().getStartTime();
+ if (TimeUtils.getInstance().isNormalTime()) {//正常时间段
+ if (System.currentTimeMillis() - startTime >= ONE_HOURS_TIME) {
+ Log.e(TAG, "isScreenshot: " + "截图");
+ doscreenshot(this);
+ }
+ } else {//非正常时间段
+ if (System.currentTimeMillis() - startTime >= TEN_MINUTES_TIME) {
+ Log.e(TAG, "isScreenshot: " + "截图");
+ doscreenshot(this);
+ }
+ }
+ }
+
+ private static Observable getScreenshot(Context context, String filePath) {
+ Observable screenshotObservable = Observable.create(new ObservableOnSubscribe() {
+ @Override
+ public void subscribe(ObservableEmitter e) {
+ int code = CmdUtil.execute("screencap -p " + filePath).code;
+ e.onNext(code);
+ e.onComplete();
+ }
+ }).subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread());
+ return screenshotObservable;
+ }
+
+ private static Observable getSendFile(String path, MultipartBody.Part body) {
+ return NetInterfaceManager.getInstance()
+ .getScreenshotApi()
+ .sendScreenshot(Utils.getSerial(), body)
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread());
+ }
+
+ public static void doscreenshot(Context context) {
+ long time = System.currentTimeMillis();
+ String path = context.getExternalFilesDir("db").getAbsolutePath();
+ String filePath = path + File.separator + time + ".png";
+ getScreenshot(context, filePath).concatMap(new Function>() {
+ @Override
+ public ObservableSource apply(Integer integer) throws Exception {
+ if (integer != 0) {
+ throw new FileNotFoundException();
+ }
+ File file = new File(filePath);
+ if (!file.exists()) {
+ throw new FileNotFoundException(filePath);
+ }
+ Bitmap bitmap = BitmapFactory.decodeFile(filePath);
+ if (bitmap.getWidth() < bitmap.getHeight()) {
+ bitmap = ImageUtils.rotate(bitmap, -90, bitmap.getWidth(), bitmap.getHeight());
+ }
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
+ file.createNewFile();
+ FileOutputStream fos = new FileOutputStream(file);
+ InputStream is = new ByteArrayInputStream(baos.toByteArray());
+ int x;
+ byte[] b = new byte[1024 * 100];
+ while ((x = is.read(b)) != -1) {
+ fos.write(b, 0, x);
+ }
+ fos.close();
+ RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file);
+ MultipartBody.Part body = MultipartBody.Part.createFormData("file", file.getName(), requestFile);
+ return getSendFile(filePath, body);
+ }
+ }).subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(new Observer() {
+ @Override
+ public void onSubscribe(Disposable d) {
+ Log.e("screenshot", "onSubscribe: ");
+ }
+
+ @Override
+ public void onNext(BaseResponse baseResponse) {
+ Log.e("screenshot", "onNext: " + baseResponse);
+ }
+
+ @Override
+ public void onError(Throwable e) {
+ Log.e("screenshot", "onError: " + e.getMessage());
+ onComplete();
+ }
+
+ @Override
+ public void onComplete() {
+ Log.e("screenshot", "onComplete: ");
+ }
+ });
+ }
+
+ //在这里处理任务执行中的状态,如进度进度条的刷新
+ @Download.onTaskRunning
+ protected void running(DownloadTask task) {
+ Log.e("aria", "正在下载:" + task.getPercent() + ":" + task.getExtendField());
+ ToastUtil.show("正在下载:" + task.getPercent() + "%" + "\t" + Formatter.formatFileSize(MainService.this, task.getSpeed()) + "/s");
+ }
+
+ @Download.onTaskComplete
+ void taskComplete(DownloadTask task) {
+ //在这里处理任务完成的状态
+
+ }
+
+ @Download.onTaskFail
+ void taskFail(DownloadTask task, Exception e) {
+
+ }
+}
diff --git a/app/src/main/java/com/uiui/os/utils/ApkUtils.java b/app/src/main/java/com/uiui/os/utils/APKUtils.java
similarity index 78%
rename from app/src/main/java/com/uiui/os/utils/ApkUtils.java
rename to app/src/main/java/com/uiui/os/utils/APKUtils.java
index 596a525..4630e72 100644
--- a/app/src/main/java/com/uiui/os/utils/ApkUtils.java
+++ b/app/src/main/java/com/uiui/os/utils/APKUtils.java
@@ -1,9 +1,11 @@
package com.uiui.os.utils;
+import android.app.Application;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.text.TextUtils;
@@ -17,7 +19,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
-public class ApkUtils {
+public class APKUtils {
private static String[] excludePackageName = {BuildConfig.APPLICATION_ID};
@@ -56,6 +58,7 @@ public class ApkUtils {
/**
* 获取第三方应用
+ *
* @param context
* @return
*/
@@ -77,6 +80,29 @@ public class ApkUtils {
return applicationInfos;
}
+ public static PackageInfo getPackageInfo(Context context, String pkg) {
+ PackageManager packageManager = context.getPackageManager();
+ PackageInfo packageInfo = null;
+ try {
+ packageInfo = packageManager.getPackageInfo(pkg, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ }
+ return packageInfo;
+ }
+
+ public static ApplicationInfo getApplicationInfo(Context context, String pkg) {
+ PackageManager packageManager = context.getPackageManager();
+ ApplicationInfo applicationInfo = null;
+ try {
+ applicationInfo = packageManager.getApplicationInfo(pkg, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ }
+
+ return applicationInfo;
+ }
+
public static void openApp(Context context, String packageName) {
Intent intent = context.getPackageManager().getLaunchIntentForPackage(packageName);
if (intent != null) {
@@ -86,14 +112,14 @@ public class ApkUtils {
}
- public static Intent getAppOpenIntentByPackageName(Context context,String packageName){
+ public static Intent getAppOpenIntentByPackageName(Context context, String packageName) {
//Activity完整名
String mainAct = null;
//根据包名寻找
PackageManager pkgMag = context.getPackageManager();
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
- intent.setFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED|Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.setFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | Intent.FLAG_ACTIVITY_NEW_TASK);
List list = pkgMag.queryIntentActivities(intent,
PackageManager.GET_ACTIVITIES);
@@ -138,4 +164,20 @@ public class ApkUtils {
return false;
}
+ public static String getAPPVersionName(Context context, String packageName) {
+ String versionName = "0";
+
+ if (TextUtils.isEmpty(packageName)) {
+ return versionName;
+ }
+ PackageManager pm = context.getPackageManager();
+ try {
+ PackageInfo packageInfo = pm.getPackageInfo(packageName, 0);
+ versionName = packageInfo.versionName;
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ }
+ return versionName;
+ }
+
}
diff --git a/app/src/main/java/com/uiui/os/utils/AlarmUtils.java b/app/src/main/java/com/uiui/os/utils/AlarmUtils.java
new file mode 100644
index 0000000..662a3a1
--- /dev/null
+++ b/app/src/main/java/com/uiui/os/utils/AlarmUtils.java
@@ -0,0 +1,287 @@
+package com.uiui.os.utils;
+
+import android.annotation.SuppressLint;
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Environment;
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.core.content.ContextCompat;
+
+import com.arialyy.aria.core.Aria;
+import com.blankj.utilcode.util.FileUtils;
+import com.google.gson.Gson;
+import com.google.gson.reflect.TypeToken;
+import com.tencent.mmkv.MMKV;
+import com.uiui.os.bean.AlarmClockData;
+import com.uiui.os.service.MainService;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.lang.reflect.Type;
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+public class AlarmUtils {
+ @SuppressLint("StaticFieldLeak")
+ private static AlarmUtils sInstance;
+ private static String TAG = AlarmUtils.class.getSimpleName();
+ private Context mContext;
+ private AlarmManager alarmManager;
+ private MMKV mmkv = MMKV.defaultMMKV();
+
+
+ private AlarmUtils(Context context) {
+ this.mContext = context;
+ alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+ }
+
+ public static void init(Context context) {
+ if (sInstance == null) {
+ sInstance = new AlarmUtils(context);
+ }
+ }
+
+ public static AlarmUtils getInstance() {
+ if (sInstance == null) {
+ throw new IllegalStateException("You must be init AmapManager first");
+ }
+ return sInstance;
+ }
+
+ private List alarmClockDataList;
+ private HashSet pendingIntents;
+
+ public void setAlarmClockData(List data) {
+ this.alarmClockDataList = data;
+ if (pendingIntents == null) {
+ pendingIntents = getOldPendingIntents();
+ }
+ for (PendingIntent pendingIntent : pendingIntents) {
+ alarmManager.cancel(pendingIntent);
+ }
+ List newData = mergeData(data);
+ for (AlarmClockData clockData : newData) {
+ setAlarm(clockData);
+ }
+ String jsonString = new Gson().toJson(newData);
+ Log.e(TAG, "setAlarmClockData: " + jsonString);
+ mmkv.encode("AlarmClock", jsonString);
+ }
+
+ private List mergeData(List data) {
+ HashMap oldData = getOldData();
+ List tempData = new ArrayList<>();
+ for (AlarmClockData alarm : data) {
+ AlarmClockData oldAlarm = oldData.get(alarm.getId());
+ if (oldAlarm == null) {
+ tempData.add(alarm);
+ } else {
+ if (oldAlarm.equals(alarm)) {
+ tempData.add(oldAlarm);
+ } else {
+ tempData.add(alarm);
+ }
+ }
+ }
+ return tempData;
+ }
+
+ public void setAlarmString(List alarmClockData) {
+ String jsonString = new Gson().toJson(alarmClockData);
+ Log.e(TAG, "setAlarmString: " + jsonString);
+ mmkv.encode("AlarmClock", jsonString);
+ }
+
+ public HashMap getOldData() {
+ String jsonString = mmkv.decodeString("AlarmClock", "");
+ Log.e(TAG, "getOldPendingIntents: " + jsonString);
+ if (TextUtils.isEmpty(jsonString)) {
+ return new HashMap<>();
+ } else {
+ Type type = new TypeToken>() {
+ }.getType();
+ Gson gson = new Gson();
+ List data = gson.fromJson(jsonString, type);
+ HashMap hashMap = new HashMap();
+ for (AlarmClockData clockData : data) {
+ hashMap.put(clockData.getId(), clockData);
+ }
+ return hashMap;
+ }
+ }
+
+ private HashSet getOldPendingIntents() {
+ HashSet pendingIntents = new HashSet<>();
+ HashMap data = getOldData();
+ for (AlarmClockData alarmClockData : data.values()) {
+ pendingIntents.add(getPendingIntent(alarmClockData));
+ }
+ return pendingIntents;
+ }
+
+ private PendingIntent getPendingIntent(AlarmClockData alarmClock) {
+ Intent intent = new Intent(MainService.ALARMWAKEUP);
+ intent.putExtra("title", alarmClock.getRemarks());
+ intent.putExtra("id", alarmClock.getId());
+ PendingIntent startPendingIntent = PendingIntent.getBroadcast(mContext, alarmClock.getId(), intent, PendingIntent.FLAG_CANCEL_CURRENT);
+ return startPendingIntent;
+ }
+
+ private long getTimestamp(String timeString) {
+ if (TextUtils.isEmpty(timeString)) {
+ return 0;
+ }
+ if (timeString.length() == 8) {
+ SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm:ss");
+ try {
+ Date date = simpleDateFormat.parse(timeString);
+ long timestamp = date.getTime() + getZeroTiemstamp();
+ return timestamp;
+ } catch (ParseException e) {
+ return 0;
+ }
+ } else {
+ SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ try {
+ Date date = simpleDateFormat.parse(timeString);
+ long timestamp = date.getTime();
+ return timestamp;
+ } catch (ParseException e) {
+ return 0;
+ }
+ }
+ }
+
+ private long getZeroTiemstamp() {
+ long nowTime = System.currentTimeMillis();
+ long dayMillisecond = 60 * 60 * 24 * 1000;
+ long zeroTime = ((nowTime) / dayMillisecond) * dayMillisecond;
+ Log.e(TAG, "getZeroTiemstamp: " + zeroTime);
+ return zeroTime;
+ }
+
+ private static final int ONCE = 1;
+ private static final int LOOP = 2;
+
+ public void setAlarm(AlarmClockData alarm) {
+ int id = alarm.getId();
+ int type = alarm.getType();
+ String timeString = alarm.getTime();
+ long timestamp = getTimestamp(timeString);
+ String title = alarm.getRemarks();
+ boolean finished = alarm.isFinished();
+ String url = alarm.getVoice();
+ String md5 = alarm.getVoice_md5();
+ if (!TextUtils.isEmpty(url)) {
+ ariaDownload(url, md5);
+ }
+ if (type == ONCE) {
+ if (!finished) {
+ if (timestamp < System.currentTimeMillis()) {
+ Intent intent = new Intent(MainService.ALARMWAKEUP);
+ intent.putExtra("title", title);
+ intent.putExtra("id", id);
+ mContext.sendBroadcast(intent);
+ } else {
+ setOnceAlarm(MainService.ALARMWAKEUP, title, id, timestamp);
+ }
+ }
+ } else if (type == LOOP) {
+ setDayLoopAlarm(MainService.ALARMWAKEUP, title, id, timestamp);
+ }
+ }
+
+ /**
+ * @param action
+ * @param requestCode
+ * @param timestamp 设置一次性闹钟
+ */
+ public void setOnceAlarm(String action, String extra, int requestCode, long timestamp) {
+ Intent intent = new Intent(action);
+ intent.putExtra("title", extra);
+ intent.putExtra("id", requestCode);
+ PendingIntent startPendingIntent = PendingIntent.getBroadcast(mContext, requestCode, intent, PendingIntent.FLAG_CANCEL_CURRENT);
+ pendingIntents.add(startPendingIntent);
+ alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, timestamp, startPendingIntent);
+ Log.e(TAG, "setOnceAlarm: " + "id: " + requestCode + " title: " + extra + " timeString: " + timestamp);
+ }
+
+ /**
+ * @param action
+ * @param requestCode
+ * @param timestamp 设置循环周期为一天的闹钟
+ */
+ public void setDayLoopAlarm(String action, String extra, int requestCode, long timestamp) {
+ setLoopAlarm(action, extra, requestCode, AlarmManager.INTERVAL_DAY, timestamp);
+ }
+
+ /**
+ * @param action
+ * @param requestCode
+ * @param timestamp 设置循环周期为一小时的闹钟
+ */
+ public void setHourLoopAlarm(String action, String extra, int requestCode, long timestamp) {
+ setLoopAlarm(action, extra, requestCode, AlarmManager.INTERVAL_HOUR, timestamp);
+ }
+
+ /**
+ * @param action
+ * @param requestCode
+ * @param intervalMillis
+ * @param timestamp 循环闹钟
+ */
+ public void setLoopAlarm(String action, String extra, int requestCode, long intervalMillis, long timestamp) {
+ Intent intent = new Intent(action);
+ intent.putExtra("title", extra);
+ intent.putExtra("id", requestCode);
+ PendingIntent startPendingIntent = PendingIntent.getBroadcast(mContext, requestCode, intent, PendingIntent.FLAG_CANCEL_CURRENT);
+ pendingIntents.add(startPendingIntent);
+ alarmManager.setWindow(AlarmManager.RTC_WAKEUP, timestamp, intervalMillis, startPendingIntent);
+ Log.e(TAG, "setLoopAlarm: " + "title: " + extra + " timeString: " + timestamp);
+ }
+
+
+
+ public void ariaDownload(String url, String md5) {
+ String fileName = Utils.getFileNamefromURL(url);
+ File file = new File(Utils.getDownLoadPath(mContext) + fileName);
+ if (file.exists() && !file.isDirectory()) {
+ String fileMD5 = FileUtils.getFileMD5ToString(file);
+ Log.e("ariaDownload", "fileOnlineMD5=" + md5);
+ Log.e("ariaDownload", "fileMD5=" + fileMD5);
+ if (!md5.equals(fileMD5)) {
+ Aria.download(this)
+ .load(url) //读取下载地址
+ .setFilePath(Utils.getDownLoadPath(mContext) + fileName)
+// .ignoreFilePathOccupy()
+ .setExtendField(md5)
+ .create(); //启动下载}
+ } else {
+ Log.e("ariaDownload", "fileName = " + fileName + " exists");
+ }
+ } else {
+ Aria.download(this)
+ .load(url) //读取下载地址
+ .setFilePath(Utils.getDownLoadPath(mContext) + fileName)
+// .ignoreFilePathOccupy()
+ .setExtendField(md5)
+ .create(); //启动下载}
+ }
+ }
+
+
+}
diff --git a/app/src/main/java/com/uiui/os/utils/CmdUtil.java b/app/src/main/java/com/uiui/os/utils/CmdUtil.java
new file mode 100644
index 0000000..f717fb6
--- /dev/null
+++ b/app/src/main/java/com/uiui/os/utils/CmdUtil.java
@@ -0,0 +1,103 @@
+package com.uiui.os.utils;
+
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.io.BufferedReader;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+public class CmdUtil {
+ private static final String TAG = "CmdUtil";
+
+ private static final String COMMAND_SH = "sh";
+ private static final String COMMAND_EXIT = "exit\n";
+ private static final String COMMAND_LINE_END = "\n";
+
+
+ /**
+ * 运行命令
+ *
+ * @param command 命令
+ * @return 结果
+ */
+ public static Result execute(String command) {
+ Log.i(TAG, "execute() command = " + command);
+ Result result = new Result();
+
+ if (TextUtils.isEmpty(command)) {
+ Log.w(TAG, "WARNING: command should not be null or empty");
+ return result;
+ }
+
+ Process process = null;
+ DataOutputStream dos = null;
+
+ try {
+ process = Runtime.getRuntime().exec(COMMAND_SH);
+ dos = new DataOutputStream(process.getOutputStream());
+ dos.write(command.trim().getBytes());
+ dos.writeBytes(COMMAND_LINE_END);
+ dos.flush();
+ dos.writeBytes(COMMAND_EXIT);
+ dos.flush();
+ result.code = process.waitFor();
+ result.success = readBuffer(new BufferedReader(new InputStreamReader(process.getInputStream())));
+ result.error = readBuffer(new BufferedReader(new InputStreamReader(process.getErrorStream())));
+ Log.i(TAG, "result = " + result);
+ } catch (IOException ioe) {
+ ioe.printStackTrace();
+ Log.e(TAG, ioe.getMessage());
+ } catch (InterruptedException ie) {
+ ie.printStackTrace();
+ Log.e(TAG, ie.getMessage());
+ } finally {
+ try {
+ if (null != dos) {
+ dos.close();
+ }
+ } catch (IOException ioe) {
+ ioe.printStackTrace();
+ Log.e(TAG, ioe.getMessage());
+ }
+ if (null != process) {
+ process.destroy();
+ }
+ }
+ return result;
+ }
+
+ private static String readBuffer(BufferedReader bufferedReader) throws IOException {
+ StringBuilder sb = new StringBuilder();
+ String s;
+ while ((s = bufferedReader.readLine()) != null) {
+ sb.append(s);
+ }
+ return sb.toString();
+ }
+
+
+ /**
+ * Command执行结果
+ */
+ public static final class Result {
+
+ public static final int SUCCESS = 0;
+ public static final int ERROR = -1;
+
+ public int code = ERROR;
+ public String error;
+ public String success;
+
+ @Override
+ public String toString() {
+ return "Result{" +
+ "code=" + code +
+ ", error='" + error + '\'' +
+ ", success='" + success + '\'' +
+ '}';
+ }
+ }
+}
+
diff --git a/app/src/main/java/com/uiui/os/utils/ForegroundAppUtil.java b/app/src/main/java/com/uiui/os/utils/ForegroundAppUtil.java
new file mode 100644
index 0000000..9b28c8e
--- /dev/null
+++ b/app/src/main/java/com/uiui/os/utils/ForegroundAppUtil.java
@@ -0,0 +1,116 @@
+package com.uiui.os.utils;
+
+import android.app.ActivityManager;
+import android.app.usage.UsageStats;
+import android.app.usage.UsageStatsManager;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Build;
+import android.provider.Settings;
+import android.text.TextUtils;
+
+import java.util.List;
+
+public class ForegroundAppUtil {
+
+ 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;
+
+ public static final String TOPAPP_KEY = "TOP_ALWAYS_SHOW_APP_NAME";
+ private static String TAG = ForegroundAppUtil.class.getSimpleName();
+
+ public static String getForegroundPackageName(Context context) {
+ //系统应用可以直接获取
+ ActivityManager mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
+ List runningTaskInfos = mActivityManager.getRunningTasks(1);
+ return runningTaskInfos.get(0).topActivity.getPackageName();
+ }
+
+ /**
+ * 获取栈顶的应用包名
+ */
+ public static String getForegroundActivityName(Context context) {
+ String currentClassName = "";
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
+ ActivityManager manager = (ActivityManager) context.getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);
+ currentClassName = manager.getRunningTasks(1).get(0).topActivity.getPackageName();
+ } else {
+ UsageStats initStat = getForegroundUsageStats(context, START_TIME, END_TIME);
+ if (initStat != null) {
+ currentClassName = initStat.getPackageName();
+ }
+ }
+ return currentClassName;
+ }
+
+ /**
+ * 判断当前应用是否在前台
+ */
+ public static boolean isForegroundApp(Context context) {
+ return TextUtils.equals(getForegroundActivityName(context), context.getPackageName());
+ }
+
+ /**
+ * 获取时间段内,
+ */
+ public static long getTotleForegroundTime(Context context) {
+ UsageStats usageStats = getCurrentUsageStats(context, START_TIME, END_TIME);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ return usageStats != null ? usageStats.getTotalTimeInForeground() : 0;
+ }
+ return 0;
+ }
+
+ /**
+ * 获取记录前台应用的UsageStats对象
+ */
+ private static UsageStats getForegroundUsageStats(Context context, long startTime, long endTime) {
+ UsageStats usageStatsResult = null;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ List usageStatses = getUsageStatsList(context, 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 static UsageStats getCurrentUsageStats(Context context, long startTime, long endTime) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ List usageStatses = getUsageStatsList(context, startTime, endTime);
+ if (usageStatses == null || usageStatses.isEmpty()) return null;
+ for (UsageStats usageStats : usageStatses) {
+ if (TextUtils.equals(usageStats.getPackageName(), context.getPackageName())) {
+ return usageStats;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * 通过UsageStatsManager获取List集合
+ */
+ public static List getUsageStatsList(Context context, long startTime, long endTime) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ UsageStatsManager manager = (UsageStatsManager) context.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);
+ context.getApplicationContext().startActivity(intent);
+ return null;
+ }
+ return usageStatses;
+ }
+ return null;
+ }
+}
diff --git a/app/src/main/java/com/uiui/os/utils/MD5Util.java b/app/src/main/java/com/uiui/os/utils/MD5Util.java
new file mode 100644
index 0000000..371ed8b
--- /dev/null
+++ b/app/src/main/java/com/uiui/os/utils/MD5Util.java
@@ -0,0 +1,112 @@
+package com.uiui.os.utils;
+
+import android.annotation.SuppressLint;
+
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+public class MD5Util {
+
+ public static String packetMD5(String str) {
+ MessageDigest messageDigest = null;
+ try {
+ messageDigest = MessageDigest.getInstance("MD5");
+
+ messageDigest.reset();
+
+ messageDigest.update(str.getBytes("UTF-8"));
+ } catch (NoSuchAlgorithmException e) {
+ System.out.println("NoSuchAlgorithmException caught!");
+ System.exit(-1);
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+
+ byte[] byteArray = messageDigest.digest();
+
+ StringBuffer md5StrBuff = new StringBuffer();
+
+ for (int i = 0; i < byteArray.length; i++) {
+ if (Integer.toHexString(0xFF & byteArray[i]).length() == 1)
+ md5StrBuff.append("0").append(
+ Integer.toHexString(0xFF & byteArray[i]));
+ else
+ md5StrBuff.append(Integer.toHexString(0xFF & byteArray[i]));
+ }
+
+ return md5StrBuff.toString();
+ }
+
+ @SuppressLint("DefaultLocale")
+ public static String getUpperMD5Str(String str) {
+ MessageDigest messageDigest = null;
+
+ try {
+ messageDigest = MessageDigest.getInstance("MD5");
+
+ messageDigest.reset();
+
+ messageDigest.update(str.getBytes("UTF-8"));
+ } catch (NoSuchAlgorithmException e) {
+ System.out.println("NoSuchAlgorithmException caught!");
+ System.exit(-1);
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+
+ byte[] byteArray = messageDigest.digest();
+
+ StringBuffer md5StrBuff = new StringBuffer();
+
+ for (int i = 0; i < byteArray.length; i++) {
+ if (Integer.toHexString(0xFF & byteArray[i]).length() == 1)
+ md5StrBuff.append("0").append(
+ Integer.toHexString(0xFF & byteArray[i]));
+ else
+ md5StrBuff.append(Integer.toHexString(0xFF & byteArray[i]));
+ }
+
+ return md5StrBuff.toString().toUpperCase();
+ }
+
+
+ /**
+ * 获取16位的MD5 值得
+ *
+ * @param str
+ * @return
+ */
+ @SuppressLint("DefaultLocale")
+ public static String getUpperMD5Str16(String str) {
+ MessageDigest messageDigest = null;
+
+ try {
+ messageDigest = MessageDigest.getInstance("MD5");
+
+ messageDigest.reset();
+
+ messageDigest.update(str.getBytes("UTF-8"));
+ } catch (NoSuchAlgorithmException e) {
+ System.out.println("NoSuchAlgorithmException caught!");
+ System.exit(-1);
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+
+ byte[] byteArray = messageDigest.digest();
+
+ StringBuffer md5StrBuff = new StringBuffer();
+
+ for (int i = 0; i < byteArray.length; i++) {
+ if (Integer.toHexString(0xFF & byteArray[i]).length() == 1)
+ md5StrBuff.append("0").append(
+ Integer.toHexString(0xFF & byteArray[i]));
+ else
+ md5StrBuff.append(Integer.toHexString(0xFF & byteArray[i]));
+ }
+
+ return md5StrBuff.toString().toUpperCase().substring(8, 24);
+ }
+
+}
diff --git a/app/src/main/java/com/uiui/os/utils/TimeUtils.java b/app/src/main/java/com/uiui/os/utils/TimeUtils.java
new file mode 100644
index 0000000..d9ed940
--- /dev/null
+++ b/app/src/main/java/com/uiui/os/utils/TimeUtils.java
@@ -0,0 +1,93 @@
+package com.uiui.os.utils;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.util.Log;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+public class TimeUtils {
+ @SuppressLint("StaticFieldLeak")
+ private static TimeUtils sInstance;
+ private Context mContext;
+
+ private SimpleDateFormat ruleSDF = new SimpleDateFormat("HH:mm:ss");
+ private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ private String TAG = TimeUtils.class.getSimpleName();
+
+ private TimeUtils(Context context) {
+ this.mContext = context;
+ }
+
+ public static void init(Context context) {
+ if (sInstance == null) {
+ sInstance = new TimeUtils(context);
+ }
+ }
+
+ public static TimeUtils getInstance() {
+ if (sInstance == null) {
+ throw new IllegalStateException("You must be init TimeUtils first");
+ }
+ return sInstance;
+ }
+
+ private static String normalStartTime = "8:00:00";
+ private static String unusualStartTime = "22:00:00";
+
+ private String appPackageName;
+ private long endTime = 0;
+ private long startTime = 0;
+
+ public void setAppPackageName(String name) {
+ this.appPackageName = name;
+ }
+
+ public String getAppPackageName() {
+ return appPackageName;
+ }
+
+ public void setStartTime(long time) {
+ this.startTime = time;
+ }
+
+ public long getStartTime() {
+ return startTime;
+ }
+
+ public void setEndTime(long time) {
+ this.endTime = time;
+ }
+
+ public long getEndTime() {
+ return endTime;
+ }
+
+ private static final long DAY_TIME = 1000 * 60 * 60 * 24;
+
+ public boolean isNormalTime() {
+ long nowTime = System.currentTimeMillis();
+ String nowTimeString = ruleSDF.format(new Date(nowTime)); // 时间戳转换日期
+ try {
+ Date startDate = ruleSDF.parse(normalStartTime);
+ Date endDate = ruleSDF.parse(unusualStartTime);
+ Date now = ruleSDF.parse(nowTimeString);
+ Log.e(TAG, "isScreenshot: startDate = " + startDate);
+ Log.e(TAG, "isScreenshot: endDate = " + endDate);
+ Log.e(TAG, "isScreenshot: now = " + now);
+ if (startDate.getTime() <= now.getTime() && now.getTime() <= endDate.getTime()) {
+ return true;
+ } else if (endDate.getTime() < now.getTime() && now.getTime() <= startDate.getTime() + DAY_TIME) {
+ return false;
+ }
+ } catch (ParseException e) {
+ e.printStackTrace();
+ Log.e(TAG, "isScreenshot: " + e.getMessage());
+ }
+ return false;
+ }
+
+
+}
diff --git a/app/src/main/java/com/uiui/os/utils/ToastUtil.java b/app/src/main/java/com/uiui/os/utils/ToastUtil.java
new file mode 100644
index 0000000..6aa0849
--- /dev/null
+++ b/app/src/main/java/com/uiui/os/utils/ToastUtil.java
@@ -0,0 +1,93 @@
+package com.uiui.os.utils;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.graphics.Color;
+import android.os.Build;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.Log;
+import android.widget.Toast;
+
+import com.blankj.utilcode.util.ToastUtils;
+import com.uiui.os.BuildConfig;
+
+
+/**
+ * Created by haoge on 2017/3/2.
+ */
+
+public class ToastUtil {
+ private static final String TAG = ToastUtil.class.getSimpleName();
+ @SuppressLint("StaticFieldLeak")
+ private static Context mContext;
+ private static Handler mainHandler = new Handler(Looper.getMainLooper());
+ private static Toast debugToast;
+ private static Toast toast;
+
+
+ @SuppressLint("ShowToast")
+ public static void init(Context context) {
+ mContext = context;
+ toast = Toast.makeText(mContext, "", Toast.LENGTH_SHORT);
+ debugToast = Toast.makeText(mContext, "", Toast.LENGTH_SHORT);
+
+ }
+
+ private static long time1 = 0L;
+ private static long time2 = 0L;
+
+ public static void show(final String msg) {
+ ToastUtils.make()
+// .setBgColor(ColorUtils.getColor(R.color.toast_color))
+ .setTextColor(Color.DKGRAY)
+// .setGravity(Gravity.CENTER, 0, 0)
+ .setNotUseSystemToast()
+ .show(msg);
+ }
+
+ public static void betaShow(final String msg) {
+ if ( BuildConfig.DEBUG) {
+ ToastUtils.make()
+// .setBgColor(ColorUtils.getColor(R.color.toast_color))
+ .setTextColor(Color.RED)
+// .setGravity(Gravity.CENTER, 0, 0)
+ .setNotUseSystemToast()
+ .setDurationIsLong(true)
+ .show(msg);
+ } else {
+ Log.e(TAG, "debugShow: " + msg);
+ }
+ }
+
+ private static Toast mToast = null;
+
+ //android 8.0以后限制
+ //https://www.jianshu.com/p/d9813ad03d59
+ //https://www.jianshu.com/p/050ce052b873
+ public static void showToast(Context context, String text, int duration) {
+ if (Build.VERSION.SDK_INT == Build.VERSION_CODES.P) {
+ Toast.makeText(context, text, duration).show();
+ } else {
+ if (mToast == null) {
+ mToast = Toast.makeText(context, text, duration);
+ } else {
+ mToast.setText(text);
+ mToast.setDuration(duration);
+ }
+ mToast.show();
+ }
+ }
+
+ // public static void showInCenter(String msg) {
+// mainHandler.post(() -> {
+// if (toast != null) {
+// toast.setGravity(Gravity.CENTER, 0, 0);
+// toast.setText(msg);
+// toast.show();
+// }
+// });
+// }
+
+
+}
diff --git a/app/src/main/java/com/uiui/os/utils/Utils.java b/app/src/main/java/com/uiui/os/utils/Utils.java
index 503c980..e9556fa 100644
--- a/app/src/main/java/com/uiui/os/utils/Utils.java
+++ b/app/src/main/java/com/uiui/os/utils/Utils.java
@@ -1,13 +1,66 @@
package com.uiui.os.utils;
+import android.annotation.SuppressLint;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import android.os.Build;
+import android.os.Environment;
+import android.util.Log;
+
+import androidx.core.content.ContextCompat;
+
+import com.uiui.os.BuildConfig;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.lang.reflect.Method;
+import java.math.BigInteger;
+import java.security.MessageDigest;
public class Utils {
+ /**
+ * 获取设备序列号
+ *
+ * @return
+ */
+ @SuppressLint("MissingPermission")
+ public static String getSerial() {
+ String serial = "unknow";
+ try {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {//9.0+
+ serial = Build.getSerial();
+ } else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N) {//8.0+
+ serial = Build.SERIAL;
+ } else {//8.0-
+ Class> c = Class.forName("android.os.SystemProperties");
+ Method get = c.getMethod("get", String.class);
+ serial = (String) get.invoke(c, "ro.serialno");
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ Log.e("e", "读取设备序列号异常:" + e.toString());
+ }
+ if (BuildConfig.DEBUG) {
+// return "QNG2DKB00463";
+ }
+ return serial;
+ }
+
+ public static String getDeviceSN() {
+ String serial = null;
+ try {
+ Class> c = Class.forName("android.os.SystemProperties");
+ Method get = c.getMethod("get", String.class);
+ serial = (String) get.invoke(c, "persist.sys.hrSerial");
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return serial;
+ }
+
/**
* 获取电量
*
@@ -23,4 +76,14 @@ public class Utils {
}
}
+ public static String getDownLoadPath(Context context) {
+ String path = ContextCompat.getExternalFilesDirs(context, Environment.DIRECTORY_DOWNLOADS)[0].getAbsolutePath();
+ return path + File.separator;
+ }
+
+ public static String getFileNamefromURL(String url) {
+ int position = url.lastIndexOf("/");
+ return url.substring(position + 1);
+ }
+
}
diff --git a/app/src/main/java/com/uiui/os/view/CustomContent.java b/app/src/main/java/com/uiui/os/view/CustomContent.java
index 90ed334..00eec53 100644
--- a/app/src/main/java/com/uiui/os/view/CustomContent.java
+++ b/app/src/main/java/com/uiui/os/view/CustomContent.java
@@ -66,6 +66,5 @@ public class CustomContent extends FrameLayout implements CustomContentCallbacks
@Override
public void onViewAdded(View child) {
super.onViewAdded(child);
-
}
}
diff --git a/app/src/main/res/drawable-hdpi/actions_logo.png b/app/src/main/res/drawable-hdpi/actions_logo.png
deleted file mode 100644
index dbbdff2..0000000
Binary files a/app/src/main/res/drawable-hdpi/actions_logo.png and /dev/null differ
diff --git a/app/src/main/res/drawable-hdpi/charging.png b/app/src/main/res/drawable-hdpi/charging.png
index e888fe8..995e7a8 100644
Binary files a/app/src/main/res/drawable-hdpi/charging.png and b/app/src/main/res/drawable-hdpi/charging.png differ
diff --git a/app/src/main/res/drawable-hdpi/voice.png b/app/src/main/res/drawable-hdpi/voice.png
new file mode 100644
index 0000000..0e8777f
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/voice.png differ
diff --git a/app/src/main/res/drawable-hdpi/voice_white.png b/app/src/main/res/drawable-hdpi/voice_white.png
new file mode 100644
index 0000000..63e8e02
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/voice_white.png differ
diff --git a/app/src/main/res/drawable-hdpi/wifi_icon.png b/app/src/main/res/drawable-hdpi/wifi_icon.png
new file mode 100644
index 0000000..1126193
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/wifi_icon.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/sos_icon.png b/app/src/main/res/drawable-xxxhdpi/sos_icon.png
new file mode 100644
index 0000000..00d093f
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/sos_icon.png differ
diff --git a/app/src/main/res/drawable/alarmclcok_background.xml b/app/src/main/res/drawable/alarmclcok_background.xml
new file mode 100644
index 0000000..bf2ee59
--- /dev/null
+++ b/app/src/main/res/drawable/alarmclcok_background.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/notice_voice_background.xml b/app/src/main/res/drawable/notice_voice_background.xml
new file mode 100644
index 0000000..0383881
--- /dev/null
+++ b/app/src/main/res/drawable/notice_voice_background.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ok_background.xml b/app/src/main/res/drawable/ok_background.xml
new file mode 100644
index 0000000..a246594
--- /dev/null
+++ b/app/src/main/res/drawable/ok_background.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/voice_background.xml b/app/src/main/res/drawable/voice_background.xml
new file mode 100644
index 0000000..8243268
--- /dev/null
+++ b/app/src/main/res/drawable/voice_background.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout-land/fragment_custom.xml b/app/src/main/res/layout-land/fragment_custom.xml
index f97bdf7..1628892 100644
--- a/app/src/main/res/layout-land/fragment_custom.xml
+++ b/app/src/main/res/layout-land/fragment_custom.xml
@@ -5,7 +5,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
-
-
-
-
@@ -120,38 +112,29 @@
android:layout_weight="2"
android:background="@drawable/custom_background">
-
-
-
+
-
-
-
+ android:background="@drawable/custom_background"
+ tools:ignore="NestedWeights">
-
-
-
-
-
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/textView5" />
+ app:layout_constraintTop_toTopOf="parent" />
+ app:layout_constraintTop_toBottomOf="@+id/iv_charging" />
+
+
+
+
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout-port/fragment_custom.xml b/app/src/main/res/layout-port/fragment_custom.xml
index 0f6e83c..584e3d0 100644
--- a/app/src/main/res/layout-port/fragment_custom.xml
+++ b/app/src/main/res/layout-port/fragment_custom.xml
@@ -89,22 +89,18 @@
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
- android:text="我的便签"
+ android:text="爱心守护"
android:textColor="@color/black"
android:textSize="19sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
-
@@ -122,32 +118,28 @@
android:layout_weight="1"
android:background="@drawable/custom_background">
-
-
+
+
-
-
-
-
-
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/textView5" />
@@ -245,33 +216,35 @@
+ app:layout_constraintTop_toTopOf="parent" />
+ app:layout_constraintTop_toBottomOf="@+id/iv_charging" />
+
+
@@ -309,35 +294,40 @@
android:orientation="horizontal">
+
+
-
-
+
diff --git a/app/src/main/res/layout/activity_notice.xml b/app/src/main/res/layout/activity_notice.xml
new file mode 100644
index 0000000..4bd0e11
--- /dev/null
+++ b/app/src/main/res/layout/activity_notice.xml
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/actions_item.xml b/app/src/main/res/layout/item_actions.xml
similarity index 95%
rename from app/src/main/res/layout/actions_item.xml
rename to app/src/main/res/layout/item_actions.xml
index bdbf5a2..1a7e9f7 100644
--- a/app/src/main/res/layout/actions_item.xml
+++ b/app/src/main/res/layout/item_actions.xml
@@ -20,6 +20,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/actions_item_drawablePaddding"
- android:textColor="@color/White"
+ android:textColor="@color/white"
android:textSize="@dimen/actions_item_font" />
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_alarmclock.xml b/app/src/main/res/layout/item_alarmclock.xml
new file mode 100644
index 0000000..a50daea
--- /dev/null
+++ b/app/src/main/res/layout/item_alarmclock.xml
@@ -0,0 +1,73 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_notification.xml b/app/src/main/res/layout/item_notification.xml
new file mode 100644
index 0000000..3cbf69c
--- /dev/null
+++ b/app/src/main/res/layout/item_notification.xml
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 233d13f..75ec446 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -3,12 +3,14 @@
#37353a
#272727
#454347
- #ffffff
+ #ffffff
#FFFFFF
#000000
- #ffffff
#4880ff
+ #F8B551
+ #0480FF
+ #4D4B50
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index c478b46..4baca5e 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -10,4 +10,24 @@
- true
+
+
diff --git a/settings.gradle b/settings.gradle
index e8fc91f..375a9f9 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,2 +1,2 @@
-rootProject.name='桌面OS'
+rootProject.name='老人平板桌面'
include ':app'