Stop long polling on error
[fonbot.git] / src / ro / ieval / fonbot / FonBotMainService.java
1 package ro.ieval.fonbot;
2
3 import static ro.ieval.fonbot.R.string.*;
4 import static ro.ieval.fonbot.Utils.toNonNull;
5
6 import java.util.Collections;
7 import java.util.EnumSet;
8 import java.util.Set;
9
10 import org.eclipse.jdt.annotation.Nullable;
11
12 import ro.ieval.fonbot.Utils.OngoingEvent;
13
14 import android.app.Notification;
15 import android.app.NotificationManager;
16 import android.app.PendingIntent;
17 import android.app.Service;
18 import android.content.Intent;
19 import android.content.IntentFilter;
20 import android.net.ConnectivityManager;
21 import android.os.IBinder;
22 import android.preference.PreferenceManager;
23 import android.support.v4.app.NotificationCompat;
24 import android.support.v4.content.LocalBroadcastManager;
25 import android.util.Log;
26
27 /*
28 * Copyright © 2013 Marius Gavrilescu
29 *
30 * This file is part of FonBot.
31 *
32 * FonBot is free software: you can redistribute it and/or modify
33 * it under the terms of the GNU General Public License as published by
34 * the Free Software Foundation, either version 3 of the License, or
35 * (at your option) any later version.
36 *
37 * FonBot is distributed in the hope that it will be useful,
38 * but WITHOUT ANY WARRANTY; without even the implied warranty of
39 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
40 * GNU General Public License for more details.
41 *
42 * You should have received a copy of the GNU General Public License
43 * along with FonBot. If not, see <http://www.gnu.org/licenses/>.
44 */
45
46 /**
47 * Main service.
48 *
49 * @author Marius Gavrilescu
50 */
51 public final class FonBotMainService extends Service {
52 /**
53 * Binder for the service. It lets clients get a reference to the service.
54 *
55 * @author Marius Gavrilescu <marius@ieval.ro>
56 */
57 public final class Binder extends android.os.Binder{
58 /**
59 * Get a reference to the {@link FonBotMainService}
60 * @return a reference to the {@link FonBotMainService}
61 */
62 public FonBotMainService getService(){
63 return FonBotMainService.this;
64 }
65 }
66
67 /**
68 * Runnable that continously long polls the server for commands
69 *
70 * @author Marius Gavrilescu <marius@ieval.ro>
71 */
72 private final class LongPollRunnable implements Runnable{
73 public void run(){
74 final ConnectivityManager man=(ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
75 final HttpCallExecutableRunnable runnable=new HttpCallExecutableRunnable("/get", null, FonBotMainService.this, new PollResultCallback(FonBotMainService.this), false);
76
77 Log.d("LongPollRunnable", "Long polling started");
78 while(man.getActiveNetworkInfo() != null && man.getActiveNetworkInfo().isConnected())
79 try {
80 runnable.run();
81 } catch (final Exception ex){
82 ex.printStackTrace();
83 break;
84 }
85 Log.d("LongPollRunnable", "Long polling stopped");
86 }
87 }
88
89 /**
90 * Broadcast action: add an ongoing event
91 */
92 public static final String ACTION_PUT_ONGOING="ro.ieval.fonbot.FonBotMainService.ACTION_PUT_ONGOING";
93 /**
94 * Broadcast action: remove an ongoing event
95 */
96 public static final String ACTION_DELETE_ONGOING="ro.ieval.fonbot.FonBotMainService.ACTION_DELETE_ONGOING";
97 /** Broadcast action: trigger a server poll */
98 public static final String ACTION_TRIGGER_POLL="ro.ieval.fonbot.FonBotMainService.ACTION_TRIGGER_POLL";
99 /**
100 * Extra: ongoing event id
101 *
102 * @see OngoingEvent
103 * @see #ACTION_DELETE_ONGOING
104 * @see #ACTION_PUT_ONGOING
105 */
106 public static final String EXTRA_ONGOING_ID="ro.ieval.fonbot.FonBotMainService.EXTRA_ONGOING_ID";
107 /**
108 * Broadcast sent when the ongoing event list is updated.
109 */
110 public static final String ACTION_ONGOING_UPDATE="ro.ieval.fonbot.FonBotMainService.ACTION_ONGOING_UPDATE";
111 /**
112 * IntentFilter for events caught by the {@link DynamicEventReceiver}
113 */
114 private static final IntentFilter DYNAMIC_BROADCAST_FILTER=new IntentFilter();
115
116 static{
117 DYNAMIC_BROADCAST_FILTER.addAction(Intent.ACTION_BATTERY_CHANGED);
118 DYNAMIC_BROADCAST_FILTER.addAction(Intent.ACTION_HEADSET_PLUG);
119 }
120
121 /**
122 * The one instance of {@link DynamicEventReceiver}
123 */
124 private final DynamicEventReceiver receiver=new DynamicEventReceiver();
125 /**
126 * Set of ongoing events.
127 */
128 private final Set<OngoingEvent> ongoing=EnumSet.noneOf(OngoingEvent.class);
129
130 /** true if running in foreground, false otherwise */
131 private boolean isForeground = false;
132
133 /** Thread that runs a {@link LongPollRunnable} */
134 private Thread longPollThread;
135
136 /**
137 * Get the set of ongoing events.
138 *
139 * @return a set of ongoing events
140 */
141 public Set<OngoingEvent> getOngoingEvents(){
142 return toNonNull(Collections.unmodifiableSet(ongoing));
143 }
144
145 @Override
146 public @Nullable IBinder onBind(final @Nullable Intent intent) {
147 return new Binder();
148 }
149
150 @Override
151 public void onCreate() {
152 super.onCreate();
153 registerReceiver(receiver, DYNAMIC_BROADCAST_FILTER);
154 }
155
156 @Override
157 public void onDestroy() {
158 super.onDestroy();
159 unregisterReceiver(receiver);
160 }
161
162 @Override
163 public int onStartCommand(final @Nullable Intent intent, final int flags, final int startId) {
164 final boolean showOngoing=PreferenceManager.getDefaultSharedPreferences(this).getBoolean("ongoing", false);
165 boolean updateNotification = false;
166 if(intent!=null && intent.getAction()==ACTION_PUT_ONGOING && intent.hasExtra(EXTRA_ONGOING_ID) && showOngoing){
167 ongoing.add(OngoingEvent.values()[intent.getIntExtra(EXTRA_ONGOING_ID, 0)]);
168 LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(ACTION_ONGOING_UPDATE));
169 updateNotification=true;
170 }
171 if(intent!=null && intent.getAction()==ACTION_DELETE_ONGOING && intent.hasExtra(EXTRA_ONGOING_ID) && showOngoing){
172 ongoing.remove(OngoingEvent.values()[intent.getIntExtra(EXTRA_ONGOING_ID, 0)]);
173 LocalBroadcastManager.getInstance(this).sendBroadcast(new Intent(ACTION_ONGOING_UPDATE));
174 updateNotification=true;
175 }
176
177 if(longPollThread == null || !longPollThread.isAlive()){
178 longPollThread = new Thread(new LongPollRunnable());
179 longPollThread.start();
180 }
181
182 final boolean runForeground=PreferenceManager.getDefaultSharedPreferences(this).getBoolean("foreground", false);
183 if(!runForeground)
184 stopForeground(true);
185
186 final NotificationManager man=(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
187 final boolean shouldNotify=runForeground||!ongoing.isEmpty();
188 if(shouldNotify && (updateNotification || runForeground != isForeground)){
189 final Intent mainIntent=new Intent(this, FonBotMainActivity.class);
190 mainIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
191 final NotificationCompat.Builder builder=new NotificationCompat.Builder(this).
192 setContentText(getString(foreground_notification_text)).
193 setContentTitle(getString(foreground_notification_title)).
194 setSmallIcon(android.R.drawable.stat_notify_sync_noanim).
195 setPriority(NotificationCompat.PRIORITY_MIN).
196 setContentIntent(PendingIntent.getActivity(this, 0, mainIntent, 0)).
197 setOngoing(true);
198
199 if(showOngoing && !ongoing.isEmpty()) {
200 final NotificationCompat.InboxStyle inboxBuilder=new NotificationCompat.InboxStyle(builder);
201
202 for(final OngoingEvent event : ongoing)
203 inboxBuilder.addLine(getString(event.resource));
204
205 }
206 final Notification notification=builder.build();
207
208 if(runForeground)
209 startForeground(1337, notification);
210 else
211 man.notify(1337, notification);
212 }
213
214 if(!shouldNotify)
215 man.cancel(1337);
216 isForeground=runForeground;
217 return START_STICKY;
218 }
219 }
This page took 0.027741 seconds and 4 git commands to generate.