-
-
Save KieronQuinn/c9950f3ee09e11f305ce16e7f48f03b8 to your computer and use it in GitHub Desktop.
package com.kieronquinn.app.controltest | |
import android.app.PendingIntent | |
import android.app.Service | |
import android.content.ComponentName | |
import android.content.Intent | |
import android.content.res.ColorStateList | |
import android.graphics.Color | |
import android.graphics.drawable.Icon | |
import android.os.Bundle | |
import android.os.IBinder | |
import android.provider.Settings | |
import android.service.controls.Control | |
import android.service.controls.ControlsProviderService | |
import android.service.controls.DeviceTypes | |
import android.service.controls.actions.BooleanAction | |
import android.service.controls.actions.ControlAction | |
import android.service.controls.actions.FloatAction | |
import android.service.controls.templates.* | |
import android.util.Log | |
import android.widget.Toast | |
import androidx.annotation.RequiresApi | |
import java.lang.reflect.Method | |
import java.util.concurrent.Flow | |
import java.util.function.Consumer | |
/* | |
Note: This was originally created before the API became public, so contains some hardcoded values rather than referring to the classes. | |
Please don't just copy paste this, use it to see how the API works. | |
*/ | |
@RequiresApi(30) | |
class ControlTile : ControlsProviderService() { | |
private val screenBrightness: Int | |
get() = Settings.System.getInt(this.contentResolver, Settings.System.SCREEN_BRIGHTNESS) | |
private val controlList: List<Control> | |
get() { | |
val mutableList = ArrayList<Control>() | |
mutableList.add { | |
val control = Control.StatefulBuilder( | |
"Button", | |
PendingIntent.getActivity( | |
this, | |
0, | |
Intent(this, MainActivity::class.java), | |
PendingIntent.FLAG_CANCEL_CURRENT | |
) | |
) | |
control.setTitle("Switch Button") | |
control.setSubtitle("Test button") | |
control.setDeviceType(DeviceTypes.TYPE_GENERIC_ON_OFF) | |
control.setControlId("button") | |
control.setStatus(1) | |
val controlButton = ControlButton(true, "button") | |
control.setControlTemplate(ToggleTemplate("button", controlButton)) | |
control.build() | |
} | |
mutableList.add { | |
val control = Control.StatefulBuilder( | |
"brightness", | |
PendingIntent.getActivity( | |
this, | |
0, | |
Intent(this, MainActivity::class.java), | |
PendingIntent.FLAG_CANCEL_CURRENT | |
) | |
) | |
control.setTitle("Brightness") | |
control.setSubtitle("Slider") | |
control.setDeviceType(DeviceTypes.TYPE_LIGHT) | |
control.setCustomIcon(Icon.createWithResource(this, R.drawable.ic_brightness)) | |
control.setCustomColor(ColorStateList.valueOf(Color.RED)) | |
control.setControlId("brightness") | |
control.setStatus(1) | |
val controlButton = ControlButton(true, "brightness") | |
control.setControlTemplate( | |
ToggleRangeTemplate( | |
"brightness", | |
controlButton, | |
RangeTemplate("range", 0f, 255f, screenBrightness.toFloat(), 5f, null) | |
) | |
) | |
control.build() | |
} | |
return mutableList | |
} | |
override fun createPublisherForAllAvailable(): Flow.Publisher<Control> { | |
return Flow.Publisher { | |
for (control in controlList) { | |
it.onNext(control) | |
} | |
it.onComplete() | |
} | |
} | |
override fun performControlAction( | |
controlId: String, | |
action: ControlAction, | |
consumer: Consumer<Int> | |
) { | |
if (controlId == "brightness") { | |
if (action is FloatAction) { | |
val value = action.newValue | |
Settings.System.putInt( | |
this.contentResolver, | |
Settings.System.SCREEN_BRIGHTNESS, | |
value.toInt() | |
) | |
return | |
} else if (action is BooleanAction) { | |
startActivity(Intent(Settings.ACTION_DISPLAY_SETTINGS).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)) | |
sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) | |
} | |
} | |
Log.d( | |
"ControlTest", | |
"performControlAction $controlId ${action.toString()} ${consumer.toString()}" | |
) | |
Toast.makeText(this, "Clicked", Toast.LENGTH_LONG).show() | |
consumer.accept(ControlAction.RESPONSE_OK) | |
} | |
override fun createPublisherFor(controlIds: MutableList<String>): Flow.Publisher<Control> { | |
Log.d("ControlTest", "publisherFor ${controlIds.toString()}") | |
return Flow.Publisher { | |
for (control in controlList) { | |
if (controlIds.contains(control.controlId)) { | |
Log.d("ControlTest", "Found ${control.controlId}") | |
it.onSubscribe(object : Flow.Subscription { | |
override fun cancel() { | |
Log.d("ControlTest", "cancel") | |
} | |
override fun request(p0: Long) { | |
Log.d("ControlTest", "request $p0") | |
} | |
}) | |
it.onNext(control) | |
} | |
} | |
} | |
} | |
private fun ArrayList<Control>.add(inline: () -> Control) { | |
this.add(inline.invoke()) | |
} | |
} |
Can you please provide a full sample for it on Github? Maybe of the minimal stuff to make a tile on the power menu?
Seems you have a bug on your code. Long pressing the tiles should open some Activity, and you need to add FLAG_ACTIVITY_NEW_TASK to the Intent.
This was meant to just be a dirty example during the previews and betas, not a full sample project. The code is out of date, launching the activity previously worked as is shown in the video on here which is running this exact code: https://www.xda-developers.com/android-11-quick-control-shortcuts-power-menu/
I don't see long pressing on the tiles. Maybe on 0:19:
https://youtu.be/zhJbzt2Ts5E?t=19
But then it becomes black.
In any case, Tasker app seems to have the same issue, and as a result I also found this crash of the OS when developers don't use it right:
https://issuetracker.google.com/issues/169658959
Yes, that is long press (there's no other interaction there that could launch anything). At that time it launched the activity in that windowed mode, but didn't work correctly, hence the black.
ok
Hi! In your example not working switching between on and off on switch button(background not switching). Do you know how to improve this issue?
Found an answer by decompiling Google Home app.