1 /* <lambda>null2 * Copyright (C) 2024 The Android Open Source Project 3 * Copyright (C) 2024 Mopria Alliance, Inc. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package com.android.bips.ui 19 20 import android.graphics.Bitmap 21 import android.graphics.BitmapFactory 22 import android.net.SSLCertificateSocketFactory 23 import android.net.TrafficStats 24 import android.net.Uri 25 import android.util.Log 26 import androidx.lifecycle.LiveData 27 import androidx.lifecycle.MutableLiveData 28 import androidx.lifecycle.ViewModel 29 import androidx.lifecycle.viewModelScope 30 import com.android.bips.BuiltInPrintService 31 import com.android.bips.jni.JobCallbackParams 32 import com.android.bips.jni.LocalPrinterCapabilities 33 import com.android.bips.jni.PrinterStatusMonitor 34 import kotlinx.coroutines.Dispatchers 35 import kotlinx.coroutines.launch 36 import java.io.IOException 37 import java.net.HttpURLConnection 38 import java.net.URL 39 import javax.net.ssl.HostnameVerifier 40 import javax.net.ssl.HttpsURLConnection 41 42 /** 43 * Printer Information ViewModel 44 */ 45 class PrinterInformationViewModel : ViewModel() { 46 companion object { 47 private const val TAG = "PrinterInformationViewModel" 48 private const val DEBUG = false 49 } 50 private val HTTPS = "https" 51 private val HTTP = "http" 52 53 /** Printer capabilities live data */ 54 private val printerCapsLiveData = MutableLiveData<LocalPrinterCapabilities>() 55 56 /** Printer status live data */ 57 private val printerStatusLiveData = MutableLiveData<JobCallbackParams>() 58 private val printerUnavailableLiveData = MutableLiveData<Boolean>() 59 private val printerBitmapLiveData = MutableLiveData<Bitmap>() 60 61 private lateinit var printerStatusMonitor: PrinterStatusMonitor 62 63 fun getPrinterCapsLiveData(): LiveData<LocalPrinterCapabilities> { 64 return printerCapsLiveData 65 } 66 67 fun setPrinterCapsLiveData(localPrinterCapabilities: LocalPrinterCapabilities) { 68 printerCapsLiveData.value = localPrinterCapabilities 69 } 70 71 fun getPrinterStatusLiveData(): LiveData<JobCallbackParams> { 72 return printerStatusLiveData 73 } 74 75 fun getPrinterUnavailableLiveData(): LiveData<Boolean> { 76 return printerUnavailableLiveData 77 } 78 79 fun setPrinterUnavailableLiveData(status: Boolean) { 80 printerUnavailableLiveData.value = status 81 } 82 83 fun getPrinterBitmapLiveData(): LiveData<Bitmap> { 84 return printerBitmapLiveData 85 } 86 87 fun getBitmap(iconUri: String) { 88 viewModelScope.launch(Dispatchers.IO) { 89 TrafficStats.setThreadStatsTag(0xF00D) 90 var con: HttpURLConnection? = null 91 try { 92 if (DEBUG) Log.d(TAG, "Fetching icon from $iconUri") 93 val url = URL(iconUri) 94 val protocol = url.protocol 95 if (protocol.equals(HTTPS, ignoreCase = true)) { 96 con = url.openConnection() as HttpsURLConnection 97 (con as HttpsURLConnection?)?.sslSocketFactory = 98 SSLCertificateSocketFactory.getInsecure(0, null) 99 (con as HttpsURLConnection?)?.hostnameVerifier = 100 HostnameVerifier { s, sslSession -> true } 101 } else if (protocol.equals(HTTP, ignoreCase = true)) { 102 con = url.openConnection() as HttpURLConnection 103 } else { 104 printerBitmapLiveData.postValue(null) 105 } 106 con?.doInput = true 107 con?.connect() 108 if (DEBUG) Log.d(TAG, "Connected with " + con?.responseCode?.toString()) 109 if (con?.responseCode == HttpURLConnection.HTTP_OK) { 110 con.inputStream.use { `in` -> 111 printerBitmapLiveData.postValue(BitmapFactory.decodeStream(`in`)) 112 } 113 } 114 } catch (e: IllegalStateException) { 115 if (DEBUG) Log.e(TAG, "Failed to download printer icon $e") 116 } catch (e: IOException) { 117 if (DEBUG) Log.e(TAG, "Failed to download printer icon $e") 118 } finally { 119 con?.disconnect() 120 TrafficStats.clearThreadStatsTag() 121 } 122 } 123 } 124 125 fun getPrinterStatus(uri: Uri, printService: BuiltInPrintService) { 126 viewModelScope.launch(Dispatchers.IO) { 127 printerStatusMonitor = PrinterStatusMonitor(uri, printService, ::onPrinterStatus) 128 } 129 } 130 131 fun stopPrinterStatusMonitor(printService: BuiltInPrintService) { 132 if (::printerStatusMonitor.isInitialized) { 133 printerStatusMonitor.stopMonitor(printService) 134 } 135 } 136 137 private fun onPrinterStatus(status: JobCallbackParams?) { 138 printerStatusLiveData.postValue(status) 139 } 140 }