99package com .parse ;
1010
1111import android .app .Service ;
12+ import android .content .ComponentName ;
1213import android .content .Context ;
1314import android .content .Intent ;
1415import android .os .IBinder ;
16+ import android .os .PowerManager ;
17+ import android .util .SparseArray ;
1518
1619import java .util .ArrayList ;
1720import java .util .List ;
18- import java .util .concurrent .Executor ;
1921import java .util .concurrent .ExecutorService ;
2022import java .util .concurrent .Executors ;
2123
22- import bolts .Task ;
23-
2424/**
2525 * A service to listen for push notifications. This operates in the same process as the parent
2626 * application.
8181 * The {@link ParsePushBroadcastReceiver} listens to this intent to track an app open event and
8282 * launch the app's launcher activity. To customize this behavior override
8383 * {@link ParsePushBroadcastReceiver#onPushOpen(Context, Intent)}.
84+ *
85+ * Starting with Android O, this is replaced by {@link PushServiceApi26}.
8486 */
8587public final class PushService extends Service {
8688 private static final String TAG = "com.parse.PushService" ;
8789
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+
88141 //region ServiceLifecycleCallbacks used for testing
89142
90143 private static List <ServiceLifecycleCallbacks > serviceLifecycleCallbacks = null ;
@@ -103,45 +156,26 @@ public final class PushService extends Service {
103156 }
104157 }
105158
106- /* package */ static void unregisterServiceLifecycleCallbacks (
107- ServiceLifecycleCallbacks callbacks ) {
159+ /* package */ static void unregisterServiceLifecycleCallbacks (ServiceLifecycleCallbacks callbacks ) {
108160 synchronized (PushService .class ) {
109161 serviceLifecycleCallbacks .remove (callbacks );
110- if (serviceLifecycleCallbacks .size () <= 0 ) {
111- serviceLifecycleCallbacks = null ;
112- }
113162 }
114163 }
115164
116165 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 );
121169 }
122170 }
123171 }
124172
125173 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 );
142177 }
143178 }
144- return callbacks ;
145179 }
146180
147181 //endregion
@@ -157,10 +191,6 @@ public PushService() {
157191 super ();
158192 }
159193
160- static PushHandler createPushHandler () {
161- return PushHandler .Factory .create (ManifestInfo .getPushType ());
162- }
163-
164194 // For tests
165195 void setPushHandler (PushHandler handler ) {
166196 this .handler = handler ;
@@ -174,10 +204,6 @@ static boolean isSupported() {
174204 return ManifestInfo .getServiceInfo (PushService .class ) != null ;
175205 }
176206
177- static Task <Void > initialize () {
178- // Some handlers might need initialization.
179- return createPushHandler ().initialize ();
180- }
181207
182208 /**
183209 * Client code should not call {@code onCreate} directly.
@@ -197,7 +223,7 @@ public void onCreate() {
197223 }
198224
199225 executor = Executors .newSingleThreadExecutor ();
200- handler = createPushHandler ();
226+ handler = PushServiceUtils . createPushHandler ();
201227 dispatchOnServiceCreated (this );
202228 }
203229
@@ -216,7 +242,7 @@ public void run() {
216242 try {
217243 handler .handlePush (intent );
218244 } finally {
219- ServiceUtils . completeWakefulIntent (intent );
245+ dispose (intent );
220246 stopSelf (startId );
221247 }
222248 }
0 commit comments