Skip to content

Commit 0222672

Browse files
committed
refactor: NavigationScene add onWindowFocusChanged ability
1 parent fe7cced commit 0222672

15 files changed

+207
-5
lines changed

demo/src/main/java/com/bytedance/scenedemo/navigation/push_pop/PushPopBasicUsageDemoScene.kt

+15-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.bytedance.scenedemo.navigation.push_pop
22

3+
import android.content.res.Configuration
34
import android.os.Bundle
45
import android.util.Log
56
import android.view.LayoutInflater
@@ -9,6 +10,7 @@ import android.widget.LinearLayout
910
import android.widget.ScrollView
1011
import com.bytedance.scene.Scene
1112
import com.bytedance.scene.animation.animatorexecutor.DialogSceneAnimatorExecutor
13+
import com.bytedance.scene.interfaces.ActivityCompatibleBehavior
1214
import com.bytedance.scene.interfaces.PushOptions
1315
import com.bytedance.scene.ktx.requireNavigationScene
1416
import com.bytedance.scenedemo.R
@@ -21,7 +23,7 @@ import com.bytedance.scenedemo.utility.addTitle
2123
/**
2224
* Created by JiangQi on 7/30/18.
2325
*/
24-
class PushPopBasicUsageDemoScene : Scene() {
26+
class PushPopBasicUsageDemoScene : Scene() ,ActivityCompatibleBehavior{
2527
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup, savedInstanceState: Bundle?): View {
2628
val scrollView = ScrollView(requireSceneContext())
2729
scrollView.fitsSystemWindows = true
@@ -76,4 +78,16 @@ class PushPopBasicUsageDemoScene : Scene() {
7678

7779
Log.i("Lifecycle",this.toString() + " $value onDestroyView")
7880
}
81+
82+
override fun onConfigurationChanged(newConfig: Configuration) {
83+
Log.i("PushPopBasicUsageDemoScene","Not yet implemented")
84+
}
85+
86+
override fun onNewIntent(arguments: Bundle?) {
87+
Log.i("PushPopBasicUsageDemoScene","Not yet implemented")
88+
}
89+
90+
override fun onWindowFocusChanged(hasFocus: Boolean) {
91+
Log.i("PushPopBasicUsageDemoScene","Not yet implemented")
92+
}
7993
}

demo/src/main/java/com/bytedance/scenedemo/navigation/push_singletop/PushSingleTopScene.kt

+4
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,8 @@ class PushSingleTopScene : Scene(), ActivityCompatibleBehavior {
5656
override fun onNewIntent(arguments: Bundle?) {
5757
Toast.makeText(sceneContext, "onNewIntent", Toast.LENGTH_SHORT).show()
5858
}
59+
60+
override fun onWindowFocusChanged(hasFocus: Boolean) {
61+
62+
}
5963
}

demo/src/main/java/com/bytedance/scenedemo/navigation/recreate/RecreateUsageDemoScene.kt

+4
Original file line numberDiff line numberDiff line change
@@ -108,4 +108,8 @@ class RecreateUsageDemoScene : Scene(),
108108
override fun onNewIntent(arguments: Bundle?) {
109109

110110
}
111+
112+
override fun onWindowFocusChanged(hasFocus: Boolean) {
113+
114+
}
111115
}

demo/src/main/java/com/bytedance/scenedemo/navigation/singletask/SingleTaskDemoScene.kt

+4
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,8 @@ class SingleTaskDemoScene : GroupScene(), ActivityCompatibleBehavior {
3838
override fun onNewIntent(arguments: Bundle?) {
3939
Toast.makeText(sceneContext, "onNewIntent", Toast.LENGTH_SHORT).show()
4040
}
41+
42+
override fun onWindowFocusChanged(hasFocus: Boolean) {
43+
44+
}
4145
}

library/scene_navigation/src/main/java/com/bytedance/scene/interfaces/ActivityCompatibleBehavior.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
package com.bytedance.scene.interfaces;
22

3-
import android.os.Bundle;
43
import android.content.res.Configuration;
5-
import androidx.annotation.NonNull;
4+
import android.os.Bundle;
65

6+
import androidx.annotation.NonNull;
77
import androidx.annotation.Nullable;
88

99
import com.bytedance.scene.Scene;
@@ -33,4 +33,6 @@ public interface ActivityCompatibleBehavior {
3333
* @see Scene#onResume
3434
*/
3535
void onNewIntent(@Nullable Bundle arguments);
36+
37+
void onWindowFocusChanged(boolean hasFocus);
3638
}

library/scene_navigation/src/main/java/com/bytedance/scene/navigation/ActivityCompatibleInfoCollector.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ public static boolean containsConfigChanges(@NonNull Scene scene) {
8282
return holder != null && holder.configChanges != null;
8383
}
8484

85-
private static boolean isTargetSceneType(@NonNull Scene scene){
85+
public static boolean isTargetSceneType(@NonNull Scene scene){
8686
return scene instanceof ActivityCompatibleBehavior;
8787
}
8888
}

library/scene_navigation/src/main/java/com/bytedance/scene/navigation/INavigationManager.java

+2
Original file line numberDiff line numberDiff line change
@@ -88,4 +88,6 @@ public interface INavigationManager {
8888
public void recycleInvisibleScenes();
8989

9090
public void onConfigurationChanged(@NonNull Configuration newConfig);
91+
92+
public void onWindowFocusChanged(boolean hasFocus);
9193
}

library/scene_navigation/src/main/java/com/bytedance/scene/navigation/NavigationScene.java

+41-1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import android.view.LayoutInflater;
3131
import android.view.View;
3232
import android.view.ViewGroup;
33+
import android.view.ViewTreeObserver;
3334
import android.widget.FrameLayout;
3435

3536
import androidx.annotation.MainThread;
@@ -122,7 +123,7 @@ public final class NavigationScene extends Scene implements NavigationListener,
122123
SceneComponentFactory mRootSceneComponentFactory; // Use this when destroying recovery
123124
NavigationSceneOptions mNavigationSceneOptions;
124125

125-
private INavigationManager mNavigationSceneManager;
126+
INavigationManager mNavigationSceneManager;
126127
private FrameLayout mSceneContainer;
127128
private FrameLayout mAnimationContainer;
128129
private final Handler mHandler = new Handler(Looper.getMainLooper());
@@ -147,6 +148,8 @@ public void run() {
147148
private boolean mIsInitRootSceneOnCreate = false;
148149

149150
private final boolean mSceneLifecycleCallbackObjectCreationOpt = SceneGlobalConfig.sceneLifecycleCallbackObjectCreationOpt;
151+
private boolean mWindowFocusChangedInstalled = false;
152+
private SceneWindowFocusChangedDispatcher mSceneWindowFocusChangedDispatcher = null;
150153

151154
@MainThread
152155
public void addNavigationListener(@NonNull final LifecycleOwner lifecycleOwner, @NonNull final NavigationListener listener) {
@@ -1081,6 +1084,43 @@ public static void preloadClasses() {
10811084
NavigationSceneGetter.class.toString();
10821085
}
10831086

1087+
/**
1088+
* @hide
1089+
*/
1090+
@RestrictTo(LIBRARY_GROUP)
1091+
public void installWindowFocusChangeListenerIfNeeded() {
1092+
if (!this.mNavigationSceneOptions.getUseWindowFocusChangedDispatch()) {
1093+
return;
1094+
}
1095+
if (!this.mWindowFocusChangedInstalled && this.getView() != null) {
1096+
this.mWindowFocusChangedInstalled = true;
1097+
this.mSceneWindowFocusChangedDispatcher = new SceneWindowFocusChangedDispatcher();
1098+
this.getView().getViewTreeObserver().addOnWindowFocusChangeListener(this.mSceneWindowFocusChangedDispatcher);
1099+
}
1100+
}
1101+
1102+
/**
1103+
* @hide
1104+
*/
1105+
@RestrictTo(LIBRARY_GROUP)
1106+
public void uninstallWindowFocusChangeListenerIfNeeded() {
1107+
if (!this.mNavigationSceneOptions.getUseWindowFocusChangedDispatch()) {
1108+
return;
1109+
}
1110+
if (this.mWindowFocusChangedInstalled && this.getView() != null) {
1111+
this.mWindowFocusChangedInstalled = false;
1112+
this.getView().getViewTreeObserver().removeOnWindowFocusChangeListener(this.mSceneWindowFocusChangedDispatcher);
1113+
this.mSceneWindowFocusChangedDispatcher = null;
1114+
}
1115+
}
1116+
1117+
private class SceneWindowFocusChangedDispatcher implements ViewTreeObserver.OnWindowFocusChangeListener {
1118+
@Override
1119+
public void onWindowFocusChanged(boolean hasFocus) {
1120+
mNavigationSceneManager.onWindowFocusChanged(hasFocus);
1121+
}
1122+
}
1123+
10841124
@Override
10851125
@Nullable
10861126
public String getSceneDebugInfo(@NonNull Scene scene) {

library/scene_navigation/src/main/java/com/bytedance/scene/navigation/NavigationSceneManager.java

+95
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,7 @@ public static void moveStateWithSeparation(@NonNull NavigationScene navigationSc
685685
break;
686686
case STARTED:
687687
scene.dispatchResume();
688+
((NavigationSceneManager)navigationScene.mNavigationSceneManager).onSceneResumedWindowFocusChanged(scene);
688689
moveStateWithSeparation(navigationScene, scene, to, bundle, causedByActivityLifeCycle, null, endAction);
689690
break;
690691
default:
@@ -694,6 +695,7 @@ public static void moveStateWithSeparation(@NonNull NavigationScene navigationSc
694695
switch (currentState) {
695696
case RESUMED:
696697
scene.dispatchPause();
698+
((NavigationSceneManager)navigationScene.mNavigationSceneManager).onScenePausedWindowFocusChanged(scene);
697699
moveStateWithSeparation(navigationScene, scene, to, bundle, causedByActivityLifeCycle, null, endAction);
698700
break;
699701
case STARTED:
@@ -1970,4 +1972,97 @@ public void onConfigurationChanged(@NonNull Configuration newConfig) {
19701972
}
19711973
}
19721974
}
1975+
1976+
@Override
1977+
public void onWindowFocusChanged(boolean hasFocus) {
1978+
if (!this.mNavigationScene.mNavigationSceneOptions.getUseWindowFocusChangedDispatch()) {
1979+
return;
1980+
}
1981+
LoggerManager.getInstance().i(TAG, "onWindowFocusChanged " + hasFocus);
1982+
1983+
if (!mSceneMessageQueue.hasPendingTasks()) {
1984+
Scene scene = getCurrentScene();
1985+
if (ActivityCompatibleInfoCollector.isTargetSceneType(scene)) {
1986+
onSceneResumedWindowFocusChangedToTarget(scene, hasFocus);
1987+
} else {
1988+
//try to uninstall window focus listener if there are no ActivityCompatibleBehavior Scene
1989+
uninstallUselessWindowFocusChangeListener();
1990+
}
1991+
} else {
1992+
LoggerManager.getInstance().i(TAG, "sync window focus by SceneMessageQueue");
1993+
1994+
//sync focus after all pending tasks are finished
1995+
NavigationRunnable syncWindowFocusRunnable = new NavigationRunnable() {
1996+
@Override
1997+
public void run() {
1998+
onWindowFocusChanged(hasFocus);
1999+
}
2000+
};
2001+
mSceneMessageQueue.postAsync(syncWindowFocusRunnable);
2002+
}
2003+
}
2004+
2005+
private void uninstallUselessWindowFocusChangeListener() {
2006+
List<Scene> sceneList = new ArrayList<>(getCurrentSceneList());
2007+
boolean found = false;
2008+
for (int i = sceneList.size() - 1; i >= 0; i--) {
2009+
Scene targetScene = sceneList.get(i);
2010+
if (ActivityCompatibleInfoCollector.isTargetSceneType(targetScene)) {
2011+
found = true;
2012+
break;
2013+
}
2014+
}
2015+
if (!found) {
2016+
LoggerManager.getInstance().i(TAG, "uninstall useless WindowFocusChangeListener");
2017+
mNavigationScene.uninstallWindowFocusChangeListenerIfNeeded();
2018+
}
2019+
}
2020+
2021+
private void onSceneResumedWindowFocusChangedToTarget(Scene scene, boolean hasFocus) {
2022+
if (!this.mNavigationScene.mNavigationSceneOptions.getUseWindowFocusChangedDispatch()) {
2023+
return;
2024+
}
2025+
if (!ActivityCompatibleInfoCollector.isTargetSceneType(scene)) {
2026+
return;
2027+
}
2028+
Record record = mNavigationScene.findRecordByScene(scene);
2029+
if (record.mLastSceneWindowFocused == hasFocus) {
2030+
return;
2031+
}
2032+
ActivityCompatibleBehavior activityCompatibleBehavior = (ActivityCompatibleBehavior) scene;
2033+
activityCompatibleBehavior.onWindowFocusChanged(hasFocus);
2034+
record.mLastSceneWindowFocused = hasFocus;
2035+
}
2036+
2037+
private void onSceneResumedWindowFocusChanged(Scene scene) {
2038+
if (!this.mNavigationScene.mNavigationSceneOptions.getUseWindowFocusChangedDispatch()) {
2039+
return;
2040+
}
2041+
if (!ActivityCompatibleInfoCollector.isTargetSceneType(scene)) {
2042+
return;
2043+
}
2044+
if (scene.getState() != State.RESUMED) {
2045+
return;
2046+
}
2047+
Activity activity = scene.requireActivity();
2048+
if (!activity.hasWindowFocus()) {
2049+
mNavigationScene.installWindowFocusChangeListenerIfNeeded();
2050+
} else {
2051+
onSceneResumedWindowFocusChangedToTarget(scene, true);
2052+
mNavigationScene.installWindowFocusChangeListenerIfNeeded();
2053+
}
2054+
}
2055+
2056+
private void onScenePausedWindowFocusChanged(Scene scene) {
2057+
if (!this.mNavigationScene.mNavigationSceneOptions.getUseWindowFocusChangedDispatch()) {
2058+
return;
2059+
}
2060+
if (!ActivityCompatibleInfoCollector.isTargetSceneType(scene)) {
2061+
return;
2062+
}
2063+
if (scene.getState() != State.STARTED) {
2064+
return;
2065+
}
2066+
onSceneResumedWindowFocusChangedToTarget(scene, false);
2067+
}
19732068
}

library/scene_navigation/src/main/java/com/bytedance/scene/navigation/NavigationSceneManagerV1.java

+5
Original file line numberDiff line numberDiff line change
@@ -1390,4 +1390,9 @@ public void recycleInvisibleScenes() {
13901390
public void onConfigurationChanged(@NonNull Configuration newConfig) {
13911391
throw new IllegalStateException("onConfigurationChanged is not supported");
13921392
}
1393+
1394+
@Override
1395+
public void onWindowFocusChanged(boolean hasFocus) {
1396+
throw new IllegalStateException("onWindowFocusChanged is not supported");
1397+
}
13931398
}

library/scene_navigation/src/main/java/com/bytedance/scene/navigation/NavigationSceneManagerV2.java

+5
Original file line numberDiff line numberDiff line change
@@ -1476,4 +1476,9 @@ public void recycleInvisibleScenes() {
14761476
public void onConfigurationChanged(@NonNull Configuration newConfig) {
14771477
throw new IllegalStateException("onConfigurationChanged is not supported");
14781478
}
1479+
1480+
@Override
1481+
public void onWindowFocusChanged(boolean hasFocus) {
1482+
throw new IllegalStateException("onWindowFocusChanged is not supported");
1483+
}
14791484
}

library/scene_navigation/src/main/java/com/bytedance/scene/navigation/NavigationSceneOptions.java

+14
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ public class NavigationSceneOptions {
3838
private static final String EXTRA_USE_ACTIVITY_CONTEXT_AND_LAYOUT_INFLATER = "extra_useActivityContextAndLayoutInflater";
3939
private static final String EXTRA_LAZY_LOAD_NAVIGATION_SCENE_UNNECESSARY_VIEW = "extra_lazyLoadNavigationSceneUnnecessaryView";
4040
private static final String EXTRA_MERGE_NAVIGATION_SCENE_VIEW = "extra_mergeNavigationSceneView";
41+
private static final String EXTRA_USE_WINDOW_FOCUS_CHANGED_DISPATCH = "extra_useWindowFocusChangedDispatch";
4142

4243
@NonNull
4344
private final String mRootSceneClassName;
@@ -53,6 +54,7 @@ public class NavigationSceneOptions {
5354
private boolean mUseActivityContextAndLayoutInflater = false;
5455
private boolean mLazyLoadNavigationSceneUnnecessaryView = false;
5556
private boolean mMergeNavigationSceneView = false;
57+
private boolean mUseWindowFocusChangedDispatch = false;
5658

5759
public NavigationSceneOptions(@NonNull Class<? extends Scene> rootSceneClazz, @Nullable Bundle rootSceneArguments) {
5860
if (rootSceneClazz.isAssignableFrom(NavigationScene.class)) {
@@ -132,6 +134,12 @@ public NavigationSceneOptions setMergeNavigationSceneView(boolean mergeNavigatio
132134
return this;
133135
}
134136

137+
@NonNull
138+
public NavigationSceneOptions setUseWindowFocusChangeDispatch(boolean useWindowFocusChangedDispatch) {
139+
this.mUseWindowFocusChangedDispatch = useWindowFocusChangedDispatch;
140+
return this;
141+
}
142+
135143
@NonNull
136144
public String getRootSceneClassName() {
137145
return this.mRootSceneClassName;
@@ -178,6 +186,10 @@ public boolean getMergeNavigationSceneView(){
178186
return this.mMergeNavigationSceneView;
179187
}
180188

189+
public boolean getUseWindowFocusChangedDispatch() {
190+
return mUseWindowFocusChangedDispatch;
191+
}
192+
181193
/**
182194
* @hide
183195
*/
@@ -199,6 +211,7 @@ public static NavigationSceneOptions fromBundle(@NonNull Bundle bundle) {
199211
navigationSceneOptions.mUseActivityContextAndLayoutInflater = bundle.getBoolean(EXTRA_USE_ACTIVITY_CONTEXT_AND_LAYOUT_INFLATER, false);
200212
navigationSceneOptions.mLazyLoadNavigationSceneUnnecessaryView = bundle.getBoolean(EXTRA_LAZY_LOAD_NAVIGATION_SCENE_UNNECESSARY_VIEW, false);
201213
navigationSceneOptions.mMergeNavigationSceneView = bundle.getBoolean(EXTRA_MERGE_NAVIGATION_SCENE_VIEW, false);
214+
navigationSceneOptions.mUseWindowFocusChangedDispatch = bundle.getBoolean(EXTRA_USE_WINDOW_FOCUS_CHANGED_DISPATCH, false);
202215
return navigationSceneOptions;
203216
}
204217

@@ -219,6 +232,7 @@ public Bundle toBundle() {
219232
bundle.putBoolean(EXTRA_USE_ACTIVITY_CONTEXT_AND_LAYOUT_INFLATER, mUseActivityContextAndLayoutInflater);
220233
bundle.putBoolean(EXTRA_LAZY_LOAD_NAVIGATION_SCENE_UNNECESSARY_VIEW, mLazyLoadNavigationSceneUnnecessaryView);
221234
bundle.putBoolean(EXTRA_MERGE_NAVIGATION_SCENE_VIEW, mMergeNavigationSceneView);
235+
bundle.putBoolean(EXTRA_USE_WINDOW_FOCUS_CHANGED_DISPATCH, mUseWindowFocusChangedDispatch);
222236
return bundle;
223237
}
224238
}

library/scene_navigation/src/main/java/com/bytedance/scene/navigation/Record.java

+3
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,14 @@ public class Record implements Parcelable {
6464

6565
@Nullable
6666
Configuration mConfiguration;
67+
boolean mLastSceneWindowFocused = false;
6768

6869
protected Record(Parcel in) {
6970
mActivityStatusRecord = in.readParcelable(ActivityStatusRecord.class.getClassLoader());
7071
mIsTranslucent = in.readByte() != 0;
7172
mSceneClassName = in.readString();
7273
mConfiguration = in.readParcelable(Configuration.class.getClassLoader());
74+
mLastSceneWindowFocused = in.readByte() != 0;
7375
}
7476

7577
public static final Creator<Record> CREATOR = new Creator<Record>() {
@@ -123,5 +125,6 @@ public void writeToParcel(Parcel dest, int flags) {
123125
dest.writeByte((byte) (mIsTranslucent ? 1 : 0));
124126
dest.writeString(mSceneClassName);
125127
dest.writeParcelable(mConfiguration, flags);
128+
dest.writeByte((byte) (mLastSceneWindowFocused ? 1 : 0));
126129
}
127130
}

library/scene_navigation/src/test/java/com/bytedance/scene/navigation/launchmode/NavigationStackLaunchModeTests.java

+5
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,11 @@ public void onNewIntent(@Nullable @org.jetbrains.annotations.Nullable Bundle arg
188188
this.mOnNewIntentInvoked = true;
189189
this.mOnNewIntentArguments = arguments;
190190
}
191+
192+
@Override
193+
public void onWindowFocusChanged(boolean hasFocus) {
194+
195+
}
191196
}
192197

193198
public static class CountChildScene extends Scene {

0 commit comments

Comments
 (0)