1c36cf2e9Sopenharmony_ci/*
2c36cf2e9Sopenharmony_ci * Copyright (c) 2023-2023 Huawei Device Co., Ltd.
3c36cf2e9Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4c36cf2e9Sopenharmony_ci * you may not use this file except in compliance with the License.
5c36cf2e9Sopenharmony_ci * You may obtain a copy of the License at
6c36cf2e9Sopenharmony_ci *
7c36cf2e9Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8c36cf2e9Sopenharmony_ci *
9c36cf2e9Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10c36cf2e9Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11c36cf2e9Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12c36cf2e9Sopenharmony_ci * See the License for the specific language governing permissions and
13c36cf2e9Sopenharmony_ci * limitations under the License.
14c36cf2e9Sopenharmony_ci */
15c36cf2e9Sopenharmony_ci
16c36cf2e9Sopenharmony_ciimport wifi from '@ohos.wifi';
17c36cf2e9Sopenharmony_ciimport P2PUtils from './utils/P2pUtils';
18c36cf2e9Sopenharmony_ciimport CheckEmptyUtils, { Log, PrinterCapability, PrinterInfo, IPP_CONNECT_ERROR } from '@ohos/common';
19c36cf2e9Sopenharmony_ciimport type { PrintServiceAdapter } from './PrintServiceAdapter';
20c36cf2e9Sopenharmony_ciimport type { LocalDiscoverySession } from './LocalDiscoverySession';
21c36cf2e9Sopenharmony_ciimport type DiscoveredPrinter from './discovery/DiscoveredPrinter';
22c36cf2e9Sopenharmony_ciimport LocalPrinterCapabilities from './napi/LocalPrinterCapabilities';
23c36cf2e9Sopenharmony_ciimport type ConnectionListener from './connect/ConnectionListener';
24c36cf2e9Sopenharmony_ciimport P2PPrinterConnection from './connect/P2pPrinterConnection';
25c36cf2e9Sopenharmony_ciimport type { CapabilitiesCache, OnLocalPrinterCapabilities } from './ipp/CapabilitiesCache';
26c36cf2e9Sopenharmony_ciimport print from '@ohos.print';
27c36cf2e9Sopenharmony_ci
28c36cf2e9Sopenharmony_ciconst TAG = 'LocalPrinter';
29c36cf2e9Sopenharmony_ci
30c36cf2e9Sopenharmony_ciexport default class LocalPrinter implements ConnectionListener, OnLocalPrinterCapabilities {
31c36cf2e9Sopenharmony_ci  private static readonly p2pDiscoveryProtocol: string = 'wifi_direct';
32c36cf2e9Sopenharmony_ci  private static readonly descriptionSplit: string = '&&';
33c36cf2e9Sopenharmony_ci  private static readonly maxRetryTimes: number = 2;
34c36cf2e9Sopenharmony_ci  private readonly mPrintServiceAdapter: PrintServiceAdapter;
35c36cf2e9Sopenharmony_ci  private readonly mSession: LocalDiscoverySession;
36c36cf2e9Sopenharmony_ci  private readonly mPrinterId: string; // number类型
37c36cf2e9Sopenharmony_ci
38c36cf2e9Sopenharmony_ci  private mTracking: boolean = false; //是否正在执行连接
39c36cf2e9Sopenharmony_ci  private mCapabilities: PrinterCapability;
40c36cf2e9Sopenharmony_ci  private mDiscoveredPrinter: DiscoveredPrinter;
41c36cf2e9Sopenharmony_ci  private mP2pPrinterConnection: P2PPrinterConnection;
42c36cf2e9Sopenharmony_ci  private getCapsFailedTimes: number = 0;
43c36cf2e9Sopenharmony_ci
44c36cf2e9Sopenharmony_ci  constructor(printServiceAdapter: PrintServiceAdapter, session: LocalDiscoverySession,
45c36cf2e9Sopenharmony_ci              discoveredPrinter: DiscoveredPrinter) {
46c36cf2e9Sopenharmony_ci    this.mPrintServiceAdapter = printServiceAdapter;
47c36cf2e9Sopenharmony_ci    this.mSession = session;
48c36cf2e9Sopenharmony_ci    this.mDiscoveredPrinter = discoveredPrinter;
49c36cf2e9Sopenharmony_ci    this.mPrinterId = discoveredPrinter.getId();
50c36cf2e9Sopenharmony_ci  }
51c36cf2e9Sopenharmony_ci
52c36cf2e9Sopenharmony_ci  /**
53c36cf2e9Sopenharmony_ci   * get capabilities
54c36cf2e9Sopenharmony_ci   *
55c36cf2e9Sopenharmony_ci   * @return Return capabilities or null if not present
56c36cf2e9Sopenharmony_ci   */
57c36cf2e9Sopenharmony_ci  getCapabilities(): void {
58c36cf2e9Sopenharmony_ci    if (CheckEmptyUtils.isEmpty(this.mDiscoveredPrinter)) {
59c36cf2e9Sopenharmony_ci      Log.error(TAG, 'discovery printer is undefined');
60c36cf2e9Sopenharmony_ci      return;
61c36cf2e9Sopenharmony_ci    }
62c36cf2e9Sopenharmony_ci    Log.info(TAG, 'caps is empty, now to request');
63c36cf2e9Sopenharmony_ci    let capabilitiesCache: CapabilitiesCache = this.mPrintServiceAdapter.capabilitiesCache;
64c36cf2e9Sopenharmony_ci    capabilitiesCache.requestCapabilities(this.mDiscoveredPrinter, this);
65c36cf2e9Sopenharmony_ci  }
66c36cf2e9Sopenharmony_ci
67c36cf2e9Sopenharmony_ci  /**
68c36cf2e9Sopenharmony_ci   * Create a PrinterInfo from this record or null if not possible
69c36cf2e9Sopenharmony_ci   *
70c36cf2e9Sopenharmony_ci   * @param knownGood boolean
71c36cf2e9Sopenharmony_ci   * @return PrinterInfo or null
72c36cf2e9Sopenharmony_ci   */
73c36cf2e9Sopenharmony_ci  createPrinterInfo(): PrinterInfo {
74c36cf2e9Sopenharmony_ci    //创建PrinterInfo对象 返回给打印框架
75c36cf2e9Sopenharmony_ci    let printerInfo: PrinterInfo = new PrinterInfo(this.mPrinterId, this.mDiscoveredPrinter.getDeviceName(), print.PrinterState.PRINTER_ADDED);
76c36cf2e9Sopenharmony_ci    if (!CheckEmptyUtils.isEmpty(this.mCapabilities)) {
77c36cf2e9Sopenharmony_ci      let printerCapability: PrinterCapability = new PrinterCapability();
78c36cf2e9Sopenharmony_ci      LocalPrinterCapabilities.buildPrinterCapability(printerCapability, this.mCapabilities);
79c36cf2e9Sopenharmony_ci      printerInfo.capability = printerCapability;
80c36cf2e9Sopenharmony_ci      printerInfo.description = LocalPrinter.p2pDiscoveryProtocol +
81c36cf2e9Sopenharmony_ci      LocalPrinter.descriptionSplit +
82c36cf2e9Sopenharmony_ci      this.mDiscoveredPrinter.getUri().host;
83c36cf2e9Sopenharmony_ci      let options: string = LocalPrinterCapabilities.buildExtraCaps(this.mCapabilities, this.mDiscoveredPrinter.getUri().toString());
84c36cf2e9Sopenharmony_ci      printerInfo.options = options;
85c36cf2e9Sopenharmony_ci    }
86c36cf2e9Sopenharmony_ci    return printerInfo;
87c36cf2e9Sopenharmony_ci  }
88c36cf2e9Sopenharmony_ci
89c36cf2e9Sopenharmony_ci
90c36cf2e9Sopenharmony_ci  /**
91c36cf2e9Sopenharmony_ci   * 开始连接打印机
92c36cf2e9Sopenharmony_ci   */
93c36cf2e9Sopenharmony_ci  public startTracking(): void {
94c36cf2e9Sopenharmony_ci    Log.debug(TAG, 'start connect to printer, track is: ' + this.mTracking);
95c36cf2e9Sopenharmony_ci    if (!P2PUtils.isP2p(this.mDiscoveredPrinter)) {
96c36cf2e9Sopenharmony_ci      Log.debug(TAG, 'mdns printer');
97c36cf2e9Sopenharmony_ci      this.getCapabilities();
98c36cf2e9Sopenharmony_ci      return;
99c36cf2e9Sopenharmony_ci    }
100c36cf2e9Sopenharmony_ci    if (this.mTracking) {
101c36cf2e9Sopenharmony_ci      Log.error(TAG, 'ERROR: isTracking: ' + this.mTracking);
102c36cf2e9Sopenharmony_ci      return;
103c36cf2e9Sopenharmony_ci    }
104c36cf2e9Sopenharmony_ci    this.mTracking = true;
105c36cf2e9Sopenharmony_ci    Log.debug(TAG, 'p2p printer');
106c36cf2e9Sopenharmony_ci    if (!CheckEmptyUtils.isEmpty(this.mP2pPrinterConnection)) {
107c36cf2e9Sopenharmony_ci      Log.error(TAG, 'ERROR: connection in progress');
108c36cf2e9Sopenharmony_ci      this.mP2pPrinterConnection = undefined;
109c36cf2e9Sopenharmony_ci      return;
110c36cf2e9Sopenharmony_ci    }
111c36cf2e9Sopenharmony_ci    this.mSession.addConnectingId(<string> this.mDiscoveredPrinter.getId());
112c36cf2e9Sopenharmony_ci    this.mP2pPrinterConnection = new P2PPrinterConnection(this.mPrintServiceAdapter, this.mDiscoveredPrinter, this);
113c36cf2e9Sopenharmony_ci    this.mP2pPrinterConnection.connectToPeer();
114c36cf2e9Sopenharmony_ci  }
115c36cf2e9Sopenharmony_ci
116c36cf2e9Sopenharmony_ci  /**
117c36cf2e9Sopenharmony_ci   * 停止连接打印机
118c36cf2e9Sopenharmony_ci   */
119c36cf2e9Sopenharmony_ci  public stopTracking(): void {
120c36cf2e9Sopenharmony_ci    if (!P2PUtils.isP2p(this.mDiscoveredPrinter)) {
121c36cf2e9Sopenharmony_ci      Log.debug(TAG, 'mdns printer, no need stop tracking');
122c36cf2e9Sopenharmony_ci      return;
123c36cf2e9Sopenharmony_ci    }
124c36cf2e9Sopenharmony_ci    if (this.mP2pPrinterConnection !== undefined) {
125c36cf2e9Sopenharmony_ci      Log.info(TAG, 'printer is connecting, close');
126c36cf2e9Sopenharmony_ci      this.mSession.removeConnectedId(this.mPrinterId);
127c36cf2e9Sopenharmony_ci      this.mP2pPrinterConnection.close();
128c36cf2e9Sopenharmony_ci    } else {
129c36cf2e9Sopenharmony_ci      Log.info(TAG, 'mP2pPrinterConnection is undefined, remove p2p group');
130c36cf2e9Sopenharmony_ci      this.mPrintServiceAdapter.wifiModel.getP2pLinkInfo().then((linkInfo: wifi.WifiP2pLinkedInfo) => {
131c36cf2e9Sopenharmony_ci        if (linkInfo.connectState === wifi.P2pConnectState.CONNECTED) {
132c36cf2e9Sopenharmony_ci          this.mPrintServiceAdapter.wifiModel.disconnectToPrinter();
133c36cf2e9Sopenharmony_ci        } else {
134c36cf2e9Sopenharmony_ci          Log.info(TAG, 'p2p is not connected');
135c36cf2e9Sopenharmony_ci          this.mPrintServiceAdapter.wifiModel.stopConnection();
136c36cf2e9Sopenharmony_ci        }
137c36cf2e9Sopenharmony_ci      });
138c36cf2e9Sopenharmony_ci    }
139c36cf2e9Sopenharmony_ci    this.mP2pPrinterConnection = undefined;
140c36cf2e9Sopenharmony_ci    this.mTracking = false;
141c36cf2e9Sopenharmony_ci  }
142c36cf2e9Sopenharmony_ci
143c36cf2e9Sopenharmony_ci  /**
144c36cf2e9Sopenharmony_ci   * get printerId
145c36cf2e9Sopenharmony_ci   *
146c36cf2e9Sopenharmony_ci   * @return PrinterId
147c36cf2e9Sopenharmony_ci   */
148c36cf2e9Sopenharmony_ci  public getPrinterId(): string {
149c36cf2e9Sopenharmony_ci    return this.mPrinterId;
150c36cf2e9Sopenharmony_ci  }
151c36cf2e9Sopenharmony_ci
152c36cf2e9Sopenharmony_ci  public setDiscoveryPrinter(printer: DiscoveredPrinter): void {
153c36cf2e9Sopenharmony_ci    this.mDiscoveredPrinter = printer;
154c36cf2e9Sopenharmony_ci  }
155c36cf2e9Sopenharmony_ci
156c36cf2e9Sopenharmony_ci  public getDiscoveryPrinter(): DiscoveredPrinter {
157c36cf2e9Sopenharmony_ci    Log.debug(TAG, 'getDiscoveryPrinter: ' + this.mDiscoveredPrinter.toString());
158c36cf2e9Sopenharmony_ci    return this.mDiscoveredPrinter;
159c36cf2e9Sopenharmony_ci  }
160c36cf2e9Sopenharmony_ci
161c36cf2e9Sopenharmony_ci
162c36cf2e9Sopenharmony_ci  /**
163c36cf2e9Sopenharmony_ci   * 获取打印机能力成功的回调
164c36cf2e9Sopenharmony_ci   *
165c36cf2e9Sopenharmony_ci   * @param printerCaps
166c36cf2e9Sopenharmony_ci   */
167c36cf2e9Sopenharmony_ci  onCapabilities(printerCaps: PrinterCapability): void {
168c36cf2e9Sopenharmony_ci    if (!CheckEmptyUtils.isEmpty(printerCaps)) {
169c36cf2e9Sopenharmony_ci      this.mCapabilities = printerCaps;
170c36cf2e9Sopenharmony_ci      this.getCapsFailedTimes = 0;
171c36cf2e9Sopenharmony_ci      // 上报打印机获取能力成功的回调
172c36cf2e9Sopenharmony_ci      let printerInfo: PrinterInfo = this.createPrinterInfo();
173c36cf2e9Sopenharmony_ci      print.updatePrinters([printerInfo]).catch((error) => {
174c36cf2e9Sopenharmony_ci        Log.error(TAG, 'update error: ' + JSON.stringify(error));
175c36cf2e9Sopenharmony_ci      });
176c36cf2e9Sopenharmony_ci    } else {
177c36cf2e9Sopenharmony_ci      if (this.getCapsFailedTimes < LocalPrinter.maxRetryTimes) {
178c36cf2e9Sopenharmony_ci        Log.error(TAG, `getCapabilities failed, retry ${this.getCapsFailedTimes} times`);
179c36cf2e9Sopenharmony_ci        this.getCapsFailedTimes++;
180c36cf2e9Sopenharmony_ci        this.getCapabilities();
181c36cf2e9Sopenharmony_ci      } else {
182c36cf2e9Sopenharmony_ci        Log.error(TAG, 'printerCaps is null');
183c36cf2e9Sopenharmony_ci        this.getCapsFailedTimes = 0;
184c36cf2e9Sopenharmony_ci        print.updateExtensionInfo(JSON.stringify(IPP_CONNECT_ERROR));
185c36cf2e9Sopenharmony_ci      }
186c36cf2e9Sopenharmony_ci    }
187c36cf2e9Sopenharmony_ci  }
188c36cf2e9Sopenharmony_ci
189c36cf2e9Sopenharmony_ci
190c36cf2e9Sopenharmony_ci  /**
191c36cf2e9Sopenharmony_ci   * 打印机连接成功回调
192c36cf2e9Sopenharmony_ci   * @param printer
193c36cf2e9Sopenharmony_ci   */
194c36cf2e9Sopenharmony_ci  onConnectionComplete(printer: DiscoveredPrinter): void {
195c36cf2e9Sopenharmony_ci    this.mTracking = false;
196c36cf2e9Sopenharmony_ci    this.mP2pPrinterConnection = undefined;
197c36cf2e9Sopenharmony_ci    if (CheckEmptyUtils.isEmpty(printer)) {
198c36cf2e9Sopenharmony_ci      Log.error(TAG, 'connect failed');
199c36cf2e9Sopenharmony_ci      return;
200c36cf2e9Sopenharmony_ci    }
201c36cf2e9Sopenharmony_ci    this.mDiscoveredPrinter = printer;
202c36cf2e9Sopenharmony_ci    this.mSession.updateLocalPrinter(printer);
203c36cf2e9Sopenharmony_ci    // 上报打印机机连接成功的状态
204c36cf2e9Sopenharmony_ci    // @ts-ignore
205c36cf2e9Sopenharmony_ci    print.updatePrinterState(this.mPrinterId, PrinterState.PRINTER_CONNECTED);
206c36cf2e9Sopenharmony_ci    this.mSession.removeConnectedId(this.mPrinterId);
207c36cf2e9Sopenharmony_ci
208c36cf2e9Sopenharmony_ci    //连接成功获取打印机能力
209c36cf2e9Sopenharmony_ci    if (CheckEmptyUtils.isEmpty(this.mCapabilities)) {
210c36cf2e9Sopenharmony_ci      this.getCapabilities();
211c36cf2e9Sopenharmony_ci    } else {
212c36cf2e9Sopenharmony_ci      this.onCapabilities(this.mCapabilities);
213c36cf2e9Sopenharmony_ci    }
214c36cf2e9Sopenharmony_ci  }
215c36cf2e9Sopenharmony_ci
216c36cf2e9Sopenharmony_ci  /**
217c36cf2e9Sopenharmony_ci   * 打印机连接超时回调
218c36cf2e9Sopenharmony_ci   * @param delayed
219c36cf2e9Sopenharmony_ci   */
220c36cf2e9Sopenharmony_ci  onConnectionDelayed(): void {
221c36cf2e9Sopenharmony_ci    this.mTracking = false;
222c36cf2e9Sopenharmony_ci    this.mP2pPrinterConnection = undefined;
223c36cf2e9Sopenharmony_ci    // 通知打印框架连接失败
224c36cf2e9Sopenharmony_ci    Log.error(TAG, 'connect delay');
225c36cf2e9Sopenharmony_ci    print.updatePrinterState(this.mPrinterId, print.PrinterState.PRINTER_DISCONNECTED);
226c36cf2e9Sopenharmony_ci    this.mSession.removeConnectedId(this.mPrinterId);
227c36cf2e9Sopenharmony_ci  }
228c36cf2e9Sopenharmony_ci}