buildTypes {
release {
- zipAlignEnabled true // zip 对齐优化
- shrinkResources true // 移除未使用的资源文件
+// zipAlignEnabled true // zip 对齐优化
+// shrinkResources true // 移除未使用的资源文件
signingConfig signingConfigs.key
- minifyEnabled true
+ // minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
renderscriptDebuggable = false
debuggable = false
implementation 'com.jakewharton.threetenabp:threetenabp:1.2.2'
implementation 'androidx.viewpager2:viewpager2:1.0.0'
+
+ implementation files('libs/android-logging-log4j-1.0.3.jar',
+ 'libs/ftp4j-1.7.2.jar',
+ 'libs/log4j-1.2.17.jar',
+ 'libs/okio-2.4.3.jar')
+
}
-[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":26,"versionName":"202106201445","enabled":true,"outputFile":"ICL02Sport_V26_202106201445_release.apk","fullName":"release","baseName":"release"},"path":"ICL02Sport_V26_202106201445_release.apk","properties":{}}]
\ No newline at end of file
+[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":27,"versionName":"202107061547","enabled":true,"outputFile":"ICL02Sport_V27_202107061547_release.apk","fullName":"release","baseName":"release"},"path":"ICL02Sport_V27_202107061547_release.apk","properties":{}}]
\ No newline at end of file
pedometerModel = new ViewModelProvider(this, factory).get(PedometerModel.class);
pedometerModel.getObsPedCount().observe(this, integer -> {
- ((PedMainFragment)myAdapter.getFragment(1)).updatePedNumber(integer);
+ ((PedMainFragment) myAdapter.getFragment(1)).updatePedNumber(integer);
});
pedometerModel.getObsPedRecord().observe(this, record -> {
- ((PedRecordFragment)myAdapter.getFragment(2)).updatePedRecord(record);
+ PedRecordFragment fragment = (PedRecordFragment) myAdapter.getFragment(2);
+ if (fragment != null) {
+ fragment.updatePedRecord(record);
+ }
});
pedometerModel.onBindService();
myAdapter = new FragmentAdapter(getSupportFragmentManager(), getLifecycle());
myViewPager2.setAdapter(myAdapter);
myViewPager2.setCurrentItem(1);
+ myViewPager2.setOffscreenPageLimit(myAdapter.getItemCount());
myViewPager2.registerOnPageChangeCallback(currentItemUpdater);
}
private final ViewPager2.OnPageChangeCallback currentItemUpdater = new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageSelected(int position) {
- IcLog.i(TAG,"onPageSelected"+position);
+ IcLog.i(TAG, "onPageSelected" + position);
indicatorAdapter.updateIndicatorState(position);
}
@Override
public void onPageScrollStateChanged(int newState) {
- IcLog.i(TAG,"onPageScrollStateChanged"+newState);
+ IcLog.i(TAG, "onPageScrollStateChanged" + newState);
if (newState == SCROLL_STATE_IDLE) {
- IcLog.i(TAG,"onPageScrollStateChanged"+newState);
+ IcLog.i(TAG, "onPageScrollStateChanged" + newState);
}
}
};
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
- View view = inflater.inflate(R.layout.fragment_ped_record, container, false);
+ View view = inflater.inflate(R.layout.fragment_ped_record, container);
mSetupRv = view.findViewById(R.id.ped_record_rv);
mSetupRv.addItemDecoration(new RecyclerView.ItemDecoration() {
@Override
}
public void updatePedRecord(List<RecordParcelable> records) {
- setupAdapter.updatePedRecordList(records);
+ if (setupAdapter != null) {
+ setupAdapter.updatePedRecordList(records);
+ }
//移动到第一个位置上
- mSetupRv.scrollToPosition(records.size() - 1);
+ if (mSetupRv != null && records != null) {
+ //不需要
+ //mSetupRv.scrollToPosition(records.size() - 1);
+ }
}
private void initRecyclerView() {
setupAdapter = new PedRecordAdapter(mContext);
LinearLayoutManager mLayoutManager =
- new LinearLayoutManager(mContext, LinearLayoutManager.VERTICAL, true);
+ new LinearLayoutManager(mContext, LinearLayoutManager.VERTICAL, false);
mSetupRv.setLayoutManager(mLayoutManager);
mSetupRv.setAdapter(setupAdapter);
}
import com.ic.aidl.ped.IPedAidlInterface;
import com.ic.aidl.ped.IPedRemoteService;
import com.ic.aidl.ped.RecordParcelable;
+import com.ic.sport.util.ICLogger;
import com.ic.sport.util.IcLog;
import com.ic.sport.util.ServiceUtil;
import java.net.FileNameMap;
+import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@Override
public void updatePedRecord(List<RecordParcelable> record) {
+ ICLogger.d("record == > " + record);
+ Collections.reverse(record);
mObsPedRecord.postValue(record);
}
};
--- /dev/null
+package com.ic.sport.util;
+
+import android.content.Context;
+
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import org.apache.log4j.PatternLayout;
+import org.apache.log4j.RollingFileAppender;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+
+import de.mindpipe.android.logging.log4j.LogConfigurator;
+
+import static org.apache.log4j.Logger.getLogger;
+
+
+public class ICLogger {
+
+ private static boolean isInitConfig = false;
+ private static Context mContext = null;
+
+ private static Logger Log = null;
+ // private static java.util.logging.Logger originLog= getLogger(ICLogger.class.getSimpleName());
+ private static final boolean DEBUG = true; //BuildConfig.DEBUG;
+
+ public static void setContext(Context context) {
+ mContext = context;
+ }
+
+ private static String getFunctionName() {
+ StackTraceElement[] currentStack = Thread.currentThread().getStackTrace();
+ if (currentStack == null) {
+ return null;
+ } else {
+ int stackLen = currentStack.length;
+
+ for (int i = 0; i < stackLen; ++i) {
+ StackTraceElement stackElement = currentStack[i];
+ if (!stackElement.isNativeMethod() &&
+ !stackElement.getClassName().equals(Thread.class.getName()) &&
+ !stackElement.getClassName().equals(ICLogger.class.getName())) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("[ ");
+ sb.append(Thread.currentThread().getName());
+ sb.append(": ");
+ sb.append(stackElement.getFileName());
+ sb.append(":");
+ sb.append(stackElement.getLineNumber());
+ sb.append(" ");
+ sb.append(stackElement.getMethodName());
+ sb.append(" ]");
+ return sb.toString();
+ }
+ }
+
+ return null;
+ }
+ }
+
+ /**
+ * 初始化与配置Logger Log4j
+ * 日志信息格式中符号所代表的含义
+ * (1)-X号: X信息输出时左对齐。
+ * (2)%p: 输出日志信息优先级,即DEBUG,INFO,WARN,ERROR,FATAL。
+ * (3)%d: 输出日志时间点的日期或时间,默认格式为ISO8601,也可以在其后指定格式,比如:%d{yyy MMM dd HH:mm:ss,SSS},输出类似:2002年10月18日 22:10:28,921。
+ * (4)%r: 输出自应用启动到输出该log信息耗费的毫秒数。
+ * (5)%c: 输出日志信息所属的类目,通常就是所在类的全名。
+ * (6)%t: 输出产生该日志事件的线程名。
+ * (7)%l: 输出日志事件的发生位置,相当于%C.%M(%F:%L)的组合,包括类目名、发生的线程,以及在代码中的行数。举例:Testlog4.main(TestLog4.java:10)。
+ * (8)%x: 输出和当前线程相关联的NDC(嵌套诊断环境),尤其用到像java servlets这样的多客户多线程的应用中。
+ * (9)%%: 输出一个"%"字符。
+ * (10)%F: 输出日志消息产生时所在的文件名称。
+ * (11)%L: 输出代码中的行号。
+ * (12)%m: 输出代码中指定的消息,产生的日志具体信息。
+ * (13)%n: 输出一个回车换行符,Windows平台为"\r\n",Unix平台为"\n"输出日志信息换行。
+ * 可以在%与模式字符之间加上修饰符来控制其最小宽度、最大宽度、和文本的对齐方式。如:
+ * (1)%20c:指定输出category的名称,最小的宽度是20,如果category的名称小于20的话,默认的情况下右对齐。
+ * (2)%-20c:指定输出category的名称,最小的宽度是20,如果category的名称小于20的话,"-"号指定左对齐。
+ * (3)%.30c:指定输出category的名称,最大的宽度是30,如果category的名称大于30的话,就会将左边多出的字符截掉,但小于30的话也不会有空格。
+ * (4)%20.30c:如果category的名称小于20就补空格,并且右对齐,如果其名称长于30字符,就从左边交远销出的字符截掉。
+ */
+ private static void initConfig() {
+ if (!isInitConfig) {
+
+ LogConfigurator logConfigurator = new LogConfigurator();
+
+ String filename = StorageUtils.getExternalStorageLogDir() + File.separator + "log.txt";
+ logConfigurator.setFileName(filename); // 日志存储路径,如果该路径没有会自动创建文件
+ logConfigurator.setRootLevel(Level.ALL);
+
+ logConfigurator.setLevel("log", Level.ALL);
+// logConfigurator.setFilePattern("%d %-5p [%c{2}]-[%L] %m%n");// 设置文件输出模式
+ logConfigurator.setFilePattern("%d %m%n ");// 设置文件输出模式
+// 02-29 16:28:38.195 4629-4658/com.enqualcomm.support E/com.enqualcomm.support.utils.ICLogger:
+ logConfigurator.setMaxBackupSize(2); // 设置最大备份数量
+ logConfigurator.setMaxFileSize(1024 * 1024 * 20);// 设置最大文件大小 20MB
+ logConfigurator.setImmediateFlush(true);// 设置是否立即刷新
+ logConfigurator.setUseFileAppender(true); // 设置用户文件输出器
+ logConfigurator.setInternalDebugging(false); //控制console是否输出
+ logConfigurator.setUseLogCatAppender(true);
+ logConfigurator.setLogCatPattern("%m%n");
+ logConfigurator.configure();// 设置提交
+
+
+// String logfilelist[]={"Log","GPS","Nmea","APILog","alarmCycle","Battery","LBS"};
+
+ //Log 和log目前是同一个配置
+ Log = getLogger("log");
+ Log.info("init Logger " + Log.getName());
+// Log.addAppender( getRollingFileAppender("log","%d %m%n "));
+// Log.info("init Logger "+Log.getName()+" "+((RollingFileAppender)Log.getAppender("log")).getFile());
+
+ isInitConfig = true;
+ }
+ }
+
+ public static void logRAWtoFile(String filename, String msg) {
+ Log.info(msg);
+ }
+
+ public static void logToFile(String filename, String msg) {
+ Log.info(msg);
+ }
+
+ private static RollingFileAppender getRollingFileAppender(String name, String layoutpattern) {
+ PatternLayout fileLayout = new PatternLayout(layoutpattern);
+ String filename = StorageUtils.getExternalStorageLogDir() + File.separator + name + ".txt";
+ RollingFileAppender rollingFileAppender = null;
+ try {
+ rollingFileAppender = new RollingFileAppender(fileLayout, filename);
+ } catch (IOException e) {
+ e.printStackTrace();
+ ICLogger.e(e.getMessage(), e);
+ return null;
+ }
+ rollingFileAppender.setName(name);
+ rollingFileAppender.setMaxBackupIndex(2); //最多3个备份文件
+ rollingFileAppender.setMaximumFileSize(10 * 1024 * 1024); //10M 大小
+ rollingFileAppender.setImmediateFlush(true);
+
+ return rollingFileAppender;
+ }
+
+ public static void v(String msg) {
+ initConfig();
+ if (Log != null)
+ Log.debug(buildMessage(msg));
+ }
+
+ public static void v(String msg, Throwable thr) {
+ initConfig();
+ if (Log != null)
+ Log.debug(buildMessage(msg), thr);
+ }
+
+ public static void d(String msg) {
+ initConfig();
+ if (Log != null)
+ Log.debug(buildMessage(msg));
+ }
+
+ public static void d(String msg, Throwable thr) {
+ initConfig();
+ if (Log != null)
+ Log.debug(buildMessage(msg), thr);
+ }
+
+ public static void i(String msg) {
+ initConfig();
+ if (Log != null)
+ Log.info(buildMessage(msg));
+ }
+
+ public static void i(String msg, Throwable thr) {
+ initConfig();
+ if (Log != null)
+ Log.info(buildMessage(msg), thr);
+ }
+
+ public static void w(String msg) {
+ initConfig();
+ if (Log != null)
+ Log.warn(buildMessage(msg));
+ }
+
+ public static void w(String msg, Throwable thr) {
+ initConfig();
+ if (Log != null)
+ Log.warn(buildMessage(msg), thr);
+ }
+
+ public static void w(Throwable thr) {
+ initConfig();
+ if (Log != null)
+ Log.warn(buildMessage(""), thr);
+ }
+
+ public static void e(String msg) {
+ initConfig();
+ if (Log != null)
+ Log.error(buildMessage(msg));
+ }
+
+ public static void e(String msg, Throwable thr) {
+ initConfig();
+ if (Log != null)
+ Log.error(buildMessage(msg), thr);
+ }
+
+ public static void PrintExceptionStackTrace(Exception e) {
+
+ StringBuffer sb = new StringBuffer();
+ sb.append(e.getMessage()).append("\n");
+ e.printStackTrace(new PrintStream(new OutputStream() {
+ @Override
+ public void write(int b) throws IOException {
+ sb.append((char) b);
+ }
+ }));
+ i(sb.toString());
+ }
+
+ /**
+ * 生成消息
+ *
+ * @param msg
+ * @return
+ */
+ protected static String buildMessage(String msg) {
+ initConfig();
+ if (DEBUG && msg != null) {
+ String var1 = getFunctionName();
+ if (var1 != null) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(var1);
+ sb.append(" - ");
+ sb.append(msg);
+ return sb.toString();
+ } else {
+ return "functionName is null";
+ }
+ } else {
+ return "msg is null";
+ }
+ }
+
+ public static void log(String TAG, String msg) {
+ if (DEBUG) {
+ if (Log != null) Log.debug(TAG + " " + msg);
+
+ }
+ }
+
+ public static void log(String TAG, String funcName, String msg) {
+ if (DEBUG) {
+ if (Log != null)
+ Log.debug(TAG + " [" + funcName + "]" + msg);
+
+ }
+ }
+
+}
+
public static void v(String tag, String msg) {
if (isDebug) {
- Log.v(mergeHeadTag(tag), msg);
+ ICLogger.v(msg);
}
}
public static void d(String tag, String msg) {
if (isDebug) {
- Log.d(mergeHeadTag(tag), msg);
+ ICLogger.d(msg);
}
}
public static void i(String tag, String msg) {
if (isDebug) {
- Log.i(mergeHeadTag(tag), msg);
+ ICLogger.i(msg);
}
}
public static void w(String tag, String msg) {
if (isDebug) {
- Log.w(mergeHeadTag(tag), msg);
+ ICLogger.w(msg);
}
}
public static void e(String tag, String msg) {
if (isDebug) {
- Log.e(mergeHeadTag(tag), msg);
+ ICLogger.e(msg);
}
}
--- /dev/null
+/*******************************************************************************
+ * Copyright 2011-2013 Sergey Tarasevich
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *******************************************************************************/
+package com.ic.sport.util;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Build;
+import android.os.Environment;
+import android.os.StatFs;
+import android.util.Log;
+
+import java.io.File;
+import java.io.IOException;
+
+import static android.os.Environment.DIRECTORY_DOCUMENTS;
+import static android.os.Environment.MEDIA_MOUNTED;
+
+/**
+ * Provides application storage paths
+ *
+ * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
+ * @since 1.0.0
+ */
+public final class StorageUtils {
+
+ private static final String EXTERNAL_STORAGE_PERMISSION = "android.permission.WRITE_EXTERNAL_STORAGE";
+ private static final String INDIVIDUAL_DIR_NAME = "uil-images";
+ private static final String TAG = "StorageUtils";
+
+ private StorageUtils() {
+ }
+
+ public static String getExternalStorageLogDir() {
+
+
+ //判断版本,如果是4.4的版本则使用旧的API
+ //如果是8.1的版本,使用publish的API
+ if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
+ File dir;
+ Log.d(TAG, "current system version is == > " + Build.VERSION.SDK_INT);
+ if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {
+ dir = new File(Environment.getExternalStoragePublicDirectory(DIRECTORY_DOCUMENTS), "Android/ic/icSport");
+ } else {
+ dir = new File(Environment.getExternalStorageDirectory().getPath(), "Android/ic/icSport");
+ }
+
+ String path = dir.getPath();
+ if (!dir.exists()) {
+ dir.mkdirs();
+ }
+ return path;
+ }
+
+ return "/storage/emulated/0/Android/ic/icSport";
+ }
+
+ /**
+ * Returns application cache directory. Cache directory will be created on SD card
+ * <i>("/Android/data/[app_package_name]/cache")</i> if card is mounted and app has appropriate permission. Else -
+ * Android defines cache directory on device's file system.
+ *
+ * @param context Application context
+ * @return Cache {@link File directory}.<br />
+ * <b>NOTE:</b> Can be null in some unpredictable cases (if SD card is unmounted and
+ * {@link Context#getCacheDir() Context.getCacheDir()} returns null).
+ */
+ public static File getCacheDirectory(Context context) {
+ return getCacheDirectory(context, true);
+ }
+
+ /**
+ * Returns application cache directory. Cache directory will be created on SD card
+ * <i>("/Android/data/[app_package_name]/cache")</i> (if card is mounted and app has appropriate permission) or
+ * on device's file system depending incoming parameters.
+ *
+ * @param context Application context
+ * @param preferExternal Whether prefer external location for cache
+ * @return Cache {@link File directory}.<br />
+ * <b>NOTE:</b> Can be null in some unpredictable cases (if SD card is unmounted and
+ * {@link Context#getCacheDir() Context.getCacheDir()} returns null).
+ */
+ public static File getCacheDirectory(Context context, boolean preferExternal) {
+ File appCacheDir = null;
+ if (preferExternal && MEDIA_MOUNTED
+ .equals(Environment.getExternalStorageState()) && hasExternalStoragePermission(context) && haveFreeSpace()) {
+ appCacheDir = getExternalCacheDir(context);
+ }
+ if (appCacheDir == null) {
+ appCacheDir = context.getCacheDir();
+ }
+ if (appCacheDir == null) {
+ String cacheDirPath = "/data/data/" + context.getPackageName() + "/cache/";
+ appCacheDir = new File(cacheDirPath);
+ }
+ return appCacheDir;
+ }
+
+ /**
+ * Returns individual application cache directory (for only image caching from ImageLoader). Cache directory will be
+ * created on SD card <i>("/Android/data/[app_package_name]/cache/uil-images")</i> if card is mounted and app has
+ * appropriate permission. Else - Android defines cache directory on device's file system.
+ *
+ * @param context Application context
+ * @return Cache {@link File directory}
+ */
+ public static File getIndividualCacheDirectory(Context context) {
+ File cacheDir = getCacheDirectory(context);
+ File individualCacheDir = new File(cacheDir, INDIVIDUAL_DIR_NAME);
+ if (!individualCacheDir.exists()) {
+ if (!individualCacheDir.mkdir()) {
+ individualCacheDir = cacheDir;
+ }
+ }
+ return individualCacheDir;
+ }
+
+ /**
+ * Returns specified application cache directory. Cache directory will be created on SD card by defined path if card
+ * is mounted and app has appropriate permission. Else - Android defines cache directory on device's file system.
+ *
+ * @param context Application context
+ * @param cacheDir Cache directory path (e.g.: "AppCacheDir", "AppDir/cache/images")
+ * @return Cache {@link File directory}
+ */
+ public static File getOwnCacheDirectory(Context context, String cacheDir) {
+ File appCacheDir = null;
+ if (MEDIA_MOUNTED.equals(Environment.getExternalStorageState()) && hasExternalStoragePermission(context)) {
+ appCacheDir = new File(Environment.getExternalStorageDirectory(), cacheDir);
+ }
+ if (appCacheDir == null || (!appCacheDir.exists() && !appCacheDir.mkdirs())) {
+ appCacheDir = context.getCacheDir();
+ }
+ return appCacheDir;
+ }
+
+ private static File getExternalCacheDir(Context context) {
+ File dataDir = new File(new File(Environment.getExternalStorageDirectory(), "Android"), "data");
+ File appCacheDir = new File(new File(dataDir, context.getPackageName()), "cache");
+ if (!appCacheDir.exists()) {
+ if (!appCacheDir.mkdirs()) {
+ return null;
+ }
+ try {
+ new File(appCacheDir, ".nomedia").createNewFile();
+ } catch (IOException e) {
+ }
+ }
+ return appCacheDir;
+ }
+
+ private static boolean hasExternalStoragePermission(Context context) {
+ int perm = context.checkCallingOrSelfPermission(EXTERNAL_STORAGE_PERMISSION);
+ return perm == PackageManager.PERMISSION_GRANTED;
+ }
+
+ private static boolean haveFreeSpace() {
+ if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
+ StatFs st = new StatFs(Environment.getExternalStorageDirectory().getPath());
+ int blockSize = st.getBlockSize();
+ long available = st.getAvailableBlocks();
+ long availableSize = (blockSize * available);
+ if (availableSize < 1024 * 1024 * 10) {// //sd卡空间如果小于10M,就认为sd卡空间不足
+ return false;
+ }
+ return true;
+ }
+ return false;
+ }
+}
-#Sun Jun 20 14:45:55 CST 2021\r
-VERSION_CODE=26\r
+#Tue Jul 06 15:47:09 CST 2021\r
+VERSION_CODE=27\r