Mon 21 Jul 22:43:21 CEST 2025
This commit is contained in:
		
							parent
							
								
									227108387f
								
							
						
					
					
						commit
						be32776303
					
				| 
						 | 
				
			
			@ -0,0 +1,287 @@
 | 
			
		|||
/*
 | 
			
		||||
    Copyright 2013-2017 appPlant GmbH
 | 
			
		||||
 | 
			
		||||
    Licensed to the Apache Software Foundation (ASF) under one
 | 
			
		||||
    or more contributor license agreements.  See the NOTICE file
 | 
			
		||||
    distributed with this work for additional information
 | 
			
		||||
    regarding copyright ownership.  The ASF licenses this file
 | 
			
		||||
    to you 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 de.appplant.cordova.plugin.background;
 | 
			
		||||
 | 
			
		||||
import android.app.Notification;
 | 
			
		||||
import android.app.NotificationManager;
 | 
			
		||||
import android.app.PendingIntent;
 | 
			
		||||
import android.app.Service;
 | 
			
		||||
import android.content.Context;
 | 
			
		||||
import android.content.Intent;
 | 
			
		||||
import android.content.res.Resources;
 | 
			
		||||
import android.os.Binder;
 | 
			
		||||
import android.os.Build;
 | 
			
		||||
import android.os.IBinder;
 | 
			
		||||
import android.os.PowerManager;
 | 
			
		||||
 | 
			
		||||
import org.json.JSONObject;
 | 
			
		||||
 | 
			
		||||
import java.lang.reflect.Method;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Puts the service in a foreground state, where the system considers it to be
 | 
			
		||||
 * something the user is actively aware of and thus not a candidate for killing
 | 
			
		||||
 * when low on memory.
 | 
			
		||||
 */
 | 
			
		||||
public class ForegroundService extends Service {
 | 
			
		||||
 | 
			
		||||
    // Fixed ID for the 'foreground' notification
 | 
			
		||||
    public static final int NOTIFICATION_ID = -574543954;
 | 
			
		||||
 | 
			
		||||
    // Default title of the background notification
 | 
			
		||||
    private static final String NOTIFICATION_TITLE =
 | 
			
		||||
            "App is running in background";
 | 
			
		||||
 | 
			
		||||
    // Default text of the background notification
 | 
			
		||||
    private static final String NOTIFICATION_TEXT =
 | 
			
		||||
            "Doing heavy tasks.";
 | 
			
		||||
 | 
			
		||||
    // Default icon of the background notification
 | 
			
		||||
    private static final String NOTIFICATION_ICON = "icon";
 | 
			
		||||
 | 
			
		||||
    // Binder given to clients
 | 
			
		||||
    private final IBinder mBinder = new ForegroundBinder();
 | 
			
		||||
 | 
			
		||||
    // Partial wake lock to prevent the app from going to sleep when locked
 | 
			
		||||
    private PowerManager.WakeLock wakeLock;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Allow clients to call on to the service.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public IBinder onBind (Intent intent) {
 | 
			
		||||
        return mBinder;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Class used for the client Binder.  Because we know this service always
 | 
			
		||||
     * runs in the same process as its clients, we don't need to deal with IPC.
 | 
			
		||||
     */
 | 
			
		||||
    public class ForegroundBinder extends Binder {
 | 
			
		||||
        ForegroundService getService() {
 | 
			
		||||
            // Return this instance of ForegroundService
 | 
			
		||||
            // so clients can call public methods
 | 
			
		||||
            return ForegroundService.this;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Put the service in a foreground state to prevent app from being killed
 | 
			
		||||
     * by the OS.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onCreate () {
 | 
			
		||||
        super.onCreate();
 | 
			
		||||
        keepAwake();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * No need to run headless on destroy.
 | 
			
		||||
     */
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onDestroy() {
 | 
			
		||||
        super.onDestroy();
 | 
			
		||||
        sleepWell();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Put the service in a foreground state to prevent app from being killed
 | 
			
		||||
     * by the OS.
 | 
			
		||||
     */
 | 
			
		||||
    private void keepAwake() {
 | 
			
		||||
        JSONObject settings = BackgroundMode.getSettings();
 | 
			
		||||
        boolean isSilent    = settings.optBoolean("silent", false);
 | 
			
		||||
 | 
			
		||||
        if (!isSilent) {
 | 
			
		||||
            startForeground(NOTIFICATION_ID, makeNotification());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        PowerManager powerMgr = (PowerManager)
 | 
			
		||||
                getSystemService(POWER_SERVICE);
 | 
			
		||||
 | 
			
		||||
        wakeLock = powerMgr.newWakeLock(
 | 
			
		||||
                PowerManager.PARTIAL_WAKE_LOCK, "BackgroundMode");
 | 
			
		||||
 | 
			
		||||
        wakeLock.acquire();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Stop background mode.
 | 
			
		||||
     */
 | 
			
		||||
    private void sleepWell() {
 | 
			
		||||
        stopForeground(true);
 | 
			
		||||
        getNotificationManager().cancel(NOTIFICATION_ID);
 | 
			
		||||
 | 
			
		||||
        if (wakeLock != null) {
 | 
			
		||||
            wakeLock.release();
 | 
			
		||||
            wakeLock = null;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create a notification as the visible part to be able to put the service
 | 
			
		||||
     * in a foreground state by using the default settings.
 | 
			
		||||
     */
 | 
			
		||||
    private Notification makeNotification() {
 | 
			
		||||
        return makeNotification(BackgroundMode.getSettings());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Create a notification as the visible part to be able to put the service
 | 
			
		||||
     * in a foreground state.
 | 
			
		||||
     *
 | 
			
		||||
     * @param settings The config settings
 | 
			
		||||
     */
 | 
			
		||||
    private Notification makeNotification(JSONObject settings) {
 | 
			
		||||
        String title    = settings.optString("title", NOTIFICATION_TITLE);
 | 
			
		||||
        String text     = settings.optString("text", NOTIFICATION_TEXT);
 | 
			
		||||
        boolean bigText = settings.optBoolean("bigText", false);
 | 
			
		||||
 | 
			
		||||
        Context context = getApplicationContext();
 | 
			
		||||
        String pkgName  = context.getPackageName();
 | 
			
		||||
        Intent intent   = context.getPackageManager()
 | 
			
		||||
                .getLaunchIntentForPackage(pkgName);
 | 
			
		||||
 | 
			
		||||
        Notification.Builder notification = new Notification.Builder(context)
 | 
			
		||||
                .setContentTitle(title)
 | 
			
		||||
                .setContentText(text)
 | 
			
		||||
                .setOngoing(true)
 | 
			
		||||
                .setSmallIcon(getIconResId(settings));
 | 
			
		||||
 | 
			
		||||
        if (settings.optBoolean("hidden", true)) {
 | 
			
		||||
            notification.setPriority(Notification.PRIORITY_MIN);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (bigText || text.contains("\n")) {
 | 
			
		||||
            notification.setStyle(
 | 
			
		||||
                    new Notification.BigTextStyle().bigText(text));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        setColor(notification, settings);
 | 
			
		||||
 | 
			
		||||
        if (intent != null && settings.optBoolean("resume")) {
 | 
			
		||||
            PendingIntent contentIntent = PendingIntent.getActivity(
 | 
			
		||||
                    context, NOTIFICATION_ID, intent,
 | 
			
		||||
                    PendingIntent.FLAG_UPDATE_CURRENT);
 | 
			
		||||
 | 
			
		||||
            notification.setContentIntent(contentIntent);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return notification.build();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Update the notification.
 | 
			
		||||
     *
 | 
			
		||||
     * @param settings The config settings
 | 
			
		||||
     */
 | 
			
		||||
    protected void updateNotification (JSONObject settings) {
 | 
			
		||||
        boolean isSilent = settings.optBoolean("silent", false);
 | 
			
		||||
 | 
			
		||||
        if (isSilent) {
 | 
			
		||||
            stopForeground(true);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Notification notification = makeNotification(settings);
 | 
			
		||||
 | 
			
		||||
        getNotificationManager().notify(
 | 
			
		||||
                NOTIFICATION_ID, notification);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Retrieves the resource ID of the app icon.
 | 
			
		||||
     *
 | 
			
		||||
     * @param settings A JSON dict containing the icon name.
 | 
			
		||||
     */
 | 
			
		||||
    private int getIconResId(JSONObject settings) {
 | 
			
		||||
        Context context = getApplicationContext();
 | 
			
		||||
        Resources res   = context.getResources();
 | 
			
		||||
        String pkgName  = context.getPackageName();
 | 
			
		||||
        String icon     = settings.optString("icon", NOTIFICATION_ICON);
 | 
			
		||||
 | 
			
		||||
        // cordova-android 6 uses mipmaps
 | 
			
		||||
        int resId = getIconResId(res, icon, "mipmap", pkgName);
 | 
			
		||||
 | 
			
		||||
        if (resId == 0) {
 | 
			
		||||
            resId = getIconResId(res, icon, "drawable", pkgName);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return resId;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Retrieve resource id of the specified icon.
 | 
			
		||||
     *
 | 
			
		||||
     * @param res The app resource bundle.
 | 
			
		||||
     * @param icon The name of the icon.
 | 
			
		||||
     * @param type The resource type where to look for.
 | 
			
		||||
     * @param pkgName The name of the package.
 | 
			
		||||
     *
 | 
			
		||||
     * @return The resource id or 0 if not found.
 | 
			
		||||
     */
 | 
			
		||||
    private int getIconResId(Resources res, String icon,
 | 
			
		||||
                             String type, String pkgName) {
 | 
			
		||||
 | 
			
		||||
        int resId = res.getIdentifier(icon, type, pkgName);
 | 
			
		||||
 | 
			
		||||
        if (resId == 0) {
 | 
			
		||||
            resId = res.getIdentifier("icon", type, pkgName);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return resId;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Set notification color if its supported by the SDK.
 | 
			
		||||
     *
 | 
			
		||||
     * @param notification A Notification.Builder instance
 | 
			
		||||
     * @param settings A JSON dict containing the color definition (red: FF0000)
 | 
			
		||||
     */
 | 
			
		||||
    private void setColor(Notification.Builder notification,
 | 
			
		||||
                          JSONObject settings) {
 | 
			
		||||
 | 
			
		||||
        String hex = settings.optString("color", null);
 | 
			
		||||
 | 
			
		||||
        if (Build.VERSION.SDK_INT < 21 || hex == null)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            int aRGB = Integer.parseInt(hex, 16) + 0xFF000000;
 | 
			
		||||
            Method setColorMethod = notification.getClass().getMethod(
 | 
			
		||||
                    "setColor", int.class);
 | 
			
		||||
 | 
			
		||||
            setColorMethod.invoke(notification, aRGB);
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            e.printStackTrace();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Shared manager for the notification service.
 | 
			
		||||
     */
 | 
			
		||||
    private NotificationManager getNotificationManager() {
 | 
			
		||||
        return (NotificationManager) getSystemService(
 | 
			
		||||
                Context.NOTIFICATION_SERVICE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user