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 package com.android.launcher3.util; 17 18 import android.util.Log; 19 20 import androidx.annotation.Nullable; 21 22 import com.android.launcher3.BaseActivity; 23 24 import java.io.PrintWriter; 25 import java.lang.ref.WeakReference; 26 import java.util.concurrent.CopyOnWriteArrayList; 27 28 /** 29 * Helper class to statically track activity creation 30 * @param <T> The activity type to track 31 */ 32 public final class ActivityTracker<T extends BaseActivity> { 33 34 private static final String TAG = "ActivityTracker"; 35 36 private WeakReference<T> mCurrentActivity = new WeakReference<>(null); 37 private CopyOnWriteArrayList<SchedulerCallback<T>> mCallbacks = new CopyOnWriteArrayList<>(); 38 39 @Nullable getCreatedActivity()40 public <R extends T> R getCreatedActivity() { 41 return (R) mCurrentActivity.get(); 42 } 43 onActivityDestroyed(T activity)44 public void onActivityDestroyed(T activity) { 45 if (mCurrentActivity.get() == activity) { 46 mCurrentActivity.clear(); 47 } 48 } 49 50 /** 51 * Call {@link SchedulerCallback#init(BaseActivity, boolean)} when the 52 * activity is ready. If the activity is already created, this is called immediately. 53 * 54 * The tracker maintains a strong ref to the callback, so it is up to the caller to return 55 * {@code false} in the callback OR to unregister the callback explicitly. 56 * 57 * @param callback The callback to call init() on when the activity is ready. 58 */ registerCallback(SchedulerCallback<T> callback, String reasonString)59 public void registerCallback(SchedulerCallback<T> callback, String reasonString) { 60 Log.d(TAG, "Registering callback: " + callback + ", reason=" + reasonString); 61 T activity = mCurrentActivity.get(); 62 mCallbacks.add(callback); 63 if (activity != null) { 64 if (!callback.init(activity, activity.isStarted())) { 65 unregisterCallback(callback, "ActivityTracker.registerCallback: Intent handled"); 66 } 67 } 68 } 69 70 /** 71 * Unregisters a registered callback. 72 */ unregisterCallback(SchedulerCallback<T> callback, String reasonString)73 public void unregisterCallback(SchedulerCallback<T> callback, String reasonString) { 74 Log.d(TAG, "Unregistering callback: " + callback + ", reason=" + reasonString); 75 mCallbacks.remove(callback); 76 } 77 handleCreate(T activity)78 public boolean handleCreate(T activity) { 79 mCurrentActivity = new WeakReference<>(activity); 80 return handleIntent(activity, false /* alreadyOnHome */); 81 } 82 handleNewIntent(T activity)83 public boolean handleNewIntent(T activity) { 84 return handleIntent(activity, activity.isStarted()); 85 } 86 handleIntent(T activity, boolean alreadyOnHome)87 private boolean handleIntent(T activity, boolean alreadyOnHome) { 88 boolean handled = false; 89 if (!mCallbacks.isEmpty()) { 90 Log.d(TAG, "handleIntent: mCallbacks=" + mCallbacks); 91 } 92 for (SchedulerCallback<T> cb : mCallbacks) { 93 if (!cb.init(activity, alreadyOnHome)) { 94 // Callback doesn't want any more updates 95 unregisterCallback(cb, "ActivityTracker.handleIntent: Intent handled"); 96 } 97 handled = true; 98 } 99 return handled; 100 } 101 dump(String prefix, PrintWriter writer)102 public void dump(String prefix, PrintWriter writer) { 103 writer.println(prefix + "ActivityTracker:"); 104 writer.println(prefix + "\tmCurrentActivity=" + mCurrentActivity.get()); 105 writer.println(prefix + "\tmCallbacks=" + mCallbacks); 106 } 107 108 public interface SchedulerCallback<T extends BaseActivity> { 109 110 /** 111 * Called when the activity is ready. 112 * @param alreadyOnHome Whether the activity is already started. 113 * @return Whether to continue receiving callbacks (i.e. if the activity is recreated). 114 */ init(T activity, boolean alreadyOnHome)115 boolean init(T activity, boolean alreadyOnHome); 116 } 117 } 118