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

Commit 8863bcd5 authored by Gabor Keszthelyi's avatar Gabor Keszthelyi Committed by Marten Gajda
Browse files

Fix NPE in QuickAddDialogFragment delayed UI update. #629 (#635)

parent 3c3781b9
Loading
Loading
Loading
Loading
+5 −12
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@ import org.dmfs.tasks.contract.TaskContract.Tasks;
import org.dmfs.tasks.model.ContentSet;
import org.dmfs.tasks.model.TaskFieldAdapters;
import org.dmfs.tasks.utils.RecentlyUsedLists;
import org.dmfs.tasks.utils.SafeFragmentUiRunnable;
import org.dmfs.tasks.utils.TasksListCursorSpinnerAdapter;


@@ -479,23 +480,15 @@ public class QuickAddDialogFragment extends SupportDialogFragment


    /**
     * A runnable that closes the dialog.
     * A {@link Runnable} that closes the dialog.
     */
    private final Runnable mDismiss = new Runnable()
    {
        @Override
        public void run()
        {
            dismiss();
        }
    };
    private final Runnable mDismiss = new SafeFragmentUiRunnable(this, this::dismiss);

    /**
     * A {@link Runnable} that resets the editor view.
     */
    private final Runnable mReset = new Runnable()
    private final Runnable mReset = new SafeFragmentUiRunnable(this, new Runnable()
    {

        @Override
        public void run()
        {
@@ -512,5 +505,5 @@ public class QuickAddDialogFragment extends SupportDialogFragment
            InputMethodManager inputMethodManager = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
            inputMethodManager.showSoftInput(mEditText, 0);
        }
    };
    });
}
+16 −26
Original line number Diff line number Diff line
@@ -69,6 +69,7 @@ import org.dmfs.tasks.utils.FlingDetector.OnFlingListener;
import org.dmfs.tasks.utils.OnChildLoadedListener;
import org.dmfs.tasks.utils.OnModelLoadedListener;
import org.dmfs.tasks.utils.RetainExpandableListView;
import org.dmfs.tasks.utils.SafeFragmentUiRunnable;
import org.dmfs.tasks.utils.SearchHistoryDatabaseHelper.SearchHistoryColumns;


@@ -206,16 +207,16 @@ public class TaskListFragment extends SupportFragment
     * A runnable that periodically updates the list. We need that to update relative dates & times. TODO: we probably should move that to the adapter to update
     * only the date & times fields, not the entire list.
     */
    private Runnable mListRedrawRunnable = new Runnable()
    private Runnable mListRedrawRunnable = new SafeFragmentUiRunnable(this, new Runnable()
    {

        @Override
        public void run()
        {
            mExpandableListView.invalidateViews();
            mHandler.postDelayed(this, INTERVAL_LISTVIEW_REDRAW);
            mHandler.postDelayed(mListRedrawRunnable, INTERVAL_LISTVIEW_REDRAW);
        }
    };
    });


    public static TaskListFragment newInstance(int instancePosition, boolean twoPaneLayout)
@@ -442,14 +443,7 @@ public class TaskListFragment extends SupportFragment
            }
        }

        mHandler.post(new Runnable()
        {
            @Override
            public void run()
            {
                mAdapter.reloadLoadedGroups();
            }
        });
        mHandler.post(new SafeFragmentUiRunnable(this, () -> mAdapter.reloadLoadedGroups()));
    }


@@ -901,7 +895,7 @@ public class TaskListFragment extends SupportFragment
    }


    Runnable setOpenHandler = new Runnable()
    private Runnable setOpenHandler = new SafeFragmentUiRunnable(this, new Runnable()
    {
        @Override
        public void run()
@@ -910,7 +904,7 @@ public class TaskListFragment extends SupportFragment
            mExpandableListView.expandGroups(mSavedExpandedGroups);
            setActivatedItem(mActivatedPositionGroup, mActivatedPositionChild);
        }
    };
    });


    public void setActivatedItem(int groupPosition, int childPosition)
@@ -969,10 +963,7 @@ public class TaskListFragment extends SupportFragment
        if (mSelectedChildPosition != null)
        {
            // post delayed to allow the list view to finish creation
            mExpandableListView.postDelayed(new Runnable()
            {
                @Override
                public void run()
            mExpandableListView.postDelayed(new SafeFragmentUiRunnable(this, () ->
            {
                mExpandableListView.expandGroup(mSelectedChildPosition.groupPosition);
                mSelectedChildPosition.flatListPosition = mExpandableListView.getFlatListPosition(
@@ -981,8 +972,7 @@ public class TaskListFragment extends SupportFragment
                setActivatedItem(mSelectedChildPosition.groupPosition, mSelectedChildPosition.childPosition);
                selectChildView(mExpandableListView, mSelectedChildPosition.groupPosition, mSelectedChildPosition.childPosition, true);
                mExpandableListView.smoothScrollToPosition(mSelectedChildPosition.flatListPosition);
                }
            }, 0);
            }), 0);
        }
    }

+2 −13
Original line number Diff line number Diff line
@@ -64,6 +64,7 @@ import org.dmfs.tasks.notification.TaskNotificationHandler;
import org.dmfs.tasks.share.ShareIntentFactory;
import org.dmfs.tasks.utils.ContentValueMapper;
import org.dmfs.tasks.utils.OnModelLoadedListener;
import org.dmfs.tasks.utils.SafeFragmentUiRunnable;
import org.dmfs.tasks.widget.TaskView;

import java.util.Arrays;
@@ -151,18 +152,6 @@ public class ViewTaskFragment extends SupportFragment

    private boolean mIsTheTitleContainerVisible = true;

    /**
     * A Runnable that updates the view.
     */
    private Runnable mUpdateViewRunnable = new Runnable()
    {
        @Override
        public void run()
        {
            updateView();
        }
    };


    public interface Callback
    {
@@ -455,7 +444,7 @@ public class ViewTaskFragment extends SupportFragment
    {
        if (mContent != null)
        {
            mContent.post(mUpdateViewRunnable);
            mContent.post(new SafeFragmentUiRunnable(this, this::updateView));
        }
    }

+53 −0
Original line number Diff line number Diff line
/*
 * Copyright 2018 dmfs GmbH
 *
 * 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 org.dmfs.tasks.utils;

import android.support.v4.app.Fragment;


/**
 * {@link Runnable} control proxy / decorator that only runs the delegate {@link Runnable}
 * if the provided {@link Fragment} is still added to its activity when {@link #run()} is called.
 * <p>
 * Use this to safely execute a delayed UI update in a {@link Fragment}.
 * <p>
 * Do not use this when execution has (side)effects which have to be guaranteed.
 *
 * @author Gabor Keszthelyi
 */
public final class SafeFragmentUiRunnable implements Runnable
{
    private final Fragment mFragment;
    private final Runnable mDelegate;


    public SafeFragmentUiRunnable(Fragment fragment, Runnable delegate)
    {
        mFragment = fragment;
        mDelegate = delegate;
    }


    @Override
    public void run()
    {
        if (mFragment.isAdded() && mFragment.getActivity() != null)
        {
            mDelegate.run();
        }
    }
}