Can't detect key press with hardware keyboard on android app (Kotlin) - android

I am creating a simple application for my android tv box, which uses a webview object to show some streaming urls and choose beetween them with PGup and PGdown of a remote control (an hardware keyboard).
I am overriding method onKeyUp, but unfortunately my app seem not to detect any key press.
This is some code excerpt:
package com.dm.tutorialwebview
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.view.KeyEvent
import android.view.Menu
import android.webkit.WebChromeClient
import android.webkit.WebView
import android.webkit.WebViewClient
import android.util.Log
import android.view.MotionEvent
class MainActivity : AppCompatActivity() {
var webview: WebView? = null
data class Channel(val number: Int, val name:String, val url: String )
object ChannelList {
private val list = mutableListOf<Channel>()
private var curChannel: Int = 0
[..]
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
ChannelList.addItem(Channel(1,"channel1","https://...3"))
ChannelList.addItem(Channel(2,"channel2","https://..."))
ChannelList.addItem(Channel(3,"channel3","https://..."))
webview = findViewById(R.id.myweb)
webview!!.webViewClient = WebViewClient()
webview!!.settings.javaScriptEnabled = false
webview!!.webChromeClient = WebChromeClient()
webview!!.settings.domStorageEnabled = true
webview!!.settings.builtInZoomControls = false
webview!!.settings.setSupportZoom(false)
webview!!.overScrollMode = WebView.OVER_SCROLL_NEVER
webview!!.settings.useWideViewPort = true
webview!!.setInitialScale(1)
webview!!.loadUrl(ChannelList.getChannelUrl())
}
override fun onKeyUp(keyCode: Int, event: KeyEvent): Boolean {
Log.i("TAG", "onKeyUp is been called");
return when (keyCode) {
KeyEvent.KEYCODE_PAGE_UP -> {
ChannelList.nextChannel()
webview!!.loadUrl(ChannelList.getChannelUrl())
true
}
KeyEvent.KEYCODE_PAGE_DOWN -> {
ChannelList.prevChannel()
webview!!.loadUrl(ChannelList.getChannelUrl())
true
}
KeyEvent.KEYCODE_1 -> {
ChannelList.setChannel(1)
webview!!.loadUrl(ChannelList.getChannelUrl())
true
}
else -> super.onKeyUp(keyCode, event)
}
}
}
Method onKeyUp doesn't seem to be triggered at all.
Any hints on what could be wrong with this code?
Thanks and regards

Thanks #Ashwini-violet, I replaced onKeyUp with dispathKeyEvent.
I used a workaround to limit inputs to one every 250ms; not very polite but it's working.
var lastclick : Long = 0
var keyDelay : Int = 250
[..]
override fun dispatchKeyEvent(event: KeyEvent?): Boolean {
return when (event!!.keyCode) {
KeyEvent.KEYCODE_PAGE_UP , KeyEvent.KEYCODE_DPAD_UP -> {
if ((SystemClock.currentThreadTimeMillis() - lastclick) < keyDelay) true
else {
ChannelList.nextChannel()
webview!!.clearHistory()
webview!!.clearCache(true)
showChannelName()
webview!!.loadUrl(ChannelList.getChannelUrl())
lastclick = SystemClock.currentThreadTimeMillis()
true
}
}

Related

Running itch.io game in my android app webview

I have a game made with unity on itch.io I want to open and play this game in my custom android app webview.
For this I'm using.
myWebView.loadUrl("https://teamwood.itch.io/super-auto-pets")
myWebView.settings.javaScriptEnabled = true
Url is being load but on tapping Run Game nothing happen. Can I even perform this in webview
Itch.io supports fullscreen webgl games altough that games can be run in web view if It is not in full screen. For full screen mode you can follow the code like, below is the code of my Game Activity code Which consists simply a web view.
package com.example.game
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.os.Bundle
import android.view.View
import android.webkit.WebChromeClient
import android.webkit.WebView
import android.webkit.WebViewClient
import android.widget.FrameLayout
import androidx.appcompat.app.AppCompatActivity
class GameActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_game)
val webView: WebView = findViewById(R.id.gameView)
webView.settings.javaScriptEnabled = true
supportActionBar?.hide()
webView.webViewClient= MyBrowser()
webView.webChromeClient = MyWebClient(this#GameActivity.applicationContext,this#GameActivity)
webView.loadUrl("https://teamwood.itch.io/super-auto-pets")
}
internal class MyBrowser : WebViewClient() {
override fun shouldOverrideUrlLoading(paramWebView: WebView, paramString: String): Boolean {
paramWebView.loadUrl(paramString)
return true
}
}
}
open class MyWebClient(private val context: Context,private val activity: GameActivity) : WebChromeClient() {
private var mCustomView: View? = null
private var mCustomViewCallback: CustomViewCallback? = null
protected var mFullscreenContainer: FrameLayout? = null
private var mOriginalOrientation = 0
private var mOriginalSystemUiVisibility = 0
override fun getDefaultVideoPoster(): Bitmap? {
return if (this == null) {
null
} else BitmapFactory.decodeResource(
context.resources, 2130837573
)
}
override fun onHideCustomView() {
(activity.window.decorView as FrameLayout).removeView(mCustomView)
mCustomView = null
activity.window.decorView.systemUiVisibility = mOriginalSystemUiVisibility
activity.requestedOrientation = mOriginalOrientation
mCustomViewCallback!!.onCustomViewHidden()
mCustomViewCallback = null
}
override fun onShowCustomView(
paramView: View?,
paramCustomViewCallback: CustomViewCallback?
) {
if (mCustomView != null) {
onHideCustomView()
return
}
mCustomView = paramView
mOriginalSystemUiVisibility =
activity.window.decorView.systemUiVisibility
mOriginalOrientation = activity.requestedOrientation
mCustomViewCallback = paramCustomViewCallback
(activity.window.decorView as FrameLayout).addView(
mCustomView,
FrameLayout.LayoutParams(-1, -1)
)
activity.window.decorView.systemUiVisibility = 3846
}
}

"evaluateJavascript()" returns "null" as localStorage value of webView

(Sorry for my poor English)
I have a web page which set a local storage value like localStorage.setItem('name', 'myName') , I load this web page inside a webView and I want to access to this local storage value inside the android app so I used below code but it returns "null", it takes half a day but i can't fix it, I'm not android developer so explain me a little more please.
package com.example.myWebViewApp
import android.os.Bundle
import android.os.Handler
import android.util.Log
import android.webkit.ValueCallback
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.appcompat.app.AppCompatActivity
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val myWebView: WebView = findViewById(R.id.webview)
val webSettings = myWebView.settings
webSettings.javaScriptEnabled = true
webSettings.javaScriptCanOpenWindowsAutomatically = true
webSettings.allowFileAccess = true
webSettings.allowContentAccess = true
webSettings.domStorageEnabled = true
webSettings.textZoom = 100
webSettings.allowFileAccess = true
myWebView.loadUrl("http://192.168.1.99:3333")
myWebView.webViewClient = object : WebViewClient() {
override fun onPageFinished(view: WebView, url: String) {
myWebView.evaluateJavascript(
"window.localStorage.getItem('name');",
ValueCallback<String?> {
n -> run { Log.d("nameTag", "$n") }
}
)
}
}
val refreshLayout = findViewById<SwipeRefreshLayout>(R.id.swipeRefresher)
refreshLayout.setOnRefreshListener {
refreshLayout.isRefreshing = true
Handler().postDelayed(Runnable {
refreshLayout.isRefreshing = false
myWebView.reload()
}, 2000)
}
}
}

Button doesn't set to Enabled even after "if conditions" are met

Below code is supposed to set "isEnabled" attribute of a button to true, but it doesn't.
I initialize a mutable list which adds a String when certain Switches are on, and remove them when are off.
I created an if condition where if the size of the list is equal to 2 then ok_button is enabled.
I can't see why the ok_button is not updated even when the conditions are met.
package com.example.malakes
import android.nfc.Tag
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.CompoundButton
import android.widget.Switch
import android.widget.Toast
import kotlinx.android.synthetic.main.activity_main.*
import android.util.Log
import android.view.View
import android.widget.Button
class MainActivity : AppCompatActivity() {
companion object{ const val TAG = "MyActivity" } //define TAG
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val epilegmenoi: MutableList<String> = mutableListOf()
val tony = findViewById<Switch>(R.id.switchTony)
val giorgis = findViewById<Switch>(R.id.switchGiorgos)
val duke = findViewById<Switch>(R.id.switchDuke)
val nikolas = findViewById<Switch>(R.id.switchNikolas)
val dionisis = findViewById<Switch>(R.id.switchDionisis)
val grigoris = findViewById<Switch>(R.id.switchGrigoris)
val ok_button = findViewById<Button>(R.id.buttonOK)
val clear_button = findViewById<Button>(R.id.buttonCLEAR)
tony.setOnCheckedChangeListener { _, isChecked ->
if (isChecked) {
epilegmenoi.add("Tony")
} else {
epilegmenoi.remove("Tony")
}
}
giorgis.setOnCheckedChangeListener { _, isChecked ->
if (isChecked) {
epilegmenoi.add("Giorgis")
} else {
epilegmenoi.remove("Giorgis")
}
}
if (epilegmenoi.size == 2) {ok_button.isEnabled=true}
}
}
‍onCreate() is a Lifecycle method in your activity. It is only called when your Activity is being called for the first time or when phone configs change, e.g. Screen Rotation, Locale change, and ...
Setting if (epilegmenoi.size == 2) {ok_button.isEnabled=true} inside onCreate doesn't do anything for you.
Consider moving this line of code to some Event-based function.
fun updateButtonState() {
my_button.isEnabled = (myList.size == 2)
}
And inside your check box events:
tony.setOnCheckedChangeListener { _, isChecked ->
if (isChecked) {
epilegmenoi.add("Tony")
} else {
epilegmenoi.remove("Tony")
}
updateButtonState()
}
giorgis.setOnCheckedChangeListener { _, isChecked ->
if (isChecked) {
epilegmenoi.add("Giorgis")
} else {
epilegmenoi.remove("Giorgis")
}
updateButtonState()
}

Android - Handle the finish of webview loading from the Activity?

I have the following Activity :
import android.graphics.Bitmap
import android.os.Bundle
import android.provider.Settings
import android.support.v7.app.AppCompatActivity
import android.util.Log
import android.webkit.WebView
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class ShowOneContactHtmlActivity : AppCompatActivity() {
private lateinit var maddress :String
private lateinit var mcontact_name : String
private lateinit var mavatar_to_str_base64: String
private lateinit var dialog: MyViewDialog
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_show_html)
val webview = findViewById<WebView>(R.id.webview)
dialog = MyViewDialog(ShowAddressessActivity#this)
dialog.showDialog()
maddress = intent.getStringExtra(SENT_ADDRESS_FROM_ADDRESSES_TO_SHOWONECONTACT_ACTIVITY)
mcontact_name = intent.getStringExtra(SENT_CONTACT_NAME_FROM_ADDRESSES_TO_SHOWONECONTACT_ACTIVITY)
val avatar = intent.getParcelableExtra<Bitmap>(SENT_BITMAP_FROM_ADDRESSES_TO_SHOWONECONTACT_ACTIVITY)
mavatar_to_str_base64 = bitmaptoStringBase64(avatar)
lateinit var htmlstring :String
GlobalScope.launch {
htmlstring = takeHtmlStringofThisContact()
withContext(Dispatchers.Main) {
webview.loadDataWithBaseURL(
"file:///android_asset/",
htmlstring,
"text/html",
"UTF-8",
""
)
dialog.hideDialog()
}
}
}
suspend private fun takeHtmlStringofThisContact():String {
lateinit var onecntcthtmlmaker: HtmlMaker
if (maddress == mcontact_name) {
onecntcthtmlmaker =
HtmlMaker(ShowOneContactHtmlActivity# this, mavatar_to_str_base64, maddress)
} else {
onecntcthtmlmaker =
HtmlMaker(
ShowOneContactHtmlActivity# this,
mavatar_to_str_base64,
mcontact_name
)
}
var smsparser = SmsParser(ShowOneContactHtmlActivity# this)
withContext(Dispatchers.Default) {
var all_messages_of_one_contact = smsparser.loadInboxAndSentOfAddress(maddress)
var sortedlist =
all_messages_of_one_contact.sortedWith(compareBy({ it.m_date_in_milli }))
for (msg in sortedlist) {
onecntcthtmlmaker.putHtmlMessageInCurrentHtml(msg)
}
onecntcthtmlmaker.clearHtmlAtLast()
}
return onecntcthtmlmaker.current_html
}
}
Rather it is unnecessary to see the whole code, my focus is on the dialog which displays a loading.gif. With this code my loading gif disappears when the loading of the url still happens.
I want the loading gif to disappears when the loading of the url has finished.
As I know (correct me if I am wrong) I have to make my WebViewClient and when onPageFinished() is executed then I have to notify the Activity and the dialog to disappear.
Is there another way ? Is there a function that is called, after the webview has stopped loading , in the activity to override it and to set there the disappearance of dialog(i.e loading gif)???
You can use WebViewClient and override onPageFinished:
webView.webViewClient = object : WebViewClient() {
override fun onPageFinished(view: WebView?, url: String?) {
// Here
}
}

Boolean arguments issue when creating Settings activity

After creating an activity for a Settings page I noticed that, mCurrentValue !== value in if (mCurrentValue !== value) returned a warning:
Identity equality for arguments of types Boolean? and Boolean can be unstable because of implicit boxing
I tried resolving this warning by adding a ? next to Boolean in override fun onXchange(value:Boolean) {, but then the following error returned:
'onXchange' overrides nothing
Any ideas on how to resolve this issue?
Activity class
import android.content.Intent
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.preference.PreferenceManager
import android.support.v7.app.AppCompatActivity
import android.view.MenuItem
class MySettingsActivity : AppCompatActivity(), MySettingsFragment.PreferenceXchangeListener {
private var mCurrentValue: Boolean? = null
override fun onCreate(savedInstanceState: Bundle?) {
val mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
mCurrentValue = mSharedPreferences.getBoolean("preference_a", false)
if (mCurrentValue as Boolean)
{
setTheme(R.style.MyDarkAppCompatTheme)
}
else
{
setTheme(R.style.MyLightAppCompatTheme)
}
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_mysettings)
val settingsFragment = MySettingsFragment()
supportFragmentManager
.beginTransaction()
.replace(R.id.settings_container, settingsFragment)
.commit()
val myActionBar = actionBar
if (myActionBar != null)
{
myActionBar.setTitle(R.string.settings)
myActionBar.setBackgroundDrawable(ColorDrawable(Color.BLACK))
myActionBar.setDisplayHomeAsUpEnabled(true)
myActionBar.setDisplayShowHomeEnabled(true)
myActionBar.setHomeAsUpIndicator(resources.getDrawable(R.drawable.ic_arrow_back_white, null))
}
}
override fun onXchange(value:Boolean?) {
if (mCurrentValue !== value) {
mCurrentValue = value
recreate()
}
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
android.R.id.home -> {
val intent = parentActivityIntent
intent?.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION)
onBackPressed()
return true
}
else ->
return super.onOptionsItemSelected(item)
}
}
}
Fragment class
class MySettingsFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChangeListener {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.app_preferences)
val mCheckBoxPreference = findPreference("preference_a") as CheckBoxPreference
mCheckBoxPreference.onPreferenceChangeListener = this
}
private var mPreferenceXchangeListener: PreferenceXchangeListener? = null
interface PreferenceXchangeListener {
fun onXchange(value:Boolean)
}
override fun onAttach(context: Context) {
super.onAttach(context)
try
{
mPreferenceXchangeListener = context as MySettingsFragment.PreferenceXchangeListener
}
catch (e:ClassCastException) {
Log.e(TAG, "onAttach::::: PreferenceXchangeListener must be set in parent Activity")
}
}
override fun onPreferenceChange(preference: Preference, newValue:Any):Boolean {
val preferenceKey = preference.key
if (preferenceKey == "preference_a")
{
(preference as CheckBoxPreference).isChecked = newValue as Boolean
mPreferenceXchangeListener!!.onXchange(newValue)
return true
}
return false
}
companion object {
private val TAG = MySettingsFragment::class.java.simpleName
}
}
So first I can explain the issue it describes. Let's propose a very contrived scenario:
BooleanProvider.java
class BooleanProvider {
#NonNull Boolean wrapMyBoolean(boolean state) {
return new Boolean(state);
}
}
BooleanProviderTest.kt
class BooleanProviderTest {
#Test fun `it returns a true value when true is provided`() {
assertSame(BooleanProvider().wrapMyBoolean(true), true)
}
}
This test will actually fail, because the instances of Boolean are not the same. In the Java code, we initialized a new instance of Boolean (rather than the statically defined Boolean.TRUE and Boolean.FALSE instances that you'll get when a primitive is auto-boxed to a java.lang.Boolean). So to avoid a potential unexpected result, it is recommending that you don't compare these types by reference.
The simplest fix would be to just change your equality test to != instead of !==. This would perform identity equality testing rather than reference equality testing, and will handle a null value on either side appropriately. This is what you want 99% of the time anyway.
Secondly, you can also just declare mCurrentValue as a non-null type, and give it a default value, if you don't need to handle a null value in a specific way. Just declare it as:
private var mCurrentValue: Boolean = false // false is the default here

Categories

Resources