• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.activity;
18 
19 import android.app.AlarmManager;
20 import android.app.Notification;
21 import android.app.PendingIntent;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.os.Binder;
25 import android.os.IBinder;
26 
27 import com.google.common.base.Preconditions;
28 import com.googlecode.android_scripting.BaseApplication;
29 import com.googlecode.android_scripting.ForegroundService;
30 import com.googlecode.android_scripting.IntentBuilders;
31 import com.googlecode.android_scripting.NotificationIdFactory;
32 import com.googlecode.android_scripting.R;
33 import com.googlecode.android_scripting.event.Event;
34 import com.googlecode.android_scripting.event.EventObserver;
35 import com.googlecode.android_scripting.facade.EventFacade;
36 import com.googlecode.android_scripting.facade.FacadeConfiguration;
37 import com.googlecode.android_scripting.facade.FacadeManager;
38 import com.googlecode.android_scripting.trigger.EventGenerationControllingObserver;
39 import com.googlecode.android_scripting.trigger.Trigger;
40 import com.googlecode.android_scripting.trigger.TriggerRepository;
41 import com.googlecode.android_scripting.trigger.TriggerRepository.TriggerRepositoryObserver;
42 
43 /**
44  * The trigger service takes care of installing triggers serialized to the preference storage.
45  *
46  * <p>
47  * The service also installs an alarm that keeps it running, unless the user force-quits the
48  * service.
49  *
50  * <p>
51  * When no triggers are installed the service shuts down silently as to not consume resources
52  * unnecessarily.
53  *
54  * @author Felix Arends (felix.arends@gmail.com)
55  * @author Damon Kohler (damonkohler@gmail.com)
56  */
57 public class TriggerService extends ForegroundService {
58   private static final int NOTIFICATION_ID = NotificationIdFactory.create();
59   private static final long PING_MILLIS = 10 * 1000 * 60;
60 
61   private final IBinder mBinder;
62   private TriggerRepository mTriggerRepository;
63   private FacadeManager mFacadeManager;
64   private EventFacade mEventFacade;
65 
66   public class LocalBinder extends Binder {
getService()67     public TriggerService getService() {
68       return TriggerService.this;
69     }
70   }
71 
TriggerService()72   public TriggerService() {
73     super(NOTIFICATION_ID);
74     mBinder = new LocalBinder();
75   }
76 
77   @Override
onBind(Intent intent)78   public IBinder onBind(Intent intent) {
79     return mBinder;
80   }
81 
82   @Override
onCreate()83   public void onCreate() {
84     super.onCreate();
85 
86     mFacadeManager =
87         new FacadeManager(FacadeConfiguration.getSdkLevel(), this, null,
88             FacadeConfiguration.getFacadeClasses());
89     mEventFacade = mFacadeManager.getReceiver(EventFacade.class);
90 
91     mTriggerRepository = ((BaseApplication) getApplication()).getTriggerRepository();
92     mTriggerRepository.bootstrapObserver(new RepositoryObserver());
93     mTriggerRepository.bootstrapObserver(new EventGenerationControllingObserver(mFacadeManager));
94     installAlarm();
95   }
96 
97   @Override
onStart(Intent intent, int startId)98   public void onStart(Intent intent, int startId) {
99     if (mTriggerRepository.isEmpty()) {
100       stopSelfResult(startId);
101       return;
102     }
103   }
104 
105   /** Returns the notification to display whenever the service is running. */
106   @Override
createNotification()107   protected Notification createNotification() {
108     Intent notificationIntent = new Intent(this, TriggerManager.class);
109     Notification.Builder builder = new Notification.Builder(this);
110     builder.setSmallIcon(R.drawable.sl4a_logo_48)
111            .setTicker("SL4A Trigger Service started.")
112            .setWhen(System.currentTimeMillis())
113            .setContentTitle("SL4A Trigger Service")
114            .setContentText("Tap to view triggers")
115            .setContentIntent(PendingIntent.getActivity(this, 0, notificationIntent, 0));
116     Notification notification = builder.build();
117     notification.flags = Notification.FLAG_NO_CLEAR | Notification.FLAG_ONGOING_EVENT;
118     return notification;
119   }
120 
121   private class TriggerEventObserver implements EventObserver {
122     private final Trigger mTrigger;
123 
TriggerEventObserver(Trigger trigger)124     public TriggerEventObserver(Trigger trigger) {
125       mTrigger = trigger;
126     }
127 
128     @Override
onEventReceived(Event event)129     public void onEventReceived(Event event) {
130       mTrigger.handleEvent(event, TriggerService.this);
131     }
132   }
133 
134   private class RepositoryObserver implements TriggerRepositoryObserver {
135     int mTriggerCount = 0;
136 
137     @Override
onPut(Trigger trigger)138     public void onPut(Trigger trigger) {
139       mTriggerCount++;
140       mEventFacade.addNamedEventObserver(trigger.getEventName(), new TriggerEventObserver(trigger));
141     }
142 
143     @Override
onRemove(Trigger trigger)144     public void onRemove(Trigger trigger) {
145       Preconditions.checkArgument(mTriggerCount > 0);
146       // TODO(damonkohler): Tear down EventObserver associated with trigger.
147       if (--mTriggerCount == 0) {
148         // TODO(damonkohler): Use stopSelfResult() which would require tracking startId.
149         stopSelf();
150       }
151     }
152   }
153 
installAlarm()154   private void installAlarm() {
155     AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
156     alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + PING_MILLIS,
157         PING_MILLIS, IntentBuilders.buildTriggerServicePendingIntent(this));
158   }
159 
uninstallAlarm()160   private void uninstallAlarm() {
161     AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
162     alarmManager.cancel(IntentBuilders.buildTriggerServicePendingIntent(this));
163   }
164 
165   @Override
onDestroy()166   public void onDestroy() {
167     super.onDestroy();
168     uninstallAlarm();
169   }
170 }
171