• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.os.Bundle
21 import android.text.TextUtils
22 import android.util.Log
23 import android.view.LayoutInflater
24 import android.view.View
25 import android.view.ViewGroup
26 import android.widget.ImageView
27 import android.widget.ProgressBar
28 import android.widget.TextView
29 import androidx.constraintlayout.widget.ConstraintLayout
30 import androidx.fragment.app.Fragment
31 import androidx.fragment.app.FragmentActivity
32 import androidx.fragment.app.activityViewModels
33 import androidx.recyclerview.widget.LinearLayoutManager
34 import androidx.recyclerview.widget.RecyclerView
35 import com.android.bips.R
36 import com.android.bips.ipp.JobStatus
37 import com.android.bips.jni.BackendConstants
38 import com.android.bips.jni.LocalPrinterCapabilities
39 import com.android.bips.jni.MediaSizes
40 import java.util.*
41 
42 /**
43  * Printer information fragment
44  */
45 class PrinterInformationFragment : Fragment() {
46 
47     /** Printer Information view model */
48     private val printerInformationViewModel: Lazy<PrinterInformationViewModel> =
49         activityViewModels()
50     private val statusMapping = LinkedHashMap(JobStatus.getBlockReasonsMap())
51     private lateinit var printerName: TextView
52     private lateinit var printerIcon: ImageView
53     private lateinit var printerStatus: TextView
54     private lateinit var printerStatusLayout: ConstraintLayout
55     private lateinit var progressBarPrinterStatus: ProgressBar
56     private lateinit var mediaReady: TextView
57     private lateinit var mediaReadyLabel: TextView
58     private lateinit var inkLevelsRecyclerView: RecyclerView
59 
60     override fun onCreateView(
61         inflater: LayoutInflater,
62         container: ViewGroup?,
63         savedInstanceState: Bundle?
64     ): View {
65         return inflater.inflate(R.layout.printer_information,
66             container, false)
67     }
68 
69     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
70         printerName = view.findViewById(R.id.printerName)
71         printerIcon = view.findViewById(R.id.printerIcon)
72         printerStatus = view.findViewById(R.id.printerStatus)
73         printerStatusLayout = view.findViewById(R.id.printerStatusLayout)
74         progressBarPrinterStatus = view.findViewById(R.id.progressBarPrinterStatus)
75         mediaReady = view.findViewById(R.id.mediaReady)
76         mediaReadyLabel = view.findViewById(R.id.mediaReadyLabel)
77         inkLevelsRecyclerView = view.findViewById(R.id.inkLevelsRecyclerView)
78         super.onViewCreated(view, savedInstanceState)
79         statusMapping[BackendConstants.PRINTER_STATE_IDLE] = R.string.printer_ready
80         statusMapping[BackendConstants.PRINTER_STATE_RUNNING] = R.string.printer_state__printing
81         statusMapping[BackendConstants.PRINTER_STATE_UNABLE_TO_CONNECT] =
82             R.string.printer_state__offline
83         statusMapping[BackendConstants.PRINTER_STATE_BLOCKED] =
84             R.string.printer_state__check_printer
85 
86         activity?.apply {
87             setPrinterImage(this)
88             setPrinterStatus(this)
89             printerInformationViewModel.value.getPrinterCapsLiveData().observe(this) {
90                 it?.also { caps ->
91                     getIconBitmap(caps)
92                     setMediaReadySize(caps)
93                     setMarkerView(caps)
94                     view.visibility = View.VISIBLE
95                     printerName.text = caps.name
96                 } ?: run {
97                     view.visibility = View.GONE
98                 }
99             }
100         }
101     }
102 
103     private fun setMediaReadySize(caps: LocalPrinterCapabilities) {
104         var mediaReadyString = ""
105         caps.mediaReadySizes?.also { mediaReadySizes ->
106             if (mediaReadySizes.isEmpty()) {
107                 mediaReady.visibility = View.GONE
108                 mediaReadyLabel.visibility = View.GONE
109             }
110             for (i in mediaReadySizes) {
111                 mediaReadyString += MediaSizes.getInstance(context)
112                     .getMediaName(i, context) + "\n"
113             }
114             mediaReady.text = mediaReadyString.dropLast(1)
115         } ?: run {
116             mediaReady.visibility = View.GONE
117             mediaReadyLabel.visibility = View.GONE
118         }
119     }
120 
121     private fun getIconBitmap(caps: LocalPrinterCapabilities) {
122         caps.mPrinterIconUris?.also { iconUri ->
123             if (iconUri.isNotEmpty()) {
124                 printerInformationViewModel.value.getBitmap(iconUri.last())
125             }
126         }
127     }
128 
129     private fun setPrinterImage(fragmentActivity: FragmentActivity) {
130         printerInformationViewModel.value.getPrinterBitmapLiveData()
131             .observe(fragmentActivity) { printerImage ->
132                 if (printerImage != null) {
133                     printerIcon.visibility = View.VISIBLE
134                     printerIcon.setImageBitmap(printerImage)
135                 } else {
136                     printerIcon.visibility = View.GONE
137                 }
138             }
139     }
140 
141     /**
142      * Set Status Of Printer
143      */
144     private fun setPrinterStatus(fragmentActivity: FragmentActivity) {
145         printerInformationViewModel.value.getPrinterUnavailableLiveData()
146             .observe(fragmentActivity) {
147                 if (it) printerStatusLayout.visibility = View.GONE
148             }
149         printerInformationViewModel.value.getPrinterStatusLiveData()
150             .observe(fragmentActivity) { callbackParams ->
151                 callbackParams.apply {
152                     val reasonsList = blockedReasons?.toList() ?: emptyList()
153                     val statusList = getPrinterStatus(printerState, reasonsList)
154                     if (statusList.isEmpty()) {
155                         printerStatusLayout.visibility = View.GONE
156                     } else {
157                         if (DEBUG) {
158                             Log.e(TAG, "printer status list ${TextUtils.join("\n", statusList)}")
159                         }
160                         printerStatus.text = TextUtils.join("\n", statusList)
161                         printerStatusLayout.visibility = View.VISIBLE
162                         printerStatus.visibility = View.VISIBLE
163                         progressBarPrinterStatus.visibility = View.GONE
164                     }
165                 }
166             }
167     }
168 
169     /**
170      * Maps the printer state and reasons into a list of status strings
171      * If the printerReasons is not empty (printer is blocked), returns a list of (one or more)
172      * blocked reasons, otherwise it will be a one item list of printer state. May return an empty
173      * list if no resource id is found for the given status(es)
174      */
175     private fun getPrinterStatus(printerState: String, printerReasons: List<String>): Set<String> {
176         val resourceIds: MutableSet<String> = LinkedHashSet()
177         for (reason in printerReasons) {
178             if (TextUtils.isEmpty(reason) ||
179                 reason == BackendConstants.BLOCKED_REASON__SPOOL_AREA_FULL &&
180                 BackendConstants.PRINTER_STATE_BLOCKED != printerState
181             ) {
182                 continue
183             }
184             statusMapping[reason]?.also { resourceIds.add(getString(it)) }
185         }
186         if (resourceIds.isEmpty() || BackendConstants.PRINTER_STATE_RUNNING == printerState) {
187             statusMapping[printerState]?.also { resourceIds.add(getString(it)) }
188         }
189         return resourceIds
190     }
191 
192     /**
193      * Set marker view
194      * Fills supplies levels views based on capabilities
195      * @param view view
196      * @param caps the selected printer's capabilities
197      */
198     private fun setMarkerView(caps: LocalPrinterCapabilities) {
199         val mMarkerInfoList = ArrayList<MarkerInfo>()
200         for (i in caps.markerTypes.indices) {
201             if ((validTonerTypes.contains(caps.markerTypes[i]) ||
202                         validInkTypes.contains(caps.markerTypes[i])) && caps.markerLevel[i] >= 0
203             ) {
204                 caps.markerColors[i].split("#").apply {
205                     for (j in 1 until size) {
206                         mMarkerInfoList.add(
207                             MarkerInfo(
208                                 caps.markerTypes[i],
209                                 "#" + this[j],
210                                 caps.markerHighLevel[i],
211                                 caps.markerLowLevel[i],
212                                 caps.markerLevel[i]
213                             )
214                         )
215 
216                     }
217                 }
218             }
219         }
220         with(inkLevelsRecyclerView) {
221             this.layoutManager = LinearLayoutManager(activity)
222             this.adapter = MarkerAdapter(mMarkerInfoList)
223         }
224     }
225 
226     companion object {
227         private val validTonerTypes = listOf("toner", "toner-cartridge")
228         private val validInkTypes = listOf("ink", "inkCartridge", "ink-cartridge")
229         private const val TAG = "PrinterInformationFragment"
230         private const val DEBUG = false
231     }
232 }