diff options
75 files changed, 3009 insertions, 533 deletions
diff --git a/api/current.txt b/api/current.txt index c578acda8b86..d90116fca2cf 100644 --- a/api/current.txt +++ b/api/current.txt @@ -3258,6 +3258,7 @@ package android.app { method public boolean onContextItemSelected(android.view.MenuItem); method public void onContextMenuClosed(android.view.Menu); method protected void onCreate(android.os.Bundle); + method protected void onCreate(android.os.Bundle, android.os.PersistableBundle); method public void onCreateContextMenu(android.view.ContextMenu, android.view.View, android.view.ContextMenu.ContextMenuInfo); method public java.lang.CharSequence onCreateDescription(); method protected deprecated android.app.Dialog onCreateDialog(int); @@ -3288,6 +3289,7 @@ package android.app { method public void onPanelClosed(int, android.view.Menu); method protected void onPause(); method protected void onPostCreate(android.os.Bundle); + method protected void onPostCreate(android.os.Bundle, android.os.PersistableBundle); method protected void onPostResume(); method protected deprecated void onPrepareDialog(int, android.app.Dialog); method protected deprecated void onPrepareDialog(int, android.app.Dialog, android.os.Bundle); @@ -3297,9 +3299,11 @@ package android.app { method public void onProvideAssistData(android.os.Bundle); method protected void onRestart(); method protected void onRestoreInstanceState(android.os.Bundle); + method protected void onRestoreInstanceState(android.os.Bundle, android.os.PersistableBundle); method protected void onResume(); method public deprecated java.lang.Object onRetainNonConfigurationInstance(); method protected void onSaveInstanceState(android.os.Bundle); + method protected void onSaveInstanceState(android.os.Bundle, android.os.PersistableBundle); method public boolean onSearchRequested(); method protected void onStart(); method protected void onStop(); @@ -4195,14 +4199,18 @@ package android.app { method public android.app.Instrumentation.ActivityMonitor addMonitor(android.content.IntentFilter, android.app.Instrumentation.ActivityResult, boolean); method public android.app.Instrumentation.ActivityMonitor addMonitor(java.lang.String, android.app.Instrumentation.ActivityResult, boolean); method public void callActivityOnCreate(android.app.Activity, android.os.Bundle); + method public void callActivityOnCreate(android.app.Activity, android.os.Bundle, android.os.PersistableBundle); method public void callActivityOnDestroy(android.app.Activity); method public void callActivityOnNewIntent(android.app.Activity, android.content.Intent); method public void callActivityOnPause(android.app.Activity); method public void callActivityOnPostCreate(android.app.Activity, android.os.Bundle); + method public void callActivityOnPostCreate(android.app.Activity, android.os.Bundle, android.os.PersistableBundle); method public void callActivityOnRestart(android.app.Activity); method public void callActivityOnRestoreInstanceState(android.app.Activity, android.os.Bundle); + method public void callActivityOnRestoreInstanceState(android.app.Activity, android.os.Bundle, android.os.PersistableBundle); method public void callActivityOnResume(android.app.Activity); method public void callActivityOnSaveInstanceState(android.app.Activity, android.os.Bundle); + method public void callActivityOnSaveInstanceState(android.app.Activity, android.os.Bundle, android.os.PersistableBundle); method public void callActivityOnStart(android.app.Activity); method public void callActivityOnStop(android.app.Activity); method public void callActivityOnUserLeaving(android.app.Activity); @@ -12870,6 +12878,7 @@ package android.inputmethodservice { method public void onStartInputView(android.view.inputmethod.EditorInfo, boolean); method public void onUnbindInput(); method public void onUpdateCursor(android.graphics.Rect); + method public void onUpdateCursorAnchorInfo(android.view.inputmethod.CursorAnchorInfo); method public void onUpdateExtractedText(int, android.view.inputmethod.ExtractedText); method public void onUpdateExtractingViews(android.view.inputmethod.EditorInfo); method public void onUpdateExtractingVisibility(android.view.inputmethod.EditorInfo); @@ -12919,6 +12928,7 @@ package android.inputmethodservice { method public void finishInput(); method public void toggleSoftInput(int, int); method public void updateCursor(android.graphics.Rect); + method public void updateCursorAnchorInfo(android.view.inputmethod.CursorAnchorInfo); method public void updateExtractedText(int, android.view.inputmethod.ExtractedText); method public void updateSelection(int, int, int, int, int, int); method public void viewClicked(boolean); @@ -17138,6 +17148,7 @@ package android.nfc.cardemulation { } public final class CardEmulation { + method public boolean categoryAllowsForegroundPreference(java.lang.String); method public android.nfc.cardemulation.AidGroup getAidGroupForService(android.content.ComponentName, java.lang.String); method public static synchronized android.nfc.cardemulation.CardEmulation getInstance(android.nfc.NfcAdapter); method public int getSelectionModeForCategory(java.lang.String); @@ -17145,6 +17156,8 @@ package android.nfc.cardemulation { method public boolean isDefaultServiceForCategory(android.content.ComponentName, java.lang.String); method public boolean registerAidGroupForService(android.content.ComponentName, android.nfc.cardemulation.AidGroup); method public boolean removeAidGroupForService(android.content.ComponentName, java.lang.String); + method public boolean setPreferredService(android.app.Activity, android.content.ComponentName); + method public boolean unsetPreferredService(android.app.Activity); field public static final java.lang.String ACTION_CHANGE_DEFAULT = "android.nfc.cardemulation.action.ACTION_CHANGE_DEFAULT"; field public static final java.lang.String CATEGORY_OTHER = "other"; field public static final java.lang.String CATEGORY_PAYMENT = "payment"; @@ -25721,6 +25734,636 @@ package android.speech.tts { } +package android.system { + + public final class ErrnoException extends java.lang.Exception { + ctor public ErrnoException(java.lang.String, int); + ctor public ErrnoException(java.lang.String, int, java.lang.Throwable); + field public final int errno; + } + + public final class Os { + method public static java.io.FileDescriptor accept(java.io.FileDescriptor, java.net.InetSocketAddress) throws android.system.ErrnoException, java.net.SocketException; + method public static boolean access(java.lang.String, int) throws android.system.ErrnoException; + method public static void bind(java.io.FileDescriptor, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException; + method public static void chmod(java.lang.String, int) throws android.system.ErrnoException; + method public static void chown(java.lang.String, int, int) throws android.system.ErrnoException; + method public static void close(java.io.FileDescriptor) throws android.system.ErrnoException; + method public static void connect(java.io.FileDescriptor, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException; + method public static java.io.FileDescriptor dup(java.io.FileDescriptor) throws android.system.ErrnoException; + method public static java.io.FileDescriptor dup2(java.io.FileDescriptor, int) throws android.system.ErrnoException; + method public static java.lang.String[] environ(); + method public static void execv(java.lang.String, java.lang.String[]) throws android.system.ErrnoException; + method public static void execve(java.lang.String, java.lang.String[], java.lang.String[]) throws android.system.ErrnoException; + method public static void fchmod(java.io.FileDescriptor, int) throws android.system.ErrnoException; + method public static void fchown(java.io.FileDescriptor, int, int) throws android.system.ErrnoException; + method public static void fdatasync(java.io.FileDescriptor) throws android.system.ErrnoException; + method public static android.system.StructStat fstat(java.io.FileDescriptor) throws android.system.ErrnoException; + method public static android.system.StructStatVfs fstatvfs(java.io.FileDescriptor) throws android.system.ErrnoException; + method public static void fsync(java.io.FileDescriptor) throws android.system.ErrnoException; + method public static void ftruncate(java.io.FileDescriptor, long) throws android.system.ErrnoException; + method public static java.lang.String gai_strerror(int); + method public static int getegid(); + method public static java.lang.String getenv(java.lang.String); + method public static int geteuid(); + method public static int getgid(); + method public static java.net.SocketAddress getpeername(java.io.FileDescriptor) throws android.system.ErrnoException; + method public static int getpid(); + method public static int getppid(); + method public static java.net.SocketAddress getsockname(java.io.FileDescriptor) throws android.system.ErrnoException; + method public static int gettid(); + method public static int getuid(); + method public static java.lang.String if_indextoname(int); + method public static java.net.InetAddress inet_pton(int, java.lang.String); + method public static boolean isatty(java.io.FileDescriptor); + method public static void kill(int, int) throws android.system.ErrnoException; + method public static void lchown(java.lang.String, int, int) throws android.system.ErrnoException; + method public static void listen(java.io.FileDescriptor, int) throws android.system.ErrnoException; + method public static long lseek(java.io.FileDescriptor, long, int) throws android.system.ErrnoException; + method public static android.system.StructStat lstat(java.lang.String) throws android.system.ErrnoException; + method public static void mincore(long, long, byte[]) throws android.system.ErrnoException; + method public static void mkdir(java.lang.String, int) throws android.system.ErrnoException; + method public static void mkfifo(java.lang.String, int) throws android.system.ErrnoException; + method public static void mlock(long, long) throws android.system.ErrnoException; + method public static long mmap(long, long, int, int, java.io.FileDescriptor, long) throws android.system.ErrnoException; + method public static void msync(long, long, int) throws android.system.ErrnoException; + method public static void munlock(long, long) throws android.system.ErrnoException; + method public static void munmap(long, long) throws android.system.ErrnoException; + method public static java.io.FileDescriptor open(java.lang.String, int, int) throws android.system.ErrnoException; + method public static java.io.FileDescriptor[] pipe() throws android.system.ErrnoException; + method public static int poll(android.system.StructPollfd[], int) throws android.system.ErrnoException; + method public static void posix_fallocate(java.io.FileDescriptor, long, long) throws android.system.ErrnoException; + method public static int prctl(int, long, long, long, long) throws android.system.ErrnoException; + method public static int pread(java.io.FileDescriptor, java.nio.ByteBuffer, long) throws android.system.ErrnoException, java.io.InterruptedIOException; + method public static int pread(java.io.FileDescriptor, byte[], int, int, long) throws android.system.ErrnoException, java.io.InterruptedIOException; + method public static int pwrite(java.io.FileDescriptor, java.nio.ByteBuffer, long) throws android.system.ErrnoException, java.io.InterruptedIOException; + method public static int pwrite(java.io.FileDescriptor, byte[], int, int, long) throws android.system.ErrnoException, java.io.InterruptedIOException; + method public static int read(java.io.FileDescriptor, java.nio.ByteBuffer) throws android.system.ErrnoException, java.io.InterruptedIOException; + method public static int read(java.io.FileDescriptor, byte[], int, int) throws android.system.ErrnoException, java.io.InterruptedIOException; + method public static java.lang.String readlink(java.lang.String) throws android.system.ErrnoException; + method public static int readv(java.io.FileDescriptor, java.lang.Object[], int[], int[]) throws android.system.ErrnoException, java.io.InterruptedIOException; + method public static int recvfrom(java.io.FileDescriptor, java.nio.ByteBuffer, int, java.net.InetSocketAddress) throws android.system.ErrnoException, java.net.SocketException; + method public static int recvfrom(java.io.FileDescriptor, byte[], int, int, int, java.net.InetSocketAddress) throws android.system.ErrnoException, java.net.SocketException; + method public static void remove(java.lang.String) throws android.system.ErrnoException; + method public static void rename(java.lang.String, java.lang.String) throws android.system.ErrnoException; + method public static long sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.util.MutableLong, long) throws android.system.ErrnoException; + method public static int sendto(java.io.FileDescriptor, java.nio.ByteBuffer, int, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException; + method public static int sendto(java.io.FileDescriptor, byte[], int, int, int, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException; + method public static void setegid(int) throws android.system.ErrnoException; + method public static void setenv(java.lang.String, java.lang.String, boolean) throws android.system.ErrnoException; + method public static void seteuid(int) throws android.system.ErrnoException; + method public static void setgid(int) throws android.system.ErrnoException; + method public static int setsid() throws android.system.ErrnoException; + method public static void setuid(int) throws android.system.ErrnoException; + method public static void shutdown(java.io.FileDescriptor, int) throws android.system.ErrnoException; + method public static java.io.FileDescriptor socket(int, int, int) throws android.system.ErrnoException; + method public static void socketpair(int, int, int, java.io.FileDescriptor, java.io.FileDescriptor) throws android.system.ErrnoException; + method public static android.system.StructStat stat(java.lang.String) throws android.system.ErrnoException; + method public static android.system.StructStatVfs statvfs(java.lang.String) throws android.system.ErrnoException; + method public static java.lang.String strerror(int); + method public static java.lang.String strsignal(int); + method public static void symlink(java.lang.String, java.lang.String) throws android.system.ErrnoException; + method public static long sysconf(int); + method public static void tcdrain(java.io.FileDescriptor) throws android.system.ErrnoException; + method public static void tcsendbreak(java.io.FileDescriptor, int) throws android.system.ErrnoException; + method public static int umask(int); + method public static android.system.StructUtsname uname(); + method public static void unsetenv(java.lang.String) throws android.system.ErrnoException; + method public static int waitpid(int, android.util.MutableInt, int) throws android.system.ErrnoException; + method public static int write(java.io.FileDescriptor, java.nio.ByteBuffer) throws android.system.ErrnoException, java.io.InterruptedIOException; + method public static int write(java.io.FileDescriptor, byte[], int, int) throws android.system.ErrnoException, java.io.InterruptedIOException; + method public static int writev(java.io.FileDescriptor, java.lang.Object[], int[], int[]) throws android.system.ErrnoException, java.io.InterruptedIOException; + } + + public final class OsConstants { + method public static boolean S_ISBLK(int); + method public static boolean S_ISCHR(int); + method public static boolean S_ISDIR(int); + method public static boolean S_ISFIFO(int); + method public static boolean S_ISLNK(int); + method public static boolean S_ISREG(int); + method public static boolean S_ISSOCK(int); + method public static boolean WCOREDUMP(int); + method public static int WEXITSTATUS(int); + method public static boolean WIFEXITED(int); + method public static boolean WIFSIGNALED(int); + method public static boolean WIFSTOPPED(int); + method public static int WSTOPSIG(int); + method public static int WTERMSIG(int); + method public static java.lang.String errnoName(int); + method public static java.lang.String gaiName(int); + field public static final int AF_INET; + field public static final int AF_INET6; + field public static final int AF_UNIX; + field public static final int AF_UNSPEC; + field public static final int AI_ADDRCONFIG; + field public static final int AI_ALL; + field public static final int AI_CANONNAME; + field public static final int AI_NUMERICHOST; + field public static final int AI_NUMERICSERV; + field public static final int AI_PASSIVE; + field public static final int AI_V4MAPPED; + field public static final int CAP_AUDIT_CONTROL; + field public static final int CAP_AUDIT_WRITE; + field public static final int CAP_BLOCK_SUSPEND; + field public static final int CAP_CHOWN; + field public static final int CAP_DAC_OVERRIDE; + field public static final int CAP_DAC_READ_SEARCH; + field public static final int CAP_FOWNER; + field public static final int CAP_FSETID; + field public static final int CAP_IPC_LOCK; + field public static final int CAP_IPC_OWNER; + field public static final int CAP_KILL; + field public static final int CAP_LAST_CAP; + field public static final int CAP_LEASE; + field public static final int CAP_LINUX_IMMUTABLE; + field public static final int CAP_MAC_ADMIN; + field public static final int CAP_MAC_OVERRIDE; + field public static final int CAP_MKNOD; + field public static final int CAP_NET_ADMIN; + field public static final int CAP_NET_BIND_SERVICE; + field public static final int CAP_NET_BROADCAST; + field public static final int CAP_NET_RAW; + field public static final int CAP_SETFCAP; + field public static final int CAP_SETGID; + field public static final int CAP_SETPCAP; + field public static final int CAP_SETUID; + field public static final int CAP_SYSLOG; + field public static final int CAP_SYS_ADMIN; + field public static final int CAP_SYS_BOOT; + field public static final int CAP_SYS_CHROOT; + field public static final int CAP_SYS_MODULE; + field public static final int CAP_SYS_NICE; + field public static final int CAP_SYS_PACCT; + field public static final int CAP_SYS_PTRACE; + field public static final int CAP_SYS_RAWIO; + field public static final int CAP_SYS_RESOURCE; + field public static final int CAP_SYS_TIME; + field public static final int CAP_SYS_TTY_CONFIG; + field public static final int CAP_WAKE_ALARM; + field public static final int E2BIG; + field public static final int EACCES; + field public static final int EADDRINUSE; + field public static final int EADDRNOTAVAIL; + field public static final int EAFNOSUPPORT; + field public static final int EAGAIN; + field public static final int EAI_AGAIN; + field public static final int EAI_BADFLAGS; + field public static final int EAI_FAIL; + field public static final int EAI_FAMILY; + field public static final int EAI_MEMORY; + field public static final int EAI_NODATA; + field public static final int EAI_NONAME; + field public static final int EAI_OVERFLOW; + field public static final int EAI_SERVICE; + field public static final int EAI_SOCKTYPE; + field public static final int EAI_SYSTEM; + field public static final int EALREADY; + field public static final int EBADF; + field public static final int EBADMSG; + field public static final int EBUSY; + field public static final int ECANCELED; + field public static final int ECHILD; + field public static final int ECONNABORTED; + field public static final int ECONNREFUSED; + field public static final int ECONNRESET; + field public static final int EDEADLK; + field public static final int EDESTADDRREQ; + field public static final int EDOM; + field public static final int EDQUOT; + field public static final int EEXIST; + field public static final int EFAULT; + field public static final int EFBIG; + field public static final int EHOSTUNREACH; + field public static final int EIDRM; + field public static final int EILSEQ; + field public static final int EINPROGRESS; + field public static final int EINTR; + field public static final int EINVAL; + field public static final int EIO; + field public static final int EISCONN; + field public static final int EISDIR; + field public static final int ELOOP; + field public static final int EMFILE; + field public static final int EMLINK; + field public static final int EMSGSIZE; + field public static final int EMULTIHOP; + field public static final int ENAMETOOLONG; + field public static final int ENETDOWN; + field public static final int ENETRESET; + field public static final int ENETUNREACH; + field public static final int ENFILE; + field public static final int ENOBUFS; + field public static final int ENODATA; + field public static final int ENODEV; + field public static final int ENOENT; + field public static final int ENOEXEC; + field public static final int ENOLCK; + field public static final int ENOLINK; + field public static final int ENOMEM; + field public static final int ENOMSG; + field public static final int ENOPROTOOPT; + field public static final int ENOSPC; + field public static final int ENOSR; + field public static final int ENOSTR; + field public static final int ENOSYS; + field public static final int ENOTCONN; + field public static final int ENOTDIR; + field public static final int ENOTEMPTY; + field public static final int ENOTSOCK; + field public static final int ENOTSUP; + field public static final int ENOTTY; + field public static final int ENXIO; + field public static final int EOPNOTSUPP; + field public static final int EOVERFLOW; + field public static final int EPERM; + field public static final int EPIPE; + field public static final int EPROTO; + field public static final int EPROTONOSUPPORT; + field public static final int EPROTOTYPE; + field public static final int ERANGE; + field public static final int EROFS; + field public static final int ESPIPE; + field public static final int ESRCH; + field public static final int ESTALE; + field public static final int ETIME; + field public static final int ETIMEDOUT; + field public static final int ETXTBSY; + field public static final int EXDEV; + field public static final int EXIT_FAILURE; + field public static final int EXIT_SUCCESS; + field public static final int FD_CLOEXEC; + field public static final int FIONREAD; + field public static final int F_DUPFD; + field public static final int F_GETFD; + field public static final int F_GETFL; + field public static final int F_GETLK; + field public static final int F_GETLK64; + field public static final int F_GETOWN; + field public static final int F_OK; + field public static final int F_RDLCK; + field public static final int F_SETFD; + field public static final int F_SETFL; + field public static final int F_SETLK; + field public static final int F_SETLK64; + field public static final int F_SETLKW; + field public static final int F_SETLKW64; + field public static final int F_SETOWN; + field public static final int F_UNLCK; + field public static final int F_WRLCK; + field public static final int IFA_F_DADFAILED; + field public static final int IFA_F_DEPRECATED; + field public static final int IFA_F_HOMEADDRESS; + field public static final int IFA_F_NODAD; + field public static final int IFA_F_OPTIMISTIC; + field public static final int IFA_F_PERMANENT; + field public static final int IFA_F_SECONDARY; + field public static final int IFA_F_TEMPORARY; + field public static final int IFA_F_TENTATIVE; + field public static final int IFF_ALLMULTI; + field public static final int IFF_AUTOMEDIA; + field public static final int IFF_BROADCAST; + field public static final int IFF_DEBUG; + field public static final int IFF_DYNAMIC; + field public static final int IFF_LOOPBACK; + field public static final int IFF_MASTER; + field public static final int IFF_MULTICAST; + field public static final int IFF_NOARP; + field public static final int IFF_NOTRAILERS; + field public static final int IFF_POINTOPOINT; + field public static final int IFF_PORTSEL; + field public static final int IFF_PROMISC; + field public static final int IFF_RUNNING; + field public static final int IFF_SLAVE; + field public static final int IFF_UP; + field public static final int IPPROTO_ICMP; + field public static final int IPPROTO_ICMPV6; + field public static final int IPPROTO_IP; + field public static final int IPPROTO_IPV6; + field public static final int IPPROTO_RAW; + field public static final int IPPROTO_TCP; + field public static final int IPPROTO_UDP; + field public static final int IPV6_CHECKSUM; + field public static final int IPV6_MULTICAST_HOPS; + field public static final int IPV6_MULTICAST_IF; + field public static final int IPV6_MULTICAST_LOOP; + field public static final int IPV6_RECVDSTOPTS; + field public static final int IPV6_RECVHOPLIMIT; + field public static final int IPV6_RECVHOPOPTS; + field public static final int IPV6_RECVPKTINFO; + field public static final int IPV6_RECVRTHDR; + field public static final int IPV6_RECVTCLASS; + field public static final int IPV6_TCLASS; + field public static final int IPV6_UNICAST_HOPS; + field public static final int IPV6_V6ONLY; + field public static final int IP_MULTICAST_IF; + field public static final int IP_MULTICAST_LOOP; + field public static final int IP_MULTICAST_TTL; + field public static final int IP_TOS; + field public static final int IP_TTL; + field public static final int MAP_FIXED; + field public static final int MAP_PRIVATE; + field public static final int MAP_SHARED; + field public static final int MCAST_BLOCK_SOURCE; + field public static final int MCAST_JOIN_GROUP; + field public static final int MCAST_JOIN_SOURCE_GROUP; + field public static final int MCAST_LEAVE_GROUP; + field public static final int MCAST_LEAVE_SOURCE_GROUP; + field public static final int MCAST_UNBLOCK_SOURCE; + field public static final int MCL_CURRENT; + field public static final int MCL_FUTURE; + field public static final int MSG_CTRUNC; + field public static final int MSG_DONTROUTE; + field public static final int MSG_EOR; + field public static final int MSG_OOB; + field public static final int MSG_PEEK; + field public static final int MSG_TRUNC; + field public static final int MSG_WAITALL; + field public static final int MS_ASYNC; + field public static final int MS_INVALIDATE; + field public static final int MS_SYNC; + field public static final int NI_DGRAM; + field public static final int NI_NAMEREQD; + field public static final int NI_NOFQDN; + field public static final int NI_NUMERICHOST; + field public static final int NI_NUMERICSERV; + field public static final int O_ACCMODE; + field public static final int O_APPEND; + field public static final int O_CREAT; + field public static final int O_EXCL; + field public static final int O_NOCTTY; + field public static final int O_NOFOLLOW; + field public static final int O_NONBLOCK; + field public static final int O_RDONLY; + field public static final int O_RDWR; + field public static final int O_SYNC; + field public static final int O_TRUNC; + field public static final int O_WRONLY; + field public static final int POLLERR; + field public static final int POLLHUP; + field public static final int POLLIN; + field public static final int POLLNVAL; + field public static final int POLLOUT; + field public static final int POLLPRI; + field public static final int POLLRDBAND; + field public static final int POLLRDNORM; + field public static final int POLLWRBAND; + field public static final int POLLWRNORM; + field public static final int PROT_EXEC; + field public static final int PROT_NONE; + field public static final int PROT_READ; + field public static final int PROT_WRITE; + field public static final int PR_SET_NO_NEW_PRIVS; + field public static final int RT_SCOPE_HOST; + field public static final int RT_SCOPE_LINK; + field public static final int RT_SCOPE_NOWHERE; + field public static final int RT_SCOPE_SITE; + field public static final int RT_SCOPE_UNIVERSE; + field public static final int R_OK; + field public static final int SEEK_CUR; + field public static final int SEEK_END; + field public static final int SEEK_SET; + field public static final int SHUT_RD; + field public static final int SHUT_RDWR; + field public static final int SHUT_WR; + field public static final int SIGABRT; + field public static final int SIGALRM; + field public static final int SIGBUS; + field public static final int SIGCHLD; + field public static final int SIGCONT; + field public static final int SIGFPE; + field public static final int SIGHUP; + field public static final int SIGILL; + field public static final int SIGINT; + field public static final int SIGIO; + field public static final int SIGKILL; + field public static final int SIGPIPE; + field public static final int SIGPROF; + field public static final int SIGPWR; + field public static final int SIGQUIT; + field public static final int SIGRTMAX; + field public static final int SIGRTMIN; + field public static final int SIGSEGV; + field public static final int SIGSTKFLT; + field public static final int SIGSTOP; + field public static final int SIGSYS; + field public static final int SIGTERM; + field public static final int SIGTRAP; + field public static final int SIGTSTP; + field public static final int SIGTTIN; + field public static final int SIGTTOU; + field public static final int SIGURG; + field public static final int SIGUSR1; + field public static final int SIGUSR2; + field public static final int SIGVTALRM; + field public static final int SIGWINCH; + field public static final int SIGXCPU; + field public static final int SIGXFSZ; + field public static final int SIOCGIFADDR; + field public static final int SIOCGIFBRDADDR; + field public static final int SIOCGIFDSTADDR; + field public static final int SIOCGIFNETMASK; + field public static final int SOCK_DGRAM; + field public static final int SOCK_RAW; + field public static final int SOCK_SEQPACKET; + field public static final int SOCK_STREAM; + field public static final int SOL_SOCKET; + field public static final int SO_BINDTODEVICE; + field public static final int SO_BROADCAST; + field public static final int SO_DEBUG; + field public static final int SO_DONTROUTE; + field public static final int SO_ERROR; + field public static final int SO_KEEPALIVE; + field public static final int SO_LINGER; + field public static final int SO_OOBINLINE; + field public static final int SO_PASSCRED; + field public static final int SO_PEERCRED; + field public static final int SO_RCVBUF; + field public static final int SO_RCVLOWAT; + field public static final int SO_RCVTIMEO; + field public static final int SO_REUSEADDR; + field public static final int SO_SNDBUF; + field public static final int SO_SNDLOWAT; + field public static final int SO_SNDTIMEO; + field public static final int SO_TYPE; + field public static final int STDERR_FILENO; + field public static final int STDIN_FILENO; + field public static final int STDOUT_FILENO; + field public static final int S_IFBLK; + field public static final int S_IFCHR; + field public static final int S_IFDIR; + field public static final int S_IFIFO; + field public static final int S_IFLNK; + field public static final int S_IFMT; + field public static final int S_IFREG; + field public static final int S_IFSOCK; + field public static final int S_IRGRP; + field public static final int S_IROTH; + field public static final int S_IRUSR; + field public static final int S_IRWXG; + field public static final int S_IRWXO; + field public static final int S_IRWXU; + field public static final int S_ISGID; + field public static final int S_ISUID; + field public static final int S_ISVTX; + field public static final int S_IWGRP; + field public static final int S_IWOTH; + field public static final int S_IWUSR; + field public static final int S_IXGRP; + field public static final int S_IXOTH; + field public static final int S_IXUSR; + field public static final int TCP_NODELAY; + field public static final int WCONTINUED; + field public static final int WEXITED; + field public static final int WNOHANG; + field public static final int WNOWAIT; + field public static final int WSTOPPED; + field public static final int WUNTRACED; + field public static final int W_OK; + field public static final int X_OK; + field public static final int _SC_2_CHAR_TERM; + field public static final int _SC_2_C_BIND; + field public static final int _SC_2_C_DEV; + field public static final int _SC_2_C_VERSION; + field public static final int _SC_2_FORT_DEV; + field public static final int _SC_2_FORT_RUN; + field public static final int _SC_2_LOCALEDEF; + field public static final int _SC_2_SW_DEV; + field public static final int _SC_2_UPE; + field public static final int _SC_2_VERSION; + field public static final int _SC_AIO_LISTIO_MAX; + field public static final int _SC_AIO_MAX; + field public static final int _SC_AIO_PRIO_DELTA_MAX; + field public static final int _SC_ARG_MAX; + field public static final int _SC_ASYNCHRONOUS_IO; + field public static final int _SC_ATEXIT_MAX; + field public static final int _SC_AVPHYS_PAGES; + field public static final int _SC_BC_BASE_MAX; + field public static final int _SC_BC_DIM_MAX; + field public static final int _SC_BC_SCALE_MAX; + field public static final int _SC_BC_STRING_MAX; + field public static final int _SC_CHILD_MAX; + field public static final int _SC_CLK_TCK; + field public static final int _SC_COLL_WEIGHTS_MAX; + field public static final int _SC_DELAYTIMER_MAX; + field public static final int _SC_EXPR_NEST_MAX; + field public static final int _SC_FSYNC; + field public static final int _SC_GETGR_R_SIZE_MAX; + field public static final int _SC_GETPW_R_SIZE_MAX; + field public static final int _SC_IOV_MAX; + field public static final int _SC_JOB_CONTROL; + field public static final int _SC_LINE_MAX; + field public static final int _SC_LOGIN_NAME_MAX; + field public static final int _SC_MAPPED_FILES; + field public static final int _SC_MEMLOCK; + field public static final int _SC_MEMLOCK_RANGE; + field public static final int _SC_MEMORY_PROTECTION; + field public static final int _SC_MESSAGE_PASSING; + field public static final int _SC_MQ_OPEN_MAX; + field public static final int _SC_MQ_PRIO_MAX; + field public static final int _SC_NGROUPS_MAX; + field public static final int _SC_NPROCESSORS_CONF; + field public static final int _SC_NPROCESSORS_ONLN; + field public static final int _SC_OPEN_MAX; + field public static final int _SC_PAGESIZE; + field public static final int _SC_PAGE_SIZE; + field public static final int _SC_PASS_MAX; + field public static final int _SC_PHYS_PAGES; + field public static final int _SC_PRIORITIZED_IO; + field public static final int _SC_PRIORITY_SCHEDULING; + field public static final int _SC_REALTIME_SIGNALS; + field public static final int _SC_RE_DUP_MAX; + field public static final int _SC_RTSIG_MAX; + field public static final int _SC_SAVED_IDS; + field public static final int _SC_SEMAPHORES; + field public static final int _SC_SEM_NSEMS_MAX; + field public static final int _SC_SEM_VALUE_MAX; + field public static final int _SC_SHARED_MEMORY_OBJECTS; + field public static final int _SC_SIGQUEUE_MAX; + field public static final int _SC_STREAM_MAX; + field public static final int _SC_SYNCHRONIZED_IO; + field public static final int _SC_THREADS; + field public static final int _SC_THREAD_ATTR_STACKADDR; + field public static final int _SC_THREAD_ATTR_STACKSIZE; + field public static final int _SC_THREAD_DESTRUCTOR_ITERATIONS; + field public static final int _SC_THREAD_KEYS_MAX; + field public static final int _SC_THREAD_PRIORITY_SCHEDULING; + field public static final int _SC_THREAD_PRIO_INHERIT; + field public static final int _SC_THREAD_PRIO_PROTECT; + field public static final int _SC_THREAD_SAFE_FUNCTIONS; + field public static final int _SC_THREAD_STACK_MIN; + field public static final int _SC_THREAD_THREADS_MAX; + field public static final int _SC_TIMERS; + field public static final int _SC_TIMER_MAX; + field public static final int _SC_TTY_NAME_MAX; + field public static final int _SC_TZNAME_MAX; + field public static final int _SC_VERSION; + field public static final int _SC_XBS5_ILP32_OFF32; + field public static final int _SC_XBS5_ILP32_OFFBIG; + field public static final int _SC_XBS5_LP64_OFF64; + field public static final int _SC_XBS5_LPBIG_OFFBIG; + field public static final int _SC_XOPEN_CRYPT; + field public static final int _SC_XOPEN_ENH_I18N; + field public static final int _SC_XOPEN_LEGACY; + field public static final int _SC_XOPEN_REALTIME; + field public static final int _SC_XOPEN_REALTIME_THREADS; + field public static final int _SC_XOPEN_SHM; + field public static final int _SC_XOPEN_UNIX; + field public static final int _SC_XOPEN_VERSION; + field public static final int _SC_XOPEN_XCU_VERSION; + } + + public final class StructPollfd { + ctor public StructPollfd(); + field public short events; + field public java.io.FileDescriptor fd; + field public short revents; + field public java.lang.Object userData; + } + + public final class StructStat { + ctor public StructStat(long, long, int, long, int, int, long, long, long, long, long, long, long); + field public final long st_atime; + field public final long st_blksize; + field public final long st_blocks; + field public final long st_ctime; + field public final long st_dev; + field public final int st_gid; + field public final long st_ino; + field public final int st_mode; + field public final long st_mtime; + field public final long st_nlink; + field public final long st_rdev; + field public final long st_size; + field public final int st_uid; + } + + public final class StructStatVfs { + ctor public StructStatVfs(long, long, long, long, long, long, long, long, long, long, long); + field public final long f_bavail; + field public final long f_bfree; + field public final long f_blocks; + field public final long f_bsize; + field public final long f_favail; + field public final long f_ffree; + field public final long f_files; + field public final long f_flag; + field public final long f_frsize; + field public final long f_fsid; + field public final long f_namemax; + } + + public final class StructUtsname { + ctor public StructUtsname(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String); + field public final java.lang.String machine; + field public final java.lang.String nodename; + field public final java.lang.String release; + field public final java.lang.String sysname; + field public final java.lang.String version; + } + +} + package android.telephony { public final class CellIdentityCdma implements android.os.Parcelable { @@ -28880,6 +29523,46 @@ package android.util { method public void previousMonth(); } + public final class MutableBoolean { + ctor public MutableBoolean(boolean); + field public boolean value; + } + + public final class MutableByte { + ctor public MutableByte(byte); + field public byte value; + } + + public final class MutableChar { + ctor public MutableChar(char); + field public char value; + } + + public final class MutableDouble { + ctor public MutableDouble(double); + field public double value; + } + + public final class MutableFloat { + ctor public MutableFloat(float); + field public float value; + } + + public final class MutableInt { + ctor public MutableInt(int); + field public int value; + } + + public final class MutableLong { + ctor public MutableLong(long); + field public long value; + } + + public final class MutableShort { + ctor public MutableShort(short); + field public short value; + } + public class NoSuchPropertyException extends java.lang.RuntimeException { ctor public NoSuchPropertyException(java.lang.String); } @@ -32553,6 +33236,34 @@ package android.view.inputmethod { field public static final android.os.Parcelable.Creator CREATOR; } + public final class CursorAnchorInfo implements android.os.Parcelable { + ctor public CursorAnchorInfo(android.os.Parcel); + method public int describeContents(); + method public int getCandidatesEnd(); + method public int getCandidatesStart(); + method public android.graphics.RectF getCharacterRect(int); + method public float getInsertionMarkerBaseline(); + method public float getInsertionMarkerBottom(); + method public float getInsertionMarkerHorizontal(); + method public float getInsertionMarkerTop(); + method public android.graphics.Matrix getMatrix(); + method public int getSelectionEnd(); + method public int getSelectionStart(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator CREATOR; + } + + public static final class CursorAnchorInfo.CursorAnchorInfoBuilder { + ctor public CursorAnchorInfo.CursorAnchorInfoBuilder(); + method public android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder addCharacterRect(int, float, float, float, float); + method public android.view.inputmethod.CursorAnchorInfo build(); + method public void reset(); + method public android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder setCandidateRange(int, int); + method public android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder setInsertionMarkerLocation(float, float, float, float); + method public android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder setMatrix(android.graphics.Matrix); + method public android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder setSelectionRange(int, int); + } + public class EditorInfo implements android.text.InputType android.os.Parcelable { ctor public EditorInfo(); method public int describeContents(); @@ -32761,6 +33472,7 @@ package android.view.inputmethod { method public void toggleSoftInput(int, int); method public void toggleSoftInputFromWindow(android.os.IBinder, int, int); method public void updateCursor(android.view.View, int, int, int, int); + method public void updateCursorAnchorInfo(android.view.View, android.view.inputmethod.CursorAnchorInfo); method public void updateExtractedText(android.view.View, int, android.view.inputmethod.ExtractedText); method public void updateSelection(android.view.View, int, int, int, int); method public void viewClicked(android.view.View); @@ -32783,6 +33495,7 @@ package android.view.inputmethod { method public abstract void finishInput(); method public abstract void toggleSoftInput(int, int); method public abstract void updateCursor(android.graphics.Rect); + method public abstract void updateCursorAnchorInfo(android.view.inputmethod.CursorAnchorInfo); method public abstract void updateExtractedText(int, android.view.inputmethod.ExtractedText); method public abstract void updateSelection(int, int, int, int, int, int); method public abstract void viewClicked(boolean); @@ -33032,7 +33745,6 @@ package android.webkit { method public abstract long getResources(); method public abstract void grant(long); field public static final long RESOURCE_AUDIO_CAPTURE = 4L; // 0x4L - field public static final long RESOURCE_GEOLOCATION = 1L; // 0x1L field public static final long RESOURCE_VIDEO_CAPTURE = 2L; // 0x2L } diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index ef6fcb726a17..66b82ebd28da 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -17,6 +17,7 @@ package android.app; import android.annotation.NonNull; +import android.os.PersistableBundle; import android.transition.Scene; import android.transition.TransitionManager; import android.util.ArrayMap; @@ -922,6 +923,30 @@ public class Activity extends ContextThemeWrapper } /** + * Same as {@link #onCreate(android.os.Bundle)} but called for those activities created with + * the attribute {@link android.R.attr#persistable} set true. + * + * @param savedInstanceState if the activity is being re-initialized after + * previously being shut down then this Bundle contains the data it most + * recently supplied in {@link #onSaveInstanceState}. + * <b><i>Note: Otherwise it is null.</i></b> + * @param persistentState if the activity is being re-initialized after + * previously being shut down or powered off then this Bundle contains the data it most + * recently supplied to outPersistentState in {@link #onSaveInstanceState}. + * <b><i>Note: Otherwise it is null.</i></b> + * + * @see #onCreate(android.os.Bundle) + * @see #onStart + * @see #onSaveInstanceState + * @see #onRestoreInstanceState + * @see #onPostCreate + */ + protected void onCreate(@Nullable Bundle savedInstanceState, + @Nullable PersistableBundle persistentState) { + onCreate(savedInstanceState); + } + + /** * The hook for {@link ActivityThread} to restore the state of this activity. * * Calls {@link #onSaveInstanceState(android.os.Bundle)} and @@ -935,6 +960,23 @@ public class Activity extends ContextThemeWrapper } /** + * The hook for {@link ActivityThread} to restore the state of this activity. + * + * Calls {@link #onSaveInstanceState(android.os.Bundle)} and + * {@link #restoreManagedDialogs(android.os.Bundle)}. + * + * @param savedInstanceState contains the saved state + * @param persistentState contains the persistable saved state + */ + final void performRestoreInstanceState(Bundle savedInstanceState, + PersistableBundle persistentState) { + onRestoreInstanceState(savedInstanceState, persistentState); + if (savedInstanceState != null) { + restoreManagedDialogs(savedInstanceState); + } + } + + /** * This method is called after {@link #onStart} when the activity is * being re-initialized from a previously saved state, given here in * <var>savedInstanceState</var>. Most implementations will simply use {@link #onCreate} @@ -962,7 +1004,34 @@ public class Activity extends ContextThemeWrapper } } } - + + /** + * This is the same as {@link #onRestoreInstanceState(Bundle)} but is called for activities + * created with the attribute {@link android.R.attr#persistable}. The {@link + * android.os.PersistableBundle} passed came from the restored PersistableBundle first + * saved in {@link #onSaveInstanceState(Bundle, PersistableBundle)}. + * + * <p>This method is called between {@link #onStart} and + * {@link #onPostCreate}. + * + * <p>If this method is called {@link #onRestoreInstanceState(Bundle)} will not be called. + * + * @param savedInstanceState the data most recently supplied in {@link #onSaveInstanceState}. + * @param persistentState the data most recently supplied in {@link #onSaveInstanceState}. + * + * @see #onRestoreInstanceState(Bundle) + * @see #onCreate + * @see #onPostCreate + * @see #onResume + * @see #onSaveInstanceState + */ + protected void onRestoreInstanceState(Bundle savedInstanceState, + PersistableBundle persistentState) { + if (savedInstanceState != null) { + onRestoreInstanceState(savedInstanceState); + } + } + /** * Restore the state of any saved managed dialogs. * @@ -1039,6 +1108,21 @@ public class Activity extends ContextThemeWrapper } /** + * This is the same as {@link #onPostCreate(Bundle)} but is called for activities + * created with the attribute {@link android.R.attr#persistable}. + * + * @param savedInstanceState The data most recently supplied in {@link #onSaveInstanceState} + * @param persistentState The data caming from the PersistableBundle first + * saved in {@link #onSaveInstanceState(Bundle, PersistableBundle)}. + * + * @see #onCreate + */ + protected void onPostCreate(@Nullable Bundle savedInstanceState, + @Nullable PersistableBundle persistentState) { + onPostCreate(savedInstanceState); + } + + /** * Called after {@link #onCreate} — or after {@link #onRestart} when * the activity had been stopped, but is now again being displayed to the * user. It will be followed by {@link #onResume}. @@ -1194,6 +1278,22 @@ public class Activity extends ContextThemeWrapper } /** + * The hook for {@link ActivityThread} to save the state of this activity. + * + * Calls {@link #onSaveInstanceState(android.os.Bundle)} + * and {@link #saveManagedDialogs(android.os.Bundle)}. + * + * @param outState The bundle to save the state to. + * @param outPersistentState The bundle to save persistent state to. + */ + final void performSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) { + onSaveInstanceState(outState, outPersistentState); + saveManagedDialogs(outState); + if (DEBUG_LIFECYCLE) Slog.v(TAG, "onSaveInstanceState " + this + ": " + outState + + ", " + outPersistentState); + } + + /** * Called to retrieve per-instance state from an activity before being killed * so that the state can be restored in {@link #onCreate} or * {@link #onRestoreInstanceState} (the {@link Bundle} populated by this method @@ -1248,6 +1348,25 @@ public class Activity extends ContextThemeWrapper } /** + * This is the same as {@link #onSaveInstanceState} but is called for activities + * created with the attribute {@link android.R.attr#persistable}. The {@link + * android.os.PersistableBundle} passed in will be saved and presented in + * {@link #onCreate(Bundle, PersistableBundle)} the first time that this activity + * is restarted following the next device reboot. + * + * @param outState Bundle in which to place your saved state. + * @param outPersistentState State which will be saved across reboots. + * + * @see #onSaveInstanceState(Bundle) + * @see #onCreate + * @see #onRestoreInstanceState(Bundle, PersistableBundle) + * @see #onPause + */ + protected void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) { + onSaveInstanceState(outState); + } + + /** * Save the state of any managed dialogs. * * @param outState place to store the saved state. @@ -5489,13 +5608,22 @@ public class Activity extends ContextThemeWrapper return mParent != null ? mParent.getActivityToken() : mToken; } - final void performCreate(Bundle icicle) { - onCreate(icicle); + final void performCreateCommon() { mVisibleFromClient = !mWindow.getWindowStyle().getBoolean( com.android.internal.R.styleable.Window_windowNoDisplay, false); mFragments.dispatchActivityCreated(); } + final void performCreate(Bundle icicle) { + onCreate(icicle); + performCreateCommon(); + } + + final void performCreate(Bundle icicle, PersistableBundle persistentState) { + onCreate(icicle, persistentState); + performCreateCommon(); + } + final void performStart() { mFragments.noteStateNotSaved(); mCalled = false; diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 57da21e770cb..ec2868afc2c7 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -40,6 +40,7 @@ import android.os.IBinder; import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.Parcelable; +import android.os.PersistableBundle; import android.os.RemoteException; import android.os.ServiceManager; import android.os.StrictMode; @@ -454,7 +455,8 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM case ACTIVITY_PAUSED_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); IBinder token = data.readStrongBinder(); - activityPaused(token); + PersistableBundle persistentState = data.readPersistableBundle(); + activityPaused(token, persistentState); reply.writeNoException(); return true; } @@ -463,10 +465,9 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM data.enforceInterface(IActivityManager.descriptor); IBinder token = data.readStrongBinder(); Bundle map = data.readBundle(); - Bitmap thumbnail = data.readInt() != 0 - ? Bitmap.CREATOR.createFromParcel(data) : null; + PersistableBundle persistentState = data.readPersistableBundle(); CharSequence description = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(data); - activityStopped(token, map, thumbnail, description); + activityStopped(token, map, persistentState, description); reply.writeNoException(); return true; } @@ -2583,31 +2584,27 @@ class ActivityManagerProxy implements IActivityManager data.recycle(); reply.recycle(); } - public void activityPaused(IBinder token) throws RemoteException + public void activityPaused(IBinder token, PersistableBundle persistentState) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeStrongBinder(token); + data.writePersistableBundle(persistentState); mRemote.transact(ACTIVITY_PAUSED_TRANSACTION, data, reply, 0); reply.readException(); data.recycle(); reply.recycle(); } public void activityStopped(IBinder token, Bundle state, - Bitmap thumbnail, CharSequence description) throws RemoteException + PersistableBundle persistentState, CharSequence description) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeStrongBinder(token); data.writeBundle(state); - if (thumbnail != null) { - data.writeInt(1); - thumbnail.writeToParcel(data, 0); - } else { - data.writeInt(0); - } + data.writePersistableBundle(persistentState); TextUtils.writeToParcel(description, data, 0); mRemote.transact(ACTIVITY_STOPPED_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY); reply.readException(); diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index b60608897788..161cb7655276 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -56,11 +56,11 @@ import android.os.DropBoxManager; import android.os.Environment; import android.os.Handler; import android.os.IBinder; -import android.os.IRemoteCallback; import android.os.Looper; import android.os.Message; import android.os.MessageQueue; import android.os.ParcelFileDescriptor; +import android.os.PersistableBundle; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; @@ -69,8 +69,6 @@ import android.os.SystemClock; import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; -import android.transition.Scene; -import android.transition.TransitionManager; import android.provider.Settings; import android.util.AndroidRuntimeException; import android.util.ArrayMap; @@ -268,6 +266,7 @@ public final class ActivityThread { Intent intent; IVoiceInteractor voiceInteractor; Bundle state; + PersistableBundle persistentState; Activity activity; Window window; Activity parent; @@ -317,6 +316,10 @@ public final class ActivityThread { return false; } + public boolean isPersistable() { + return (activityInfo.flags & ActivityInfo.FLAG_PERSISTABLE) != 0; + } + public String toString() { ComponentName componentName = intent != null ? intent.getComponent() : null; return "ActivityRecord{" @@ -605,8 +608,8 @@ public final class ActivityThread { // activity itself back to the activity manager. (matters more with ipc) public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident, ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo, - IVoiceInteractor voiceInteractor, - int procState, Bundle state, List<ResultInfo> pendingResults, + IVoiceInteractor voiceInteractor, int procState, Bundle state, + PersistableBundle persistentState, List<ResultInfo> pendingResults, List<Intent> pendingNewIntents, boolean notResumed, boolean isForward, String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler, Bundle resumeArgs) { @@ -622,6 +625,7 @@ public final class ActivityThread { r.activityInfo = info; r.compatInfo = compatInfo; r.state = state; + r.persistentState = persistentState; r.pendingResults = pendingResults; r.pendingIntents = pendingNewIntents; @@ -2205,7 +2209,11 @@ public final class ActivityThread { } activity.mCalled = false; - mInstrumentation.callActivityOnCreate(activity, r.state); + if (r.isPersistable()) { + mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState); + } else { + mInstrumentation.callActivityOnCreate(activity, r.state); + } if (!activity.mCalled) { throw new SuperNotCalledException( "Activity " + r.intent.getComponent().toShortString() + @@ -2218,13 +2226,23 @@ public final class ActivityThread { r.stopped = false; } if (!r.activity.mFinished) { - if (r.state != null) { + if (r.isPersistable()) { + if (r.state != null || r.persistentState != null) { + mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state, + r.persistentState); + } + } else if (r.state != null) { mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state); } } if (!r.activity.mFinished) { activity.mCalled = false; - mInstrumentation.callActivityOnPostCreate(activity, r.state); + if (r.isPersistable()) { + mInstrumentation.callActivityOnPostCreate(activity, r.state, + r.persistentState); + } else { + mInstrumentation.callActivityOnPostCreate(activity, r.state); + } if (!activity.mCalled) { throw new SuperNotCalledException( "Activity " + r.intent.getComponent().toShortString() + @@ -2842,6 +2860,7 @@ public final class ActivityThread { r.paused = false; r.stopped = false; r.state = null; + r.persistentState = null; } catch (Exception e) { if (!mInstrumentation.onException(r.activity, e)) { throw new RuntimeException( @@ -3069,7 +3088,7 @@ public final class ActivityThread { // Tell the activity manager we have paused. try { - ActivityManagerNative.getDefault().activityPaused(token); + ActivityManagerNative.getDefault().activityPaused(token, r.persistentState); } catch (RemoteException ex) { } } @@ -3099,17 +3118,13 @@ public final class ActivityThread { + r.intent.getComponent().toShortString()); Slog.e(TAG, e.getMessage(), e); } - Bundle state = null; if (finished) { r.activity.mFinished = true; } try { // Next have the activity save its current state and managed dialogs... if (!r.activity.mFinished && saveState) { - state = new Bundle(); - state.setAllowFds(false); - mInstrumentation.callActivityOnSaveInstanceState(r.activity, state); - r.state = state; + callCallActivityOnSaveInstanceState(r); } // Now we are idle. r.activity.mCalled = false; @@ -3145,7 +3160,7 @@ public final class ActivityThread { listeners.get(i).onPaused(r.activity); } - return state; + return !r.activity.mFinished && saveState ? r.state : null; } final void performStopActivity(IBinder token, boolean saveState) { @@ -3156,7 +3171,7 @@ public final class ActivityThread { private static class StopInfo implements Runnable { ActivityClientRecord activity; Bundle state; - Bitmap thumbnail; + PersistableBundle persistentState; CharSequence description; @Override public void run() { @@ -3164,7 +3179,7 @@ public final class ActivityThread { try { if (DEBUG_MEMORY_TRIM) Slog.v(TAG, "Reporting activity stopped: " + activity); ActivityManagerNative.getDefault().activityStopped( - activity.token, state, thumbnail, description); + activity.token, state, persistentState, description); } catch (RemoteException ex) { } } @@ -3203,7 +3218,6 @@ public final class ActivityThread { private void performStopActivityInner(ActivityClientRecord r, StopInfo info, boolean keepShown, boolean saveState) { if (localLOGV) Slog.v(TAG, "Performing stop of " + r); - Bundle state = null; if (r != null) { if (!keepShown && r.stopped) { if (r.activity.mFinished) { @@ -3223,7 +3237,6 @@ public final class ActivityThread { // First create a thumbnail for the activity... // For now, don't create the thumbnail here; we are // doing that by doing a screen snapshot. - info.thumbnail = null; //createThumbnailBitmap(r); info.description = r.activity.onCreateDescription(); } catch (Exception e) { if (!mInstrumentation.onException(r.activity, e)) { @@ -3238,12 +3251,7 @@ public final class ActivityThread { // Next have the activity save its current state and managed dialogs... if (!r.activity.mFinished && saveState) { if (r.state == null) { - state = new Bundle(); - state.setAllowFds(false); - mInstrumentation.callActivityOnSaveInstanceState(r.activity, state); - r.state = state; - } else { - state = r.state; + callCallActivityOnSaveInstanceState(r); } } @@ -3319,6 +3327,7 @@ public final class ActivityThread { // manager to proceed and allow us to go fully into the background. info.activity = r; info.state = r.state; + info.persistentState = r.persistentState; mH.post(info); } @@ -3775,9 +3784,7 @@ public final class ActivityThread { performPauseActivity(r.token, false, r.isPreHoneycomb()); } if (r.state == null && !r.stopped && !r.isPreHoneycomb()) { - r.state = new Bundle(); - r.state.setAllowFds(false); - mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state); + callCallActivityOnSaveInstanceState(r); } handleDestroyActivity(r.token, false, configChanges, true); @@ -3807,6 +3814,18 @@ public final class ActivityThread { handleLaunchActivity(r, currentIntent); } + private void callCallActivityOnSaveInstanceState(ActivityClientRecord r) { + r.state = new Bundle(); + r.state.setAllowFds(false); + if (r.isPersistable()) { + r.persistentState = new PersistableBundle(); + mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state, + r.persistentState); + } else { + mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state); + } + } + ArrayList<ComponentCallbacks2> collectComponentCallbacks( boolean allActivities, Configuration newConfig) { ArrayList<ComponentCallbacks2> callbacks diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java index 7f2fb59585e3..e7902a9d9825 100644 --- a/core/java/android/app/ApplicationThreadNative.java +++ b/core/java/android/app/ApplicationThreadNative.java @@ -29,6 +29,7 @@ import android.os.Binder; import android.os.Bundle; import android.os.Debug; import android.os.Parcelable; +import android.os.PersistableBundle; import android.os.RemoteException; import android.os.IBinder; import android.os.Parcel; @@ -141,6 +142,7 @@ public abstract class ApplicationThreadNative extends Binder data.readStrongBinder()); int procState = data.readInt(); Bundle state = data.readBundle(); + PersistableBundle persistentState = data.readPersistableBundle(); List<ResultInfo> ri = data.createTypedArrayList(ResultInfo.CREATOR); List<Intent> pi = data.createTypedArrayList(Intent.CREATOR); boolean notResumed = data.readInt() != 0; @@ -151,9 +153,9 @@ public abstract class ApplicationThreadNative extends Binder boolean autoStopProfiler = data.readInt() != 0; Bundle resumeArgs = data.readBundle(); scheduleLaunchActivity(intent, b, ident, info, curConfig, compatInfo, - voiceInteractor, procState, state, - ri, pi, notResumed, isForward, profileName, profileFd, autoStopProfiler, - resumeArgs); + voiceInteractor, procState, state, persistentState, + ri, pi, notResumed, isForward, profileName, profileFd, + autoStopProfiler, resumeArgs); return true; } @@ -731,8 +733,8 @@ class ApplicationThreadProxy implements IApplicationThread { public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident, ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo, - IVoiceInteractor voiceInteractor, - int procState, Bundle state, List<ResultInfo> pendingResults, + IVoiceInteractor voiceInteractor, int procState, Bundle state, + PersistableBundle persistentState, List<ResultInfo> pendingResults, List<Intent> pendingNewIntents, boolean notResumed, boolean isForward, String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler, Bundle resumeArgs) @@ -748,6 +750,7 @@ class ApplicationThreadProxy implements IApplicationThread { data.writeStrongBinder(voiceInteractor != null ? voiceInteractor.asBinder() : null); data.writeInt(procState); data.writeBundle(state); + data.writePersistableBundle(persistentState); data.writeTypedList(pendingResults); data.writeTypedList(pendingNewIntents); data.writeInt(notResumed ? 1 : 0); diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 2e9cdf3b7655..074b427244f4 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -45,6 +45,7 @@ import android.os.IInterface; import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.Parcelable; +import android.os.PersistableBundle; import android.os.RemoteException; import android.os.StrictMode; import android.service.voice.IVoiceInteractionSession; @@ -104,9 +105,9 @@ public interface IActivityManager extends IInterface { public void activityResumed(IBinder token) throws RemoteException; public void activityIdle(IBinder token, Configuration config, boolean stopProfiling) throws RemoteException; - public void activityPaused(IBinder token) throws RemoteException; + public void activityPaused(IBinder token, PersistableBundle persistentState) throws RemoteException; public void activityStopped(IBinder token, Bundle state, - Bitmap thumbnail, CharSequence description) throws RemoteException; + PersistableBundle persistentState, CharSequence description) throws RemoteException; public void activitySlept(IBinder token) throws RemoteException; public void activityDestroyed(IBinder token) throws RemoteException; public String getCallingPackage(IBinder token) throws RemoteException; diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java index fefba8a64c3f..a8320342d45d 100644 --- a/core/java/android/app/IApplicationThread.java +++ b/core/java/android/app/IApplicationThread.java @@ -28,6 +28,7 @@ import android.content.res.Configuration; import android.os.Bundle; import android.os.Debug; import android.os.ParcelFileDescriptor; +import android.os.PersistableBundle; import android.os.RemoteException; import android.os.IBinder; import android.os.IInterface; @@ -58,8 +59,8 @@ public interface IApplicationThread extends IInterface { void scheduleLaunchActivity(Intent intent, IBinder token, int ident, ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo, IVoiceInteractor voiceInteractor, int procState, Bundle state, - List<ResultInfo> pendingResults, List<Intent> pendingNewIntents, boolean notResumed, - boolean isForward, + PersistableBundle persistentState, List<ResultInfo> pendingResults, + List<Intent> pendingNewIntents, boolean notResumed, boolean isForward, String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler, Bundle resumeArgs) throws RemoteException; diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java index e58ccb81d479..bb3e002a97f2 100644 --- a/core/java/android/app/Instrumentation.java +++ b/core/java/android/app/Instrumentation.java @@ -30,6 +30,7 @@ import android.os.IBinder; import android.os.Looper; import android.os.MessageQueue; import android.os.PerformanceCollector; +import android.os.PersistableBundle; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; @@ -1061,15 +1062,7 @@ public class Instrumentation { return (Activity)cl.loadClass(className).newInstance(); } - /** - * Perform calling of an activity's {@link Activity#onCreate} - * method. The default implementation simply calls through to that method. - * - * @param activity The activity being created. - * @param icicle The previously frozen state (or null) to pass through to - * onCreate(). - */ - public void callActivityOnCreate(Activity activity, Bundle icicle) { + private void prePerformCreate(Activity activity) { if (mWaitingActivities != null) { synchronized (mSync) { final int N = mWaitingActivities.size(); @@ -1083,9 +1076,9 @@ public class Instrumentation { } } } - - activity.performCreate(icicle); - + } + + private void postPerformCreate(Activity activity) { if (mActivityMonitors != null) { synchronized (mSync) { final int N = mActivityMonitors.size(); @@ -1096,6 +1089,33 @@ public class Instrumentation { } } } + + /** + * Perform calling of an activity's {@link Activity#onCreate} + * method. The default implementation simply calls through to that method. + * + * @param activity The activity being created. + * @param icicle The previously frozen state (or null) to pass through to onCreate(). + */ + public void callActivityOnCreate(Activity activity, Bundle icicle) { + prePerformCreate(activity); + activity.performCreate(icicle); + postPerformCreate(activity); + } + + /** + * Perform calling of an activity's {@link Activity#onCreate} + * method. The default implementation simply calls through to that method. + * @param activity The activity being created. + * @param icicle The previously frozen state (or null) to pass through to + * @param persistentState The previously persisted state (or null) + */ + public void callActivityOnCreate(Activity activity, Bundle icicle, + PersistableBundle persistentState) { + prePerformCreate(activity); + activity.performCreate(icicle, persistentState); + postPerformCreate(activity); + } public void callActivityOnDestroy(Activity activity) { // TODO: the following block causes intermittent hangs when using startActivity @@ -1130,7 +1150,7 @@ public class Instrumentation { /** * Perform calling of an activity's {@link Activity#onRestoreInstanceState} * method. The default implementation simply calls through to that method. - * + * * @param activity The activity being restored. * @param savedInstanceState The previously saved state being restored. */ @@ -1139,9 +1159,22 @@ public class Instrumentation { } /** + * Perform calling of an activity's {@link Activity#onRestoreInstanceState} + * method. The default implementation simply calls through to that method. + * + * @param activity The activity being restored. + * @param savedInstanceState The previously saved state being restored. + * @param persistentState The previously persisted state (or null) + */ + public void callActivityOnRestoreInstanceState(Activity activity, Bundle savedInstanceState, + PersistableBundle persistentState) { + activity.performRestoreInstanceState(savedInstanceState, persistentState); + } + + /** * Perform calling of an activity's {@link Activity#onPostCreate} method. * The default implementation simply calls through to that method. - * + * * @param activity The activity being created. * @param icicle The previously frozen state (or null) to pass through to * onPostCreate(). @@ -1151,6 +1184,19 @@ public class Instrumentation { } /** + * Perform calling of an activity's {@link Activity#onPostCreate} method. + * The default implementation simply calls through to that method. + * + * @param activity The activity being created. + * @param icicle The previously frozen state (or null) to pass through to + * onPostCreate(). + */ + public void callActivityOnPostCreate(Activity activity, Bundle icicle, + PersistableBundle persistentState) { + activity.onPostCreate(icicle, persistentState); + } + + /** * Perform calling of an activity's {@link Activity#onNewIntent} * method. The default implementation simply calls through to that method. * @@ -1215,7 +1261,7 @@ public class Instrumentation { /** * Perform calling of an activity's {@link Activity#onSaveInstanceState} * method. The default implementation simply calls through to that method. - * + * * @param activity The activity being saved. * @param outState The bundle to pass to the call. */ @@ -1224,6 +1270,18 @@ public class Instrumentation { } /** + * Perform calling of an activity's {@link Activity#onSaveInstanceState} + * method. The default implementation simply calls through to that method. + * @param activity The activity being saved. + * @param outState The bundle to pass to the call. + * @param outPersistentState The persistent bundle to pass to the call. + */ + public void callActivityOnSaveInstanceState(Activity activity, Bundle outState, + PersistableBundle outPersistentState) { + activity.performSaveInstanceState(outState, outPersistentState); + } + + /** * Perform calling of an activity's {@link Activity#onPause} method. The * default implementation simply calls through to that method. * @@ -1428,7 +1486,7 @@ public class Instrumentation { } /** - * Like {@link #execStartActivity}, + * Like {@link #execStartActivity(Context, IBinder, IBinder, Activity, Intent, int, Bundle)}, * but accepts an array of activities to be started. Note that active * {@link ActivityMonitor} objects only match against the first activity in * the array. @@ -1442,7 +1500,7 @@ public class Instrumentation { } /** - * Like {@link #execStartActivity}, + * Like {@link #execStartActivity(Context, IBinder, IBinder, Activity, Intent, int, Bundle)}, * but accepts an array of activities to be started. Note that active * {@link ActivityMonitor} objects only match against the first activity in * the array. @@ -1545,7 +1603,8 @@ public class Instrumentation { } /** - * Like {@link #execStartActivity}, but for starting as a particular user. + * Like {@link #execStartActivity(Context, IBinder, IBinder, Activity, Intent, int, Bundle)}, + * but for starting as a particular user. * * @param who The Context from which the activity is being started. * @param contextThread The main thread of the Context from which the activity diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 24bb2cc44ce0..58049fd11914 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -16,8 +16,6 @@ package android.app.admin; -import org.xmlpull.v1.XmlPullParserException; - import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.content.ComponentName; @@ -39,6 +37,8 @@ import android.util.Log; import com.android.org.conscrypt.TrustedCertificateStore; +import org.xmlpull.v1.XmlPullParserException; + import java.io.ByteArrayInputStream; import java.io.IOException; import java.net.InetSocketAddress; @@ -359,8 +359,8 @@ public class DevicePolicyManager { } /** - * Retrieve the current minimum password quality for all admins - * or a particular one. + * Retrieve the current minimum password quality for all admins of this user + * and its profiles or a particular one. * @param admin The name of the admin component to check, or null to aggregate * all admins. */ @@ -412,8 +412,8 @@ public class DevicePolicyManager { } /** - * Retrieve the current minimum password length for all admins - * or a particular one. + * Retrieve the current minimum password length for all admins of this + * user and its profiles or a particular one. * @param admin The name of the admin component to check, or null to aggregate * all admins. */ @@ -467,8 +467,9 @@ public class DevicePolicyManager { /** * Retrieve the current number of upper case letters required in the - * password for all admins or a particular one. This is the same value as - * set by {#link {@link #setPasswordMinimumUpperCase(ComponentName, int)} + * password for all admins of this user and its profiles or a particular one. + * This is the same value as set by + * {#link {@link #setPasswordMinimumUpperCase(ComponentName, int)} * and only applies when the password quality is * {@link #PASSWORD_QUALITY_COMPLEX}. * @@ -527,8 +528,9 @@ public class DevicePolicyManager { /** * Retrieve the current number of lower case letters required in the - * password for all admins or a particular one. This is the same value as - * set by {#link {@link #setPasswordMinimumLowerCase(ComponentName, int)} + * password for all admins of this user and its profiles or a particular one. + * This is the same value as set by + * {#link {@link #setPasswordMinimumLowerCase(ComponentName, int)} * and only applies when the password quality is * {@link #PASSWORD_QUALITY_COMPLEX}. * @@ -644,8 +646,9 @@ public class DevicePolicyManager { /** * Retrieve the current number of numerical digits required in the password - * for all admins or a particular one. This is the same value as - * set by {#link {@link #setPasswordMinimumNumeric(ComponentName, int)} + * for all admins of this user and its profiles or a particular one. + * This is the same value as set by + * {#link {@link #setPasswordMinimumNumeric(ComponentName, int)} * and only applies when the password quality is * {@link #PASSWORD_QUALITY_COMPLEX}. * @@ -760,8 +763,9 @@ public class DevicePolicyManager { /** * Retrieve the current number of non-letter characters required in the - * password for all admins or a particular one. This is the same value as - * set by {#link {@link #setPasswordMinimumNonLetter(ComponentName, int)} + * password for all admins of this user and its profiles or a particular one. + * This is the same value as set by + * {#link {@link #setPasswordMinimumNonLetter(ComponentName, int)} * and only applies when the password quality is * {@link #PASSWORD_QUALITY_COMPLEX}. * @@ -868,9 +872,10 @@ public class DevicePolicyManager { /** * Get the current password expiration time for the given admin or an aggregate of - * all admins if admin is null. If the password is expired, this will return the time since - * the password expired as a negative number. If admin is null, then a composite of all - * expiration timeouts is returned - which will be the minimum of all timeouts. + * all admins of this user and its profiles if admin is null. If the password is + * expired, this will return the time since the password expired as a negative number. + * If admin is null, then a composite of all expiration timeouts is returned + * - which will be the minimum of all timeouts. * * @param admin The name of the admin component to check, or null to aggregate all admins. * @return The password expiration time, in ms. @@ -887,8 +892,8 @@ public class DevicePolicyManager { } /** - * Retrieve the current password history length for all admins - * or a particular one. + * Retrieve the current password history length for all admins of this + * user and its profiles or a particular one. * @param admin The name of the admin component to check, or null to aggregate * all admins. * @return The length of the password history @@ -923,14 +928,13 @@ public class DevicePolicyManager { /** * Determine whether the current password the user has set is sufficient * to meet the policy requirements (quality, minimum length) that have been - * requested. + * requested by the admins of this user and its profiles. * * <p>The calling device admin must have requested * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call * this method; if it has not, a security exception will be thrown. * - * @return Returns true if the password meets the current requirements, - * else false. + * @return Returns true if the password meets the current requirements, else false. */ public boolean isActivePasswordSufficient() { if (mService != null) { @@ -993,7 +997,7 @@ public class DevicePolicyManager { /** * Retrieve the current maximum number of login attempts that are allowed - * before the device wipes itself, for all admins + * before the device wipes itself, for all admins of this user and its profiles * or a particular one. * @param admin The name of the admin component to check, or null to aggregate * all admins. @@ -1037,6 +1041,8 @@ public class DevicePolicyManager { * {@link DeviceAdminInfo#USES_POLICY_RESET_PASSWORD} to be able to call * this method; if it has not, a security exception will be thrown. * + * Can not be called from a managed profile. + * * @param password The new password for the user. * @param flags May be 0 or {@link #RESET_PASSWORD_REQUIRE_ENTRY}. * @return Returns true if the password was applied, or false if it is @@ -1077,8 +1083,8 @@ public class DevicePolicyManager { } /** - * Retrieve the current maximum time to unlock for all admins - * or a particular one. + * Retrieve the current maximum time to unlock for all admins of this user + * and its profiles or a particular one. * @param admin The name of the admin component to check, or null to aggregate * all admins. */ diff --git a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java index 8437228257a0..ed223d1fd503 100644 --- a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java +++ b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java @@ -36,6 +36,7 @@ import android.view.MotionEvent; import android.view.inputmethod.CompletionInfo; import android.view.inputmethod.ExtractedText; import android.view.inputmethod.InputMethodSession; +import android.view.inputmethod.CursorAnchorInfo; class IInputMethodSessionWrapper extends IInputMethodSession.Stub implements HandlerCaller.Callback { @@ -46,6 +47,7 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub private static final int DO_UPDATE_EXTRACTED_TEXT = 67; private static final int DO_UPDATE_SELECTION = 90; private static final int DO_UPDATE_CURSOR = 95; + private static final int DO_UPDATE_CURSOR_ANCHOR_INFO = 99; private static final int DO_APP_PRIVATE_COMMAND = 100; private static final int DO_TOGGLE_SOFT_INPUT = 105; private static final int DO_FINISH_SESSION = 110; @@ -108,6 +110,10 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub mInputMethodSession.updateCursor((Rect)msg.obj); return; } + case DO_UPDATE_CURSOR_ANCHOR_INFO: { + mInputMethodSession.updateCursorAnchorInfo((CursorAnchorInfo)msg.obj); + return; + } case DO_APP_PRIVATE_COMMAND: { SomeArgs args = (SomeArgs)msg.obj; mInputMethodSession.appPrivateCommand((String)args.arg1, @@ -181,6 +187,12 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub } @Override + public void updateCursorAnchorInfo(CursorAnchorInfo cursorAnchorInfo) { + mCaller.executeOrSendMessage( + mCaller.obtainMessageO(DO_UPDATE_CURSOR_ANCHOR_INFO, cursorAnchorInfo)); + } + + @Override public void appPrivateCommand(String action, Bundle data) { mCaller.executeOrSendMessage( mCaller.obtainMessageOO(DO_APP_PRIVATE_COMMAND, action, data)); diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index f6438b444cb5..4bccaf1d6f52 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -51,6 +51,7 @@ import android.view.WindowManager; import android.view.WindowManager.BadTokenException; import android.view.animation.AnimationUtils; import android.view.inputmethod.CompletionInfo; +import android.view.inputmethod.CursorAnchorInfo; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.ExtractedText; import android.view.inputmethod.ExtractedTextRequest; @@ -545,6 +546,17 @@ public class InputMethodService extends AbstractInputMethodService { public void toggleSoftInput(int showFlags, int hideFlags) { InputMethodService.this.onToggleSoftInput(showFlags, hideFlags); } + + /** + * Call {@link InputMethodService#onUpdateCursorAnchorInfo + * InputMethodService.onUpdateCursorAnchorInfo()}. + */ + public void updateCursorAnchorInfo(CursorAnchorInfo info) { + if (!isEnabled()) { + return; + } + InputMethodService.this.onUpdateCursorAnchorInfo(info); + } } /** @@ -1717,6 +1729,17 @@ public class InputMethodService extends AbstractInputMethodService { } /** + * Called when the application has reported a new location of its text insertion point and + * characters in the composition string. This is only called if explicitly requested by the + * input method. The default implementation does nothing. + * @param cursorAnchorInfo The positional information of the text insertion point and the + * composition string. + */ + public void onUpdateCursorAnchorInfo(CursorAnchorInfo cursorAnchorInfo) { + // Intentionally empty + } + + /** * Update the cursor/anthor monitor mode. */ public void setCursorAnchorMonitorMode(int monitorMode) { diff --git a/core/java/android/net/Proxy.java b/core/java/android/net/Proxy.java index 8f41e8561876..daf0065d1c47 100644 --- a/core/java/android/net/Proxy.java +++ b/core/java/android/net/Proxy.java @@ -278,7 +278,9 @@ public final class Proxy { host = p.getHost(); port = Integer.toString(p.getPort()); exclList = p.getExclusionListAsString(); - pacFileUrl = p.getPacFileUrl().toString(); + if (p.getPacFileUrl() != null) { + pacFileUrl = p.getPacFileUrl().toString(); + } } setHttpProxySystemProperty(host, port, exclList, pacFileUrl); } diff --git a/core/java/android/nfc/INfcCardEmulation.aidl b/core/java/android/nfc/INfcCardEmulation.aidl index ae9796b23ac3..521f4fd7b767 100644 --- a/core/java/android/nfc/INfcCardEmulation.aidl +++ b/core/java/android/nfc/INfcCardEmulation.aidl @@ -34,4 +34,6 @@ interface INfcCardEmulation AidGroup getAidGroupForService(int userHandle, in ComponentName service, String category); boolean removeAidGroupForService(int userHandle, in ComponentName service, String category); List<ApduServiceInfo> getServices(int userHandle, in String category); + boolean setPreferredService(in ComponentName service); + boolean unsetPreferredService(); } diff --git a/core/java/android/nfc/cardemulation/AidGroup.java b/core/java/android/nfc/cardemulation/AidGroup.java index 2820f4037e78..b04492247e59 100644 --- a/core/java/android/nfc/cardemulation/AidGroup.java +++ b/core/java/android/nfc/cardemulation/AidGroup.java @@ -12,10 +12,15 @@ import android.os.Parcelable; import android.util.Log; /** - * The AidGroup class represents a group of ISO/IEC 7816-4 - * Application Identifiers (AIDs) for a specific application - * category, along with a description resource describing - * the group. + * The AidGroup class represents a group of Application Identifiers (AIDs). + * + * <p>An instance of this object can be used with + * {@link CardEmulation#registerAidGroupForService(android.content.ComponentName, AidGroup)} + * to tell the OS which AIDs are handled by your HCE- or SE-based service. + * + * <p>The format of AIDs is defined in the ISO/IEC 7816-4 specification. This class + * requires the AIDs to be input as a hexadecimal string, with an even amount of + * hexadecimal characters, e.g. "F014811481". */ public final class AidGroup implements Parcelable { /** @@ -33,7 +38,7 @@ public final class AidGroup implements Parcelable { * Creates a new AidGroup object. * * @param aids The list of AIDs present in the group - * @param category The category of this group + * @param category The category of this group, e.g. {@link CardEmulation#CATEGORY_PAYMENT} */ public AidGroup(ArrayList<String> aids, String category) { if (aids == null || aids.size() == 0) { @@ -42,11 +47,12 @@ public final class AidGroup implements Parcelable { if (aids.size() > MAX_NUM_AIDS) { throw new IllegalArgumentException("Too many AIDs in AID group."); } - if (!isValidCategory(category)) { - throw new IllegalArgumentException("Category specified is not valid."); + if (isValidCategory(category)) { + this.category = category; + } else { + this.category = CardEmulation.CATEGORY_OTHER; } this.aids = aids; - this.category = category; this.description = null; } @@ -158,7 +164,7 @@ public final class AidGroup implements Parcelable { } } - boolean isValidCategory(String category) { + static boolean isValidCategory(String category) { return CardEmulation.CATEGORY_PAYMENT.equals(category) || CardEmulation.CATEGORY_OTHER.equals(category); } diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java index 94f35ed5a87f..f379ee8b7f0a 100644 --- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java +++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java @@ -290,6 +290,20 @@ public final class ApduServiceInfo implements Parcelable { return groups; } + /** + * Returns the category to which this service has attributed the AID that is passed in, + * or null if we don't know this AID. + */ + public String getCategoryForAid(String aid) { + ArrayList<AidGroup> groups = getAidGroups(); + for (AidGroup group : groups) { + if (group.aids.contains(aid)) { + return group.category; + } + } + return null; + } + public boolean hasCategory(String category) { return (mStaticAidGroups.containsKey(category) || mDynamicAidGroups.containsKey(category)); } diff --git a/core/java/android/nfc/cardemulation/CardEmulation.java b/core/java/android/nfc/cardemulation/CardEmulation.java index 41f039cfc7ca..e24a22acbf3b 100644 --- a/core/java/android/nfc/cardemulation/CardEmulation.java +++ b/core/java/android/nfc/cardemulation/CardEmulation.java @@ -18,6 +18,7 @@ package android.nfc.cardemulation; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; +import android.app.Activity; import android.app.ActivityThread; import android.content.ComponentName; import android.content.Context; @@ -28,6 +29,7 @@ import android.nfc.NfcAdapter; import android.os.RemoteException; import android.os.UserHandle; import android.provider.Settings; +import android.provider.Settings.SettingNotFoundException; import android.util.Log; import java.util.HashMap; @@ -248,6 +250,33 @@ public final class CardEmulation { } /** + * Returns whether the user has allowed AIDs registered in the + * specified category to be handled by a service that is preferred + * by the foreground application, instead of by a pre-configured default. + * + * Foreground applications can set such preferences using the + * {@link #setPreferredService(Activity, ComponentName)} method. + * + * @param category The category, e.g. {@link #CATEGORY_PAYMENT} + * @return whether AIDs in the category can be handled by a service + * specified by the foreground app. + */ + public boolean categoryAllowsForegroundPreference(String category) { + if (CATEGORY_PAYMENT.equals(category)) { + boolean preferForeground = false; + try { + preferForeground = Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.NFC_PAYMENT_FOREGROUND) != 0; + } catch (SettingNotFoundException e) { + } + return preferForeground; + } else { + // Allowed for all other categories + return true; + } + } + + /** * Returns the service selection mode for the passed in category. * Valid return values are: * <p>{@link #SELECTION_MODE_PREFER_DEFAULT} the user has requested a default @@ -269,7 +298,6 @@ public final class CardEmulation { return SELECTION_MODE_ALWAYS_ASK; } } else { - // All other categories are in "only ask if conflict" mode return SELECTION_MODE_ASK_IF_CONFLICT; } } @@ -283,7 +311,7 @@ public final class CardEmulation { * that AID group will be replaced with this one. * * <p>Note that you can only register AIDs for a service that - * is running under the same UID as you are. Typically + * is running under the same UID as the caller of this API. Typically * this means you need to call this from the same * package as the service itself, though UIDs can also * be shared between packages using shared UIDs. @@ -352,7 +380,7 @@ public final class CardEmulation { * method. It will *not* remove AID groups that were statically registered in * the manifest. If a dynamically registered AID group is removed using * this method, and a statically registered AID group for the same category - * exists in the manifest, that AID group will become active again. + * exists in the manifest, the static AID group will become active again. * * @param service The component name of the service * @param category The category of the AID group to be removed, e.g. {@link #CATEGORY_PAYMENT} @@ -378,6 +406,96 @@ public final class CardEmulation { } /** + * Allows a foreground application to specify which card emulation service + * should be preferred while a specific Activity is in the foreground. + * + * <p>The specified Activity must currently be in resumed state. A good + * paradigm is to call this method in your {@link Activity#onResume}, and to call + * {@link #unsetPreferredService(Activity)} in your {@link Activity#onPause}. + * + * <p>This method call will fail in two specific scenarios: + * <ul> + * <li> If the service registers one or more AIDs in the {@link #CATEGORY_PAYMENT} + * category, but the user has indicated that foreground apps are not allowed + * to override the default payment service. + * <li> If the service registers one or more AIDs in the {@link #CATEGORY_OTHER} + * category that are also handled by the default payment service, and the + * user has indicated that foreground apps are not allowed to override the + * default payment service. + * </ul> + * + * <p> Use {@link #categoryAllowsForegroundPreference(String)} to determine + * whether foreground apps can override the default payment service. + * + * <p>Note that this preference is not persisted by the OS, and hence must be + * called every time the Activity is resumed. + * + * @param activity The activity which prefers this service to be invoked + * @param service The service to be preferred while this activity is in the foreground + * @return whether the registration was successful + */ + public boolean setPreferredService(Activity activity, ComponentName service) { + // Verify the activity is in the foreground before calling into NfcService + if (activity == null || service == null) { + throw new NullPointerException("activity or service or category is null"); + } + if (!activity.isResumed()) { + throw new IllegalArgumentException("Activity must be resumed."); + } + try { + return sService.setPreferredService(service); + } catch (RemoteException e) { + // Try one more time + recoverService(); + if (sService == null) { + Log.e(TAG, "Failed to recover CardEmulationService."); + return false; + } + try { + return sService.setPreferredService(service); + } catch (RemoteException ee) { + Log.e(TAG, "Failed to reach CardEmulationService."); + return false; + } + } + } + + /** + * Unsets the preferred service for the specified Activity. + * + * <p>Note that the specified Activity must still be in resumed + * state at the time of this call. A good place to call this method + * is in your {@link Activity#onPause} implementation. + * + * @param activity The activity which the service was registered for + * @return true when successful + */ + public boolean unsetPreferredService(Activity activity) { + if (activity == null) { + throw new NullPointerException("activity is null"); + } + if (!activity.isResumed()) { + throw new IllegalArgumentException("Activity must be resumed."); + } + try { + return sService.unsetPreferredService(); + } catch (RemoteException e) { + // Try one more time + recoverService(); + if (sService == null) { + Log.e(TAG, "Failed to recover CardEmulationService."); + return false; + } + try { + return sService.unsetPreferredService(); + } catch (RemoteException ee) { + Log.e(TAG, "Failed to reach CardEmulationService."); + return false; + } + } + } + + /** * @hide */ public boolean setDefaultServiceForCategory(ComponentName service, String category) { diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index e78ce339d120..8b7467fa1619 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -135,7 +135,7 @@ public abstract class BatteryStats implements Parcelable { /** * Bump the version on this if the checkin format changes. */ - private static final int BATTERY_STATS_CHECKIN_VERSION = 7; + private static final int BATTERY_STATS_CHECKIN_VERSION = 8; private static final long BYTES_PER_KB = 1024; private static final long BYTES_PER_MB = 1048576; // 1024^2 diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl index 899a9586863e..cd470997184b 100644 --- a/core/java/android/os/IUserManager.aidl +++ b/core/java/android/os/IUserManager.aidl @@ -36,6 +36,7 @@ interface IUserManager { Bitmap getUserIcon(int userHandle); List<UserInfo> getUsers(boolean excludeDying); List<UserInfo> getProfiles(int userHandle, boolean enabledOnly); + UserInfo getProfileParent(int userHandle); UserInfo getUserInfo(int userHandle); boolean isRestricted(); void setGuestEnabled(boolean enable); diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index e379621d414d..312cdbefa348 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -301,7 +301,8 @@ public class UserManager { } /** - * Returns the user handle for the user that this application is running for. + * Returns the user handle for the user that the calling process is running on. + * * @return the user handle of the user making this call. * @hide */ @@ -617,7 +618,8 @@ public class UserManager { } /** - * Returns a list of UserHandles for profiles associated with this user, including this user. + * Returns a list of UserHandles for profiles associated with the user that the calling process + * is running on, including the user itself. * * @return A non-empty list of UserHandles associated with the calling user. */ @@ -638,6 +640,21 @@ public class UserManager { } /** + * Returns the parent of the profile which this method is called from + * or null if called from a user that is not a profile. + * + * @hide + */ + public UserInfo getProfileParent(int userHandle) { + try { + return mService.getProfileParent(userHandle); + } catch (RemoteException re) { + Log.w(TAG, "Could not get profile parent", re); + return null; + } + } + + /** * If the target user is a managed profile of the calling user or the caller * is itself a managed profile, then this returns a badged copy of the given * icon to be able to distinguish it from the original icon. @@ -664,7 +681,7 @@ public class UserManager { private int getBadgeResIdForUser(int userHandle) { // Return the framework-provided badge. - List<UserInfo> userProfiles = getProfiles(UserHandle.myUserId()); + List<UserInfo> userProfiles = getProfiles(getUserHandle()); for (UserInfo user : userProfiles) { if (user.id == userHandle && user.isManagedProfile()) { diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index dc618c86d58b..1847b5558f29 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -4529,6 +4529,12 @@ public final class Settings { public static final String NFC_PAYMENT_DEFAULT_COMPONENT = "nfc_payment_default_component"; /** + * Whether NFC payment is handled by the foreground application or a default. + * @hide + */ + public static final String NFC_PAYMENT_FOREGROUND = "nfc_payment_foreground"; + + /** * Specifies the package name currently configured to be the primary sms application * @hide */ diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java index 05e202bf8a7c..2d1016a68233 100644 --- a/core/java/android/view/KeyEvent.java +++ b/core/java/android/view/KeyEvent.java @@ -1685,10 +1685,6 @@ public class KeyEvent extends InputEvent implements Parcelable { case KeyEvent.KEYCODE_BRIGHTNESS_DOWN: case KeyEvent.KEYCODE_BRIGHTNESS_UP: case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK: - case KeyEvent.KEYCODE_DPAD_UP: - case KeyEvent.KEYCODE_DPAD_RIGHT: - case KeyEvent.KEYCODE_DPAD_DOWN: - case KeyEvent.KEYCODE_DPAD_LEFT: return true; } diff --git a/core/java/android/view/inputmethod/CorrectionInfo.java b/core/java/android/view/inputmethod/CorrectionInfo.java index 1b04e4980588..a43dfe89cee1 100644 --- a/core/java/android/view/inputmethod/CorrectionInfo.java +++ b/core/java/android/view/inputmethod/CorrectionInfo.java @@ -88,16 +88,15 @@ public final class CorrectionInfo implements Parcelable { /** * Used to make this class parcelable. */ - public static final Parcelable.Creator<CorrectionInfo> CREATOR - = new Parcelable.Creator<CorrectionInfo>() { - public CorrectionInfo createFromParcel(Parcel source) { - return new CorrectionInfo(source); - } - - public CorrectionInfo[] newArray(int size) { - return new CorrectionInfo[size]; - } - }; + public static final Parcelable.Creator<CorrectionInfo> CREATOR = + new Parcelable.Creator<CorrectionInfo>() { + public CorrectionInfo createFromParcel(Parcel source) { + return new CorrectionInfo(source); + } + public CorrectionInfo[] newArray(int size) { + return new CorrectionInfo[size]; + } + }; public int describeContents() { return 0; diff --git a/core/java/android/view/inputmethod/CursorAnchorInfo.aidl b/core/java/android/view/inputmethod/CursorAnchorInfo.aidl new file mode 100644 index 000000000000..2ee9edbd1b31 --- /dev/null +++ b/core/java/android/view/inputmethod/CursorAnchorInfo.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2014 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 android.view.inputmethod; + +parcelable CursorAnchorInfo; diff --git a/core/java/android/view/inputmethod/CursorAnchorInfo.java b/core/java/android/view/inputmethod/CursorAnchorInfo.java new file mode 100644 index 000000000000..92455df900b1 --- /dev/null +++ b/core/java/android/view/inputmethod/CursorAnchorInfo.java @@ -0,0 +1,449 @@ +/* + * Copyright (C) 2014 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 android.view.inputmethod; + +import android.graphics.Matrix; +import android.graphics.RectF; +import android.os.Parcel; +import android.os.Parcelable; +import android.text.Layout; +import android.view.inputmethod.SparseRectFArray.SparseRectFArrayBuilder; + +import java.util.Objects; + +/** + * Positional information about the text insertion point and characters in the composition string. + * + * <p>This class encapsulates locations of the text insertion point and the composition string in + * the screen coordinates so that IMEs can render their UI components near where the text is + * actually inserted.</p> + */ +public final class CursorAnchorInfo implements Parcelable { + private final int mSelectionStart; + private final int mSelectionEnd; + private final int mCandidatesStart; + private final int mCandidatesEnd; + + /** + * Horizontal position of the insertion marker, in the local coordinates that will be + * transformed with the transformation matrix when rendered on the screen. This should be + * calculated or compatible with {@link Layout#getPrimaryHorizontal(int)}. This can be + * {@code java.lang.Float.NaN} when no value is specified. + */ + private final float mInsertionMarkerHorizontal; + /** + * Vertical position of the insertion marker, in the local coordinates that will be + * transformed with the transformation matrix when rendered on the screen. This should be + * calculated or compatible with {@link Layout#getLineTop(int)}. This can be + * {@code java.lang.Float.NaN} when no value is specified. + */ + private final float mInsertionMarkerTop; + /** + * Vertical position of the insertion marker, in the local coordinates that will be + * transformed with the transformation matrix when rendered on the screen. This should be + * calculated or compatible with {@link Layout#getLineBaseline(int)}. This can be + * {@code java.lang.Float.NaN} when no value is specified. + */ + private final float mInsertionMarkerBaseline; + /** + * Vertical position of the insertion marker, in the local coordinates that will be + * transformed with the transformation matrix when rendered on the screen. This should be + * calculated or compatible with {@link Layout#getLineBottom(int)}. This can be + * {@code java.lang.Float.NaN} when no value is specified. + */ + private final float mInsertionMarkerBottom; + + /** + * Container of rectangular position of characters, keyed with character index in a unit of + * Java chars, in the local coordinates that will be transformed with the transformation matrix + * when rendered on the screen. + */ + private final SparseRectFArray mCharacterRects; + + /** + * Transformation matrix that is applied to any positional information of this class to + * transform local coordinates into screen coordinates. + */ + private final Matrix mMatrix; + + public CursorAnchorInfo(final Parcel source) { + mSelectionStart = source.readInt(); + mSelectionEnd = source.readInt(); + mCandidatesStart = source.readInt(); + mCandidatesEnd = source.readInt(); + mInsertionMarkerHorizontal = source.readFloat(); + mInsertionMarkerTop = source.readFloat(); + mInsertionMarkerBaseline = source.readFloat(); + mInsertionMarkerBottom = source.readFloat(); + mCharacterRects = source.readParcelable(SparseRectFArray.class.getClassLoader()); + mMatrix = new Matrix(); + mMatrix.setValues(source.createFloatArray()); + } + + /** + * Used to package this object into a {@link Parcel}. + * + * @param dest The {@link Parcel} to be written. + * @param flags The flags used for parceling. + */ + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mSelectionStart); + dest.writeInt(mSelectionEnd); + dest.writeInt(mCandidatesStart); + dest.writeInt(mCandidatesEnd); + dest.writeFloat(mInsertionMarkerHorizontal); + dest.writeFloat(mInsertionMarkerTop); + dest.writeFloat(mInsertionMarkerBaseline); + dest.writeFloat(mInsertionMarkerBottom); + dest.writeParcelable(mCharacterRects, flags); + final float[] matrixArray = new float[9]; + mMatrix.getValues(matrixArray); + dest.writeFloatArray(matrixArray); + } + + @Override + public int hashCode(){ + // TODO: Improve the hash function. + final float floatHash = mSelectionStart + mSelectionEnd + mCandidatesStart + mCandidatesEnd + + mInsertionMarkerHorizontal + mInsertionMarkerTop + mInsertionMarkerBaseline + + mInsertionMarkerBottom; + int hash = floatHash > 0 ? (int) floatHash : (int)(-floatHash); + if (mCharacterRects != null) { + hash += mCharacterRects.hashCode(); + } + hash += mMatrix.hashCode(); + return hash; + } + + @Override + public boolean equals(Object obj){ + if (obj == null) { + return false; + } + if (this == obj) { + return true; + } + if (!(obj instanceof CursorAnchorInfo)) { + return false; + } + final CursorAnchorInfo that = (CursorAnchorInfo) obj; + if (hashCode() != that.hashCode()) { + return false; + } + if (mSelectionStart != that.mSelectionStart + || mSelectionEnd != that.mSelectionEnd + || mCandidatesStart != that.mCandidatesStart + || mCandidatesEnd != that.mCandidatesEnd) { + return false; + } + if (!Objects.equals(mCharacterRects, that.mCharacterRects)) { + return false; + } + if (!Objects.equals(mMatrix, that.mMatrix)) { + return false; + } + return true; + } + + @Override + public String toString() { + return "SelectionInfo{mSelection=" + mSelectionStart + "," + mSelectionEnd + + " mCandiadtes=" + mCandidatesStart + "," + mCandidatesEnd + + " mInsertionMarkerHorizontal=" + mInsertionMarkerHorizontal + + " mInsertionMarkerTop=" + mInsertionMarkerTop + + " mInsertionMarkerBaseline=" + mInsertionMarkerBaseline + + " mInsertionMarkerBottom=" + mInsertionMarkerBottom + + " mCharacterRects=" + (mCharacterRects != null ? mCharacterRects : "null") + + " mMatrix=" + mMatrix + + "}"; + } + + /** + * Builder for {@link CursorAnchorInfo}. This class is not designed to be thread-safe. + */ + public static final class CursorAnchorInfoBuilder { + /** + * Sets the text range of the selection. Calling this can be skipped if there is no + * selection. + */ + public CursorAnchorInfoBuilder setSelectionRange(final int newStart, final int newEnd) { + mSelectionStart = newStart; + mSelectionEnd = newEnd; + return this; + } + private int mSelectionStart = -1; + private int mSelectionEnd = -1; + + /** + * Sets the text range of the composition string. Calling this can be skipped if there is + * no composition. + */ + public CursorAnchorInfoBuilder setCandidateRange(final int start, final int end) { + mCandidateStart = start; + mCandidateEnd = end; + return this; + } + private int mCandidateStart = -1; + private int mCandidateEnd = -1; + + /** + * Sets the location of the text insertion point (zero width cursor) as a rectangle in + * local coordinates. Calling this can be skipped when there is no text insertion point; + * however if there is an insertion point, editors must call this method. + * @param horizontalPosition horizontal position of the insertion marker, in the local + * coordinates that will be transformed with the transformation matrix when rendered on the + * screen. This should be calculated or compatible with + * {@link Layout#getPrimaryHorizontal(int)}. + * @param lineTop vertical position of the insertion marker, in the local coordinates that + * will be transformed with the transformation matrix when rendered on the screen. This + * should be calculated or compatible with {@link Layout#getLineTop(int)}. + * @param lineBaseline vertical position of the insertion marker, in the local coordinates + * that will be transformed with the transformation matrix when rendered on the screen. This + * should be calculated or compatible with {@link Layout#getLineBaseline(int)}. + * @param lineBottom vertical position of the insertion marker, in the local coordinates + * that will be transformed with the transformation matrix when rendered on the screen. This + * should be calculated or compatible with {@link Layout#getLineBottom(int)}. + */ + public CursorAnchorInfoBuilder setInsertionMarkerLocation( + final float horizontalPosition, final float lineTop, final float lineBaseline, + final float lineBottom){ + mInsertionMarkerHorizontal = horizontalPosition; + mInsertionMarkerTop = lineTop; + mInsertionMarkerBaseline = lineBaseline; + mInsertionMarkerBottom = lineBottom; + return this; + } + private float mInsertionMarkerHorizontal = Float.NaN; + private float mInsertionMarkerTop = Float.NaN; + private float mInsertionMarkerBaseline = Float.NaN; + private float mInsertionMarkerBottom = Float.NaN; + + /** + * Adds the bounding box of the character specified with the index. + * <p> + * Editor authors should not call this method for characters that are invisible. + * </p> + * + * @param index index of the character in Java chars units. Must be specified in + * ascending order across successive calls. + * @param leadingEdgeX x coordinate of the leading edge of the character in local + * coordinates, that is, left edge for LTR text and right edge for RTL text. + * @param leadingEdgeY y coordinate of the leading edge of the character in local + * coordinates. + * @param trailingEdgeX x coordinate of the trailing edge of the character in local + * coordinates, that is, right edge for LTR text and left edge for RTL text. + * @param trailingEdgeY y coordinate of the trailing edge of the character in local + * coordinates. + * @throws IllegalArgumentException If the index is a negative value, or not greater than + * all of the previously called indices. + */ + public CursorAnchorInfoBuilder addCharacterRect(final int index, + final float leadingEdgeX, final float leadingEdgeY, final float trailingEdgeX, + final float trailingEdgeY) { + if (index < 0) { + throw new IllegalArgumentException("index must not be a negative integer."); + } + if (mCharacterRectBuilder == null) { + mCharacterRectBuilder = new SparseRectFArrayBuilder(); + } + mCharacterRectBuilder.append(index, leadingEdgeX, leadingEdgeY, trailingEdgeX, + trailingEdgeY); + return this; + } + private SparseRectFArrayBuilder mCharacterRectBuilder = null; + + /** + * Sets the matrix that transforms local coordinates into screen coordinates. + * @param matrix transformation matrix from local coordinates into screen coordinates. null + * is interpreted as an identity matrix. + */ + public CursorAnchorInfoBuilder setMatrix(final Matrix matrix) { + if (matrix != null) { + mMatrix = matrix; + } else { + mMatrix = Matrix.IDENTITY_MATRIX; + } + return this; + } + private Matrix mMatrix = Matrix.IDENTITY_MATRIX; + + /** + * @return {@link CursorAnchorInfo} using parameters in this + * {@link CursorAnchorInfoBuilder}. + */ + public CursorAnchorInfo build() { + return new CursorAnchorInfo(this); + } + + /** + * Resets the internal state so that this instance can be reused to build another + * instance of {@link CursorAnchorInfo}. + */ + public void reset() { + mSelectionStart = -1; + mSelectionEnd = -1; + mCandidateStart = -1; + mCandidateEnd = -1; + mInsertionMarkerHorizontal = Float.NaN; + mInsertionMarkerTop = Float.NaN; + mInsertionMarkerBaseline = Float.NaN; + mInsertionMarkerBottom = Float.NaN; + mMatrix = Matrix.IDENTITY_MATRIX; + if (mCharacterRectBuilder != null) { + mCharacterRectBuilder.reset(); + } + } + } + + private CursorAnchorInfo(final CursorAnchorInfoBuilder builder) { + mSelectionStart = builder.mSelectionStart; + mSelectionEnd = builder.mSelectionEnd; + mCandidatesStart = builder.mCandidateStart; + mCandidatesEnd = builder.mCandidateEnd; + mInsertionMarkerHorizontal = builder.mInsertionMarkerHorizontal; + mInsertionMarkerTop = builder.mInsertionMarkerTop; + mInsertionMarkerBaseline = builder.mInsertionMarkerBaseline; + mInsertionMarkerBottom = builder.mInsertionMarkerBottom; + mCharacterRects = builder.mCharacterRectBuilder != null ? + builder.mCharacterRectBuilder.build() : null; + mMatrix = builder.mMatrix; + } + + /** + * Returns the index where the selection starts. + * @return -1 if there is no selection. + */ + public int getSelectionStart() { + return mSelectionStart; + } + + /** + * Returns the index where the selection ends. + * @return -1 if there is no selection. + */ + public int getSelectionEnd() { + return mSelectionEnd; + } + + /** + * Returns the index where the composition starts. + * @return -1 if there is no composition. + */ + public int getCandidatesStart() { + return mCandidatesStart; + } + + /** + * Returns the index where the composition ends. + * @return -1 if there is no composition. + */ + public int getCandidatesEnd() { + return mCandidatesEnd; + } + + /** + * Returns the horizontal start of the insertion marker, in the local coordinates that will + * be transformed with {@link #getMatrix()} when rendered on the screen. + * @return x coordinate that is compatible with {@link Layout#getPrimaryHorizontal(int)}. + * Pay special care to RTL/LTR handling. + * {@code java.lang.Float.NaN} if not specified. + * @see Layout#getPrimaryHorizontal(int) + */ + public float getInsertionMarkerHorizontal() { + return mInsertionMarkerHorizontal; + } + /** + * Returns the vertical top position of the insertion marker, in the local coordinates that + * will be transformed with {@link #getMatrix()} when rendered on the screen. + * @return y coordinate that is compatible with {@link Layout#getLineTop(int)}. + * {@code java.lang.Float.NaN} if not specified. + */ + public float getInsertionMarkerTop() { + return mInsertionMarkerTop; + } + /** + * Returns the vertical baseline position of the insertion marker, in the local coordinates + * that will be transformed with {@link #getMatrix()} when rendered on the screen. + * @return y coordinate that is compatible with {@link Layout#getLineBaseline(int)}. + * {@code java.lang.Float.NaN} if not specified. + */ + public float getInsertionMarkerBaseline() { + return mInsertionMarkerBaseline; + } + /** + * Returns the vertical bottom position of the insertion marker, in the local coordinates + * that will be transformed with {@link #getMatrix()} when rendered on the screen. + * @return y coordinate that is compatible with {@link Layout#getLineBottom(int)}. + * {@code java.lang.Float.NaN} if not specified. + */ + public float getInsertionMarkerBottom() { + return mInsertionMarkerBottom; + } + + /** + * Returns a new instance of {@link RectF} that indicates the location of the character + * specified with the index. + * <p> + * Note that coordinates are not necessarily contiguous or even monotonous, especially when + * RTL text and LTR text are mixed. + * </p> + * @param index index of the character in a Java chars. + * @return a new instance of {@link RectF} that represents the location of the character in + * local coordinates. null if the character is invisible or the application did not provide + * the location. Note that the {@code left} field can be greater than the {@code right} field + * if the character is in RTL text. + */ + // TODO: Prepare a document about the expected behavior for surrogate pairs, combining + // characters, and non-graphical chars. + public RectF getCharacterRect(final int index) { + if (mCharacterRects == null) { + return null; + } + return mCharacterRects.get(index); + } + + /** + * Returns a new instance of {@link android.graphics.Matrix} that indicates the transformation + * matrix that is to be applied other positional data in this class. + * @return a new instance (copy) of the transformation matrix. + */ + public Matrix getMatrix() { + return new Matrix(mMatrix); + } + + /** + * Used to make this class parcelable. + */ + public static final Parcelable.Creator<CursorAnchorInfo> CREATOR + = new Parcelable.Creator<CursorAnchorInfo>() { + @Override + public CursorAnchorInfo createFromParcel(Parcel source) { + return new CursorAnchorInfo(source); + } + + @Override + public CursorAnchorInfo[] newArray(int size) { + return new CursorAnchorInfo[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } +} diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 02278733d270..e1c6f522f101 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -49,6 +49,7 @@ import android.view.InputEventSender; import android.view.KeyEvent; import android.view.View; import android.view.ViewRootImpl; +import android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -321,6 +322,7 @@ public final class InputMethodManager { * The buffer to retrieve the view location in screen coordinates in {@link #updateCursor}. */ private final int[] mViewTopLeft = new int[2]; + private final CursorAnchorInfoBuilder mCursorAnchorInfoBuilder = new CursorAnchorInfoBuilder(); // ----------------------------------------------------------- @@ -1435,7 +1437,7 @@ public final class InputMethodManager { || mCurrentTextBoxAttribute == null || mCurMethod == null) { return; } - + if (mCursorSelStart != selStart || mCursorSelEnd != selEnd || mCursorCandStart != candidatesStart || mCursorCandEnd != candidatesEnd) { @@ -1556,6 +1558,31 @@ public final class InputMethodManager { } /** + * Report positional change of the text insertion point and/or characters in the composition + * string. + */ + public void updateCursorAnchorInfo(View view, final CursorAnchorInfo cursorAnchorInfo) { + if (view == null || cursorAnchorInfo == null) { + return; + } + checkFocus(); + synchronized (mH) { + if ((mServedView != view && + (mServedView == null || !mServedView.checkInputConnectionProxy(view))) + || mCurrentTextBoxAttribute == null || mCurMethod == null) { + return; + } + if (DEBUG) Log.d(TAG, "updateCursorAnchorInfo"); + + try { + mCurMethod.updateCursorAnchorInfo(cursorAnchorInfo); + } catch (RemoteException e) { + Log.w(TAG, "IME died: " + mCurId, e); + } + } + } + + /** * Call {@link InputMethodSession#appPrivateCommand(String, Bundle) * InputMethodSession.appPrivateCommand()} on the current Input Method. * @param view Optional View that is sending the command, or null if diff --git a/core/java/android/view/inputmethod/InputMethodSession.java b/core/java/android/view/inputmethod/InputMethodSession.java index 63862999519d..74fbbc7e22ad 100644 --- a/core/java/android/view/inputmethod/InputMethodSession.java +++ b/core/java/android/view/inputmethod/InputMethodSession.java @@ -165,7 +165,7 @@ public interface InputMethodSession { public void appPrivateCommand(String action, Bundle data); /** - * Toggle the soft input window. + * Toggle the soft input window. * Applications can toggle the state of the soft input window. * @param showFlags Provides additional operating flags. May be * 0 or have the {@link InputMethodManager#SHOW_IMPLICIT}, @@ -175,4 +175,14 @@ public interface InputMethodSession { * {@link InputMethodManager#HIDE_NOT_ALWAYS} bit set. */ public void toggleSoftInput(int showFlags, int hideFlags); + + /** + * This method is called when the cursor and/or the character position relevant to text input + * is changed on the screen. This is not called by default. It will only be reported if + * requested by the input method. + * + * @param cursorAnchorInfo Positional information relevant to text input, such as text + * insertion point and composition string. + */ + public void updateCursorAnchorInfo(CursorAnchorInfo cursorAnchorInfo); } diff --git a/core/java/android/view/inputmethod/SparseRectFArray.java b/core/java/android/view/inputmethod/SparseRectFArray.java new file mode 100644 index 000000000000..40cade74f864 --- /dev/null +++ b/core/java/android/view/inputmethod/SparseRectFArray.java @@ -0,0 +1,265 @@ +/* + * Copyright (C) 2014 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 android.view.inputmethod; + +import android.graphics.RectF; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Arrays; + +/** + * An implementation of SparseArray specialized for {@link android.graphics.RectF}. + * <p> + * As this is a sparse array, it represents an array of {@link RectF} most of which are null. This + * class could be in some other packages like android.graphics or android.util but currently + * belong to android.view.inputmethod because this class is hidden and used only in input method + * framework. + * </p> + * @hide + */ +public final class SparseRectFArray implements Parcelable { + /** + * The keys, in ascending order, of those {@link RectF} that are not null. For example, + * {@code [null, null, null, Rect1, null, Rect2]} would be represented by {@code [3,5]}. + * @see #mCoordinates + */ + private final int[] mKeys; + + /** + * Stores coordinates of the rectangles, in the order of + * {@code rects[mKeys[0]].left}, {@code rects[mKeys[0]].top}, + * {@code rects[mKeys[0]].right}, {@code rects[mKeys[0]].bottom}, + * {@code rects[mKeys[1]].left}, {@code rects[mKeys[1]].top}, + * {@code rects[mKeys[1]].right}, {@code rects[mKeys[1]].bottom}, + * {@code rects[mKeys[2]].left}, {@code rects[mKeys[2]].top}, .... + */ + private final float[] mCoordinates; + + public SparseRectFArray(final Parcel source) { + mKeys = source.createIntArray(); + mCoordinates = source.createFloatArray(); + } + + /** + * Used to package this object into a {@link Parcel}. + * + * @param dest The {@link Parcel} to be written. + * @param flags The flags used for parceling. + */ + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeIntArray(mKeys); + dest.writeFloatArray(mCoordinates); + } + + @Override + public int hashCode() { + // TODO: Improve the hash function. + if (mKeys == null || mKeys.length == 0) { + return 0; + } + int hash = mKeys.length; + // For performance reasons, only the first rectangle is used for the hash code now. + for (int i = 0; i < 4; i++) { + hash *= 31; + hash += mCoordinates[i]; + } + return hash; + } + + @Override + public boolean equals(Object obj){ + if (obj == null) { + return false; + } + if (this == obj) { + return true; + } + if (!(obj instanceof SparseRectFArray)) { + return false; + } + final SparseRectFArray that = (SparseRectFArray) obj; + + return Arrays.equals(mKeys, that.mKeys) && Arrays.equals(mCoordinates, that.mCoordinates); + } + + @Override + public String toString() { + if (mKeys == null || mCoordinates == null) { + return "SparseRectFArray{}"; + } + final StringBuilder sb = new StringBuilder(); + sb.append("SparseRectFArray{"); + for (int i = 0; i < mKeys.length; i++) { + if (i != 0) { + sb.append(", "); + } + final int baseIndex = i * 4; + sb.append(mKeys[i]); + sb.append(":["); + sb.append(mCoordinates[baseIndex + 0]); + sb.append(","); + sb.append(mCoordinates[baseIndex + 1]); + sb.append("],["); + sb.append(mCoordinates[baseIndex + 2]); + sb.append(","); + sb.append(mCoordinates[baseIndex + 3]); + sb.append("]"); + } + sb.append("}"); + return sb.toString(); + } + + /** + * Builder for {@link SparseRectFArray}. This class is not designed to be thread-safe. + * @hide + */ + public static final class SparseRectFArrayBuilder { + /** + * Throws {@link IllegalArgumentException} to make sure that this class is correctly used. + * @param key key to be checked. + */ + private void checkIndex(final int key) { + if (mCount == 0) { + return; + } + if (mKeys[mCount - 1] >= key) { + throw new IllegalArgumentException("key must be greater than all existing keys."); + } + } + + /** + * Extends the internal array if necessary. + */ + private void ensureBufferSize() { + if (mKeys == null) { + mKeys = new int[INITIAL_SIZE]; + } + if (mCoordinates == null) { + mCoordinates = new float[INITIAL_SIZE * 4]; + } + final int requiredIndexArraySize = mCount + 1; + if (mKeys.length <= requiredIndexArraySize) { + final int[] newArray = new int[requiredIndexArraySize * 2]; + System.arraycopy(mKeys, 0, newArray, 0, mCount); + mKeys = newArray; + } + final int requiredCoordinatesArraySize = (mCount + 1) * 4; + if (mCoordinates.length <= requiredCoordinatesArraySize) { + final float[] newArray = new float[requiredCoordinatesArraySize * 2]; + System.arraycopy(mCoordinates, 0, newArray, 0, mCount * 4); + mCoordinates = newArray; + } + } + + /** + * Puts the rectangle with an integer key. + * @param key the key to be associated with the rectangle. It must be greater than all + * existing keys that have been previously specified. + * @param left left of the rectangle. + * @param top top of the rectangle. + * @param right right of the rectangle. + * @param bottom bottom of the rectangle. + * @return the receiver object itself for chaining method calls. + * @throws IllegalArgumentException If the index is not greater than all of existing keys. + */ + public SparseRectFArrayBuilder append(final int key, + final float left, final float top, final float right, final float bottom) { + checkIndex(key); + ensureBufferSize(); + final int baseCoordinatesIndex = mCount * 4; + mCoordinates[baseCoordinatesIndex + 0] = left; + mCoordinates[baseCoordinatesIndex + 1] = top; + mCoordinates[baseCoordinatesIndex + 2] = right; + mCoordinates[baseCoordinatesIndex + 3] = bottom; + mKeys[mCount] = key; + ++mCount; + return this; + } + private int mCount = 0; + private int[] mKeys = null; + private float[] mCoordinates = null; + private static int INITIAL_SIZE = 16; + + /** + * @return {@link SparseRectFArray} using parameters in this {@link SparseRectFArray}. + */ + public SparseRectFArray build() { + return new SparseRectFArray(this); + } + + public void reset() { + if (mCount == 0) { + mKeys = null; + mCoordinates = null; + } + mCount = 0; + } + } + + private SparseRectFArray(final SparseRectFArrayBuilder builder) { + if (builder.mCount == 0) { + mKeys = null; + mCoordinates = null; + } else { + mKeys = new int[builder.mCount]; + mCoordinates = new float[builder.mCount * 4]; + System.arraycopy(builder.mKeys, 0, mKeys, 0, builder.mCount); + System.arraycopy(builder.mCoordinates, 0, mCoordinates, 0, builder.mCount * 4); + } + } + + public RectF get(final int index) { + if (mKeys == null) { + return null; + } + if (index < 0) { + return null; + } + final int arrayIndex = Arrays.binarySearch(mKeys, index); + if (arrayIndex < 0) { + return null; + } + final int baseCoordIndex = arrayIndex * 4; + return new RectF(mCoordinates[baseCoordIndex], + mCoordinates[baseCoordIndex + 1], + mCoordinates[baseCoordIndex + 2], + mCoordinates[baseCoordIndex + 3]); + } + + /** + * Used to make this class parcelable. + */ + public static final Parcelable.Creator<SparseRectFArray> CREATOR = + new Parcelable.Creator<SparseRectFArray>() { + @Override + public SparseRectFArray createFromParcel(Parcel source) { + return new SparseRectFArray(source); + } + @Override + public SparseRectFArray[] newArray(int size) { + return new SparseRectFArray[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } +} + diff --git a/core/java/android/webkit/EventLogTags.logtags b/core/java/android/webkit/EventLogTags.logtags index b0b5493ee547..a90aebd71716 100644 --- a/core/java/android/webkit/EventLogTags.logtags +++ b/core/java/android/webkit/EventLogTags.logtags @@ -8,3 +8,4 @@ option java_package android.webkit; # 70103- used by the browser app itself 70150 browser_snap_center +70151 exp_det_attempt_to_call_object_getclass (app_signature|3) diff --git a/core/java/android/webkit/PermissionRequest.java b/core/java/android/webkit/PermissionRequest.java index 3e334984ea9f..fa760b77cc37 100644 --- a/core/java/android/webkit/PermissionRequest.java +++ b/core/java/android/webkit/PermissionRequest.java @@ -28,6 +28,7 @@ import android.net.Uri; public interface PermissionRequest { /** * Resource belongs to geolocation service. + * @hide - see b/14668406 */ public final static long RESOURCE_GEOLOCATION = 1 << 0; /** diff --git a/core/java/com/android/internal/view/IInputMethodSession.aidl b/core/java/com/android/internal/view/IInputMethodSession.aidl index 90210ce9866c..367b713ed78f 100644 --- a/core/java/com/android/internal/view/IInputMethodSession.aidl +++ b/core/java/com/android/internal/view/IInputMethodSession.aidl @@ -21,6 +21,7 @@ import android.os.Bundle; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.inputmethod.CompletionInfo; +import android.view.inputmethod.CursorAnchorInfo; import android.view.inputmethod.ExtractedText; /** @@ -47,4 +48,6 @@ oneway interface IInputMethodSession { void toggleSoftInput(int showFlags, int hideFlags); void finishSession(); + + void updateCursorAnchorInfo(in CursorAnchorInfo cursorAnchorInfo); } diff --git a/core/tests/inputmethodtests/run_core_inputmethod_test.sh b/core/tests/inputmethodtests/run_core_inputmethod_test.sh index 9029ba5c3f39..e0f4f6d4303a 100755 --- a/core/tests/inputmethodtests/run_core_inputmethod_test.sh +++ b/core/tests/inputmethodtests/run_core_inputmethod_test.sh @@ -21,4 +21,4 @@ if [[ $rebuild == true ]]; then $COMMAND fi -adb shell am instrument -w -e class android.os.InputMethodTest,android.os.InputMethodSubtypeArrayTest,android.os.InputMethodSubtypeSwitchingControllerTest com.android.frameworks.coretests.inputmethod/android.test.InstrumentationTestRunner +adb shell am instrument -w -e class android.os.InputMethodTest,android.os.InputMethodSubtypeArrayTest,android.os.InputMethodSubtypeSwitchingControllerTest,android.os.CursorAnchorInfoTest,android.os.SparseRectFArrayTest com.android.frameworks.coretests.inputmethod/android.test.InstrumentationTestRunner diff --git a/core/tests/inputmethodtests/src/android/os/CursorAnchorInfoTest.java b/core/tests/inputmethodtests/src/android/os/CursorAnchorInfoTest.java new file mode 100644 index 000000000000..59a63144c954 --- /dev/null +++ b/core/tests/inputmethodtests/src/android/os/CursorAnchorInfoTest.java @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2014 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 android.os; + +import android.graphics.Matrix; +import android.graphics.RectF; +import android.test.InstrumentationTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import android.view.inputmethod.CursorAnchorInfo; +import android.view.inputmethod.CursorAnchorInfo.CursorAnchorInfoBuilder; + +public class CursorAnchorInfoTest extends InstrumentationTestCase { + // null represents a character that is invisible, for example because it's overlapped by some + // other UI elements. + private static final RectF[] MANY_RECTS = new RectF[] { + null, + new RectF(102.0f, 202.0f, 302.0f, 402.0f), + new RectF(103.0f, 203.0f, 303.0f, 403.0f), + new RectF(104.0f, 204.0f, 304.0f, 404.0f), + new RectF(105.0f, 205.0f, 305.0f, 405.0f), + new RectF(106.0f, 206.0f, 306.0f, 406.0f), + null, + new RectF(108.0f, 208.0f, 308.0f, 408.0f), + new RectF(109.0f, 209.0f, 309.0f, 409.0f), + new RectF(110.0f, 210.0f, 310.0f, 410.0f), + new RectF(111.0f, 211.0f, 311.0f, 411.0f), + new RectF(112.0f, 212.0f, 312.0f, 412.0f), + new RectF(113.0f, 213.0f, 313.0f, 413.0f), + new RectF(114.0f, 214.0f, 314.0f, 414.0f), + new RectF(115.0f, 215.0f, 315.0f, 415.0f), + new RectF(116.0f, 216.0f, 316.0f, 416.0f), + new RectF(117.0f, 217.0f, 317.0f, 417.0f), + null, + null, + }; + + @SmallTest + public void testBuilder() throws Exception { + final int SELECTION_START = 30; + final int SELECTION_END = 40; + final int CANDIDATES_START = 32; + final int CANDIDATES_END = 33; + final float INSERTION_MARKER_HORIZONTAL = 10.5f; + final float INSERTION_MARKER_TOP = 100.1f; + final float INSERTION_MARKER_BASELINE = 110.4f; + final float INSERTION_MARKER_BOTOM = 111.0f; + Matrix TRANSFORM_MATRIX = new Matrix(Matrix.IDENTITY_MATRIX); + TRANSFORM_MATRIX.setScale(10.0f, 20.0f); + + final CursorAnchorInfoBuilder builder = new CursorAnchorInfoBuilder(); + builder.setSelectionRange(SELECTION_START, SELECTION_END) + .setCandidateRange(CANDIDATES_START, CANDIDATES_END) + .setInsertionMarkerLocation(INSERTION_MARKER_HORIZONTAL, INSERTION_MARKER_TOP, + INSERTION_MARKER_BASELINE, INSERTION_MARKER_BOTOM) + .setMatrix(TRANSFORM_MATRIX); + for (int i = 0; i < MANY_RECTS.length; i++) { + final RectF rect = MANY_RECTS[i]; + if (rect != null) { + builder.addCharacterRect(i, rect.left, rect.top, rect.right, rect.bottom); + } + } + + final CursorAnchorInfo info = builder.build(); + assertEquals(SELECTION_START, info.getSelectionStart()); + assertEquals(SELECTION_END, info.getSelectionEnd()); + assertEquals(CANDIDATES_START, info.getCandidatesStart()); + assertEquals(CANDIDATES_END, info.getCandidatesEnd()); + assertEquals(INSERTION_MARKER_HORIZONTAL, info.getInsertionMarkerHorizontal()); + assertEquals(INSERTION_MARKER_TOP, info.getInsertionMarkerTop()); + assertEquals(INSERTION_MARKER_BASELINE, info.getInsertionMarkerBaseline()); + assertEquals(INSERTION_MARKER_BOTOM, info.getInsertionMarkerBottom()); + assertEquals(TRANSFORM_MATRIX, info.getMatrix()); + for (int i = 0; i < MANY_RECTS.length; i++) { + final RectF rect = MANY_RECTS[i]; + assertEquals(rect, info.getCharacterRect(i)); + } + + // Make sure that the builder can reproduce the same object. + final CursorAnchorInfo info2 = builder.build(); + assertEquals(SELECTION_START, info2.getSelectionStart()); + assertEquals(SELECTION_END, info2.getSelectionEnd()); + assertEquals(CANDIDATES_START, info2.getCandidatesStart()); + assertEquals(CANDIDATES_END, info2.getCandidatesEnd()); + assertEquals(INSERTION_MARKER_HORIZONTAL, info2.getInsertionMarkerHorizontal()); + assertEquals(INSERTION_MARKER_TOP, info2.getInsertionMarkerTop()); + assertEquals(INSERTION_MARKER_BASELINE, info2.getInsertionMarkerBaseline()); + assertEquals(INSERTION_MARKER_BOTOM, info2.getInsertionMarkerBottom()); + assertEquals(TRANSFORM_MATRIX, info2.getMatrix()); + for (int i = 0; i < MANY_RECTS.length; i++) { + final RectF rect = MANY_RECTS[i]; + assertEquals(rect, info2.getCharacterRect(i)); + } + assertEquals(info, info2); + assertEquals(info.hashCode(), info2.hashCode()); + + // Make sure that object can be marshalled via {@link Parsel}. + final CursorAnchorInfo info3 = cloneViaParcel(info2); + assertEquals(SELECTION_START, info3.getSelectionStart()); + assertEquals(SELECTION_END, info3.getSelectionEnd()); + assertEquals(CANDIDATES_START, info3.getCandidatesStart()); + assertEquals(CANDIDATES_END, info3.getCandidatesEnd()); + assertEquals(INSERTION_MARKER_HORIZONTAL, info3.getInsertionMarkerHorizontal()); + assertEquals(INSERTION_MARKER_TOP, info3.getInsertionMarkerTop()); + assertEquals(INSERTION_MARKER_BASELINE, info3.getInsertionMarkerBaseline()); + assertEquals(INSERTION_MARKER_BOTOM, info3.getInsertionMarkerBottom()); + assertEquals(TRANSFORM_MATRIX, info3.getMatrix()); + for (int i = 0; i < MANY_RECTS.length; i++) { + final RectF rect = MANY_RECTS[i]; + assertEquals(rect, info3.getCharacterRect(i)); + } + assertEquals(info.hashCode(), info3.hashCode()); + + builder.reset(); + final CursorAnchorInfo uninitializedInfo = builder.build(); + assertEquals(-1, uninitializedInfo.getSelectionStart()); + assertEquals(-1, uninitializedInfo.getSelectionEnd()); + assertEquals(-1, uninitializedInfo.getCandidatesStart()); + assertEquals(-1, uninitializedInfo.getCandidatesEnd()); + assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerHorizontal()); + assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerTop()); + assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerBaseline()); + assertEquals(Float.NaN, uninitializedInfo.getInsertionMarkerBottom()); + assertEquals(Matrix.IDENTITY_MATRIX, uninitializedInfo.getMatrix()); + } + + @SmallTest + public void testBuilderAdd() throws Exception { + // A negative index should be rejected. + try { + new CursorAnchorInfoBuilder().addCharacterRect(-1, 0.0f, 0.0f, 0.0f, 0.0f); + } catch (IllegalArgumentException ex) { + assertTrue(true); + } + } + + private static CursorAnchorInfo cloneViaParcel(final CursorAnchorInfo src) { + Parcel parcel = null; + try { + parcel = Parcel.obtain(); + src.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + return new CursorAnchorInfo(parcel); + } finally { + if (parcel != null) { + parcel.recycle(); + } + } + } +} + diff --git a/core/tests/inputmethodtests/src/android/os/SparseRectFArrayTest.java b/core/tests/inputmethodtests/src/android/os/SparseRectFArrayTest.java new file mode 100644 index 000000000000..fae7230ac6ca --- /dev/null +++ b/core/tests/inputmethodtests/src/android/os/SparseRectFArrayTest.java @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2014 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 android.os; + +import android.graphics.RectF; +import android.test.InstrumentationTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import android.view.inputmethod.SparseRectFArray; +import android.view.inputmethod.SparseRectFArray.SparseRectFArrayBuilder; + +import java.util.Objects; + +public class SparseRectFArrayTest extends InstrumentationTestCase { + // A test data for {@link SparseRectFArray}. null represents the gap of indices. + private static final RectF[] MANY_RECTS = new RectF[] { + null, + new RectF(102.0f, 202.0f, 302.0f, 402.0f), + new RectF(103.0f, 203.0f, 303.0f, 403.0f), + new RectF(104.0f, 204.0f, 304.0f, 404.0f), + new RectF(105.0f, 205.0f, 305.0f, 405.0f), + new RectF(106.0f, 206.0f, 306.0f, 406.0f), + null, + new RectF(108.0f, 208.0f, 308.0f, 408.0f), + new RectF(109.0f, 209.0f, 309.0f, 409.0f), + new RectF(110.0f, 210.0f, 310.0f, 410.0f), + new RectF(111.0f, 211.0f, 311.0f, 411.0f), + new RectF(112.0f, 212.0f, 312.0f, 412.0f), + new RectF(113.0f, 213.0f, 313.0f, 413.0f), + new RectF(114.0f, 214.0f, 314.0f, 414.0f), + new RectF(115.0f, 215.0f, 315.0f, 415.0f), + new RectF(116.0f, 216.0f, 316.0f, 416.0f), + new RectF(117.0f, 217.0f, 317.0f, 417.0f), + null, + null, + new RectF(118.0f, 218.0f, 318.0f, 418.0f), + }; + + @SmallTest + public void testBuilder() throws Exception { + final RectF TEMP_RECT = new RectF(10.0f, 20.0f, 30.0f, 40.0f); + + final SparseRectFArrayBuilder builder = new SparseRectFArrayBuilder(); + builder.append(100, TEMP_RECT.left, TEMP_RECT.top, TEMP_RECT.right, TEMP_RECT.bottom); + assertNull(builder.build().get(-1)); + assertNull(builder.build().get(0)); + assertNull(builder.build().get(99)); + assertEquals(TEMP_RECT, builder.build().get(100)); + assertNull(builder.build().get(101)); + + // Test if {@link SparseRectFArrayBuilder#reset} resets its internal state. + builder.reset(); + assertNull(builder.build().get(100)); + + builder.reset(); + for (int i = 0; i < MANY_RECTS.length; i++) { + final RectF rect = MANY_RECTS[i]; + if (rect != null) { + builder.append(i, rect.left, rect.top, rect.right, rect.bottom); + } + } + final SparseRectFArray array = builder.build(); + for (int i = 0; i < MANY_RECTS.length; i++) { + final RectF rect = MANY_RECTS[i]; + assertEquals(rect, array.get(i)); + } + + // Make sure the builder reproduces an equivalent object. + final SparseRectFArray array2 = builder.build(); + for (int i = 0; i < MANY_RECTS.length; i++) { + final RectF rect = MANY_RECTS[i]; + assertEquals(rect, array2.get(i)); + } + assertEqualRects(array, array2); + + // Make sure the instance can be marshaled via {@link Parcel}. + final SparseRectFArray array3 = cloneViaParcel(array); + for (int i = 0; i < MANY_RECTS.length; i++) { + final RectF rect = MANY_RECTS[i]; + assertEquals(rect, array3.get(i)); + } + assertEqualRects(array, array3); + + // Make sure the builder can be reset. + builder.reset(); + assertNull(builder.build().get(0)); + } + + @SmallTest + public void testEquality() throws Exception { + // Empty array should be equal. + assertEqualRects(new SparseRectFArrayBuilder().build(), + new SparseRectFArrayBuilder().build()); + + assertEqualRects( + new SparseRectFArrayBuilder().append(100, 1.0f, 2.0f, 3.0f, 4.0f).build(), + new SparseRectFArrayBuilder().append(100, 1.0f, 2.0f, 3.0f, 4.0f).build()); + assertNotEqualRects( + new SparseRectFArrayBuilder().append(100, 1.0f, 2.0f, 3.0f, 4.0f).build(), + new SparseRectFArrayBuilder().append(100, 2.0f, 2.0f, 3.0f, 4.0f).build()); + assertNotEqualRects( + new SparseRectFArrayBuilder().append(100, 1.0f, 2.0f, 3.0f, 4.0f).build(), + new SparseRectFArrayBuilder().append(101, 1.0f, 2.0f, 3.0f, 4.0f).build()); + + assertEqualRects( + new SparseRectFArrayBuilder() + .append(100, 1.0f, 2.0f, 3.0f, 4.0f) + .append(101, 0.0f, 0.0f, 0.0f, 0.0f).build(), + new SparseRectFArrayBuilder() + .append(100, 1.0f, 2.0f, 3.0f, 4.0f) + .append(101, 0.0f, 0.0f, 0.0f, 0.0f).build()); + assertNotEqualRects( + new SparseRectFArrayBuilder() + .append(100, 1.0f, 2.0f, 3.0f, 4.0f).build(), + new SparseRectFArrayBuilder() + .append(100, 1.0f, 2.0f, 3.0f, 4.0f) + .append(101, 0.0f, 0.0f, 0.0f, 0.0f).build()); + assertNotEqualRects( + new SparseRectFArrayBuilder() + .append(100, 1.0f, 2.0f, 3.0f, 4.0f) + .append(101, 0.0f, 0.0f, 0.0f, 0.0f).build(), + new SparseRectFArrayBuilder() + .append(100, 1.0f, 2.0f, 3.0f, 4.0f).build()); + assertNotEqualRects( + new SparseRectFArrayBuilder() + .append(100, 1.0f, 2.0f, 3.0f, 4.0f) + .append(101, 0.0f, 0.0f, 0.0f, 0.0f).build(), + new SparseRectFArrayBuilder() + .append(100, 1.0f, 2.0f, 3.0f, 4.0f) + .append(101, 1.0f, 0.0f, 0.0f, 0.0f).build()); + assertNotEqualRects( + new SparseRectFArrayBuilder() + .append(100, 1.0f, 2.0f, 3.0f, 4.0f) + .append(101, 1.0f, 0.0f, 0.0f, 0.0f).build(), + new SparseRectFArrayBuilder() + .append(100, 1.0f, 2.0f, 3.0f, 4.0f) + .append(101, 0.0f, 0.0f, 0.0f, 0.0f).build()); + assertNotEqualRects( + new SparseRectFArrayBuilder() + .append(100, 1.0f, 2.0f, 3.0f, 4.0f) + .append(101, 0.0f, 0.0f, 0.0f, 0.0f).build(), + new SparseRectFArrayBuilder() + .append(100, 1.0f, 2.0f, 3.0f, 4.0f) + .append(102, 0.0f, 0.0f, 0.0f, 0.0f).build()); + + assertEqualRects( + new SparseRectFArrayBuilder() + .append(1, 1.0f, 2.0f, 3.0f, 4.0f) + .append(1000, 0.0f, 0.0f, 0.0f, 0.0f) + .append(100000000, 0.0f, 0.0f, 0.0f, 0.0f) + .build(), + new SparseRectFArrayBuilder() + .append(1, 1.0f, 2.0f, 3.0f, 4.0f) + .append(1000, 0.0f, 0.0f, 0.0f, 0.0f) + .append(100000000, 0.0f, 0.0f, 0.0f, 0.0f) + .build()); + + assertNotEqualRects( + new SparseRectFArrayBuilder() + .append(1, 1.0f, 2.0f, 3.0f, 4.0f) + .append(1000, 0.0f, 0.0f, 0.0f, 0.0f) + .append(100000000, 0.0f, 0.0f, 0.0f, 0.0f) + .build(), + new SparseRectFArrayBuilder() + .append(1, 1.0f, 2.0f, 3.0f, 4.0f) + .build()); + assertNotEqualRects( + new SparseRectFArrayBuilder() + .append(1, 1.0f, 2.0f, 3.0f, 4.0f) + .append(1000, 0.0f, 0.0f, 0.0f, 0.0f) + .append(100000000, 0.0f, 0.0f, 0.0f, 0.0f) + .build(), + new SparseRectFArrayBuilder() + .append(1, 1.0f, 2.0f, 3.0f, 4.0f) + .append(1000, 1.0f, 0.0f, 0.0f, 0.0f) + .append(100000000, 0.0f, 0.0f, 0.0f, 0.0f) + .build()); + } + + @SmallTest + public void testBuilderAppend() throws Exception { + // Key should be appended in ascending order. + try { + new SparseRectFArrayBuilder().append(10, 0, 0, 0, 0).append(0, 1, 2, 3, 4); + } catch (IllegalArgumentException ex) { + assertTrue(true); + } + + try { + new SparseRectFArrayBuilder().append(10, 0, 0, 0, 0).append(10, 1, 2, 3, 4); + } catch (IllegalArgumentException ex) { + assertTrue(true); + } + } + + private static void assertEqualRects(SparseRectFArray a, SparseRectFArray b) { + assertEquals(a, b); + if (a != null && b != null) { + assertEquals(a.hashCode(), b.hashCode()); + } + } + + private static void assertNotEqualRects(SparseRectFArray a, SparseRectFArray b) { + assertFalse(Objects.equals(a, b)); + } + + private static SparseRectFArray cloneViaParcel(final SparseRectFArray src) { + Parcel parcel = null; + try { + parcel = Parcel.obtain(); + src.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + return new SparseRectFArray(parcel); + } finally { + if (parcel != null) { + parcel.recycle(); + } + } + } +} diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index 0c8a823d8792..724022b2411b 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -149,6 +149,7 @@ public class AudioService extends IAudioService.Stub { private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 18; private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 19; private static final int MSG_UNLOAD_SOUND_EFFECTS = 20; + private static final int MSG_SYSTEM_READY = 21; // start of messages handled under wakelock // these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(), // and not with sendMsg(..., ..., SENDMSG_QUEUE, ...) @@ -370,7 +371,7 @@ public class AudioService extends IAudioService.Stub { private int mScoConnectionState; // true if boot sequence has been completed - private boolean mBootCompleted; + private boolean mSystemReady; // listener for SoundPool sample load completion indication private SoundPoolCallback mSoundPoolCallBack; // thread for SoundPool listener @@ -525,7 +526,6 @@ public class AudioService extends IAudioService.Stub { intentFilter.addAction(Intent.ACTION_DOCK_EVENT); intentFilter.addAction(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG); intentFilter.addAction(Intent.ACTION_USB_AUDIO_DEVICE_PLUG); - intentFilter.addAction(Intent.ACTION_BOOT_COMPLETED); intentFilter.addAction(Intent.ACTION_SCREEN_ON); intentFilter.addAction(Intent.ACTION_SCREEN_OFF); intentFilter.addAction(Intent.ACTION_USER_SWITCHED); @@ -559,6 +559,43 @@ public class AudioService extends IAudioService.Stub { } + public void systemReady() { + sendMsg(mAudioHandler, MSG_SYSTEM_READY, SENDMSG_QUEUE, + 0, 0, null, 0); + } + + public void onSystemReady() { + mSystemReady = true; + sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, + 0, 0, null, 0); + + mKeyguardManager = + (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE); + mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR; + resetBluetoothSco(); + getBluetoothHeadset(); + //FIXME: this is to maintain compatibility with deprecated intent + // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate. + Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED); + newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, + AudioManager.SCO_AUDIO_STATE_DISCONNECTED); + sendStickyBroadcastToAll(newIntent); + + BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); + if (adapter != null) { + adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener, + BluetoothProfile.A2DP); + } + + sendMsg(mAudioHandler, + MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED, + SENDMSG_REPLACE, + 0, + 0, + null, + SAFE_VOLUME_CONFIGURE_TIMEOUT_MS); + } + private void createAudioSystemThread() { mAudioSystemThread = new AudioSystemThread(); mAudioSystemThread.start(); @@ -1996,7 +2033,7 @@ public class AudioService extends IAudioService.Stub { /** @see AudioManager#startBluetoothSco() */ public void startBluetoothSco(IBinder cb, int targetSdkVersion){ if (!checkAudioSettingsPermission("startBluetoothSco()") || - !mBootCompleted) { + !mSystemReady) { return; } ScoClient client = getScoClient(cb, true); @@ -2013,7 +2050,7 @@ public class AudioService extends IAudioService.Stub { /** @see AudioManager#stopBluetoothSco() */ public void stopBluetoothSco(IBinder cb){ if (!checkAudioSettingsPermission("stopBluetoothSco()") || - !mBootCompleted) { + !mSystemReady) { return; } ScoClient client = getScoClient(cb, false); @@ -3277,7 +3314,7 @@ public class AudioService extends IAudioService.Stub { int status; synchronized (mSoundEffectsLock) { - if (!mBootCompleted) { + if (!mSystemReady) { Log.w(TAG, "onLoadSoundEffects() called before boot complete"); return false; } @@ -3700,6 +3737,10 @@ public class AudioService extends IAudioService.Stub { case MSG_BROADCAST_BT_CONNECTION_STATE: onBroadcastScoConnectionState(msg.arg1); break; + + case MSG_SYSTEM_READY: + onSystemReady(); + break; } } } @@ -4169,36 +4210,6 @@ public class AudioService extends IAudioService.Stub { newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState); sendStickyBroadcastToAll(newIntent); } - } else if (action.equals(Intent.ACTION_BOOT_COMPLETED)) { - mBootCompleted = true; - sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, - 0, 0, null, 0); - - mKeyguardManager = - (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE); - mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR; - resetBluetoothSco(); - getBluetoothHeadset(); - //FIXME: this is to maintain compatibility with deprecated intent - // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate. - Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED); - newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, - AudioManager.SCO_AUDIO_STATE_DISCONNECTED); - sendStickyBroadcastToAll(newIntent); - - BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); - if (adapter != null) { - adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener, - BluetoothProfile.A2DP); - } - - sendMsg(mAudioHandler, - MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED, - SENDMSG_REPLACE, - 0, - 0, - null, - SAFE_VOLUME_CONFIGURE_TIMEOUT_MS); } else if (action.equals(Intent.ACTION_SCREEN_ON)) { AudioSystem.setParameters("screen_state=on"); } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-hdpi/ic_notify_clear_normal.png Binary files differdeleted file mode 100644 index 54dde8216825..000000000000 --- a/packages/SystemUI/res/drawable-hdpi/ic_notify_clear_normal.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notify_open_normal.png b/packages/SystemUI/res/drawable-hdpi/ic_notify_open_normal.png Binary files differdeleted file mode 100644 index 3c0dc4e00b5b..000000000000 --- a/packages/SystemUI/res/drawable-hdpi/ic_notify_open_normal.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_notify_clear_normal.png Binary files differdeleted file mode 100644 index c526433fd2f4..000000000000 --- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_notify_clear_normal.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_notify_clear_normal.png Binary files differdeleted file mode 100644 index d13bc69c4baa..000000000000 --- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_notify_clear_normal.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_notify_clear_normal.png Binary files differdeleted file mode 100644 index a137a80e866a..000000000000 --- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_notify_clear_normal.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_notify_clear_normal.png Binary files differdeleted file mode 100644 index 8da79450caec..000000000000 --- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_notify_clear_normal.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_clear_normal.png Binary files differdeleted file mode 100644 index 7cb52e3fc867..000000000000 --- a/packages/SystemUI/res/drawable-mdpi/ic_notify_clear_normal.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_open_normal.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_open_normal.png Binary files differdeleted file mode 100644 index 8010ce7e2e59..000000000000 --- a/packages/SystemUI/res/drawable-mdpi/ic_notify_open_normal.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_clear_normal.png Binary files differdeleted file mode 100644 index b9afa444b902..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/ic_notify_clear_normal.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_open_normal.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_open_normal.png Binary files differdeleted file mode 100644 index 6d46fddcc195..000000000000 --- a/packages/SystemUI/res/drawable-xhdpi/ic_notify_open_normal.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-xxhdpi/ic_notify_clear_normal.png Binary files differdeleted file mode 100644 index afdee8fbd2a2..000000000000 --- a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_clear_normal.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_open_normal.png b/packages/SystemUI/res/drawable-xxhdpi/ic_notify_open_normal.png Binary files differdeleted file mode 100644 index 774220779087..000000000000 --- a/packages/SystemUI/res/drawable-xxhdpi/ic_notify_open_normal.png +++ /dev/null diff --git a/packages/SystemUI/res/drawable/ic_notifications.xml b/packages/SystemUI/res/drawable/ic_notifications.xml deleted file mode 100644 index 97a7623cf343..000000000000 --- a/packages/SystemUI/res/drawable/ic_notifications.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2012 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. ---> - -<selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_pressed="true" - android:drawable="@drawable/ic_notify_open_normal" /> - <item - android:drawable="@drawable/ic_notify_open_normal" /> -</selector> - diff --git a/packages/SystemUI/res/drawable/ic_notify_clear.xml b/packages/SystemUI/res/drawable/ic_notify_clear.xml deleted file mode 100644 index 21631985821e..000000000000 --- a/packages/SystemUI/res/drawable/ic_notify_clear.xml +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- 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. ---> - -<selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_pressed="true" - android:drawable="@drawable/ic_notify_clear_normal" /> - <item android:drawable="@drawable/ic_notify_clear_normal" /> -</selector> diff --git a/packages/SystemUI/res/drawable/notification_header_bg.xml b/packages/SystemUI/res/drawable/notification_header_bg.xml new file mode 100644 index 000000000000..c5ba18b584f5 --- /dev/null +++ b/packages/SystemUI/res/drawable/notification_header_bg.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2014 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 + --> + +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_pressed="true"> + <shape> + <solid android:color="#ff54656e" /> + <corners android:radius="@*android:dimen/notification_quantum_rounded_rect_radius" /> + </shape> + </item> + <item> + <shape> + <solid android:color="#ff374248" /> + <corners android:radius="@*android:dimen/notification_quantum_rounded_rect_radius" /> + </shape> + </item> +</selector>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/heads_up.xml b/packages/SystemUI/res/layout/heads_up.xml index e4954e781bbd..7d9cfa1c49f0 100644 --- a/packages/SystemUI/res/layout/heads_up.xml +++ b/packages/SystemUI/res/layout/heads_up.xml @@ -20,7 +20,7 @@ <com.android.systemui.statusbar.policy.HeadsUpNotificationView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_height="wrap_content" - android:layout_width="@dimen/notification_panel_width" + android:layout_width="match_parent" android:id="@+id/content_holder" android:background="@drawable/notification_panel_bg" />
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml index 3267c36c7ef3..5b3f365f22c4 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded.xml @@ -22,7 +22,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui" android:id="@+id/notification_panel" - android:layout_width="0dp" + android:layout_width="match_parent" android:layout_height="match_parent" > @@ -61,7 +61,7 @@ <com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer android:id="@+id/notification_container_parent" android:layout_width="match_parent" - android:layout_height="wrap_content" + android:layout_height="match_parent" android:clipToPadding="false" android:clipChildren="false"> @@ -102,6 +102,8 @@ <include layout="@layout/status_bar_expanded_header" android:layout_width="match_parent" android:layout_height="@dimen/status_bar_header_height" + android:layout_marginLeft="@dimen/notification_side_padding" + android:layout_marginRight="@dimen/notification_side_padding" /> <include diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml index 460dd4bee6d9..adfa1e4eaf72 100644 --- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml +++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml @@ -25,6 +25,7 @@ android:orientation="horizontal" android:gravity="center_vertical" android:baselineAligned="false" + android:elevation="14dp" > <View @@ -77,22 +78,4 @@ android:padding="2dp" /> - <include layout="@layout/status_bar_flip_button" - android:id="@+id/header_flipper" - android:layout_width="50dp" - android:layout_height="50dp" - android:layout_alignParentEnd="true"/> - - <ImageView android:id="@+id/clear_all_button" - android:layout_width="50dp" - android:layout_height="50dp" - android:layout_toStartOf="@id/header_flipper" - android:scaleType="center" - android:src="@drawable/ic_notify_clear" - android:background="@drawable/ic_notify_button_bg" - android:contentDescription="@string/accessibility_clear_all" - /> - - - </com.android.systemui.statusbar.phone.StatusBarHeaderView> diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml index f9b022cc8795..c29da1895b98 100644 --- a/packages/SystemUI/res/layout/super_status_bar.xml +++ b/packages/SystemUI/res/layout/super_status_bar.xml @@ -35,9 +35,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" > <include layout="@layout/status_bar_expanded" - android:layout_width="@dimen/notification_panel_width" - android:layout_height="match_parent" - android:layout_gravity="start|top" /> + style="@style/StatusBarExpanded" /> </com.android.systemui.statusbar.phone.PanelHolder> </com.android.systemui.statusbar.phone.StatusBarWindowView> diff --git a/packages/SystemUI/res/values-sw600dp/styles.xml b/packages/SystemUI/res/values-sw600dp/styles.xml index b7becac57010..1ea94429e738 100644 --- a/packages/SystemUI/res/values-sw600dp/styles.xml +++ b/packages/SystemUI/res/values-sw600dp/styles.xml @@ -18,4 +18,10 @@ <style name="BrightnessDialogContainer" parent="@style/BaseBrightnessDialogContainer"> <item name="android:layout_width">480dp</item> </style> + + <style name="StatusBarExpanded"> + <item name="android:layout_width">@dimen/notification_panel_width</item> + <item name="android:layout_height">match_parent</item> + <item name="android:layout_gravity">start|top</item> + </style> </resources> diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index 928126501571..c78ff8eec550 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -30,7 +30,6 @@ <drawable name="recents_callout_line">#99ffffff</drawable> <drawable name="notification_item_background_legacy_color">#ffaaaaaa</drawable> <drawable name="heads_up_notification_bg_pressed">#ff33B5E5</drawable> - <drawable name="notification_header_bg">#FF000000</drawable> <color name="notification_panel_scrim_color">#A0000000</color> <color name="notification_panel_scrim_color_keyguard">#80000000</color> <color name="batterymeter_frame_color">#66FFFFFF</color><!-- 40% white --> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index c6fdc16a757d..b6e6ee281393 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -196,9 +196,6 @@ <!-- Quick Settings CA Cert Warning tile geometry: gap between icon and text --> <dimen name="qs_cawarn_tile_margin_below_icon">3dp</dimen> - <!-- The width of the notification panel window: match_parent below sw600dp --> - <dimen name="notification_panel_width">-1dp</dimen> - <!-- used by DessertCase --> <dimen name="dessert_case_cell_size">192dp</dimen> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 8ab646d2f766..6608c5d1e2ce 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -171,4 +171,10 @@ <style name="systemui_theme" parent="@android:style/Theme.DeviceDefault" /> + <style name="StatusBarExpanded"> + <item name="android:layout_width">match_parent</item> + <item name="android:layout_height">match_parent</item> + <item name="android:layout_gravity">start|top</item> + </style> + </resources> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index f63ba9c3b07f..377ef9cd69de 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -144,7 +144,6 @@ public class NotificationPanelView extends PanelView implements public void setQsExpansionEnabled(boolean qsExpansionEnabled) { mQsExpansionEnabled = qsExpansionEnabled; - mHeader.setExpansionEnabled(qsExpansionEnabled); } public void closeQs() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index 92eee4e6e876..fa31b33438a4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -240,8 +240,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, String mKeyguardHotwordPhrase = ""; int mKeyguardMaxNotificationCount; View mDateTimeView; - View mClearButton; - ImageView mHeaderFlipper; // carrier/wifi label private TextView mCarrierLabel; @@ -640,11 +638,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mKeyguardBottomArea.setActivityStarter(this); mKeyguardIndicationTextView = (KeyguardIndicationTextView) mStatusBarWindow.findViewById( R.id.keyguard_indication_text); - mClearButton = mStatusBarWindow.findViewById(R.id.clear_all_button); - mClearButton.setOnClickListener(mClearButtonListener); - mClearButton.setAlpha(0f); - mClearButton.setVisibility(View.INVISIBLE); - mClearButton.setEnabled(false); mDateView = (DateView)mStatusBarWindow.findViewById(R.id.date); mDateTimeView = mNotificationPanelHeader.findViewById(R.id.datetime); @@ -653,8 +646,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mDateTimeView.setEnabled(true); } - mHeaderFlipper = (ImageView) mStatusBarWindow.findViewById(R.id.header_flipper); - if (!mNotificationPanelIsFullScreenWidth) { mNotificationPanel.setSystemUiVisibility( View.STATUS_BAR_DISABLE_NOTIFICATION_ICONS | @@ -1118,19 +1109,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, if (mNavigationBarView != null) { mNavigationBarView.setLayoutDirection(layoutDirection); } - - if (mClearButton != null && mClearButton instanceof ImageView) { - // Force asset reloading - ((ImageView)mClearButton).setImageDrawable(null); - ((ImageView)mClearButton).setImageResource(R.drawable.ic_notify_clear); - } - - if (mHeaderFlipper != null) { - // Force asset reloading - mHeaderFlipper.setImageDrawable(null); - mHeaderFlipper.setImageResource(R.drawable.ic_notify_quicksettings); - } - refreshAllStatusBarIcons(); } @@ -1301,38 +1279,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, + " any=" + any + " clearable=" + clearable); } - if (mFlipSettingsView != null - && mFlipSettingsView.getVisibility() == View.VISIBLE - && mStackScroller.getVisibility() != View.VISIBLE) { - // the flip settings panel is unequivocally showing; we should not be shown - mClearButton.setVisibility(View.INVISIBLE); - } else if (mClearButton.isShown()) { - if (clearable != (mClearButton.getAlpha() == 1.0f)) { - ObjectAnimator clearAnimation = ObjectAnimator.ofFloat( - mClearButton, "alpha", clearable ? 1.0f : 0.0f).setDuration(250); - clearAnimation.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - if (mClearButton.getAlpha() <= 0.0f) { - mClearButton.setVisibility(View.INVISIBLE); - } - } - - @Override - public void onAnimationStart(Animator animation) { - if (mClearButton.getAlpha() <= 0.0f) { - mClearButton.setVisibility(View.VISIBLE); - } - } - }); - clearAnimation.start(); - } - } else { - mClearButton.setAlpha(clearable ? 1.0f : 0.0f); - mClearButton.setVisibility(clearable ? View.VISIBLE : View.INVISIBLE); - } - mClearButton.setEnabled(clearable); - final View nlo = mStatusBarView.findViewById(R.id.notification_lights_out); final boolean showDot = (any&&!areLightsOn()); if (showDot != (nlo.getAlpha() == 1.0f)) { @@ -2449,10 +2395,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, final Context context = mContext; final Resources res = context.getResources(); - if (mClearButton instanceof TextView) { - ((TextView)mClearButton).setText(context.getText(R.string.status_bar_clear_all_button)); - } - // Update the QuickSettings container if (mQS != null) mQS.updateResources(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java index 9d33930a1746..fd53d1581d2b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java @@ -32,7 +32,6 @@ public class StatusBarHeaderView extends RelativeLayout { private boolean mExpanded; private View mBackground; - private View mFlipper; private int mCollapsedHeight; private int mExpandedHeight; @@ -45,7 +44,6 @@ public class StatusBarHeaderView extends RelativeLayout { protected void onFinishInflate() { super.onFinishInflate(); mBackground = findViewById(R.id.background); - mFlipper = findViewById(R.id.header_flipper); loadDimens(); } @@ -73,10 +71,6 @@ public class StatusBarHeaderView extends RelativeLayout { } } - public void setExpansionEnabled(boolean enabled) { - mFlipper.setVisibility(enabled ? View.VISIBLE : View.GONE); - } - public void setExpansion(float height) { if (height < mCollapsedHeight) { height = mCollapsedHeight; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index f24c1b625ea4..48c54fc7a85f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -73,8 +73,7 @@ public class StatusBarKeyguardViewManager { public void show(Bundle options) { mShowing = true; mStatusBarWindowManager.setKeyguardShowing(true); - showBouncerOrKeyguard(); - updateStates(); + reset(); } /** @@ -105,13 +104,15 @@ public class StatusBarKeyguardViewManager { * Reset the state of the view. */ public void reset() { - if (mOccluded) { - mPhoneStatusBar.hideKeyguard(); - mBouncer.hide(); - } else { - showBouncerOrKeyguard(); + if (mShowing) { + if (mOccluded) { + mPhoneStatusBar.hideKeyguard(); + mBouncer.hide(); + } else { + showBouncerOrKeyguard(); + } + updateStates(); } - updateStates(); } public void onScreenTurnedOff() { @@ -121,7 +122,6 @@ public class StatusBarKeyguardViewManager { public void onScreenTurnedOn(final IKeyguardShowCallback callback) { mScreenOn = true; - reset(); if (callback != null) { callbackAfterDraw(callback); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java index a4c9df56ac78..c2061f326a88 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java @@ -79,8 +79,9 @@ public class StatusBarWindowManager { | WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, PixelFormat.TRANSLUCENT); + mLp.width = ViewGroup.LayoutParams.MATCH_PARENT; mLp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED; - mLp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL; + mLp.gravity = Gravity.TOP; mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; mLp.setTitle("StatusBar"); mLp.packageName = mContext.getPackageName(); diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 361911219e19..4a59a8f063bf 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -38,6 +38,7 @@ import android.content.ServiceConnection; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; +import android.content.pm.UserInfo; import android.database.ContentObserver; import android.graphics.Point; import android.graphics.Rect; @@ -197,6 +198,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { private final SparseArray<UserState> mUserStates = new SparseArray<UserState>(); + private final UserManager mUserManager; + private int mCurrentUserId = UserHandle.USER_OWNER; private final LongArray mTempLongArray = new LongArray(); @@ -210,15 +213,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { return getUserStateLocked(mCurrentUserId); } - private UserState getUserStateLocked(int userId) { - UserState state = mUserStates.get(userId); - if (state == null) { - state = new UserState(userId); - mUserStates.put(userId, state); - } - return state; - } - /** * Creates a new instance. * @@ -228,6 +222,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { mContext = context; mPackageManager = mContext.getPackageManager(); mWindowManagerService = LocalServices.getService(WindowManagerInternal.class); + mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); mSecurityPolicy = new SecurityPolicy(); mMainHandler = new MainHandler(mContext.getMainLooper()); registerBroadcastReceivers(); @@ -235,11 +230,22 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { context.getContentResolver()); } + private UserState getUserStateLocked(int userId) { + UserState state = mUserStates.get(userId); + if (state == null) { + state = new UserState(userId); + mUserStates.put(userId, state); + } + return state; + } + private void registerBroadcastReceivers() { PackageMonitor monitor = new PackageMonitor() { @Override public void onSomePackagesChanged() { synchronized (mLock) { + // Only the profile parent can install accessibility services. + // Therefore we ignore packages from linked profiles. if (getChangingUserId() != mCurrentUserId) { return; } @@ -262,6 +268,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { public void onPackageRemoved(String packageName, int uid) { synchronized (mLock) { final int userId = getChangingUserId(); + // Only the profile parent can install accessibility services. + // Therefore we ignore packages from linked profiles. if (userId != mCurrentUserId) { return; } @@ -297,6 +305,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { int uid, boolean doit) { synchronized (mLock) { final int userId = getChangingUserId(); + // Only the profile parent can install accessibility services. + // Therefore we ignore packages from linked profiles. if (userId != mCurrentUserId) { return false; } @@ -359,6 +369,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { @Override public int addClient(IAccessibilityManagerClient client, int userId) { synchronized (mLock) { + // We treat calls from a profile as if made by its parent as profiles + // share the accessibility state of the parent. The call below + // performs the current profile parent resolution. final int resolvedUserId = mSecurityPolicy .resolveCallingUserIdEnforcingPermissionsLocked(userId); // If the client is from a process that runs across users such as @@ -388,6 +401,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { @Override public boolean sendAccessibilityEvent(AccessibilityEvent event, int userId) { synchronized (mLock) { + // We treat calls from a profile as if made by its parent as profiles + // share the accessibility state of the parent. The call below + // performs the current profile parent resolution.. final int resolvedUserId = mSecurityPolicy .resolveCallingUserIdEnforcingPermissionsLocked(userId); // This method does nothing for a background user. @@ -414,6 +430,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { @Override public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList(int userId) { synchronized (mLock) { + // We treat calls from a profile as if made by its parent as profiles + // share the accessibility state of the parent. The call below + // performs the current profile parent resolution. final int resolvedUserId = mSecurityPolicy .resolveCallingUserIdEnforcingPermissionsLocked(userId); // The automation service is a fake one and should not be reported @@ -435,6 +454,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { int userId) { List<AccessibilityServiceInfo> result = null; synchronized (mLock) { + // We treat calls from a profile as if made by its parent as profiles + // share the accessibility state of the parent. The call below + // performs the current profile parent resolution. final int resolvedUserId = mSecurityPolicy .resolveCallingUserIdEnforcingPermissionsLocked(userId); @@ -468,6 +490,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { public void interrupt(int userId) { CopyOnWriteArrayList<Service> services; synchronized (mLock) { + // We treat calls from a profile as if made by its parent as profiles + // share the accessibility state of the parent. The call below + // performs the current profile parent resolution. final int resolvedUserId = mSecurityPolicy .resolveCallingUserIdEnforcingPermissionsLocked(userId); // This method does nothing for a background user. @@ -491,6 +516,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { public int addAccessibilityInteractionConnection(IWindow windowToken, IAccessibilityInteractionConnection connection, int userId) throws RemoteException { synchronized (mLock) { + // We treat calls from a profile as if made by its parent as profiles + // share the accessibility state of the parent. The call below + // performs the current profile parent resolution. final int resolvedUserId = mSecurityPolicy .resolveCallingUserIdEnforcingPermissionsLocked(userId); final int windowId = sNextWindowId++; @@ -527,6 +555,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { @Override public void removeAccessibilityInteractionConnection(IWindow window) { synchronized (mLock) { + // We treat calls from a profile as if made by its parent as profiles + // share the accessibility state of the parent. The call below + // performs the current profile parent resolution. mSecurityPolicy.resolveCallingUserIdEnforcingPermissionsLocked( UserHandle.getCallingUserId()); IBinder token = window.asBinder(); @@ -675,6 +706,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { Manifest.permission.RETRIEVE_WINDOW_TOKEN, GET_WINDOW_TOKEN); synchronized (mLock) { + // We treat calls from a profile as if made by its parent as profiles + // share the accessibility state of the parent. The call below + // performs the current profile parent resolution. final int resolvedUserId = mSecurityPolicy .resolveCallingUserIdEnforcingPermissionsLocked( UserHandle.getCallingUserId()); @@ -770,7 +804,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } // Disconnect from services for the old user. - UserState oldUserState = getUserStateLocked(mCurrentUserId); + UserState oldUserState = getCurrentUserStateLocked(); oldUserState.onSwitchToAnotherUser(); // Disable the local managers for the old user. @@ -2034,6 +2068,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { @Override public List<AccessibilityWindowInfo> getWindows() { synchronized (mLock) { + // We treat calls from a profile as if made by its perent as profiles + // share the accessibility state of the parent. The call below + // performs the current profile parent resolution. final int resolvedUserId = mSecurityPolicy .resolveCallingUserIdEnforcingPermissionsLocked( UserHandle.getCallingUserId()); @@ -2062,6 +2099,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { @Override public AccessibilityWindowInfo getWindow(int windowId) { synchronized (mLock) { + // We treat calls from a profile as if made by its parent as profiles + // share the accessibility state of the parent. The call below + // performs the current profile parent resolution. final int resolvedUserId = mSecurityPolicy .resolveCallingUserIdEnforcingPermissionsLocked( UserHandle.getCallingUserId()); @@ -2092,6 +2132,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { final int resolvedWindowId; IAccessibilityInteractionConnection connection = null; synchronized (mLock) { + // We treat calls from a profile as if made by its parent as profiles + // share the accessibility state of the parent. The call below + // performs the current profile parent resolution. final int resolvedUserId = mSecurityPolicy .resolveCallingUserIdEnforcingPermissionsLocked( UserHandle.getCallingUserId()); @@ -2136,9 +2179,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { final int resolvedWindowId; IAccessibilityInteractionConnection connection = null; synchronized (mLock) { + // We treat calls from a profile as if made by its parent as profiles + // share the accessibility state of the parent. The call below + // performs the current profile parent resolution. final int resolvedUserId = mSecurityPolicy .resolveCallingUserIdEnforcingPermissionsLocked( - UserHandle.getCallingUserId()); + UserHandle.getCallingUserId()); if (resolvedUserId != mCurrentUserId) { return false; } @@ -2180,9 +2226,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { final int resolvedWindowId; IAccessibilityInteractionConnection connection = null; synchronized (mLock) { + // We treat calls from a profile as if made by its parent as profiles + // share the accessibility state of the parent. The call below + // performs the current profile parent resolution. final int resolvedUserId = mSecurityPolicy .resolveCallingUserIdEnforcingPermissionsLocked( - UserHandle.getCallingUserId()); + UserHandle.getCallingUserId()); if (resolvedUserId != mCurrentUserId) { return false; } @@ -2224,9 +2273,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { final int resolvedWindowId; IAccessibilityInteractionConnection connection = null; synchronized (mLock) { + // We treat calls from a profile as if made by its parent as profiles + // share the accessibility state of the parent. The call below + // performs the current profile parent resolution. final int resolvedUserId = mSecurityPolicy .resolveCallingUserIdEnforcingPermissionsLocked( - UserHandle.getCallingUserId()); + UserHandle.getCallingUserId()); if (resolvedUserId != mCurrentUserId) { return false; } @@ -2268,9 +2320,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { final int resolvedWindowId; IAccessibilityInteractionConnection connection = null; synchronized (mLock) { + // We treat calls from a profile as if made by its parent as profiles + // share the accessibility state of the parent. The call below + // performs the current profile parent resolution. final int resolvedUserId = mSecurityPolicy .resolveCallingUserIdEnforcingPermissionsLocked( - UserHandle.getCallingUserId()); + UserHandle.getCallingUserId()); if (resolvedUserId != mCurrentUserId) { return false; } @@ -2311,9 +2366,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { final int resolvedWindowId; IAccessibilityInteractionConnection connection = null; synchronized (mLock) { + // We treat calls from a profile as if made by its parent as profiles + // share the accessibility state of the parent. The call below + // performs the current profile parent resolution. final int resolvedUserId = mSecurityPolicy .resolveCallingUserIdEnforcingPermissionsLocked( - UserHandle.getCallingUserId()); + UserHandle.getCallingUserId()); if (resolvedUserId != mCurrentUserId) { return false; } @@ -2346,9 +2404,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { public boolean performGlobalAction(int action) { synchronized (mLock) { + // We treat calls from a profile as if made by its parent as profiles + // share the accessibility state of the parent. The call below + // performs the current profile parent resolution. final int resolvedUserId = mSecurityPolicy .resolveCallingUserIdEnforcingPermissionsLocked( - UserHandle.getCallingUserId()); + UserHandle.getCallingUserId()); if (resolvedUserId != mCurrentUserId) { return false; } @@ -3407,16 +3468,35 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { & AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT) != 0; } + private int resolveProfileParentLocked(int userId) { + if (userId != mCurrentUserId) { + final long identity = Binder.clearCallingIdentity(); + try { + UserInfo parent = mUserManager.getProfileParent(userId); + if (parent != null) { + return parent.getUserHandle().getIdentifier(); + } + } finally { + Binder.restoreCallingIdentity(identity); + } + } + return userId; + } + public int resolveCallingUserIdEnforcingPermissionsLocked(int userId) { final int callingUid = Binder.getCallingUid(); if (callingUid == 0 || callingUid == Process.SYSTEM_UID || callingUid == Process.SHELL_UID) { - return mCurrentUserId; + if (userId == UserHandle.USER_CURRENT + || userId == UserHandle.USER_CURRENT_OR_SELF) { + return mCurrentUserId; + } + return resolveProfileParentLocked(userId); } final int callingUserId = UserHandle.getUserId(callingUid); if (callingUserId == userId) { - return userId; + return resolveProfileParentLocked(userId); } if (!hasPermission(Manifest.permission.INTERACT_ACROSS_USERS) && !hasPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL)) { @@ -3673,8 +3753,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { public void onChange(boolean selfChange, Uri uri) { if (mAccessibilityEnabledUri.equals(uri)) { synchronized (mLock) { - // We will update when the automation service dies. + // Profiles share the accessibility state of the parent. Therefore, + // we are checking for changes only the parent settings. UserState userState = getCurrentUserStateLocked(); + // We will update when the automation service dies. if (userState.mUiAutomationService == null) { if (readAccessibilityEnabledSettingLocked(userState)) { onUserStateChangedLocked(userState); @@ -3683,8 +3765,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } } else if (mTouchExplorationEnabledUri.equals(uri)) { synchronized (mLock) { - // We will update when the automation service dies. + // Profiles share the accessibility state of the parent. Therefore, + // we are checking for changes only the parent settings. UserState userState = getCurrentUserStateLocked(); + // We will update when the automation service dies. if (userState.mUiAutomationService == null) { if (readTouchExplorationEnabledSettingLocked(userState)) { onUserStateChangedLocked(userState); @@ -3693,8 +3777,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } } else if (mDisplayMagnificationEnabledUri.equals(uri)) { synchronized (mLock) { - // We will update when the automation service dies. + // Profiles share the accessibility state of the parent. Therefore, + // we are checking for changes only the parent settings. UserState userState = getCurrentUserStateLocked(); + // We will update when the automation service dies. if (userState.mUiAutomationService == null) { if (readDisplayMagnificationEnabledSettingLocked(userState)) { onUserStateChangedLocked(userState); @@ -3703,8 +3789,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } } else if (mEnabledAccessibilityServicesUri.equals(uri)) { synchronized (mLock) { - // We will update when the automation service dies. + // Profiles share the accessibility state of the parent. Therefore, + // we are checking for changes only the parent settings. UserState userState = getCurrentUserStateLocked(); + // We will update when the automation service dies. if (userState.mUiAutomationService == null) { if (readEnabledAccessibilityServicesLocked(userState)) { onUserStateChangedLocked(userState); @@ -3713,8 +3801,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } } else if (mTouchExplorationGrantedAccessibilityServicesUri.equals(uri)) { synchronized (mLock) { - // We will update when the automation service dies. + // Profiles share the accessibility state of the parent. Therefore, + // we are checking for changes only the parent settings. UserState userState = getCurrentUserStateLocked(); + // We will update when the automation service dies. if (userState.mUiAutomationService == null) { if (readTouchExplorationGrantedAccessibilityServicesLocked(userState)) { onUserStateChangedLocked(userState); @@ -3723,8 +3813,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { } } else if (mEnhancedWebAccessibilityUri.equals(uri)) { synchronized (mLock) { - // We will update when the automation service dies. + // Profiles share the accessibility state of the parent. Therefore, + // we are checking for changes only the parent settings. UserState userState = getCurrentUserStateLocked(); + // We will update when the automation service dies. if (userState.mUiAutomationService == null) { if (readEnhancedWebAccessibilityEnabledChangedLocked(userState)) { onUserStateChangedLocked(userState); @@ -3739,8 +3831,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { || mDisplayInversionUri.equals(uri) || mDisplayDaltonizerUri.equals(uri)) { synchronized (mLock) { - // We will update when the automation service dies. + // Profiles share the accessibility state of the parent. Therefore, + // we are checking for changes only the parent settings. UserState userState = getCurrentUserStateLocked(); + // We will update when the automation service dies. if (userState.mUiAutomationService == null) { if (readDisplayColorAdjustmentSettingsLocked(userState)) { updateDisplayColorAdjustmentSettingsLocked(userState); diff --git a/services/core/java/com/android/server/WiredAccessoryManager.java b/services/core/java/com/android/server/WiredAccessoryManager.java index 50cfe48f69c8..c32beda8b6a4 100644 --- a/services/core/java/com/android/server/WiredAccessoryManager.java +++ b/services/core/java/com/android/server/WiredAccessoryManager.java @@ -70,6 +70,7 @@ final class WiredAccessoryManager implements WiredAccessoryCallbacks { private static final String NAME_HDMI = "hdmi"; private static final int MSG_NEW_DEVICE_STATE = 1; + private static final int MSG_SYSTEM_READY = 2; private final Object mLock = new Object(); @@ -96,19 +97,9 @@ final class WiredAccessoryManager implements WiredAccessoryCallbacks { context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack); mObserver = new WiredAccessoryObserver(); - - IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED); - filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); - context.registerReceiver(new BroadcastReceiver() { - @Override - public void onReceive(Context ctx, Intent intent) { - bootCompleted(); - } - }, - filter, null, null); } - private void bootCompleted() { + private void onSystemReady() { if (mUseDevInputEventForAudioJack) { int switchValues = 0; if (mInputManager.getSwitchState(-1, InputDevice.SOURCE_ANY, SW_HEADPHONE_INSERT) == 1) { @@ -159,6 +150,16 @@ final class WiredAccessoryManager implements WiredAccessoryCallbacks { } } + @Override + public void systemReady() { + synchronized (mLock) { + mWakeLock.acquire(); + + Message msg = mHandler.obtainMessage(MSG_SYSTEM_READY, 0, 0, null); + mHandler.sendMessage(msg); + } + } + /** * Compare the existing headset state with the new state and pass along accordingly. Note * that this only supports a single headset at a time. Inserting both a usb and jacked headset @@ -220,6 +221,11 @@ final class WiredAccessoryManager implements WiredAccessoryCallbacks { case MSG_NEW_DEVICE_STATE: setDevicesState(msg.arg1, msg.arg2, (String)msg.obj); mWakeLock.release(); + break; + case MSG_SYSTEM_READY: + onSystemReady(); + mWakeLock.release(); + break; } } }; diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 09e7e12140a7..5358c1aaca52 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -35,6 +35,7 @@ import android.app.IActivityContainerCallback; import android.appwidget.AppWidgetManager; import android.graphics.Rect; import android.os.BatteryStats; +import android.os.PersistableBundle; import android.service.voice.IVoiceInteractionSession; import android.util.ArrayMap; @@ -1327,12 +1328,14 @@ public final class ActivityManagerService extends ActivityManagerNative String host = ""; String port = ""; String exclList = ""; - String pacFileUrl = null; + String pacFileUrl = ""; if (proxy != null) { host = proxy.getHost(); port = Integer.toString(proxy.getPort()); exclList = proxy.getExclusionListAsString(); - pacFileUrl = proxy.getPacFileUrl().toString(); + if (proxy.getPacFileUrl() != null) { + pacFileUrl = proxy.getPacFileUrl().toString(); + } } synchronized (ActivityManagerService.this) { for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) { @@ -5427,22 +5430,21 @@ public final class ActivityManagerService extends ActivityManagerNative } @Override - public final void activityPaused(IBinder token) { + public final void activityPaused(IBinder token, PersistableBundle persistentState) { final long origId = Binder.clearCallingIdentity(); synchronized(this) { ActivityStack stack = ActivityRecord.getStackLocked(token); if (stack != null) { - stack.activityPausedLocked(token, false); + stack.activityPausedLocked(token, false, persistentState); } } Binder.restoreCallingIdentity(origId); } @Override - public final void activityStopped(IBinder token, Bundle icicle, Bitmap thumbnail, - CharSequence description) { - if (localLOGV) Slog.v( - TAG, "Activity stopped: token=" + token); + public final void activityStopped(IBinder token, Bundle icicle, + PersistableBundle persistentState, CharSequence description) { + if (localLOGV) Slog.v(TAG, "Activity stopped: token=" + token); // Refuse possible leaked file descriptors if (icicle != null && icicle.hasFileDescriptors()) { @@ -5454,7 +5456,7 @@ public final class ActivityManagerService extends ActivityManagerNative synchronized (this) { ActivityRecord r = ActivityRecord.isInStackLocked(token); if (r != null) { - r.task.stack.activityStoppedLocked(r, icicle, thumbnail, description); + r.task.stack.activityStoppedLocked(r, icicle, persistentState, description); } } diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index efd2b57c8bac..8391f793f4a5 100755 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -16,6 +16,7 @@ package com.android.server.am; +import android.os.PersistableBundle; import android.os.Trace; import com.android.internal.app.ResolverActivity; import com.android.server.AttributeCache; @@ -117,6 +118,7 @@ final class ActivityRecord { ProcessRecord app; // if non-null, hosting application ActivityState state; // current state we are in Bundle icicle; // last saved activity state + PersistableBundle persistentState; // last persistently saved activity state boolean frontOfTask; // is this the root activity of its task? boolean launchFailed; // set if a launched failed, to abort on 2nd try boolean haveState; // have we gotten the last activity state? diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 442da314bd60..7c29d85c70ad 100755 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -68,6 +68,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.Message; +import android.os.PersistableBundle; import android.os.RemoteException; import android.os.SystemClock; import android.os.Trace; @@ -276,7 +277,7 @@ final class ActivityStack { if (r.app != null) { mService.logAppTooSlow(r.app, r.pauseTime, "pausing " + r); } - activityPausedLocked(r.appToken, true); + activityPausedLocked(r.appToken, true, r.persistentState); } } break; case LAUNCH_TICK_MSG: { @@ -860,13 +861,15 @@ final class ActivityStack { } } - final void activityPausedLocked(IBinder token, boolean timeout) { + final void activityPausedLocked(IBinder token, boolean timeout, + PersistableBundle persistentState) { if (DEBUG_PAUSE) Slog.v( TAG, "Activity paused: token=" + token + ", timeout=" + timeout); final ActivityRecord r = isInStackLocked(token); if (r != null) { mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r); + r.persistentState = persistentState; if (mPausingActivity == r) { if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSED: " + r + (timeout ? " (due to timeout)" : " (pause complete)")); @@ -881,13 +884,14 @@ final class ActivityStack { } } - final void activityStoppedLocked(ActivityRecord r, Bundle icicle, Bitmap thumbnail, - CharSequence description) { + final void activityStoppedLocked(ActivityRecord r, Bundle icicle, + PersistableBundle persistentState, CharSequence description) { if (r.state != ActivityState.STOPPING) { Slog.i(TAG, "Activity reported stop, but no longer stopping: " + r); mHandler.removeMessages(STOP_TIMEOUT_MSG, r); return; } + r.persistentState = persistentState; if (DEBUG_SAVED_STATE) Slog.i(TAG, "Saving icicle of " + r + ": " + icicle); if (icicle != null) { // If icicle is null, this is happening due to a timeout, so we @@ -895,7 +899,7 @@ final class ActivityStack { r.icicle = icicle; r.haveState = true; r.launchCount = 0; - r.updateThumbnail(thumbnail, description); + r.updateThumbnail(null, description); } if (!r.stopped) { if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPED: " + r + " (stop complete)"); diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index ce3d853d800a..6f62a030b67c 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -1026,10 +1026,10 @@ public final class ActivityStackSupervisor implements DisplayListener { r.clearOptionsLocked(); app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken, System.identityHashCode(r), r.info, - new Configuration(mService.mConfiguration), r.compat, - r.task.voiceInteractor, app.repProcState, r.icicle, results, newIntents, - !andResume, mService.isNextTransitionForward(), profileFile, profileFd, - profileAutoStop, options); + new Configuration(mService.mConfiguration), r.compat, r.task.voiceInteractor, + app.repProcState, r.icicle, r.persistentState, results, newIntents, !andResume, + mService.isNextTransitionForward(), profileFile, profileFd, profileAutoStop, + options); if ((app.info.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) { // This may be a heavy-weight process! Note that the package diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index 54cb0352a6c7..0f5805c857d6 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -323,6 +323,10 @@ public class InputManagerService extends IInputManager.Stub mHandler.sendEmptyMessage(MSG_RELOAD_DEVICE_ALIASES); mHandler.sendEmptyMessage(MSG_UPDATE_KEYBOARD_LAYOUTS); + + if (mWiredAccessoryCallbacks != null) { + mWiredAccessoryCallbacks.systemReady(); + } } private void reloadKeyboardLayouts() { @@ -1588,6 +1592,7 @@ public class InputManagerService extends IInputManager.Stub */ public interface WiredAccessoryCallbacks { public void notifyWiredAccessoryChanged(long whenNanos, int switchValues, int switchMask); + public void systemReady(); } /** diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index fce86e88e3f5..46985874045d 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -444,7 +444,7 @@ public class NotificationManagerService extends SystemService { public static final class NotificationRecord { final StatusBarNotification sbn; - final SingleNotificationStats stats = new SingleNotificationStats(); + SingleNotificationStats stats; IBinder statusBarKey; NotificationRecord(StatusBarNotification sbn) @@ -1639,7 +1639,7 @@ public class NotificationManagerService extends SystemService { } else { old = mNotificationList.get(index); mNotificationList.set(index, r); - mUsageStats.registerUpdatedByApp(r); + mUsageStats.registerUpdatedByApp(r, old); // Make sure we don't lose the foreground service state. if (old != null) { notification.flags |= diff --git a/services/core/java/com/android/server/notification/NotificationUsageStats.java b/services/core/java/com/android/server/notification/NotificationUsageStats.java index 45ab3d3bd2e5..a60e95b12ac8 100644 --- a/services/core/java/com/android/server/notification/NotificationUsageStats.java +++ b/services/core/java/com/android/server/notification/NotificationUsageStats.java @@ -58,6 +58,7 @@ public class NotificationUsageStats { * Called when a notification has been posted. */ public synchronized void registerPostedByApp(NotificationRecord notification) { + notification.stats = new SingleNotificationStats(); notification.stats.posttimeElapsedMs = SystemClock.elapsedRealtime(); for (AggregatedStats stats : getAggregatedStatsLocked(notification)) { stats.numPostedByApp++; @@ -68,7 +69,8 @@ public class NotificationUsageStats { /** * Called when a notification has been updated. */ - public void registerUpdatedByApp(NotificationRecord notification) { + public void registerUpdatedByApp(NotificationRecord notification, NotificationRecord old) { + notification.stats = old.stats; for (AggregatedStats stats : getAggregatedStatsLocked(notification)) { stats.numUpdatedByApp++; } diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 60c6313c17e4..60212bfa5ab4 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -288,6 +288,20 @@ public class UserManagerService extends IUserManager.Stub { return users; } + @Override + public UserInfo getProfileParent(int userHandle) { + checkManageUsersPermission("get the profile parent"); + synchronized (mPackagesLock) { + UserInfo profile = getUserInfoLocked(userHandle); + int parentUserId = profile.profileGroupId; + if (parentUserId == UserInfo.NO_PROFILE_GROUP_ID) { + return null; + } else { + return getUserInfoLocked(parentUserId); + } + } + } + private boolean isProfileOf(UserInfo user, UserInfo profile) { return user.id == profile.id || (user.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID @@ -1022,17 +1036,6 @@ public class UserManagerService extends IUserManager.Stub { } } - private int getNextProfileGroupIdLocked() { - int maxGroupId = UserInfo.NO_PROFILE_GROUP_ID; - for (int i = 0; i < mUsers.size(); i++) { - UserInfo ui = mUsers.valueAt(i); - if (maxGroupId < ui.profileGroupId) { - maxGroupId = ui.profileGroupId; - } - } - return maxGroupId + 1; - } - @Override public UserInfo createProfileForUser(String name, int flags, int userId) { checkManageUsersPermission("Only the system can create users"); @@ -1049,16 +1052,16 @@ public class UserManagerService extends IUserManager.Stub { return createUserInternal(name, flags, UserHandle.USER_NULL); } - private UserInfo createUserInternal(String name, int flags, int profileId) { + private UserInfo createUserInternal(String name, int flags, int parentId) { final long ident = Binder.clearCallingIdentity(); UserInfo userInfo = null; try { synchronized (mInstallLock) { synchronized (mPackagesLock) { - UserInfo profile = null; - if (profileId != UserHandle.USER_NULL) { - profile = getUserInfoLocked(profileId); - if (profile == null) return null; + UserInfo parent = null; + if (parentId != UserHandle.USER_NULL) { + parent = getUserInfoLocked(parentId); + if (parent == null) return null; } if (isUserLimitReachedLocked()) return null; int userId = getNextAvailableIdLocked(); @@ -1071,12 +1074,12 @@ public class UserManagerService extends IUserManager.Stub { Environment.getUserSystemDirectory(userInfo.id).mkdirs(); mUsers.put(userId, userInfo); writeUserListLocked(); - if (profile != null) { - if (profile.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID) { - profile.profileGroupId = getNextProfileGroupIdLocked(); - writeUserLocked(profile); + if (parent != null) { + if (parent.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID) { + parent.profileGroupId = parent.id; + writeUserLocked(parent); } - userInfo.profileGroupId = profile.profileGroupId; + userInfo.profileGroupId = parent.profileGroupId; } writeUserLocked(userInfo); mPm.createNewUserLILPw(userId, userPath); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 4e22b2ada559..1980d1eb546a 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -130,6 +130,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private static final boolean DBG = false; final Context mContext; + final UserManager mUserManager; final PowerManager.WakeLock mWakeLock; IPowerManager mIPowerManager; @@ -209,7 +210,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { + action + " for user " + userHandle); mHandler.post(new Runnable() { public void run() { - handlePasswordExpirationNotification(getUserData(userHandle)); + handlePasswordExpirationNotification(userHandle); } }); } @@ -611,6 +612,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { */ public DevicePolicyManagerService(Context context) { mContext = context; + mUserManager = UserManager.get(mContext); mHasFeature = context.getPackageManager().hasSystemFeature( PackageManager.FEATURE_DEVICE_ADMIN); mWakeLock = ((PowerManager)context.getSystemService(Context.POWER_SERVICE)) @@ -818,6 +820,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { sendAdminCommandLocked(admin, action, null); } + /** + * Send an update to one specific admin, get notified when that admin returns a result. + */ void sendAdminCommandLocked(ActiveAdmin admin, String action, BroadcastReceiver result) { Intent intent = new Intent(action); intent.setComponent(admin.info.getComponent()); @@ -832,12 +837,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + /** + * Send an update to all admins of a user that enforce a specified policy. + */ void sendAdminCommandLocked(String action, int reqPolicy, int userHandle) { final DevicePolicyData policy = getUserData(userHandle); final int count = policy.mAdminList.size(); if (count > 0) { for (int i = 0; i < count; i++) { - ActiveAdmin admin = policy.mAdminList.get(i); + final ActiveAdmin admin = policy.mAdminList.get(i); if (admin.info.usesPolicy(reqPolicy)) { sendAdminCommandLocked(admin, action); } @@ -845,6 +853,19 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + /** + * Send an update intent to all admins of a user and its profiles. Only send to admins that + * enforce a specified policy. + */ + private void sendAdminCommandToSelfAndProfilesLocked(String action, int reqPolicy, + int userHandle) { + List<UserInfo> profiles = mUserManager.getProfiles(userHandle); + for (UserInfo ui : profiles) { + int id = ui.getUserHandle().getIdentifier(); + sendAdminCommandLocked(action, reqPolicy, id); + } + } + void removeActiveAdminLocked(final ComponentName adminReceiver, int userHandle) { final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle); if (admin != null) { @@ -1190,23 +1211,29 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - private void handlePasswordExpirationNotification(DevicePolicyData policy) { + private void handlePasswordExpirationNotification(int userHandle) { synchronized (this) { final long now = System.currentTimeMillis(); - final int N = policy.mAdminList.size(); - if (N <= 0) { - return; - } - for (int i=0; i < N; i++) { - ActiveAdmin admin = policy.mAdminList.get(i); - if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD) - && admin.passwordExpirationTimeout > 0L - && admin.passwordExpirationDate > 0L - && now >= admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS) { - sendAdminCommandLocked(admin, DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING); + + List<UserInfo> profiles = mUserManager.getProfiles(userHandle); + for (UserInfo ui : profiles) { + int profileUserHandle = ui.getUserHandle().getIdentifier(); + final DevicePolicyData policy = getUserData(profileUserHandle); + final int count = policy.mAdminList.size(); + if (count > 0) { + for (int i = 0; i < count; i++) { + final ActiveAdmin admin = policy.mAdminList.get(i); + if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD) + && admin.passwordExpirationTimeout > 0L + && now >= admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS + && admin.passwordExpirationDate > 0L) { + sendAdminCommandLocked(admin, + DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING); + } + } } } - setExpirationAlarmCheckLocked(mContext, policy); + setExpirationAlarmCheckLocked(mContext, getUserData(userHandle)); } } @@ -1216,8 +1243,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { final boolean hasCert = DevicePolicyManager.hasAnyCaCertsInstalled(); if (! hasCert) { if (intent.getAction().equals(KeyChain.ACTION_STORAGE_CHANGED)) { - UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE); - for (UserInfo user : um.getUsers()) { + for (UserInfo user : mUserManager.getUsers()) { notificationManager.cancelAsUser( null, MONITORING_CERT_NOTIFICATION_ID, user.getUserHandle()); } @@ -1256,8 +1282,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // If this is a boot intent, this will fire for each user. But if this is a storage changed // intent, it will fire once, so we need to notify all users. if (intent.getAction().equals(KeyChain.ACTION_STORAGE_CHANGED)) { - UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE); - for (UserInfo user : um.getUsers()) { + for (UserInfo user : mUserManager.getUsers()) { notificationManager.notifyAsUser( null, MONITORING_CERT_NOTIFICATION_ID, noti, user.getUserHandle()); } @@ -1434,18 +1459,22 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { enforceCrossUserPermission(userHandle); synchronized (this) { int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; - DevicePolicyData policy = getUserData(userHandle); if (who != null) { ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); return admin != null ? admin.passwordQuality : mode; } - final int N = policy.mAdminList.size(); - for (int i=0; i<N; i++) { - ActiveAdmin admin = policy.mAdminList.get(i); - if (mode < admin.passwordQuality) { - mode = admin.passwordQuality; + // Return strictest policy for this user and profiles that are visible from this user. + List<UserInfo> profiles = mUserManager.getProfiles(userHandle); + for (UserInfo userInfo : profiles) { + DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier()); + final int N = policy.mAdminList.size(); + for (int i=0; i<N; i++) { + ActiveAdmin admin = policy.mAdminList.get(i); + if (mode < admin.passwordQuality) { + mode = admin.passwordQuality; + } } } return mode; @@ -1476,7 +1505,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } enforceCrossUserPermission(userHandle); synchronized (this) { - DevicePolicyData policy = getUserData(userHandle); int length = 0; if (who != null) { @@ -1484,11 +1512,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return admin != null ? admin.minimumPasswordLength : length; } - final int N = policy.mAdminList.size(); - for (int i=0; i<N; i++) { - ActiveAdmin admin = policy.mAdminList.get(i); - if (length < admin.minimumPasswordLength) { - length = admin.minimumPasswordLength; + // Return strictest policy for this user and profiles that are visible from this user. + List<UserInfo> profiles = mUserManager.getProfiles(userHandle); + for (UserInfo userInfo : profiles) { + DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier()); + final int N = policy.mAdminList.size(); + for (int i=0; i<N; i++) { + ActiveAdmin admin = policy.mAdminList.get(i); + if (length < admin.minimumPasswordLength) { + length = admin.minimumPasswordLength; + } } } return length; @@ -1519,7 +1552,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } enforceCrossUserPermission(userHandle); synchronized (this) { - DevicePolicyData policy = getUserData(userHandle); int length = 0; if (who != null) { @@ -1527,11 +1559,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return admin != null ? admin.passwordHistoryLength : length; } - final int N = policy.mAdminList.size(); - for (int i = 0; i < N; i++) { - ActiveAdmin admin = policy.mAdminList.get(i); - if (length < admin.passwordHistoryLength) { - length = admin.passwordHistoryLength; + // Return strictest policy for this user and profiles that are visible from this user. + List<UserInfo> profiles = mUserManager.getProfiles(userHandle); + for (UserInfo userInfo : profiles) { + DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier()); + final int N = policy.mAdminList.size(); + for (int i = 0; i < N; i++) { + ActiveAdmin admin = policy.mAdminList.get(i); + if (length < admin.passwordHistoryLength) { + length = admin.passwordHistoryLength; + } } } return length; @@ -1577,19 +1614,23 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } enforceCrossUserPermission(userHandle); synchronized (this) { + long timeout = 0L; + if (who != null) { ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); - return admin != null ? admin.passwordExpirationTimeout : 0L; + return admin != null ? admin.passwordExpirationTimeout : timeout; } - long timeout = 0L; - DevicePolicyData policy = getUserData(userHandle); - final int N = policy.mAdminList.size(); - for (int i = 0; i < N; i++) { - ActiveAdmin admin = policy.mAdminList.get(i); - if (timeout == 0L || (admin.passwordExpirationTimeout != 0L - && timeout > admin.passwordExpirationTimeout)) { - timeout = admin.passwordExpirationTimeout; + List<UserInfo> profiles = mUserManager.getProfiles(userHandle); + for (UserInfo userInfo : profiles) { + DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier()); + final int N = policy.mAdminList.size(); + for (int i = 0; i < N; i++) { + ActiveAdmin admin = policy.mAdminList.get(i); + if (timeout == 0L || (admin.passwordExpirationTimeout != 0L + && timeout > admin.passwordExpirationTimeout)) { + timeout = admin.passwordExpirationTimeout; + } } } return timeout; @@ -1601,19 +1642,23 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * Returns 0 if not configured. */ private long getPasswordExpirationLocked(ComponentName who, int userHandle) { + long timeout = 0L; + if (who != null) { ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); - return admin != null ? admin.passwordExpirationDate : 0L; + return admin != null ? admin.passwordExpirationDate : timeout; } - long timeout = 0L; - DevicePolicyData policy = getUserData(userHandle); - final int N = policy.mAdminList.size(); - for (int i = 0; i < N; i++) { - ActiveAdmin admin = policy.mAdminList.get(i); - if (timeout == 0L || (admin.passwordExpirationDate != 0 - && timeout > admin.passwordExpirationDate)) { - timeout = admin.passwordExpirationDate; + List<UserInfo> profiles = mUserManager.getProfiles(userHandle); + for (UserInfo userInfo : profiles) { + DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier()); + final int N = policy.mAdminList.size(); + for (int i = 0; i < N; i++) { + ActiveAdmin admin = policy.mAdminList.get(i); + if (timeout == 0L || (admin.passwordExpirationDate != 0 + && timeout > admin.passwordExpirationDate)) { + timeout = admin.passwordExpirationDate; + } } } return timeout; @@ -1660,12 +1705,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return admin != null ? admin.minimumPasswordUpperCase : length; } - DevicePolicyData policy = getUserData(userHandle); - final int N = policy.mAdminList.size(); - for (int i=0; i<N; i++) { - ActiveAdmin admin = policy.mAdminList.get(i); - if (length < admin.minimumPasswordUpperCase) { - length = admin.minimumPasswordUpperCase; + // Return strictest policy for this user and profiles that are visible from this user. + List<UserInfo> profiles = mUserManager.getProfiles(userHandle); + for (UserInfo userInfo : profiles) { + DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier()); + final int N = policy.mAdminList.size(); + for (int i=0; i<N; i++) { + ActiveAdmin admin = policy.mAdminList.get(i); + if (length < admin.minimumPasswordUpperCase) { + length = admin.minimumPasswordUpperCase; + } } } return length; @@ -1700,12 +1749,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return admin != null ? admin.minimumPasswordLowerCase : length; } - DevicePolicyData policy = getUserData(userHandle); - final int N = policy.mAdminList.size(); - for (int i=0; i<N; i++) { - ActiveAdmin admin = policy.mAdminList.get(i); - if (length < admin.minimumPasswordLowerCase) { - length = admin.minimumPasswordLowerCase; + // Return strictest policy for this user and profiles that are visible from this user. + List<UserInfo> profiles = mUserManager.getProfiles(userHandle); + for (UserInfo userInfo : profiles) { + DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier()); + final int N = policy.mAdminList.size(); + for (int i=0; i<N; i++) { + ActiveAdmin admin = policy.mAdminList.get(i); + if (length < admin.minimumPasswordLowerCase) { + length = admin.minimumPasswordLowerCase; + } } } return length; @@ -1743,12 +1796,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return admin != null ? admin.minimumPasswordLetters : length; } - DevicePolicyData policy = getUserData(userHandle); - final int N = policy.mAdminList.size(); - for (int i=0; i<N; i++) { - ActiveAdmin admin = policy.mAdminList.get(i); - if (length < admin.minimumPasswordLetters) { - length = admin.minimumPasswordLetters; + // Return strictest policy for this user and profiles that are visible from this user. + List<UserInfo> profiles = mUserManager.getProfiles(userHandle); + for (UserInfo userInfo : profiles) { + DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier()); + final int N = policy.mAdminList.size(); + for (int i=0; i<N; i++) { + ActiveAdmin admin = policy.mAdminList.get(i); + if (length < admin.minimumPasswordLetters) { + length = admin.minimumPasswordLetters; + } } } return length; @@ -1786,12 +1843,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return admin != null ? admin.minimumPasswordNumeric : length; } - DevicePolicyData policy = getUserData(userHandle); - final int N = policy.mAdminList.size(); - for (int i = 0; i < N; i++) { - ActiveAdmin admin = policy.mAdminList.get(i); - if (length < admin.minimumPasswordNumeric) { - length = admin.minimumPasswordNumeric; + // Return strictest policy for this user and profiles that are visible from this user. + List<UserInfo> profiles = mUserManager.getProfiles(userHandle); + for (UserInfo userInfo : profiles) { + DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier()); + final int N = policy.mAdminList.size(); + for (int i = 0; i < N; i++) { + ActiveAdmin admin = policy.mAdminList.get(i); + if (length < admin.minimumPasswordNumeric) { + length = admin.minimumPasswordNumeric; + } } } return length; @@ -1829,12 +1890,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return admin != null ? admin.minimumPasswordSymbols : length; } - DevicePolicyData policy = getUserData(userHandle); - final int N = policy.mAdminList.size(); - for (int i=0; i<N; i++) { - ActiveAdmin admin = policy.mAdminList.get(i); - if (length < admin.minimumPasswordSymbols) { - length = admin.minimumPasswordSymbols; + // Return strictest policy for this user and profiles that are visible from this user. + List<UserInfo> profiles = mUserManager.getProfiles(userHandle); + for (UserInfo userInfo : profiles) { + DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier()); + final int N = policy.mAdminList.size(); + for (int i=0; i<N; i++) { + ActiveAdmin admin = policy.mAdminList.get(i); + if (length < admin.minimumPasswordSymbols) { + length = admin.minimumPasswordSymbols; + } } } return length; @@ -1872,12 +1937,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return admin != null ? admin.minimumPasswordNonLetter : length; } - DevicePolicyData policy = getUserData(userHandle); - final int N = policy.mAdminList.size(); - for (int i=0; i<N; i++) { - ActiveAdmin admin = policy.mAdminList.get(i); - if (length < admin.minimumPasswordNonLetter) { - length = admin.minimumPasswordNonLetter; + // Return strictest policy for this user and profiles that are visible from this user. + List<UserInfo> profiles = mUserManager.getProfiles(userHandle); + for (UserInfo userInfo : profiles) { + DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier()); + final int N = policy.mAdminList.size(); + for (int i=0; i<N; i++) { + ActiveAdmin admin = policy.mAdminList.get(i); + if (length < admin.minimumPasswordNonLetter) { + length = admin.minimumPasswordNonLetter; + } } } return length; @@ -1889,8 +1958,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return true; } enforceCrossUserPermission(userHandle); + synchronized (this) { - DevicePolicyData policy = getUserData(userHandle); + + // The active password is stored in the user that runs the launcher + // If the user this is called from is part of a profile group, that is the parent + // of the group. + UserInfo parent = getProfileParent(userHandle); + int id = parent == null ? userHandle : parent.id; + DevicePolicyData policy = getUserData(id); + // This API can only be called by an active device admin, // so try to retrieve it to check that the caller is one. getActiveAdminForCallerLocked(null, @@ -1912,13 +1989,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } public int getCurrentFailedPasswordAttempts(int userHandle) { - enforceCrossUserPermission(userHandle); synchronized (this) { // This API can only be called by an active device admin, // so try to retrieve it to check that the caller is one. getActiveAdminForCallerLocked(null, DeviceAdminInfo.USES_POLICY_WATCH_LOGIN); - return getUserData(userHandle).mFailedPasswordAttempts; + + // The active password is stored in the parent. + DevicePolicyData policy = getUserData(getProfileParent(userHandle).id); + + return policy.mFailedPasswordAttempts; } } @@ -1928,6 +2008,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } enforceCrossUserPermission(userHandle); synchronized (this) { + if (who == null) { + throw new NullPointerException("ComponentName is null"); + } // This API can only be called by an active device admin, // so try to retrieve it to check that the caller is one. getActiveAdminForCallerLocked(who, @@ -1947,7 +2030,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } enforceCrossUserPermission(userHandle); synchronized (this) { - DevicePolicyData policy = getUserData(userHandle); int count = 0; if (who != null) { @@ -1955,14 +2037,19 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return admin != null ? admin.maximumFailedPasswordsForWipe : count; } - final int N = policy.mAdminList.size(); - for (int i=0; i<N; i++) { - ActiveAdmin admin = policy.mAdminList.get(i); - if (count == 0) { - count = admin.maximumFailedPasswordsForWipe; - } else if (admin.maximumFailedPasswordsForWipe != 0 - && count > admin.maximumFailedPasswordsForWipe) { - count = admin.maximumFailedPasswordsForWipe; + // Return strictest policy for this user and profiles that are visible from this user. + List<UserInfo> profiles = mUserManager.getProfiles(userHandle); + for (UserInfo userInfo : profiles) { + DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier()); + final int N = policy.mAdminList.size(); + for (int i=0; i<N; i++) { + ActiveAdmin admin = policy.mAdminList.get(i); + if (count == 0) { + count = admin.maximumFailedPasswordsForWipe; + } else if (admin.maximumFailedPasswordsForWipe != 0 + && count > admin.maximumFailedPasswordsForWipe) { + count = admin.maximumFailedPasswordsForWipe; + } } } return count; @@ -1974,9 +2061,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return false; } enforceCrossUserPermission(userHandle); + enforceNotManagedProfile(userHandle, "reset the password"); + int quality; synchronized (this) { - // This API can only be called by an active device admin, + // This api can only be called by an active device admin, // so try to retrieve it to check that the caller is one. getActiveAdminForCallerLocked(null, DeviceAdminInfo.USES_POLICY_RESET_PASSWORD); @@ -2154,15 +2243,19 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return admin != null ? admin.maximumTimeToUnlock : time; } - DevicePolicyData policy = getUserData(userHandle); - final int N = policy.mAdminList.size(); - for (int i=0; i<N; i++) { - ActiveAdmin admin = policy.mAdminList.get(i); - if (time == 0) { - time = admin.maximumTimeToUnlock; - } else if (admin.maximumTimeToUnlock != 0 - && time > admin.maximumTimeToUnlock) { - time = admin.maximumTimeToUnlock; + // Return strictest policy for this user and profiles that are visible from this user. + List<UserInfo> profiles = mUserManager.getProfiles(userHandle); + for (UserInfo userInfo : profiles) { + DevicePolicyData policy = getUserData(userInfo.getUserHandle().getIdentifier()); + final int N = policy.mAdminList.size(); + for (int i=0; i<N; i++) { + ActiveAdmin admin = policy.mAdminList.get(i); + if (time == 0) { + time = admin.maximumTimeToUnlock; + } else if (admin.maximumTimeToUnlock != 0 + && time > admin.maximumTimeToUnlock) { + time = admin.maximumTimeToUnlock; + } } } return time; @@ -2320,7 +2413,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { public void run() { try { ActivityManagerNative.getDefault().switchUser(UserHandle.USER_OWNER); - ((UserManager) mContext.getSystemService(Context.USER_SERVICE)) + (mUserManager) .removeUser(userHandle); } catch (RemoteException re) { // Shouldn't happen @@ -2368,6 +2461,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return; } enforceCrossUserPermission(userHandle); + enforceNotManagedProfile(userHandle, "set the active password"); + mContext.enforceCallingOrSelfPermission( android.Manifest.permission.BIND_DEVICE_ADMIN, null); DevicePolicyData p = getUserData(userHandle); @@ -2396,7 +2491,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { saveSettingsLocked(userHandle); updatePasswordExpirationsLocked(userHandle); setExpirationAlarmCheckLocked(mContext, p); - sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED, + sendAdminCommandToSelfAndProfilesLocked( + DeviceAdminReceiver.ACTION_PASSWORD_CHANGED, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userHandle); } finally { Binder.restoreCallingIdentity(ident); @@ -2406,26 +2502,31 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } /** - * Called any time the device password is updated. Resets all password expiration clocks. + * Called any time the device password is updated. Resets all password expiration clocks. */ private void updatePasswordExpirationsLocked(int userHandle) { - DevicePolicyData policy = getUserData(userHandle); - final int N = policy.mAdminList.size(); - if (N > 0) { - for (int i=0; i<N; i++) { - ActiveAdmin admin = policy.mAdminList.get(i); - if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) { - long timeout = admin.passwordExpirationTimeout; - long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L; - admin.passwordExpirationDate = expiration; + List<UserInfo> profiles = mUserManager.getProfiles(userHandle); + for (UserInfo userInfo : profiles) { + int profileId = userInfo.getUserHandle().getIdentifier(); + DevicePolicyData policy = getUserData(profileId); + final int N = policy.mAdminList.size(); + if (N > 0) { + for (int i=0; i<N; i++) { + ActiveAdmin admin = policy.mAdminList.get(i); + if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) { + long timeout = admin.passwordExpirationTimeout; + long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L; + admin.passwordExpirationDate = expiration; + } + } } + saveSettingsLocked(profileId); } - saveSettingsLocked(userHandle); - } } public void reportFailedPasswordAttempt(int userHandle) { enforceCrossUserPermission(userHandle); + enforceNotManagedProfile(userHandle, "report failed password attempt"); mContext.enforceCallingOrSelfPermission( android.Manifest.permission.BIND_DEVICE_ADMIN, null); @@ -2440,7 +2541,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (max > 0 && policy.mFailedPasswordAttempts >= max) { wipeDeviceOrUserLocked(0, userHandle); } - sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED, + sendAdminCommandToSelfAndProfilesLocked( + DeviceAdminReceiver.ACTION_PASSWORD_FAILED, DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle); } } finally { @@ -2463,7 +2565,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { policy.mPasswordOwner = -1; saveSettingsLocked(userHandle); if (mHasFeature) { - sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED, + sendAdminCommandToSelfAndProfilesLocked( + DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED, DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle); } } finally { @@ -2492,7 +2595,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // Scan through active admins and find if anyone has already // set the global proxy. Set<ComponentName> compSet = policy.mAdminMap.keySet(); - for (ComponentName component : compSet) { + for (ComponentName component : compSet) { ActiveAdmin ap = policy.mAdminMap.get(component); if ((ap.specifiesGlobalProxy) && (!component.equals(who))) { // Another admin already sets the global proxy @@ -2521,8 +2624,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // Reset the global proxy accordingly // Do this using system permissions, as apps cannot write to secure settings long origId = Binder.clearCallingIdentity(); - resetGlobalProxyLocked(policy); - Binder.restoreCallingIdentity(origId); + try { + resetGlobalProxyLocked(policy); + } finally { + Binder.restoreCallingIdentity(origId); + } return null; } } @@ -2907,8 +3013,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null); - UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE); - if (um.getUserInfo(userHandle) == null) { + if (mUserManager.getUserInfo(userHandle) == null) { // User doesn't exist. throw new IllegalArgumentException( "Attempted to set profile owner for invalid userId: " + userHandle); @@ -2954,10 +3059,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { int userId = UserHandle.getCallingUserId(); Slog.d(LOG_TAG, "Enabling the profile for: " + userId); - UserManager um = UserManager.get(mContext); long id = Binder.clearCallingIdentity(); try { - um.setUserEnabled(userId); + mUserManager.setUserEnabled(userId); Intent intent = new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED); intent.putExtra(Intent.EXTRA_USER, new UserHandle(UserHandle.getCallingUserId())); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY | @@ -3021,6 +3125,30 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + private void enforceNotManagedProfile(int userHandle, String message) { + if(isManagedProfile(userHandle)) { + throw new SecurityException("You can not " + message + " from a managed profile. "); + } + } + + private UserInfo getProfileParent(int userHandle) { + long ident = Binder.clearCallingIdentity(); + try { + return mUserManager.getProfileParent(userHandle); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + private boolean isManagedProfile(int userHandle) { + long ident = Binder.clearCallingIdentity(); + try { + return mUserManager.getUserInfo(userHandle).isManagedProfile(); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + private void enableIfNecessary(String packageName, int userId) { try { IPackageManager ipm = AppGlobals.getPackageManager(); @@ -3124,10 +3252,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - UserManager um = UserManager.get(mContext); long id = Binder.clearCallingIdentity(); try { - um.setApplicationRestrictions(packageName, settings, userHandle); + mUserManager.setApplicationRestrictions(packageName, settings, userHandle); } finally { restoreCallingIdentity(id); } @@ -3191,10 +3318,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - UserManager um = UserManager.get(mContext); long id = Binder.clearCallingIdentity(); try { - return um.getApplicationRestrictions(packageName, userHandle); + return mUserManager.getApplicationRestrictions(packageName, userHandle); } finally { restoreCallingIdentity(id); } @@ -3211,10 +3337,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - UserManager um = UserManager.get(mContext); long id = Binder.clearCallingIdentity(); try { - um.setUserRestriction(key, enabled, userHandle); + mUserManager.setUserRestriction(key, enabled, userHandle); } finally { restoreCallingIdentity(id); } diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 716823cf80a2..22e2a6e7c48a 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -334,6 +334,7 @@ public final class SystemServer { InputManagerService inputManager = null; TelephonyRegistry telephonyRegistry = null; ConsumerIrService consumerIr = null; + AudioService audioService = null; boolean onlyCore = false; boolean firstBoot = false; @@ -769,7 +770,8 @@ public final class SystemServer { if (!disableMedia && !"0".equals(SystemProperties.get("system_init.startaudioservice"))) { try { Slog.i(TAG, "Audio Service"); - ServiceManager.addService(Context.AUDIO_SERVICE, new AudioService(context)); + audioService = new AudioService(context); + ServiceManager.addService(Context.AUDIO_SERVICE, audioService); } catch (Throwable e) { reportWtf("starting Audio Service", e); } @@ -1084,6 +1086,7 @@ public final class SystemServer { final InputManagerService inputManagerF = inputManager; final TelephonyRegistry telephonyRegistryF = telephonyRegistry; final MediaRouterService mediaRouterF = mediaRouter; + final AudioService audioServiceF = audioService; // We now tell the activity manager it is okay to run third party // code. It will call back into us once it has gotten to the state @@ -1152,6 +1155,11 @@ public final class SystemServer { } catch (Throwable e) { reportWtf("making Recognition Service ready", e); } + try { + if (audioServiceF != null) audioServiceF.systemReady(); + } catch (Throwable e) { + reportWtf("Notifying AudioService running", e); + } Watchdog.getInstance().start(); // It is now okay to let the various system services start their diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java index ce8c8b84faf4..85b81d969362 100644 --- a/wifi/java/android/net/wifi/WifiConfiguration.java +++ b/wifi/java/android/net/wifi/WifiConfiguration.java @@ -506,6 +506,12 @@ public class WifiConfiguration implements Parcelable { * @hide */ public boolean isValid() { + if (SSID == null) + return false; + + if (allowedKeyManagement == null) + return false; + if (allowedKeyManagement.cardinality() > 1) { if (allowedKeyManagement.cardinality() != 2) { return false; |