1:Euinstaller 框架
2: develop tips
- WizardScreenManager,如何管理多个View
在installer的安装过程中,会选择国家,制式,operator,等等,如何在这些screen间前进和后退。如下图所示:
类图如下:
code流程图:
在启动InstallerWizardActivity,新建一个WizardScreenManager实例,
// launch normal wizard installation
wizardScreenManager = new WizardScreenManager(WizardFlow.NORMAL_INSTALLTION,parentContainerView, ctx);
wizardScreenManager.startWizardFlow();
紧接着根据传入的wizardType去启动wizard,在启动wizard时,会根据RequestScreen创建一个HashMap,和一个Stack。
public void startWizardFlow() {
Log.d(TAG, "startWizardFlow");
wizardScreenMapping = new HashMap<ScreenRequest, IWizardScreen>();
mScreenRequestStack = new Stack<WizardScreenManager.ScreenRequest>();
if (currentWizardFlow == WizardFlow.NORMAL_INSTALLTION) {
mLaunchItem = ScreenRequest.START_SCREEN;
} else if (currentWizardFlow == WizardFlow.NETWORK_UPDATE) {
mLaunchItem = ScreenRequest.NWK_UPDATING_SCREEN;
} else if (currentWizardFlow == WizardFlow.CAM_URGENT_INSTALL) {
nwrap.selectCamBasedInstallation();
nwrap.setCurrentInstallationMode(NativeAPIEnums.InstallationMode.CAM_INSTALLATION);
mLaunchItem = ScreenRequest.SEARCHING_SCREEN;
}
launchScreen(mLaunchItem, null);
}
最后去LaunchSreen,会判断当前的screen是否有创建,并将它加到Hashmap中,并且将当前的screen入栈。
public void launchScreen(ScreenRequest launchItem, ScreenRequest requestedByScreen) {
wizardScreenMapping.put(launchItem, createWizardScreen(launchItem));
// first get the corresponding wizard screen object
targetWizardScreen = wizardScreenMapping.get(launchItem);
// call exit routine of the existing screen with fade away animation
if (requestedByScreen != null) { // its the first screen
if (wizardScreenMapping.containsKey(requestedByScreen)) {
wizardScreenMapping.get(requestedByScreen).exitScreen();
wizardScreenMapping.get(requestedByScreen).detachView();
}
}
// remove all existing views
parentView.removeAllViews();
// push to backstack
mScreenRequestStack.push(mLaunchItem);
// current requested screen
mLaunchItem = launchItem;
// add requested view to viewgroup
parentView.addView(targetWizardScreen.getExistingLayout());
//start fade-in animation for the added view
targetWizardScreen.attachView();
// call initScreen
targetWizardScreen.initScreen();
}
根据LauchItem创建对应的screen
private IWizardScreen createWizardScreen(ScreenRequest launchItem) {
IWizardScreen targetWizardScreen = null;
switch (launchItem) {
case ANTENNA_SCREEN:
targetWizardScreen = new AntennaCableScreen(mContext);
break;
case COUNTRY_SCREEN:
targetWizardScreen = new CountryScreen(mContext);
break;
......
}
HandleActionList
在install channel过程中,会分几个阶段,比如,ScanPrepare,ScanDVBT,ScanDVBC,TvProviderCheck等等,当在执行这些Action时,如何确保这些ScanAction有序的执行。
首先定义一个ScanAction的类和可能会执行到的Scan Type
private enum ActionType
{
ScanDVBT,
ScanDVBTMpegOnly,
ScanDVBC,
ScanDVBCAdvanced,
ScanDVBCQuickAfterAdv,
ScanAnalog,
ScanCAM,
ChListCheck,
CamChListCheck,
ChListArrange,
ScannerCheck,
ScanPrepare,
ScanCamPrepare,
ScanDtrPrepare,
TvProviderCheck
}
private class ScanAction {
public ActionType meAction;
public int miInstMode;
public int miStartProg;
public int miProgFactor;
public ScanAction(ActionType aeAction, int aiInstMode, int aiStartProgress, int aiProgressFactor) {
meAction = aeAction;
miInstMode = aiInstMode;
miStartProg = aiStartProgress;
miProgFactor = aiProgressFactor;
}
public ScanAction(ActionType aeAction) {
meAction = aeAction;
miInstMode = InsEventConst.InstallationModeNone;
miStartProg = 0;
miProgFactor = 1;
}
}
然后,定义一个ScanAction的数组,将需要执行的Scan Type放到list里。
private ArrayList<ScanAction> mvActionList = new ArrayList<ScanAction>();
mvActionList.add(new ScanAction(ActionType.ScanPrepare, mode, 0, 1));
mvActionList.add(new ScanAction(ActionType.ScannerCheck, mode, 0, 1));
mvActionList.add(new ScanAction(ActionType.ScanDVBT, mode, scanIndex * 100 / scanStep, scanStep));
mvActionList.add(new ScanAction(ActionType.TvProviderCheck, mode, 0, 1));
mvActionList.add(new ScanAction(ActionType.ChListCheck));
在开始Scan的时候,去执行执行这些Action,新建一个Thread来执行。
private void doHandleActionList() {
//Log.d(TAG, "doHandleActionList INST_SERVICE");
Thread thread = new Thread(
new Runnable() {
@Override
public void run() {
handleActionList();
}
}
);
thread.start();
}
接着来看handleActionList,如果list数组size为空,表示先前加入到Action List中的内容已全部执行完毕。同时,没执行一次的时候,将数组中第一个Action删除掉。
private void handleActionList() {
Logger.LOGD(TAG, "handleActionList");
if (mvActionList.size() == 0) {
Log.d(TAG, "Action list is empty now");
ntf.notifyAllObservers(EventIDs.EVENT_INST_COMPLETED, "");
return;
}
ScanAction fAction = mvActionList.remove(0);
Log.d(TAG, "handleActionList() " + fAction.meAction);
switch (fAction.meAction) {
case ScanDVBT:
case ScanDVBTMpegOnly:
Sleep(1500);
scanDVBT(fAction);
break;
case ScanDVBC:
......
}
- IScanner
在Scan过程中,分Scan DVBT, DVBC, ATV, NTSC 这几种scan方式,但是这些都必须通过MTK TVAPI来实现,因此可以将常用的方法抽象出一个接口,其他的类来实现这个接口,就可以优化code结构。
Scan 类图如下所示:
初始化IScanner对象,在执行scan时,可将scan Runnable post到scan 线程,
private IScanner mMTKScanner = null;
mMTKScanner = new DVBTScanner(fScanParam)
mMtkScanHandler.postDelayed(mMtkFullScan, 0);
private Runnable mMtkFullScan = new Runnable() {
boolean bRet = false;
@Override
public void run() {
if (mMTKScanner != null) {
bRet = mMTKScanner.fullScan();
if (false == bRet) {
Log.d(TAG, "mMtkFullScan fail.");
if (mMtkScanHandler != null) {
Log.d(TAG, "mMtkFullScan try again.");
mMtkScanHandler.postDelayed(mMtkFullScan, 3000);
}
}
Log.d(TAG, "mMtkFullScan ok.");
}
}
};
文件存储,Searalizable
当TV有完整做完一次full-scan,在下次scan的时候,希望能得到上次scan过程选择的country,mediatype,operator时,该如何将上次选择的值保存下来,这里用到了Searilizable。
类图关系如下:
在DVBSettings 定义需要保存的值。
class DVBSettings implements Serializable {
private static final long serialVersionUID = 1L;
int ScanMode = MwDataTypes.InstallerConstants.InstallationStyleQuick; /* Quick/Full Scan */
int SymbolRateMode = MwDataTypes.InstallerConstants.AutomaticValue; /* Auto/Manual */
int[] SymbolRate = null; /* Array of SymbolRates */
int NetworkIDMode = MwDataTypes.InstallerConstants.AutomaticValue; /* Auto/Manual */
int NetworkID = -1; /* Can be any valid networkId */
int NetworkFrequencyMode = MwDataTypes.InstallerConstants.AutomaticValue; /* Auto/Manual */
int[] NetworkFrequency = null; /* List of frequencies fixed per country */
int ModulationMode = MwDataTypes.InstallerConstants.AutomaticValue; /* Auto/Manual */
int[] Modulation; /* List of Mod types fixed per country */
int DigitalOption = 1; /* ON - DVBC_Lite OFF - NO DVBC */
int[] UserSymbolRate;
int FreqStepSize = MwDataTypes.InstallerConstants.DVBCStepSize8;
int InstalledCity = -1; /* For china, as NVM is not avbl. hence flash approach followed */
int InstalledONID = -1;
int ScrambledState = -1;
int NetworkOperator = -1; /* for Netherlands Cable */
int LCNSorting = 0;
int DualAnalogPass = 0;
int DTTScanonAnalog = 0;
int LCNOption = 1;
int InstalledCountry = -1;
public DVBSettings() {
}
}
先定义一个DVBSettings 的Object
private DVBSettings mSettingPersistent;
当扫台结束时,将数据写到mSettingPersistent
public void CommitPreferred() {
FileOutputStream fos = null;
ObjectOutputStream oos = null;
Log.d(TAG, "CommitPreferred()");
CopyTemporaryToPersistent();
try {
fos = mActivityInstance.openFileOutput(gsFileName, Context.MODE_PRIVATE);
oos = new ObjectOutputStream(fos);
oos.writeObject(mSettingPersistent);
} catch (FileNotFoundException e) {
Log.d(TAG, "The file of AttributeStore is not found.");
} catch (StreamCorruptedException e) {
Log.d(TAG, "Writing of AttributeStore file fail. " + e.toString());
} catch (IOException e) {
Log.d(TAG, "Writing of AttributeStore file fail. " + e.toString());
}
try {
if (oos != null)
oos.close();
} catch (IOException e) {
}
try {
if (fos != null)
fos.close();
} catch (IOException e) {
}
}
在下次scan时,将上次scan的值load出来
private DVBSettings loadPresistentSettings() {
DVBSettings fSettings = null;
FileInputStream fis = null;
ObjectInputStream ois = null;
Log.d(TAG, "loadPresistentSettings()");
try {
fis = mActivityInstance.openFileInput(gsFileName);
ois = new ObjectInputStream(fis);
fSettings = (DVBSettings) ois.readObject();
} catch (FileNotFoundException e) {
Log.d(TAG, "The file of AttributeStore is not found.");
} catch (StreamCorruptedException e) {
Log.d(TAG, "Loading of AttributeStore file fail. " + e.toString());
} catch (IOException e) {
Log.d(TAG, "Loading of AttributeStore file fail. " + e.toString());
} catch (ClassNotFoundException e) {
Log.d(TAG, "AttributeStore can not be found in the file.");
}
try {
if (ois != null)
ois.close();
} catch (IOException e) {
}
try {
if (fis != null)
fis.close();
} catch (IOException e) {
}
return fSettings;
}