1 /*
2  * Copyright (C) 2006 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 android.os;
18 
19 /** @hide */
20 public class Broadcaster
21 {
Broadcaster()22     public Broadcaster()
23     {
24     }
25 
26     /**
27      *  Sign up for notifications about something.
28      *
29      *  When this broadcaster pushes a message with senderWhat in the what field,
30      *  target will be sent a copy of that message with targetWhat in the what field.
31      */
request(int senderWhat, Handler target, int targetWhat)32     public void request(int senderWhat, Handler target, int targetWhat)
33     {
34         synchronized (this) {
35             Registration r = null;
36             if (mReg == null) {
37                 r = new Registration();
38                 r.senderWhat = senderWhat;
39                 r.targets = new Handler[1];
40                 r.targetWhats = new int[1];
41                 r.targets[0] = target;
42                 r.targetWhats[0] = targetWhat;
43                 mReg = r;
44                 r.next = r;
45                 r.prev = r;
46             } else {
47                 // find its place in the map
48                 Registration start = mReg;
49                 r = start;
50                 do {
51                     if (r.senderWhat >= senderWhat) {
52                         break;
53                     }
54                     r = r.next;
55                 } while (r != start);
56                 int n;
57                 if (r.senderWhat != senderWhat) {
58                     // we didn't find a senderWhat match, but r is right
59                     // after where it goes
60                     Registration reg = new Registration();
61                     reg.senderWhat = senderWhat;
62                     reg.targets = new Handler[1];
63                     reg.targetWhats = new int[1];
64                     reg.next = r;
65                     reg.prev = r.prev;
66                     r.prev.next = reg;
67                     r.prev = reg;
68 
69                     if (r == mReg && r.senderWhat > reg.senderWhat) {
70                         mReg = reg;
71                     }
72 
73                     r = reg;
74                     n = 0;
75                 } else {
76                     n = r.targets.length;
77                     Handler[] oldTargets = r.targets;
78                     int[] oldWhats = r.targetWhats;
79                     // check for duplicates, and don't do it if we are dup.
80                     for (int i=0; i<n; i++) {
81                         if (oldTargets[i] == target && oldWhats[i] == targetWhat) {
82                             return;
83                         }
84                     }
85                     r.targets = new Handler[n+1];
86                     System.arraycopy(oldTargets, 0, r.targets, 0, n);
87                     r.targetWhats = new int[n+1];
88                     System.arraycopy(oldWhats, 0, r.targetWhats, 0, n);
89                 }
90                 r.targets[n] = target;
91                 r.targetWhats[n] = targetWhat;
92             }
93         }
94     }
95 
96     /**
97      * Unregister for notifications for this senderWhat/target/targetWhat tuple.
98      */
cancelRequest(int senderWhat, Handler target, int targetWhat)99     public void cancelRequest(int senderWhat, Handler target, int targetWhat)
100     {
101         synchronized (this) {
102             Registration start = mReg;
103             Registration r = start;
104 
105             if (r == null) {
106                 return;
107             }
108 
109             do {
110                 if (r.senderWhat >= senderWhat) {
111                     break;
112                 }
113                 r = r.next;
114             } while (r != start);
115 
116             if (r.senderWhat == senderWhat) {
117                 Handler[] targets = r.targets;
118                 int[] whats = r.targetWhats;
119                 int oldLen = targets.length;
120                 for (int i=0; i<oldLen; i++) {
121                     if (targets[i] == target && whats[i] == targetWhat) {
122                         r.targets = new Handler[oldLen-1];
123                         r.targetWhats = new int[oldLen-1];
124                         if (i > 0) {
125                             System.arraycopy(targets, 0, r.targets, 0, i);
126                             System.arraycopy(whats, 0, r.targetWhats, 0, i);
127                         }
128 
129                         int remainingLen = oldLen-i-1;
130                         if (remainingLen != 0) {
131                             System.arraycopy(targets, i+1, r.targets, i,
132                                     remainingLen);
133                             System.arraycopy(whats, i+1, r.targetWhats, i,
134                                     remainingLen);
135                         }
136                         break;
137                     }
138                 }
139             }
140         }
141     }
142 
143     /**
144      * For debugging purposes, print the registrations to System.out
145      */
dumpRegistrations()146     public void dumpRegistrations()
147     {
148         synchronized (this) {
149             Registration start = mReg;
150             System.out.println("Broadcaster " + this + " {");
151             if (start != null) {
152                 Registration r = start;
153                 do {
154                     System.out.println("    senderWhat=" + r.senderWhat);
155                     int n = r.targets.length;
156                     for (int i=0; i<n; i++) {
157                         System.out.println("        [" + r.targetWhats[i]
158                                         + "] " + r.targets[i]);
159                     }
160                     r = r.next;
161                 } while (r != start);
162             }
163             System.out.println("}");
164         }
165     }
166 
167     /**
168      * Send out msg.  Anyone who has registered via the request() method will be
169      * sent the message.
170      */
broadcast(Message msg)171     public void broadcast(Message msg)
172     {
173         synchronized (this) {
174             if (mReg == null) {
175                 return;
176             }
177 
178             int senderWhat = msg.what;
179             Registration start = mReg;
180             Registration r = start;
181             do {
182                 if (r.senderWhat >= senderWhat) {
183                     break;
184                 }
185                 r = r.next;
186             } while (r != start);
187             if (r.senderWhat == senderWhat) {
188                 Handler[] targets = r.targets;
189                 int[] whats = r.targetWhats;
190                 int n = targets.length;
191                 for (int i=0; i<n; i++) {
192                     Handler target = targets[i];
193                     Message m = Message.obtain();
194                     m.copyFrom(msg);
195                     m.what = whats[i];
196                     target.sendMessage(m);
197                 }
198             }
199         }
200     }
201 
202     private class Registration
203     {
204         Registration next;
205         Registration prev;
206 
207         int senderWhat;
208         Handler[] targets;
209         int[] targetWhats;
210     }
211     private Registration mReg;
212 }
213