商米收银管家 TEST 隐藏

商米收银管家 TEST 隐藏商米收银管家 TEST 隐藏商米收银管家 TEST 隐藏

CodeID

Number Code Type CodeID Zebra CodeID Newland CodeID Fp/NL  Notice   Example  
1 Code128 D j j Newland,Fp/NL:
AIM-128 — f
SETTING 128 — t
     
2 UCC·EAN128(GS1-128)   j u        
3 ISBT 128 D j  j  Zebra:
ISBT 128 Concatenated — D
     
4 EAN8 A d g        
5 EAN13 A d d        
6 UPC-E A c h        
7 UPC-E1 A            
8 UPC-A A c c   Instruction
9 Interleaved 2 of 5(ITF) F e e Newland,:
ITF-6 —  e
ITF-14 — e 
Fp/NL:
ITF-6 —  r
ITF-14 — q
Head noun Paraphrase Scanner ID
10 Matrix 2 of 5 S v v   Nls NewLand (EM2096) ]N
11 Code39 B b b Zebra:
Trioptic Code 39 — M 
Zebra Zebra (4710) ]Z
12 Codabar C a a   Fp(Falcon) Falcon(BSM1825) ]FN
13 Code93 E i y   NL NewLand(EM1365) ]FN
14 GS1 DataBar(RSS) R R R        
15 Composite-UCC T     Zebra:
MiroQRTCIF Linked Code 39(TLC 39) — T 
     
16 Composite-UPC              
17 Code11 H H z        
18 ISBN(Bookland EAN) L B B   Return: Scanner ID+Code ID  
19 Industrial 2 of 5   D i        
20 Standard 2 of 5   s s   Example:
scanner:Zebra 
code content:123456 
code type:code 128

return:]ZD123456

21 Discrete 2 of 5(DTF) G            
22 Chinese 2 of 5 U            
23 Korea 3 of 5 V            
24 Plessey   p p Newland:
UK Plessey — p
     
25 MIS-Plessey J m m        
26 Composite A/B              
27 Composite C              
28 ISSN EAN X n n        
29 PDF417 X r          
30 QR Code P01 Q          
31 Aztec z            
32 DataMatrix P00 u          
33 HanXin P0H h          
34 MaxiCode P02            
35 AustralinPostal P08            
36 US Postnet P03            
37 US Planet P04            
38 Uk Postal P06            
39 Japan Postal P05            
40 Deutsche 12   l l        
41 Deutsche 14   w w        
42 Code32 B b b         
43 Netherlands KIX Code P08            
44 USPS 4CB/One Code/Intelligent Mail P0A            
45 UPU FICS Postal P0B            
46 Signature Capture P0X            
47 Coupon Code N            

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:debug the
device

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

operation instructions: debugging description

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

T1 Debugging Descriptions


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

7397593677815748

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



USB device

Instructions Document for USB Serial Device

1.Introduction:

To meet the business demands of different customers, Sunmi T1 provides universal communication interfaces such as LAN port, cash box port, 5 usb2.0 ports, serial port, headphone jack, etc.

This text mainly introduces the usage method of cash box port, usb port and serial port.

2.1. Port descriptions:

1)1) Cash box port:

Sunmi T1 cash box port uses RJ12 port. The developer can control the cash box by sending data to the cash box port.

Cash box developer document and resource file

2)Serial port:

Sunmi T1 serial port uses RJ11 port. The developer can control the peripherals by sending data via serial port. For safety, T1 doesn’t support serial port node traversal, but you can directly open the port for communication (the node path of the serial port at the device base /dev/ttyHSL1)

demo source code of the serial port 

Example of communication document: communication document for Jaynes serial port electronic scale (as for different electronic scale communication protocol, it is required to refer to the documents provided by each manufacturer)  

3)USB port:

Sunmi T1 supports USB devices with USB2.0 protocol.

Developer document for USB communication

3.1.) Obtain PID/VID of USB device:

Method 1: java code

try {

Process p=Runtime.getRuntime().exec("cat /proc/bus/input/devices");
BufferedReader in = new BufferedReader(new
InputStreamReader(p.getInputStream()));
String line = null;
while((line = in.readLine())!= null){
}
String deviceInfo = line.trim();

} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}

Method 2: adb command

adb shell cat /proc/bus/input/devices

图片 1

3.2.)Universal USB peripherals

  • HID device

Sunmi supports by default HID protocol devices (mouse, keyboard, code scanning gun, etc.), which can plug and play.

HID code scanning gun

HID code scanning gun can plug and play: connect Sunmi device, open an editable box on it and obtain the 

focal point, carry out code scanning. At this time, bar code or QR code content should be entered into this editable box. As for obtaining code scanning content from the code, you may refer to Google developer document for USB peripherals communication

  • U disk 

The supported U disk format:

FAT32: readable & writable; NTFS: readable but not writable; exFAT: not supported

  • Camera

 Sunmi supports USB UVC camera

Demo source code of the development package

Github source code address

EF90DAE9-C61C-4FDE-A280-479AAC985B26

 Sunmi reader-writer

 Sunmi card reader can be accessed to the sidebar (slot reader interface)

Sunmi card reader contains two parts. One part is magnetic strip card, for which you may refer to Sunmi card reader development package & card reader demo. The other part is nfc, which is android native interface, and you may refer to android nfc development document for it.  

Sunmi card reader development package

Sunmi card reader demo

Source code of Sunmi card reader demo

  • Third party universal reader-writer

Currently, Sunmi has already supported four types of third party usb universal reader-writer. The developer may refer to demo provided by Sunmi to carry out the operation of reading and writing the card.

1. UM 002 card reader of Esystech

2. T10 reader-writer of Shenzhen Deka Technology (it is required to support android version, power supply charging version)

3. ACR1281U-C1 reader-writer of Advanced Card Systems Ltd.

4. ACR1281U-K1 reader-writer of Advanced Card Systems Ltd.

Development document 2.0

demo of universal reader-writer

 

demo source code of universal reader-writer

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


                    

                                                           Development of T1 Customized Second Display Program

[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.

<receiver android:name="sunmi.ds.MsgReceiver">
    <intent-filter>
        <action android:name="com.sunmi.hcservice" />
        <action android:name="com.sunmi.hcservice.status" />
    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.

Scan code driver


      Sunmi Code Scanning Driver

Why to apply the code scanning driver
encapsulated by Sunmi

 

Sunmi has provided the code scanning driver
matching its own devices. Compared to the currently applied open source
solution, Sunmi code scanning driver has the following five advantages

1.      
High recognition rate. Through a
lot of tests simulating real scenarios, Sunmi code

scanning driver has increased by 74% in
average in terms of code scanning recognition rate compared to the commonly
used code scanning solution based on ZXing open source project.

2.      
Compared to ZXing solution, it
has increased by above 100% in terms of code scanning

speed of 1 D code.

3.      
Simpler usage mode. You can add
code scanning function in your own project just by use

of five lines of code.

4.      
Up to 15 types of code to
support scanning. More code types will be added subsequently.

5.      
It perfectly matches the Sunmi
devices. The combination of software with hardware can

ensure highly efficient & stable
functions.

 

 

How to use Sunmi code scanning driver

 

There are two methods available for the
developers to use Sunmi code scanning driver

1.      
The developer’s App invokes the
code scanning module integrated by Sunmi system to

complete code scanning and obtains the
return value. This is a simple & easy to use method.

2.      
Write the camera interface by
himself/herself and invoke the code scanning driver

encapsulated by Sunmi to complete the
picture parse. This is a relatively complicated method, but it provides a
higher degree of freedom.

 

 

The first type of usage mode:

To reduce the development difficulty, Sunmi
set a built-in code scanning module in the newest SUNMI OS (V1 firmware version
187, M1 firmware version 37) system. The developer invokes Sunmi code scanning
module where it is necessary to invoke code scanning for the project via
startActivityForResult(), and then receives the return value of the code
scanning result in onActivityResult() method.

 

Receive the returned parameters of the code
scanning result in onActivityResult method. You may refer to the following
code:


    /**

    * 

    *Creating a Intent at where you want start scanner, calling the scanner by startActiityForResult();

    */

    Intent intent = new Intent("com.summi.scan");

    intent.setPackage("com.sunmi.sunmiqrcodescanner");

            

    /**

    * The method is the same function as above 

    *Intent intent = new Intent("com.summi.scan");

    *intent.setClassName("com.sunmi.sunmiqrcodescanner", "com.sunmi.sunmiqrcodescanner.activity.ScanActivity");

    */


    /**


    //there is also some options item about the scanner module, you can transfer parameters to control some settings, each item has a defaut status,transform parameter is not necessary,

    intent.putExtra("CURRENT_PPI", 0X0003);//The current preview resolution ,PPI_1920_1080 = 0X0001;PPI_1280_720 = 0X0002;PPI_BEST = 0X0003;

    intent.putExtra("PLAY_SOUND", true);// Prompt tone after scanning  ,default true

    intent.putExtra("PLAY_VIBRATE", false);//vibrate after scanning,default false,only support M1 right now.

    intent.putExtra("IDENTIFY_INVERSE_QR_CODE", true);//Whether to identify inverse code

    intent.putExtra("IDENTIFY_MORE_CODE", false);// Whether to identify several code,default false        

    intent.putExtra("IS_SHOW_SETTING", true);// Wether display set up button  at the top-right corner,default true

    intent.putExtra("IS_SHOW_ALBUM", true);// Wether display album,default true

    */

    startActivityForResult(intent, START_SCAN);


The second type of usage mode:

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
                if (requestCode == 1 && data != null) {
                        Bundle bundle = data.getExtras();
                        ArrayList> result = (ArrayList>) bundle
                                        .getSerializable("data");
                        
                        Iterator> it = result.iterator();

                        while (it.hasNext()) {
                                HashMap hashMap = it.next();
                                
                                Log.i("sunmi", hashMap.get("TYPE"));//this is the type of the code 
                                Log.i("sunmi", hashMap.get("VALUE"));//this is the result of the code 
                                
                        }

                }
                super.onActivityResult(requestCode, resultCode, data);
        }

In principle, the developer is required to realize
the basic knowledge of android customized camera before developing his/her own
code scanning function by directly applying Sunmi code scanning library. Please
download resource file to check code comments in it. The basic usage
method for Sunmi code scanning driver is explained based on SunmiScanDemo as
follows, and this Demo is an eclipse project.

 

1.      
Add four library files of libiconv.so,libscaninit.so,libsunmiscan.so and
sunmiscan.jar
according to the following hierarchy in
libs directory of the project.


project

2.      
Introduce header files &
decoding library into the code to handle business. You may refer

to DEMO.


import com.sunmi.scan.Config;
import com.sunmi.scan.Image; 
import com.sunmi.scan.ImageScanner; 
import com.sunmi.scan.Symbol;
import com.sunmi.scan.SymbolSet; 


3.      
Initialization and
configuration.

private ImageScanner scanner;// declare the scanner
scanner = new ImageScanner();// create a scanner
scanner.setConfig(0, Config.X_DENSITY, 2);// the interval time of line
scanner.setConfig(0, Config.Y_DENSITY, 2);//the interval time of raw
scanner.setConfig(0, Config.ENABLE_MULTILESYMS, 0);
//turn on the multiple parse in one picture, 0 means one , 1 means multiple
scanner.setConfig(0, Config.ENABLE_INVERSE, 0);// turn on the reserve color ?

scanner.setConfig( Symbol.QRCODE,Config.ENABLE, 1);//enable QR, 1:enable(default);0:disable

scanner.setConfig( Symbol.PDF417,Config.ENABLE, 1);//enable PDF417, 1:enable;0:disable(default)

scanner.setConfig(Symbol.DataMatrix, Config.ENABLE, 1);//enable DataMatrix, 1:enable;0:disable(default)

scanner.setConfig(Symbol.AZTEC, Config.ENABLE, 1);//enable AZTEC, 1:enable;0:disable(default)


4.      
Pass the image data and
decoding. The following code can be written in the method

PreviewCallback.onPreviewFrame(byte[] data,
Camera camera).

    /**

    creating image,width is the preview image's width and  height is the preview image's height,generally speaking,high generally speaking also means clearer image,but slower decoding speed.cause the decoding arithmetic need the the original data and the default format of the preview image is YCbCr_420_SP,you must transform the fromat, parameter "Y800" is the format of image what you want transform.

    */

    Image source = new Image(width, height, "Y800");


    /**

    *Set the scan area

    */

    Rect cropRect = finder_view.getScanImageRect(size.height, size.width);//finder_view is the custom widget of the demo

    source.setCrop(cropRect.top,cropRect.left,cropRect.height(),cropRect.width());


    /*filling the data, this is the source data of camera*/

    source.setData(data); 


    /*decoding ,return value 0 means failure,>0 means successful*/

    int result = scanner.scanImage(source); 



    Rect cropRect = finder_view.getScanImageRect(size.height, size.width);

    source.setCrop(cropRect.top,cropRect.left,cropRect.height(),cropRect.width());


    /*filling the data,this is the source data of camera*/

    source.setData(data); 


    /*decode,returned value 0 means failure,>0 means success*/

    int result = scanner.scanImage(source); 

5.      Obtain the decoding result and
the type of bar code.

    if (result != 0) {

             

        SymbolSet syms = scanner.getResults();

            for (Symbol sym : syms) {   

              Log.i("sunmi", "type:"+sym.getSymbolName());//code type,such as “EAN-8”

              Log.i("sunmi","result:"+sym.getResult())//getting the result

                

              }


    }

More descriptions

The code scanning types currently supported
by Sunmi code scanning driver include the following ones:
• 1 D code:
 EAN-8,
EAN-13, UPC-A, UPC-E, Codabar, Code39, Code93, Code128, ISBN10, ISBN13,
DataBar, DataBar Expanded, Interleaved 2 of 5
• QR code: QR Code,
PDF417

Printer driver

Sunmi Printer Driver

 

Introduction

 

Sunmi V1, P1, T1 all have their built-in thermal printers, to allow App to directly print out the thermal receipts. As for the built-in printers of Sunmi products, two specifications are available in total:

•        80 mm wide, with cutter. Compatible with 58 mm. H10, T1 has been equipped with this type of printer.

•        58 mm wide, without cutter. V1, V2 has been equipped with this type of printer.

 

How App invokes the built-in thermal printer

App developers can invoke the built-in thermal printer with 3 types of methods:

1.      To connect the printer via Bluetooth

2.      To connect the printer via AIDL

3.      To invoke the printer via JS bridge

 

Take V1 device as an example as follows to introduce two types of invoke methods. This solution is also applicable for P1, T1 device.

One. To connect and invoke via Bluetooth

You can see an already matched and everlasting Bluetooth device in V1’s Bluetooth device list—“InnerPrinter”, which is a printer device virtualized by the operating system and does not exist in reality. Yet its communication method is almost identical to that of an external Bluetooth printer. It is used to make it easy for the developers who have already been familiar with ESC/POS commands to adapt to V1. In this way, they can quickly transfer the print code to V1 without modifying the code.

 

Thus, you are suggested to use Bluetooth connection mode if the following conditions are met: the developer has already been familiar with ESC/POS commands, or even his/her owned App has already completed the development in terms of ESC/POS commands,or it is expected to keep the versatility of the printing method, not to highly depend on the features of Sunmi devices.

 

If you are still not familiar with ESC/POS commands, you can click here to  download “Instructions for ESC/POS Commands” to realize the command set supported by V1.

 

The principle of completing the print via connecting InnerPrinter virtual printer is:

1.       Establish connection with this Bluetooth device

2.       Splice the commands & text content and transcode them to Bytes

3.       Send it to InnerPrinter

4.       The bottom layer print service drives the printing device to complete printing

 

As for how to connect “InnerPrinter”, the developers can search online the Bluetooth connection related basic course. To make it easy for reading, the development code of Bluetooth device connection is described in brief as follows, for the convenience of getting started quickly.

The following is the printing effect of Bluetooth Demo App, click here to download Demo Apk & source code 

 

Among it, 5 key operations are included:

1.        Add Bluetooth Permissions Statement in App project

  
    
    
    

2.       Obtain BluetoothAdapter of Bluetooth device

  BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    if (mBluetoothAdapter == null && !mBluetoothAdapter.isEnabled()) {
       Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);  
       startActivityForResult(intent, REQUEST_ENABLE_BT);
    }

3.       Obtain Virtual Bluetooth device

 String innerprinter_address = "00:11:22:33:44:55";
    BluetoothDevice innerprinter_device = null;
    Set devices = mBluetoothAdapter.getBondedDevices();
    for(BluetoothDevice device : devices){
        if(device.getAddress().equals(innerprinter_address)){
              innerprinter_device = device;
         }
     }

4.       Obtain BluetoothSocket (Bluetooth socket)

 UUID PRINTER_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
   BluetoothSocket mSocket = 
   innerprinter_device.createRfcommSocketToServiceRecord(PRINTER_UUID);

5.       Send the print command Bytes that has already finished slicing to InnerPrinter via sendData (byte[]bytes) method

  OutputStream mOut = mSocket.getOutputStream();
   private void sendData(byte[] bytes) {
          if (mOut != null) {
              try {
                  mOut.write(bytes, 0, bytes.length);
                  mOut.flush();
              } catch (IOException e) {
                  Log.e("TAG", e.getMessage());
              } finally {
                 try {
                      mOut.close();
                  } catch (IOException e) { }
              }
          }
    }

The byte[]bytes parameter in the fifth key operation is the receipt content that is ready for printing, which is the content to be sliced with command Byte after the text has been converted to Byte via “GBK” code.

 

Each line of 58 mm printer contains 384 pixels. The default width of each Chinese character is 24 pixels while that of each English character is 12 pixels. Thus, 16 Chinese characters or 32 English characters can be printed out at maximum in one line, and automatic line wrap will be carried out after printing each line. You can certainly carry out mandatory line wrap by printing the character of “”.

The default height of each line is 30 pixels. You can control the font size by setting times of height & times of width with command, and control the text position of each line with alignment command.

 

Please refer to “Instructions for ESC/POS Commands” to know about more details of the control commands.

Note: the problem that several Apps initiate the print request at the same time may occur. We suggest that you’d better send the print data all at one time if you are going to print with Virtual Bluetooth.

 

 Two. Invoke the printer with AIDL

 Background

 

The inventor of receipt printer is EPSON, who also designed and defined the ESC/POS commands. It appeared before Android and had already been applied extensively in catering, retail industry before the popularization of Internet, with a history of above 15 years up to now

 

Therefore, the data processing method in the command is nearer to the bottom layer, and some developers that have experienced traditional software development may have their own encapsulation & accumulation at these command sets. However, to the emerging Internet developers, they’ll be loaded down with trivial details no matter it’s print text, picture or formatting, which require the investment of certain cost cycle to adapt to them.

 

Therefore, the V1 developers may also have built-in print service by use of AIDL connection of Android standard, and invoke the printer.

 

AIDL is the abbreviation for Android Interface Definition Language, which is a type of descriptive language for the communication interface of Android internal process. Through it, we can define the communication interface between processes. The developer may check the relevant online documentation for relevant instructions as for AIDL’s usage method.

Certainly, the developers may also temporarily skip the principles of AIDL, and quickly realize the invoke method via the short instructions & example code in the following text.

Course

 It is required to first download AIDL file & Demo, and the
compression document contains two parts of content:

 1.      Demo is the source code of print example project we prepare. The following effect is the receipt printed via Demo, T1.

2.      AIDL file is the interface method list exposed by all the print service, which is required to be integrated into its own App source code project.

 

The following is the interpretation of the concrete key operation invoking in Demo App:

 1.      Add AIDL file attached to the resource file to his/her own project:

(1)    Establish woyou.aidlservice.jiuiv package under src;

(2)    Add two files of IWoyouService.aidl, ICallback.aidl.

 

2.      Realize ServiceConnection in the code class to control the print.

 private ServiceConnection connService = new ServiceConnection() {
       @Override
        public void onServiceDisconnected(ComponentName name) {
                woyouService = null;
            }
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
                woyouService = IWoyouService.Stub.asInterface(service);
                setButtonEnable(true);
           }
        };  

3.      Invoke ApplicationContext.bindService(), and transfer in the realization of ServiceConnection.

 Note: bindservice is a non-blocking invoke, which means that the binding is not successfully done immediately after completing the invoke, and it must be subject to serviceConnected.

 Intent intent=new Intent(); 
 intent.setPackage("woyou.aidlservice.jiuiv5"); 
 intent.setAction("woyou.aidlservice.jiuiv5.IWoyouService"); 
 startService(intent); bindService(intent, connService, 
 Context.BIND_AUTO_CREATE);

4.      In the realization of ServiceConnection.onServiceConnected(), you will receive an IBinder example (Service to be invoked).  Invoke IWoyouService.Stub.asInterface(service) and convert the parameters to IWoyouService type.

 

5.      Now it’s OK to invoke various methods defined at IWoyouService interface to carry out printing. In this step, you’ll always detect RemoteException exception, which are thrown out when disconnected, and thus requiring to be processed here. It will only be thrown out by remote method. In the interface method, ICallback can transfer null. When disconnected, ApplicationContext.unbindService() in the interface example is invoked.

Methods of printing a variety of data and controlling the format are encapsulated in IWoyouService, for example:

 woyouService.printText("this is a text",callback); 
 woyouService.printTextWithFont("this is a text with font","",36,callback); 
 woyouService.setFontSize(24,callback); 
 woyouservice.printColumnsText("print a line of a table!",12,0,callback);

This interface also contains at the same time the method of printing
the data sliced by ESC/POS:

 woyouService.sendRAWData(bytes,callback);

Note: the problem that several Apps initiate the print request at the same time may occur. We suggest that you use transaction printing if you are going to print via AIDL.

Three. Invoke the printer via JS in HTML

To invoke the printer with JS is in essence to operate android native code in HTML via JS bridge to realize printing, that is, to realize printing via Bluetooth printing or AIDL method. We have prepared a Demo for the developers. In this Demo, you may invoke a method already written in java by clicking one button in HTML, and then invoke the printer with AIDL method to print out a piece of self-checking receipt.

 

Concrete invoking procedure as follows:

 

1.       Define the method to be used in android in HTML.

document.getElementsByTagName('a')[0].addEventListener('click', function(){
          
          var a = "wellcome to sunmi";
                  javascript:lee.funAndroid(a);   
          return false;
      }, false);      

2.      Initialization of WebView.

    WebView mWebView = (WebView) findViewById(R.id.wv_view);
    // 设置编码
    mWebView.getSettings().setDefaultTextEncodingName("utf-8");
    // 支持js
    mWebView.getSettings().setJavaScriptEnabled(true);
    mWebView.setWebChromeClient(new WebChromeClient());

    Initialization of print service

Intent intent = new Intent();
intent.setPackage("woyou.aidlservice.jiuiv5");
intent.setAction("woyou.aidlservice.jiuiv5.IWoyouService");
startService(intent);//Start printer service
bindService(intent, connService, Context.BIND_AUTO_CREATE);

3.      Add monitor for WebView, invoke WebView.addJavascriptInterface(new JsObject(), ‘lee’) in the callback method of onPageFinished; In JsObject class, define the operating method specified in HTML via @JavascriptInterface, and print out a piece of receipt by invoking AIDL printing mode in this method.

mWebView.setWebViewClient(new WebViewClientDemo());//添加一个页面相应监听类

class WebViewClientDemo extends WebViewClient {

     @Override
     public boolean shouldOverrideUrlLoading(WebView view, String url) {
        // 当打开新链接时,使用当前的 WebView,不会使用系统其他浏览器
         view.loadUrl(url);
         return true;
       }

      @Override
      public void onPageFinished(WebView view, String url) {
      super.onPageFinished(view, url);
         /**
          * 注册JavascriptInterface,其中"lee"的名字随便取,如果你用"lee",那么在html中只要用  lee.方法名()
          * 即可调用MyJavascriptInterface里的同名方法,参数也要一致
          */
           mWebView.addJavascriptInterface(new JsObject(), "lee");
                }

        }
        
        
        class JsObject {

                @JavascriptInterface
                public void funAndroid(final String i) {
                        Toast.makeText(getApplicationContext(), "calling the local method funAndroid by JS. " + i,
                        Toast.LENGTH_SHORT).show();
                                
                        try {
                                woyouService.printerSelfChecking(callback);//Using AIDL to print something. 
                        } catch (RemoteException e) {
                                e.printStackTrace();
                        }
                }
        }

4.       Load HTML file, and then it’s OK to print out a piece of receipt when clicking a button in HTML.

// 载入包含js的html
mWebView.loadData("", "text/html", null);
mWebView.loadUrl("file:///android_asset/test.html");//这里是您业务html所在的网页

 About invoking printer with jar package 

Due to the upgrade of our print service, the invoke of this method will no longer be compatible as for print service versions above 2.0.0. If you have already used this method for printing, we suggest that you judge whether it is greater than or equal to ‘2.0.0’ by obtaining the printer version number, so as to be compatible with print service with different versions. You may use the codes similar to those as follows:

   ... //绑定打印服务成功后得到一个IWoyouService类型的变量woyouService
    String version=woyouService.getServiceVersion(); //获取到打印服务的版本号
    if(version.compareTo("2.0.0")>=0){  //判断是否是新的打印服务
      ... //AIDL的方式调用打印服务
    }else{
      ... //依旧是通过jar包来调用打印服务
    }

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:

template 7寸 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.