1/*
2 * Copyright (c) 2023-2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import print from '@ohos.print';
17import commonEvent from '@ohos.commonEventManager';
18import {
19  AppCommonEvent,
20	AppStorageKeyName,
21	convertToPrinterInfo,
22  PrintErrorCode
23} from '@ohos/common';
24import AppStorageHelper from '../Common/Adapter/AppStorageHelper';
25import WifiP2pHelper from '../Common/Adapter/WifiP2pHelper';
26import { Log } from '@ohos/common';
27import { PrinterDiscModel } from '../Model/PrinterDiscModel';
28import emitter from '@ohos.events.emitter';
29import { StringUtil } from '@ohos/common';
30import { PrinterCapability, PrinterInfo } from '@ohos/common';
31
32const TAG = '[PrinterDiscController]:';
33
34/**
35 * PrinterDiscController
36 */
37export class PrinterDiscController {
38  private mPrinterDiscModel: PrinterDiscModel = new PrinterDiscModel();
39  private eventSubscriber = null;
40
41  /**
42   * create print Job
43   *
44   * @param jobId printJob id
45   * @return job state
46   */
47  public init(): void {
48    Log.info(TAG, 'PrinterDiscController init');
49    AppStorageHelper.createValue<Array<PrinterInfo>>(this.getModel().mPrinters, AppStorageKeyName.PRINTER_QUEUE_NAME);
50    this.registerPrinterCallback();
51    this.subscribeCommonEvent();
52  }
53
54  /**
55   * on destroy
56   */
57  public destroy(): void {
58    Log.info(TAG, 'PrinterDiscController destroy');
59    this.unregisterPrinterCallback();
60  }
61
62  /**
63   * start discovery
64   *
65   * @param jobId job id
66   * @param extensionList extension list
67   */
68  public startDiscovery(jobId: string, extensionList: Array<string>): void {
69    Log.info(TAG, 'startDiscovery, jobId = ' + JSON.stringify(jobId) + ', extensionList ' + JSON.stringify(extensionList));
70    this.mPrinterDiscModel.reset();
71    print.queryAllPrinterExtensionInfos().then((extensionInfos: object[]) => {
72      Log.info(TAG, 'queryExtensionAbilityInfos success : ' + JSON.stringify(extensionInfos));
73      print.startDiscoverPrinter(extensionList).then((data) => {
74        Log.info(TAG, 'start Discovery success data : ' + JSON.stringify(data));
75      }).catch((err) => {
76        Log.error(TAG, 'failed to start Discovery because : ' + JSON.stringify(err));
77      });
78    }).catch((error) => {
79      Log.error(TAG, 'start discovery fail because :' + JSON.stringify(error));
80    });
81  }
82
83  /**
84   * register printer callback
85   */
86  private registerPrinterCallback(): void {
87    Log.info(TAG, 'registerPrinterCallback');
88    print.on('printerStateChange', this.onPrinterStateChanged);
89  }
90
91  /**
92   * printer state change callback
93   *
94   * @param state printer state
95   * @param info printer info
96   */
97  private onPrinterStateChanged = (state: print.PrinterState, printerInfo: print.PrinterInfo): void => {
98    if (state === null || printerInfo === null) {
99      Log.error(TAG, 'printer state changed state is null or info is null');
100      return;
101    }
102
103    let info: PrinterInfo = convertToPrinterInfo(printerInfo);
104    Log.info(TAG, 'on printer state changed, state = ' + JSON.stringify(state) + ' ,info =' + info?.toString());
105    switch (state) {
106      case print.PrinterState.PRINTER_ADDED:
107        this.onPrinterFound(info);
108        break;
109      case print.PrinterState.PRINTER_REMOVED:
110        this.onPrinterOffline(info);
111        break;
112      case print.PrinterState.PRINTER_CAPABILITY_UPDATED:
113        this.onPrinterUpdateCapability(info);
114        break;
115      case print.PrinterState.PRINTER_CONNECTED:
116      case print.PrinterState.PRINTER_DISCONNECTED:
117      case print.PrinterState.PRINTER_RUNNING:
118        this.onPrinterStateChange(info);
119        break;
120      default:
121        break;
122    }
123  };
124
125  /**
126   * deal printer offline
127   *
128   * @param info printer info
129   */
130  private onPrinterOffline(info: print.PrinterInfo): void {
131    if (info === null) {
132      Log.error(TAG, 'onPrinterOffline for null info');
133      return;
134    }
135    Log.info(TAG, 'on printer offline, printer = ' + StringUtil.splitMac(<string> info.printerId));
136    this.mPrinterDiscModel.removePrinter(<string> info.printerId);
137  }
138
139  /**
140   * deal printer find
141   *
142   * @param info printer info
143   */
144  private onPrinterFound(info: PrinterInfo): void {
145    Log.info(TAG, 'enter onPrinterFound');
146    if (info === null) {
147      Log.error(TAG, 'onPrinterFound for null data');
148      return;
149    }
150    this.mPrinterDiscModel.addPrinter(info);
151    Log.info(TAG, 'foundPrinter = ' + StringUtil.encodeCommonString(info.printerName));
152  }
153
154  /**
155   * find printer
156   *
157   * @param printerId printerId
158   */
159  public findPrinter(printerId: string): boolean {
160    Log.debug(TAG, 'findPrinter = ' + StringUtil.splitMac(printerId));
161    let res: boolean = this.mPrinterDiscModel.findPrinter(printerId);
162    return res;
163  }
164
165  /**
166   * deal printer state change
167   *
168   * @param info printer info
169   */
170  private onPrinterStateChange(info: PrinterInfo): void {
171    if (info === null) {
172      Log.error(TAG, 'onPrinterStateChange for null data');
173      return;
174    }
175    Log.error(TAG, 'onPrinterStateChange, info = ' + info?.toString());
176    this.mPrinterDiscModel.printerStateChange(<string> info.printerId, <number> info.printerState);
177  }
178
179  /**
180   * deal printer capability update
181   *
182   * @param info printer info
183   */
184  private onPrinterUpdateCapability(info: PrinterInfo): void {
185    if (info === null) {
186      Log.error(TAG, 'onPrinterUpdateCapability for null data');
187      return;
188    }
189    Log.info(TAG, 'onPrinterUpdateCapability, info = ' + info?.toString());
190    this.mPrinterDiscModel.printerUpdateCapability(info.printerId, info.capability, info.options, info.description);
191  }
192
193  /**
194   * stop discovery
195   *
196   * @param jobId job id
197   */
198  public stopDiscovery(jobId: string): void {
199    Log.info(TAG, 'stopDiscovery');
200    print.stopDiscoverPrinter().then((data) => {
201      Log.info(TAG, 'stop Discovery success data : ' + JSON.stringify(data));
202    }).catch((err) => {
203      Log.error(TAG, 'failed to stop Discovery because ' + JSON.stringify(err));
204    });
205  }
206
207  /**
208   * register printer callback
209   */
210  private unregisterPrinterCallback(): void {
211    Log.info(TAG, 'unregisterPrinterCallback');
212    print.off('printerStateChange', (data) => {
213      console.info('off printerStateChange data : ' + JSON.stringify(data));
214    });
215  }
216
217  /**
218   * connect Printer
219   *
220   * @param printerId printer id
221   */
222  public connectPrinter(printer: PrinterInfo): void {
223    let printerId: string = printer.printerId;
224    Log.debug(TAG, 'connectPrinter printerId = ' + StringUtil.splitMac(printerId));
225    print.connectPrinter(printerId).then((data) => {
226      Log.debug(TAG, 'start connect Printer success data : ' + JSON.stringify(data));
227    }).catch((err) => {
228      Log.error(TAG, 'failed to connect Printer because ' + JSON.stringify(err));
229      if (err === PrintErrorCode.E_PRINT_INVALID_PRINTER) {
230        let innerEvent = {
231          eventId: AppCommonEvent.PRINTER_INVALID_EVENT,
232          priority: emitter.EventPriority.HIGH
233        };
234        let eventData = {
235          data: {
236            'printerId': printerId
237          }
238        };
239        emitter.emit(innerEvent, eventData);
240        Log.error(TAG, 'delete invalid printer printerId = ' + JSON.stringify(printerId));
241        this.mPrinterDiscModel.removePrinter(printerId);
242        this.startDiscovery('', []);
243      }
244    });
245  }
246
247  /**
248   * disconnect Printer
249   *
250   * @param printerId printer id
251   */
252  public async disconnectPrinter(printerId: string): Promise<void> {
253    Log.info(TAG, 'disconnectPrinter');
254    await print.disconnectPrinter(printerId).then((data) => {
255      Log.info(TAG, 'start disconnect Printer success data : ' + JSON.stringify(data));
256    }).catch((err) => {
257      Log.error(TAG, 'failed to disconnect Printer because ' + JSON.stringify(err));
258    });
259  }
260
261  /**
262   * query Printer Capability
263   *
264   * @param printerId printer id
265   * @return printer capability
266   */
267  public async queryPrinterCapability(printerId: string): Promise<void> {
268    Log.info(TAG, 'queryPrinterCapability');
269    print.queryPrinterCapability(printerId);
270  }
271
272  /**
273   * get model
274   *
275   * @return PrinterDiscModel
276   */
277  public getModel(): PrinterDiscModel {
278    return this.mPrinterDiscModel;
279  }
280
281  /**
282   * subscribe CommonEvent
283   */
284  public subscribeCommonEvent(): void {
285    Log.info(TAG, 'subscribeCommonEvent');
286    let subscribeInfo = {
287      events: [commonEvent.Support.COMMON_EVENT_WIFI_POWER_STATE],
288    };
289    commonEvent.createSubscriber(subscribeInfo).then((subscriber) => {
290      Log.info(TAG, 'start createSubscriber subscriber : ' + JSON.stringify(subscriber));
291      this.eventSubscriber = subscriber;
292      commonEvent.subscribe(this.eventSubscriber, (err, commonEventData) => {
293        Log.error(TAG, 'subscribe callback : ' + JSON.stringify(commonEventData));
294        if (commonEventData.event === commonEvent.Support.COMMON_EVENT_WIFI_POWER_STATE) {
295          if (!WifiP2pHelper.checkWifiActive()) {
296            Log.error(TAG, 'wifi inactive ');
297            this.mPrinterDiscModel.reset();
298            let innerEvent = {
299              eventId: AppCommonEvent.WLAN_INACTIVE_EVENT,
300              priority: emitter.EventPriority.HIGH
301            };
302            emitter.emit(innerEvent);
303          } else {
304            let innerEvent = {
305              eventId: AppCommonEvent.WLAN_ACTIVE_EVENT,
306              priority: emitter.EventPriority.HIGH
307            };
308            emitter.emit(innerEvent);
309          }
310        }
311      });
312    }).catch((err) => {
313      Log.error(TAG, 'failed createSubscriber because ' + JSON.stringify(err));
314    });
315  }
316}