]> Pileus Git - ~andy/spades/blob - src/Task.java
Updates for Android SDK 23.
[~andy/spades] / src / Task.java
1 package org.pileus.spades;
2
3 import java.util.List;
4 import java.util.LinkedList;
5 import java.util.concurrent.locks.Lock;
6 import java.util.concurrent.locks.ReentrantLock;
7
8 import android.app.Notification;
9 import android.app.PendingIntent;
10 import android.app.Service;
11 import android.content.Context;
12 import android.content.Intent;
13 import android.content.SharedPreferences;
14 import android.os.IBinder;
15 import android.os.Looper;
16 import android.os.Messenger;
17 import android.preference.PreferenceManager;
18
19 public class Task extends Service implements Runnable
20 {
21         /* Commands */
22         public static final int REGISTER   = 0;
23         public static final int MESSAGE    = 1;
24         public static final int CONNECT    = 2;
25         public static final int DISCONNECT = 3;
26         public static final int NOTIFY     = 4;
27
28         /* Private data */
29         private SharedPreferences prefs;
30         private Messenger         messenger;
31         private Thread            thread;
32         private Client            client;
33         private List<Object>      log;
34         private Lock              lock;
35
36         /* Private methods */
37         private void command(int cmd, Object value)
38         {
39                 if (cmd == MESSAGE || cmd == NOTIFY) {
40                         this.lock.lock();
41                         this.log.add(value);
42                         this.lock.unlock();
43                 }
44                 try {
45                         android.os.Message msg = android.os.Message.obtain();
46                         msg.what = cmd;
47                         msg.obj  = value;
48                         this.messenger.send(msg);
49                 } catch (Exception e) {
50                         Os.debug("Task: error sending message", e);
51                 }
52         }
53
54         @SuppressWarnings("deprecation")
55         private void notify(String text, int icon)
56         {
57                 // Notify Main
58                 this.command(NOTIFY, text);
59
60                 // Notification bar
61                 Intent        intent = new Intent(this, Main.class);
62                 PendingIntent pend   = PendingIntent.getActivity(this, 0, intent, 0);
63
64                 Notification.Builder nb = new Notification.Builder(this)
65                                 .setContentIntent(pend)
66                                 .setSmallIcon(icon)
67                                 .setContentTitle("Spades!")
68                                 .setOngoing(true)
69                                 .setContentText(text);
70
71                 Notification note = nb.build();
72                 this.startForeground(1, note);
73         }
74
75         private void handle(int cmd, Messenger mgr)
76         {
77                 // Validate messenger
78                 if (cmd != REGISTER && mgr != null && mgr != this.messenger) {
79                         Os.debug("Task: handle - invalid messenger");
80                 }
81
82                 // Setup communication with Main
83                 if (cmd == REGISTER) {
84                         Os.debug("Task: handle - register");
85                         this.messenger = mgr;
86                         this.command(REGISTER, this);
87                 }
88
89                 // Create client thread
90                 if (cmd == CONNECT && this.thread == null) {
91                         Os.debug("Task: handle - connect");
92                         this.thread = new Thread(this);
93                         this.thread.start();
94                 }
95
96                 // Stop client thread
97                 if (cmd == DISCONNECT && this.thread != null) {
98                         Os.debug("Task: handle - register");
99                         try {
100                                 this.client.abort();
101                                 this.thread.join();
102                         } catch (Exception e) {
103                                 Os.debug("Task: error stopping service", e);
104                         }
105                 }
106         }
107
108         /* Public methods */
109         public Message send(String dst, String txt)
110         {
111                 if (this.client == null)
112                         return null;
113                 Message msg = this.client.send(dst, txt);
114                 if (msg != null)
115                         this.command(MESSAGE, msg);
116                 return msg;
117         }
118
119         public Message send(String txt)
120         {
121                 if (this.client == null)
122                         return null;
123                 Message msg = this.client.send(txt);
124                 if (msg != null)
125                         this.command(MESSAGE, msg);
126                 return msg;
127         }
128
129         public List<Object> getLog()
130         {
131                 this.lock.lock();
132                 LinkedList<Object> out = new LinkedList<Object>(this.log);
133                 this.lock.unlock();
134                 return out;
135         }
136
137         public boolean isRunning()
138         {
139                 return this.thread != null;
140         }
141
142         /* Runnable methods */
143         public void run()
144         {
145                 Os.debug("Task: thread run");
146
147                 // Setup notification bar
148                 this.notify("Connecting..", android.R.drawable.presence_invisible);
149
150                 // Grab preferences
151                 String  server   = this.prefs.getString ("pref_server",   this.client.server);
152                 String  port     = this.prefs.getString ("pref_port",     this.client.port + "");
153                 String  nickname = this.prefs.getString ("pref_nickname", this.client.nickname);
154                 String  channel  = this.prefs.getString ("pref_channel",  this.client.channel);
155                 boolean usesasl  = this.prefs.getBoolean("pref_usesasl",  this.client.usesasl);
156                 String  authname = this.prefs.getString ("pref_authname", this.client.authname);
157                 String  password = this.prefs.getString ("pref_password", this.client.password);
158
159                 // Update client settings
160                 this.client.setServer(server, Integer.parseInt(port));
161                 this.client.setUser(nickname, channel);
162                 this.client.setAuth(usesasl, authname, password);
163
164                 // Start connecting
165                 if (!this.client.connect()) {
166                         this.command(DISCONNECT, null);
167                         this.notify("Unable to connect", android.R.drawable.presence_offline);
168                         this.thread = null;
169                         return;
170                 }
171
172                 // Wait for login
173                 while (this.client.state == Client.State.SETUP) {
174                         Message msg = this.client.recv();
175                         if (msg == null)
176                                 break;
177                         this.command(MESSAGE, msg);
178                 }
179
180                 // Notify connection status
181                 if (this.client.state == Client.State.READY) {
182                         this.command(CONNECT, null);
183                         this.notify("Connected", android.R.drawable.presence_online);
184                 } else {
185                         this.command(DISCONNECT, null);
186                         this.notify("Connetion aborted", android.R.drawable.presence_offline);
187                 }
188
189                 // Process messages
190                 while (this.client.state == Client.State.READY) {
191                         Message msg = this.client.recv();
192                         if (msg == null)
193                                 break;
194                         this.command(MESSAGE, msg);
195                 }
196
197                 // Notify disconnect disconnected
198                 this.notify("Disconnected", android.R.drawable.presence_offline);
199                 this.command(DISCONNECT, null);
200
201                 // Shutdown the client
202                 this.client.abort();
203                 this.thread = null;
204
205                 Os.debug("Task: thread exit");
206         }
207
208         /* Service Methods */
209         @Override
210         public void onCreate()
211         {
212                 Os.debug("Task: onCreate");
213                 super.onCreate();
214
215                 this.log    = new LinkedList<Object>();
216                 this.lock   = new ReentrantLock();
217                 this.client = new Client();
218                 this.prefs  = PreferenceManager.getDefaultSharedPreferences(this);
219         }
220
221         @Override
222         public void onDestroy()
223         {
224                 Os.debug("Task: onDestroy");
225                 this.handle(DISCONNECT, null);
226         }
227
228         @Override
229         public int onStartCommand(Intent intent, int flags, int startId)
230         {
231                 Os.debug("Task: onStart");
232                 super.onStartCommand(intent, flags, startId);
233                 int       cmd = intent.getExtras().getInt("Command");
234                 Messenger mgr = (Messenger)intent.getExtras().get("Messenger");
235                 this.handle(cmd, mgr);
236                 return START_STICKY;
237         }
238
239         @Override
240         public IBinder onBind(Intent intent)
241         {
242                 Os.debug("Task: onBind");
243                 return null;
244         }
245 }