1 /*
2  * Copyright (C) 2019 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 com.android.permissioncontroller.permission.service;
18 
19 import android.app.Service;
20 import android.content.Intent;
21 import android.os.Handler;
22 
23 import androidx.annotation.NonNull;
24 import androidx.lifecycle.Lifecycle;
25 import androidx.lifecycle.LifecycleOwner;
26 import androidx.lifecycle.LifecycleRegistry;
27 
28 /**
29  * A copy of the AndroidX ServiceLifecycleDispatcher.
30  */
31 public class ServiceLifecycleDispatcher {
32     private final LifecycleRegistry mRegistry;
33     private final Handler mHandler;
34     private DispatchRunnable mLastDispatchRunnable;
35 
36     /**
37      * @param provider {@link LifecycleOwner} for a service, usually it is a service itself
38      */
ServiceLifecycleDispatcher(@onNull LifecycleOwner provider)39     public ServiceLifecycleDispatcher(@NonNull LifecycleOwner provider) {
40         mRegistry = new CheckLifecycleRegistry(provider);
41         mHandler = new Handler();
42     }
43 
postDispatchRunnable(Lifecycle.Event event)44     private void postDispatchRunnable(Lifecycle.Event event) {
45         if (mLastDispatchRunnable != null) {
46             mLastDispatchRunnable.run();
47         }
48         mLastDispatchRunnable = new DispatchRunnable(mRegistry, event);
49         mHandler.postAtFrontOfQueue(mLastDispatchRunnable);
50     }
51 
52     /**
53      * Must be the first call in {@link Service#onCreate()} method, even before super.onCreate call.
54      */
onServicePreSuperOnCreate()55     public void onServicePreSuperOnCreate() {
56         postDispatchRunnable(Lifecycle.Event.ON_CREATE);
57     }
58 
59     /**
60      * Must be the first call in {@link Service#onBind(Intent)} method, even before super.onBind
61      * call.
62      */
onServicePreSuperOnBind()63     public void onServicePreSuperOnBind() {
64         postDispatchRunnable(Lifecycle.Event.ON_START);
65         postDispatchRunnable(Lifecycle.Event.ON_RESUME);
66     }
67 
68     /**
69      * Must be a first call in {@link Service#onStart(Intent, int)} or
70      * {@link Service#onStartCommand(Intent, int, int)} methods, even before
71      * a corresponding super call.
72      */
onServicePreSuperOnStart()73     public void onServicePreSuperOnStart() {
74         postDispatchRunnable(Lifecycle.Event.ON_START);
75     }
76 
77     /**
78      * Must be the first call in {@link Service#onDestroy()} method, even before super.OnDestroy
79      * call.
80      */
onServicePreSuperOnUnbind()81     public void onServicePreSuperOnUnbind() {
82         postDispatchRunnable(Lifecycle.Event.ON_STOP);
83     }
84 
85     /**
86      * Must be the first call in {@link Service#onDestroy()} method, even before super.OnDestroy
87      * call.
88      */
onServicePreSuperOnDestroy()89     public void onServicePreSuperOnDestroy() {
90         postDispatchRunnable(Lifecycle.Event.ON_STOP);
91         postDispatchRunnable(Lifecycle.Event.ON_DESTROY);
92     }
93 
94     /**
95      * @return {@link Lifecycle} for the given {@link LifecycleOwner}
96      */
97     @NonNull
getLifecycle()98     public Lifecycle getLifecycle() {
99         return mRegistry;
100     }
101 
102     static class DispatchRunnable implements Runnable {
103         private final LifecycleRegistry mRegistry;
104         final Lifecycle.Event mEvent;
105         private boolean mWasExecuted = false;
106 
DispatchRunnable(@onNull LifecycleRegistry registry, Lifecycle.Event event)107         DispatchRunnable(@NonNull LifecycleRegistry registry, Lifecycle.Event event) {
108             mRegistry = registry;
109             mEvent = event;
110         }
111 
112         @Override
run()113         public void run() {
114             if (!mWasExecuted) {
115                 mRegistry.handleLifecycleEvent(mEvent);
116                 mWasExecuted = true;
117             }
118         }
119     }
120 }
121