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