44import android .animation .AnimatorInflater ;
55import android .animation .ValueAnimator ;
66import android .app .Dialog ;
7- import android .app .DialogFragment ;
87import android .app .Fragment ;
98import android .content .res .Resources ;
109import android .graphics .Color ;
2322import java .lang .reflect .Field ;
2423
2524/**
26- * ImmersiveDialogFragment is a dialog fragment with no decoration that will take up as much of the screen
27- * as possible
25+ * DialogFragment is a dialog fragment with the fragment animation bug fix applied and an immersive mode
26+ * bug fix applied (when
27+ * read more about the bug fixes here:
28+ * - http://stackoverflow.com/questions/14900738/nested-fragments-disappear-during-transition-animation
29+ * - https://stackoverflow.com/questions/32758559/maintain-immersive-mode-when-dialogfragment-is-shown
2830 * Created by Mark on 11/9/16.
2931 */
30- abstract class ImmersiveDialogFragment extends DialogFragment implements ViewTreeObserver .OnGlobalLayoutListener {
32+ public abstract class DialogFragment extends android . app . DialogFragment implements ViewTreeObserver .OnGlobalLayoutListener {
3133
32- private static String TAG = ImmersiveDialogFragment .class .getSimpleName ();
34+ private static String TAG = DialogFragment .class .getSimpleName ();
3335
3436 /**
3537 * sDefaultChildAnimationDuration is an arbitrary, but reasonable transition duration we can use if
@@ -39,8 +41,16 @@ abstract class ImmersiveDialogFragment extends DialogFragment implements ViewTre
3941
4042 private Dialog mDialog ;
4143 private Handler mHandler ;
44+ private boolean mIsImmersive ;
4245
43- @ Override public Dialog onCreateDialog (final Bundle savedInstanceState ) {
46+ @ Override public Dialog onCreateDialog (Bundle savedInstanceState ) {
47+
48+ // check to see if the dialog is immersive
49+ mIsImmersive = (getActivity ().getWindow ().getDecorView ().getSystemUiVisibility () & View .SYSTEM_UI_FLAG_IMMERSIVE_STICKY ) == View .SYSTEM_UI_FLAG_IMMERSIVE_STICKY ;
50+ if (!mIsImmersive ) {
51+ Log .d (TAG , getActivity ().getWindow ().getDecorView ().getSystemUiVisibility () + " is not immersive" );
52+ return super .onCreateDialog (savedInstanceState );
53+ }
4454
4555 // create a handler
4656 mHandler = new Handler ();
@@ -94,9 +104,8 @@ public boolean onTouch(View v, MotionEvent event) {
94104 super .onDestroyView ();
95105 }
96106
97- @ Override
98- public void onGlobalLayout () {
99- if (!isDialog ()) {
107+ @ Override public void onGlobalLayout () {
108+ if (!isDialog () || !mIsImmersive ) {
100109 return ;
101110 }
102111 mHandler .postDelayed (new Runnable () {
@@ -109,7 +118,7 @@ public void run() {
109118
110119 @ Override public void onResume () {
111120 super .onResume ();
112- if (!isDialog ()) {
121+ if (!isDialog () || ! mIsImmersive ) {
113122 return ;
114123 }
115124
@@ -120,40 +129,33 @@ public void run() {
120129 EditText firstEditText = getFirstEditText ((ViewGroup ) mDialog .getWindow ().getDecorView ());
121130 if (firstEditText != null ) {
122131 mDialog .getWindow ().setSoftInputMode (WindowManager .LayoutParams .SOFT_INPUT_STATE_ALWAYS_VISIBLE );
123- Log .d ("FFF" , firstEditText .toString () + " | " + firstEditText .getText ().toString () + " " + firstEditText .getText ().length ());
124132 firstEditText .setSelection (firstEditText .getText ().length ());
125133 }
126134 }
127135
136+ /**
137+ * onCreateAnimator is overridden to fix the following animation bug:
138+ * http://stackoverflow.com/questions/14900738/nested-fragments-disappear-during-transition-animation
139+ */
128140 @ Override public Animator onCreateAnimator (int transit , boolean enter , int nextAnim ) {
129-
130- // if a child fragment is being removed because its parent is being removed
131- // return a fake animator that lasts the duration of the parent's animator
132- Fragment removingParentFragment = getRemovingParent (getParentFragment ());
133- if (!enter && removingParentFragment != null ) {
134- // This is a workaround for the bug where child fragments disappear when
135- // the parent is removed (as all children are first removed from the parent)
136- // See https://code.google.com/p/android/issues/detail?id=55228
137- long duration = getNextAnimatiorDuration (removingParentFragment );
138- Log .d (TAG , "TAG: " + getTag () + " | DURATION: " + duration );
139- return ValueAnimator .ofFloat (0 , 1 ).setDuration (duration );
141+ if (!enter ) {
142+ Fragment removingParentFragment = getRemovingParentFragment ();
143+ if (removingParentFragment != null ) {
144+ return ValueAnimator .ofFloat (0f , 1f ).setDuration (getNextAnimatorDuration (removingParentFragment ));
145+ }
140146 }
141-
142- // inflate the animator
143- Animator animator = null ;
144- try {
145- animator = AnimatorInflater .loadAnimator (getActivity (), nextAnim );
146- } catch (Exception e ) {}
147-
148- return animator ;
147+ return super .onCreateAnimator (transit , enter , nextAnim );
149148 }
150149
150+
151151 /**
152- * getRemovingParent returns the first fragment or parent fragment that is removing r null if it can't find one
152+ * getRemovingParentFragment returns the first fragment or parent fragment that is removing r null if it can't find one
153153 */
154- private static Fragment getRemovingParent (Fragment fragment ) {
154+ private android .app .Fragment getRemovingParentFragment () {
155+ android .app .Fragment fragment = getParentFragment ();
155156 while (fragment != null ) {
156157 if (fragment .isRemoving ()) {
158+ Log .v (TAG , fragment .toString () + " is removing" );
157159 return fragment ;
158160 }
159161 fragment = fragment .getParentFragment ();
@@ -163,29 +165,35 @@ private static Fragment getRemovingParent(Fragment fragment) {
163165
164166 /**
165167 * getNextAnimationDuration returns the "mNextAnim" animators duration
166- * TODO: this is broken, so i just set sDefaultChildAnimationDuration to @integer/slide_transition_duration
168+ * TODO: this needs a bug fix, but its not mission critical unless people are adding fragment transition
167169 */
168- private static long getNextAnimatiorDuration ( Fragment fragment ) {
170+ private static long getNextAnimatorDuration ( android . app . Fragment fragment ) {
169171 try {
170172
171173 // attempt to get the resource ID of the next animation that will be applied to the given fragment.
172- Field nextAnimField = Fragment .class .getDeclaredField ("mNextAnim" );
174+ Field nextAnimField = android . app . Fragment .class .getDeclaredField ("mNextAnim" );
173175 nextAnimField .setAccessible (true );
174- int nextAnimResource = nextAnimField .getInt (fragment );
176+ int nextAnimResourceID = nextAnimField .getInt (fragment );
177+
178+ Log .v (TAG , "nextAnimResourceID: " + nextAnimResourceID );
179+ if (nextAnimResourceID < 1 ) {
180+ return sDefaultChildAnimationDuration ;
181+ }
175182
176183 // load the animator
177- Animator nextAnim = AnimatorInflater .loadAnimator (fragment .getActivity (), nextAnimResource );
184+ Animator nextAnim = AnimatorInflater .loadAnimator (fragment .getActivity (), nextAnimResourceID );
185+
186+ Log .v (TAG , "nextAnim.getDuration(): " + nextAnim .getDuration ());
178187
179188 // return its duration
180189 return (nextAnim == null || nextAnim .getDuration () < 0 ) ? sDefaultChildAnimationDuration : nextAnim .getDuration ();
181190
182191 } catch (NoSuchFieldException |IllegalAccessException |Resources .NotFoundException ex ) {
183- // Log.w (TAG, "Unable to load next animation from parent." , ex);
192+ Log .e (TAG , ex . getMessage () , ex );
184193 return sDefaultChildAnimationDuration ;
185194 }
186195 }
187196
188-
189197 /**
190198 * getFirstEditText returns the first edit text in the parents hierarchy
191199 */
@@ -236,4 +244,11 @@ private boolean isDialog() {
236244 return mDialog != null && mDialog .getWindow () != null ;
237245 }
238246
247+ /**
248+ * isImmersive returns true if the dialog was initialized in immersive mode
249+ */
250+ protected boolean isImmersive () {
251+ return mIsImmersive ;
252+ }
253+
239254}
0 commit comments