[AdSense-A]

We will learn through this Android tutorial how to use a “service” that runs in the background.

To illustrate this concept little known and somewhat mysterious, we will create a small application to make a joke to your friends.

Application features.

Android tutorial Android tutorial

The principle is simple, this application replaces the home screen of the smartphone with an image showing the broken screen.

At launch, the application asks you to validate the joke by pressing the center button. Once the action taken, the application closes and nothing happens until the next use of the smartphone by your friend. He then discover its home screen with a false image of the broken screen.

No stress, once your friend will unlock the smartphone, the false image disappear.

A service, what is it?

A service is a component that runs in the background. As an activity, a service has a life cycle (OnCreate (), OnStart (Intent i) or OnStartCommand (i Intent, int flags, int startId) and OnDestroy ()). The big difference is an activity that has no GUI. The user therefore can not interact with it.

Why use a service in this tutorial Android?

In some cases, it is useful to create a program that runs in the background, without the application is visible, such as a music player (which works without the application open) or a timing system that performs actions at regular intervals.

In our example, we use a service so that the user does not see our application running. The display of the image of the broken screen must be through a program that has no GUI and is therefore not visible to the user. To not our friend would suspect the joke, the service will add the image when the smartphone switches to standby. For this we will use the service in a “BroadcastReceiver” will allow us to detect the smartphone standby and unlocking (to delete the image and destroy the service).

Execution of the application.

The visible application.

  1. Launching the application.
  2. Press the center button.
  3. Launch service.
  4. Closing the application.

Service.

  1. Detection standby smartphone.
  2. Adding the image of the broken screen.
  3. When the user presses button to turn on the smartphone, the image of the broken screen is visible.
  4. Detection of the unlocking of the smartphone by the user.
  5. Remove the image, and destruction of the service.

Creating the application.

 Note: To follow this tutorial, we consider that you know to create a new Android app with Android Studio.
  1. Create a new application with Android Studio by choosing “Blank Activity”.
  2. Name the application (MyJokeApplication“) in our case.
  3. Once the project created by Android Studio, open the MainActivity.java file and add the following code:
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button button_close_app_and_go_joke = (Button) findViewById(R.id.button_close_app_and_go_joke);
        button_close_app_and_go_joke.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {

                Intent service = new Intent(getApplicationContext(), JokeService.class);
                startService(service); // Lancement du service
                finish(); // Fermeture de l'application

            }
        });
    }
}

 The main activity is very simple. After loading the GUI (R.layout.activity_main), we assign a “listener” to the middle button to detect the click by the user.

When clicking on the button, the application starts the service (an Intent and startService) and closes automatically (finish ()). So there is more that the service “runs” in the background.

The activity_main.xml graphic file is also very simple:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="fr.webdream.myjokeapplication.MainActivity">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/fermerapplication"
        android:id="@+id/button_close_app_and_go_joke"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true" />
</RelativeLayout>

To work, the service must be initially declared in the manifest file of the application.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="fr.webdream.myjokeapplication">

    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service
            android:name=".JokeService"
            android:enabled="true"
            android:exported="true"></service>

    </application>

</manifest>

After starting the service, and to detect the sleep and unlocking of the smartphone we will initialize the “BroadcastReceiver” in the “onStartCommand” service.

public int onStartCommand (Intent intent, int flags, int startId){
      try {
        IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
        filter.addAction(Intent.ACTION_SCREEN_OFF); //détection de la mise en veille du smartphone
        filter.addAction(Intent.ACTION_USER_PRESENT); //détection du déverrouillage du smartphone
        BroadcastReceiver mReceiver = new receiverScreen();
        registerReceiver(mReceiver, filter);
    } catch (Exception e) {

    }
    return START_STICKY;
}

public class receiverScreen extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {

        if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)){
            Show_joke(); //Affichage de l'image de l'écran cassé
        }
        if (intent.getAction().equals(Intent.ACTION_USER_PRESENT)){
            hide_broken_screen_and_destroy_service(); //On supprime l'image et on détruit le service.
        }
    }

}

To view / delete the image we use the “WindowManager” which adds a view to the smartphone screen.

private void Show_joke(){

    if (showing){return;} //Si l'image est déjà affichée, on sort.

    windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
    
    broken_screen_View = new ImageView(this); //Création de l'image de l'écran cassé
    Bitmap bmp_broken_screen;
    if(getResources().getDisplayMetrics().widthPixels>getResources().getDisplayMetrics().heightPixels) //On choisi l'image en fonction du mode portrait ou en paysage
    {
        bmp_broken_screen = BitmapFactory.decodeResource(getResources(), R.drawable.broken_screen_land);
    }
    else
    {
        bmp_broken_screen = BitmapFactory.decodeResource(getResources(), R.drawable.broken_screen);
    }
    broken_screen_View.setImageBitmap(bmp_broken_screen);
    broken_screen_View.setScaleType(ImageView.ScaleType.FIT_XY);

    //Définition des paramètres a appliquer à l'image
    final WindowManager.LayoutParams params = new WindowManager.LayoutParams(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY, WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED|WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN|WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT);

    //Affichage de l'image
    windowManager.addView(broken_screen_View, params);
    showing=true;
}

private void hide_broken_screen_and_destroy_service(){
    windowManager.removeViewImmediate(broken_screen_View);
    showing=false;
    stopSelf();
}

This gives us the following complete service:

package fr.webdream.myjokeapplication;

import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.IBinder;
import android.graphics.PixelFormat;
import android.util.Log;
import android.view.WindowManager;
import android.widget.ImageView;

public class JokeService extends Service {

    private WindowManager windowManager;
    private ImageView broken_screen_View;
    private Boolean showing;

    public JokeService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        return null;
    }

    public int onStartCommand (Intent intent, int flags, int startId){

          try {
            IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);

            filter.addAction(Intent.ACTION_SCREEN_OFF);
            filter.addAction(Intent.ACTION_USER_PRESENT);

            BroadcastReceiver mReceiver = new receiverScreen();

            registerReceiver(mReceiver, filter);
        } catch (Exception e) {

        }

        return START_STICKY;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        showing=false;
    }

    @Override
    public void onDestroy(){
        Log.v("SERVICE", "Service killed");
        if (showing){
            windowManager.removeViewImmediate(broken_screen_View);
            showing=false;
        }
        super.onDestroy();
    }

    private void Show_joke(){

        if (showing){return;} //Si l'image est déjà affichée, on sort.

        windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);

        broken_screen_View = new ImageView(this); //Création de l'image de l'écran cassé
        Bitmap bmp_broken_screen;
        if(getResources().getDisplayMetrics().widthPixels>getResources().getDisplayMetrics().heightPixels) //On choisi l'image en fonction du mode portrait ou en paysage
        {
            bmp_broken_screen = BitmapFactory.decodeResource(getResources(), R.drawable.broken_screen_land);
        }
        else
        {
            bmp_broken_screen = BitmapFactory.decodeResource(getResources(), R.drawable.broken_screen);
        }
        broken_screen_View.setImageBitmap(bmp_broken_screen);
        broken_screen_View.setScaleType(ImageView.ScaleType.FIT_XY);

        //Définition des paramètres a appliquer à l'image
        final WindowManager.LayoutParams params = new WindowManager.LayoutParams(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY, WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED|WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN|WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT);

        //Affichage de l'image
        windowManager.addView(broken_screen_View, params);
        showing=true;
    }

    private void hide_broken_screen_and_destroy_service(){
        windowManager.removeViewImmediate(broken_screen_View);
        showing=false;
        stopSelf();
    }

    public class receiverScreen extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {

            if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)){
                Show_joke(); //Affichage de l'image de l'écran cassé
            }
            if (intent.getAction().equals(Intent.ACTION_USER_PRESENT)){
                hide_broken_screen_and_destroy_service(); //On supprime l'image et on détruit le service.
            }
        }

    }

}

In conclusion, the use of service in an Android application is simple and can be very useful in applications or background tasks actions must be performed.

If you wish to reproduce this app you will find two image files (portrait and landscape) used:

Image portrait

Image landscape

2751 View