9
9
package com .parse ;
10
10
11
11
import android .app .Service ;
12
+ import android .content .ComponentName ;
12
13
import android .content .Context ;
13
14
import android .content .Intent ;
14
15
import android .os .IBinder ;
16
+ import android .os .PowerManager ;
17
+ import android .util .SparseArray ;
15
18
16
19
import java .util .ArrayList ;
17
20
import java .util .List ;
18
- import java .util .concurrent .Executor ;
19
21
import java .util .concurrent .ExecutorService ;
20
22
import java .util .concurrent .Executors ;
21
23
22
- import bolts .Task ;
23
-
24
24
/**
25
25
* A service to listen for push notifications. This operates in the same process as the parent
26
26
* application.
81
81
* The {@link ParsePushBroadcastReceiver} listens to this intent to track an app open event and
82
82
* launch the app's launcher activity. To customize this behavior override
83
83
* {@link ParsePushBroadcastReceiver#onPushOpen(Context, Intent)}.
84
+ *
85
+ * Starting with Android O, this is replaced by {@link PushServiceApi26}.
84
86
*/
85
87
public final class PushService extends Service {
86
88
private static final String TAG = "com.parse.PushService" ;
87
89
90
+ //region run and dispose
91
+
92
+ private static final String WAKE_LOCK_EXTRA = "parseWakeLockId" ;
93
+ private static final SparseArray <ParseWakeLock > wakeLocks = new SparseArray <>();
94
+ private static int wakeLockId = 0 ;
95
+
96
+ /*
97
+ * Same as Context.startService, but acquires a wake lock before starting the service. The wake
98
+ * lock must later be released by calling dispose().
99
+ */
100
+ static boolean run (Context context , Intent intent ) {
101
+ String reason = intent .toString ();
102
+ ParseWakeLock wl = ParseWakeLock .acquireNewWakeLock (context , PowerManager .PARTIAL_WAKE_LOCK , reason , 0 );
103
+
104
+ synchronized (wakeLocks ) {
105
+ intent .putExtra (WAKE_LOCK_EXTRA , wakeLockId );
106
+ wakeLocks .append (wakeLockId , wl );
107
+ wakeLockId ++;
108
+ }
109
+
110
+ intent .setClass (context , PushService .class );
111
+ ComponentName name = context .startService (intent );
112
+ if (name == null ) {
113
+ PLog .e (TAG , "Could not start the service. Make sure that the XML tag "
114
+ + "<service android:name=\" " + PushService .class + "\" /> is in your "
115
+ + "AndroidManifest.xml as a child of the <application> element." );
116
+ dispose (intent );
117
+ return false ;
118
+ }
119
+ return true ;
120
+ }
121
+
122
+ static void dispose (Intent intent ) {
123
+ if (intent != null && intent .hasExtra (WAKE_LOCK_EXTRA )) {
124
+ int id = intent .getIntExtra (WAKE_LOCK_EXTRA , -1 );
125
+ ParseWakeLock wakeLock ;
126
+
127
+ synchronized (wakeLocks ) {
128
+ wakeLock = wakeLocks .get (id );
129
+ wakeLocks .remove (id );
130
+ }
131
+
132
+ if (wakeLock == null ) {
133
+ PLog .e (TAG , "Got wake lock id of " + id + " in intent, but no such lock found in " +
134
+ "global map. Was disposePushService called twice for the same intent?" );
135
+ } else {
136
+ wakeLock .release ();
137
+ }
138
+ }
139
+ }
140
+
88
141
//region ServiceLifecycleCallbacks used for testing
89
142
90
143
private static List <ServiceLifecycleCallbacks > serviceLifecycleCallbacks = null ;
@@ -103,45 +156,26 @@ public final class PushService extends Service {
103
156
}
104
157
}
105
158
106
- /* package */ static void unregisterServiceLifecycleCallbacks (
107
- ServiceLifecycleCallbacks callbacks ) {
159
+ /* package */ static void unregisterServiceLifecycleCallbacks (ServiceLifecycleCallbacks callbacks ) {
108
160
synchronized (PushService .class ) {
109
161
serviceLifecycleCallbacks .remove (callbacks );
110
- if (serviceLifecycleCallbacks .size () <= 0 ) {
111
- serviceLifecycleCallbacks = null ;
112
- }
113
162
}
114
163
}
115
164
116
165
private static void dispatchOnServiceCreated (Service service ) {
117
- Object [] callbacks = collectServiceLifecycleCallbacks ();
118
- if (callbacks != null ) {
119
- for (Object callback : callbacks ) {
120
- ((ServiceLifecycleCallbacks ) callback ).onServiceCreated (service );
166
+ if (serviceLifecycleCallbacks != null ) {
167
+ for (ServiceLifecycleCallbacks callback : serviceLifecycleCallbacks ) {
168
+ callback .onServiceCreated (service );
121
169
}
122
170
}
123
171
}
124
172
125
173
private static void dispatchOnServiceDestroyed (Service service ) {
126
- Object [] callbacks = collectServiceLifecycleCallbacks ();
127
- if (callbacks != null ) {
128
- for (Object callback : callbacks ) {
129
- ((ServiceLifecycleCallbacks ) callback ).onServiceDestroyed (service );
130
- }
131
- }
132
- }
133
-
134
- private static Object [] collectServiceLifecycleCallbacks () {
135
- Object [] callbacks = null ;
136
- synchronized (PushService .class ) {
137
- if (serviceLifecycleCallbacks == null ) {
138
- return null ;
139
- }
140
- if (serviceLifecycleCallbacks .size () > 0 ) {
141
- callbacks = serviceLifecycleCallbacks .toArray ();
174
+ if (serviceLifecycleCallbacks != null ) {
175
+ for (ServiceLifecycleCallbacks callback : serviceLifecycleCallbacks ) {
176
+ callback .onServiceDestroyed (service );
142
177
}
143
178
}
144
- return callbacks ;
145
179
}
146
180
147
181
//endregion
@@ -157,10 +191,6 @@ public PushService() {
157
191
super ();
158
192
}
159
193
160
- static PushHandler createPushHandler () {
161
- return PushHandler .Factory .create (ManifestInfo .getPushType ());
162
- }
163
-
164
194
// For tests
165
195
void setPushHandler (PushHandler handler ) {
166
196
this .handler = handler ;
@@ -174,10 +204,6 @@ static boolean isSupported() {
174
204
return ManifestInfo .getServiceInfo (PushService .class ) != null ;
175
205
}
176
206
177
- static Task <Void > initialize () {
178
- // Some handlers might need initialization.
179
- return createPushHandler ().initialize ();
180
- }
181
207
182
208
/**
183
209
* Client code should not call {@code onCreate} directly.
@@ -197,7 +223,7 @@ public void onCreate() {
197
223
}
198
224
199
225
executor = Executors .newSingleThreadExecutor ();
200
- handler = createPushHandler ();
226
+ handler = PushServiceUtils . createPushHandler ();
201
227
dispatchOnServiceCreated (this );
202
228
}
203
229
@@ -216,7 +242,7 @@ public void run() {
216
242
try {
217
243
handler .handlePush (intent );
218
244
} finally {
219
- ServiceUtils . completeWakefulIntent (intent );
245
+ dispose (intent );
220
246
stopSelf (startId );
221
247
}
222
248
}
0 commit comments