这是indexloc提供的服务,不要输入任何密码
Skip to content

Add initial infrastructure for FragmentStrictMode #123

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions fragment/fragment/api/public_plus_experimental_current.txt
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@ package androidx.fragment.app {
method public androidx.fragment.app.FragmentFactory getFragmentFactory();
method public java.util.List<androidx.fragment.app.Fragment!> getFragments();
method public androidx.fragment.app.Fragment? getPrimaryNavigationFragment();
method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY) public androidx.fragment.app.strictmode.FragmentStrictMode.Policy? getStrictModePolicy();
method public boolean isDestroyed();
method public boolean isStateSaved();
method public void popBackStack();
Expand All @@ -303,6 +304,7 @@ package androidx.fragment.app {
method public void setFragmentFactory(androidx.fragment.app.FragmentFactory);
method public final void setFragmentResult(String, android.os.Bundle);
method public final void setFragmentResultListener(String, androidx.lifecycle.LifecycleOwner, androidx.fragment.app.FragmentResultListener);
method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY) public void setStrictModePolicy(androidx.fragment.app.strictmode.FragmentStrictMode.Policy?);
method public void unregisterFragmentLifecycleCallbacks(androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks);
field public static final int POP_BACK_STACK_INCLUSIVE = 1; // 0x1
}
Expand Down Expand Up @@ -452,3 +454,32 @@ package androidx.fragment.app {

}

package androidx.fragment.app.strictmode {

@RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY) public final class FragmentStrictMode {
method public static androidx.fragment.app.strictmode.FragmentStrictMode.Policy getDefaultPolicy();
method public static void setDefaultPolicy(androidx.fragment.app.strictmode.FragmentStrictMode.Policy);
}

@RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY) public static interface FragmentStrictMode.OnViolationListener {
method public void onViolation(androidx.fragment.app.strictmode.Violation);
}

@RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY) public static final class FragmentStrictMode.Policy {
field public static final androidx.fragment.app.strictmode.FragmentStrictMode.Policy LAX;
}

@RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY) public static final class FragmentStrictMode.Policy.Builder {
ctor public FragmentStrictMode.Policy.Builder();
method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy build();
method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy.Builder penaltyDeath();
method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy.Builder penaltyListener(androidx.fragment.app.strictmode.FragmentStrictMode.OnViolationListener);
method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy.Builder penaltyLog();
}

@RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY) public abstract class Violation extends java.lang.RuntimeException {
ctor public Violation();
}

}

31 changes: 31 additions & 0 deletions fragment/fragment/api/restricted_current.txt
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ package androidx.fragment.app {
method public androidx.fragment.app.FragmentFactory getFragmentFactory();
method public java.util.List<androidx.fragment.app.Fragment!> getFragments();
method public androidx.fragment.app.Fragment? getPrimaryNavigationFragment();
method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY) public androidx.fragment.app.strictmode.FragmentStrictMode.Policy? getStrictModePolicy();
method public boolean isDestroyed();
method public boolean isStateSaved();
method @Deprecated @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public androidx.fragment.app.FragmentTransaction openTransaction();
Expand All @@ -308,6 +309,7 @@ package androidx.fragment.app {
method public void setFragmentFactory(androidx.fragment.app.FragmentFactory);
method public final void setFragmentResult(String, android.os.Bundle);
method public final void setFragmentResultListener(String, androidx.lifecycle.LifecycleOwner, androidx.fragment.app.FragmentResultListener);
method @RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY) public void setStrictModePolicy(androidx.fragment.app.strictmode.FragmentStrictMode.Policy?);
method public void unregisterFragmentLifecycleCallbacks(androidx.fragment.app.FragmentManager.FragmentLifecycleCallbacks);
field public static final int POP_BACK_STACK_INCLUSIVE = 1; // 0x1
}
Expand Down Expand Up @@ -478,3 +480,32 @@ package androidx.fragment.app {

}

package androidx.fragment.app.strictmode {

@RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY) public final class FragmentStrictMode {
method public static androidx.fragment.app.strictmode.FragmentStrictMode.Policy getDefaultPolicy();
method public static void setDefaultPolicy(androidx.fragment.app.strictmode.FragmentStrictMode.Policy);
}

@RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY) public static interface FragmentStrictMode.OnViolationListener {
method public void onViolation(androidx.fragment.app.strictmode.Violation);
}

@RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY) public static final class FragmentStrictMode.Policy {
field public static final androidx.fragment.app.strictmode.FragmentStrictMode.Policy LAX;
}

@RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY) public static final class FragmentStrictMode.Policy.Builder {
ctor public FragmentStrictMode.Policy.Builder();
method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy build();
method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy.Builder penaltyDeath();
method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy.Builder penaltyListener(androidx.fragment.app.strictmode.FragmentStrictMode.OnViolationListener);
method public androidx.fragment.app.strictmode.FragmentStrictMode.Policy.Builder penaltyLog();
}

@RestrictTo(androidx.annotation.RestrictTo.Scope.LIBRARY) public abstract class Violation extends java.lang.RuntimeException {
ctor public Violation();
}

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* Copyright 2021 The Android Open Source Project
*
* 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 androidx.fragment.app.strictmode

import androidx.fragment.app.StrictFragment
import androidx.fragment.app.executePendingTransactions
import androidx.fragment.app.test.FragmentTestActivity
import androidx.test.core.app.ActivityScenario
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
import androidx.testutils.withActivity
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith

@MediumTest
@RunWith(AndroidJUnit4::class)
public class FragmentStrictModeTest {
private lateinit var originalPolicy: FragmentStrictMode.Policy

@Before
public fun setup() {
originalPolicy = FragmentStrictMode.getDefaultPolicy()
}

@After
public fun teardown() {
FragmentStrictMode.setDefaultPolicy(originalPolicy)
}

@Test
public fun penaltyDeath() {
val policy = FragmentStrictMode.Policy.Builder()
.penaltyDeath()
.build()
FragmentStrictMode.setDefaultPolicy(policy)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What Lint actually wanted you to do was:

FragmentStrictMode.setDefaultPolicy(
    FragmentStrictMode.Policy.Builder()
        .penaltyDeath()
        .build()
)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I just thought this would be more readable. You want me to change it?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We actually have a codestyles.xml that enforces the style ian mentioned just to have some consistency, does that not automatically configure for you when starting studio via ./gradlew studio?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used ./gradlew studio, but could be that I just didn't auto-format before committing.


var violation: Violation? = null
try {
FragmentStrictMode.onPolicyViolation(StrictFragment(), object : Violation() {})
} catch (thrown: Violation) {
violation = thrown
}
assertWithMessage("No exception thrown on policy violation").that(violation).isNotNull()
}

@Test
public fun policyHierarchy() {
var lastTriggeredPolicy = ""
val violation = object : Violation() {}

fun policy(name: String) = FragmentStrictMode.Policy.Builder()
.penaltyListener { lastTriggeredPolicy = name }
.build()

with(ActivityScenario.launch(FragmentTestActivity::class.java)) {
val fragmentManager = withActivity { supportFragmentManager }

val parentFragment = StrictFragment()
fragmentManager.beginTransaction()
.add(parentFragment, "parentFragment")
.commit()
executePendingTransactions()

val childFragment = StrictFragment()
parentFragment.childFragmentManager.beginTransaction()
.add(childFragment, "childFragment")
.commit()
executePendingTransactions()

FragmentStrictMode.setDefaultPolicy(policy("Default policy"))
FragmentStrictMode.onPolicyViolation(childFragment, violation)
assertThat(lastTriggeredPolicy).isEqualTo("Default policy")

fragmentManager.strictModePolicy = policy("Parent policy")
FragmentStrictMode.onPolicyViolation(childFragment, violation)
assertThat(lastTriggeredPolicy).isEqualTo("Parent policy")

parentFragment.childFragmentManager.strictModePolicy = policy("Child policy")
FragmentStrictMode.onPolicyViolation(childFragment, violation)
assertThat(lastTriggeredPolicy).isEqualTo("Child policy")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
import androidx.collection.ArraySet;
import androidx.core.os.CancellationSignal;
import androidx.fragment.R;
import androidx.fragment.app.strictmode.FragmentStrictMode;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleEventObserver;
import androidx.lifecycle.LifecycleOwner;
Expand Down Expand Up @@ -518,6 +519,8 @@ public SpecialEffectsController createController(@NonNull ViewGroup container) {

private FragmentManagerViewModel mNonConfig;

private FragmentStrictMode.Policy mStrictModePolicy;

private Runnable mExecCommit = new Runnable() {
@Override
public void run() {
Expand Down Expand Up @@ -3465,6 +3468,26 @@ LayoutInflater.Factory2 getLayoutInflaterFactory() {
return mLayoutInflaterFactory;
}

/** Returns the current policy for this FragmentManager. If no policy is set, returns null. */
@Nullable
@RestrictTo(RestrictTo.Scope.LIBRARY) // TODO: Make API public as soon as we have a few checks
public FragmentStrictMode.Policy getStrictModePolicy() {
return mStrictModePolicy;
}

/**
* Sets the policy for what actions should be detected, as well as the penalty if such actions
* occur. The {@link Fragment#getChildFragmentManager() child FragmentManager} of all Fragments
* in this FragmentManager will also use this policy if one is not explicitly set. Pass null to
* clear the policy.
*
* @param policy the policy to put into place
*/
@RestrictTo(RestrictTo.Scope.LIBRARY) // TODO: Make API public as soon as we have a few checks
public void setStrictModePolicy(@Nullable FragmentStrictMode.Policy policy) {
mStrictModePolicy = policy;
}

/**
* An add or pop transaction to be scheduled for the UI thread.
*/
Expand Down
Loading