• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of 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,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under 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  */
55 public class TriggerService extends ForegroundService {
56   private static final int NOTIFICATION_ID = NotificationIdFactory.create();
57   private static final long PING_MILLIS = 10 * 1000 * 60;
58 
59   private final IBinder mBinder;
60   private TriggerRepository mTriggerRepository;
61   private FacadeManager mFacadeManager;
62   private EventFacade mEventFacade;
63 
64   public class LocalBinder extends Binder {
getService()65     public TriggerService getService() {
66       return TriggerService.this;
67     }
68   }
69 
TriggerService()70   public TriggerService() {
71     super(NOTIFICATION_ID);
72     mBinder = new LocalBinder();
73   }
74 
75   @Override
onBind(Intent intent)76   public IBinder onBind(Intent intent) {
77     return mBinder;
78   }
79 
80   @Override
onCreate()81   public void onCreate() {
82     super.onCreate();
83 
84     mFacadeManager =
85         new FacadeManager(FacadeConfiguration.getSdkLevel(), this, null,
86             FacadeConfiguration.getFacadeClasses());
87     mEventFacade = mFacadeManager.getReceiver(EventFacade.class);
88 
89     mTriggerRepository = ((BaseApplication) getApplication()).getTriggerRepository();
90     mTriggerRepository.bootstrapObserver(new RepositoryObserver());
91     mTriggerRepository.bootstrapObserver(new EventGenerationControllingObserver(mFacadeManager));
92     installAlarm();
93   }
94 
95   @Override
onStart(Intent intent, int startId)96   public void onStart(Intent intent, int startId) {
97     if (mTriggerRepository.isEmpty()) {
98       stopSelfResult(startId);
99       return;
100     }
101   }
102 
103   /** Returns the notification to display whenever the service is running. */
104   @Override
createNotification()105   protected Notification createNotification() {
106     Intent notificationIntent = new Intent(this, TriggerManager.class);
107     Notification.Builder builder = new Notification.Builder(this);
108     builder.setSmallIcon(R.drawable.sl4a_logo_48)
109            .setTicker("SL4A Trigger Service started.")
110            .setWhen(System.currentTimeMillis())
111            .setContentTitle("SL4A Trigger Service")
112            .setContentText("Tap to view triggers")
113            .setContentIntent(PendingIntent.getActivity(this, 0, notificationIntent, 0));
114     Notification notification = builder.build();
115     notification.flags = Notification.FLAG_NO_CLEAR | Notification.FLAG_ONGOING_EVENT;
116     return notification;
117   }
118 
119   private class TriggerEventObserver implements EventObserver {
120     private final Trigger mTrigger;
121 
TriggerEventObserver(Trigger trigger)122     public TriggerEventObserver(Trigger trigger) {
123       mTrigger = trigger;
124     }
125 
126     @Override
onEventReceived(Event event)127     public void onEventReceived(Event event) {
128       mTrigger.handleEvent(event, TriggerService.this);
129     }
130   }
131 
132   private class RepositoryObserver implements TriggerRepositoryObserver {
133     int mTriggerCount = 0;
134 
135     @Override
onPut(Trigger trigger)136     public void onPut(Trigger trigger) {
137       mTriggerCount++;
138       mEventFacade.addNamedEventObserver(trigger.getEventName(), new TriggerEventObserver(trigger));
139     }
140 
141     @Override
onRemove(Trigger trigger)142     public void onRemove(Trigger trigger) {
143       Preconditions.checkArgument(mTriggerCount > 0);
144       // TODO(damonkohler): Tear down EventObserver associated with trigger.
145       if (--mTriggerCount == 0) {
146         // TODO(damonkohler): Use stopSelfResult() which would require tracking startId.
147         stopSelf();
148       }
149     }
150   }
151 
installAlarm()152   private void installAlarm() {
153     AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
154     alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + PING_MILLIS,
155         PING_MILLIS, IntentBuilders.buildTriggerServicePendingIntent(this));
156   }
157 
uninstallAlarm()158   private void uninstallAlarm() {
159     AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
160     alarmManager.cancel(IntentBuilders.buildTriggerServicePendingIntent(this));
161   }
162 
163   @Override
onDestroy()164   public void onDestroy() {
165     super.onDestroy();
166     uninstallAlarm();
167   }
168 }
169