RedBend关于DM的培训总结报告
本次会议历时2天, 总计4个小时左右, 比较全面地介绍了FOTA, FUMO等协议以及RedBend公司关于DM(移动售后增强服务)的实现。
第一天下午先对Questionnire问题单的重要性进行了讲解。RedBend公司需要我们提供具体机器的相关参数以便提供精确的实现库。因为库的具 体实现是需要根据机型来确定的, RedBend北京分公司只有在获取到这个Questionnaire反馈单之后提供给总部才能获得库。 我们在初期对这个Questionnaire的反馈不够及时, 造成了进度上的一些延后, 这是以后在合作的时候需要改进的地方。
然后重点说明了FOTA协议以及它和DM的关联。简单来说, FOTA是用来进行手机固件升级的一个组件。它将差分包从服务器上下载下来, 然后生成新的Image, 替换掉手机中老的体统, 达到升级的目的。其中如何将差分包做到尽可能的小, 是一个难题。RedBend公司有他们的专利技术。RedBend提供了UPI, 它是安装升级的底层库, 但是针对具体平台还需要我们去实现一个UA(Update Agent),UA实现与设备的直接操作,我们需要把UPI集成到UA里面去。
在进行固件升级的时候, 有几个方面是需要注意的:
1. 使更新能够访问到UPI, 保证重启之后在系统层就能更新。
2. 不能更新调用更新模块的区域。 因为如果已经刚好擦除了调用更新模块的区域, 然后断电了, 再重启之后那段代码已经被擦除,就无法再继续更新。
3. 更新时进入Recovery模式, 无法连接到网络, 完成后需要重启, 正常进入手机系统后才能汇报更新结果。
UA在检测到固件更新的时候, 调用vCurrentMobileInstaller来具体操作。流程如下:
1. 在FLASH中找到差分包文件
2. 把差分包数据拷贝到RAM区域, 以便读写。
3. 读取RAM区域的差分包, 并且生成新的镜像块。
4. 把镜像块从RAM区拷贝到FLASH区域
5. 把FLASH中的镜像块覆盖设备固件中。
第三步和第四步重复执行, 直到整个固件差分包解析完。 其中我们需要注意的是为什么不直接把在RAM区生成的镜像块直接写到设备固件中去, 而要先缓冲在FLASH区域呢? 这也是容错考虑。 万一更新过程中收到其他的影响(手机没电了), 导致更新中断, 那么下次进来的时候就可以读取FLASH中之前更新的进度, 接着更新了。
我们要实现的时候, 需要去完成UA中的RB_ImageUpdate() , getUPIVersion(), getBlockSize()等方法。 这是主要的工作, 需要对底层操作有经验的人来完成。 这部分可以参考北研所之前的FOTA代码。 会对我们的进度有些帮助。
FOTA和DM的关系其实是依赖包含关系。 FOTA是负责附件更新的一个比较独立的组件; 而DM更偏向于应用层, 它有跟服务器交互的具体协议, 其中更新固件的部分调用FOTA来实现。
第二天上午介绍了DM中的FUMO, SCOMO, LAWMO协议和固件更新处理的过程。
FUMO是固件下载更新中需要遵循的协议, 和服务器交互的数据是个树形的结构, 包含了包名, Download/Update、DownloadAndUpdate命令, 对应的PKGUrl.
SCOMO是具体应用安装升级协议。 它包括Inventory和Download两部分。Inventory部分列出手机上安装的应用程序列表, 在每次DM需要进行升级软件的时候去收集手机上的应用程序列表。以便上报到服务器进行比对。Download用于标示那个应用需要去下载安装。
LAWMO是手机锁屏的协议。包括锁定(PartiallyLock), 解锁(UnLock) 和 恢复出厂设置(FactoryReset)。 比如我们在手机丢失的情况下, 可以致电中国移动申请锁定手机, 删除手机上的信息。 服务器发送这些命令到手机, 就可以完成这些操作。
DM中固件更新过程分为四个阶段
1. 发现阶段
2. 下载阶段
3. 升级阶段
4. 更新通知
每个过程都是与服务器使用命令进行通讯, GET, ALERT, REPLACE. 一方会对另一方的命令进行执行结果的回复。需要注意的是在下载中PKGUrl并不是需要下载的文件, 而是一个Download Descriptor文件, 其中描述了文件大小, 下载需要多久等信息, 给用户一个提示。用户确认后会根据DD文件里的实际文件地址去下载。
Activity之间的通信
Activity 之间的通信是通过Intent实现的
1.由activity A 到B -- 调用同一个应用下的activity
a.普通方式
流程:创建一个Intent实例 ,通过Intent指定从哪个Activity到哪个Activity,然后 A实例对象.startActivity(Intent实例) eg:
Intent intent = new Intent(A.this,B.class);
你也可以传参数到目标Activity
intent.putExtra("key",value);----有个中重载,如果你要传的值是自己定义的类对象,那么这个类必须实现
java.io.Serializable 接口
A的实例对象.startActivity(intent);
b.启动带返回值的Activity
既然能从A传参数到B,肯定也能从B返回数据给A
流程: 创建一个Intent实例,然后A的实例对象.startActivityForResult(Intent实例,int类型的请求标示);
重写A类的onActivityResult(int requestCode, int resultCode, Intent data) ;
注意:int类型的请求标示必须是唯一的,通常情况下 我们使用布局文件的int表示方式作为请求标示
eg:
//启动 带返回值的activity
Intent intent = new Intent(A.this,B.class);
A的实例对象.startActivityForResult(intent, R.layout.main);
//在B类中 指定返回值
Intent intent=B的实例对象.getIntent().putExtra("key","hello");
B的实例对象.setResult(20,intent);
//重写A类的onActivityResult(int requestCode, int resultCode, Intent data) 接收数据
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// TODO Auto-generated method stub
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case R.layout.main:
if(requestCode==20)
{
String resultStr= data.getStringExtra("key");
}
break;
default:
break;
}
}
变量resultStr 就是返回值 为 hello;
2.调用不同应用程序的Activity
创建Intent实例时 有很多重载
public Intent(Context packageContext,Class<?> cls); --- 上面已经使用了
public Intent(String action);
public Intent(String action,Uri uri);
调用其他应用程序的Activity 就是通过后两种构造实现的 (通过Action 的方式);
a.调用系统的应用程序
android 系统自带很多功能的应用,像打电话,浏览网页,发送Email等。。
eg: 打电话
Intent intent = new (Intent.Action_CALL,Uri.parse("tel:"+电话号码));
startActivity(intent);
b.己的Activity Action 供别的应用调用
流程:在AndroidManifest.xml 中的被调用的Activity的节点下定义Action ,在调用方使用Intent(String action) 构造调用
注意:两个Activity 可以 属于不同的应用
eg :
AndroidManifest.xml 中定义 Action
<activity android:name=".Main"
android:label="@string/app_name">
<intent-filter>
<action android:name="com.myaction"/>
</intent-filter>
</activity>
调用方调用
Intent intent = new Intent("com.myaction");
startActivity(intent);
c.用需要传参的其他应用的Activity
由第三种构造( public Intent(String action,Uri uri);) 可以了解我们可以通过Uri对象给被调用的Activity传递参数
分析Uri的格式("tel:12345678")可以发现Uri需要一个头 ("tel"); 这个头在你自定义action 的时候需要自己定义
这个头也是在Androidmanifest.xml 中定义
流程:在AndroidManifest.xml 中的被调用的Activity的节点下定义Action 和Uri头,在调用方使用
Intent(String action,Uri uri);构造调用
eg:
在AndroidManifest.xml 中定义Action 和 Uri头
<activity android:name=".Main"
android:label="@string/app_name">
<intent-filter>
<action android:name="com.myaction"/>
<!--Uri头-->
<data android:scheme="myscheme"></data>
</intent-filter>
</activity>
在调用方调用
Uri uri = Uri.parse("myscheme://哈哈哈");
Intent intent = new Intent("com.myaction",uri);
startActivity(intent);
在被调用方的到传过来的参数
Uri uri = getIntent().getData();
String str= uri.getHost();
str变量得到的值就是“哈哈哈”
在Android中,我们可以通过两种方式来创建对话框:
1. 借助Dialog类,或它的子类(如AlertDialog)
2. 使用Activity的对话框主题
使用Dialog类:
让我们先来看下如何借助Dialog类创建对话框,首先,我们需要定义一个继承了Dialog类的子类:
class MyDialog extends Dialog {
public MyDialog(Context context) {
super(context);
}
}
然后,为这个对话框的内容定义一个布局文件,比如:
<?xml version=”1.0″ encoding=”utf-8″?>
<LinearLayout
android:id=”@+id/widget28″
android:layout_width=”fill_parent”
android:layout_height=”fill_parent”
android:orientation=”vertical”
xmlns:android=”http://schemas.android.com/apk/res/android”>
<TextView
android:id=”@+id/nameMessage”
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:text=”Enter Name:”></TextView>
<EditText
android:id=”@+id/nameEditText”
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:textSize=”18sp”></EditText>
<LinearLayout
android:id=”@+id/buttonLayout”
android:layout_width=”fill_parent”
android:layout_height=”wrap_content”
android:layout_gravity=”center_horizontal”>
<Button
android:id=”@+id/okButton”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”OK”></Button>
<Button
android:id=”@+id/cancelButton”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”Cancel”></Button>
</LinearLayout>
</LinearLayout>
接着,将上面这份布局文件应用到我们的对话框上来:
class MyDialog extends Dialog {
….
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(”TestApp”, “Dialog created”);
setContentView(R.layout.mydialog);
}
}
现在,我们就可以调用这个对话框类的show方法来让它显示:
…
MyDialog dialog = new MyDialog(context);
dialog.show();
…
对话框组件的事件处理机制和Activity是相同的,让我们来看下如何处理对话框中的OK和Cancle按钮的事件:
class MyDialog extends Dialog implements OnClickListener {
private Button okButton;
private Button cancelButton;
private EditText nameEditText;
protected void onCreate(Bundle savedInstanceState) {
okButton = (Button) findViewById(R.id.okButton);
cancelButton = (Button) findViewById(R.id.cancelButton);
nameEditText = (EditText) findViewById(R.id.nameEditText);
okButton.setOnClickListener(this);
cancelButton.setOnClickListener(this);
}
public void onClick(View view) {
switch (view.getId()) {
case R.id.okButton:
dismiss();
break;
case R.id.cancelButton:
cancel();
break;
}
}
}
在对话框关闭时,对话框类的dismiss()方法将会被调用,该方法可以被对话框自身调用,也可以被其他外部代码调用。
对话框支持“取消”功能,“取消”的含义是指不再需要执行对话框上的任何功能和动作。对话框的取消可以通过调用cancel()方法来实现。取消对话框也将会自动调用dismiss()方法。
当用户点击手机设备上的“返回”按钮时,屏幕上的对话框将会被取消,如果你想让你的对话框不在这种情况下被取消掉的话,你可以如下设置你的对话框:
setCancelable(false);
对话框的取消和关闭事件可以通过OnCancelListener和OnDismissListener两个监听器来被监听处理。
从对话框中返回信息:
现在,到了我们要从对话框上获取用户输入的值,将它返回到主调的Activity中的时候了。然而, Dialog类并没有提供可以直接返回这些值的方法…但是,我们可以使用自己创建的监听类:
public interface MyDialogListener {
public void onOkClick(String name);
public void onCancelClick();
}
我们的对话框类的构造方法同时需要作一点小小的修改:
public MyDialog(Context context, MyDialogListener listener) {
super(context);
this.listener = listener;
}
接着,你就得在创建这个对话框的时候提供一个已经实现了MyDialogListener这接口的监听器实现对象了。
然后,我们要在对话框的onclick方法中传出这个值:
public void onClick(View view) {
switch (view.getId()) {
case R.id.okButton:
listener.onOkClick(nameEditText.getText().toString());
dismiss();
break;
case R.id.cancelButton:
cancel();
break;
}
}
使用AlertDialog:
AlertDialog类是Dialog类的子类。它默认提供了3个按钮和一个文本消息。这些按钮可以按需要来使他们显示或隐藏。下列代码将创建一个AlertDialog对话框,对话框上将向用户展示一个问题以及备选的yes/no答案:
AlertDialog dialog = new AlertDialog.Builder(context).create();
dialog.setMessage(”Do you play cricket?”);
dialog.setButton(”Yes”, myOnClickListener);
dialog.setButton2(”No”, myOnClickListener);
dialog.show();
myOnClickListener这个事件监听器的代码可以类似如下:
public void onClick(DialogInterface dialog, int i) {
switch (i) {
case AlertDialog.BUTTON1:
break;
case AlertDialog.BUTTON2:
break;
}
}
AlertDialog.Builder:
AlertDialog类中有一个内部类,名为 ‘Builder’,Builder类提供了为对话框添加多选或单选列表,以及为这些列表添加事件处理的功能。另外,这个Builder类将 AlertDialog对话框上的3个按钮按照他们的位置分别称呼为:PositiveButton, NeutralButton, NegativeButton
下列代码是一个多选列表的例子:
new AlertDialog.Builder(context)
.setIcon(R.drawable.icon)
.setTitle(R.string.alert_dialog_multi_choice)
.setMultiChoiceItems(
R.array.select_dialog_items,
new boolean[]{false, true, false, true, false},
new DialogInterface.OnMultiChoiceClickListener() {
public void onClick(DialogInterface dialog, int whichButton, boolean isChecked) {
}
}).setPositiveButton(R.string.alert_dialog_ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
}
}).setNegativeButton(R.string.alert_dialog_cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int whichButton) {
}
}
).create();
Activity托管对话框:
Android也提供了创建对话框的快捷方式,在Activity中可以通过如showDialog(), onCreateDialog(), onPrepareDialog(),dismissDialog(), removeDialog()等方法来创建和管理对话框。
Activity的onCreateDialog方法用于在创建并显示对话框的时候调用,比如:
@Override
protected Dialog onCreateDialog(int id) {
return new AlertDialog.Builder(this).setMessage(”How are you?”).setPositiveButton(
”Fine”,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
}
}).setNegativeButton(”Not so good”, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
}
}
).create();
}
你可以同时创建多个对话框,通过为他们设置id参数来区分它们,然后可以通过 showDialog(id)方法来显示。 onCreateDialog方法只会在第一次调用showDialog方法时才会被调用,在之后的showDialog()的调用中,对话框不是被新建出来的,而是直接显示之前创建过的那些对话框。
如果你想要更新对话框的内容,你只要在 onPrepareDialog()中作相应的工作就可以了,该方法会在对话框显示之前进行调用。
dismissDialog()方法是用来关闭对话框的;removeDialog()方法用来将对话框从Activity的托管中移除(如果对已经移除的对话框重新进行调用showDialog ,则该对话框将进行重新创建)。
使用Dialog主题:
另外一种简单的显示对话框的方式是让Activity以Dialog的方式来工作(假装?),这种Activity被称作浮动Activity。这种Activity可以通过配置它的主题来实现,我们可以在 AndroidManifest.xml中进行类似如下的配置:
<activity android:name=”.DialogActivity” android:label=”@string/activity_dialog” android:theme=”@android:style/Theme.Dialog”>
…
</activity>
这样,该Activity就会应用了 ‘Theme.Dialog’的主题而看起来像对话框了。