How to handle tap events for an interactive watch faces with androidx.wear? - wear-os

What is the correct way of handling tap events with the new androidx.wear.watchface libraries? I was doing this with the now deprecated android.support:wearable libraries without any problem with Java (using onTapCommand). Now, everything seems to be quite different, especially since the documentation and examples seem to be available only in Kotlin. Also, I can't find any example which properly shows how the functions are used.
The documentation mentions setTapListener, TapListener. And then there are the functions onTap, onTapEvent and onTapCommand. This seems very confusing.
Could somebody put here a small example? Or point me to a working example on the internet?
Any help much appreciated!

Implementing this seemed to work for me
https://developer.android.com/reference/androidx/wear/watchface/WatchFace.TapListener
My code:
class WatchFaceRenderer(...): Renderer.CanvasRenderer(...), WatchFace.TapListener {
override fun onTapEvent(tapType: Int, tapEvent: TapEvent, complicationSlot: ComplicationSlot?) {
if (tapType == TapType.UP)
// do something
invalidate()
}
}
class Service : WatchFaceService() {
override suspend fun createWatchFace(
surfaceHolder: SurfaceHolder,
watchState: WatchState,
complicationSlotsManager: ComplicationSlotsManager,
currentUserStyleRepository: CurrentUserStyleRepository
): WatchFace {
val renderer = WatchFaceRenderer(
context = applicationContext,
surfaceHolder = surfaceHolder,
watchState = watchState,
currentUserStyleRepository = currentUserStyleRepository,
canvasType = CanvasType.SOFTWARE,
)
return WatchFace(WatchFaceType.ANALOG, renderer).setTapListener(renderer)
}
}

Related

Optaplanner: How to get solver instance in Quarkus

I am using Quarkus optaplanner, so instead of using SolverFactory to build a solver, I us ethe Quarkus way to inject a solverManager then let it solve the problem:
val solverJob: SolverJob<SolarDesign, UUID> = solverManager.solve(problemId, problem)
But I want to still be able to addEventListener like:
solver.addEventListener(SolverEventListener<SolarDesign>() {
fun bestSolutionChanged(event: BestSolutionChangedEvent<MyProblem>) {
val solution = event.getNewBestSolution()
if (solution.score.isFeasible()) {
println("found new best solution")
println(solution)
}
}
})
Question is how do I get a solver instance in Quarkus optaplanner so I can use it to addEventListener? It does not seem to be doable from solverManager.
Thanks
Yes, that is possible with SolverManager and you don't need to obtain a Solver instance.
Use SolverManager.solverAndListen(problemId, problemFinder, bestSolutionConsumer). The third argument is a consumer where you can do whatever you want with each best solution that is found. It could look something like this in your case:
fun solve() {
val solverJob: SolverJob<SolarDesign, UUID> = solverManager
.solveAndListen(problemId, { problemId -> problem }, this::printSolution)
}
fun printSolution(solution: SolarDesign) {
if (solution.score.isFeasible()) {
println("found new best solution")
println(solution)
}
}
Find more details in this section about SolverManager.
The following example shows how to obtain a Solver instance in Quarkus. The SolverManager API does not cover this option so the alternative approach is to inject a SolverFactory, use it to build a Solver instance and manage its lifecycle yourself.
The example also shows how to get access to the Phase lifecycle. It can be useful for experiments during development. However, that's only possible through casting the solver instance to DefaultSolver, which is an internal API. There are no backward compatibility guarantees on the internal classes. They can significantly change in future minor releases and cause compilation errors if you use them in your code. Do not use it in production.
class MySolverResource(private val solverFactory: SolverFactory<SolarDesign>) {
fun solve(problemId : UUID) {
// WARNING: DefaultSolver is OptaPlanner's internal class.
// Backward compatibility is not guaranteed.
// Its usage is totally not recommended.
val solver: DefaultSolver<SolarDesign> = solverFactory.buildSolver() as DefaultSolver<SolarDesign>
solver.addPhaseLifecycleListener(object : PhaseLifecycleListenerAdapter<SolarDesign>() {
override fun stepEnded(stepScope: AbstractStepScope<SolarDesign>) {
printSolution(stepScope.createOrGetClonedSolution())
}
})
solver.solve(loadProblem(problemId))
}
fun printSolution(solution: SolarDesign) {}
}

Is CoroutineScope(SupervisorJob()) runs in Main scope?

I was doing this code lab
https://developer.android.com/codelabs/android-room-with-a-view-kotlin#13
and having a question
class WordsApplication : Application() {
// No need to cancel this scope as it'll be torn down with the process
val applicationScope = CoroutineScope(SupervisorJob())
// Using by lazy so the database and the repository are only created when they're needed
// rather than when the application starts
val database by lazy { WordRoomDatabase.getDatabase(this, applicationScope) }
val repository by lazy { WordRepository(database.wordDao()) }
}
private class WordDatabaseCallback(
private val scope: CoroutineScope
) : RoomDatabase.Callback() {
override fun onCreate(db: SupportSQLiteDatabase) {
super.onCreate(db)
INSTANCE?.let { database ->
scope.launch {
var wordDao = database.wordDao()
// Delete all content here.
wordDao.deleteAll()
// Add sample words.
var word = Word("Hello")
wordDao.insert(word)
word = Word("World!")
wordDao.insert(word)
// TODO: Add your own words!
word = Word("TODO!")
wordDao.insert(word)
}
}
}
}
this is the code I found, as you can see, it is directly calling scope.launch(...)
my question is that:
isn't all the Room operations supposed to run in non-UI scope? Could someone help me to understand this? thanks so much!
Is CoroutineScope(SupervisorJob()) runs in Main scope?
No. By default CoroutineScope() uses Dispatchers.Default, as can be found in the documentation:
CoroutineScope() uses Dispatchers.Default for its coroutines.
isn't all the Room operations supposed to run in non-UI scope?
I'm not very familiar specifically with Room, but generally speaking it depends if the operation is suspending or blocking. You can run suspend functions from any dispatcher/thread. deleteAll() and insert() functions in the example are marked as suspend, therefore you can run them from both UI and non-UI threads.

Spring Webflux throws a "block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-nio-2"

I have a small issue with doing a blocking operation in Spring Webflux. I retrieve a list of article documents and from the list of article documents, i would like to update another object.
When i execute the below, sometimes it works and sometimes it throws a "block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-nio-2". Could you please suggest how to fix. I dont really want to make it blocking but not sure how to proceed. There are similar threads in stackoverflow but not with respective to my requirement.
It would be really nice if someone could suggest a way to work around ?
private OrderInfo setPrices(final OrderInfo orderInfo) {
final List<ArticleDocument> articleDocuments = getArticleDocuments(orderInfo).block(); // Problematic line
for (ArticleDocument article : articleDocuments) {
//Update orderInfo based on one of the article price and few more condition.
}
return orderInfo;
}
private Mono<List<ArticleDocument>> getArticleDocuments(final OrderInfo orderInfo) {
return this.articleRepository.findByArticleName(orderInfo.getArticleName()).collectList();
}
It has to be something like this. Please take note that I have not tested it on my IDE. To modify anything please comment and figure it out together.
private Mono<OrderInfo> setPrices(final OrderInfo orderInfo) {
getArticleDocuments(orderInfo)
.map(articleDocuments -> {
articleDocuments.forEach(article -> // UPDATE AS YOU NEED);
return orderInfo;
});
private Mono<List<ArticleDocument>> getArticleDocuments(final OrderInfo orderInfo) {
return this.articleRepository.findByArticleName(orderInfo.getArticleName()).collectList();
}
Remember, you have to put everything under chaining. that's why you have to return Mono<OrderInfo> instead of OrderInfo from setPrices method. If you find my suggested code is tough to adapt to your current coding structure, you can show me the full code. Let's find out we can build a good chain or not.
BTW, you were using getArticleDocuments(orderInfo).block();. See? you were using .block()? Don't do that in a chain. don't ever block anything in a request to the response chain process. you will return mono or flux from the controller and everything will be handled by webflux

How to register a Renderer with CRaSH

After reading about the remote shell in the Spring Boot documentation I started playing around with it. I implemented a new Command that produces a Stream of one of my database entities called company.
This works fine. So I want to output my stream of companies in the console. This is done by calling toString() by default. While this seams reasonable there is also a way to get nicer results by using a Renderer.
Implementing one should be straight forward as I can delegate most of the work to one of the already existing ones. I use MapRenderer.
class CompanyRenderer extends Renderer<Company> {
private final mapRenderer = new MapRenderer()
#Override Class<Company> getType() { Company }
#Override LineRenderer renderer(Iterator<Company> stream) {
def list = []
stream.forEachRemaining({
list.add([id: it.id, name: it.name])
})
return mapRenderer.renderer(list.iterator())
}
}
As you can see I just take some fields from my entity put them into a Mapand then delegate to a instance of MapRenderer to do the real work.
TL;DR
Only problem is: How do I register my Renderer with CRaSH?
Links
Spring Boot documentation http://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-remote-shell.html
CRaSH documentation (not helping) http://www.crashub.org/1.3/reference.html#_renderers

Fetch windows setting value

How do I fetch the Measurement System setting value in javascript?
I'm guessing that it would be throw some WinJS call.
The logical place would be Windows.Globalization, but not seeing if offered there. One pretty simple workaround - faster to write than to research the setting :) is to create a Windows Runtime Component in C# that calls in to System.Globalization:
namespace WindowsRuntimeComponent
{
public sealed class RegionalSettings
{
public bool isMetric()
{
return System.Globalization.RegionInfo.CurrentRegion.IsMetric;
}
}
}
Then add as a reference to your JavaScript app and invoke there:
var r = new WindowsRuntimeComponent.RegionalSettings;
var isMetric = r.isMetric();

Resources