1 /*
2  * Copyright (C) 2017 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 package com.android.launcher3.states;
17 
18 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
19 
20 import android.content.Intent;
21 import android.os.Binder;
22 import android.os.Bundle;
23 import android.os.IBinder;
24 
25 import com.android.launcher3.Launcher;
26 import com.android.launcher3.LauncherAppState;
27 import com.android.launcher3.model.BgDataModel.Callbacks;
28 
29 import java.lang.ref.WeakReference;
30 
31 /**
32  * Utility class to sending state handling logic to Launcher from within the same process.
33  *
34  * Extending {@link Binder} ensures that the platform maintains a single instance of each object
35  * which allows this object to safely navigate the system process.
36  */
37 public abstract class InternalStateHandler extends Binder {
38 
39     public static final String EXTRA_STATE_HANDLER = "launcher.state_handler";
40 
41     private static final Scheduler sScheduler = new Scheduler();
42 
43     /**
44      * Initializes the handler when the launcher is ready.
45      * @return true if the handler wants to stay alive.
46      */
init(Launcher launcher, boolean alreadyOnHome)47     protected abstract boolean init(Launcher launcher, boolean alreadyOnHome);
48 
addToIntent(Intent intent)49     public final Intent addToIntent(Intent intent) {
50         Bundle extras = new Bundle();
51         extras.putBinder(EXTRA_STATE_HANDLER, this);
52         intent.putExtras(extras);
53         return intent;
54     }
55 
initWhenReady()56     public final void initWhenReady() {
57         sScheduler.schedule(this);
58     }
59 
clearReference()60     public boolean clearReference() {
61         return sScheduler.clearReference(this);
62     }
63 
hasPending()64     public static boolean hasPending() {
65         return sScheduler.hasPending();
66     }
67 
handleCreate(Launcher launcher, Intent intent)68     public static boolean handleCreate(Launcher launcher, Intent intent) {
69         return handleIntent(launcher, intent, false, false);
70     }
71 
handleNewIntent(Launcher launcher, Intent intent, boolean alreadyOnHome)72     public static boolean handleNewIntent(Launcher launcher, Intent intent, boolean alreadyOnHome) {
73         return handleIntent(launcher, intent, alreadyOnHome, true);
74     }
75 
handleIntent( Launcher launcher, Intent intent, boolean alreadyOnHome, boolean explicitIntent)76     private static boolean handleIntent(
77             Launcher launcher, Intent intent, boolean alreadyOnHome, boolean explicitIntent) {
78         boolean result = false;
79         if (intent != null && intent.getExtras() != null) {
80             IBinder stateBinder = intent.getExtras().getBinder(EXTRA_STATE_HANDLER);
81             if (stateBinder instanceof InternalStateHandler) {
82                 InternalStateHandler handler = (InternalStateHandler) stateBinder;
83                 if (!handler.init(launcher, alreadyOnHome)) {
84                     intent.getExtras().remove(EXTRA_STATE_HANDLER);
85                 }
86                 result = true;
87             }
88         }
89         if (!result && !explicitIntent) {
90             result = sScheduler.initIfPending(launcher, alreadyOnHome);
91         }
92         return result;
93     }
94 
95     private static class Scheduler implements Runnable {
96 
97         private WeakReference<InternalStateHandler> mPendingHandler = new WeakReference<>(null);
98 
schedule(InternalStateHandler handler)99         public void schedule(InternalStateHandler handler) {
100             synchronized (this) {
101                 mPendingHandler = new WeakReference<>(handler);
102             }
103             MAIN_EXECUTOR.execute(this);
104         }
105 
106         @Override
run()107         public void run() {
108             LauncherAppState app = LauncherAppState.getInstanceNoCreate();
109             if (app == null) {
110                 return;
111             }
112             Callbacks cb = app.getModel().getCallback();
113             if (!(cb instanceof Launcher)) {
114                 return;
115             }
116             Launcher launcher = (Launcher) cb;
117             initIfPending(launcher, launcher.isStarted());
118         }
119 
initIfPending(Launcher launcher, boolean alreadyOnHome)120         public boolean initIfPending(Launcher launcher, boolean alreadyOnHome) {
121             InternalStateHandler pendingHandler = mPendingHandler.get();
122             if (pendingHandler != null) {
123                 if (!pendingHandler.init(launcher, alreadyOnHome)) {
124                     clearReference(pendingHandler);
125                 }
126                 return true;
127             }
128             return false;
129         }
130 
clearReference(InternalStateHandler handler)131         public boolean clearReference(InternalStateHandler handler) {
132             synchronized (this) {
133                 if (mPendingHandler.get() == handler) {
134                     mPendingHandler.clear();
135                     return true;
136                 }
137                 return false;
138             }
139         }
140 
hasPending()141         public boolean hasPending() {
142             return mPendingHandler.get() != null;
143         }
144     }
145 }