## 一、管控APP功能分析

### 1、包含的服务

#### 1.1、BackService

系统启动成功之后，如果打开酒店模式或者网络变化，就会打开TclIntentService，之后每半小时启动一次service。

#### 1.2、TclIntentService

-  接受action为connect_server

- - 接受index_order

  - - REQUEST_CHECK_APK

​    自升级和更新

- - - SYSTEM_MODE_CHANGED

  禁用APP，启用默认APP

- - - REQUEST_CHECK_OTA

​       检测OTA升级

- 接受action为com.android.systemservice.MANAGEMENT_APP

​     禁用APP，启用默认APP

#### 1.3、TvOnlineService

- /api/tvlogs/tv_turn_on  上报数据

#### 1.4、AppOnlineService

- /api/tvlogs/tv_app_turn_on 上报数据

#### 1.5、GrantService

- action 为 com.tcl.grant.AUTH 或者 action 为com.android.systemservice.auth.CHANGED

​      延迟20s之后，如果酒店模式打开了，调用 /api/terminal2 接口 进行注册。

注册成之后调用 /api/heartbeat2 获取在线授权信息。然后按照接口返回的心跳时间进行下一次操作。

- 应用自升级（应用平台）

### 2、包含的广播

#### 2.1、ManagementReceiver

-  启动成功或者收到TCL 的P0广播

- - 启动 TclIntentService ，action 为 ACTION_MANAGEMENT_APP， 禁用APP，启用默认APP
  - 如果开启酒店模式，发送com.tcl.grant.AUTH，启动GrantService
  - 检查授权信息

-  启动成功

- - 启动 TvOnlineService ，调用 /api/tvlogs/tv_turn_on 
  - 启动 AppOnlineService，调用 /api/tvlogs/tv_app_turn_on
  - 如果开启酒店模式，发送com.tcl.grant.AUTH，启动GrantService
  - 检查APP更新，检查OTA更新

-  收到TCL P0广播

- - 注册网络变化广播
  - 启动TclIntentService，action为 connect_server，index_order 为 SYSTEM_MODE_CHANGED，禁用APP，启用默认APP

-  网络变化或者酒店模式改变

- - 启动TclIntentService，action为 connect_server，index_order 为 SYSTEM_MODE_CHANGED，禁用APP，启用默认APP
  - 如果开启酒店模式，发送com.tcl.grant.AUTH，启动GrantService

- 检测USB挂载

检查U盘更目录下的 /installation/installation文件的installation字段，如果是true就打开GrantActivity

#### 2.2、TclBroadcastReceiver

- 启动成功

- - 启动 BackService -> 启动TclIntentService 

​    action 为 connect_server，index_order 为 REQUEST_CHECK_ALIVE 空实现

- 网络变化或者action为ACTION_OTA_TEST（com.android.systemservice.OTA_TEST）

- - 启动 BackService -> 启动TclIntentService 

​    action 为 connect_server，index_order 为 REQUEST_CHECK_ALIVE 空实现

- - 启动TclIntentService，action为 connect_server ，附带参数 index_order 分别为 REQUEST_CHECK_APK，REQUEST_REGISTER，REQUEST_CHECK_OTA

  - - REQUEST_CHECK_APK

  调用 api/upgrade 接口下载和更新apk

- - - REQUEST_REGISTER

​        空实现

- - - REQUEST_CHECK_OTA

​        ota升级逻辑

- 检测USB端口挂载

本地离线授权

- 检测外设摄像头插拔

​      插：展示摄像头信息，拔：关闭摄像头

### 3、主要功能汇总

#### 3.1、自更新和升级，包括应用平台

#### 3.2、APK管理，包括禁用和启用

#### 3.3、检测OTA升级（管控后台）

#### 3.4、向/api/tvlogs/tv_turn_on  上报数据（可以考虑去掉）

#### 3.5、向/api/tvlogs/tv_app_turn_on 上报数据（可以考虑去掉）

#### 3.6、酒店注册  /api/terminal2

#### 3.7、获取在线授权信息 /api/heartbeat2

#### 3.8、本地离线授权和在线授权结合

#### 3.9、检测外设摄像头挂载（暂时没有用到，）

## 二、963和920差异对比

### 1、TclIntentService

com.android.systemservice.server.TclIntentService

```
//920上的实现
private List<String> getDisableList(AppInfo info, String softVersion) {
        //这里不一致
        if (info == null || softVersion == null || softVersion.trim().length() == 0) {
            return null;
        }
        String ver = softVersion.substring(0, 7);
        Log.i(TAG, "ver:" + ver);
        switch (ver) {
            case Constants.SOFT_VERSION_A260:
                return info.getDisableA26X();
            case Constants.SOFT_VERSION_A360:
                return info.getDisableA36X();
            case Constants.SOFT_VERSION_G5X://这里不一致
                return info.getDisableG5X();//这里不一致
            default:
                return info.getDisable();
        }
    }
//963上的实现
private List<String> getDisableList(AppInfo info, String softVersion) {
              //这里不一致
        if (info == null || softVersion == null || softVersion.trim().length() < 7) {
            return null;
        }
        String ver = softVersion.substring(0, 7);
        Log.i(TAG, "ver:" + ver);
        switch (ver) {
            case Constants.SOFT_VERSION_A260:
                return info.getDisableA26X();
            case Constants.SOFT_VERSION_A360:
                return info.getDisableA36X();
            case Constants.SOFT_VERSION_T972://这里不一致
                return info.getDisableA26X(); //这里不一致
            default:
                return info.getDisable();
        }
    }
```

### 2、Constants

com.android.systemservice.utils.Constants

```
  //920
  public static final String SOFT_VERSION_A260 = "V8-S38P";
  public static final String SOFT_VERSION_A360 = "V8-A962";
  public static final String SOFT_VERSION_G5X = "V8-A920";


  //963
  public static final String SOFT_VERSION_A260 = "V8-S38P";
  public static final String SOFT_VERSION_A360 = "V8-A962";
  public static final String SOFT_VERSION_T972 = "V8-A972";
    public static final String ANDROID = "android";
```

### 3、AppInfo

com.tcl.app.AppInfo

```
//920
public List<String> getDisableG5X(){
    return DisableAppG5X.list;
}


AwesomeHotelDisable@add
public void add() {
  awsomeHotelDisable.add(AWSOME_HOTEL2);
  awsomeHotelDisable.add(APP_MANAGER);
  awsomeHotelDisable.add(UPDATE);
}


DisableAppA26X#list
public List<String> list = Arrays.asList("com.android.tcl.messagebox", "com.tcl.c2dm.client",
                "com.tcl.appmarket2", "tv.huan.tvhelper", "com.tcl.MultiScreenInteraction_TV", "com.droidlogic.miracast",
                "com.hpplay.allcast", "com.huan.edu.lexue.frontend", "com.tcl.browser", "com.audiocn.kalaok.tv",
                "com.android.keychain", "com.tcl.SmartTVHelp", "com.tcl.bootadservice", "com.tcl.tv.jtq",
                "com.tcl.esticker", "com.tcl.appmarket2", "cn.wps.moffice_i18n_TV", "com.tcl.tshop",
                "com.tcl.weixin", "com.tcl.screensaver", "com.tcl.common.weather", "com.tcl.usagestats",
                "com.tcl.usercenter", "com.tcl.vod", "com.tcl.wholenetsearch", "com.tcl.gamecenter",
                "com.golive.cinema", "com.tcl.tvweishi");


DisableAppA36X#list
public final List<String> list = Arrays.asList("com.android.tcl.messagebox", "com.tcl.c2dm.client",
                "com.tcl.appmarket2", "tv.huan.tvhelper", "com.tcl.MultiScreenInteraction_TV", "com.droidlogic.miracast",
                "com.hpplay.allcast", "com.tcl.tshop", "com.golive.cinema", "com.audiocn.kalaok.tv",
                "com.tcl.weixin", "com.tcl.vod", "com.tcl.tvhealthcheck", "cn.wps.moffice_i18n_TV",
                "com.tcl.browser", "com.tcl.bootadservice", "com.tcl.screensaver", "com.tcl.usagestats",
                "com.tcl.tv.jtq", "com.tcl.gamecenter", "com.tcl.triava", "com.tcl.common.weather",
                "com.tcl.wholenetsearch", "com.tcl.SmartTVHelp", "com.huan.edu.lexue.frontend", "com.tcl.voicemanager",
                "com.tcl.usercenter", "com.tcl.tvweishi");


DisableAppG5X#list
public static final List<String> list = Arrays.asList("com.pptv.tvsports.preinstall","com.tcl.wholenetsearch",
                "com.tcl.initsetup","com.tcl.common.weather","com.golive.cinema","com.tcl.browser",
                "com.tcl.appmarket2","com.tcl.tshop","com.android.tcl.messagebox",
                "com.tcl.vod","com.tcl.weixin","com.tcl.SmartTVHelp","com.tcl.gamecenter",
                "com.tcl.usercenter","com.tcl.tvweishi","com.tcl.ffeducation","com.tcl.c2dm.client",
                "com.tcl.usagestats");


//963
AwesomeHotelDisable@add
public void add() {
  awsomeHotelDisable.add(AWSOME_HOTEL);
  awsomeHotelDisable.add(AWSOME_HOTEL2);
  awsomeHotelDisable.add(APP_MANAGER);
}


DisableAppA26X#list
public List<String> list = Arrays.asList("com.android.tcl.messagebox", "com.tcl.c2dm.client",
                "com.tcl.appmarket2", "tv.huan.tvhelper", "com.tcl.MultiScreenInteraction_TV", "com.droidlogic.miracast",
                "com.hpplay.allcast", "com.tcl.tvweishi", "com.huan.edu.lexue.frontend", "com.tcl.browser",
                "com.audiocn.kalaok.tv", "com.android.keychain", "com.tcl.SmartTVHelp", "com.tcl.bootadservice",
                "com.tcl.tv.jtq", "com.tcl.esticker", "com.tcl.appmarket2", "cn.wps.moffice_i18n_TV", "com.tcl.tshop",
                "com.tcl.weixin", "com.tcl.screensaver", "com.tcl.common.weather", "com.tcl.usagestats", "com.tcl.usercenter",
                "com.tcl.vod", "com.tcl.wholenetsearch", "com.tcl.gamecenter", "com.golive.cinema");


DisableAppA36X#list
public final List<String> list = Arrays.asList("com.android.tcl.messagebox", "com.tcl.c2dm.client",
                "com.tcl.appmarket2", "tv.huan.tvhelper", "com.tcl.MultiScreenInteraction_TV", "com.droidlogic.miracast",
                "com.hpplay.allcast", "com.tcl.tvweishi", "com.tcl.tshop", "com.golive.cinema",
                "com.audiocn.kalaok.tv", "com.tcl.weixin", "com.tcl.vod", "com.tcl.tvhealthcheck", "cn.wps.moffice_i18n_TV",
                "com.tcl.browser", "com.tcl.bootadservice", "com.tcl.screensaver", "com.tcl.usagestats",
                "com.tcl.tv.jtq", "com.tcl.gamecenter", "com.tcl.triava", "com.tcl.common.weather", "com.tcl.wholenetsearch",
                "com.tcl.SmartTVHelp", "com.huan.edu.lexue.frontend", "com.tcl.voicemanager", "com.tcl.usercenter");
```

### 4、ManagementReceiver

com.tcl.broadcast.ManagementReceiver

```
//963比920多了
//在ACTION_BOOT_COMPLETED之后
应用自升级检测
ota升级检测
```

### 5、GrantActivity

com.tcl.grant.GrantActivity  以963方式为主

```
//920
private void initGrantInfo(){
        mMac = TVUtils.getEthMacAddress();
        mGrantInfo = new DeviceInfo();
        mGrantInfo.setMac(mMac==null?mMac:mMac.replace(":",""))
                .setMachineType(TVUtils.getModelName(getApplicationContext()))
                .setVersion(HotelUtils.getAgencyVersion(getApplicationContext()))
                .setVer(TVUtils.getSoftwareVersion()) //这里
                .setLauncher(mLauncher);
    }
//963
private String getSoftwareVersion() {
        if (mCustomerApiHandler.getCustomerApi() != null) {
            try {
                return mCustomerApiHandler.getCustomerApi().getSoftwareVersion();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return TVUtils.getSoftwareVersion();
    }
```

### 6、HotelUtils

com.tcl.hoteltv.factory.HotelUtils  （此方法使用920的方式，但是要改动）

```
//920
public static String getDefaultAgencyVersion(Context context){
        StringBuilder builder = new StringBuilder();
        builder.append("TCL-")
                .append(TVUtils.getModelName(context))
//                .append("G60")
                .append("-20200325-V000");
        return builder.toString();
    }
//963
public static String getDefaultAgencyVersion(Context context) {
        StringBuilder builder = new StringBuilder();
        builder.append("TCL-")
                //.append(TVUtils.getModelName(context))
                .append("G60")
                .append("-20200325-V000");
        return builder.toString();
    }
```

### 7、TVUtils

com.tcl.hoteltv.factory.TVUtils  （用920的方式，需要验证）

```
//920
 public static String getModelName(Context context) {
        String versionName = getSoftwareVersion();
        if (versionName.contains(Constants.SOFT_VERSION_G5X)) {
            return FactoryManager.getInstance(context).doGetProjectName();
        } else {
            return TDeviceInfo.getInstance().getModelName(getProjectIDValue(context));
        }
    }


//963
public static String getModelName(Context context) {
        return TDeviceInfo.getInstance().getModelName(getProjectIDValue(context));
    }
```

### 8、Files

com.tcl.utils.Files

```
//920
public static void changePermission(String path){
        FileUtils.setPermissions(path, FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IRWXO, -1, -1) ;
    }
//963
public static void changePermission(String path){
        MyFileUtils.setPermissions(path);
        //FileUtils.setPermissions(path, FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IRWXO, -1, -1) ;
    }
```

### 9、jar包整理

#### 两个机型都有的jar包：

ah-extension-1.0.1.aar

 

920文件md5：0794a887e3b80205854a3e3a4edc346d

-  963文件md5：0794a887e3b80205854a3e3a4edc346d

appassistsdk-2.0.11.aar

 

920文件md5：a53bb0b822fb8245855bdcdf3add9783

-  963文件md5：a53bb0b822fb8245855bdcdf3add9783

com.tcl.customerapi.jar

 

920文件md5：75802fa86e077513cf058db99cf4359f

-  963文件md5：469bca8de85ca2c19c6ba9557e850425

com.tcl.tvos.addon.jar

 

920文件md5：2621d0f692fc8c4c83e8750efe5b5bfc

-  963文件md5：2621d0f692fc8c4c83e8750efe5b5bfc

factory.jar

 

920文件md5：3a3895919fb0a80e93eae9ea8402536f

-  963文件md5：3a3895919fb0a80e93eae9ea8402536f

fastjson-1.1.51.android.jar

 

920文件md5：24295b91c61c7a64dcba6b5518915867

-  963文件md5：24295b91c61c7a64dcba6b5518915867

framework.jar

 

920文件md5：4146ff34d7040bc93470e6adddf9439a

-  963文件md5：4146ff34d7040bc93470e6adddf9439a

services.jar

 

920文件md5：327debb1084d31350e4b721adea601b8

-  963文件md5：327debb1084d31350e4b721adea601b8

snack-1.0.2.aar

 

920文件md5：cc2f1a12750505b0777e0e93d6be8a07

-  963文件md5：cc2f1a12750505b0777e0e93d6be8a07

tornado-0.1.4.jar

 

920文件md5：01817d2b50ad9f5bfd1871095c208ee5

-  963文件md5：01817d2b50ad9f5bfd1871095c208ee5

tvapi.jar

 

920文件md5：45949462ec4ec42ac6eb5d84ffe7da72

-  963文件md5：45949462ec4ec42ac6eb5d84ffe7da72

zxing-core-3.3.3.jar

 

920文件md5：3ee2c714be5d25ac6c9b941f666bfea6

-  963文件md5：3ee2c714be5d25ac6c9b941f666bfea6

#### 仅963有的jar包

- rainbow-0.1.jar
- virtualApi-0.1.jar

## 三、合并方案

### 1、合并方式

有三种合并方式。

一种是不动代码结构，仅根据两者差异在差异点进行不同机型的适配，根据两个项目中源码对比的结果来看，此方法是可行的。此方法优点在于改动量小，而且基本能保证之前的功能。

第二种是大改代码结构，将整个项目进行重构，根据功能进行模块划分和重组。此方法的优点是可以趁机统一下代码风格，缺点是周期长，改动大，而且可能会丢失之前已经存在的功能。

第三种是前两者的结合，首先使用第一种方式完成不同机型的兼容。对项目内的部分功能点进行抽离和整理。

我个人建议采用第三种方式。

### 2、建议抽离的功能点

#### 2.1、更新功能

包括应用自升级和ota升级的逻辑可以抽离到一起，提供统一入口

#### 2.2、数据上报相关

提供统一的入口，定时进行数据上报。包括注册和心跳

#### 2.3、授权相关

## 离线授权和在线授权的整合 