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.content.Intent; 19 import android.os.Bundle; 20 import android.os.IBinder; 21 22 import androidx.annotation.Nullable; 23 24 import com.android.launcher3.BaseActivity; 25 26 import java.lang.ref.WeakReference; 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 WeakReference<T> mCurrentActivity = new WeakReference<>(null); 35 36 private static final String EXTRA_SCHEDULER_CALLBACK = "launcher.scheduler_callback"; 37 38 @Nullable getCreatedActivity()39 public <R extends T> R getCreatedActivity() { 40 return (R) mCurrentActivity.get(); 41 } 42 onActivityDestroyed(T activity)43 public void onActivityDestroyed(T activity) { 44 if (mCurrentActivity.get() == activity) { 45 mCurrentActivity.clear(); 46 } 47 } 48 49 /** 50 * Call {@link SchedulerCallback#init(BaseActivity, boolean)} when the activity is ready. 51 * If the activity is already created, this is called immediately, otherwise we add the 52 * callback as an extra on the intent, and will call init() when we get handleIntent(). 53 * @param callback The callback to call init() on when the activity is ready. 54 * @param intent The intent that will be used to initialize the activity, if the activity 55 * doesn't already exist. We add the callback as an extra on this intent. 56 */ runCallbackWhenActivityExists(SchedulerCallback<T> callback, Intent intent)57 public void runCallbackWhenActivityExists(SchedulerCallback<T> callback, Intent intent) { 58 T activity = mCurrentActivity.get(); 59 if (activity != null) { 60 callback.init(activity, activity.isStarted()); 61 } else { 62 callback.addToIntent(intent); 63 } 64 } 65 handleCreate(T activity)66 public boolean handleCreate(T activity) { 67 mCurrentActivity = new WeakReference<>(activity); 68 return handleIntent(activity, activity.getIntent(), false); 69 } 70 handleNewIntent(T activity, Intent intent)71 public boolean handleNewIntent(T activity, Intent intent) { 72 return handleIntent(activity, intent, activity.isStarted()); 73 } 74 handleIntent(T activity, Intent intent, boolean alreadyOnHome)75 private boolean handleIntent(T activity, Intent intent, boolean alreadyOnHome) { 76 if (intent != null && intent.getExtras() != null) { 77 IBinder stateBinder = intent.getExtras().getBinder(EXTRA_SCHEDULER_CALLBACK); 78 if (stateBinder instanceof ObjectWrapper) { 79 SchedulerCallback<T> handler = 80 ((ObjectWrapper<SchedulerCallback>) stateBinder).get(); 81 if (!handler.init(activity, alreadyOnHome)) { 82 intent.getExtras().remove(EXTRA_SCHEDULER_CALLBACK); 83 } 84 return true; 85 } 86 } 87 return false; 88 } 89 90 public interface SchedulerCallback<T extends BaseActivity> { 91 92 /** 93 * Called when the activity is ready. 94 * @param alreadyOnHome Whether the activity is already started. 95 * @return Whether to continue receiving callbacks (i.e. if the activity is recreated). 96 */ init(T activity, boolean alreadyOnHome)97 boolean init(T activity, boolean alreadyOnHome); 98 99 /** 100 * Adds this callback as an extra on the intent, so we can retrieve it in handleIntent() and 101 * call {@link #init}. The intent should be used to start the activity after calling this 102 * method in order for us to get handleIntent(). 103 */ addToIntent(Intent intent)104 default Intent addToIntent(Intent intent) { 105 Bundle extras = new Bundle(); 106 extras.putBinder(EXTRA_SCHEDULER_CALLBACK, ObjectWrapper.wrap(this)); 107 intent.putExtras(extras); 108 return intent; 109 } 110 } 111 } 112