worker8 / TourGuide

TourGuide is an Android library that aims to provide an easy way to add pointers with animations over a desired Android View
MIT License
2.63k stars 416 forks source link

Crash on API 15 #52

Open NSouth opened 8 years ago

NSouth commented 8 years ago

My app is crashing for devices on API 15 (4.0.3) when mTutorialHandler.next() is called in my TourGuide sequence. I would appreciate any insight as to why this might be happening. This code is now in production, so I would really like to figure it out!

Logcat output:

11-07 23:48:42.171    6863-6863/com.MyDomain.MyApp W/dalvikvm﹕ threadid=1: thread exiting with uncaught exception (group=0xb3131180)
11-07 23:48:42.171    6863-6863/com.MyDomain.MyApp W/System.err﹕ java.lang.NullPointerException
11-07 23:48:42.171    6863-6863/com.MyDomain.MyApp W/System.err﹕ at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2488)
11-07 23:48:42.171    6863-6863/com.MyDomain.MyApp W/System.err﹕ at android.view.View.draw(View.java:10981)
11-07 23:48:42.171    6863-6863/com.MyDomain.MyApp W/System.err﹕ at android.widget.FrameLayout.draw(FrameLayout.java:450)
11-07 23:48:42.171    6863-6863/com.MyDomain.MyApp W/System.err﹕ at android.view.ViewGroup.drawChild(ViewGroup.java:2887)
11-07 23:48:42.171    6863-6863/com.MyDomain.MyApp W/System.err﹕ at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2489)
11-07 23:48:42.171    6863-6863/com.MyDomain.MyApp W/System.err﹕ at android.view.View.draw(View.java:10981)
11-07 23:48:42.171    6863-6863/com.MyDomain.MyApp W/System.err﹕ at android.view.ViewGroup.drawChild(ViewGroup.java:2887)
11-07 23:48:42.171    6863-6863/com.MyDomain.MyApp W/System.err﹕ at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2489)
11-07 23:48:42.171    6863-6863/com.MyDomain.MyApp W/System.err﹕ at android.view.ViewGroup.drawChild(ViewGroup.java:2885)
11-07 23:48:42.171    6863-6863/com.MyDomain.MyApp W/System.err﹕ at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2489)
11-07 23:48:42.171    6863-6863/com.MyDomain.MyApp W/System.err﹕ at android.view.View.draw(View.java:10981)
11-07 23:48:42.171    6863-6863/com.MyDomain.MyApp W/System.err﹕ at android.view.ViewGroup.drawChild(ViewGroup.java:2887)
11-07 23:48:42.171    6863-6863/com.MyDomain.MyApp W/System.err﹕ at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2489)
11-07 23:48:42.171    6863-6863/com.MyDomain.MyApp W/System.err﹕ at android.view.View.draw(View.java:10981)
11-07 23:48:42.171    6863-6863/com.MyDomain.MyApp W/System.err﹕ at android.widget.FrameLayout.draw(FrameLayout.java:450)
11-07 23:48:42.171    6863-6863/com.MyDomain.MyApp W/System.err﹕ at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:2126)
11-07 23:48:42.171    6863-6863/com.MyDomain.MyApp W/System.err﹕ at android.view.ViewRootImpl.draw(ViewRootImpl.java:2026)
11-07 23:48:42.171    6863-6863/com.MyDomain.MyApp W/System.err﹕ at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1634)
11-07 23:48:42.171    6863-6863/com.MyDomain.MyApp W/System.err﹕ at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2442)
11-07 23:48:42.171    6863-6863/com.MyDomain.MyApp W/System.err﹕ at android.os.Handler.dispatchMessage(Handler.java:99)
11-07 23:48:42.171    6863-6863/com.MyDomain.MyApp W/System.err﹕ at android.os.Looper.loop(Looper.java:137)
11-07 23:48:42.171    6863-6863/com.MyDomain.MyApp W/System.err﹕ at android.app.ActivityThread.main(ActivityThread.java:4424)
11-07 23:48:42.171    6863-6863/com.MyDomain.MyApp W/System.err﹕ at java.lang.reflect.Method.invokeNative(Native Method)
11-07 23:48:42.171    6863-6863/com.MyDomain.MyApp W/System.err﹕ at java.lang.reflect.Method.invoke(Method.java:511)
11-07 23:48:42.171    6863-6863/com.MyDomain.MyApp W/System.err﹕ at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
11-07 23:48:42.171    6863-6863/com.MyDomain.MyApp W/System.err﹕ at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
11-07 23:48:42.171    6863-6863/com.MyDomain.MyApp W/System.err﹕ at dalvik.system.NativeStart.main(Native Method)
11-07 23:48:42.171    6863-6863/com.MyDomain.MyApp W/FlurryAgent﹕ Error logged: uncaught
11-07 23:48:42.180    6863-6863/com.MyDomain.MyApp E/AndroidRuntime﹕ FATAL EXCEPTION: main
    java.lang.NullPointerException
            at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2488)
            at android.view.View.draw(View.java:10981)
            at android.widget.FrameLayout.draw(FrameLayout.java:450)
            at android.view.ViewGroup.drawChild(ViewGroup.java:2887)
            at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2489)
            at android.view.View.draw(View.java:10981)
            at android.view.ViewGroup.drawChild(ViewGroup.java:2887)
            at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2489)
            at android.view.ViewGroup.drawChild(ViewGroup.java:2885)
            at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2489)
            at android.view.View.draw(View.java:10981)
            at android.view.ViewGroup.drawChild(ViewGroup.java:2887)
            at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2489)
            at android.view.View.draw(View.java:10981)
            at android.widget.FrameLayout.draw(FrameLayout.java:450)
            at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:2126)
            at android.view.ViewRootImpl.draw(ViewRootImpl.java:2026)
            at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1634)
            at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2442)
            at android.os.Handler.dispatchMessage(Handler.java:99)
            at android.os.Looper.loop(Looper.java:137)
            at android.app.ActivityThread.main(ActivityThread.java:4424)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:511)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
            at dalvik.system.NativeStart.main(Native Method)

My code. As far as I can tell from debugging, the last step I reach is mTourGuide.next();

        public TourGuide mTutorialHandler;

        private void initiateTourGuide() {

            initPointer();
            initToolTipAnimations();
            initOverlay();
            initOverlayToPagerFrag();
            buildTourGuideSequenceMainFrag();
            blocking_view.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    mTutorialHandler.getOverlay().performClick();
                }
            });
        }

        private Pointer pointer;

        private void initPointer() {
            pointer = new Pointer().setColor(getResources().getColor(R.color.accent)).setGravity(Gravity.BOTTOM | Gravity.LEFT);
        }

        private Overlay overlay;

        private void initOverlay() {
            overlay = new Overlay().setStyle(Overlay.Style.Rectangle)
                    .disableClick(true)
                    .setEnterAnimation(toolTipEnterAnimation)
                    .setExitAnimation(toolTipExitAnimation)
                    .setBackgroundColor(Color.parseColor("#dd151515"))
                    .setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            try {
                                mTutorialHandler.next();  //*** Last step called in my code ***
                            } catch (Exception ex){
                                ex.printStackTrace();
                            }
                        }
                    })
            ;
        }

        private Overlay overlayToPagerFrag;

        private void initOverlayToPagerFrag() {
            overlayToPagerFrag = new Overlay().setStyle(Overlay.Style.Rectangle)
                    .disableClick(true)
                    .setEnterAnimation(toolTipEnterAnimation)
                    .setExitAnimation(toolTipExitAnimation)
                    .setBackgroundColor(Color.parseColor("#dd151515"))
                    .setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View view) {
                            mTutorialHandler.cleanUp();
                            blocking_view.setVisibility(View.GONE);
                            Fragment frag = getParentFragment();
                            if (frag != null) {
                                if (frag instanceof MainPagerFragment) {
                                    ((MainPagerFragment) frag).initiateTourGuide();
                                }
                            }
                        }
                    })
            ;
        }

        private ToolTip toolTip;

        Animation toolTipEnterAnimation;
        Animation toolTipExitAnimation;

        private void initToolTipAnimations() {
            /* setup enter and exit animation */
            toolTipEnterAnimation = new AlphaAnimation(0f, 1f);
            toolTipEnterAnimation.setDuration(800);
            toolTipEnterAnimation.setFillAfter(true);

            toolTipExitAnimation = new AlphaAnimation(1f, 0f);
            toolTipExitAnimation.setDuration(800);
            toolTipExitAnimation.setFillAfter(true);
        }

        private static final int TOUR_TAP_COURSE_STEP = 15;
        private static final int TOUR_EXPLAIN_ASSIGNMENTS_STEP = 16;
        private static final int TOUR_INDICATE_SCHEDULE_TAB_STEP = 17;

        private ToolTip getToolTip(int tutorialStep) {
            int ori = getResources().getConfiguration().orientation;
            switch (tutorialStep) {
                case TOUR_TAP_COURSE_STEP:
                    toolTip = new ToolTip()
                            .setTextColor(Color.WHITE)
                            .setBackgroundColor(Color.TRANSPARENT)
                            .setShadow(false);

                    if (ori != Configuration.ORIENTATION_LANDSCAPE) {
                        toolTip.setTitle("\n" + getActivity().getString(R.string.tour_tap_course));
                        toolTip.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL);
                    } else {
                        toolTip.setTitle(getActivity().getString(R.string.tour_tap_course));
                        toolTip.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL);
                    }

                    return toolTip;
                case TOUR_EXPLAIN_ASSIGNMENTS_STEP:
                    toolTip = new ToolTip()
                            .setTextColor(Color.WHITE)
                            .setBackgroundColor(Color.TRANSPARENT)
                            .setShadow(false);

                    if (ori != Configuration.ORIENTATION_LANDSCAPE) {
                        toolTip.setTitle("\n" + getActivity().getString(R.string.tour_approaching_assignments));
                        toolTip.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL);
                    } else {
                        toolTip.setTitle(getActivity().getString(R.string.tour_approaching_assignments));
                        toolTip.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL);
                    }

                    return toolTip;
                case TOUR_INDICATE_SCHEDULE_TAB_STEP:
                    toolTip = new ToolTip()
                            .setTextColor(getResources().getColor(R.color.primary_dark))
                            .setBackgroundColor(Color.TRANSPARENT)
                            .setShadow(true);

                    if (ori != Configuration.ORIENTATION_LANDSCAPE) {
                        toolTip.setTitle("\n\n" + getActivity().getString(R.string.assignments_and_schedule));
                        toolTip.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL);
                    } else {
                        toolTip.setTitle(getActivity().getString(R.string.assignments_and_schedule));
                        toolTip.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL);
                    }
                    return toolTip;
                default:
                    return null;
            }
        }

        private void buildTourGuideSequenceMainFrag() {

            TourGuide tourGuide1_tapCourse = TourGuide.init(getActivity())
                    .setPointer(pointer)
                    .setToolTip(getToolTip(TOUR_TAP_COURSE_STEP))
                    .playLater(rootView.findViewById(R.id.course_entire_list_card_view));

            TourGuide tourGuide2_explainAssignments = TourGuide.init(getActivity())
                    .setPointer(pointer)
                    .setToolTip(getToolTip(TOUR_EXPLAIN_ASSIGNMENTS_STEP))
                    .setOverlay(overlayToPagerFrag)
                    .playLater(rootView.findViewById(R.id.assignment_entire_list_card_view));

            Sequence sequence = new Sequence.SequenceBuilder()
                    .add(tourGuide1_tapCourse, tourGuide2_explainAssignments)
                    .setDefaultOverlay(overlay)
                    .setDefaultPointer(null)
                    .setContinueMethod(Sequence.ContinueMethod.OverlayListener)
                    .build();

            blocking_view.setVisibility(View.VISIBLE);
            mTutorialHandler = TourGuide.init(getActivity()).playInSequence(sequence);
        }
    }
alessandrodd commented 8 years ago

Same here, everything works fine on Lollipop but crashes on ICS.

    /* setup enter and exit animation */
    AlphaAnimation mEnterAnimation = new AlphaAnimation(0f, 1f);
    mEnterAnimation.setDuration(600);
    mEnterAnimation.setFillAfter(true);

    AlphaAnimation mExitAnimation = new AlphaAnimation(1f, 0f);
    mExitAnimation.setDuration(600);
    mExitAnimation.setFillAfter(true);

    // the return handler is used to manipulate the cleanup of all the tutorial elements
    TourGuide tourGuide1 = TourGuide.init(this)
            .setToolTip(new ToolTip()
                    .setTitle(getString(R.string.tutorial1_title))
                    .setDescription(getString(R.string.tutorial1))
                    .setGravity(Gravity.CENTER)
            )
            // note that there is not Overlay here, so the default one will be used
            .playLater(screenCenter);

    TourGuide tourGuide2 = TourGuide.init(this)
            .setToolTip(new ToolTip()
                    .setTitle(getString(R.string.tutorial2_title))
                    .setDescription(getString(R.string.tutorial2))
                    .setGravity(Gravity.BOTTOM)
                    .setBackgroundColor(Color.parseColor("#c0392b"))
            )
            .playLater(noticeContainer);

    TourGuide tourGuide3 = TourGuide.init(this)
            .setToolTip(new ToolTip()
                    .setDescription(getString(R.string.tutorial3))
                    .setGravity(Gravity.BOTTOM)
            )
            // note that there is not Overlay here, so the default one will be used
            .playLater(noticeContainer);

    Sequence sequence = new Sequence.SequenceBuilder()
            .add(tourGuide1, tourGuide2, tourGuide3)
            .setDefaultOverlay(new Overlay()
                    .setEnterAnimation(mEnterAnimation)
                    .setExitAnimation(mExitAnimation).setBackgroundColor(Color.parseColor("#8800796B")).setStyle(Overlay.Style.Rectangle)
            )
            .setDefaultPointer(null)
            .setContinueMethod(Sequence.ContinueMethod.Overlay)
            .build();
    TourGuide.init(this).playInSequence(sequence);
rikkert09 commented 8 years ago

Still not fixed on ICS (API 15) any updates?

06-04 10:32:03.574 6158-6158/xx.xxxx.xxxx.xxxx E/AndroidRuntime: FATAL EXCEPTION: main
                                                                          java.lang.NullPointerException
                                                                              at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2488)
                                                                              at android.view.View.draw(View.java:10986)
                                                                              at android.widget.FrameLayout.draw(FrameLayout.java:450)
                                                                              at android.view.View.getDisplayList(View.java:10422)
                                                                              at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:2597)
                                                                              at android.view.View.getDisplayList(View.java:10385)
                                                                              at android.view.ViewGroup.drawChild(ViewGroup.java:2850)
                                                                              at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2489)
                                                                              at android.view.View.draw(View.java:10986)
                                                                              at android.widget.FrameLayout.draw(FrameLayout.java:450)
                                                                              at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:2126)
                                                                              at android.view.View.getDisplayList(View.java:10422)
                                                                              at android.view.HardwareRenderer$GlRenderer.draw(HardwareRenderer.java:849)
                                                                              at android.view.ViewRootImpl.draw(ViewRootImpl.java:1910)
                                                                              at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1634)
                                                                              at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2442)
                                                                              at android.os.Handler.dispatchMessage(Handler.java:99)
                                                                              at android.os.Looper.loop(Looper.java:137)
                                                                              at android.app.ActivityThread.main(ActivityThread.java:4424)
                                                                              at java.lang.reflect.Method.invokeNative(Native Method)
                                                                              at java.lang.reflect.Method.invoke(Method.java:511)
                                                                              at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
                                                                              at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
                                                                              at dalvik.system.NativeStart.main(Native Method)
cdecron commented 6 years ago

I had the same problem, and I found that it's caused by the Overlay exit animation. Don't set any exit animation for Android API 15, and it's fixed!