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

Commit 5bf96a8f authored by Satoshi Kataoka's avatar Satoshi Kataoka Committed by Android (Google) Code Review
Browse files

Merge "Add AsyncResultHolder."

parents 21066960 acdabb25
Loading
Loading
Loading
Loading
+7 −19
Original line number Diff line number Diff line
@@ -86,6 +86,7 @@ import com.android.inputmethod.latin.settings.SettingsActivity;
import com.android.inputmethod.latin.settings.SettingsValues;
import com.android.inputmethod.latin.suggestions.SuggestionStripView;
import com.android.inputmethod.latin.utils.ApplicationUtils;
import com.android.inputmethod.latin.utils.AsyncResultHolder;
import com.android.inputmethod.latin.utils.AutoCorrectionUtils;
import com.android.inputmethod.latin.utils.CapsModeUtils;
import com.android.inputmethod.latin.utils.CollectionUtils;
@@ -107,8 +108,6 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Locale;
import java.util.TreeSet;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * Input method implementation for Qwerty'ish keyboard.
@@ -2428,31 +2427,20 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
            return;
        }

        final CountDownLatch latch = new CountDownLatch(1);
        final SuggestedWords[] suggestedWordsArray = new SuggestedWords[1];
        final AsyncResultHolder<SuggestedWords> holder = new AsyncResultHolder<SuggestedWords>();
        getSuggestedWordsOrOlderSuggestionsAsync(Suggest.SESSION_TYPING,
                new OnGetSuggestedWordsCallback() {
                    @Override
                    public void onGetSuggestedWords(final SuggestedWords suggestedWords) {
                        suggestedWordsArray[0] = suggestedWords;
                        latch.countDown();
                        holder.set(suggestedWords);
                    }
                }
        );

        // TODO: Quit blocking the main thread.
        try {
            // Wait for the result of getSuggestedWords
            // We set the time out to avoid ANR.
            latch.await(GET_SUGGESTED_WORDS_TIMEOUT, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            // TODO: Cancel all pending "getSuggestedWords" tasks when it failed. We may want to add
            // "onGetSuggestionFailed" to "OnGetSuggestedWordsCallback".
            Log.e(TAG, "InterruptedException while waiting for getSuggestedWords.", e);
            return;
        }
        if (suggestedWordsArray[0] != null) {
            showSuggestionStrip(suggestedWordsArray[0]);
        // This line may cause the current thread to wait.
        final SuggestedWords suggestedWords = holder.get(null, GET_SUGGESTED_WORDS_TIMEOUT);
        if (suggestedWords != null) {
            showSuggestionStrip(suggestedWords);
        }
    }

+71 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * 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 com.android.inputmethod.latin.utils;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * This class is a holder of a result of asynchronous computation.
 *
 * @param <E> the type of the result.
 */
public class AsyncResultHolder<E> {

    private final Object mLock = new Object();

    private E mResult;
    private final CountDownLatch mLatch;

    public AsyncResultHolder() {
        mLatch = new CountDownLatch(1);
    }

    /**
     * Sets the result value to this holder.
     *
     * @param result the value which is set.
     */
    public void set(final E result) {
        synchronized(mLock) {
            if (mLatch.getCount() > 0) {
                mResult = result;
                mLatch.countDown();
            }
        }
    }

    /**
     * Gets the result value held in this holder.
     * Causes the current thread to wait unless the value is set or the specified time is elapsed.
     *
     * @param defaultValue the default value.
     * @param timeOut the time to wait.
     * @return if the result is set until the time limit then the result, otherwise defaultValue.
     */
    public E get(final E defaultValue, final long timeOut) {
        try {
            if(mLatch.await(timeOut, TimeUnit.MILLISECONDS)) {
                return mResult;
            } else {
                return defaultValue;
            }
        } catch (InterruptedException e) {
            return defaultValue;
        }
    }
}
+73 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * 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 com.android.inputmethod.latin.utils;

import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.MediumTest;
import android.util.Log;

@MediumTest
public class AsyncResultHolderTests extends AndroidTestCase {
    private static final String TAG = AsyncResultHolderTests.class.getSimpleName();

    private static final int TIMEOUT_IN_MILLISECONDS = 500;
    private static final int MARGIN_IN_MILLISECONDS = 250;
    private static final int DEFAULT_VALUE = 2;
    private static final int SET_VALUE = 1;

    private <T> void setAfterGivenTime(final AsyncResultHolder<T> holder, final T value,
            final long time) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(time);
                } catch (InterruptedException e) {
                    Log.d(TAG, "Exception while sleeping", e);
                }
                holder.set(value);
            }
        }).start();
    }

    public void testGetWithoutSet() {
        final AsyncResultHolder<Integer> holder = new AsyncResultHolder<Integer>();
        final int resultValue = holder.get(DEFAULT_VALUE, TIMEOUT_IN_MILLISECONDS);
        assertEquals(DEFAULT_VALUE, resultValue);
    }

    public void testGetBeforeSet() {
        final AsyncResultHolder<Integer> holder = new AsyncResultHolder<Integer>();
        setAfterGivenTime(holder, SET_VALUE, TIMEOUT_IN_MILLISECONDS + MARGIN_IN_MILLISECONDS);
        final int resultValue = holder.get(DEFAULT_VALUE, TIMEOUT_IN_MILLISECONDS);
        assertEquals(DEFAULT_VALUE, resultValue);
    }

    public void testGetAfterSet() {
        final AsyncResultHolder<Integer> holder = new AsyncResultHolder<Integer>();
        holder.set(SET_VALUE);
        final int resultValue = holder.get(DEFAULT_VALUE, TIMEOUT_IN_MILLISECONDS);
        assertEquals(SET_VALUE, resultValue);
    }

    public void testGetBeforeTimeout() {
        final AsyncResultHolder<Integer> holder = new AsyncResultHolder<Integer>();
        setAfterGivenTime(holder, SET_VALUE, TIMEOUT_IN_MILLISECONDS - MARGIN_IN_MILLISECONDS);
        final int resultValue = holder.get(DEFAULT_VALUE, TIMEOUT_IN_MILLISECONDS);
        assertEquals(SET_VALUE, resultValue);
    }
}