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