1 /* 2 * Copyright (C) 2016 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 17 package com.googlecode.android_scripting; 18 19 import android.app.Notification; 20 import android.app.NotificationManager; 21 import android.app.Service; 22 23 import java.lang.reflect.Method; 24 25 public abstract class ForegroundService extends Service { 26 private static final Class<?>[] mStartForegroundSignature = 27 new Class[] { int.class, Notification.class }; 28 private static final Class<?>[] mStopForegroundSignature = new Class[] { boolean.class }; 29 30 private final int mNotificationId; 31 32 private NotificationManager mNotificationManager; 33 private Method mStartForeground; 34 private Method mStopForeground; 35 private Object[] mStartForegroundArgs = new Object[2]; 36 private Object[] mStopForegroundArgs = new Object[1]; 37 ForegroundService(int id)38 public ForegroundService(int id) { 39 mNotificationId = id; 40 } 41 createNotification()42 protected abstract Notification createNotification(); 43 44 /** 45 * This is a wrapper around the new startForeground method, using the older APIs if it is not 46 * available. 47 */ startForegroundCompat(Notification notification)48 private void startForegroundCompat(Notification notification) { 49 // If we have the new startForeground API, then use it. 50 if (mStartForeground != null) { 51 mStartForegroundArgs[0] = Integer.valueOf(mNotificationId); 52 mStartForegroundArgs[1] = notification; 53 try { 54 mStartForeground.invoke(this, mStartForegroundArgs); 55 } catch (Exception e) { 56 Log.e(e); 57 } 58 return; 59 } 60 61 // Fall back on the old API. 62 setForeground(true); 63 if (notification != null) { 64 mNotificationManager.notify(mNotificationId, notification); 65 } 66 } 67 68 /** 69 * This is a wrapper around the new stopForeground method, using the older APIs if it is not 70 * available. 71 */ stopForegroundCompat()72 private void stopForegroundCompat() { 73 // If we have the new stopForeground API, then use it. 74 if (mStopForeground != null) { 75 mStopForegroundArgs[0] = Boolean.TRUE; 76 try { 77 mStopForeground.invoke(this, mStopForegroundArgs); 78 } catch (Exception e) { 79 Log.e(e); 80 } 81 return; 82 } 83 84 // Fall back on the old API. Note to cancel BEFORE changing the 85 // foreground state, since we could be killed at that point. 86 mNotificationManager.cancel(mNotificationId); 87 setForeground(false); 88 } 89 90 @Override onCreate()91 public void onCreate() { 92 mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); 93 try { 94 mStartForeground = getClass().getMethod("startForeground", mStartForegroundSignature); 95 mStopForeground = getClass().getMethod("stopForeground", mStopForegroundSignature); 96 } catch (NoSuchMethodException e) { 97 // Running on an older platform. 98 mStartForeground = mStopForeground = null; 99 } 100 startForegroundCompat(createNotification()); 101 } 102 103 @Override onDestroy()104 public void onDestroy() { 105 // Make sure our notification is gone. 106 stopForegroundCompat(); 107 } 108 } 109