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.