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 {
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'
# 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 <fields>;
+}
+
+# 保留本地native方法不被混淆
+-keepclasseswithmembernames class * {
+ native <methods>;
+}
+
+# 保留在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 <init>(android.content.Context);
+ public <init>(android.content.Context, android.util.AttributeSet);
+ public <init>(android.content.Context, android.util.AttributeSet, int);
+}
+
+-keepclasseswithmembernames class * {
+ public <init>(android.content.Context, android.util.AttributeSet);
+}
+
+-keepclasseswithmembernames class * {
+ public <init>(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 <fields>;
+ !private <fields>;
+ !private <methods>;
+ 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
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
- package="com.ic.launcher">
+ package="com.ic.launcher"
+ android:sharedUserId="android.uid.system">
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
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 {
mBatteryPresenter = new BatteryPresenter(this);
timeDatePresenter = new TimeDatePresenter(this);
appListPresenter = new AppListPresenter(this);
+
+ CrashHandler crashHandler = CrashHandler.getInstance();
+ crashHandler.init(getApplicationContext());
}
public PhoneStatePresenter getPhoneStatePresenter() {
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
+import android.content.Intent;
import android.os.Bundle;
import com.ic.launcher.fragment.AppListFragment;
MainClockGestureDetectorImpl.OnClockGestureFlingListener,
IChangeMainFragmentListener {
+ private static final String PACKAGE_NAME_LAUNCHER = "mobile.miki";
private FragmentManager fragmentManager;
private List<Fragment> mAddFt;
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
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;
}
}
commitFragment(l02MainFt);
}
- private void crateFragment() {
- l02MainFt = L02MainFragment.newInstance();
- appListFt = AppListFragment.newInstance();
- }
-
private void commitFragment(Fragment fragment) {
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
private List<AppInfoEntity> 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<AppInfoEntity> list){
+ public void updateAppInfoList(List<AppInfoEntity> list) {
appArray.clear();
appArray.addAll(list);
notifyDataSetChanged();
}
+ public int getAppEndIndex() {
+ return appArray.size() - 1;
+ }
+
@NonNull
@Override
public AppHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
@Override
public void onBindViewHolder(@NonNull AppHolder holder, int position) {
- holder.bindAppInfo(mContext, appArray.get(position),mListener,position);
+ holder.bindAppInfo(mContext, appArray.get(position), mListener, position);
}
@Override
}
- public void bindAppInfo(Context context, AppInfoEntity entity, ICheckAppItemListener listener,int pos) {
+ public void bindAppInfo(Context context, AppInfoEntity entity, ICheckAppItemListener listener, int pos) {
if (binding == null || entity == null) {
return;
}
--- /dev/null
+package com.ic.launcher.adapter;
+
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.ic.launcher.databinding.ItemIndicatorLayoutBinding;
+
+
+public class IndicatorAdapter extends RecyclerView.Adapter<IndicatorAdapter.IndicatorHolder> {
+
+ 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();
+ }
+ }
+ }
+}
"", ""));
//天气
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"));
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;
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";
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);
}
}
- 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
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);
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
appListModel.onStartAppActivity(pos);
}
};
+
+
}
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;
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
@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;
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 {
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() {
mStateBarBinding.setBatteryValue(value);
});
- phoneModel.querySimCardState();
+ phoneModel.onStartQuery();
}
}
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;
watchBinding = FragmentL02WatchBinding.inflate(inflater, container, false);
initWatchFaceModel();
-
- watchBinding.setHeartValue("100");
- watchBinding.setStepValue("100000");
return watchBinding.getRoot();
}
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);
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();
}
}
package com.ic.launcher.listener;
+import android.os.SystemClock;
import android.view.GestureDetector;
import android.view.MotionEvent;
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;
}
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();
+ }
+ }
+ }
}
private final AppListPresenter appListPresenter;
private final LiveData<List<AppInfoEntity>> mObsAppInfoList;
+ private final LiveData<boolean[]> mObsAppState;
+ private final LiveData<String> 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<List<AppInfoEntity>> getObsAppInfoList() {
return mObsAppInfoList;
}
+ public LiveData<boolean[]> getObsAppState() {
+ return mObsAppState;
+ }
+
+ public LiveData<String> getObsActivityError() {
+ return mObsActivityError;
+ }
+
public void updateAppInfoList() {
appListPresenter.updateSystemApp();
}
import com.ic.launcher.presenter.BatteryPresenter;
import com.ic.launcher.presenter.PhoneStatePresenter;
+import com.ic.launcher.util.IcLog;
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(){
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;
public class WatchFaceModel extends AndroidViewModel {
- private TimeDatePresenter timeDatePresenter;
+ private final TimeDatePresenter timeDatePresenter;
+ private final HardwarePresenter hardwarePresenter;
private final LiveData<ArrayList<Integer>> mObsTime;
private final LiveData<String> mObsYear;
private final LiveData<String> mObsWeek;
+ private final LiveData<String> mObsHardwareHeart;
+ private final LiveData<String> 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<ArrayList<Integer>> getObsTime() {
return mObsWeek;
}
+ public LiveData<String> getObsHardwareHeart() {
+ return mObsHardwareHeart;
+ }
+
+ public LiveData<String> getObsHardwarePed() {
+ return mObsHardwarePed;
+ }
+
+ public void onCreateView(){
+ hardwarePresenter.registerHardwareBroadcast();
+ }
+
public void onResumeView() {
timeDatePresenter.onResumePresenter();
+ hardwarePresenter.sendGetPedBroadcast();
}
public void onPauseView() {
public void onDestroyView() {
timeDatePresenter.unRegisterTimeDateReceiver();
+ hardwarePresenter.unRegisterHardwareReceiver();
}
public static class Factory extends ViewModelProvider.NewInstanceFactory {
private Context context;
private MutableLiveData<List<AppInfoEntity>> mObsAppInfoList;
+ private MutableLiveData<boolean[]> mObsAppState;
private MutableLiveData<String> 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<List<AppInfoEntity>> getObsAppInfoList() {
return mObsActivityError;
}
- public void updateSystemApp(){
+ public MutableLiveData<boolean[]> 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;
}
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;
}
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);
}
}
import androidx.lifecycle.MediatorLiveData;
import com.ic.launcher.configure.l02.L02Icon;
+import com.ic.launcher.util.IcLog;
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) {
--- /dev/null
+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<String> mObsHardwareHeart;
+ private MediatorLiveData<String> mObsHardwarePed;
+
+ public HardwarePresenter(Context context) {
+
+ this.mContext = context;
+
+ mObsHardwareHeart = new MediatorLiveData<>();
+ mObsHardwarePed = new MediatorLiveData<>();
+ }
+
+ public MediatorLiveData<String> getObsHardwareHeart() {
+ return mObsHardwareHeart;
+ }
+
+ public MediatorLiveData<String> 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;
+ }
+ }
+ }
+ };
+}
private MediatorLiveData<Integer> mObsPhoneSignalID;
private MediatorLiveData<Integer> 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);
mObsPhoneTransportID = new MediatorLiveData<>();
trafficPooler = new QueryTrafficPooler(mObsPhoneTransportID);
+ simCardState = new QuerySimCardState(mTM,mObsPhoneTypeID,mObsPhoneSignalID);
}
public LiveData<Integer> getPhoneTypeObservable() {
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;
}
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();
}
};
- 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;
--- /dev/null
+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<Integer> mObsPhoneTypeID;
+ private MediatorLiveData<Integer> mObsPhoneSignalID;
+
+ public QuerySimCardState(TelephonyManager mTM,
+ MediatorLiveData<Integer> mObsPhoneTypeID,
+ MediatorLiveData<Integer> 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
}
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())) {
--- /dev/null
+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<String, String> infos = new HashMap<String, String>();
+ // 用于格式化日期,作为日志文件名的一部分
+ 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<String, String> 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;
+ }
+}
}
}
- 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);
}
--- /dev/null
+<vector android:height="18dp" android:tint="#A7A5A5"
+ android:viewportHeight="24.0" android:viewportWidth="24.0"
+ android:width="18dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillColor="#A7A5A5" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2z"/>
+</vector>
--- /dev/null
+<vector android:height="18dp" android:tint="#FFFFFF"
+ android:viewportHeight="24.0" android:viewportWidth="24.0"
+ android:width="18dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillColor="#FFFFFF" android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2z"/>
+</vector>
android:oneshot="false">
<item
android:drawable="@mipmap/l02_battery_0"
- android:duration="150" />
+ android:duration="800" />
<item
android:drawable="@mipmap/l02_battery_1"
- android:duration="150" />
+ android:duration="800" />
<item
android:drawable="@mipmap/l02_battery_2"
- android:duration="150" />
+ android:duration="800" />
<item
android:drawable="@mipmap/l02_battery_3"
- android:duration="150" />
+ android:duration="800" />
<item
android:drawable="@mipmap/l02_battery_4"
- android:duration="150" />
+ android:duration="800" />
<item
android:drawable="@mipmap/l02_battery_5"
- android:duration="150" />
+ android:duration="800" />
</animation-list>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/app_list"
android:layout_width="match_parent"
- android:layout_height="match_parent"/>
+ android:layout_height="match_parent"
+ android:overScrollMode="never"/>
-</LinearLayout>
\ No newline at end of file
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/app_indicator_rv"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom|center_horizontal"
+ android:overScrollMode="never"
+ android:layout_marginBottom="5dp"/>
+
+</FrameLayout>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <data>
+
+ <variable
+ name="isCheckItem"
+ type="boolean" />
+ </data>
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@{isCheckItem ? @drawable/ic_white_circle : @drawable/ic_transparent_circle}" />
+ </LinearLayout>
+</layout>
<string name="app_name_setting">设置</string>
<string name="error_start_activity">应用程序启动失败</string>
+
+ <string name="program_abnormal">很抱歉,程序出现异常,即将退出</string>
</resources>
--- /dev/null
+#Sat Mar 07 15:05:05 CST 2020
+VERSION_CODE=10