diff --git a/app/build.gradle b/app/build.gradle index 6051bec..f2862bb 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,11 +1,11 @@ apply plugin: 'com.android.application' def appName() { - return "学习系统" + return "桌面" } def releaseTime() { - return new Date().format("yyyyMMddHHmmss", TimeZone.getDefault()) + return new Date().format("yyyyMMdd-HHmmss", TimeZone.getDefault()) } android { @@ -15,12 +15,27 @@ android { applicationId "com.uiui.os" minSdkVersion 24 targetSdkVersion 29 - versionCode 1 - versionName "1.0" + versionCode 2 + versionName "1.1" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } + lintOptions { + checkReleaseBuilds false + // Or, if you prefer, you can continue to check for errors in release builds, + // but continue the build even when errors are found: + abortOnError false + } + + aaptOptions.cruncherEnabled = false + aaptOptions.useNewCruncher = false + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + signingConfigs { zhanRui { storeFile file("src/doc/zhanxun.keystore") @@ -133,9 +148,24 @@ dependencies { testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' - - implementation 'com.squareup.okhttp3:okhttp:3.12.12' - implementation 'com.google.code.gson:gson:2.6.2' + //RxJava +// implementation 'io.reactivex.rxjava2:rxjava:2.2.12' +// implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' + // + implementation 'com.squareup.okhttp3:okhttp:4.9.1' + implementation 'com.squareup.retrofit2:retrofit:2.9.0' + implementation 'com.squareup.retrofit2:converter-gson:2.9.0' +// implementation 'com.squareup.retrofit2:adapter-rxjava2:2.4.0' + implementation "com.squareup.retrofit2:adapter-rxjava3:2.9.0" + //Gson + implementation 'com.google.code.gson:gson:2.8.7' + implementation 'com.google.zxing:core:3.3.0' + //生命周期管理 + implementation 'com.trello.rxlifecycle4:rxlifecycle:4.0.2' + implementation 'com.trello.rxlifecycle4:rxlifecycle-android:4.0.2' + implementation 'com.trello.rxlifecycle4:rxlifecycle-components:4.0.2' + implementation 'com.trello.rxlifecycle4:rxlifecycle-components-preference:4.0.2' + implementation 'com.trello.rxlifecycle4:rxlifecycle-android-lifecycle:4.0.2' //bindView implementation 'com.jakewharton:butterknife:10.1.0' annotationProcessor 'com.jakewharton:butterknife-compiler:10.1.0' @@ -148,4 +178,9 @@ dependencies { //指示器 implementation 'com.github.hackware1993:MagicIndicator:1.7.0' // for androidx implementation 'com.king.view:circleprogressview:1.1.2' + //工具类 + implementation 'com.blankj:utilcodex:1.30.6' + //aria + implementation 'com.arialyy.aria:core:3.8.15' + annotationProcessor 'com.arialyy.aria:compiler:3.8.15' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 95b824c..f46e691 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -7,32 +7,20 @@ - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - - - + - + android:value="${AMAP_KEY}" /> + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/assets/aria_config.xml b/app/src/main/assets/aria_config.xml new file mode 100644 index 0000000..a85bbf6 --- /dev/null +++ b/app/src/main/assets/aria_config.xml @@ -0,0 +1,161 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/java/com/uiui/os/activity/MainActivity.java b/app/src/main/java/com/uiui/os/activity/MainActivity.java index e694912..7efbb59 100644 --- a/app/src/main/java/com/uiui/os/activity/MainActivity.java +++ b/app/src/main/java/com/uiui/os/activity/MainActivity.java @@ -7,14 +7,16 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; import android.content.res.Configuration; import android.graphics.Color; import android.os.IBinder; import android.os.RemoteException; import android.text.TextUtils; +import android.text.format.DateUtils; import android.util.Log; import android.view.KeyEvent; -import android.view.View; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; @@ -23,24 +25,19 @@ import androidx.fragment.app.FragmentTransaction; import androidx.viewpager.widget.ViewPager; import com.alarmclock.uiui.IAlarmAidlInterface; -import com.amap.api.location.AMapLocation; -import com.amap.api.location.AMapLocationClient; -import com.amap.api.location.AMapLocationListener; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; -import com.qweather.sdk.bean.base.Code; -import com.qweather.sdk.bean.base.Lang; -import com.qweather.sdk.bean.base.Unit; -import com.qweather.sdk.bean.weather.WeatherNowBean; -import com.qweather.sdk.view.QWeather; import com.uiui.os.R; import com.uiui.os.base.BaseActivity; import com.uiui.os.bean.AlarmItem; +import com.uiui.os.bean.BaseResponse; import com.uiui.os.fragment.AppListFragment; import com.uiui.os.fragment.BaseFragmentPagerAdapter; import com.uiui.os.fragment.CustomFragment; -import com.uiui.os.utils.AmapManager; -import com.uiui.os.utils.ApkUtils; +import com.uiui.os.network.NetInterfaceManager; +import com.uiui.os.utils.APKUtils; +import com.uiui.os.utils.TimeUtils; +import com.uiui.os.utils.Utils; import com.uiui.os.view.ScaleCircleNavigator; import net.lucode.hackware.magicindicator.MagicIndicator; @@ -52,6 +49,8 @@ import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; +import io.reactivex.rxjava3.core.Observer; +import io.reactivex.rxjava3.disposables.Disposable; public class MainActivity extends BaseActivity { private String TAG = MainActivity.class.getSimpleName(); @@ -111,9 +110,9 @@ public class MainActivity extends BaseActivity { customFragment.setAlarmItem(null); return; } - Type type = new TypeToken() { + Type type = new TypeToken>() { }.getType(); - AlarmItem alarmItem = new Gson().fromJson(json, type); + List alarmItem = new Gson().fromJson(json, type); customFragment.setAlarmItem(alarmItem); } catch (RemoteException e) { e.printStackTrace(); @@ -142,7 +141,7 @@ public class MainActivity extends BaseActivity { public void initData() { registmNewAppReceiver(); fragments.add(customFragment); - ArrayList applicationInfoList = ApkUtils.queryFilterAppInfo(this); + ArrayList applicationInfoList = APKUtils.queryFilterAppInfo(this); int x = 0; for (int i = 0; i <= applicationInfoList.size(); i++) { if (i != 0 && i % APP_LIST_SIZE == 0) { @@ -176,7 +175,7 @@ public class MainActivity extends BaseActivity { private void addData() { List fragmentList = new ArrayList<>(); - ArrayList applicationInfoList = ApkUtils.queryFilterAppInfo(this); + ArrayList applicationInfoList = APKUtils.queryFilterAppInfo(this); int x = 0; for (int i = 0; i <= applicationInfoList.size(); i++) { if (i != 0 && i % APP_LIST_SIZE == 0) { @@ -245,7 +244,58 @@ public class MainActivity extends BaseActivity { @Override protected void onResume() { super.onResume(); + String packagename = TimeUtils.getInstance().getAppPackageName(); + Log.e("SendcloseApp", "packagename=" + packagename); + TimeUtils.getInstance().setEndTime(System.currentTimeMillis()); + if (packagename != null && packagename.length() > 0) { + ApplicationInfo app = APKUtils.getApplicationInfo(this, packagename); + PackageManager pm = getPackageManager(); + if (app != null) { + Log.e(TAG, "onResume: " + app.loadLabel(pm).toString()); + Log.e(TAG, "onResume: " + app.packageName); + NetInterfaceManager.getInstance().getAppUsageRecordControl() + .sendappUsageRecord(Utils.getSerial(), + app.loadLabel(pm).toString(), app.packageName, + TimeUtils.getInstance().getStartTime() / 1000, + TimeUtils.getInstance().getEndTime() / 1000) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + Log.e("onResume", "onSubscribe: "); + } + + @Override + public void onNext(BaseResponse baseResponse) { + Log.e("onResume", "onNext: " + baseResponse); + } + + @Override + public void onError(Throwable e) { + Log.e("onResume", "onError: " + e.getMessage()); + } + + @Override + public void onComplete() { + Log.e("onResume", "onComplete: "); + } + }); + TimeUtils.getInstance().setAppPackageName(""); + } else { + Log.e("fht", "app = null" + packagename); + } + } getAlarmData(); + + } + + @Override + protected void onRestart() { + super.onRestart(); + } + + @Override + protected void onStop() { + super.onStop(); } private void registmNewAppReceiver() { @@ -264,7 +314,10 @@ public class MainActivity extends BaseActivity { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); Log.e(TAG, "onReceive: " + action); - addData(); + if (Intent.ACTION_PACKAGE_ADDED.equals(action) + || Intent.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) { + addData(); + } } } } diff --git a/app/src/main/java/com/uiui/os/activity/MainContact.java b/app/src/main/java/com/uiui/os/activity/MainContact.java new file mode 100644 index 0000000..276657f --- /dev/null +++ b/app/src/main/java/com/uiui/os/activity/MainContact.java @@ -0,0 +1,21 @@ +package com.uiui.os.activity; + +import com.uiui.os.base.BasePresenter; +import com.uiui.os.base.BaseView; +import com.uiui.os.bean.AlarmClockData; + +import java.util.List; + +public class MainContact { + public interface Presenter extends BasePresenter { + //设置所有信息 + void getAlarmClock(); + + } + + public interface MainView extends BaseView { + //获取所有信息 + void setAlarmClock(List dataList); + + } +} diff --git a/app/src/main/java/com/uiui/os/activity/MainPresenter.java b/app/src/main/java/com/uiui/os/activity/MainPresenter.java new file mode 100644 index 0000000..193a2dd --- /dev/null +++ b/app/src/main/java/com/uiui/os/activity/MainPresenter.java @@ -0,0 +1,90 @@ +package com.uiui.os.activity; + +import android.content.Context; +import android.util.Log; + +import com.tencent.mmkv.MMKV; +import com.trello.rxlifecycle4.android.ActivityEvent; +import com.uiui.os.bean.AlarmClockData; +import com.uiui.os.bean.BaseResponse; +import com.uiui.os.network.NetInterfaceManager; +import com.uiui.os.utils.AlarmUtils; + +import java.util.List; + +import io.reactivex.rxjava3.core.Observer; +import io.reactivex.rxjava3.disposables.Disposable; +import io.reactivex.rxjava3.subjects.BehaviorSubject; + + +/** + * MainActivity和MainService 的 Presenter + * + * @author jgy02 + */ +public class MainPresenter implements MainContact.Presenter { + private static final String TAG = MainPresenter.class.getSimpleName(); + private static final int OK = 200; + private MainContact.MainView mView; + private Context mContext; + + private BehaviorSubject lifecycle; + + public void setLifecycle(BehaviorSubject lifecycle) { + this.lifecycle = lifecycle; + } + + public BehaviorSubject getLifecycle() { + return lifecycle; + } + + public MainPresenter(Context context) { + this.mContext = context; + Log.e(TAG, "MainPresenter: " + context.getClass()); + } + + @Override + public void attachView(@androidx.annotation.NonNull MainContact.MainView view) { + this.mView = view; + } + + @Override + public void detachView() { + this.mView = null; + } + + + @Override + public void getAlarmClock() { + MMKV mmkv = MMKV.defaultMMKV(); + NetInterfaceManager.getInstance().getAlarmClockApiObservable() + .subscribe(new Observer>>() { + @Override + public void onSubscribe(Disposable d) { + Log.e("getAlarmClock", "onSubscribe: "); + } + + @Override + public void onNext(BaseResponse> listBaseResponse) { + Log.e("getAlarmClock", "onNext: "+listBaseResponse); + if (listBaseResponse.code == 200) { + List data = listBaseResponse.data; + AlarmUtils.getInstance().setAlarmClockData(data); + } else { + + } + } + + @Override + public void onError(Throwable e) { + Log.e("getAlarmClock", "onError: " + e.getMessage()); + onComplete(); + } + + @Override + public void onComplete() { + Log.e("getAlarmClock", "onComplete: "); + } + }); + } +} diff --git a/app/src/main/java/com/uiui/os/activity/NoticeActivity.java b/app/src/main/java/com/uiui/os/activity/NoticeActivity.java new file mode 100644 index 0000000..5dec510 --- /dev/null +++ b/app/src/main/java/com/uiui/os/activity/NoticeActivity.java @@ -0,0 +1,125 @@ +package com.uiui.os.activity; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.constraintlayout.widget.ConstraintLayout; + +import android.content.Intent; +import android.media.MediaPlayer; +import android.os.Bundle; +import android.text.TextUtils; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; + +import com.blankj.utilcode.util.FileUtils; +import com.uiui.os.R; +import com.uiui.os.bean.AlarmClockData; +import com.uiui.os.utils.AlarmUtils; +import com.uiui.os.utils.Utils; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import butterknife.BindView; +import butterknife.ButterKnife; + +public class NoticeActivity extends AppCompatActivity { + @BindView(R.id.tv_title) + TextView tv_title; + @BindView(R.id.bt_ok) + Button bt_ok; + @BindView(R.id.constraintLayout) + ConstraintLayout constraintLayout; + private AlarmClockData alarmClockData; + int code; + private MediaPlayer mediaPlayer; + private String TAG = NoticeActivity.class.getSimpleName(); + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_notice); + ButterKnife.bind(this); + Intent intent = getIntent(); + code = intent.getIntExtra("id", -1); + if (code == -1) { + finish(); + } else { + HashMap oldData = AlarmUtils.getInstance().getOldData(); + alarmClockData = oldData.get(code); + if (alarmClockData == null) { + finish(); + } + showData(alarmClockData); + } + + } + + private void showData(AlarmClockData alarmClockData) { + tv_title.setText(alarmClockData.getRemarks()); + bt_ok.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + HashMap oldData = AlarmUtils.getInstance().getOldData(); + List data = new ArrayList<>(); + for (AlarmClockData alarm : oldData.values()) { + if (alarm.getId() == code) { + alarm.setFinished(true); + } + data.add(alarm); + } + AlarmUtils.getInstance().setAlarmString(data); + finish(); + } + }); + String url = alarmClockData.getVoice(); + String md5 = alarmClockData.getVoice_md5(); + if (!TextUtils.isEmpty(url)) { + constraintLayout.setVisibility(View.VISIBLE); + String fileName = Utils.getFileNamefromURL(url); + File file = new File(Utils.getDownLoadPath(NoticeActivity.this) + fileName); + String fileMD5 = FileUtils.getFileMD5ToString(file); +// if (!md5.equals(fileMD5)) { +// // TODO: 2021/12/16 +// } else { + mediaPlayer = new MediaPlayer(); + try { + // 切歌之前先重置,释放掉之前的资源 + mediaPlayer.reset(); + FileInputStream fis = new FileInputStream(file); + mediaPlayer.setDataSource(fis.getFD()); + // 设置播放源 +// mediaPlayer.setDataSource(file.getAbsolutePath()); + // 开始播放前的准备工作,加载多媒体资源,获取相关信息 + mediaPlayer.prepare(); + // 开始播放 + mediaPlayer.start(); + } catch (IOException e) { + e.printStackTrace(); + Log.e(TAG, "showData: " + e.getMessage()); + } +// } + } else { + constraintLayout.setVisibility(View.GONE); + } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + if (mediaPlayer != null) { + if (mediaPlayer.isPlaying()) { + mediaPlayer.stop(); + } + mediaPlayer.release(); + mediaPlayer = null; + } + } +} diff --git a/app/src/main/java/com/uiui/os/adapter/AlarmClockAdapter.java b/app/src/main/java/com/uiui/os/adapter/AlarmClockAdapter.java new file mode 100644 index 0000000..4c1c3d0 --- /dev/null +++ b/app/src/main/java/com/uiui/os/adapter/AlarmClockAdapter.java @@ -0,0 +1,61 @@ +package com.uiui.os.adapter; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import com.uiui.os.R; +import com.uiui.os.bean.AlarmItem; + +import java.util.List; + +public class AlarmClockAdapter extends RecyclerView.Adapter { + private List alarmItemList; + + public void setAlarmItemList(List alarmItems) { + this.alarmItemList = alarmItems; + notifyDataSetChanged(); + } + + + @NonNull + @Override + public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + return new AlarmClockAdapter.ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_alarmclock, parent, false)); + + } + + @Override + public void onBindViewHolder(@NonNull ViewHolder holder, int position) { + AlarmItem alarmItem = alarmItemList.get(position); + holder.tv_time.setText(alarmItem.mTime); + holder.tv_type.setText(alarmItem.mRepeatType); + if (alarmItem.mActive) { + holder.tv_status.setText("打开"); + } else { + holder.tv_status.setText("关闭"); + } + } + + @Override + public int getItemCount() { + return alarmItemList == null ? 0 : alarmItemList.size(); + } + + static class ViewHolder extends RecyclerView.ViewHolder { + TextView tv_time; + TextView tv_status; + TextView tv_type; + + ViewHolder(@NonNull View itemView) { + super(itemView); + tv_time = itemView.findViewById(R.id.tv_time); + tv_status = itemView.findViewById(R.id.tv_status); + tv_type = itemView.findViewById(R.id.tv_type); + } + } +} diff --git a/app/src/main/java/com/uiui/os/adapter/NotificationAdapter.java b/app/src/main/java/com/uiui/os/adapter/NotificationAdapter.java new file mode 100644 index 0000000..705b97b --- /dev/null +++ b/app/src/main/java/com/uiui/os/adapter/NotificationAdapter.java @@ -0,0 +1,53 @@ +package com.uiui.os.adapter; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; + +import com.uiui.os.R; +import com.uiui.os.bean.AlarmClockData; + +import java.util.List; + +public class NotificationAdapter extends RecyclerView.Adapter { + private List dataList; + + @NonNull + @Override + public Holder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + return new Holder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_notification, parent, false)); + } + + @Override + public void onBindViewHolder(@NonNull Holder holder, int position) { + AlarmClockData alarmClockData = dataList.get(position); + holder.tv_title.setText("提醒事件:" + alarmClockData.getRemarks()); + holder.tv_time.setText("提醒时间:" + alarmClockData.getTime()); + + } + + @Override + public int getItemCount() { + return dataList == null ? 0 : dataList.size(); + } + + public void setDataList(List data) { + this.dataList = data; + notifyDataSetChanged(); + } + + class Holder extends RecyclerView.ViewHolder { + TextView tv_title; + TextView tv_time; + + public Holder(@NonNull View itemView) { + super(itemView); + tv_title = itemView.findViewById(R.id.tv_title); + tv_time = itemView.findViewById(R.id.tv_time); + } + } +} diff --git a/app/src/main/java/com/uiui/os/base/BaseActivity.java b/app/src/main/java/com/uiui/os/base/BaseActivity.java index 84cc88d..a17ab6a 100644 --- a/app/src/main/java/com/uiui/os/base/BaseActivity.java +++ b/app/src/main/java/com/uiui/os/base/BaseActivity.java @@ -2,39 +2,78 @@ package com.uiui.os.base; import android.os.Bundle; +import androidx.annotation.CallSuper; +import androidx.annotation.CheckResult; +import androidx.annotation.ContentView; +import androidx.annotation.LayoutRes; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; +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.uiui.os.R; import com.zackratos.ultimatebarx.ultimatebarx.java.UltimateBarX; -public abstract class BaseActivity extends AppCompatActivity { - @Override - protected void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setBar(); - //状态栏改变放在setContentView前后有所不同 - setContentView(this.getLayoutId()); - initView(); - initData(); +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.subjects.BehaviorSubject; + + +public abstract class BaseActivity extends AppCompatActivity implements LifecycleProvider { + public final BehaviorSubject lifecycleSubject = BehaviorSubject.create(); + + public BaseActivity() { + super(); } - private void setBar() { + @ContentView + public BaseActivity(@LayoutRes int contentLayoutId) { + super(contentLayoutId); + } + + @Override + @NonNull + @CheckResult + public final Observable lifecycle() { + return lifecycleSubject.hide(); + } + + @Override + @NonNull + @CheckResult + public final LifecycleTransformer bindUntilEvent(@NonNull ActivityEvent event) { + return RxLifecycle.bindUntilEvent(lifecycleSubject, event); + } + + @Override + @NonNull + @CheckResult + public final LifecycleTransformer bindToLifecycle() { + return RxLifecycleAndroid.bindActivity(lifecycleSubject); + } + + @Override + @CallSuper + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + lifecycleSubject.onNext(ActivityEvent.CREATE); +// StatusBarUtil.init(this); UltimateBarX.statusBar(this) .transparent() .colorRes(R.color.colorPrimaryDark) -// .light(true) + .light(true) .apply(); UltimateBarX.navigationBar(this) .transparent() .colorRes(R.color.colorPrimaryDark) -// .light(true) + .light(true) .apply(); - } - - @Override - protected void onDestroy() { - super.onDestroy(); + setContentView(this.getLayoutId()); + initView(); + initData(); } /** @@ -52,4 +91,39 @@ public abstract class BaseActivity extends AppCompatActivity { * 初始化数据 */ public abstract void initData(); + + @Override + @CallSuper + protected void onStart() { + super.onStart(); + lifecycleSubject.onNext(ActivityEvent.START); + } + + @Override + @CallSuper + protected void onResume() { + super.onResume(); + lifecycleSubject.onNext(ActivityEvent.RESUME); + } + + @Override + @CallSuper + protected void onPause() { + lifecycleSubject.onNext(ActivityEvent.PAUSE); + super.onPause(); + } + + @Override + @CallSuper + protected void onStop() { + lifecycleSubject.onNext(ActivityEvent.STOP); + super.onStop(); + } + + @Override + @CallSuper + protected void onDestroy() { + lifecycleSubject.onNext(ActivityEvent.DESTROY); + super.onDestroy(); + } } diff --git a/app/src/main/java/com/uiui/os/base/BaseApplication.java b/app/src/main/java/com/uiui/os/base/BaseApplication.java index 32e21c6..8cee691 100644 --- a/app/src/main/java/com/uiui/os/base/BaseApplication.java +++ b/app/src/main/java/com/uiui/os/base/BaseApplication.java @@ -3,12 +3,20 @@ package com.uiui.os.base; import android.annotation.SuppressLint; import android.app.Application; import android.content.Context; +import android.content.Intent; import android.os.Handler; import android.os.Looper; import android.util.Log; +import com.arialyy.aria.core.Aria; import com.qweather.sdk.view.HeConfig; +import com.tencent.mmkv.MMKV; +import com.uiui.os.BuildConfig; +import com.uiui.os.network.NetInterfaceManager; +import com.uiui.os.service.MainService; +import com.uiui.os.utils.AlarmUtils; import com.uiui.os.utils.AmapManager; +import com.uiui.os.utils.TimeUtils; public class BaseApplication extends Application { @@ -35,8 +43,20 @@ public class BaseApplication extends Application { public void onCreate() { super.onCreate(); context = this; + if (!BuildConfig.DEBUG) { + catchException(); + } + String rootDir = MMKV.initialize(this); + Log.e(TAG, "mmkv root: " + rootDir); + Aria.init(this); + Aria.get(this).getDownloadConfig().setMaxTaskNum(1); + Aria.get(this).getDownloadConfig().setConvertSpeed(true); + TimeUtils.init(this); + AlarmUtils.init(this); HeConfig.init("HE2111041506381545", "32b5ec69545e44119583a5e0ed4e87df"); AmapManager.init(this); + NetInterfaceManager.init(this); + startService(new Intent(this, MainService.class)); } diff --git a/app/src/main/java/com/uiui/os/base/BasePresenter.java b/app/src/main/java/com/uiui/os/base/BasePresenter.java new file mode 100644 index 0000000..3abc217 --- /dev/null +++ b/app/src/main/java/com/uiui/os/base/BasePresenter.java @@ -0,0 +1,10 @@ +package com.uiui.os.base; + +import androidx.annotation.NonNull; + +public interface BasePresenter { + + void attachView(@NonNull V view); + + void detachView(); +} diff --git a/app/src/main/java/com/uiui/os/base/BaseService.java b/app/src/main/java/com/uiui/os/base/BaseService.java new file mode 100644 index 0000000..3b4b424 --- /dev/null +++ b/app/src/main/java/com/uiui/os/base/BaseService.java @@ -0,0 +1,56 @@ +package com.uiui.os.base; + +import android.app.Service; +import android.content.Intent; + +import androidx.annotation.NonNull; + +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 io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.subjects.BehaviorSubject; + + +public abstract class BaseService extends Service implements LifecycleProvider { + public final BehaviorSubject lifecycleSubject = BehaviorSubject.create(); + + public BaseService() { + super(); + } + + @Override + public final Observable lifecycle() { + return lifecycleSubject.hide(); + } + + @Override + public final LifecycleTransformer bindUntilEvent(@NonNull ActivityEvent event) { + return RxLifecycle.bindUntilEvent(lifecycleSubject, event); + } + + @Override + public final LifecycleTransformer bindToLifecycle() { + return RxLifecycleAndroid.bindActivity(lifecycleSubject); + } + + @Override + public void onCreate() { + super.onCreate(); + lifecycleSubject.onNext(ActivityEvent.CREATE); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + return super.onStartCommand(intent, flags, startId); + } + + @Override + public void onDestroy() { + super.onDestroy(); + lifecycleSubject.onNext(ActivityEvent.STOP); + } +} diff --git a/app/src/main/java/com/uiui/os/base/BaseView.java b/app/src/main/java/com/uiui/os/base/BaseView.java new file mode 100644 index 0000000..f11b175 --- /dev/null +++ b/app/src/main/java/com/uiui/os/base/BaseView.java @@ -0,0 +1,4 @@ +package com.uiui.os.base; + +public interface BaseView { +} diff --git a/app/src/main/java/com/uiui/os/bean/AlarmClockData.java b/app/src/main/java/com/uiui/os/bean/AlarmClockData.java new file mode 100644 index 0000000..daad1af --- /dev/null +++ b/app/src/main/java/com/uiui/os/bean/AlarmClockData.java @@ -0,0 +1,97 @@ +package com.uiui.os.bean; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.google.gson.Gson; +import com.google.gson.JsonParser; + +import java.io.Serializable; + +public class AlarmClockData implements Serializable { + private static final long serialVersionUID = -5856502480745183157L; + + int id; + int type; + String time; + String remarks; + String voice; + String voice_md5; + boolean finished = false; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public String getTime() { + return time; + } + + public void setTime(String time) { + this.time = time; + } + + public String getRemarks() { + return remarks; + } + + public void setRemarks(String remarks) { + this.remarks = remarks; + } + + public String getVoice() { + return voice; + } + + public void setVoice(String voice) { + this.voice = voice; + } + + public String getVoice_md5() { + return voice_md5; + } + + public void setVoice_md5(String voice_md5) { + this.voice_md5 = voice_md5; + } + + public boolean isFinished() { + return finished; + } + + public void setFinished(boolean finished) { + this.finished = finished; + } + + @NonNull + @Override + public String toString() { + return JsonParser.parseString(new Gson().toJson(this)).getAsJsonObject().toString(); + } + + + @Override + public boolean equals(@Nullable Object obj) { + if (obj == null) return false; + if (!(obj instanceof AlarmClockData)) return false; + if (id != ((AlarmClockData) obj).id) return false; + if (type != ((AlarmClockData) obj).type) return false; + if (!time.equals(((AlarmClockData) obj).time)) return false; + if (!remarks.equals(((AlarmClockData) obj).remarks)) return false; + if (!voice.equals(((AlarmClockData) obj).voice)) return false; + if (!voice_md5.equals(((AlarmClockData) obj).voice_md5)) return false; + return true; + } +} diff --git a/app/src/main/java/com/uiui/os/bean/BaseResponse.java b/app/src/main/java/com/uiui/os/bean/BaseResponse.java new file mode 100644 index 0000000..b86ee59 --- /dev/null +++ b/app/src/main/java/com/uiui/os/bean/BaseResponse.java @@ -0,0 +1,23 @@ +package com.uiui.os.bean; + +import androidx.annotation.NonNull; + +import com.google.gson.Gson; +import com.google.gson.JsonParser; + +import java.io.Serializable; + + +public class BaseResponse implements Serializable { + private static final long serialVersionUID = 5468533687801294972L; + + public int code; + public String msg; + public T data; + + @NonNull + @Override + public String toString() { + return JsonParser.parseString(new Gson().toJson(this)).getAsJsonObject().toString(); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/uiui/os/fragment/AppListFragment.java b/app/src/main/java/com/uiui/os/fragment/AppListFragment.java index 8338a45..4d7cc13 100644 --- a/app/src/main/java/com/uiui/os/fragment/AppListFragment.java +++ b/app/src/main/java/com/uiui/os/fragment/AppListFragment.java @@ -1,12 +1,12 @@ package com.uiui.os.fragment; +import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.os.Bundle; import androidx.annotation.NonNull; -import androidx.core.app.NavUtils; import androidx.fragment.app.Fragment; import android.util.Log; @@ -16,17 +16,22 @@ import android.view.ViewGroup; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; -import android.widget.Toast; +import com.google.gson.JsonObject; import com.uiui.os.R; -import com.uiui.os.utils.ApkUtils; +import com.uiui.os.bean.BaseResponse; +import com.uiui.os.network.NetInterfaceManager; +import com.uiui.os.utils.APKUtils; import com.uiui.os.utils.BitmapUtils; import com.uiui.os.utils.IconUtils; +import com.uiui.os.utils.TimeUtils; import com.uiui.os.view.MyGridLayout; import java.util.ArrayList; import java.util.Arrays; -import java.util.List; + +import io.reactivex.rxjava3.core.Observer; +import io.reactivex.rxjava3.disposables.Disposable; /** * A simple {@link Fragment} subclass. @@ -106,7 +111,7 @@ public class AppListFragment extends Fragment { @Override public View getView(int index) { PackageManager pm = rootView.getContext().getPackageManager(); - View view = getLayoutInflater().inflate(R.layout.actions_item, + View view = getLayoutInflater().inflate(R.layout.item_actions, null); ImageView iv = view.findViewById(R.id.iv); TextView tv = view.findViewById(R.id.tv); @@ -148,12 +153,50 @@ public class AppListFragment extends Fragment { public void onItemClick(View v, int index) { ApplicationInfo applicationInfo = applicationInfos.get(index); if (applicationInfo != null) { - ApkUtils.openPackage(v.getContext(), applicationInfo.packageName); + APKUtils.openPackage(v.getContext(), applicationInfo.packageName); + TimeUtils.getInstance().setAppPackageName(applicationInfo.packageName); + TimeUtils.getInstance().setStartTime(System.currentTimeMillis()); + SendRunningApp(getActivity()); } } }); } + private void SendRunningApp(Context context) { + String packageName = TimeUtils.getInstance().getAppPackageName(); + long time = TimeUtils.getInstance().getStartTime(); + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("app_package", packageName); + jsonObject.addProperty("version_name", APKUtils.getAPPVersionName(context, packageName)); + jsonObject.addProperty("start_time", time / 1000); + String jsonString = jsonObject.toString(); + Log.e(TAG, "SendRunningApp: " + jsonString); + NetInterfaceManager.getInstance() + .getRunningAppObservable(jsonString) + .subscribe(new Observer() { + @Override + public void onSubscribe(Disposable d) { + Log.e("SendRunningApp", "onSubscribe: "); + } + + @Override + public void onNext(BaseResponse baseResponse) { + Log.e("SendRunningApp", "onSubscribe: " + baseResponse); + } + + @Override + public void onError(Throwable e) { + Log.e("SendRunningApp", "onError: " + e.getMessage()); + onComplete(); + } + + @Override + public void onComplete() { + Log.e("SendRunningApp", "onComplete: "); + } + }); + } + public void setAppList(ArrayList appList) { this.applicationInfos = appList; } diff --git a/app/src/main/java/com/uiui/os/fragment/CustomFragment.java b/app/src/main/java/com/uiui/os/fragment/CustomFragment.java index 065ebf4..bddc6c7 100644 --- a/app/src/main/java/com/uiui/os/fragment/CustomFragment.java +++ b/app/src/main/java/com/uiui/os/fragment/CustomFragment.java @@ -5,13 +5,20 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.net.ConnectivityManager; +import android.net.NetworkInfo; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; import android.os.BatteryManager; import android.os.Bundle; import androidx.constraintlayout.widget.ConstraintLayout; import androidx.fragment.app.Fragment; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; -import android.os.SystemClock; +import android.provider.Settings; +import android.text.TextUtils; import android.util.Log; import android.view.LayoutInflater; import android.view.View; @@ -22,45 +29,73 @@ import android.widget.TextView; import com.amap.api.location.AMapLocation; import com.amap.api.location.AMapLocationClient; import com.amap.api.location.AMapLocationListener; +import com.blankj.utilcode.util.NetworkUtils; import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; import com.king.view.circleprogressview.CircleProgressView; import com.qweather.sdk.bean.base.Code; import com.qweather.sdk.bean.base.Lang; import com.qweather.sdk.bean.base.Unit; import com.qweather.sdk.bean.weather.WeatherNowBean; import com.qweather.sdk.view.QWeather; +import com.tencent.mmkv.MMKV; import com.uiui.os.BuildConfig; import com.uiui.os.R; +import com.uiui.os.adapter.AlarmClockAdapter; +import com.uiui.os.adapter.NotificationAdapter; +import com.uiui.os.bean.AlarmClockData; import com.uiui.os.bean.AlarmItem; import com.uiui.os.utils.AmapManager; -import com.uiui.os.utils.ApkUtils; +import com.uiui.os.utils.APKUtils; import com.uiui.os.utils.AppUtil; import com.uiui.os.utils.Utils; import java.lang.reflect.Method; +import java.lang.reflect.Type; import java.util.List; import butterknife.BindView; import butterknife.ButterKnife; + /** * A simple {@link Fragment} subclass. * Use the {@link CustomFragment#newInstance} factory method to * create an instance of this fragment. */ -public class CustomFragment extends Fragment { +public class CustomFragment extends Fragment implements NetworkUtils.OnNetworkStatusChangedListener { + @BindView(R.id.tv_add) + TextView tv_add; + @BindView(R.id.tv_battery) + TextView tv_battery; + @BindView(R.id.tv_location) + TextView tv_location; + @BindView(R.id.iv_pic) + ImageView iv_pic; + @BindView(R.id.tv_temp) + TextView tv_temp; + @BindView(R.id.cpv) + CircleProgressView cpv; + @BindView(R.id.cl_alarm) + ConstraintLayout cl_alarm; + @BindView(R.id.iv_charging) + ImageView iv_charging; + @BindView(R.id.recyclerView) + RecyclerView recyclerView; + @BindView(R.id.rv_clock) + RecyclerView rv_clock; + @BindView(R.id.wifi_ssid) + TextView wifi_ssid; + @BindView(R.id.cl_wifi) + ConstraintLayout cl_wifi; + private String TAG = CustomFragment.class.getSimpleName(); - - private TextView tv_time,tv_add, tv_type, tv_status; - private ImageView iv_pic; - private TextView tv_temp; - private TextView tv_battery; - private TextView tv_location; - private CircleProgressView cpv; - private ConstraintLayout cl_alarm; - private ImageView iv_charging; private int[] mShaderColors = new int[]{0xFFfa3db5, 0xFFF8867E, 0xFFF79F6B, 0xFFF79F6B, 0xFFF79F6B, 0xFFF8867E, 0xFFfa3db5}; - + private View rootView; + private List alarmItemList; + private NotificationAdapter notificationAdapter; + private AlarmClockAdapter alarmClockAdapter; + private MMKV mmkv; // TODO: Rename parameter arguments, choose names that match // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER @@ -71,9 +106,6 @@ public class CustomFragment extends Fragment { private String mParam1; private String mParam2; - private View rootView; - private AlarmItem alarmItem; - public CustomFragment() { // Required empty public constructor } @@ -96,18 +128,20 @@ public class CustomFragment extends Fragment { return fragment; } - public void setAlarmItem(AlarmItem item) { - this.alarmItem = item; + public void setAlarmItem(List alarmItem) { + this.alarmItemList = alarmItem; setAlarm(); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + NetworkUtils.registerNetworkStatusChangedListener(this); if (getArguments() != null) { mParam1 = getArguments().getString(ARG_PARAM1); mParam2 = getArguments().getString(ARG_PARAM2); } + mmkv = MMKV.defaultMMKV(); registerBatteryReceiver(); getActivity().registerReceiver(mbatteryReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); } @@ -128,6 +162,39 @@ public class CustomFragment extends Fragment { BatteryReceiver batteryReceiver; + @Override + public void onDisconnected() { + wifi_ssid.setText("WiFi未连接"); + } + + @Override + public void onConnected(NetworkUtils.NetworkType networkType) { + if (networkType == NetworkUtils.NetworkType.NETWORK_WIFI) { + wifi_ssid.setText(getConnectWifiSsid()); + } else { + wifi_ssid.setText("WiFi未连接"); + } + } + + private String getConnectWifiSsid() { + WifiManager wifiManager = (WifiManager) getActivity().getSystemService(Context.WIFI_SERVICE); + WifiInfo wifiInfo = wifiManager.getConnectionInfo(); + Log.d("wifiInfo", wifiInfo.toString()); + Log.d("SSID", wifiInfo.getSSID()); + return wifiInfo.getSSID(); + } + + /** + * 检查wifi是否处开连接状态 + * + * @return + */ + public boolean isWifiConnect() { + ConnectivityManager connManager = (ConnectivityManager) getActivity().getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo mWifiInfo = connManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI); + return mWifiInfo.isConnected(); + } + private class BatteryReceiver extends BroadcastReceiver { @Override @@ -139,7 +206,7 @@ public class CustomFragment extends Fragment { // 最大电量 int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 0); int elec = (level * 100) / scale; - Log.e(TAG, "electricity:=" + elec + "%"); + Log.i(TAG, "electricity:=" + elec + "%"); tv_battery.setText(elec + "%"); } else if (Intent.ACTION_POWER_CONNECTED.equals(action) || Intent.ACTION_POWER_DISCONNECTED.equals(action) @@ -155,14 +222,14 @@ public class CustomFragment extends Fragment { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); - Log.e(TAG, "onReceive: " + action); + Log.i(TAG, "onReceive: " + action); if (Intent.ACTION_BATTERY_CHANGED.equals(action)) { int status = intent.getIntExtra("status", BatteryManager.BATTERY_STATUS_UNKNOWN); if (status == BatteryManager.BATTERY_STATUS_CHARGING) { if (rootView != null) { iv_charging.setVisibility(View.VISIBLE); } - }else { + } else { if (rootView != null) { iv_charging.setVisibility(View.GONE); } @@ -176,67 +243,63 @@ public class CustomFragment extends Fragment { Bundle savedInstanceState) { // Inflate the layout for this fragment rootView = inflater.inflate(R.layout.fragment_custom, container, false); + ButterKnife.bind(this, rootView); initView(); initData(); return rootView; } private void initView() { - tv_time = rootView.findViewById(R.id.tv_time); - tv_add = rootView.findViewById(R.id.tv_add); - tv_type = rootView.findViewById(R.id.tv_type); - tv_status = rootView.findViewById(R.id.tv_status); - - iv_pic = rootView.findViewById(R.id.iv_pic); - tv_temp = rootView.findViewById(R.id.tv_temp); - tv_location = rootView.findViewById(R.id.tv_location); - tv_battery = rootView.findViewById(R.id.tv_battery); Log.e(TAG, "initView: " + Utils.getBatteryLevel(getActivity())); tv_battery.setText(Utils.getBatteryLevel(getActivity()) + "%"); - cpv = rootView.findViewById(R.id.cpv); cpv.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { killBackgroundApp(); } }); - cl_alarm = rootView.findViewById(R.id.cl_alarm); cl_alarm.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - ApkUtils.openPackage(getActivity(), "com.alarmclock.uiui"); + APKUtils.openPackage(getActivity(), "com.alarmclock.uiui"); } }); - iv_charging = rootView.findViewById(R.id.iv_charging); + notificationAdapter = new NotificationAdapter(); + recyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); + recyclerView.setAdapter(notificationAdapter); + if (isWifiConnect()) { + wifi_ssid.setText(getConnectWifiSsid()); + } else { + wifi_ssid.setText("WiFi未连接"); + } + cl_wifi.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + startActivity(new Intent(Settings.ACTION_WIFI_SETTINGS)); //直接进入手机中的wifi网络设置界面 + } + }); + alarmClockAdapter = new AlarmClockAdapter(); + rv_clock.setLayoutManager(new LinearLayoutManager(getActivity())); + rv_clock.setAdapter(alarmClockAdapter); setAlarm(); refreshMemory(); } private void setAlarm() { if (rootView == null) return; - if (alarmItem == null) { - tv_time.setText("暂无闹钟"); - tv_time.setVisibility(View.GONE); + if (alarmItemList == null) { tv_add.setVisibility(View.VISIBLE); - tv_type.setVisibility(View.GONE); - tv_status.setVisibility(View.GONE); + rv_clock.setVisibility(View.GONE); } else { - tv_time.setText(alarmItem.mTime); - tv_time.setVisibility(View.VISIBLE); tv_add.setVisibility(View.GONE); - tv_type.setText(alarmItem.mRepeatType); - tv_type.setVisibility(View.VISIBLE); - tv_status.setVisibility(View.VISIBLE); - if (alarmItem.mActive) { - tv_status.setText("打开"); - } else { - tv_status.setText("关闭"); - } + rv_clock.setVisibility(View.VISIBLE); + alarmClockAdapter.setAlarmItemList(alarmItemList); } } private void initData() { initAmap(); + getAlarmClock(); } private void initAmap() { @@ -258,6 +321,17 @@ public class CustomFragment extends Fragment { }); } + private void getAlarmClock() { + String jsonString = mmkv.decodeString("AlarmClock", ""); + if (!TextUtils.isEmpty(jsonString)) { + Type type = new TypeToken>() { + }.getType(); + Gson gson = new Gson(); + List data = gson.fromJson(jsonString, type); + notificationAdapter.setDataList(data); + } + } + private void getweather(double longitude, double latitude) { /** * 实况天气数据 @@ -276,7 +350,7 @@ public class CustomFragment extends Fragment { @Override public void onSuccess(WeatherNowBean weatherBean) { - Log.e(TAG, "getWeather onSuccess: " + new Gson().toJson(weatherBean)); +// Log.e(TAG, "getWeather onSuccess: " + new Gson().toJson(weatherBean)); //先判断返回的status是否正确,当status正确时获取数据,若status不正确,可查看status对应的Code值找到原因 if (Code.OK == weatherBean.getCode()) { WeatherNowBean.NowBaseBean now = weatherBean.getNow(); @@ -295,7 +369,7 @@ public class CustomFragment extends Fragment { private void killBackgroundApp() { - List pkgList = ApkUtils.queryFilterAppList(getActivity()); + List pkgList = APKUtils.queryFilterAppList(getActivity()); for (String pkg : pkgList) { if (pkg.equalsIgnoreCase(BuildConfig.APPLICATION_ID)) continue; killBackgroundProcesses(pkg); @@ -333,6 +407,7 @@ public class CustomFragment extends Fragment { @Override public void onDestroy() { super.onDestroy(); + NetworkUtils.unregisterNetworkStatusChangedListener(this); if (batteryReceiver != null) { getActivity().unregisterReceiver(batteryReceiver); } diff --git a/app/src/main/java/com/uiui/os/network/NetInterfaceManager.java b/app/src/main/java/com/uiui/os/network/NetInterfaceManager.java new file mode 100644 index 0000000..7372d54 --- /dev/null +++ b/app/src/main/java/com/uiui/os/network/NetInterfaceManager.java @@ -0,0 +1,178 @@ +package com.uiui.os.network; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.util.Log; + +import com.uiui.os.bean.AlarmClockData; +import com.uiui.os.bean.BaseResponse; +import com.uiui.os.network.api.AlarmClockApi; +import com.uiui.os.network.api.AppUsageRecordApi; +import com.uiui.os.network.api.RunNewApp; +import com.uiui.os.network.api.SendScreenshotApi; +import com.uiui.os.utils.MD5Util; +import com.uiui.os.utils.Utils; + +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; + +import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; +import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.schedulers.Schedulers; +import okhttp3.Cache; +import okhttp3.Headers; +import okhttp3.Interceptor; +import okhttp3.OkHttpClient; +import okhttp3.Protocol; +import okhttp3.Request; +import okhttp3.Response; +import retrofit2.Retrofit; +import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory; +import retrofit2.converter.gson.GsonConverterFactory; + +public class NetInterfaceManager { + @SuppressLint("StaticFieldLeak") + private static NetInterfaceManager INSTANCE; + private Context mContext; + private Retrofit mRetrofit; + private OkHttpClient okHttpClient; + private final ConcurrentHashMap 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 @@ + + + + + + + + + + + + + +