Compare commits

42 Commits

Author SHA1 Message Date
ad72e265c1 1.补充上次提交Launcher实现方法abstract setFragmentsDisableRefreshDataFlag
2.sharepreference config.xml存储是否刷新数据标识
3.推荐页禁止数据刷新代码补充
4.二级菜单按Home键和返回键更新刷新数据变量,home键重置FragmentManager
2026-03-20 16:16:18 +08:00
2f7539febb 1.解决打开二级和设置等多层级页面按Home键app被杀死和跳转到Launcher两种情况,针对被杀死的处理 2026-03-20 15:40:39 +08:00
c7600b014a 1.解决同列长按或快按方向上下键焦点并未落在同例而是可视最后一个item问题 2026-03-18 11:13:36 +08:00
c7f0f1ef7b 1.取消延长动画时间办法解决焦点问题,更改为组件发生滚动取消获取焦点即可 2026-03-16 15:36:29 +08:00
724d4cff36 1.解决Fragment注销EventBus广播,其禁止加载数据状态按返回进行重置为可加载的状态 2026-03-16 14:30:12 +08:00
2e6bf877fe 1.解决开机无网络跟开机首次失败相冲突问题,Service由MXQ_4K代码替换 2026-03-16 08:45:54 +08:00
283099c7e8 1.解决开机无网络跟开机首次失败相冲突问题,Service由MXQ_4K代码替换 2026-03-16 08:45:19 +08:00
43ceb03f5a 1.解决开机无网络跟开机首次失败相冲突问题,Service由MXQ_4K代码替换 2026-03-16 08:44:16 +08:00
a5d952a5f7 1.解决二级+添加界面快速按返回键,退回界面,光标丢失问题 2026-03-14 10:08:44 +08:00
682c87e27d 1.解决二级界面从左往右快速切换页面时,快按光标异常徘徊问题 2026-03-13 20:12:52 +08:00
84883cd7a8 1.解决动画结束焦点未落在快捷栏的问题 2026-03-11 21:49:37 +08:00
e519adfb02 1.解决首次安装请求失败网络变化后未先延迟5min分钟请求,直接按每隔1小时请求1次,直到请求成功改每隔8小时请求1次的问题 2026-03-09 15:00:07 +08:00
4bbdcd9a63 1.解决快捷栏添加应用界面、二级菜单列表、二级菜单添加应用界面、myapp界面长名称应用走马灯出现花屏条 2026-03-06 17:28:46 +08:00
fafc03993d 1.解决首页按方向键光标移动错误定位问题 2026-03-06 10:16:46 +08:00
42854c9555 1.解决服务器请求错误码在请求从未成功的情况下未按每隔1小时询问一次; 2026-03-05 19:34:58 +08:00
4ae70fd9ef 1.解决时间回退未立刻发生请求问题 2026-03-05 19:17:06 +08:00
53dbef8f48 1.删除第三方广告sdk的集成和依赖
2.禁止开屏视频和广告位视频下载播放
2026-03-05 09:30:11 +08:00
59783d89e3 1.第一次加载本地配置收藏夹,不校验本地app是否已安装 2026-03-04 14:55:17 +08:00
260ff0825b 1.开机取消10定时直接显示默认图,后续网络或本地图片再次替换更新
2.视频定时轮播时间间隔1min改5min
2026-03-04 13:49:54 +08:00
a14f3c6561 1.二级菜单已展开app列表内,快速按下滚动时焦点跳跃落在底行最后一个item问题 2026-02-09 15:57:38 +08:00
0cd4779419 1.已展开app列表,有app卸载或新任务安装时,下方已勾选误抢焦点的问题 2026-02-09 10:22:48 +08:00
2a5dfbd73b 1.二级菜单翻页自动获取首个item焦点 2026-02-07 18:07:41 +08:00
753ef290eb 1.高版本apk下载完成先不删除由clearApkFileByPowerDown删除 2026-02-07 14:22:55 +08:00
25c77aad68 1.打开二级菜单apps界面有概率崩溃,getActivity()为空 2026-02-07 14:14:22 +08:00
27457cf8ce 1.shareference config.xml建立本地收藏夹和网络隔离收藏夹,本地数据库收藏夹改由shareference存储记录
2.收藏夹version比对时不清空表记录清空netshortbean表,打开任务时需要重新插netshortbean表
3.MXQRES本地文件时全部记录到shareference本地收藏夹内
2026-02-06 20:53:18 +08:00
494d7e63ff 1.下载文件报错异常可以先建立临时空文件方便下次任务驱动下载
2.启动第三方应用需要建立新栈
2026-02-06 18:50:35 +08:00
b8b8989166 1.persistent 导致无法升级bug,取消 2025-12-27 18:52:36 +08:00
0acf5066b0 1.SharePre 仅一个广告位仅更新广告数据后删除数据为[]因size>0未更新到Sharepreference 2025-12-25 19:31:20 +08:00
e10fe43759 1.ADManager处理安装apk重启设备安装应用回调不严谨误删安装APK
2.ADManager 处理同一个广告位更新广告数据后未上报前重启未清除之前已上报的信息
3.Manifest 文件application标签添加persistent阻止Launcher轻易被杀死
4.开屏自定义View xml文件属性更正
2025-12-25 15:05:53 +08:00
9fdeb528cc 1.ADSWindowManager单例中防止所有视频广告位都无法播放进入播放死循环
2.自定义组件在layout目录缺失xml文件进行补充
2025-12-17 20:50:14 +08:00
540e24d5eb 1.ADSWindowManager单例中handler会造成内存泄漏进行纠正
2.CategoryApp 删除多余单例再次初始化
3.第三方日志开关和本应用日志为统一一个开关
2025-12-12 15:41:09 +08:00
81e5f90ab8 1.sw540dp xml适配纠正 chrome按键自定义属性 2025-12-08 14:50:33 +08:00
c8fb7a5d93 1.考虑到retrofit 头header 有d-time 字段 舍弃UploadADBean dtime字段漏提交 2025-11-26 20:49:22 +08:00
824c5fed37 1.考虑到retrofit 头header 有d-time 字段 舍弃UploadADBean dtime字段 2025-11-26 20:38:26 +08:00
7df8c91156 1.优化断电重启文件丢失(服务器已上报),重新下载图片 2025-11-26 19:59:22 +08:00
3311bda502 1.优化处理后台任务含视频有空地址的情况保持代码健壮性
2.优化处理apk下载完成不上报后台后减少EventBus通知
2025-11-26 16:04:15 +08:00
ab21451616 1.上报接口需求由0-资源下载完成1-app下载完成2-app安装完成更改为增加3-app已存在,0改为图片下载完成,1改为视频下载完成,上报字段添加dtime
2.Shareprerence删除key未删除成功更正
3.取消上报接口 原1-app下载完成
2025-11-22 17:12:10 +08:00
ecdbb788f5 1.广告位上报接口和对已上报进行Sharedference存储
2.对广告位更新资源对Sharedference进行清除
2025-11-21 19:29:53 +08:00
7c9a2c44fd 1.同一个广告位交替更换图片有概率产生图片已下载完成但下载任务表未删的情况 2025-11-11 22:10:42 +08:00
fd76fa3a2f 1.优化apk 安装过程中重启apk未安装未删除安装包修改为继续安装 2025-11-11 15:58:34 +08:00
632000cb56 1.apk 安装过程中重启apk未安装未删除安装包修改为继续安装并删除安装包
2.apk 安装过程中重启apk已安装未删除安装包修改为删除安装包
3.DownLoadManager撤回下载任务但文件丢失会产生-tmp 0 size大小文件bug,下载异常日志打印
2025-11-10 16:42:17 +08:00
646719c3fb 1.AppManager和SplashView处理图片断电重启无论多少次图片不显示而其原因为文件变回-tmp情况,广告位5s后刷新
2.DownLoadManeger 处理下载apk安装未完成重启无论多少次不安装情况
3.重命名系统概率不成功把重命名和删除文件操作分开间隔5s
2025-11-08 09:03:38 +08:00
62 changed files with 2367 additions and 955 deletions

View File

@@ -11,8 +11,8 @@ android {
minSdkVersion 21
targetSdkVersion 34
multiDexEnabled true
versionCode 568888804
versionName "SNFLauncher-5.6.4"
versionCode 568888806
versionName "SNFLauncher-5.6.6"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
buildConfigField "String", "MANUFACTURER", '"allwinner"'
buildConfigField "boolean", "LOG_ENABLED", "false"
@@ -99,7 +99,7 @@ dependencies {
//消息组件
implementation 'org.greenrobot:eventbus:3.1.1'
implementation 'com.google.android.gms:play-services-ads:20.3.0'
// implementation 'com.google.android.gms:play-services-ads:20.3.0'
}

Binary file not shown.

View File

@@ -27,6 +27,7 @@
<uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.GET_TASKS"/>
<uses-permission
android:name="android.permission.INSTALL_PACKAGES"/>
<uses-permission android:name="permission.REQUEST_DELETE_PACKAGES" />

View File

@@ -22,16 +22,19 @@ import com.android.device.NetStateChangeObserver;
import com.android.nebulasdk.bean.ADInfo;
import com.android.nebulasdk.presenter.AppnetPresenter;
import com.android.nebulasdk.presenter.callback.AppnetCallback;
import com.android.util.DeviceUtil;
import com.android.util.LogUtils;
import com.android.util.NetUtil;
import com.android.util.NetworkType;
import java.lang.ref.WeakReference;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;
import java.util.UUID;
/**
* 资源同步后台服务
@@ -43,150 +46,113 @@ import java.util.TimeZone;
*/
public class SystemService extends Service implements AppnetCallback, NetStateChangeObserver {
private static final int WHAT_REQUEST_ADMSG = 0;
private static final int WHAT_NETWORK_CHANGE = 3;
private static final int WHAT_PERIODIC_REQUEST = 4;
private static final String TAG = SystemService.class.getName();
private AppnetPresenter appnetPresenter;
String deviceId = "";
/**launcher 资源更新通知*/
public static final String NOTIFY_LAUNCHER_UPDATE="com.ik.launcher.res.notify";
/**Advert 资源更新通知*/
public static final String NOTIFY_ADVERT_UPDATE="com.ik.Advert.res.notify";
private static boolean isRunning = false;
// 请求间隔8小时正式环境
// private static final long REQUEST_INTERVAL = 8 * 60 * 60 * 1000;
// 测试用短间隔
private static final long REQUEST_INTERVAL = 5 * 60 * 1000; // 5分钟
//请求launcher资源信息
private static final int WHAT_REQUEST_ADMSG=0;
/**更新资源信息*/
private static final int WHAT_REQUEST_UPDATEADINFO=1;
//开启诊断是否启动任务
private static final int WHAT_ASK_CIRCLETASK=2;
/**网络变化通知*/
private static final int WHAT_NETWORK_CHANGE=3;
// -1表示无有效网络
private int lastEffectiveNetworkType = -1;
//标记当前是否有广告请求在进行(防止并行请求)
private boolean isRequesting = false;
// 上次网络触发请求的时间戳(毫秒)
private long lastNetTriggerTime = 0L;
// 网络请求最小间隔60秒
private static final long NET_REQUEST_INTERVAL = 10*60 * 1000;
private static final long FIVE_MINUS_DELAY=5*60 * 1000;
private static final long ONE_HOUR_DELAY= 60 * 60 * 1000;
private boolean isFirstRequestDone;
private boolean hasRequestDone;//请求成功过 更新时间间隔 8h
private SharedPreferences sharedPreferences;
//持久化存储成功请求时间
private static final String KEY_LAST_SUCCESS_TIME = "last_success_time";
private boolean isFirstRequestDone = false; // 首次请求是否完成重启后重置为false
private boolean isRunning = false;
private boolean isRequesting = false;
private AppnetPresenter appnetPresenter;
private Handler handler;
private SharedPreferences sharedPreferences;
private PowerManager powerManager;
@Override
public void onCreate() {
super.onCreate();
if (!isRunning) {
isRunning = true;
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
powerManager = (PowerManager) getSystemService(POWER_SERVICE);
initHandler();
NetStateChangeReceiver.registerReceiver(this);
NetStateChangeReceiver.registerObserver(this);
// 检查是否是重启后首次启动服务
checkRebootStatus();
// 检查网络并执行首次请求
checkNetworkAndInitiateFirstRequest();
//handler.postDelayed(() -> ADManager.getInstance().restDownloadTask(), 3000);
private static class MyHandler extends Handler{
WeakReference<SystemService> weakReference;
private MyHandler(SystemService service,Looper looper){
super(looper);
if(weakReference==null) weakReference= new WeakReference<>(service);
}
}
/**
* 检查是否是重启后首次启动
*/
private void checkRebootStatus() {
if (powerManager != null) {
// 判断是否是开机后首次启动服务
boolean isReboot = powerManager.isInteractive();
if (isReboot) {
// LogUtils.loge("检测到设备重启,重置为首次请求状态");
isFirstRequestDone = false;
}
}
}
private void initHandler() {
handler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
switch (msg.what) {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
SystemService systemService = weakReference.get();
if(systemService!=null){
switch (msg.what){
case WHAT_REQUEST_ADMSG:
handleAdRequest();
systemService.isRequesting=true;
try {
if (systemService.appnetPresenter == null) {
systemService.appnetPresenter = new AppnetPresenter(systemService);
}
systemService.appnetPresenter.postLauncherAds(systemService);
} catch (Exception e) {
LogUtils.loge("request exception");
systemService.isRequesting=false;
if(!systemService.isFirstRequestDone){
systemService.isFirstRequestDone=true;
}else {
if(systemService.hasRequestDone){
systemService.lastNetTriggerTime=System.currentTimeMillis();
systemService.sharedPreferences.edit().putLong(KEY_LAST_SUCCESS_TIME, systemService.lastNetTriggerTime).apply();
}else {
if(systemService.lastNetTriggerTime!=0L){
systemService.handler.removeMessages(WHAT_ASK_CIRCLETASK);
systemService.handler.sendEmptyMessageDelayed(WHAT_ASK_CIRCLETASK, NET_REQUEST_INTERVAL);
return;
}
}
}
systemService.scheduleNextCircleAsk();
}
break;
case WHAT_REQUEST_UPDATEADINFO:
//发送更新广告信息的广播
break;
case WHAT_ASK_CIRCLETASK:
if(!systemService.isRequesting&&systemService.shouldRequestImmediately()&& systemService.isNetworkAvailable()){
systemService.handler.removeMessages(WHAT_REQUEST_ADMSG);
systemService.handler.sendEmptyMessage(WHAT_REQUEST_ADMSG);
}else{
systemService.scheduleNextCircleAsk();//刷新定时或启动定时
}
break;
case WHAT_NETWORK_CHANGE:
notifyNetworkChange();
break;
case WHAT_PERIODIC_REQUEST:
handlePeriodicRequest();
LogUtils.loge("发送网络变化的通知");
EventBusUtils.postMsg(new MessageEvent(MessageEvent.ACTION_UPADATE_MEDIA_STATUS)); //网络变化刷新图标
break;
}
}
};
}
private void handlePeriodicRequest() {
// boolean should=shouldRequestImmediately();
// LogUtils.loge("shouldRequestImmediately()="+should+"isRequesting="+isRequesting);
if (isNetworkAvailable() && shouldRequestImmediately() && !isRequesting) {
LogUtils.loge("定时任务:满足条件,执行请求,task turn on");
handleAdRequest();
} else {
scheduleNextPeriodicRequest();
}
}
private void checkNetworkAndInitiateFirstRequest() {
if (isFirstRequestDone) {
if (shouldRequestImmediately() && !isRequesting) {
handler.sendEmptyMessage(WHAT_REQUEST_ADMSG);
} else {
LogUtils.loge("首次请求已完成,启动定时任务 first request");
scheduleNextPeriodicRequest();
}
return;
}
boolean currentNetworkAvailable = isNetworkAvailable();
if (currentNetworkAvailable && !isRequesting) {
LogUtils.loge("执行首次请求 first request handler msg");
handler.sendEmptyMessage(WHAT_REQUEST_ADMSG);
} else {
LogUtils.loge("网络不可用,安排首次请求检查 network dont work");
scheduleNextPeriodicRequest();
}
}
private void scheduleNextPeriodicRequest() {
handler.removeMessages(WHAT_PERIODIC_REQUEST);
if (!isFirstRequestDone) {
LogUtils.loge("首次请求未完成5分钟后再次检查 first uncompletely");
handler.sendEmptyMessageDelayed(WHAT_PERIODIC_REQUEST, 5*60 * 1000);
return;
}
long lastSuccessTime = getLastSuccessTime();
long currentTime = System.currentTimeMillis();
// 从未成功过,使用检查间隔
if (lastSuccessTime == 0) {
LogUtils.loge("从未成功请求过1个小时后再次尝试,no success,1hour later try");
handler.sendEmptyMessageDelayed(WHAT_PERIODIC_REQUEST, 60 * 60 * 1000);
return;
}
long nextRequestTime = lastSuccessTime + REQUEST_INTERVAL;
long delay = Math.max(0, nextRequestTime - currentTime);
LogUtils.loge("delay="+delay);
handler.sendEmptyMessageDelayed(WHAT_PERIODIC_REQUEST, delay);
// if (isNetworkAvailable()){
// LogUtils.loge("定时任务安排完成:" +
// "上次成功时间=" + formatTime(lastSuccessTime) +
// ",当前时间=" + formatTime(currentTime) +
// ",延迟=" + (delay / 1000 / 60) + "分钟" +
// ",下次执行=" + formatTime(currentTime + delay));
// }
}
private MyHandler handler;
private boolean shouldRequestImmediately() {
if (!isFirstRequestDone) {
return true;
}
long lastSuccessTime = getLastSuccessTime();
long lastSuccessTime = sharedPreferences.getLong(KEY_LAST_SUCCESS_TIME, 0);
long currentTime = System.currentTimeMillis();
if (lastSuccessTime == 0) {
@@ -199,7 +165,7 @@ public class SystemService extends Service implements AppnetCallback, NetStateCh
}
long timeDiff = currentTime - lastSuccessTime;
if (timeDiff >= REQUEST_INTERVAL) {
if (timeDiff >= NET_REQUEST_INTERVAL) {
LogUtils.loge("满足8小时间隔条件应立即请求 delay 8 hour task turn on");
return true;
}
@@ -208,130 +174,23 @@ public class SystemService extends Service implements AppnetCallback, NetStateCh
return false;
}
private void markFirstRequestDone() {
isFirstRequestDone = true;
// LogUtils.loge("标记首次请求已完成");
}
private void handleAdRequest() {
if (isRequesting) {
return;
@Override
public void onCreate() {
super.onCreate();
if(!isRunning){
isRunning =true;
handler=new MyHandler(SystemService.this,Looper.getMainLooper());
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
deviceId= DeviceUtil.getEthernetMac();
LogUtils.loge( "onCreate: systemservice is start :"+deviceId);
NetStateChangeReceiver.registerReceiver(this);
NetStateChangeReceiver.registerObserver(this);
lastNetTriggerTime = sharedPreferences.getLong(KEY_LAST_SUCCESS_TIME, 0);
handler.removeMessages(WHAT_ASK_CIRCLETASK);
handler.sendEmptyMessage(WHAT_ASK_CIRCLETASK);
}
if (appnetPresenter == null) {
try {
appnetPresenter = new AppnetPresenter(this);
} catch (Exception e) {
isRequesting = false;
if (!isFirstRequestDone) {
markFirstRequestDone();
}
// 失败时不保存时间
// saveLastSuccessTime();
LogUtils.loge("请求异常 request exception");
scheduleNextPeriodicRequest();
return;
}
}
isRequesting = true;
appnetPresenter.postLauncherAds(this);
}
private void notifyNetworkChange() {
EventBusUtils.postMsg(new MessageEvent(MessageEvent.ACTION_UPADATE_MEDIA_STATUS));
}
private boolean isNetworkAvailable() {
int netState = NetUtil.getNetWorkState(this);
return netState == NetUtil.NETWORK_MOBILE
|| netState == NetUtil.NETWORK_WIFI
|| netState == NetUtil.NETWORK_ETHERNET;
}
private long getLastSuccessTime() {
return sharedPreferences.getLong(KEY_LAST_SUCCESS_TIME, 0);
}
private void saveLastSuccessTime() {
long currentTime = System.currentTimeMillis();
sharedPreferences.edit()
.putLong(KEY_LAST_SUCCESS_TIME, currentTime)
.apply();
LogUtils.loge("已保存本次成功请求时间refresh" + formatTime(currentTime));
}
@Override
public void onNetDisconnected() {
LogUtils.loge("网络断开 netdisconnect");
handler.sendEmptyMessage(WHAT_NETWORK_CHANGE);
}
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
public void onNetConnected(NetworkType networkType) {
LogUtils.loge("网络连接恢复netconnect" + networkType.name());
scheduleNextPeriodicRequest();
handler.sendEmptyMessage(WHAT_NETWORK_CHANGE);
}
@Override
public void onResult(Object data) {
isRequesting = false;
List<ADInfo> adInfoList = (data instanceof List<?>) ? (List<ADInfo>) data : new ArrayList<>();
ADManager.getInstance().updateADInfo(adInfoList);
if (!isFirstRequestDone) {
markFirstRequestDone();
}
// 成功时保存时间
saveLastSuccessTime();
scheduleNextPeriodicRequest();
}
@Override
public void onViewFailureString(int code, String message) {
isRequesting = false;
LogUtils.loge("接口请求失败(视图层):错误码= code" + code + ",错误信息= viewmsg" + message);
handleRequestFailure();
}
@Override
public void onExceptionFailure(String message) {
isRequesting = false;
LogUtils.loge("接口请求异常:异常信息= exceptionmsg" + message);
handleRequestFailure();
}
@Override
public void onServerFailure(int code, String message) {
isRequesting = false;
LogUtils.loge("接口请求失败(服务端):错误码= code" + code + ",错误信息= servermsg" + message);
// handleRequestFailure();
// 仅保留首次请求完成标记(必须保留,避免无限重复首次请求)
if (!isFirstRequestDone) {
markFirstRequestDone();
}
boolean isTimeout = code==0 || message.contains("The server is busy");
if (isTimeout) {
handler.removeMessages(WHAT_PERIODIC_REQUEST);
handler.sendEmptyMessageDelayed(WHAT_PERIODIC_REQUEST, REQUEST_INTERVAL);
} else {
//保留原逻辑
scheduleNextPeriodicRequest();
}
}
private void handleRequestFailure() {
if (!isFirstRequestDone) {
markFirstRequestDone();
}
// 失败时不保存时间
// saveLastSuccessTime();
scheduleNextPeriodicRequest();
}
@RequiresApi(api = Build.VERSION_CODES.O)
@@ -340,6 +199,9 @@ public class SystemService extends Service implements AppnetCallback, NetStateCh
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
return null;
@@ -347,26 +209,177 @@ public class SystemService extends Service implements AppnetCallback, NetStateCh
@Override
public void onDestroy() {
super.onDestroy();
isRunning = false;
isRequesting = false;
NetStateChangeReceiver.unRegisterObserver(this);
NetStateChangeReceiver.unRegisterReceiver(this);
if (handler != null) {
handler.removeCallbacksAndMessages(null);
}
if (appnetPresenter != null) {
appnetPresenter = null;
}
isRunning = false;
super.onDestroy();
}
private String formatTime(long timestamp) {
if (timestamp == 0) return "未记录 no record";
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS", Locale.getDefault());
sdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
return sdf.format(new Date(timestamp));
@Override
public void onResult(Object data) {
isRequesting=false;
List<ADInfo> adInfoList;
if(data==null){
adInfoList = new ArrayList<>();
}else {
adInfoList = (List<ADInfo>) data;
}
ADManager.getInstance().updateADInfo(adInfoList);
if(!isFirstRequestDone){
isFirstRequestDone=true;
}
hasRequestDone=true;
lastNetTriggerTime=System.currentTimeMillis();
sharedPreferences.edit().putLong(KEY_LAST_SUCCESS_TIME,lastNetTriggerTime).apply();
scheduleNextCircleAsk();
}
@Override
public void onViewFailureString(int code, String message) {
LogUtils.loge("onViewFailureString()"+message);
isRequesting=false;
if(!isFirstRequestDone){
isFirstRequestDone=true;
}else {
if(hasRequestDone){
lastNetTriggerTime=System.currentTimeMillis();
sharedPreferences.edit().putLong(KEY_LAST_SUCCESS_TIME,lastNetTriggerTime).apply();
}else {
if(lastNetTriggerTime!=0L){
handler.removeMessages(WHAT_ASK_CIRCLETASK);
handler.sendEmptyMessageDelayed(WHAT_ASK_CIRCLETASK, NET_REQUEST_INTERVAL);
return;
}
}
}
scheduleNextCircleAsk();
}
@Override
public void onExceptionFailure(String message) {
LogUtils.loge("onExceptionFailure()"+message);
isRequesting=false;
if(!isFirstRequestDone){
isFirstRequestDone=true;
}else {
if(hasRequestDone){
lastNetTriggerTime=System.currentTimeMillis();
sharedPreferences.edit().putLong(KEY_LAST_SUCCESS_TIME,lastNetTriggerTime).apply();
}else {
if(lastNetTriggerTime!=0L){
handler.removeMessages(WHAT_ASK_CIRCLETASK);
handler.sendEmptyMessageDelayed(WHAT_ASK_CIRCLETASK, NET_REQUEST_INTERVAL);
return;
}
}
}
scheduleNextCircleAsk();
}
@Override
public void onServerFailure(int code, String message) {
LogUtils.loge("onServerFailure()"+message);
isRequesting=false;
if(!isFirstRequestDone){
isFirstRequestDone=true;
}else {
if(hasRequestDone){
lastNetTriggerTime=System.currentTimeMillis();
sharedPreferences.edit().putLong(KEY_LAST_SUCCESS_TIME,lastNetTriggerTime).apply();
}else {
if(lastNetTriggerTime!=0L){
handler.removeMessages(WHAT_ASK_CIRCLETASK);
handler.sendEmptyMessageDelayed(WHAT_ASK_CIRCLETASK, NET_REQUEST_INTERVAL);
return;
}
}
}
scheduleNextCircleAsk();
}
@Override
public void onNetDisconnected() {
handler.sendEmptyMessage(WHAT_NETWORK_CHANGE);
}
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
public void onNetConnected(NetworkType networkType) {
int netWorkState = NetUtil.getNetWorkState(this);
if (netWorkState == NetUtil.NETWORK_MOBILE || netWorkState == NetUtil.NETWORK_WIFI||netWorkState==NetUtil.NETWORK_ETHERNET) {
LogUtils.loge("network is ok");
// if(!isRequesting){
// handler.removeMessages(WHAT_REQUEST_ADMSG);
// handler.sendEmptyMessage(WHAT_REQUEST_ADMSG);
// }
handler.removeMessages(WHAT_ASK_CIRCLETASK);
handler.sendEmptyMessage(WHAT_ASK_CIRCLETASK);
} else {
LogUtils.loge("network is not ok");
}
handler.sendEmptyMessage(WHAT_NETWORK_CHANGE);
}
private String createUUID(){
String timems =System.currentTimeMillis()+"";
return timems+"-"+ UUID.randomUUID().toString();
}
private void scheduleNextRequest() {
handler.removeMessages(WHAT_REQUEST_ADMSG);
if (!isFirstRequestDone) {
LogUtils.loge("first uncompletely,5mins later");
handler.sendEmptyMessageDelayed(WHAT_REQUEST_ADMSG, FIVE_MINUS_DELAY);
return;
}
long currentTime = System.currentTimeMillis();
// 从未成功过,使用检查间隔
if (lastNetTriggerTime == 0) {
LogUtils.loge("no success,1hour later try");
handler.sendEmptyMessageDelayed(WHAT_REQUEST_ADMSG, ONE_HOUR_DELAY);
return;
}
long nextRequestTime = lastNetTriggerTime + NET_REQUEST_INTERVAL;
long delay = Math.max(0, nextRequestTime - currentTime);
LogUtils.loge("delay="+delay);
handler.sendEmptyMessageDelayed(WHAT_REQUEST_ADMSG, delay);
}
private void scheduleNextCircleAsk() {
handler.removeMessages(WHAT_ASK_CIRCLETASK);
if (!isFirstRequestDone) {
LogUtils.loge("first uncompletely,5mins later try");
handler.sendEmptyMessageDelayed(WHAT_ASK_CIRCLETASK, FIVE_MINUS_DELAY);
return;
}
long currentTime = System.currentTimeMillis();
// 从未成功过,使用检查间隔
if (lastNetTriggerTime == 0) {
LogUtils.loge("no success,1hour later try");
handler.sendEmptyMessageDelayed(WHAT_ASK_CIRCLETASK, ONE_HOUR_DELAY);
return;
}
long nextRequestTime = lastNetTriggerTime + NET_REQUEST_INTERVAL;
long delay = Math.max(0, nextRequestTime - currentTime);
LogUtils.loge("delay="+delay);
handler.sendEmptyMessageDelayed(WHAT_ASK_CIRCLETASK, delay);
}
private boolean isNetworkAvailable() {
int netState = NetUtil.getNetWorkState(this);
return netState == NetUtil.NETWORK_MOBILE
|| netState == NetUtil.NETWORK_WIFI
|| netState == NetUtil.NETWORK_ETHERNET;
}
}

View File

@@ -3,6 +3,7 @@ package com.ik.mboxlauncher.ui;
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import androidx.media3.common.Player;
@@ -11,10 +12,8 @@ import com.android.monitor.DataBeeObserver;
import com.android.monitor.impl.EventFactory;
import com.android.nebulasdk.ADManager;
import com.android.util.LogUtils;
import com.ik.mboxlauncher.view.AdMultiView;
import com.ik.mboxlauncher.view.MultiView;
import com.ik.mboxlauncher.view.HomeMultiView;
import com.seraphic.ad.AdStateListener;
import java.io.File;
import java.util.List;
@@ -27,18 +26,19 @@ public class ADSWindowManager implements HomeMultiView.MultiViewListener{
private int currentADIndex=0;
private Context mContext;
private static ADSWindowManager mInstance = null;
private Handler mHandler= new Handler();
private MyHandler mHandler;
/**广告延迟播放时间*/
// private static final long DELAYED_TIME=1000*60*5;
private static final long DELAYED_TIME=1000*60*1;
private static final long DELAYED_TIME=1000*60*5;
// private static final long DELAYED_TIME=1000*60*1;
/**是否开启播放模式*/
private boolean isPlayMode=false;
//防止所有视频广告位都无法播放 进入startVideo()死循环
private boolean hasOncePlayOk;
private ADSWindowManager(Context context){
this.mContext =context;
mHandler=new MyHandler(Looper.getMainLooper());
}
public static void init(Context context){
@@ -64,7 +64,7 @@ public class ADSWindowManager implements HomeMultiView.MultiViewListener{
for (MultiView multiView:mMultiViewList){
multiView.setMultiViewListener(this);
}
if(hasOncePlayOk) hasOncePlayOk=false;
}
public void startVideo(){
isPlayMode =true;
@@ -99,9 +99,6 @@ public class ADSWindowManager implements HomeMultiView.MultiViewListener{
if(mMultiViewList!=null&&currentADIndex<mMultiViewList.size()) {
if(mMultiViewList.get(currentADIndex) instanceof HomeMultiView) {
mMultiViewList.get(currentADIndex).resetView();
} else if (mMultiViewList.get(currentADIndex) instanceof AdMultiView
&& mMultiViewList.get(currentADIndex).isAdPlaying()) {
return;
}
}
LogUtils.loge("按键事件触发停止播放wait ad play "+DELAYED_TIME+" , index is "+currentADIndex);
@@ -116,22 +113,21 @@ public class ADSWindowManager implements HomeMultiView.MultiViewListener{
if(adInfo!=null){
try {
if (adInfo.getState() == 1) {
if(multiView instanceof AdMultiView){
LogUtils.loge(" ad playing id:" + adInfo.getId());
multiView.onVideoRestart(adInfo.getLocalFilePath());
return;
}
File file = new File(adInfo.getLocalFilePath());
if (file.isFile() && file.exists()) {
LogUtils.loge(" ad playing id:" + adInfo.getId());
multiView.onVideoRestart(adInfo.getLocalFilePath());
hasOncePlayOk=true;
return;
}
}
}catch (Exception e){
e.printStackTrace();
LogUtils.loge("error file is not exists:"+adInfo.getLocalFilePath());
if(mMultiViewList.size()-1==currentADIndex&&!hasOncePlayOk){
hasOncePlayOk=false;
return;
}
}
currentADIndex++;
if (currentADIndex >= mMultiViewList.size()) { //所有文件都不存在,跳出循环,都不播放
@@ -156,7 +152,7 @@ public class ADSWindowManager implements HomeMultiView.MultiViewListener{
// );
// }
// }
if(playbackState== Player.STATE_ENDED||playbackState==Player.STATE_IDLE|| playbackState==AdStateListener.AD_ERROR) {
if(playbackState== Player.STATE_ENDED||playbackState==Player.STATE_IDLE|| playbackState==0) {
// if(playbackState== Player.STATE_ENDED){
// if(currentADIndex<mAdsInfoBeanList.size()) {
// DataBeeObserver.getInstance().recordEventMsg(
@@ -195,6 +191,10 @@ public class ADSWindowManager implements HomeMultiView.MultiViewListener{
};
private static class MyHandler extends Handler{
private MyHandler(Looper looper){
super(looper);
}
}
}

View File

@@ -10,6 +10,7 @@ import android.view.View;
import com.android.device.MediaStateChangeObserver;
import com.android.eventbaus.MessageEvent;
import com.android.util.LogUtils;
import com.android.util.SharedPreferencesUtil;
import com.ik.mboxlauncher.R;
import com.ik.mboxlauncher.ui.base.FragmentActivity;
import com.ik.mboxlauncher.ui.fragment.AppsFragment;
@@ -73,6 +74,11 @@ public class CategoryActivity extends FragmentActivity {
return null;
}
@Override
public void setFragmentsDisableRefreshDataFlag() {
FragmentManager.getInstance().pressBackUpdateAllFragmentDisableRefreshDataFlag();
}
@Override
public void popBackStackFragment() {
@@ -94,9 +100,24 @@ public class CategoryActivity extends FragmentActivity {
}
@Override
protected void onResume() {
super.onResume();
onResumeResetDisableFreshDataFlag();
}
private void onResumeResetDisableFreshDataFlag() {
if(SharedPreferencesUtil.getSharePrefrencesBoolean(this,SharedPreferencesUtil.CONFIG_RESET_DISABLE_FRESHDATA_FLAG)){
SharedPreferencesUtil.setSharePrefrencesBoolean(this,SharedPreferencesUtil.CONFIG_RESET_DISABLE_FRESHDATA_FLAG,false);
FragmentManager.getInstance().pressBackUpdateAllFragmentDisableRefreshDataFlag();
if(currentFragment!=null){
currentFragment.onResumeFragment(new MessageEvent());
}
}
}
// public void setPopWindow(int top, int bottom){
// public void setPopWindow(int top, int bottom){
// View view = this.getWindow().getDecorView();
// view.layout(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
// view.setDrawingCacheEnabled(true);
@@ -122,6 +143,7 @@ public class CategoryActivity extends FragmentActivity {
@Override
protected void onDestroy() {
FragmentManager.getInstance().destory();
super.onDestroy();
}
@@ -135,9 +157,16 @@ public class CategoryActivity extends FragmentActivity {
if(currentFragment.onKeyDown(keyCode,event)){
return true;
}else {
//currentFragment.resetDisableRefreshDataFlag();
FragmentManager.getInstance().pressBackUpdateAllFragmentDisableRefreshDataFlag();
return super.onKeyDown(keyCode,event);
}
}
if(keyCode==KeyEvent.KEYCODE_HOME){
LogUtils.loge("onKeyDown===>KEYCODE_HOME");
currentFragment.onDetach();
FragmentManager.getInstance().pressBackUpdateAllFragmentDisableRefreshDataFlag();
}
return super.onKeyDown(keyCode,event);
}

View File

@@ -2,6 +2,7 @@ package com.ik.mboxlauncher.ui;
import android.content.Context;
import com.android.util.LogUtils;
import com.ik.mboxlauncher.ui.base.BaseFragment;
import com.ik.mboxlauncher.ui.base.NotifyInterface;
import com.ik.mboxlauncher.ui.fragment.AppsFragment;
@@ -55,9 +56,10 @@ public class FragmentManager {
public static void init(Context context, NotifyInterface notifyInterface){
if(mInstance==null){
LogUtils.loge("FragmentManager init null");
mInstance = new FragmentManager(context,notifyInterface);
}
LogUtils.loge("FragmentManager init end");
}
public static FragmentManager getInstance(){
@@ -82,6 +84,62 @@ public class FragmentManager {
return null;
}
public void destory(){
// 清空所有 Fragment 引用
if(mAppsFragment != null) {
mAppsFragment = null;
}
if(mLocalFragment != null) {
mLocalFragment = null;
}
if(mMainFragment != null) {
mMainFragment = null;
}
if(mMusicFragment != null) {
mMusicFragment = null;
}
if(mRecommendFragment != null) {
mRecommendFragment = null;
}
if(mVideoFragment != null) {
mVideoFragment = null;
}
mInstance = null;
}
public String getPackageName(){
if(mContext!=null){
return mContext.getPackageName();
}
return "";
}
//按返回键 home键 等必须恢复 刷新数据处理
public void pressBackUpdateAllFragmentDisableRefreshDataFlag(){
if(mAppsFragment!=null){
mAppsFragment.resetDisableRefreshDataFlag();
}else {
LogUtils.loge("mAppsFragment==null");
}
if(mLocalFragment!=null){
mLocalFragment.resetDisableRefreshDataFlag();
}else {
LogUtils.loge("mLocalFragment==null");
}
if(mVideoFragment!=null){
mVideoFragment.resetDisableRefreshDataFlag();
}else {
LogUtils.loge("mVideoFragment==null");
}
if(mMusicFragment!=null){
mMusicFragment.resetDisableRefreshDataFlag();
}else {
LogUtils.loge("mMusicFragment==null");
}
if(mRecommendFragment!=null){
mRecommendFragment.resetDisableRefreshDataFlag();
}else {
LogUtils.loge("mRecommendFragment==null");
}
}
}

View File

@@ -26,10 +26,12 @@ import android.widget.GridView;
import android.widget.Toast;
import androidx.media3.common.Player;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
import com.android.MXQConfig;
import com.android.SharePreUtils;
import com.android.api.encrytion.UtilEncrypt;
import com.android.database.lib.AdsInfoBean;
import com.android.database.lib.AppBean;
@@ -41,9 +43,13 @@ import com.android.monitor.DataBeeObserver;
import com.android.nebulasdk.ADManager;
import com.android.nebulasdk.AppManager;
import com.android.nebulasdk.bean.FavNaviBean;
import com.android.nebulasdk.bean.UploadADBean;
import com.android.nebulasdk.presenter.DownLoadAdPresenter;
import com.android.nebulasdk.presenter.callback.AppnetCallback;
import com.android.util.GsonUtil;
import com.android.util.IntentUtil;
import com.android.util.LogUtils;
import com.android.util.NetUtil;
import com.android.util.PakageInstallUtil;
import com.ik.mboxlauncher.R;
import com.ik.mboxlauncher.ui.adapter.CustomAppAdapter;
@@ -56,10 +62,10 @@ import com.ik.mboxlauncher.ui.fragment.MusicFragment;
import com.ik.mboxlauncher.ui.fragment.RecommendFragment;
import com.ik.mboxlauncher.ui.fragment.VideoFragment;
import com.ik.mboxlauncher.view.MultiView;
import com.ik.mboxlauncher.view.AdMultiView;
import com.ik.mboxlauncher.view.CustomRecyclerView;
import com.ik.mboxlauncher.view.SplashView;
import com.ik.mboxlauncher.view.TimeTextView;
import com.ik.mboxlauncher.view.TvRecyclerView;
import java.util.ArrayList;
import java.util.HashMap;
@@ -72,9 +78,10 @@ import java.util.Map;
public class Launcher extends FragmentActivity implements SplashView.SplashAdListener {
public static final String TAG="com.ik.mboxlauncher.ui.fragment.MainFragment";
private MultiView layout_video,layout_music,layout_primevideo,layout_filemanager,layout_hbomax,layout_setting,layout_youtube,layout_recommend,layout_netflix,layout_chrome;
private AdMultiView layout_miracastreceive;
private MultiView layout_miracastreceive;
private int[] imageResIds={R.drawable.img_video,R.drawable.img_miracastreceive,R.drawable.img_youtube,R.drawable.img_recommend,R.drawable.img_music,R.drawable.img_netflix,R.drawable.img_primevideo,R.drawable.img_filemanager,R.drawable.img_chrome,R.drawable.img_hbomax,R.drawable.img_setting};
private CustomRecyclerView gv_shortcut,grid_coustom_apps;
private CustomRecyclerView gv_shortcut;
private TvRecyclerView grid_coustom_apps;
private StatusLoader mStatusLoader;
private ShortAppInfoAdapter mShortAppInfoAdapter=null;
private CustomAppAdapter mCustomAppAdapter=null;
@@ -101,6 +108,7 @@ public class Launcher extends FragmentActivity implements SplashView.SplashAdLi
/**闪屏界面是否结束*/
private boolean isSplashEnd=false;
private SplashView mSplashView;
private DownLoadAdPresenter downLoadAdPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -150,7 +158,7 @@ public class Launcher extends FragmentActivity implements SplashView.SplashAdLi
ad_full_root = findViewById(R.id.ad_full_root);
layout_miracastreceive = findViewById(R.id.layout_miracastreceive);
layout_miracastreceive.setOnClickListener(onClickListener);
layout_miracastreceive.setFullRooView(ad_full_root);
// layout_miracastreceive.setFullRooView(ad_full_root);
multiViewArray[1]=layout_miracastreceive;
layout_youtube = findViewById(R.id.layout_youtube);
layout_youtube.setOnClickListener(onClickListener);
@@ -261,31 +269,34 @@ public class Launcher extends FragmentActivity implements SplashView.SplashAdLi
gv_shortcut.setCanFocusOutHorizontal(false);
gv_shortcut.setCanFocusOutVertical(true);
StaggeredGridLayoutManager customLayoutManager = new StaggeredGridLayoutManager(9, StaggeredGridLayoutManager.VERTICAL);
GridLayoutManager customLayoutManager = new GridLayoutManager(Launcher.this,9);
grid_coustom_apps.setLayoutManager(customLayoutManager);
grid_coustom_apps.setAdapter(mCustomAppAdapter);
grid_coustom_apps.addOnScrollListener(new RecyclerView.OnScrollListener() {
int childViewPosition=0;
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
View childView = recyclerView.getFocusedChild();
childViewPosition= recyclerView.getChildAdapterPosition(childView);
LogUtils.loge("childView|childViewPosition==>"+childViewPosition);
if(childViewPosition==-1){//当焦点错乱是,强制修正找到目标位置(例如第一个可见项)
int[] rows=new int[8];
((StaggeredGridLayoutManager) recyclerView.getLayoutManager()).findFirstVisibleItemPositions(rows);
View targetView = recyclerView.findViewHolderForAdapterPosition(rows[0]).itemView;
targetView.post(() -> targetView.requestFocus());
}
}
}
});
// grid_coustom_apps.addOnScrollListener(new RecyclerView.OnScrollListener() {
// int childViewPosition=0;
// @Override
// public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
// if (newState == RecyclerView.SCROLL_STATE_IDLE) {
// View childView = recyclerView.getFocusedChild();
// childViewPosition= recyclerView.getChildAdapterPosition(childView);
// LogUtils.loge("childView|childViewPosition==>"+childViewPosition);
// if(childViewPosition==-1){//当焦点错乱是,强制修正找到目标位置(例如第一个可见项)
// int[] rows=new int[8];
// ((StaggeredGridLayoutManager) recyclerView.getLayoutManager()).findFirstVisibleItemPositions(rows);
// View targetView = recyclerView.findViewHolderForAdapterPosition(rows[0]).itemView;
// targetView.post(() -> targetView.requestFocus());
// }
//
// }
// }
// });
ADSWindowManager.init(this);
bindAdsWindowMultiView();
//内存不足时释放单列所有Fragment 打开设置按Home出现单个Fragment异常
if(FragmentManager.getInstance()!=null){
FragmentManager.getInstance().destory();
}
}
@@ -322,7 +333,12 @@ public class Launcher extends FragmentActivity implements SplashView.SplashAdLi
}
private boolean isNetworkAvailable() {
int netState = NetUtil.getNetWorkState(this);
return netState == NetUtil.NETWORK_MOBILE
|| netState == NetUtil.NETWORK_WIFI
|| netState == NetUtil.NETWORK_ETHERNET;
}
@Override
protected int getFramlayoutId() {
return R.layout.main;
@@ -504,7 +520,29 @@ private void loadShortAppList(){
}
sortAppList(filteredList);
mCustomAppAdapter.addDatas(filteredList);
grid_coustom_apps.setAdapter(mCustomAppAdapter);
// grid_coustom_apps.setAdapter(mCustomAppAdapter);
// if(filteredList.size()>0){
// if(Build.VERSION.SDK_INT<29){
// grid_coustom_apps.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
// @Override
// public void onGlobalLayout() {
// grid_coustom_apps.getViewTreeObserver().removeOnGlobalLayoutListener(this);
// grid_coustom_apps.scrollToPosition(0);
// grid_coustom_apps.post(()->{
// int[] rows = new int[9];
// ((StaggeredGridLayoutManager) grid_coustom_apps.getLayoutManager()).findFirstVisibleItemPositions(rows);
// View targetView = grid_coustom_apps.findViewHolderForAdapterPosition(rows[0]).itemView;
// if(targetView!=null){
// targetView.post(() -> targetView.requestFocus());
// }
// });
//
// }
// });
// }else {
// grid_coustom_apps.setSelectedPosition(0);
// }
// }
}
});
@@ -631,6 +669,45 @@ public boolean onGenericMotionEvent(MotionEvent event) {
LogUtils.loge("onMessageEvent===>"+event.action);
if(MessageEvent.ACTION_UPADATE_DATA_SOURCE.equals(event.action)) {
ADManager.getInstance().updateDownloadTaskBeanTable();
if(isNetworkAvailable()){
ArrayList<UploadADBean.RecordsBean> uploadAds = ADManager.getInstance().getUploadAds();
if(uploadAds.size()>0){
if(downLoadAdPresenter==null){
downLoadAdPresenter = new DownLoadAdPresenter(new AppnetCallback() {
@Override
public void onResult(Object data) {
LogUtils.loge("DownLoadAdPresenter result="+String.valueOf(data));
SharePreUtils.savePreference();
}
@Override
public void onViewFailureString(int code, String message) {
LogUtils.loge("DownLoadAdPresenter onViewFailureString="+message);
SharePreUtils.resetDataList();
}
@Override
public void onExceptionFailure(String message) {
LogUtils.loge("DownLoadAdPresenter onExceptionFailure="+message);
SharePreUtils.resetDataList();
}
@Override
public void onServerFailure(int code, String message) {
LogUtils.loge("DownLoadAdPresenter onServerFailure="+message+"code="+code);
SharePreUtils.resetDataList();
}
});
}
try {
downLoadAdPresenter.postDownLoadAds(Launcher.this,uploadAds);
} catch (Exception e) {
LogUtils.loge("downLoadAdPresenter net request error"+e.getMessage());
SharePreUtils.resetDataList();
//throw new RuntimeException(e);
}
}
}
handler.removeCallbacks(runnable);
handler.postDelayed(runnable,1000*5);
@@ -638,6 +715,7 @@ public boolean onGenericMotionEvent(MotionEvent event) {
displayStatus();
}else if(MessageEvent.ACTION_UPADATE_APPS_SOURCE.equals(event.action)){
if(currentFragment!=null&&currentFragment instanceof AppsFragment){
LogUtils.loge("Launcher onMessageEvent===>"+event.action);
currentFragment.onResumeFragment(event);
}
@@ -645,6 +723,11 @@ public boolean onGenericMotionEvent(MotionEvent event) {
}
@Override
public void setFragmentsDisableRefreshDataFlag() {
}
private void displayStatus() {
runOnUiThread(new Runnable() {
@@ -829,12 +912,14 @@ public boolean onGenericMotionEvent(MotionEvent event) {
@Override
public void onAnimationStart(Animation animation) {
coustom_view.setTranslationZ(0);
grid_coustom_apps.disScrollFocus();
loadShortAppList();
coustom_view.clearFocus();
}
@Override
public void onAnimationEnd(Animation animation) {
LogUtils.loge("dismissCustomApp onAnimationEnd()");
coustom_view.setVisibility(View.GONE);
gv_shortcut.requestFocus();
@@ -949,7 +1034,10 @@ public boolean onGenericMotionEvent(MotionEvent event) {
if(isSplashEnd) {
ADSWindowManager.getInstance().startVideo();
}
ADManager.getInstance().clearTaskInteruptQueueAndRestart();
if(isNetworkAvailable()){
ADManager.getInstance().clearTaskInteruptQueueAndRestart();
ADManager.getInstance().clearApkFileByPowerDown();
}
setImageViewData();
loadShortAppList();
}

View File

@@ -5,6 +5,7 @@ import android.content.Context;
import android.content.Intent;
import android.util.Log;
import com.android.SharePreUtils;
import com.android.monitor.DataBeeObserver;
import com.android.nebulasdk.ADManager;
import com.android.nebulasdk.AppManager;
@@ -12,8 +13,6 @@ import com.android.util.LogManager;
import com.android.util.LogUtils;
import com.google.android.gms.ads.identifier.AdvertisingIdClient;
import com.ik.mboxlauncher.SystemService;
import com.seraphic.ad.AdConfig;
import com.seraphic.ad.AdManager;
import java.io.PrintWriter;
import java.io.StringWriter;
@@ -27,16 +26,7 @@ public class MyApplication extends Application {
DataBeeObserver.init(getApplicationContext());
AppManager.init(getApplicationContext());
ADManager.init(getApplicationContext());
AdConfig config = new AdConfig.Builder()
.isDebug(false)//是否开始 debug 模式开启会打印更多log供开发调试
.productName("aike")//正式发版时使用正式的PN
.productTag("launcher")//正式发版时使用正式的PT
// .productName("test")//仅限开发测试使用
// .productTag("test")//仅限开发测试使用
.adId(getAdId(this))
.build();
AdManager.getInstance().init(MyApplication.this, config);
SharePreUtils.getInstance(getApplicationContext());
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread thread, Throwable throwable) {

View File

@@ -1,6 +1,8 @@
package com.ik.mboxlauncher.ui;
import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -18,6 +20,7 @@ import com.android.nebulasdk.AppManager;
import com.android.util.EventBusType;
import com.android.util.LogManager;
import com.android.util.LogUtils;
import com.android.util.SharedPreferencesUtil;
import com.ik.mboxlauncher.SystemService;
import java.util.List;
@@ -102,10 +105,39 @@ public class StartupBroadcast extends BroadcastReceiver {
break;
}
EventBusUtils.postMsg(messageEvent);
if(!isTopAppPackage(context)){
LogUtils.loge("three app activity on top of layer");
boolean sharePrefrencesBoolean = SharedPreferencesUtil.getSharePrefrencesBoolean(context, SharedPreferencesUtil.CONFIG_RESET_DISABLE_FRESHDATA_FLAG);
if(!sharePrefrencesBoolean){
SharedPreferencesUtil.setSharePrefrencesBoolean(context,SharedPreferencesUtil.CONFIG_RESET_DISABLE_FRESHDATA_FLAG,true);
}
}
}
}
}
/**
* 获取顶层应用的包名
* @param context 上下文
* @return 顶层应用包名,如果获取失败返回 null
*/
public static boolean isTopAppPackage(Context context) {
try {
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
if (activityManager != null) {
List<ActivityManager.RunningTaskInfo> runningTasks = activityManager.getRunningTasks(1);
if (runningTasks != null && !runningTasks.isEmpty()) {
ActivityManager.RunningTaskInfo taskInfo = runningTasks.get(0);
ComponentName topActivity = taskInfo.topActivity;
LogUtils.loge("topActivity packagename: " + topActivity.getPackageName());
return topActivity.getPackageName().equalsIgnoreCase(context.getPackageName());
}
}
} catch (Exception e) {
LogUtils.loge("Error getting top app package name: " + e.getMessage());
e.printStackTrace();
}
return true;
}
/**
* 获取指定包名应用的Launcher Activity信息

View File

@@ -112,7 +112,7 @@ public class CustomAppAdapter extends RecyclerView.Adapter<CustomAppAdapter.View
if(hasFocus){
viewHolder.item_name.setSelected(true);
viewHolder.itemView.setBackgroundResource(R.drawable.app_item_select);
viewHolder.itemView.requestFocus();
// viewHolder.itemView.requestFocus();
scaleView(viewHolder.itemView, 1.07f);
// viewHolder.itemView.post(() -> viewHolder.itemView.requestFocus());
}else {

View File

@@ -27,6 +27,7 @@ import android.view.View;
import android.view.ViewGroup;
import com.android.eventbaus.MessageEvent;
import com.android.util.LogUtils;
/** A fragment which slides when it is entering/exiting. */
public abstract class BaseFragment extends Fragment {
@@ -38,6 +39,8 @@ public abstract class BaseFragment extends Fragment {
protected static final int MODEL_NORMAL = 0x00;
protected static final int MODEL_CUSTOM = 0x01;
protected int cuttentModel=MODEL_NORMAL;
private View view;
public NotifyInterface getNotifyInterface() {
return notifyInterface;
}
@@ -110,7 +113,12 @@ public abstract class BaseFragment extends Fragment {
@Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(getLayoutResourceId(), container, false);
if(view==null){
view = inflater.inflate(getLayoutResourceId(), container, false);
LogUtils.loge("onCreateView()==>view=null"+getClass().getSimpleName());
}else {
LogUtils.loge("onCreateView()==>view!=null"+getClass().getSimpleName());
}
initView( view);
handler.post(inidataRunnable);
return view;
@@ -152,7 +160,7 @@ public abstract class BaseFragment extends Fragment {
protected abstract void initView(View view);
protected abstract void initData();
public abstract void resetDisableRefreshDataFlag();
@Override
public void setEnterTransition(Transition transition) {
super.setEnterTransition(transition);

View File

@@ -23,6 +23,7 @@ import android.app.FragmentTransaction;
import android.os.Bundle;
import com.android.eventbaus.MessageEvent;
import com.android.util.LogUtils;
/**
@@ -42,16 +43,19 @@ public abstract class FragmentActivity extends BaseActivity implements NotifyInt
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getlayoutId());
if (savedInstanceState == null) {
LogUtils.loge("savedInstanceState===>null");
showInitialFragment();
} else {
mShowInitialFragment = false;
LogUtils.loge("savedInstanceState===>not null");
}
mFragmentManager = getFragmentManager();
initView();
initData();
// Show initial fragment only when the saved state is not restored, because the last
// fragment is restored if savesInstanceState is not null.
if (savedInstanceState == null) {
showInitialFragment();
} else {
mShowInitialFragment = false;
}
}
@@ -95,10 +99,11 @@ public abstract class FragmentActivity extends BaseActivity implements NotifyInt
protected FragmentTransaction showFragment(Fragment fragment, boolean addToBackStack) {
currentFragment = (BaseFragment) fragment;
currentFragment.setNotifyInterface(this);
LogUtils.loge("showFragment===>mFragmentManager1");
if (mFragmentManager == null) {
return null;
}
LogUtils.loge("showFragment===>mFragmentManager2");
FragmentTransaction ft = mFragmentManager.beginTransaction();
// ft.setCustomAnimations(
// R.anim.slide_left_in,
@@ -128,6 +133,7 @@ public abstract class FragmentActivity extends BaseActivity implements NotifyInt
}
if (!fragment.isAdded()) {
ft.replace(getFramlayoutId(), fragment, tag).commit();
LogUtils.loge("showFragment===>replace");
} else {
ft.show(fragment).commit();
}
@@ -139,7 +145,9 @@ public abstract class FragmentActivity extends BaseActivity implements NotifyInt
@Override
public void onMessageEvent(MessageEvent event) {
super.onMessageEvent(event);
// if(MessageEvent.ACTION_UPADATE_DATA_SOURCE.equals(event.action)){
if(MessageEvent.ACTION_UPADATE_APPS_SOURCE.equals(event.action)){
setFragmentsDisableRefreshDataFlag();
}
// 更新UI
if(currentFragment!=null){
currentFragment.onResumeFragment(event);
@@ -147,7 +155,7 @@ public abstract class FragmentActivity extends BaseActivity implements NotifyInt
// }
}
public abstract void setFragmentsDisableRefreshDataFlag();
protected boolean isShowDisplay() {
int count = mFragmentManager.getBackStackEntryCount();
if (count > 0) {

View File

@@ -1,11 +1,14 @@
package com.ik.mboxlauncher.ui.fragment;
import android.content.Intent;
import android.os.Build;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.Toast;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.android.database.lib.AppBean;
import com.android.eventbaus.MessageEvent;
@@ -13,6 +16,7 @@ import com.android.nebulasdk.AppManager;
import com.android.util.IntentUtil;
import com.android.util.LogUtils;
import com.ik.mboxlauncher.R;
import com.ik.mboxlauncher.ui.FragmentManager;
import com.ik.mboxlauncher.ui.adapter.MyAppInfoAdapter;
import java.util.ArrayList;
@@ -21,6 +25,7 @@ import java.util.List;
public class AppsFragment extends CategoryFragment {
public static final String ACTION="com.ik.mboxlauncher.ui.fragment.AppsFragment";
private MyAppInfoAdapter mMyAppInfoAdapter = null;
private final int SCROLLPOSITION=17;
@Override
protected void initView(View view) {
super.initView(view);
@@ -56,10 +61,25 @@ public class AppsFragment extends CategoryFragment {
LogUtils.loge("hasFocus===>"+hasFocus);
}
});
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
gv_category_apps.setOnScrollChangeListener(new View.OnScrollChangeListener() {
@Override
public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
lastFocusPositon=gv_category_apps.getmCurrentFocusPosition();
LogUtils.loge("onScrollChange()AppsFragment pos="+lastFocusPositon);
}
});
}
// h3翻页后gv_category_apps失去焦点处理
if(Build.VERSION.SDK_INT<29&&disableFreshData){
gv_category_apps.requestFocus();
}
LogUtils.loge("AppsFragment initView==>"+disableFreshData);
}
@Override
protected void initData() {
LogUtils.loge("initData===>AppsFragment");
loadAppInfoByCategory(AppManager.CATEGORY_MYAPPS);
}
@@ -68,11 +88,13 @@ public class AppsFragment extends CategoryFragment {
runUiThread(new Runnable() {
@Override
public void run() {
if(disableFreshData) return;
if (data != null) {
disableFreshData=true;
List<AppBean> appBeanList = (List<AppBean>) data;
// 创建过滤后的列表
List<AppBean> filteredList = new ArrayList<>();
String selfPackageName = getActivity().getPackageName();
String selfPackageName = FragmentManager.getInstance().getPackageName();;
for (AppBean appBean : appBeanList) {
// 跳过自身应用
@@ -87,6 +109,21 @@ public class AppsFragment extends CategoryFragment {
// 使用过滤后的列表更新适配器
mMyAppInfoAdapter.addDatas(filteredList);
}
gv_category_apps.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
gv_category_apps.getViewTreeObserver().removeOnGlobalLayoutListener(this);
gv_category_apps.scrollToPosition(0);
gv_category_apps.post(()->{
int firstVisibleItemPosition = ((GridLayoutManager) gv_category_apps.getLayoutManager()).findFirstVisibleItemPosition();
RecyclerView.ViewHolder holderview = gv_category_apps.findViewHolderForAdapterPosition(firstVisibleItemPosition);
if(holderview !=null){
View targetView = holderview.itemView;
targetView.post(() -> targetView.requestFocus());
}
});
}
});
// if(data!=null){
// List<AppBean> appBeanList = (List<AppBean>) data;
// mMyAppInfoAdapter.addDatas(appBeanList);
@@ -100,8 +137,9 @@ public class AppsFragment extends CategoryFragment {
@Override
public void onResumeFragment(MessageEvent event) {
super.onResumeFragment(event);
disableFreshData=false;
loadAppInfoByCategory(AppManager.CATEGORY_MYAPPS);//重新加载数据
LogUtils.loge("onResumeFragment===>AppsFragment");
}
@@ -125,11 +163,17 @@ public class AppsFragment extends CategoryFragment {
@Override
protected void toNextPage() {
doneEvents(new MessageEvent(MusicFragment.ACTION));
if(lastFocusPositon>SCROLLPOSITION){
disableFreshData=false;
}
}
@Override
protected void toPreviousPage() {
doneEvents(new MessageEvent(RecommendFragment.ACTION));
if(lastFocusPositon>SCROLLPOSITION){
disableFreshData=false;
}
}
}

View File

@@ -3,10 +3,12 @@ package com.ik.mboxlauncher.ui.fragment;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.animation.TranslateAnimation;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
@@ -18,11 +20,13 @@ import com.android.nebulasdk.presenter.callback.AppnetCallback;
import com.android.util.GsonUtil;
import com.android.util.LogUtils;
import com.ik.mboxlauncher.R;
import com.ik.mboxlauncher.ui.Launcher;
import com.ik.mboxlauncher.ui.adapter.CustomAppAdapter;
import com.ik.mboxlauncher.ui.adapter.VideoAppAdapter;
import com.ik.mboxlauncher.ui.adapter.MyAppInfoAdapter;
import com.ik.mboxlauncher.ui.base.BaseFragment;
import com.ik.mboxlauncher.view.CustomRecyclerViewer;
import com.ik.mboxlauncher.view.TvRecyclerView;
import java.util.HashMap;
import java.util.List;
@@ -32,7 +36,7 @@ public abstract class CategoryFragment extends BaseFragment implements AppnetCal
private CategoryAppPresenter mCategoryAppPresenter =null;
// private MyAppInfoAdapter mMyAppInfoAdapter = null;
protected RecyclerView grid_coustom_apps;
protected TvRecyclerView grid_coustom_apps;
protected CustomRecyclerViewer gv_category_apps;
protected ImageView img_logo,img_tab_video, img_tab_recommend, img_tab_apps, img_tab_music, img_tab_local;
protected TextView tv_title;
@@ -40,7 +44,8 @@ public abstract class CategoryFragment extends BaseFragment implements AppnetCal
protected CustomAppAdapter mCustomAppAdapter=null;
protected int mCategory=-1;
protected boolean disableFreshData;//禁止再次刷新数据
protected int lastFocusPositon;//记录焦点位置
protected static final int VIDEO_CATEGORY=0;
protected static final int RECOMMEND_CATEGORY=1;
@@ -48,6 +53,8 @@ public abstract class CategoryFragment extends BaseFragment implements AppnetCal
protected static final int LOCAL_CATEGORY=3;
protected static final int APPS_CATEGORY=4;
protected Map<String,String> collectAppMap=new HashMap();
private Runnable customFocusRunnable;
@Override
protected int getLayoutResourceId() {
return R.layout.layout_category_app;
@@ -100,28 +107,28 @@ public abstract class CategoryFragment extends BaseFragment implements AppnetCal
}
});
}
StaggeredGridLayoutManager customLayoutManager = new StaggeredGridLayoutManager(8, StaggeredGridLayoutManager.VERTICAL);
GridLayoutManager customLayoutManager = new GridLayoutManager(getActivity(),8);
grid_coustom_apps.setLayoutManager(customLayoutManager);
grid_coustom_apps.setAdapter(mCustomAppAdapter);
grid_coustom_apps.addOnScrollListener(new RecyclerView.OnScrollListener() {
int childViewPosition=0;
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
// 找到目标位置(例如第一个可见项)
View childView = recyclerView.getFocusedChild();
childViewPosition= recyclerView.getChildAdapterPosition(childView);
LogUtils.loge("childView|childViewPosition==>"+childViewPosition);
if(childViewPosition==-1){ //当焦点错乱是,强制修正找到目标位置(例如第一个可见项)
int[] rows=new int[8];
((StaggeredGridLayoutManager) recyclerView.getLayoutManager()).findFirstVisibleItemPositions(rows);
View targetView = recyclerView.findViewHolderForAdapterPosition(rows[0]).itemView;
targetView.post(() -> targetView.requestFocus());
}
}
}
});
// grid_coustom_apps.addOnScrollListener(new RecyclerView.OnScrollListener() {
// int childViewPosition=0;
// @Override
// public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
// if (newState == RecyclerView.SCROLL_STATE_IDLE) {
// // 找到目标位置(例如第一个可见项)
// View childView = recyclerView.getFocusedChild();
// childViewPosition= recyclerView.getChildAdapterPosition(childView);
// LogUtils.loge("childView|childViewPosition==>"+childViewPosition);
// if(childViewPosition==-1){ //当焦点错乱是,强制修正找到目标位置(例如第一个可见项)
// int[] rows=new int[8];
// ((StaggeredGridLayoutManager) recyclerView.getLayoutManager()).findFirstVisibleItemPositions(rows);
// View targetView = recyclerView.findViewHolderForAdapterPosition(rows[0]).itemView;
// targetView.post(() -> targetView.requestFocus());
// }
//
// }
// }
// });
loadCustomAppList();
gv_category_apps.setmFocusOnBoundaryListener(new CustomRecyclerViewer.FocusOnBoundaryListener() {
@@ -146,7 +153,10 @@ public abstract class CategoryFragment extends BaseFragment implements AppnetCal
mCategoryAppPresenter.loadAppByCategory(category);
}
@Override
public void resetDisableRefreshDataFlag() {
disableFreshData=false;
}
protected abstract void toNextPage();
@@ -231,19 +241,24 @@ public abstract class CategoryFragment extends BaseFragment implements AppnetCal
translateAnimation.setDuration(300);
translateAnimation.setFillAfter(true);
content_view.startAnimation(translateAnimation);
handler.postDelayed(new Runnable() {
@Override
public void run() {
coustom_view.requestFocus();
}
},800);
if(customFocusRunnable==null){
customFocusRunnable = new Runnable() {
@Override
public void run() {
coustom_view.requestFocus();
}
};
}
handler.postDelayed(customFocusRunnable,800);
}
private void dismissCustomApp(){
handler.removeCallbacks(customFocusRunnable);
cuttentModel = MODEL_NORMAL;
disableFreshData=false;
LogUtils.loge("coustom_view.getHeight():"+coustom_view.getLayoutParams().height);
TranslateAnimation exitTransAnim = new TranslateAnimation(0.0f, 0.0f, 0,(float)(0 - coustom_view.getLayoutParams().height));
@@ -286,7 +301,21 @@ public abstract class CategoryFragment extends BaseFragment implements AppnetCal
LogUtils.loge("data size is "+shortcutInfoBeanList.size());
mCustomAppAdapter.addDatas(shortcutInfoBeanList);
grid_coustom_apps.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
grid_coustom_apps.getViewTreeObserver().removeOnGlobalLayoutListener(this);
grid_coustom_apps.scrollToPosition(0);
grid_coustom_apps.post(()->{
int firstVisibleItemPosition = ((GridLayoutManager) grid_coustom_apps.getLayoutManager()).findFirstVisibleItemPosition();
RecyclerView.ViewHolder holderview = grid_coustom_apps.findViewHolderForAdapterPosition(firstVisibleItemPosition);
if(holderview !=null){
View targetView = holderview.itemView;
targetView.post(() -> targetView.requestFocus());
}
});
}
});
}else {
LogUtils.loge("no data");
}

View File

@@ -1,11 +1,14 @@
package com.ik.mboxlauncher.ui.fragment;
import android.content.Intent;
import android.os.Build;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.Toast;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.android.database.lib.AppBean;
import com.android.database.lib.LocalAppBean;
@@ -23,6 +26,8 @@ public class LocalFragment extends CategoryFragment {
public static final String ACTION="com.ik.mboxlauncher.ui.fragment.LocalFragment";
private LocalAppAdapter mLocalAppAdapter =null;
private final int SCROLLPOSITION=17;
@Override
protected void initView(View view) {
mCategory=AppManager.CATEGORY_LOCAL;
@@ -51,6 +56,20 @@ public class LocalFragment extends CategoryFragment {
GridLayoutManager customLayoutManager = new GridLayoutManager(view.getContext(), 6);
gv_category_apps.setLayoutManager(customLayoutManager);
gv_category_apps.setAdapter(mLocalAppAdapter);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
gv_category_apps.setOnScrollChangeListener(new View.OnScrollChangeListener() {
@Override
public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
lastFocusPositon=gv_category_apps.getmCurrentFocusPosition();
LogUtils.loge("onScrollChange()LocalFragment pos="+lastFocusPositon);
}
});
}
// h3翻页后gv_category_apps失去焦点处理
if(Build.VERSION.SDK_INT<29&&disableFreshData){
gv_category_apps.requestFocus();
}
LogUtils.loge("LocalFragment initView==>"+disableFreshData);
}
@@ -58,7 +77,9 @@ public class LocalFragment extends CategoryFragment {
@Override
public void onResult(Object data) {
if(disableFreshData) return;
if(data!=null){
disableFreshData=true;//禁用再次刷新数据
collectAppMap.clear();
List<LocalAppBean> appBeanList = (List<LocalAppBean>) data;
@@ -69,6 +90,23 @@ public class LocalFragment extends CategoryFragment {
appBeanList.add(new LocalAppBean());
mLocalAppAdapter.addDatas(appBeanList);
}
if(!isShowCustomApp()){
gv_category_apps.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
gv_category_apps.getViewTreeObserver().removeOnGlobalLayoutListener(this);
gv_category_apps.scrollToPosition(0);
gv_category_apps.post(()->{
int firstVisibleItemPosition = ((GridLayoutManager) gv_category_apps.getLayoutManager()).findFirstVisibleItemPosition();
RecyclerView.ViewHolder holderview = gv_category_apps.findViewHolderForAdapterPosition(firstVisibleItemPosition);
if(holderview !=null){
View targetView = holderview.itemView;
targetView.post(() -> targetView.requestFocus());
}
});
}
});
}
super.onResult(data);
}
@@ -108,13 +146,16 @@ public class LocalFragment extends CategoryFragment {
@Override
protected void toPreviousPage() {
doneEvents(new MessageEvent(MusicFragment.ACTION));
if(lastFocusPositon>SCROLLPOSITION){
disableFreshData=false;
}
}
@Override
public void onResumeFragment(MessageEvent event) {
super.onResumeFragment(event);
disableFreshData=false;
loadAppInfoByCategory(AppManager.CATEGORY_LOCAL);//重新加载数据
}

View File

@@ -135,9 +135,10 @@ public class MainFragment extends BaseFragment implements ShortAppInfoAdapter.On
ADSWindowManager.getInstance().startVideo();
}
@Override
public void resetDisableRefreshDataFlag() {
}
@SuppressLint("UnsafeOptInUsageError")

View File

@@ -1,11 +1,14 @@
package com.ik.mboxlauncher.ui.fragment;
import android.content.Intent;
import android.os.Build;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.Toast;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.android.database.lib.AppBean;
import com.android.database.lib.MusicAppBean;
@@ -23,6 +26,7 @@ public class MusicFragment extends CategoryFragment {
public static final String ACTION="com.ik.mboxlauncher.ui.fragment.MusicFragment";
private MusicAppAdapter mMusicAppAdapter;
private final int SCROLLPOSITION=17;
@Override
protected void initView(View view) {
super.initView(view);
@@ -51,6 +55,20 @@ public class MusicFragment extends CategoryFragment {
GridLayoutManager customLayoutManager = new GridLayoutManager(view.getContext(), 6);
gv_category_apps.setLayoutManager(customLayoutManager);
gv_category_apps.setAdapter(mMusicAppAdapter);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
gv_category_apps.setOnScrollChangeListener(new View.OnScrollChangeListener() {
@Override
public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
lastFocusPositon=gv_category_apps.getmCurrentFocusPosition();
LogUtils.loge("onScrollChange()MusicFragment pos="+lastFocusPositon);
}
});
}
// h3翻页后gv_category_apps失去焦点处理
if(Build.VERSION.SDK_INT<29&&disableFreshData){
gv_category_apps.requestFocus();
}
LogUtils.loge("MusicFragment initView==>"+disableFreshData);
}
@@ -67,6 +85,23 @@ public class MusicFragment extends CategoryFragment {
appBeanList.add(new MusicAppBean());
mMusicAppAdapter.addDatas(appBeanList);
}
if(!isShowCustomApp()){
gv_category_apps.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
gv_category_apps.getViewTreeObserver().removeOnGlobalLayoutListener(this);
gv_category_apps.scrollToPosition(0);
gv_category_apps.post(()->{
int firstVisibleItemPosition = ((GridLayoutManager) gv_category_apps.getLayoutManager()).findFirstVisibleItemPosition();
RecyclerView.ViewHolder holderview = gv_category_apps.findViewHolderForAdapterPosition(firstVisibleItemPosition);
if(holderview !=null){
View targetView = holderview.itemView;
targetView.post(() -> targetView.requestFocus());
}
});
}
});
}
super.onResult(data);
}
@@ -108,18 +143,24 @@ public class MusicFragment extends CategoryFragment {
@Override
protected void toNextPage() {
doneEvents(new MessageEvent(LocalFragment.ACTION));
if(lastFocusPositon>SCROLLPOSITION){
disableFreshData=false;
}
}
@Override
protected void toPreviousPage() {
doneEvents(new MessageEvent(AppsFragment.ACTION));
if(lastFocusPositon>SCROLLPOSITION){
disableFreshData=false;
}
}
@Override
public void onResumeFragment(MessageEvent event) {
super.onResumeFragment(event);
disableFreshData=false;
loadAppInfoByCategory(AppManager.CATEGORY_MUSIC);//重新加载数据
}

View File

@@ -1,16 +1,20 @@
package com.ik.mboxlauncher.ui.fragment;
import android.content.Intent;
import android.os.Build;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.Toast;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.android.database.lib.AppBean;
import com.android.database.lib.RecommendAppBean;
import com.android.eventbaus.MessageEvent;
import com.android.nebulasdk.AppManager;
import com.android.util.GsonUtil;
import com.android.util.IntentUtil;
import com.android.util.LogUtils;
import com.ik.mboxlauncher.R;
@@ -22,6 +26,7 @@ public class RecommendFragment extends CategoryFragment {
public static final String ACTION="com.ik.mboxlauncher.ui.fragment.RecommendFragment";
private RecommendAppAdapter mRecommendAppAdapter;
private final int SCROLLPOSITION=17;
@Override
protected void initView(View view) {
mCategory=AppManager.CATEGORY_RECOMMEND;
@@ -51,12 +56,28 @@ public class RecommendFragment extends CategoryFragment {
GridLayoutManager customLayoutManager = new GridLayoutManager(view.getContext(), 6);
gv_category_apps.setLayoutManager(customLayoutManager);
gv_category_apps.setAdapter(mRecommendAppAdapter);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
gv_category_apps.setOnScrollChangeListener(new View.OnScrollChangeListener() {
@Override
public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
lastFocusPositon=gv_category_apps.getmCurrentFocusPosition();
LogUtils.loge("onScrollChange()RecommendFragment pos="+lastFocusPositon);
}
});
}
// h3翻页后gv_category_apps失去焦点处理
if(Build.VERSION.SDK_INT<29&&disableFreshData){
gv_category_apps.requestFocus();
}
LogUtils.loge("RecommendFragment initView==>"+disableFreshData);
}
@Override
public void onResult(Object data) {
if(disableFreshData) return;
if(data!=null){
disableFreshData=true;
collectAppMap.clear();
List<RecommendAppBean> appBeanList = (List<RecommendAppBean>) data;
for (RecommendAppBean recommendAppBean:appBeanList){
@@ -66,6 +87,24 @@ public class RecommendFragment extends CategoryFragment {
appBeanList.add(new RecommendAppBean());
mRecommendAppAdapter.addDatas(appBeanList);
}
if(!isShowCustomApp()){
gv_category_apps.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
gv_category_apps.getViewTreeObserver().removeOnGlobalLayoutListener(this);
LogUtils.loge("onGlobalLayout===>RecommendFragment"+ GsonUtil.GsonString(data));
gv_category_apps.scrollToPosition(0);
gv_category_apps.post(()->{
int firstVisibleItemPosition = ((GridLayoutManager) gv_category_apps.getLayoutManager()).findFirstVisibleItemPosition();
RecyclerView.ViewHolder holderview = gv_category_apps.findViewHolderForAdapterPosition(firstVisibleItemPosition);
if(holderview !=null){
View targetView = holderview.itemView;
targetView.post(() -> targetView.requestFocus());
}
});
}
});
}
super.onResult(data);
}
@@ -105,17 +144,24 @@ public class RecommendFragment extends CategoryFragment {
@Override
protected void toNextPage() {
doneEvents(new MessageEvent(AppsFragment.ACTION));
if(lastFocusPositon>SCROLLPOSITION){
disableFreshData=false;
}
}
@Override
protected void toPreviousPage() {
doneEvents(new MessageEvent(VideoFragment.ACTION));
if(lastFocusPositon>SCROLLPOSITION){
disableFreshData=false;
}
}
@Override
public void onResumeFragment(MessageEvent event) {
super.onResumeFragment(event);
disableFreshData=false;
loadAppInfoByCategory(AppManager.CATEGORY_RECOMMEND);//重新加载数据
}
}

View File

@@ -1,11 +1,14 @@
package com.ik.mboxlauncher.ui.fragment;
import android.content.Intent;
import android.os.Build;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.Toast;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.android.database.lib.AppBean;
import com.android.database.lib.VideoAppBean;
@@ -22,6 +25,7 @@ public class VideoFragment extends CategoryFragment {
public static final String ACTION="com.ik.mboxlauncher.ui.fragment.VideoFragment";
private VideoAppAdapter mVideoAppAdapter = null;
private final int SCROLLPOSITION=17;
@Override
protected void initView(View view) {
mCategory=AppManager.CATEGORY_VIDEO;
@@ -51,12 +55,28 @@ public class VideoFragment extends CategoryFragment {
GridLayoutManager layoutManager = new GridLayoutManager(view.getContext(), 6);
gv_category_apps.setLayoutManager(layoutManager);
gv_category_apps.setAdapter(mVideoAppAdapter);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
gv_category_apps.setOnScrollChangeListener(new View.OnScrollChangeListener() {
@Override
public void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
lastFocusPositon=gv_category_apps.getmCurrentFocusPosition();
LogUtils.loge("onScrollChange()VideoFragment pos="+lastFocusPositon);
}
});
}
// h3翻页后gv_category_apps失去焦点处理
if(Build.VERSION.SDK_INT<29&&disableFreshData){
gv_category_apps.requestFocus();
}
LogUtils.loge("VideoFragment initView==>"+disableFreshData);
}
@Override
public void onResult(Object data) {
if(disableFreshData) return;
if(data!=null){
disableFreshData=true;
collectAppMap.clear();
List<VideoAppBean> appBeanList = (List<VideoAppBean>) data;
for (VideoAppBean videoAppBean:appBeanList){
@@ -67,6 +87,24 @@ public class VideoFragment extends CategoryFragment {
appBeanList.add(new VideoAppBean());
mVideoAppAdapter.addDatas(appBeanList);
}
if(!isShowCustomApp()){
gv_category_apps.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
gv_category_apps.getViewTreeObserver().removeOnGlobalLayoutListener(this);
gv_category_apps.scrollToPosition(0);
gv_category_apps.post(()->{
int firstVisibleItemPosition = ((GridLayoutManager) gv_category_apps.getLayoutManager()).findFirstVisibleItemPosition();
RecyclerView.ViewHolder holderview = gv_category_apps.findViewHolderForAdapterPosition(firstVisibleItemPosition);
if(holderview !=null){
View targetView = holderview.itemView;
targetView.post(() -> targetView.requestFocus());
}
});
}
});
}
super.onResult(data);
}
@@ -92,6 +130,7 @@ public class VideoFragment extends CategoryFragment {
@Override
protected void initData() {
LogUtils.loge("VideoFragment===>initData()");
loadAppInfoByCategory(AppManager.CATEGORY_VIDEO);
}
@@ -108,6 +147,9 @@ public class VideoFragment extends CategoryFragment {
@Override
protected void toNextPage() {
doneEvents(new MessageEvent(RecommendFragment.ACTION));
if(lastFocusPositon>SCROLLPOSITION){
disableFreshData=false;
}
}
@Override
@@ -119,6 +161,8 @@ public class VideoFragment extends CategoryFragment {
@Override
public void onResumeFragment(MessageEvent event) {
super.onResumeFragment(event);
LogUtils.loge("VideoFragment===>onResumeFragment()");
disableFreshData=false;
loadAppInfoByCategory(AppManager.CATEGORY_VIDEO);//重新加载数据
}
}

View File

@@ -1,484 +0,0 @@
package com.ik.mboxlauncher.view;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Outline;
import android.graphics.Rect;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
import android.view.animation.Animation;
import android.view.animation.ScaleAnimation;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.media3.common.Player;
import com.android.util.LogUtils;
import com.bumptech.glide.Glide;
import com.ik.mboxlauncher.R;
import com.seraphic.ad.AdPlayManager;
import com.seraphic.ad.AdStateListener;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class AdMultiView extends MultiView {
private Context mContext;
private View mView;
private ImageView img_view;
private TextView tx_view;
private long animDuration = 50;
private View mMultiInsideLayout;
private ViewGroup mAdRootView;
private AdPlayManager mAdPlayManager;
private ViewGroup mFullRootView;
private boolean isFullAdShow;
private int mWidth = 0;
private int mHeight = 0;
private int oldMarginstart=0;
private int oldMargintop=0;
private int mAdState = -1;
public AdMultiView(@NonNull Context context) {
super(context);
}
public AdMultiView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public AdMultiView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public AdMultiView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
public void initView(Context context, AttributeSet attrs){
mContext = context;
LayoutInflater inflater = LayoutInflater.from(context);
mView = inflater.inflate(R.layout.ad_multi_layout,this);
tx_view = mView.findViewById(R.id.tx_view);
mMultiInsideLayout = mView.findViewById(R.id.multi_inside);
mAdRootView = mView.findViewById(R.id.ad_root);
img_view = mView.findViewById(R.id.img_view);
mView.findViewById(R.id.tx_view).setVisibility(View.INVISIBLE);
if(attrs!=null){
TypedArray a= context.getTheme().obtainStyledAttributes(attrs,R.styleable.AdMultiView,0,0);
try {
int titleResId = a.getResourceId(R.styleable.AdMultiView_adMultiViewTitle,-1);
int imageResId = a.getResourceId(R.styleable.AdMultiView_adMultiViewImage,-1);
if(titleResId!=-1){
tx_view.setText(titleResId);
tx_view.setVisibility(View.VISIBLE);
} else {
tx_view.setVisibility(View.INVISIBLE);
}
if(imageResId!=-1){
img_view.setImageResource(imageResId);
}
}catch (Exception e){
e.printStackTrace();
}
}
mMultiInsideLayout.setOutlineProvider(new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
outline.setRoundRect(4, 4, view.getWidth()-4, view.getHeight()-4, 20);
}
});
mMultiInsideLayout.setClipToOutline(true);
hookWebView();
}
@Override
public void onVideoRestart(String uri) {
startAd();
}
@Override
public void onImageRestart(String uri) {
}
@Override
public void onImageRestartLocal(String path) {
if(path==null){
return;
}
img_view.setVisibility(VISIBLE);
File tmpfile= new File(path);
LogUtils.loge("AdMultiView tmpfile===>"+tmpfile.exists());
if(tmpfile.exists()) {
Glide.with(mContext).load(tmpfile).into(img_view);
}
}
@Override
public void loadIamgeRes(String uri, int defaultImageId) {
}
@Override
public void loadDefaultImage(int resId) {
img_view.setImageResource(resId);
}
@Override
public void resetView() {
//TODO 如果无需响应用户操作取消广告(即:广告可点击),删掉下方一行代码
// stopAd();
}
@Override
public void stopView() {
LogUtils.loge( "stopView=====>");
stopAd();
if(mFullRootView.getVisibility()==VISIBLE){
mFullRootView.setVisibility(GONE);
}
}
@Override
public void releaseView() {
}
@Override
public void pauseView() {
}
@Override
public boolean isAdPlaying() {
return mAdState == AdStateListener.AD_PLAYING
|| mAdState == AdStateListener.AD_LOADING
|| mAdState == AdStateListener.AD_LOADED;
}
public void setFullRooView(ViewGroup fullRooView){
mFullRootView = fullRooView;
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if(mWidth == 0 || mHeight == 0) {
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) getLayoutParams();
mWidth = getWidth();
mHeight = getHeight();
oldMarginstart =layoutParams.leftMargin;
oldMargintop =layoutParams.topMargin;
}
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
stopAd();
}
@SuppressLint("SoonBlockedPrivateApi")
private void hookWebView() {
int sdkInt = Build.VERSION.SDK_INT;
try {
Class factoryClass = Class.forName("android.webkit.WebViewFactory");
Field field = factoryClass.getDeclaredField("sProviderInstance");
field.setAccessible(true);
Object sProviderInstance = field.get(null);
if (sProviderInstance != null) {
LogUtils.logi("sProviderInstance isn't null");
return;
}
Method getProviderClassMethod = null;
if (sdkInt > 22) {
getProviderClassMethod = factoryClass.getDeclaredMethod("getProviderClass");
} else if (sdkInt == 22) {
getProviderClassMethod = factoryClass.getDeclaredMethod("getFactoryClass");
} else {
LogUtils.logi("Don't need to Hook WebView");
return;
}
getProviderClassMethod.setAccessible(true);
Class factoryProviderClass = (Class) getProviderClassMethod.invoke(factoryClass);
Class delegateClass = Class.forName("android.webkit.WebViewDelegate");
Constructor delegateConstructor = delegateClass.getDeclaredConstructor();
delegateConstructor.setAccessible(true);
if (sdkInt < 26) { //低于Android O版本
Constructor providerConstructor = factoryProviderClass.getConstructor(delegateClass);
if (providerConstructor != null) {
providerConstructor.setAccessible(true);
sProviderInstance = providerConstructor.newInstance(delegateConstructor.newInstance());
}
} else {
Field chromiumMethodName = factoryClass.getDeclaredField("CHROMIUM_WEBVIEW_FACTORY_METHOD");
chromiumMethodName.setAccessible(true);
String chromiumMethodNameStr = (String) chromiumMethodName.get(null);
if (chromiumMethodNameStr == null) {
chromiumMethodNameStr = "create";
}
Method staticFactory = factoryProviderClass.getMethod(chromiumMethodNameStr, delegateClass);
if (staticFactory != null) {
sProviderInstance = staticFactory.invoke(null, delegateConstructor.newInstance());
}
}
if (sProviderInstance != null) {
field.set("sProviderInstance", sProviderInstance);
LogUtils.logi("can use webview");
} else {
LogUtils.logi("can not use webview");
}
} catch (Exception e) {
}
}
private void startAd(){
if(mAdPlayManager != null){
stopAd();
}
mAdPlayManager = new AdPlayManager(mContext, AdPlayManager.TYPE_WITH_CONTAINER,
0, adstate -> {
if(mMultiViewListener != null) {
int playState = Player.STATE_IDLE;
switch (adstate){
case AdStateListener.AD_LOADING:
playState = Player.STATE_BUFFERING;
break;
case AdStateListener.AD_LOADED:
case AdStateListener.AD_PLAYING:
playState = Player.STATE_READY;
break;
case AdStateListener.AD_ERROR:
playState = adstate;
break;
case AdStateListener.AD_COMPLETE_ALL:
playState = Player.STATE_ENDED;
break;
}
LogUtils.loge("AdMultiView adstate ===>"+adstate);
if((mAdState == -1 || mAdState != adstate) && playState != Player.STATE_IDLE) {
mMultiViewListener.onPlaybackStateChanged(getId(), playState);
}
}
mAdState = adstate;
if(adstate == AdStateListener.AD_COMPLETE_ALL||adstate == AdStateListener.AD_ERROR){
if(isFullAdShow){
isFullAdShow = false;
requestFocus();
}
stopAd();
}
}); //position 必填
mAdPlayManager.setAdFullRootView(mFullRootView);//设置全屏的 ad root
if(isFocused()) {//焦点在当前view时显示back提示
mAdPlayManager.setNeedCancelTips(true);
}
mAdPlayManager.startAd(mAdRootView,0);
}
@Override
public void stopAd() {
LogUtils.loge( "stopAd=====>");
if (mAdPlayManager != null) {
mAdPlayManager.stopAd();
mAdPlayManager = null;
}
}
@Override
public boolean onAdViewClick(){
boolean isNeed = false;
if (mAdPlayManager != null) {
isNeed = mAdPlayManager.onAdViewClick();
}
isFullAdShow = isNeed;
return isNeed;
}
public boolean onAdBackClick(){
boolean isNeed = false;
//NOTE: 如果希望全局按back键取消广告可以移除焦点判断
if (isFocused() && mAdPlayManager != null) {
isNeed = mAdPlayManager.onAdBackClick();
}
return isNeed;
}
private boolean mGainFocus=false;
// @Override
// protected void onFocusChanged(boolean gainFocus, int direction, @Nullable Rect previouslyFocusedRect) {
// super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
// mGainFocus = gainFocus;
//
// if (gainFocus) {
// if(mAdPlayManager != null) {
// mAdPlayManager.setNeedCancelTips(true);
// }
// setBackgroundResource(R.drawable.app_item_border);
// setTranslationZ(10);
// setElevation(10);
//
// scaleView(1.05f);
//
//// ScaleAnimation anim = new ScaleAnimation(1f, 1.1f, 1f, 1.1f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
//// anim.setZAdjustment(Animation.ZORDER_TOP);
//// anim.setDuration(animDuration);
//// anim.setFillAfter(true);
//// this.startAnimation(anim);
// this.bringToFront();
// } else {
// if(mAdPlayManager != null) {
// mAdPlayManager.setNeedCancelTips(false);
// }
// setBackgroundResource(R.color.transparent_background);
// setTranslationZ(0);
// setElevation(0);
// scaleView(1.0f);
//// ScaleAnimation anim = new ScaleAnimation(1.1f, 1f, 1.1f, 1f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
//// anim.setZAdjustment(Animation.ZORDER_TOP);
//// anim.setDuration(animDuration);
//// anim.setFillAfter(true);
//// this.startAnimation(anim);
// }
// }
@Override
protected void onFocusChanged(boolean gainFocus, int direction, @Nullable Rect previouslyFocusedRect) {
super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
// int width = getWidth();
// int height = getHeight();
mGainFocus = gainFocus;
if(gainFocus){
if(mAdPlayManager != null) {
mAdPlayManager.setNeedCancelTips(true);
}
setBackgroundResource(R.drawable.app_item_border);
setTranslationZ(8);
setElevation(8);
ValueAnimator animator = ValueAnimator.ofFloat(1f,1.1f);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(@NonNull ValueAnimator valueAnimator) {
float scale = (float) valueAnimator.getAnimatedValue();
// RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) getLayoutParams();
// layoutParams.height = (int) (height*scale);
// layoutParams.width = (int) (width*scale);
// setLayoutParams(layoutParams);
// setScaleWithLayoutd(scale);
setScaleWithLayoutd(scale);
invalidate();
}
});
animator.setDuration(animDuration);
animator.start();
this.bringToFront();
}else {
if(mAdPlayManager != null) {
mAdPlayManager.setNeedCancelTips(false);
}
setBackgroundResource(R.color.transparent_background);
setTranslationZ(0);
setElevation(0);
ValueAnimator animator = ValueAnimator.ofFloat(1.1f, 1f);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(@NonNull ValueAnimator valueAnimator) {
float scale = (float) valueAnimator.getAnimatedValue();
// RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) getLayoutParams();
// layoutParams.height = (int) (height*scale);
// layoutParams.width = (int) (width*scale);
// if(layoutParams.height < mHeight || layoutParams.width < mWidth){
// layoutParams.height = mHeight;
// layoutParams.width = mWidth;
// }
// setLayoutParams(layoutParams);
// setScaleWithLayoutd(scale);
setScaleWithLayoutd(scale);
invalidate();
}
});
animator.setDuration(animDuration);
animator.start();
}
}
// 缩放方法
public void scaleView(float scale) {
setScaleX(scale);
setScaleY(scale);
setScaleWithLayoutd(scale);
invalidate(); // 可选,通常不需要
}
// 或者如果需要同时改变布局大小
public void setScaleWithLayoutd(float scale) {
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) getLayoutParams();
int newWidth = (int) (mWidth * scale);
int newHeight = (int) (mHeight * scale);
// 调整margin保持中心位置
lp.leftMargin -= (newWidth - lp.width) / 2;
lp.topMargin -= (newHeight - lp.height) / 2;
lp.width = newWidth;
lp.height = newHeight;
setLayoutParams(lp);
}
// public void setScaleWithLayouts(float scale) {
// RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) getLayoutParams();
// // 调整margin保持中心位置
// lp.leftMargin -= (mWidth - lp.width) / 2;
// lp.topMargin -= (mWidth - lp.height) / 2;
// lp.width = mWidth;
// lp.height = mWidth;
// setLayoutParams(lp);
// }
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
LogUtils.loge("AdMultiView onKeyDown==>"+keyCode);
switch (keyCode){
case KeyEvent.KEYCODE_BACK:
if(mGainFocus){
onAdBackClick();
return true;
}
break;
}
return super.onKeyDown(keyCode, event);
}
}

View File

@@ -6,6 +6,7 @@ import android.content.res.TypedArray;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.FocusFinder;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
@@ -166,6 +167,10 @@ public class CustomRecyclerViewer extends RecyclerView {
super.requestChildFocus(child, focused);//执行过super.requestChildFocus之后hasFocus会变成true
mCurrentFocusPosition = getChildViewHolder(child).getAdapterPosition();
}
//获取当前焦点位置
public int getmCurrentFocusPosition() {
return mCurrentFocusPosition;
}
//实现焦点记忆的关键代码
@Override
@@ -223,7 +228,7 @@ public class CustomRecyclerViewer extends RecyclerView {
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
// int keyCode = event.getKeyCode();
int keyCode = event.getKeyCode();
// if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN || keyCode == KeyEvent.KEYCODE_DPAD_UP) {
// long current = System.currentTimeMillis();
// boolean res;
@@ -236,34 +241,42 @@ public class CustomRecyclerViewer extends RecyclerView {
// return res;
// }
//
if(keyCode == KeyEvent.KEYCODE_DPAD_DOWN || keyCode == KeyEvent.KEYCODE_DPAD_UP) {
// View focusedView = getFocusedChild(); // 获取当前获得焦点的view
// View nextFocusView;
// try {
// if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
// // 通过findNextFocus获取下一个需要得到焦点的view
// nextFocusView = FocusFinder.getInstance().findNextFocus(this, focusedView, View.FOCUS_DOWN);
// } else {
// // 通过findNextFocus获取下一个需要得到焦点的view
// nextFocusView = FocusFinder.getInstance().findNextFocus(this, focusedView, View.FOCUS_UP);
// }
//
//
// LogUtils.loge("nextFocusView===>"+nextFocusView);
//
// } catch (Exception e) {
// nextFocusView = null;
// }
//
// // 如果获取失败(也就是说需要交给系统来处理焦点, 消耗掉事件,不让系统处理, 并让先前获取焦点的view获取焦点)
// if (nextFocusView == null) {
// focusedView.requestFocus();
// return true;
//
// }
View focusedView = getFocusedChild(); // 获取当前获得焦点的view
View nextFocusView;
try {
if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
// 通过findNextFocus获取下一个需要得到焦点的view
nextFocusView = FocusFinder.getInstance().findNextFocus(this, focusedView, View.FOCUS_DOWN);
} else {
// 通过findNextFocus获取下一个需要得到焦点的view
nextFocusView = FocusFinder.getInstance().findNextFocus(this, focusedView, View.FOCUS_UP);
}
LogUtils.loge("nextFocusView===>" + nextFocusView);
} catch (Exception e) {
nextFocusView = null;
}
// 如果获取失败(也就是说需要交给系统来处理焦点, 消耗掉事件,不让系统处理, 并让先前获取焦点的view获取焦点)
if (nextFocusView == null) {
if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
focusedView.requestFocus(View.FOCUS_DOWN);
}
if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
focusedView.requestFocus(View.FOCUS_UP);
}
return true;
}
// }
// }
}
// }
}
return super.dispatchKeyEvent(event);
}

View File

@@ -66,6 +66,7 @@ public class HomeMultiView extends MultiView {
private int animDuration=50;
private View mMultiInsideLayout;
private int imageResId;
public HomeMultiView(@NonNull Context context) {
@@ -98,7 +99,7 @@ public class HomeMultiView extends MultiView {
TypedArray a= context.getTheme().obtainStyledAttributes(attrs,R.styleable.MultiView,0,0);
try {
int titleResId = a.getResourceId(R.styleable.MultiView_multiViewTitle,-1);
int imageResId = a.getResourceId(R.styleable.MultiView_multiViewImage,-1);
imageResId = a.getResourceId(R.styleable.MultiView_multiViewImage,-1);
boolean adsSwitch = a.getBoolean(R.styleable.MultiView_adsSwitch,false);
if(titleResId!=-1){
tx_view.setText(titleResId);
@@ -107,7 +108,7 @@ public class HomeMultiView extends MultiView {
tx_view.setVisibility(View.INVISIBLE);
}
if(imageResId!=-1){
if(imageResId !=-1){
img_view.setImageResource(imageResId);
}
@@ -184,7 +185,7 @@ public class HomeMultiView extends MultiView {
@Override
public void onImageRestartLocal(String path){
LogUtils.loge("onImageRestartLocal==>"+path);
if(path==null){
if(TextUtils.isEmpty(path)){
return;
}
img_view.setVisibility(VISIBLE);
@@ -196,7 +197,7 @@ public class HomeMultiView extends MultiView {
File tmpfile= new File(path);
LogUtils.loge("tmpfile===>"+tmpfile.exists());
if(tmpfile.exists()) {
Glide.with(mContext).load(tmpfile).into(img_view);
Glide.with(mContext).load(tmpfile).placeholder(imageResId).into(img_view);
}
}

View File

@@ -147,26 +147,33 @@ public class SplashView {
if(adsInfoBeanInfo==null){
LogUtils.loge("adsInfoBeanInfo is null===>");
mHandler.sendEmptyMessageDelayed(2,10000);
mHandler.sendEmptyMessage(2);
return ;
}
if(adsInfoBeanInfo.getLocalFilePath()==null){
LogUtils.loge("getLocalFilePath is null===>");
mHandler.sendEmptyMessageDelayed(2,10000);
mHandler.sendEmptyMessage(2);
return ;
}
File file = new File(adsInfoBeanInfo.getLocalFilePath());
if(!file.exists()){
LogUtils.loge("file is not exits===>");
mHandler.sendEmptyMessageDelayed(2,10000);
return ;
File tempFile=new File(adsInfoBeanInfo.getLocalFilePath()+"-tmp");
if(tempFile.exists()&&tempFile.length()==adsInfoBeanInfo.getAdSize()){
tempFile.renameTo(file);
tempFile.delete();
LogUtils.loge("下载大小完成但重命名失败同时下载任务已清除图片至始至终未显示优化处理 system rename file file bug compose");
}else {
LogUtils.loge("file is not exits===>");
mHandler.sendEmptyMessage(2);
return ;
}
}
if(adsInfoBeanInfo.getState()==0){
LogUtils.loge("splash task is closd ");
mHandler.sendEmptyMessageDelayed(2,5000);
mHandler.sendEmptyMessage(2);
return ;
}

View File

@@ -0,0 +1,692 @@
package com.ik.mboxlauncher.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.FocusFinder;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import androidx.core.view.ViewCompat;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
import com.android.util.LogUtils;
import com.ik.mboxlauncher.R;
/**
* Created by ksl on 2026/1/9.
*/
public class TvRecyclerView extends RecyclerView {
private static final String TAG = "TvRecyclerView";
private int position;
private int lastFocusPosition;
//焦点是否居中
private boolean mSelectedItemCentered;
private boolean hasResetFocus;//自控焦点
private boolean mScrollDirecitonUp;//默认向下滚
private int mSelectedItemOffsetStart;
private int mSelectedItemOffsetEnd;
//分页的时候使用
private int mLoadMoreBeforehandCount = 0;
private PressBackListenner mPressbackLister;
public TvRecyclerView(Context context) {
this(context, null);
}
public TvRecyclerView(Context context, AttributeSet attrs) {
this(context, attrs, -1);
}
public TvRecyclerView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs, defStyle);
}
private void init(Context context, AttributeSet attrs, int defStyle) {
initView();
initAttr(context, attrs);
}
private void initView() {
setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
setHasFixedSize(true);
setWillNotDraw(true);
setOverScrollMode(View.OVER_SCROLL_NEVER);
setChildrenDrawingOrderEnabled(true);
setClipChildren(false);
setClipToPadding(false);
setClickable(false);
setFocusable(true);
setFocusableInTouchMode(true);
/**
防止RecyclerView刷新时焦点不错乱bug的步骤如下:
(1)adapter执行setHasStableIds(true)方法
(2)重写getItemId()方法,让每个view都有各自的id
(3)RecyclerView的动画必须去掉
*/
setItemAnimator(null);
}
private void initAttr(Context context, AttributeSet attrs) {
if (attrs != null) {
final TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.TvRecyclerView);
/**
* 如果是towWayView的layoutManager
*/
final String name = a.getString(R.styleable.TvRecyclerView_tv_layoutManager);
mSelectedItemCentered = a.getBoolean(R.styleable.TvRecyclerView_tv_selectedItemCentered, false);
mLoadMoreBeforehandCount = a.getInteger(R.styleable.TvRecyclerView_tv_loadMoreBeforehandCount, 0);
mSelectedItemOffsetStart = a.getDimensionPixelSize(R.styleable.TvRecyclerView_tv_selectedItemOffsetStart, 0);
mSelectedItemOffsetEnd = a.getDimensionPixelSize(R.styleable.TvRecyclerView_tv_selectedItemOffsetEnd, 0);
a.recycle();
}
}
private int getFreeWidth() {
return getWidth() - getPaddingLeft() - getPaddingRight();
}
private int getFreeHeight() {
return getHeight() - getPaddingTop() - getPaddingBottom();
}
@Override
protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
// View lastFocusedView = getLayoutManager().findViewByPosition(lastFocusPosition);
// if(lastFocusedView!=null){
// lastFocusedView.requestFocus();
// }
if(!gainFocus){
hasResetFocus=false;
LogUtils.loge("TvRecyclerView gainFocus="+gainFocus);
}
}
//防止失去焦点还是会继续滚动再度获取焦点
public void disScrollFocus(){
hasResetFocus=false;
}
@Override
public boolean hasFocus() {
return super.hasFocus();
}
@Override
public boolean isInTouchMode() {
// 解决4.4版本抢焦点的问题
if (Build.VERSION.SDK_INT == 19) {
return !(hasFocus() && !super.isInTouchMode());
} else {
return super.isInTouchMode();
}
//return super.isInTouchMode();
}
@Override
public void requestChildFocus(View child, View focused) {
if (null != child) {
if (mSelectedItemCentered) {
mSelectedItemOffsetStart = !isVertical() ? (getFreeWidth() - child.getWidth()) : (getFreeHeight() - child.getHeight());
mSelectedItemOffsetStart /= 2;
mSelectedItemOffsetEnd = mSelectedItemOffsetStart;
}
lastFocusPosition=getChildViewHolder(child).getAdapterPosition();
Log.e(TAG,"lastFocusPosition="+lastFocusPosition);
}
super.requestChildFocus(child, focused);
}
@Override
public boolean requestChildRectangleOnScreen(View child, Rect rect, boolean immediate) {
final int parentLeft = getPaddingLeft();
final int parentRight = getWidth() - getPaddingRight();
final int parentTop = getPaddingTop();
final int parentBottom = getHeight() - getPaddingBottom();
final int childLeft = child.getLeft() + rect.left;
final int childTop = child.getTop() + rect.top;
final int childRight = childLeft + rect.width();
final int childBottom = childTop + rect.height();
final int offScreenLeft = Math.min(0, childLeft - parentLeft - mSelectedItemOffsetStart);
final int offScreenRight = Math.max(0, childRight - parentRight + mSelectedItemOffsetEnd);
final int offScreenTop = Math.min(0, childTop - parentTop - mSelectedItemOffsetStart);
final int offScreenBottom = Math.max(0, childBottom - parentBottom + mSelectedItemOffsetEnd);
final boolean canScrollHorizontal = getLayoutManager().canScrollHorizontally();
final boolean canScrollVertical = getLayoutManager().canScrollVertically();
// Favor the "start" layout direction over the end when bringing one side or the other
// of a large rect into view. If we decide to bring in end because start is already
// visible, limit the scroll such that start won't go out of bounds.
final int dx;
if (canScrollHorizontal) {
if (ViewCompat.getLayoutDirection(this) == ViewCompat.LAYOUT_DIRECTION_RTL) {
dx = offScreenRight != 0 ? offScreenRight
: Math.max(offScreenLeft, childRight - parentRight);
} else {
dx = offScreenLeft != 0 ? offScreenLeft
: Math.min(childLeft - parentLeft, offScreenRight);
}
} else {
dx = 0;
}
// Favor bringing the top into view over the bottom. If top is already visible and
// we should scroll to make bottom visible, make sure top does not go out of bounds.
final int dy;
if (canScrollVertical) {
dy = offScreenTop != 0 ? offScreenTop : Math.min(childTop - parentTop, offScreenBottom);
} else {
dy = 0;
}
if (dx != 0 || dy != 0) {
if (immediate) {
scrollBy(dx, dy);
} else {
smoothScrollBy(dx, dy);
}
// 重绘是为了选中item置顶具体请参考getChildDrawingOrder方法
postInvalidate();
return true;
}
return false;
}
@Override
public int getBaseline() {
return -1;
}
public int getSelectedItemOffsetStart() {
return mSelectedItemOffsetStart;
}
public int getSelectedItemOffsetEnd() {
return mSelectedItemOffsetEnd;
}
@Override
public void setLayoutManager(LayoutManager layout) {
super.setLayoutManager(layout);
}
/**
* 判断是垂直,还是横向.
*/
private boolean isVertical() {
LayoutManager manager = getLayoutManager();
if (manager != null) {
LinearLayoutManager layout = (LinearLayoutManager) getLayoutManager();
return layout.getOrientation() == LinearLayoutManager.VERTICAL;
}
return false;
}
/**
* 设置选中的Item距离开始或结束的偏移量
* 与滚动方向有关;
* 与setSelectedItemAtCentered()方法二选一
*
* @param offsetStart
* @param offsetEnd 从结尾到你移动的位置.
*/
public void setSelectedItemOffset(int offsetStart, int offsetEnd) {
setSelectedItemAtCentered(false);
mSelectedItemOffsetStart = offsetStart;
mSelectedItemOffsetEnd = offsetEnd;
}
/**
* 设置选中的Item居中
* 与setSelectedItemOffset()方法二选一
*
* @param isCentered
*/
public void setSelectedItemAtCentered(boolean isCentered) {
this.mSelectedItemCentered = isCentered;
}
@Override
protected int getChildDrawingOrder(int childCount, int i) {
View view = getFocusedChild();
if (null != view) {
position = getChildAdapterPosition(view) - getFirstVisiblePosition();
if (position < 0) {
return i;
} else {
if (i == childCount - 1) {//这是最后一个需要刷新的item
if (position > i) {
position = i;
}
return position;
}
if (i == position) {//这是原本要在最后一个刷新的item
return childCount - 1;
}
}
}
return i;
}
public int getFirstVisiblePosition() {
if (getChildCount() == 0)
return 0;
else
return getChildAdapterPosition(getChildAt(0));
}
public int getLastVisiblePosition() {
final int childCount = getChildCount();
if (childCount == 0)
return 0;
else
return getChildAdapterPosition(getChildAt(childCount - 1));
}
/***********
* 按键加载更多 start
**********/
private OnLoadMoreListener mOnLoadMoreListener;
public interface OnLoadMoreListener {
void onLoadMore();
}
public void setOnLoadMoreListener(OnLoadMoreListener onLoadMoreListener) {
this.mOnLoadMoreListener = onLoadMoreListener;
}
//
// private PressBackListenner mPressbackLister;
//
//
// public void setOnPressBackListener(PressBackListenner listener) {
// this.mPressbackLister = listener;
// }
/**
* 设置为0这样可以防止View获取焦点的时候ScrollView自动滚动到焦点View的位置
*/
protected int computeScrollDeltaToGetChildRectOnScreen(Rect rect) {
return 0;
}
@Override
public void onScrollStateChanged(int state) {
if (state == SCROLL_STATE_IDLE) {
// 加载更多回调
if (null != mOnLoadMoreListener) {
if (getLastVisiblePosition() >= getAdapter().getItemCount() - (1 + mLoadMoreBeforehandCount)) {
mOnLoadMoreListener.onLoadMore();
}
}
LayoutManager layoutManager = getLayoutManager();
GridLayoutManager staggeredGridLayoutManager = (GridLayoutManager) layoutManager;
int spanCount = staggeredGridLayoutManager.getSpanCount();
int itemCount = staggeredGridLayoutManager.getItemCount();
Log.i(TAG,"onScrollStateChanged() spanCount="+spanCount+"itemCount="+itemCount);
if(hasResetFocus&&mScrollDirecitonUp&&lastFocusPosition>=spanCount){
Log.i(TAG,"onScrollStateChanged() hasResetFocus1="+hasResetFocus);
hasResetFocus=false;
setSelectedPosition(lastFocusPosition-spanCount);
View view = layoutManager.findViewByPosition(lastFocusPosition-spanCount);
if (view != null) {
view.requestFocus();
}
}
if(hasResetFocus&&!mScrollDirecitonUp&&lastFocusPosition<itemCount-spanCount){
Log.i(TAG,"onScrollStateChanged() hasResetFocus2="+hasResetFocus);
hasResetFocus=false;
View view = layoutManager.findViewByPosition(lastFocusPosition+spanCount);
if (view != null) {
view.requestFocus();
}
}
if(hasResetFocus&&!mScrollDirecitonUp&&lastFocusPosition>=itemCount-spanCount&&lastFocusPosition<spanCount*(itemCount/spanCount)&&itemCount%spanCount!=0){
hasResetFocus=false;
Log.i(TAG,"onScrollStateChanged() hasResetFocus3="+hasResetFocus);
View view = layoutManager.findViewByPosition(itemCount-1);
if (view != null) {
view.requestFocus();
}
}
}
super.onScrollStateChanged(state);
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
boolean result = super.dispatchKeyEvent(event);
View focusView = this.getFocusedChild();
if (focusView == null) {
return result;
} else {
int dy = 0;
int dx = 0;
if (getChildCount() > 0) {
View firstView = this.getChildAt(0);
dy = firstView.getHeight();
dx = firstView.getWidth();
}
if (event.getAction() == KeyEvent.ACTION_UP) {
return true;
} else {
switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_DPAD_RIGHT:
View rightView = FocusFinder.getInstance().findNextFocus(this, focusView, View.FOCUS_RIGHT);
Log.i(TAG, "rightView is null:" + (rightView == null));
if (rightView != null) {
rightView.requestFocus();
return true;
} else {
this.smoothScrollBy(dx, 0);
return true;
}
case KeyEvent.KEYCODE_DPAD_LEFT:
View leftView = FocusFinder.getInstance().findNextFocus(this, focusView, View.FOCUS_LEFT);
Log.i(TAG, "leftView is null:" + (leftView == null));
if (leftView != null) {
leftView.requestFocus();
return true;
} else {
this.smoothScrollBy(-dx, 0);
return true;
}
case KeyEvent.KEYCODE_DPAD_DOWN:
mScrollDirecitonUp=false;
View downView = FocusFinder.getInstance().findNextFocus(this, focusView, View.FOCUS_DOWN);
Log.i(TAG, " downView is null:" + (downView == null));
if (downView != null) {
hasResetFocus=false;
downView.requestFocus();
return true;
} else {
this.smoothScrollBy(0, dy);
hasResetFocus=true;
return true;// true解决item滚动滑向中间item
}
case KeyEvent.KEYCODE_DPAD_UP:
mScrollDirecitonUp=true;
View upView = FocusFinder.getInstance().findNextFocus(this, focusView, View.FOCUS_UP);
Log.i(TAG, "upView is null:" + (upView == null));
if (event.getAction() == KeyEvent.ACTION_UP) {
return false;
} else {
if (upView != null) {
hasResetFocus=false;
upView.requestFocus();
return true;
} else {
hasResetFocus=true;
this.smoothScrollBy(0, -dy);
Log.e(TAG,"KEYCODE_DPAD_UP");
return true;
}
}
}
if(event.getKeyCode()== KeyEvent.KEYCODE_BACK){
if(mPressbackLister!=null){
mPressbackLister.hasPressback(this);
}
}
}
}
Log.e(TAG,"dispatchKeyEvent()="+result);
return result;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent e) {
return super.onInterceptTouchEvent(e);
}
/**
* 设置默认选中.
*/
public void setSelectedPosition(int pos) {
this.smoothScrollToPosition(pos);
}
//防止Activity时,RecyclerView崩溃
@Override
protected void onDetachedFromWindow() {
if (getLayoutManager() != null) {
super.onDetachedFromWindow();
}
}
/**
* 是否是最右边的item如果是竖向表示右边如果是横向表示下边
*
* @param childPosition
* @return
*/
public boolean isRightEdge(int childPosition) {
LayoutManager layoutManager = getLayoutManager();
if (layoutManager instanceof GridLayoutManager) {
GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
GridLayoutManager.SpanSizeLookup spanSizeLookUp = gridLayoutManager.getSpanSizeLookup();
int totalSpanCount = gridLayoutManager.getSpanCount();
int totalItemCount = gridLayoutManager.getItemCount();
int childSpanCount = 0;
for (int i = 0; i <= childPosition; i++) {
childSpanCount += spanSizeLookUp.getSpanSize(i);
}
if (isVertical()) {
if (childSpanCount % gridLayoutManager.getSpanCount() == 0) {
return true;
}
} else {
int lastColumnSize = totalItemCount % totalSpanCount;
if (lastColumnSize == 0) {
lastColumnSize = totalSpanCount;
}
if (childSpanCount > totalItemCount - lastColumnSize) {
return true;
}
}
} else if (layoutManager instanceof LinearLayoutManager) {
if (isVertical()) {
return true;
}else{
return childPosition == getLayoutManager().getItemCount() - 1;
}
}
return false;
}
/**
* 是否是最左边的item如果是竖向表示左方如果是横向表示上边
*
* @param childPosition
* @return
*/
public boolean isLeftEdge(int childPosition) {
LayoutManager layoutManager = getLayoutManager();
if (layoutManager instanceof GridLayoutManager) {
GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
GridLayoutManager.SpanSizeLookup spanSizeLookUp = gridLayoutManager.getSpanSizeLookup();
int totalSpanCount = gridLayoutManager.getSpanCount();
int childSpanCount = 0;
for (int i = 0; i <= childPosition; i++) {
childSpanCount += spanSizeLookUp.getSpanSize(i);
}
if (isVertical()) {
if (childSpanCount % gridLayoutManager.getSpanCount() == 1) {
return true;
}
} else {
if (childSpanCount <= totalSpanCount) {
return true;
}
}
} else if (layoutManager instanceof LinearLayoutManager) {
if (isVertical()) {
return true;
} else {
return childPosition == 0;
}
}
return false;
}
/**
* 是否是最上边的item以recyclerview的方向做参考
*
* @param childPosition
* @return
*/
public boolean isTopEdge(int childPosition) {
LayoutManager layoutManager = getLayoutManager();
if (layoutManager instanceof GridLayoutManager) {
GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
GridLayoutManager.SpanSizeLookup spanSizeLookUp = gridLayoutManager.getSpanSizeLookup();
int totalSpanCount = gridLayoutManager.getSpanCount();
int childSpanCount = 0;
for (int i = 0; i <= childPosition; i++) {
childSpanCount += spanSizeLookUp.getSpanSize(i);
}
if (isVertical()) {
if (childSpanCount <= totalSpanCount) {
return true;
}
} else {
if (childSpanCount % totalSpanCount == 1) {
return true;
}
}
} else if (layoutManager instanceof LinearLayoutManager) {
if (isVertical()) {
return childPosition == 0;
} else {
return true;
}
}
return false;
}
/**
* 是否是最下边的item以recyclerview的方向做参考
*
* @param childPosition
* @return
*/
public boolean isBottomEdge(int childPosition) {
LayoutManager layoutManager = getLayoutManager();
if (layoutManager instanceof GridLayoutManager) {
GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
GridLayoutManager.SpanSizeLookup spanSizeLookUp = gridLayoutManager.getSpanSizeLookup();
int itemCount = gridLayoutManager.getItemCount();
int childSpanCount = 0;
int totalSpanCount = gridLayoutManager.getSpanCount();
for (int i = 0; i <= childPosition; i++) {
childSpanCount += spanSizeLookUp.getSpanSize(i);
}
if (isVertical()) {
//最后一行item的个数
int lastRowCount = itemCount % totalSpanCount;
if (lastRowCount == 0) {
lastRowCount = gridLayoutManager.getSpanCount();
}
if (childSpanCount > itemCount - lastRowCount) {
return true;
}
} else {
if (childSpanCount % totalSpanCount == 0) {
return true;
}
}
} else if (layoutManager instanceof LinearLayoutManager) {
if (isVertical()) {
return childPosition == getLayoutManager().getItemCount() - 1;
} else {
return true;
}
}
return false;
}
public interface PressBackListenner {
void hasPressback(TvRecyclerView tvRecyclerViewer);
}
public void setOnPressBackListener(PressBackListenner listener) {
this.mPressbackLister = listener;
}
}

View File

@@ -4,9 +4,11 @@
android:layout_height="100dp"
android:focusable="true"
android:padding="5dp"
android:clipChildren="false"
android:descendantFocusability="beforeDescendants">
<RelativeLayout
android:id="@+id/item_bg"
android:clipChildren="false"
android:layout_width="match_parent"
android:layout_height="match_parent">
@@ -22,13 +24,14 @@
android:layout_height="wrap_content"
android:paddingStart="10dp"
android:paddingEnd="10dp"
android:includeFontPadding="false"
android:layout_centerHorizontal="true"
android:gravity="center"
android:singleLine="true"
android:marqueeRepeatLimit="marquee_forever"
android:ellipsize="marquee"
android:textSize="13dp"
android:layout_marginVertical="5dp"
android:textSize="11sp"
android:layout_marginVertical="2dp"
android:layout_alignParentBottom="true"
android:textColor="@color/item_text_color"
/>

View File

@@ -12,6 +12,7 @@
tools:ignore="MissingDefaultResource">
<RelativeLayout
android:id="@+id/item_bg"
android:clipChildren="false"
android:layout_width="match_parent"
android:layout_height="match_parent">
@@ -38,6 +39,7 @@
android:paddingEnd="6dp"
android:layout_centerHorizontal="true"
android:gravity="center"
android:includeFontPadding="false"
android:singleLine="true"
android:marqueeRepeatLimit="marquee_forever"
android:ellipsize="marquee"

View File

@@ -3,6 +3,7 @@
android:layout_width="93dp"
android:layout_height="98dp"
android:id="@+id/item_bg"
android:clipChildren="false"
android:background="@drawable/app_info_bg"
android:descendantFocusability="beforeDescendants"
android:focusable="true">

View File

@@ -8,7 +8,7 @@
android:background="@drawable/bg">
<com.ik.mboxlauncher.view.CustomRecyclerView
<com.ik.mboxlauncher.view.TvRecyclerView
android:id="@+id/grid_coustom_apps"
android:layout_width="match_parent"
android:layout_height="match_parent"

View File

@@ -98,13 +98,13 @@
/>
<com.ik.mboxlauncher.view.AdMultiView
<com.ik.mboxlauncher.view.HomeMultiView
android:id="@+id/layout_miracastreceive"
android:layout_width="285dp"
android:layout_height="117dp"
android:layout_marginStart="64dp"
android:layout_marginTop="302dp"
app:adMultiViewImage="@drawable/img_miracastreceive"
app:multiViewImage="@drawable/img_miracastreceive"
android:focusableInTouchMode="true"
android:descendantFocusability="beforeDescendants"
/>

View File

@@ -4,9 +4,11 @@
android:layout_height="99dp"
android:focusable="true"
android:gravity="center"
android:clipChildren="false"
android:focusableInTouchMode="true">
<RelativeLayout
android:id="@+id/item_bg"
android:clipChildren="false"
android:layout_width="match_parent"
android:layout_height="match_parent">
@@ -22,12 +24,13 @@
android:layout_height="wrap_content"
android:paddingStart="7dp"
android:paddingEnd="7dp"
android:includeFontPadding="false"
android:layout_centerHorizontal="true"
android:gravity="center"
android:singleLine="true"
android:marqueeRepeatLimit="marquee_forever"
android:ellipsize="marquee"
android:textSize="11sp"
android:textSize="13sp"
android:layout_marginVertical="2dp"
android:layout_alignParentBottom="true"
android:textColor="@color/item_text_color"

View File

@@ -12,6 +12,7 @@
tools:ignore="MissingDefaultResource">
<RelativeLayout
android:id="@+id/item_bg"
android:clipChildren="false"
android:layout_width="match_parent"
android:layout_height="match_parent">
@@ -41,6 +42,7 @@
android:marqueeRepeatLimit="marquee_forever"
android:ellipsize="marquee"
android:textSize="16sp"
android:includeFontPadding="false"
android:layout_marginVertical="10dp"
android:layout_alignParentBottom="true"
android:textColor="@color/item_text_color"

View File

@@ -4,6 +4,7 @@
android:layout_height="110dp"
android:id="@+id/item_bg"
android:background="@drawable/app_info_bg"
android:clipChildren="false"
android:descendantFocusability="beforeDescendants"
android:focusable="true">

View File

@@ -4,7 +4,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/app_info_add_bg">
<com.ik.mboxlauncher.view.CustomRecyclerView
<com.ik.mboxlauncher.view.TvRecyclerView
android:id="@+id/grid_coustom_apps"
android:layout_width="wrap_content"
android:layout_height="match_parent"

View File

@@ -98,13 +98,13 @@
/>
<com.ik.mboxlauncher.view.AdMultiView
<com.ik.mboxlauncher.view.HomeMultiView
android:id="@+id/layout_miracastreceive"
android:layout_width="321dp"
android:layout_height="131dp"
android:layout_marginStart="72dp"
android:layout_marginTop="339dp"
app:adMultiViewImage="@drawable/img_miracastreceive"
app:multiViewImage="@drawable/img_miracastreceive"
android:focusableInTouchMode="true"
android:descendantFocusability="beforeDescendants"
/>
@@ -117,7 +117,7 @@
android:layout_marginTop="339dp"
android:focusable="true"
android:focusableInTouchMode="true"
app:adMultiViewImage="@drawable/img_chrome"
app:multiViewImage="@drawable/img_chrome"
android:descendantFocusability="beforeDescendants"
/>
<com.ik.mboxlauncher.view.HomeMultiView

View File

@@ -4,9 +4,11 @@
android:layout_height="132dp"
android:focusable="true"
android:gravity="center"
android:clipChildren="false"
android:focusableInTouchMode="true">
<RelativeLayout
android:id="@+id/item_bg"
android:clipChildren="false"
android:layout_width="match_parent"
android:layout_height="match_parent">
@@ -22,6 +24,7 @@
android:layout_height="wrap_content"
android:paddingStart="10dp"
android:paddingEnd="10dp"
android:includeFontPadding="false"
android:layout_centerHorizontal="true"
android:gravity="center"
android:singleLine="true"

View File

@@ -12,6 +12,7 @@
tools:ignore="MissingDefaultResource">
<RelativeLayout
android:id="@+id/item_bg"
android:clipChildren="false"
android:layout_width="match_parent"
android:layout_height="match_parent">
@@ -39,6 +40,7 @@
android:layout_centerHorizontal="true"
android:gravity="center"
android:singleLine="true"
android:includeFontPadding="false"
android:marqueeRepeatLimit="marquee_forever"
android:ellipsize="marquee"
android:textSize="21sp"

View File

@@ -4,6 +4,7 @@
android:layout_height="147dp"
android:id="@+id/item_bg"
android:background="@drawable/app_info_bg"
android:clipChildren="false"
android:descendantFocusability="beforeDescendants"
android:focusable="true">

View File

@@ -4,7 +4,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/app_info_add_bg">
<com.ik.mboxlauncher.view.CustomRecyclerView
<com.ik.mboxlauncher.view.TvRecyclerView
android:id="@+id/grid_coustom_apps"
android:layout_width="wrap_content"
android:layout_height="match_parent"

View File

@@ -98,13 +98,13 @@
/>
<com.ik.mboxlauncher.view.AdMultiView
<com.ik.mboxlauncher.view.HomeMultiView
android:id="@+id/layout_miracastreceive"
android:layout_width="428dp"
android:layout_height="175dp"
android:layout_marginStart="96dp"
android:layout_marginTop="453dp"
app:adMultiViewImage="@drawable/img_miracastreceive"
app:multiViewImage="@drawable/img_miracastreceive"
android:focusableInTouchMode="true"
android:descendantFocusability="beforeDescendants"
/>

View File

@@ -5,7 +5,7 @@
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@color/bg"
tools:context=".ui.SplashscreenActivity"
tools:context=".ui.Launcher"
tools:ignore="MergeRootFrame">

View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/layout_rect_group"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:ignore="MissingDefaultResource">
<RelativeLayout
android:id="@+id/multi_inside"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<ImageView
android:id="@+id/img_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"/>
<TextView
android:id="@+id/tx_view"
android:layout_width="match_parent"
android:layout_height="53dp"
android:background="@drawable/item_text_bg"
android:textSize="15sp"
android:paddingStart="16dp"
android:paddingTop="12dp"
android:paddingBottom="19dp"
android:gravity="left"
android:textColor="@color/btn_text_color"/>
<RelativeLayout
android:id="@+id/ad_root"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
</RelativeLayout>

View File

@@ -4,9 +4,11 @@
android:layout_height="150dp"
android:focusable="true"
android:padding="5dp"
android:clipChildren="false"
android:descendantFocusability="beforeDescendants">
<RelativeLayout
android:id="@+id/item_bg"
android:clipChildren="false"
android:layout_width="match_parent"
android:layout_height="match_parent">
@@ -22,13 +24,14 @@
android:layout_height="wrap_content"
android:paddingStart="10dp"
android:paddingEnd="10dp"
android:includeFontPadding="false"
android:layout_centerHorizontal="true"
android:gravity="center"
android:singleLine="true"
android:marqueeRepeatLimit="marquee_forever"
android:ellipsize="marquee"
android:textSize="18sp"
android:layout_marginVertical="5dp"
android:textSize="15sp"
android:layout_marginVertical="3dp"
android:layout_alignParentBottom="true"
android:textColor="@color/item_text_color"
/>

View File

@@ -5,6 +5,7 @@
android:id="@+id/item_bg"
android:layout_margin="5dp"
android:descendantFocusability="beforeDescendants"
android:clipChildren="false"
android:focusable="true">
<ImageView
@@ -24,6 +25,6 @@
android:ellipsize="end"
android:gravity="center"
android:textColor="@color/btn_text_color"
android:textSize="20dp"/>
android:textSize="20sp"/>
</com.ik.mboxlauncher.view.MyRelativeLayout>

View File

@@ -8,7 +8,7 @@
android:background="@drawable/bg">
<com.ik.mboxlauncher.view.CustomRecyclerView
<com.ik.mboxlauncher.view.TvRecyclerView
android:id="@+id/grid_coustom_apps"
android:layout_width="match_parent"
android:layout_height="match_parent"

View File

@@ -97,13 +97,13 @@
/>
<com.ik.mboxlauncher.view.AdMultiView
<com.ik.mboxlauncher.view.HomeMultiView
android:id="@+id/layout_miracastreceive"
android:layout_width="321dp"
android:layout_height="131dp"
android:layout_marginStart="72dp"
android:layout_marginTop="339dp"
app:adMultiViewImage="@drawable/img_miracastreceive"
app:multiViewImage="@drawable/img_miracastreceive"
android:focusableInTouchMode="true"
android:descendantFocusability="beforeDescendants"
/>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<resources xmlns:tools="http://schemas.android.com/tools">
<declare-styleable name="MultiView">
<attr name="multiViewTitle" format="reference"/>
<attr name="multiViewImage" format="reference"/>
@@ -12,4 +12,16 @@
<attr name="adMultiViewTitle" format="reference"/>
<attr name="adMultiViewImage" format="reference"/>
</declare-styleable>
<declare-styleable name="TvRecyclerView">
<attr name="android:orientation" tools:ignore="ResourceName"/>
<attr name="tv_layoutManager" format="string"/>
<attr name="tv_numColumns" format="integer"/>
<attr name="tv_numRows" format="integer"/>
<attr name="tv_selectedItemCentered" format="boolean" />
<attr name="tv_loadMoreBeforehandCount" format="integer" />
<attr name="tv_selectedItemOffsetStart" format="dimension" />
<attr name="tv_selectedItemOffsetEnd" format="dimension" />
</declare-styleable>
</resources>

View File

@@ -0,0 +1,103 @@
package com.android;
import android.content.Context;
import android.content.SharedPreferences;
import android.text.TextUtils;
import com.android.util.GsonUtil;
import com.android.util.LogUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class SharePreUtils {
public static final String SHARERE_NAME="upload_ads_droid";
private static SharePreUtils mInstance;
private static List<Map<String, Object>> dataList;//处理一对多的关系 key为AdSourceId value 为任务类型值
private static SharedPreferences.Editor editor;
private static SharedPreferences sharedPreferences;
public SharePreUtils(Context context) {
sharedPreferences=context.getSharedPreferences(SHARERE_NAME,Context.MODE_PRIVATE);
editor=sharedPreferences.edit();
dataList=getDataList();
}
public synchronized static SharePreUtils getInstance(Context context){
if(mInstance==null){
mInstance=new SharePreUtils(context);
}
return mInstance;
}
public synchronized static List<Map<String, Object>> getDataList(){
if(dataList==null){
String adsHasUpload = sharedPreferences.getString("ads_has_upload", "");
if(!TextUtils.isEmpty(adsHasUpload)){
List<Map<String, Object>> mapList = GsonUtil.GsonToListMaps(adsHasUpload);
dataList=mapList;
}else{
dataList=new ArrayList<>();
}
}
return dataList;
}
public synchronized static void addRelation(String key, Object value) {
if(dataList!=null){
Map<String, Object> record = new HashMap<>();
record.put("relation_key", key);
record.put("relation_value", value);
dataList.add(record);
}
}
public static boolean filterByKeyValue(String key, Object value) {
List<Map<String, Object>> filtered = new ArrayList<>();
if(dataList!=null){
for (Map<String, Object> record : dataList) {
if (key.equals(record.get("relation_key")) &&(value == null ? record.get("relation_value") == null :value.equals(record.get("relation_value")))) {
filtered.add(record);
}
}
}
LogUtils.loge("filterByKeyValue() size"+filtered.size()+"dataList() size"+dataList.size());
return filtered.size()==1;
}
public synchronized static void savePreference(){
if(dataList!=null&&dataList.size()>=0){
String commitJson = GsonUtil.GsonString(dataList);
editor.putString("ads_has_upload",commitJson).apply();
}
}
public static void removeKeyFromAllMaps(String keyToRemove) {
if (dataList == null || keyToRemove == null) {
return;
}
List<Map<String, Object>> current=new ArrayList<>();
// 遍历列表中的每个Map
for (Map<String, Object> map : dataList) {
if (map != null) {
// 使用remove方法删除指定键
if(!map.containsValue(keyToRemove)){
current.add(map);
}
}
}
dataList=current;
//LogUtils.loge("removeKeyFromAllMaps current()"+current.size());
}
public static void resetDataList(){
String adsHasUpload = sharedPreferences.getString("ads_has_upload", "");
if(!TextUtils.isEmpty(adsHasUpload)&& GsonUtil.isJson(adsHasUpload)){
List<Map<String, Object>> mapList = GsonUtil.GsonToListMaps(adsHasUpload);
dataList=mapList;
}else{
dataList=new ArrayList<>();
}
}
}

View File

@@ -27,4 +27,8 @@ public interface ServerApi {
@POST(ServerInterface.POST_LAUNCHER_ADS)
Call<String> postLauncherAds(@Body RequestBody requestBody);
@Headers({"Content-type:application/json;charset=UTF-8"})
@POST(ServerInterface.POST_DOWNLOAD_ADS)
Call<String> postDownLoadAds(@Body RequestBody requestBody);
}

View File

@@ -21,6 +21,8 @@ public class ServerInterface {
/**上传事件信息*/
public static final String POST_EVENTINFO_DEVICE="/app-api/third/launcher/ad/play/callback";
public static final String POST_DOWNLOAD_ADS="/app-api/launcher/ad/cb";
private static final boolean USER_DEBUG=false;

View File

@@ -4,6 +4,7 @@ package com.android.api.biz;
import com.android.api.biz.OnBaseListener;
import com.android.database.lib.RecordEventBean;
import com.android.nebulasdk.bean.EventDataInfo;
import com.android.nebulasdk.bean.UploadADBean;
import java.util.List;
import java.util.Map;
@@ -19,8 +20,8 @@ public interface Biz {
void postLauncherAds(Map<String ,String > map, OnBaseListener listener);
//记录设备事件的接口
void postEventData(List<EventDataInfo> recordEventBeans, OnBaseListener listener);
//上传各个广告位下载状态
void postDownloadAd(UploadADBean uploadADBean, OnBaseListener listener);

View File

@@ -2,6 +2,7 @@ package com.android.api.biz.bizimpl;
import com.android.api.biz.Biz;
import com.android.nebulasdk.bean.EventDataInfo;
import com.android.nebulasdk.bean.UploadADBean;
import com.google.gson.JsonObject;
import com.android.api.ServerApi;
import com.android.api.biz.BaseBiz;
@@ -110,5 +111,38 @@ public class BizImpl extends BaseBiz implements Biz {
});
}
@Override
public void postDownloadAd(UploadADBean uploadADBean, OnBaseListener listener) {
RequestBody requestBody = RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"), GsonUtil.GsonString(uploadADBean));
getStringRetrofit().create(ServerApi.class).postDownLoadAds(requestBody).enqueue(new Callback<String>() {
@Override
public void onResponse(Call<String> call, Response<String> response) {
if(call != null){
if (response.body() != null) {
LogUtils.loge("postLauncherAds response==>" + GsonUtil.GsonString(response.body()));
if (response.isSuccessful()) {
listener.onResponse(response.body());
} else {
listener.onFailure(response.message(), response.raw().code());
}
} else {
listener.onFailure("The server is busy, please try again later", response.raw().code());
}
}else {
LogUtils.loge("postDownloadAd Biz>>>>>>>>>>>>>>>>>>call == null<<<<<<<<<<<<<<<<<<");
}
}
@Override
public void onFailure(Call<String> call, Throwable t) {
if (call.isExecuted()) {
call.cancel();
}
LogUtils.loge("recoedDeviceEvent Biz服务器未响应请求失败==>" + GsonUtil.GsonString(t.getMessage()));
listener.onFailure("The server is busy, please try again later", 0);
}
});
}
}

View File

@@ -9,6 +9,7 @@ import com.android.util.GsonUtil;
import com.android.util.LogUtils;
import java.io.File;
import java.io.IOException;
import java.util.List;
public class DownLoadManeger {
@@ -132,9 +133,23 @@ public class DownLoadManeger {
for (DownLoadTaskBean downLoadTaskBean:list) {
if(!TextUtils.isEmpty(downLoadTaskBean.getUrl())&&!TextUtils.isEmpty(downLoadTaskBean.getFileName())&&!TextUtils.isEmpty(downLoadTaskBean.getPath())){
File file = new File(downLoadTaskBean.getPath()+downLoadTaskBean.getFileName()+"-tmp");
if(file.exists()&&downLoadTaskBean.getCurrentProgress()==file.length()&&file.length()<=downLoadTaskBean.getTotal()){
if(file.exists()&&downLoadTaskBean.getCurrentProgress()==file.length()&&file.length()<=downLoadTaskBean.getTotal()){
TaskQueue.getInstance().remove(downLoadTaskBean);
TaskQueue.getInstance().add(new DownLoadTaskThread(downLoadTaskBean, observer));
}else if(downLoadTaskBean.getTaskType()==1){//apk 下载完成未安装断电重新启动下载任务 因为需要安装apk
File apkFile = new File(downLoadTaskBean.getPath()+downLoadTaskBean.getFileName());
if(apkFile.exists()&&apkFile.length()==downLoadTaskBean.getTotal()&&downLoadTaskBean.getCurrentProgress()<downLoadTaskBean.getTotal()){
TaskQueue.getInstance().remove(downLoadTaskBean);
TaskQueue.getInstance().add(new DownLoadTaskThread(downLoadTaskBean, observer));
}
}else if(downLoadTaskBean.getTaskType()==0){//图片文件下载完成 删除downloadtaskbean表数据脏数据
File imgFile = new File(downLoadTaskBean.getPath()+downLoadTaskBean.getFileName());
if(imgFile.exists()&&imgFile.length()==downLoadTaskBean.getTotal()){
DaoManager.getInstance().delete(DownLoadTaskBean.class,downLoadTaskBean);
}
}
if(!file.exists()&&downLoadTaskBean.getCurrentProgress()==0){
LogUtils.loge("power down but downloadstaskbean table remain task");
}
}
}
@@ -274,4 +289,9 @@ public class DownLoadManeger {
}
}
};
public boolean checkTaskQueueClear(){
LogUtils.loge("checkTaskQueueClear() size="+TaskQueue.getInstance().getAllTask().size());
return TaskQueue.getInstance().size()==0;
}
}

View File

@@ -49,6 +49,7 @@ public class DownLoadTaskThread implements Runnable {
File dataFile = new File(bean.getPath(), bean.getFileName());
if(dataFile.exists()&&dataFile.length()==bean.getTotal()){ //判断该文件已下载无需再下载
LogUtils.loge("dont need download "+bean.getFileName());
observer.onFinish(bean, bean.getTaskId(), dataFile.length());
return;
}
@@ -63,9 +64,9 @@ public class DownLoadTaskThread implements Runnable {
if(currentTotal==bean.getTotal()){
File targFile = new File(bean.getPath(), bean.getFileName());
file.renameTo(targFile);//重命名
file.delete();//删除临时文件
Thread.sleep(5000);
Thread.sleep(3000);
observer.onFinish(bean, bean.getTaskId(), currentTotal);
file.delete();//删除临时文件
return;
}
//设置下载位置
@@ -114,10 +115,10 @@ public class DownLoadTaskThread implements Runnable {
LogUtils.loge("download Exception===>sleeping before");
File targFile = new File(bean.getPath(), bean.getFileName());
file.renameTo(targFile);//重命名
file.delete();//删除临时文件
Thread.sleep(5000);
Thread.sleep(3000);
LogUtils.loge("download Exception===>sleeping after");
observer.onFinish(bean, bean.getTaskId(), currentTotal);
file.delete();//删除临时文件
}else {
LogUtils.loge("下载失败");
if (observer != null) {
@@ -128,6 +129,15 @@ public class DownLoadTaskThread implements Runnable {
} catch (Exception e) {
e.printStackTrace();
LogUtils.loge("download Exception===>"+e.getMessage());
// TODO: 2025/12/17 异常检验-tmp是否存在不存在再建一个0KB临时空文件可保证 文件以后一定能下载下来
File file = new File(bean.getPath(), bean.getFileName()+"-tmp");
if(!file.exists()){
try {
file.createNewFile();
} catch (IOException ex) {
LogUtils.loge("exception happen before file create,must create tmp file");
}
}
if (observer != null) {
observer.onError(bean, bean.getTaskId(), e.getMessage());
}

View File

@@ -4,9 +4,11 @@ import android.content.Context;
import android.os.Handler;
import android.text.TextUtils;
import com.android.SharePreUtils;
import com.android.database.AdsInfoBeanDao;
import com.android.database.DaoManager;
import com.android.database.lib.AdsInfoBean;
import com.android.database.lib.AppBean;
import com.android.database.lib.DownLoadTaskBean;
import com.android.database.lib.NetShortAppBean;
import com.android.database.lib.ShortAppBean;
@@ -14,10 +16,12 @@ import com.android.download.DownLoadManeger;
import com.android.eventbaus.EventBusUtils;
import com.android.eventbaus.MessageEvent;
import com.android.nebulasdk.bean.ADInfo;
import com.android.nebulasdk.bean.UploadADBean;
import com.android.util.FileUtil;
import com.android.util.GsonUtil;
import com.android.util.LogUtils;
import com.android.util.PakageInstallUtil;
import com.android.util.SharedPreferencesUtil;
import java.io.File;
import java.util.ArrayList;
@@ -89,6 +93,7 @@ public class ADManager implements DownLoadManeger.DownloadListener {
// }
// }
if(adsInfoBean.getId()==12){ //删除收藏数据
configUtilSaveNetEmptyApp();
DaoManager.getInstance().delete(AdsInfoBean.class,adsInfoBean);
DaoManager.getInstance().deleteAll(NetShortAppBean.class);
List<NetShortAppBean> netShortAppBeanList = DaoManager.getInstance().queryList(NetShortAppBean.class);
@@ -115,18 +120,20 @@ public class ADManager implements DownLoadManeger.DownloadListener {
// if(adsInfoBean.getAdId()==aDInfo.getAdId()){ //是同一个任务,根据版本号更新新资源
LogUtils.loge("aDInfo.getAdVersion()|adsInfoBean.getAdVersion():"+aDInfo.getAdVersion()+"|"+adsInfoBean.getAdVersion());
if(Long.valueOf(aDInfo.getAdVersion())!=adsInfoBean.getAdVersion()){ //更新新资源
SharePreUtils.removeKeyFromAllMaps(String.valueOf(adsInfoBean.getAdResourceId()));
LogUtils.loge("广告位"+adsInfoBean.getId()+"已存在,是同一个任务同步资源,需要删除缓存文件:"+GsonUtil.GsonString(adsInfoBean));//先删除旧任务的缓存文件,再更新数据
String dbLocalFilePath=adsInfoBean.getLocalFilePath();
if(!TextUtils.isEmpty(dbLocalFilePath)) {
int lastIndex = dbLocalFilePath.lastIndexOf("/");
String fileName=lastIndex==-1?dbLocalFilePath:dbLocalFilePath.substring(lastIndex+1);
if(!aDInfo.getAdUri().contains(fileName)){
if(TextUtils.isEmpty(aDInfo.getAdUri())||!aDInfo.getAdUri().contains(fileName)){
File oldfile = new File(dbLocalFilePath);
List<AdsInfoBean> adSInfoBeanList =DaoManager.getInstance().queryByKeyList(AdsInfoBean.class,"localFilePath",dbLocalFilePath);
if (oldfile.exists()&& adSInfoBeanList.size()==1) {
oldfile.delete();
}
}else {
//todo SharePreUtils.addRelation(String.valueOf(aDInfo.getAdResourceId()),String.valueOf(0));
LogUtils.loge("广告位仅换apk不换图 fresh apk not fresh img,dont delete img but download");
}
}
@@ -151,7 +158,9 @@ public class ADManager implements DownLoadManeger.DownloadListener {
if(aDInfo.getState()!=null) {
adsInfoBean.setState(aDInfo.getState());
}
if(adsInfoBean.getId()==12){
configUtilSaveNetEmptyApp();//任务更新必须移除 隔离收藏夹记录
}
if(aDInfo.getState()==0){ //任务已关闭,需要删除数据
LogUtils.loge(aDInfo.getId()+"任务已关闭,暂不删除本地缓存");
adsInfoBean.setState(0);
@@ -177,6 +186,7 @@ public class ADManager implements DownLoadManeger.DownloadListener {
continue;
}
DaoManager.getInstance().update(AdsInfoBean.class,adsInfoBean);
SharePreUtils.savePreference();
analysisResInfo(aDInfo,adsInfoBean);
}else {
LogUtils.loge(aDInfo.getId()+"广告任务已存在");
@@ -191,7 +201,7 @@ public class ADManager implements DownLoadManeger.DownloadListener {
// }
if(aDInfo.getId()==12){ //删除收藏数据
LogUtils.loge(aDInfo.getId()+"任务已关闭,删除本地缓存");
DaoManager.getInstance().delete(AdsInfoBean.class,adsInfoBean);
//DaoManager.getInstance().delete(AdsInfoBean.class,adsInfoBean);
DaoManager.getInstance().deleteAll(NetShortAppBean.class);
List<NetShortAppBean> netShortAppBeanList = DaoManager.getInstance().queryList(NetShortAppBean.class);
if(netShortAppBeanList==null){
@@ -205,7 +215,9 @@ public class ADManager implements DownLoadManeger.DownloadListener {
//打开任务
adsInfoBean.setState(1); //任务已存在只需要改变数据,不需要重新下载
DaoManager.getInstance().update(AdsInfoBean.class,adsInfoBean);
if(adsInfoBean.getId()==12){
analysisResInfo(aDInfo,adsInfoBean);
}
}
// if(aDInfo.getState()==0){ //任务已关闭,需要删除数据
// LogUtils.loge("任务已关闭,删除本地缓存"+adsInfoBean.getLocalFilePath());
@@ -278,7 +290,16 @@ public class ADManager implements DownLoadManeger.DownloadListener {
EventBusUtils.postMsg(new MessageEvent(MessageEvent.ACTION_UPADATE_DATA_SOURCE));
}
private void configUtilSaveNetEmptyApp() {
String sharePrefrencesString = SharedPreferencesUtil.getSharePrefrencesString(mContext, SharedPreferencesUtil.CONFIG_NET_DEFEND_BOOKMARK_APP);
List<AppBean> saveList=new ArrayList<>();
if(TextUtils.isEmpty(sharePrefrencesString)){
return;
}
String saveConfig = GsonUtil.GsonString(saveList);
SharedPreferencesUtil.setSharePrefrencesString(mContext,SharedPreferencesUtil.CONFIG_NET_DEFEND_BOOKMARK_APP,saveConfig);
}
/***
* 根据id来查询广告展位信息
*/
@@ -335,7 +356,7 @@ public class ADManager implements DownLoadManeger.DownloadListener {
}else {
LogUtils.loge("app已安装");
SharePreUtils.addRelation(String.valueOf(adinfo.getAdResourceId()),String.valueOf(3));
}
}else {
LogUtils.loge("没有app任务");
@@ -343,9 +364,9 @@ public class ADManager implements DownLoadManeger.DownloadListener {
LogUtils.loge("analysisResInfo AdType===>"+adinfo.getAdType());
if(ADTYPE_VIDEO.equals(adinfo.getAdType())){
if(adinfo.getAdUri()!=null&&adinfo.getAdSize()!=null) {
addDownloadTask(adsInfoBean, adinfo.getAdUri(), 0, adinfo.getAdSize());
}
// if(adinfo.getAdUri()!=null&&adinfo.getAdSize()!=null) {
// addDownloadTask(adsInfoBean, adinfo.getAdUri(), 0, adinfo.getAdSize());
// }
}else if(ADTYPE_FAV.equals(adinfo.getAdType())){
if( adinfo.getInfo()!=null){
String[] packageArray =adinfo.getInfo().split(",");
@@ -396,17 +417,28 @@ public class ADManager implements DownLoadManeger.DownloadListener {
LogUtils.loge("onFinish filePath==>" + bean.getTaskType()+"||"+appInstallPath);
if(bean.getTaskType()==1){
boolean flag = PakageInstallUtil.silentInstall(mContext, appInstallPath);
List<AdsInfoBean> list = DaoManager.getInstance().queryByKeyList(AdsInfoBean.class, "appUrl", bean.getUrl());
AdsInfoBean adsInfoBean=null;
if(list!=null&&list.size()>0){
adsInfoBean=list.get(0);
}else {
LogUtils.loge("onFinish: adsInfoBean table no apk url data");
}
AdsInfoBean finalAdsInfoBean = adsInfoBean;
handler.postDelayed(new Runnable() {
@Override
public void run() {
if (flag) {
FileUtil.deleteFile(appInstallPath); //安装成功后删除文件
if (flag&&finalAdsInfoBean!=null&&PakageInstallUtil.checkAppInstall(mContext, finalAdsInfoBean.getInfo())) {
if(PakageInstallUtil.checkAppInstall(mContext, finalAdsInfoBean.getInfo(), (int) finalAdsInfoBean.getAppVersion())){
//升级apk 不删apk文件 交给clearApkFileByPowerDown 去删除文件
FileUtil.deleteFile(appInstallPath); //安装成功后删除文件
}
LogUtils.loge("executeAppInstall==>" + flag + "||" + appInstallPath);
}
EventBusUtils.postMsg(new MessageEvent(MessageEvent.ACTION_UPADATE_DATA_SOURCE));
}
},1000*5);
// EventBusUtils.postMsg(new MessageEvent(MessageEvent.ACTION_UPADATE_DATA_SOURCE));
}else{
EventBusUtils.postMsg(new MessageEvent(MessageEvent.ACTION_UPADATE_DATA_SOURCE));
}
@@ -454,7 +486,117 @@ public class ADManager implements DownLoadManeger.DownloadListener {
DownLoadManeger.getInstance().updateDownloadTaskBeanTable();
}
public void clearApkFileByPowerDown(){
List<DownLoadTaskBean> list = DaoManager.getInstance().queryList(DownLoadTaskBean.class);
if(list==null||list.size()==0){
String apkDir = FileUtil.getBakPath(mContext, 1);
File apkFile = new File(apkDir);
if(apkFile.exists()){
File[] files = apkFile.listFiles();
for (int i = 0; i < files.length; i++) {
boolean isApk = files[i].getAbsolutePath().endsWith("apk");
if(isApk){
String apkFileName = files[i].getName();
int apkFileContainIndex=-1;
List<AdsInfoBean> adsInfoBeanList = DaoManager.getInstance().queryList(AdsInfoBean.class);
for (int j = 0; j < adsInfoBeanList.size(); j++) {
if(!TextUtils.isEmpty(adsInfoBeanList.get(j).getAppUrl())&&adsInfoBeanList.get(j).getAppUrl().contains(apkFileName)){
apkFileContainIndex=j;
break;
}
}
if(apkFileContainIndex==-1){
files[i].delete();
LogUtils.loge("apk data rm need delete app");
}else {
AdsInfoBean adsInfoBean = adsInfoBeanList.get(apkFileContainIndex);
if(!(PakageInstallUtil.checkAppInstall(mContext,adsInfoBean.getInfo()))||PakageInstallUtil.checkAppUpdate(mContext,adsInfoBean.getInfo(),(int) adsInfoBean.getAppVersion())){ //需要跟新app
LogUtils.loge("need reinstall app");
addDownloadTask(adsInfoBean,adsInfoBean.getAppUrl(),1,adsInfoBean.getAppSize());
}else {
LogUtils.loge("need delete app");
files[i].delete();
}
}
}
}
}
}
}
public void hasDownloadButLostFile(AdsInfoBean adsInfoBean,String url, int taskType,long fileSize){
addDownloadTask(adsInfoBean,url,taskType,fileSize);
}
public boolean checkTaskQueueClear(){
return DownLoadManeger.getInstance().checkTaskQueueClear();
}
public ArrayList<UploadADBean.RecordsBean> getUploadAds(){
List<AdsInfoBean> adsInfoBeanList = DaoManager.getInstance().queryByKeyList(AdsInfoBean.class, "state", "1");
ArrayList<UploadADBean.RecordsBean> uploadAdList=new ArrayList<>();
for (int i = 0; i < adsInfoBeanList.size(); i++) {
AdsInfoBean adsInfoBean = adsInfoBeanList.get(i);
String appUrl=adsInfoBean.getAppUrl();
if(!TextUtils.isEmpty(adsInfoBean.getAppUrl())){
// int lastIndex = appUrl.lastIndexOf("/");
// String fileName=lastIndex==-1?appUrl:appUrl.substring(lastIndex+1);
// String filePath = FileUtil.getBakPath(mContext,1)+"/"+fileName;
// String tmpFilePath = FileUtil.getBakPath(mContext, 1) + "/" + fileName + "-tmp";
// File tmpFile=new File(tmpFilePath);
// File file =new File(filePath);
if((PakageInstallUtil.checkAppInstall(mContext,adsInfoBean.getInfo()))&& !PakageInstallUtil.checkAppUpdate(mContext,adsInfoBean.getInfo(),(int) adsInfoBean.getAppVersion())) {
if (!SharePreUtils.filterByKeyValue(String.valueOf(adsInfoBean.getAdResourceId()), String.valueOf(2))) {
SharePreUtils.addRelation(String.valueOf(adsInfoBean.getAdResourceId()), String.valueOf(2));
UploadADBean.RecordsBean recordsBean = new UploadADBean.RecordsBean();
recordsBean.setAdResourceId(adsInfoBean.getAdResourceId());
if (SharePreUtils.filterByKeyValue(String.valueOf(adsInfoBean.getAdResourceId()), String.valueOf(3))) {//考虑到3为app已安装 analysisResInfo
recordsBean.setType(3);
} else {
recordsBean.setType(2);
}
uploadAdList.add(recordsBean);
}
LogUtils.loge("==============resid" + adsInfoBean.getAdResourceId());
}
// }else if(file.exists()||(tmpFile.exists()&&tmpFile.length()==adsInfoBean.getAppSize())){
// if(!SharePreUtils.filterByKeyValue(String.valueOf(adsInfoBean.getAdResourceId()),String.valueOf(1))){
// SharePreUtils.addRelation(String.valueOf(adsInfoBean.getAdResourceId()),String.valueOf(1));
// UploadADBean.RecordsBean recordsBean = new UploadADBean.RecordsBean();
// recordsBean.setAdResourceId(adsInfoBean.getAdResourceId());
// recordsBean.setType(1);
// uploadAdList.add(recordsBean);
// }
// }
}
if(!TextUtils.isEmpty(adsInfoBean.getLocalFilePath())){
File file = new File(adsInfoBean.getLocalFilePath());
File tmpFile=new File(adsInfoBean.getLocalFilePath()+"-tmp");
if(file.exists()||(tmpFile.exists()&&tmpFile.length()==adsInfoBean.getAdSize())){
if(ADTYPE_IMAGE.equalsIgnoreCase(adsInfoBean.getAdType())){
if(!SharePreUtils.filterByKeyValue(String.valueOf(adsInfoBean.getAdResourceId()),String.valueOf(0))){
SharePreUtils.addRelation(String.valueOf(adsInfoBean.getAdResourceId()),String.valueOf(0));
UploadADBean.RecordsBean recordsBean = new UploadADBean.RecordsBean();
recordsBean.setAdResourceId(adsInfoBean.getAdResourceId());
recordsBean.setType(0);
uploadAdList.add(recordsBean);
}
}else if(ADTYPE_VIDEO.equalsIgnoreCase(adsInfoBean.getAdType())){
if(!SharePreUtils.filterByKeyValue(String.valueOf(adsInfoBean.getAdResourceId()),String.valueOf(1))){
SharePreUtils.addRelation(String.valueOf(adsInfoBean.getAdResourceId()),String.valueOf(1));
UploadADBean.RecordsBean recordsBean = new UploadADBean.RecordsBean();
recordsBean.setAdResourceId(adsInfoBean.getAdResourceId());
recordsBean.setType(1);
uploadAdList.add(recordsBean);
}
}
LogUtils.loge("==============resid"+adsInfoBean.getAdResourceId());
}
}
}
if(uploadAdList.size()>0){
LogUtils.loge(GsonUtil.GsonString(uploadAdList));
}
return uploadAdList;
}
}

View File

@@ -5,17 +5,23 @@ import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.text.TextUtils;
import com.android.SharePreUtils;
import com.android.database.DaoManager;
import com.android.database.lib.AdsInfoBean;
import com.android.database.lib.AppBean;
import com.android.database.lib.DownLoadTaskBean;
import com.android.database.lib.LocalAppBean;
import com.android.database.lib.MusicAppBean;
import com.android.database.lib.NetShortAppBean;
import com.android.database.lib.RecommendAppBean;
import com.android.database.lib.ShortAppBean;
import com.android.database.lib.VideoAppBean;
import com.android.eventbaus.EventBusUtils;
import com.android.eventbaus.MessageEvent;
import com.android.nebulasdk.bean.FavNaviBean;
import com.android.util.FileUtil;
import com.android.util.GsonUtil;
import com.android.util.LogUtils;
import com.android.util.PakageInstallUtil;
@@ -67,7 +73,8 @@ public class AppManager {
/**主界面推荐数据*/
private Map<Integer, FavNaviBean> favRecommendCacheData = new HashMap<>();
//包名-应用名
private Map<String, String> appNameCacheData = new HashMap<>();
private AppManager(Context context){
this.mContext = context;
@@ -119,7 +126,7 @@ public class AppManager {
for (NetShortAppBean netShortAppBean:netShortAppBeanList){
if(filterAppBeanMap.size()<SHORT_COUNT) {
if(PakageInstallUtil.checkAppInstall(mContext, netShortAppBean.getPackageName())){
if(PakageInstallUtil.checkAppInstall(mContext, netShortAppBean.getPackageName())&&!configUtilContainNetApp(netShortAppBean.getPackageName())){
ShortAppBean shortAppBean = new ShortAppBean();
shortAppBean.setCategory(netShortAppBean.getCategory());
shortAppBean.setAppName(netShortAppBean.getAppName());
@@ -137,19 +144,40 @@ public class AppManager {
}
for (ShortAppBean shortAppBean:shortAppBeanList){
if(filterAppBeanMap.size()<SHORT_COUNT) {
if(PakageInstallUtil.checkAppInstall(mContext, shortAppBean.getPackageName())) {
shortAppBean.setIndex(netShortStartIndex);
filterAppBeanMap.put(shortAppBean.getPackageName(), shortAppBean);
netShortStartIndex++;
// for (ShortAppBean shortAppBean:shortAppBeanList){
// if(filterAppBeanMap.size()<SHORT_COUNT) {
// if(PakageInstallUtil.checkAppInstall(mContext, shortAppBean.getPackageName())) {
// shortAppBean.setIndex(netShortStartIndex);
// filterAppBeanMap.put(shortAppBean.getPackageName(), shortAppBean);
// netShortStartIndex++;
// }
// }else {
// break;
// }
// }
String sharePrefrencesString = SharedPreferencesUtil.getSharePrefrencesString(mContext, SharedPreferencesUtil.CONFIG_LOCAL_BOOKMARK_APP);
LogUtils.loge("SNFLauncher--->getSharePrefrencesStringList4444 :" + GsonUtil.GsonString(netShortAppBeanList));
if(!TextUtils.isEmpty(sharePrefrencesString)){
List<AppBean> appBeans = GsonUtil.GsonToList(sharePrefrencesString, AppBean.class);
for (AppBean bean : appBeans) {
if(filterAppBeanMap.size() < SHORT_COUNT){
if (PakageInstallUtil.checkAppInstall(mContext, bean.getPackageName())) {
ShortAppBean shortAppBean = new ShortAppBean();
shortAppBean.setCategory(bean.getCategory());
shortAppBean.setAppName(bean.getAppName());
shortAppBean.setId(bean.getId());
shortAppBean.setIndex(netShortStartIndex);
shortAppBean.setItemType(bean.getItemType());
shortAppBean.setPackageName(bean.getPackageName());
filterAppBeanMap.put(bean.getPackageName(), shortAppBean);
netShortStartIndex++;
}
}else {
break;
}
}else {
break;
}
}
List<ShortAppBean> newShortAppBeanList = new ArrayList<>();
Iterator it= filterAppBeanMap.keySet().iterator();
while (it.hasNext()){
@@ -252,7 +280,12 @@ public class AppManager {
shortAppBean.setCategory(CATEGORY_SHORT);
shortAppBean.setItemType(1);
DaoManager.getInstance().insert(ShortAppBean.class,shortAppBean);
// 存 本地收藏夹config.xml 与 网络配置隔离收藏夹分开 book compose
if(!configUtilContainNetApp(appBean.getPackageName())){
configUtilSaveLocalApp(appBean);
}else {
configUtilRmNetApp(appBean.getPackageName());
}
}else {
@@ -263,8 +296,10 @@ public class AppManager {
}
List<NetShortAppBean> netShortAppBeanList = DaoManager.getInstance().queryByKeyList(NetShortAppBean.class,"packageName",appBean.getPackageName());
if(netShortAppBeanList!=null&&netShortAppBeanList.size()>0){
DaoManager.getInstance().deleteByList(NetShortAppBean.class,netShortAppBeanList);
configUtilSaveNetApp(appBean);
//DaoManager.getInstance().deleteByList(NetShortAppBean.class,netShortAppBeanList);
}
configUtilRmLocalApp(appBean);
}
// if(appBeanList!=null&&appBeanList.size()>0){
@@ -286,7 +321,89 @@ public class AppManager {
}
private void configUtilSaveLocalApp(AppBean appBean) {
String sharePrefrencesString = SharedPreferencesUtil.getSharePrefrencesString(mContext, SharedPreferencesUtil.CONFIG_LOCAL_BOOKMARK_APP);
List<AppBean> saveList=null;
if(TextUtils.isEmpty(sharePrefrencesString)){
saveList=new ArrayList<>();
}
if(!TextUtils.isEmpty(sharePrefrencesString)){
saveList= GsonUtil.GsonToList(sharePrefrencesString ,AppBean.class);
}
if(saveList!=null){
saveList.add(appBean);
String saveConfig = GsonUtil.GsonString(saveList);
SharedPreferencesUtil.setSharePrefrencesString(mContext,SharedPreferencesUtil.CONFIG_LOCAL_BOOKMARK_APP,saveConfig);
}
}
private void configUtilRmLocalApp(AppBean appBean) {
String sharePrefrencesString = SharedPreferencesUtil.getSharePrefrencesString(mContext, SharedPreferencesUtil.CONFIG_LOCAL_BOOKMARK_APP);
if(!TextUtils.isEmpty(sharePrefrencesString)){
List<AppBean> appBeans = GsonUtil.GsonToList(sharePrefrencesString, AppBean.class);
List<AppBean> appNewBeans=new ArrayList<>();
for (AppBean bean :appBeans) {
if(!bean.getPackageName().equalsIgnoreCase(appBean.getPackageName())){
appNewBeans.add(bean);
}
}
String saveConfig = GsonUtil.GsonString(appNewBeans);
LogUtils.loge("SNFLauncher--->configUtilRmLocalApp() List:"+saveConfig);
SharedPreferencesUtil.setSharePrefrencesString(mContext,SharedPreferencesUtil.CONFIG_LOCAL_BOOKMARK_APP,saveConfig);
}
}
private void configUtilSaveNetApp(AppBean appBean) {
String sharePrefrencesString = SharedPreferencesUtil.getSharePrefrencesString(mContext, SharedPreferencesUtil.CONFIG_NET_DEFEND_BOOKMARK_APP);
List<AppBean> saveList=null;
if(TextUtils.isEmpty(sharePrefrencesString)){
saveList=new ArrayList<>();
}
if(!TextUtils.isEmpty(sharePrefrencesString)){
saveList= GsonUtil.GsonToList(sharePrefrencesString ,AppBean.class);
}
if(saveList!=null){
saveList.add(appBean);
String saveConfig = GsonUtil.GsonString(saveList);
SharedPreferencesUtil.setSharePrefrencesString(mContext,SharedPreferencesUtil.CONFIG_NET_DEFEND_BOOKMARK_APP,saveConfig);
}
}
private void configUtilRmNetApp(String name) {
String sharePrefrencesString = SharedPreferencesUtil.getSharePrefrencesString(mContext, SharedPreferencesUtil.CONFIG_NET_DEFEND_BOOKMARK_APP);
if(!TextUtils.isEmpty(sharePrefrencesString)){
List<AppBean> appBeans = GsonUtil.GsonToList(sharePrefrencesString, AppBean.class);
List<AppBean> appNewBeans=new ArrayList<>();
for (AppBean bean :appBeans) {
if(!bean.getPackageName().equalsIgnoreCase(name)){
appNewBeans.add(bean);
}
}
String saveConfig = GsonUtil.GsonString(appNewBeans);
LogUtils.loge("SNFLauncher--->configUtilRmNetApp() List:"+saveConfig);
SharedPreferencesUtil.setSharePrefrencesString(mContext,SharedPreferencesUtil.CONFIG_NET_DEFEND_BOOKMARK_APP,saveConfig);
}
}
private boolean configUtilContainNetApp(String name) {
boolean isContain = false;
String sharePrefrencesString = SharedPreferencesUtil.getSharePrefrencesString(mContext, SharedPreferencesUtil.CONFIG_NET_DEFEND_BOOKMARK_APP);
if(!TextUtils.isEmpty(sharePrefrencesString)){
List<AppBean> appBeans = GsonUtil.GsonToList(sharePrefrencesString, AppBean.class);
for (AppBean bean :appBeans) {
if(bean.getPackageName().equalsIgnoreCase(name)){
isContain = true;
break;
}
}
}
return isContain;
}
public void addShortcutInfo(String packageName,String apName,int index){
List<AppBean> shortcutInfoBeanList =DaoManager.getInstance().queryByKeyList(AppBean.class,"packageName",packageName);
@@ -348,6 +465,7 @@ public class AppManager {
favNaviBean.setAppName(jsonobjectTmp.getString("name"));
favRecommendCacheData.put(favNaviBean.getIndex(), favNaviBean);
}
appNameCacheData.put(packageName,jsonobjectTmp.getString("name"));
}
@@ -367,26 +485,40 @@ public class AppManager {
// DaoManager.getInstance().update(ShortAppBean.class,tmpapp);
// }
// }
String sharePrefrencesString = SharedPreferencesUtil.getSharePrefrencesString(mContext, SharedPreferencesUtil.CONFIG_LOCAL_BOOKMARK_APP);
int flag =SharedPreferencesUtil.getSharePrefrencesInteger(mContext,SharedPreferencesUtil.CONFIG_INIOR);
if(flag==1){//数据已初始化完成
if(flag==1&&!TextUtils.isEmpty(sharePrefrencesString)){//数据已初始化完成
return;
}
String[] shortcutArray =appStr.split(",");
List<ShortAppBean> appBeanList = new ArrayList<>();
List<AppBean> appBeans =new ArrayList<>();
for (int i = 0; i < shortcutArray.length; i++) {
String packageName= shortcutArray[i];
if(PakageInstallUtil.checkAppInstall(mContext,packageName)) {
// if(PakageInstallUtil.checkAppInstall(mContext,packageName)) {
ShortAppBean appBean = new ShortAppBean();
AppBean bean =new AppBean();
appBean.setPackageName(packageName);
bean.setPackageName(packageName);
appBean.setIndex(i);
bean.setIndex(i);
bean.setId(5L);
appBean.setItemType(1);
bean.setItemType(1);
bean.setCategory(0);
bean.setAppName(appNameCacheData.get(packageName));
bean.setSelect(1);
appBeanList.add(appBean);
}
appBeans.add(bean);
// }
}
if(appBeans.size()>0){
String saveConfig = GsonUtil.GsonString(appBeans);
SharedPreferencesUtil.setSharePrefrencesString(mContext,SharedPreferencesUtil.CONFIG_LOCAL_BOOKMARK_APP,saveConfig);
}
if(appBeanList.size()>0){
DaoManager.getInstance().insert(ShortAppBean.class, appBeanList);
SharedPreferencesUtil.setSharePrefrencesInteger(mContext, SharedPreferencesUtil.CONFIG_INIOR, 1);
@@ -586,12 +718,55 @@ public class AppManager {
File file = new File(adsInfoBean.getLocalFilePath());
if (file.exists()) {
favNaviBean = new FavNaviBean(index, adsInfoBean.getLocalFilePath(), adsInfoBean.getInfo(), null);
}else {
}else {//考虑下载好图片重启后变回 -tmp文件的情况
File tempFile=new File(adsInfoBean.getLocalFilePath()+"-tmp");
//对已上报的图片文件 系统丢失文件情况 重新下载
if(!tempFile.exists()&& SharePreUtils.filterByKeyValue(String.valueOf(adsInfoBean.getAdResourceId()),String.valueOf(0))){
LogUtils.loge("sys lost file which has upload,redownload it but not notify");
ADManager.getInstance().hasDownloadButLostFile(adsInfoBean,adsInfoBean.getAdUri(),0,adsInfoBean.getAdSize());
}
if(tempFile.exists()&&tempFile.length()==adsInfoBean.getAdSize()){
tempFile.renameTo(file);
tempFile.delete();
EventBusUtils.postMsg(new MessageEvent(MessageEvent.ACTION_UPADATE_DATA_SOURCE));
LogUtils.loge("下载大小完成但重命名失败同时下载任务已清除图片至始至终未显示处理 sys rename failed bug solved");
}
LogUtils.loge(file.getPath()+" is not exit");
}
}
}else {
LogUtils.loge(adsInfoBean.getInfo()+" is not exit");
LogUtils.loge(adsInfoBean.getInfo()+" is not exit");//考虑下载好APK重启后变回 -tmp文件的情况 补充clearApkFileByPowerDown 下载任务有脏数据情况下
String appUrl = adsInfoBean.getAppUrl();
boolean taskTableHasIt=false;
List<DownLoadTaskBean> list = DaoManager.getInstance().queryList(DownLoadTaskBean.class);
for (int i = 0; i <list.size() ; i++) {
if(list.get(i).getUrl().equalsIgnoreCase(appUrl)){
taskTableHasIt=true;
break;
}
}
if(!TextUtils.isEmpty(appUrl)&&!taskTableHasIt){
int lastIndex = appUrl.lastIndexOf("/");
String fileName=lastIndex==-1?appUrl:appUrl.substring(lastIndex+1);
String filePath = FileUtil.getBakPath(mContext,1)+"/"+fileName;
String tmpFilePath = FileUtil.getBakPath(mContext, 1) + "/" + fileName + "-tmp";
File tmpFile=new File(tmpFilePath);
File file =new File(filePath);
if(tmpFile.exists()&&tmpFile.length()==adsInfoBean.getAppSize()){
LogUtils.loge(adsInfoBean.getInfo()+" but apk tmpfile is exit");
tmpFile.renameTo(file);
//tmpFile.delete();
if(list!=null&&list.size()>0){
boolean flag = PakageInstallUtil.silentInstall(mContext, file.getAbsolutePath());
LogUtils.loge("no task and restart sys apk back to tmp install result="+flag);
}
}else if(file.exists()&&file.length()==adsInfoBean.getAppSize()){
if(list!=null&&list.size()>0){
boolean flag = PakageInstallUtil.silentInstall(mContext, file.getAbsolutePath());
LogUtils.loge("no task and restart sys apk not install result="+flag);
}
}
}
}
}

View File

@@ -0,0 +1,77 @@
package com.android.nebulasdk.bean;
import java.util.List;
public class UploadADBean {
/**
* mac : 9C:00:D3:86:31:DF
* cpu : 1747248796593488611d7d3114575b9
* records : [{"adId":494,"type":0,"ts":1763450525769},{"adId":494,"type":2,"ts":1763450525769},{"adId":494,"type":0,"ts":1763450925769},{"adId":396,"type":0,"ts":1763450525769}]
*/
private String mac;
private String cpu;
private List<RecordsBean> records;
public String getMac() {
return mac;
}
public void setMac(String mac) {
this.mac = mac;
}
public String getCpu() {
return cpu;
}
public void setCpu(String cpu) {
this.cpu = cpu;
}
public List<RecordsBean> getRecords() {
return records;
}
public void setRecords(List<RecordsBean> records) {
this.records = records;
}
public static class RecordsBean {
/**
* adId : 494
* type : 0
* ts : 1763450525769
*/
private long adResourceId;
private int type;
//private long ts;
public long getAdResourceId() {
return adResourceId;
}
public void setAdResourceId(long adId) {
this.adResourceId = adId;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
// public long getTs() {
// return ts;
// }
//
// public void setTs(long ts) {
// this.ts = ts;
// }
}
}

View File

@@ -36,7 +36,7 @@ public class CategoryAppPresenter {
public CategoryAppPresenter(Context context,AppnetCallback appnetCallback) {
this.mAppnetCallback = appnetCallback;
AppManager.init(context);
//AppManager.init(context);
}

View File

@@ -0,0 +1,69 @@
package com.android.nebulasdk.presenter;
import android.content.Context;
import android.util.Log;
import com.android.MXQConfig;
import com.android.api.ServerInterface;
import com.android.api.biz.Biz;
import com.android.api.biz.OnBaseListener;
import com.android.api.biz.bizimpl.BizImpl;
import com.android.api.response.EventResponse;
import com.android.nebulasdk.bean.ADInfoResponse;
import com.android.nebulasdk.bean.UploadADBean;
import com.android.nebulasdk.presenter.callback.AppnetCallback;
import com.android.util.DeviceUtil;
import com.android.util.GsonUtil;
import com.android.util.LogUtils;
import com.android.util.RKDeviceUtil;
import java.util.ArrayList;
public class DownLoadAdPresenter {
private Biz biz;
private AppnetCallback mAppnetCallback;
public DownLoadAdPresenter(AppnetCallback mAppnetCallback) {
this.mAppnetCallback = mAppnetCallback;
biz = new BizImpl(ServerInterface.createHttpUrl());
}
public void postDownLoadAds(Context context,ArrayList<UploadADBean.RecordsBean> recordsBeans){
UploadADBean uploadADBean=new UploadADBean();
String cpuId ="";
if(MXQConfig.ALLWINNER_PLATFORM.equalsIgnoreCase(MXQConfig.getManufacturer())) {
cpuId = DeviceUtil.getCpu();
}else if(MXQConfig.RK_PLATFORM.equalsIgnoreCase(MXQConfig.getManufacturer())){
cpuId = RKDeviceUtil.getCpu();
}
uploadADBean.setCpu(cpuId);
uploadADBean.setMac(DeviceUtil.getEthernetMac());
uploadADBean.setRecords(recordsBeans);
biz.postDownloadAd(uploadADBean, new OnBaseListener() {
@Override
public void onResponse(String result) {
LogUtils.loge(GsonUtil.GsonString(result));
if(GsonUtil.isJson(result)){
try {
EventResponse eventResponse = GsonUtil.GsonToBean(result, EventResponse.class);
if (eventResponse.getCode() == ServerInterface.SUCCESS) {
mAppnetCallback.onResult(eventResponse.getData());
} else {
mAppnetCallback.onViewFailureString(eventResponse.getCode(), eventResponse.getMsg());
}
} catch (Exception e) {
e.printStackTrace();
mAppnetCallback.onExceptionFailure("json 解析异常:"+e.getMessage());
}
}else {
mAppnetCallback.onServerFailure(0,"获取签到信息,服务器繁忙··");
}
}
@Override
public void onFailure(String e, int code) {
mAppnetCallback.onServerFailure(code,e);
}
});
}
}

View File

@@ -19,6 +19,7 @@ public class IntentUtil {
intent = context.getPackageManager().getLeanbackLaunchIntentForPackage(packageName);
}
if(intent!=null){
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}else {
Toast.makeText( context, tipmsg, Toast.LENGTH_SHORT).show();

View File

@@ -34,7 +34,7 @@ public class PakageInstallUtil {
private static final String TAG= "INSTALL";
/**检测app是否安装*/
public static boolean checkAppUpdate(Context context,String packageName,int versionCode){
public static boolean checkAppUpdate(Context context,String packageName,int versionCode){
try {
PackageInfo packageInfo = context.getPackageManager().getPackageInfo(packageName,0);

View File

@@ -27,6 +27,9 @@ public class SharedPreferencesUtil {
/**是否要更新app信息到服务器*/
public static final String CONFIG_INIOR="CONFIG_INIOR";
public static final String CONFIG_LOCAL_BOOKMARK_APP="config_local_bookmark_app";//本地配置 收藏夹
public static final String CONFIG_NET_DEFEND_BOOKMARK_APP="config_net_defend_bookmark_app";//网络隔离 收藏夹
public static final String CONFIG_RESET_DISABLE_FRESHDATA_FLAG="config_reset_disable_freshdata_flag";//重置设备禁止刷新数据为true可刷新
public static String getSharePrefrencesString(Context context,String key){
SharedPreferences sharedPreferences=context.getSharedPreferences(SHARE_NAME,0);