comparison android/DWindows.kt @ 2502:b6319aed3298

Android: Massive thread safety overhaul. Not quite back to fully functional. WebView is having many complaints about not being on the UI thread... better to get this figured out early... All UI calls will be wrapped in a waitOnUiThread() closure. This is our version of Android's runOnUiThread() except it waits for the closure to finish running so we can return results... and also so that our calls will be in the order desired in the application.
author bsmith@81767d24-ef19-dc11-ae90-00e081727c95
date Thu, 06 May 2021 09:55:32 +0000
parents 41984ffb5ca2
children 1c2a79313b04
comparison
equal deleted inserted replaced
2501:41984ffb5ca2 2502:b6319aed3298
29 import androidx.viewpager2.widget.ViewPager2 29 import androidx.viewpager2.widget.ViewPager2
30 import com.google.android.material.tabs.TabLayout 30 import com.google.android.material.tabs.TabLayout
31 import com.google.android.material.tabs.TabLayout.OnTabSelectedListener 31 import com.google.android.material.tabs.TabLayout.OnTabSelectedListener
32 import com.google.android.material.tabs.TabLayoutMediator 32 import com.google.android.material.tabs.TabLayoutMediator
33 import java.util.* 33 import java.util.*
34 import java.util.concurrent.locks.Lock
35 import java.util.concurrent.locks.ReentrantLock
34 36
35 37
36 class DWTabViewPagerAdapter : RecyclerView.Adapter<DWTabViewPagerAdapter.DWEventViewHolder>() { 38 class DWTabViewPagerAdapter : RecyclerView.Adapter<DWTabViewPagerAdapter.DWEventViewHolder>() {
37 public val viewList = mutableListOf<LinearLayout>() 39 public val viewList = mutableListOf<LinearLayout>()
38 public val pageList = mutableListOf<Long>() 40 public val pageList = mutableListOf<Long>()
53 } 55 }
54 56
55 class DWindows : AppCompatActivity() { 57 class DWindows : AppCompatActivity() {
56 var firstWindow: Boolean = true 58 var firstWindow: Boolean = true
57 var windowLayout: LinearLayout? = null 59 var windowLayout: LinearLayout? = null
60 var threadLock = ReentrantLock()
61 var threadCond = threadLock.newCondition()
62
63 // Our version of runOnUiThread that waits for execution
64 fun waitOnUiThread(runnable: Runnable)
65 {
66 if(Looper.myLooper() == Looper.getMainLooper()) {
67 runnable.run()
68 } else {
69 threadLock.lock()
70 val ourRunnable = Runnable {
71 threadLock.lock()
72 runnable.run()
73 threadCond.signal()
74 threadLock.unlock()
75 }
76 runOnUiThread(ourRunnable)
77 threadCond.await()
78 threadLock.unlock()
79 }
80 }
58 81
59 // We only want to call this once when the app starts up 82 // We only want to call this once when the app starts up
60 // By default Android will call onCreate for rotation and other 83 // By default Android will call onCreate for rotation and other
61 // changes. This is incompatible with Dynamic Windows... 84 // changes. This is incompatible with Dynamic Windows...
62 // Make sure the following is in your AndroidManifest.xml 85 // Make sure the following is in your AndroidManifest.xml
94 * These are the Android calls to actually create the UI... 117 * These are the Android calls to actually create the UI...
95 * forwarded from the C Dynamic Windows API 118 * forwarded from the C Dynamic Windows API
96 */ 119 */
97 fun windowNew(title: String, style: Int): LinearLayout? { 120 fun windowNew(title: String, style: Int): LinearLayout? {
98 if (firstWindow) { 121 if (firstWindow) {
99 var dataArrayMap = SimpleArrayMap<String, Long>() 122 waitOnUiThread {
100 windowLayout = LinearLayout(this) 123 var dataArrayMap = SimpleArrayMap<String, Long>()
101 124 windowLayout = LinearLayout(this)
102 windowLayout!!.tag = dataArrayMap 125
103 setContentView(windowLayout) 126 windowLayout!!.tag = dataArrayMap
104 this.title = title 127 setContentView(windowLayout)
105 // For now we just return our DWindows' main activity layout... 128 this.title = title
106 // in the future, later calls should create new activities 129 // For now we just return our DWindows' main activity layout...
107 firstWindow = false 130 // in the future, later calls should create new activities
131 firstWindow = false
132 }
108 return windowLayout 133 return windowLayout
109 } 134 }
110 return null 135 return null
111 } 136 }
112 137
136 } 161 }
137 return retval 162 return retval
138 } 163 }
139 164
140 fun windowSetEnabled(window: View, state: Boolean) { 165 fun windowSetEnabled(window: View, state: Boolean) {
141 window.setEnabled(state) 166 waitOnUiThread {
167 window.setEnabled(state)
168 }
142 } 169 }
143 170
144 fun windowSetText(window: View, text: String) { 171 fun windowSetText(window: View, text: String) {
145 if (window is TextView) { 172 waitOnUiThread {
146 var textview: TextView = window 173 if (window is TextView) {
147 textview.text = text 174 var textview: TextView = window
148 } else if (window is Button) { 175 textview.text = text
149 var button: Button = window 176 } else if (window is Button) {
150 button.text = text 177 var button: Button = window
151 } else if (window is LinearLayout) { 178 button.text = text
152 // TODO: Make sure this is actually the top-level layout, not just a box 179 } else if (window is LinearLayout) {
153 this.title = text 180 // TODO: Make sure this is actually the top-level layout, not just a box
181 this.title = text
182 }
154 } 183 }
155 } 184 }
156 185
157 fun windowGetText(window: View): String? { 186 fun windowGetText(window: View): String? {
158 if (window is TextView) { 187 var text: String? = null
159 var textview: TextView = window 188
160 return textview.text.toString() 189 waitOnUiThread {
161 } else if (window is Button) { 190 if (window is TextView) {
162 var button: Button = window 191 var textview: TextView = window
163 return button.text.toString() 192 text = textview.text.toString()
164 } else if (window is LinearLayout) { 193 } else if (window is Button) {
165 // TODO: Make sure this is actually the top-level layout, not just a box 194 var button: Button = window
166 return this.title.toString() 195 text = button.text.toString()
167 } 196 } else if (window is LinearLayout) {
168 return null 197 // TODO: Make sure this is actually the top-level layout, not just a box
198 text = this.title.toString()
199 }
200 }
201 return text
169 } 202 }
170 203
171 fun clipboardGetText(): String { 204 fun clipboardGetText(): String {
172 var cm: ClipboardManager = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager 205 var cm: ClipboardManager = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
173 var clipdata = cm.primaryClip 206 var clipdata = cm.primaryClip
183 var clipdata = ClipData.newPlainText("text", text) 216 var clipdata = ClipData.newPlainText("text", text)
184 217
185 cm.setPrimaryClip(clipdata) 218 cm.setPrimaryClip(clipdata)
186 } 219 }
187 220
188 fun boxNew(type: Int, pad: Int): LinearLayout { 221 fun boxNew(type: Int, pad: Int): LinearLayout? {
189 val box = LinearLayout(this) 222 var box: LinearLayout? = null
190 var dataArrayMap = SimpleArrayMap<String, Long>() 223 waitOnUiThread {
191 224 box = LinearLayout(this)
192 box.tag = dataArrayMap 225 var dataArrayMap = SimpleArrayMap<String, Long>()
193 box.layoutParams = 226
227 box!!.tag = dataArrayMap
228 box!!.layoutParams =
194 LinearLayout.LayoutParams( 229 LinearLayout.LayoutParams(
195 LinearLayout.LayoutParams.WRAP_CONTENT, 230 LinearLayout.LayoutParams.WRAP_CONTENT,
196 LinearLayout.LayoutParams.WRAP_CONTENT 231 LinearLayout.LayoutParams.WRAP_CONTENT
197 ) 232 )
198 if (type > 0) { 233 if (type > 0) {
199 box.orientation = LinearLayout.VERTICAL 234 box!!.orientation = LinearLayout.VERTICAL
200 } else { 235 } else {
201 box.orientation = LinearLayout.HORIZONTAL 236 box!!.orientation = LinearLayout.HORIZONTAL
202 } 237 }
203 box.setPadding(pad, pad, pad, pad) 238 box!!.setPadding(pad, pad, pad, pad)
239 }
204 return box 240 return box
205 } 241 }
206 242
207 fun scrollBoxNew(type: Int, pad: Int) : ScrollView { 243 fun scrollBoxNew(type: Int, pad: Int) : ScrollView? {
208 val scrollBox = ScrollView(this) 244 var scrollBox: ScrollView? = null
209 val box = LinearLayout(this) 245
210 var dataArrayMap = SimpleArrayMap<String, Long>() 246 waitOnUiThread {
211 247 val box = LinearLayout(this)
212 scrollBox.tag = dataArrayMap 248 scrollBox = ScrollView(this)
213 box.layoutParams = 249 var dataArrayMap = SimpleArrayMap<String, Long>()
214 LinearLayout.LayoutParams( 250
215 LinearLayout.LayoutParams.MATCH_PARENT, 251 scrollBox!!.tag = dataArrayMap
216 LinearLayout.LayoutParams.MATCH_PARENT 252 box.layoutParams =
217 ) 253 LinearLayout.LayoutParams(
218 if (type > 0) { 254 LinearLayout.LayoutParams.MATCH_PARENT,
219 box.orientation = LinearLayout.VERTICAL 255 LinearLayout.LayoutParams.MATCH_PARENT
220 } else { 256 )
221 box.orientation = LinearLayout.HORIZONTAL 257 if (type > 0) {
222 } 258 box.orientation = LinearLayout.VERTICAL
223 box.setPadding(pad, pad, pad, pad) 259 } else {
224 // Add a pointer back to the ScrollView 260 box.orientation = LinearLayout.HORIZONTAL
225 box.tag = scrollBox 261 }
226 scrollBox.addView(box) 262 box.setPadding(pad, pad, pad, pad)
263 // Add a pointer back to the ScrollView
264 box.tag = scrollBox
265 scrollBox!!.addView(box)
266 }
227 return scrollBox 267 return scrollBox
228 } 268 }
229 269
230 fun boxPack( 270 fun boxPack(
231 boxview: View, 271 boxview: View,
235 height: Int, 275 height: Int,
236 hsize: Int, 276 hsize: Int,
237 vsize: Int, 277 vsize: Int,
238 pad: Int 278 pad: Int
239 ) { 279 ) {
240 var w: Int = LinearLayout.LayoutParams.WRAP_CONTENT 280 waitOnUiThread {
241 var h: Int = LinearLayout.LayoutParams.WRAP_CONTENT 281 var w: Int = LinearLayout.LayoutParams.WRAP_CONTENT
242 var box: LinearLayout? = null 282 var h: Int = LinearLayout.LayoutParams.WRAP_CONTENT
243 283 var box: LinearLayout? = null
244 // Handle scrollboxes by pulling the LinearLayout 284
245 // out of the ScrollView to pack into 285 // Handle scrollboxes by pulling the LinearLayout
246 if(boxview is LinearLayout) { 286 // out of the ScrollView to pack into
247 box = boxview as LinearLayout 287 if (boxview is LinearLayout) {
248 } else if(boxview is ScrollView) { 288 box = boxview as LinearLayout
249 var sv: ScrollView = boxview 289 } else if (boxview is ScrollView) {
250 290 var sv: ScrollView = boxview
251 if(sv.getChildAt(0) is LinearLayout) { 291
252 box = sv.getChildAt(0) as LinearLayout 292 if (sv.getChildAt(0) is LinearLayout) {
253 } 293 box = sv.getChildAt(0) as LinearLayout
254 } 294 }
255 295 }
256 if(box != null) { 296
257 if ((item is LinearLayout) or (item is ScrollView)) { 297 if (box != null) {
298 if ((item is LinearLayout) or (item is ScrollView)) {
299 if (box.orientation == LinearLayout.VERTICAL) {
300 if (hsize > 0) {
301 w = LinearLayout.LayoutParams.MATCH_PARENT
302 }
303 } else {
304 if (vsize > 0) {
305 h = LinearLayout.LayoutParams.MATCH_PARENT
306 }
307 }
308 }
309 var params: LinearLayout.LayoutParams = LinearLayout.LayoutParams(w, h)
310
311 if (item !is LinearLayout && (width != -1 || height != -1)) {
312 item.measure(0, 0)
313 if (width > 0) {
314 w = width
315 } else if (width == -1) {
316 w = item.getMeasuredWidth()
317 }
318 if (height > 0) {
319 h = height
320 } else if (height == -1) {
321 h = item.getMeasuredHeight()
322 }
323 }
258 if (box.orientation == LinearLayout.VERTICAL) { 324 if (box.orientation == LinearLayout.VERTICAL) {
259 if (hsize > 0) { 325 if (vsize > 0) {
260 w = LinearLayout.LayoutParams.MATCH_PARENT 326 if (w > 0) {
327 params.weight = w.toFloat()
328 } else {
329 params.weight = 1F
330 }
261 } 331 }
262 } else { 332 } else {
263 if (vsize > 0) { 333 if (hsize > 0) {
264 h = LinearLayout.LayoutParams.MATCH_PARENT 334 if (h > 0) {
335 params.weight = h.toFloat()
336 } else {
337 params.weight = 1F
338 }
265 } 339 }
266 } 340 }
267 } 341 if (pad > 0) {
268 var params: LinearLayout.LayoutParams = LinearLayout.LayoutParams(w, h) 342 params.setMargins(pad, pad, pad, pad)
269 343 }
270 if (item !is LinearLayout && (width != -1 || height != -1)) { 344 var grav: Int = Gravity.CLIP_HORIZONTAL or Gravity.CLIP_VERTICAL
271 item.measure(0, 0) 345 if (hsize > 0 && vsize > 0) {
272 if (width > 0) { 346 params.gravity = Gravity.FILL or grav
273 w = width 347 } else if (hsize > 0) {
274 } else if (width == -1) { 348 params.gravity = Gravity.FILL_HORIZONTAL or grav
275 w = item.getMeasuredWidth() 349 } else if (vsize > 0) {
276 } 350 params.gravity = Gravity.FILL_VERTICAL or grav
277 if (height > 0) { 351 }
278 h = height 352 item.layoutParams = params
279 } else if (height == -1) { 353 box.addView(item, index)
280 h = item.getMeasuredHeight() 354 }
281 } 355 }
282 } 356 }
283 if (box.orientation == LinearLayout.VERTICAL) { 357
284 if (vsize > 0) { 358 fun boxUnpack(item: View) {
285 if (w > 0) { 359 waitOnUiThread {
286 params.weight = w.toFloat() 360 var box: LinearLayout = item.parent as LinearLayout
287 } else { 361 box.removeView(item)
288 params.weight = 1F 362 }
289 } 363 }
290 } 364
365 fun boxUnpackAtIndex(box: LinearLayout, index: Int): View? {
366 var item: View? = null
367
368 waitOnUiThread {
369 item = box.getChildAt(index)
370
371 box.removeView(item)
372 }
373 return item
374 }
375
376 fun buttonNew(text: String, cid: Int): Button? {
377 var button: Button? = null
378 waitOnUiThread {
379 button = Button(this)
380 var dataArrayMap = SimpleArrayMap<String, Long>()
381
382 button!!.tag = dataArrayMap
383 button!!.text = text
384 button!!.id = cid
385 button!!.setOnClickListener {
386 eventHandlerSimple(button!!, 8)
387 }
388 }
389 return button
390 }
391
392 fun entryfieldNew(text: String, cid: Int, password: Int): EditText? {
393 var entryfield: EditText? = null
394
395 waitOnUiThread {
396 var dataArrayMap = SimpleArrayMap<String, Long>()
397 entryfield = EditText(this)
398
399 entryfield!!.tag = dataArrayMap
400 entryfield!!.id = cid
401 if (password > 0) {
402 entryfield!!.transformationMethod = PasswordTransformationMethod.getInstance()
403 }
404 entryfield!!.setText(text)
405 }
406 return entryfield
407 }
408
409 fun entryfieldSetLimit(entryfield: EditText, limit: Long) {
410 waitOnUiThread {
411 entryfield.filters = arrayOf<InputFilter>(LengthFilter(limit.toInt()))
412 }
413 }
414
415 fun radioButtonNew(text: String, cid: Int): RadioButton? {
416 var radiobutton: RadioButton? = null
417
418 waitOnUiThread {
419 var dataArrayMap = SimpleArrayMap<String, Long>()
420 radiobutton = RadioButton(this)
421
422 radiobutton!!.tag = dataArrayMap
423 radiobutton!!.id = cid
424 radiobutton!!.text = text
425 radiobutton!!.setOnClickListener {
426 eventHandlerSimple(radiobutton!!, 8)
427 }
428 }
429 return radiobutton
430 }
431
432 fun checkboxNew(text: String, cid: Int): CheckBox? {
433 var checkbox: CheckBox? = null
434
435 waitOnUiThread {
436 var dataArrayMap = SimpleArrayMap<String, Long>()
437
438 checkbox = CheckBox(this)
439 checkbox!!.tag = dataArrayMap
440 checkbox!!.id = cid
441 checkbox!!.text = text
442 checkbox!!.setOnClickListener {
443 eventHandlerSimple(checkbox!!, 8)
444 }
445 }
446 return checkbox
447 }
448
449 fun checkOrRadioSetChecked(control: View, state: Int)
450 {
451 waitOnUiThread {
452 if (control is CheckBox) {
453 var checkbox: CheckBox = control
454 checkbox.isChecked = state != 0
455 } else if (control is RadioButton) {
456 var radiobutton: RadioButton = control
457 radiobutton.isChecked = state != 0
458 }
459 }
460 }
461
462 fun checkOrRadioGetChecked(control: View): Boolean
463 {
464 var retval: Boolean = false
465
466 waitOnUiThread {
467 if (control is CheckBox) {
468 var checkbox: CheckBox = control
469 retval = checkbox.isChecked
470 } else if (control is RadioButton) {
471 var radiobutton: RadioButton = control
472 retval = radiobutton.isChecked
473 }
474 }
475 return retval
476 }
477
478 fun textNew(text: String, cid: Int, status: Int): TextView? {
479 var textview: TextView? = null
480
481 waitOnUiThread {
482 var dataArrayMap = SimpleArrayMap<String, Long>()
483
484 textview = TextView(this)
485 textview!!.tag = dataArrayMap
486 textview!!.id = cid
487 textview!!.text = text
488 if (status != 0) {
489 val border = GradientDrawable()
490
491 // Set a black border on white background...
492 // might need to change this to invisible...
493 // or the color from windowSetColor
494 border.setColor(-0x1)
495 border.setStroke(1, -0x1000000)
496 textview!!.background = border
497 }
498 }
499 return textview
500 }
501
502 fun notebookNew(cid: Int, top: Int): RelativeLayout?
503 {
504 var notebook: RelativeLayout? = null
505
506 waitOnUiThread {
507 val pager = ViewPager2(this)
508 val tabs = TabLayout(this)
509 var w: Int = RelativeLayout.LayoutParams.MATCH_PARENT
510 var h: Int = RelativeLayout.LayoutParams.WRAP_CONTENT
511 var dataArrayMap = SimpleArrayMap<String, Long>()
512
513 notebook = RelativeLayout(this)
514 notebook!!.tag = dataArrayMap
515 notebook!!.id = cid
516 tabs.id = View.generateViewId()
517 pager.id = View.generateViewId()
518 pager.adapter = DWTabViewPagerAdapter()
519 TabLayoutMediator(tabs, pager) { tab, position ->
520 // This code never gets called?
521 }.attach()
522
523 var params: RelativeLayout.LayoutParams = RelativeLayout.LayoutParams(w, h)
524 if (top != 0) {
525 params.addRule(RelativeLayout.ALIGN_PARENT_TOP)
291 } else { 526 } else {
292 if (hsize > 0) { 527 params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM)
293 if (h > 0) { 528 }
294 params.weight = h.toFloat() 529 tabs.tabGravity = TabLayout.GRAVITY_FILL
295 } else { 530 tabs.tabMode = TabLayout.MODE_FIXED
296 params.weight = 1F 531 notebook!!.addView(tabs, params)
297 } 532 params = RelativeLayout.LayoutParams(w, w)
298 } 533 if (top != 0) {
299 } 534 params.addRule(RelativeLayout.BELOW, tabs.id)
300 if (pad > 0) { 535 } else {
301 params.setMargins(pad, pad, pad, pad) 536 params.addRule(RelativeLayout.ABOVE, tabs.id)
302 } 537 }
303 var grav: Int = Gravity.CLIP_HORIZONTAL or Gravity.CLIP_VERTICAL 538 notebook!!.addView(pager, params)
304 if (hsize > 0 && vsize > 0) { 539 tabs.addOnTabSelectedListener(object : OnTabSelectedListener {
305 params.gravity = Gravity.FILL or grav 540 override fun onTabSelected(tab: TabLayout.Tab) {
306 } else if (hsize > 0) { 541 val adapter = pager.adapter as DWTabViewPagerAdapter
307 params.gravity = Gravity.FILL_HORIZONTAL or grav 542
308 } else if (vsize > 0) { 543 pager.currentItem = tab.position
309 params.gravity = Gravity.FILL_VERTICAL or grav 544 eventHandlerNotebook(notebook!!, 15, adapter.pageList[tab.position])
310 } 545 }
311 item.layoutParams = params 546
312 box.addView(item, index) 547 override fun onTabUnselected(tab: TabLayout.Tab) {}
313 } 548 override fun onTabReselected(tab: TabLayout.Tab) {}
314 } 549 })
315 550 }
316 fun boxUnpack(item: View) {
317 var box: LinearLayout = item.parent as LinearLayout
318 box.removeView(item)
319 }
320
321 fun boxUnpackAtIndex(box: LinearLayout, index: Int): View? {
322 var item: View = box.getChildAt(index)
323
324 box.removeView(item)
325 return item
326 }
327
328 fun buttonNew(text: String, cid: Int): Button {
329 val button = Button(this)
330 var dataArrayMap = SimpleArrayMap<String, Long>()
331
332 button.tag = dataArrayMap
333 button.text = text
334 button.id = cid
335 button.setOnClickListener {
336 eventHandlerSimple(button, 8)
337 }
338 return button
339 }
340
341 fun entryfieldNew(text: String, cid: Int, password: Int): EditText {
342 val entryfield = EditText(this)
343 var dataArrayMap = SimpleArrayMap<String, Long>()
344
345 entryfield.tag = dataArrayMap
346 entryfield.id = cid
347 if (password > 0) {
348 entryfield.transformationMethod = PasswordTransformationMethod.getInstance()
349 }
350 entryfield.setText(text)
351 return entryfield
352 }
353
354 fun entryfieldSetLimit(entryfield: EditText, limit: Long) {
355 entryfield.filters = arrayOf<InputFilter>(LengthFilter(limit.toInt()))
356 }
357
358 fun radioButtonNew(text: String, cid: Int): RadioButton {
359 val radiobutton = RadioButton(this)
360 var dataArrayMap = SimpleArrayMap<String, Long>()
361
362 radiobutton.tag = dataArrayMap
363 radiobutton.id = cid
364 radiobutton.text = text
365 radiobutton.setOnClickListener {
366 eventHandlerSimple(radiobutton, 8)
367 }
368 return radiobutton
369 }
370
371 fun checkboxNew(text: String, cid: Int): CheckBox {
372 val checkbox = CheckBox(this)
373 var dataArrayMap = SimpleArrayMap<String, Long>()
374
375 checkbox.tag = dataArrayMap
376 checkbox.id = cid
377 checkbox.text = text
378 checkbox.setOnClickListener {
379 eventHandlerSimple(checkbox, 8)
380 }
381 return checkbox
382 }
383
384 fun checkOrRadioSetChecked(control: View, state: Int)
385 {
386 if(control is CheckBox) {
387 var checkbox: CheckBox = control
388 checkbox.isChecked = state != 0
389 } else if(control is RadioButton) {
390 var radiobutton: RadioButton = control
391 radiobutton.isChecked = state != 0
392 }
393 }
394
395 fun checkOrRadioGetChecked(control: View): Boolean
396 {
397 if(control is CheckBox) {
398 var checkbox: CheckBox = control
399 return checkbox.isChecked
400 } else if(control is RadioButton) {
401 var radiobutton: RadioButton = control
402 return radiobutton.isChecked
403 }
404 return false
405 }
406
407 fun textNew(text: String, cid: Int, status: Int): TextView {
408 val textview = TextView(this)
409 var dataArrayMap = SimpleArrayMap<String, Long>()
410
411 textview.tag = dataArrayMap
412 textview.id = cid
413 textview.text = text
414 if (status != 0) {
415 val border = GradientDrawable()
416
417 // Set a black border on white background...
418 // might need to change this to invisible...
419 // or the color from windowSetColor
420 border.setColor(-0x1)
421 border.setStroke(1, -0x1000000)
422 textview.background = border
423 }
424 return textview
425 }
426
427 fun notebookNew(cid: Int, top: Int): RelativeLayout
428 {
429 val notebook = RelativeLayout(this)
430 val pager = ViewPager2(this)
431 val tabs = TabLayout(this)
432 var w: Int = RelativeLayout.LayoutParams.MATCH_PARENT
433 var h: Int = RelativeLayout.LayoutParams.WRAP_CONTENT
434 var dataArrayMap = SimpleArrayMap<String, Long>()
435
436 notebook.tag = dataArrayMap
437 notebook.id = cid
438 tabs.id = View.generateViewId()
439 pager.id = View.generateViewId()
440 pager.adapter = DWTabViewPagerAdapter()
441 TabLayoutMediator(tabs, pager) { tab, position ->
442 // This code never gets called?
443 }.attach()
444
445 var params: RelativeLayout.LayoutParams = RelativeLayout.LayoutParams(w, h)
446 if(top != 0) {
447 params.addRule(RelativeLayout.ALIGN_PARENT_TOP)
448 } else {
449 params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM)
450 }
451 tabs.tabGravity = TabLayout.GRAVITY_FILL
452 tabs.tabMode = TabLayout.MODE_FIXED
453 notebook.addView(tabs, params)
454 params = RelativeLayout.LayoutParams(w, w)
455 if(top != 0) {
456 params.addRule(RelativeLayout.BELOW, tabs.id)
457 } else {
458 params.addRule(RelativeLayout.ABOVE, tabs.id)
459 }
460 notebook.addView(pager, params)
461 tabs.addOnTabSelectedListener(object : OnTabSelectedListener {
462 override fun onTabSelected(tab: TabLayout.Tab) {
463 val adapter = pager.adapter as DWTabViewPagerAdapter
464
465 pager.currentItem = tab.position
466 eventHandlerNotebook(notebook, 15, adapter.pageList[tab.position])
467 }
468 override fun onTabUnselected(tab: TabLayout.Tab) {}
469 override fun onTabReselected(tab: TabLayout.Tab) {}
470 })
471 return notebook 551 return notebook
472 } 552 }
473 553
474 fun notebookPageNew(notebook: RelativeLayout, flags: Long, front: Int): Long 554 fun notebookPageNew(notebook: RelativeLayout, flags: Long, front: Int): Long
475 { 555 {
476 var pager: ViewPager2? = null
477 var tabs: TabLayout? = null
478 var pageID = 0L 556 var pageID = 0L
479 557
480 if(notebook.getChildAt(0) is ViewPager2 && notebook.getChildAt(1) is TabLayout) { 558 waitOnUiThread {
481 pager = notebook.getChildAt(0) as ViewPager2 559 var pager: ViewPager2? = null
482 tabs = notebook.getChildAt(1) as TabLayout 560 var tabs: TabLayout? = null
483 } else if(notebook.getChildAt(1) is ViewPager2 && notebook.getChildAt(0) is TabLayout) { 561
484 pager = notebook.getChildAt(1) as ViewPager2 562 if (notebook.getChildAt(0) is ViewPager2 && notebook.getChildAt(1) is TabLayout) {
485 tabs = notebook.getChildAt(0) as TabLayout 563 pager = notebook.getChildAt(0) as ViewPager2
486 } 564 tabs = notebook.getChildAt(1) as TabLayout
487 565 } else if (notebook.getChildAt(1) is ViewPager2 && notebook.getChildAt(0) is TabLayout) {
488 if(pager != null && tabs != null) { 566 pager = notebook.getChildAt(1) as ViewPager2
489 var adapter: DWTabViewPagerAdapter = pager.adapter as DWTabViewPagerAdapter 567 tabs = notebook.getChildAt(0) as TabLayout
490 var tab = tabs.newTab() 568 }
491 569
492 // Increment our page ID... making sure no duplicates exist 570 if (pager != null && tabs != null) {
493 do { 571 var adapter: DWTabViewPagerAdapter = pager.adapter as DWTabViewPagerAdapter
494 adapter.currentPageID += 1 572 var tab = tabs.newTab()
495 } 573
496 while(adapter.currentPageID == 0L || adapter.pageList.contains(adapter.currentPageID)) 574 // Increment our page ID... making sure no duplicates exist
497 pageID = adapter.currentPageID 575 do {
498 // Temporarily add a black tab with an empty layout/box 576 adapter.currentPageID += 1
499 if(front != 0) { 577 } while (adapter.currentPageID == 0L || adapter.pageList.contains(adapter.currentPageID))
500 adapter.viewList.add(0, LinearLayout(this)) 578 pageID = adapter.currentPageID
501 adapter.pageList.add(0, pageID) 579 // Temporarily add a black tab with an empty layout/box
502 tabs.addTab(tab, 0) 580 if (front != 0) {
503 } else { 581 adapter.viewList.add(0, LinearLayout(this))
504 adapter.viewList.add(LinearLayout(this)) 582 adapter.pageList.add(0, pageID)
505 adapter.pageList.add(pageID) 583 tabs.addTab(tab, 0)
506 tabs.addTab(tab) 584 } else {
585 adapter.viewList.add(LinearLayout(this))
586 adapter.pageList.add(pageID)
587 tabs.addTab(tab)
588 }
507 } 589 }
508 } 590 }
509 return pageID 591 return pageID
510 } 592 }
511 593
512 fun notebookPageDestroy(notebook: RelativeLayout, pageID: Long) 594 fun notebookPageDestroy(notebook: RelativeLayout, pageID: Long)
513 { 595 {
514 var pager: ViewPager2? = null 596 waitOnUiThread {
515 var tabs: TabLayout? = null 597 var pager: ViewPager2? = null
516 598 var tabs: TabLayout? = null
517 if(notebook.getChildAt(0) is ViewPager2 && notebook.getChildAt(1) is TabLayout) { 599
518 pager = notebook.getChildAt(0) as ViewPager2 600 if (notebook.getChildAt(0) is ViewPager2 && notebook.getChildAt(1) is TabLayout) {
519 tabs = notebook.getChildAt(1) as TabLayout 601 pager = notebook.getChildAt(0) as ViewPager2
520 } else if(notebook.getChildAt(1) is ViewPager2 && notebook.getChildAt(0) is TabLayout) { 602 tabs = notebook.getChildAt(1) as TabLayout
521 pager = notebook.getChildAt(1) as ViewPager2 603 } else if (notebook.getChildAt(1) is ViewPager2 && notebook.getChildAt(0) is TabLayout) {
522 tabs = notebook.getChildAt(0) as TabLayout 604 pager = notebook.getChildAt(1) as ViewPager2
523 } 605 tabs = notebook.getChildAt(0) as TabLayout
524 606 }
525 if(pager != null && tabs != null) { 607
526 var adapter: DWTabViewPagerAdapter = pager.adapter as DWTabViewPagerAdapter 608 if (pager != null && tabs != null) {
527 val index = adapter.pageList.indexOf(pageID) 609 var adapter: DWTabViewPagerAdapter = pager.adapter as DWTabViewPagerAdapter
528 val tab = tabs.getTabAt(index) 610 val index = adapter.pageList.indexOf(pageID)
529 611 val tab = tabs.getTabAt(index)
530 if (tab != null) { 612
531 adapter.viewList.removeAt(index) 613 if (tab != null) {
532 adapter.pageList.removeAt(index) 614 adapter.viewList.removeAt(index)
533 tabs.removeTab(tab) 615 adapter.pageList.removeAt(index)
616 tabs.removeTab(tab)
617 }
534 } 618 }
535 } 619 }
536 } 620 }
537 621
538 fun notebookPageSetText(notebook: RelativeLayout, pageID: Long, text: String) 622 fun notebookPageSetText(notebook: RelativeLayout, pageID: Long, text: String)
539 { 623 {
540 var pager: ViewPager2? = null 624 waitOnUiThread {
541 var tabs: TabLayout? = null 625 var pager: ViewPager2? = null
542 626 var tabs: TabLayout? = null
543 if(notebook.getChildAt(0) is ViewPager2 && notebook.getChildAt(1) is TabLayout) { 627
544 pager = notebook.getChildAt(0) as ViewPager2 628 if (notebook.getChildAt(0) is ViewPager2 && notebook.getChildAt(1) is TabLayout) {
545 tabs = notebook.getChildAt(1) as TabLayout 629 pager = notebook.getChildAt(0) as ViewPager2
546 } else if(notebook.getChildAt(1) is ViewPager2 && notebook.getChildAt(0) is TabLayout) { 630 tabs = notebook.getChildAt(1) as TabLayout
547 pager = notebook.getChildAt(1) as ViewPager2 631 } else if (notebook.getChildAt(1) is ViewPager2 && notebook.getChildAt(0) is TabLayout) {
548 tabs = notebook.getChildAt(0) as TabLayout 632 pager = notebook.getChildAt(1) as ViewPager2
549 } 633 tabs = notebook.getChildAt(0) as TabLayout
550 634 }
551 if(pager != null && tabs != null) { 635
552 val adapter: DWTabViewPagerAdapter = pager.adapter as DWTabViewPagerAdapter 636 if (pager != null && tabs != null) {
553 val index = adapter.pageList.indexOf(pageID) 637 val adapter: DWTabViewPagerAdapter = pager.adapter as DWTabViewPagerAdapter
554 val tab = tabs.getTabAt(index) 638 val index = adapter.pageList.indexOf(pageID)
555 639 val tab = tabs.getTabAt(index)
556 if (tab != null) { 640
557 tab.text = text 641 if (tab != null) {
642 tab.text = text
643 }
558 } 644 }
559 } 645 }
560 } 646 }
561 647
562 fun notebookPagePack(notebook: RelativeLayout, pageID: Long, box: LinearLayout) 648 fun notebookPagePack(notebook: RelativeLayout, pageID: Long, box: LinearLayout)
563 { 649 {
564 var pager: ViewPager2? = null 650 waitOnUiThread {
565 var tabs: TabLayout? = null 651 var pager: ViewPager2? = null
566 652 var tabs: TabLayout? = null
567 if(notebook.getChildAt(0) is ViewPager2 && notebook.getChildAt(1) is TabLayout) { 653
568 pager = notebook.getChildAt(0) as ViewPager2 654 if (notebook.getChildAt(0) is ViewPager2 && notebook.getChildAt(1) is TabLayout) {
569 tabs = notebook.getChildAt(1) as TabLayout 655 pager = notebook.getChildAt(0) as ViewPager2
570 } else if(notebook.getChildAt(1) is ViewPager2 && notebook.getChildAt(0) is TabLayout) { 656 tabs = notebook.getChildAt(1) as TabLayout
571 pager = notebook.getChildAt(1) as ViewPager2 657 } else if (notebook.getChildAt(1) is ViewPager2 && notebook.getChildAt(0) is TabLayout) {
572 tabs = notebook.getChildAt(0) as TabLayout 658 pager = notebook.getChildAt(1) as ViewPager2
573 } 659 tabs = notebook.getChildAt(0) as TabLayout
574 660 }
575 if(pager != null && tabs != null) { 661
576 var adapter: DWTabViewPagerAdapter = pager.adapter as DWTabViewPagerAdapter 662 if (pager != null && tabs != null) {
577 val index = adapter.pageList.indexOf(pageID) 663 var adapter: DWTabViewPagerAdapter = pager.adapter as DWTabViewPagerAdapter
578 664 val index = adapter.pageList.indexOf(pageID)
579 // Make sure the box is MATCH_PARENT 665
580 box.layoutParams = LinearLayout.LayoutParams( 666 // Make sure the box is MATCH_PARENT
581 LinearLayout.LayoutParams.MATCH_PARENT, 667 box.layoutParams = LinearLayout.LayoutParams(
582 LinearLayout.LayoutParams.MATCH_PARENT 668 LinearLayout.LayoutParams.MATCH_PARENT,
583 ); 669 LinearLayout.LayoutParams.MATCH_PARENT
584 670 );
585 adapter.viewList[index] = box 671
672 adapter.viewList[index] = box
673 }
586 } 674 }
587 } 675 }
588 676
589 fun notebookPageGet(notebook: RelativeLayout): Long 677 fun notebookPageGet(notebook: RelativeLayout): Long
590 { 678 {
591 var pager: ViewPager2? = null 679 var retval: Long = 0L
592 var tabs: TabLayout? = null 680
593 681 waitOnUiThread {
594 if(notebook.getChildAt(0) is ViewPager2 && notebook.getChildAt(1) is TabLayout) { 682 var pager: ViewPager2? = null
595 pager = notebook.getChildAt(0) as ViewPager2 683 var tabs: TabLayout? = null
596 tabs = notebook.getChildAt(1) as TabLayout 684
597 } else if(notebook.getChildAt(1) is ViewPager2 && notebook.getChildAt(0) is TabLayout) { 685 if (notebook.getChildAt(0) is ViewPager2 && notebook.getChildAt(1) is TabLayout) {
598 pager = notebook.getChildAt(1) as ViewPager2 686 pager = notebook.getChildAt(0) as ViewPager2
599 tabs = notebook.getChildAt(0) as TabLayout 687 tabs = notebook.getChildAt(1) as TabLayout
600 } 688 } else if (notebook.getChildAt(1) is ViewPager2 && notebook.getChildAt(0) is TabLayout) {
601 689 pager = notebook.getChildAt(1) as ViewPager2
602 if(pager != null && tabs != null) { 690 tabs = notebook.getChildAt(0) as TabLayout
603 var adapter: DWTabViewPagerAdapter = pager.adapter as DWTabViewPagerAdapter 691 }
604 return adapter.pageList.get(tabs.selectedTabPosition) 692
605 } 693 if (pager != null && tabs != null) {
606 return 0L 694 var adapter: DWTabViewPagerAdapter = pager.adapter as DWTabViewPagerAdapter
695 retval = adapter.pageList.get(tabs.selectedTabPosition)
696 }
697 }
698 return retval
607 } 699 }
608 700
609 fun notebookPageSet(notebook: RelativeLayout, pageID: Long) 701 fun notebookPageSet(notebook: RelativeLayout, pageID: Long)
610 { 702 {
611 var pager: ViewPager2? = null 703 waitOnUiThread {
612 var tabs: TabLayout? = null 704 var pager: ViewPager2? = null
613 705 var tabs: TabLayout? = null
614 if(notebook.getChildAt(0) is ViewPager2 && notebook.getChildAt(1) is TabLayout) { 706
615 pager = notebook.getChildAt(0) as ViewPager2 707 if (notebook.getChildAt(0) is ViewPager2 && notebook.getChildAt(1) is TabLayout) {
616 tabs = notebook.getChildAt(1) as TabLayout 708 pager = notebook.getChildAt(0) as ViewPager2
617 } else if(notebook.getChildAt(1) is ViewPager2 && notebook.getChildAt(0) is TabLayout) { 709 tabs = notebook.getChildAt(1) as TabLayout
618 pager = notebook.getChildAt(1) as ViewPager2 710 } else if (notebook.getChildAt(1) is ViewPager2 && notebook.getChildAt(0) is TabLayout) {
619 tabs = notebook.getChildAt(0) as TabLayout 711 pager = notebook.getChildAt(1) as ViewPager2
620 } 712 tabs = notebook.getChildAt(0) as TabLayout
621 713 }
622 if(pager != null && tabs != null) { 714
623 val adapter: DWTabViewPagerAdapter = pager.adapter as DWTabViewPagerAdapter 715 if (pager != null && tabs != null) {
624 val index = adapter.pageList.indexOf(pageID) 716 val adapter: DWTabViewPagerAdapter = pager.adapter as DWTabViewPagerAdapter
625 val tab = tabs.getTabAt(index) 717 val index = adapter.pageList.indexOf(pageID)
626 718 val tab = tabs.getTabAt(index)
627 tabs.selectTab(tab) 719
628 } 720 tabs.selectTab(tab)
629 } 721 }
630 722 }
631 fun sliderNew(vertical: Int, increments: Int, cid: Int): SeekBar 723 }
632 { 724
633 val slider = SeekBar(this) 725 fun sliderNew(vertical: Int, increments: Int, cid: Int): SeekBar?
634 var dataArrayMap = SimpleArrayMap<String, Long>() 726 {
635 727 var slider: SeekBar? = null
636 slider.tag = dataArrayMap 728
637 slider.id = cid 729 waitOnUiThread {
638 slider.max = increments 730 var dataArrayMap = SimpleArrayMap<String, Long>()
639 if(vertical != 0) { 731
640 slider.rotation = 270F 732 slider = SeekBar(this)
641 } 733 slider!!.tag = dataArrayMap
642 slider.setOnSeekBarChangeListener(object : OnSeekBarChangeListener { 734 slider!!.id = cid
643 override fun onStopTrackingTouch(seekBar: SeekBar) { 735 slider!!.max = increments
644 } 736 if (vertical != 0) {
645 737 slider!!.rotation = 270F
646 override fun onStartTrackingTouch(seekBar: SeekBar) { 738 }
647 } 739 slider!!.setOnSeekBarChangeListener(object : OnSeekBarChangeListener {
648 740 override fun onStopTrackingTouch(seekBar: SeekBar) {
649 override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) { 741 }
650 eventHandler(slider, null, 14, null, null, slider.progress, 0, 0, 0) 742
651 } 743 override fun onStartTrackingTouch(seekBar: SeekBar) {
652 }) 744 }
745
746 override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
747 eventHandler(slider, null, 14, null, null, slider!!.progress, 0, 0, 0)
748 }
749 })
750 }
653 return slider 751 return slider
654 } 752 }
655 753
656 fun percentNew(cid: Int): ProgressBar 754 fun percentNew(cid: Int): ProgressBar?
657 { 755 {
658 val percent = ProgressBar(this) 756 var percent: ProgressBar? = null
659 var dataArrayMap = SimpleArrayMap<String, Long>() 757
660 758 waitOnUiThread {
661 percent.tag = dataArrayMap 759 var dataArrayMap = SimpleArrayMap<String, Long>()
662 percent.id = cid 760
663 percent.max = 100 761 percent = ProgressBar(this)
762 percent!!.tag = dataArrayMap
763 percent!!.id = cid
764 percent!!.max = 100
765 }
664 return percent 766 return percent
665 } 767 }
666 768
667 fun percentGetPos(percent: ProgressBar): Int 769 fun percentGetPos(percent: ProgressBar): Int
668 { 770 {
669 return percent.progress 771 var retval: Int = 0
772
773 waitOnUiThread {
774 retval = percent.progress
775 }
776 return retval
670 } 777 }
671 778
672 fun percentSetPos(percent: ProgressBar, position: Int) 779 fun percentSetPos(percent: ProgressBar, position: Int)
673 { 780 {
674 percent.progress = position 781 waitOnUiThread {
782 percent.progress = position
783 }
675 } 784 }
676 785
677 fun percentSetRange(percent: ProgressBar, range: Int) 786 fun percentSetRange(percent: ProgressBar, range: Int)
678 { 787 {
679 percent.max = range 788 waitOnUiThread {
789 percent.max = range
790 }
680 } 791 }
681 792
682 fun htmlNew(cid: Int): WebView? 793 fun htmlNew(cid: Int): WebView?
683 { 794 {
684 val looper = Looper.myLooper() 795 var html: WebView? = null
685 796
686 // WebView requires an active Looper 797 waitOnUiThread {
687 if(looper == null) { 798 var dataArrayMap = SimpleArrayMap<String, Long>()
688 Looper.prepare() 799
689 } 800 html = WebView(this)
690 801 html!!.tag = dataArrayMap
691 var dataArrayMap = SimpleArrayMap<String, Long>() 802 html!!.id = cid
692 val html = WebView(this) 803 }
693
694 html.tag = dataArrayMap
695 html.id = cid
696 return html 804 return html
697 } 805 }
698 806
699 fun htmlLoadURL(html: WebView, url: String) 807 fun htmlLoadURL(html: WebView, url: String)
700 { 808 {
701 html.loadUrl(url) 809 waitOnUiThread {
810 html.loadUrl(url)
811 }
702 } 812 }
703 813
704 fun htmlRaw(html: WebView, data: String) 814 fun htmlRaw(html: WebView, data: String)
705 { 815 {
706 val encodedHtml: String = Base64.encodeToString(data.toByteArray(), Base64.NO_PADDING) 816 waitOnUiThread {
707 html.loadData(encodedHtml, "text/html", "base64") 817 val encodedHtml: String = Base64.encodeToString(data.toByteArray(), Base64.NO_PADDING)
818 html.loadData(encodedHtml, "text/html", "base64")
819 }
708 } 820 }
709 821
710 fun htmlJavascriptRun(html: WebView, javascript: String, data: Long) 822 fun htmlJavascriptRun(html: WebView, javascript: String, data: Long)
711 { 823 {
712 html.evaluateJavascript(javascript) { value -> 824 waitOnUiThread {
713 // Execute onReceiveValue's code 825 html.evaluateJavascript(javascript) { value ->
714 eventHandlerHTMLResult(html, 18, value, data) 826 // Execute onReceiveValue's code
827 eventHandlerHTMLResult(html, 18, value, data)
828 }
715 } 829 }
716 } 830 }
717 831
718 fun htmlAction(html: WebView, action: Int) 832 fun htmlAction(html: WebView, action: Int)
719 { 833 {
720 when (action) { 834 waitOnUiThread {
721 0 -> html.goBack() 835 when (action) {
722 1 -> html.goForward() 836 0 -> html.goBack()
723 2 -> html.loadUrl("http://dwindows.netlabs.org") 837 1 -> html.goForward()
724 4 -> html.reload() 838 2 -> html.loadUrl("http://dwindows.netlabs.org")
725 5 -> html.stopLoading() 839 4 -> html.reload()
840 5 -> html.stopLoading()
841 }
726 } 842 }
727 } 843 }
728 844
729 fun timerConnect(interval: Long, sigfunc: Long, data: Long): Timer 845 fun timerConnect(interval: Long, sigfunc: Long, data: Long): Timer
730 { 846 {
761 Log.d(null, text) 877 Log.d(null, text)
762 } 878 }
763 879
764 fun messageBox(title: String, body: String, flags: Int): Int 880 fun messageBox(title: String, body: String, flags: Int): Int
765 { 881 {
766 // make a text input dialog and show it
767 var alert = AlertDialog.Builder(this)
768 var retval: Int = 0 882 var retval: Int = 0
769 883
770 alert.setTitle(title) 884 waitOnUiThread {
771 alert.setMessage(body) 885 // make a text input dialog and show it
772 if((flags and (1 shl 3)) != 0) { 886 var alert = AlertDialog.Builder(this)
773 alert.setPositiveButton( 887
774 "Yes", 888 alert.setTitle(title)
775 DialogInterface.OnClickListener { _: DialogInterface, _: Int -> 889 alert.setMessage(body)
776 retval = 1 890 if ((flags and (1 shl 3)) != 0) {
777 throw java.lang.RuntimeException() 891 alert.setPositiveButton(
778 }); 892 "Yes",
779 } 893 DialogInterface.OnClickListener { _: DialogInterface, _: Int ->
780 if((flags and ((1 shl 1) or (1 shl 2))) != 0) { 894 retval = 1
781 alert.setNegativeButton( 895 throw java.lang.RuntimeException()
782 "Ok", 896 });
783 DialogInterface.OnClickListener { _: DialogInterface, _: Int -> 897 }
784 retval = 0 898 if ((flags and ((1 shl 1) or (1 shl 2))) != 0) {
785 throw java.lang.RuntimeException() 899 alert.setNegativeButton(
786 }); 900 "Ok",
787 } 901 DialogInterface.OnClickListener { _: DialogInterface, _: Int ->
788 if((flags and ((1 shl 3) or (1 shl 4))) != 0) { 902 retval = 0
789 alert.setNegativeButton( 903 throw java.lang.RuntimeException()
790 "No", 904 });
791 DialogInterface.OnClickListener { _: DialogInterface, _: Int -> 905 }
792 retval = 0 906 if ((flags and ((1 shl 3) or (1 shl 4))) != 0) {
793 throw java.lang.RuntimeException() 907 alert.setNegativeButton(
794 }); 908 "No",
795 } 909 DialogInterface.OnClickListener { _: DialogInterface, _: Int ->
796 if((flags and ((1 shl 2) or (1 shl 4))) != 0) { 910 retval = 0
797 alert.setNeutralButton( 911 throw java.lang.RuntimeException()
798 "Cancel", 912 });
799 DialogInterface.OnClickListener { _: DialogInterface, _: Int -> 913 }
800 retval = 2 914 if ((flags and ((1 shl 2) or (1 shl 4))) != 0) {
801 throw java.lang.RuntimeException() 915 alert.setNeutralButton(
802 }); 916 "Cancel",
803 } 917 DialogInterface.OnClickListener { _: DialogInterface, _: Int ->
804 alert.show(); 918 retval = 2
805 919 throw java.lang.RuntimeException()
806 // loop till a runtime exception is triggered. 920 });
807 try { 921 }
808 Looper.loop() 922 alert.show();
809 } catch (e2: RuntimeException) { 923
924 // loop till a runtime exception is triggered.
925 try {
926 Looper.loop()
927 } catch (e2: RuntimeException) {
928 }
810 } 929 }
811 return retval 930 return retval
812 } 931 }
813 932
814 fun dwindowsExit(exitcode: Int) 933 fun dwindowsExit(exitcode: Int)
815 { 934 {
816 this.finishAffinity() 935 waitOnUiThread {
817 System.exit(exitcode) 936 this.finishAffinity()
937 System.exit(exitcode)
938 }
818 } 939 }
819 940
820 fun dwindowsShutdown() 941 fun dwindowsShutdown()
821 { 942 {
822 this.finishAffinity() 943 waitOnUiThread {
944 this.finishAffinity()
945 }
823 } 946 }
824 947
825 /* 948 /*
826 * Native methods that are implemented by the 'dwindows' native library, 949 * Native methods that are implemented by the 'dwindows' native library,
827 * which is packaged with this application. 950 * which is packaged with this application.