LAMW Timer service
lazarus / 43-Android
----------------------------------------------------------------------
Segator · 2020-09-13 19:17
Hi @jmpessoa, it's possible to implement a jtimerservice based on
jtimer?, the proposed is keep the app running and do general tasks in
the background usind the broadcast from the timer service like
jdownloadservice but continuously.
----------------------------------------------------------------------
jmpessoa · 2020-09-13 19:39
Can you, please, point out some java/android example?
----------------------------------------------------------------------
Segator · 2020-09-13 21:08
i think that it's possible using de jdownloadservice service and
replace the downloaded funtion with the jtimer component, i don't see
any example but you can based on jdownloadservice not download
anything only send a broadcast with the ontimer event.
----------------------------------------------------------------------
Segator · 2020-09-14 14:25
Hi i found this example on
https://gist.github.com/mjohnsullivan/403149218ecb480e7759
Example of how to create a long running timer service that survives
activity destruction by moving to the foreground, and back to the
background when a new activity bind to it.
Code: Pascal [Select][+][-]window.onload = function(){var x1 =
document.getElementById("main_content_section"); if (x1) { var x =
document.getElementsByClassName("geshi");for (var i = 0; i ////
Copyright 2015 Google Inc. All Rights Reserved.//// Licensed
under the Apache License, Version 2.0 (the "License");// you may
not use this file except in compliance with the License.// You may
obtain a copy of the License at////
http://www.apache.org/licenses/LICENSE-2.0//// Unless required by
applicable law or agreed to in writing, software// distributed
under the License is distributed on an "AS IS" BASIS,// WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.//
See the License for the specific language governing permissions and//
limitations under the License. package
com.example.google.timerservice; import
android.app.Notification;import android.app.PendingIntent;import
android.app.Service;import android.content.ComponentName;import
android.content.Intent;import android.content.ServiceConnection;import
android.os.Binder;import android.os.Bundle;import
android.os.Handler;import android.os.IBinder;import
android.os.Message;import
android.support.v4.app.NotificationCompat;import
android.support.v7.app.AppCompatActivity;import
android.util.Log;import android.view.View;import
android.widget.Button;import android.widget.TextView; import
java.lang.ref.WeakReference; /** * Example activity to manage a long-
running timer, which survives the destruction of the activity * by
using a foreground service and notification * * Add the following to
the manifest: * */ public class TimerActivity extends
AppCompatActivity { private static final String TAG =
TimerActivity.class.getSimpleName(); private TimerService
timerService; private boolean serviceBound; private Button
timerButton; private TextView timerTextView; // Handler to
update the UI every second when the timer is running private final
Handler mUpdateTimeHandler = new UIUpdateHandler(this); //
Message type for the handler private final static int
MSG_UPDATE_TIME = 0; protected void onCreate(Bundle
savedInstanceState) { super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); timerButton =
(Button)findViewById(R.id.timer_button); timerTextView =
(TextView)findViewById(R.id.timer_text_view); } @Override
protected void onStart() { super.onStart(); if
(Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG, "Starting
and binding service"); } Intent i = new Intent(this,
TimerService.class); startService(i); bindService(i,
mConnection, 0); } @Override protected void onStop() {
super.onStop(); updateUIStopRun(); if (serviceBound) {
// If a timer is active, foreground the service, otherwise
kill the service if (timerService.isTimerRunning()) {
timerService.foreground(); } else {
stopService(new Intent(this, TimerService.class));
} // Unbind the service
unbindService(mConnection); serviceBound = false; }
} public void runButtonClick(View v) { if (serviceBound
&& !timerService.isTimerRunning()) { if
(Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG,
"Starting timer"); } timerService.startTimer();
updateUIStartRun(); } else if (serviceBound &&
timerService.isTimerRunning()) { if (Log.isLoggable(TAG,
Log.VERBOSE)) { Log.v(TAG, "Stopping timer");
} timerService.stopTimer(); updateUIStopRun();
} } /** * Updates the UI when a run starts */
private void updateUIStartRun() {
mUpdateTimeHandler.sendEmptyMessage(MSG_UPDATE_TIME);
timerButton.setText(R.string.timer_stop_button); } /** *
Updates the UI when a run stops */ private void
updateUIStopRun() {
mUpdateTimeHandler.removeMessages(MSG_UPDATE_TIME);
timerButton.setText(R.string.timer_start_button); } /** *
Updates the timer readout in the UI; the service must be bound */
private void updateUITimer() { if (serviceBound) {
timerTextView.setText(timerService.elapsedTime() + " seconds");
} } /** * Callback for service binding, passed to
bindService() */ private ServiceConnection mConnection = new
ServiceConnection() { @Override public void
onServiceConnected(ComponentName className, IBinder service) {
if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG,
"Service bound"); }
TimerService.RunServiceBinder binder = (TimerService.RunServiceBinder)
service; timerService = binder.getService();
serviceBound = true; // Ensure the service is not in the
foreground when bound timerService.background();
// Update the UI if the service is already running the timer
if (timerService.isTimerRunning()) {
updateUIStartRun(); } } @Override
public void onServiceDisconnected(ComponentName name) { if
(Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG,
"Service disconnect"); } serviceBound = false;
} }; /** * When the timer is running, use this handler
to update * the UI every second to show timer progress */
static class UIUpdateHandler extends Handler { private final
static int UPDATE_RATE_MS = 1000; private final
WeakReference activity;
UIUpdateHandler(TimerActivity activity) { this.activity =
new WeakReference<>(activity); } @Override
public void handleMessage(Message message) { if
(MSG_UPDATE_TIME == message.what) { if
(Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG,
"updating time"); }
activity.get().updateUITimer();
sendEmptyMessageDelayed(MSG_UPDATE_TIME, UPDATE_RATE_MS);
} } } /** * Timer service tracks the start and end
time of timer; service can be placed into the * foreground to
prevent it being killed when the activity goes away */ public
static class TimerService extends Service { private static
final String TAG = TimerService.class.getSimpleName(); //
Start and end times in milliseconds private long startTime,
endTime; // Is the service tracking time? private
boolean isTimerRunning; // Foreground notification id
private static final int NOTIFICATION_ID = 1; // Service
binder private final IBinder serviceBinder = new
RunServiceBinder(); public class RunServiceBinder extends
Binder { TimerService getService() { return
TimerService.this; } } @Override
public void onCreate() { if (Log.isLoggable(TAG,
Log.VERBOSE)) { Log.v(TAG, "Creating service");
} startTime = 0; endTime = 0;
isTimerRunning = false; } @Override public int
onStartCommand(Intent intent, int flags, int startId) { if
(Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG,
"Starting service"); } return
Service.START_STICKY; } @Override public IBinder
onBind(Intent intent) { if (Log.isLoggable(TAG,
Log.VERBOSE)) { Log.v(TAG, "Binding service");
} return serviceBinder; } @Override
public void onDestroy() { super.onDestroy(); if
(Log.isLoggable(TAG, Log.VERBOSE)) { Log.v(TAG,
"Destroying service"); } } /** *
Starts the timer */ public void startTimer() {
if (!isTimerRunning) { startTime =
System.currentTimeMillis(); isTimerRunning = true;
} else { Log.e(TAG, "startTimer
request for an already running timer"); } }
/** * Stops the timer */ public void
stopTimer() { if (isTimerRunning) { endTime
= System.currentTimeMillis(); isTimerRunning = false;
} else { Log.e(TAG, "stopTimer
request for a timer that isn't running"); } }
/** * @return whether the timer is running */
public boolean isTimerRunning() { return isTimerRunning;
} /** * Returns the elapsed time *
* @return the elapsed time in seconds */ public long
elapsedTime() { // If the timer is running, the end time
will be zero return endTime > startTime ?
(endTime - startTime) / 1000 :
(System.currentTimeMillis() - startTime) / 1000; } /**
* Place the service into the foreground */
public void foreground() { startForeground(NOTIFICATION_ID,
createNotification()); } /** * Return the
service to the background */ public void background()
{ stopForeground(true); } /** *
Creates a notification for placing the service into the foreground
* * @return a notification for interacting with the
service when in the foreground */ private Notification
createNotification() { NotificationCompat.Builder builder =
new NotificationCompat.Builder(this)
.setContentTitle("Timer Active")
.setContentText("Tap to return to the timer")
.setSmallIcon(R.mipmap.ic_launcher); Intent resultIntent =
new Intent(this, TimerActivity.class); PendingIntent
resultPendingIntent =
PendingIntent.getActivity(this, 0, resultIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(resultPendingIntent); return
builder.build(); } } }
----------------------------------------------------------------------
Segator · 2020-09-15 21:23
i am go to try modify the jtimer with the jdownloadservice method and
class to improve a jtimerservice
----------------------------------------------------------------------
jmpessoa · 2020-09-16 02:33
Yes,
mimic "jdownloadservice" can be more easy!
----------------------------------------------------------------------
Segator · 2020-09-17 13:53
I make some progress, i have a concept test attached here, but i have
some questions, when you use other service like USSD service and do
this:
Code: Pascal [Select][+][-]window.onload = function(){var x1 =
document.getElementById("main_content_section"); if (x1) { var x =
document.getElementsByClassName("geshi");for (var i = 0; i
jBroadcastReceiver1.Unregister();
the service is stopped?, auto destroy? or just you no listen then
anymore?.
----------------------------------------------------------------------
jmpessoa · 2020-09-17 16:59
Quoteor just you no listen then anymore?.
Yes.
----------------------------------------------------------------------
Segator · 2020-10-13 17:54
Hi all, i continue to trying implement a timer service for lamw, i
make some progress but in the wrong direction, i finish the componet
but when you using the class IntentService that is not a realy goog
service to work in the background with a timer, it work but when you
remove the main application from the recent running app the service
stop, we must use the extends Service or the JobIntentService now hi
is the problem:
jTimerService.java
Code: Pascal [Select][+][-]window.onload = function(){var x1 =
document.getElementById("main_content_section"); if (x1) { var x =
document.getElementsByClassName("geshi");for (var i = 0; i package
com.example.apptimerservicedemo1; import
java.lang.reflect.Field;import java.util.Random;import
android.app.PendingIntent;import android.app.Service;import
android.content.Context;import android.content.Intent;import
android.os.Environment;import android.os.Handler;import
android.os.Build;import android.util.Log;import
android.os.Binder;import android.os.IBinder;import
android.widget.Toast; /*Draft java code by "Lazarus Android Module
Wizard" [5/26/2016 20:15:41]*//*https://github.com/jmpessoa/lazandroid
modulewizard*//*jControl template*/ public class jTimerService extends
Service { private long pascalObj = 0; // Pascal Object
private Controls controls = null; // Control Class -> Java/Pascal
Interface ... private Context context = null; private int
result = 0; //0 = fail; -1 = ok! private String mIntentAction;
@Override public IBinder onBind(Intent intent) { return
null; } @Override public void onCreate() {
Toast.makeText(this, "Service Created", Toast.LENGTH_LONG).show();
//myPlayer = MediaPlayer.create(this, R.raw.sun);
//myPlayer.setLooping(false); // Set looping } @Override public
void onStart(Intent intent, int startid) { Toast.makeText(this,
"Service Started", Toast.LENGTH_LONG).show();
//myPlayer.start(); } @Override public void onDestroy() {
Toast.makeText(this, "Service Stopped", Toast.LENGTH_LONG).show();
//myPlayer.stop(); } @Override public int
onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(controls.activity,
"StartCommand",Toast.LENGTH_SHORT).show();
//super.onStartCommand(intent, flags, startId);
//startTimer(); //SetEnabled(true); return START_STICKY;
} //GUIDELINE: please, preferentially, init all yours params names
with "_", ex: int _flag, String _hello ... public
jTimerService(Controls _ctrls, long _Self) { //Add more others news
"_xxx" params if needed! //super("jTimerService");
//super(_ctrls.activity); super(); context =
_ctrls.activity; pascalObj = _Self; controls = _ctrls;
} public jTimerService() { } public void jFree() { //free
local objects... } //write others [public] methods code
here...... //GUIDELINE: please, preferentially, init all yours
params names with "_", ex: int _flag, String _hello ... ///////////
///////////////////////timer////////////////////////////////
//Property private boolean mEnabled = false; // default :
false private int mInterval = 1000; // 1000msec
//Java Object private Handler mHandler = null; private
RunnableStop mRunnable = null; public class RunnableStop implements
Runnable { boolean isEnabled; public RunnableStop() {
isEnabled = true; } @Override public void run() {
if( !isEnabled ) return; //Start("", mIntentAction);
//publishResults( -1, mIntentAction,
(System.currentTimeMillis())); if ((mHandler != null) &&
isEnabled) mHandler.postDelayed(mRunnable,
mInterval); } public void disable() { isEnabled =
false; } } //////////////////////////////////////////////////
///////////////////// //@Override //protected void
onHandleIntent(Intent intent) { // will be called asynchronously by
Android // //TODO Auto-generated method stub //
//String urlPath = intent.getStringExtra("URL"); //
//String fileName = intent.getStringExtra("FILENAME"); //
//String filePath = intent.getStringExtra("PATH"); //
String iaction = intent.getStringExtra("ACTION"); // //
long startTime = System.currentTimeMillis(); // // result
= -1; //Activity.RESULT_OK; // // startTime =
System.currentTimeMillis(); // // publishResults( result,
iaction, (System.currentTimeMillis() - startTime)); //} public
void publishResults( int result, String _action, long time) {
//Implicit intents specify the action which should be performed and
optionally data which //provides content for the action.
Intent intent = new Intent(_action); if (result
== -1) intent.putExtra("Result", "RESULT_OK");
else intent.putExtra("Result", "RESULT_CANCELED");
intent.putExtra("ElapsedTimeInSeconds", (int)time/1000); //long
sendBroadcast(intent); } //Method to start the service
public void Start(String _intentActionNotification, int flags, int
startId) { //mURL = _urlString; mIntentAction
= _intentActionNotification; mHandler = new Handler();
//SetEnabled(true); //Explicit intents explicitly
define the component which should be called by the Android system,
//by using the Java class as identifier //Create
an intent for a specific component. Intent intent = new
Intent(context, jTimerService.class);
//intent.putExtra("FILENAME", mFileSaveAs); //
//intent.putExtra("URL", mURL); //intent.putExtra("PATH",
mFILEPATH); intent.putExtra("ACTION", mIntentAction);
controls.activity.startService(intent);
//getApplicationContext().startService(intent);
//startService(intent);
//context.onStartCommand(intent); } public void SetInterval(int
interval) { mInterval = interval; } public void
SetEnabled(boolean _enabled) { if (mEnabled == _enabled)
return; mEnabled = _enabled; if (mEnabled) {
if( mRunnable == null ){ mRunnable = new
RunnableStop(); mHandler.postDelayed(mRunnable,
mInterval); } } else{ if( mRunnable != null
){ mRunnable.disable(); mRunnable =
null; mHandler.removeCallbacksAndMessages(null);
} } } }
timerservice.pas
Code: Pascal [Select][+][-]window.onload = function(){var x1 =
document.getElementById("main_content_section"); if (x1) { var x =
document.getElementsByClassName("geshi");for (var i = 0; i unit
timerservice; {$mode delphi} interface uses Classes, SysUtils,
And_jni, AndroidWidget; type {Draft Component code by "Lazarus Android
Module Wizard" [5/26/2016 23:50:23]}{https://github.com/jmpessoa/lazan
droidmodulewizard} {jControl template} jTimerService =
class(jControl) private public constructor Create(AOwner:
TComponent); override; destructor Destroy; override; procedure
Init(refApp: jApp); override; function jCreate(): jObject;
procedure jFree(); procedure Start(_intentActionNotification:
string; _flags:integer; _startId:integer); procedure
SetEnabled(_enable:boolean); procedure
SetInterval(_interval:integer); published end; function
jTimerService_jCreate(env: PJNIEnv;_Self: int64; this: jObject):
jObject;procedure jTimerService_jFree(env: PJNIEnv; _jtimerservice:
JObject);procedure jTimerService_Start(env: PJNIEnv; _jtimerservice:
JObject;_intentAction: string; _flags:integer;
_startId:integer);procedure jTimerService_SetEnabled(env: PJNIEnv;
_jtimerservice: JObject; _enable: boolean);procedure
jTimerService_SetInterval(env: PJNIEnv; _jtimerservice: JObject;
_interval: integer); implementation {--------- jTimerService
--------------} constructor jTimerService.Create(AOwner:
TComponent);begin inherited Create(AOwner);//your code
here....end; destructor jTimerService.Destroy;begin if not
(csDesigning in ComponentState) then begin if FjObject <> nil
then begin jFree(); FjObject:= nil; end; end;
//you others free code here...' inherited Destroy;end; procedure
jTimerService.Init(refApp: jApp);begin if FInitialized then Exit;
inherited Init(refApp); //set default ViewParent/FjPRLayout as
jForm.View! //your code here: set/initialize create params....
FjObject := jCreate(); if FjObject = nil then exit; FInitialized:=
True;end; function jTimerService.jCreate(): jObject;begin Result:=
jTimerService_jCreate(FjEnv, int64(Self), FjThis);end; procedure
jTimerService.jFree();begin //in designing component state: set value
here... if FInitialized then jTimerService_jFree(FjEnv,
FjObject);end; procedure
jTimerService.Start(_intentActionNotification: string; _flags:integer;
_startId:integer);begin //in designing component state: set value
here... if FInitialized then jTimerService_Start(FjEnv,
FjObject,_intentActionNotification, _flags, _startId);end; procedure
jTimerService.SetEnabled(_enable: boolean);begin //in designing
component state: set value here... if FInitialized then
jTimerService_SetEnabled(FjEnv, FjObject, _enable);end; procedure
jTimerService.SetInterval(_interval: integer);begin //in designing
component state: set value here... if FInitialized then
jTimerService_SetInterval(FjEnv, FjObject, _interval);end; {--------
jTimerService_JNI_Bridge ----------} function
jTimerService_jCreate(env: PJNIEnv;_Self: int64; this: jObject):
jObject;var jParams: array[0..0] of jValue; jMethod: jMethodID=nil;
jCls: jClass=nil;begin jParams[0].j:= _Self; jCls:=
Get_gjClass(env); jMethod:= env^.GetMethodID(env, jCls,
'jTimerService_jCreate', '(J)Ljava/lang/Object;'); Result:=
env^.CallObjectMethodA(env, this, jMethod, @jParams); Result:=
env^.NewGlobalRef(env, Result);end; (*//Please, you need insert:
public java.lang.Object jTimerService_jCreate(long _Self) {
return (java.lang.Object)(new jTimerService(this,_Self)); } //to end
of "public class Controls" in "Controls.java"*) procedure
jTimerService_jFree(env: PJNIEnv; _jtimerservice: JObject);var
jMethod: jMethodID=nil; jCls: jClass=nil;begin jCls:=
env^.GetObjectClass(env, _jtimerservice); jMethod:=
env^.GetMethodID(env, jCls, 'jFree', '()V'); env^.CallVoidMethod(env,
_jtimerservice, jMethod); env^.DeleteLocalRef(env,
jCls);end; procedure jTimerService_Start(env: PJNIEnv;
_jtimerservice: JObject; _intentAction: string; _flags:integer;
_startId:integer);var jParams: array[0..2] of jValue; jMethod:
jMethodID=nil; jCls: jClass=nil;begin jParams[0].l:=
env^.NewStringUTF(env, PChar(_intentAction)); jParams[1].i :=
_flags; jParams[2].i := _startId; jCls:= env^.GetObjectClass(env,
_jtimerservice); jMethod:= env^.GetMethodID(env, jCls, 'Start',
'(Ljava/lang/String;Ljava/lang/String;)(II)V');
env^.CallVoidMethodA(env, _jtimerservice, jMethod, @jParams);
env^.DeleteLocalRef(env,jParams[0].l); env^.DeleteLocalRef(env,
jCls);end; procedure jTimerService_SetEnabled(env: PJNIEnv;
_jtimerservice: JObject; _enable: boolean);var jParams: array[0..0]
of jValue; jMethod: jMethodID=nil; jCls: jClass=nil;begin
jParams[0].z := JBool(_enable); jCls:= env^.GetObjectClass(env,
_jtimerservice); jMethod:= env^.GetMethodID(env, jCls, 'SetEnabled',
'(Z)V'); env^.CallVoidMethodA(env, _jtimerservice, jMethod,
@jParams); env^.DeleteLocalRef(env, jCls);end; procedure
jTimerService_SetInterval(env: PJNIEnv; _jtimerservice: JObject;
_interval: integer);var jParams: array[0..0] of jValue; jMethod:
jMethodID=nil; jCls: jClass=nil;begin jParams[0].i := _interval;
jCls:= env^.GetObjectClass(env, _jtimerservice); jMethod:=
env^.GetMethodID(env, jCls, 'SetInterval', '(I)V');
env^.CallVoidMethodA(env, _jtimerservice, jMethod, @jParams);
env^.DeleteLocalRef(env, jCls);end; end.
in then jTimerService.java i try to start the service with the Start
methot but the app always crash, the problem is how start the service,
controls.activity.startService(intent); work for an IntentService but
not for this, any help.
----------------------------------------------------------------------
jmpessoa · 2020-11-12 02:49
NEW "jcToyTimerService" component [need gradle]
NEW demo "AppJCenterToyTimerServiceDemo1"
The "jcToyTimerService" component is just a "a proof of concept"
to guide how to implement a service in LAMW.
Thank you!
----------------------------------------------------------------------
Segator · 2020-11-12 03:17
Thanks a lot!!!, am going to test right now.