view src/com/five_ten_sg/connectbot/service/PromptHelper.java @ 251:587570134645

add range checking on get/set fields
author Carl Byington <carl@five-ten-sg.com>
date Mon, 14 Jul 2014 12:22:46 -0700
parents 0ce5cc452d02
children
line wrap: on
line source

/*
 * ConnectBot: simple, powerful, open-source SSH client for Android
 * Copyright 2007 Kenny Root, Jeffrey Sharkey
 *
 * 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.five_ten_sg.connectbot.service;

import java.util.concurrent.Semaphore;

import android.os.Handler;
import android.os.Message;

/**
 * Helps provide a relay for prompts and responses between a possible user
 * interface and some underlying service.
 *
 * @author jsharkey
 */
public class PromptHelper {
    private final Object tag;

    private Handler handler = null;

    private Semaphore promptToken;
    private Semaphore promptResponse;

    public String promptInstructions = null;
    public String promptHint = null;
    public Object promptRequested = null;
    public boolean passwordRequested = true;

    private Object response = null;

    public PromptHelper(Object tag) {
        this.tag = tag;
        // Threads must acquire this before they can send a prompt.
        promptToken = new Semaphore(1);
        // Responses will release this semaphore.
        promptResponse = new Semaphore(0);
    }


    /**
     * Register a user interface handler, if available.
     */
    public void setHandler(Handler handler) {
        this.handler = handler;
    }

    /**
     * Set an incoming value from an above user interface. Will automatically
     * notify any waiting requests.
     */
    public void setResponse(Object value) {
        response = value;
        promptRequested = null;
        promptInstructions = null;
        promptHint = null;
        promptResponse.release();
    }

    /**
     * Return the internal response value just before erasing and returning it.
     */
    protected Object popResponse() {
        Object value = response;
        response = null;
        return value;
    }


    /**
     * Request a prompt response from parent. This is a blocking call until user
     * interface returns a value.
     * Only one thread can call this at a time. cancelPrompt() will force this to
     * immediately return.
     */
    private Object requestPrompt(String instructions, String hint, Object type) throws InterruptedException {
        Object response = null;
        promptToken.acquire();

        try {
            promptInstructions = instructions;
            promptHint = hint;
            promptRequested = type;

            // notify any parent watching for live events
            if (handler != null)
                Message.obtain(handler, -1, tag).sendToTarget();

            // acquire lock until user passes back value
            promptResponse.acquire();
            response = popResponse();
        }
        finally {
            promptToken.release();
        }

        return response;
    }

    /**
     * Request a string response from parent. This is a blocking call until user
     * interface returns a value.
     * @param hint prompt hint for user to answer
     * @return string user has entered
     */
    public String requestStringPrompt(String instructions, String hint) {
        String value = null;
        passwordRequested = false;

        try {
            value = (String)this.requestPrompt(instructions, hint, String.class);
        }
        catch (Exception e) {
        }

        return value;
    }

    /**
     * Request a password response from parent. This is a blocking call until user
     * interface returns a value.
     * @param hint prompt hint for user to answer
     * @return string user has entered
     */
    public String requestPasswordPrompt(String instructions, String hint) {
        String value = null;
        passwordRequested = true;

        try {
            value = (String)this.requestPrompt(instructions, hint, String.class);
        }
        catch (Exception e) {
        }

        return value;
    }

    /**
     * Request a boolean response from parent. This is a blocking call until user
     * interface returns a value.
     * @param hint prompt hint for user to answer
     * @return choice user has made (yes/no)
     */
    public Boolean requestBooleanPrompt(String instructions, String hint) {
        Boolean value = null;

        try {
            value = (Boolean)this.requestPrompt(instructions, hint, Boolean.class);
        }
        catch (Exception e) {
        }

        return value;
    }

    /**
     * Cancel an in-progress prompt.
     */
    public void cancelPrompt() {
        if (!promptToken.tryAcquire()) {
            // A thread has the token, so try to interrupt it
            response = null;
            promptResponse.release();
        }
        else {
            // No threads have acquired the token
            promptToken.release();
        }
    }
}