aboutsummaryrefslogtreecommitdiffstats
path: root/app/src/main/java/org/connectbot/service/PromptHelper.java
blob: 9c34f1abb9a4640669463b9a08d63a235c1aac0c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/*
 * 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 org.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;

	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;
		try {
			value = (String) 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) 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();
		}
	}
}