<commit_before>package com.github.st1hy.countthemcalories.activities.ingredients.presenter;

import android.content.Context;
import android.database.Cursor;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.MotionEvent;
import android.view.View;
import android.widget.CursorAdapter;
import android.widget.SimpleCursorAdapter;

import com.github.st1hy.countthemcalories.activities.tags.fragment.model.RxTagsDatabaseModel;
import com.github.st1hy.countthemcalories.core.BasicLifecycle;
import com.github.st1hy.countthemcalories.core.adapter.ForwardingAdapter;
import com.github.st1hy.countthemcalories.core.tokensearch.SearchResult;
import com.github.st1hy.countthemcalories.core.tokensearch.TokenSearchView;
import com.github.st1hy.countthemcalories.database.TagDao;
import com.github.st1hy.countthemcalories.inject.PerActivity;
import com.google.common.base.Optional;
import com.jakewharton.rxbinding.view.RxView;

import java.util.Collections;

import javax.inject.Inject;
import javax.inject.Named;

import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.subscriptions.CompositeSubscription;

@PerActivity
public class SearchSuggestionsAdapter extends ForwardingAdapter<CursorAdapter> implements BasicLifecycle {

    private static final String COLUMN = TagDao.Properties.Name.columnName;

    @NonNull
    private final RxTagsDatabaseModel databaseModel;
    @NonNull
    private final TokenSearchView view;
    @NonNull
    private final Observable<SearchResult> searchResultObservable;
    private Optional<String> filter;
    @Inject
    @Named("touchOverlay")
    View touchOverlay;

    private boolean isDropDownVisible;

    private final CompositeSubscription subscriptions = new CompositeSubscription();

    @Inject
    public SearchSuggestionsAdapter(@NonNull @Named("activityContext") Context context,
                                    @NonNull RxTagsDatabaseModel databaseModel,
                                    @NonNull TokenSearchView view,
                                    @NonNull Observable<SearchResult> searchResultObservable,
                                    @NonNull Optional<String> filter) {
        super(new SimpleCursorAdapter(context,
                android.R.layout.simple_list_item_1,
                null,
                new String[]{COLUMN},
                new int[]{android.R.id.text1},
                0));
        this.databaseModel = databaseModel;
        this.view = view;
        this.searchResultObservable = searchResultObservable;
        this.filter = filter;
    }

    @Override
    public void onStart() {
        subscriptions.add(searchResultObservable
                .flatMap(searchResult -> {
                    if (searchResult.getQuery().trim().length() > 0)
                        return databaseModel.getAllFiltered(searchResult.getQuery(), searchResult.getTokens());
                    else return Observable.just(null);
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(this::changeCursor)
        );
        subscriptions.add(
                view.dropDownChange().subscribe(visible -> isDropDownVisible = visible)
        );
        subscriptions.add(
                RxView.touches(touchOverlay,
                        (event1) -> isDropDownVisible
                                && event1.getAction() == MotionEvent.ACTION_DOWN
                                || event1.getAction() == MotionEvent.ACTION_UP)
                        .filter(event -> event.getAction() == MotionEvent.ACTION_UP)
                        .subscribe(ignore -> view.dismissDropDown())
        );
        if (filter.isPresent()) {
            view.setQuery("", Collections.singletonList(filter.get()));
            view.expand(false);
            filter = Optional.absent();
        }
    }


    @Override
    public void onStop() {
        subscriptions.clear();
        changeCursor(null);
    }

    private void changeCursor(@Nullable Cursor cursor) {
        getParent().changeCursor(cursor);
    }

    /**
     * Some magic happens: while internally adapter uses cursor, from outside perspective this adapter
     * should be adapter of String, TokenSearchView assumes object it type of TokenSearchView
     * template parameter when creating chips
     */
    @Override
    public Object getItem(int position) {
        Cursor cursor = (Cursor) super.getItem(position);
        cursor.moveToPosition(position);
        return cursor.getString(cursor.getColumnIndexOrThrow(COLUMN));
    }

}<commit_msg>Trying to pinpoint cause of swapping to an closed cursor. Once.<commit_after>package com.github.st1hy.countthemcalories.activities.ingredients.presenter;

import android.content.Context;
import android.database.Cursor;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.MotionEvent;
import android.view.View;
import android.widget.CursorAdapter;
import android.widget.SimpleCursorAdapter;

import com.github.st1hy.countthemcalories.activities.tags.fragment.model.RxTagsDatabaseModel;
import com.github.st1hy.countthemcalories.core.BasicLifecycle;
import com.github.st1hy.countthemcalories.core.adapter.ForwardingAdapter;
import com.github.st1hy.countthemcalories.core.tokensearch.SearchResult;
import com.github.st1hy.countthemcalories.core.tokensearch.TokenSearchView;
import com.github.st1hy.countthemcalories.database.TagDao;
import com.github.st1hy.countthemcalories.inject.PerActivity;
import com.google.common.base.Optional;
import com.jakewharton.rxbinding.view.RxView;

import java.util.Collections;

import javax.inject.Inject;
import javax.inject.Named;

import rx.Observable;
import rx.android.schedulers.AndroidSchedulers;
import rx.subscriptions.CompositeSubscription;

@PerActivity
public class SearchSuggestionsAdapter extends ForwardingAdapter<CursorAdapter> implements BasicLifecycle {

    private static final String COLUMN = TagDao.Properties.Name.columnName;

    @NonNull
    private final RxTagsDatabaseModel databaseModel;
    @NonNull
    private final TokenSearchView view;
    @NonNull
    private final Observable<SearchResult> searchResultObservable;
    private Optional<String> filter;
    @Inject
    @Named("touchOverlay")
    View touchOverlay;

    private boolean isDropDownVisible;

    private final CompositeSubscription subscriptions = new CompositeSubscription();

    @Inject
    public SearchSuggestionsAdapter(@NonNull @Named("activityContext") Context context,
                                    @NonNull RxTagsDatabaseModel databaseModel,
                                    @NonNull TokenSearchView view,
                                    @NonNull Observable<SearchResult> searchResultObservable,
                                    @NonNull Optional<String> filter) {
        super(new SimpleCursorAdapter(context,
                android.R.layout.simple_list_item_1,
                null,
                new String[]{COLUMN},
                new int[]{android.R.id.text1},
                0));
        this.databaseModel = databaseModel;
        this.view = view;
        this.searchResultObservable = searchResultObservable;
        this.filter = filter;
    }

    @Override
    public void onStart() {
        subscriptions.add(searchResultObservable
                .flatMap(searchResult -> {
                    if (searchResult.getQuery().trim().length() > 0)
                        return databaseModel.getAllFiltered(searchResult.getQuery(), searchResult.getTokens());
                    else return Observable.just(null);
                })
                .doOnNext(SearchSuggestionsAdapter::assertCursorNotClosed)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(this::changeCursor)
        );
        subscriptions.add(
                view.dropDownChange().subscribe(visible -> isDropDownVisible = visible)
        );
        subscriptions.add(
                RxView.touches(touchOverlay,
                        (event1) -> isDropDownVisible
                                && event1.getAction() == MotionEvent.ACTION_DOWN
                                || event1.getAction() == MotionEvent.ACTION_UP)
                        .filter(event -> event.getAction() == MotionEvent.ACTION_UP)
                        .subscribe(ignore -> view.dismissDropDown())
        );
        if (filter.isPresent()) {
            view.setQuery("", Collections.singletonList(filter.get()));
            view.expand(false);
            filter = Optional.absent();
        }
    }


    @Override
    public void onStop() {
        subscriptions.clear();
        changeCursor(null);
    }

    private void changeCursor(@Nullable Cursor cursor) {
        assertCursorNotClosed(cursor);
        getParent().changeCursor(cursor);
    }

    /**
     * Some magic happens: while internally adapter uses cursor, from outside perspective this adapter
     * should be adapter of String, TokenSearchView assumes object it type of TokenSearchView
     * template parameter when creating chips
     */
    @Override
    public Object getItem(int position) {
        Cursor cursor = (Cursor) super.getItem(position);
        cursor.moveToPosition(position);
        return cursor.getString(cursor.getColumnIndexOrThrow(COLUMN));
    }

    private static void assertCursorNotClosed(@Nullable Cursor cursor) {
        if (cursor != null && cursor.isClosed())
            throw new IllegalStateException("Cannot change to closed cursor");
    }
}
{'fraction_non_alphanumeric': 0.0873057265046417, 'fraction_numerical': 0.003129237509126943, 'mean_word_length': 2.65675057208238, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7397722', 'n_tokens_mistral': 2471, 'n_tokens_neox': 2399, 'n_words': 475}