Commit c875c4a1 by Baoxy

build: 替换背景/完成应用使用情况首页

parent 74e2efc4
......@@ -50,6 +50,7 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"></uses-permission>
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="middleware.permission.MDM" />
<application
android:persistent="true"
......
......@@ -29,6 +29,7 @@
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
android:protectionLevel="signatureOrSystem" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />
<uses-permission android:name="com.android.launcher.permission.WRITE_SETTINGS" />
<uses-permission android:name="com.android.launcher3.permission.READ_SETTINGS" />
......
......@@ -3,6 +3,7 @@ package com.android.launcher3.function.setting
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.GridLayout
import android.widget.LinearLayout
......@@ -10,26 +11,107 @@ import com.android.launcher3.BaseActivity
import com.android.launcher3.R
import com.qmuiteam.qmui.widget.grouplist.QMUICommonListItemView
import com.qmuiteam.qmui.widget.grouplist.QMUIGroupListView
import com.secspace.lib.common.function.database.DatabaseManager
import com.secspace.lib.common.function.entity.UseAppEntity
import com.secspace.lib.common.function.model.UseTime
import com.secspace.lib.common.utils.*
import kotlinx.android.synthetic.main.activity_setting.*
import kotlinx.android.synthetic.main.activity_setting.tv_setting_title
import kotlinx.android.synthetic.main.activity_use_app.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlin.properties.Delegates
class AppUseActivity : BaseActivity() {
private var TAG: String? = "TagAppUseActivity"
private var mContext: Context? = null
private var useAppEntitys: ArrayList<UseAppEntity>? = null
private var startTime: Long = 0
private var endTime: Long = 0
private var totalTime = 0L
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setAndroidNativeLightStatusBar(true)
setContentView(R.layout.activity_use_app)
mContext = this
tv_setting_title.setText(R.string.edu_item_app_use_title)
if (useAppEntitys == null) {
loadData()
} else {
initView()
}
}
private fun loadData() {
endTime = System.currentTimeMillis()
startTime = endTime - 24 * 60 * 60 * 1000
useAppEntitys = ArrayList()
totalTime = 0L
GlobalScope.launch(Dispatchers.IO) {
mContext?.let { it ->
val useAppDao = DatabaseManager.getInstance(it).getUseAppDao()
val useTimeDao = DatabaseManager.getInstance(it).getUseTimeDao()
val useApps = useAppDao?.queryAll()
val useTimes = useTimeDao?.queryByTime(startTime, endTime)
if (useApps == null) {
return@let
}
Log.i(TAG, "useApps: ${useApps.size} useTimes: ${useTimes?.size}")
val tempEntitys = ArrayList<UseAppEntity>()
useTimes?.map<UseTime, UseTime> { useTime ->
if (useTime.useStartTime < startTime) {
useTime.useStartTime = startTime
}
if (useTime.useEndTime > endTime) {
useTime.useEndTime = endTime
}
useTime
}?.filter { useTime ->
useApps.any { useApp ->
useApp.appPackage == useTime.appPackage
}
}?.forEach { useTime ->
val useApp = UseAppEntity(useTime.appPackage, "", (useTime.useEndTime - useTime.useStartTime)/1000/60)
tempEntitys.add(useApp)
}
tempEntitys.groupBy {
it.appPackage
}.values.flatten().forEach { useAppEntity ->
useApps.forEach {
if (it.appPackage == useAppEntity.appPackage){
useAppEntity.appName = it.appName
}
}
useAppEntitys?.add(useAppEntity)
totalTime += useAppEntity.useTime
}
// 根据使用时间降序排列
useAppEntitys!!.sortByDescending { it.useTime }
if(useAppEntitys!!.size > 4){
val tempAppEntity = UseAppEntity("", "", 0)
for (i in 4..useAppEntitys!!.size){
tempAppEntity.appPackage = "Other"
tempAppEntity.appName = "其他"
tempAppEntity.useTime = tempAppEntity.useTime + useAppEntitys!![i -1].useTime
}
useAppEntitys!![3] = tempAppEntity
useAppEntitys!!.removeAt(4)
}
loadFinished()
}
}
}
private suspend fun loadFinished() = withContext(Dispatchers.Main){
initView()
}
private fun initView() {
tv_setting_title.setText(R.string.edu_item_app_use_title)
tv_app_use_time.text = String.format(getString(R.string.edu_item_app_use_last_day), "50")
tv_app_use_time.text = String.format(getString(R.string.edu_item_app_use_last_day), totalTime)
time_progress.setData(useAppEntitys, totalTime)
time_progress.initAnimation()
}
......
package com.android.launcher3.settings;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.text.TextUtils;
import android.view.WindowManager;
......@@ -31,6 +33,7 @@ public class BlankActivity extends BaseActivity {
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
}
@RequiresApi(api = Build.VERSION_CODES.M)
@Override
protected void onResume() {
super.onResume();
......
......@@ -9,7 +9,7 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission
android:name="android.permission.GET_ACCOUNTS"
android:maxSdkVersion="22" />
......
package com.secspace.lib.common.dialog;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.secspace.lib.common.R;
import com.secspace.lib.common.dialog.other.DialogUIUtils;
import com.secspace.log.Log;
......@@ -55,7 +68,28 @@ public class LoadingDialog {
public void show(String text) {
if (mDialog == null) {
mDialog = DialogUIUtils.showLoading(mContext, text, true, false, false, true).show();
View root;
root = LayoutInflater.from(mContext).inflate(R.layout.dialogui_loading_vertical, null);
View llBg = root.findViewById(R.id.dialogui_ll_bg);
ProgressBar pbBg = root.findViewById(R.id.pb_bg);
TextView tvMsg = root.findViewById(R.id.dialogui_tv_msg);
tvMsg.setText(text);
llBg.setBackgroundResource(R.drawable.dialogui_shape_wihte_round_corner);
pbBg.setIndeterminateDrawable(mContext.getResources().getDrawable(R.drawable.dialogui_rotate_mum));
tvMsg.setTextColor(mContext.getResources().getColor(R.color.text_black));
mDialog = new android.app.AlertDialog.Builder(mContext)
.setView(root)
.setCancelable(false)
.create();
setDialogStyle(mContext, mDialog);
Window window = mDialog.getWindow();
if (window != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
window.setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
} else {
window.setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
}
}
}
if (!mDialog.isShowing()) {
try {
......@@ -81,4 +115,36 @@ public class LoadingDialog {
mDialog = null;
}
}
public void setDialogStyle(Context context, Dialog dialog) {
if (dialog == null) {
return;
}
Window window = dialog.getWindow();
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
window.setGravity(Gravity.CENTER);
WindowManager.LayoutParams wl = window.getAttributes();
// 以下这两句是为了保证按钮可以水平满屏
int width = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getWidth();
int height = (int) (((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getHeight() * 0.9);
wl.width = (int) (width * 0.94); // todo keycode to keep gap
wl.height = ViewGroup.LayoutParams.WRAP_CONTENT; //TODO 一般情况下为wrapcontent,最大值为height*0.9
// if (measuredHeight > height) {
// wl.height = height;
// }
if (context instanceof Activity) {
Activity activity1 = (Activity) context;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
if (activity1.isDestroyed()) {
context = DialogUIUtils.appContext;
}
}
} else {
wl.type = WindowManager.LayoutParams.TYPE_TOAST;
//todo keycode to improve window level,同时要让它的后面半透明背景也拦截事件,不要传递到下面去
//todo 单例化,不然连续弹出两次,只能关掉第二次的
}
dialog.onWindowAttributesChanged(wl);
}
}
\ No newline at end of file
......@@ -8,7 +8,6 @@ import android.os.Handler
import android.os.Looper
import android.os.SystemClock
import com.secspace.lib.common.R
import com.secspace.lib.common.dialog.LoadingDialog
import com.secspace.lib.common.env.Packages.PkgSecSpace
import com.secspace.lib.common.env.SEnvironment
import com.secspace.lib.common.function.ActivationHelper.ActivationListener
......@@ -71,7 +70,7 @@ object WorkManager {
Log.i(TAG, "system agent request runtime permission")
return
}
LoadingDialog.getInstance(launcher).show("切换中")
// LoadingDialog.getInstance(launcher).show("切换中")
GlobalScope.launch(Dispatchers.IO) {
openAccessibility(launcher)
SwitchInMdm.onInit(launcher)
......
......@@ -22,14 +22,14 @@ public interface UseAppDao {
UseApp queryByPkg(String packageName);
@Insert
long insertTargetApp(UseApp targetApp);
long insertUseApp(UseApp useApp);
@Insert
List<Long> insertTargetApps(List<UseApp> targetApps);
List<Long> insertUseApps(List<UseApp> useApps);
@Update
void updateTargetApp(UseApp targetApp);
void updateUseApp(UseApp useApp);
@Update
void updateTargetApps(List<UseApp> targetApps);
void updateUseApps(List<UseApp> useApps);
}
package com.secspace.lib.common.function.entity
data class UseAppEntity(var appPackage: String, var appName: String, var useTime: Long)
\ No newline at end of file
......@@ -5,7 +5,6 @@ import android.util.Log
import com.secspace.lib.common.function.database.DatabaseManager
import com.secspace.lib.common.function.model.UseApp
import com.secspace.lib.common.function.model.UseTime
import com.secspace.lib.common.utils.getApplicationIcon
import com.secspace.lib.common.utils.getApplicationName
class UseAppManager private constructor(val context: Context) {
......@@ -18,48 +17,48 @@ class UseAppManager private constructor(val context: Context) {
useTime.useStartTime = System.currentTimeMillis()
useTime.uploadTime = 0
// 是否是应该被忽略的应用
if(ignorePkg.contains(packageName)){
if (ignorePkg.contains(packageName)) {
if (pkgQueue.isEmpty()) {
return
}
if(pkgQueue.size == 1){
if (pkgQueue.size == 1) {
val existPkg = pkgQueue[0]
// 本次应用与上次应用一样,清空缓存
if (existPkg.appPackage == useTime.appPackage){
if (existPkg.appPackage == useTime.appPackage) {
pkgQueue.clear()
return
}
// 本次应用与上次不一样,计算时间,如果大于65s,则将赋予上次应用结束时间,存入数据库,并将上次应用移除
Log.i(TAG, "上次时间 ${existPkg.useStartTime}, 本次时间 ${useTime.useStartTime} 差: ${useTime.useStartTime - existPkg.useStartTime}")
if (useTime.useStartTime - existPkg.useStartTime >= 65 * 1000){
if (useTime.useStartTime - existPkg.useStartTime >= 65 * 1000) {
// 给应用赋予结束时间
existPkg.useEndTime = System.currentTimeMillis()
Log.i(TAG, "insertUseTime:${DatabaseManager.getInstance(context).getUseTimeDao()}")
// 存入数据库
val result = DatabaseManager.getInstance(context).getUseTimeDao()?.insertUseTime(existPkg)
Log.i(TAG, "insertUseTime result:$result")
DatabaseManager.getInstance(context).getUseTimeDao()?.insertUseTime(existPkg)
pkgQueue.clear()
}
}
return
}
disposeApp(packageName)
// 第一次打开某应用,将其放到第一位
if (pkgQueue.isEmpty()) {
Log.i(TAG, "pkgQueue is Empty")
pkgQueue.add(0, useTime)
return
}
if(pkgQueue.size == 1){
if (pkgQueue.size == 1) {
// 取出上一轮存储的应用
val existPkg = pkgQueue[0]
// 本次应用与上次应用一样,什么也不做
Log.i(TAG, "上次应用 ${existPkg.appPackage}, 本次应用 ${useTime.appPackage}")
if (existPkg.appPackage == useTime.appPackage){
if (existPkg.appPackage == useTime.appPackage) {
return
}
// 本次应用与上次不一样,计算时间,如果大于65s,则将赋予上次应用结束时间,存入数据库,并将上次应用移除
Log.i(TAG, "上次时间 ${existPkg.useStartTime}, 本次时间 ${useTime.useStartTime} 差: ${useTime.useStartTime - existPkg.useStartTime}")
if (useTime.useStartTime - existPkg.useStartTime >= 65 * 1000){
if (useTime.useStartTime - existPkg.useStartTime >= 65 * 1000) {
// 给应用赋予结束时间
existPkg.useEndTime = System.currentTimeMillis()
// 存入数据库
......@@ -71,10 +70,22 @@ class UseAppManager private constructor(val context: Context) {
}
}
private fun disposeApp(packageName: String){
val appName = getApplicationName(context, packageName)
val icon = getApplicationIcon(context, packageName)
private fun disposeApp(packageName: String) {
val useAppDb = DatabaseManager.getInstance(context).getUseAppDao()?.queryByPkg(packageName)
if (useAppDb != null) {
return
}
val useApp = UseApp()
useApp.appName = getApplicationName(context, packageName)
useApp.appPackage = packageName
useApp.uploadTime = 0
DatabaseManager.getInstance(context).getUseAppDao()?.insertUseApp(useApp)
// val icon = getApplicationIcon(context, packageName)
// 将图片转为字符串
// val iconString = drawableToString(icon)
// 将字符串写入文件,因为日志无法打印全
// Log.e(TAG, "文件写入完毕")
// write2File(iconString,Environment.getExternalStorageDirectory().toString() + "/temp1.txt")
}
companion object {
......
......@@ -12,6 +12,8 @@ import android.util.TypedValue;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;
import com.secspace.lib.common.function.entity.UseAppEntity;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collections;
......@@ -22,7 +24,7 @@ import java.util.List;
* 应用使用时间进度条
*/
public class TimeProgress extends View {
private List<UseAppEntity> useAppEntities = new ArrayList<>();
private Paint bgPaint;
private Paint textPaint;
......@@ -109,7 +111,12 @@ public class TimeProgress extends View {
paintColors.add(0xFF9BFA13);
paintColors.add(0xFFFAB613);
paintColors.add(0xFFE5E5E5);
allTime = 160;
}
public void setData(List<UseAppEntity> useAppEntities, long allTime) {
this.useAppEntities = useAppEntities;
this.allTime = allTime;
invalidate();
}
/**
......@@ -227,6 +234,9 @@ public class TimeProgress extends View {
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(useAppEntities.size() == 0){
return;
}
// 初始化width,padding等参数
parameterAssignment();
// 绘制横向柱状图
......@@ -236,31 +246,33 @@ public class TimeProgress extends View {
private void drawIndicator(Canvas canvas) {
// 平分后每份的长度
float share = mWidth / times.size();
float share = mWidth / useAppEntities.size();
float x, y;
for (int i = 0; i < times.size(); i++) {
int time = times.get(i);
for (int i = 0; i < useAppEntities.size(); i++) {
long time = useAppEntities.get(i).getUseTime();
String appName = useAppEntities.get(i).getAppName();
String text = time + "分钟";
textPaint.setColor(0xff000000);
bgPaint.setColor(paintColors.get(i));
float textHeight = getTextHeight(text, textPaint);
float textWidth = getTextWidth(text, textPaint);
float textHeight = getTextHeight(appName, textPaint);
float appNameTextWidth = getTextWidth(appName, textPaint);
float timeTextWidth = getTextWidth(text, textPaint);
float realWidth = timeTextWidth > appNameTextWidth?timeTextWidth:appNameTextWidth;
x = share * i + share / 2;
if (i == 0) {
x = x + paddingLeft;
}
y = textHeight + tipsMargin + progressHeight + paddingLeft;
canvas.drawRect(x - textWidth, y - textHeight + indicatorMargin, x - textWidth + textHeight, y + indicatorMargin, bgPaint);
canvas.drawText(text, x, y, textPaint);
canvas.drawRect(x - realWidth, y - textHeight + indicatorMargin, x - realWidth + textHeight, y + indicatorMargin, bgPaint);
canvas.drawText(appName, x, y, textPaint);
canvas.drawText(text, x, y + textHeight + tipsMargin / 3, textPaint);
}
}
private void drawHorizontalCylindrical(Canvas canvas) {
for (int i = 0; i < times.size(); i++) {
int time = times.get(i);
for (int i = 0; i < useAppEntities.size(); i++) {
long time = useAppEntities.get(i).getUseTime();
float rate = time / allTime;
if (i == 0) {
bgRectF.left = cylindricalStartLeft + paddingLeft;
......@@ -272,7 +284,7 @@ public class TimeProgress extends View {
bgRectF.top = paddingTop;
bgRectF.right = mWidth * rate * animationValue / 100 + cylindricalStartLeft;
bgRectF.bottom = bgRectF.top + progressHeight;
if (i == times.size() - 1) {
if (i == useAppEntities.size() - 1) {
bgRectF.right = mWidth * rate * animationValue / 100 - paddingRight + cylindricalStartLeft;
}
cylindricalStartLeft = bgRectF.right;
......
......@@ -2,10 +2,18 @@ package com.secspace.lib.common.utils
import android.content.Context
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.PixelFormat
import android.graphics.drawable.Drawable
import android.provider.Settings
import android.util.Base64
import com.secspace.lib.common.function.service.EduAccessibilityService
import com.skr.activation.utils.DesUtil
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileWriter
fun decrypt(strMi: String): String {
return DesUtil.decrypt(strMi)
......@@ -52,3 +60,41 @@ fun getApplicationIcon(context: Context?, packageName: String): Drawable? {
pm?.getApplicationInfo(packageName, PackageManager.GET_META_DATA)?.loadIcon(pm)
}
}
@Synchronized
fun drawableToString(drawable: Drawable?): String? {
drawable?.let {
val bitmap = Bitmap
.createBitmap(
it.intrinsicWidth,
it.intrinsicHeight,
if (it.opacity != PixelFormat.OPAQUE) Bitmap.Config.ARGB_8888 else Bitmap.Config.RGB_565)
val canvas = Canvas(bitmap)
it.setBounds(0, 0, it.intrinsicWidth,
it.intrinsicHeight)
it.draw(canvas)
val size = bitmap.width * bitmap.height * 4
// 创建一个字节数组输出流,流的大小为size
val baos = ByteArrayOutputStream(size)
// 设置位图的压缩格式,质量为100%,并放入字节数组输出流中
bitmap.compress(Bitmap.CompressFormat.PNG, 10, baos)
// 将字节数组输出流转化为字节数组byte[]
val imagedata: ByteArray = baos.toByteArray()
return Base64.encodeToString(imagedata, Base64.DEFAULT)
}
return null
}
fun write2File(source: String, filePath: String) {
val file = File(filePath)
if(file.exists()){
file.delete()
}
if (!file.createNewFile()) {
return
}
val fileWriter = FileWriter(file, false)
fileWriter.use {
fileWriter.write(source)
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment