Quick Links: Download Gideros Studio | Gideros Documentation | Gideros Development Center | Gideros community chat | DONATE
what is the easiest way to check if the device is an android tv? — Gideros Forum

what is the easiest way to check if the device is an android tv?

what is the easiest way to check if the device is an android tv? ty

Comments

  • I think this should help
    https://stackoverflow.com/questions/27138838/how-can-i-check-if-an-app-is-running-on-an-android-tv

    Then you can use the native bridge to call some android native functions from LUA side

    Likes: MoKaLux

    Coming soon
    +1 -1 (+1 / -0 )Share on Facebook
  • SinisterSoftSinisterSoft Maintainer
    Accepted Answer
    It's reported back.
    device={application:getDeviceInfo()}
    print(device[1])
    print(device[2])
    print(device[3])
    print(device[4])
    print(device[5])
     
    if device[5]=="TV" then tv=true end
    if device[1]=="Windows" or device[1]=="Mac OS" then
    	sysOS=device[1]
    	--application:set("cursor","blank")
    	pc=true
    	premium=true
    	application:setWindowSize(600,1024)
    	if not secret then
    		--application:setScaleMode("noScale")
    		--application:setWindowSize(600,1024)
    		application:setFullScreen(true)
    --	application:setScaleMode("letterbox")
    --	application:setOrientation("landscapeLeft")
    --	application:setFullScreen(true)
    	end
    	tv=true
    elseif device[1]=="Web" then
    	sysOS=device[1]
    	web=true premium=true
    	if JS then
    		local url=JS.eval("window.location.href")
    		local line=find(url,"?")
    		if line then
    			params=parseUrl(sub(url,line+1))
    		end
    		language=JS.eval("navigator.language||navigator.userLanguage"):lower() or language
    		sysName=JS.eval("navigator.vendor")
    		sysOS=JS.eval("navigator.userAgent") or sysOS
    		if JS.eval("window.matchMedia('(prefers-color-scheme:dark)').matches")=="true" then sysDark=1 else sysDark=0 end
    	end
    elseif device[1]=="Win32" then win32=true tv=true premium=true sysOS=device[1]
    elseif device[1]=="WinRT" then winrt=true premium=true sysOS=device[1]
    elseif device[1]=="Windows Phone" then winrt=true slow=true premium=true sysOS=device[1]
    elseif device[1]=="Android" then android=true sysOS=device[1] sysName=device[3].." "..device[4]
    	if device[3]=="Amazon" then kindle=true
    		if sub(device[4],1,3)=="AFT" then tv=true if device[4]=="AFTM" then slow=true end end
    	elseif device[3]=="OUYA" then ouya=true tv=true slow=true
    	elseif device[3]=="Geniatech" then tv=true
    		if sub(device[4],1,9)=="GameStick" or device[4]=="TotoTV Stick" then gamestick=true slow=true end
    	elseif device[3]=="HardKernel Co., Ltd." then tv=true hardkernel=true
    		if device[4]=="ODROIDC" then odroidc=true slow=true end
    	elseif device[4]=="Nexus Player" then tv=true nexusplayer=true
    	elseif device[3]=="razer" then tv=true razer=true
    		if device[4]=="Forge" then forgetv=true end
    	elseif device[3]=="IRIVER" then slow=true end
    elseif device[1]=="iOS" then ios=true sysOS=device[1] sysName=device[3]
    	if device[3]=="AppleTV" then tv=true appletv=true end
    end
    Coder, video game industry veteran (since the '80s, ❤'s assembler), arrested - never convicted hacker (in the '90s), dad of five, he/him (if that even matters!).
    https://deluxepixel.com
    +1 -1 (+3 / -0 )Share on Facebook
  • SinisterSoftSinisterSoft Maintainer
    edited October 2021
    btw, you should code your games so that joysticks are detected then turn off any on-screen controls. If you get a touch event then turn them back on, off again when you get a joystick button press, etc.

    This is because there are tablets / phones out there with joysticks built in or connected via bluetooth.

    imho every game should try support joysticks and keyboard, it also makes it easier to make a version for pc, mac, xbox, etc...

    joysticks are supported by every type of export, including html5, you just have to include the controller plugin. I made a joystick controller 'demo' that's included with Gideros if you need an example.



    Likes: keszegh, MoKaLux

    Coder, video game industry veteran (since the '80s, ❤'s assembler), arrested - never convicted hacker (in the '90s), dad of five, he/him (if that even matters!).
    https://deluxepixel.com
    +1 -1 (+2 / -0 )Share on Facebook
  • thanks, good idea, i will also support joysticks.
    +1 -1 (+2 / -0 )Share on Facebook
  • and do you know the keycode of the 'ok' and 'back' button on android tv remotes?
  • keszeghkeszegh Member
    edited October 2021
    @SinisterSoft , on my TCL Android TV actually device[5] is nil as all other device[i] for (i=1..5). application:getDeviceInfo() returns "Android". so in this case how to notice that it's a tv?
    EDIT:
    it works now, i did not notice the {} around application:getDeviceInfo().

    for 'back' button event.keyCode=4 for me after testing, i don't know if this has a name in gideros. for 'ok' button i think it was 96, again i'm not sure if it has a name.

  • SinisterSoftSinisterSoft Maintainer
    edited October 2021
    These are some snips of unified joystick and keyboard controls being made into a bitpattern that the rest of the game uses. It makes it easy to support both keyboard or joystick or anything else you need to insert into the bitpattern.

    The bitpattern is:

    YZrlABUDLR where R is bit 0. (U is up, D is down, L is left and R is right, the others are buttons).

    KeyCode.BUTTON_BACK is used for checking if the button is the back button.

    My code that inserts bits/removes bits...
    function controllerDown(p,k,i)
    	touchScreen=false
    	idleCounter=0
    	if k==KeyCode.BUTTON_A or k==KeyCode.BUTTON_Y or k==buttonA or k==KeyCode.BUTTON_MENU then p.padRGUDLR=p.padRGUDLR|0b100000
    	elseif k==KeyCode.BUTTON_B or k==KeyCode.BUTTON_X or k==KeyCode.U or k==buttonB then p.padRGUDLR=p.padRGUDLR|0b010000
    	elseif k==KeyCode.DPAD_UP then p.padRGUDLR=p.padRGUDLR|0b001000
    	elseif k==KeyCode.DPAD_DOWN then p.padRGUDLR=p.padRGUDLR|0b000100
    	elseif k==KeyCode.DPAD_LEFT then p.padRGUDLR=p.padRGUDLR|0b000010
    	elseif k==KeyCode.DPAD_RIGHT then p.padRGUDLR=p.padRGUDLR|0b000001
    	elseif k==KeyCode.BUTTON_L1 then p.padRGUDLR=p.padRGUDLR|0b10000000
    	elseif k==KeyCode.BUTTON_R1 then p.padRGUDLR=p.padRGUDLR|0b01000000
    	elseif k==KeyCode.Y then p.padRGUDLR=p.padRGUDLR|0b1000000000 -- or k==KeyCode.BUTTON_L2
    	elseif k==KeyCode.Z then p.padRGUDLR=p.padRGUDLR|0b0100000000
    	--elseif k==KeyCode.BUTTON_R2 then setPause()
    	elseif k==KeyCode.BUTTON_BACK then back=true 
    	else
    		print("Button Down ", i, k, findKeyCode(k))
    	end
    	if p.padRGUDLR~=0 then p.joypad=true end
    end
     
    function controllerUp(p,k,i)
    	touchScreen=false
    	idleCounter=0
    	if k==KeyCode.BUTTON_A or k==KeyCode.BUTTON_Y or k==buttonA or k==KeyCode.BUTTON_MENU then p.padRGUDLR=p.padRGUDLR&0b1111011111
    	elseif k==KeyCode.BUTTON_B or k==KeyCode.BUTTON_X or k==KeyCode.U or k==buttonB then p.padRGUDLR=p.padRGUDLR&0b1111101111
    	elseif k==KeyCode.DPAD_UP then p.padRGUDLR=p.padRGUDLR&0b1111110111
    	elseif k==KeyCode.DPAD_DOWN then p.padRGUDLR=p.padRGUDLR&0b1111111011
    	elseif k==KeyCode.DPAD_LEFT then p.padRGUDLR=p.padRGUDLR&0b1111111101
    	elseif k==KeyCode.DPAD_RIGHT then p.padRGUDLR=p.padRGUDLR&0b1111111110
    	elseif k==KeyCode.BUTTON_L1 then p.padRGUDLR=p.padRGUDLR&0b1101111111
    	elseif k==KeyCode.BUTTON_R1 then p.padRGUDLR=p.padRGUDLR&0b1110111111
    	elseif k==KeyCode.Y then p.padRGUDLR=p.padRGUDLR&0b0111111111	-- or k==KeyCode.BUTTON_L2
    	elseif k==KeyCode.Z then p.padRGUDLR=p.padRGUDLR&0b1011111111
    	else
    		print("Button Up ", i, k, findKeyCode(k))
    	end
    end
    My code that calls the above two routines for controllers - I do it this way so if I want I can feed in joypad moves pretty easily from other routines, you will have to modify it to work in your case as I have other code that checks for controller removal, priorities, etc But it should get you 'there'...
    	controller:addEventListener(Event.KEY_DOWN, function(e)
    	--	print("Button Down ", e.keyCode, findKeyCode(e.keyCode))
    		local id,id2=0,e.playerId
    		for loop=1,#controllerMap do
    			if id2==controllerMap[loop] then
    				id=loop
    				break
    			end
    		end
    		if id>=1 and id<=#players then
    			controllerDown(players[id],e.keyCode,id)
    		else
    			if find(lower(controller:getControllerName(e.playerId)),"remote")~=nil then
    				controllerDown(players[1],e.keyCode,0)
    			end
    		end
    	end)
     
    	controller:addEventListener(Event.KEY_UP, function(e)
    		local id,id2=0,e.playerId
    		for loop=1,#controllerMap do
    			if id2==controllerMap[loop] then
    				id=loop
    				break
    			end
    		end
    		if id>=1 and id
    This is the keyboard routine that listens for the keys and modifies the bits:
    stage:addEventListener(Event.KEY_DOWN,function(e)
    	idleCounter=0
    	local p=players[2]
    	--print("Button Down ", id, e.keyCode, e.realCode)
    	local k=e.keyCode
    	local beep=false
    	if k==KeyCode.BACK or k==KeyCode.ESC then back=true
    	elseif k==KeyCode.SPACE or k==KeyCode.CENTER or e.realCode==buttonA then p.padRGUDLR=p.padRGUDLR|0b100000 touchScreen=false
    	elseif k==KeyCode.ENTER or e.realCode==buttonB then p.padRGUDLR=p.padRGUDLR|0b010000 touchScreen=false
    	elseif k==KeyCode.UP then p.padRGUDLR=p.padRGUDLR|0b001000 touchScreen=false
    	elseif k==KeyCode.DOWN then p.padRGUDLR=p.padRGUDLR|0b000100 touchScreen=false
    	elseif k==KeyCode.LEFT then p.padRGUDLR=p.padRGUDLR|0b000010 touchScreen=false
    	elseif k==KeyCode.RIGHT then p.padRGUDLR=p.padRGUDLR|0b000001 touchScreen=false
    	elseif k==KeyCode.R and not recordMode then recordMode=true sfx[15].play=true
    	elseif k==KeyCode.NUM_1 then saveRecording(1)
    	elseif k==KeyCode.NUM_2 then saveRecording(2)
    	elseif k==KeyCode.L then
    		levelSkip=true
    	elseif k==KeyCode.Q then
    		gameQuit=true
    	end
    	--if not optionsMode then
    	--if k==KeyCode.P then setPause() end
     
    	--	if not pause then
     
    	--		if k==KeyCode.F then if setView(0) then beep=true end
    	--		elseif k==KeyCode.A then if setView(1) then beep=true end
    	--		elseif k==KeyCode.L then if setView(2) then beep=true end
    	--		elseif k==KeyCode.G then setGalacticChart()
    	--		elseif k==KeyCode.H then setHyperwarp()
    	--		elseif k==KeyCode.S then setShields()
    			--elseif k==KeyCode.B then megaBomb()
    			--elseif k==KeyCode.T then setTracking()
    	--		elseif k==KeyCode.C then setComputer()
    			--elseif k==KeyCode.M then setTarget()
    	--		elseif k==KeyCode.NUM_0 then setVelocity(0)
    	--		elseif k==KeyCode.NUM_1 then setVelocity(1)
    	--		elseif k==KeyCode.NUM_2 then setVelocity(2)
    	--		elseif k==KeyCode.NUM_3 then setVelocity(3)
    	--		elseif k==KeyCode.NUM_4 then setVelocity(4)
    	--		elseif k==KeyCode.NUM_5 then setVelocity(5)
    	--		elseif k==KeyCode.NUM_6 then setVelocity(6)
    	--		elseif k==KeyCode.NUM_7 then setVelocity(7)
    	--		elseif k==KeyCode.NUM_8 then setVelocity(8)
    	--		elseif k==KeyCode.NUM_9 then setVelocity(9)
    	--		end
    	--	end
    	--end
    	--if beep then sfx[1].play=true end
    end)
     
    stage:addEventListener(Event.KEY_UP,function(e)
    	local p=players[2]
    	local k=e.keyCode
    	--elseif k==KeyCode.F and pc then
    		--if fullScreen then fullScreen=false else fullScreen=true end
    		--application:setFullScreen(fullScreen)		
    	if k==KeyCode.SPACE or k==KeyCode.CENTER or e.realCode==buttonA then p.padRGUDLR=p.padRGUDLR&0b1111011111 touchScreen=false
    	elseif k==KeyCode.ENTER or e.realCode==buttonB then p.padRGUDLR=p.padRGUDLR&0b1111101111 touchScreen=false
    	elseif k==KeyCode.UP then p.padRGUDLR=p.padRGUDLR&0b1111110111 touchScreen=false
    	elseif k==KeyCode.DOWN then p.padRGUDLR=p.padRGUDLR&0b1111111011 touchScreen=false
    	elseif k==KeyCode.LEFT then p.padRGUDLR=p.padRGUDLR&0b1111111101 touchScreen=false
    	elseif k==KeyCode.RIGHT then p.padRGUDLR=p.padRGUDLR&0b1111111110 touchScreen=false
    	end
    end)
    Then in my main loop, because it's a bit pattern I can do debounce of all the joypad movement pretty easily in one go:
    		p.padDbRGUDLR=(p.padRGUDLR~p.padOld)&p.padRGUDLR
    		p.padOld=p.padRGUDLR
    You use padDbRGUDLR to see what buttons have just been pressed (not over a sustained period). Handy for up/down menus, non-repeating fire buttons, jumping, etc

    The bitpattern and the debounce method are things I've been doing ever since the mid 80s - but then in assembly code. In enemy 'brains' I sometimes make them generate the same bit patterns - these are then fed into the movement for the enemy. That way, a second player can 'take over' any of the enemies or you can use it for debugging how enemies should move.

    In the code you will also see touchscreen=false. This flags the game to remove any on screen touchscreen buttons. If the screen is touched then it sets the flag and puts the buttons back. The games start with touchscreen set to false.
    Coder, video game industry veteran (since the '80s, ❤'s assembler), arrested - never convicted hacker (in the '90s), dad of five, he/him (if that even matters!).
    https://deluxepixel.com
  • thanks @SinisterSoft , i've managed to make controller work, you can try it out:
    https://play.google.com/store/apps/details?id=com.longtitle.macimaze

    what i did not manage to do is to publish my app on the developer console to android tvs. by searching it seems this should be done in the pricing page but for a free app i do not see there anything that could do that. so if you know what i miss, let me know.
  • hgy29hgy29 Maintainer
    keszegh said:


    what i did not manage to do is to publish my app on the developer console to android tvs. by searching it seems this should be done in the pricing page but for a free app i do not see there anything that could do that. so if you know what i miss, let me know.

    I don't think there is a specific Android TV pricing, but maybe you need to enable TV compat in the manifest, in 'require' plugin
  • keszeghkeszegh Member
    edited October 2021
    @hgy29 , i did allow it in require.

    i refer to https://developer.android.com/distribute/best-practices/launch/distribute-tv
    in particular:

    "Before you can publish to Android TV users, you need to opt-in to Android TV from the Pricing and Distribution section of the Play Console. Opt-in means that you want your app to be made available to Android TV users through Google Play, and that your app meets the TV app quality guidelines. "

    however at the app pricing part of the developer console what i see is only this:
    "Your app is available for free on Google Play, and can't be changed to paid"

  • hgy29hgy29 Maintainer
    Strange, I don't remember having to do anything in the 'pricing' section of the store (my app is free). Uploading TV assets (screenshots, banner) on the store page was enough
  • i did not upload such things, i did not see tv specific upload parts. where should i do this?
  • hgy29hgy29 Maintainer
    Just below the screen shots for phone and tablet, on my console there is a section for Android TV screenshots
  • hgy29 said:

    Just below the screen shots for phone and tablet, on my console there is a section for Android TV screenshots

    i think i did not have such, but i will later doublecheck.
  • You need to add the require plugin and tick all the relevant tv options:



    Untick things you don't think should be mandatory - eg gps on a TV.

    Then upload the game to the play store. After that you will see the TV options available. At least that's the way it works for me.
    Coder, video game industry veteran (since the '80s, ❤'s assembler), arrested - never convicted hacker (in the '90s), dad of five, he/him (if that even matters!).
    https://deluxepixel.com
  • You also go through the TV approval service, they approve it differently than a normal app - there are slightly more rules to follow.
    Coder, video game industry veteran (since the '80s, ❤'s assembler), arrested - never convicted hacker (in the '90s), dad of five, he/him (if that even matters!).
    https://deluxepixel.com
  • my issue seems to stem from the fact that previously my app was not android tv targeted and now i want to extend to android tv's as well.
  • for most tv devices in device catalog it is written "Not opted in" for me, that's what i want to change. (there are some for which "Supported" is written).
  • i've asked support and they quickly told me the secret recipe i missed:

    "Kindly follow steps below on how to include your app to Android TV :
    Access the Play Console and select the app.
    Go to “Release” > "Setup" > "Advanced settings"
    Go to the "Release types" tab. (If you need to optimize the app for Android TV, Play Console will show the requirements.)"
  • now that this is done they rejected due to this:
    "No full-size app banner
    Your app does not contain a full-size app banner or is it not visible in the launcher. We are targeting 1080P, which we consider xhdpi. Apps should include the banner in the xhdpi (320 dpi) drawables folder with a size of (320px × 180px). Please refer to our Home Screen Banner and UI Patterns documentation."

    and indeed, even though i added a tv banner in gideros to my app it does not put it into the xhdpi folder, this probably should be corrected in next gideros version.
  • i thought to correct this issue by simply copying the banner in that folder too but then the aab cannot be uploaded anymore:
    "Your Android App Bundle has an invalid signature. Upload again with a valid signature."
    i guess there is some checksum or something preventing this, so really gideros itself should package the aab in a correct way.
    or is there some simple workaround meanwhile? thanks
  • hgy29hgy29 Maintainer
    Is this a new requirement ? I have successfully uploaded Aab to the store with older Gideros last year.
  • hgy29hgy29 Maintainer
    Btw if you feel it is missing, you can add it in your Template/APK.gexport file, around line 236.
  • thanks, i've added it and resubmitted, let's see.
    in fact they have noted another issue which i've not corrected:

    "The title should help users identify apps in the launcher. Please refer to our Visual Design and User Interaction documentation for more information.
    For example, your app title is not visible on the banner"

    but i hope this won't be a dealbreaker, i prefer my banner without the text.
  • SinisterSoftSinisterSoft Maintainer
    edited October 2021
    You need to appeal - let them know where the banner is - the manifest tells them. Whoever refused it didn't look at the manifest, they just assumed it would be in that folder.
    Coder, video game industry veteran (since the '80s, ❤'s assembler), arrested - never convicted hacker (in the '90s), dad of five, he/him (if that even matters!).
    https://deluxepixel.com
  • @SinisterSoft , good idea, although i hate to argue with these reviewers. yet i've resubmitted already, so next time.
    perhaps they will still have issue with having no name in the banner even though many other apps are like this.
  • I had this happen to me before - you do need the name, and the appeal about where the image is does work. It gets raised to someone higher. The person who looked at yours will be new or lazy. :)
    Coder, video game industry veteran (since the '80s, ❤'s assembler), arrested - never convicted hacker (in the '90s), dad of five, he/him (if that even matters!).
    https://deluxepixel.com
  • @SinisterSoft , ok let's see, if i need to put the title in the image, i will use the occasion to complain about the banner placement as well.
Sign In or Register to comment.