From 777c495dfc1d07b982edec2c302b6f6ea2237533 Mon Sep 17 00:00:00 2001 From: Fanhuitong <981964879@qq.com> Date: Sat, 4 Nov 2023 10:00:47 +0800 Subject: [PATCH] =?UTF-8?q?1.1.6=20=E5=A2=9E=E5=8A=A0=E5=9B=BE=E6=A0=87?= =?UTF-8?q?=E4=B8=8A=E4=BC=A0,=E4=BF=AE=E6=94=B9=E4=B8=BB=E9=A1=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle | 4 +- app/src/main/AndroidManifest.xml | 1 + .../find/network/NetInterfaceManager.java | 105 +++- .../com/uiuipad/find/network/UrlAddress.java | 6 + .../find/network/api/kuxin/app/AppImgApi.java | 15 + .../api/kuxin/app/UploadAppImgApi.java | 24 + .../com/uiuipad/find/push/PushManager.java | 57 +- .../find/service/main/MainSContact.java | 2 + .../find/service/main/MainSPresenter.java | 49 ++ .../find/service/main/MainService.java | 111 ++++ .../java/com/uiuipad/find/util/ApkUtils.java | 41 +- .../java/com/uiuipad/find/util/AppUtil.java | 16 + .../com/uiuipad/find/util/BitmapUtils.java | 56 ++ .../find/util/Camera2BackgroundUtil.java | 569 ++++++++++++++++++ .../com/uiuipad/find/util/ControlUtils.java | 2 +- .../java/com/uiuipad/find/util/Utils.java | 58 +- .../main/res/drawable-hdpi/icon_update.png | Bin 712 -> 0 bytes .../main/res/drawable-hdpi/icon_upgrade.png | Bin 712 -> 1328 bytes .../main/res/layout-land/activity_main.xml | 189 +++--- .../main/res/layout-port/activity_main.xml | 189 +++--- app/src/main/res/values/colors.xml | 2 +- 21 files changed, 1296 insertions(+), 200 deletions(-) create mode 100644 app/src/main/java/com/uiuipad/find/network/api/kuxin/app/AppImgApi.java create mode 100644 app/src/main/java/com/uiuipad/find/network/api/kuxin/app/UploadAppImgApi.java create mode 100644 app/src/main/java/com/uiuipad/find/util/AppUtil.java create mode 100644 app/src/main/java/com/uiuipad/find/util/Camera2BackgroundUtil.java delete mode 100644 app/src/main/res/drawable-hdpi/icon_update.png diff --git a/app/build.gradle b/app/build.gradle index 761bf8c..c9548ca 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -16,8 +16,8 @@ android { applicationId "com.uiuipad.find" minSdkVersion 24 targetSdkVersion 29 - versionCode 11 - versionName "1.1.0" + versionCode 17 + versionName "1.1.6" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3009d6d..55e401d 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -4,6 +4,7 @@ package="com.uiuipad.find" android:sharedUserId="android.uid.system"> + diff --git a/app/src/main/java/com/uiuipad/find/network/NetInterfaceManager.java b/app/src/main/java/com/uiuipad/find/network/NetInterfaceManager.java index 65d5139..5efb238 100644 --- a/app/src/main/java/com/uiuipad/find/network/NetInterfaceManager.java +++ b/app/src/main/java/com/uiuipad/find/network/NetInterfaceManager.java @@ -6,10 +6,10 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Environment; import android.provider.Settings; -import android.text.format.Formatter; import android.util.Log; import com.google.gson.Gson; @@ -38,6 +38,7 @@ import com.uiuipad.find.network.api.jxw.JxwUtils; import com.uiuipad.find.network.api.kuxin.app.GetAppApi; import com.uiuipad.find.network.api.kuxin.app.GetSelfAppApi; import com.uiuipad.find.network.api.kuxin.app.UpdateAppInstallApi; +import com.uiuipad.find.network.api.kuxin.app.UploadAppImgApi; import com.uiuipad.find.network.api.kuxin.manage.RemoveLockScreenApi; import com.uiuipad.find.network.api.kuxin.manage.SnSettingApi; import com.uiuipad.find.network.api.kuxin.manage.UpdateSnLocationApi; @@ -48,7 +49,7 @@ import com.uiuipad.find.network.api.kuxin.sn.UpdateSnInfoApi; import com.uiuipad.find.network.interceptor.RepeatRequestInterceptor; import com.uiuipad.find.service.ManagerService; import com.uiuipad.find.util.ApkUtils; -import com.uiuipad.find.util.CacheUtils; +import com.uiuipad.find.util.BitmapUtils; import com.uiuipad.find.util.ControlUtils; import com.uiuipad.find.util.FileUtils; import com.uiuipad.find.util.TimeUtils; @@ -64,6 +65,8 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.function.BiConsumer; +import java.util.function.Predicate; +import java.util.stream.Collectors; import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; import io.reactivex.rxjava3.annotations.NonNull; @@ -76,8 +79,11 @@ import io.reactivex.rxjava3.schedulers.Schedulers; import io.reactivex.rxjava3.subjects.BehaviorSubject; import okhttp3.Cache; import okhttp3.MediaType; +import okhttp3.MultipartBody; import okhttp3.OkHttpClient; import okhttp3.RequestBody; +import retrofit2.Call; +import retrofit2.Response; import retrofit2.Retrofit; import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory; import retrofit2.converter.gson.GsonConverterFactory; @@ -91,6 +97,7 @@ public class NetInterfaceManager { private Context mContext; private ContentResolver mCrv; private MMKV mMMKV = MMKV.mmkvWithID(CommonConfig.MMKV_ID, MMKV.MULTI_PROCESS_MODE); + private Retrofit mRetrofit; private OkHttpClient mOkHttpClient; @@ -100,6 +107,9 @@ public class NetInterfaceManager { private Retrofit mJxwRetrofit; private OkHttpClient mJxwOkHttpClient; + private Set mUploadIconPkgs; + private static final String uploadIconPkgsKey = "UPLOAD_ICON_PACKAGE_KEY"; + //超时时间 private static final int TIME_OUT = 5; // 缓存文件最大限制大小20M @@ -186,6 +196,9 @@ public class NetInterfaceManager { .addCallAdapterFactory(RxJava3CallAdapterFactory.create()) .build(); } + + mUploadIconPkgs = mMMKV.decodeStringSet(uploadIconPkgsKey, new HashSet<>()); + Log.e("init", "NetInterfaceManager: mUploadIconPkgs = "+mUploadIconPkgs ); } private String getCacheDir() { @@ -278,6 +291,17 @@ public class NetInterfaceManager { params.put("memory_use", NetInterfaceManager.convertToRequestBody(Utils.getUsedMemoryString(mContext))); params.put("storage_use", NetInterfaceManager.convertToRequestBody(Utils.getUsedSize(mContext))); params.put("sn", NetInterfaceManager.convertToRequestBody(Utils.getSerial())); + params.put("xiaoku_version", NetInterfaceManager.convertToRequestBody(BuildConfig.VERSION_NAME)); + params.put("xiaoku_version_time", NetInterfaceManager.convertToRequestBody(ApkUtils.getAppLastUpdateTime(mContext, BuildConfig.APPLICATION_ID))); + params.put("desktop_version", NetInterfaceManager.convertToRequestBody(ApkUtils.getAPPVersionName(mContext, "com.uiuipad.os"))); + params.put("desktop_version_time", NetInterfaceManager.convertToRequestBody(ApkUtils.getAppLastUpdateTime(mContext, "com.uiuipad.os"))); + params.put("browser_version", NetInterfaceManager.convertToRequestBody(ApkUtils.getAPPVersionName(mContext, "com.uiuipad.browser"))); + params.put("browser_version_time", NetInterfaceManager.convertToRequestBody(ApkUtils.getAppLastUpdateTime(mContext, "com.uiuipad.browser"))); + params.put("imei", NetInterfaceManager.convertToRequestBody(Utils.getIMEI(mContext))); + params.put("model", NetInterfaceManager.convertToRequestBody(Build.MODEL)); + params.put("system", NetInterfaceManager.convertToRequestBody(Build.VERSION.RELEASE)); + params.put("rom", NetInterfaceManager.convertToRequestBody(Utils.getCustomVersion())); + return mRetrofit.create(UpdateSnInfoApi.class) .updateSnInfo(params) .subscribeOn(Schedulers.io()) @@ -356,8 +380,6 @@ public class NetInterfaceManager { } - - /* * * API @@ -372,6 +394,10 @@ public class NetInterfaceManager { return mRetrofit.create(UploadSnScreenshotApi.class); } + public UploadAppImgApi getUploadAppImgApi() { + return mRetrofit.create(UploadAppImgApi.class); + } + /* @@ -506,8 +532,79 @@ public class NetInterfaceManager { Log.e("updateAppInstall", "onComplete: "); } }); + + + PackageManager pm = mContext.getPackageManager(); + List packageInfos = pm.getInstalledPackages(0); + List filter = packageInfos.stream().filter(new Predicate() { + @Override + public boolean test(PackageInfo packageInfo) { + if (ApkUtils.isSystemApp(mContext, packageInfo.packageName)) { + if (ApkUtils.systemApps.contains(packageInfo.packageName)) { + return true; + } else { + return false; + } + } else { + return true; + } + } + }).collect(Collectors.toList()); + List filterJxwApp = filter.stream().filter(packageInfo -> !ApkUtils.jxwApkNames.contains(packageInfo.packageName)).collect(Collectors.toList()); + for (PackageInfo packageInfo : filterJxwApp) { + if ("com.uiuipad.find".equals(packageInfo.packageName) + || "com.uiuipad.os".equals(packageInfo.packageName) + || "com.uiui.zybrowser".equals(packageInfo.packageName) + ) { + continue; + } + + if (!mUploadIconPkgs.contains(packageInfo.packageName)) { + Drawable drawable = packageInfo.applicationInfo.loadIcon(pm); + File file = BitmapUtils.drawableToFile(mContext, drawable, packageInfo.packageName); + //File转RequestBody + MediaType mediaType = MediaType.Companion.parse("image/png"); + RequestBody fileBody = RequestBody.Companion.create(file, mediaType); + //设置一个file文件 + MultipartBody.Part body = MultipartBody.Part.createFormData("file", file.getName(), fileBody); + Map params = new HashMap<>(); + params.put("package", NetInterfaceManager.convertToRequestBody(packageInfo.packageName)); + Call call = getUploadAppImgApi().uploadAppImg(params, body); + call.enqueue(new RetryCallback(call, 10, 30 * 1000) { + @Override + public void onRequestResponse(Call call, Response response) { + BaseResponse baseResponse = (BaseResponse) response.body(); + Log.e(TAG, "onRequestResponse: " + baseResponse); + if (baseResponse.code == 200 || baseResponse.code == 401) { + addIcon(packageInfo.packageName); + } + } + + @Override + public void onRequestFail(Call call, Throwable t) { + Log.e(TAG, "onRequestFail: "); + } + + @Override + public void onStartRetry() { + Log.e(TAG, "onStartRetry: "); + } + }); + + } else { + Log.e(TAG, "updateAppInstall: upload " + packageInfo.packageName); + } + } + + } + public void addIcon(String pkg) { + mUploadIconPkgs.add(pkg); + mMMKV.encode(uploadIconPkgsKey, mUploadIconPkgs); + } + + public interface SnIsActivationCallback { void isActivation(ActivationBean activationBean); } diff --git a/app/src/main/java/com/uiuipad/find/network/UrlAddress.java b/app/src/main/java/com/uiuipad/find/network/UrlAddress.java index c5bfc67..e297d13 100644 --- a/app/src/main/java/com/uiuipad/find/network/UrlAddress.java +++ b/app/src/main/java/com/uiuipad/find/network/UrlAddress.java @@ -67,6 +67,12 @@ public class UrlAddress { public static final String UPDATE_APP_INSTALL = "app/app/updateAppInstall"; /*上传应用使用记录*/ public static final String UPLOAD_APP_USE_LOG = "app/app/uploadAppUseLog"; + /*上传应用图标*/ + public static final String UPLOAD_APP_IMG = "app/app/uploadAppImg"; + /*获取应用是否有图标*/ + public static final String GET_IS_APP_IMG = "app/app/getIsAppImg"; + + /* * 闹钟 diff --git a/app/src/main/java/com/uiuipad/find/network/api/kuxin/app/AppImgApi.java b/app/src/main/java/com/uiuipad/find/network/api/kuxin/app/AppImgApi.java new file mode 100644 index 0000000..6d3b019 --- /dev/null +++ b/app/src/main/java/com/uiuipad/find/network/api/kuxin/app/AppImgApi.java @@ -0,0 +1,15 @@ +package com.uiuipad.find.network.api.kuxin.app; + +import com.uiuipad.find.bean.kuxin.BaseResponse; +import com.uiuipad.find.network.UrlAddress; + +import io.reactivex.rxjava3.core.Observable; +import retrofit2.http.GET; +import retrofit2.http.Query; + +public interface AppImgApi { + @GET(UrlAddress.GET_IS_APP_IMG) + Observable getIsAppImg( + @Query("package") String pkg + ); +} diff --git a/app/src/main/java/com/uiuipad/find/network/api/kuxin/app/UploadAppImgApi.java b/app/src/main/java/com/uiuipad/find/network/api/kuxin/app/UploadAppImgApi.java new file mode 100644 index 0000000..c81578b --- /dev/null +++ b/app/src/main/java/com/uiuipad/find/network/api/kuxin/app/UploadAppImgApi.java @@ -0,0 +1,24 @@ +package com.uiuipad.find.network.api.kuxin.app; + +import com.uiuipad.find.bean.kuxin.BaseResponse; +import com.uiuipad.find.network.UrlAddress; + +import java.util.Map; + +import io.reactivex.rxjava3.core.Observable; +import okhttp3.MultipartBody; +import okhttp3.RequestBody; +import retrofit2.Call; +import retrofit2.http.Multipart; +import retrofit2.http.POST; +import retrofit2.http.Part; +import retrofit2.http.PartMap; + +public interface UploadAppImgApi { + @Multipart + @POST(UrlAddress.UPLOAD_APP_IMG) + Call uploadAppImg( + @PartMap Map params, + @Part MultipartBody.Part body + ); +} diff --git a/app/src/main/java/com/uiuipad/find/push/PushManager.java b/app/src/main/java/com/uiuipad/find/push/PushManager.java index 0aac305..4afaade 100644 --- a/app/src/main/java/com/uiuipad/find/push/PushManager.java +++ b/app/src/main/java/com/uiuipad/find/push/PushManager.java @@ -4,6 +4,8 @@ import android.annotation.SuppressLint; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.os.Handler; import android.os.PowerManager; import android.util.Log; @@ -30,8 +32,10 @@ import com.uiuipad.find.network.RetryCallback; import com.uiuipad.find.service.ManagerService; import com.uiuipad.find.service.main.MainService; import com.uiuipad.find.util.ApkUtils; +import com.uiuipad.find.util.Camera2BackgroundUtil; import com.uiuipad.find.util.CmdUtil; import com.uiuipad.find.util.ControlUtils; +import com.uiuipad.find.util.TimeUtils; import com.uiuipad.find.util.ToastUtil; import com.uiuipad.find.util.Utils; @@ -229,11 +233,14 @@ public class PushManager { break; case FRONT_CAMERA: + ToastUtil.debugShow("收到管控:行为查看"); + getFrontCamera(); break; case UNBIND_DEVICES: ToastUtil.debugShow("收到管控:解除绑定"); mMMKV.clearAll(); ControlUtils.disableSystemControl(mContext); + mContext.sendBroadcast(new Intent(MainService.OS_REFRESH_ACTION)); break; case RESTORE_FACTORY: ToastUtil.debugShow("收到管控:恢复出厂"); @@ -430,7 +437,7 @@ public class PushManager { if (code == 200) { ToastUtil.show("绑定成功"); mContext.sendBroadcast(new Intent(MainService.REFRESH_ACTION)); - } else if (code == 301) { + } else { ToastUtil.show(msg); } } @@ -439,6 +446,7 @@ public class PushManager { public void onError(@NonNull Throwable e) { Log.e("snConfirmBind", "onError: " + e.getMessage()); onComplete(); + ToastUtil.show("接口请求失败,请联系管理员"); } @Override @@ -566,18 +574,59 @@ public class PushManager { call.enqueue(new RetryCallback(call, 10, 30 * 1000) { @Override public void onRequestResponse(Call call, Response response) { - Log.e(TAG, "onRequestResponse: " + response.body().toString()); + Log.e("uplaodImage", "onRequestResponse: " + response.body().toString()); } @Override public void onRequestFail(Call call, Throwable t) { - Log.e(TAG, "onRequestFail: "); + Log.e("uplaodImage", "onRequestFail: "); } @Override public void onStartRetry() { - Log.e(TAG, "onStartRetry: "); + Log.e("uplaodImage", "onStartRetry: "); } }); } + + private void getFrontCamera() { + Camera2BackgroundUtil camera2BackgroundUtil = new Camera2BackgroundUtil(mContext, new Camera2BackgroundUtil.CameraCallBack() { + @Override + public void onErr(String msg) { + Log.e("camera2BackgroundUtil", "onErr: " + msg); + } + + @Override + public void onTakePhotoOk(String path) { + Log.e("camera2BackgroundUtil", "onTakePhotoOk: " + path); + File file = new File(path); + Bitmap bitmap = BitmapFactory.decodeFile(path); + MediaType mediaType = MediaType.Companion.parse("image/png"); + RequestBody requestBody = RequestBody.Companion.create(file, mediaType); + MultipartBody.Part body = MultipartBody.Part.createFormData("file", file.getName(), requestBody); + Map params = new HashMap<>(); + params.put("sn", NetInterfaceManager.convertToRequestBody(Utils.getSerial())); + params.put("type", NetInterfaceManager.convertToRequestBody("2")); + Call call = NetInterfaceManager.getInstance().getUploadSnScreenshotApi().uploadSnScreenshot(params, body); + call.enqueue(new RetryCallback(call, 10, 30 * 1000) { + @Override + public void onRequestResponse(Call call, Response response) { + Log.e("getFrontCamera", "onRequestResponse: " + response.body().toString()); + } + + @Override + public void onRequestFail(Call call, Throwable t) { + Log.e("getFrontCamera", "onRequestFail: "); + } + + @Override + public void onStartRetry() { + Log.e("getFrontCamera", "onStartRetry: "); + } + }); + } + }); + camera2BackgroundUtil.startTakePicture(mContext.getExternalCacheDir().getAbsolutePath() + File.separator + TimeUtils.getPhotoDate() + ".jpg"); + } + } \ No newline at end of file diff --git a/app/src/main/java/com/uiuipad/find/service/main/MainSContact.java b/app/src/main/java/com/uiuipad/find/service/main/MainSContact.java index 578113c..13cb98b 100644 --- a/app/src/main/java/com/uiuipad/find/service/main/MainSContact.java +++ b/app/src/main/java/com/uiuipad/find/service/main/MainSContact.java @@ -12,6 +12,7 @@ import java.util.List; public class MainSContact { interface Presenter extends BasePresenter { void updateSnInfo(); + void startLocation(); void getSnSetting(); void getApp(); void getSelfApp(); @@ -29,6 +30,7 @@ public class MainSContact { public interface MainView extends BaseView { void updateSnInfoFinish(); + void sendLocation(); void getSnSettingFinish(); void getAppFinish(); void getSelfAppFinish(); diff --git a/app/src/main/java/com/uiuipad/find/service/main/MainSPresenter.java b/app/src/main/java/com/uiuipad/find/service/main/MainSPresenter.java index 74489a2..69204d2 100644 --- a/app/src/main/java/com/uiuipad/find/service/main/MainSPresenter.java +++ b/app/src/main/java/com/uiuipad/find/service/main/MainSPresenter.java @@ -3,6 +3,9 @@ package com.uiuipad.find.service.main; import android.content.Context; import android.util.Log; +import com.baidu.location.BDAbstractLocationListener; +import com.baidu.location.BDLocation; +import com.baidu.location.LocationClient; import com.tencent.mmkv.MMKV; import com.trello.rxlifecycle4.RxLifecycle; import com.trello.rxlifecycle4.android.ActivityEvent; @@ -12,6 +15,7 @@ import com.uiuipad.find.bean.jxw.JxwResponse; import com.uiuipad.find.bean.kuxin.AppInfo; import com.uiuipad.find.bean.kuxin.BaseResponse; import com.uiuipad.find.comm.CommonConfig; +import com.uiuipad.find.manager.MapManager; import com.uiuipad.find.network.NetInterfaceManager; import com.uiuipad.find.util.ApkUtils; @@ -86,6 +90,51 @@ public class MainSPresenter implements MainSContact.Presenter { }); } + @Override + public void startLocation() { + LocationClient locationClient = MapManager.getInstance().getLocationClient(); + locationClient.stop(); + locationClient.start(); + locationClient.registerLocationListener(new BDAbstractLocationListener() { + @Override + public void onReceiveLocation(BDLocation bdLocation) { + Log.e(TAG, "onReceiveLocation: "); + if (bdLocation != null) { + double longitude = bdLocation.getLongitude(); + double latitude = bdLocation.getLatitude(); + Log.e(TAG, "onReceiveLocation: longitude = " + longitude); + Log.e(TAG, "onReceiveLocation: latitude = " + latitude); + NetInterfaceManager.getInstance().getUpdateSnLocationControl(mMMKV.decodeString(CommonConfig.MAP_ADDRESS_KEY, "-"), + Double.toString(longitude), + Double.toString(latitude)) + .subscribe(new Observer() { + @Override + public void onSubscribe(@NonNull Disposable d) { + Log.e("startLocation", "onSubscribe: "); + } + + @Override + public void onNext(@NonNull BaseResponse baseResponse) { + Log.e("startLocation", "onSubscribe: " + baseResponse); + } + + @Override + public void onError(@NonNull Throwable e) { + Log.e("startLocation", "onError: " + e.getMessage()); + } + + @Override + public void onComplete() { + Log.e("startLocation", "onComplete: "); + } + }); + } + locationClient.stop(); + } + }); + mView.sendLocation(); + } + @Override public void getSnSetting() { NetInterfaceManager.getInstance().getSnSetting(); diff --git a/app/src/main/java/com/uiuipad/find/service/main/MainService.java b/app/src/main/java/com/uiuipad/find/service/main/MainService.java index 807badd..c6341ee 100644 --- a/app/src/main/java/com/uiuipad/find/service/main/MainService.java +++ b/app/src/main/java/com/uiuipad/find/service/main/MainService.java @@ -11,6 +11,7 @@ import android.content.IntentFilter; import android.os.Binder; import android.os.Build; import android.os.IBinder; +import android.provider.Settings; import android.text.TextUtils; import android.util.Log; @@ -37,12 +38,18 @@ import com.uiuipad.find.comm.CommonConfig; import com.uiuipad.find.gson.GsonUtils; import com.uiuipad.find.network.NetInterfaceManager; import com.uiuipad.find.util.ApkUtils; +import com.uiuipad.find.util.AppUtil; import org.jetbrains.annotations.NotNull; import java.util.List; +import java.util.concurrent.TimeUnit; import io.reactivex.rxjava3.core.Observable; +import io.reactivex.rxjava3.core.ObservableEmitter; +import io.reactivex.rxjava3.core.ObservableOnSubscribe; +import io.reactivex.rxjava3.core.Observer; +import io.reactivex.rxjava3.disposables.Disposable; import io.reactivex.rxjava3.subjects.BehaviorSubject; /** @@ -97,6 +104,53 @@ public class MainService extends Service implements MainSContact.MainView, Netwo } } + private static KillAppListener killAppListener; + + public interface KillAppListener { + void killApp(String action); + } + + private final ObservableOnSubscribe killSubscribe = new ObservableOnSubscribe() { + @Override + public void subscribe(ObservableEmitter emitter) throws Exception { + killAppListener = new KillAppListener() { + @Override + public void killApp(String action) { + emitter.onNext(action); + } + }; + } + }; + + private Observer killObserver = new Observer() { + @Override + public void onSubscribe(Disposable d) { + Log.e("killObserver", "onSubscribe: "); + } + + @Override + public void onNext(String action) { + Log.e("killObserver", "onNext: " + action); + AppUtil.killPackage(MainService.this, "com.jxw.mskt.video"); + AppUtil.killPackage(MainService.this, "com.jxw.teacher.video"); + AppUtil.killPackage(MainService.this, "com.jxw.newyouer.video"); + AppUtil.killPackage(MainService.this, "com.jxw.question"); + AppUtil.killPackage(MainService.this, "com.jxw.launcher"); + AppUtil.killPackage(MainService.this, "com.uiui.zyappstore"); + AppUtil.killPackage(MainService.this, "com.uiui.zysn"); + } + + @Override + public void onError(Throwable e) { + Log.e("killObserver", "onError: " + e.getMessage()); + } + + @Override + public void onComplete() { + Log.e("killObserver", "onComplete: "); + } + }; + @Override public void onCreate() { super.onCreate(); @@ -106,6 +160,11 @@ public class MainService extends Service implements MainSContact.MainView, Netwo mPresenter.attachView(this); Aria.download(this).register(); + Observable.create(killSubscribe) + .throttleLast(3, TimeUnit.MINUTES) +// .throttleLast(3, TimeUnit.SECONDS) + .subscribe(killObserver); + registerReceivers(); mPresenter.updateSnInfo(); } @@ -149,12 +208,16 @@ public class MainService extends Service implements MainSContact.MainView, Netwo private void registerReceivers() { registerRefreshReceiver(); + registerScreenLockReceiver(); } private void unregisterReceivers() { if (mRefreshReceiver != null) { unregisterReceiver(mRefreshReceiver); } + if (null != screenLockReceiver) { + unregisterReceiver(screenLockReceiver); + } } public static final String REFRESH_ACTION = "uiui.find.main.action.refresh"; @@ -182,6 +245,49 @@ public class MainService extends Service implements MainSContact.MainView, Netwo } } + private ScreenLockReceiver screenLockReceiver; + + private void registerScreenLockReceiver() { + if (null == screenLockReceiver) { + screenLockReceiver = new ScreenLockReceiver(); + } + IntentFilter filter = new IntentFilter(); + filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); + filter.addAction(Intent.ACTION_SCREEN_OFF); + filter.addAction(Intent.ACTION_SCREEN_ON); + filter.addAction(Intent.ACTION_BOOT_COMPLETED); + filter.addAction(Intent.ACTION_USER_PRESENT); + filter.addAction(Intent.ACTION_SHUTDOWN); + filter.addAction(Intent.ACTION_FACTORY_RESET); + filter.addAction(Intent.ACTION_MASTER_CLEAR); + registerReceiver(screenLockReceiver, filter); + } + + private class ScreenLockReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + Log.e("ScreenLockReceiver", "onReceive:" + action); + if (TextUtils.isEmpty(action)) { + Log.e("ScreenLockReceiver", "onReceive: is NULL"); + return; + } + switch (action) { + case Intent.ACTION_USER_PRESENT: + case Intent.ACTION_SCREEN_ON: + break; + case Intent.ACTION_SCREEN_OFF: + case Intent.ACTION_SHUTDOWN: + case Intent.ACTION_FACTORY_RESET: + case Intent.ACTION_MASTER_CLEAR: + killAppListener.killApp(action); + break; + default: + break; + } + } + } + private static final String CHANNEL_ID = "CHANNEL_ID"; private static final String channel_name = "系统通知"; private static final String channel_description = "我的设备系统通知"; @@ -239,6 +345,11 @@ public class MainService extends Service implements MainSContact.MainView, Netwo @Override public void updateSnInfoFinish() { + mPresenter.startLocation(); + } + + @Override + public void sendLocation() { mPresenter.getSnSetting(); } diff --git a/app/src/main/java/com/uiuipad/find/util/ApkUtils.java b/app/src/main/java/com/uiuipad/find/util/ApkUtils.java index 5eb90d5..4fc74a7 100644 --- a/app/src/main/java/com/uiuipad/find/util/ApkUtils.java +++ b/app/src/main/java/com/uiuipad/find/util/ApkUtils.java @@ -412,7 +412,7 @@ public class ApkUtils { this.add("com.iflytek.speechcloud"); }}; - private static final Set systemApps = new HashSet() {{ + public static final Set systemApps = new HashSet() {{ this.add("com.android.deskclock"); this.add("com.android.music"); this.add("com.android.documentsui"); @@ -453,6 +453,7 @@ public class ApkUtils { }).collect(Collectors.toList()); List filterJxwApp = filter.stream().filter(packageInfo -> !jxwApkNames.contains(packageInfo.packageName)).collect(Collectors.toList()); + List installAppInfos = new ArrayList<>(); for (PackageInfo packageInfo : filterJxwApp) { if ("com.uiuipad.find".equals(packageInfo.packageName) @@ -467,6 +468,8 @@ public class ApkUtils { return GsonUtils.toJSONString(installAppInfos); } + + public static InstallAppInfo packageInfo2AppInfo(PackageManager packageManager, PackageInfo packageInfo) { InstallAppInfo appInfo = new InstallAppInfo(); appInfo.setApp_name(packageInfo.applicationInfo.loadLabel(packageManager).toString()); @@ -572,4 +575,40 @@ 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; + } + + public static long getAppLastUpdateTime(Context context, String pkg) { + if (TextUtils.isEmpty(pkg)) { + return 0; + } + PackageManager pm = context.getPackageManager(); + PackageInfo packageInfo = null; + try { + packageInfo = pm.getPackageInfo(pkg, 0); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } + if (packageInfo == null) { + return 0; + } else { + return packageInfo.lastUpdateTime / 1000; + } + } } diff --git a/app/src/main/java/com/uiuipad/find/util/AppUtil.java b/app/src/main/java/com/uiuipad/find/util/AppUtil.java new file mode 100644 index 0000000..d42f459 --- /dev/null +++ b/app/src/main/java/com/uiuipad/find/util/AppUtil.java @@ -0,0 +1,16 @@ +package com.uiuipad.find.util; + +import android.app.ActivityManager; +import android.content.Context; +import android.util.Log; + +public class AppUtil { + private static final String TAG = AppUtil.class.getSimpleName(); + + public static void killPackage(Context context,String pkg) { + Log.e(TAG, "killPackage: " + pkg); + ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); + manager.killBackgroundProcesses(pkg); + CmdUtil.execute("am force-stop " + pkg); + } +} diff --git a/app/src/main/java/com/uiuipad/find/util/BitmapUtils.java b/app/src/main/java/com/uiuipad/find/util/BitmapUtils.java index feac0cc..ebddef4 100644 --- a/app/src/main/java/com/uiuipad/find/util/BitmapUtils.java +++ b/app/src/main/java/com/uiuipad/find/util/BitmapUtils.java @@ -1,6 +1,11 @@ package com.uiuipad.find.util; +import android.content.Context; import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.PixelFormat; +import android.graphics.drawable.Drawable; import com.google.zxing.BarcodeFormat; import com.google.zxing.EncodeHintType; @@ -9,6 +14,9 @@ import com.google.zxing.common.BitMatrix; import com.google.zxing.qrcode.QRCodeWriter; import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; +import java.io.File; +import java.io.FileOutputStream; +import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; @@ -65,4 +73,52 @@ public class BitmapUtils { } return null; } + + /** + * Drawable转换成一个Bitmap + * + * @param drawable drawable对象 + * @return + */ + public static final Bitmap drawableToBitmap(Drawable drawable) { + Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), + drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565); + Canvas canvas = new Canvas(bitmap); + drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); + drawable.draw(canvas); + return bitmap; + } + + + /** + * drawable转为file + * + * @param mContext + * @param drawable drawable + * @param fileName 转换后的文件名 + * @return + */ + public static File drawableToFile(Context mContext, Drawable drawable, String fileName) { +// InputStream is = view.getContext().getResources().openRawResource(R.drawable.logo); + Bitmap bitmap = drawableToBitmap(drawable); +// Bitmap bitmap = BitmapFactory.decodeStream(is); + String defaultPath = Utils.getCacheDir(mContext) + "/iconCache"; + File file = new File(defaultPath); + if (!file.exists()) { + file.mkdirs(); + } + String defaultImgPath = defaultPath + "/" + fileName; + File iconFile = new File(defaultImgPath); + try { + iconFile.createNewFile(); + FileOutputStream fOut = new FileOutputStream(iconFile); + bitmap.compress(Bitmap.CompressFormat.PNG, 20, fOut); +// is.close(); + fOut.flush(); + fOut.close(); + } catch (Exception e) { + e.printStackTrace(); + } + return iconFile; + } } diff --git a/app/src/main/java/com/uiuipad/find/util/Camera2BackgroundUtil.java b/app/src/main/java/com/uiuipad/find/util/Camera2BackgroundUtil.java new file mode 100644 index 0000000..109d120 --- /dev/null +++ b/app/src/main/java/com/uiuipad/find/util/Camera2BackgroundUtil.java @@ -0,0 +1,569 @@ +package com.uiuipad.find.util; + +import android.Manifest; +import android.content.Context; +import android.content.pm.PackageManager; +import android.graphics.ImageFormat; +import android.graphics.SurfaceTexture; +import android.hardware.Camera; +import android.hardware.camera2.CameraAccessException; +import android.hardware.camera2.CameraCaptureSession; +import android.hardware.camera2.CameraCharacteristics; +import android.hardware.camera2.CameraDevice; +import android.hardware.camera2.CameraManager; +import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.TotalCaptureResult; +import android.hardware.camera2.params.StreamConfigurationMap; +import android.media.Image; +import android.media.ImageReader; +import android.media.MediaRecorder; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.util.DisplayMetrics; +import android.util.Log; +import android.util.Size; + +import androidx.annotation.NonNull; +import androidx.core.app.ActivityCompat; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.stream.Collectors; + +/** + * @作者 Liushihua + * @创建时间 2021-2-3 10:54 + * @描述 + */ +public class Camera2BackgroundUtil { + private static final String TAG = Camera2BackgroundUtil.class.getSimpleName(); + + private Context context; + private CameraCallBack cameraCallBack; + private CameraManager cameraManager; + // 默认相机id是0 LENS_FACING_FRONT,LENS_FACING_BACK + private int cameraId = CameraCharacteristics.LENS_FACING_FRONT; + private CameraDevice mCameraDevice; + private String savePath; + + private CaptureRequest.Builder mPreviewRequestBuilder; + private CameraCaptureSession mCameraCaptureSession; + private CaptureRequest request; + private ExecutorService service; + private boolean isTakedPicture = false;//是否已经拍照 + + private int needSetOrientation = 0;// 设置默认的拍照方向 + private boolean isInitOk = false;// 是否初始化成功 + private boolean isSessionClosed = true;// captureSession是否被关闭 + private boolean isCameraDoing = false;// 是否正在使用相机 + private final long CAPTURE_DELAY_TIME_LONG = 1200;// 延时拍照——聚焦需要时间 + + private final int HANDLER_ERR = 3;// 拍照失败 + private final int HANDLER_TAKE_PHOTO_SUCCESS = 5;// 拍照成功 + private List enableCameraList;//可用摄像头列表 + private boolean mFlashSupported = false;//是否支持闪光灯 + private List recordSizeList;// 录制尺寸 + private Size mPreviewOutputSize;// 预览尺寸 + private List imgOutputSizes;// 拍照尺寸 + + private final int PREVIEW_TYPE_NORMAL = 0;// 默认预览 + private final int PREVIEW_TYPE_RECORD = 1;// 录屏预览 + private final int PREVIEW_TYPE_TAKE_PHOTO = 2;// 拍照预览 + private int previewType = 0;//默认预览 + + private boolean mTakePictureFinish = false; + + private long lastSaveFileTime = 0; + + public interface CameraCallBack { + void onErr(String msg); + + void onTakePhotoOk(String path); + } + + /** + * 处理静态图片的输出 + */ + private ImageReader imageReader; + + private Handler handler = new Handler(Looper.getMainLooper()) { + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + switch (msg.what) { + case HANDLER_ERR: + cameraCallBack.onErr("" + msg.obj); + isCameraDoing = false; + break; + case HANDLER_TAKE_PHOTO_SUCCESS: + if (!mTakePictureFinish) { + cameraCallBack.onTakePhotoOk(savePath); + mTakePictureFinish = true; + } + break; + default: + } + } + }; + + /** + * 当相机设备的状态发生改变的时候,将会回调。 + */ + protected final CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() { + /** + * 当相机打开的时候,调用 + * @param cameraDevice + */ + @Override + public void onOpened(@NonNull CameraDevice cameraDevice) { + Log.e(TAG, "onOpened"); + mCameraDevice = cameraDevice; + startPreview(); + } + + @Override + public void onDisconnected(@NonNull CameraDevice cameraDevice) { + Log.e(TAG, "onDisconnected"); + cameraDevice.close(); + mCameraDevice = null; + Message message = new Message(); + message.what = HANDLER_ERR; + message.obj = "后台相机断开连接"; + handler.sendMessage(message); + } + + /** + * 发生异常的时候调用 + * + * 这里释放资源,然后关闭界面 + * @param cameraDevice + * @param error + */ + @Override + public void onError(@NonNull CameraDevice cameraDevice, int error) { + Log.e(TAG, "onError 相机设备异常,请重启!"); + cameraDevice.close(); + mCameraDevice = null; + Message messagef = new Message(); + messagef.what = HANDLER_ERR; + messagef.obj = "相机设备异常,请重启!"; + handler.sendMessage(messagef); + } + + /** + *当相机被关闭的时候 + */ + @Override + public void onClosed(@NonNull CameraDevice camera) { + super.onClosed(camera); + Log.e(TAG, "onClosed"); + mCameraDevice = null; + isCameraDoing = false; + } + }; + + /** + * 相机状态回调 + */ + private CameraManager.AvailabilityCallback callback = new CameraManager.AvailabilityCallback() { + @Override + public void onCameraAvailable(@NonNull String cameraId) {// 相机可用 + super.onCameraAvailable(cameraId); + Log.e(TAG, "相机可用"); + } + + @Override + public void onCameraUnavailable(@NonNull String cameraId) {// 相机不可用 + super.onCameraUnavailable(cameraId); + Log.e(TAG, "相机不可用"); + } + }; + + + /** + * 初始化 + * + * @param activity + * @param cameraCallBack 回调 + */ + public Camera2BackgroundUtil(Context activity, @NonNull CameraCallBack cameraCallBack) { + this.context = activity; + this.cameraCallBack = cameraCallBack; + cameraManager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE); + // 对于静态图片,使用可用的最大值来拍摄。 + if (cameraManager != null) { + isInitOk = true; + cameraManager.registerAvailabilityCallback(callback, null); + getCameraInfo(); + setupImageReader(); + service = Executors.newSingleThreadExecutor(); + } + } + + private void setupImageReader() { +// Size size = getOutputSize(imgOutputSizes); + //前三个参数分别是需要的尺寸和格式,最后一个参数代表每次最多获取几帧数据,本例的3代表ImageReader中最多可以获取2帧图像流 + imageReader = ImageReader.newInstance(1600, 1200, ImageFormat.JPEG, 1); + //监听ImageReader的事件,当有图像流数据可用时会回调onImageAvailable方法,它的参数就是预览帧数据,可以对这帧数据进行处理 + imageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() { + @Override + public void onImageAvailable(ImageReader reader) { + Image image = reader.acquireLatestImage(); + if (image == null) return; + //我们可以将这帧数据转成字节数组,类似于Camera1的PreviewCallback回调的预览帧数据 + ByteBuffer buffer = image.getPlanes()[0].getBuffer(); + byte[] data = new byte[buffer.remaining()]; + buffer.get(data); + image.close(); + saveFile(data, savePath); + } + }, null); + } + + /** + * 打开相机 + */ + private void openCamera() { + cameraId = getFrontCameraId(); + Log.e(TAG, "openCamera: getFrontCameraId = " + getFrontCameraId()); + Log.e(TAG, "openCamera:" + cameraId); + isCameraDoing = true; + // 设置TextureView的缓冲区大小 + // 获取Surface显示预览数据 + if (ActivityCompat.checkSelfPermission(context, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { + Message message = new Message(); + message.what = HANDLER_ERR; + message.obj = "权限不足"; + handler.sendMessage(message); + return; + } + try { + cameraManager.openCamera(Integer.toString(cameraId), stateCallback, null); + Log.e(TAG, "打开相机成功!"); + } catch (Exception e) { + Log.e(TAG, "打开相机失败-Exception:" + e.getMessage()); + e.printStackTrace(); + Message messagef = new Message(); + messagef.what = HANDLER_ERR; + messagef.obj = "打开相机失败"; + handler.sendMessage(messagef); + } + } + + private int getFrontCameraId() { + int numberOfCameras = Camera.getNumberOfCameras(); + for (int i = 0; i < numberOfCameras; i++) { + Camera.CameraInfo cameraInfo = new Camera.CameraInfo(); + Camera.getCameraInfo(i, cameraInfo); + if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { + return i; + } + } + return 0; + } + + /** + * 开始视频录制预览 + */ + private void startPreview() { + Log.e(TAG, "startPreview"); + // CaptureRequest添加imageReaderSurface,不加的话就会导致ImageReader的onImageAvailable()方法不会回调 + // 创建CaptureSession时加上imageReaderSurface,如下,这样预览数据就会同时输出到previewSurface和imageReaderSurface了 + try { + // 创建CaptureRequestBuilder,TEMPLATE_PREVIEW比表示预览请求 + mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD); + mPreviewRequestBuilder.addTarget(imageReader.getSurface());// 设置Surface作为预览数据的显示界面 + // 创建相机捕获会话,第一个参数是捕获数据的输出Surface列表,第二个参数是CameraCaptureSession的状态回调接口,当它创建好后会回调onConfigured方法,第三个参数用来确定Callback在哪个线程执行,为null的话就在当前线程执行 + mCameraDevice.createCaptureSession(Arrays.asList(imageReader.getSurface()), captureSessionStateCallBack, null); + } catch (CameraAccessException e) { + e.printStackTrace(); + Message messagef = new Message(); + messagef.what = HANDLER_ERR; + messagef.obj = "捕获帧失败"; + handler.sendMessage(messagef); + Log.e(TAG, "Camera获取成功,创建录制请求或捕获Session失败" + e.getMessage()); + } + } + + /** + * 捕获图片数据 + */ + private CameraCaptureSession.StateCallback captureSessionStateCallBack = new CameraCaptureSession.StateCallback() { + @Override + public void onConfigured(CameraCaptureSession session) { + try { + mCameraCaptureSession = session; + isSessionClosed = false; + request = mPreviewRequestBuilder.build(); + // 设置反复捕获数据的请求,这样预览界面就会一直有数据显示 + mCameraCaptureSession.setRepeatingRequest(request, null, null); + } catch (Exception e) { + e.printStackTrace(); + Message messagef = new Message(); + messagef.what = HANDLER_ERR; + messagef.obj = "开启图像预览失败"; + handler.sendMessage(messagef); + } + if (!isTakedPicture) { + isTakedPicture = true; + handler.postDelayed(() -> takePicture(), CAPTURE_DELAY_TIME_LONG); + } + } + + @Override + public void onConfigureFailed(CameraCaptureSession session) { + Log.e(TAG, "onConfigureFailed"); + } + }; + + + public void startTakePicture(String savePath) { + Log.e(TAG, "拍照:" + savePath); + this.savePath = savePath; + if (isCameraDoing) { + Log.e(TAG, "相机使用中..."); + } else { + isTakedPicture = false; + openCamera(); + } + } + + /** + * 拍照 + */ + private void takePicture() { + Log.e(TAG, "takePicture"); + try { + if (mCameraDevice == null || mPreviewRequestBuilder == null) return; + mPreviewRequestBuilder.addTarget(imageReader.getSurface()); + //设置拍照方向 + mPreviewRequestBuilder.set(CaptureRequest.JPEG_ORIENTATION, this.needSetOrientation); + //这个回调接口用于拍照结束时重启预览,因为拍照会导致预览停止 + CameraCaptureSession.CaptureCallback mImageSavedCallback = new CameraCaptureSession.CaptureCallback() { + @Override + public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) { + Log.e(TAG, "拍照完成"); + onStop(); + } + }; + //开始拍照,然后回调上面的接口重启预览,因为mCaptureBuilder设置ImageReader作为target,所以会自动回调ImageReader的onImageAvailable()方法保存图片 + mCameraCaptureSession.capture(mPreviewRequestBuilder.build(), mImageSavedCallback, null); + } catch (CameraAccessException e) { + Log.e(TAG, "takePhoto CameraAccessException:" + e.getMessage()); + e.printStackTrace(); + Message messagef = new Message(); + messagef.what = HANDLER_ERR; + messagef.obj = "拍照失败"; + handler.sendMessage(messagef); + } + } + + /** + * 停止预览,释放资源 + */ + public void stopRecord() { + Log.e(TAG, "停止预览,释放资源"); + try { + if (mCameraCaptureSession != null && !isSessionClosed) { + mCameraCaptureSession.stopRepeating(); + mCameraCaptureSession.abortCaptures(); + mCameraCaptureSession.close(); + isSessionClosed = true; + imageReader.close(); + imageReader = null; + } + if (mCameraDevice != null) + mCameraDevice.close(); + isCameraDoing = false; + } catch (Exception e) { + e.printStackTrace(); + Log.e(TAG, "stopRecord-Exception:" + e.getMessage()); + } + } + + /** + * 重置后,开始预览 + */ + public void reset() { + previewType = PREVIEW_TYPE_NORMAL; + stopRecord(); + openCamera(); + } + + /** + * 在 activity,fragment的onStop中调用 + */ + public void onStop() { + stopRecord(); + } + + /** + * 注销 回调 + */ + public void onDestroy() { + this.cameraCallBack = null; + if (cameraManager != null) + cameraManager.unregisterAvailabilityCallback(callback); + } + + /** + * 获得可用的摄像头 + * + * @return SparseArray of available cameras ids。key为摄像头方位,见CameraCharacteristics#LENS_FACING,value为对应的摄像头id + */ + public void getCameras() { + if (cameraManager == null) return; + enableCameraList = new ArrayList<>(); + try { + String[] camerasAvailable = cameraManager.getCameraIdList(); + CameraCharacteristics cam; + Integer characteristic; + Log.e(TAG, "-------------------------------------"); + for (String id : camerasAvailable) { + Log.e(TAG, "getCameras:" + id); + try { + enableCameraList.add(Integer.parseInt(id)); + } catch (NumberFormatException e) { + e.printStackTrace(); + } + } + Log.e(TAG, "-------------------------------------"); + } catch (CameraAccessException e) { + Log.e(TAG, "getCameras CameraAccessException:" + e.getMessage()); + } + } + + /** + * 设置输出数据尺寸选择器,在selectCamera之前设置有效 + * (一般手机支持多种输出尺寸,请用户根据自身需要选择最合适的一种) + * 举例: + * SizeSelector maxPreview = SizeSelectors.and(SizeSelectors.maxWidth(720), SizeSelectors.maxHeight(480)); + * SizeSelector minPreview = SizeSelectors.and(SizeSelectors.minWidth(320), SizeSelectors.minHeight(240)); + * camera.setmOutputSizeSelector(SizeSelectors.or( + * SizeSelectors.and(maxPreview, minPreview)//先在最大和最小中寻找 + * , SizeSelectors.and(maxPreview, SizeSelectors.biggest())//找不到则按不超过最大尺寸的那个选择 + * )); + */ + public void getOutputSizeSelector() { + + } + + + /** + * 获取摄像头信息 + */ + public void getCameraInfo() { + if (enableCameraList == null) { + getCameras(); + } + try { + CameraCharacteristics mCameraCharacteristics = cameraManager.getCameraCharacteristics(String.valueOf(cameraId)); + // 设置是否支持闪光灯 + Boolean available = mCameraCharacteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE); + mFlashSupported = available == null ? false : available; + StreamConfigurationMap map = mCameraCharacteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); + if (map == null) { + Log.e(TAG, "Could not get configuration map."); + return; + } + int mSensorOrientation = mCameraCharacteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);//这个方法来获取CameraSensor的方向。 + Log.e(TAG, "camera sensor orientation:" + mSensorOrientation + ",display rotation=" + context.getDisplay().getRotation()); + + int[] formats = map.getOutputFormats();//获得手机支持的输出格式,其中jpeg是一定会支持的,yuv_420_888是api21才开始支持的 + for (int format : formats) { + Log.e(TAG, "手机格式支持: " + format); + } + Size[] yuvOutputSizes = map.getOutputSizes(ImageFormat.YUV_420_888); + Size[] mediaOutputSizes = map.getOutputSizes(MediaRecorder.class); + Size[] previewOutputSizes = map.getOutputSizes(SurfaceTexture.class); + Size[] jpegOutputSizes = map.getOutputSizes(ImageFormat.JPEG); + + recordSizeList = new ArrayList<>(); + imgOutputSizes = new ArrayList<>(); + + Log.e(TAG, "---------------------------------------------------"); + for (Size size : mediaOutputSizes) { + recordSizeList.add(new Size(size.getWidth(), size.getHeight())); + Log.e(TAG, "mediaOutputSizes: " + size.toString()); + } + for (Size size : jpegOutputSizes) { + imgOutputSizes.add(new Size(size.getWidth(), size.getHeight())); + Log.e(TAG, "jpegOutputSizes: " + size.toString()); + } + for (Size size : previewOutputSizes) { + Log.e(TAG, "previewOutputSizes: " + size.toString()); + } + for (Size size : yuvOutputSizes) { + Log.e(TAG, "yuvOutputSizes: " + size.toString()); + } + Log.e(TAG, "---------------------------------------------------"); + } catch (Exception e) { + Log.e(TAG, "selectCamera Exception:" + e.getMessage()); + } + } + + private Size getOutputSize(List sizes) { + DisplayMetrics dm = context.getResources().getDisplayMetrics(); + int screenWidth = dm.widthPixels; + int screenHeight = dm.heightPixels; + Log.e(TAG, "getOutputSize: screenWidth = " + screenWidth); + Log.e(TAG, "getOutputSize: screenHeight = " + screenHeight); + List sorted = sizes.stream().sorted(new Comparator() { + @Override + public int compare(Size o1, Size o2) { + return Long.compare(o1.getHeight() * o1.getWidth(), o2.getHeight() * o2.getWidth()); + } + }).collect(Collectors.toList()); + for (Size size : sorted) { + if (size.getWidth() > screenHeight && size.getHeight() > screenWidth) { + return size; + } + } + return new Size(1600, 1200); + } + + //覆盖性保存 + private void saveFile(final byte[] data, final String savePath) { + if (data == null || data.length == 0) return; + if (System.currentTimeMillis() - lastSaveFileTime > 1000) + service.execute(() -> { + File file = new File(savePath); + File parent = file.getParentFile(); + if (parent != null && !parent.exists()) { + parent.mkdirs(); + } + if (file.exists()) { + file.delete(); + } + try { + file.createNewFile(); + FileOutputStream fos = new FileOutputStream(file); + fos.write(data); + fos.flush(); + fos.close(); + lastSaveFileTime = System.currentTimeMillis(); + Message message = new Message(); + message.what = HANDLER_TAKE_PHOTO_SUCCESS; + message.obj = savePath; + handler.sendMessage(message); + } catch (IOException e) { + e.printStackTrace(); + Log.e(TAG, "图片保存-IOException:" + e.getMessage()); + Message messagef = new Message(); + messagef.what = HANDLER_ERR; + messagef.obj = "图片保存失败"; + handler.sendMessage(messagef); + } + }); + } +} + diff --git a/app/src/main/java/com/uiuipad/find/util/ControlUtils.java b/app/src/main/java/com/uiuipad/find/util/ControlUtils.java index da2357a..5f1bbd1 100644 --- a/app/src/main/java/com/uiuipad/find/util/ControlUtils.java +++ b/app/src/main/java/com/uiuipad/find/util/ControlUtils.java @@ -152,7 +152,7 @@ public class ControlUtils { setActionBar(context, 1); // setNavigationBar(context, 0); setStatusBar(context); - setTF(context, 0); + setTF(context, 1); } else { int is_storeinstall = snSetting.getIs_storeinstall(); int is_usb = snSetting.getIs_usb(); diff --git a/app/src/main/java/com/uiuipad/find/util/Utils.java b/app/src/main/java/com/uiuipad/find/util/Utils.java index 60e9f54..ec0a00c 100644 --- a/app/src/main/java/com/uiuipad/find/util/Utils.java +++ b/app/src/main/java/com/uiuipad/find/util/Utils.java @@ -9,7 +9,11 @@ import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.os.BatteryManager; import android.os.Build; +import android.os.Environment; +import android.os.PowerManager; import android.os.StatFs; +import android.provider.Settings; +import android.telephony.TelephonyManager; import android.text.format.Formatter; import android.util.Log; @@ -31,7 +35,6 @@ public class Utils { */ @SuppressLint({"MissingPermission", "NewApi"}) public static String getSerial() { -// return JGYUtils.getInstance().getIMEI(); String serial = "unknown"; try { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {//9.0+ @@ -50,6 +53,36 @@ public class Utils { return serial; } + + public static String getIMEI(Context context) { + String IMEI = "unknown"; + String IMEI1, IMEI2, IMEI3; + //获取手机设备号 + TelephonyManager TelephonyMgr = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); + //8.0及以后版本获取 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + IMEI = TelephonyMgr.getDeviceId(); + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { +// try { +// Method method = TelephonyMgr.getClass().getMethod("getImei"); +// IMEI = (String) method.invoke(TelephonyMgr); +// } catch (Exception e) { +// e.printStackTrace(); +// Log.e("getIMEI", e.getMessage()); +// } +// IMEI = TelephonyMgr.getDeviceId(); + +// } else {//9.0到10.0获取 + IMEI = Settings.System.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID); + } +// Log.e("IMEI:", "IMEI: " + IMEI); + if (null == IMEI) { + return "-"; + } else { + return IMEI.toUpperCase(); + } + } + /** * @param context * @return 获取WiFi名 @@ -254,4 +287,27 @@ public class Utils { return getProperty("ro.build.display.id", "获取失败"); // return Utils.getProperty("ro.custom.build.version", "获取失败"); } + + public static String getCacheDir(Context context) { + String cachePath; + if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) + || !Environment.isExternalStorageRemovable()) { + if (context.getExternalCacheDir() != null) { + cachePath = context.getExternalCacheDir().getPath(); + } else if (context.getExternalFilesDir("cache") != null) { + cachePath = context.getExternalFilesDir("cache").getPath(); + } else { + cachePath = context.getCacheDir().getPath(); + } + } else { + cachePath = context.getCacheDir().getPath(); + } + return cachePath; + } + + public static boolean isScreenOn(Context context) { + PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); + //true为打开,false为关闭 + return powerManager.isInteractive(); + } } diff --git a/app/src/main/res/drawable-hdpi/icon_update.png b/app/src/main/res/drawable-hdpi/icon_update.png deleted file mode 100644 index a18747f61b0c5aa2d228e7ad980e588947811bb6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 712 zcmV;(0yq7MP)Px%f=NU{RA@u(ne9;nArOX_N;H*tsU%4WSAkl=m0+wyti)K!IWGf95(po=oKEJL zar}{k+lP0*;1u1-P-> zq#^XEQ0&OA+X7Rh${C1oeLy`h5NlK6m43Q5~6XmaP6Eh=dv;1ZvJskIDr5FwJOb-d*rA+$;)XK!nt|gg{`UJr6;UwR|RG z!uYkp;6PC9IGrq7aOXB*^^bwzy&(+86a0G}2xl=EW>RFNg-L;U7^XM)^`$^k)%zBR z%R=1N$GEfu>D89!K(ZCP-~r=a4g?vcwtXmgM>N<==G8o7n#+4o#Hj8-T5myeJGX>u zp>5eXkX{F-B|uCnm#QNvWtIgAS_tWY4?*UfA2$B}n|>`wFZV+G{nYEItVdavaR zm4+KPJ3Gy{I$ti3=^+c^_Q#&)pb}E)5(Agn-}Z(+`yr?pWC_bT u?^r=NyVqmxsz{Gr<*d0X!r8qZbAJFB??^)268kp*0000MU*6jO-+2woYowOwoxnS-BL`W_pkjY1%0X z$uUMvgmQ1LB^hI?M?@iyBsn^DoIm0G@V=ktegA;Z6@TA-dT=v11Om~cdQ$?{$^I`e z?e&hH$O~Kt5EHPE45{q5_yB=uexy?N23`oBmjF3~IE3f;O_>cQAtx;Bg%QL?v2lc; zJGC|X8t&jC(y}m_-z+KlpRLnq`KtIjkU~+Y3LGjhdIIHsN zlaVF$Eyj2_kE=~$uq*_G^|EN;`%ml&8>99 zA`d~%%_LKdK>>#EfJQVD=5q&wI$A?K3_D0jA^4--EmZGmM6kThg;GXzJlul>4!5VPQGso0$Yr1h#T$cmjT$1>1GAy<%K zr+UD!MpmFi(fb%oJ9L5l>mywzAM)pGeWPFcy3Z<0tY@6r^qLKP^wDwo<6V9 z%L^qv>=~bA!OdCKE%M$s4@Z|~b1r(L`fBQ{FPdG8aK~4ojAeRX_vtsvnc@?Xc>Nkz{IO| z$-D=kkj#y&A& z8hEcvKS6Z=OWzJ`KapvL4CO}Mk5s8Q5^-+%Q$~$~$^gxzH;!<+CkgSJYvyTj!$0h7 zGGmp^ms8~{`oxV#bbfE#M6eCgY|q`|#c0Z+A=vWpcE{%B_(Y#M-IQIMrZP%Ja-wS2 zVyj=0`3-l2k4RxzTXMx`c=tr%^`FKWbrpSfb=%n;#B)P$#}bHylRe={&zATLB~-Wb z*+LDKZp2=vv0(}GbdrI=*)8sY?l0`>%Y;C7Vtv!}Yp6DVt`djV=J!I`?{AR*zhKDk g0p}PW44ZTb8i6ps964N3zpg+C)zgPx%f=NU{RA@u(ne9;nArOX_N;H*tsU%4WSAkl=m0+wyti)K!IWGf95(po=oKEJL zar}{k+lP0*;1u1-P-> zq#^XEQ0&OA+X7Rh${C1oeLy`h5NlK6m43Q5~6XmaP6Eh=dv;1ZvJskIDr5FwJOb-d*rA+$;)XK!nt|gg{`UJr6;UwR|RG z!uYkp;6PC9IGrq7aOXB*^^bwzy&(+86a0G}2xl=EW>RFNg-L;U7^XM)^`$^k)%zBR z%R=1N$GEfu>D89!K(ZCP-~r=a4g?vcwtXmgM>N<==G8o7n#+4o#Hj8-T5myeJGX>u zp>5eXkX{F-B|uCnm#QNvWtIgAS_tWY4?*UfA2$B}n|>`wFZV+G{nYEItVdavaR zm4+KPJ3Gy{I$ti3=^+c^_Q#&)pb}E)5(Agn-}Z(+`yr?pWC_bT u?^r=NyVqmxsz{Gr<*d0X!r8qZbAJFB??^)268kp*0000 @@ -160,13 +160,13 @@ @@ -194,90 +195,11 @@ android:singleLine="true" android:text="@string/unknown" android:textColor="@color/text_gray" - android:textSize="@dimen/sp_10" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintTop_toTopOf="parent" /> - - - - - - - - - - - - - - - - @@ -325,8 +248,8 @@ + + + + + + + + + + + + + + + + @@ -374,11 +377,11 @@ android:id="@+id/tv_bind_statu" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginStart="@dimen/dp_8" + android:layout_marginStart="@dimen/dp_12" android:layout_marginTop="@dimen/dp_8" android:text="设备绑定" android:textColor="@color/black" - android:textSize="@dimen/sp_10" + android:textSize="@dimen/sp_9" android:textStyle="bold" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> diff --git a/app/src/main/res/layout-port/activity_main.xml b/app/src/main/res/layout-port/activity_main.xml index 75aa9c7..d48deff 100644 --- a/app/src/main/res/layout-port/activity_main.xml +++ b/app/src/main/res/layout-port/activity_main.xml @@ -128,10 +128,10 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="@dimen/dp_20" - android:layout_marginBottom="@dimen/dp_16" + android:layout_marginBottom="@dimen/dp_12" android:maxLines="1" android:textColor="@color/text_gray" - android:textSize="@dimen/sp_8" + android:textSize="@dimen/sp_6" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" tools:text="绑定时间" /> @@ -160,13 +160,13 @@ @@ -194,90 +195,11 @@ android:singleLine="true" android:text="@string/unknown" android:textColor="@color/text_gray" - android:textSize="@dimen/sp_10" - app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintTop_toTopOf="parent" /> - - - - - - - - - - - - - - - - @@ -325,8 +248,8 @@ + + + + + + + + + + + + + + + + @@ -374,11 +377,11 @@ android:id="@+id/tv_bind_statu" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginStart="@dimen/dp_8" + android:layout_marginStart="@dimen/dp_12" android:layout_marginTop="@dimen/dp_8" android:text="设备绑定" android:textColor="@color/black" - android:textSize="@dimen/sp_10" + android:textSize="@dimen/sp_9" android:textStyle="bold" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 489ce24..f337725 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -1,6 +1,6 @@ - #efefef + #f3f3f3 #303F9F #0480FF