Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fca66cd8 authored by Dianne Hackborn's avatar Dianne Hackborn Committed by Android (Google) Code Review
Browse files

Merge "DO NOT MERGE Fix issue #6697105: App launching sometimes has random pauses" into jb-dev

parents 5d88c14c 357d99c6
Loading
Loading
Loading
Loading
+10 −9
Original line number Diff line number Diff line
@@ -65,7 +65,6 @@ import com.android.internal.telephony.ITelephony;
import com.android.internal.widget.PointerLocationView;

import android.service.dreams.IDreamManager;
import android.speech.RecognizerIntent;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
@@ -160,6 +159,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
    static final boolean localLOGV = false;
    static final boolean DEBUG_LAYOUT = false;
    static final boolean DEBUG_INPUT = false;
    static final boolean DEBUG_STARTING_WINDOW = false;
    static final boolean SHOW_STARTING_ANIMATIONS = true;
    static final boolean SHOW_PROCESSES_ON_ALT_MENU = false;

@@ -1454,8 +1454,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {

        try {
            Context context = mContext;
            //Log.i(TAG, "addStartingWindow " + packageName + ": nonLocalizedLabel="
            //        + nonLocalizedLabel + " theme=" + Integer.toHexString(theme));
            if (DEBUG_STARTING_WINDOW) Slog.d(TAG, "addStartingWindow " + packageName
                    + ": nonLocalizedLabel=" + nonLocalizedLabel + " theme="
                    + Integer.toHexString(theme));
            if (theme != context.getThemeResId() || labelRes != 0) {
                try {
                    context = context.createPackageContext(packageName, 0);
@@ -1522,7 +1523,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                return null;
            }

            if (localLOGV) Log.v(
            if (DEBUG_STARTING_WINDOW) Slog.d(
                TAG, "Adding starting window for " + packageName
                + " / " + appToken + ": "
                + (view.getParent() != null ? view : null));
@@ -1547,11 +1548,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {

    /** {@inheritDoc} */
    public void removeStartingWindow(IBinder appToken, View window) {
        // RuntimeException e = new RuntimeException();
        // Log.i(TAG, "remove " + appToken + " " + window, e);

        if (localLOGV) Log.v(
            TAG, "Removing starting window for " + appToken + ": " + window);
        if (DEBUG_STARTING_WINDOW) {
            RuntimeException e = new RuntimeException("here");
            e.fillInStackTrace();
            Log.v(TAG, "Removing starting window for " + appToken + ": " + window, e);
        }

        if (window != null) {
            WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
+4 −0
Original line number Diff line number Diff line
@@ -35,6 +35,10 @@ public class AppWindowAnimator {
    // AppWindowToken animations.
    int animLayerAdjustment;

    // Propagated from AppWindowToken.allDrawn, to determine when
    // the state changes.
    boolean allDrawn;

    // Special surface for thumbnail animation.
    Surface thumbnail;
    int thumbnailTransactionSeq;
+8 −2
Original line number Diff line number Diff line
@@ -241,12 +241,18 @@ class AppWindowToken extends WindowToken {
            pw.print(prefix); pw.print("paused="); pw.println(paused);
        }
        if (numInterestingWindows != 0 || numDrawnWindows != 0
                || inPendingTransaction || allDrawn) {
                || allDrawn || mAppAnimator.allDrawn) {
            pw.print(prefix); pw.print("numInterestingWindows=");
                    pw.print(numInterestingWindows);
                    pw.print(" numDrawnWindows="); pw.print(numDrawnWindows);
                    pw.print(" inPendingTransaction="); pw.print(inPendingTransaction);
                    pw.print(" allDrawn="); pw.println(allDrawn);
                    pw.print(" allDrawn="); pw.print(allDrawn);
                    pw.print(" (animator="); pw.print(mAppAnimator.allDrawn);
                    pw.println(")");
        }
        if (inPendingTransaction) {
            pw.print(prefix); pw.print("inPendingTransaction=");
                    pw.println(inPendingTransaction);
        }
        if (startingData != null || removed || firstWindowDrawn) {
            pw.print(prefix); pw.print("startingData="); pw.print(startingData);
+54 −97
Original line number Diff line number Diff line
@@ -38,7 +38,6 @@ public class WindowAnimator {
    ArrayList<WindowStateAnimator> mWinAnimators = new ArrayList<WindowStateAnimator>();

    boolean mAnimating;
    boolean mTokenMayBeDrawn;
    boolean mForceHiding;
    WindowState mWindowAnimationBackground;
    int mWindowAnimationBackgroundColor;
@@ -57,7 +56,7 @@ public class WindowAnimator {

    /** Skip repeated AppWindowTokens initialization. Note that AppWindowsToken's version of this
     * is a long initialized to Long.MIN_VALUE so that it doesn't match this value on startup. */
    private int mTransactionSequence;
    private int mAnimTransactionSequence;

    /** The one and only screen rotation if one is happening */
    ScreenRotationAnimation mScreenRotationAnimation = null;
@@ -194,7 +193,7 @@ public class WindowAnimator {
    }

    private void updateWindowsAndWallpaperLocked() {
        ++mTransactionSequence;
        ++mAnimTransactionSequence;

        ArrayList<WindowStateAnimator> unForceHiding = null;
        boolean wallpaperInUnForceHiding = false;
@@ -332,46 +331,8 @@ public class WindowAnimator {
            }

            final AppWindowToken atoken = win.mAppToken;
            if (atoken != null && (!atoken.allDrawn || atoken.mAppAnimator.freezingScreen)) {
                if (atoken.lastTransactionSequence != mTransactionSequence) {
                    atoken.lastTransactionSequence = mTransactionSequence;
                    atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
                    atoken.startingDisplayed = false;
                }
                if ((win.isOnScreen() || winAnimator.mAttrType
                        == WindowManager.LayoutParams.TYPE_BASE_APPLICATION)
                        && !win.mExiting && !win.mDestroying) {
                    if (WindowManagerService.DEBUG_VISIBILITY ||
                            WindowManagerService.DEBUG_ORIENTATION) {
                        Slog.v(TAG, "Eval win " + win + ": isDrawn=" + win.isDrawnLw()
                                + ", isAnimating=" + winAnimator.isAnimating());
                        if (!win.isDrawnLw()) {
                            Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurface
                                    + " pv=" + win.mPolicyVisibility
                                    + " mDrawState=" + winAnimator.mDrawState
                                    + " ah=" + win.mAttachedHidden
                                    + " th=" + atoken.hiddenRequested
                                    + " a=" + winAnimator.mAnimating);
                        }
                    }
                    if (win != atoken.startingWindow) {
                        if (!atoken.mAppAnimator.freezingScreen || !win.mAppFreezing) {
                            atoken.numInterestingWindows++;
                            if (win.isDrawnLw()) {
                                atoken.numDrawnWindows++;
                                if (WindowManagerService.DEBUG_VISIBILITY ||
                                        WindowManagerService.DEBUG_ORIENTATION) Slog.v(TAG,
                                        "tokenMayBeDrawn: " + atoken
                                        + " freezingScreen=" + atoken.mAppAnimator.freezingScreen
                                        + " mAppFreezing=" + win.mAppFreezing);
                                mTokenMayBeDrawn = true;
                            }
                        }
                    } else if (win.isDrawnLw()) {
                        atoken.startingDisplayed = true;
                    }
                }
            } else if (winAnimator.mDrawState == WindowStateAnimator.READY_TO_SHOW) {
            if (winAnimator.mDrawState == WindowStateAnimator.READY_TO_SHOW) {
                if (atoken == null || atoken.allDrawn) {
                    if (winAnimator.performShowLocked()) {
                        mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
                        if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
@@ -380,11 +341,12 @@ public class WindowAnimator {
                        }
                    }
                }
            }
            final AppWindowAnimator appAnimator =
                    atoken == null ? null : atoken.mAppAnimator;
            if (appAnimator != null && appAnimator.thumbnail != null) {
                if (appAnimator.thumbnailTransactionSeq != mTransactionSequence) {
                    appAnimator.thumbnailTransactionSeq = mTransactionSequence;
                if (appAnimator.thumbnailTransactionSeq != mAnimTransactionSequence) {
                    appAnimator.thumbnailTransactionSeq = mAnimTransactionSequence;
                    appAnimator.thumbnailLayer = 0;
                }
                if (appAnimator.thumbnailLayer < winAnimator.mAnimLayer) {
@@ -414,30 +376,22 @@ public class WindowAnimator {
        final int NT = appTokens.size();
        for (int i=0; i<NT; i++) {
            AppWindowToken wtoken = appTokens.get(i);
            final boolean allDrawn = wtoken.allDrawn;
            if (allDrawn != wtoken.mAppAnimator.allDrawn) {
                wtoken.mAppAnimator.allDrawn = allDrawn;
                if (allDrawn) {
                    // The token has now changed state to having all
                    // windows shown...  what to do, what to do?
                    if (wtoken.mAppAnimator.freezingScreen) {
                int numInteresting = wtoken.numInterestingWindows;
                if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
                    if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
                            "allDrawn: " + wtoken
                            + " interesting=" + numInteresting
                            + " drawn=" + wtoken.numDrawnWindows);
                        wtoken.mAppAnimator.showAllWindowsLocked();
                        mService.unsetAppFreezingScreenLocked(wtoken, false, true);
                        if (WindowManagerService.DEBUG_ORIENTATION) Slog.i(TAG,
                                "Setting mOrientationChangeComplete=true because wtoken "
                            + wtoken + " numInteresting=" + numInteresting
                                + wtoken + " numInteresting=" + wtoken.numInterestingWindows
                                + " numDrawn=" + wtoken.numDrawnWindows);
                        // This will set mOrientationChangeComplete and cause a pass through layout.
                        mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
                }
            } else if (!wtoken.allDrawn) {
                int numInteresting = wtoken.numInterestingWindows;
                if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
                    if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
                            "allDrawn: " + wtoken
                            + " interesting=" + numInteresting
                            + " drawn=" + wtoken.numDrawnWindows);
                    wtoken.allDrawn = true;
                    } else {
                        mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
                        if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
                            mService.debugLayoutRepeats("testTokenMayBeDrawnLocked",
@@ -452,9 +406,9 @@ public class WindowAnimator {
                }
            }
        }
    }

    private void performAnimationsLocked() {
        mTokenMayBeDrawn = false;
        mForceHiding = false;
        mDetachedWallpaper = null;
        mWindowAnimationBackground = null;
@@ -465,10 +419,8 @@ public class WindowAnimator {
            mPendingActions |= WALLPAPER_ACTION_PENDING;
        }

        if (mTokenMayBeDrawn) {
        testTokenMayBeDrawnLocked();
    }
    }

    synchronized void animate() {
        mPendingLayoutChanges = 0;
@@ -584,18 +536,23 @@ public class WindowAnimator {
    }

    public void dump(PrintWriter pw, String prefix, boolean dumpAll) {
        if (dumpAll) {
            if (mWindowDetachedWallpaper != null) {
            pw.print("  mWindowDetachedWallpaper="); pw.println(mWindowDetachedWallpaper);
                pw.print(prefix); pw.print("mWindowDetachedWallpaper=");
                        pw.println(mWindowDetachedWallpaper);
            }
            pw.print(prefix); pw.print("mAnimTransactionSequence=");
                    pw.println(mAnimTransactionSequence);
            if (mWindowAnimationBackgroundSurface != null) {
            pw.println("  mWindowAnimationBackgroundSurface:");
            mWindowAnimationBackgroundSurface.printTo("    ", pw);
                pw.print(prefix); pw.print("mWindowAnimationBackgroundSurface:");
                        mWindowAnimationBackgroundSurface.printTo(prefix + "  ", pw);
            }
            if (mDimAnimator != null) {
            pw.println("  mDimAnimator:");
            mDimAnimator.printTo("    ", pw);
                pw.print(prefix); pw.print("mDimAnimator:");
                mDimAnimator.printTo(prefix + "  ", pw);
            } else {
            pw.println( "  no DimAnimator ");
                pw.print(prefix); pw.print("no DimAnimator ");
            }
        }
    }

+104 −7
Original line number Diff line number Diff line
@@ -96,6 +96,7 @@ import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.FloatMath;
import android.util.Log;
import android.util.LogPrinter;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseIntArray;
@@ -642,6 +643,10 @@ public class WindowManagerService extends IWindowManager.Stub
    }
    LayoutFields mInnerFields = new LayoutFields();

    /** Skip repeated AppWindowTokens initialization. Note that AppWindowsToken's version of this
     * is a long initialized to Long.MIN_VALUE so that it doesn't match this value on startup. */
    private int mTransactionSequence;

    /** Only do a maximum of 6 repeated layouts. After that quit */
    private int mLayoutRepeatCount;

@@ -802,6 +807,8 @@ public class WindowManagerService extends IWindowManager.Stub
        @Override
        public void run() {
            Looper.prepare();
            //Looper.myLooper().setMessageLogging(new LogPrinter(
            //        android.util.Log.DEBUG, TAG, android.util.Log.LOG_ID_SYSTEM));
            WindowManagerService s = new WindowManagerService(mContext, mPM,
                    mHaveInputMethods, mAllowBootMessages, mOnlyCore);
            android.os.Process.setThreadPriority(
@@ -3582,7 +3589,7 @@ public class WindowManagerService extends IWindowManager.Stub

    public void setAppGroupId(IBinder token, int groupId) {
        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                "setAppStartingIcon()")) {
                "setAppGroupId()")) {
            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
        }

@@ -4005,7 +4012,7 @@ public class WindowManagerService extends IWindowManager.Stub
            CharSequence nonLocalizedLabel, int labelRes, int icon,
            int windowFlags, IBinder transferFrom, boolean createIfNeeded) {
        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                "setAppStartingIcon()")) {
                "setAppStartingWindow()")) {
            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
        }

@@ -4061,12 +4068,13 @@ public class WindowManagerService extends IWindowManager.Stub
                        startingWindow.mToken = wtoken;
                        startingWindow.mRootToken = wtoken;
                        startingWindow.mAppToken = wtoken;
                        if (DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG,
                                "Removing starting window: " + startingWindow);
                        if (DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE || DEBUG_STARTING_WINDOW) {
                            Slog.v(TAG, "Removing starting window: " + startingWindow);
                        }
                        mWindows.remove(startingWindow);
                        mWindowsChanged = true;
                        if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Removing starting " + startingWindow
                                + " from " + ttoken);
                        if (DEBUG_ADD_REMOVE) Slog.v(TAG,
                                "Removing starting " + startingWindow + " from " + ttoken);
                        ttoken.windows.remove(startingWindow);
                        ttoken.allAppWindows.remove(startingWindow);
                        addWindowToListInOrderLocked(startingWindow, true);
@@ -4153,6 +4161,8 @@ public class WindowManagerService extends IWindowManager.Stub
            // show a starting window -- the current effect (a full-screen
            // opaque starting window that fades away to the real contents
            // when it is ready) does not work for this.
            if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Checking theme of starting window: 0x"
                    + Integer.toHexString(theme));
            if (theme != 0) {
                AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme,
                        com.android.internal.R.styleable.Window);
@@ -4161,6 +4171,15 @@ public class WindowManagerService extends IWindowManager.Stub
                    // pretend like we didn't see that.
                    return;
                }
                if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Translucent="
                        + ent.array.getBoolean(
                                com.android.internal.R.styleable.Window_windowIsTranslucent, false)
                        + " Floating="
                        + ent.array.getBoolean(
                                com.android.internal.R.styleable.Window_windowIsFloating, false)
                        + " ShowWallpaper="
                        + ent.array.getBoolean(
                                com.android.internal.R.styleable.Window_windowShowWallpaper, false));
                if (ent.array.getBoolean(
                        com.android.internal.R.styleable.Window_windowIsTranslucent, false)) {
                    return;
@@ -4184,6 +4203,7 @@ public class WindowManagerService extends IWindowManager.Stub
                }
            }

            if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Creating StartingData");
            mStartingIconInTransition = true;
            wtoken.startingData = new StartingData(pkg, theme, compatInfo, nonLocalizedLabel,
                    labelRes, icon, windowFlags);
@@ -4191,6 +4211,7 @@ public class WindowManagerService extends IWindowManager.Stub
            // Note: we really want to do sendMessageAtFrontOfQueue() because we
            // want to process the message ASAP, before any other queued
            // messages.
            if (DEBUG_STARTING_WINDOW) Slog.v(TAG, "Enqueueing ADD_STARTING");
            mH.sendMessageAtFrontOfQueue(m);
        }
    }
@@ -8462,6 +8483,26 @@ public class WindowManagerService extends IWindowManager.Stub
        }
    }

    private void updateAllDrawnLocked() {
        // See if any windows have been drawn, so they (and others
        // associated with them) can now be shown.
        final ArrayList<AppWindowToken> appTokens = mAnimatingAppTokens;
        final int NT = appTokens.size();
        for (int i=0; i<NT; i++) {
            AppWindowToken wtoken = appTokens.get(i);
            if (!wtoken.allDrawn) {
                int numInteresting = wtoken.numInterestingWindows;
                if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
                    if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
                            "allDrawn: " + wtoken
                            + " interesting=" + numInteresting
                            + " drawn=" + wtoken.numDrawnWindows);
                    wtoken.allDrawn = true;
                }
            }
        }
    }

    // "Something has changed!  Let's make it correct now."
    private final void performLayoutAndPlaceSurfacesLockedInner(
            boolean recoveringMemory) {
@@ -8501,6 +8542,7 @@ public class WindowManagerService extends IWindowManager.Stub
        mInnerFields.mHoldScreen = null;
        mInnerFields.mScreenBrightness = -1;
        mInnerFields.mButtonBrightness = -1;
        mTransactionSequence++;

        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
                ">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
@@ -8578,6 +8620,7 @@ public class WindowManagerService extends IWindowManager.Stub
            mInnerFields.mSyswin = false;

            boolean focusDisplayed = false;
            boolean updateAllDrawn = false;
            final int N = mWindows.size();
            for (i=N-1; i>=0; i--) {
                WindowState w = mWindows.get(i);
@@ -8634,6 +8677,53 @@ public class WindowManagerService extends IWindowManager.Stub
                    }

                    winAnimator.setSurfaceBoundaries(recoveringMemory);

                    final AppWindowToken atoken = w.mAppToken;
                    if (DEBUG_STARTING_WINDOW && atoken != null && w == atoken.startingWindow) {
                        Slog.d(TAG, "updateWindows: starting " + w + " isOnScreen="
                            + w.isOnScreen() + " allDrawn=" + atoken.allDrawn
                            + " freezingScreen=" + atoken.mAppAnimator.freezingScreen);
                    }
                    if (atoken != null && (!atoken.allDrawn || atoken.mAppAnimator.freezingScreen)) {
                        if (atoken.lastTransactionSequence != mTransactionSequence) {
                            atoken.lastTransactionSequence = mTransactionSequence;
                            atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
                            atoken.startingDisplayed = false;
                        }
                        if ((w.isOnScreen() || winAnimator.mAttrType
                                == WindowManager.LayoutParams.TYPE_BASE_APPLICATION)
                                && !w.mExiting && !w.mDestroying) {
                            if (WindowManagerService.DEBUG_VISIBILITY ||
                                    WindowManagerService.DEBUG_ORIENTATION) {
                                Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawnLw()
                                        + ", isAnimating=" + winAnimator.isAnimating());
                                if (!w.isDrawnLw()) {
                                    Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurface
                                            + " pv=" + w.mPolicyVisibility
                                            + " mDrawState=" + winAnimator.mDrawState
                                            + " ah=" + w.mAttachedHidden
                                            + " th=" + atoken.hiddenRequested
                                            + " a=" + winAnimator.mAnimating);
                                }
                            }
                            if (w != atoken.startingWindow) {
                                if (!atoken.mAppAnimator.freezingScreen || !w.mAppFreezing) {
                                    atoken.numInterestingWindows++;
                                    if (w.isDrawnLw()) {
                                        atoken.numDrawnWindows++;
                                        if (WindowManagerService.DEBUG_VISIBILITY ||
                                                WindowManagerService.DEBUG_ORIENTATION) Slog.v(TAG,
                                                "tokenMayBeDrawn: " + atoken
                                                + " freezingScreen=" + atoken.mAppAnimator.freezingScreen
                                                + " mAppFreezing=" + w.mAppFreezing);
                                        updateAllDrawn = true;
                                    }
                                }
                            } else if (w.isDrawnLw()) {
                                atoken.startingDisplayed = true;
                            }
                        }
                    }
                }

                if (someoneLosingFocus && w == mCurrentFocus && w.isDisplayedLw()) {
@@ -8643,6 +8733,10 @@ public class WindowManagerService extends IWindowManager.Stub
                updateResizingWindows(w);
            }

            if (updateAllDrawn) {
                updateAllDrawnLocked();
            }

            if (focusDisplayed) {
                mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS);
            }
@@ -9771,7 +9865,8 @@ public class WindowManagerService extends IWindowManager.Stub
            }
            pw.print("  mSystemBooted="); pw.print(mSystemBooted);
                    pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled);
            pw.print("  mLayoutNeeded="); pw.println(mLayoutNeeded);
            pw.print("  mLayoutNeeded="); pw.print(mLayoutNeeded);
                    pw.print("mTransactionSequence="); pw.println(mTransactionSequence);
            pw.print("  mDisplayFrozen="); pw.print(mDisplayFrozen);
                    pw.print(" mWindowsFreezingScreen="); pw.print(mWindowsFreezingScreen);
                    pw.print(" mAppsFreezingScreen="); pw.print(mAppsFreezingScreen);
@@ -9832,6 +9927,8 @@ public class WindowManagerService extends IWindowManager.Stub
            }
            pw.print("  mStartingIconInTransition="); pw.print(mStartingIconInTransition);
                    pw.print(" mSkipAppTransitionAnimation="); pw.println(mSkipAppTransitionAnimation);
            pw.println("  Window Animator:");
            mAnimator.dump(pw, "    ", dumpAll);
        }
    }

Loading