From: kfl_614 Date: Mon, 23 Mar 2020 12:42:36 +0000 (+0800) Subject: 1.完成IcLauncher基础功能。 X-Git-Url: http://git.snicker.com.cn/?a=commitdiff_plain;h=2d62d878f25258ab8ae230093bf0b5f5a9b5b192;p=launcher4.git 1.完成IcLauncher基础功能。 Signed-off-by: kfl_614 --- diff --git a/app/build.gradle b/app/build.gradle index bb500df..e7d619a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,14 +1,23 @@ apply plugin: 'com.android.application' +static def getL02ApkBaseName() { + return "ICL02Launcher" +} + + android { + + def currentVersionCode = getVersionCode() + def currentVersionName = releaseTime() + compileSdkVersion 29 buildToolsVersion "29.0.2" defaultConfig { applicationId "com.ic.launcher" minSdkVersion 19 targetSdkVersion 29 - versionCode 1 - versionName "1.0" + versionCode currentVersionCode + versionName "${currentVersionName}" } dataBinding { @@ -21,14 +30,79 @@ android { sourceCompatibility JavaVersion.VERSION_1_8 } + sourceSets { + main { + jni.srcDirs = [] + manifest.srcFile 'src/main/AndroidManifest.xml' + java.srcDirs = ['src/main/java', 'src/main/aidl'] + resources.srcDirs = ['src/main/java', 'src/main/aidl'] + aidl.srcDirs = ['src/main/aidl'] + res.srcDirs = ['src/main/res'] + assets.srcDirs = ['src/main/assets'] + } + } + + signingConfigs { + key { + storeFile file("EQC_G5.jks") + storePassword "123456" + keyAlias "watch_g5" + keyPassword "123456" + } + } + buildTypes { release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + zipAlignEnabled true // zip 对齐优化 + shrinkResources true // 移除未使用的资源文件 + signingConfig signingConfigs.key + minifyEnabled true + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + renderscriptDebuggable = false + debuggable = false + jniDebuggable = false + manifestPlaceholders = [:] + } + + debug { + signingConfig signingConfigs.key + } + } + + android.applicationVariants.all { variant -> + variant.outputs.all { + if (variant.buildType.name == "release") { + outputFileName = "${getL02ApkBaseName()}_V${currentVersionCode}_${currentVersionName}_release.apk" + } else { + outputFileName = "${getL02ApkBaseName()}_V${currentVersionCode}_${currentVersionName}_debug.apk" + } } } } +def getVersionCode() { + def versionCodeFile = file('version_code.properties') + if (versionCodeFile.canRead()) { + Properties properties = new Properties() + properties.load(new FileInputStream(versionCodeFile)) + def versionCode = properties['VERSION_CODE'].toInteger()//读取version_code.properties文件存放的版本号。 + def runTasks = gradle.startParameter.taskNames + def task = ':app:assembleRelease' + if (task in runTasks) { + properties['VERSION_CODE'] = (++versionCode).toString() + properties.store(versionCodeFile.newWriter(), null) + } + + return versionCode + } else { + throw new GradleException("无法读取version_code.properties文件!") + } +} + +def releaseTime() { + return new Date().format("yyyyMMddHHmm", TimeZone.getTimeZone("GMT+08:00")) +} + dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation 'androidx.appcompat:appcompat:1.1.0' diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index f1b4245..a86af50 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -19,3 +19,105 @@ # If you keep the line number information, uncomment this to # hide the original source file name. #-renamesourcefileattribute SourceFile +-dontoptimize # 混合时不使用大小写混合,混合后的类名为小写 +-dontusemixedcaseclassnames # 混合时不使用大小写混合,混合后的类名为小写 +-dontskipnonpubliclibraryclasses # 不跳过library中的非public的类 +-dontskipnonpubliclibraryclassmembers # 不跳过library中的非public的类成员 +-dontpreverify # 不做预校验,preverify是proguard的四个步骤之一,Android平台不需要preverify,去掉这一步能够加快混淆速度 +-verbose # 在处理时打印冗长的信息 + +# 保留异常表,以便编译器知道哪些异常可能被抛出 +# 保留InnerClasses,否则外部无法引用内部类 +# 保留Signature,否则无法访问泛型 +-keepattributes Exceptions,SourceFile,LineNumberTable,EnclosingMethod,Signature,*Annotation*,InnerClasses,Deprecated + +################################## 需要保留的公共部分 ################################## +# 保留四大组件,自定义的Application等等这些类不被混淆 +-keep public class * extends android.app.Activity +-keep public class * extends android.app.Application +-keep public class * extends android.app.Service +-keep public class * extends android.content.BroadcastReceiver +-keep public class * extends android.content.ContentProvider +-keep public class * extends android.app.backup.BackupAgentHelper +-keep public class * extends android.preference.Preference +-keep public class * extends android.view.View +-keep public class com.android.vending.licensing.ILicensingService + +-keep class android.support.** { *; } +-keep public class * extends android.support.v4.** +-keep public class * extends android.support.v7.** +-keep public class * extends android.support.annotation.** +-keep public class * extends android.app.Fragment +-keep class com.google.** { *; } + +# 保留R下面的资源 +-keep class **.R$* {*;} +-keepclassmembers class **.R$* { + public static ; +} + +# 保留本地native方法不被混淆 +-keepclasseswithmembernames class * { + native ; +} + +# 保留在Activity中的方法参数是view的方法, +# 这样以来我们在layout中写的onClick就不会被影响 +-keepclassmembers class * extends android.app.Activity{ + public void *(android.view.View); +} + +# 保留我们自定义控件(继承自View)不被混淆 +-keep public class * extends android.view.View{ + *** get*(); + void set*(***); + public (android.content.Context); + public (android.content.Context, android.util.AttributeSet); + public (android.content.Context, android.util.AttributeSet, int); +} + +-keepclasseswithmembernames class * { + public (android.content.Context, android.util.AttributeSet); +} + +-keepclasseswithmembernames class * { + public (android.content.Context, android.util.AttributeSet, int); +} + +# 保留枚举类不被混淆 +-keepclassmembers enum * { + public static **[] values(); + public static ** valueOf(java.lang.String); +} + +# 保留Parcelable序列化类不被混淆 +-keep class * implements android.os.Parcelable { + public static final android.os.Parcelable$Creator *; +} + +# 保留Serializable序列化的类不被混淆 +-keepclassmembers class * implements java.io.Serializable { + static final long serialVersionUID; + private static final java.io.ObjectStreamField[] serialPersistentFields; + !static !transient ; + !private ; + !private ; + private void writeObject(java.io.ObjectOutputStream); + private void readObject(java.io.ObjectInputStream); + java.lang.Object writeReplace(); + java.lang.Object readResolve(); +} + +# 对于带有回调函数的onXXEvent、**On*Listener的,不能被混淆 +-keepclassmembers class * { + void *(**On*Event); + void *(**On*Listener); +} + + +-keep class com.sun.jna.** { *; } +-dontwarn com.sun.jna.** + +-keep public class com.android.support.a +-keep public class com.android.support.b +-keep public class rx.internal.util \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 5184a30..c8fe296 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,7 +1,8 @@ + package="com.ic.launcher" + android:sharedUserId="android.uid.system"> diff --git a/app/src/main/java/com/ic/launcher/IcLauncherApplication.java b/app/src/main/java/com/ic/launcher/IcLauncherApplication.java index 134dc0c..0779d2a 100644 --- a/app/src/main/java/com/ic/launcher/IcLauncherApplication.java +++ b/app/src/main/java/com/ic/launcher/IcLauncherApplication.java @@ -6,6 +6,7 @@ import com.ic.launcher.presenter.AppListPresenter; import com.ic.launcher.presenter.BatteryPresenter; import com.ic.launcher.presenter.PhoneStatePresenter; import com.ic.launcher.presenter.TimeDatePresenter; +import com.ic.launcher.util.CrashHandler; import com.ic.launcher.util.IcLog; public class IcLauncherApplication extends Application { @@ -25,6 +26,9 @@ public class IcLauncherApplication extends Application { mBatteryPresenter = new BatteryPresenter(this); timeDatePresenter = new TimeDatePresenter(this); appListPresenter = new AppListPresenter(this); + + CrashHandler crashHandler = CrashHandler.getInstance(); + crashHandler.init(getApplicationContext()); } public PhoneStatePresenter getPhoneStatePresenter() { diff --git a/app/src/main/java/com/ic/launcher/MainActivity.java b/app/src/main/java/com/ic/launcher/MainActivity.java index f47e5d8..53b24c7 100644 --- a/app/src/main/java/com/ic/launcher/MainActivity.java +++ b/app/src/main/java/com/ic/launcher/MainActivity.java @@ -5,6 +5,7 @@ import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; +import android.content.Intent; import android.os.Bundle; import com.ic.launcher.fragment.AppListFragment; @@ -21,6 +22,7 @@ public class MainActivity extends AppCompatActivity implements MainClockGestureDetectorImpl.OnClockGestureFlingListener, IChangeMainFragmentListener { + private static final String PACKAGE_NAME_LAUNCHER = "mobile.miki"; private FragmentManager fragmentManager; private List mAddFt; @@ -35,12 +37,23 @@ public class MainActivity extends AppCompatActivity implements mAddFt = new ArrayList<>(); fragmentManager = getSupportFragmentManager(); - crateFragment(); + l02MainFt = L02MainFragment.newInstance(); + commitFragment(l02MainFt); ServiceUtil.startServiceUtil(getApplicationContext(), - "com.ic.action.WORK_SERVICE", - getPackageName()); + "com.ic.action.WORK_SERVICE", getPackageName()); + } + + @Override + public void onDouble() { + try { + // 启动工厂测试 + Intent intent = getPackageManager().getLaunchIntentForPackage(PACKAGE_NAME_LAUNCHER); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); + startActivity(intent); + } catch (Exception ignored) { + } } @Override @@ -48,10 +61,21 @@ public class MainActivity extends AppCompatActivity implements switch (flag) { case 1: //左滑 + if (appListFt == null) { + appListFt = AppListFragment.newInstance(1); + } else { + appListFt.setMoveEndItem(false); + } commitFragment(appListFt); break; case 2: //右滑 + if (appListFt == null) { + appListFt = AppListFragment.newInstance(2); + } else { + appListFt.setMoveEndItem(true); + } + commitFragment(appListFt); break; } } @@ -62,11 +86,6 @@ public class MainActivity extends AppCompatActivity implements commitFragment(l02MainFt); } - private void crateFragment() { - l02MainFt = L02MainFragment.newInstance(); - appListFt = AppListFragment.newInstance(); - } - private void commitFragment(Fragment fragment) { FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); diff --git a/app/src/main/java/com/ic/launcher/adapter/AppInfoAdapter.java b/app/src/main/java/com/ic/launcher/adapter/AppInfoAdapter.java index ecdc53d..3c49af5 100644 --- a/app/src/main/java/com/ic/launcher/adapter/AppInfoAdapter.java +++ b/app/src/main/java/com/ic/launcher/adapter/AppInfoAdapter.java @@ -21,18 +21,22 @@ public class AppInfoAdapter extends RecyclerView.Adapter appArray; private ICheckAppItemListener mListener; - public AppInfoAdapter(Context context,ICheckAppItemListener listener) { + public AppInfoAdapter(Context context, ICheckAppItemListener listener) { this.mContext = context; appArray = new ArrayList<>(); this.mListener = listener; } - public void updateAppInfoList(List list){ + public void updateAppInfoList(List list) { appArray.clear(); appArray.addAll(list); notifyDataSetChanged(); } + public int getAppEndIndex() { + return appArray.size() - 1; + } + @NonNull @Override public AppHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { @@ -41,7 +45,7 @@ public class AppInfoAdapter extends RecyclerView.Adapter { + + private boolean[] stateList; + + private int oldCheckIndex=0; + + public IndicatorAdapter(boolean[] state){ + stateList = state; + } + + public void updateIndicatorState(int index){ + if(oldCheckIndex != index){ + stateList[index] = true; + stateList[oldCheckIndex] =false; + oldCheckIndex = index; + + notifyDataSetChanged(); + } + } + + @NonNull + @Override + public IndicatorHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + return new IndicatorHolder(ItemIndicatorLayoutBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false)); + } + + @Override + public void onBindViewHolder(@NonNull IndicatorHolder holder, int position) { + holder.bindItem(stateList[position]); + } + + @Override + public int getItemCount() { + return stateList.length; + } + + static class IndicatorHolder extends RecyclerView.ViewHolder { + private ItemIndicatorLayoutBinding binding = null; + + public IndicatorHolder(@NonNull ItemIndicatorLayoutBinding itemView) { + super(itemView.getRoot()); + binding = itemView; + } + + public void bindItem(boolean state) { + if (binding != null) { + binding.setIsCheckItem(state); + binding.executePendingBindings(); + } + } + } +} diff --git a/app/src/main/java/com/ic/launcher/configure/l02/L02AppInfo.java b/app/src/main/java/com/ic/launcher/configure/l02/L02AppInfo.java index 239ad06..1be15c0 100644 --- a/app/src/main/java/com/ic/launcher/configure/l02/L02AppInfo.java +++ b/app/src/main/java/com/ic/launcher/configure/l02/L02AppInfo.java @@ -28,10 +28,10 @@ public class L02AppInfo { "", "")); //天气 add(new AppInfoEntity(BACK_COLOUR, R.mipmap.icon_weather_l02, R.string.app_name_weather, - "com.ic.hardware", "com.ic.hardware.WeatherActivity")); + "com.ic.weather", "com.ic.weather.WeatherActivity")); //心率 add(new AppInfoEntity(BACK_COLOUR, R.mipmap.icon_heartrate_l02, R.string.app_name_heart, - "com.ic.hardware", "com.ic.hardware.BloodActivity")); + "com.ic.blood", "com.ic.blood.BloodActivity")); //支付包 add(new AppInfoEntity(BACK_COLOUR, R.mipmap.icon_alipay_l02, R.string.app_name_alipay, "com.eg.android.AlipayGphone", "com.alipay.watch.ui.MainActivity")); diff --git a/app/src/main/java/com/ic/launcher/fragment/AppListFragment.java b/app/src/main/java/com/ic/launcher/fragment/AppListFragment.java index 3bd0537..29ba6b7 100644 --- a/app/src/main/java/com/ic/launcher/fragment/AppListFragment.java +++ b/app/src/main/java/com/ic/launcher/fragment/AppListFragment.java @@ -8,11 +8,9 @@ import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; import androidx.lifecycle.ViewModelProvider; import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.LinearSmoothScroller; import androidx.recyclerview.widget.PagerSnapHelper; import androidx.recyclerview.widget.RecyclerView; -import android.util.SparseArray; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -20,14 +18,12 @@ import android.view.ViewGroup; import com.ic.launcher.IcLauncherApplication; import com.ic.launcher.R; import com.ic.launcher.adapter.AppInfoAdapter; -import com.ic.launcher.entity.AppInfoEntity; +import com.ic.launcher.adapter.IndicatorAdapter; import com.ic.launcher.listener.IChangeMainFragmentListener; import com.ic.launcher.listener.ICheckAppItemListener; import com.ic.launcher.mode.AppListModel; import com.ic.launcher.util.IcLog; -import static android.widget.AbsListView.OnScrollListener.SCROLL_STATE_IDLE; - public class AppListFragment extends Fragment { private static final String TAG = "AppListFragment"; @@ -37,13 +33,17 @@ public class AppListFragment extends Fragment { private IcLauncherApplication mApp; - private TopSmoothScroller mScroller; - private LinearLayoutManager mLayoutManager; private IChangeMainFragmentListener changeMainFragmentListener; private AppInfoAdapter appAdapter; private AppListModel appListModel; + private RecyclerView indicatorRv; + private IndicatorAdapter indicatorAdapter; + + //1 显示第一个 2 显示最后一个 + private int mCurrType; + @Override public void onAttach(@NonNull Context context) { super.onAttach(context); @@ -57,14 +57,22 @@ public class AppListFragment extends Fragment { } } - public static AppListFragment newInstance() { - return new AppListFragment(); + public static AppListFragment newInstance(int type) { + AppListFragment fragment = new AppListFragment(); + Bundle args = new Bundle(); + args.putInt("type", type); + fragment.setArguments(args); + return fragment; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mApp = (IcLauncherApplication) mContext.getApplicationContext(); + Bundle bundle = getArguments(); + if (bundle != null) { + mCurrType = bundle.getInt("type"); + } } @Override @@ -72,21 +80,45 @@ public class AppListFragment extends Fragment { Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_app_list, container, false); mAppRv = view.findViewById(R.id.app_list); + indicatorRv = view.findViewById(R.id.app_indicator_rv); + initRecyclerView(); initAppListModel(); + return view; } @Override public void onResume() { super.onResume(); - mScroller.setTargetPosition(0); - mLayoutManager.startSmoothScroll(mScroller); + IcLog.i(TAG, "onResume"); + if (mCurrType == 2) { + //只有初始化进来的时候才执行, + mAppRv.scrollToPosition(appAdapter.getAppEndIndex()); + indicatorAdapter.updateIndicatorState(appAdapter.getAppEndIndex()); + mCurrType = 0; + } } - private void initRecyclerView(){ - appAdapter = new AppInfoAdapter(mContext,itemListener); - mLayoutManager = new LinearLayoutManager(mContext, LinearLayoutManager.HORIZONTAL, false); + @Override + public void onPause() { + super.onPause(); + IcLog.i(TAG, "onPause"); + } + + public void setMoveEndItem(boolean move) { + if (move) { + mAppRv.scrollToPosition(appAdapter.getAppEndIndex()); + indicatorAdapter.updateIndicatorState(appAdapter.getAppEndIndex()); + } else { + mAppRv.scrollToPosition(0); + indicatorAdapter.updateIndicatorState(0); + } + } + + private void initRecyclerView() { + appAdapter = new AppInfoAdapter(mContext, itemListener); + LinearLayoutManager mLayoutManager = new LinearLayoutManager(mContext, LinearLayoutManager.HORIZONTAL, false); mAppRv.setLayoutManager(mLayoutManager); mAppRv.setAdapter(appAdapter); @@ -94,57 +126,81 @@ public class AppListFragment extends Fragment { new PagerSnapHelper().attachToRecyclerView(mAppRv); mAppRv.addOnScrollListener(scrollListener); - - mScroller = new TopSmoothScroller(mContext); } private void initAppListModel() { - - AppListModel.Factory factory = new AppListModel.Factory(mApp,mApp.getAppListPresenter()); + AppListModel.Factory factory = new AppListModel.Factory(mApp, mApp.getAppListPresenter()); appListModel = new ViewModelProvider(this, factory).get(AppListModel.class); appListModel.getObsAppInfoList().observe(getViewLifecycleOwner(), appList -> { appAdapter.updateAppInfoList(appList); }); + appListModel.getObsAppState().observe(getViewLifecycleOwner(), this::initIndicator); + appListModel.updateAppInfoList(); } + private void initIndicator(boolean[] state) { + indicatorAdapter = new IndicatorAdapter(state); + LinearLayoutManager mLayoutManager = new LinearLayoutManager(mContext, LinearLayoutManager.HORIZONTAL, false); + indicatorRv.setLayoutManager(mLayoutManager); + indicatorRv.setAdapter(indicatorAdapter); + } + private RecyclerView.OnScrollListener scrollListener = new RecyclerView.OnScrollListener() { - private boolean isAllowLeft = false; - private boolean isAllowRight = false; + private boolean isJudge = true; @Override public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); - if (newState == SCROLL_STATE_IDLE) { - if (!isAllowLeft || !isAllowRight) { - //此处返回主界面 - IcLog.i(TAG, "Change To Main Fragment"); - changeMainFragmentListener.onChangeMain(); - } + //IcLog.i(TAG, "newState:" + newState); + switch (newState) { + case RecyclerView.SCROLL_STATE_IDLE: + judgeItemPosition(recyclerView, isJudge); + break; + case RecyclerView.SCROLL_STATE_DRAGGING: + isJudge = true; + break; + case RecyclerView.SCROLL_STATE_SETTLING: + isJudge = false; + break; } } @Override public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); - isAllowLeft = mAppRv.canScrollHorizontally(-1); - isAllowRight = mAppRv.canScrollHorizontally(1); } - }; - private class TopSmoothScroller extends LinearSmoothScroller{ - public TopSmoothScroller(Context context) { - super(context); - } + private void judgeItemPosition(RecyclerView recyclerView, boolean isJudge) { + LinearLayoutManager manager = (LinearLayoutManager) recyclerView.getLayoutManager(); + if (manager == null) return; + //获取最后一个完全显示的ItemPosition ,角标值 + int first = manager.findFirstVisibleItemPosition(); + indicatorAdapter.updateIndicatorState(first); + if (!isJudge) { + return; + } + int lastVisibleItem = manager.findLastCompletelyVisibleItemPosition(); + //所有条目,数量值 + int totalItemCount = manager.getItemCount(); + + // 判断是否滚动到底部,并且是向右滚动 + if (lastVisibleItem == (totalItemCount - 1)) { + //加载更多功能的代码 + IcLog.i(TAG, "lastVisibleItem:" + lastVisibleItem); + changeMainFragmentListener.onChangeMain(); + } - @Override - protected int getHorizontalSnapPreference() { - return SNAP_TO_START;//具体见源码注释 + if (lastVisibleItem == 0) { + //加载更多功能的代码 + IcLog.i(TAG, "Start VisibleItem:" + lastVisibleItem); + changeMainFragmentListener.onChangeMain(); + } } - } + }; private ICheckAppItemListener itemListener = new ICheckAppItemListener() { @Override @@ -152,4 +208,6 @@ public class AppListFragment extends Fragment { appListModel.onStartAppActivity(pos); } }; + + } diff --git a/app/src/main/java/com/ic/launcher/fragment/L02MainFragment.java b/app/src/main/java/com/ic/launcher/fragment/L02MainFragment.java index 8027c59..439576b 100644 --- a/app/src/main/java/com/ic/launcher/fragment/L02MainFragment.java +++ b/app/src/main/java/com/ic/launcher/fragment/L02MainFragment.java @@ -17,10 +17,13 @@ import com.ic.launcher.R; import com.ic.launcher.fragment.l02.L02WatchFragment; import com.ic.launcher.fragment.l02.L02StatusBarFragment; import com.ic.launcher.listener.MainClockGestureDetectorImpl; +import com.ic.launcher.util.IcLog; public class L02MainFragment extends Fragment { + private static final String TAG = "L02MainFragment"; + private Context mContext; private L02StatusBarFragment statusBarFt; @@ -50,16 +53,24 @@ public class L02MainFragment extends Fragment { return view; } + @Override + public void onHiddenChanged(boolean hidden) { + super.onHiddenChanged(hidden); + IcLog.i(TAG, "onHiddenChanged hidden" + hidden); + } + @Override public void onResume() { super.onResume(); controlStatusBar(true); + IcLog.i(TAG, "onResume"); } @Override public void onPause() { super.onPause(); controlStatusBar(false); + IcLog.i(TAG, "onPause"); } @Override @@ -96,7 +107,7 @@ public class L02MainFragment extends Fragment { @SuppressLint("ClickableViewAccessibility") private void initOnTouchListener(View view) { - gesture = new GestureDetectorCompat(mContext,new MainClockGestureDetectorImpl(flingListener)); + gesture = new GestureDetectorCompat(mContext, new MainClockGestureDetectorImpl(flingListener)); view.setOnTouchListener((v, event) -> { if (gesture.onTouchEvent(event)) { return true; diff --git a/app/src/main/java/com/ic/launcher/fragment/l02/L02StatusBarFragment.java b/app/src/main/java/com/ic/launcher/fragment/l02/L02StatusBarFragment.java index bda1c9c..772592d 100644 --- a/app/src/main/java/com/ic/launcher/fragment/l02/L02StatusBarFragment.java +++ b/app/src/main/java/com/ic/launcher/fragment/l02/L02StatusBarFragment.java @@ -15,6 +15,7 @@ import android.view.ViewGroup; import com.ic.launcher.IcLauncherApplication; import com.ic.launcher.databinding.FragmentL02StatusBarBinding; import com.ic.launcher.mode.StateBarModel; +import com.ic.launcher.util.IcLog; public class L02StatusBarFragment extends Fragment { @@ -43,25 +44,30 @@ public class L02StatusBarFragment extends Fragment { Bundle savedInstanceState) { mStateBarBinding = FragmentL02StatusBarBinding.inflate(inflater, container, false); initStateBarModel(); + phoneModel.registerBatteryReceiver(); + IcLog.i(TAG,"onCreateView"); return mStateBarBinding.getRoot(); } @Override public void onResume() { super.onResume(); + IcLog.i(TAG,"onResume"); phoneModel.onResumeView(); } @Override public void onPause() { super.onPause(); + IcLog.i(TAG,"onPause"); phoneModel.onPauseView(); } @Override - public void onDestroyView() { - super.onDestroyView(); + public void onDestroy() { + super.onDestroy(); phoneModel.onDestroyView(); + phoneModel.unregisterBatteryReceiver(); } private void initStateBarModel() { @@ -92,6 +98,6 @@ public class L02StatusBarFragment extends Fragment { mStateBarBinding.setBatteryValue(value); }); - phoneModel.querySimCardState(); + phoneModel.onStartQuery(); } } diff --git a/app/src/main/java/com/ic/launcher/fragment/l02/L02WatchFragment.java b/app/src/main/java/com/ic/launcher/fragment/l02/L02WatchFragment.java index 0183986..e012afa 100644 --- a/app/src/main/java/com/ic/launcher/fragment/l02/L02WatchFragment.java +++ b/app/src/main/java/com/ic/launcher/fragment/l02/L02WatchFragment.java @@ -15,9 +15,12 @@ import android.view.ViewGroup; import com.ic.launcher.IcLauncherApplication; import com.ic.launcher.databinding.FragmentL02WatchBinding; import com.ic.launcher.mode.WatchFaceModel; +import com.ic.launcher.util.IcLog; public class L02WatchFragment extends Fragment { + private static final String TAG = "L02WatchFragment"; + private Context mContext; private IcLauncherApplication mApp; @@ -43,9 +46,6 @@ public class L02WatchFragment extends Fragment { watchBinding = FragmentL02WatchBinding.inflate(inflater, container, false); initWatchFaceModel(); - - watchBinding.setHeartValue("100"); - watchBinding.setStepValue("100000"); return watchBinding.getRoot(); } @@ -53,20 +53,23 @@ public class L02WatchFragment extends Fragment { public void onResume() { super.onResume(); watchFaceModel.onResumeView(); + IcLog.i(TAG, "onResume"); } @Override public void onPause() { super.onPause(); watchFaceModel.onPauseView(); + IcLog.i(TAG, "onPause"); } @Override - public void onDestroyView() { - super.onDestroyView(); + public void onDestroy() { + super.onDestroy(); watchFaceModel.onDestroyView(); } + private void initWatchFaceModel() { WatchFaceModel.Factory factory = new WatchFaceModel.Factory(mApp, mApp.getTimeDatePresenter()); watchFaceModel = new ViewModelProvider(this, factory).get(WatchFaceModel.class); @@ -82,5 +85,17 @@ public class L02WatchFragment extends Fragment { watchFaceModel.getObsYear().observe(getViewLifecycleOwner(), year -> { watchBinding.setWatchDate(year); }); + + watchFaceModel.getObsHardwareHeart().observe(getViewLifecycleOwner(), heart -> { + watchBinding.setHeartValue(heart); + }); + + watchFaceModel.getObsHardwarePed().observe(getViewLifecycleOwner(), ped -> { + watchBinding.setStepValue(ped); + }); + + watchBinding.setHeartValue("0"); + watchBinding.setStepValue("0"); + watchFaceModel.onCreateView(); } } diff --git a/app/src/main/java/com/ic/launcher/listener/MainClockGestureDetectorImpl.java b/app/src/main/java/com/ic/launcher/listener/MainClockGestureDetectorImpl.java index dab2a74..ece2e7c 100644 --- a/app/src/main/java/com/ic/launcher/listener/MainClockGestureDetectorImpl.java +++ b/app/src/main/java/com/ic/launcher/listener/MainClockGestureDetectorImpl.java @@ -1,5 +1,6 @@ package com.ic.launcher.listener; +import android.os.SystemClock; import android.view.GestureDetector; import android.view.MotionEvent; @@ -8,26 +9,37 @@ import com.ic.launcher.util.IcLog; public class MainClockGestureDetectorImpl extends GestureDetector.SimpleOnGestureListener { private static final String TAG = "MainClockGesture"; - public interface OnClockGestureFlingListener{ + private final int COUNTS = 2;//点击次数 + private final long DURATION = 3 * 1000;//规定有效时间 + private long[] mHits = new long[COUNTS]; + + public interface OnClockGestureFlingListener { void onDirection(int flag); + void onDouble(); } private OnClockGestureFlingListener mListener; - public MainClockGestureDetectorImpl(OnClockGestureFlingListener flingListener ){ + public MainClockGestureDetectorImpl(OnClockGestureFlingListener flingListener) { this.mListener = flingListener; } + @Override + public boolean onDown(MotionEvent e) { + doubleClick(); + return super.onDown(e); + } + @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { - IcLog.i(TAG, "onFling x1:" + e1.getX()+ "x2:" + e2.getX()); + IcLog.i(TAG, "onFling x1:" + e1.getX() + "x2:" + e2.getX()); - if(e1.getX() - e2.getX() > 30){ + if (e1.getX() - e2.getX() > 30) { onCallBackListener(1); return true; } - if(e2.getX() - e1.getX() > 30){ + if (e2.getX() - e1.getX() > 30) { onCallBackListener(2); return true; } @@ -35,9 +47,19 @@ public class MainClockGestureDetectorImpl extends GestureDetector.SimpleOnGestur return super.onFling(e1, e2, velocityX, velocityY); } - private void onCallBackListener(int flag){ - if(mListener != null){ + private void onCallBackListener(int flag) { + if (mListener != null) { mListener.onDirection(flag); } } + + private void doubleClick() { + System.arraycopy(mHits, 1, mHits, 0, mHits.length - 1); + mHits[mHits.length - 1] = SystemClock.uptimeMillis(); + if (mHits[0] >= (SystemClock.uptimeMillis() - DURATION)) { + if (mListener != null) { + mListener.onDouble(); + } + } + } } diff --git a/app/src/main/java/com/ic/launcher/mode/AppListModel.java b/app/src/main/java/com/ic/launcher/mode/AppListModel.java index 549e742..09693b5 100644 --- a/app/src/main/java/com/ic/launcher/mode/AppListModel.java +++ b/app/src/main/java/com/ic/launcher/mode/AppListModel.java @@ -19,18 +19,31 @@ public class AppListModel extends AndroidViewModel { private final AppListPresenter appListPresenter; private final LiveData> mObsAppInfoList; + private final LiveData mObsAppState; + private final LiveData mObsActivityError; public AppListModel(@NonNull Application application, @NonNull AppListPresenter appListPresenter) { super(application); this.appListPresenter = appListPresenter; mObsAppInfoList = appListPresenter.getObsAppInfoList(); + + mObsAppState = appListPresenter.getObsAppState(); + mObsActivityError = appListPresenter.getObsActivityError(); } public LiveData> getObsAppInfoList() { return mObsAppInfoList; } + public LiveData getObsAppState() { + return mObsAppState; + } + + public LiveData getObsActivityError() { + return mObsActivityError; + } + public void updateAppInfoList() { appListPresenter.updateSystemApp(); } diff --git a/app/src/main/java/com/ic/launcher/mode/StateBarModel.java b/app/src/main/java/com/ic/launcher/mode/StateBarModel.java index 6c02a44..3c6b3d3 100644 --- a/app/src/main/java/com/ic/launcher/mode/StateBarModel.java +++ b/app/src/main/java/com/ic/launcher/mode/StateBarModel.java @@ -10,6 +10,7 @@ import androidx.lifecycle.ViewModelProvider; import com.ic.launcher.presenter.BatteryPresenter; import com.ic.launcher.presenter.PhoneStatePresenter; +import com.ic.launcher.util.IcLog; public class StateBarModel extends AndroidViewModel { @@ -64,18 +65,25 @@ public class StateBarModel extends AndroidViewModel { return mObsBatteryResID; } - public void querySimCardState(){ - mPhonePresenter.querySimCardState(); + + public void onStartQuery(){ + mPhonePresenter.onStartQuery(); } public void onResumeView(){ mPhonePresenter.onResumePresenter(); + } + + public void registerBatteryReceiver(){ mBatteryPresenter.registerBatteryReceiver(); } + public void unregisterBatteryReceiver(){ + mBatteryPresenter.unRegisterBatteryReceiver(); + } + public void onPauseView(){ mPhonePresenter.onPausePresenter(); - mBatteryPresenter.unRegisterBatteryReceiver(); } public void onDestroyView(){ diff --git a/app/src/main/java/com/ic/launcher/mode/WatchFaceModel.java b/app/src/main/java/com/ic/launcher/mode/WatchFaceModel.java index dff03e4..eb1e6e4 100644 --- a/app/src/main/java/com/ic/launcher/mode/WatchFaceModel.java +++ b/app/src/main/java/com/ic/launcher/mode/WatchFaceModel.java @@ -5,10 +5,10 @@ import android.app.Application; import androidx.annotation.NonNull; import androidx.lifecycle.AndroidViewModel; import androidx.lifecycle.LiveData; -import androidx.lifecycle.MediatorLiveData; import androidx.lifecycle.ViewModel; import androidx.lifecycle.ViewModelProvider; +import com.ic.launcher.presenter.HardwarePresenter; import com.ic.launcher.presenter.TimeDatePresenter; import java.util.ArrayList; @@ -16,20 +16,29 @@ import java.util.ArrayList; public class WatchFaceModel extends AndroidViewModel { - private TimeDatePresenter timeDatePresenter; + private final TimeDatePresenter timeDatePresenter; + private final HardwarePresenter hardwarePresenter; private final LiveData> mObsTime; private final LiveData mObsYear; private final LiveData mObsWeek; + private final LiveData mObsHardwareHeart; + private final LiveData mObsHardwarePed; public WatchFaceModel(@NonNull Application application, @NonNull TimeDatePresenter timeDatePresenter) { super(application); + this.timeDatePresenter = timeDatePresenter; + hardwarePresenter = new HardwarePresenter(application); + mObsTime = timeDatePresenter.getObsTime(); mObsYear = timeDatePresenter.getObsYear(); mObsWeek = timeDatePresenter.getmObsWeek(); + + mObsHardwareHeart = hardwarePresenter.getObsHardwareHeart(); + mObsHardwarePed = hardwarePresenter.getObsHardwarePed(); } public LiveData> getObsTime() { @@ -44,8 +53,21 @@ public class WatchFaceModel extends AndroidViewModel { return mObsWeek; } + public LiveData getObsHardwareHeart() { + return mObsHardwareHeart; + } + + public LiveData getObsHardwarePed() { + return mObsHardwarePed; + } + + public void onCreateView(){ + hardwarePresenter.registerHardwareBroadcast(); + } + public void onResumeView() { timeDatePresenter.onResumePresenter(); + hardwarePresenter.sendGetPedBroadcast(); } public void onPauseView() { @@ -54,6 +76,7 @@ public class WatchFaceModel extends AndroidViewModel { public void onDestroyView() { timeDatePresenter.unRegisterTimeDateReceiver(); + hardwarePresenter.unRegisterHardwareReceiver(); } public static class Factory extends ViewModelProvider.NewInstanceFactory { diff --git a/app/src/main/java/com/ic/launcher/presenter/AppListPresenter.java b/app/src/main/java/com/ic/launcher/presenter/AppListPresenter.java index e07f88f..4ff9840 100644 --- a/app/src/main/java/com/ic/launcher/presenter/AppListPresenter.java +++ b/app/src/main/java/com/ic/launcher/presenter/AppListPresenter.java @@ -17,16 +17,18 @@ public class AppListPresenter { private Context context; private MutableLiveData> mObsAppInfoList; + private MutableLiveData mObsAppState; private MutableLiveData mObsActivityError; private String mErrorInfo; - public AppListPresenter(Context context){ - this.context=context; + public AppListPresenter(Context context) { + this.context = context; mObsAppInfoList = new MutableLiveData<>(); mObsActivityError = new MutableLiveData<>(); + mObsAppState = new MutableLiveData<>(); - mErrorInfo = context.getString(R.string.error_start_activity); + mErrorInfo = context.getString(R.string.error_start_activity); } public MutableLiveData> getObsAppInfoList() { @@ -37,12 +39,22 @@ public class AppListPresenter { return mObsActivityError; } - public void updateSystemApp(){ + public MutableLiveData getObsAppState() { + return mObsAppState; + } + + public void updateSystemApp() { mObsAppInfoList.setValue(L02AppInfo.mL02DefaultAppList); + boolean[] state = new boolean[L02AppInfo.mL02DefaultAppList.size()]; + for (int i = 0; i < state.length; i++) { + state[i] = false; + } + state[0] = true; + mObsAppState.setValue(state); } - public void startAppActivity(int index){ - if(index <0 || index > L02AppInfo.mL02DefaultAppList.size()){ + public void startAppActivity(int index) { + if (index < 0 || index > L02AppInfo.mL02DefaultAppList.size()) { mObsActivityError.setValue(mErrorInfo); return; } @@ -51,7 +63,7 @@ public class AppListPresenter { String pck = entity.getPackageName(); String activity = entity.getActivityName(); - if(TextUtils.isEmpty(pck) || TextUtils.isEmpty(activity)){ + if (TextUtils.isEmpty(pck) || TextUtils.isEmpty(activity)) { mObsActivityError.setValue(mErrorInfo); return; } @@ -61,7 +73,7 @@ public class AppListPresenter { intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setComponent(new ComponentName(pck, activity)); context.startActivity(intent); - } catch (Exception e ) { + } catch (Exception e) { mObsActivityError.setValue(mErrorInfo); } } diff --git a/app/src/main/java/com/ic/launcher/presenter/BatteryPresenter.java b/app/src/main/java/com/ic/launcher/presenter/BatteryPresenter.java index 53f0f84..9ca23e4 100644 --- a/app/src/main/java/com/ic/launcher/presenter/BatteryPresenter.java +++ b/app/src/main/java/com/ic/launcher/presenter/BatteryPresenter.java @@ -10,6 +10,7 @@ import android.text.TextUtils; import androidx.lifecycle.MediatorLiveData; import com.ic.launcher.configure.l02.L02Icon; +import com.ic.launcher.util.IcLog; public class BatteryPresenter { @@ -46,10 +47,15 @@ public class BatteryPresenter { } public void unRegisterBatteryReceiver() { - mContext.unregisterReceiver(mIntentReceiver); + try { + mContext.unregisterReceiver(mIntentReceiver); + }catch (Exception e){ + IcLog.e("BatteryPresenter",e.getMessage()); + } + } - private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { + private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { diff --git a/app/src/main/java/com/ic/launcher/presenter/HardwarePresenter.java b/app/src/main/java/com/ic/launcher/presenter/HardwarePresenter.java new file mode 100644 index 0000000..73eed9f --- /dev/null +++ b/app/src/main/java/com/ic/launcher/presenter/HardwarePresenter.java @@ -0,0 +1,76 @@ +package com.ic.launcher.presenter; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.text.TextUtils; + +import androidx.lifecycle.MediatorLiveData; + +public class HardwarePresenter { + + private static final String HEART_ACTION = "com.ic.action.BLOOD_HEART"; + private static final String PED_ACTION = "com.ic.action.PED_COUNT"; + + private static final String GET_PED_ACTION = "com.ic.action.GET_PED_COUNT"; + + private Context mContext; + private MediatorLiveData mObsHardwareHeart; + private MediatorLiveData mObsHardwarePed; + + public HardwarePresenter(Context context) { + + this.mContext = context; + + mObsHardwareHeart = new MediatorLiveData<>(); + mObsHardwarePed = new MediatorLiveData<>(); + } + + public MediatorLiveData getObsHardwareHeart() { + return mObsHardwareHeart; + } + + public MediatorLiveData getObsHardwarePed() { + return mObsHardwarePed; + } + + public void registerHardwareBroadcast() { + IntentFilter filter = new IntentFilter(); + filter.addAction(PED_ACTION); + filter.addAction(HEART_ACTION); + mContext.registerReceiver(mIntentReceiver, filter); + } + + public void unRegisterHardwareReceiver() { + mContext.unregisterReceiver(mIntentReceiver); + } + + public void sendGetPedBroadcast(){ + Intent pedIntent = new Intent(); + pedIntent.setAction(GET_PED_ACTION); + mContext.sendBroadcast(pedIntent); + } + + private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (intent != null) { + String acyion = intent.getAction(); + if(TextUtils.isEmpty(acyion)){ + return; + } + switch (acyion) { + case PED_ACTION: + int count = intent.getIntExtra("PED_COUNT", 0); + mObsHardwarePed.setValue(String.valueOf(count)); + break; + case HEART_ACTION: + int heart = intent.getIntExtra("BLOOD_HEART", 0); + mObsHardwareHeart.setValue(String.valueOf(heart)); + break; + } + } + } + }; +} diff --git a/app/src/main/java/com/ic/launcher/presenter/PhoneStatePresenter.java b/app/src/main/java/com/ic/launcher/presenter/PhoneStatePresenter.java index 52293bc..71d5afe 100644 --- a/app/src/main/java/com/ic/launcher/presenter/PhoneStatePresenter.java +++ b/app/src/main/java/com/ic/launcher/presenter/PhoneStatePresenter.java @@ -21,13 +21,13 @@ public class PhoneStatePresenter { private MediatorLiveData mObsPhoneSignalID; private MediatorLiveData mObsPhoneTransportID; + private QuerySimCardState simCardState; private QueryTrafficPooler trafficPooler; private TelephonyManager mTM; private Thread mThread; - - private boolean isSimCard = false; + private Thread mQueryThread; public PhoneStatePresenter(Context context) { mTM = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); @@ -36,6 +36,7 @@ public class PhoneStatePresenter { mObsPhoneTransportID = new MediatorLiveData<>(); trafficPooler = new QueryTrafficPooler(mObsPhoneTransportID); + simCardState = new QuerySimCardState(mTM,mObsPhoneTypeID,mObsPhoneSignalID); } public LiveData getPhoneTypeObservable() { @@ -50,50 +51,27 @@ public class PhoneStatePresenter { return mObsPhoneTransportID; } - public void querySimCardState() { - int resIdIndex = 0; - if (mTM == null) { - return; - } - - int simState = mTM.getSimState(); - switch (simState) { - case TelephonyManager.SIM_STATE_READY: - resIdIndex = 2; - break; - case TelephonyManager.SIM_STATE_NETWORK_LOCKED: - case TelephonyManager.SIM_STATE_PUK_REQUIRED: - case TelephonyManager.SIM_STATE_PIN_REQUIRED: - resIdIndex = 1; - break; - } - - if (resIdIndex == 2) { - mObsPhoneTypeID.setValue(queryPhoneNetworkTypeResId(mTM)); - mObsPhoneSignalID.setValue(l02SignalResId[6]); - startQueryTraffic(); - isSimCard = true; - } else if (resIdIndex == 1) { - mObsPhoneSignalID.setValue(l02SignalResId[1]); - } else { - mObsPhoneSignalID.setValue(l02SignalResId[0]); - } + public void onStartQuery(){ + mQueryThread = new Thread(simCardState); + mQueryThread.start(); + startQueryTraffic(); } public void onResumePresenter() { - if (isSimCard) { - resumeQueryTraffic(); - listenPhoneState(); - } + resumeQuerySimCard(); + resumeQueryTraffic(); + listenPhoneState(); } public void onPausePresenter() { + pauseQuerySimCard(); pauseQueryTraffic(); stopListenPhoneState(); } public void onDestroyPresenter() { stopQueryTraffic(); + stopQuerySimCard(); mTM=null; } @@ -110,6 +88,26 @@ public class PhoneStatePresenter { mThread = null; } + public void resumeQuerySimCard() { + if (mQueryThread != null && simCardState != null) { + simCardState.resumeQueryThread(); + } + } + + public void pauseQuerySimCard() { + if (mQueryThread != null && simCardState != null) { + simCardState.pauseQueryThread(); + } + } + + private void stopQuerySimCard() { + if (mQueryThread != null) { + mQueryThread.interrupt(); + } + + mQueryThread = null; + } + public void resumeQueryTraffic() { if (mThread != null && trafficPooler != null) { trafficPooler.resumeQueryThread(); @@ -148,12 +146,7 @@ public class PhoneStatePresenter { } }; - private int queryPhoneNetworkTypeResId(TelephonyManager tm) { - if (tm.getNetworkType() == TelephonyManager.NETWORK_TYPE_LTE) { - return l02PhoneTypeResId[0]; - } - return -1; - } + private int checkSignalLevel(int dbm){ int index=6; diff --git a/app/src/main/java/com/ic/launcher/presenter/QuerySimCardState.java b/app/src/main/java/com/ic/launcher/presenter/QuerySimCardState.java new file mode 100644 index 0000000..0bc3808 --- /dev/null +++ b/app/src/main/java/com/ic/launcher/presenter/QuerySimCardState.java @@ -0,0 +1,70 @@ +package com.ic.launcher.presenter; + +import android.telephony.TelephonyManager; + +import androidx.lifecycle.MediatorLiveData; + +import com.ic.launcher.util.IcLog; + +import static com.ic.launcher.configure.l02.L02Icon.l02PhoneTypeResId; +import static com.ic.launcher.configure.l02.L02Icon.l02SignalResId; + +public class QuerySimCardState extends QueryThread { + + private static final String TAG = "QuerySimCardState"; + + private TelephonyManager mTM; + private MediatorLiveData mObsPhoneTypeID; + private MediatorLiveData mObsPhoneSignalID; + + public QuerySimCardState(TelephonyManager mTM, + MediatorLiveData mObsPhoneTypeID, + MediatorLiveData mObsPhoneSignalID) { + this.mTM=mTM; + this.mObsPhoneTypeID=mObsPhoneTypeID; + this.mObsPhoneSignalID=mObsPhoneSignalID; + } + + @Override + void onThreadExecute() { + querySimCardState(); + } + + private void querySimCardState() { + int resIdIndex = 0; + if (mTM == null) { + return; + } + + int simState = mTM.getSimState(); + + IcLog.i(TAG,"simState:"+simState); + + switch (simState) { + case TelephonyManager.SIM_STATE_READY: + resIdIndex = 2; + break; + case TelephonyManager.SIM_STATE_NETWORK_LOCKED: + case TelephonyManager.SIM_STATE_PUK_REQUIRED: + case TelephonyManager.SIM_STATE_PIN_REQUIRED: + resIdIndex = 1; + break; + } + + if (resIdIndex == 2) { + mObsPhoneTypeID.postValue(l02PhoneTypeResId[0]); + mObsPhoneSignalID.postValue(l02SignalResId[6]); + } else if (resIdIndex == 1) { + mObsPhoneSignalID.postValue(l02SignalResId[1]); + } else { + mObsPhoneSignalID.postValue(l02SignalResId[0]); + } + } + + private int queryPhoneNetworkTypeResId(TelephonyManager tm) { + if (tm.getNetworkType() == TelephonyManager.NETWORK_TYPE_LTE) { + return l02PhoneTypeResId[0]; + } + return -1; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/ic/launcher/presenter/TimeDatePresenter.java b/app/src/main/java/com/ic/launcher/presenter/TimeDatePresenter.java index be1e7ac..49bfe38 100644 --- a/app/src/main/java/com/ic/launcher/presenter/TimeDatePresenter.java +++ b/app/src/main/java/com/ic/launcher/presenter/TimeDatePresenter.java @@ -77,10 +77,14 @@ public class TimeDatePresenter { } public void unRegisterTimeDateReceiver() { - mContext.unregisterReceiver(mIntentReceiver); + try { + mContext.unregisterReceiver(mIntentReceiver); + }catch (Exception e){ + IcLog.e(TAG,e.getMessage()); + } } - private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { + private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (Intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) { diff --git a/app/src/main/java/com/ic/launcher/util/CrashHandler.java b/app/src/main/java/com/ic/launcher/util/CrashHandler.java new file mode 100644 index 0000000..2396a75 --- /dev/null +++ b/app/src/main/java/com/ic/launcher/util/CrashHandler.java @@ -0,0 +1,213 @@ +package com.ic.launcher.util; + +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.os.Build; +import android.os.Environment; +import android.os.Looper; +import android.util.Log; +import android.widget.Toast; + +import com.ic.launcher.R; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.Writer; +import java.lang.reflect.Field; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +/** + * Created by Administrator on 2017/5/18. + */ + +public class CrashHandler implements Thread.UncaughtExceptionHandler { + public static final String TAG = CrashHandler.class.getName(); + + // 系统默认的UncaughtException处理类 + private Thread.UncaughtExceptionHandler mDefaultHandler; + // CrashHandler实例 + private static CrashHandler INSTANCE = new CrashHandler(); + // 程序的Context对象 + private Context mContext; + // 用来存储设备信息和异常信息 + private Map infos = new HashMap(); + // 用于格式化日期,作为日志文件名的一部分 + private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS", Locale.getDefault()); + private DateFormat dateFormatDate = new SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()); + + /** + * 保证只有一个CrashHandler实例 + */ + private CrashHandler() { + } + + /** + * 获取CrashHandler实例 ,单例模式 + */ + public static CrashHandler getInstance() { + return INSTANCE; + } + + /** + * 初始化 + * + * @param context + */ + public void init(Context context) { + mContext = context; + // 获取系统默认的UncaughtException处理器 + mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler(); + // 设置该CrashHandler为程序的默认处理器 + Thread.setDefaultUncaughtExceptionHandler(this); + } + + /** + * 当UncaughtException发生时会转入该函数来处理 + */ + @Override + public void uncaughtException(Thread thread, Throwable ex) { + if (!handleException(ex) && mDefaultHandler != null) { + // 如果用户没有处理则让系统默认的异常处理器来处理 + mDefaultHandler.uncaughtException(thread, ex); + } else { + try { + Thread.sleep(3000); + } catch (InterruptedException e) { +// Log.e(TAG, "error : " + e); + e.printStackTrace(); + } + } + + // 退出程序 + ex.printStackTrace(); + android.os.Process.killProcess(android.os.Process.myPid()); + System.exit(1); + } + + /** + * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成. + * + * @param ex + * @return true:如果处理了该异常信息;否则返回false. + */ + private boolean handleException(Throwable ex) { + if (ex == null) { + return false; + } + // 使用Toast来显示异常信息 + new Thread() { + @Override + public void run() { + Looper.prepare(); + if (mContext != null) { + Toast.makeText(mContext, R.string.program_abnormal, Toast.LENGTH_LONG) + .show(); + Looper.loop(); + } + } + }.start(); + // 收集设备参数信息 + collectDeviceInfo(mContext); + // 保存日志文件 + saveCrashInfo2File(ex); + return true; + } + + /** + * 收集设备参数信息 + * + * @param ctx + */ + public void collectDeviceInfo(Context ctx) { + infos.clear(); + infos.put("===", " PackageInfo ==="); + try { + PackageManager pm = ctx.getPackageManager(); + PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), PackageManager.GET_ACTIVITIES); + + if (pi != null) { + String versionName = pi.versionName; + String versionCode = pi.versionCode + ""; + infos.put("versionName", versionName); + infos.put("versionCode", versionCode); + } + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "an error occured when collect package info " + e); + } + + infos.put("===", " Build ==="); + Field[] fields = Build.class.getDeclaredFields(); + for (Field field : fields) { + try { + field.setAccessible(true); + infos.put(field.getName(), field.get(null).toString()); + Log.d(TAG, field.getName() + ":" + field.get(null)); + } catch (Exception e) { + Log.e(TAG, "an error occured when collect crash info," + e); + } + } + } + + /** + * 保存错误信息到文件中 + * + * @param ex + * @return 返回文件名称, 便于将文件传送到服务器 + */ + private String saveCrashInfo2File(Throwable ex) { + + String time = formatter.format(new Date()); + StringBuilder sb = new StringBuilder(); + sb.append("=== ").append(time).append(" ===\n"); + + Writer writer = new StringWriter(); + PrintWriter printWriter = new PrintWriter(writer); + ex.printStackTrace(printWriter); +// ex.printStackTrace(); + Throwable cause = ex.getCause(); + while (cause != null) { + cause.printStackTrace(printWriter); + cause = cause.getCause(); +// cause.printStackTrace(); + } + printWriter.close(); + String result = writer.toString(); + sb.append(result); + sb.append("\n"); + + sb.append("--- DEVICE INFO ---\n"); + for (Map.Entry entry : infos.entrySet()) { + String key = entry.getKey(); + String value = entry.getValue(); + sb.append(key).append("=").append(value).append("\n"); + } + sb.append("\n\n"); + + try { + String fileName = "IcLauncher-" + dateFormatDate.format(new Date()) + ".log"; + if (Environment.getExternalStorageState().equals( + Environment.MEDIA_MOUNTED)) { + File dir = new File(Environment.getExternalStorageDirectory().getPath(), "Android/ic/crash/IcLauncher"); + String path = dir.getPath(); + if (!dir.exists()) { + dir.mkdirs(); + } + FileOutputStream fos = new FileOutputStream(new File(path, fileName), true); + fos.write(sb.toString().getBytes()); + fos.close(); + } + return fileName; + } catch (Exception e) { + Log.e(TAG, "an error occured while writing file...," + e); + } + return null; + } +} diff --git a/app/src/main/java/com/ic/launcher/util/ServiceUtil.java b/app/src/main/java/com/ic/launcher/util/ServiceUtil.java index c79a084..1a3b429 100644 --- a/app/src/main/java/com/ic/launcher/util/ServiceUtil.java +++ b/app/src/main/java/com/ic/launcher/util/ServiceUtil.java @@ -19,9 +19,10 @@ public class ServiceUtil { } } - public static void bindServiceUtil(Context context , String action, ServiceConnection connection,int type) { + public static void bindServiceUtil(Context context , String action, ServiceConnection connection,String pck,int type) { Intent in = getExplicitIntent(context, new Intent(action)); if(in != null){ + in.setPackage(pck); in.putExtra("REQ_TYPE",type); context.bindService(in, connection, 0); } diff --git a/app/src/main/res/drawable/ic_transparent_circle.xml b/app/src/main/res/drawable/ic_transparent_circle.xml new file mode 100644 index 0000000..7fd130f --- /dev/null +++ b/app/src/main/res/drawable/ic_transparent_circle.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_white_circle.xml b/app/src/main/res/drawable/ic_white_circle.xml new file mode 100644 index 0000000..a032825 --- /dev/null +++ b/app/src/main/res/drawable/ic_white_circle.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/l02_battery_charging_anim.xml b/app/src/main/res/drawable/l02_battery_charging_anim.xml index b9ab884..f460bf9 100644 --- a/app/src/main/res/drawable/l02_battery_charging_anim.xml +++ b/app/src/main/res/drawable/l02_battery_charging_anim.xml @@ -3,20 +3,20 @@ android:oneshot="false"> + android:duration="800" /> + android:duration="800" /> + android:duration="800" /> + android:duration="800" /> + android:duration="800" /> + android:duration="800" /> \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_app_list.xml b/app/src/main/res/layout/fragment_app_list.xml index cf356fd..9def55e 100644 --- a/app/src/main/res/layout/fragment_app_list.xml +++ b/app/src/main/res/layout/fragment_app_list.xml @@ -1,5 +1,5 @@ - + android:layout_height="match_parent" + android:overScrollMode="never"/> - \ No newline at end of file + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_indicator_layout.xml b/app/src/main/res/layout/item_indicator_layout.xml new file mode 100644 index 0000000..8ca6c6d --- /dev/null +++ b/app/src/main/res/layout/item_indicator_layout.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 79c519f..2078193 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -16,4 +16,6 @@ 设置 应用程序启动失败 + + 很抱歉,程序出现异常,即将退出 diff --git a/app/version_code.properties b/app/version_code.properties new file mode 100644 index 0000000..9d0e34f --- /dev/null +++ b/app/version_code.properties @@ -0,0 +1,2 @@ +#Sat Mar 07 15:05:05 CST 2020 +VERSION_CODE=10