Merge "Add Java 6's java.io.Console." into dalvik-dev
diff --git a/luni-kernel/src/main/java/java/lang/System.java b/luni-kernel/src/main/java/java/lang/System.java
index aa78b1b..6a69c2e 100644
--- a/luni-kernel/src/main/java/java/lang/System.java
+++ b/luni-kernel/src/main/java/java/lang/System.java
@@ -32,6 +32,7 @@
 
 package java.lang;
 
+import java.io.Console;
 import java.io.FileDescriptor;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
@@ -496,6 +497,17 @@
     }
 
     /**
+     * Returns the {@link java.io.Console} associated with this VM, or null.
+     * Not all VMs will have an associated console. A console is typically only
+     * available for programs run from the command line.
+     * @since 1.6
+     * @hide
+     */
+    public static Console console() {
+        return Console.getConsole();
+    }
+
+    /**
      * Returns the active security manager.
      * 
      * @return the system security manager object.
diff --git a/luni/src/main/java/java/io/Console.java b/luni/src/main/java/java/io/Console.java
new file mode 100644
index 0000000..4bbf4eb
--- /dev/null
+++ b/luni/src/main/java/java/io/Console.java
@@ -0,0 +1,199 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 java.io;
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.util.Formatter;
+
+/**
+ * Provides access to the console, if available. The system-wide instance can
+ * be accessed via {@link java.lang.System.console}.
+ * @since 1.6
+ * @hide
+ */
+public final class Console implements Flushable {
+    private static final Object CONSOLE_LOCK = new Object();
+
+    private static final Console console = makeConsole();
+    private static native boolean isatty(int fd);
+
+    private final ConsoleReader reader;
+    private final PrintWriter writer;
+
+    /**
+     * Secret accessor for {@code System.console}.
+     * @hide
+     */
+    public static Console getConsole() {
+        return console;
+    }
+
+    private static Console makeConsole() {
+        if (!isatty(0) || !isatty(1)) {
+            return null;
+        }
+        try {
+            return new Console();
+        } catch (IOException ex) {
+            throw new AssertionError(ex);
+        }
+    }
+
+    private Console() throws IOException {
+        this.reader = new ConsoleReader(System.in);
+        this.writer = new ConsoleWriter(System.out);
+    }
+
+    public void flush() {
+        writer.flush();
+    }
+
+    /**
+     * Writes a formatted string to the console using
+     * the specified format string and arguments.
+     *
+     * @param fmt the format string.
+     * @param args the arguments used by the formatter.
+     * @return the console instance.
+     */
+    public Console format(String fmt, Object... args) {
+        Formatter f = new Formatter(writer);
+        f.format(fmt, args);
+        f.flush();
+        return this;
+    }
+
+    /**
+     * Equivalent to {@code format(fmt, args)}.
+     */
+    public Console printf(String fmt, Object... args) {
+        return format(fmt, args);
+    }
+
+    /**
+     * Returns the {@link Reader} associated with this console.
+     */
+    public Reader reader() {
+        return reader;
+    }
+
+    /**
+     * Reads a line from the console.
+     *
+     * @return the line, or null at EOF.
+     */
+    public String readLine() {
+        try {
+            return reader.readLine();
+        } catch (IOException e) {
+            throw new IOError(e);
+        }
+    }
+
+    /**
+     * Reads a line from this console, using the specified prompt.
+     * The prompt is given as a format string and optional arguments.
+     * Note that this can be a source of errors: if it is possible that your
+     * prompt contains {@code %} characters, you must use the format string {@code "%s"}
+     * and pass the actual prompt as a parameter.
+     *
+     * @param fmt the format string.
+     * @param args the arguments used by the formatter.
+     * @return the line, or null at EOF.
+     */
+    public String readLine(String fmt, Object... args) {
+        synchronized (CONSOLE_LOCK) {
+            format(fmt, args);
+            return readLine();
+        }
+    }
+
+    /**
+     * Reads a password from the console. The password will not be echoed to the display.
+     *
+     * @return a character array containing the password, or null at EOF.
+     */
+    public char[] readPassword() {
+        synchronized (CONSOLE_LOCK) {
+            int previousState = setEcho(false, 0);
+            try {
+                String password = readLine();
+                writer.println(); // We won't have echoed the user's newline.
+                return (password == null) ? null : password.toCharArray();
+            } finally {
+                setEcho(true, previousState);
+            }
+        }
+    }
+
+    private static int setEcho(boolean on, int previousState) {
+        try {
+            return setEchoImpl(on, previousState);
+        } catch (IOException ex) {
+            throw new IOError(ex);
+        }
+    }
+    private static native int setEchoImpl(boolean on, int previousState) throws IOException;
+
+    /**
+     * Reads a password from the console. The password will not be echoed to the display.
+     * A formatted prompt is also displayed.
+     *
+     * @param fmt the format string.
+     * @param args the arguments used by the formatter.
+     * @return a character array containing the password, or null at EOF.
+     */
+    public char[] readPassword(String fmt, Object... args) {
+        synchronized (CONSOLE_LOCK) {
+            format(fmt, args);
+            return readPassword();
+        }
+    }
+
+    /**
+     * Returns the {@link Writer} associated with this console.
+     */
+    public PrintWriter writer() {
+        return writer;
+    }
+
+    private static class ConsoleReader extends BufferedReader {
+        public ConsoleReader(InputStream in) throws IOException {
+            super(new InputStreamReader(in, System.getProperty("file.encoding")), 256);
+            lock = CONSOLE_LOCK;
+        }
+
+        @Override
+        public void close() {
+            // Console.reader cannot be closed.
+        }
+    }
+
+    private static class ConsoleWriter extends PrintWriter {
+        public ConsoleWriter(OutputStream out) {
+            super(out, true);
+            lock = CONSOLE_LOCK;
+        }
+
+        @Override
+        public void close() {
+            // Console.writer cannot be closed.
+            flush();
+        }
+    }
+}
diff --git a/luni/src/main/native/java_io_Console.cpp b/luni/src/main/native/java_io_Console.cpp
new file mode 100644
index 0000000..ee48383
--- /dev/null
+++ b/luni/src/main/native/java_io_Console.cpp
@@ -0,0 +1,55 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You 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.
+ */
+
+#include "AndroidSystemNatives.h"
+#include "JNIHelp.h"
+
+#include <errno.h>
+#include <termios.h>
+#include <unistd.h>
+
+static jboolean java_io_Console_isatty(JNIEnv* env, jclass, jint fd) {
+    return TEMP_FAILURE_RETRY(isatty(fd));
+}
+
+static jint java_io_Console_setEcho(JNIEnv* env, jclass, jboolean on, jint previousState) {
+    termios state;
+    if (TEMP_FAILURE_RETRY(tcgetattr(STDIN_FILENO, &state)) == -1) {
+        jniThrowIOException(env, errno);
+        return 0;
+    }
+    if (on) {
+        state.c_lflag = previousState;
+    } else {
+        previousState = state.c_lflag;
+        state.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
+    }
+    if (TEMP_FAILURE_RETRY(tcsetattr(STDIN_FILENO, TCSAFLUSH, &state)) == -1){
+        jniThrowIOException(env, errno);
+        return 0;
+    }
+    return previousState;
+}
+
+static JNINativeMethod gMethods[] = {
+    /* name, signature, funcPtr */
+    { "isatty", "(I)Z", (void*) java_io_Console_isatty },
+    { "setEchoImpl", "(ZI)I", (void*) java_io_Console_setEcho },
+};
+int register_java_io_Console(JNIEnv* env) {
+    return jniRegisterNativeMethods(env, "java/io/Console", gMethods, NELEM(gMethods));
+}
diff --git a/luni/src/main/native/sub.mk b/luni/src/main/native/sub.mk
index f0287cf..a562e4c 100644
--- a/luni/src/main/native/sub.mk
+++ b/luni/src/main/native/sub.mk
@@ -3,6 +3,7 @@
 # or BUILD_*_LIBRARY.
 
 LOCAL_SRC_FILES := \
+	java_io_Console.cpp \
 	java_io_File.cpp \
 	java_io_FileDescriptor.c \
 	java_io_ObjectInputStream.c \