package com.application.zhangshi_app_android.ui.dialog; import android.Manifest; import android.animation.ValueAnimator; import android.app.DownloadManager; import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.graphics.BitmapFactory; import android.net.Uri; import android.os.Build; import android.os.Environment; import android.text.TextUtils; import android.text.method.ScrollingMovementMethod; import android.util.Log; import android.view.View; import android.widget.ProgressBar; import android.widget.TextView; import androidx.core.app.NotificationCompat; import androidx.core.content.ContextCompat; import androidx.core.content.FileProvider; import com.android.app_base.base.dialog.BaseDialog; import com.android.app_base.manager.UserManager; import com.android.app_base.utils.ToastUtils; import com.android.app_base.utils.Utils; import com.application.zhangshi_app_android.MyApplication; import com.application.zhangshi_app_android.R; import com.blankj.utilcode.util.NetworkUtils; import com.blankj.utilcode.util.PermissionUtils; import com.hjq.http.EasyHttp; import com.hjq.http.listener.OnDownloadListener; import com.hjq.http.model.HttpMethod; import java.io.File; import java.util.Locale; import java.util.Timer; import java.util.TimerTask; /** * 版本更新弹窗 */ public final class UpdateDialog { public static final class Builder extends BaseDialog.Builder { private final TextView mNameView; private final TextView mContentView; private final ProgressBar mProgressView; private final TextView mUpdateView; private final TextView mCloseView; /** Apk 文件 */ private File mApkFile; /** 文件名 */ private String fileName; /** 下载地址 */ private String mDownloadUrl; /** 文件 MD5 */ private String mFileMd5; /** 是否强制更新 */ private boolean mForceUpdate; /** 当前是否下载中 */ private boolean mDownloading; /** 当前是否下载完毕 */ private boolean mDownloadComplete; public Builder(Context context) { super(context); setContentView(R.layout.dialog_update); setAnimStyle(BaseDialog.ANIM_BOTTOM); setCancelable(false); mNameView = findViewById(R.id.tv_update_name); mContentView = findViewById(R.id.tv_update_content); mProgressView = findViewById(R.id.pb_update_progress); mUpdateView = findViewById(R.id.tv_update_update); mCloseView = findViewById(R.id.tv_update_close); setOnClickListener(mUpdateView, mCloseView); // 让 TextView 支持滚动 mContentView.setMovementMethod(new ScrollingMovementMethod()); } /** * 设置版本名 */ public Builder setVersionName(CharSequence name) { mNameView.setText(name); return this; } /** * 设置更新日志 */ public Builder setUpdateLog(CharSequence text) { mContentView.setText(text); mContentView.setVisibility(text == null ? View.GONE : View.VISIBLE); return this; } /** * 设置强制更新 */ public Builder setForceUpdate(boolean force) { mForceUpdate = force; mCloseView.setVisibility(force ? View.GONE : View.VISIBLE); setCancelable(!force); setCanceledOnTouchOutside(!force); return this; } /** * 设置下载 url */ public Builder setDownloadUrl(String url) { mDownloadUrl = url; return this; } /** * 设置文件 md5 */ public Builder setFileMd5(String md5) { mFileMd5 = md5; return this; } @Override public void onClick(View view) { if (view == mCloseView) { dismiss(); } else if (view == mUpdateView) { fileName = getContext().getString(R.string.app_name) + "_v" + mNameView.getText().toString() + ".apk"; // 创建要下载的文件对象 // mApkFile = new File(getContext().getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), fileName); String pathname = Environment.getExternalStorageDirectory().getPath() + "/" + Environment.DIRECTORY_DOWNLOADS + "/" + fileName; mApkFile = new File(pathname); if (mApkFile.exists() && mApkFile.isFile()) { // 如果有设置MD5,则判断MD5是否一致 if (TextUtils.isEmpty(mFileMd5)) { // 没有设置MD5,直接安装 Utils.installAPK(getContext(),fileName); } else { // 设置了MD5,判断MD5是否一致 String md5 = Utils.calculateMD5(mApkFile); if (md5 != null && md5.equalsIgnoreCase(mFileMd5)) { // 已下载,直接安装 Utils.installAPK(getContext(),fileName); } else { // 删除旧 Apk boolean delete = mApkFile.delete(); if (!delete) { ToastUtils.showShort("删除旧 Apk 失败,请先手动删除后重试"); }else { // 重新下载 downloadApk(); } } } } else { // 判断下载状态 if (mDownloadComplete) { // 下载完毕,安装 Apk // installApk(); Utils.installAPK(getContext(),fileName); } else if (!mDownloading) { // 没有下载,开启下载 downloadApk(); } } } } /** * 下载 Apk */ private void downloadApk() { if (!Utils.checkNetwork()){ ToastUtils.showShort("当前没有网络连接,请检查网络设置"); return; } // 设置对话框不能被取消 setCancelable(false); // NotificationManager notificationManager = ContextCompat.getSystemService(getContext(), NotificationManager.class); // int notificationId = getContext().getApplicationInfo().uid; // String channelId = ""; // // 适配 Android 8.0 通知渠道新特性 // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // NotificationChannel channel = new NotificationChannel("update", "升级通知", NotificationManager.IMPORTANCE_LOW); // channel.enableLights(false); // channel.enableVibration(false); // channel.setVibrationPattern(new long[]{0}); // channel.setSound(null, null); // if (notificationManager != null) { // notificationManager.createNotificationChannel(channel); // } // channelId = channel.getId(); // } // // NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(getContext(), channelId) // // 设置通知时间 // .setWhen(System.currentTimeMillis()) // // 设置通知标题 // .setContentTitle(getContext().getString(R.string.app_name)) // // 设置通知小图标 // .setSmallIcon(R.mipmap.ic_logo) // // 设置通知大图标 // .setLargeIcon(BitmapFactory.decodeResource(getContext().getResources(), R.mipmap.ic_logo)) // // 设置通知静音 // .setDefaults(NotificationCompat.FLAG_ONLY_ALERT_ONCE) // // 设置震动频率 // .setVibrate(new long[]{0}) // // 设置声音文件 // .setSound(null) // // 设置通知的优先级 // .setPriority(NotificationCompat.PRIORITY_DEFAULT); //创建下载任务,downloadUrl就是下载链接 DownloadManager.Request request = new DownloadManager.Request(Uri.parse(mDownloadUrl)); request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE);//下载进行中和下载完成的通知栏是否显示 request.allowScanningByMediaScanner();//设置允许被扫描到 request.setVisibleInDownloadsUi(true);//下载的文件可以被系统的Downloads应用扫描到并管理 request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName); //指定下载路径和下载文件名 final DownloadManager downloadManager = (DownloadManager) MyApplication.getInstance().getSystemService(Context.DOWNLOAD_SERVICE);//获取下载管理器 final long downloadID = downloadManager.enqueue(request);//将下载任务加入下载队列,否则不会进行下载 final DownloadManager.Query query = new DownloadManager.Query(); query.setFilterById(downloadID);//筛选下载任务,传入任务ID,可变参数 // 标记为下载中 mDownloading = true; // 标记成未下载完成 mDownloadComplete = false; // 后台更新 mCloseView.setVisibility(View.GONE); // 显示进度条 mProgressView.setVisibility(View.VISIBLE); mUpdateView.setText("正在下载.."); final Timer mTimer = new Timer(); mTimer.schedule(new TimerTask() { @Override public void run() { Cursor c = null; try { c = downloadManager.query(query); if (c != null) { if (c.moveToFirst()) { // 下载状态 int status = c.getInt(c.getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS)); // 已下载的字节大小 final long downloadedSoFar = c.getLong(c.getColumnIndexOrThrow(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR)); // 下载文件的总字节大小 final long totalSize = c.getLong(c.getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES)); int progress = (int) (downloadedSoFar * 100 / totalSize); switch (status) { case DownloadManager.STATUS_PAUSED: Log.d("APPUpdate", "下载暂停:" + fileName); case DownloadManager.STATUS_PENDING: Log.d("APPUpdate", "下载延迟:" + fileName); case DownloadManager.STATUS_RUNNING: Log.d("APPUpdate", "正在下载:" + fileName); // ValueAnimator animator = ValueAnimator.ofInt(mProgressView.getProgress(), progress); // animator.setDuration(100); // animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { // @Override // public void onAnimationUpdate(ValueAnimator animation) { // int currentValue = (int) animation.getAnimatedValue(); // // } // }); // animator.start(); mUpdateView.setText(String.format(Locale.CHINA,"下载中 %d%%", progress)); mProgressView.setProgress(progress); // 更新下载通知 // notificationManager.notify(notificationId, notificationBuilder // // 设置通知的文本 // .setContentText(String.format(Locale.CHINA,"下载中 %d%%", progress)) // // 设置下载的进度 // .setProgress(100, progress, false) // // 设置点击通知后是否自动消失 // .setAutoCancel(false) // // 是否正在交互中 // .setOngoing(true) // // 重新创建新的通知对象 // .build()); break; case DownloadManager.STATUS_SUCCESSFUL: Log.d("APPUpdate", "下载完成:" + fileName); mTimer.cancel(); dismiss(); // if (notificationManager != null) { //// // 显示下载成功通知 // notificationManager.notify(notificationId, notificationBuilder // // 设置通知的文本 // .setContentText(String.format(Locale.CHINA,"下载中 %d%%",100)) // // 设置下载的进度 // .setProgress(100, 100, false) // // 设置通知点击之后的意图 // .setContentIntent(PendingIntent.getActivity(getContext(), 1, getInstallIntent(), PendingIntent.FLAG_IMMUTABLE)) // // 设置点击通知后是否自动消失 // .setAutoCancel(true) // // 是否正在交互中 // .setOngoing(false) // .build()); // } mUpdateView.setText("下载完成,点击安装"); // 标记成下载完成 mDownloadComplete = true; // 标记当前不是下载中 mDownloading = false; // 如果当前不是强制更新,对话框就恢复成可取消状态 if (!mForceUpdate) { setCancelable(true); } // 安装 Apk // installApk(); Utils.installAPK(getContext(), fileName); break; case DownloadManager.STATUS_FAILED: Log.d("APPUpdate", "下载失败:" + fileName); // if (notificationManager != null) { // // 清除通知 // notificationManager.cancel(notificationId); // } mUpdateView.setText("下载失败,点击重试"); // 删除下载的文件 mApkFile.delete(); break; } } } } finally { if (c != null) { c.close(); } } } }, 0, 1000); } /** * 安装 Apk */ private void installApk() { getContext().startActivity(getInstallIntent()); } /** * 获取安装意图 */ private Intent getInstallIntent() { Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); Uri uri; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { uri = FileProvider.getUriForFile(getContext(), getContext().getApplicationContext().getPackageName() + ".fileprovider", mApkFile); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); } else { uri = Uri.fromFile(mApkFile); } intent.setDataAndType(uri, "application/vnd.android.package-archive"); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); return intent; } } }