From 3facefa1c1a4af3d674a6a227a020d9b147708c9 Mon Sep 17 00:00:00 2001 From: Ztiany Date: Wed, 30 Oct 2019 17:57:20 +0800 Subject: [PATCH] add debug tools --- .../android/base/utils/debug/Environment.kt | 66 ++++++ .../utils/debug/EnvironmentConfigFragment.kt | 45 ++++ .../base/utils/debug/EnvironmentItemLayout.kt | 56 +++++ .../base/utils/upgrade/ApkDownloader.java | 137 ++++++++++++ .../base/utils/upgrade/AppUpgradeChecker.kt | 202 ++++++++++++++++++ .../android/base/utils/upgrade/UpgradeInfo.kt | 16 ++ .../base/utils/upgrade/UpgradeInteractor.kt | 35 +++ .../base/utils/upgrade/UpgradeService.java | 110 ++++++++++ .../res/drawable/base_shape_debug_divider.xml | 10 + .../res/layout/base_debug_environment.xml | 32 +++ .../layout/base_debug_environment_item.xml | 51 +++++ 11 files changed, 760 insertions(+) create mode 100644 lib_base/src/main/java/com/android/base/utils/debug/Environment.kt create mode 100644 lib_base/src/main/java/com/android/base/utils/debug/EnvironmentConfigFragment.kt create mode 100644 lib_base/src/main/java/com/android/base/utils/debug/EnvironmentItemLayout.kt create mode 100644 lib_base/src/main/java/com/android/base/utils/upgrade/ApkDownloader.java create mode 100644 lib_base/src/main/java/com/android/base/utils/upgrade/AppUpgradeChecker.kt create mode 100644 lib_base/src/main/java/com/android/base/utils/upgrade/UpgradeInfo.kt create mode 100644 lib_base/src/main/java/com/android/base/utils/upgrade/UpgradeInteractor.kt create mode 100644 lib_base/src/main/java/com/android/base/utils/upgrade/UpgradeService.java create mode 100644 lib_base/src/main/res/drawable/base_shape_debug_divider.xml create mode 100644 lib_base/src/main/res/layout/base_debug_environment.xml create mode 100644 lib_base/src/main/res/layout/base_debug_environment_item.xml diff --git a/lib_base/src/main/java/com/android/base/utils/debug/Environment.kt b/lib_base/src/main/java/com/android/base/utils/debug/Environment.kt new file mode 100644 index 0000000..1fbbf65 --- /dev/null +++ b/lib_base/src/main/java/com/android/base/utils/debug/Environment.kt @@ -0,0 +1,66 @@ +package com.android.base.utils.debug + +import com.android.base.utils.BaseUtils +import com.android.base.utils.android.cache.SpCache +import com.android.base.utils.common.ifNonNull +import com.android.base.utils.common.ifNull +import com.android.base.utils.common.otherwise + + +object EnvironmentContext { + + private val spCache = SpCache(BaseUtils.getAppContext().packageName, false) + + private val envMap = HashMap>() + + private fun addEnv(category: String, env: Environment) { + envMap[category].ifNonNull { + add(env) + Unit + } otherwise { + envMap[category] = mutableListOf().apply { add(env) } + } + } + + fun startEdit(adder: EnvironmentAdder.() -> Unit) { + adder(object : EnvironmentAdder { + override fun add(category: String, env: Environment) { + addEnv(category, env) + } + }) + endAdding() + } + + private fun endAdding() { + envMap.forEach { (category, list) -> + val url = spCache.getString(category, "") + list.find { + url == it.url + }.ifNull { + spCache.putString(category, list[0].url) + } + } + } + + internal fun allCategory(): Map> { + return envMap + } + + internal fun select(category: String, env: Environment) { + spCache.putString(category, env.url) + } + + fun selected(category: String): Environment { + val url = spCache.getString(category, "") + return envMap[category]?.find { + url == it.url + } ?: throw NullPointerException("no selected Environment with category: $category") + } + +} + +interface EnvironmentAdder { + fun add(category: String, env: Environment) +} + +class Environment(val name: String, val url: String) \ No newline at end of file diff --git a/lib_base/src/main/java/com/android/base/utils/debug/EnvironmentConfigFragment.kt b/lib_base/src/main/java/com/android/base/utils/debug/EnvironmentConfigFragment.kt new file mode 100644 index 0000000..51b415b --- /dev/null +++ b/lib_base/src/main/java/com/android/base/utils/debug/EnvironmentConfigFragment.kt @@ -0,0 +1,45 @@ +package com.android.base.utils.debug + +import android.os.Bundle +import android.view.View +import android.view.ViewGroup +import com.android.base.R +import com.android.base.app.fragment.BaseFragment +import com.android.base.utils.android.views.visibleOrGone +import kotlinx.android.synthetic.main.base_debug_environment.* + +/** + * @author Ztiany + * Email: ztiany3@gmail.com + * Date : 2019-08-13 19:17 + */ +class EnvironmentConfigFragment : BaseFragment() { + + companion object { + private const val SHOW_TITLE = "show_title" + + fun newInstance(showTitle: Boolean) = EnvironmentConfigFragment().apply { + arguments = Bundle().apply { + putBoolean(SHOW_TITLE, showTitle) + } + } + + } + + override fun provideLayout() = R.layout.base_debug_environment + + override fun onViewPrepared(view: View, savedInstanceState: Bundle?) { + super.onViewPrepared(view, savedInstanceState) + + baseToolbarDebug.visibleOrGone(arguments?.getBoolean(SHOW_TITLE, false) ?: false) + + val allCategory = EnvironmentContext.allCategory() + allCategory.forEach { (category, list) -> + val environmentItemLayout = EnvironmentItemLayout(requireContext()) + environmentItemLayout.bindEnvironmentList(category, list) + baseLlDebugHostContent.addView(environmentItemLayout, ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)) + } + } + +} + diff --git a/lib_base/src/main/java/com/android/base/utils/debug/EnvironmentItemLayout.kt b/lib_base/src/main/java/com/android/base/utils/debug/EnvironmentItemLayout.kt new file mode 100644 index 0000000..fa64803 --- /dev/null +++ b/lib_base/src/main/java/com/android/base/utils/debug/EnvironmentItemLayout.kt @@ -0,0 +1,56 @@ +package com.android.base.utils.debug + +import android.annotation.SuppressLint +import android.content.Context +import android.util.AttributeSet +import android.view.View +import android.widget.LinearLayout +import androidx.appcompat.app.AlertDialog +import com.android.base.R +import com.android.base.utils.android.views.dip +import com.android.base.utils.android.views.setPaddingAll +import kotlinx.android.synthetic.main.base_debug_environment_item.view.* + +class EnvironmentItemLayout @JvmOverloads constructor( + context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 +) : LinearLayout(context, attrs, defStyleAttr) { + + init { + orientation = VERTICAL + setPaddingAll(dip(10)) + View.inflate(context, R.layout.base_debug_environment_item, this) + } + + private lateinit var list: List + private lateinit var categoryName: String + + fun bindEnvironmentList(categoryName: String, list: List) { + this.categoryName = categoryName + this.list = list + baseTvDebugHostName.text = categoryName + + showSelectedValue(EnvironmentContext.selected(categoryName)) + + baseBtnDebugSwitch.setOnClickListener { + showSwitchDialog() + } + } + + @SuppressLint("SetTextI18n") + private fun showSelectedValue(selected: Environment) { + baseTvDebugHostValue.text = "${selected.name}:${selected.url}" + } + + private fun showSwitchDialog() { + val first = list.indexOf(EnvironmentContext.selected(categoryName)) + + AlertDialog.Builder(context) + .setSingleChoiceItems(list.map { it.name }.toTypedArray(), first) { dialog, which -> + dialog.dismiss() + val env = list[which] + showSelectedValue(env) + EnvironmentContext.select(categoryName, env) + }.show() + } + +} \ No newline at end of file diff --git a/lib_base/src/main/java/com/android/base/utils/upgrade/ApkDownloader.java b/lib_base/src/main/java/com/android/base/utils/upgrade/ApkDownloader.java new file mode 100644 index 0000000..cc0332a --- /dev/null +++ b/lib_base/src/main/java/com/android/base/utils/upgrade/ApkDownloader.java @@ -0,0 +1,137 @@ +package com.android.base.utils.upgrade; + +import com.android.base.utils.common.Files; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; + +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.ResponseBody; + +import static com.blankj.utilcode.util.CloseUtils.closeIOQuietly; + +/** + * 下载APK + * + * @author Ztiany + * Email: 1169654504@qq.com + * Date : 2017-01-04 10:40 + */ +final class ApkDownloader { + + private String mUrl; + private String mDigitalAbstract; + private ApkDownloaderListener mApkDownloaderListener; + private File mDesFile; + private File mTempDesFile; + private static final String TEMP_MASK = "temp_%s"; + private long mNotifyTime = 0; + + + ApkDownloader(String url, String desFilePath, String digitalAbstract, ApkDownloaderListener apkDownloaderListener) { + mUrl = url; + mDigitalAbstract = digitalAbstract; + mApkDownloaderListener = apkDownloaderListener; + mDesFile = new File(desFilePath); + String name = mDesFile.getName(); + mTempDesFile = new File(mDesFile.getParent(), String.format(TEMP_MASK, name)); + } + + void start() { + OkHttpClient.Builder builder = new OkHttpClient.Builder(); + builder.interceptors().clear(); + OkHttpClient okHttpClient = builder.build(); + + Request request = new Request.Builder() + .url(mUrl) + .build(); + + ResponseBody body; + + try { + Response response = okHttpClient.newCall(request).execute(); + if (response.isSuccessful()) { + body = response.body(); + } else { + mApkDownloaderListener.onFail(new RuntimeException("网络错误")); + return; + } + } catch (IOException e) { + e.printStackTrace(); + mApkDownloaderListener.onFail(e); + return; + } + + //检查body + if (body == null) { + mApkDownloaderListener.onFail(new RuntimeException("网络错误")); + return; + } + + if (mDesFile.exists() && mDesFile.length() == body.contentLength() && AppUpgradeChecker.upgradeInteractor.checkApkFile(mDesFile, mDigitalAbstract)) { + mApkDownloaderListener.onSuccess(mDesFile); + } else { + Files.makeParentPath(mDesFile); + Files.makeParentPath(mTempDesFile); + boolean success = startDownload(body); + if (success) { + boolean renameToSuccess = mTempDesFile.renameTo(mDesFile); + if (renameToSuccess) { + if (AppUpgradeChecker.upgradeInteractor.checkApkFile(mDesFile, mDigitalAbstract)) { + mApkDownloaderListener.onSuccess(mDesFile); + } else { + mApkDownloaderListener.onFail(new RuntimeException("数字摘要对比失败")); + } + } + } + } + } + + private boolean startDownload(ResponseBody body) { + InputStream is = null; + FileOutputStream fos = null; + try { + byte[] buf = new byte[1024 * 2];//缓冲器 + int len;//每次读取的长度 + assert body != null; + final long total = body.contentLength();//总的长度 + is = body.byteStream(); + long sum = 0; + fos = new FileOutputStream(mTempDesFile); + + while ((len = is.read(buf)) != -1) { + sum += len; + fos.write(buf, 0, len); + if ((System.currentTimeMillis() - mNotifyTime) >= 300) { + mNotifyTime = System.currentTimeMillis(); + mApkDownloaderListener.onProgress(total, sum); + } + } + + mApkDownloaderListener.onProgress(total, total); + fos.flush(); + return true; + } catch (IOException e) { + e.printStackTrace(); + mApkDownloaderListener.onFail(e); + return false; + } finally { + closeIOQuietly(is, fos); + } + } + + interface ApkDownloaderListener { + + void onProgress(long total, long progress); + + void onSuccess(File desFile); + + void onFail(Exception e); + + } + +} \ No newline at end of file diff --git a/lib_base/src/main/java/com/android/base/utils/upgrade/AppUpgradeChecker.kt b/lib_base/src/main/java/com/android/base/utils/upgrade/AppUpgradeChecker.kt new file mode 100644 index 0000000..955b829 --- /dev/null +++ b/lib_base/src/main/java/com/android/base/utils/upgrade/AppUpgradeChecker.kt @@ -0,0 +1,202 @@ +package com.android.base.utils.upgrade + +import android.app.Activity +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.localbroadcastmanager.content.LocalBroadcastManager +import com.android.base.app.Sword +import com.android.base.data.State +import com.android.base.rx.observeOnUI +import com.android.base.utils.BaseUtils +import com.android.base.utils.android.XAppUtils +import com.app.base.upgrade.UpgradeInteractor +import com.blankj.utilcode.util.AppUtils +import com.blankj.utilcode.util.Utils +import timber.log.Timber +import java.io.File + +object AppUpgradeChecker { + + private var successOnce = false + + var isDownloading = false + private set + + private var currentState = State.noChange() + set(value) { + field = value + notifyStateChanged(value) + } + + private fun notifyStateChanged(state: State) { + innerLiveState.postValue(state) + } + + private val innerLiveState = MutableLiveData>() + + val upgradeState: LiveData> + get() = innerLiveState + + private var resultReceiver: ResultBroadcastReceiver? = null + + private val isUpgradeServiceRunning: Boolean + get() = XAppUtils.isServiceRunning(BaseUtils.getAppContext(), UpgradeService::class.java.name) + + private lateinit var upgradeInfo: UpgradeInfo + + lateinit var upgradeInteractor: UpgradeInteractor + + fun installInteractor(upgradeInteractor: UpgradeInteractor) { + AppUpgradeChecker.upgradeInteractor = upgradeInteractor + } + + fun checkAppUpgrade(force: Boolean = false) { + Timber.d("checkAppUpgrade-->currentState == $currentState") + /*正在检查*/ + if (currentState.isLoading) { + return + } + /*已经检查过了*/ + if (!force && successOnce) { + return + } + /*正在下载*/ + if (isUpgradeServiceRunning) { + return + } + realCheck() + } + + private fun realCheck() { + currentState = State.loading() + + upgradeInteractor.checkUpgrade() + .observeOnUI() + .subscribe( + { upgradeInfo -> + currentState = State.success(upgradeInfo) + successOnce = true + processUpdateInfo(upgradeInfo) + }, + { + currentState = State.error(it) + } + ) + } + + private fun processUpdateInfo(upgradeInfo: UpgradeInfo) { + if (upgradeInfo.isNewVersion) { + AppUpgradeChecker.upgradeInfo = upgradeInfo + safeContext { + upgradeInteractor.showUpgradeDialog(it, upgradeInfo, + onCancel = { + currentState = State.success() + }, + onConfirm = { + doUpdate() + }) + } + } else { + currentState = State.success() + } + } + + private fun doUpdate() { + //show loading dialog + safeContext { + upgradeInteractor.showDownloadingDialog(it, upgradeInfo.isForce) + } + //register result receiver + var receiver = resultReceiver + if (receiver == null) { + receiver = ResultBroadcastReceiver() + resultReceiver = receiver + LocalBroadcastManager.getInstance(BaseUtils.getAppContext()).registerReceiver(receiver, IntentFilter(UpgradeService.DOWNLOAD_APK_RESULT_ACTION)) + } + //start downloading + isDownloading = true + UpgradeService.start(BaseUtils.getAppContext(), upgradeInfo.downloadUrl, upgradeInfo.versionName, upgradeInfo.digitalAbstract, upgradeInfo.isForce) + } + + private class ResultBroadcastReceiver : BroadcastReceiver() { + override fun onReceive(context: Context, intent: Intent) { + if (intent.action != UpgradeService.DOWNLOAD_APK_RESULT_ACTION) { + return + } + when (intent.getIntExtra(UpgradeService.NOTIFY_TYPE_KEY, -1)) { + UpgradeService.NOTIFY_TYPE_SUCCESS -> processOnDownloadingFileSuccessful(intent) + UpgradeService.NOTIFY_TYPE_FAILED -> processOnDownloadingFileFailed() + UpgradeService.NOTIFY_TYPE_PROGRESS -> { + val total = intent.getLongExtra(UpgradeService.TOTAL_PROGRESS_KEY, 0) + val progress = intent.getLongExtra(UpgradeService.PROGRESS_KEY, 0) + upgradeInteractor.onProgress(total, progress) + } + } + } + } + + private fun processOnDownloadingFileSuccessful(intent: Intent) { + isDownloading = false + //start installing + val apkFile = intent.getSerializableExtra(UpgradeService.APK_FILE_KEY) as File + startInstall(apkFile) + //dismiss download dialog + upgradeInteractor.dismissDownloadingDialog() + // if it is force upgrade, we show a no cancelable dialog to make user have to install the new apk. + safeContext { + showInstallTipsDialog(it, apkFile) + } + } + + private fun showInstallTipsDialog(topActivity: Activity, apkFile: File) { + upgradeInteractor.showInstallTipsDialog(topActivity, upgradeInfo.isForce, + onCancel = { + currentState = State.success() + }, + onConfirm = { + startInstall(apkFile) + }) + } + + private fun processOnDownloadingFileFailed() { + isDownloading = false + upgradeInteractor.dismissDownloadingDialog() + safeContext { + showDownloadingFailedTips(it, upgradeInfo.isForce) + } + } + + private fun showDownloadingFailedTips(safeContext: Activity, isForce: Boolean) { + upgradeInteractor.showDownloadingFailed(safeContext, isForce, + onConfirm = { + doUpdate() + }, + onCancel = { + currentState = State.success() + }) + } + + private fun safeContext(onContext: (Activity) -> Unit) { + val topActivity = Sword.get().topActivity + if (topActivity != null) { + onContext(topActivity) + } else { + AppUtils.registerAppStatusChangedListener(this, object : Utils.OnAppStatusChangedListener { + override fun onBackground() = Unit + override fun onForeground() { + AppUtils.unregisterAppStatusChangedListener(this) + Sword.get().topActivity?.let { onContext(it) } + } + }) + } + } + + private fun startInstall(apkFile: File) { + upgradeInteractor.installApk(apkFile, upgradeInfo) + } + +} \ No newline at end of file diff --git a/lib_base/src/main/java/com/android/base/utils/upgrade/UpgradeInfo.kt b/lib_base/src/main/java/com/android/base/utils/upgrade/UpgradeInfo.kt new file mode 100644 index 0000000..6d3b953 --- /dev/null +++ b/lib_base/src/main/java/com/android/base/utils/upgrade/UpgradeInfo.kt @@ -0,0 +1,16 @@ +package com.android.base.utils.upgrade + +/** + *@author Ztiany + * Email: ztiany3@gmail.com + * Date : 2019-10-29 19:17 + */ +data class UpgradeInfo( + val isNewVersion: Boolean, + val isForce: Boolean, + val versionName: String, + val downloadUrl: String, + val description: String, + val digitalAbstract: String, + val raw: Any? +) \ No newline at end of file diff --git a/lib_base/src/main/java/com/android/base/utils/upgrade/UpgradeInteractor.kt b/lib_base/src/main/java/com/android/base/utils/upgrade/UpgradeInteractor.kt new file mode 100644 index 0000000..9c4d4a8 --- /dev/null +++ b/lib_base/src/main/java/com/android/base/utils/upgrade/UpgradeInteractor.kt @@ -0,0 +1,35 @@ +package com.app.base.upgrade + +import android.content.Context +import com.android.base.utils.upgrade.UpgradeInfo +import io.reactivex.Flowable +import java.io.File + +/** + *@author Ztiany + * Email: ztiany3@gmail.com + * Date : 2019-10-29 19:16 + */ +interface UpgradeInteractor { + + fun checkUpgrade(): Flowable + + fun showUpgradeDialog(context: Context, upgradeInfo: UpgradeInfo, onCancel: () -> Unit, onConfirm: () -> Unit) + + fun showInstallTipsDialog(context: Context, force: Boolean, onCancel: () -> Unit, onConfirm: () -> Unit) + + fun showDownloadingFailed(context: Context, force: Boolean, onCancel: () -> Unit, onConfirm: () -> Unit) + + fun showDownloadingDialog(context: Context, force: Boolean) + + fun dismissDownloadingDialog() + + fun onProgress(total: Long, progress: Long) + + fun installApk(file: File, upgradeInfo: UpgradeInfo) + + fun checkApkFile(apkFile: File, digitalAbstract: String): Boolean + + fun generateAppDownloadPath(versionName: String): String + +} \ No newline at end of file diff --git a/lib_base/src/main/java/com/android/base/utils/upgrade/UpgradeService.java b/lib_base/src/main/java/com/android/base/utils/upgrade/UpgradeService.java new file mode 100644 index 0000000..f86e29c --- /dev/null +++ b/lib_base/src/main/java/com/android/base/utils/upgrade/UpgradeService.java @@ -0,0 +1,110 @@ +package com.android.base.utils.upgrade; + + +import android.app.IntentService; +import android.content.Context; +import android.content.Intent; +import android.os.Handler; +import android.os.Looper; +import android.text.TextUtils; + +import com.android.base.utils.BaseUtils; +import com.android.base.utils.common.Strings; + +import java.io.File; + +import androidx.localbroadcastmanager.content.LocalBroadcastManager; +import timber.log.Timber; + +/** + * 下载服务,不要配置在子进程。 + */ +public class UpgradeService extends IntentService { + + static final String DOWNLOAD_APK_RESULT_ACTION = BaseUtils.getAppContext().getPackageName() + ".upgrade.result"; + + static final String IS_FORCE = "is_force"; + static final String NOTIFY_TYPE_KEY = "notify_type"; + static final String APK_FILE_KEY = "apk_path_key"; + static final String URL_KEY = "url_key"; + static final String VERSION_KEY = "version_key"; + static final String TOTAL_PROGRESS_KEY = "total_progress_key"; + static final String PROGRESS_KEY = "progress_key"; + static final String DIGITAL_ABSTRACT_KEY = "digital_abstract_key"; + + public static final int NOTIFY_TYPE_FAILED = 1; + public static final int NOTIFY_TYPE_PROGRESS = 2; + public static final int NOTIFY_TYPE_SUCCESS = 3; + + private Handler mHandler; + private boolean mIsForceUpdate; + private String mDigitalAbstract; + + private class FlagDownloaderListener implements ApkDownloader.ApkDownloaderListener { + + @Override + public void onProgress(long total, long progress) { + Timber.d("onProgress() called with: total = [" + total + "], progress = [" + progress + "]"); + mHandler.post(() -> notifyDownloadResult(NOTIFY_TYPE_PROGRESS, null, total, progress)); + } + + @Override + public void onSuccess(File desFile) { + Timber.d("onSuccess() called with: desFile = [" + desFile + "]"); + mHandler.post(() -> notifyDownloadResult(NOTIFY_TYPE_SUCCESS, desFile, 0, 0)); + } + + @Override + public void onFail(Exception e) { + Timber.d("onFail() called with: e = [" + e + "]"); + mHandler.post(() -> notifyDownloadResult(NOTIFY_TYPE_FAILED, null, 0, 0)); + } + } + + public UpgradeService() { + super("GW-UpgradeService"); + } + + public static void start(Context context, String updateUrl, String versionName, String digitalAbstract, boolean isForceUpdate) { + if (Strings.isEmpty(updateUrl) || Strings.isEmpty(versionName)) { + return; + } + Intent intent = new Intent(context, UpgradeService.class); + intent.putExtra(URL_KEY, updateUrl); + intent.putExtra(IS_FORCE, isForceUpdate); + intent.putExtra(VERSION_KEY, versionName); + intent.putExtra(DIGITAL_ABSTRACT_KEY, digitalAbstract); + context.startService(intent); + } + + @Override + protected void onHandleIntent(Intent intent) { + String url = intent.getStringExtra(URL_KEY); + String versionName = intent.getStringExtra(VERSION_KEY); + mIsForceUpdate = intent.getBooleanExtra(IS_FORCE, false); + mDigitalAbstract = intent.getStringExtra(DIGITAL_ABSTRACT_KEY); + if (!TextUtils.isEmpty(url) && !TextUtils.isEmpty(versionName)) { + new ApkDownloader(url, AppUpgradeChecker.upgradeInteractor.generateAppDownloadPath(versionName), mDigitalAbstract, new FlagDownloaderListener()).start(); + } + } + + @Override + public void onCreate() { + super.onCreate(); + mHandler = new Handler(Looper.getMainLooper()); + } + + private void notifyDownloadResult(int notifyType, File desFile, long total, long progress) { + Intent intent = new Intent(); + intent.setAction(DOWNLOAD_APK_RESULT_ACTION); + intent.putExtra(IS_FORCE, mIsForceUpdate); + intent.putExtra(NOTIFY_TYPE_KEY, notifyType); + intent.putExtra(TOTAL_PROGRESS_KEY, total); + intent.putExtra(PROGRESS_KEY, progress); + if (desFile != null) { + intent.putExtra(APK_FILE_KEY, desFile); + } + LocalBroadcastManager.getInstance(this).sendBroadcast(intent); + } + +} \ No newline at end of file diff --git a/lib_base/src/main/res/drawable/base_shape_debug_divider.xml b/lib_base/src/main/res/drawable/base_shape_debug_divider.xml new file mode 100644 index 0000000..3800217 --- /dev/null +++ b/lib_base/src/main/res/drawable/base_shape_debug_divider.xml @@ -0,0 +1,10 @@ + + + + + + + + \ No newline at end of file diff --git a/lib_base/src/main/res/layout/base_debug_environment.xml b/lib_base/src/main/res/layout/base_debug_environment.xml new file mode 100644 index 0000000..612f99b --- /dev/null +++ b/lib_base/src/main/res/layout/base_debug_environment.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/lib_base/src/main/res/layout/base_debug_environment_item.xml b/lib_base/src/main/res/layout/base_debug_environment_item.xml new file mode 100644 index 0000000..862089d --- /dev/null +++ b/lib_base/src/main/res/layout/base_debug_environment_item.xml @@ -0,0 +1,51 @@ + + + + + + + + + +