aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPablo Leite <wpl020@motorola.com>2011-05-30 15:14:14 -0300
committerPablo Leite <wpl020@motorola.com>2011-08-11 17:06:28 -0300
commit924958e21bbe1d3c918235d9ca78a6dc64c7879b (patch)
tree7056015ca3fc9ae9ac622467da481f52197ea8df
parent8b7e1b8e01a90c08b94880aa0ddc68135593a309 (diff)
downloadsdk-924958e21bbe1d3c918235d9ca78a6dc64c7879b.zip
sdk-924958e21bbe1d3c918235d9ca78a6dc64c7879b.tar.gz
sdk-924958e21bbe1d3c918235d9ca78a6dc64c7879b.tar.bz2
Add support for authenticated add-on servers.
Displays a login prompt if necessary. Note: This code depends on Apache http-client libraries. Build files had been modified in order to add this dependency. http-client libraries had also be added on prebuilt project. prebuilt changeID=I084d78dd09a431bc3a2d77e77810b84c693bdcb7 GerritLink=https://review.source.android.com/#change,23387 Change-Id: Icada9b41a21fe3aacef9a1eff209a3fe5591a4e0
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/.classpath5
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF8
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/build.properties7
-rwxr-xr-xsdkmanager/app/etc/android.bat5
-rw-r--r--sdkmanager/libs/sdklib/.classpath5
-rw-r--r--sdkmanager/libs/sdklib/Android.mk7
-rw-r--r--sdkmanager/libs/sdklib/manifest.txt2
-rwxr-xr-xsdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AddonsListFetcher.java27
-rwxr-xr-xsdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ArchiveInstaller.java6
-rwxr-xr-xsdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ITaskMonitor.java17
-rwxr-xr-xsdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/NullTaskMonitor.java7
-rwxr-xr-xsdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/SdkSource.java32
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/UrlOpener.java193
-rwxr-xr-xsdkmanager/libs/sdklib/tests/src/com/android/sdklib/internal/repository/MockMonitor.java5
-rwxr-xr-xsdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/SdkUpdaterNoWindow.java74
-rwxr-xr-xsdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/tasks/IProgressUiProvider.java17
-rwxr-xr-xsdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/tasks/ProgressTaskDialog.java45
-rwxr-xr-xsdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/tasks/ProgressView.java57
-rwxr-xr-xsdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/tasks/TaskMonitorImpl.java24
-rw-r--r--sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/ui/AuthenticationDialog.java132
20 files changed, 620 insertions, 55 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/.classpath b/eclipse/plugins/com.android.ide.eclipse.adt/.classpath
index a77b6b6..72a5c8b 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/.classpath
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/.classpath
@@ -1,6 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry excluding="Makefile|resources/" kind="src" path="src"/>
+ <classpathentry kind="lib" path="libs/commons-codec-1.4.jar"/>
+ <classpathentry kind="lib" path="libs/commons-logging-1.1.1.jar"/>
+ <classpathentry kind="lib" path="libs/httpclient-4.1.1.jar"/>
+ <classpathentry kind="lib" path="libs/httpcore-4.1.jar"/>
+ <classpathentry kind="lib" path="libs/httpmime-4.1.1.jar"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="lib" path="libs/androidprefs.jar" sourcepath="/AndroidPrefs"/>
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF b/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF
index 49f73e6..ebcf44f 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF
@@ -14,7 +14,13 @@ Bundle-ClassPath: .,
libs/layoutlib_api.jar,
libs/ide_common.jar,
libs/common.jar,
- libs/assetstudio.jar
+ libs/assetstudio.jar,
+ libs/httpclient-4.1.1.jar,
+ libs/httpcore-4.1.jar,
+ libs/httpmime-4.1.1.jar,
+ libs/httpclient-4.1.1.jar,
+ libs/commons-logging-1.1.1.jar,
+ libs/commons-codec-1.4.jar
Bundle-Activator: com.android.ide.eclipse.adt.AdtPlugin
Bundle-Vendor: The Android Open Source Project
Require-Bundle: com.android.ide.eclipse.ddms,
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/build.properties b/eclipse/plugins/com.android.ide.eclipse.adt/build.properties
index 96d191e..a82e779 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/build.properties
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/build.properties
@@ -8,7 +8,12 @@ bin.includes = plugin.xml,\
about.properties,\
NOTICE,\
about.html,\
- libs/common.jar
+ libs/common.jar,\
+ libs/httpclient-4.1.1.jar,\
+ libs/httpcore-4.1.jar,\
+ libs/httpmime-4.1.1.jar,\
+ libs/commons-logging-1.1.1.jar,\
+ libs/commons-codec-1.4.jar
source.. = src/
output.. = bin/
bin.excludes = libs/.gitignore
diff --git a/sdkmanager/app/etc/android.bat b/sdkmanager/app/etc/android.bat
index f616dd7..3233ebd 100755
--- a/sdkmanager/app/etc/android.bat
+++ b/sdkmanager/app/etc/android.bat
@@ -61,6 +61,11 @@ if not "%1"=="" goto EndTempCopy
copy /B /D /Y lib\common.jar %tmp_dir%\lib\ > nul
copy /B /D /Y lib\commons-compress* %tmp_dir%\lib\ > nul
copy /B /D /Y lib\swtmenubar.jar %tmp_dir%\lib\ > nul
+ copy /B /D /Y lib\commons-logging* %tmp_dir%\lib\ > nul
+ copy /B /D /Y lib\commons-codec* %tmp_dir%\lib\ > nul
+ copy /B /D /Y lib\httpclient* %tmp_dir%\lib\ > nul
+ copy /B /D /Y lib\httpcode* %tmp_dir%\lib\ > nul
+ copy /B /D /Y lib\httpmime* %tmp_dir%\lib\ > nul
rem jar_path and swt_path are relative to PWD so we don't need to adjust them, just change dirs.
set tools_dir=%cd%
diff --git a/sdkmanager/libs/sdklib/.classpath b/sdkmanager/libs/sdklib/.classpath
index 7cabaa0..c48e0bf 100644
--- a/sdkmanager/libs/sdklib/.classpath
+++ b/sdkmanager/libs/sdklib/.classpath
@@ -7,5 +7,10 @@
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/>
<classpathentry kind="var" path="ANDROID_SRC/prebuilt/common/commons-compress/commons-compress-1.0.jar"/>
<classpathentry combineaccessrules="false" kind="src" path="/common"/>
+ <classpathentry kind="var" path="ANDROID_SRC/prebuilt/common/http-client/commons-codec-1.4.jar"/>
+ <classpathentry kind="var" path="ANDROID_SRC/prebuilt/common/http-client/commons-logging-1.1.1.jar"/>
+ <classpathentry kind="var" path="ANDROID_SRC/prebuilt/common/http-client/httpclient-4.1.1.jar"/>
+ <classpathentry kind="var" path="ANDROID_SRC/prebuilt/common/http-client/httpcore-4.1.jar"/>
+ <classpathentry kind="var" path="ANDROID_SRC/prebuilt/common/http-client/httpmime-4.1.1.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath> \ No newline at end of file
diff --git a/sdkmanager/libs/sdklib/Android.mk b/sdkmanager/libs/sdklib/Android.mk
index 7ed009c..ab800da 100644
--- a/sdkmanager/libs/sdklib/Android.mk
+++ b/sdkmanager/libs/sdklib/Android.mk
@@ -28,7 +28,12 @@ LOCAL_JAR_MANIFEST := manifest.txt
LOCAL_JAVA_LIBRARIES := \
androidprefs \
common \
- commons-compress-1.0
+ commons-compress-1.0 \
+ httpclient-4.1.1 \
+ httpcore-4.1 \
+ httpmime-4.1.1 \
+ commons-logging-1.1.1 \
+ commons-codec-1.4
LOCAL_MODULE := sdklib
diff --git a/sdkmanager/libs/sdklib/manifest.txt b/sdkmanager/libs/sdklib/manifest.txt
index 0ead4fc..0efb701 100644
--- a/sdkmanager/libs/sdklib/manifest.txt
+++ b/sdkmanager/libs/sdklib/manifest.txt
@@ -1 +1 @@
-Class-Path: androidprefs.jar common.jar commons-compress-1.0.jar
+Class-Path: androidprefs.jar common.jar commons-compress-1.0.jar httpclient-4.1.1.jar httpcore-4.1.jar httpmime-4.1.1.jar commons-logging-1.1.1.jar commons-codec-1.4.jar
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AddonsListFetcher.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AddonsListFetcher.java
index 11dad83..93a8a98 100755
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AddonsListFetcher.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AddonsListFetcher.java
@@ -31,7 +31,6 @@ import java.io.ByteArrayInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
-import java.net.URL;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.regex.Matcher;
@@ -91,7 +90,7 @@ public class AddonsListFetcher {
url = url == null ? "" : url.trim();
- monitor.setProgressMax(4);
+ monitor.setProgressMax(5);
monitor.setDescription("Fetching %1$s", url);
monitor.incProgress(1);
@@ -101,7 +100,7 @@ public class AddonsListFetcher {
Document validatedDoc = null;
String validatedUri = null;
- ByteArrayInputStream xml = fetchUrl(url, exception);
+ ByteArrayInputStream xml = fetchUrl(url, monitor.createSubMonitor(1), exception);
if (xml != null) {
monitor.setDescription("Validate XML");
@@ -176,21 +175,19 @@ public class AddonsListFetcher {
}
/**
- * Fetches the document at the given URL and returns it as a stream.
- * Returns null if anything wrong happens.
- *
- * References: <br/>
- * Java URL Connection: http://java.sun.com/docs/books/tutorial/networking/urls/readingWriting.html <br/>
- * Java URL Reader: http://java.sun.com/docs/books/tutorial/networking/urls/readingURL.html <br/>
- * Java set Proxy: http://java.sun.com/docs/books/tutorial/networking/urls/_setProxy.html <br/>
+ * Fetches the document at the given URL and returns it as a stream. Returns
+ * null if anything wrong happens. References: <br/>
+ * URL Connection:
*
+ * @see {@link UrlOpener} which handles all URL logic.
* @param urlString The URL to load, as a string.
- * @param outException If non null, where to store any exception that happens during the fetch.
+ * @param monitor {@link ITaskMonitor} related to this URL.
+ * @param outException If non null, where to store any exception that
+ * happens during the fetch.
*/
- private ByteArrayInputStream fetchUrl(String urlString, Exception[] outException) {
- URL url;
+ private ByteArrayInputStream fetchUrl(String urlString, ITaskMonitor monitor,
+ Exception[] outException) {
try {
- url = new URL(urlString);
InputStream is = null;
@@ -199,7 +196,7 @@ public class AddonsListFetcher {
byte[] result = new byte[inc];
try {
- is = url.openStream();
+ is = UrlOpener.openURL(urlString, monitor);
int n;
while ((n = is.read(result, curr, result.length - curr)) != -1) {
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ArchiveInstaller.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ArchiveInstaller.java
index 552c7bb..06e64df 100755
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ArchiveInstaller.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ArchiveInstaller.java
@@ -30,7 +30,6 @@ import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Enumeration;
@@ -38,7 +37,6 @@ import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
-
/**
* Performs the work of installing a given {@link Archive}.
*/
@@ -267,15 +265,13 @@ public class ArchiveInstaller {
String urlString,
String description,
ITaskMonitor monitor) {
- URL url;
description += " (%1$d%%, %2$.0f KiB/s, %3$d %4$s left)";
FileOutputStream os = null;
InputStream is = null;
try {
- url = new URL(urlString);
- is = url.openStream();
+ is = UrlOpener.openURL(urlString, monitor);
os = new FileOutputStream(tmpFile);
MessageDigest digester = archive.getChecksumType().getMessageDigest();
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ITaskMonitor.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ITaskMonitor.java
index 313f36e..4a1a1e0 100755
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ITaskMonitor.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/ITaskMonitor.java
@@ -17,6 +17,7 @@
package com.android.sdklib.internal.repository;
import com.android.sdklib.ISdkLog;
+import com.android.util.Pair;
/**
@@ -131,4 +132,20 @@ public interface ITaskMonitor extends ISdkLog {
* @return true if YES was clicked.
*/
public boolean displayPrompt(final String title, final String message);
+
+ /**
+ * Launch an interface which asks for login and password. Implementations
+ * MUST allow this to be called from any thread, e.g. by making sure the
+ * dialog is opened synchronously in the UI thread.
+ *
+ * @param title The title of the dialog box.
+ * @param message The message to be displayed as an instruction.
+ * @return Returns a {@link Pair} holding the entered login and password.
+ * The information must always be in the following order:
+ * Login,Password. So in order to retrieve the <b>login</b> callers
+ * should retrieve the first element, and the second value for the
+ * <b>password</b>.
+ If operation is <b>canceled</b> by user the return value must be <b>null</b>.
+ */
+ public Pair<String, String> displayLoginPasswordPrompt(String title, String message);
}
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/NullTaskMonitor.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/NullTaskMonitor.java
index afe291f..8cd52d6 100755
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/NullTaskMonitor.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/NullTaskMonitor.java
@@ -18,6 +18,7 @@ package com.android.sdklib.internal.repository;
import com.android.sdklib.ISdkLog;
import com.android.sdklib.NullSdkLog;
+import com.android.util.Pair;
/**
@@ -92,6 +93,11 @@ public class NullTaskMonitor implements ITaskMonitor {
return false;
}
+ /** Always return null. */
+ public Pair<String, String> displayLoginPasswordPrompt(String title, String message) {
+ return null;
+ }
+
// --- ISdkLog ---
public void error(Throwable t, String errorFormat, Object... args) {
@@ -105,4 +111,5 @@ public class NullTaskMonitor implements ITaskMonitor {
public void printf(String msgFormat, Object... args) {
mLog.printf(msgFormat, args);
}
+
}
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/SdkSource.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/SdkSource.java
index 22b9c42..a5b16c3 100755
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/SdkSource.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/SdkSource.java
@@ -249,7 +249,7 @@ public abstract class SdkSource implements IDescription, Comparable<SdkSource> {
*/
public void load(ITaskMonitor monitor, boolean forceHttp) {
- monitor.setProgressMax(4);
+ monitor.setProgressMax(6);
setDefaultDescription();
@@ -265,7 +265,7 @@ public abstract class SdkSource implements IDescription, Comparable<SdkSource> {
Boolean[] validatorFound = new Boolean[] { Boolean.FALSE };
String[] validationError = new String[] { null };
Exception[] exception = new Exception[] { null };
- InputStream xml = fetchUrl(url, exception);
+ InputStream xml = fetchUrl(url, monitor.createSubMonitor(1), exception);
Document validatedDoc = null;
boolean usingAlternateXml = false;
boolean usingAlternateUrl = false;
@@ -279,13 +279,15 @@ public abstract class SdkSource implements IDescription, Comparable<SdkSource> {
}
url += getUrlDefaultXmlFile();
- xml = fetchUrl(url, exception);
+ xml = fetchUrl(url, monitor.createSubMonitor(1), exception);
usingAlternateUrl = true;
}
if (xml != null) {
monitor.setDescription(String.format("Validate XML: %1$s", url));
+ ITaskMonitor subMonitor = monitor.createSubMonitor(2);
+ subMonitor.setProgressMax(2);
for (int tryOtherUrl = 0; tryOtherUrl < 2; tryOtherUrl++) {
// Explore the XML to find the potential XML schema version
int version = getXmlSchemaVersion(xml);
@@ -347,8 +349,8 @@ public abstract class SdkSource implements IDescription, Comparable<SdkSource> {
}
url += getUrlDefaultXmlFile();
- xml = fetchUrl(url, null /*outException*/);
-
+ xml = fetchUrl(url, subMonitor.createSubMonitor(1), null /* outException */);
+ subMonitor.incProgress(1);
// Loop to try the alternative document
if (xml != null) {
usingAlternateUrl = true;
@@ -465,21 +467,19 @@ public abstract class SdkSource implements IDescription, Comparable<SdkSource> {
}
/**
- * Fetches the document at the given URL and returns it as a string.
- * Returns null if anything wrong happens and write errors to the monitor.
- *
+ * Fetches the document at the given URL and returns it as a string. Returns
+ * null if anything wrong happens and write errors to the monitor.
* References: <br/>
- * Java URL Connection: http://java.sun.com/docs/books/tutorial/networking/urls/readingWriting.html <br/>
- * Java URL Reader: http://java.sun.com/docs/books/tutorial/networking/urls/readingURL.html <br/>
- * Java set Proxy: http://java.sun.com/docs/books/tutorial/networking/urls/_setProxy.html <br/>
+ * URL Connection:
*
+ * @see {@link UrlOpener} which handles all URL logic.
* @param urlString The URL to load, as a string.
- * @param outException If non null, where to store any exception that happens during the fetch.
+ * @param monitor {@link ITaskMonitor} related to this URL.
+ * @param outException If non null, where to store any exception that
+ * happens during the fetch.
*/
- private InputStream fetchUrl(String urlString, Exception[] outException) {
- URL url;
+ private InputStream fetchUrl(String urlString, ITaskMonitor monitor, Exception[] outException) {
try {
- url = new URL(urlString);
InputStream is = null;
@@ -488,7 +488,7 @@ public abstract class SdkSource implements IDescription, Comparable<SdkSource> {
byte[] result = new byte[inc];
try {
- is = url.openStream();
+ is = UrlOpener.openURL(urlString, monitor);
int n;
while ((n = is.read(result, curr, result.length - curr)) != -1) {
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/UrlOpener.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/UrlOpener.java
new file mode 100644
index 0000000..a99baf6
--- /dev/null
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/UrlOpener.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * 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 com.android.sdklib.internal.repository;
+
+import com.android.util.Pair;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.AuthState;
+import org.apache.http.auth.Credentials;
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.protocol.ClientContext;
+import org.apache.http.entity.BufferedHttpEntity;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.impl.conn.ProxySelectorRoutePlanner;
+import org.apache.http.protocol.BasicHttpContext;
+import org.apache.http.protocol.HttpContext;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.ProxySelector;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This class holds methods for adding URLs management.
+ */
+public class UrlOpener {
+
+ private static Map<String, Pair<String, String>> sRealmCache =
+ new HashMap<String, Pair<String, String>>();
+
+ /**
+ * Open a URL. It can be a simple URL or one which requires basic
+ * authentication. </br> <i>Description</i>
+ * <p>
+ * Tries to access the given URL. If http response is either
+ * {@link HttpStatus.SC_UNAUTHORIZED} or
+ * {@link HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED} asks for
+ * login/password and tries to authenticate into proxy server and/or URL.
+ * </p>
+ * <p>
+ * This implementation relies on the Apache Http Client due to its
+ * capabilities of proxy/http authentication. </br> Proxy configuration is
+ * determined by {@link ProxySelectorRoutePlanner} using the JVM proxy
+ * settings by default. For more information see:
+ * <a>http://hc.apache.org/httpcomponents-client-ga/</a>
+ * <a>http://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/impl/conn/ProxySelectorRoutePlanner.html</a>
+ * </p>
+ * <p>
+ * There's a very simple<b>cache</b> implementation. Login/Password for each
+ * realm are stored on a static {@link Map}. Before asking the user the
+ * method verifies if the information is already available in cache
+ * </p>
+ *
+ * @param url the URL string to be opened.
+ * @param monitor {@link ITaskMonitor} which is related to this URL
+ * fetching.
+ * @return Returns an {@link InputStream} holding the URL content.
+ * @throws IOException Exception thrown when there are problems retrieving
+ * the URL or its content.
+ */
+ static InputStream openURL(String url, ITaskMonitor monitor) throws IOException {
+
+ InputStream stream = null;
+ HttpEntity entity = null;
+ Pair<String, String> result = null;
+ String realm = null;
+
+ // use the simple one
+ DefaultHttpClient httpclient = new DefaultHttpClient();
+
+ // create local execution context
+ HttpContext localContext = new BasicHttpContext();
+ HttpGet httpget = new HttpGet(url);
+
+ // retrieve local java configured network in case there is the need to
+ // authenticate a proxy
+ ProxySelectorRoutePlanner routePlanner = new ProxySelectorRoutePlanner(httpclient
+ .getConnectionManager().getSchemeRegistry(), ProxySelector.getDefault());
+ httpclient.setRoutePlanner(routePlanner);
+
+ boolean trying = true;
+ // loop while the response is being fetched
+ while (trying) {
+ // connect and get status code
+ HttpResponse response = httpclient.execute(httpget, localContext);
+ int statusCode = response.getStatusLine().getStatusCode();
+
+ // check whether any authentication is required
+ AuthState authenticationState = null;
+ if (statusCode == HttpStatus.SC_UNAUTHORIZED) {
+ // Target host authentication required
+ authenticationState = (AuthState) localContext
+ .getAttribute(ClientContext.TARGET_AUTH_STATE);
+ }
+ if (statusCode == HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED) {
+ // Proxy authentication required
+ authenticationState = (AuthState) localContext
+ .getAttribute(ClientContext.PROXY_AUTH_STATE);
+ }
+ if (statusCode == HttpStatus.SC_OK) {
+ // in case the status is OK and there is a realm and result,
+ // cache it
+ if (realm != null && result != null) {
+ sRealmCache.put(realm, result);
+ }
+ }
+
+ // there is the need for authentication
+ if (authenticationState != null) {
+
+ // get scope and realm
+ AuthScope authScope = authenticationState.getAuthScope();
+
+ // If the current realm is different from the last one it means
+ // a pass was performed successfully to the last URL, therefore
+ // cache the last realm
+ if (realm != null && !realm.equals(authScope.getRealm())) {
+ sRealmCache.put(realm, result);
+ }
+
+ realm = authScope.getRealm();
+
+ // in case there is cache for this Realm, use it to authenticate
+ if (sRealmCache.containsKey(realm)) {
+ result = sRealmCache.get(realm);
+ } else {
+ // since there is no cache, request for login and password
+ result = monitor.displayLoginPasswordPrompt("Site Authentication",
+ "Please login to the following domain: " + realm +
+ "\n\nServer requiring authentication:\n" + authScope.getHost());
+ if (result == null) {
+ throw new IOException("User canceled login dialog.");
+ }
+ }
+
+ // retrieve authentication data
+ String user = result.getFirst();
+ String password = result.getSecond();
+
+ // proceed in case there is indeed a user
+ if (user != null && user.length() > 0) {
+ Credentials credentials = new UsernamePasswordCredentials(user, password);
+ httpclient.getCredentialsProvider().setCredentials(authScope, credentials);
+ trying = true;
+ } else {
+ trying = false;
+ }
+ } else {
+ trying = false;
+ }
+ entity = response.getEntity();
+ if (entity != null) {
+ // in case another pass to the Http Client will be performed,
+ // consume the entity
+ if (trying) {
+ entity.consumeContent();
+ }
+ // since no pass to the Http Client is needed, retrieve the
+ // entity's content
+ else {
+ // Use a buffered entity because the stream in which it will
+ // be transfered, will not be closed later, unexpectedly
+ BufferedHttpEntity bufferedEntity = new BufferedHttpEntity(entity);
+ stream = bufferedEntity.getContent();
+ }
+ }
+ }
+
+ // since Http Client is no longer needed, close it
+ httpclient.getConnectionManager().shutdown();
+
+ return stream;
+ }
+}
diff --git a/sdkmanager/libs/sdklib/tests/src/com/android/sdklib/internal/repository/MockMonitor.java b/sdkmanager/libs/sdklib/tests/src/com/android/sdklib/internal/repository/MockMonitor.java
index c006707..e61184d 100755
--- a/sdkmanager/libs/sdklib/tests/src/com/android/sdklib/internal/repository/MockMonitor.java
+++ b/sdkmanager/libs/sdklib/tests/src/com/android/sdklib/internal/repository/MockMonitor.java
@@ -16,6 +16,7 @@
package com.android.sdklib.internal.repository;
+import com.android.util.Pair;
/**
* Mock implementation of {@link ITaskMonitor} that simply captures
@@ -95,4 +96,8 @@ public class MockMonitor implements ITaskMonitor {
public void warning(String warningFormat, Object... args) {
}
+
+ public Pair<String, String> displayLoginPasswordPrompt(String title, String message) {
+ return null;
+ }
}
diff --git a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/SdkUpdaterNoWindow.java b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/SdkUpdaterNoWindow.java
index ef4864b..10f4074 100755
--- a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/SdkUpdaterNoWindow.java
+++ b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/SdkUpdaterNoWindow.java
@@ -23,7 +23,9 @@ import com.android.sdklib.internal.repository.ITaskFactory;
import com.android.sdklib.internal.repository.ITaskMonitor;
import com.android.sdklib.internal.repository.NullTaskMonitor;
import com.android.sdklib.repository.SdkRepoConstants;
+import com.android.util.Pair;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Properties;
@@ -336,6 +338,74 @@ public class SdkUpdaterNoWindow {
}
/**
+ * Displays a prompt message to the user and read two values,
+ * login/password.
+ * <p>
+ * <i>Asks user for login/password information.</i>
+ * <p>
+ * This method shows a question in the standard output, asking for login
+ * and password.</br>
+ * <b>Method Output:</b></br>
+ * Title</br>
+ * Message</br>
+ * Login: (Wait for user input)</br>
+ * Password: (Wait for user input)</br>
+ * <p>
+ *
+ * @param title The title of the iteration.
+ * @param message The message to be displayed.
+ * @return A {@link Pair} holding the entered login and password. The
+ * <b>first element</b> is always the <b>Login</b>, and the
+ * <b>second element</b> is always the <b>Password</b>. This
+ * method will never return null, in case of error the pair will
+ * be filled with empty strings.
+ * @see ITaskMonitor#displayLoginPasswordPrompt(String, String)
+ */
+ public Pair<String, String> displayLoginPasswordPrompt(String title, String message) {
+ String login = ""; //$NON-NLS-1$
+ String password = ""; //$NON-NLS-1$
+ mSdkLog.printf("\n%1$s\n%2$s", title, message);
+ byte[] readBuffer = new byte[2048];
+ try {
+ mSdkLog.printf("\nLogin: ");
+ login = readLine(readBuffer);
+ mSdkLog.printf("\nPassword: ");
+ password = readLine(readBuffer);
+ /*
+ * TODO: Implement a way to don't echo the typed password On
+ * Java 5 there's no simple way to do this. There's just a
+ * workaround which is output backspaces on each keystroke.
+ * A good alternative is to use Java 6 java.io.Console
+ */
+ } catch (IOException e) {
+ // Reset login/pass to empty Strings.
+ login = ""; //$NON-NLS-1$
+ password = ""; //$NON-NLS-1$
+ //Just print the error to console.
+ mSdkLog.printf("\nError occurred during login/pass query: %s\n", e.getMessage());
+ }
+
+ return Pair.of(login, password);
+ }
+
+ private String readLine(byte[] buffer) throws IOException {
+ int count = System.in.read(buffer);
+
+ // is the input longer than the buffer?
+ if (count == buffer.length && buffer[count-1] != 10) {
+ throw new IOException(String.format(
+ "Input is longer than the buffer size, (%1$s) bytes", buffer.length));
+ }
+
+ // ignore end whitespace
+ while (count > 0 && (buffer[count-1] == '\r' || buffer[count-1] == '\n')) {
+ count--;
+ }
+
+ return new String(buffer, 0, count);
+ }
+
+ /**
* Creates a sub-monitor that will use up to tickCount on the progress bar.
* tickCount must be 1 or more.
*/
@@ -433,6 +503,10 @@ public class SdkUpdaterNoWindow {
return mRoot.displayPrompt(title, message);
}
+ public Pair<String, String> displayLoginPasswordPrompt(String title, String message) {
+ return mRoot.displayLoginPasswordPrompt(title, message);
+ }
+
public ITaskMonitor createSubMonitor(int tickCount) {
assert mSubCoef > 0;
assert tickCount > 0;
diff --git a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/tasks/IProgressUiProvider.java b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/tasks/IProgressUiProvider.java
index 4a7922d..f6e13c6 100755
--- a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/tasks/IProgressUiProvider.java
+++ b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/tasks/IProgressUiProvider.java
@@ -17,6 +17,7 @@
package com.android.sdkuilib.internal.tasks;
import com.android.sdklib.internal.repository.ITaskMonitor;
+import com.android.util.Pair;
import org.eclipse.swt.widgets.ProgressBar;
@@ -90,4 +91,20 @@ interface IProgressUiProvider {
*/
public abstract boolean displayPrompt(String title, String message);
+ /**
+ * Launch an interface which asks for login and password. Implementations
+ * MUST allow this to be called from any thread, e.g. by making sure the
+ * dialog is opened synchronously in the UI thread.
+ *
+ * @param title The title of the dialog box.
+ * @param message The message to be displayed as an instruction.
+ * @return Returns a {@link Pair} holding the entered login and password.
+ * The information must always be in the following order:
+ * Login,Password. So in order to retrieve the <b>login</b> callers
+ * should retrieve the first element, and the second value for the
+ * <b>password</b>. This method should never return a null pair.
+ * It's elements however can be empty Strings
+ */
+ public abstract Pair<String, String> displayLoginPasswordPrompt(String title, String message);
+
}
diff --git a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/tasks/ProgressTaskDialog.java b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/tasks/ProgressTaskDialog.java
index a4236fa..dbc871f 100755
--- a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/tasks/ProgressTaskDialog.java
+++ b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/tasks/ProgressTaskDialog.java
@@ -18,6 +18,9 @@ package com.android.sdkuilib.internal.tasks;
import com.android.sdklib.SdkConstants;
import com.android.sdklib.internal.repository.ITaskMonitor;
+import com.android.sdkuilib.ui.AuthenticationDialog;
+import com.android.sdkuilib.ui.GridDialog;
+import com.android.util.Pair;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.SWT;
@@ -154,7 +157,8 @@ final class ProgressTaskDialog extends Dialog implements IProgressUiProvider {
});
mResultText = new Text(mRootComposite,
- SWT.BORDER | SWT.READ_ONLY | SWT.WRAP | SWT.H_SCROLL | SWT.V_SCROLL | SWT.CANCEL | SWT.MULTI);
+ SWT.BORDER | SWT.READ_ONLY | SWT.WRAP |
+ SWT.H_SCROLL | SWT.V_SCROLL | SWT.CANCEL | SWT.MULTI);
mResultText.setEditable(true);
mResultText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
}
@@ -393,6 +397,45 @@ final class ProgressTaskDialog extends Dialog implements IProgressUiProvider {
}
/**
+ * This method opens a pop-up window which requests for User Login and
+ * password.
+ *
+ * @param title The title of the window.
+ * @param message The message to displayed in the login/password window.
+ * @return Returns a {@link Pair} holding the entered login and password.
+ * The information must always be in the following order:
+ * Login,Password. So in order to retrieve the <b>login</b> callers
+ * should retrieve the first element, and the second value for the
+ * <b>password</b>.
+ * If operation is <b>canceled</b> by user the return value must be <b>null</b>.
+ * @see ITaskMonitor#displayLoginPasswordPrompt(String, String)
+ */
+ public Pair<String, String> displayLoginPasswordPrompt(
+ final String title, final String message) {
+ final String[] resultArray = new String[2];
+ Display display = mDialogShell.getDisplay();
+
+ // open dialog and request login and password
+ display.syncExec(new Runnable() {
+ public void run() {
+ AuthenticationDialog authenticationDialog = new AuthenticationDialog(mDialogShell,
+ title,
+ message);
+ int dlgResult= authenticationDialog.open();
+ if(dlgResult == GridDialog.OK) {
+ resultArray[0] = authenticationDialog.getLogin();
+ resultArray[1] = authenticationDialog.getPassword();
+ } else {
+ resultArray[0] = null;
+ resultArray[1] = null;
+ }
+ }
+ });
+
+ return resultArray[0] == null ? null : Pair.of(resultArray[0], resultArray[1]);
+ }
+
+ /**
* Starts the thread that runs the task.
* This is deferred till the UI is created.
*/
diff --git a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/tasks/ProgressView.java b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/tasks/ProgressView.java
index d90eaed..9485885 100755
--- a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/tasks/ProgressView.java
+++ b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/tasks/ProgressView.java
@@ -19,11 +19,13 @@ package com.android.sdkuilib.internal.tasks;
import com.android.sdklib.ISdkLog;
import com.android.sdklib.internal.repository.ITask;
import com.android.sdklib.internal.repository.ITaskMonitor;
+import com.android.sdkuilib.ui.AuthenticationDialog;
+import com.android.sdkuilib.ui.GridDialog;
+import com.android.util.Pair;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
@@ -325,20 +327,53 @@ public final class ProgressView implements IProgressUiProvider {
public boolean displayPrompt(final String title, final String message) {
final boolean[] result = new boolean[] { false };
- if (!mProgressBar.isDisposed()) {
- final Shell shell = mProgressBar.getShell();
- Display display = shell.getDisplay();
-
- display.syncExec(new Runnable() {
- public void run() {
- result[0] = MessageDialog.openQuestion(shell, title, message);
- }
- });
- }
+ syncExec(mProgressBar, new Runnable() {
+ public void run() {
+ Shell shell = mProgressBar.getShell();
+ result[0] = MessageDialog.openQuestion(shell, title, message);
+ }
+ });
return result[0];
}
+ /**
+ * This method opens a pop-up window which requests for User Login and
+ * password.
+ *
+ * @param title The title of the window.
+ * @param message The message to displayed in the login/password window.
+ * @return Returns a {@link Pair} holding the entered login and password.
+ * The information must always be in the following order:
+ * Login,Password. So in order to retrieve the <b>login</b> callers
+ * should retrieve the first element, and the second value for the
+ * <b>password</b>.
+ * If operation is <b>canceled</b> by user the return value must be <b>null</b>.
+ * @see ITaskMonitor#displayLoginPasswordPrompt(String, String)
+ */
+ public Pair<String, String>
+ displayLoginPasswordPrompt(final String title, final String message) {
+ final String[] resultArray = new String[] {"", ""};
+ // open dialog and request login and password
+ syncExec(mProgressBar, new Runnable() {
+ public void run() {
+ Shell shell = mProgressBar.getShell();
+ AuthenticationDialog authenticationDialog = new AuthenticationDialog(shell,
+ title,
+ message);
+ int dlgResult = authenticationDialog.open();
+ if (dlgResult == GridDialog.OK) {
+ resultArray[0] = authenticationDialog.getLogin();
+ resultArray[1] = authenticationDialog.getPassword();
+ } else {
+ resultArray[0] = null;
+ resultArray[1] = null;
+ }
+ }
+ });
+ return resultArray[0] == null ? null : Pair.of(resultArray[0], resultArray[1]);
+ }
+
// ----
/**
diff --git a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/tasks/TaskMonitorImpl.java b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/tasks/TaskMonitorImpl.java
index 5286df5..f3dff37 100755
--- a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/tasks/TaskMonitorImpl.java
+++ b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/tasks/TaskMonitorImpl.java
@@ -17,8 +17,7 @@
package com.android.sdkuilib.internal.tasks;
import com.android.sdklib.internal.repository.ITaskMonitor;
-
-import org.eclipse.swt.widgets.ProgressBar;
+import com.android.util.Pair;
/**
* Internal class that implements the logic of an {@link ITaskMonitor}.
@@ -156,7 +155,7 @@ class TaskMonitorImpl implements ITaskMonitor {
}
/**
- * Display a yes/no question dialog box.
+ * Displays a yes/no question dialog box.
*
* This implementation allow this to be called from any thread, it
* makes sure the dialog is opened synchronously in the ui thread.
@@ -170,6 +169,21 @@ class TaskMonitorImpl implements ITaskMonitor {
}
/**
+ * Displays a Login/Password dialog. This implementation allows this method to be
+ * called from any thread, it makes sure the dialog is opened synchronously
+ * in the ui thread.
+ *
+ * @param title The title of the dialog box
+ * @param message Message to be displayed
+ * @return Pair with entered login/password. Login is always the first
+ * element and Password is always the second. If any error occurs a
+ * pair with empty strings is returned.
+ */
+ public Pair<String, String> displayLoginPasswordPrompt(String title, String message) {
+ return mUi.displayLoginPasswordPrompt(title, message);
+ }
+
+ /**
* Creates a sub-monitor that will use up to tickCount on the progress bar.
* tickCount must be 1 or more.
*/
@@ -284,6 +298,10 @@ class TaskMonitorImpl implements ITaskMonitor {
return mRoot.displayPrompt(title, message);
}
+ public Pair<String, String> displayLoginPasswordPrompt(String title, String message) {
+ return mRoot.displayLoginPasswordPrompt(title, message);
+ }
+
public ITaskMonitor createSubMonitor(int tickCount) {
assert mSubCoef > 0;
assert tickCount > 0;
diff --git a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/ui/AuthenticationDialog.java b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/ui/AuthenticationDialog.java
new file mode 100644
index 0000000..497c752
--- /dev/null
+++ b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/ui/AuthenticationDialog.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * 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 com.android.sdkuilib.ui;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Text;
+
+/**
+ * Dialog which collects from the user his/her login and password.
+ */
+public class AuthenticationDialog extends GridDialog {
+
+ private Text mTxtLogin;
+
+ private Text mTxtPassword;
+
+ private String mTitle;
+
+ private String mMessage;
+
+ protected String mLogin;
+
+ protected String mPassword;
+
+ /**
+ * Constructor which retrieves the parent {@link Shell} and the message to
+ * be displayed in this dialog.
+ *
+ * @param parentShell Parent Shell
+ * @param title Title of the window.
+ * @param message Message the be displayed in this dialog.
+ */
+ public AuthenticationDialog(Shell parentShell, String title, String message) {
+ super(parentShell, 1, false);
+ // assign fields
+ mTitle = title;
+ mMessage = message;
+ }
+
+ @Override
+ public void createDialogContent(Composite parent) {
+ // Configure Dialog
+ getShell().setText(mTitle);
+ GridData data = new GridData(SWT.FILL, SWT.FILL, true, true);
+ parent.setLayoutData(data);
+
+ // Upper Composite
+ Composite upperComposite = new Composite(parent, SWT.NONE);
+ GridLayout layout = new GridLayout(2, false);
+ layout.verticalSpacing = 10;
+ upperComposite.setLayout(layout);
+ data = new GridData(SWT.FILL, SWT.CENTER, true, true);
+ upperComposite.setLayoutData(data);
+
+ // add message label
+ Label lblMessage = new Label(upperComposite, SWT.WRAP);
+ lblMessage.setText(mMessage);
+ data = new GridData(SWT.FILL, SWT.CENTER, true, true, 2, 1);
+ data.widthHint = 500;
+ lblMessage.setLayoutData(data);
+
+ // add user name label and text field
+ Label lblUserName = new Label(upperComposite, SWT.NONE);
+ lblUserName.setText("Login:");
+ data = new GridData(SWT.LEFT, SWT.CENTER, false, false);
+ lblUserName.setLayoutData(data);
+
+ mTxtLogin = new Text(upperComposite, SWT.SINGLE | SWT.BORDER);
+ data = new GridData(SWT.FILL, SWT.CENTER, true, false);
+ mTxtLogin.setLayoutData(data);
+ mTxtLogin.setFocus();
+ mTxtLogin.addModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent arg0) {
+ mLogin = mTxtLogin.getText();
+ }
+ });
+
+ // add password label and text field
+ Label lblPassword = new Label(upperComposite, SWT.NONE);
+ lblPassword.setText("Password:");
+ data = new GridData(SWT.LEFT, SWT.CENTER, false, false);
+ lblPassword.setLayoutData(data);
+
+ mTxtPassword = new Text(upperComposite, SWT.SINGLE | SWT.PASSWORD | SWT.BORDER);
+ data = new GridData(SWT.FILL, SWT.CENTER, true, false);
+ mTxtPassword.setLayoutData(data);
+ mTxtPassword.addModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent arg0) {
+ mPassword = mTxtPassword.getText();
+ }
+ });
+ }
+
+ /**
+ * Retrieves the Login field information
+ *
+ * @return Login field value or empty String. Return value is never null
+ */
+ public String getLogin() {
+ return mLogin != null ? mLogin : ""; //$NON-NLS-1$
+ }
+
+ /**
+ * Retrieves the Password field information
+ *
+ * @return Password field value or empty String. Return value is never null
+ */
+ public String getPassword() {
+ return mPassword != null ? mPassword : ""; //$NON-NLS-1$
+ }
+}