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  * @author jsharkey
     30  */
     31 public class PromptHelper {
     32 	private final Object tag;
     33 
     34 	private Handler handler = null;
     35 
     36 	private Semaphore promptToken;
     37 	private Semaphore promptResponse;
     38 
     39 	public String promptInstructions = null;
     40 	public String promptHint = null;
     41 	public Object promptRequested = null;
     42 
     43 	private Object response = null;
     44 
     45 	public PromptHelper(Object tag) {
     46 		this.tag = tag;
     47 
     48 		// Threads must acquire this before they can send a prompt.
     49 		promptToken = new Semaphore(1);
     50 
     51 		// Responses will release this semaphore.
     52 		promptResponse = new Semaphore(0);
     53 	}
     54 
     55 
     56 	/**
     57 	 * Register a user interface handler, if available.
     58 	 */
     59 	public void setHandler(Handler handler) {
     60 		this.handler = handler;
     61 	}
     62 
     63 	/**
     64 	 * Set an incoming value from an above user interface. Will automatically
     65 	 * notify any waiting requests.
     66 	 */
     67 	public void setResponse(Object value) {
     68 		response = value;
     69 		promptRequested = null;
     70 		promptInstructions = null;
     71 		promptHint = null;
     72 		promptResponse.release();
     73 	}
     74 
     75 	/**
     76 	 * Return the internal response value just before erasing and returning it.
     77 	 */
     78 	protected Object popResponse() {
     79 		Object value = response;
     80 		response = null;
     81 		return value;
     82 	}
     83 
     84 
     85 	/**
     86 	 * Request a prompt response from parent. This is a blocking call until user
     87 	 * interface returns a value.
     88 	 * Only one thread can call this at a time. cancelPrompt() will force this to
     89 	 * immediately return.
     90 	 */
     91 	private Object requestPrompt(String instructions, String hint, Object type) throws InterruptedException {
     92 		Object response = null;
     93 
     94 		promptToken.acquire();
     95 
     96 		try {
     97 			promptInstructions = instructions;
     98 			promptHint = hint;
     99 			promptRequested = type;
    100 
    101 			// notify any parent watching for live events
    102 			if (handler != null)
    103 				Message.obtain(handler, -1, tag).sendToTarget();
    104 
    105 			// acquire lock until user passes back value
    106 			promptResponse.acquire();
    107 
    108 			response = popResponse();
    109 		} finally {
    110 			promptToken.release();
    111 		}
    112 
    113 		return response;
    114 	}
    115 
    116 	/**
    117 	 * Request a string response from parent. This is a blocking call until user
    118 	 * interface returns a value.
    119 	 * @param hint prompt hint for user to answer
    120 	 * @return string user has entered
    121 	 */
    122 	public String requestStringPrompt(String instructions, String hint) {
    123 		String value = null;
    124 		try {
    125 			value = (String)this.requestPrompt(instructions, hint, String.class);
    126 		} catch(Exception e) {
    127 		}
    128 		return value;
    129 	}
    130 
    131 	/**
    132 	 * Request a boolean response from parent. This is a blocking call until user
    133 	 * interface returns a value.
    134 	 * @param hint prompt hint for user to answer
    135 	 * @return choice user has made (yes/no)
    136 	 */
    137 	public Boolean requestBooleanPrompt(String instructions, String hint) {
    138 		Boolean value = null;
    139 		try {
    140 			value = (Boolean)this.requestPrompt(instructions, hint, Boolean.class);
    141 		} catch(Exception e) {
    142 		}
    143 		return value;
    144 	}
    145 
    146 	/**
    147 	 * Cancel an in-progress prompt.
    148 	 */
    149 	public void cancelPrompt() {
    150 		if (!promptToken.tryAcquire()) {
    151 			// A thread has the token, so try to interrupt it
    152 			response = null;
    153 			promptResponse.release();
    154 		} else {
    155 			// No threads have acquired the token
    156 			promptToken.release();
    157 		}
    158 	}
    159 }
    160