Skip to content

Commit

Permalink
feature: add ViewUtility.findSceneByView(View) View.requireScene() Vi…
Browse files Browse the repository at this point in the history
…ew.requireNavigationScene()
  • Loading branch information
qii committed Dec 7, 2019
1 parent 8e9ddcc commit fc90c6b
Show file tree
Hide file tree
Showing 8 changed files with 144 additions and 13 deletions.
7 changes: 5 additions & 2 deletions library/scene/src/main/java/com/bytedance/scene/Scene.java
Expand Up @@ -17,10 +17,8 @@

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Application;
import android.arch.lifecycle.*;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.res.Resources;
import android.os.*;
import android.support.annotation.*;
Expand Down Expand Up @@ -112,6 +110,10 @@
* ```
*/
public abstract class Scene implements LifecycleOwner, ViewModelStoreOwner {
/**
* use ViewUtility.findSceneByView(View) instead
*/
@Deprecated
public static final String SCENE_SERVICE = "scene";
private static final String TAG = "Scene";

Expand Down Expand Up @@ -362,6 +364,7 @@ public void dispatchCreateView(@Nullable Bundle savedInstanceState, @NonNull Vie
}
}

view.setTag(R.id.bytedance_scene_view_scene_tag, this);
view.setSaveFromParentEnabled(false);
mView = view;
mCalled = false;
Expand Down
@@ -0,0 +1,42 @@
/*
* Copyright (C) 2019 ByteDance Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.bytedance.scene.utlity;

import android.support.annotation.Nullable;
import android.view.View;
import android.view.ViewParent;
import com.bytedance.scene.R;
import com.bytedance.scene.Scene;

public class ViewUtility {
@Nullable
public static Scene findSceneByView(@Nullable View view) {
while (view != null) {
Scene scene = (Scene) view.getTag(R.id.bytedance_scene_view_scene_tag);
if (scene != null) {
return scene;
} else {
ViewParent viewParent = view.getParent();
if (viewParent instanceof View) {
view = (View) viewParent;
} else {
view = null;
}
}
}
return null;
}
}
1 change: 1 addition & 0 deletions library/scene/src/main/res/values/ids.xml
@@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item type="id" name="navigation_scene_content" />
<item type="id" name="bytedance_scene_view_scene_tag" />
</resources>
Expand Up @@ -15,6 +15,7 @@
import com.bytedance.scene.navigation.NavigationScene;
import com.bytedance.scene.utlity.ViewIdGenerator;

import com.bytedance.scene.utlity.ViewUtility;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
Expand Down Expand Up @@ -578,6 +579,7 @@ private static void checkSceneState(Scene scene, State state, boolean addedBefor
assertFalse(scene.isVisible());
assertNotNull(scene.getView());
assertSame(scene.getView().getContext().getSystemService(Scene.SCENE_SERVICE), scene);
assertEquals(ViewUtility.findSceneByView(scene.getView()), scene);
assertNotNull(scene.getParentScene());
assertNotNull(scene.getNavigationScene());
assertNotNull(scene.getActivity());
Expand All @@ -595,6 +597,7 @@ private static void checkSceneState(Scene scene, State state, boolean addedBefor
assertTrue(scene.isVisible());
assertNotNull(scene.getView());
assertSame(scene.getView().getContext().getSystemService(Scene.SCENE_SERVICE), scene);
assertEquals(ViewUtility.findSceneByView(scene.getView()), scene);
assertNotNull(scene.getParentScene());
assertNotNull(scene.getNavigationScene());
assertNotNull(scene.getActivity());
Expand All @@ -612,6 +615,7 @@ private static void checkSceneState(Scene scene, State state, boolean addedBefor
assertTrue(scene.isVisible());
assertNotNull(scene.getView());
assertSame(scene.getView().getContext().getSystemService(Scene.SCENE_SERVICE), scene);
assertEquals(ViewUtility.findSceneByView(scene.getView()), scene);
assertNotNull(scene.getParentScene());
assertNotNull(scene.getNavigationScene());
assertNotNull(scene.getActivity());
Expand Down
Expand Up @@ -9,6 +9,7 @@
import android.view.View;
import android.view.ViewGroup;
import com.bytedance.scene.navigation.NavigationScene;
import com.bytedance.scene.utlity.ViewUtility;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
Expand Down Expand Up @@ -51,6 +52,7 @@ public void testSceneLifecycle() {
assertTrue(testScene.getStateHistory().contains(State.ACTIVITY_CREATED.getName()));

assertEquals(testScene.getView().getContext().getSystemService(Scene.SCENE_SERVICE), testScene);
assertEquals(ViewUtility.findSceneByView(testScene.getView()), testScene);
assertFalse(testScene.isVisible());

testScene.requireView();
Expand Down
@@ -0,0 +1,69 @@
package com.bytedance.scene;

import android.arch.lifecycle.Lifecycle;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.util.Pair;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import com.bytedance.scene.group.GroupScene;
import com.bytedance.scene.navigation.NavigationScene;
import com.bytedance.scene.utlity.ViewUtility;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;

import static org.junit.Assert.assertEquals;


@RunWith(RobolectricTestRunner.class)
@Config(manifest = Config.NONE)
public class ViewUtilityTests {
@Test
public void testSceneContext() {
final TestScene testScene = new TestScene();

Pair<SceneLifecycleManager<NavigationScene>, NavigationScene> pair = NavigationSourceUtility.createFromInitSceneLifecycleManager(testScene);
View view = testScene.requireView();
assertEquals(ViewUtility.findSceneByView(view), testScene);

FrameLayout frameLayout = (FrameLayout) view;
View childView = new View(testScene.requireSceneContext());
frameLayout.addView(childView);
assertEquals(ViewUtility.findSceneByView(childView), testScene);
}

@Test
public void testActivityContext() {
final TestScene2 testScene = new TestScene2();

Pair<SceneLifecycleManager<NavigationScene>, NavigationScene> pair = NavigationSourceUtility.createFromInitSceneLifecycleManager(testScene);
View view = testScene.requireView();
assertEquals(ViewUtility.findSceneByView(view), testScene);

FrameLayout frameLayout = (FrameLayout) view;
View childView = new View(testScene.requireSceneContext());
frameLayout.addView(childView);
assertEquals(ViewUtility.findSceneByView(childView), testScene);
}

public static class TestScene extends GroupScene {
@NonNull
@Override
public ViewGroup onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container, @Nullable Bundle savedInstanceState) {
return new FrameLayout(requireSceneContext());
}
}

public static class TestScene2 extends GroupScene {
@NonNull
@Override
public ViewGroup onCreateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container, @Nullable Bundle savedInstanceState) {
return new FrameLayout(requireActivity());
}
}
}
Expand Up @@ -15,18 +15,24 @@
*/
package com.bytedance.scene.ktx

import android.annotation.SuppressLint
import android.view.View
import com.bytedance.scene.Scene
import com.bytedance.scene.navigation.NavigationScene
import com.bytedance.scene.utlity.ViewUtility
import java.lang.IllegalStateException

@SuppressLint("WrongConstant")
fun View.getScene(): Scene {
val value = context.getSystemService(Scene.SCENE_SERVICE)
?: throw IllegalArgumentException("Scene View should use getSceneContext() as View constructor argument in Scene.onCreateView()")
return value as Scene
fun View.getScene(): Scene? {
return ViewUtility.findSceneByView(this)
}

fun View.requireScene(): Scene {
return ViewUtility.findSceneByView(this) ?: throw IllegalStateException("Scene not found")
}

fun View.getNavigationScene(): NavigationScene? {
return getScene().navigationScene
return getScene()?.navigationScene
}

fun View.requireNavigationScene(): NavigationScene {
return requireScene().requireNavigationScene()
}
Expand Up @@ -5,11 +5,13 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.bytedance.scene.Scene
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertSame
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
import java.lang.IllegalStateException


@RunWith(RobolectricTestRunner::class)
Expand All @@ -24,17 +26,18 @@ class ViewExtensionsTests {
}
createFromSceneLifecycleManager(groupScene)
assertSame(groupScene, groupScene.requireView().getScene())
assertSame(groupScene, groupScene.requireView().requireScene())
}

@Test(expected = IllegalArgumentException::class)
fun testGetSceneException() {
@Test(expected = IllegalStateException::class)
fun testRequireSceneException() {
val groupScene = object : Scene() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup, savedInstanceState: Bundle?): View {
return View(requireActivity())
}
}
createFromSceneLifecycleManager(groupScene)
groupScene.requireView().getScene()
View(groupScene.requireActivity()).requireScene()
}

@Test
Expand All @@ -45,6 +48,7 @@ class ViewExtensionsTests {
}
}
val navigationScene = createFromSceneLifecycleManager(groupScene)
assertSame(navigationScene, groupScene.requireView().getNavigationScene())
assertNotNull(groupScene.requireView().getNavigationScene())
assertSame(navigationScene, groupScene.requireView().requireNavigationScene())
}
}

0 comments on commit fc90c6b

Please sign in to comment.