Custom Vice Screen Display App

Development Descriptions for Customized Customer Display Program

Content update

2018-01-15

•        Remove the common method, descriptions of the key class

•        Update Demo source code

•        Update the method of the development debugging of double screen App


One. Introduction

T1 double screen device has three combinations: host, host + 7 inch second screen, host + 14 inch second screen. Both main & second screen run SUNMI OS customized system, and realize the communication via Sunmi’s encapsulated interface. Main screen is mainly used to run business App, for example: cashier system. Second screen is mainly used for customer display settlement, advertisement content.

Double screen communication principle:

7304985152216485

From the bottom up in turn:

• Driver: this layer is a communication protocol at the bottom layer, the developers do not need to care about it.

• Service: this layer is a communication service encapsulated by Sunmi, the developers also do not need to care about it.

• SDK: this layer is the communication interface used by T1’s self-contained second display program, and the customized customer display program invokes the interface of this layer.

• App: indicating the business app and built-in second display program owned by the developer himself/herself.

There are two methods available for the developers to realize second screen display:

• T1 second screen system has its built-in second screen display App by default, and also several built-in commonly used templates. The developer only need to send data with correct format to the second screen via Sunmi’s SDK, and then the second screen’s content display will be realized.

• To develop his/her own second screen display App, it is required to handle by oneself the actions of data receive & send, content display, etc.

Although Sunmi’s encapsulated built-in customer display program can meet the usage demands of the

vast majority of developers, yet considering the business diversity, Sunmi adheres to the opening principle, and supports the second screen display customized by the developer himself/herself.

The following text is going to explain the development of customized double screen App.

Two. How to debug App

Since main & second screen communicate via USB, when USB line is plugged in main/second screen, the connection of main & second screen will be disconnected, leading to the impossibility to debug the device. The solution provided by Sunmi is: place the computer to be developed and T1 host to be debugged into the same LAN environment, and carry out the debugging of the device via network.

How to debug

1. Enable USB debug, and the debugging permission:

operation instructions:debugging devices

2. Carry out ADB debug to the device via network:

operation instructions: debugging instructions

Three. How to develop customized double screen App

(It is emphasized: Sunmi OS is customized based on Android 6.0, it is required by Android 6.0+ that partial sensitive permissions need to have dynamic application)

1. Initialization of the configuration

How to realize customized double screen App will be explained as follows based on Demo.

Step 1:

   Download DoubleApp resource file. (the source code will be compiled with AndroidStudio)

step 2:

   Refer to Demo source code, and declare the following code directly in build.gradle file under app module of Android Studio.

compile 'com.sunmi:DS_Lib:1.0.9'      //Commercial library provides lib, contains the interface has been packaged
compile 'com.google.code.gson:gson:2.6.2'  //gson any version

step 3:

  Register broadcast under the node of the list file AndroidManifest.xml (the developer may refer to the source code to realize the broadcast class by himself/herself).

"...Broadcasting...">  //Receive data broadcast

"com.sunmi.hcservice"/>
"com.sunmi.hcservice.status"/>

step 4:

  Initialize SDK code at the appropriate location, you may refer to Demo source code.

private void initSdk() {
mDSKernel = DSKernel.newInstance();  
mDSKernel.init(this, mIConnectionCallback);  //Bind the service callback
mDSKernel.addReceiveCallback(mIReceiveCallback);  //Dual-screen communications receive data callback
}

2. Develop double screen App

Refer to Demo source code to realize the interaction of double screen data. Its concrete method can be defined by oneself, and we are not going to provide an example here.

When the business logic of main screen and second screen have all been realized, it is required to combine the business codes of main screen and second screen into one apk (since the installation logic of App market is to respectively install one App onto main & second screen, only one APK is required to be submitted as for double screen App).

Four. Preparations before the release of App

The customized double screen App has well been developed, and then this App is going to be released to Sunmi App market for distribution. Before this action, it is required to complete one important step, that is to enable the App market to recognize that this App is double screen App.

Add one line of identification code to AndroidManifest.xml of the App, thus this App will be displayed as double screen App on the App market. In the installation, the App market will install this App respectively onto main screen and second screen.

"sunmi_dual" android:value="open"/>

Debugging instructions

Background:

  • Why is it required to pass network debugging?    

    Currently, T1 main screen communicates with second screen via USB connection, with main screen as primary device, second screen as slave device and USB peripherals also as slave device. PC connects main screen or second screen via USB line to carry out debugging, with PC as primary device, main screen or second screen as slave device. At this time, the communication between main screen and second screen will be disconnected, and the connection of peripheral USB device will also be disconnected. Thus, to connect PC with USB line can only carry out the single debugging of main screen or second screen, and also leading to the disconnection of USB peripherals. That is to say, it’s impossible to debug the App applied to main & second screen at the same time, and it’s also impossible to debug the App applied to USB peripherals.

  • Sunmi has provided the solution to solve all the above problems:    

PC connects T1 device via wired or wireless LAN, and it’s OK to debug the App applied in T1 double screen or USB peripherals without affecting the usage of T1 double screen communication and peripherals.

Debugging principle


Descriptions:

  • T1 main screen and second screen have been connected with each other via built-in USB line, without the need to connect with other USB lines;
  • PC need to be connected with T1 double screen device (main screen) via network;
  • Debugging main screen: PC debugs the main screen directly via WiFi/wired network;
  • Debugging second screen: PC first connects the main screen via network, then debugs the second screen via main screen bridging.

Front-loading conditions:

  1.  WiFi/wired LAN, the network connection is normal;
  2.  PC and T1 main screen are within the same LAN;
  3.  The versions of T1 double screen system all support double screen ADB debugging; (14 inch main screen: V1.11.4 and above; 14 inch second screen: V1.8.3 and above);
  4.  T1 main screen enables USB debugging; (T1 main screen system setting-Developer setting-Enable USB debugging);
  5.  Not to have an external connection of USB debugging line on double screen device; (main screen/second screen external USB debugging line will cause the disconnection of double screen communication, you can only debug one of the screens);
  6.  PC supports ADB debugging environment;
  7.  T1 main & second screen communication is normal (open main screen’s “Second Screen Setting”, and you can check the system version information of the second screen). 

Operating steps

1.Obtain main screen’s IP address

    Check main screen IP in T1 Main Screen System Setting—About—Status Information, and record IP

address.  For example:

192.168.1.12

2. Add terminal—main screen

Open the terminal command line tool on PC, enter the following command:

adb connect 192.168.1.12:5555

Descriptions: “192.168.1.12” shall be replaced with the recorded main screen IP address, the port number corresponding to the main screen is “5555”, which cannot be modified. At this time, it shall be displayed that “Connected to 192.168.1.12: 5555”, which indicates that the main screen has been connected.

3. Add terminal—second screen, continue with step 2, enter the following command:

adb connect 192.168.1.12:5554

Descriptions: “192.168.1.12” shall be replaced with the recorded main screen IP address, the port number corresponding to the second screen is “5554”, which cannot be modified. At this time, it shall be displayed that “Connected to 192.168.1.12: 5554”, which indicates that the second screen has been connected.

It is emphasized: the second screen must be connected after connecting the main screen first.

4.Query about the added terminal

Continue with step 2 or step 3, enter the following command:

adb devices

Descriptions: at this time, 1 to 2 terminal devices shall be displayed.

5.Debug the specified terminal

Continue with step 3, it is required to enter the following command when debugging main screen:

adb -s 192.168.1.12:5555 shell ls

Descriptions: “192.168.1.12” shall be replaced with the main screen’s IP address, the port number corresponding to the main screen is “5555”, which cannot be modified. At this time, the directory of the main screen storage shall be displayed. “shell Is” can be replaced with other ADB commands.

Continue with step 3, it is required to enter the following command when debugging second screen:

adb -s 192.168.1.12:5554 shell ls

Descriptions: “192.168.1.12” shall be replaced with the main screen’s IP address, the port number corresponding to the second screen is “5554”, which cannot be modified. At this time, the directory of the second screen storage shall be displayed. “shell Is” can be replaced with other ADB commands.

6.Disconnect the terminal connection

Continue with Step 3, it is required to enter the following command when disconnecting main & second

screen:

adb disconnect 192.168.1.12:5555

Descriptions: “192.168.1.12” shall be replaced with the main screen’s IP address, the port number corresponding to the main screen is “5555”, which cannot be modified. Right now, the connections of main screen and second screen shall be disconnected at the same time.

It is emphasized: the connection of the second screen will be disconnected at the same time when the main screen connection is disconnected.\

Sample description

Add terminal:

1

Debug the specified terminal—main screen:

2

Debug the specified terminal—second screen:

3

Disconnect the terminal connection—main screen and second screen:

4

T1 Dual Screen Communication Interface

                       Descriptions for the Key Classes (Docking Document for T1 Double Screen Communication Interface)

Including sunmi.ds

DSKernel class: SDK core class, which exposes the function to send data to second screen and initialize SDK

  •  newInstance(): DSKernel

Descriptions: instantiate the static function of DSKernel class.

  •  getDSDPackageName(): String

Descriptions: static function to obtain App package name of second screen receive data.

Return value: packageName, the second screen is responsible for receiving App package name of the data

  • init(Context context, IConnectionCallback stateCallback, StringvicePackageName): void

Descriptions: initialize SDK.

Parameters:

context: android context object.

stateCallback: callback of second screen’s connection status.

  •  isConnected():boolean

Descriptions: judge whether the double screen communication connection is smooth or not

Return value: isConn true is smooth, false is disconnected.

  • sendData(DataPacket pack): void

Parameters:

pack: object of DataPacket type, which has encapsulated the data to be sent.

  •  sendCMD(String recePackageName, String cmd, long fileId, ISendCallback callback): void

Descriptions: send CMD command package, you may specify the cache file id to be used.

Parameters:

recePackName: name of the receiving end package.

cmd: command. fileId: the cache file id to be used; if not available, transfer 0.

callback: send the result callback.

  • sendCMD(DataPacket dataPacket): void

Descriptions: send CMD command package, you may specify the cache file id to be used.

Parameters: dataPacket: CMD type data package.

  •  sendQuery(DataPacket mPack, QueryCallback callback): void

Descriptions: send data, used when the second screen sends the query data package.

For example: in the user protocol layer, main screen sends a query data package to the second screen, which indicates the query about second screen brightness. After the second screen has received it and obtained the brightness, it will then invoke sendResult(long queryId) function to send back a result data package carrying brightness to the main screen, and this Result data package’s queryId must be consistent with the taskId of Query data package. Only in this way can the main screen recognize that it’s the previous query result.

Note: when using QueryCallback to receive the result data package, the callback example registered via addReceiveCallback() will not be invoked.

Parameters:  pack: object of DataPacket type, which has encapsulated the data to be sent. callback query result callback 

  •  sendQuery(String recePackageName, String queryStr, ISendCallback, sendCallback, QueryCallback callback): void

Descriptions: send data, used when the second screen sends the query data package. For example: in the user protocol layer, main screen sends a query data package to the second screen, which indicates the query about second screen brightness. After the second screen has received it and obtained the brightness, it will then invoke sendResult(long queryId) function to send back a result data package carrying brightness to the main screen, and this Result data package’s queryId must be consistent with the taskId of Query data package. Only in this way can the main screen recognize that it’s the previous query result.

Note: when using QueryCallback to receive the result data package, the callback example registered via addReceiveCallback() will not be invoked.

Parameters: recePackageName: receiving end package name. queryStr: character string data to be carried

sendCallback: send the result callback    callback: query about the result callback

  •  sendResult(String recePackageName, String resultStr, long queryId, ISendCallback sendCallback): void

Descriptions: send Result data package. Parameters: recePackName: receiving end package name. resultStr: query result. queryId: taskId of Query data package. sendCallback: send result callback.

  •  sendFile(String recePackName, String filePath, ISendCallback callback): long

Descriptions: send file.

Parameters: recePackName: app package name received by the second screen. filePath: file path. callback: send the result callback.

Return value: taskId, maintain this task Id until receiving the callback that has been sent successfully. Then you can send command to the second screen and carry out the customization operation of the file. For example: the operations of displaying pictures, opening files, etc.

Note: after the file has been transmitted to the second screen, it will be cached and form mapping relation with the returned taskId. If you want to reuse this file for a long term, you need to maintain taskId permanently.

  •  sendFile(String recePackName, String msg, String filePath, ISendCallback callback): long

Descriptions: send data of one file + String type.    Parameters: recePackName: app package name received by the second screen.  msg: data of String type, for example: a character string of json format, a paragraph of text information, etc.  filePath: file path.  callback: send the result callback. 

Return value: taskId, maintain this task Id until receiving the callback that has been sent successfully. Then you can send command to the second screen and carry out the customization operation of the file. For example: the operations of displaying pictures, opening files, etc. 

Note: after the file has been transmitted to the second screen, it will be cached and form mapping relation with the returned taskId. If you want to reuse this file for a long term, you need to maintain taskId permanently.

  •  sendFilles(String recePackName, String msg, List files, ISendFilesCallback callback): long

Descriptions: send data of several files + String type.  Parameters: recePackName: app package name received by the second screen.  msg: data of String type, for example: a character string of json format, a paragraph of text information, etc.  files: file paths set.  Callback: send the result callback in terms of several files.

Return value: taskId, maintain this task Id until receiving the callback that has been sent successfully. Then you can send command to the second screen and carry out the customization operation of the file. For example: the operations of displaying pictures, opening files, etc.

Note: after the file has been transmitted to the second screen, it will be cached and form mapping relation with the returned taskId. If you want to reuse this file for a long term, you need to maintain taskId permanently.

  •  checkFileExist(long fileId, final ICheckFileCallback callback): void

Descriptions: check whether the file corresponding to fileId exists on the second screen or not

Parameters: fileId:file Id.  callback: check the result callback

  •  addConnCallback(IConnectionCallback callback): void

Descriptions: register a callback to monitor connection, you can register several ones.

Parameters: stateCallback: callback the status of connection with the second screen.

  •  removeConnCallback(IConnectionCallback callback): void

Descriptions: remove the callback to monitor connection.

Parameters: stateCallback: callback the status of connection with the second screen.

  •  checkConnection(): void

Descriptions: detect the status of connection with the second screen. If there is a result, the registered IConnectionCallback will be called back.

  •  addReceiveCallback(IReceiveCallback receiveCallback): void

Descriptions: register the callback of data receiving, you can register several ones.

Parameters: receiveCallback: the receiving end is used in the callback interface that receives the sending end data.

  • removeReceiveCallback(IReceiveCallback receiveCallback): void

Descriptions: remove the data receiving callback.

Parameters: receiveCallback: callback example to be logged out.

FilesManager class: maintain permanently the files received by the cache, cache DSFile, DSFiles taking taskId that sends file task as key.

  •  getFile(Long taskId): DSFile descriptions: obtain the file according to task ID.  Parameters: taskId: task ID corresponding to the file.

  •  getFile(Long taskId): DSFile descriptions: obtain several files according to task ID.  Parameters: taskId: task ID corresponding to the file.

sunmi.ds.callback package

IReceiveCallback class: the callback interface during the data receiving.

  • onReceiveData(DSData data): void   Descriptions: callback upon receiving the data.  Parameters: data: data that have been received

data that have been received

  • onReceiveFile(DSFile file): void   Descriptions: callback upon receiving single file.  Parameters: file: filethat has been received

  • onReceiveFiles(DSFiles files): void   Descriptions: callback upon receiving data of >=one file + a paragraph of String type.  Parameters: files: the files that have been received + String data

 onReceiveCMD(DSData cmd): void   Descriptions: callback upon receiving data of CMD type.  

Parameters: cmd: data of CMD type that have been receivedreceiving the query result data package.

QueryCallback class: callback upon receiving the query result data package.

  • onReceiveData(DSData data): void   Descriptions: callback upon receiving the result data package.Parameters: data: data that have been received

IConnectionCallback class: callback interface in double screen communication connection status, all the callback functions run in child thread.

  • onDisConnect(): void   Descriptions: callback when disconnected.

  • onDisConnect(ConnState state): void   Descriptions: callback when the connection status is updated. 

The connection statuses are divided into 3 types: 1. normal link with local service; 2. normal connection with second screen service (in this status, it’s OK to send data to the second screen); 3. normal connection with second screen App.   Parameters: state: connection status

ICheckFileCallback class: check the file result callback interface.

  • onCheckFail(): void   Descriptions: check fails (communication fails).

  • onResult(Boolean exist): Boolean  Descriptions: check fails (communication fails).

Parameters: exist: true indicates existence, false indicates non-existence.

IConnectionCallback class: callback interface in double screen communication connection status, all the callback functions run in child thread.

  • onDisConnect(): void   Descriptions: callback when disconnected.

  • onDisConnect(ConnState state): void   Descriptions: callback when the connection status is updated. 

The connection statuses are divided into 3 types: 1. normal link with local service; 2. normal connection with second screen service (in this status, it’s OK to send data to the second screen); 3. normal connection with second screen App.   Parameters: state: connection status

ISendCallback class: callback interface to send String data or single file, all the callback functions run in child thread.

  • onSendSuccess(long taskId): void  Descriptions: callback upon successful sending. taskId: task Id,corresponding to the data or file to be sent.

  • onSendFail(int errorId, String errorInfo): void  Descriptions: callback upon failure in sending.Parameters: errorId: error identification code. errorInfo: error descriptions.

  • onSendProcess(long totle, long sended): void   Descriptions: callback of sending progress.  Parameters: totle: total size of the data, unit: byte.  sended: size of the data that have already been sent, unit: byte.

ISendFilesCallback class: callback interface to send >=one file+String data, all the callback functions run in child thread.
  • onAllSendSuccess(long fileId): void  Descriptions: callback upon the successful sending of several files.fileId: task Id is also the corresponding fielId cached in the second screen file.

  • onSendSuccess(String path, long taskId): void  Descriptions: callback upon the successful sending of one certain file. taskId: task Id, the taskId of several files to be sent are the same since they belong to the same task.

  • onSendFail(int errorId, String errorInfo): void  Descriptions: callback upon the failure in sending Stringdata, String data will not continue to send files after it fails to be sent.   Parameters: errorId: error identification code. errorInfo: error descriptions.

  • onSendFileFaile(String path, int errorId, String errorInfo): void  Descriptions: callback upon the failure in sending one certain file.  Parameters: path: the file path corresponding to sending failure. errorId: error identification code. errorInfo: error descriptions.

  • onSendProcess(String path, long totle, long sended): void  Descriptions: callback of the progress of sending one certain file.   Parameters: path: the corresponding file path. totle: total size of the data, unit: byte.  sended: size of the data that have already been sent, unit: byte

sunmi.ds.data package

DataPacket class: it has been encapsulated with sending data and sending callback, and it’s a parameter entity class required by invoking sendData(DataPacket pack) function of DSKernel class.

DataPacket.Builder class: DataPacket’s builder class.

  • Builder(DSData.DataType dataType) descriptions: constructor function.  Parameters: datatype: data type to be built.

  • recPackName(String recPackName): Builder descriptions: name of the App package to be specified to receive data.  Parameters: recPackName: name of the App package to receive data. Return value: Builder example

  •  data(String data): Builder descriptions: specify the data to be sent.   Parameters: data: String data to be 

sent.  Return value: Builder example

  • taskId(long taskId): Builder descriptions: specify the task Id, it will be automatically generated if not specified.  Parameters: taskId: task Id.   Return value: Builder example

  • fileId(long fileId): Builder descriptions: specify the cache file Id.  Parameters: fileId: cache file Id.   Return value: Builder example

  • queryId(long queryId): Builder descriptions: specify Id of Query data package.  Parameters: fileId: Id of Query data package.  Return value: Builder example

  • isReport(Boolean isReport): Builder descriptions: specify whether result callback is required or not. Parameters: isReport: whether result callback is required or not.  Return value: Builder example.

  •  addCallback(ISendCallback callback): Builder descriptions: example of setting sending result callback. Parameters: callback: example of sending result callback.  Return value: Builder example

  •  build(): DataPacket descriptions: example of building one DataPacket.  Return value: DataPacket example

DSData class: data encapsulation of double screen communication.

  •  sender: String descriptions: app package name at the sending end.

  •  taskId: long descriptions: task Id.

  •  fileId: long descriptions: cache file Id.

  •  queryId: long descriptions: task Id of Query data package.

  •  dataType: DataType descriptions: data type.

  •  data: String descriptions: data to be sent.

DSData.DataType enumeration class: data type describes the encapsulation.

  •  DATA: DataType descriptions: indicating data.

  •  FILE: DataType descriptions: indicating file.

  •  CMD: DataType descriptions: indicating command.

  •  typeCode: int descriptions: type code.

DSFile class: file class to be received at the receiving end.

  •  sender: String descriptions: name of app package at the sending end.

  •  path: String descriptions: file path to be received.

  •  taskId: long descriptions: task Id.

DSFiles class: multiple files class to be received at the receiving end.

  •  filesDescribe: FilesDescribe descriptions: String data and file quantity to be received has been encapsulated.
  •  sender: String descriptions: name of app package at the sending end.
  •  files: List descriptions: file path set to be received.
  •  taskId: long descriptions: task Id.

FilesDescribe class: String data and file quantity to be received has been encapsulated.

  •  msg: String descriptions: String data to be received.
  •  fileCount: int descriptions: file quantity.

T1 Custom Vice Screen Display App

[Prompt: please read carefully the content in the document before the development. If you have any queries, please contact Sunmi Technology for consultation support.]

                                  【Note: plug in usb debugging line, which will lead to the disconnection of main & second screen.

About T1 Double Screen

As for Sunmi T1, there are two types of double screen configurations available:

1.  14 inch main screen, 7 inch second screen.

Note: 7 inch second screen only supports browsing, but does not support touch control and the installation of app. If the user needs to modify second screen interface, please refer to Docking Document for Built-in Second Display Program 

Ouk69hAZ0gIkhS99

2.  14 inch main screen, 14 inch second screen, touch control second screen.

VzaGKG2DvekBhhS3 (1)


Please check Introduction of Official Website for detailed hardware instructions. Both main and second screen of the device run SUNMI OS system, and they realize communication via the interface encapsulated by Sunmi.

Note: not to confuse the relevant codes of Sunmi, which may cause the component not to be able to work

#sunmi

-keep class com.luedongtech.kr3000.sunmi.** {*;}

-keep class sunmi.ds.**{*;}

-keep class com.sunmi.**{*;}

-keep class sunmi.sc.**{*;}

-keep class com.google.gson.**{*;}

Normally, the developer’s business app runs at the main screen while the second screen is required to display the content of list information, propaganda pictures, videos, etc., sometimes to realize simple interactive operation. As for the developers, two methods are available to display content with T1 second screen:

 1.  Use the built-in display program of T1 second screen system. The second display program will display the content only if the main screen app send data with specific format to the second display program according to Sunmi specifications (suggested for low development cost).

 2.  The developer writes second screen display app by himself/herself (with high development cost and degree of freedom).

 Although Sunmi’s encapsulated second display program can meet the demands of the vast majority of developers on second screen display content, yet the business is diverse. Sunmi always adheres to the openness principle to support the developers to write their own second display program. The following is the detailed description for writing the second display program by oneself.

  •  The distribution of second display app

We stipulate that business App will install on the second screen while installing on the main screen via App market only if one line configuration (to be described at the end of the document) is added to your main screen business App’s AndroidManifest.xml. That is to say, your main screen App is at the same time second screen App. Here, you are required to control the content displayed in the home page in the code.

Get Right to the Point

The core problem of the development of customized second display program is the communication of main & second screen. After realizing the communication of main & second screen, you may regard the second screen as ordinary second screen app relevant to the development of tablet computer. Here, it is necessary to first realize the communication method of double screen, and we’d like to provide you with visual presentation of the communication protocol of T1 double screen via a piece of picture.

 

T1’s communication protocol includes the following layers in turn from the bottom up:

1. Driver layer, which is the communication protocol at the lowest level. The developers do not need to care about it.

2. Service layer, which is a type of communication service encapsulated by Sunmi. The developers also do not need to care about it.

3. SDK layer, which is a communication interface used by T1’s self-contained second display program. The customized second display program also invokes the interface of this layer.

4.APP layer, which is the business app and built-in second display program owned by the developer himself/herself.

  • If T1 built-in second display program is used, the data communication method is as shown in the above figure. The developer’s main screen business App only needs to invoke Sunmi’s SDK and send data to the second display according to the data format specified by Sunmi, the rest will be done by the system.
  • If you are going to develop second display program by yourself, you need to process by yourself the actions of data receive & send, content display, etc. If you do not have a strong demand for customization, we suggest that you use T1’s self-contained second display program to display the content, which will save a lot of labor & material cost.

Start Developing

We have provided the developers with a Demo of double screen communication. You can download Develop Resources of Second Display Program, and refer to the code in Demo to realize your own second display app. Please deploy this Demo according to the following process:

    1.Install HCService.apk in the resource file onto two devices that simulate main & second screen Communication. The resource contains two apk of HCService. Please install release version first. If the installation fails, please try to install apk of unsigned version.

    2. This program is run respectively on main & second screen. Enter your own IP address on the first device, check “As Main Screen”, click Determine. 

    3.  Enter IP address of the main screen device on another device, click Determine (not to check “As MainScreen”), and you’ll see toast prompt “Connect with Main/Second Screen” popped up on the screen, which represents that it’s OK for main & second screen to communicate. If there is no popup prompt, please find HCService program in App Management in Setting (get into Setting -> App -> Click More at the Top Right Corner -> Click Display the System Progress, and then you will see HCService), to mandatorily stop HCService service on main & second screen, and then repeat the above-mentioned steps to have a try.

   4. Import MyDSD project into AndroidStudio. If an error is reported, please check whether your version in the compiling environment is compatible with demo. You can make the relevant adjustment by yourself. Note: we do not suggest that you use eclipse to develop second display program, currently there is no relevant eclipse resource package available.

    5.  Here, please modify the enabling page in AndroidManifest.xml to MainSceenActivity, and then deploy the project into the main screen device, and run.

    6.  Then modify the enabling page to ViceScreenActivity, and deploy the project into the second screen device, and run.

    7. Click the button for sending text on the main screen, check the change of the second screen’s displayed content, and then you may send the pictures to the second screen for checking the display situation

In this Demo, the methods of sending character data mutually between main & second screen are included. They are method of sending single file and that of sending several files. We are going to explain the development process of main & second screen communication based on Demo as follows:

1. To add the following content to build.gradle depends on:

dependencies {
    compile files('libs/commons-codec-1.9.jar')
    provided files('libs/framework.jar')
    compile 'com.android.support:appcompat-v7:22.2.1'
    compile 'com.sunmi:DS_Lib:latest.release'
    compile 'com.google.code.gson:gson:2.6.2'
}

The permission that is required to be added:

One more broadcast receiver. Please note: this is a fixed writing method, do not modify it.


    
        
        
    intent-filter>
receiver>

2.  Initialization. You may initialize SDK code in Application, and also initialize anywhere you want:

private void initSDK() {
    mDSKernel = DSKernel.newInstance();
    mDSKernel.init(this, mConnCallback);
}

The above DSKernel class is the core class in SDK, and almost all the methods relevant to double screen communication are among this class. Two monitor classes are required to be added after the initialization:

//Add the connect status listener
mDSKernel.addConnCallback(new IConnectionCallback(){
                        @Override
                        public void onConnected(ConnState arg0) {
                        //connect success
                        }

                        @Override
                        public void onDisConnect() {
                        //disconnect
                        }
                        
                });

//Add the data received listener               
mDSKernel.addReceiveCallback(new IReceiveCallback(){

                        @Override
                        public void onReceiveCMD(DSData arg0) {
                          //receive the CMD     
                        }

                        @Override
                        public void onReceiveData(DSData arg0) {
                           //receive some data
                        }

                        @Override
                        public void onReceiveFile(DSFile arg0) {
                           //receive one file
                        }

                        @Override
                        public void onReceiveFiles(DSFiles arg0) {
                           //receive multiple files
                        }
             
                        
                });   

Above we complete the initialization, and sure the communication will separate send and receive of the information. Main & second screen can send & receive data between each other. It can be seen that within MyDSD, many methods of sending data are included in MainScreenActivity, many methods of receiving data are included in ViewScreenActivity.

All the methods can be checked in DSKernel class, and you can also check Docking Document for T1 Double Screen Communication Interface for details. We are going to explain the usage of partial interfaces as follows:

1. Send character data, the second screen receives and display

DataPacket packet = UPacketFactory.buildShowText(DSKernel.getDSDPackageName(),  "receive characters success!",null); 
//The param DataPacket is the data package class of Dual Screen Communication 
mDSKernel.sendData(packet);

The receiving method is in onReceiveData (DSData data) of IReceiveCallback interface:

@Override
public void onReceiveData(DSData data) {
    Log.d(TAG, "Data received:" + data.data);
}

2.  Method of sending command:


String json = UPacketFactory.createJson(DataModel.QRCODE, ""); 
//Three parameters: 1.package name of the app which receive the CMD,  
//2. the Command which you want send. 3. The result callback 
mDSKernel.sendCMD(DSKernel.getDSDPackageName(), json.toString(), l,null);

Method of receiving command:

@Override
public void onReceiveCMD(DSData cmd) {
     Log.d(TAG, "Data received :" + cmd.data);
}

Example of usage scenarios of the command: as for the display of pictures, videos, etc., it is required to first send the file to the second screen, and the second screen will return an id of the file to the main screen. Then command is sent to the second screen to display pictures or videos of the specified id.

3.  Method of sending single file:


//Three parameters: 1. the package name of the receiver app in vice screen; 
//2. The local path of the file. 3. result callback. 
mDSKernel.sendFile(PACKAGE_OF_VICE, Environment.getExternalStorageDirectory().toString() +"/"+videoInAsserts,       
new ISendCallback() {          
         public void onSendSuccess(long l) {                
//             showVideo(l);          
         }
         public void onSendFail(int i, String s) {             
//             tv_show_id.setText("fail:" + s);             
               Log.i("sunmi", "---:" + s);          
         }
         public void onSendProcess(long l, long l1) {             
//             process
          }       
});

Method of receiving single file. Via invoking FilesManager.saveFile (DSFile file) in onReceiveFile (DSFile file) of IReceiveCallback interface, the file will be saved locally:

@Override
public void onReceiveFile(DSFile file) {
   Log.i(TAG,"path of the file received :"+file.path);
   Log.i(TAG,"taskId of the file received :"+file.taskId);
    mFilesManager.saveFile(file);
}

4. Method of sending several files

mDSKernel.sendFiles(PACKAGE_OF_VICE, json.toString(), paths, new ISendFilesCallback(){
   @Override
   public void onAllSendSuccess(long l) {
     //all those files send success
   }
   @Override
   public void onSendFaile(int arg0, String arg1) {}
   @Override
   public void onSendFileFaile(String arg0, int arg1, String arg2) {}
   @Override
   public void onSendProcess(String arg0, long arg1, long arg2) {}
   @Override
   public void onSendSuccess(String arg0, long arg1) {
   }
   
});

Method of receiving several files:

@Override
public void onReceiveFiles(DSFiles dsFiles) {
            mFilesManager.saveFiles(dsFiles);
        }

5. Method of enabling specified App

Refer to Demo’s generated data and send command to the second screen. This code needs the support of DSD program. You can find this apk in the downloaded resource file and install it on the second screen.

The above is the introduction of the usage of some basic interfaces. Please check the code comments in DSKernel for more interfaces.

DataPacket dsPacket   = UPacketFactory.buildOpenApp(PACKAGE_OF_VICE, null);
//PACKAGE_OF_VICE is the package name of app which you want start, such as :com.sunmi.mydsd
mDSKernel.sendCMD(dsPacket);

6.  Method of deleting the files that have been transferred to the second screen

The files that have been sent to the second screen via method 3, 4 (pictures & text, videos, APK) will be saved under the uniform folder. When there are too many data that will affect the normal storage, it is required to execute command to delete all these contents.

Release of App

All the Apps of main & second screen have been well developed, it’s sure to distribute this App in large scale via Sunmi App market. As we mentioned above, this App will install this App (it will only take effect via the installation of the App market) at the same time only if one line of configuration is added to AndroidManifest.xml of App and this App is installed on the main screen via App market with smooth communication of double screen. Main & second screen programs are written in one App, thus it is required that you add the relevant judgment logic in the inlet class. That’s the cause for your modifying the enabling page when running Demo. You may refer to Demo as for the concrete code to judge main & second screen.

Debugging second screen 

 

 


 "sunmi_dual" android:value="open"/>

 

Currently, the developers can debug the main screen via USB. Since normally the second screen only complete simple content display functions, considering a safe & stable second screen, Sunmi currently doesn’t open the second screen device to debug the operating environment directly via USB, and the second screen does not have its independent network connection. But don’t worry, we provide a type of alternative debugging solution (due to different environments, it may cause being unable to debug or debug exception).

Our engineers have simulated double screen communication channel base on the communication method of LAN. You may install double screen communication service prepared by us at any two Android tablet computers, set IP address, and then you can simulate the communication method of T1 main screen and second screen:

that is to say, we take two T1 devices, use the main screen of a T1 device to simulate the second screen and use that T1 device as main screen to communicate. Sure, you may use any Android mobile phone or tablet as the second screen, and then distribute the Apps to the devices via App market after completing the development debugging.

To supplement descriptions for one T1 wireless debugging:

1. The computer connects the device via USB, to ensure that the permission of the device debugging is open.

2. Enter “adb shell” in cmd command prompt to access T1 control console.

3. Enter “setprop service.adb.tcp.port 5555” in the control console.

4. Enter “ifconfig” in the control console to check ip address of T1 in the LAN, e.g.: 192.168.1.202

5. Access the options of the device: Setting -> Developer (If it has not been seen, you may access About the Device, click continuously several times the version number to open the developer mode) to find “Use DHCP Client End of the Old Version”, click it to open it.

6. Unplug USB.

7. Enter “adb connect ” in cmd, e.g.: adb connect 192.168.0.219. (Note: if prompt “Due to the active refusal of the target computer, it cannot be connected. (10061)” appears in this step, you can first close and then open the “USB debugging” option in the developer option, and then reenter the above command one time to have a try. )

8. The device pops up Toast prompt “You can begin to carry out the debugging”.

After completing the above steps, T1 wireless debugging can be realized.

T1 built-in vice screen display app

 

T1 built-in vice screen display app

Updates

2018-01-16 

  • New fucntion: 14 inch vice screen support carousel video;
  • New fucntion: 14 inch vice screen support video seeding; 
  • New fucntion: 7 inch vice screen support slides; 
  • New fucntion: 7 inch vice screen to support a single video; 
  • New fucntion: 7 inch vice screen support video carousel; 
  • New fucntion: 7 inch vice screen support video seeding; 
  • Add method of determining the size of vice screen; 
  • Add new ways to manage the vice screen cache file; 
  • DS_Lib library updated to 1.0.16;

                                                                                                                                                                                                                  

First, the introduction

T1 dual-screen machine has three combinations: host, host +7 inch vice screen, host +14 inch vice screen. The main screen and the vice screen are running SUNMI OS system, communicated through the packaged interface.

The main screen is mainly used to run business APP, for example: cash register system. Vice screen mainly used for customer settlement, advertising content.

Developers have two ways to achieve displaying of vice screen:

  • T1 vice screen system have built-in default vice screen display APP and multiple common templates. Developers only need to refer to the template implementation code to achieve the vice screen content displaying;
  • Developing own vice screen display APP, you need to handle the data transceiver, content displaying and other actions;

If you do not have strong customization needs, we recommend you to use the default vice display APP, to save a lot of research and development costs.

This article will explain how to access the built-in vice screen guest program.

Second, how to debug the application

Since the main screen and vice screen communicate via USB, when the main / vice screen is plugged with USB cable, main/vice screens are will be disconnected and the device can not be debugged.

SUNMI solution: put development computers and debugging T1 host in a same local area network environment, through the network to debug.

How to debug:

    1、open the USB debugging, and debugging authority;

      Instructions

    2、Device ADB debugging through the network;

      Instructions

Third, how to access the default vice screen APP

(Emphasis: Sunmi OS is customized based on Android6.0. Android6.0 + requires some sensitive permissions and need dynamic application)

Sunmi default vice screen APP provides multiple displaying templates, developers only need to be realize the code of vice screen controlling on the main screen, and then send the data to the default vice screen App to achieve displaying. 

1、Initialize the configuration

Docking 7-inch or 14-inch default sub-screen APP initialization are the same process.

step 1:

    Download DemoApp resource file.

step 2:

    Refer to the DemoApp source code, clarification the following code in the build.gradle file under the Android Studio app module:

dependencies {
compile 'com.sunmi:DS_Lib:1.0.15' //Commercial library provides lib, contains the interface has been packaged
compile 'com.alibaba:fastjson:1.1.67.android' //fastjson any version }

step 3:

    Configure the following statement under the node in the manifest file AndroidMainfest.xml:


....
"sunmi.ds.MsgReceiver"> //Receive data broadcast

"com.sunmi.hcservice">
"com.sunmi.hcservice.status">


step 4:

    Initialize the SDK code in proper place; you can refer to the implementation code in DSC_Demo.

DSKernel mDSKernel =DSKernel.newInstance();
mDSKernel.init(context, mConnCallback); //Bind the service callback
mDSKernel.addReceiveCallback(mReceiveCallback); //receive Dual-screen communications data callback

Then you can refer to the DemoApp source code, the default vice screen to apply the contents of the built-in template displaying.

proguard  ds_lib:

-keep interface sunmi.ds.**{ *; }

-keep class sunmi.ds.**{ *; }

In addition, you need to mix up Greendao and Fastjson, and the specific confusion rules are subject to the official supply of Greendao and Fastjson

2, built-in vice-screen displaying program templates

Supported templates comparison of 7-inch and 14 inch vice screen:

template7寸14寸
Text
Text + QR code
Single picture
Slide
Single video
Video carousel
List×
List + single picture×
List + Slide×
List + single video×
List + video carousel×

2.1, two lines of text

1

Implementation code:

JSONObject json = new JSONObject();
json.put("title", title);    //title is the content of the line above
json.put("content", content);    //content is the content of the following line
String jsonStr = json.toString();    //Build the DataPacket class
DataPacket packet = UPacketFactory.buildShowText(DSKernel.getDSDPackageName(), jsonStr, callback);    //The first parameter is the package name of data receiving sub-application, you can refer the demo here, the second parameter is the displaying contents string, the third parameter is the result callback.

mDSKernel.sendData(packet);    //Call SendData to send text

2.2, QR code + text

2

Implementation code:

JSONObject json = new JSONObject();
try {
json.put("title", "微信支付");
json.put("content", "10.00");
} catch (JSONException e) {
e.printStackTrace();
}

mDSKernel.sendFile(DSKernel.getDSDPackageName(), json.toString(), Environment.getExternalStorageDirectory().getPath() + "/qrcode.png", new ISendCallback() {
@Override
public void onSendSuccess(long l) {
//display image
try {
JSONObject json = new JSONObject();
json.put("dataModel", "QRCODE");
json.put("data", "default");
mDSKernel.sendCMD(SF.DSD_PACKNAME, json.toString(), l, null);
} catch (JSONException e) {
e.printStackTrace();
}
}

@Override
public void onSendFail(int i, String s) { 
}

@Override
public void onSendProcess(long l, long l1) {
}
});

2.3, a single picture

3

Implementation code:

mDSKernel.sendFile(DSKernel.getDSDPackageName(), Environment.getExternalStorageDirectory().getPath() + "/img_01.png", new ISendCallback() {

@Override
public void onSendSuccess(long taskId) {
showPicture(taskId);
}

@Override
public void onSendFail(int errorId, String errorInfo) {
}

@Override
public void onSendProcess(long totle, long sended) {
}
});
}

/**
* 
* Show a single picture
*
* @param taskId
*/

private void showPicture(long taskId) {
//display image
try {
JSONObject json = new JSONObject();
json.put("dataModel", "SHOW_IMG_WELCOME");
json.put("data", "default");
mDSKernel.sendCMD(DSKernel.getDSDPackageName(), json.toString(), taskId, null);
} catch (JSONException e) {
e.printStackTrace();
}
}

2.4, slide

4

Implementation code:

JSONObject json = new JSONObject();
json.put("rotation_time",5000);     //Slide switching time is calculated in milliseconds, the default is 10000 milliseconds

List pathList = new ArrayList<>();
pathList.add("/sdcard/img1.png");
pathList.add("/sdcard/img2.png");
...
mDSKernel.sendFiles(DSKernel.getDSDPackageName(), json.toString(), 
pathList, new ISendFilesCallback() {
public void onAllSendSuccess(long fileId) {
show(fileId);
}
public void onSendSuccess(final String s,final long l) {}
public void onSendFaile(int errorId, String errorInfo) {}
public void onSendFileFaile(String path, int errorId, String errorInfo){}
public void onSendProcess(String path, long total, long sended) {}
});

private void show(long fileId) {
String json = UPacketFactory.createJson(DataModel.IMAGES,"");
mDSKernel.sendCMD(DSKernel.getDSDPackageName(),json,fileId,null);
}

2.5, a single video

5

Implementation code:

mDSKernel.sendFile(DSKernel.getDSDPackageName(), Environment.getExternalStorageDirectory().getPath() + "/video_01.mp4", new sunmi.ds.callback.ISendCallback() {
@Override
public void onSendSuccess(long l) { 
playvideo(l); 
}

@Override
public void onSendFail(int i, String s) {
Log.d("highsixty", "发送单个文件视频文件失败 ------------>" + s); 
}

@Override
public void onSendProcess(final long l, final long l1) {
}
});
}

private void playvideo(long taskID) { 
String json = UPacketFactory.createJson(DataModel.VIDEO, "true");     //"true" video broadcast; false video playback from the beginning
mDSKernel.sendCMD(DSKernel.getDSDPackageName(), json, taskID, null);
}

2.6, video carousel

6

Implementation code:

/**
* 
* Send multiple videos
*/

private void sendVideos() {
//Please judge whether the file exists or not
List files = new ArrayList<>();
files.add(Environment.getExternalStorageDirectory().getPath() + "/video_01.mp4");
files.add(Environment.getExternalStorageDirectory().getPath() + "/video_02.mp4");
files.add(Environment.getExternalStorageDirectory().getPath() + "/video_03.mp4");
mDSKernel.sendFiles(DSKernel.getDSDPackageName(), "", files, new ISendFilesCallback() {

@Override
public void onAllSendSuccess(long fileid) {
playvideos(fileid);
}

@Override
public void onSendSuccess(String path, long taskId) { 
}

@Override
public void onSendFaile(int errorId, String errorInfo) { 
}

@Override
public void onSendFileFaile(String path, int errorId, String errorInfo) { 
}

@Override
public void onSendProcess(String path, long totle, long sended) {
}
});
}

private void playvideos(long taskID) {
Log.d(TAG, "playvideos: ------------>" + taskID);
String json = UPacketFactory.createJson(DataModel.VIDEOS, "true");     //The second parameter true: video broadcast  false: video playback from beginning
mDSKernel.sendCMD(DSKernel.getDSDPackageName(), json, taskID, null);
}

2.7, list

7

Implementation code:

{
"title": "三米奶茶店欢迎您", 
"head": {
"param1": "序列号",
"param2": "商品名",
"param3": "单价",
"param4": "数量",
"param5": "小结"
},
"list": [
{
"param1": "1",
"param2": "华夫饼",
"param3": "10.00",
"param4": "1",
"param5":"10.00"
},
{
"param1": "1",
"param2": "吞拿鱼华夫饼",
"param3": "12.00",
"param4": "1",
"param5":"12.00"
}
... ...//Here is the same format of data

],
"KVPList": [
{
"name": "收款",
"value": "¥40.00"
},
{
"name": "优惠",
"value": "¥3.00"
},
{
"name": "找零",
"value": "¥3.00"
},
{
"name": "实收",
"value": "¥37.00"
}
]
}

/**
*JSON data format description:
*1: title field for the title
*2: head field is the header field
*3: list is the products list, the number of fields in the header and table should be the same
*4: KVPList for the settlement of key-value list
*/

/**
*rule:
*When the display of graphic mixed: head params assignment minimum 1 maximum 4; params assignment of each element in list minimum 1, maximum 4; KVPList size minimum 1 maximum 4.
*/ 

/**
*receiverPackageName The secondary screen of the received data shows the app's package name DataType.DATA
*DataType.DATA 
*DataModel.TEXT 
*jsonStr display data content, the specific format, see the box below
callback callback
*/
DataPacket pack = buildPack(receiverPackageName, DataType.DATA, DataModel.TEXT, jsonStr, callback);
mDSKernel.sendData(pack);

2.8, list + single picture

8

Implementation code:

{
"title": "三米奶茶店欢迎您", 
"head": {
"param1": "序列号",
"param2": "商品名",
"param3": "单价",
"param4": "数量",
"param5": "小结"
},
"list": [
{
"param1": "1",
"param2": "华夫饼",
"param3": "10.00",
"param4": "1",
"param5":"10.00"
},
{
"param1": "1",
"param2": "吞拿鱼华夫饼",
"param3": "12.00",
"param4": "1",
"param5":"12.00"
}
... ...//Here is the same format of data

],
"KVPList": [
{
"name": "收款",
"value": "¥40.00"
},
{
"name": "优惠",
"value": "¥3.00"
},
{
"name": "找零",
"value": "¥3.00"
},
{
"name": "实收",
"value": "¥37.00"
}
]
}

/**
*JSON数据格式说明:
*1:title字段为标题
*2:head字段是表头字段
*3:list是商品列表,表头和表的字段数量要一致 
*4:KVPList为结算键值对列表
*/

/**
*规则:
*当显示图文混合时:head的params赋值个数最小1个最大4个;list中每个元素的params赋值个数最*小1个最大4个;KVPList的size
*最小1个最大4个。
*/ 

String filePath = "xxx/img.png";    //The path of the picture shown
mDSKernel.sendFile(DSKernel.getDSDPackageName(), filePath, new ISendCallback() {
public void onSendSuccess(long fileId) {
show(fileId, jsonStr);    //The picture is sent successfully, showing the text content
} 
public void onSendFail(int errorId, String errorInfo) {}
public void onSendProcess(long total, long sended) {}
});

void show(long fileId, String jsonStr){
jsonStr = UPacketFactory.createJson(DataModel.SHOW_IMG_LIST, jsonStr);    
//The first parameter DataModel.SHOW_IMG_LIST to display layout mode, jsonStr to display the contents of the characters
mDSKernel.sendCMD(DSKernel.getDSDPackageName(), jsonStr, fileId,null);
}

2.9, list + slide

9

Implementation code:

{
"title": "三米奶茶店欢迎您", 
"head": {
"param1": "序列号",
"param2": "商品名",
"param3": "单价",
"param4": "数量",
"param5": "小结"
},
"list": [
{
"param1": "1",
"param2": "华夫饼",
"param3": "10.00",
"param4": "1",
"param5":"10.00"
},
{
"param1": "1",
"param2": "吞拿鱼华夫饼",
"param3": "12.00",
"param4": "1",
"param5":"12.00"
}
... ...//这里是相同格式的数据
],
"KVPList": [
{
"name": "收款",
"value": "¥40.00"
},
{
"name": "优惠",
"value": "¥3.00"
},
{
"name": "找零",
"value": "¥3.00"
},
{
"name": "实收",
"value": "¥37.00"
}
]
}

/**
*JSON数据格式说明:
*1:title字段为标题
*2:head字段是表头字段
*3:list是商品列表,表头和表的字段数量要一致 
*4:KVPList为结算键值对列表
*/

/**
*规则:
*当显示图文混合时:head的params赋值个数最小1个最大4个;list中每个元素的params赋值个数最*小1个最大4个;KVPList的size
*最小1个最大4个。
*/ 

List paths = new ArrayList<>();
paths.add(Environment.getExternalStorageDirectory().getPath() + "/sunmi1.png");
paths.add(Environment.getExternalStorageDirectory().getPath() + "/sunmi2.png");
paths.add(Environment.getExternalStorageDirectory().getPath() + "/sunmi3.png");
paths.add(Environment.getExternalStorageDirectory().getPath() + "/sunmi4.png");

mDSKernel.sendFiles(DSKernel.getDSDPackageName(), "", paths, new ISendFilesCallback() {
@Override
public void onAllSendSuccess(long fileId) { 
sendImgsListCMD(fileId,json); 
}

@Override
public void onSendSuccess(String path, long taskId) {}
@Override
public void onSendFaile(int errorId, String errorInfo) {}
@Override
public void onSendFileFaile(String path, int errorId, String errorInfo) {}
@Override
public void onSendProcess(String path, long totle, long sended) {}
});

void sendImgsListCMD(long fileId, String jsonStr){ 
jsonStr= UPacketFactory.createJson(DataModel.SHOW_IMGS_LIST, json);
mDSKernel.sendCMD(DSKernel.getDSDPackageName(), jsonStr, fileId,null);
}

2.10, list + single video

10

Implementation code:

mDSKernel.sendFile(DSKernel.getDSDPackageName(), Environment.getExternalStorageDirectory().getPath() + "/video_01.mp4", new sunmi.ds.callback.ISendCallback() {
@Override
public void onSendSuccess(long l) { 
playVideoMenu(l); 
}

@Override
public void onSendFail(int i, String s) {
Log.d("highsixty", "发送单个文件视频和清单文件失败 ------------>" + s); 
}

@Override
public void onSendProcess(final long l, final long l1) {
}
});

private void playVideoMenu(long fileId) {
try {
JSONObject data = new JSONObject();
data.put("title", "商米奶茶店收银");
JSONObject head = new JSONObject();
head.put("param1", "序号");
head.put("param2", "商品名");
head.put("param3", "单价");
data.put("head", head);
data.put("flag", "true");     //When set as true, the video will play following the previous progress. Set as false, the video will be played from the beginning.
JSONArray list = new JSONArray();
for (int i = 1; i < 11; i++) {
JSONObject listItem = new JSONObject();
listItem.put("param1", "" + i);
listItem.put("param2", products.get(i - 1));
listItem.put("param3", prices.get(i - 1));
list.put(listItem);
}

data.put("list", list);
JSONArray KVPList = new JSONArray();
JSONObject KVPListOne = new JSONObject();
KVPListOne.put("name", "总计 ");
KVPListOne.put("value", "132.00");
JSONObject KVPListTwo = new JSONObject();
KVPListTwo.put("name", "优惠 ");
KVPListTwo.put("value", "12.00");
JSONObject KVPListThree = new JSONObject();
KVPListThree.put("name", "数量 ");
KVPListThree.put("value", "10");
JSONObject KVPListFour = new JSONObject();
KVPListFour.put("name", "应收 ");
KVPListFour.put("value", "120.00");
KVPList.put(0, KVPListOne);
KVPList.put(1, KVPListTwo);
KVPList.put(2, KVPListThree);
KVPList.put(3, KVPListFour);
data.put("KVPList", KVPList);
Log.d("HHHH", "onClick: ---------->" + data.toString());
String json = UPacketFactory.createJson(DataModel.SHOW_VIDEO_LIST, data.toString());
mDSKernel.sendCMD(DSKernel.getDSDPackageName(), json, fileId, null);
} catch (Exception e) {
e.printStackTrace();
}
}

2.11, list + video carousel

11

Implementation code:

/**
*list + video carousel
*/
private void sendMenuVideos() {
Log.d(TAG, "sendMenuVideos: ------------->");
List files = new ArrayList<>();
files.add(Environment.getExternalStorageDirectory().getPath() + "/video_01.mp4");
files.add(Environment.getExternalStorageDirectory().getPath() + "/video_02.mp4");
files.add(Environment.getExternalStorageDirectory().getPath() + "/video_03.mp4");

mDSKernel.sendFiles(DSKernel.getDSDPackageName(), "", files, new ISendFilesCallback() {

@Override
public void onAllSendSuccess(long fileid) { 
playMenuVideos(fileid);
}

@Override
public void onSendSuccess(String path, long taskId) { 
}

@Override
public void onSendFaile(int errorId, String errorInfo) { 
}

@Override
public void onSendFileFaile(String path, int errorId, String errorInfo) { 
}

@Override
public void onSendProcess(String path, long totle, long sended) {
}
});
}

private void playMenuVideos(long taskID) { 
try {
JSONObject data = new JSONObject();
data.put("title", "商米奶茶店收银");
JSONObject head = new JSONObject();
head.put("param1", "序号");
head.put("param2", "商品名");
head.put("param3", "单价");
data.put("head", head);
data.put("flag", "true"); //"True" video broadcast; false play from the beginning
JSONArray list = new JSONArray();
for (int i = 1; i < 11; i++) {
JSONObject listItem = new JSONObject();
listItem.put("param1", "" + i);
listItem.put("param2", products.get(i - 1));
listItem.put("param3", prices.get(i - 1));
list.put(listItem);
}
data.put("list", list);
JSONArray KVPList = new JSONArray();
JSONObject KVPListOne = new JSONObject();
KVPListOne.put("name", "总计 ");
KVPListOne.put("value", "132.00");
JSONObject KVPListTwo = new JSONObject();
KVPListTwo.put("name", "优惠 ");
KVPListTwo.put("value", "12.00");
JSONObject KVPListThree = new JSONObject();
KVPListThree.put("name", "数量 ");
KVPListThree.put("value", "10");
JSONObject KVPListFour = new JSONObject();
KVPListFour.put("name", "应收 ");
KVPListFour.put("value", "120.00");
KVPList.put(0, KVPListOne);
KVPList.put(1, KVPListTwo);
KVPList.put(2, KVPListThree);
KVPList.put(3, KVPListFour);
data.put("KVPList", KVPList);
Log.d("HHHH", "onClick: ---------->" + data.toString());
String json = UPacketFactory.createJson(DataModel.MENUVIDEOS, data.toString());
mDSKernel.sendCMD(DSKernel.getDSDPackageName(), json, taskID, null);
} catch (JSONException e) {
e.printStackTrace();
}
}

3, determine the size of the secondary screen

The main screen application can determine the size of the vice screen by acquiring the vice screen Model value and output the business logic of the corresponding displaying content according to the size.

3.1, Access to the sub-screen Model value from Main model

String subModel = Settings.Global.getString(getContentResolver(), "sunmi_sub_model")

//Return value: "t1sub14" corresponds to 14 inch vice screen, "t1sub7" corresponds to 7 inch vice screen. Returning other values indicates that the acquisition failed.

3.2, Access the Vice-screen Model value from vice screen

//Obtain secondary screen model from secondary screen
case R.id.btn_get_sub_model:
JSONObject jsonObject2 = new JSONObject();
try {
jsonObject2.put("dataModel", "GET_MODEL");
jsonObject2.put("data", "");
} catch (JSONException e) {
e.printStackTrace();
}

DataPacket p2 = new DataPacket.Builder(DSData.DataType.CMD).recPackName(SF.SUNMI_DSD_PACKNAME).data(jsonObject2.toString())
.addCallback(new ISendCallback() {
@Override
public void onSendSuccess(long taskId) {
} 

@Override 
public void onSendFail(int errorId, String errorInfo) { } 

@Override
public void onSendProcess(long totle, long sended) { }
}).build();

mDSKernel.sendQuery(p2, new QueryCallback() { 
@Override 
public void onReceiveData(final DSData data) { Log.d("highsixty", "onReceiveData: ------------>" + data.data); runOnUiThread(new Runnable() { 
@Override 
public void run() { 
Toast.makeText(MainActivity.this, "从副屏获取副屏model-->" + data.data, Toast.LENGTH_LONG).show(); 
}
});
}
}); 
break;
//Return value: "t1sub14" corresponds to 14 inch vice screen, "t1sub7" corresponds to 7 inch vice screen. Returning other values indicates that the acquisition failed.

4, clear the vice screen cache

4.1, Query specified cache directory size of the vice screen

JSONObject jsonObject = new JSONObject();
try {
jsonObject.put("dataModel", "GETVICECACHEFILESIZE");
jsonObject.put("data", Environment.getExternalStorageDirectory().getAbsolutePath() + "/HCService/" + getPackageName().replace(".", "_"));
} catch (JSONException e) {
e.printStackTrace();
}

DataPacket packet = new DataPacket.Builder(DSData.DataType.CMD).recPackName(SF.SUNMI_DSD_PACKNAME).data(jsonObject.toString())
.addCallback(null).build();
mDSKernel.sendQuery(packet, new QueryCallback() {
@Override
public void onReceiveData(final DSData data) {
Log.d("highsixty", "onReceiveData: ------------>" + data.data);
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "副屏缓存文件大小字节数为" + data.data, Toast.LENGTH_LONG).show();
}
});
}
});

4.2, clear designated cache directory of the vice screen

DataPacket packet2 = UPacketFactory.remove_folders(DSKernel.getDSDPackageName(), Environment.getExternalStorageDirectory().getAbsolutePath() + "/HCService/" + getPackageName().replace(".", "_"), new ISendCallback() {
@Override
public void onSendSuccess(long taskId) {
showToast("清除缓存文件成功");
}

@Override
public void onSendFail(int errorId, String errorInfo) {
showToast("清除缓存文件失败");
}

@Override
public void onSendProcess(long totle, long sended) {
}
});

mDSKernel.sendCMD(packet2);

4.3, check the exists of specified cache file 

To avoid sending duplicate multimedia files, developers are advised to check whether the multimedia file has been cached by calling DSKernel.checkFileExist (long fileId, final ICheckFileCallback callback) before sending the multimedia file. If it is already cached, it can be played directly by specifying file ID .

//Note: This method checks fileId corresponding file exists in the vice screen, The first parameter is the file id returned by the vice screen before sending the file, which is unique for all files, and the second parameter is the result callback

mDSKernel.checkFileExist(fileId, new ICheckFileCallback(){
@Override
public void onCheckFail() {}

@Override
public void onResult(boolean arg0) {
//The return value is true
//The return value false does not exist
} 
});

4.4, clear the vice screen specific cache file

mDSKernel.deleteFileExist(FileID, new ICheckFileCallback() {
@Override
public void onCheckFail() {
Log.d(TAG, "onCheckFail: ----------->");
}

@Override
public void onResult(boolean exist) {
Log.d(TAG, "onResult: ---------->" + exist);
}
});

5, picture / video displaying rules

Picture / video scaling rules:

    By default, the image / video is scaled with at least two edges touching the display container boundary.

Picture / video recommended resolution:

    7 inch:

            Full screen image: 1024 * 600

            Full screen video: 1024 * 600

    14 inch:

            Full-screen display image / video: 1920 * 1080

            Image / Video + List: 1186 * 1080

Recommended file size:

    Picture: ≤1MB / sheet

    Video: ≤5MB / month

Recommended number of slide files:

    Picture: ≤10 sheets

Recommended number of carousel video files:

    Video: ≤10

Note: Due to the time required to transfer the file to the vice screen, there may be a delay in displaying files. So try to cache the pictures and video files to the vice screen in advance when it is idle, and when it needs to be displayed on the vice screen, it is called according to the file ID.