1. 文件管理

管理设备sd、usb、flash的文件, 可以实现文件的浏览、删除, 文件下载、文件读取、格式化等功能。典型功能: 音乐管理

1.1. 文件浏览

函数名

参数

返回值

作用说明

addFileObserver

FileObserver: FileObserver

void

注册目录浏览观察者

removeFileObserver

FileObserver: FileObserver

void

注销目录浏览观察者

setPageSize

int: 每次浏览文件个数,范围:[1, 30]

void

设置每次浏览文件个数

getPageSize

void

int: 每次浏览文件个数

获取每次浏览文件个数

getOnlineStorage

FileStruct: FileStruct

SDCardBean: SDCardBean

获取在线存储器

getCurrentReadFile

SDCardBean: SDCardBean

Folder: Folder

获取当前浏览目录

getCurrentFileStructs

SDCardBean: SDCardBean

List<FileStruct>: 子文件列表

读取当前目录下的已加载文件

isReading

void

boolean: 是否正在读取文件

是否正在读取文件

isOnline

int: 存储器索引号

boolean: 是否在线

存储器是否在线

getSdCardBeans

void

List<SDCardBean>: 存储器列表

获取存储器信息列表

getOnlineDev

void

List<SDCardBean>: 在线存储器列表

获取在线存储器列表

listFiles

Folder: Folder
int: 起始偏移

int: 操作结果码

目录浏览

listFiles

Folder: Folder
int: 起始偏移
boolean: 是否通知结果

int: 操作结果码

目录浏览

loadMore

SDCardBean: SDCardBean

int: 操作结果码

加载更多文件信息

appenBrowse

FileStruct: FileStruct
SDCardBean: SDCardBean

int: 操作结果码

浏览下一级目录

appenBrowse

Folder: Folder

int: 操作结果码

浏览下一级目录

backBrowse

SDCardBean: SDCardBean

int: 操作结果码

返回上一级目录(有回调)

backBrowse

SDCardBean: SDCardBean
boolean: 是否回调文件数据

int: 操作结果码

返回上一级目录

deleteFile

SDCardBean: SDCardBean
List<FileStruct>: 删除文件列表
DeleteCallback: 删除文件回调

int: 操作结果码

删除文件

deleteFile

SDCardBean: SDCardBean
List<FileStruct>: 删除文件列表
boolean: 是否需要准备环境
DeleteCallback: 删除文件回调

int: 操作结果码

删除文件

deleteFile

List<FileStruct>: 删除文件列表
boolean: 是否需要准备环境
DeleteCallback: 删除文件回调

int: 操作结果码

删除文件

playFile

FileStruct: FileStruct
SDCardBean: SDCardBean

int: 操作结果码

播放音乐文件

playFile

RegFile: RegFile

int: 操作结果码

播放音乐文件

formatDevice

SDCardBean: SDCardBean
OperatCallback: 操作回调

int: 操作结果码

格式化存储器

cleanCache

void

void

清除所有缓存

cleanCache

BluetoothDevice: 蓝牙设备

void

清除指定设备的所有缓存

cleanCache

SDCardBean: SDCardBean

void

清除指定存储器的所有缓存

1.1.1. 操作结果码

名称

码值

描述

FileBrowseConstant#SUCCESS

0(0x0000)

成功结果

FileBrowseConstant#ERR_PARAM

4096(0x1001)

无效参数

FileBrowseConstant#ERR_BUSY

12291(0x3003)

系统繁忙

FileBrowseConstant#ERR_READING

16385(0x4001)

正在目录浏览

FileBrowseConstant#ERR_OFFLINE

16384(0x4000)

存储器下线

FileBrowseConstant#ERR_LOAD_FINISHED

16386(0x4002)

文件列表已加载完毕

FileBrowseConstant#ERR_NO_DATA

16387(0x4003)

丢失文件数据

FileBrowseConstant#ERR_BEYOND_MAX_DEPTH

16388(0x4004)

超过限制目录层级

FileBrowseConstant#ERR_OPERATION_TIMEOUT

4098(0x1003)

操作超时

FileBrowseConstant#ERR_FILE_NOT_IN_STORAGE

16390(0x4006)

文件结构与存储器不一致
说明输入参数冲突

1.1.2. FileObserver

目录浏览观察者

public interface FileObserver {

     /**
      * 收到目录文件数据后回调
      *
      * @param fileStructs 文件结构列表
      */
     void onFileReceiver(List<FileStruct> fileStructs);

     /**
      * 一次文件读取结束
      *
      * @param isEnd 是否结束
      */
     void onFileReadStop(boolean isEnd);

     /**
      * 文件读取开始
      */
     void onFileReadStart();

     /**
      * 文件读取失败
      *
      * @param reason 错误码
      */
     void onFileReadFailed(int reason);

     /**
      * 设备的存储设备状态变化
      *
      * @param onLineCards 在线设备列表
      */
     void onSdCardStatusChange(List<SDCardBean> onLineCards);

     /**
      * 文件点播成功回调
      */
     void OnFlayCallback(boolean success);

 }

1.1.3. FileStruct

文件结构

public class FileStruct implements IDataOp, Parcelable {

     /**
      * 是否文件
      *
      * <p>结果说明:
      * true -- 文件
      * false -- 文件夹</p>
      */
     private boolean file;
     /**
      * 是否Unicode编码
      *
      * <p>
      * 结果说明:
      * true -- Unicode编码
      * false -- ASCII编码
      * </p>
      */
     private boolean unicode;
     /**
      * 簇号。唯一标识
      */
     private int cluster = 0;
     /**
      * 文件夹序号
      */
     private short fileNum = 1;
     /**
      * 文件名
      */
     private String name = "";
     /**
      * 存储器类型
      */
     private byte devIndex;
}

1.1.4. SDCardBean

存储器信息

public class SDCardBean implements Parcelable {

 /**
  * SD卡类型
  */
 public static final int SD = 0;
 /**
  * USB类型
  */
 public static final int USB = 1;
 /**
  * Flash类型
  */
 public static final int FLASH = 2;
 /**
  * LineIn类型
  */
 public static final int LINEIN = 3;
 /**
  * Flash2类型
  */
 public static final int FLASH_2 = 4;

 //index
 /**
  * USB索引
  */
 public static final int INDEX_USB = 0;
 /**
  * SD0索引
  */
 public static final int INDEX_SD0 = 1;
 /**
  * SD1类型
  */
 public static final int INDEX_SD1 = 2;
 /**
  * Flash索引
  */
 public static final int INDEX_FLASH = 3;
 /**
  * 输入设备索引
  */
 public static final int INDEX_LINE_IN = 4;
 /**
  * Flash2索引
  */
 public static final int INDEX_FLASH2 = 5;
 /**
  * Flash3索引
  */
 public static final int INDEX_FLASH3 = 6;


 /**
  * 存储器索引
  */
 private int index;
 /**
  * 存储器类型
  */
 private int type;
 /**
  * 存储器名称
  */
 private String name;
 /**
  * 存储器句柄
  */
 private int devHandler = -1;
 /**
  * 是否在线
  */
 private boolean online;
 /**
  * 操作设备
  */
 private BluetoothDevice device;
}

1.1.5. Folder

文件夹

public class Folder extends File {
  /**
   * 文件列表
   */
  private final transient List<File> files = new ArrayList<>();
  /**
   * 是否加载完成
   */
  private boolean isLoadFinish = false;
}

1.1.6. RegFile

资源文件

public class RegFile extends File {

}

public abstract class File extends FileStruct {

 /**
  * 父类文件夹
  */
 private transient final Folder parent;
 /**
  * 目录层级
  */
 private final int level;
}

1.2. 目录浏览

FileObserver fileObserver = new FileObserver() {
    @Override
    public void onFileReceiver(List<FileStruct> fileStructs) {
        // 读取到文件列表,仅仅回调本次读取的文件列表
    }

    @Override
    public void onFileReadStop(boolean isEnd) {
        // 文件列表读取结束
    }

    @Override
    public void onFileReadStart() {
        // 开始文件列表读取
    }

    @Override
    public void onFileReadFailed(int reason) {
        // 文件列表读取失败
    }

    @Override
    public void onSdCardStatusChange(List<SDCardBean> onLineCards) {
        //在线设备有变化
    }

    @Override
    public void OnFlayCallback(boolean success) {
        //歌曲点播回调
    }
};
//第一步:注册观察者

// 第2步:获取在线设备列表,可以通过fileObserver处理设备状态变化
FileBrowseManager.getInstance().addFileObserver(fileObserver);

// 第3步:读取当前设备正在读的当前目录
List<SDCardBean> list = FileBrowseManager.getInstance().getOnlineDev();
if(list.size()<1){
    //没有在线设备
    return;
}
SDCardBean sdCardBean = list.get(0);//获取设备,如果有多个设备,请根据需求获取相应的设备
Folder currentFolder = FileBrowseManager.getInstance().getCurrentReadFile(sdCardBean);

//第4步:获取当前目录下已经读了但在缓存中的子文件
List<FileStruct> fileStructs = currentFolder.getChildFileStructs();

//第5步:浏览操作
//加载更多
FileBrowseManager.getInstance().loadMore(sdCardBean);
//进入下一级目录
FileStruct fileStruct = currentFolder.getChildFileStructs().get(0);//根据需要获取需要读取的文件夹
FileBrowseManager.getInstance().appenBrowse(fileStruct, sdCardBean);
//返回上一级目录没有列表回调
boolean hasEvent = true;//是否需要FileObserver的事件回调
FileBrowseManager.getInstance().backBrowse(sdCardBean,hasEvent);
//点播文件
FileBrowseManager.getInstance().playFile(fileStruct, sdCardBean);

1.3. 文件删除

List<SDCardBean> list = FileBrowseManager.getInstance().getOnlineDev();
if(list.size() < 1){
    //没有在线设备
    return;
}
SDCardBean sdCardBean = list.get(0);//获取设备,如果有多个设备,请根据需求获取相应的设备
List<FileStruct> fileStructs = new ArrayList<>();//注意fileStructs一定要是在sdCardBean中
boolean withEnv = false;//准备环境,一般使用false
FileBrowseManager.getInstance().deleteFile(sdCardBean, fileStructs,withEnv, new DeleteCallback() {
    @Override
    public void onSuccess(FileStruct fileStruct) {
        //成功
    }

    @Override
    public void onError(int code, FileStruct fileStruct) {
        //fileStruct 删除失败
    }

    @Override
    public void onFinish() {
        //删除结束,通过onError判断是否有删除失败的文件
    }
});

1.4. 格式化

 //格式化,仅仅格式化设备
    List<SDCardBean> list = FileBrowseManager.getInstance().getOnlineDev();
if (list.size() < 1) {
    //没有在线设备
    return;
}
SDCardBean sdCardBean = list.get(0);//获取设备,如果有多个设备,请根据需求获取相应的设备
FileBrowseManager.getInstance().formatDevice(sdCardBean, new OperatCallback() {
    @Override
    public void onSuccess() {
        //成功
    }

    @Override
    public void onError(int code) {
        //失败
    }
});

Important

  1. 格式化操作请和固件确认是否需要备份或者准备环境

  2. 删除文件操作请和固件确认是否需要备份或者准备环境

1.5. 大文件传输

1.5.1. 文件下载(APP -> 设备)

对应类

功能说明

TransferTask

大文件传输任务(Path方式)

UriTransferTask

大文件传输任务(Uri方式)

示例代码

//WatchManager是WatchOpImpl的子类,须在1.3配置好sdk
    WatchManager watchManager = WatchManager.getInstance();
SDCardBean sdCardBean = DeviceChoseUtil.getTargetDev();//获取设备目标设备,这里需要判断设备是否为空
if(sdCardBean == null) return;
    TransferTask.Param param = new TransferTask.Param();
param.devHandler = sdCardBean.getDevHandler();//设置设备句柄,可以理解为选择文件存储的设备:如sd,usb等,
/**
 * 是否使用其他编码方式。
 * 默认false,编码方式如下:<br/>
 * - 短文件名:  GBK {@link Charset#forName(String)}<br/>
 * - 长文件名: 增加"\\U" + Unicode编码数据 + 结束符, {@link Charset#forName(String)}
 * 若为true, 则{@link #encodeType} 属性生效
 */
param.isOtherEncode = false;
String path = "需要传输的文件路径";
ITask task = new TransferTask(watchManager,path,param);
task.setListener(new TaskListener() {
    @Override
    public void onBegin() {
        //文件传输开始
    }

    @Override
    public void onProgress(int progress) {
        //进度回调
    }

    @Override
    public void onFinish() {
        //传输结束
    }

    @Override
    public void onError(int code, String msg) {
        //传输异常
    }

    @Override
    public void onCancel(int reason) {
        //传输已取消
    }
});
//开始传输文件
if(!task.isRun()){
    task.start();
}else {
    //文件正在传输
}
    // 主动取消传输
    task.cancel((byte) 0x01);

Important

  1. 需要保证文件具有访问权限, 在Android API 28及以上, 部分文件无法通过文件路径读取, 可以使用UriTransferTask替代TransferTask, 两者在使用上仅仅是构造函数不同

ITask task = null;
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
    task = new UriTransferTask(context, watchManager, uri, title, param);
 } else {
    task = new TransferTask(watchManager, path, param);
}

1.5.1.1. TransferTask.Param

public static class Param {
    public int devHandler; //设备句柄
    public boolean appHasCrc16 = true; //app是否支持crc16,一般用默认值
    public boolean useFlash = false;  //是否是flash设备

    /**
     * 是否使用其他编码方式
     *
     * <p>
     * 默认false,编码方式如下:<br/>
     * - 短文件名:  GBK {@link Charset#forName(String)}<br/>
     * - 长文件名: 增加"\\U" + Unicode编码数据 + 结束符, {@link Charset#forName(String)}
     * 若为true, 则{@link #encodeType} 属性生效
     * </p>
     */
    public boolean isOtherEncode = false; //是否使用其他编码方式

    /**
     * 编码方式
     *
     * <strong>1. 注意需要{@link  #isOtherEncode} 为 true, 字段才生效</strong>
     */
    public String encodeType = StandardCharsets.UTF_16LE.name(); //默认编码方式
    /**
     * 指定输出目录路径
     * 若为空,则指定输出文件的路径。
     */
    public String outputDirPath;
}

1.5.2. 文件读取(设备 -> APP)

对应类

功能说明

GetFileByClusterTask

通过文件簇号读取文件任务

GetFileByNameTask

通过文件名读取文件任务

1.5.2.1. 通过文件簇号读取文件

推荐读取文件方式

示例代码

//WatchManager是WatchOpImpl的子类,须在1.3配置好sdk
WatchManager watchManager = WatchManager.getInstance();
List<SDCardBean> list = FileBrowseManager.getInstance().getOnlineDev();
if (list.size() < 1) {
    //没有在线设备
    return;
}
SDCardBean sdCardBean = list.get(0);//获取设备,如果有多个设备,请根据需求获取相应的设备
FileStruct fileStruct = null;//注意fileStructs一定要是在sdCardBean中
int devHandle = sdCardBean.getDevHandler();
int cluster = fileStruct.getCluster();
int offset = 0;
String path = "读取内容的保存路径";
GetFileByClusterTask.Param param = new GetFileByClusterTask.Param(devHandle, 0, cluster, path);
GetFileByClusterTask task = new GetFileByClusterTask(watchManager, param);
task.setListener(new TaskListener() {
    @Override
    public void onBegin() {
        //开始
    }

    @Override
    public void onProgress(int progress) {
        //进度回调
    }

    @Override
    public void onFinish() {
        //成功
    }

    @Override
    public void onError(int code, String msg) {
        //失败
    }

    @Override
    public void onCancel(int reason) {
        //取消
    }
});
task.start();

1.5.2.2. 通过文件名读取文件

不推荐,需要固件端支持

//WatchManager是WatchOpImpl的子类,须在1.3配置好sdk
WatchManager watchManager = WatchManager.getInstance();
String name = "文件名";
String path = "保存路径";
List<SDCardBean> list = FileBrowseManager.getInstance().getOnlineDev();
if (list.size() < 1) {
    //没有在线设备
    return;
}
SDCardBean sdCardBean = list.get(0);//获取设备,如果有多个设备,请根据需求获取相应的设备
int devHandle = sdCardBean.getDevHandler();
boolean unicode = false;//文件名是否支持长文件名(长文件采用unicode编码,短文件名使用8+3结构的ASCII编码)
GetFileByNameTask.Param param = new GetFileByNameTask.Param(devHandle,name,path,unicode);
GetFileByNameTask task = new GetFileByNameTask(watchManager,param);
task.setListener(new TaskListener() {
    @Override
    public void onBegin() {
        //开始
    }

    @Override
    public void onProgress(int progress) {
        //进度回调
    }

    @Override
    public void onFinish() {
        //成功
    }

    @Override
    public void onError(int code, String msg) {
        //失败
    }

    @Override
    public void onCancel(int reason) {
        //取消
    }
});
task.start();

Important

  1. 同一个watchManager实例同一时间只能运行一个文件管理的操作, 如果要连续执行多个操作, 需要做串行限制

  2. OTA过程中, 不允许调用文件操作

1.6. 特殊操作(需要设备端配置)

使用以下接口时,请与固件端开发人员沟通是否支持。

1.6.1. 通过文件名删除文件

//WatchManager是WatchOpImpl的子类,须在1.3配置好sdk
WatchManager watchManager = WatchManager.getInstance();
String name = "文件名";
DeleteFileByNameCmd deleteFileByNameCmd = new DeleteFileByNameCmd(new DeleteFileByNameCmd.Param(name));
watchManager.sendRcspCommand(watchManager.getTargetDevice(), deleteFileByNameCmd, new BooleanRcspActionCallback("DeleteFileByName",
            new OnOperationCallback<Boolean>() {
                @Override
                public void onSuccess(Boolean result) {
                    //成功
                }

                @Override
                public void onFailed(BaseError error) {
                    //失败
                }
            }));

Important

  1. 使用文件管理的相关接口时需要先检查存储设备是否上线

  2. 特殊操作需要和固件确认是否支持

  3. OTA过程中, 不允许调用文件操作