
首先,在android 原生的设置中就已经有了ota联网升级的功能,可以仿照哪个做一个开机联网检测是否有新版本的功能,想法是在SystemUI 中增加,在第一次开机联网的时候检测更新
AndroidManifest.xml
增加权限
diff --git a/frameworks/base/packages/SystemUI/AndroidManifest.xml b/frameworks/base/packages/SystemUI/AndroidManifest.xml
old mode 100644
new mode 100755
index 5599b5a..e678030
--- a/frameworks/base/packages/SystemUI/AndroidManifest.xml
+++ b/frameworks/base/packages/SystemUI/AndroidManifest.xml
@@ -70,6 +70,7 @@
<uses-permission android:name="android.permission.REQUEST_NETWORK_SCORES" />
<uses-permission android:name="android.permission.CONTROL_VPN" />
<uses-permission android:name="android.permission.PEERS_MAC_ADDRESS"/>
+ <uses-permission android:name="android.permission.INTERNET" />
<!-- Physical hardware -->
<uses-permission android:name="android.permission.MANAGE_USB" />
<uses-permission android:name="android.permission.CONTROL_DISPLAY_BRIGHTNESS" />
@@ -105,7 +106,6 @@
<!-- DreamManager -->
<uses-permission android:name="android.permission.READ_DREAM_STATE" />
<uses-permission android:name="android.permission.WRITE_DREAM_STATE" />
<!-- Alarm clocks -->
<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
@@ -229,6 +229,7 @@
android:theme="@style/Theme.SystemUI"
android:defaultToDeviceProtectedStorage="true"
android:directBootAware="true"
+ android:usesCleartextTraffic="true"
android:appComponentFactory="android.support.v4.app.CoreComponentFactory">
<!-- Keep theme in sync with SystemUIApplication.onCreate().
Setting the theme on the application does not affect views inflated by services.
android:usesCleartextTraffic="true"表示是否打算使用明文网络流量,例如明文HTTP, Aandroid 9 及以上默认为false,推荐使用 HTTPS 加密的方式传输,更安全
NetworkControllerImpl.java
网络监听广播,监听到网络变化后,检测网络是否可用,可用检测是否有版本升级,有就弹出升级dialog
SystemProperties.set(“zwt.update.ischeck”, “1”); 是这只系统的变量,因为不是persist 或 ro 开头的变量,所以断电上电后这个属性就被删除了,达到开机只检测一次的目的
diff --git a/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/frameworks/base/packages/SystemUI/sr
old mode 100644
new mode 100755
index b8d6f13..b65093c
--- a/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -34,6 +34,8 @@ import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.PersistableBundle;
+import android.os.Build;
+import android.os.SystemProperties;
import android.provider.Settings;
import android.telephony.CarrierConfigManager;
import android.telephony.ServiceState;
@@ -58,6 +60,8 @@ import com.android.systemui.R;
import com.android.systemui.settings.CurrentUserTracker;
import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
// Mediatek Android Patch Begin
+import com.android.systemui.update.CheckoutUpdateVersion;
+import com.android.systemui.update.UpdateVersionDialogImpl;
import com.android.systemui.util.Utils;
// Mediatek Android Patch End
@@ -462,6 +466,17 @@ public class NetworkControllerImpl extends BroadcastReceiver
break;
case ConnectivityManager.CONNECTIVITY_ACTION:
case ConnectivityManager.INET_CONDITION_ACTION:
+ // 2022 add update dialog start
+ Log.d(TAG,"##zwt_UpdateDialog## internet change,isCheck::"+("1".equals(SystemProperties.get("wssl.ischeck"))));
+ if (!("1".equals(SystemProperties.get("wssl.update.ischeck")))){
+ if (isNetworkAvailable()){
+ SystemProperties.set("zwt.update.ischeck", "1");
+ CheckoutUpdateVersion checkoutUpdateVersion = new CheckoutUpdateVersion(new UpdateVersionDialogImpl(mContext).getHandler());
+ Log.d(TAG,"##zwt_UpdateDialog## show dialog");
+ checkoutUpdateVersion.checkout();
+ }
+ }
+ // 2022 add update dialog end
updateConnectivity(intent);
break;
// Mediatek Android Patch End
@@ -1121,4 +1136,30 @@ public class NetworkControllerImpl extends BroadcastReceiver
return config;
}
}
+ // 2022 add update dialog start
+ public boolean isNetworkAvailable(){
+ ConnectivityManager connectivityManager = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+ if (connectivityManager == null){
+ return false;
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
+ Network[] networks = connectivityManager.getAllNetworks();
+ NetworkInfo networkInfo;
+ for (Network network : networks){
+ networkInfo = connectivityManager.getNetworkInfo(network);
+ if (networkInfo.getState().equals(NetworkInfo.State.CONNECTED))
+ return true;
+ }
+ }else {
+ NetworkInfo[] networkInfos = connectivityManager.getAllNetworkInfo();
+ for (NetworkInfo networkInfo : networkInfos) {
+ if (networkInfo.getState() == NetworkInfo.State.CONNECTED) {
+ return true;
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+ // 2022 add update dialog end
}
后面是新增的弹出 dialog 文件,逻辑很简单不作解释
CheckoutUpdateVersion.java
package com.android.systemui.update;
import android.content.Context;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.os.SystemProperties;
import android.util.Log;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
public class CheckoutUpdateVersion {
private final String TAG = "CheckoutUpdateVersion";
Handler handler;
public CheckoutUpdateVersion(Handler handler){
this.handler = handler;
}
private static final String JSON_URL = "填写ota服务器url";
public Boolean checkout(){
new Thread(new Runnable() {
@Override
public void run() {
String jsonStr = getJsonString();
String updateVersion = getVersionInfo(jsonStr);
if(checkVersion(updateVersion)){
Log.d(TAG,"has new version:"+updateVersion);
Message msg = handler.obtainMessage();
msg.what = 1;
msg.obj = updateVersion;
handler.sendMessage(msg);
}
}
}).start();
//checkVersion(getVersionInfo(getJsonString()));
return true;
}
private String getJsonString(){
StringBuffer buffer = new StringBuffer();
HttpURLConnection httpUrlConnection = null;
InputStream inputStream = null;
BufferedReader bufferedReader = null;
try {
final String systemVersion = Build.VERSION.INCREMENTAL;
final String systemDevice = SystemProperties.get("ro.product.device");
final String customerId = SystemProperties.get("ro.build.version.customerid");
// final String systemDevice = "mt5862_bga_1g";
String urlstr = JSON_URL + "?" + "version=" + systemVersion + "&" + "device=" + systemDevice + "&customer=" + customerId;
Log.d(TAG, urlstr);
URL url = new URL(urlstr);
httpUrlConnection = (HttpURLConnection) url.openConnection();
httpUrlConnection.setRequestProperty("Content-Type", "text/json; charset=UTF-8");
httpUrlConnection.connect();
inputStream = httpUrlConnection.getInputStream();
bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
String line = "";
while ((line = bufferedReader.readLine()) != null) {
buffer.append(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (httpUrlConnection != null)
httpUrlConnection.disconnect();
if (inputStream != null)
inputStream.close();
if (bufferedReader != null)
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return buffer.toString();
}
private String getVersionInfo(String jsonString) {
String resultVersion = "";
try{
JSONObject jsonObject = new JSONObject(jsonString);
resultVersion = jsonObject.getString("FW_VER");
} catch (JSONException e) {
e.printStackTrace();
}
return resultVersion;
}
private boolean checkVersion(String updateVersion){
String ignoreUpdateVersion = file2String("/mnt/sdcard/Android/ignoreUpdateVersion");
if (ignoreUpdateVersion.contains(updateVersion)){
Log.d(TAG, "ignore");
return false;
}
final String systemVersion = Build.VERSION.INCREMENTAL;
if (systemVersion == null){
return false;
}
if (updateVersion != null && systemVersion.contains(".")) {
if (updateVersion.compareTo(systemVersion) > 0) {
return true;
} else {
return false;
}
}
return false;
}
private String file2String(String ignoreUpdateVersionFile) {
String content="";
File file = new File(ignoreUpdateVersionFile);
if (!file.exists()) return "Unable to open file!";
try {
InputStream inputStream = new FileInputStream(file);
if (inputStream != null){
InputStreamReader reader = new InputStreamReader(inputStream,"GB2312");
BufferedReader bufferedReader = new BufferedReader(reader);
String line;
while ((line = bufferedReader.readLine()) != null){
content += line + "\n";
}
inputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
return content;
}
}
UpdateVersionDialogImpl.java
package com.android.systemui.update;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.drawable.ColorDrawable;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.TextView;
import com.android.systemui.R;
import android.os.Environment;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.StringReader;
import android.util.Log;
import android.os.Handler;
import android.os.Message;
public class UpdateVersionDialogImpl {
private CheckBox checkBox;
private Button btnUpdate;
private Button btnCancel;
private TextView alertDialogTips;
private final Context mContext;
AlertDialog dialog;
AlertDialog.Builder mbuilder;
public UpdateVersionDialogImpl(Context context){
mContext = context;
}
@SuppressLint("SdCardPath")
private void show(String updateVersion){
mbuilder = new AlertDialog.Builder(mContext);
dialog = mbuilder.create();
Window mWindow = dialog.getWindow();
mWindow.requestFeature(Window.FEATURE_NO_TITLE);
mWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
mWindow.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND
| WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR);
mWindow.addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
mWindow.setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
final WindowManager.LayoutParams lp = mWindow.getAttributes();
lp.format = PixelFormat.TRANSLUCENT;
lp.windowAnimations = -1;
mWindow.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
mWindow.setBackgroundDrawableResource(R.drawable.dialog_background);
dialog.setCanceledOnTouchOutside(true);
mWindow.setAttributes(lp);
dialog.show();
//View view = LayoutInflater.from(mContext).inflate(R.layout.system_update_dialog, null);
//TextView tvTitle = (TextView) view.findViewById(R.id.alert_dialog_title);
dialog.setContentView(R.layout.system_update_dialog);
btnUpdate = dialog.findViewById(R.id.alert_dialog_button_update);
btnCancel = dialog.findViewById(R.id.alert_dialog_button_cancel);
checkBox = dialog.findViewById(R.id.alert_dialog_checkBox);
alertDialogTips = dialog.findViewById(R.id.alert_dialog_tips);
// dialog.show();
btnUpdate.setOnClickListener((View v)->{
Intent intent = new Intent();
ComponentName comp = new ComponentName("com.android.tv.settings", "com.android.tv.settings.update.SystemNetUpdateActivity");
intent.setComponent(comp);
intent.putExtra("other", "true");
intent.setAction("android.intent.action.VIEW");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);
dialog.dismiss();
});
btnCancel.setOnClickListener((View v)->{
if (checkBox.isChecked()){
//string2File("aaa","/data/user/ignoreUpdateVersion");
string2File(updateVersion+"#","/mnt/sdcard/Android/ignoreUpdateVersion");
}
dialog.dismiss();
});
checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked){//选中
btnUpdate.setEnabled(false);
//alertDialogTips.setVisibility(View.VISIBLE);
}else {
//alertDialogTips.setVisibility(View.INVISIBLE);
btnUpdate.setEnabled(true);
}
}
});
}
private boolean string2File(String res, String filePath) {
boolean flag = true;
BufferedReader bufferedReader = null;
BufferedWriter bufferedWriter = null;
try {
File distFile = new File(filePath);
if (!distFile.getParentFile().exists()){
distFile.getParentFile().mkdirs();
}
bufferedReader = new BufferedReader(new StringReader(res));
bufferedWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(distFile, true)));
char buf[] = new char[1024];
int len;
while ((len = bufferedReader.read(buf)) != -1) {
bufferedWriter.write(buf, 0, len);
}
bufferedWriter.flush();
bufferedReader.close();
bufferedWriter.close();
} catch (IOException e) {
e.printStackTrace();
flag = false;
return flag;
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return flag;
}
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
String updateVersion = (String) msg.obj;
show(updateVersion);
break;
default:
break;
}
}
};
public Handler getHandler(){
return handler;
}
}
ComponentName comp = new ComponentName(“com.android.tv.settings”, “com.android.tv.settings.update.SystemNetUpdateActivity”);
是去调起系统的更新界面,也可以自己写服务后台下载升级,偷懒就直接调用系统的升级界面
dialog_background.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid
android:color="#ffffff"/>
<stroke
android:width="2dp"
android:color="#ffffff" />
<corners
android:radius="30dp"/>
</shape>
system_update_dialog.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="2dp">
<TextView
android:id="@+id/alert_dialog_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="#000000"
android:textSize="23sp"
android:text="@string/system_update_dialog_title"
android:paddingTop="20dp"
android:paddingBottom="10dp"
android:paddingLeft="30dp"
/>
<TextView
android:id="@+id/alert_dialog_message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#FFFFFF"
android:textColor="#171718"
android:textSize="18sp"
android:paddingLeft="20dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:text="@string/system_update_dialog_message"/>
<TextView
android:id="@+id/alert_dialog_tips"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000000"
android:text="将不会在收到这个版本的更新提示,可在设置中手动升级"
android:layout_gravity="center"
android:visibility="gone"/>
<CheckBox
android:id="@+id/alert_dialog_checkBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000000"
android:text="@string/system_update_dialog_ignore"
android:checked="false"
android:layout_gravity="right"
android:layout_marginRight="30dp"/>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="2dp"
android:gravity="right"
android:layout_marginBottom="10dp">
<Button
android:id="@+id/alert_dialog_button_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="20dp"
android:text="@string/system_update_dialog_cancel" />
<Button
android:id="@+id/alert_dialog_button_update"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity= "center"
android:text="@string/system_update_dialog_update"
android:layout_marginRight="30dp"/>
</LinearLayout>
</LinearLayout>
字符串的国际化的修改
diff --git a/frameworks/base/packages/SystemUI/res/values/strings.xml b/frameworks/base/packages/SystemUI/res/values/strings.xml
old mode 100644
new mode 100755
index edf56af..9403469
--- a/frameworks/base/packages/SystemUI/res/values/strings.xml
+++ b/frameworks/base/packages/SystemUI/res/values/strings.xml
@@ -2243,4 +2243,12 @@
app for debugging. Will not be seen by users. [CHAR LIMIT=20] -->
<string name="heap_dump_tile_name">Dump SysUI Heap</string>
+
+ <!-- ota system update dialog -->
+ <string name="system_update_dialog_title">System Update</string>
+ <string name="system_update_dialog_message">A new version has been detected. Do you want to update it</string>
+ <string name="system_update_dialog_ignore">Ignore this version</string>
+ <string name="system_update_dialog_cancel">Cancel</string>
+ <string name="system_update_dialog_update">Update</string>
+ <!-- ota system update dialog -->
</resources>
diff --git a/frameworks/base/packages/SystemUI/res/values-zh-rCN/strings.xml b/frameworks/base/packages/SystemUI/res/values-zh-rCN/strings.xml
old mode 100644
new mode 100755
index 3bf909b..a9b8b11
--- a/frameworks/base/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/frameworks/base/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -854,4 +854,11 @@
<string name="open_saver_setting_action" msgid="8314624730997322529">"设置"</string>
<string name="auto_saver_okay_action" msgid="2701221740227683650">"知道了"</string>
<string name="heap_dump_tile_name" msgid="9141031328971226374">"转储 SysUI 堆"</string>
+ <!-- ota system update dialog -->
+ <string name="system_update_dialog_title">系统更新</string>
+ <string name="system_update_dialog_message">检测到新版本,是否更新</string>
+ <string name="system_update_dialog_ignore">忽略此版本</string>
+ <string name="system_update_dialog_cancel">取消</string>
+ <string name="system_update_dialog_update">更新</string>
+ <!-- ota system update dialog -->
</resources>
注意,因为修改了AndroidManifest.xml 文件,单编过后复制到系统中时,需要将 oat 目录也一起复制过去,不然AndroidManifest.xml 文件没有替换,会报权限问题,至于单编systemui 编译不过这篇文章中有讲:https://blog.csdn.net/weixin_44128558/article/details/125396703
至此添加完成
Settings\src\com\android\tv\settings\update\SystemNetUpdateActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.system_net_update);
findViews(); //初始化
checkStorage(); //检查空间是否充足,主要检查/cache 文件夹的空间是否充足,不充足则使用其他外部存储的空间
mCurrentProgress = 0; //当前下载进度为0
new Thread(new Runnable() { //http 请求为耗时操作,要放到线程中,不然报错
@Override
public void run() {
getVersionInfo(); // 获得远程升级包信息,通过http请求,并将返回的信息保存到 mVersionInfo 对象中
// check new version
handler.sendEmptyMessage(CHECK_NEW_VERSION); //handler根据获得的版本号进行不同的逻辑显示
}
}).start();
registerListeners(); //注册监听点击事件等
}
//获得远程升级版本信息
private void getVersionInfo() {
try {
JSONObject jsonObject = new JSONObject(JSONData.getUpgradeInfo()); //http请求返回jason字符串
mVersionInfo.setVersion(jsonObject.getString("FW_VER")); //版本号
mVersionInfo.setUrl(jsonObject.getString("FW_URL")); //ota包下载URL
mVersionInfo.setSize(jsonObject.getLong("size")); //ota包大小,用于校验
mVersionInfo.setMd5(jsonObject.getString("md5")); //ota包的MD5值,用于校验
} catch (JSONException e) {
e.printStackTrace();
handler.sendEmptyMessage(CHECK_VERSION_FAIL);
}
}
通过 getVersionInfo() 方法中的 JSONData.getUpgradeInfo();进行http请求,去获取服务器端的升级版本信息json字符串,并将相关的信息放到 mVersionInfo 对象中保存起来
Settings\src\com\android\tv\settings\update\JSONData.java
private static final String JSON_URL = "ota服务器地址";
private static String json_data = null;
@SuppressLint("NewApi")
private static String getJsonString(JSONObject json) { //请求json字符串
StringBuffer buffer = new StringBuffer();
HttpURLConnection httpUrlConnection = null;
InputStream inputStream = null;
BufferedReader bufferedReader = null;
try {
final String systemVersion = Tools.getSystemVersion();
final String systemDevice = SystemProperties.get("ro.product.device"); //获得版型
final String customerId = SystemProperties.get("ro.build.version.customerid"); //获得客户id
String urlstr = JSON_URL + "?" + "version=" + systemVersion + "&" + "device=" + systemDevice + "&customer=" + customerId; //服务器根据传过来的systemVersion等信息查找相应的更新包,get方式传递参数给服务器
URL url = new URL(urlstr);
Log.d(TAG, "json url, " + urlstr);
httpUrlConnection = (HttpURLConnection) url.openConnection();
httpUrlConnection.setRequestProperty("Content-Type", "text/json; charset=UTF-8");
httpUrlConnection.connect();
Log.d(TAG, "response code, " + httpUrlConnection.getResponseCode());
inputStream = httpUrlConnection.getInputStream();
bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
String line = "";
while ((line = bufferedReader.readLine()) != null) {
buffer.append(line);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (httpUrlConnection != null) {
httpUrlConnection.disconnect();
}
if (inputStream != null) {
inputStream.close();
}
if (bufferedReader != null) {
bufferedReader.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
Log.d(TAG, "buffer.toString, " + buffer.toString());
return buffer.toString();
}
@SuppressLint("NewApi")
public static String getUpgradeInfo() {
if (json_data == null || json_data.isEmpty()){ //判断是否已经有保存的数据,避免重复请求
JSONObject json = new JSONObject();
json_data = getJsonString(json); //通过http协议请求
}
return json_data;
}
回到Settings\src\com\android\tv\settings\update\SystemNetUpdateActivity.java请求成功后oCreate会调用到下面的地方
// Handler
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case CHECK_STORAGE:
checkStorage();
break;
case CHECK_NEW_VERSION: //检查新版本
mHasNewVersion = checkUpdateVersion();
if (mHasNewVersion) { //当前系统版本为空或者有新版本,显示为 下载 按钮
mUpdateInfo += getString(R.string.new_version) + mNewVersion + "\n";
mUpdateInfoText.setText(mUpdateInfo);
mUpdateButton.setText(getString(R.string.download));
mUpdateButton.setEnabled(true);
} else { //版本校验失败,显示你的系统版本已经是最新 显示为 退出 按钮
mUpdateInfo += getString(R.string.latest) + "\n";
mUpdateInfoText.setText(mUpdateInfo);
mUpdateButton.setText(getString(R.string.exit));
mUpdateButton.setEnabled(true);
}
break;
case DOWNLOAD_ERROR:
.
.
.
default:
break;
}
}
};
private void init() {
String directoryName = "";
mPackageSize = mVersionInfo.getSize(); //获得的升级包信息大小
long cacheFreeSize = getCacheFreeSize(); //获得catch 文件夹大小
if (cacheFreeSize > mPackageSize) {
directoryName = "/cache/versioninfor";
} else { //获取根路径,优先外部存储
directoryName = Environment.getExternalStorageDirectory().toString() + "/versioninfor";
}
Tools.string2File(JSONData.getUpgradeInfo(), directoryName); //将升级json写到本地 /cache/versioninfor
}
private boolean checkUpdateVersion() {
init();
mNewVersion = mVersionInfo.getVersion(); // 获得升级的版本号
mPackageSize = mVersionInfo.getSize(); //获得升级包大小
mDownloadUrl = mVersionInfo.getUrl(); //获得下载的URL
if (mDownloadUrl != null) { //通过SharedPreferences 存储升级信息
commitURLValue(DOWNLOAD_ADDRESS, mDownloadUrl);
commitURLValue(VERSION, mNewVersion);
commitURLValue(PACKAGE_SIZE, String.valueOf(mPackageSize));
}
return checkVersion();
}
private boolean checkVersion() {
final String systemVersion = Tools.getSystemVersion(); //获取本机及其的内部版本号,Build.VERSION.INCREMENTAL;
if (systemVersion == null) { //当前版本为空,请求的时候会传递过去,在服务器端处理,应该是下载默认的应用
mHasNewVersion = true;
return mHasNewVersion;
}
if (systemVersion.equals(mNewVersion)) { //两个版本相同,显示已经是最新的版本
mHasNewVersion = false;
return mHasNewVersion;
}
if (mNewVersion != null && systemVersion.contains(".")) { //判断版本大小,要大于当前版本
if (mNewVersion.compareTo(systemVersion) > 0) {
mHasNewVersion = true;
} else {
mHasNewVersion = false;
}
}
Log.d(TAG, "mHasNewVersion, " + mHasNewVersion);
return mHasNewVersion;
}
private void commitURLValue(String key, String value) {
SharedPreferences preference = getSharedPreferences(NAME, Context.MODE_PRIVATE);
Editor edit = preference.edit();
edit.putString(key, value);
edit.commit();
}
到这里http请求服务器查看有没有版本更新的代码就完成了,如果有新版本,按钮显示Download,没有新版本则提示已经是最新版本,按钮显示Exit
private void registerListeners() {
mUpdateButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (mHasNewVersion) { //是否有新版本
if (!isNetConnected()) { //网络是否连接
Toast.makeText(SystemNetUpdateActivity.this,
getString(R.string.not_network), Toast.LENGTH_SHORT).show();
return;
}
mUpdateInfo += getString(R.string.downloading) + "\n"; //Downloading new version......
mUpdateInfoText.setText(mUpdateInfo);
mLayout.setVisibility(View.VISIBLE); //显示下载进度
Log.d(TAG, "downUrl, " + mVersionInfo.getUrl());
Log.d(TAG, "newVersion, " + mVersionInfo.getVersion());
Log.d(TAG, "size, " + mVersionInfo.getSize());
Intent intent = new Intent(SystemNetUpdateActivity.this, UpdateService.class);
Bundle bundle = new Bundle();
bundle.putString("downUrl", mDownloadUrl); //传递下载的信息
bundle.putString("newVersion", mNewVersion);
bundle.putString("size", String.valueOf(mPackageSize));
intent.putExtras(bundle);
SystemNetUpdateActivity.this.startServiceAsUser(intent, UserHandle.CURRENT);//开启下载服务
mUpdateButton.setEnabled(false); //设置按钮不能点击
mUpdateButton.setText(getString(R.string.download_ing)); //Downloading
} else if (mHasDownloaded) { //是否已经下载完成
mUpdateInfo += getString(R.string.check_package);
mUpdateInfoText.setText(mUpdateInfo);
mHasDownloaded = false;
mLayout.setVisibility(View.VISIBLE);
mUpdateButton.setEnabled(false);
isUpdating = true; //表示正在更新
new UpdateSystemThread().start(); //开启线程,更新系统
} else {
finish(); //退出应用
}
}
});
}
如果有新版本,当点击按钮的时候就会开启一个下载服务在后台下载,SystemNetUpdateActivity.this.startServiceAsUser(intent, UserHandle.CURRENT);
Settings\src\com\android\tv\settings\update\UpdateService.java
public class UpdateService extends Service {
private Handler mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
super.handleMessage(msg);
Log.d(TAG, "mHandler msg " + msg.what);
if (msg.what <= 100) {
if (msg.what == 0) { // 准备下载
mNotification.contentView = mRemoteViews;
mNotification.contentIntent = mPendingIntent;
mNotificationManager.notify(DOWNLOADING, mNotification);
}
if (msg.what == 100) { //下载完成
commitPercentValue(PERCENT, 100);
mNotificationManager.cancel(DOWNLOADING);
mNotification.flags |= Notification.FLAG_AUTO_CANCEL;
showNotification(R.drawable.appwidget_bg_holo, R.string.downloading, msg.what);
}
mRemoteViews.setTextViewText(R.id.task_percent, msg.what + "%");
mRemoteViews.setProgressBar(R.id.task_progressbar, 100, msg.what, false);
sendPercentData(); //发送广播通知ui下载进度
}
mNotification.contentView = mRemoteViews;
mNotification.contentIntent = mPendingIntent;
mNotificationManager.notify(DOWNLOADING, mNotification); //刷新通知显示
};
};
//下载错误时
private Handler mErrorHandler = new Handler() {
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == DOWNLOAD_ERROR) {
commitPercentValue(PERCENT, mDownloadPercent);
onUpdateError(ERROR_DOWNLOAD); //此方法也是发送广播,通知ui下载异常
}
};
};
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
mDownloadPercent = 0; //下载百分比
showNotification(R.drawable.appwidget_bg_holo, R.string.downloading, mDownloadPercent);//定义通知,开启前台服务
Message msg = mHandler.obtainMessage();
msg.what = mDownloadPercent;
mHandler.sendMessage(msg); // 发送handler DownloadPercent = 0 在handler中做一些初始化
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
mDownloadUrl = intent.getStringExtra("downUrl"); //获得传递过来的下载版本信息
mNewVersion = intent.getStringExtra("newVersion");
mSize = intent.getStringExtra("size");
Log.d(TAG, "UpdateService-downUrl, " + mDownloadUrl);
Log.d(TAG, "UpdateService-newVersion, " + mNewVersion);
Log.d(TAG, "UpdateService-mSize, " + mSize);
startDownload(); //开始下载
return super.onStartCommand(intent, flags, startId);
}
/**
* start download the update package.
*/
private void startDownload() {
String directoryName = "";
long cacheFreeSize = getCacheFreeSize(); //获得cache目录剩余空间大小
if (cacheFreeSize > Long.parseLong(mSize)) { //判断下载的文件放到哪个位置
directoryName = "/cache/update_signed.zip";
} else {
directoryName = Environment.getExternalStorageDirectory().toString()
+ "/update_signed.zip";
}
// if ota upgrade package exited, delete it
File f = new File(directoryName);
if (f.exists()) {
f.delete();
}
// 下载监听 监听下载进度
IDownloadProgressListener downloadProgressListener = new IDownloadProgressListener() {
@Override
public void onDownloadSizeChange(int percent) {
mDownloadPercent = percent;
Log.d(TAG, "percent:" + percent);
Message msg = mHandler.obtainMessage();
msg.what = percent;
mHandler.sendMessage(msg);
}
};
//UpgradeTask 实现 Runnable
UpgradeTask upgradeTask = new UpgradeTask(UpdateService.this, mDownloadUrl, directoryName,
mNewVersion, downloadProgressListener, mErrorHandler);
new Thread(upgradeTask).start(); //开启任务线程下载
}
}
Settings\src\com\android\tv\settings\update\UpgradeTask.java
public class UpgradeTask implements Runnable {
@Override
public void run() {
prepare(); //准备 获得相关信息,下载地址版本和大小
int count = 20;
int loop = 0;
int res = -1;
while(loop < count) //尝试20次下载
{
res = download(); //开始下载
if (res == -1) {
Log.d(TAG, "download failed");
mHandler.sendEmptyMessage(DOWNLOAD_ERROR);
return;
} else if ( res == -2) {
loop++;
Log.d(TAG, "download except, retry...");
continue;
} else {
return;
}
}
};
private void prepare() {
File file = new File(mLocalPath);
if (!file.getParentFile().exists()) { //创建文件夹
file.getParentFile().mkdirs();
}
String versionString = getStringData(VERSION); //获得要下载版本
if (versionString.equals(mVersion)) {
mUpgradeURL = getStringData(DOWNLOAD_ADDRESS);
mTotalSize = Long.parseLong(getStringData(PACKAGE_SIZE));
} else {
Log.d(TAG, "delete file");
file.delete();
}
}
/*
* @see
* com.jrm.core.container.cmps.upgrade.task.BaseUpgradeTask#onDownload()
*/
protected int download() {
File file = new File(mLocalPath);
if (file.exists()) { //判断下载的文件是否存在
mDownloadedSize = file.length();
} else {
mDownloadedSize = 0;
}
// check package whether be downloaded
if (mDownloadedSize == mTotalSize && this.mDownloadProgressListener != null) { //对比两个文件大小,一样表示已经下载过,无需重新下载
mDownloadProgressListener.onDownloadSizeChange(100); //回调下载进度100%
return 0;
} else if (mDownloadedSize > mTotalSize) {
if (!file.delete()) {
return -1;
}
}
Log.d(TAG, "==> mUpgradeURL, " + mUpgradeURL + " downloadedSize, " + mDownloadedSize);
HttpURLConnection httpConnection = null;
URL url = null;
BufferedInputStream binStream = null;
BufferedOutputStream boutStream = null;
try {
url = new URL(mUpgradeURL);
httpConnection = (HttpURLConnection) url.openConnection();
httpConnection.setRequestMethod("GET");
httpConnection.setRequestProperty("Range", "bytes=" + mDownloadedSize + "-");
httpConnection.setRequestProperty("Connection", "close");
httpConnection.setReadTimeout(10*1000);
httpConnection.connect();
Log.d(TAG, "response code, " + httpConnection.getResponseCode());
binStream = new BufferedInputStream(httpConnection.getInputStream());
boutStream = new BufferedOutputStream(new FileOutputStream(mLocalPath, true));
int offset = 0;
int count = 0;
int perUnit = (int) mTotalSize / 8192 / 100;
byte[] buffer = new byte[8192];
while ((offset = binStream.read(buffer, 0, 8192)) != -1) {
boutStream.write(buffer, 0, offset);
count++;
if (count == perUnit && mDownloadedSize < mTotalSize) {
mDownloadPercent = (int) (mDownloadedSize * 100 / mTotalSize);
if (this.mDownloadProgressListener != null) {
mDownloadProgressListener.onDownloadSizeChange(mDownloadPercent);
}
count = 0;
}
mDownloadedSize += offset;
}
if (mDownloadedSize == mTotalSize && this.mDownloadProgressListener != null) {
mDownloadProgressListener.onDownloadSizeChange(100);
Log.d(TAG, "download finished.");
return 0;
} else {
Log.d(TAG, "download error.");
return -2;
}
} catch (Exception e) {
e.printStackTrace();
return -2;
} finally {
try {
if (binStream != null) {
binStream.close();
}
if (httpConnection != null) {
httpConnection.disconnect();
}
if (boutStream != null) {
boutStream.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
到这里,下载完成后会通知SystemNetUpdateActivity.java 下载的进度为100%,SystemNetUpdateActivity.java会更新ui,将button显示的字符更改为update,当用户点击按钮时,就 new UpdateSystemThread().start(); 去更新系统