Home | History | Annotate | Download | only in service
      1 /*
      2  * ConnectBot: simple, powerful, open-source SSH client for Android
      3  * Copyright 2007 Kenny Root, Jeffrey Sharkey
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 
     18 package org.connectbot.service;
     19 
     20 import java.util.concurrent.Semaphore;
     21 
     22 import android.os.Handler;
     23 import android.os.Message;
     24 
     25 /**
     26  * Helps provide a relay for prompts and responses between a possible user
     27  * interface and some underlying service.
     28  *
     29  */
     30 public class PromptHelper {
     31 	private final Object tag;
     32 
     33 	private Handler handler = null;
     34 
     35 	private Semaphore promptToken;
     36 	private Semaphore promptResponse;
     37 
     38 	public String promptInstructions = null;
     39 	public String promptHint = null;
     40 	public Object promptRequested = null;
     41 
     42 	private Object response = null;
     43 
     44 	public PromptHelper(Object tag) {
     45 		this.tag = tag;
     46 
     47 		// Threads must acquire this before they can send a prompt.
     48 		promptToken = new Semaphore(1);
     49 
     50 		// Responses will release this semaphore.
     51 		promptResponse = new Semaphore(0);
     52 	}
     53 
     54 
     55 	/**
     56 	 * Register a user interface handler, if available.
     57 	 */
     58 	public void setHandler(Handler handler) {
     59 		this.handler = handler;
     60 	}
     61 
     62 	/**
     63 	 * Set an incoming value from an above user interface. Will automatically
     64 	 * notify any waiting requests.
     65 	 */
     66 	public void setResponse(Object value) {
     67 		response = value;
     68 		promptRequested = null;
     69 		promptInstructions = null;
     70 		promptHint = null;
     71 		promptResponse.release();
     72 	}
     73 
     74 	/**
     75 	 * Return the internal response value just before erasing and returning it.
     76 	 */
     77 	protected Object popResponse() {
     78 		Object value = response;
     79 		response = null;
     80 		return value;
     81 	}
     82 
     83 
     84 	/**
     85 	 * Request a prompt response from parent. This is a blocking call until user
     86 	 * interface returns a value.
     87 	 * Only one thread can call this at a time. cancelPrompt() will force this to
     88 	 * immediately return.
     89 	 */
     90 	private Object requestPrompt(String instructions, String hint, Object type) throws InterruptedException {
     91 		Object response = null;
     92 
     93 		promptToken.acquire();
     94 
     95 		try {
     96 			promptInstructions = instructions;
     97 			promptHint = hint;
     98 			promptRequested = type;
     99 
    100 			// notify any parent watching for live events
    101 			if (handler != null)
    102 				Message.obtain(handler, -1, tag).sendToTarget();
    103 
    104 			// acquire lock until user passes back value
    105 			promptResponse.acquire();
    106 
    107 			response = popResponse();
    108 		} finally {
    109 			promptToken.release();
    110 		}
    111 
    112 		return response;
    113 	}
    114 
    115 	/**
    116 	 * Request a string response from parent. This is a blocking call until user
    117 	 * interface returns a value.
    118 	 * @param hint prompt hint for user to answer
    119 	 * @return string user has entered
    120 	 */
    121 	public String requestStringPrompt(String instructions, String hint) {
    122 		String value = null;
    123 		try {
    124 			value = (String)this.requestPrompt(instructions, hint, String.class);
    125 		} catch(Exception e) {
    126 		}
    127 		return value;
    128 	}
    129 
    130 	/**
    131 	 * Request a boolean response from parent. This is a blocking call until user
    132 	 * interface returns a value.
    133 	 * @param hint prompt hint for user to answer
    134 	 * @return choice user has made (yes/no)
    135 	 */
    136 	public Boolean requestBooleanPrompt(String instructions, String hint) {
    137 		Boolean value = null;
    138 		try {
    139 			value = (Boolean)this.requestPrompt(instructions, hint, Boolean.class);
    140 		} catch(Exception e) {
    141 		}
    142 		return value;
    143 	}
    144 
    145 	/**
    146 	 * Cancel an in-progress prompt.
    147 	 */
    148 	public void cancelPrompt() {
    149 		if (!promptToken.tryAcquire()) {
    150 			// A thread has the token, so try to interrupt it
    151 			response = null;
    152 			promptResponse.release();
    153 		} else {
    154 			// No threads have acquired the token
    155 			promptToken.release();
    156 		}
    157 	}
    158 }
    159