diff options
53 files changed, 1618 insertions, 893 deletions
diff --git a/api/current.txt b/api/current.txt index 4f801cb97082..e50eba11393f 100644 --- a/api/current.txt +++ b/api/current.txt @@ -5807,6 +5807,7 @@ package android.app.admin { method public java.lang.String getLongSupportMessage(android.content.ComponentName); method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName); method public long getMaximumTimeToLock(android.content.ComponentName); + method public int getOrganizationColor(android.content.ComponentName); method public boolean getPackageSuspended(android.content.ComponentName, java.lang.String); method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName); method public long getPasswordExpiration(android.content.ComponentName); @@ -5875,6 +5876,7 @@ package android.app.admin { method public void setMasterVolumeMuted(android.content.ComponentName, boolean); method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int); method public void setMaximumTimeToLock(android.content.ComponentName, long); + method public void setOrganizationColor(android.content.ComponentName, int); method public boolean setPackageSuspended(android.content.ComponentName, java.lang.String, boolean); method public void setPasswordExpirationTimeout(android.content.ComponentName, long); method public void setPasswordHistoryLength(android.content.ComponentName, int); @@ -43606,6 +43608,7 @@ package android.view.inputmethod { field public android.os.Bundle extras; field public int fieldId; field public java.lang.String fieldName; + field public android.util.LocaleList hintLocales; field public java.lang.CharSequence hintText; field public int imeOptions; field public int initialCapsMode; @@ -43613,7 +43616,6 @@ package android.view.inputmethod { field public int initialSelStart; field public int inputType; field public java.lang.CharSequence label; - field public android.util.LocaleList locales; field public java.lang.String packageName; field public java.lang.String privateImeOptions; } @@ -46860,6 +46862,7 @@ package android.widget { method public int getHyphenationFrequency(); method public int getImeActionId(); method public java.lang.CharSequence getImeActionLabel(); + method public android.util.LocaleList getImeHintLocales(); method public int getImeOptions(); method public boolean getIncludeFontPadding(); method public android.os.Bundle getInputExtras(boolean); @@ -46966,6 +46969,7 @@ package android.widget { method public void setHorizontallyScrolling(boolean); method public void setHyphenationFrequency(int); method public void setImeActionLabel(java.lang.CharSequence, int); + method public void setImeHintLocales(android.util.LocaleList); method public void setImeOptions(int); method public void setIncludeFontPadding(boolean); method public void setInputExtras(int) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; @@ -47919,10 +47923,8 @@ package java.io { } public final class Console implements java.io.Flushable { - method public static java.io.Console console(); method public void flush(); method public java.io.Console format(java.lang.String, java.lang.Object...); - method public static synchronized java.io.Console getConsole(); method public java.io.Console printf(java.lang.String, java.lang.Object...); method public java.lang.String readLine(java.lang.String, java.lang.Object...); method public java.lang.String readLine(); @@ -48206,7 +48208,6 @@ package java.io { public class InterruptedIOException extends java.io.IOException { ctor public InterruptedIOException(); ctor public InterruptedIOException(java.lang.String); - ctor public InterruptedIOException(java.lang.Throwable); field public int bytesTransferred; } @@ -48877,7 +48878,6 @@ package java.lang { method public long longValue(); method public static byte parseByte(java.lang.String, int) throws java.lang.NumberFormatException; method public static byte parseByte(java.lang.String) throws java.lang.NumberFormatException; - method public static java.lang.String toHexString(byte, boolean); method public static java.lang.String toString(byte); method public static java.lang.Byte valueOf(byte); method public static java.lang.Byte valueOf(java.lang.String, int) throws java.lang.NumberFormatException; @@ -51029,7 +51029,6 @@ package java.net { public class BindException extends java.net.SocketException { ctor public BindException(java.lang.String); ctor public BindException(); - ctor public BindException(java.lang.String, java.lang.Throwable); } public abstract class CacheRequest { @@ -51047,7 +51046,6 @@ package java.net { public class ConnectException extends java.net.SocketException { ctor public ConnectException(java.lang.String); ctor public ConnectException(); - ctor public ConnectException(java.lang.String, java.lang.Throwable); } public abstract class ContentHandler { @@ -51127,7 +51125,6 @@ package java.net { method public void disconnect(); method public synchronized boolean getBroadcast() throws java.net.SocketException; method public java.nio.channels.DatagramChannel getChannel(); - method public final java.io.FileDescriptor getFileDescriptor$(); method public java.net.InetAddress getInetAddress(); method public java.net.InetAddress getLocalAddress(); method public int getLocalPort(); @@ -51204,7 +51201,6 @@ package java.net { method public boolean hasExpired(); method public boolean isHttpOnly(); method public static java.util.List<java.net.HttpCookie> parse(java.lang.String); - method public static java.util.List<java.net.HttpCookie> parse(java.lang.String, boolean); method public void setComment(java.lang.String); method public void setCommentURL(java.lang.String); method public void setDiscard(boolean); @@ -51297,9 +51293,6 @@ package java.net { } public final class Inet4Address extends java.net.InetAddress { - field public static final java.net.InetAddress ALL; - field public static final java.net.InetAddress ANY; - field public static final java.net.InetAddress LOOPBACK; } public final class Inet6Address extends java.net.InetAddress { @@ -51308,8 +51301,6 @@ package java.net { method public int getScopeId(); method public java.net.NetworkInterface getScopedInterface(); method public boolean isIPv4CompatibleAddress(); - field public static final java.net.InetAddress ANY; - field public static final java.net.InetAddress LOOPBACK; } public class InetAddress implements java.io.Serializable { @@ -51437,13 +51428,11 @@ package java.net { public class PortUnreachableException extends java.net.SocketException { ctor public PortUnreachableException(java.lang.String); ctor public PortUnreachableException(); - ctor public PortUnreachableException(java.lang.String, java.lang.Throwable); } public class ProtocolException extends java.io.IOException { ctor public ProtocolException(java.lang.String); ctor public ProtocolException(); - ctor public ProtocolException(java.lang.String, java.lang.Throwable); } public abstract interface ProtocolFamily { @@ -51578,8 +51567,6 @@ package java.net { public class SocketException extends java.io.IOException { ctor public SocketException(java.lang.String); ctor public SocketException(); - ctor public SocketException(java.lang.Throwable); - ctor public SocketException(java.lang.String, java.lang.Throwable); } public abstract class SocketImpl implements java.net.SocketOptions { @@ -51649,8 +51636,6 @@ package java.net { public class SocketTimeoutException extends java.io.InterruptedIOException { ctor public SocketTimeoutException(java.lang.String); ctor public SocketTimeoutException(); - ctor public SocketTimeoutException(java.lang.Throwable); - ctor public SocketTimeoutException(java.lang.String, java.lang.Throwable); } public final class StandardProtocolFamily extends java.lang.Enum implements java.net.ProtocolFamily { @@ -59595,7 +59580,6 @@ package java.util.jar { ctor public JarFile(java.io.File, boolean, int) throws java.io.IOException; method public java.util.jar.JarEntry getJarEntry(java.lang.String); method public java.util.jar.Manifest getManifest() throws java.io.IOException; - method public boolean hasClassPathAttribute() throws java.io.IOException; field public static final java.lang.String MANIFEST_NAME = "META-INF/MANIFEST.MF"; } diff --git a/api/system-current.txt b/api/system-current.txt index 47a51d4112ca..2d358bfe0bf8 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -5947,6 +5947,7 @@ package android.app.admin { method public java.lang.String getLongSupportMessage(android.content.ComponentName); method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName); method public long getMaximumTimeToLock(android.content.ComponentName); + method public int getOrganizationColor(android.content.ComponentName); method public boolean getPackageSuspended(android.content.ComponentName, java.lang.String); method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName); method public long getPasswordExpiration(android.content.ComponentName); @@ -6021,6 +6022,7 @@ package android.app.admin { method public void setMasterVolumeMuted(android.content.ComponentName, boolean); method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int); method public void setMaximumTimeToLock(android.content.ComponentName, long); + method public void setOrganizationColor(android.content.ComponentName, int); method public boolean setPackageSuspended(android.content.ComponentName, java.lang.String, boolean); method public void setPasswordExpirationTimeout(android.content.ComponentName, long); method public void setPasswordHistoryLength(android.content.ComponentName, int); @@ -6293,6 +6295,7 @@ package android.app.backup { method public static void dataChanged(java.lang.String); method public long getAvailableRestoreToken(java.lang.String); method public java.lang.String getCurrentTransport(); + method public boolean isAppEligibleForBackup(java.lang.String); method public boolean isBackupEnabled(); method public java.lang.String[] listAllTransports(); method public int requestBackup(java.lang.String[], android.app.backup.BackupObserver); @@ -6342,6 +6345,7 @@ package android.app.backup { method public int getNextFullRestoreDataChunk(android.os.ParcelFileDescriptor); method public int getRestoreData(android.os.ParcelFileDescriptor); method public int initializeDevice(); + method public boolean isAppEligibleForBackup(android.content.pm.PackageInfo, boolean); method public java.lang.String name(); method public android.app.backup.RestoreDescription nextRestorePackage(); method public int performBackup(android.content.pm.PackageInfo, android.os.ParcelFileDescriptor, int); @@ -46034,6 +46038,7 @@ package android.view.inputmethod { field public android.os.Bundle extras; field public int fieldId; field public java.lang.String fieldName; + field public android.util.LocaleList hintLocales; field public java.lang.CharSequence hintText; field public int imeOptions; field public int initialCapsMode; @@ -46041,7 +46046,6 @@ package android.view.inputmethod { field public int initialSelStart; field public int inputType; field public java.lang.CharSequence label; - field public android.util.LocaleList locales; field public java.lang.String packageName; field public java.lang.String privateImeOptions; } @@ -49614,6 +49618,7 @@ package android.widget { method public int getHyphenationFrequency(); method public int getImeActionId(); method public java.lang.CharSequence getImeActionLabel(); + method public android.util.LocaleList getImeHintLocales(); method public int getImeOptions(); method public boolean getIncludeFontPadding(); method public android.os.Bundle getInputExtras(boolean); @@ -49720,6 +49725,7 @@ package android.widget { method public void setHorizontallyScrolling(boolean); method public void setHyphenationFrequency(int); method public void setImeActionLabel(java.lang.CharSequence, int); + method public void setImeHintLocales(android.util.LocaleList); method public void setImeOptions(int); method public void setIncludeFontPadding(boolean); method public void setInputExtras(int) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; @@ -50673,10 +50679,8 @@ package java.io { } public final class Console implements java.io.Flushable { - method public static java.io.Console console(); method public void flush(); method public java.io.Console format(java.lang.String, java.lang.Object...); - method public static synchronized java.io.Console getConsole(); method public java.io.Console printf(java.lang.String, java.lang.Object...); method public java.lang.String readLine(java.lang.String, java.lang.Object...); method public java.lang.String readLine(); @@ -50960,7 +50964,6 @@ package java.io { public class InterruptedIOException extends java.io.IOException { ctor public InterruptedIOException(); ctor public InterruptedIOException(java.lang.String); - ctor public InterruptedIOException(java.lang.Throwable); field public int bytesTransferred; } @@ -51631,7 +51634,6 @@ package java.lang { method public long longValue(); method public static byte parseByte(java.lang.String, int) throws java.lang.NumberFormatException; method public static byte parseByte(java.lang.String) throws java.lang.NumberFormatException; - method public static java.lang.String toHexString(byte, boolean); method public static java.lang.String toString(byte); method public static java.lang.Byte valueOf(byte); method public static java.lang.Byte valueOf(java.lang.String, int) throws java.lang.NumberFormatException; @@ -53783,7 +53785,6 @@ package java.net { public class BindException extends java.net.SocketException { ctor public BindException(java.lang.String); ctor public BindException(); - ctor public BindException(java.lang.String, java.lang.Throwable); } public abstract class CacheRequest { @@ -53801,7 +53802,6 @@ package java.net { public class ConnectException extends java.net.SocketException { ctor public ConnectException(java.lang.String); ctor public ConnectException(); - ctor public ConnectException(java.lang.String, java.lang.Throwable); } public abstract class ContentHandler { @@ -53881,7 +53881,6 @@ package java.net { method public void disconnect(); method public synchronized boolean getBroadcast() throws java.net.SocketException; method public java.nio.channels.DatagramChannel getChannel(); - method public final java.io.FileDescriptor getFileDescriptor$(); method public java.net.InetAddress getInetAddress(); method public java.net.InetAddress getLocalAddress(); method public int getLocalPort(); @@ -53958,7 +53957,6 @@ package java.net { method public boolean hasExpired(); method public boolean isHttpOnly(); method public static java.util.List<java.net.HttpCookie> parse(java.lang.String); - method public static java.util.List<java.net.HttpCookie> parse(java.lang.String, boolean); method public void setComment(java.lang.String); method public void setCommentURL(java.lang.String); method public void setDiscard(boolean); @@ -54051,9 +54049,6 @@ package java.net { } public final class Inet4Address extends java.net.InetAddress { - field public static final java.net.InetAddress ALL; - field public static final java.net.InetAddress ANY; - field public static final java.net.InetAddress LOOPBACK; } public final class Inet6Address extends java.net.InetAddress { @@ -54062,8 +54057,6 @@ package java.net { method public int getScopeId(); method public java.net.NetworkInterface getScopedInterface(); method public boolean isIPv4CompatibleAddress(); - field public static final java.net.InetAddress ANY; - field public static final java.net.InetAddress LOOPBACK; } public class InetAddress implements java.io.Serializable { @@ -54191,13 +54184,11 @@ package java.net { public class PortUnreachableException extends java.net.SocketException { ctor public PortUnreachableException(java.lang.String); ctor public PortUnreachableException(); - ctor public PortUnreachableException(java.lang.String, java.lang.Throwable); } public class ProtocolException extends java.io.IOException { ctor public ProtocolException(java.lang.String); ctor public ProtocolException(); - ctor public ProtocolException(java.lang.String, java.lang.Throwable); } public abstract interface ProtocolFamily { @@ -54332,8 +54323,6 @@ package java.net { public class SocketException extends java.io.IOException { ctor public SocketException(java.lang.String); ctor public SocketException(); - ctor public SocketException(java.lang.Throwable); - ctor public SocketException(java.lang.String, java.lang.Throwable); } public abstract class SocketImpl implements java.net.SocketOptions { @@ -54403,8 +54392,6 @@ package java.net { public class SocketTimeoutException extends java.io.InterruptedIOException { ctor public SocketTimeoutException(java.lang.String); ctor public SocketTimeoutException(); - ctor public SocketTimeoutException(java.lang.Throwable); - ctor public SocketTimeoutException(java.lang.String, java.lang.Throwable); } public final class StandardProtocolFamily extends java.lang.Enum implements java.net.ProtocolFamily { @@ -62349,7 +62336,6 @@ package java.util.jar { ctor public JarFile(java.io.File, boolean, int) throws java.io.IOException; method public java.util.jar.JarEntry getJarEntry(java.lang.String); method public java.util.jar.Manifest getManifest() throws java.io.IOException; - method public boolean hasClassPathAttribute() throws java.io.IOException; field public static final java.lang.String MANIFEST_NAME = "META-INF/MANIFEST.MF"; } diff --git a/api/test-current.txt b/api/test-current.txt index 6b5b8b02c36d..bcdf5c1b22d9 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -5809,6 +5809,7 @@ package android.app.admin { method public java.lang.String getLongSupportMessage(android.content.ComponentName); method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName); method public long getMaximumTimeToLock(android.content.ComponentName); + method public int getOrganizationColor(android.content.ComponentName); method public boolean getPackageSuspended(android.content.ComponentName, java.lang.String); method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName); method public long getPasswordExpiration(android.content.ComponentName); @@ -5877,6 +5878,7 @@ package android.app.admin { method public void setMasterVolumeMuted(android.content.ComponentName, boolean); method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int); method public void setMaximumTimeToLock(android.content.ComponentName, long); + method public void setOrganizationColor(android.content.ComponentName, int); method public boolean setPackageSuspended(android.content.ComponentName, java.lang.String, boolean); method public void setPasswordExpirationTimeout(android.content.ComponentName, long); method public void setPasswordHistoryLength(android.content.ComponentName, int); @@ -43622,6 +43624,7 @@ package android.view.inputmethod { field public android.os.Bundle extras; field public int fieldId; field public java.lang.String fieldName; + field public android.util.LocaleList hintLocales; field public java.lang.CharSequence hintText; field public int imeOptions; field public int initialCapsMode; @@ -43629,7 +43632,6 @@ package android.view.inputmethod { field public int initialSelStart; field public int inputType; field public java.lang.CharSequence label; - field public android.util.LocaleList locales; field public java.lang.String packageName; field public java.lang.String privateImeOptions; } @@ -46876,6 +46878,7 @@ package android.widget { method public int getHyphenationFrequency(); method public int getImeActionId(); method public java.lang.CharSequence getImeActionLabel(); + method public android.util.LocaleList getImeHintLocales(); method public int getImeOptions(); method public boolean getIncludeFontPadding(); method public android.os.Bundle getInputExtras(boolean); @@ -46982,6 +46985,7 @@ package android.widget { method public void setHorizontallyScrolling(boolean); method public void setHyphenationFrequency(int); method public void setImeActionLabel(java.lang.CharSequence, int); + method public void setImeHintLocales(android.util.LocaleList); method public void setImeOptions(int); method public void setIncludeFontPadding(boolean); method public void setInputExtras(int) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; @@ -47935,10 +47939,8 @@ package java.io { } public final class Console implements java.io.Flushable { - method public static java.io.Console console(); method public void flush(); method public java.io.Console format(java.lang.String, java.lang.Object...); - method public static synchronized java.io.Console getConsole(); method public java.io.Console printf(java.lang.String, java.lang.Object...); method public java.lang.String readLine(java.lang.String, java.lang.Object...); method public java.lang.String readLine(); @@ -48222,7 +48224,6 @@ package java.io { public class InterruptedIOException extends java.io.IOException { ctor public InterruptedIOException(); ctor public InterruptedIOException(java.lang.String); - ctor public InterruptedIOException(java.lang.Throwable); field public int bytesTransferred; } @@ -48893,7 +48894,6 @@ package java.lang { method public long longValue(); method public static byte parseByte(java.lang.String, int) throws java.lang.NumberFormatException; method public static byte parseByte(java.lang.String) throws java.lang.NumberFormatException; - method public static java.lang.String toHexString(byte, boolean); method public static java.lang.String toString(byte); method public static java.lang.Byte valueOf(byte); method public static java.lang.Byte valueOf(java.lang.String, int) throws java.lang.NumberFormatException; @@ -51045,7 +51045,6 @@ package java.net { public class BindException extends java.net.SocketException { ctor public BindException(java.lang.String); ctor public BindException(); - ctor public BindException(java.lang.String, java.lang.Throwable); } public abstract class CacheRequest { @@ -51063,7 +51062,6 @@ package java.net { public class ConnectException extends java.net.SocketException { ctor public ConnectException(java.lang.String); ctor public ConnectException(); - ctor public ConnectException(java.lang.String, java.lang.Throwable); } public abstract class ContentHandler { @@ -51143,7 +51141,6 @@ package java.net { method public void disconnect(); method public synchronized boolean getBroadcast() throws java.net.SocketException; method public java.nio.channels.DatagramChannel getChannel(); - method public final java.io.FileDescriptor getFileDescriptor$(); method public java.net.InetAddress getInetAddress(); method public java.net.InetAddress getLocalAddress(); method public int getLocalPort(); @@ -51220,7 +51217,6 @@ package java.net { method public boolean hasExpired(); method public boolean isHttpOnly(); method public static java.util.List<java.net.HttpCookie> parse(java.lang.String); - method public static java.util.List<java.net.HttpCookie> parse(java.lang.String, boolean); method public void setComment(java.lang.String); method public void setCommentURL(java.lang.String); method public void setDiscard(boolean); @@ -51313,9 +51309,6 @@ package java.net { } public final class Inet4Address extends java.net.InetAddress { - field public static final java.net.InetAddress ALL; - field public static final java.net.InetAddress ANY; - field public static final java.net.InetAddress LOOPBACK; } public final class Inet6Address extends java.net.InetAddress { @@ -51324,8 +51317,6 @@ package java.net { method public int getScopeId(); method public java.net.NetworkInterface getScopedInterface(); method public boolean isIPv4CompatibleAddress(); - field public static final java.net.InetAddress ANY; - field public static final java.net.InetAddress LOOPBACK; } public class InetAddress implements java.io.Serializable { @@ -51453,13 +51444,11 @@ package java.net { public class PortUnreachableException extends java.net.SocketException { ctor public PortUnreachableException(java.lang.String); ctor public PortUnreachableException(); - ctor public PortUnreachableException(java.lang.String, java.lang.Throwable); } public class ProtocolException extends java.io.IOException { ctor public ProtocolException(java.lang.String); ctor public ProtocolException(); - ctor public ProtocolException(java.lang.String, java.lang.Throwable); } public abstract interface ProtocolFamily { @@ -51594,8 +51583,6 @@ package java.net { public class SocketException extends java.io.IOException { ctor public SocketException(java.lang.String); ctor public SocketException(); - ctor public SocketException(java.lang.Throwable); - ctor public SocketException(java.lang.String, java.lang.Throwable); } public abstract class SocketImpl implements java.net.SocketOptions { @@ -51665,8 +51652,6 @@ package java.net { public class SocketTimeoutException extends java.io.InterruptedIOException { ctor public SocketTimeoutException(java.lang.String); ctor public SocketTimeoutException(); - ctor public SocketTimeoutException(java.lang.Throwable); - ctor public SocketTimeoutException(java.lang.String, java.lang.Throwable); } public final class StandardProtocolFamily extends java.lang.Enum implements java.net.ProtocolFamily { @@ -59611,7 +59596,6 @@ package java.util.jar { ctor public JarFile(java.io.File, boolean, int) throws java.io.IOException; method public java.util.jar.JarEntry getJarEntry(java.lang.String); method public java.util.jar.Manifest getManifest() throws java.io.IOException; - method public boolean hasClassPathAttribute() throws java.io.IOException; field public static final java.lang.String MANIFEST_NAME = "META-INF/MANIFEST.MF"; } diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java index 9728e384d9a2..67d63a44a908 100644 --- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java +++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java @@ -16,8 +16,11 @@ package com.android.commands.bmgr; +import android.app.backup.BackupManager; +import android.app.backup.BackupProgress; import android.app.backup.RestoreSet; import android.app.backup.IBackupManager; +import android.app.backup.IBackupObserver; import android.app.backup.IRestoreObserver; import android.app.backup.IRestoreSession; import android.os.RemoteException; @@ -108,6 +111,11 @@ public final class Bmgr { return; } + if ("backupnow".equals(op)) { + doBackupNow(); + return; + } + System.err.println("Unknown command"); showUsage(); } @@ -189,6 +197,88 @@ public final class Bmgr { } } + class BackupObserver extends IBackupObserver.Stub { + boolean done = false; + + @Override + public void onUpdate(String currentPackage, BackupProgress backupProgress) { + System.out.println( + "onUpdate: " + currentPackage + " with progress: " + backupProgress.bytesTransferred + + "/" + backupProgress.bytesExpected); + } + + @Override + public void onResult(String currentPackage, int status) { + System.out.println("onResult: " + currentPackage + " with result: " + + convertBackupStatusToString(status)); + } + + @Override + public void backupFinished(int status) { + System.out.println("backupFinished: " + convertBackupStatusToString(status)); + synchronized (this) { + done = true; + this.notify(); + } + } + + public void waitForCompletion() { + // The backupFinished() callback will throw the 'done' flag; we + // just sit and wait on that notification. + synchronized (this) { + while (!this.done) { + try { + this.wait(); + } catch (InterruptedException ex) { + } + } + } + } + + } + + private static String convertBackupStatusToString(int errorCode) { + switch (errorCode) { + case BackupManager.SUCCESS: + return "Success"; + case BackupManager.ERROR_BACKUP_NOT_ALLOWED: + return "Backup is not allowed"; + case BackupManager.ERROR_PACKAGE_NOT_FOUND: + return "Package not found"; + case BackupManager.ERROR_TRANSPORT_ABORTED: + return "Transport error"; + case BackupManager.ERROR_TRANSPORT_PACKAGE_REJECTED: + return "Transport rejected package"; + case BackupManager.ERROR_AGENT_FAILURE: + return "Agent error"; + default: + return "Unknown error"; + } + } + + private void doBackupNow() { + String pkg; + ArrayList<String> allPkgs = new ArrayList<String>(); + while ((pkg = nextArg()) != null) { + allPkgs.add(pkg); + } + if (allPkgs.size() > 0) { + try { + BackupObserver observer = new BackupObserver(); + int err = mBmgr.requestBackup(allPkgs.toArray(new String[allPkgs.size()]), observer); + if (err == 0) { + // Off and running -- wait for the backup to complete + observer.waitForCompletion(); + } else { + System.err.println("Unable to run backup"); + } + } catch (RemoteException e) { + System.err.println(e.toString()); + System.err.println(BMGR_NOT_RUNNING_ERR); + } + } + } + private void doTransport() { try { String which = nextArg(); @@ -528,5 +618,10 @@ public final class Bmgr { System.err.println(""); System.err.println("The 'fullbackup' command induces a full-data stream backup for one or more"); System.err.println("packages. The data is sent via the currently active transport."); + System.err.println(""); + System.err.println("The 'backupnow' command runs an immediate backup for one or more packages."); + System.err.println("For each package it will run key/value or full data backup "); + System.err.println("depending on the package's manifest declarations."); + System.err.println("The data is sent via the currently active transport."); } } diff --git a/core/java/android/app/IntentService.java b/core/java/android/app/IntentService.java index 3cda9736e91c..f33af396070e 100644 --- a/core/java/android/app/IntentService.java +++ b/core/java/android/app/IntentService.java @@ -17,6 +17,7 @@ package android.app; import android.annotation.WorkerThread; +import android.annotation.Nullable; import android.content.Intent; import android.os.Handler; import android.os.HandlerThread; @@ -113,7 +114,7 @@ public abstract class IntentService extends Service { } @Override - public void onStart(Intent intent, int startId) { + public void onStart(@Nullable Intent intent, int startId) { Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; msg.obj = intent; @@ -127,7 +128,7 @@ public abstract class IntentService extends Service { * @see android.app.Service#onStartCommand */ @Override - public int onStartCommand(Intent intent, int flags, int startId) { + public int onStartCommand(@Nullable Intent intent, int flags, int startId) { onStart(intent, startId); return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY; } @@ -139,10 +140,11 @@ public abstract class IntentService extends Service { /** * Unless you provide binding for your service, you don't need to implement this - * method, because the default implementation returns null. + * method, because the default implementation returns null. * @see android.app.Service#onBind */ @Override + @Nullable public IBinder onBind(Intent intent) { return null; } @@ -158,7 +160,11 @@ public abstract class IntentService extends Service { * * @param intent The value passed to {@link * android.content.Context#startService(Intent)}. + * This may be null if the service is being restarted after + * its process has gone away; see + * {@link android.app.Service#onStartCommand} + * for details. */ @WorkerThread - protected abstract void onHandleIntent(Intent intent); + protected abstract void onHandleIntent(@Nullable Intent intent); } diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 20cacffaae72..a655bfd823b1 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -5142,4 +5142,55 @@ public class DevicePolicyManager { return null; } } + + /** + * Called by a profile owner of a managed profile to set the color used for customization. + * This color is used as background color of the confirm credentials screen for that user. + * The default color is {@link android.graphics.Color#GRAY}. + * + * <p>The confirm credentials screen can be created using + * {@link android.app.KeyguardManager#createConfirmDeviceCredentialIntent}. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param color The 32bit representation of the color to be used. + */ + public void setOrganizationColor(@NonNull ComponentName admin, int color) { + try { + mService.setOrganizationColor(admin, color); + } catch (RemoteException re) { + Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re); + } + } + + /** + * Called by a profile owner of a managed profile to retrieve the color used for customization. + * This color is used as background color of the confirm credentials screen for that user. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @return The 32bit representation of the color to be used. + */ + public int getOrganizationColor(@NonNull ComponentName admin) { + try { + return mService.getOrganizationColor(admin); + } catch (RemoteException re) { + Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re); + return 0; + } + } + + /** + * @hide + * Retrieve the customization color for a given user. + * + * @param userHandle The user id of the user we're interested in. + * @return The 32bit representation of the color to be used. + */ + public int getOrganizationColorForUser(int userHandle) { + try { + return mService.getOrganizationColorForUser(userHandle); + } catch (RemoteException re) { + Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re); + return 0; + } + } } diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 08cab8846290..82115a2880f4 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -263,4 +263,8 @@ interface IDevicePolicyManager { String getLongSupportMessageForUser(in ComponentName admin, int userHandle); boolean isSeparateProfileChallengeAllowed(int userHandle); + + void setOrganizationColor(in ComponentName admin, in int color); + int getOrganizationColor(in ComponentName admin); + int getOrganizationColorForUser(int userHandle); } diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java index 193a0b2c768d..c27eaa4f59bf 100644 --- a/core/java/android/app/backup/BackupManager.java +++ b/core/java/android/app/backup/BackupManager.java @@ -426,6 +426,29 @@ public class BackupManager { } /** + * Ask the framework whether this app is eligible for backup. + * + * <p>Callers must hold the android.permission.BACKUP permission to use this method. + * + * @param packageName The name of the package. + * @return Whether this app is eligible for backup. + * + * @hide + */ + @SystemApi + public boolean isAppEligibleForBackup(String packageName) { + checkServiceBinder(); + if (sService != null) { + try { + return sService.isAppEligibleForBackup(packageName); + } catch (RemoteException e) { + Log.e(TAG, "isAppEligibleForBackup(pkg) couldn't connect"); + } + } + return false; + } + + /** * Request an immediate backup, providing an observer to which results of the backup operation * will be published. The Android backup system will decide for each package whether it will * be full app data backup or key/value-pair-based backup. diff --git a/core/java/android/app/backup/BackupTransport.java b/core/java/android/app/backup/BackupTransport.java index 4363604cba92..aca115f29e78 100644 --- a/core/java/android/app/backup/BackupTransport.java +++ b/core/java/android/app/backup/BackupTransport.java @@ -482,6 +482,18 @@ public class BackupTransport { "Transport cancelFullBackup() not implemented"); } + /** + * Ask the transport whether this app is eligible for backup. + * + * @param targetPackage The identity of the application. + * @param isFullBackup If set, transport should check if app is eligible for full data backup, + * otherwise to check if eligible for key-value backup. + * @return Whether this app is eligible for backup. + */ + public boolean isAppEligibleForBackup(PackageInfo targetPackage, boolean isFullBackup) { + return true; + } + // ------------------------------------------------------------------------------------ // Full restore interfaces @@ -659,6 +671,12 @@ public class BackupTransport { } @Override + public boolean isAppEligibleForBackup(PackageInfo targetPackage, boolean isFullBackup) + throws RemoteException { + return BackupTransport.this.isAppEligibleForBackup(targetPackage, isFullBackup); + } + + @Override public int getNextFullRestoreDataChunk(ParcelFileDescriptor socket) { return BackupTransport.this.getNextFullRestoreDataChunk(socket); } diff --git a/core/java/android/app/backup/IBackupManager.aidl b/core/java/android/app/backup/IBackupManager.aidl index 2a1c00f9adc4..5d4cc6fe2dc9 100644 --- a/core/java/android/app/backup/IBackupManager.aidl +++ b/core/java/android/app/backup/IBackupManager.aidl @@ -329,6 +329,16 @@ interface IBackupManager { long getAvailableRestoreToken(String packageName); /** + * Ask the framework whether this app is eligible for backup. + * + * <p>Callers must hold the android.permission.BACKUP permission to use this method. + * + * @param packageName The name of the package. + * @return Whether this app is eligible for backup. + */ + boolean isAppEligibleForBackup(String packageName); + + /** * Request an immediate backup, providing an observer to which results of the backup operation * will be published. The Android backup system will decide for each package whether it will * be full app data backup or key/value-pair-based backup. diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java index 3ff95228f15e..85893b0c0b08 100644 --- a/core/java/android/view/inputmethod/EditorInfo.java +++ b/core/java/android/view/inputmethod/EditorInfo.java @@ -16,6 +16,7 @@ package android.view.inputmethod; +import android.annotation.Nullable; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; @@ -341,20 +342,26 @@ public class EditorInfo implements InputType, Parcelable { public Bundle extras; /** - * Additional context information that tells what languages are expected by the user. + * List of the languages that the user is supposed to switch to no matter what input method + * subtype is currently used. This special "hint" can be used mainly for, but not limited to, + * multilingual users who want IMEs to switch language context automatically. * - * <p><strong>IME authors:</strong> Possible use cases for IME developers would be:</p> - * <ul> - * <li>Automatically switching keyboard layout.</li> - * <li>Changing language model for better typing experience.</li> - * </ul> + * <p>{@code null} means that no special language "hint" is needed.</p> * - * <p><strong>Editor authors:</strong> Providing this context information can help IMEs to - * improve text input experience. For example, chat applications can remember what language is - * used in the last conversation for each chat session, and put the last used language at the - * top of {@link #locales}.</p> + * <p><strong>Editor authors:</strong> Specify this only when you are confident that the user + * will switch to certain languages in this context no matter what input method subtype is + * currently selected. Otherwise, keep this {@code null}. Explicit user actions and/or + * preferences would be good signals to specify this special "hint", For example, a chat + * application may be able to put the last used language at the top of {@link #hintLocales} + * based on whom the user is going to talk, by remembering what language is used in the last + * conversation. Do not specify {@link android.widget.TextView#getTextLocales()} only because + * it is used for text rendering.</p> + * + * @see android.widget.TextView#setImeHintLocales(LocaleList) + * @see android.widget.TextView#getImeHintLocales() */ - public LocaleList locales = LocaleList.getEmptyLocaleList(); + @Nullable + public LocaleList hintLocales = null; /** * Ensure that the data in this EditorInfo is compatible with an application @@ -410,7 +417,7 @@ public class EditorInfo implements InputType, Parcelable { + " fieldId=" + fieldId + " fieldName=" + fieldName); pw.println(prefix + "extras=" + extras); - pw.println(prefix + "locales=" + locales); + pw.println(prefix + "hintLocales=" + hintLocales); } /** @@ -434,7 +441,11 @@ public class EditorInfo implements InputType, Parcelable { dest.writeInt(fieldId); dest.writeString(fieldName); dest.writeBundle(extras); - locales.writeToParcel(dest, flags); + if (hintLocales != null) { + hintLocales.writeToParcel(dest, flags); + } else { + LocaleList.getEmptyLocaleList().writeToParcel(dest, flags); + } } /** @@ -458,7 +469,8 @@ public class EditorInfo implements InputType, Parcelable { res.fieldId = source.readInt(); res.fieldName = source.readString(); res.extras = source.readBundle(); - res.locales = LocaleList.CREATOR.createFromParcel(source); + LocaleList hintLocales = LocaleList.CREATOR.createFromParcel(source); + res.hintLocales = hintLocales.isEmpty() ? null : hintLocales; return res; } diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java index 4fc66656f625..43306d094bda 100644 --- a/core/java/android/view/inputmethod/InputMethodInfo.java +++ b/core/java/android/view/inputmethod/InputMethodInfo.java @@ -191,6 +191,8 @@ public final class InputMethodInfo implements Parcelable { .InputMethod_Subtype_label, 0)) .setSubtypeIconResId(a.getResourceId(com.android.internal.R.styleable .InputMethod_Subtype_icon, 0)) + .setLanguageTag(a.getString(com.android.internal.R.styleable + .InputMethod_Subtype_languageTag)) .setSubtypeLocale(a.getString(com.android.internal.R.styleable .InputMethod_Subtype_imeSubtypeLocale)) .setSubtypeMode(a.getString(com.android.internal.R.styleable diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 6241a4cd3462..6c2c956efa7d 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -3203,42 +3203,74 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te return mContextMenuInfo; } - /** @hide */ + @Override + public boolean showContextMenu() { + return showContextMenuInternal(0, 0, false); + } + @Override public boolean showContextMenu(float x, float y) { + return showContextMenuInternal(x, y, true); + } + + private boolean showContextMenuInternal(float x, float y, boolean useOffsets) { final int position = pointToPosition((int)x, (int)y); if (position != INVALID_POSITION) { final long id = mAdapter.getItemId(position); View child = getChildAt(position - mFirstPosition); if (child != null) { mContextMenuInfo = createContextMenuInfo(child, position, id); - return super.showContextMenuForChild(AbsListView.this, x, y); + if (useOffsets) { + return super.showContextMenuForChild(this, x, y); + } else { + return super.showContextMenuForChild(this); + } } } - return super.showContextMenu(x, y); + if (useOffsets) { + return super.showContextMenu(x, y); + } else { + return super.showContextMenu(); + } } @Override public boolean showContextMenuForChild(View originalView) { + return showContextMenuForChildInternal(originalView, 0, 0, false); + } + + @Override + public boolean showContextMenuForChild(View originalView, float x, float y) { + return showContextMenuForChildInternal(originalView,x, y, true); + } + + private boolean showContextMenuForChildInternal(View originalView, float x, float y, + boolean useOffsets) { final int longPressPosition = getPositionForView(originalView); - if (longPressPosition >= 0) { - final long longPressId = mAdapter.getItemId(longPressPosition); - boolean handled = false; - - if (mOnItemLongClickListener != null) { - handled = mOnItemLongClickListener.onItemLongClick(AbsListView.this, originalView, - longPressPosition, longPressId); - } - if (!handled) { - mContextMenuInfo = createContextMenuInfo( - getChildAt(longPressPosition - mFirstPosition), - longPressPosition, longPressId); + if (longPressPosition < 0) { + return false; + } + + final long longPressId = mAdapter.getItemId(longPressPosition); + boolean handled = false; + + if (mOnItemLongClickListener != null) { + handled = mOnItemLongClickListener.onItemLongClick(this, originalView, + longPressPosition, longPressId); + } + + if (!handled) { + final View child = getChildAt(longPressPosition - mFirstPosition); + mContextMenuInfo = createContextMenuInfo(child, longPressPosition, longPressId); + + if (useOffsets) { + handled = super.showContextMenuForChild(originalView, x, y); + } else { handled = super.showContextMenuForChild(originalView); } - - return handled; } - return false; + + return handled; } @Override diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index df5af25cb73e..4355eb3bcd69 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -69,6 +69,7 @@ import android.text.style.SuggestionSpan; import android.text.style.TextAppearanceSpan; import android.text.style.URLSpan; import android.util.DisplayMetrics; +import android.util.LocaleList; import android.util.Log; import android.util.SparseArray; import android.view.ActionMode; @@ -5299,6 +5300,7 @@ public class Editor { Bundle extras; OnEditorActionListener onEditorActionListener; boolean enterDown; + LocaleList imeHintLocales; } static class InputMethodState { diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java index 9ebbe36da1c5..a6ef572a2e3a 100644 --- a/core/java/android/widget/Gallery.java +++ b/core/java/android/widget/Gallery.java @@ -16,6 +16,7 @@ package android.widget; +import android.annotation.NonNull; import android.annotation.Widget; import android.content.Context; import android.content.res.TypedArray; @@ -1097,15 +1098,15 @@ public class Gallery extends AbsSpinner implements GestureDetector.OnGestureList } @Override - public void onLongPress(MotionEvent e) { - + public void onLongPress(@NonNull MotionEvent e) { if (mDownTouchPosition < 0) { return; } performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); - long id = getItemIdAtPosition(mDownTouchPosition); - dispatchLongPress(mDownTouchView, mDownTouchPosition, id); + + final long id = getItemIdAtPosition(mDownTouchPosition); + dispatchLongPress(mDownTouchView, mDownTouchPosition, id, e.getX(), e.getY(), true); } // Unused methods from GestureDetector.OnGestureListener below @@ -1159,29 +1160,47 @@ public class Gallery extends AbsSpinner implements GestureDetector.OnGestureList @Override public boolean showContextMenuForChild(View originalView) { + return showContextMenuForChildInternal(originalView, 0, 0, false); + } + + @Override + public boolean showContextMenuForChild(View originalView, float x, float y) { + return showContextMenuForChildInternal(originalView, x, y, true); + } + private boolean showContextMenuForChildInternal(View originalView, float x, float y, + boolean useOffsets) { final int longPressPosition = getPositionForView(originalView); if (longPressPosition < 0) { return false; } final long longPressId = mAdapter.getItemId(longPressPosition); - return dispatchLongPress(originalView, longPressPosition, longPressId); + return dispatchLongPress(originalView, longPressPosition, longPressId, x, y, useOffsets); } @Override public boolean showContextMenu() { - + return showContextMenuInternal(0, 0, false); + } + + @Override + public boolean showContextMenu(float x, float y) { + return showContextMenuInternal(x, y, true); + } + + private boolean showContextMenuInternal(float x, float y, boolean useOffsets) { if (isPressed() && mSelectedPosition >= 0) { - int index = mSelectedPosition - mFirstPosition; - View v = getChildAt(index); - return dispatchLongPress(v, mSelectedPosition, mSelectedRowId); + final int index = mSelectedPosition - mFirstPosition; + final View v = getChildAt(index); + return dispatchLongPress(v, mSelectedPosition, mSelectedRowId, x, y, useOffsets); } return false; } - private boolean dispatchLongPress(View view, int position, long id) { + private boolean dispatchLongPress(View view, int position, long id, float x, float y, + boolean useOffsets) { boolean handled = false; if (mOnItemLongClickListener != null) { @@ -1191,7 +1210,12 @@ public class Gallery extends AbsSpinner implements GestureDetector.OnGestureList if (!handled) { mContextMenuInfo = new AdapterContextMenuInfo(view, position, id); - handled = super.showContextMenuForChild(this); + + if (useOffsets) { + handled = super.showContextMenuForChild(view, x, y); + } else { + handled = super.showContextMenuForChild(this); + } } if (handled) { diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 7535caa8981f..c626af65016c 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -5002,6 +5002,35 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } /** + * Change "hint" locales associated with the text view, which will be reported to an IME with + * {@link EditorInfo#hintLocales} when it has focus. + * + * <p><strong>Note:</strong> If you want new "hint" to take effect immediately you need to + * call {@link InputMethodManager#restartInput(View)}.</p> + * @param hintLocales List of the languages that the user is supposed to switch to no matter + * what input method subtype is currently used. Set {@code null} to clear the current "hint". + * @see #getImeHIntLocales() + * @see android.view.inputmethod.EditorInfo#hintLocales + */ + public void setImeHintLocales(@Nullable LocaleList hintLocales) { + createEditorIfNeeded(); + mEditor.createInputContentTypeIfNeeded(); + mEditor.mInputContentType.imeHintLocales = hintLocales; + } + + /** + * @return The current languages list "hint". {@code null} when no "hint" is available. + * @see #setImeHintLocales(LocaleList) + * @see android.view.inputmethod.EditorInfo#hintLocales + */ + @Nullable + public LocaleList getImeHintLocales() { + if (mEditor == null) { return null; } + if (mEditor.mInputContentType == null) { return null; } + return mEditor.mInputContentType.imeHintLocales; + } + + /** * Returns the error message that was set to be displayed with * {@link #setError}, or <code>null</code> if no error was set * or if it the error was cleared by the widget after user input. @@ -6421,8 +6450,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener outAttrs.actionLabel = mEditor.mInputContentType.imeActionLabel; outAttrs.actionId = mEditor.mInputContentType.imeActionId; outAttrs.extras = mEditor.mInputContentType.extras; + outAttrs.hintLocales = mEditor.mInputContentType.imeHintLocales; } else { outAttrs.imeOptions = EditorInfo.IME_NULL; + outAttrs.hintLocales = null; } if (focusSearch(FOCUS_DOWN) != null) { outAttrs.imeOptions |= EditorInfo.IME_FLAG_NAVIGATE_NEXT; @@ -6450,9 +6481,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener outAttrs.imeOptions |= EditorInfo.IME_FLAG_NO_ENTER_ACTION; } outAttrs.hintText = mHint; - // LocaleList is designed to be immutable. This is theoretically equivalent to copy - // the snapshot of the current text locales. - outAttrs.locales = getTextLocales(); if (mText instanceof Editable) { InputConnection ic = new EditableInputConnection(this); outAttrs.initialSelStart = getSelectionStart(); diff --git a/core/java/com/android/internal/backup/IBackupTransport.aidl b/core/java/com/android/internal/backup/IBackupTransport.aidl index b1fc20d18d38..444dbfa71e8c 100644 --- a/core/java/com/android/internal/backup/IBackupTransport.aidl +++ b/core/java/com/android/internal/backup/IBackupTransport.aidl @@ -239,6 +239,16 @@ interface IBackupTransport { int sendBackupData(int numBytes); void cancelFullBackup(); + /** + * Ask the transport whether this app is eligible for backup. + * + * @param targetPackage The identity of the application. + * @param isFullBackup If set, transport should check if app is eligible for full data backup, + * otherwise to check if eligible for key-value backup. + * @return Whether this app is eligible for backup. + */ + boolean isAppEligibleForBackup(in PackageInfo targetPackage, boolean isFullBackup); + // full restore stuff /** @@ -286,5 +296,4 @@ interface IBackupTransport { * operation will immediately be finished with no further attempts to restore app data. */ int abortFullRestore(); - } diff --git a/core/jni/android/graphics/MinikinUtils.cpp b/core/jni/android/graphics/MinikinUtils.cpp index 0597d3f37a71..309d35b90260 100644 --- a/core/jni/android/graphics/MinikinUtils.cpp +++ b/core/jni/android/graphics/MinikinUtils.cpp @@ -62,6 +62,15 @@ void MinikinUtils::doLayout(Layout* layout, const Paint* paint, int bidiFlags, layout->doLayout(buf, start, count, bufSize, bidiFlags, minikinStyle, minikinPaint); } +float MinikinUtils::measureText(const Paint* paint, int bidiFlags, TypefaceImpl* typeface, + const uint16_t* buf, size_t start, size_t count, size_t bufSize, float *advances) { + FontCollection *font; + MinikinPaint minikinPaint; + FontStyle minikinStyle = prepareMinikinPaint(&minikinPaint, &font, paint, typeface); + return Layout::measureText(buf, start, count, bufSize, bidiFlags, minikinStyle, minikinPaint, + font, advances); +} + bool MinikinUtils::hasVariationSelector(TypefaceImpl* typeface, uint32_t codepoint, uint32_t vs) { const TypefaceImpl* resolvedFace = TypefaceImpl_resolveDefault(typeface); return resolvedFace->fFontCollection->hasVariationSelector(codepoint, vs); diff --git a/core/jni/android/graphics/MinikinUtils.h b/core/jni/android/graphics/MinikinUtils.h index 5bf1eec4507d..91525397b2ba 100644 --- a/core/jni/android/graphics/MinikinUtils.h +++ b/core/jni/android/graphics/MinikinUtils.h @@ -40,6 +40,9 @@ public: TypefaceImpl* typeface, const uint16_t* buf, size_t start, size_t count, size_t bufSize); + static float measureText(const Paint* paint, int bidiFlags, TypefaceImpl* typeface, + const uint16_t* buf, size_t start, size_t count, size_t bufSize, float *advances); + static bool hasVariationSelector(TypefaceImpl* typeface, uint32_t codepoint, uint32_t vs); static float xOffsetForTextAlign(Paint* paint, const Layout& layout); diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp index 98f8ce3e93c9..a3214eb2c9e3 100644 --- a/core/jni/android/graphics/Paint.cpp +++ b/core/jni/android/graphics/Paint.cpp @@ -493,16 +493,16 @@ namespace PaintGlue { return 0; } } - - Layout layout; - MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, text, start, count, - contextCount); - if (advances != NULL) { - std::unique_ptr<jfloat> advancesArray(new jfloat[count]); - layout.getAdvances(advancesArray.get()); + std::unique_ptr<jfloat[]> advancesArray; + if (advances) { + advancesArray.reset(new jfloat[count]); + } + const float advance = MinikinUtils::measureText(paint, bidiFlags, typeface, text, + start, count, contextCount, advancesArray.get()); + if (advances) { env->SetFloatArrayRegion(advances, advancesIndex, count, advancesArray.get()); } - return layout.getAdvance(); + return advance; } static jfloat getTextAdvances___CIIIII_FI(JNIEnv* env, jobject clazz, jlong paintHandle, diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java index e54723ea1b13..edbfef9c82bc 100644 --- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java +++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java @@ -48,6 +48,9 @@ import android.test.ActivityInstrumentationTestCase2; import android.test.suitebuilder.annotation.SmallTest; import android.view.KeyEvent; +import static org.hamcrest.Matchers.anyOf; +import static org.hamcrest.Matchers.is; + /** * Tests the TextView widget from an Activity */ @@ -84,6 +87,43 @@ public class TextViewActivityTest extends ActivityInstrumentationTestCase2<TextV } @SmallTest + public void testPositionCursorAtTextAtIndex_arabic() throws Exception { + // Arabic text. The expected cursorable boundary is + // | \u0623 \u064F | \u067A | \u0633 \u0652 | + final String text = "\u0623\u064F\u067A\u0633\u0652"; + onView(withId(R.id.textview)).perform(click()); + onView(withId(R.id.textview)).perform(replaceText(text)); + + onView(withId(R.id.textview)).perform(clickOnTextAtIndex(0)); + onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(0)); + onView(withId(R.id.textview)).perform(clickOnTextAtIndex(1)); + onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(anyOf(is(0), is(2)))); + onView(withId(R.id.textview)).perform(clickOnTextAtIndex(2)); + onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(2)); + onView(withId(R.id.textview)).perform(clickOnTextAtIndex(3)); + onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(3)); + onView(withId(R.id.textview)).perform(clickOnTextAtIndex(4)); + onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(anyOf(is(3), is(5)))); + onView(withId(R.id.textview)).perform(clickOnTextAtIndex(5)); + onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(5)); + } + + @SmallTest + public void testPositionCursorAtTextAtIndex_devanagari() throws Exception { + // Devanagari text. The expected cursorable boundary is | \u0915 \u093E | + final String text = "\u0915\u093E"; + onView(withId(R.id.textview)).perform(click()); + onView(withId(R.id.textview)).perform(replaceText(text)); + + onView(withId(R.id.textview)).perform(clickOnTextAtIndex(0)); + onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(0)); + onView(withId(R.id.textview)).perform(clickOnTextAtIndex(1)); + onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(anyOf(is(0), is(2)))); + onView(withId(R.id.textview)).perform(clickOnTextAtIndex(2)); + onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(2)); + } + + @SmallTest public void testLongPressToSelect() throws Exception { final String helloWorld = "Hello Kirk!"; onView(withId(R.id.textview)).perform(click()); diff --git a/libs/androidfw/DisplayEventDispatcher.cpp b/libs/androidfw/DisplayEventDispatcher.cpp index 99cd1732031c..b8ef9ea49293 100644 --- a/libs/androidfw/DisplayEventDispatcher.cpp +++ b/libs/androidfw/DisplayEventDispatcher.cpp @@ -103,7 +103,7 @@ int DisplayEventDispatcher::handleEvent(int, int events, void*) { int32_t vsyncDisplayId; uint32_t vsyncCount; if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) { - ALOGE("dispatcher %p ~ Vsync pulse: timestamp=%" PRId64 ", id=%d, count=%d", + ALOGV("dispatcher %p ~ Vsync pulse: timestamp=%" PRId64 ", id=%d, count=%d", this, ns2ms(vsyncTimestamp), vsyncDisplayId, vsyncCount); mWaitingForVsync = false; dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount); diff --git a/libs/hwui/Texture.cpp b/libs/hwui/Texture.cpp index c5000e4cadbc..92de89491127 100644 --- a/libs/hwui/Texture.cpp +++ b/libs/hwui/Texture.cpp @@ -180,6 +180,10 @@ static void colorTypeToGlFormatAndType(SkColorType colorType, *outFormat = GL_RGBA; *outType = GL_UNSIGNED_BYTE; break; + case kGray_8_SkColorType: + *outFormat = GL_LUMINANCE; + *outType = GL_UNSIGNED_BYTE; + break; default: LOG_ALWAYS_FATAL("Unsupported bitmap colorType: %d", colorType); break; diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java b/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java index 7f6b1e1d3abd..7a238bd6ce7d 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java +++ b/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java @@ -24,6 +24,7 @@ import android.content.Context; import android.os.RemoteException; import android.provider.DocumentsContract; import android.provider.DocumentsContract.Document; +import android.util.Log; import com.android.documentsui.R; import com.android.documentsui.model.DocumentInfo; @@ -92,6 +93,15 @@ final class MoveJob extends CopyJob { } } + // Moving virtual files by bytes is not supported. This is because, it would involve + // conversion, and the source file should not be deleted in such case (as it's a different + // file). + if (src.isVirtualDocument()) { + Log.w(TAG, "Cannot move virtual files byte by byte."); + onFileFailed(src); + return false; + } + // If we couldn't do an optimized copy...we fall back to vanilla byte copy. boolean copied = byteCopyDocument(src, dest); diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/services/MoveJobTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/services/MoveJobTest.java index 7edfcdb8f82f..69d2db778be9 100644 --- a/packages/DocumentsUI/tests/src/com/android/documentsui/services/MoveJobTest.java +++ b/packages/DocumentsUI/tests/src/com/android/documentsui/services/MoveJobTest.java @@ -16,6 +16,9 @@ package com.android.documentsui.services; +import static com.google.common.collect.Lists.newArrayList; + +import android.net.Uri; import android.test.suitebuilder.annotation.MediumTest; import com.android.documentsui.model.DocumentInfo; @@ -33,15 +36,23 @@ public class MoveJobTest extends AbstractCopyJobTest<MoveJob> { } public void testMoveVirtualTypedFile() throws Exception { - runCopyVirtualTypedFileTest(); + Uri testFile = mDocs.createVirtualFile( + mSrcRoot, "/virtual.sth", "virtual/mime-type", + FRUITY_BYTES, "application/pdf", "text/html"); + createJob(newArrayList(testFile)).run(); - mDocs.assertChildCount(mSrcRoot, 0); + mJobListener.waitForFinished(); + + // Should have failed, source not deleted. Moving by bytes for virtual files + // is not supported. + mDocs.assertChildCount(mDestRoot, 0); + mDocs.assertChildCount(mSrcRoot, 1); } public void testMoveVirtualNonTypedFile() throws Exception { runCopyVirtualNonTypedFileTest(); - // should have failed, source not deleted + // Should have failed, source not deleted. mDocs.assertChildCount(mSrcRoot, 1); } diff --git a/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml b/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml deleted file mode 100644 index 1fcb2dfdd6c3..000000000000 --- a/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml +++ /dev/null @@ -1,322 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -** -** Copyright 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. ---> - -<!-- navigation bar for sw600dp (small tablets) --> -<com.android.systemui.statusbar.phone.NavigationBarView - xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:systemui="http://schemas.android.com/apk/res-auto" - android:layout_height="match_parent" - android:layout_width="match_parent" - android:background="@drawable/system_bar_background" - > - - <FrameLayout android:id="@+id/rot0" - android:layout_height="match_parent" - android:layout_width="match_parent" - > - - <LinearLayout - android:layout_height="match_parent" - android:layout_width="match_parent" - android:orientation="horizontal" - android:clipChildren="false" - android:clipToPadding="false" - android:id="@+id/nav_buttons" - android:animateLayoutChanges="true" - > - - <!-- navigation controls --> - <View - android:layout_width="@dimen/navigation_extra_key_width" - android:layout_height="match_parent" - android:layout_weight="0" - android:layout_marginStart="2dp" - android:visibility="invisible" - /> - <Space - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_weight="1" - /> - <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back" - android:layout_width="128dp" android:paddingStart="25dp" android:paddingEnd="25dp" - android:layout_height="match_parent" - android:src="@drawable/ic_sysbar_back" - android:scaleType="centerInside" - systemui:keyCode="4" - android:layout_weight="0" - android:contentDescription="@string/accessibility_back" - /> - <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home" - android:layout_width="128dp" android:paddingStart="25dp" android:paddingEnd="25dp" - android:layout_height="match_parent" - android:src="@drawable/ic_sysbar_home" - android:scaleType="centerInside" - systemui:keyCode="3" - systemui:keyRepeat="true" - android:layout_weight="0" - android:contentDescription="@string/accessibility_home" - /> - <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/recent_apps" - android:layout_width="128dp" android:paddingStart="25dp" android:paddingEnd="25dp" - android:layout_height="match_parent" - android:src="@drawable/ic_sysbar_recent" - android:scaleType="centerInside" - android:layout_weight="0" - android:contentDescription="@string/accessibility_recent" - /> - <Space - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_weight="1" - /> - <FrameLayout - android:layout_width="@dimen/navigation_extra_key_width" - android:layout_height="match_parent" - android:layout_weight="0" - android:layout_marginEnd="2dp" > - <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu" - android:layout_width="@dimen/navigation_extra_key_width" - android:layout_height="match_parent" - android:src="@drawable/ic_sysbar_menu" - android:scaleType="centerInside" - android:layout_marginEnd="2dp" - systemui:keyCode="82" - android:visibility="invisible" - android:contentDescription="@string/accessibility_menu" - /> - <com.android.systemui.statusbar.policy.KeyButtonView - android:id="@+id/ime_switcher" - android:layout_width="@dimen/navigation_extra_key_width" - android:layout_height="match_parent" - android:layout_marginEnd="2dp" - android:scaleType="centerInside" - android:src="@drawable/ic_ime_switcher_default" - android:visibility="invisible" - android:contentDescription="@string/accessibility_ime_switch_button" /> - </FrameLayout> - </LinearLayout> - - <!-- lights out layout to match exactly --> - <LinearLayout - android:layout_height="match_parent" - android:layout_width="match_parent" - android:orientation="horizontal" - android:id="@+id/lights_out" - android:visibility="gone" - > - <Space - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_weight="1" - /> - <ImageView - android:layout_width="128dp" android:paddingStart="25dp" android:paddingEnd="25dp" - android:layout_height="match_parent" - android:layout_marginStart="40dp" - android:src="@drawable/ic_sysbar_lights_out_dot_small" - android:scaleType="center" - android:layout_weight="0" - android:contentDescription="@string/accessibility_back" - /> - <ImageView - android:layout_width="128dp" android:paddingStart="25dp" android:paddingEnd="25dp" - android:layout_height="match_parent" - android:src="@drawable/ic_sysbar_lights_out_dot_large" - android:scaleType="center" - android:layout_weight="0" - android:contentDescription="@string/accessibility_home" - /> - <ImageView - android:layout_width="128dp" android:paddingStart="25dp" android:paddingEnd="25dp" - android:layout_marginEnd="40dp" - android:layout_height="match_parent" - android:src="@drawable/ic_sysbar_lights_out_dot_small" - android:scaleType="center" - android:layout_weight="0" - android:contentDescription="@string/accessibility_recent" - /> - <Space - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_weight="1" - /> - </LinearLayout> - - <com.android.systemui.statusbar.policy.DeadZone - android:id="@+id/deadzone" - android:layout_height="match_parent" - android:layout_width="match_parent" - systemui:minSize="@dimen/navigation_bar_deadzone_size" - systemui:maxSize="@dimen/navigation_bar_deadzone_size_max" - systemui:holdTime="@integer/navigation_bar_deadzone_hold" - systemui:decayTime="@integer/navigation_bar_deadzone_decay" - systemui:orientation="horizontal" - android:layout_gravity="top" - /> - </FrameLayout> - - <FrameLayout android:id="@+id/rot90" - android:layout_height="match_parent" - android:layout_width="match_parent" - android:visibility="gone" - android:paddingTop="0dp" - > - - <LinearLayout - android:layout_height="match_parent" - android:layout_width="match_parent" - android:orientation="horizontal" - android:clipChildren="false" - android:clipToPadding="false" - android:id="@+id/nav_buttons" - android:animateLayoutChanges="true" - > - - <!-- navigation controls --> - <View - android:layout_width="@dimen/navigation_extra_key_width" - android:layout_height="match_parent" - android:layout_weight="0" - android:layout_marginStart="2dp" - android:visibility="invisible" - /> - <Space - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_weight="1" - /> - <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back" - android:layout_width="162dp" android:paddingStart="42dp" android:paddingEnd="42dp" - android:layout_height="match_parent" - android:src="@drawable/ic_sysbar_back" - android:scaleType="centerInside" - systemui:keyCode="4" - android:layout_weight="0" - android:contentDescription="@string/accessibility_back" - /> - <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home" - android:layout_width="162dp" android:paddingStart="42dp" android:paddingEnd="42dp" - android:layout_height="match_parent" - android:src="@drawable/ic_sysbar_home" - android:scaleType="centerInside" - systemui:keyCode="3" - systemui:keyRepeat="true" - android:layout_weight="0" - android:contentDescription="@string/accessibility_home" - /> - <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/recent_apps" - android:layout_width="162dp" android:paddingStart="42dp" android:paddingEnd="42dp" - android:layout_height="match_parent" - android:src="@drawable/ic_sysbar_recent" - android:scaleType="centerInside" - android:layout_weight="0" - android:contentDescription="@string/accessibility_recent" - /> - <Space - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_weight="1" - /> - <FrameLayout - android:layout_width="@dimen/navigation_extra_key_width" - android:layout_height="match_parent" - android:layout_marginEnd="2dp" - android:layout_weight="0" > - <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu" - android:layout_width="@dimen/navigation_extra_key_width" - android:layout_height="match_parent" - android:layout_marginEnd="2dp" - android:src="@drawable/ic_sysbar_menu" - android:scaleType="centerInside" - systemui:keyCode="82" - android:visibility="invisible" - android:contentDescription="@string/accessibility_menu" /> - <com.android.systemui.statusbar.policy.KeyButtonView - android:id="@+id/ime_switcher" - android:layout_width="@dimen/navigation_extra_key_width" - android:layout_height="match_parent" - android:layout_marginEnd="2dp" - android:src="@drawable/ic_ime_switcher_default" - android:visibility="invisible" - android:contentDescription="@string/accessibility_ime_switch_button" - android:scaleType="centerInside" /> - </FrameLayout> - </LinearLayout> - - <!-- lights out layout to match exactly --> - <LinearLayout - android:layout_height="match_parent" - android:layout_width="match_parent" - android:orientation="horizontal" - android:id="@+id/lights_out" - android:visibility="gone" - > - <Space - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_weight="1" - /> - <ImageView - android:layout_width="162dp" android:paddingStart="42dp" android:paddingEnd="42dp" - android:layout_height="match_parent" - android:layout_marginStart="40dp" - android:src="@drawable/ic_sysbar_lights_out_dot_small" - android:scaleType="center" - android:layout_weight="0" - android:contentDescription="@string/accessibility_back" - /> - <ImageView - android:layout_width="162dp" android:paddingStart="42dp" android:paddingEnd="42dp" - android:layout_height="match_parent" - android:src="@drawable/ic_sysbar_lights_out_dot_large" - android:scaleType="center" - android:layout_weight="0" - android:contentDescription="@string/accessibility_home" - /> - <ImageView - android:layout_width="162dp" android:paddingStart="42dp" android:paddingEnd="42dp" - android:layout_marginEnd="40dp" - android:layout_height="match_parent" - android:src="@drawable/ic_sysbar_lights_out_dot_small" - android:scaleType="center" - android:layout_weight="0" - android:contentDescription="@string/accessibility_recent" - /> - <Space - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_weight="1" - /> - </LinearLayout> - - <!-- On tablets in landscape the navbar is on the bottom, so use a - horizontal dead zone. --> - <com.android.systemui.statusbar.policy.DeadZone - android:id="@+id/deadzone" - android:layout_height="match_parent" - android:layout_width="match_parent" - systemui:minSize="@dimen/navigation_bar_deadzone_size" - systemui:maxSize="@dimen/navigation_bar_deadzone_size_max" - systemui:holdTime="@integer/navigation_bar_deadzone_hold" - systemui:decayTime="@integer/navigation_bar_deadzone_decay" - systemui:orientation="horizontal" - android:layout_gravity="top" - /> - </FrameLayout> -</com.android.systemui.statusbar.phone.NavigationBarView> diff --git a/packages/SystemUI/res/layout-sw600dp/navigation_layout_rot90.xml b/packages/SystemUI/res/layout-sw600dp/navigation_layout_rot90.xml new file mode 100644 index 000000000000..dd559c534351 --- /dev/null +++ b/packages/SystemUI/res/layout-sw600dp/navigation_layout_rot90.xml @@ -0,0 +1,90 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2016 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. +--> +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:systemui="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <FrameLayout + android:id="@+id/nav_buttons" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <LinearLayout + android:id="@+id/start_group" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="start" + android:orientation="horizontal" /> + + <LinearLayout + android:id="@+id/center_group" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="center" + android:orientation="horizontal" /> + + <LinearLayout + android:id="@+id/end_group" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="end" + android:orientation="horizontal" /> + + </FrameLayout> + + <FrameLayout + android:id="@+id/lights_out" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <LinearLayout + android:id="@+id/start_group_lightsout" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="start" + android:orientation="horizontal" /> + + <LinearLayout + android:id="@+id/center_group_lightsout" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="center" + android:orientation="horizontal" /> + + <LinearLayout + android:id="@+id/end_group_lightsout" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="end" + android:orientation="horizontal" /> + + </FrameLayout> + + <com.android.systemui.statusbar.policy.DeadZone + android:id="@+id/deadzone" + android:layout_height="match_parent" + android:layout_width="match_parent" + android:layout_gravity="top" + systemui:minSize="@dimen/navigation_bar_deadzone_size" + systemui:maxSize="@dimen/navigation_bar_deadzone_size_max" + systemui:holdTime="@integer/navigation_bar_deadzone_hold" + systemui:decayTime="@integer/navigation_bar_deadzone_decay" + systemui:orientation="horizontal" + /> + +</FrameLayout> diff --git a/packages/SystemUI/res/layout/back.xml b/packages/SystemUI/res/layout/back.xml new file mode 100644 index 000000000000..d2566224d02b --- /dev/null +++ b/packages/SystemUI/res/layout/back.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2016 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. +--> + +<com.android.systemui.statusbar.policy.KeyButtonView + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:systemui="http://schemas.android.com/apk/res-auto" + android:id="@+id/back" + android:layout_width="@dimen/navigation_key_width" + android:layout_height="match_parent" + android:layout_weight="0" + android:src="@drawable/ic_sysbar_back" + systemui:keyCode="4" + android:scaleType="center" + android:contentDescription="@string/accessibility_back" + android:paddingStart="@dimen/navigation_key_padding" + android:paddingEnd="@dimen/navigation_key_padding" + /> + diff --git a/packages/SystemUI/res/layout/home.xml b/packages/SystemUI/res/layout/home.xml new file mode 100644 index 000000000000..f11592de37ef --- /dev/null +++ b/packages/SystemUI/res/layout/home.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2016 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. +--> +<com.android.systemui.statusbar.policy.KeyButtonView + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:systemui="http://schemas.android.com/apk/res-auto" + android:id="@+id/home" + android:layout_width="@dimen/navigation_key_width" + android:layout_height="match_parent" + android:layout_weight="0" + android:src="@drawable/ic_sysbar_home" + systemui:keyCode="3" + android:scaleType="center" + android:contentDescription="@string/accessibility_home" + android:paddingStart="@dimen/navigation_key_padding" + android:paddingEnd="@dimen/navigation_key_padding" + /> + diff --git a/packages/SystemUI/res/layout/menu_ime.xml b/packages/SystemUI/res/layout/menu_ime.xml new file mode 100644 index 000000000000..90b74d0b57d1 --- /dev/null +++ b/packages/SystemUI/res/layout/menu_ime.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2016 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. +--> + +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:systemui="http://schemas.android.com/apk/res-auto" + android:layout_width="@dimen/navigation_side_padding" + android:layout_height="match_parent" + android:layout_weight="0" + > + <com.android.systemui.statusbar.policy.KeyButtonView + android:id="@+id/menu" + android:layout_width="@dimen/navigation_extra_key_width" + android:layout_height="match_parent" + android:layout_marginEnd="2dp" + android:src="@drawable/ic_sysbar_menu" + android:scaleType="centerInside" + systemui:keyCode="82" + android:visibility="invisible" + android:contentDescription="@string/accessibility_menu" + /> + <com.android.systemui.statusbar.policy.KeyButtonView + android:id="@+id/ime_switcher" + android:layout_width="@dimen/navigation_extra_key_width" + android:layout_height="match_parent" + android:layout_marginEnd="2dp" + android:src="@drawable/ic_ime_switcher_default" + android:visibility="invisible" + android:contentDescription="@string/accessibility_ime_switch_button" + android:scaleType="centerInside" + /> +</FrameLayout> diff --git a/packages/SystemUI/res/layout/nav_key_space.xml b/packages/SystemUI/res/layout/nav_key_space.xml new file mode 100644 index 000000000000..3986841b1838 --- /dev/null +++ b/packages/SystemUI/res/layout/nav_key_space.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +** Copyright 2016, 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. +*/ +--> + +<Space xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:systemui="http://schemas.android.com/apk/res-auto" + android:layout_width="@dimen/navigation_side_padding" + android:layout_height="match_parent" + android:layout_weight="0" + > +</Space> diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml index 8498a4f08e8f..36e937d4d3ef 100644 --- a/packages/SystemUI/res/layout/navigation_bar.xml +++ b/packages/SystemUI/res/layout/navigation_bar.xml @@ -22,309 +22,17 @@ xmlns:systemui="http://schemas.android.com/apk/res-auto" android:layout_height="match_parent" android:layout_width="match_parent" - android:background="@drawable/system_bar_background" - > + android:background="@drawable/system_bar_background"> - <FrameLayout android:id="@+id/rot0" - android:layout_height="match_parent" + <com.android.systemui.statusbar.phone.NavigationBarInflaterView + android:id="@+id/navigation_inflater" android:layout_width="match_parent" - > + android:layout_height="match_parent"> - <LinearLayout - android:layout_height="match_parent" - android:layout_width="match_parent" - android:orientation="horizontal" - android:clipChildren="false" - android:clipToPadding="false" - android:id="@+id/nav_buttons" - android:animateLayoutChanges="true" - > + <include android:id="@+id/rot0" layout="@layout/navigation_layout" /> - <!-- navigation controls --> - <View - android:layout_width="@dimen/navigation_side_padding" - android:layout_height="match_parent" - android:layout_weight="0" - android:visibility="invisible" - /> - <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back" - android:layout_width="@dimen/navigation_key_width" - android:layout_height="match_parent" - android:src="@drawable/ic_sysbar_back" - systemui:keyCode="4" - android:layout_weight="0" - android:scaleType="center" - android:contentDescription="@string/accessibility_back" - /> - <View - android:layout_width="0dp" - android:layout_height="match_parent" - android:layout_weight="1" - android:visibility="invisible" - /> - <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home" - android:layout_width="@dimen/navigation_key_width" - android:layout_height="match_parent" - android:src="@drawable/ic_sysbar_home" - systemui:keyCode="3" - systemui:keyRepeat="false" - android:layout_weight="0" - android:scaleType="center" - android:contentDescription="@string/accessibility_home" - /> - <View - android:layout_width="0dp" - android:layout_height="match_parent" - android:layout_weight="1" - android:visibility="invisible" - /> - <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/recent_apps" - android:layout_width="@dimen/navigation_key_width" - android:layout_height="match_parent" - android:src="@drawable/ic_sysbar_recent" - android:layout_weight="0" - android:scaleType="center" - android:contentDescription="@string/accessibility_recent" - /> - <FrameLayout - android:layout_width="@dimen/navigation_side_padding" - android:layout_height="match_parent" - android:layout_weight="0" > - <com.android.systemui.statusbar.policy.KeyButtonView - android:id="@+id/menu" - android:layout_width="@dimen/navigation_extra_key_width" - android:layout_height="match_parent" - android:contentDescription="@string/accessibility_menu" - android:src="@drawable/ic_sysbar_menu" - android:visibility="invisible" - android:scaleType="centerInside" - android:layout_gravity="end" - systemui:keyCode="82" /> + <include android:id="@+id/rot90" layout="@layout/navigation_layout_rot90" /> - <com.android.systemui.statusbar.policy.KeyButtonView - android:id="@+id/ime_switcher" - android:layout_width="@dimen/navigation_extra_key_width" - android:layout_height="match_parent" - android:contentDescription="@string/accessibility_ime_switch_button" - android:scaleType="centerInside" - android:src="@drawable/ic_ime_switcher_default" - android:visibility="invisible" - android:layout_gravity="end" /> - </FrameLayout> - - </LinearLayout> - - <!-- lights out layout to match exactly --> - <LinearLayout - android:layout_height="match_parent" - android:layout_width="match_parent" - android:orientation="horizontal" - android:id="@+id/lights_out" - android:visibility="gone" - > - <ImageView - android:layout_width="@dimen/navigation_key_width" - android:layout_height="match_parent" - android:layout_marginStart="@dimen/navigation_side_padding" - android:src="@drawable/ic_sysbar_lights_out_dot_small" - android:scaleType="center" - android:layout_weight="0" - android:contentDescription="@string/accessibility_back" - /> - <View - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_weight="1" - android:visibility="invisible" - /> - <ImageView - android:layout_width="@dimen/navigation_key_width" - android:layout_height="match_parent" - android:src="@drawable/ic_sysbar_lights_out_dot_large" - android:scaleType="center" - android:layout_weight="0" - android:contentDescription="@string/accessibility_home" - /> - <View - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_weight="1" - android:visibility="invisible" - /> - <ImageView - android:layout_width="@dimen/navigation_key_width" - android:layout_marginEnd="@dimen/navigation_side_padding" - android:layout_height="match_parent" - android:src="@drawable/ic_sysbar_lights_out_dot_small" - android:scaleType="center" - android:layout_weight="0" - android:contentDescription="@string/accessibility_recent" - /> - </LinearLayout> - - <com.android.systemui.statusbar.policy.DeadZone - android:id="@+id/deadzone" - android:layout_height="match_parent" - android:layout_width="match_parent" - systemui:minSize="@dimen/navigation_bar_deadzone_size" - systemui:maxSize="@dimen/navigation_bar_deadzone_size_max" - systemui:holdTime="@integer/navigation_bar_deadzone_hold" - systemui:decayTime="@integer/navigation_bar_deadzone_decay" - systemui:orientation="horizontal" - android:layout_gravity="top" - /> - </FrameLayout> - - <FrameLayout android:id="@+id/rot90" - android:layout_height="match_parent" - android:layout_width="match_parent" - android:visibility="gone" - android:paddingTop="0dp" - > - - <LinearLayout - android:layout_height="match_parent" - android:layout_width="match_parent" - android:orientation="vertical" - android:clipChildren="false" - android:clipToPadding="false" - android:id="@+id/nav_buttons" - android:animateLayoutChanges="true" - > - - <!-- navigation controls --> - <FrameLayout - android:layout_weight="0" - android:layout_width="match_parent" - android:layout_height="@dimen/navigation_side_padding" > - <com.android.systemui.statusbar.policy.KeyButtonView - android:id="@+id/ime_switcher" - android:layout_width="match_parent" - android:layout_height="@dimen/navigation_extra_key_width" - android:contentDescription="@string/accessibility_ime_switch_button" - android:scaleType="centerInside" - android:src="@drawable/ic_ime_switcher_default" - android:layout_gravity="top" - android:visibility="invisible" /> - - <com.android.systemui.statusbar.policy.KeyButtonView - android:id="@+id/menu" - android:layout_width="match_parent" - android:layout_height="40dp" - android:contentDescription="@string/accessibility_menu" - android:src="@drawable/ic_sysbar_menu" - android:scaleType="centerInside" - android:layout_gravity="top" - android:visibility="invisible" - systemui:keyCode="82" /> - </FrameLayout> - - <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/recent_apps" - android:layout_height="@dimen/navigation_key_width" - android:layout_width="match_parent" - android:src="@drawable/ic_sysbar_recent" - android:scaleType="center" - android:layout_weight="0" - android:contentDescription="@string/accessibility_recent" - /> - <View - android:layout_height="match_parent" - android:layout_width="match_parent" - android:layout_weight="1" - android:visibility="invisible" - /> - <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home" - android:layout_height="@dimen/navigation_key_width" - android:layout_width="match_parent" - android:src="@drawable/ic_sysbar_home" - android:scaleType="center" - systemui:keyCode="3" - systemui:keyRepeat="false" - android:layout_weight="0" - android:contentDescription="@string/accessibility_home" - /> - <View - android:layout_height="match_parent" - android:layout_width="match_parent" - android:layout_weight="1" - android:visibility="invisible" - /> - <com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back" - android:layout_height="@dimen/navigation_key_width" - android:layout_width="match_parent" - android:src="@drawable/ic_sysbar_back" - android:scaleType="center" - systemui:keyCode="4" - android:layout_weight="0" - android:contentDescription="@string/accessibility_back" - /> - <View - android:layout_height="@dimen/navigation_side_padding" - android:layout_width="match_parent" - android:layout_weight="0" - android:visibility="invisible" - /> - </LinearLayout> - - <!-- lights out layout to match exactly --> - <LinearLayout - android:layout_height="match_parent" - android:layout_width="match_parent" - android:orientation="vertical" - android:id="@+id/lights_out" - android:visibility="gone" - > - <ImageView - android:layout_height="@dimen/navigation_key_width" - android:layout_marginTop="@dimen/navigation_side_padding" - android:layout_width="match_parent" - android:src="@drawable/ic_sysbar_lights_out_dot_small" - android:scaleType="center" - android:layout_weight="0" - android:contentDescription="@string/accessibility_recent" - /> - <View - android:layout_height="match_parent" - android:layout_width="match_parent" - android:layout_weight="1" - android:visibility="invisible" - /> - <ImageView - android:layout_height="@dimen/navigation_key_width" - android:layout_width="match_parent" - android:src="@drawable/ic_sysbar_lights_out_dot_large" - android:scaleType="center" - android:layout_weight="0" - android:contentDescription="@string/accessibility_home" - /> - <View - android:layout_height="match_parent" - android:layout_width="match_parent" - android:layout_weight="1" - android:visibility="invisible" - /> - <ImageView - android:layout_height="@dimen/navigation_key_width" - android:layout_marginBottom="@dimen/navigation_side_padding" - android:layout_width="match_parent" - android:src="@drawable/ic_sysbar_lights_out_dot_small" - android:scaleType="center" - android:layout_weight="0" - android:contentDescription="@string/accessibility_back" - /> - </LinearLayout> - - <com.android.systemui.statusbar.policy.DeadZone - android:id="@+id/deadzone" - android:layout_height="match_parent" - android:layout_width="match_parent" - systemui:minSize="@dimen/navigation_bar_deadzone_size" - systemui:maxSize="@dimen/navigation_bar_deadzone_size_max" - systemui:holdTime="@integer/navigation_bar_deadzone_hold" - systemui:decayTime="@integer/navigation_bar_deadzone_decay" - systemui:orientation="vertical" - android:layout_gravity="top" - /> - </FrameLayout> + </com.android.systemui.statusbar.phone.NavigationBarInflaterView> </com.android.systemui.statusbar.phone.NavigationBarView> diff --git a/packages/SystemUI/res/layout/navigation_layout.xml b/packages/SystemUI/res/layout/navigation_layout.xml new file mode 100644 index 000000000000..7ebf4edfc78b --- /dev/null +++ b/packages/SystemUI/res/layout/navigation_layout.xml @@ -0,0 +1,91 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2016 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. +--> + +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:systemui="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <FrameLayout + android:id="@+id/nav_buttons" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <LinearLayout + android:id="@+id/start_group" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="start" + android:orientation="horizontal" /> + + <LinearLayout + android:id="@+id/center_group" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="center" + android:orientation="horizontal" /> + + <LinearLayout + android:id="@+id/end_group" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="end" + android:orientation="horizontal" /> + + </FrameLayout> + + <FrameLayout + android:id="@+id/lights_out" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <LinearLayout + android:id="@+id/start_group_lightsout" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="start" + android:orientation="horizontal" /> + + <LinearLayout + android:id="@+id/center_group_lightsout" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="center" + android:orientation="horizontal" /> + + <LinearLayout + android:id="@+id/end_group_lightsout" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="end" + android:orientation="horizontal" /> + + </FrameLayout> + + <com.android.systemui.statusbar.policy.DeadZone + android:id="@+id/deadzone" + android:layout_height="match_parent" + android:layout_width="match_parent" + android:layout_gravity="top" + systemui:minSize="@dimen/navigation_bar_deadzone_size" + systemui:maxSize="@dimen/navigation_bar_deadzone_size_max" + systemui:holdTime="@integer/navigation_bar_deadzone_hold" + systemui:decayTime="@integer/navigation_bar_deadzone_decay" + systemui:orientation="horizontal" + /> + +</FrameLayout> diff --git a/packages/SystemUI/res/layout/navigation_layout_rot90.xml b/packages/SystemUI/res/layout/navigation_layout_rot90.xml new file mode 100644 index 000000000000..46df97347a1c --- /dev/null +++ b/packages/SystemUI/res/layout/navigation_layout_rot90.xml @@ -0,0 +1,91 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2016 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. +--> + +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:systemui="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <FrameLayout + android:id="@+id/nav_buttons" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <com.android.systemui.statusbar.phone.ReverseLinearLayout + android:id="@+id/start_group" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="bottom" + android:orientation="vertical" /> + + <com.android.systemui.statusbar.phone.ReverseLinearLayout + android:id="@+id/center_group" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="center" + android:orientation="vertical" /> + + <com.android.systemui.statusbar.phone.ReverseLinearLayout + android:id="@+id/end_group" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="top" + android:orientation="vertical" /> + + </FrameLayout> + + <FrameLayout + android:id="@+id/lights_out" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <com.android.systemui.statusbar.phone.ReverseLinearLayout + android:id="@+id/start_group_lightsout" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="bottom" + android:orientation="vertical" /> + + <com.android.systemui.statusbar.phone.ReverseLinearLayout + android:id="@+id/center_group_lightsout" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="center" + android:orientation="vertical" /> + + <com.android.systemui.statusbar.phone.ReverseLinearLayout + android:id="@+id/end_group_lightsout" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="top" + android:orientation="vertical" /> + + </FrameLayout> + + <com.android.systemui.statusbar.policy.DeadZone + android:id="@+id/deadzone" + android:layout_height="match_parent" + android:layout_width="match_parent" + android:layout_gravity="top" + systemui:minSize="@dimen/navigation_bar_deadzone_size" + systemui:maxSize="@dimen/navigation_bar_deadzone_size_max" + systemui:holdTime="@integer/navigation_bar_deadzone_hold" + systemui:decayTime="@integer/navigation_bar_deadzone_decay" + systemui:orientation="vertical" + /> + +</FrameLayout> diff --git a/packages/SystemUI/res/layout/recent_apps.xml b/packages/SystemUI/res/layout/recent_apps.xml new file mode 100644 index 000000000000..eb8ee43c0263 --- /dev/null +++ b/packages/SystemUI/res/layout/recent_apps.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2016 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. +--> + +<com.android.systemui.statusbar.policy.KeyButtonView + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:systemui="http://schemas.android.com/apk/res-auto" + android:id="@+id/recent_apps" + android:layout_width="@dimen/navigation_key_width" + android:layout_height="match_parent" + android:layout_weight="0" + android:src="@drawable/ic_sysbar_recent" + android:scaleType="center" + android:contentDescription="@string/accessibility_recent" + android:paddingStart="@dimen/navigation_key_padding" + android:paddingEnd="@dimen/navigation_key_padding" + /> + diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml index f084bc2c3ddb..be5b856a65f5 100644 --- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml +++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml @@ -34,4 +34,7 @@ In sw600dp we want the buttons centered so this fills the space, (screen_pinning_request_width - 3 * screen_pinning_request_button_width) / 2 --> <dimen name="screen_pinning_request_side_width">2dp</dimen> + + <dimen name="navigation_key_width">162dp</dimen> + <dimen name="navigation_key_padding">42dp</dimen> </resources> diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml index 17ff19549a0d..db4da10756ed 100644 --- a/packages/SystemUI/res/values-sw600dp/config.xml +++ b/packages/SystemUI/res/values-sw600dp/config.xml @@ -42,4 +42,8 @@ while the stack is not focused. --> <item name="recents_layout_unfocused_range_min" format="float" type="integer">-2</item> <item name="recents_layout_unfocused_range_max" format="float" type="integer">2.5</item> + + <!-- Nav bar button default ordering/layout --> + <string name="config_navBarLayout" translatable="false">space;back,home,recent;menu_ime</string> + </resources> diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml index 49dbac2f5f65..71f92fd18587 100644 --- a/packages/SystemUI/res/values-sw600dp/dimens.xml +++ b/packages/SystemUI/res/values-sw600dp/dimens.xml @@ -90,4 +90,7 @@ <dimen name="screen_pinning_request_side_width">8dp</dimen> <dimen name="fab_margin">24dp</dimen> + + <dimen name="navigation_key_width">128dp</dimen> + <dimen name="navigation_key_padding">25dp</dimen> </resources> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 7a873147fdfb..aedc2c52e05b 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -288,5 +288,8 @@ <!-- SystemUIFactory component --> <string name="config_systemUIFactoryComponent" translatable="false">com.android.systemui.SystemUIFactory</string> + <!-- Nav bar button default ordering/layout --> + <string name="config_navBarLayout" translatable="false">space,back;home;recent,menu_ime</string> + </resources> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index d7bd86ffa887..46a0f2ae2ae7 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -96,6 +96,11 @@ <!-- The width of the view containing navigation buttons --> <dimen name="navigation_key_width">70dp</dimen> + <dimen name="navigation_key_padding">0dp</dimen> + + <dimen name="navigation_key_width_sw600dp_land">162dp</dimen> + <dimen name="navigation_key_padding_sw600dp_land">42dp</dimen> + <!-- The width of the view containing the menu/ime navigation bar icons --> <dimen name="navigation_extra_key_width">36dp</dimen> diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java index 3eee08766c73..f8cbf656dfa0 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java @@ -651,7 +651,7 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub implements mDummyStackView.updateLayoutForStack(stack); final Task toTask = new Task(); final TaskViewTransform toTransform = getThumbnailTransitionTransform(stack, stackView, - topTask.id, toTask); + toTask); ForegroundThread.getHandler().postAtFrontOfQueue(new Runnable() { @Override public void run() { @@ -721,7 +721,7 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub implements // Update the destination rect Task toTask = new Task(); TaskViewTransform toTransform = getThumbnailTransitionTransform(stack, stackView, - topTask.id, toTask); + toTask); RectF toTaskRect = toTransform.rect; Bitmap thumbnail = getThumbnailBitmap(topTask, toTask, toTransform); if (thumbnail != null) { @@ -754,14 +754,14 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub implements * Returns the transition rect for the given task id. */ private TaskViewTransform getThumbnailTransitionTransform(TaskStack stack, - TaskStackView stackView, int runningTaskId, Task runningTaskOut) { + TaskStackView stackView, Task runningTaskOut) { // Find the running task in the TaskStack Task launchTask = stack.getLaunchTarget(); if (launchTask != null) { runningTaskOut.copyFrom(launchTask); } else { // If no task is specified or we can not find the task just use the front most one - launchTask = stack.getStackFrontMostTask(); + launchTask = stack.getStackFrontMostTask(true /* includeFreeform */); runningTaskOut.copyFrom(launchTask); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java index c73273e6f258..de1daa8ea988 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java @@ -527,9 +527,9 @@ public class TaskStack { */ public void removeTask(Task t, TaskViewAnimation animation) { if (mStackTaskList.contains(t)) { - boolean wasFrontMostTask = (getStackFrontMostTask() == t); + boolean wasFrontMostTask = (getStackFrontMostTask(false /* includeFreeform */) == t); removeTaskImpl(mStackTaskList, t); - Task newFrontMostTask = getStackFrontMostTask(); + Task newFrontMostTask = getStackFrontMostTask(false /* includeFreeform */); if (mCb != null) { // Notify that a task has been removed mCb.onStackTaskRemoved(this, t, wasFrontMostTask, newFrontMostTask, animation); @@ -616,14 +616,14 @@ public class TaskStack { /** * Gets the front-most task in the stack. */ - public Task getStackFrontMostTask() { + public Task getStackFrontMostTask(boolean includeFreeformTasks) { ArrayList<Task> stackTasks = mStackTaskList.getTasks(); if (stackTasks.isEmpty()) { return null; } for (int i = stackTasks.size() - 1; i >= 0; i--) { Task task = stackTasks.get(i); - if (!task.isFreeformTask()) { + if (!task.isFreeformTask() || includeFreeformTasks) { return task; } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java index 809d4eed7a11..de045f46f9f9 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -1427,7 +1427,8 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } // Restore the action button visibility if it is the front most task view - if (mScreenPinningEnabled && tv.getTask() == mStack.getStackFrontMostTask()) { + if (mScreenPinningEnabled && tv.getTask() == + mStack.getStackFrontMostTask(false /* includeFreeform */)) { tv.showActionButton(false /* fadeIn */, 0 /* fadeInDuration */); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java new file mode 100644 index 000000000000..8e3886bcb2de --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.android.systemui.statusbar.phone; + +import com.android.systemui.statusbar.policy.KeyButtonView; + +import android.graphics.drawable.Drawable; +import android.view.View; +import android.widget.ImageView; + +import java.util.ArrayList; + +/** + * Dispatches common view calls to multiple views. This is used to handle + * multiples of the same nav bar icon appearing. + */ +public class ButtonDispatcher { + + private final ArrayList<View> mViews = new ArrayList<>(); + + private final int mId; + + private View.OnClickListener mClickListener; + private View.OnTouchListener mTouchListener; + private View.OnLongClickListener mLongClickListener; + private Boolean mLongClickable; + private Integer mAlpha; + private Integer mVisibility = -1; + private int mImageResource = -1; + private Drawable mImageDrawable; + private View mCurrentView; + + public ButtonDispatcher(int id) { + mId = id; + } + + void clear() { + mViews.clear(); + } + + void addView(View view) { + mViews.add(view); + view.setOnClickListener(mClickListener); + view.setOnTouchListener(mTouchListener); + view.setOnLongClickListener(mLongClickListener); + if (mLongClickable != null) { + view.setLongClickable(mLongClickable); + } + if (mAlpha != null) { + view.setAlpha(mAlpha); + } + if (mVisibility != null) { + view.setVisibility(mVisibility); + } + if (mImageResource > 0) { + ((ImageView) view).setImageResource(mImageResource); + } else if (mImageDrawable != null) { + ((ImageView) view).setImageDrawable(mImageDrawable); + } + } + + public int getId() { + return mId; + } + + public int getVisibility() { + return mVisibility; + } + + public float getAlpha() { + return mAlpha; + } + + public void setImageDrawable(Drawable drawable) { + mImageDrawable = drawable; + mImageResource = -1; + final int N = mViews.size(); + for (int i = 0; i < N; i++) { + ((ImageView) mViews.get(i)).setImageDrawable(mImageDrawable); + } + } + + public void setImageResource(int resource) { + mImageResource = resource; + mImageDrawable = null; + final int N = mViews.size(); + for (int i = 0; i < N; i++) { + ((ImageView) mViews.get(i)).setImageResource(mImageResource); + } + } + + public void setVisibility(int visibility) { + if (mVisibility == visibility) return; + mVisibility = visibility; + final int N = mViews.size(); + for (int i = 0; i < N; i++) { + mViews.get(i).setVisibility(mVisibility); + } + } + + public void abortCurrentGesture() { + // This seems to be an instantaneous thing, so not going to persist it. + final int N = mViews.size(); + for (int i = 0; i < N; i++) { + ((KeyButtonView) mViews.get(i)).abortCurrentGesture(); + } + } + + public void setAlpha(int alpha) { + mAlpha = alpha; + final int N = mViews.size(); + for (int i = 0; i < N; i++) { + mViews.get(i).setAlpha(alpha); + } + } + + public void setOnClickListener(View.OnClickListener clickListener) { + mClickListener = clickListener; + final int N = mViews.size(); + for (int i = 0; i < N; i++) { + mViews.get(i).setOnClickListener(mClickListener); + } + } + + public void setOnTouchListener(View.OnTouchListener touchListener) { + mTouchListener = touchListener; + final int N = mViews.size(); + for (int i = 0; i < N; i++) { + mViews.get(i).setOnTouchListener(mTouchListener); + } + } + + public void setLongClickable(boolean isLongClickable) { + mLongClickable = isLongClickable; + final int N = mViews.size(); + for (int i = 0; i < N; i++) { + mViews.get(i).setLongClickable(mLongClickable); + } + } + + public void setOnLongClickListener(View.OnLongClickListener longClickListener) { + mLongClickListener = longClickListener; + final int N = mViews.size(); + for (int i = 0; i < N; i++) { + mViews.get(i).setOnLongClickListener(mLongClickListener); + } + } + + public View getCurrentView() { + return mCurrentView; + } + + public void setCurrentView(View currentView) { + mCurrentView = currentView.findViewById(mId); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java index ae6a11ffd2ba..abe357ae004c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java @@ -164,12 +164,14 @@ public class NavigationBarGestureHelper extends GestureDetector.SimpleOnGestureL mTouchDownY = (int) event.getY(); if (mNavigationBarView != null) { - View recentsButton = mNavigationBarView.getRecentsButton(); + View recentsButton = mNavigationBarView.getRecentsButton().getCurrentView(); if (recentsButton != null) { mDownOnRecents = mTouchDownX >= recentsButton.getLeft() && mTouchDownX <= recentsButton.getRight() && mTouchDownY >= recentsButton.getTop() && mTouchDownY <= recentsButton.getBottom(); + } else { + mDownOnRecents = false; } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java new file mode 100644 index 000000000000..b8ae81f7c3fb --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java @@ -0,0 +1,266 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.android.systemui.statusbar.phone; + +import android.content.Context; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.util.AttributeSet; +import android.util.SparseArray; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.Space; +import com.android.systemui.R; +import com.android.systemui.tuner.TunerService; + +import java.util.Objects; + +public class NavigationBarInflaterView extends FrameLayout implements TunerService.Tunable { + + private static final String TAG = "NavBarInflater"; + + public static final String NAV_BAR_VIEWS = "sysui_nav_bar"; + + private static final String MENU_IME = "menu_ime"; + private static final String BACK = "back"; + private static final String HOME = "home"; + private static final String RECENT = "recent"; + private static final String NAVSPACE = "space"; + + public static final String GRAVITY_SEPARATOR = ";"; + public static final String BUTTON_SEPARATOR = ","; + + private final LayoutInflater mLayoutInflater; + private final LayoutInflater mLandscapeInflater; + + private FrameLayout mRot0; + private FrameLayout mRot90; + private SparseArray<ButtonDispatcher> mButtonDispatchers; + private String mCurrentLayout; + + public NavigationBarInflaterView(Context context, AttributeSet attrs) { + super(context, attrs); + mLayoutInflater = LayoutInflater.from(context); + Configuration landscape = new Configuration(); + landscape.setTo(context.getResources().getConfiguration()); + landscape.orientation = Configuration.ORIENTATION_LANDSCAPE; + mLandscapeInflater = LayoutInflater.from(context.createConfigurationContext(landscape)); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + mRot0 = (FrameLayout) findViewById(R.id.rot0); + mRot90 = (FrameLayout) findViewById(R.id.rot90); + clearViews(); + inflateLayout(getDefaultLayout()); + } + + private String getDefaultLayout() { + return mContext.getString(R.string.config_navBarLayout); + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + TunerService.get(getContext()).addTunable(this, NAV_BAR_VIEWS); + } + + @Override + protected void onDetachedFromWindow() { + TunerService.get(getContext()).removeTunable(this); + super.onDetachedFromWindow(); + } + + @Override + public void onTuningChanged(String key, String newValue) { + if (NAV_BAR_VIEWS.equals(key)) { + if (newValue == null) { + newValue = getDefaultLayout(); + } + if (!Objects.equals(mCurrentLayout, newValue)) { + clearViews(); + inflateLayout(newValue); + } + } + } + + public void setButtonDispatchers(SparseArray<ButtonDispatcher> buttonDisatchers) { + mButtonDispatchers = buttonDisatchers; + for (int i = 0; i < buttonDisatchers.size(); i++) { + initiallyFill(buttonDisatchers.valueAt(i)); + } + } + + private void initiallyFill(ButtonDispatcher buttonDispatcher) { + addAll(buttonDispatcher, (ViewGroup) mRot0.findViewById(R.id.start_group)); + addAll(buttonDispatcher, (ViewGroup) mRot0.findViewById(R.id.center_group)); + addAll(buttonDispatcher, (ViewGroup) mRot0.findViewById(R.id.end_group)); + addAll(buttonDispatcher, (ViewGroup) mRot90.findViewById(R.id.start_group)); + addAll(buttonDispatcher, (ViewGroup) mRot90.findViewById(R.id.center_group)); + addAll(buttonDispatcher, (ViewGroup) mRot90.findViewById(R.id.end_group)); + } + + private void addAll(ButtonDispatcher buttonDispatcher, ViewGroup parent) { + for (int i = 0; i < parent.getChildCount(); i++) { + // Need to manually search for each id, just in case each group has more than one + // of a single id. It probably mostly a waste of time, but shouldn't take long + // and will only happen once. + if (parent.getChildAt(i).getId() == buttonDispatcher.getId()) { + buttonDispatcher.addView(parent.getChildAt(i)); + } else if (parent.getChildAt(i) instanceof ViewGroup) { + addAll(buttonDispatcher, (ViewGroup) parent.getChildAt(i)); + } + } + } + + private void inflateLayout(String newLayout) { + mCurrentLayout = newLayout; + String[] sets = newLayout.split(GRAVITY_SEPARATOR); + String[] start = sets[0].split(BUTTON_SEPARATOR); + String[] center = sets[1].split(BUTTON_SEPARATOR); + String[] end = sets[2].split(BUTTON_SEPARATOR); + inflateButtons(start, (ViewGroup) mRot0.findViewById(R.id.start_group), + (ViewGroup) mRot0.findViewById(R.id.start_group_lightsout), false); + inflateButtons(start, (ViewGroup) mRot90.findViewById(R.id.start_group), + (ViewGroup) mRot90.findViewById(R.id.start_group_lightsout), true); + inflateButtons(center, (ViewGroup) mRot0.findViewById(R.id.center_group), + (ViewGroup) mRot0.findViewById(R.id.start_group_lightsout), false); + inflateButtons(center, (ViewGroup) mRot90.findViewById(R.id.center_group), + (ViewGroup) mRot90.findViewById(R.id.start_group_lightsout), true); + inflateButtons(end, (ViewGroup) mRot0.findViewById(R.id.end_group), + (ViewGroup) mRot0.findViewById(R.id.start_group_lightsout), false); + inflateButtons(end, (ViewGroup) mRot90.findViewById(R.id.end_group), + (ViewGroup) mRot90.findViewById(R.id.start_group_lightsout), true); + } + + private void inflateButtons(String[] buttons, ViewGroup parent, ViewGroup lightsOutParent, + boolean landscape) { + for (int i = 0; i < buttons.length; i++) { + copyToLightsout(inflateButton(buttons[i], parent, landscape), lightsOutParent); + } + } + + private void copyToLightsout(View view, ViewGroup lightsOutParent) { + if (view instanceof FrameLayout) { + // The only ViewGroup we support in here is a FrameLayout, so copy those manually. + FrameLayout original = (FrameLayout) view; + FrameLayout layout = new FrameLayout(view.getContext()); + for (int i = 0; i < original.getChildCount(); i++) { + copyToLightsout(original.getChildAt(i), layout); + } + lightsOutParent.addView(layout, copy(view.getLayoutParams())); + } else if (view instanceof Space) { + lightsOutParent.addView(new Space(view.getContext()), copy(view.getLayoutParams())); + } else { + lightsOutParent.addView(generateLightsOutView(view), copy(view.getLayoutParams())); + } + } + + private View generateLightsOutView(View view) { + ImageView imageView = new ImageView(view.getContext()); + // Copy everything we can about the original view. + imageView.setPadding(view.getPaddingLeft(), view.getPaddingTop(), view.getPaddingRight(), + view.getPaddingBottom()); + imageView.setContentDescription(view.getContentDescription()); + imageView.setId(view.getId()); + // Only home gets a big dot, everything else will be little. + imageView.setImageResource(view.getId() == R.id.home + ? R.drawable.ic_sysbar_lights_out_dot_large + : R.drawable.ic_sysbar_lights_out_dot_small); + return imageView; + } + + private ViewGroup.LayoutParams copy(ViewGroup.LayoutParams layoutParams) { + return new LayoutParams(layoutParams.width, layoutParams.height); + } + + private View inflateButton(String button, ViewGroup parent, boolean landscape) { + View v = null; + if (HOME.equals(button)) { + v = (landscape ? mLandscapeInflater : mLayoutInflater) + .inflate(R.layout.home, parent, false); + if (landscape && isSw600Dp()) { + setupLandButton(v); + } + } else if (BACK.equals(button)) { + v = (landscape ? mLandscapeInflater : mLayoutInflater) + .inflate(R.layout.back, parent, false); + if (landscape && isSw600Dp()) { + setupLandButton(v); + } + } else if (RECENT.equals(button)) { + v = (landscape ? mLandscapeInflater : mLayoutInflater) + .inflate(R.layout.recent_apps, parent, false); + if (landscape && isSw600Dp()) { + setupLandButton(v); + } + } else if (MENU_IME.equals(button)) { + v = (landscape ? mLandscapeInflater : mLayoutInflater) + .inflate(R.layout.menu_ime, parent, false); + } else if (NAVSPACE.equals(button)) { + v = (landscape ? mLandscapeInflater : mLayoutInflater) + .inflate(R.layout.nav_key_space, parent, false); + } else { + throw new IllegalArgumentException("Unknown button " + button); + } + parent.addView(v); + if (mButtonDispatchers != null) { + final int indexOfKey = mButtonDispatchers.indexOfKey(v.getId()); + if (indexOfKey >= 0) { + mButtonDispatchers.valueAt(indexOfKey).addView(v); + } + } + return v; + } + + private boolean isSw600Dp() { + Configuration configuration = mContext.getResources().getConfiguration(); + return (configuration.smallestScreenWidthDp >= 600); + } + + /** + * This manually sets the width of sw600dp landscape buttons because despite + * overriding the configuration from the overridden resources aren't loaded currently. + */ + private void setupLandButton(View v) { + Resources res = mContext.getResources(); + v.getLayoutParams().width = res.getDimensionPixelOffset( + R.dimen.navigation_key_width_sw600dp_land); + int padding = res.getDimensionPixelOffset(R.dimen.navigation_key_padding_sw600dp_land); + v.setPadding(padding, v.getPaddingTop(), padding, v.getPaddingBottom()); + } + + private void clearViews() { + if (mButtonDispatchers != null) { + for (int i = 0; i < mButtonDispatchers.size(); i++) { + mButtonDispatchers.valueAt(i).clear(); + } + } + clearAllChildren((ViewGroup) mRot0.findViewById(R.id.nav_buttons)); + clearAllChildren((ViewGroup) mRot0.findViewById(R.id.lights_out)); + clearAllChildren((ViewGroup) mRot90.findViewById(R.id.nav_buttons)); + clearAllChildren((ViewGroup) mRot90.findViewById(R.id.lights_out)); + } + + private void clearAllChildren(ViewGroup group) { + for (int i = 0; i < group.getChildCount(); i++) { + ((ViewGroup) group.getChildAt(i)).removeAllViews(); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java index 5309903266aa..839b57956f9a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -35,6 +35,7 @@ import android.os.Message; import android.os.RemoteException; import android.util.AttributeSet; import android.util.Log; +import android.util.SparseArray; import android.view.Display; import android.view.Gravity; import android.view.IDockedStackListener.Stub; @@ -45,15 +46,11 @@ import android.view.ViewGroup; import android.view.WindowManager; import android.view.WindowManagerGlobal; import android.view.inputmethod.InputMethodManager; -import android.widget.FrameLayout; -import android.widget.ImageView; import android.widget.LinearLayout; - import com.android.systemui.R; import com.android.systemui.RecentsComponent; import com.android.systemui.stackdivider.Divider; import com.android.systemui.statusbar.policy.DeadZone; -import com.android.systemui.statusbar.policy.KeyButtonView; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -101,6 +98,8 @@ public class NavigationBarView extends LinearLayout { private boolean mWakeAndUnlocking; private boolean mCarMode = false; + private final SparseArray<ButtonDispatcher> mButtonDisatchers = new SparseArray<>(); + private class NavTransitionListener implements TransitionListener { private boolean mBackTransitioning; private boolean mHomeAppearing; @@ -132,13 +131,12 @@ public class NavigationBarView extends LinearLayout { } public void onBackAltCleared() { - View backButton = getBackButton(); - View homeButton = getHomeButton(); + ButtonDispatcher backButton = getBackButton(); // When dismissing ime during unlock, force the back button to run the same appearance // animation as home (if we catch this condition early enough). - if (backButton != null && !mBackTransitioning && backButton.getVisibility() == VISIBLE - && mHomeAppearing && homeButton != null && getHomeButton().getAlpha() == 0) { + if (!mBackTransitioning && backButton.getVisibility() == VISIBLE + && mHomeAppearing && getHomeButton().getAlpha() == 0) { getBackButton().setAlpha(0); ValueAnimator a = ObjectAnimator.ofFloat(backButton, "alpha", 0, 1); a.setStartDelay(mStartDelay); @@ -194,6 +192,12 @@ public class NavigationBarView extends LinearLayout { getIcons(context); mBarTransitions = new NavigationBarTransitions(this); + + mButtonDisatchers.put(R.id.back, new ButtonDispatcher(R.id.back)); + mButtonDisatchers.put(R.id.home, new ButtonDispatcher(R.id.home)); + mButtonDisatchers.put(R.id.recent_apps, new ButtonDispatcher(R.id.recent_apps)); + mButtonDisatchers.put(R.id.menu, new ButtonDispatcher(R.id.menu)); + mButtonDisatchers.put(R.id.ime_switcher, new ButtonDispatcher(R.id.ime_switcher)); } public BarTransitions getBarTransitions() { @@ -226,10 +230,7 @@ public class NavigationBarView extends LinearLayout { } public void abortCurrentGesture() { - View homeButton = getHomeButton(); - if (homeButton != null) { - getHomeButton().abortCurrentGesture(); - } + getHomeButton().abortCurrentGesture(); } private H mHandler = new H(); @@ -242,31 +243,24 @@ public class NavigationBarView extends LinearLayout { return mRotatedViews; } - // The following Buttons can possibly return null if NavigationBarView is extended to provide - // a different layout and the buttons do not exist in that new layout. - @Nullable - public KeyButtonView getRecentsButton() { - return (KeyButtonView) getCurrentView().findViewById(R.id.recent_apps); + public ButtonDispatcher getRecentsButton() { + return mButtonDisatchers.get(R.id.recent_apps); } - @Nullable - public View getMenuButton() { - return getCurrentView().findViewById(R.id.menu); + public ButtonDispatcher getMenuButton() { + return mButtonDisatchers.get(R.id.menu); } - @Nullable - public View getBackButton() { - return getCurrentView().findViewById(R.id.back); + public ButtonDispatcher getBackButton() { + return mButtonDisatchers.get(R.id.back); } - @Nullable - public KeyButtonView getHomeButton() { - return (KeyButtonView) getCurrentView().findViewById(R.id.home); + public ButtonDispatcher getHomeButton() { + return mButtonDisatchers.get(R.id.home); } - @Nullable - public View getImeSwitchButton() { - return getCurrentView().findViewById(R.id.ime_switcher); + public ButtonDispatcher getImeSwitchButton() { + return mButtonDisatchers.get(R.id.ime_switcher); } @Nullable @@ -344,26 +338,19 @@ public class NavigationBarView extends LinearLayout { ? getBackIconWithAlt(mCarMode, mVertical) : getBackIcon(mCarMode, mVertical); - View backButton = getBackButton(); - if (backButton != null && backButton instanceof ImageView) { - ((ImageView) backButton).setImageDrawable(backIcon); - } + getBackButton().setImageDrawable(backIcon); - ImageView recentsButton = getRecentsButton(); - if (recentsButton != null) { - recentsButton.setImageDrawable(mVertical ? mRecentLandIcon : mRecentIcon); - } + getRecentsButton().setImageDrawable( + mVertical ? mRecentLandIcon : mRecentIcon); - ImageView homeButton = getHomeButton(); - if (homeButton != null) { - homeButton.setImageDrawable(mCarMode ? mHomeCarModeIcon : mHomeDefaultIcon); + if (mCarMode) { + getHomeButton().setImageDrawable(mHomeCarModeIcon); + } else { + getHomeButton().setImageDrawable(mHomeDefaultIcon); } final boolean showImeButton = ((hints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) != 0); - View imeSwitchButton = getImeSwitchButton(); - if (imeSwitchButton != null) { - imeSwitchButton.setVisibility(showImeButton ? View.VISIBLE : View.INVISIBLE); - } + getImeSwitchButton().setVisibility(showImeButton ? View.VISIBLE : View.INVISIBLE); // Update menu button in case the IME state has changed. setMenuVisibility(mShowMenu, true); @@ -405,20 +392,9 @@ public class NavigationBarView extends LinearLayout { disableRecent = false; } - View backButton = getBackButton(); - if (backButton != null) { - backButton.setVisibility(disableBack ? View.INVISIBLE : View.VISIBLE); - } - - View homeButton = getHomeButton(); - if (homeButton != null) { - homeButton.setVisibility(disableHome ? View.INVISIBLE : View.VISIBLE); - } - - View recentsButton = getRecentsButton(); - if (recentsButton != null) { - recentsButton.setVisibility(disableRecent ? View.INVISIBLE : View.VISIBLE); - } + getBackButton().setVisibility(disableBack ? View.INVISIBLE : View.VISIBLE); + getHomeButton().setVisibility(disableHome ? View.INVISIBLE : View.VISIBLE); + getRecentsButton().setVisibility(disableRecent ? View.INVISIBLE : View.VISIBLE); // The app shelf, if it exists, follows the visibility of the home button. View appShelf = getAppShelf(); @@ -510,10 +486,7 @@ public class NavigationBarView extends LinearLayout { final boolean shouldShow = mShowMenu && ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) == 0); - View menuButton = getMenuButton(); - if (menuButton != null) { - menuButton.setVisibility(shouldShow ? View.VISIBLE : View.INVISIBLE); - } + getMenuButton().setVisibility(shouldShow ? View.VISIBLE : View.INVISIBLE); } @Override @@ -526,11 +499,13 @@ public class NavigationBarView extends LinearLayout { mRotatedViews[Surface.ROTATION_270] = mRotatedViews[Surface.ROTATION_90]; mCurrentView = mRotatedViews[Surface.ROTATION_0]; - - View imeSwitchButton = getImeSwitchButton(); - if (imeSwitchButton != null) { - imeSwitchButton.setOnClickListener(mImeSwitcherClickListener); + for (int i = 0; i < mButtonDisatchers.size(); i++) { + mButtonDisatchers.valueAt(i).setCurrentView(mCurrentView); } + ((NavigationBarInflaterView) findViewById(R.id.navigation_inflater)).setButtonDispatchers( + mButtonDisatchers); + + getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener); updateRTLOrder(); @@ -556,13 +531,9 @@ public class NavigationBarView extends LinearLayout { } private void updateRecentsIcon(boolean dockedStackExists) { - ImageView recentsButton = getRecentsButton(); - - if (recentsButton != null) { - recentsButton.setImageResource(dockedStackExists - ? R.drawable.ic_sysbar_docked - : R.drawable.ic_sysbar_recent); - } + getRecentsButton().setImageResource(dockedStackExists + ? R.drawable.ic_sysbar_docked + : R.drawable.ic_sysbar_recent); } public boolean isVertical() { @@ -576,12 +547,12 @@ public class NavigationBarView extends LinearLayout { } mCurrentView = mRotatedViews[rot]; mCurrentView.setVisibility(View.VISIBLE); + for (int i = 0; i < mButtonDisatchers.size(); i++) { + mButtonDisatchers.valueAt(i).setCurrentView(mCurrentView); + } updateLayoutTransitionsEnabled(); - View imeSwitchButton = getImeSwitchButton(); - if (imeSwitchButton != null) { - imeSwitchButton.setOnClickListener(mImeSwitcherClickListener); - } + getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener); mDeadZone = (DeadZone) mCurrentView.findViewById(R.id.deadzone); @@ -669,33 +640,16 @@ public class NavigationBarView extends LinearLayout { // We swap all children of the 90 and 270 degree layouts, since they are vertical View rotation90 = mRotatedViews[Surface.ROTATION_90]; - swapChildrenOrderIfVertical(rotation90.findViewById(R.id.nav_buttons)); - adjustExtraKeyGravity(rotation90, isLayoutRtl); + swapChildrenOrderIfVertical(rotation90); View rotation270 = mRotatedViews[Surface.ROTATION_270]; if (rotation90 != rotation270) { - swapChildrenOrderIfVertical(rotation270.findViewById(R.id.nav_buttons)); - adjustExtraKeyGravity(rotation270, isLayoutRtl); + swapChildrenOrderIfVertical(rotation270); } mIsLayoutRtl = isLayoutRtl; } } - private void adjustExtraKeyGravity(View navBar, boolean isLayoutRtl) { - View menu = navBar.findViewById(R.id.menu); - View imeSwitcher = navBar.findViewById(R.id.ime_switcher); - if (menu != null) { - FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) menu.getLayoutParams(); - lp.gravity = isLayoutRtl ? Gravity.BOTTOM : Gravity.TOP; - menu.setLayoutParams(lp); - } - if (imeSwitcher != null) { - FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) imeSwitcher.getLayoutParams(); - lp.gravity = isLayoutRtl ? Gravity.BOTTOM : Gravity.TOP; - imeSwitcher.setLayoutParams(lp); - } - } - /** * Swaps the children order of a LinearLayout if it's orientation is Vertical * @@ -705,6 +659,11 @@ public class NavigationBarView extends LinearLayout { if (group instanceof LinearLayout) { LinearLayout linearLayout = (LinearLayout) group; if (linearLayout.getOrientation() == VERTICAL) { + if ((linearLayout.getGravity() & Gravity.TOP) != 0) { + linearLayout.setGravity(Gravity.BOTTOM); + } else if ((linearLayout.getGravity() & Gravity.BOTTOM) != 0) { + linearLayout.setGravity(Gravity.TOP); + } int childCount = linearLayout.getChildCount(); ArrayList<View> childList = new ArrayList<>(childCount); for (int i = 0; i < childCount; i++) { @@ -715,6 +674,11 @@ public class NavigationBarView extends LinearLayout { linearLayout.addView(childList.get(i)); } } + } else if (group instanceof ViewGroup) { + ViewGroup viewGroup = (ViewGroup) group; + for (int i = 0; i < viewGroup.getChildCount(); i++) { + swapChildrenOrderIfVertical(viewGroup.getChildAt(i)); + } } } @@ -802,13 +766,12 @@ public class NavigationBarView extends LinearLayout { pw.println(" }"); } - private static void dumpButton(PrintWriter pw, String caption, View button) { + private static void dumpButton(PrintWriter pw, String caption, ButtonDispatcher button) { pw.print(" " + caption + ": "); if (button == null) { pw.print("null"); } else { - pw.print(PhoneStatusBar.viewInfo(button) - + " " + visibilityToString(button.getVisibility()) + pw.print(visibilityToString(button.getVisibility()) + " alpha=" + button.getAlpha() ); } @@ -818,4 +781,5 @@ public class NavigationBarView extends LinearLayout { public interface OnVerticalChangedListener { void onVerticalChanged(boolean isVertical); } + } 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 71b6713aaba5..ffc836c7bbf8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -293,7 +293,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, Display mDisplay; Point mCurrentDisplaySize = new Point(); - StatusBarWindowView mStatusBarWindow; + protected StatusBarWindowView mStatusBarWindow; PhoneStatusBarView mStatusBarView; private int mStatusBarWindowState = WINDOW_STATE_SHOWING; protected StatusBarWindowManager mStatusBarWindowManager; @@ -673,8 +673,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, updateDisplaySize(); // populates mDisplayMetrics updateResources(); - mStatusBarWindow = (StatusBarWindowView) View.inflate(context, - R.layout.super_status_bar, null); + inflateStatusBarWindow(context); mStatusBarWindow.setService(this); mStatusBarWindow.setOnTouchListener(new View.OnTouchListener() { @Override @@ -935,6 +934,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, return mStatusBarView; } + protected void inflateStatusBarWindow(Context context) { + mStatusBarWindow = (StatusBarWindowView) View.inflate(context, + R.layout.super_status_bar, null); + } + protected void createNavigationBarView(Context context) { inflateNavigationBarView(context); mNavigationBarView.setDisabledFlags(mDisabled1); @@ -1185,25 +1189,19 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, private void prepareNavigationBarView() { mNavigationBarView.reorient(); - View recentsButton = mNavigationBarView.getRecentsButton(); - if (recentsButton != null) { - recentsButton.setOnClickListener(mRecentsClickListener); - recentsButton.setOnTouchListener(mRecentsPreloadOnTouchListener); - recentsButton.setLongClickable(true); - recentsButton.setOnLongClickListener(mRecentsLongClickListener); - } + ButtonDispatcher recentsButton = mNavigationBarView.getRecentsButton(); + recentsButton.setOnClickListener(mRecentsClickListener); + recentsButton.setOnTouchListener(mRecentsPreloadOnTouchListener); + recentsButton.setLongClickable(true); + recentsButton.setOnLongClickListener(mRecentsLongClickListener); - View backButton = mNavigationBarView.getBackButton(); - if (backButton != null) { - backButton.setLongClickable(true); - backButton.setOnLongClickListener(mLongPressBackListener); - } + ButtonDispatcher backButton = mNavigationBarView.getBackButton(); + backButton.setLongClickable(true); + backButton.setOnLongClickListener(mLongPressBackListener); - View homeButton = mNavigationBarView.getHomeButton(); - if (homeButton != null) { - homeButton.setOnTouchListener(mHomeActionListener); - homeButton.setOnLongClickListener(mLongPressHomeListener); - } + ButtonDispatcher homeButton = mNavigationBarView.getHomeButton(); + homeButton.setOnTouchListener(mHomeActionListener); + homeButton.setOnLongClickListener(mLongPressHomeListener); mAssistManager.onConfigurationChanged(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ReverseLinearLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ReverseLinearLayout.java new file mode 100644 index 000000000000..da16954d0d46 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ReverseLinearLayout.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package com.android.systemui.statusbar.phone; + +import android.annotation.Nullable; +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; + +/** + * Automatically reverses the order of children as they are added. + * Also reverse the width and height values of layout params + */ +public class ReverseLinearLayout extends LinearLayout { + + public ReverseLinearLayout(Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + } + + @Override + public void addView(View child) { + reversParams(child.getLayoutParams()); + super.addView(child, 0); + } + + @Override + public void addView(View child, ViewGroup.LayoutParams params) { + reversParams(params); + super.addView(child, 0, params); + } + + private void reversParams(ViewGroup.LayoutParams params) { + if (params == null) { + return; + } + int width = params.width; + params.width = params.height; + params.height = width; + } + +} diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java index 234c94e6faa7..d63dd0c8d03a 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerService.java +++ b/services/backup/java/com/android/server/backup/BackupManagerService.java @@ -676,8 +676,13 @@ public class BackupManagerService { return true; } + // Checks if the app is in a stopped state, that means it won't receive broadcasts. + private static boolean appIsStopped(ApplicationInfo app) { + return ((app.flags & ApplicationInfo.FLAG_STOPPED) != 0); + } + /* does *not* check overall backup eligibility policy! */ - public static boolean appGetsFullBackup(PackageInfo pkg) { + private static boolean appGetsFullBackup(PackageInfo pkg) { if (pkg.applicationInfo.backupAgentName != null) { // If it has an agent, it gets full backups only if it says so return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_FULL_BACKUP_ONLY) != 0; @@ -2758,7 +2763,7 @@ public class BackupManagerService { return; } - if ((mCurrentPackage.applicationInfo.flags & ApplicationInfo.FLAG_STOPPED) != 0) { + if (appIsStopped(mCurrentPackage.applicationInfo)) { // The app has been force-stopped or cleared or just installed, // and not yet launched out of that state, so just as it won't // receive broadcasts, we won't run it for backup. @@ -4179,28 +4184,18 @@ public class BackupManagerService { try { PackageInfo info = mPackageManager.getPackageInfo(pkg, PackageManager.GET_SIGNATURES); - if ((info.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0 - || pkg.equals(SHARED_BACKUP_AGENT_PACKAGE)) { + if (!appIsEligibleForBackup(info.applicationInfo)) { // Cull any packages that have indicated that backups are not permitted, + // that run as system-domain uids but do not define their own backup agents, // as well as any explicit mention of the 'special' shared-storage agent // package (we handle that one at the end). if (MORE_DEBUG) { - Slog.d(TAG, "Ignoring opted-out package " + pkg); - } - sendBackupOnResult(mBackupObserver, pkg, - BackupManager.ERROR_BACKUP_NOT_ALLOWED); - continue; - } else if ((info.applicationInfo.uid < Process.FIRST_APPLICATION_UID) - && (info.applicationInfo.backupAgentName == null)) { - // Cull any packages that run as system-domain uids but do not define their - // own backup agents - if (MORE_DEBUG) { - Slog.d(TAG, "Ignoring non-agent system package " + pkg); + Slog.d(TAG, "Ignoring not eligible package " + pkg); } sendBackupOnResult(mBackupObserver, pkg, - BackupManager.ERROR_BACKUP_NOT_ALLOWED); + BackupManager.ERROR_BACKUP_NOT_ALLOWED); continue; - } else if ((info.applicationInfo.flags & ApplicationInfo.FLAG_STOPPED) != 0) { + } else if (appIsStopped(info.applicationInfo)) { // Cull any packages in the 'stopped' state: they've either just been // installed or have explicitly been force-stopped by the user. In both // cases we do not want to launch them for backup. @@ -9538,6 +9533,32 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF } } + public boolean isAppEligibleForBackup(String packageName) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, + "isAppEligibleForBackup"); + try { + PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName, + PackageManager.GET_SIGNATURES); + if (!appIsEligibleForBackup(packageInfo.applicationInfo) || + appIsStopped(packageInfo.applicationInfo)) { + return false; + } + IBackupTransport transport = getTransport(mCurrentTransport); + if (transport != null) { + try { + return transport.isAppEligibleForBackup(packageInfo, + appGetsFullBackup(packageInfo)); + } catch (RemoteException e) { + Slog.e(TAG, "Unable to contact transport"); + } + } + // If transport is not present we couldn't tell that the package is not eligible. + return true; + } catch (NameNotFoundException e) { + return false; + } + } + // ----- Restore session ----- class ActiveRestoreSession extends IRestoreSession.Stub { diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java index 505a1a53d25f..bbf881be102f 100644 --- a/services/backup/java/com/android/server/backup/Trampoline.java +++ b/services/backup/java/com/android/server/backup/Trampoline.java @@ -326,6 +326,12 @@ public class Trampoline extends IBackupManager.Stub { } @Override + public boolean isAppEligibleForBackup(String packageName) { + BackupManagerService svc = mService; + return (svc != null) ? svc.isAppEligibleForBackup(packageName) : false; + } + + @Override public int requestBackup(String[] packages, IBackupObserver observer) throws RemoteException { BackupManagerService svc = mService; return (svc != null) ? svc.requestBackup(packages, observer) : null; diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index eb759140bbf6..f68a2996541d 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -67,6 +67,7 @@ import android.content.pm.ServiceInfo; import android.content.pm.UserInfo; import android.database.ContentObserver; import android.graphics.Bitmap; +import android.graphics.Color; import android.media.AudioManager; import android.media.IAudioService; import android.net.ConnectivityManager; @@ -487,6 +488,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private static final String TAG_SHORT_SUPPORT_MESSAGE = "short-support-message"; private static final String TAG_LONG_SUPPORT_MESSAGE = "long-support-message"; private static final String TAG_PARENT_ADMIN = "parent-admin"; + private static final String TAG_ORGANIZATION_COLOR = "organization-color"; final DeviceAdminInfo info; @@ -580,6 +582,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { String shortSupportMessage = null; String longSupportMessage = null; + // Background color of confirm credentials screen. Default: gray. + static final int DEF_ORGANIZATION_COLOR = Color.GRAY; + int organizationColor = DEF_ORGANIZATION_COLOR; + ActiveAdmin(DeviceAdminInfo _info, boolean parent) { info = _info; isParent = parent; @@ -787,6 +793,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { parentAdmin.writeToXml(out); out.endTag(null, TAG_PARENT_ADMIN); } + if (organizationColor != DEF_ORGANIZATION_COLOR) { + out.startTag(null, TAG_ORGANIZATION_COLOR); + out.attribute(null, ATTR_VALUE, Integer.toString(organizationColor)); + out.endTag(null, TAG_ORGANIZATION_COLOR); + } } void writePackageListToXml(XmlSerializer out, String outerTag, @@ -920,6 +931,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } else if (TAG_PARENT_ADMIN.equals(tag)) { parentAdmin = new ActiveAdmin(info, /* parent */ true); parentAdmin.readFromXml(parser); + } else if (TAG_ORGANIZATION_COLOR.equals(tag)) { + organizationColor = Integer.parseInt( + parser.getAttributeValue(null, ATTR_VALUE)); } else { Slog.w(LOG_TAG, "Unknown admin tag: " + tag); XmlUtils.skipCurrentTag(parser); @@ -7685,4 +7699,46 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } return null; } + + @Override + public void setOrganizationColor(@NonNull ComponentName who, int color) { + final int userHandle = mInjector.userHandleGetCallingUserId(); + if (!mHasFeature || !isManagedProfile(userHandle)) { + return; + } + Preconditions.checkNotNull(who, "ComponentName is null"); + synchronized (this) { + ActiveAdmin admin = getActiveAdminForCallerLocked(who, + DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); + admin.organizationColor = color; + saveSettingsLocked(userHandle); + } + } + + @Override + public int getOrganizationColor(@NonNull ComponentName who) { + final int userHandle = mInjector.userHandleGetCallingUserId(); + if (!mHasFeature || !isManagedProfile(userHandle)) { + return ActiveAdmin.DEF_ORGANIZATION_COLOR; + } + synchronized (this) { + ActiveAdmin admin = getActiveAdminForCallerLocked(who, + DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); + return admin.organizationColor; + } + } + + @Override + public int getOrganizationColorForUser(int userHandle) { + if (!mHasFeature || !isManagedProfile(userHandle)) { + return ActiveAdmin.DEF_ORGANIZATION_COLOR; + } + enforceCrossUsersPermission(userHandle); + synchronized (this) { + ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userHandle); + return (profileOwner != null) + ? profileOwner.organizationColor + : ActiveAdmin.DEF_ORGANIZATION_COLOR; + } + } } diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java index 08258c99c25e..037ce57ced1b 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java @@ -492,6 +492,11 @@ public class BridgePackageManager extends PackageManager { } @Override + public Drawable getUserBadgeForDensityNoBackground(UserHandle user, int density) { + return null; + } + + @Override public CharSequence getUserBadgedLabel(CharSequence label, UserHandle user) { return null; } |