一般在本地进行OTA升级时,将升级包拷贝到SD卡,然后进入recovery模式选择升级包进行升级,但不是很方便,于是做了一个小应用,通过调用RecoverySystem类中的接口来进行升级。实际上最终也是在recovery模式下进行升级,只不过是在应用层对升级包进行签名验证和发送升级命令。
内容比较简单直接上代码。
一、主要类
SdCardUpgradeWarning.java
一个简单的Activity,对用户升级前进行一些警告提示。
SdCardUpgradeIntroduction.java
对升级过程一些注意事项的提示。
SdCardUpgradeProcess.java
这个是最主要的一个类,读取升级包并进行验证,然后调用installPackage进行升级。
二、详细代码
1.AndroidManifest.xml
<pre style="font-family: Consolas; font-size: 9.8pt; background-color: rgb(255, 255, 255);"><pre name="code" class="java"><?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.windy.sdcardupgrade"
android:sharedUserId="android.uid.system">
<uses-permission android:name="android.permission.ACCESS_CACHE_FILESYSTEM" />
<uses-permission android:name="android.permission.MASTER_CLEAR" />
<uses-permission android:name="android.permission.REBOOT" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".SdCardUpgradeWarning"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".SdCardUpgradeIntroduction"></activity>
<activity
android:name=".SdCardUpgradeProcess"
android:configChanges="keyboardHidden|orientation"
android:screenOrientation="portrait"></activity>
</application>
</manifest>
注意添加
android:sharedUserId="android.uid.system",否则一些系统权限无法使用,如重启。
2.SdCardUpgradeWarning.java
public class SdCardUpgradeWarning extends Activity implements View.OnClickListener {
private static final String TAG = "SdCardUpgradeWarning";
private static String updatePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/update.zip";
private Button mCancle;
private Button mConfirm;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.sdcardupgrade_warning);
mCancle = (Button) findViewById(R.id.cancle);
mCancle.setOnClickListener(this);
mConfirm = (Button) findViewById(R.id.confirm);
mConfirm.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.cancle:
finish();
break;
case R.id.confirm:
confirmUpdatePackageExist();
break;
default:
break;
}
}
public void confirmUpdatePackageExist() {
File updatePackage = new File(updatePath);
if (isFileExist(updatePackage)) {
boolean isZipfileExist = updatePackage.exists();
if (!isZipfileExist) {
Toast toast = Toast.makeText(getApplicationContext(), getString(R.string.update_package_not_found), Toast.LENGTH_LONG);
toast.setGravity(0, 0, 100);
toast.show();
} else {
Intent intent = new Intent();
intent.setClass(this, SdCardUpgradeIntroduction.class);
startActivity(intent);
}
} else {
Toast toast = Toast.makeText(getApplicationContext(), getString(R.string.sdcard_not_mounted), Toast.LENGTH_LONG);
toast.setGravity(0, 0, 100);
toast.show();
}
}
public boolean isFileExist(File file) {
if (file.exists()) {
return true;
} else {
Log.d(TAG, "Update zip file not exist.");
return false;
}
}
}
3.SdCardUpgradeIntroduction.java
public class SdCardUpgradeIntroduction extends Activity implements View.OnClickListener {
private Button mcancle;
private Button mconfirm;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.sdcardupgrade_introduction);
mcancle=(Button)findViewById(R.id.cancle);
mcancle.setOnClickListener(this);
mconfirm=(Button)findViewById(R.id.confirm);
mconfirm.setOnClickListener(this);
}
@Override
public void onClick(View v){
switch(v.getId()){
case R.id.cancle:
finish();
break;
case R.id.confirm:
Intent intent = new Intent();
intent.setClass(this, SdCardUpgradeProcess.class);
startActivity(intent);
break;
default:
break;
}
}
}
4.SdCardUpgradeProcess.java
public class SdCardUpgradeProcess extends Activity implements RecoverySystem.ProgressListener {
private static final String TAG = "SdCardUpgradeProcess";
private static final int VERIFY_COMPLETE = 70;
private static final int INSTALL_COMPLETE = 100;
private static String updatePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/update.zip";
private ProgressBar mProcessbar;
private TextView mUpdateStep;
private TextView mUpdateState;
private TextView mNotify;
private TextView sdcard_update_introduction_textview_one;
private TextView sdcard_update_introduction_textview_two;
private ImageView mCompleteImg;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.sdcardupgrade_processbar);
mUpdateStep = (TextView)findViewById(R.id.step_number);
mUpdateState = (TextView)findViewById(R.id.processbar_title);
mNotify = (TextView)findViewById(R.id.update_notify);
mCompleteImg = (ImageView)findViewById(R.id.update_complete);
mProcessbar=(ProgressBar)findViewById(R.id.processbar);
mProcessbar.setMax(110);
mProcessbar.setProgress(0);
mProcessbar.setIndeterminate(false);
runnable.start();
}
Handler mHandler = new Handler(){
public void handleMessage(Message msg) {
mProcessbar.setProgress(msg.arg1);
switch(msg.arg1){
case VERIFY_COMPLETE:
mUpdateStep.setText(getString(R.string.the_next_step_number));
mUpdateState.setText(getString(R.string.install_process));
mNotify.setText("");
break;
case INSTALL_COMPLETE:
mUpdateState.setText(getString(R.string.install_process_complete));
mNotify.setText(getString(R.string.restart));
mCompleteImg.setBackgroundResource(R.drawable.update_complete);
break;
default:
break;
}
}
};
Thread runnable = new Thread(){
@Override
public void run() {
Log.d(TAG, "Start update .............");
File file = new File(updatePath);
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "SdCardUpgrade ProcessBar");
try{
wl.acquire();//升级保持亮屏状态
RecoverySystem.verifyPackage(file, SdCardUpgradeProcess.this, null);
Log.d(TAG,"Verify package complete.");
RecoverySystem.installPackage(SdCardUpgradeProcess.this, file);
}catch(Exception e){
Log.e(TAG, e.getMessage(), e);
}finally{
wl.release();
}
}
};
@Override
public void onProgress(int progress) {
Log.d(TAG,"progress="+progress);
Message msg = Message.obtain();
msg.arg1 = progress;
mHandler.sendMessage(msg);
}
@Override
public void onBackPressed() {
// TODO Auto-generated method stub
System.exit(0);
}
}
5.下面是三个布局文件
sdcardupgrade_warning.xml
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="5dp">
<TextView
android:id="@+id/sdCard_upgrade_textview_one"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/sdcard_upgrade_warning_title"
android:textSize="22dp" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/sdcard_update_image_first"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/sdcard_upgrade_warning" />
<TextView
android:id="@+id/sdCard_upgrade_textview_two"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/sdcard_update_image_first"
android:text="@string/sdcard_upgrade_warning_list_first"
android:textSize="18dp" />
<ImageView
android:id="@+id/sdcard_update_image_second"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/sdCard_upgrade_textview_two"
android:background="@drawable/sdcard_upgrade_warning" />
<TextView
android:id="@+id/sdCard_upgrade_textview_three"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/sdCard_upgrade_textview_two"
android:layout_toRightOf="@id/sdcard_update_image_second"
android:text="@string/sdcard_upgrade_warning_list_second"
android:textSize="18dp" />
<ImageView
android:id="@+id/sdcard_update_image_third"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/sdCard_upgrade_textview_three"
android:background="@drawable/sdcard_upgrade_warning" />
<TextView
android:id="@+id/sdCard_upgrade_textview_four"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/sdCard_upgrade_textview_three"
android:layout_toRightOf="@id/sdcard_update_image_third"
android:text="@string/sdcard_upgrade_warning_list_third"
android:textSize="18dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="bottom"
android:orientation="horizontal">
<Button
android:id="@+id/cancle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="@string/sdcard_upgrade_cancle" />
<Button
android:id="@+id/confirm"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/cancle"
android:layout_weight="1"
android:gravity="center"
android:text="@string/sdcard_upgrade_confirm" />
</LinearLayout>
</RelativeLayout>
</LinearLayout>
sdcardupgrade_introduction.xml
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:padding="5dp">
<TextView
android:id="@+id/sdCard_upgrade_introduction_one"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/sdcard_upgrade_introduction"
android:textSize="18dp" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="bottom"
android:orientation="horizontal">
<Button
android:id="@+id/cancle"
android:layout_width="90dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/sdcard_upgrade_cancle" />
<Button
android:id="@+id/confirm"
android:layout_width="90dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/sdcard_upgrade_confirm" />
</LinearLayout>
</LinearLayout>
sdcardupgrade_processbar.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="36dp">
<TextView
android:id="@+id/processbar_step"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/sdcardupgrade_step_one"
android:textSize="20dp" />
<TextView
android:id="@+id/step_number"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/the_step_number"
android:textSize="20dp" />
<TextView
android:id="@+id/processbar_title"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/sdcardupgrade_title_one"
android:textSize="35dp" />
<ProgressBar
android:id="@+id/processbar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="240dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:padding="10dp"
android:visibility="visible" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="bottom"
android:orientation="vertical">
<ImageView
android:id="@+id/update_complete"
android:layout_width="45dp"
android:layout_height="40dp"
android:layout_gravity="center" />
<TextView
android:id="@+id/update_notify"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:padding="3dp"
android:text="@string/update_introduction"
android:textSize="20dp" />
</LinearLayout>
</LinearLayout>
6.字符串资源文件
<resources>
<string name="app_name">SdCardUpgrade</string>
<string name="action_settings">Settings</string>
<!-- Add for sdcard upgrade-->
<string name="settings_storage_software_upgrade">SoftWare Upgrade</string>
<string name="settings_storage_sdcard_upgrade">SD card Upgrade</string>
<string name="sdcard_upgrade_warning_title">Warning</string>
<string name="sdcard_upgrade_warning_list_first">During the upgrade,do not remove the battery,UIM card,and SD card.</string>
<string name="sdcard_upgrade_warning_list_second">Make sure that the battery level is sufficent.</string>
<string name="sdcard_upgrade_warning_list_third">You are recommanded to back up data to SD card before upgrade.</string>
<string name="sdcard_upgrade_cancle">Cancle</string>
<string name="sdcard_upgrade_confirm">Confirm</string>
<string name="sdcard_upgrade_introduction">The upgrade takes about two minutes.Do not perform any operations during the upgrade.The upgrade application will automatically stop in 30s.</string>
<string name="sdcardupgrade_step_one">Firmware update</string>
<string name="sdcardupgrade_title_one">Unpacking...</string>
<string name="update_introduction">The full update will take about 2 minutes.Please do not turn off the device during this period.</string>
<string name="update_introduction_two">Do not turn off the device.</string>
<string name="the_step_number">Step 1/2</string>
<string name="the_next_step_number">Step 2/2</string>
<string name="install_process">Install...</string>
<string name="install_process_complete">Update Complete!</string>
<string name="restart">restart...</string>
<string name="update_package_not_found">No update package found!</string>
<string name="sdcard_not_mounted">SD card not mounted!</string>
</resources>
注意:
生成apk后需要使用平台签名文件进行签名,或者在Android.mk文件中配置签名属性并在源码中编译,否则无法运行。
三、最终效果图