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