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 PromptHelper(Object tag)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 */ setHandler(Handler handler)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 */ setResponse(Object value)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 */ popResponse()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 */ requestPrompt(String instructions, String hint, Object type)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 */ requestStringPrompt(String instructions, String hint)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 */ requestBooleanPrompt(String instructions, String hint)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 */ cancelPrompt()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