diff options
144 files changed, 3342 insertions, 2514 deletions
@@ -705,7 +705,7 @@ $(full_target): $(framework_built) $(gen) $(INTERNAL_PLATFORM_API_FILE): $(full_target) $(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_API_FILE)) -# ==== the private api stubs =================================== +# ==== the system api stubs =================================== include $(CLEAR_VARS) LOCAL_SRC_FILES:=$(framework_docs_LOCAL_API_CHECK_SRC_FILES) @@ -717,11 +717,11 @@ LOCAL_DROIDDOC_HTML_DIR:=$(framework_docs_LOCAL_DROIDDOC_HTML_DIR) LOCAL_ADDITIONAL_JAVA_DIR:=$(framework_docs_LOCAL_API_CHECK_ADDITIONAL_JAVA_DIR) LOCAL_ADDITIONAL_DEPENDENCIES:=$(framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES) -LOCAL_MODULE := private-api-stubs +LOCAL_MODULE := system-api-stubs LOCAL_DROIDDOC_OPTIONS:=\ $(framework_docs_LOCAL_DROIDDOC_OPTIONS) \ - -stubs $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android_private_stubs_current_intermediates/src \ + -stubs $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/android_system_stubs_current_intermediates/src \ -showAnnotation android.annotation.SystemApi \ -nodocs diff --git a/api/current.txt b/api/current.txt index a09a853..2f813ac 100644 --- a/api/current.txt +++ b/api/current.txt @@ -7041,6 +7041,7 @@ package android.content { field public static final java.lang.String SEARCH_SERVICE = "search"; field public static final java.lang.String SENSOR_SERVICE = "sensor"; field public static final java.lang.String STORAGE_SERVICE = "storage"; + field public static final java.lang.String TELECOMM_SERVICE = "telecomm"; field public static final java.lang.String TELEPHONY_SERVICE = "phone"; field public static final java.lang.String TEXT_SERVICES_MANAGER_SERVICE = "textservices"; field public static final java.lang.String TV_INPUT_SERVICE = "tv_input"; @@ -27675,6 +27676,7 @@ package android.telecomm { field public static final java.lang.String ACTION_CALL_SERVICE; field public static final java.lang.String ACTION_CALL_SERVICE_PROVIDER; field public static final java.lang.String ACTION_CALL_SERVICE_SELECTOR; + field public static final java.lang.String ACTION_CHANGE_DEFAULT_PHONE = "android.telecomm.ACTION_CHANGE_DEFAULT_PHONE"; field public static final java.lang.String ACTION_INCOMING_CALL = "android.intent.action.INCOMING_CALL"; field public static final char DTMF_CHARACTER_PAUSE = 44; // 0x002c ',' field public static final char DTMF_CHARACTER_WAIT = 59; // 0x003b ';' @@ -27682,6 +27684,10 @@ package android.telecomm { field public static final java.lang.String EXTRA_CALL_DISCONNECT_MESSAGE = "android.telecomm.extra.CALL_DISCONNECT_MESSAGE"; field public static final java.lang.String EXTRA_CALL_SERVICE_DESCRIPTOR = "android.intent.extra.CALL_SERVICE_DESCRIPTOR"; field public static final java.lang.String EXTRA_INCOMING_CALL_EXTRAS = "android.intent.extra.INCOMING_CALL_EXTRAS"; + field public static final java.lang.String EXTRA_PACKAGE_NAME = "package"; + } + + public class TelecommManager { } } @@ -33084,7 +33090,7 @@ package android.view { method public abstract boolean onTouch(android.view.View, android.view.MotionEvent); } - public class ViewAnimationUtils { + public final class ViewAnimationUtils { method public static final android.animation.ValueAnimator createCircularReveal(android.view.View, int, int, float, float); } @@ -35188,12 +35194,25 @@ package android.webkit { method public void onRequestFocus(android.webkit.WebView); method public void onShowCustomView(android.view.View, android.webkit.WebChromeClient.CustomViewCallback); method public deprecated void onShowCustomView(android.view.View, int, android.webkit.WebChromeClient.CustomViewCallback); + method public boolean showFileChooser(android.webkit.WebView, android.webkit.ValueCallback<android.net.Uri[]>, android.webkit.WebChromeClient.FileChooserParams); } public static abstract interface WebChromeClient.CustomViewCallback { method public abstract void onCustomViewHidden(); } + public static class WebChromeClient.FileChooserParams { + ctor public WebChromeClient.FileChooserParams(); + field public static final int MODE_OPEN_FOLDER = 2; // 0x2 + field public static final int MODE_OPEN_MULTIPLE = 1; // 0x1 + field public static final int MODE_SAVE = 4; // 0x4 + field public java.lang.String acceptTypes; + field public boolean capture; + field public java.lang.String defaultFilename; + field public int mode; + field public java.lang.String title; + } + public class WebHistoryItem implements java.lang.Cloneable { method public android.graphics.Bitmap getFavicon(); method public java.lang.String getOriginalUrl(); @@ -37749,6 +37768,7 @@ package android.widget { method public float getShadowDx(); method public float getShadowDy(); method public float getShadowRadius(); + method public final boolean getShowSoftInputOnFocus(); method public java.lang.CharSequence getText(); method public static int getTextColor(android.content.Context, android.content.res.TypedArray, int); method public final android.content.res.ColorStateList getTextColors(); @@ -37842,6 +37862,7 @@ package android.widget { method public void setScroller(android.widget.Scroller); method public void setSelectAllOnFocus(boolean); method public void setShadowLayer(float, float, float, int); + method public final void setShowSoftInputOnFocus(boolean); method public void setSingleLine(); method public void setSingleLine(boolean); method public final void setSpannableFactory(android.text.Spannable.Factory); @@ -40007,109 +40028,6 @@ package java.lang { field public static final java.lang.Character.UnicodeBlock YI_SYLLABLES; } - public static final class Character.UnicodeScript extends java.lang.Enum { - method public static java.lang.Character.UnicodeScript forName(java.lang.String); - method public static java.lang.Character.UnicodeScript of(int); - method public static java.lang.Character.UnicodeScript valueOf(java.lang.String); - method public static final java.lang.Character.UnicodeScript[] values(); - enum_constant public static final java.lang.Character.UnicodeScript ARABIC; - enum_constant public static final java.lang.Character.UnicodeScript ARMENIAN; - enum_constant public static final java.lang.Character.UnicodeScript AVESTAN; - enum_constant public static final java.lang.Character.UnicodeScript BALINESE; - enum_constant public static final java.lang.Character.UnicodeScript BAMUM; - enum_constant public static final java.lang.Character.UnicodeScript BATAK; - enum_constant public static final java.lang.Character.UnicodeScript BENGALI; - enum_constant public static final java.lang.Character.UnicodeScript BOPOMOFO; - enum_constant public static final java.lang.Character.UnicodeScript BRAHMI; - enum_constant public static final java.lang.Character.UnicodeScript BRAILLE; - enum_constant public static final java.lang.Character.UnicodeScript BUGINESE; - enum_constant public static final java.lang.Character.UnicodeScript BUHID; - enum_constant public static final java.lang.Character.UnicodeScript CANADIAN_ABORIGINAL; - enum_constant public static final java.lang.Character.UnicodeScript CARIAN; - enum_constant public static final java.lang.Character.UnicodeScript CHAM; - enum_constant public static final java.lang.Character.UnicodeScript CHEROKEE; - enum_constant public static final java.lang.Character.UnicodeScript COMMON; - enum_constant public static final java.lang.Character.UnicodeScript COPTIC; - enum_constant public static final java.lang.Character.UnicodeScript CUNEIFORM; - enum_constant public static final java.lang.Character.UnicodeScript CYPRIOT; - enum_constant public static final java.lang.Character.UnicodeScript CYRILLIC; - enum_constant public static final java.lang.Character.UnicodeScript DESERET; - enum_constant public static final java.lang.Character.UnicodeScript DEVANAGARI; - enum_constant public static final java.lang.Character.UnicodeScript EGYPTIAN_HIEROGLYPHS; - enum_constant public static final java.lang.Character.UnicodeScript ETHIOPIC; - enum_constant public static final java.lang.Character.UnicodeScript GEORGIAN; - enum_constant public static final java.lang.Character.UnicodeScript GLAGOLITIC; - enum_constant public static final java.lang.Character.UnicodeScript GOTHIC; - enum_constant public static final java.lang.Character.UnicodeScript GREEK; - enum_constant public static final java.lang.Character.UnicodeScript GUJARATI; - enum_constant public static final java.lang.Character.UnicodeScript GURMUKHI; - enum_constant public static final java.lang.Character.UnicodeScript HAN; - enum_constant public static final java.lang.Character.UnicodeScript HANGUL; - enum_constant public static final java.lang.Character.UnicodeScript HANUNOO; - enum_constant public static final java.lang.Character.UnicodeScript HEBREW; - enum_constant public static final java.lang.Character.UnicodeScript HIRAGANA; - enum_constant public static final java.lang.Character.UnicodeScript IMPERIAL_ARAMAIC; - enum_constant public static final java.lang.Character.UnicodeScript INHERITED; - enum_constant public static final java.lang.Character.UnicodeScript INSCRIPTIONAL_PAHLAVI; - enum_constant public static final java.lang.Character.UnicodeScript INSCRIPTIONAL_PARTHIAN; - enum_constant public static final java.lang.Character.UnicodeScript JAVANESE; - enum_constant public static final java.lang.Character.UnicodeScript KAITHI; - enum_constant public static final java.lang.Character.UnicodeScript KANNADA; - enum_constant public static final java.lang.Character.UnicodeScript KATAKANA; - enum_constant public static final java.lang.Character.UnicodeScript KAYAH_LI; - enum_constant public static final java.lang.Character.UnicodeScript KHAROSHTHI; - enum_constant public static final java.lang.Character.UnicodeScript KHMER; - enum_constant public static final java.lang.Character.UnicodeScript LAO; - enum_constant public static final java.lang.Character.UnicodeScript LATIN; - enum_constant public static final java.lang.Character.UnicodeScript LEPCHA; - enum_constant public static final java.lang.Character.UnicodeScript LIMBU; - enum_constant public static final java.lang.Character.UnicodeScript LINEAR_B; - enum_constant public static final java.lang.Character.UnicodeScript LISU; - enum_constant public static final java.lang.Character.UnicodeScript LYCIAN; - enum_constant public static final java.lang.Character.UnicodeScript LYDIAN; - enum_constant public static final java.lang.Character.UnicodeScript MALAYALAM; - enum_constant public static final java.lang.Character.UnicodeScript MANDAIC; - enum_constant public static final java.lang.Character.UnicodeScript MEETEI_MAYEK; - enum_constant public static final java.lang.Character.UnicodeScript MONGOLIAN; - enum_constant public static final java.lang.Character.UnicodeScript MYANMAR; - enum_constant public static final java.lang.Character.UnicodeScript NEW_TAI_LUE; - enum_constant public static final java.lang.Character.UnicodeScript NKO; - enum_constant public static final java.lang.Character.UnicodeScript OGHAM; - enum_constant public static final java.lang.Character.UnicodeScript OLD_ITALIC; - enum_constant public static final java.lang.Character.UnicodeScript OLD_PERSIAN; - enum_constant public static final java.lang.Character.UnicodeScript OLD_SOUTH_ARABIAN; - enum_constant public static final java.lang.Character.UnicodeScript OLD_TURKIC; - enum_constant public static final java.lang.Character.UnicodeScript OL_CHIKI; - enum_constant public static final java.lang.Character.UnicodeScript ORIYA; - enum_constant public static final java.lang.Character.UnicodeScript OSMANYA; - enum_constant public static final java.lang.Character.UnicodeScript PHAGS_PA; - enum_constant public static final java.lang.Character.UnicodeScript PHOENICIAN; - enum_constant public static final java.lang.Character.UnicodeScript REJANG; - enum_constant public static final java.lang.Character.UnicodeScript RUNIC; - enum_constant public static final java.lang.Character.UnicodeScript SAMARITAN; - enum_constant public static final java.lang.Character.UnicodeScript SAURASHTRA; - enum_constant public static final java.lang.Character.UnicodeScript SHAVIAN; - enum_constant public static final java.lang.Character.UnicodeScript SINHALA; - enum_constant public static final java.lang.Character.UnicodeScript SUNDANESE; - enum_constant public static final java.lang.Character.UnicodeScript SYLOTI_NAGRI; - enum_constant public static final java.lang.Character.UnicodeScript SYRIAC; - enum_constant public static final java.lang.Character.UnicodeScript TAGALOG; - enum_constant public static final java.lang.Character.UnicodeScript TAGBANWA; - enum_constant public static final java.lang.Character.UnicodeScript TAI_LE; - enum_constant public static final java.lang.Character.UnicodeScript TAI_THAM; - enum_constant public static final java.lang.Character.UnicodeScript TAI_VIET; - enum_constant public static final java.lang.Character.UnicodeScript TAMIL; - enum_constant public static final java.lang.Character.UnicodeScript TELUGU; - enum_constant public static final java.lang.Character.UnicodeScript THAANA; - enum_constant public static final java.lang.Character.UnicodeScript THAI; - enum_constant public static final java.lang.Character.UnicodeScript TIBETAN; - enum_constant public static final java.lang.Character.UnicodeScript TIFINAGH; - enum_constant public static final java.lang.Character.UnicodeScript UGARITIC; - enum_constant public static final java.lang.Character.UnicodeScript UNKNOWN; - enum_constant public static final java.lang.Character.UnicodeScript VAI; - enum_constant public static final java.lang.Character.UnicodeScript YI; - } - public final class Class implements java.lang.reflect.AnnotatedElement java.lang.reflect.GenericDeclaration java.io.Serializable java.lang.reflect.Type { method public java.lang.Class<? extends U> asSubclass(java.lang.Class<U>); method public T cast(java.lang.Object); @@ -41950,13 +41868,11 @@ package java.net { method public java.lang.String getValue(); method public int getVersion(); method public boolean hasExpired(); - method public boolean isHttpOnly(); method public static java.util.List<java.net.HttpCookie> parse(java.lang.String); method public void setComment(java.lang.String); method public void setCommentURL(java.lang.String); method public void setDiscard(boolean); method public void setDomain(java.lang.String); - method public void setHttpOnly(boolean); method public void setMaxAge(long); method public void setPath(java.lang.String); method public void setPortlist(java.lang.String); @@ -42347,11 +42263,6 @@ package java.net { method public abstract java.net.SocketImpl createSocketImpl(); } - public abstract interface SocketOption { - method public abstract java.lang.String name(); - method public abstract java.lang.Class<T> type(); - } - public abstract interface SocketOptions { method public abstract java.lang.Object getOption(int) throws java.net.SocketException; method public abstract void setOption(int, java.lang.Object) throws java.net.SocketException; @@ -42382,21 +42293,6 @@ package java.net { ctor public SocketTimeoutException(java.lang.String); } - public final class StandardSocketOptions { - ctor public StandardSocketOptions(); - field public static final java.net.SocketOption IP_MULTICAST_IF; - field public static final java.net.SocketOption IP_MULTICAST_LOOP; - field public static final java.net.SocketOption IP_MULTICAST_TTL; - field public static final java.net.SocketOption IP_TOS; - field public static final java.net.SocketOption SO_BROADCAST; - field public static final java.net.SocketOption SO_KEEPALIVE; - field public static final java.net.SocketOption SO_LINGER; - field public static final java.net.SocketOption SO_RCVBUF; - field public static final java.net.SocketOption SO_REUSEADDR; - field public static final java.net.SocketOption SO_SNDBUF; - field public static final java.net.SocketOption TCP_NODELAY; - } - public final class URI implements java.lang.Comparable java.io.Serializable { ctor public URI(java.lang.String) throws java.net.URISyntaxException; ctor public URI(java.lang.String, java.lang.String, java.lang.String) throws java.net.URISyntaxException; @@ -42492,7 +42388,6 @@ package java.net { method public java.lang.Object getContent(java.lang.Class[]) throws java.io.IOException; method public java.lang.String getContentEncoding(); method public int getContentLength(); - method public long getContentLengthLong(); method public java.lang.String getContentType(); method public long getDate(); method public static boolean getDefaultAllowUserInteraction(); @@ -42507,7 +42402,6 @@ package java.net { method public long getHeaderFieldDate(java.lang.String, long); method public int getHeaderFieldInt(java.lang.String, int); method public java.lang.String getHeaderFieldKey(int); - method public long getHeaderFieldLong(java.lang.String, long); method public java.util.Map<java.lang.String, java.util.List<java.lang.String>> getHeaderFields(); method public long getIfModifiedSince(); method public java.io.InputStream getInputStream() throws java.io.IOException; @@ -42858,10 +42752,6 @@ package java.nio { package java.nio.channels { - public class AlreadyBoundException extends java.lang.IllegalStateException { - ctor public AlreadyBoundException(); - } - public class AlreadyConnectedException extends java.lang.IllegalStateException { ctor public AlreadyConnectedException(); } @@ -42909,32 +42799,25 @@ package java.nio.channels { ctor public ConnectionPendingException(); } - public abstract class DatagramChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.MulticastChannel java.nio.channels.ScatteringByteChannel { + public abstract class DatagramChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.ScatteringByteChannel { ctor protected DatagramChannel(java.nio.channels.spi.SelectorProvider); - method public java.nio.channels.DatagramChannel bind(java.net.SocketAddress) throws java.io.IOException; method public abstract java.nio.channels.DatagramChannel connect(java.net.SocketAddress) throws java.io.IOException; method public abstract java.nio.channels.DatagramChannel disconnect() throws java.io.IOException; - method public java.net.SocketAddress getLocalAddress() throws java.io.IOException; - method public T getOption(java.net.SocketOption<T>) throws java.io.IOException; method public abstract boolean isConnected(); - method public java.nio.channels.MembershipKey join(java.net.InetAddress, java.net.NetworkInterface) throws java.io.IOException; - method public java.nio.channels.MembershipKey join(java.net.InetAddress, java.net.NetworkInterface, java.net.InetAddress) throws java.io.IOException; method public static java.nio.channels.DatagramChannel open() throws java.io.IOException; method public abstract int read(java.nio.ByteBuffer) throws java.io.IOException; method public abstract long read(java.nio.ByteBuffer[], int, int) throws java.io.IOException; method public final synchronized long read(java.nio.ByteBuffer[]) throws java.io.IOException; method public abstract java.net.SocketAddress receive(java.nio.ByteBuffer) throws java.io.IOException; method public abstract int send(java.nio.ByteBuffer, java.net.SocketAddress) throws java.io.IOException; - method public java.nio.channels.DatagramChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException; method public abstract java.net.DatagramSocket socket(); - method public java.util.Set<java.net.SocketOption<?>> supportedOptions(); method public final int validOps(); method public abstract int write(java.nio.ByteBuffer) throws java.io.IOException; method public abstract long write(java.nio.ByteBuffer[], int, int) throws java.io.IOException; method public final synchronized long write(java.nio.ByteBuffer[]) throws java.io.IOException; } - public abstract class FileChannel extends java.nio.channels.spi.AbstractInterruptibleChannel implements java.nio.channels.GatheringByteChannel java.nio.channels.ScatteringByteChannel java.nio.channels.SeekableByteChannel { + public abstract class FileChannel extends java.nio.channels.spi.AbstractInterruptibleChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.ScatteringByteChannel { ctor protected FileChannel(); method public abstract void force(boolean) throws java.io.IOException; method public final java.nio.channels.FileLock lock() throws java.io.IOException; @@ -42966,7 +42849,6 @@ package java.nio.channels { public abstract class FileLock implements java.lang.AutoCloseable { ctor protected FileLock(java.nio.channels.FileChannel, long, long, boolean); - method public java.nio.channels.Channel acquiredBy(); method public final java.nio.channels.FileChannel channel(); method public final void close() throws java.io.IOException; method public final boolean isShared(); @@ -42999,32 +42881,6 @@ package java.nio.channels { method public abstract void close() throws java.io.IOException; } - public abstract class MembershipKey { - ctor protected MembershipKey(); - method public abstract java.nio.channels.MembershipKey block(java.net.InetAddress) throws java.io.IOException; - method public abstract java.nio.channels.MulticastChannel channel(); - method public abstract void drop(); - method public abstract java.net.InetAddress group(); - method public abstract boolean isValid(); - method public abstract java.net.NetworkInterface networkInterface(); - method public abstract java.net.InetAddress sourceAddress(); - method public abstract java.nio.channels.MembershipKey unblock(java.net.InetAddress); - } - - public abstract interface MulticastChannel implements java.nio.channels.NetworkChannel { - method public abstract void close() throws java.io.IOException; - method public abstract java.nio.channels.MembershipKey join(java.net.InetAddress, java.net.NetworkInterface) throws java.io.IOException; - method public abstract java.nio.channels.MembershipKey join(java.net.InetAddress, java.net.NetworkInterface, java.net.InetAddress) throws java.io.IOException; - } - - public abstract interface NetworkChannel implements java.lang.AutoCloseable java.nio.channels.Channel java.io.Closeable { - method public abstract java.nio.channels.NetworkChannel bind(java.net.SocketAddress) throws java.io.IOException; - method public abstract java.net.SocketAddress getLocalAddress() throws java.io.IOException; - method public abstract T getOption(java.net.SocketOption<T>) throws java.io.IOException; - method public abstract java.nio.channels.NetworkChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException; - method public abstract java.util.Set<java.net.SocketOption<?>> supportedOptions(); - } - public class NoConnectionPendingException extends java.lang.IllegalStateException { ctor public NoConnectionPendingException(); } @@ -43075,15 +42931,6 @@ package java.nio.channels { method public abstract long read(java.nio.ByteBuffer[], int, int) throws java.io.IOException; } - public abstract interface SeekableByteChannel implements java.nio.channels.ByteChannel { - method public abstract long position() throws java.io.IOException; - method public abstract java.nio.channels.SeekableByteChannel position(long) throws java.io.IOException; - method public abstract int read(java.nio.ByteBuffer) throws java.io.IOException; - method public abstract long size() throws java.io.IOException; - method public abstract java.nio.channels.SeekableByteChannel truncate(long) throws java.io.IOException; - method public abstract int write(java.nio.ByteBuffer) throws java.io.IOException; - } - public abstract class SelectableChannel extends java.nio.channels.spi.AbstractInterruptibleChannel implements java.nio.channels.Channel { ctor protected SelectableChannel(); method public abstract java.lang.Object blockingLock(); @@ -43132,27 +42979,18 @@ package java.nio.channels { method public abstract java.nio.channels.Selector wakeup(); } - public abstract class ServerSocketChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.NetworkChannel { + public abstract class ServerSocketChannel extends java.nio.channels.spi.AbstractSelectableChannel { ctor protected ServerSocketChannel(java.nio.channels.spi.SelectorProvider); method public abstract java.nio.channels.SocketChannel accept() throws java.io.IOException; - method public final java.nio.channels.ServerSocketChannel bind(java.net.SocketAddress) throws java.io.IOException; - method public java.nio.channels.ServerSocketChannel bind(java.net.SocketAddress, int) throws java.io.IOException; - method public java.net.SocketAddress getLocalAddress() throws java.io.IOException; - method public T getOption(java.net.SocketOption<T>) throws java.io.IOException; method public static java.nio.channels.ServerSocketChannel open() throws java.io.IOException; - method public java.nio.channels.ServerSocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException; method public abstract java.net.ServerSocket socket(); - method public java.util.Set<java.net.SocketOption<?>> supportedOptions(); method public final int validOps(); } - public abstract class SocketChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.NetworkChannel java.nio.channels.ScatteringByteChannel { + public abstract class SocketChannel extends java.nio.channels.spi.AbstractSelectableChannel implements java.nio.channels.ByteChannel java.nio.channels.GatheringByteChannel java.nio.channels.ScatteringByteChannel { ctor protected SocketChannel(java.nio.channels.spi.SelectorProvider); - method public java.nio.channels.SocketChannel bind(java.net.SocketAddress) throws java.io.IOException; method public abstract boolean connect(java.net.SocketAddress) throws java.io.IOException; method public abstract boolean finishConnect() throws java.io.IOException; - method public java.net.SocketAddress getLocalAddress() throws java.io.IOException; - method public T getOption(java.net.SocketOption<T>) throws java.io.IOException; method public abstract boolean isConnected(); method public abstract boolean isConnectionPending(); method public static java.nio.channels.SocketChannel open() throws java.io.IOException; @@ -43160,9 +42998,7 @@ package java.nio.channels { method public abstract int read(java.nio.ByteBuffer) throws java.io.IOException; method public abstract long read(java.nio.ByteBuffer[], int, int) throws java.io.IOException; method public final synchronized long read(java.nio.ByteBuffer[]) throws java.io.IOException; - method public java.nio.channels.SocketChannel setOption(java.net.SocketOption<T>, T) throws java.io.IOException; method public abstract java.net.Socket socket(); - method public java.util.Set<java.net.SocketOption<?>> supportedOptions(); method public final int validOps(); method public abstract int write(java.nio.ByteBuffer) throws java.io.IOException; method public abstract long write(java.nio.ByteBuffer[], int, int) throws java.io.IOException; @@ -47122,7 +46958,6 @@ package java.util { method public java.lang.String getDisplayName(java.util.Locale); method public static java.util.Currency getInstance(java.lang.String); method public static java.util.Currency getInstance(java.util.Locale); - method public int getNumericCode(); method public java.lang.String getSymbol(); method public java.lang.String getSymbol(java.util.Locale); } @@ -47407,13 +47242,6 @@ package java.util { method public int getWidth(); } - public class IllformedLocaleException extends java.lang.RuntimeException { - ctor public IllformedLocaleException(); - ctor public IllformedLocaleException(java.lang.String); - ctor public IllformedLocaleException(java.lang.String, int); - method public int getErrorIndex(); - } - public class InputMismatchException extends java.util.NoSuchElementException implements java.io.Serializable { ctor public InputMismatchException(); ctor public InputMismatchException(java.lang.String); @@ -47528,7 +47356,6 @@ package java.util { ctor public Locale(java.lang.String, java.lang.String); ctor public Locale(java.lang.String, java.lang.String, java.lang.String); method public java.lang.Object clone(); - method public static java.util.Locale forLanguageTag(java.lang.String); method public static java.util.Locale[] getAvailableLocales(); method public java.lang.String getCountry(); method public static java.util.Locale getDefault(); @@ -47538,24 +47365,15 @@ package java.util { method public java.lang.String getDisplayLanguage(java.util.Locale); method public final java.lang.String getDisplayName(); method public java.lang.String getDisplayName(java.util.Locale); - method public java.lang.String getDisplayScript(); - method public java.lang.String getDisplayScript(java.util.Locale); method public final java.lang.String getDisplayVariant(); method public java.lang.String getDisplayVariant(java.util.Locale); - method public java.lang.String getExtension(char); - method public java.util.Set<java.lang.Character> getExtensionKeys(); method public java.lang.String getISO3Country(); method public java.lang.String getISO3Language(); method public static java.lang.String[] getISOCountries(); method public static java.lang.String[] getISOLanguages(); method public java.lang.String getLanguage(); - method public java.lang.String getScript(); - method public java.util.Set<java.lang.String> getUnicodeLocaleAttributes(); - method public java.util.Set<java.lang.String> getUnicodeLocaleKeys(); - method public java.lang.String getUnicodeLocaleType(java.lang.String); method public java.lang.String getVariant(); method public static synchronized void setDefault(java.util.Locale); - method public java.lang.String toLanguageTag(); method public final java.lang.String toString(); field public static final java.util.Locale CANADA; field public static final java.util.Locale CANADA_FRENCH; @@ -47573,33 +47391,14 @@ package java.util { field public static final java.util.Locale KOREA; field public static final java.util.Locale KOREAN; field public static final java.util.Locale PRC; - field public static final char PRIVATE_USE_EXTENSION = 120; // 0x0078 'x' field public static final java.util.Locale ROOT; field public static final java.util.Locale SIMPLIFIED_CHINESE; field public static final java.util.Locale TAIWAN; field public static final java.util.Locale TRADITIONAL_CHINESE; field public static final java.util.Locale UK; - field public static final char UNICODE_LOCALE_EXTENSION = 117; // 0x0075 'u' field public static final java.util.Locale US; } - public static final class Locale.Builder { - ctor public Locale.Builder(); - method public java.util.Locale.Builder addUnicodeLocaleAttribute(java.lang.String); - method public java.util.Locale build(); - method public java.util.Locale.Builder clear(); - method public java.util.Locale.Builder clearExtensions(); - method public java.util.Locale.Builder removeUnicodeLocaleAttribute(java.lang.String); - method public java.util.Locale.Builder setExtension(char, java.lang.String); - method public java.util.Locale.Builder setLanguage(java.lang.String); - method public java.util.Locale.Builder setLanguageTag(java.lang.String); - method public java.util.Locale.Builder setLocale(java.util.Locale); - method public java.util.Locale.Builder setRegion(java.lang.String); - method public java.util.Locale.Builder setScript(java.lang.String); - method public java.util.Locale.Builder setUnicodeLocaleKeyword(java.lang.String, java.lang.String); - method public java.util.Locale.Builder setVariant(java.lang.String); - } - public abstract interface Map { method public abstract void clear(); method public abstract boolean containsKey(java.lang.Object); @@ -48286,35 +48085,6 @@ package java.util.concurrent { method public V replace(K, V); } - public class ConcurrentLinkedDeque extends java.util.AbstractCollection implements java.util.Deque java.io.Serializable { - ctor public ConcurrentLinkedDeque(); - ctor public ConcurrentLinkedDeque(java.util.Collection<? extends E>); - method public void addFirst(E); - method public void addLast(E); - method public java.util.Iterator<E> descendingIterator(); - method public E element(); - method public E getFirst(); - method public E getLast(); - method public java.util.Iterator<E> iterator(); - method public boolean offer(E); - method public boolean offerFirst(E); - method public boolean offerLast(E); - method public E peek(); - method public E peekFirst(); - method public E peekLast(); - method public E poll(); - method public E pollFirst(); - method public E pollLast(); - method public E pop(); - method public void push(E); - method public E remove(); - method public E removeFirst(); - method public boolean removeFirstOccurrence(java.lang.Object); - method public E removeLast(); - method public boolean removeLastOccurrence(java.lang.Object); - method public int size(); - } - public class ConcurrentLinkedQueue extends java.util.AbstractQueue implements java.util.Queue java.io.Serializable { ctor public ConcurrentLinkedQueue(); ctor public ConcurrentLinkedQueue(java.util.Collection<? extends E>); @@ -48555,94 +48325,6 @@ package java.util.concurrent { method public static java.util.concurrent.ScheduledExecutorService unconfigurableScheduledExecutorService(java.util.concurrent.ScheduledExecutorService); } - public class ForkJoinPool extends java.util.concurrent.AbstractExecutorService { - ctor public ForkJoinPool(); - ctor public ForkJoinPool(int); - ctor public ForkJoinPool(int, java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory, java.lang.Thread.UncaughtExceptionHandler, boolean); - method public boolean awaitQuiescence(long, java.util.concurrent.TimeUnit); - method public boolean awaitTermination(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException; - method protected int drainTasksTo(java.util.Collection<? super java.util.concurrent.ForkJoinTask<?>>); - method public void execute(java.util.concurrent.ForkJoinTask<?>); - method public void execute(java.lang.Runnable); - method public int getActiveThreadCount(); - method public boolean getAsyncMode(); - method public java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory getFactory(); - method public int getParallelism(); - method public int getPoolSize(); - method public int getQueuedSubmissionCount(); - method public long getQueuedTaskCount(); - method public int getRunningThreadCount(); - method public long getStealCount(); - method public java.lang.Thread.UncaughtExceptionHandler getUncaughtExceptionHandler(); - method public boolean hasQueuedSubmissions(); - method public T invoke(java.util.concurrent.ForkJoinTask<T>); - method public boolean isQuiescent(); - method public boolean isShutdown(); - method public boolean isTerminated(); - method public boolean isTerminating(); - method public static void managedBlock(java.util.concurrent.ForkJoinPool.ManagedBlocker) throws java.lang.InterruptedException; - method protected java.util.concurrent.ForkJoinTask<?> pollSubmission(); - method public void shutdown(); - method public java.util.List<java.lang.Runnable> shutdownNow(); - method public java.util.concurrent.ForkJoinTask<T> submit(java.util.concurrent.ForkJoinTask<T>); - field public static final java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory defaultForkJoinWorkerThreadFactory; - } - - public static abstract interface ForkJoinPool.ForkJoinWorkerThreadFactory { - method public abstract java.util.concurrent.ForkJoinWorkerThread newThread(java.util.concurrent.ForkJoinPool); - } - - public static abstract interface ForkJoinPool.ManagedBlocker { - method public abstract boolean block() throws java.lang.InterruptedException; - method public abstract boolean isReleasable(); - } - - public abstract class ForkJoinTask implements java.util.concurrent.Future java.io.Serializable { - ctor public ForkJoinTask(); - method public static java.util.concurrent.ForkJoinTask<?> adapt(java.lang.Runnable); - method public static java.util.concurrent.ForkJoinTask<T> adapt(java.lang.Runnable, T); - method public static java.util.concurrent.ForkJoinTask<T> adapt(java.util.concurrent.Callable<? extends T>); - method public boolean cancel(boolean); - method public void complete(V); - method public void completeExceptionally(java.lang.Throwable); - method protected abstract boolean exec(); - method public final java.util.concurrent.ForkJoinTask<V> fork(); - method public final V get() throws java.util.concurrent.ExecutionException, java.lang.InterruptedException; - method public final V get(long, java.util.concurrent.TimeUnit) throws java.util.concurrent.ExecutionException, java.lang.InterruptedException, java.util.concurrent.TimeoutException; - method public final java.lang.Throwable getException(); - method public static java.util.concurrent.ForkJoinPool getPool(); - method public static int getQueuedTaskCount(); - method public abstract V getRawResult(); - method public static int getSurplusQueuedTaskCount(); - method public static void helpQuiesce(); - method public static boolean inForkJoinPool(); - method public final V invoke(); - method public static void invokeAll(java.util.concurrent.ForkJoinTask<?>, java.util.concurrent.ForkJoinTask<?>); - method public static void invokeAll(java.util.concurrent.ForkJoinTask<?>...); - method public static java.util.Collection<T> invokeAll(java.util.Collection<T>); - method public final boolean isCancelled(); - method public final boolean isCompletedAbnormally(); - method public final boolean isCompletedNormally(); - method public final boolean isDone(); - method public final V join(); - method protected static java.util.concurrent.ForkJoinTask<?> peekNextLocalTask(); - method protected static java.util.concurrent.ForkJoinTask<?> pollNextLocalTask(); - method protected static java.util.concurrent.ForkJoinTask<?> pollTask(); - method public final void quietlyInvoke(); - method public final void quietlyJoin(); - method public void reinitialize(); - method protected abstract void setRawResult(V); - method public boolean tryUnfork(); - } - - public class ForkJoinWorkerThread extends java.lang.Thread { - ctor protected ForkJoinWorkerThread(java.util.concurrent.ForkJoinPool); - method public java.util.concurrent.ForkJoinPool getPool(); - method public int getPoolIndex(); - method protected void onStart(); - method protected void onTermination(java.lang.Throwable); - } - public abstract interface Future { method public abstract boolean cancel(boolean); method public abstract V get() throws java.util.concurrent.ExecutionException, java.lang.InterruptedException; @@ -48727,52 +48409,6 @@ package java.util.concurrent { method public E take() throws java.lang.InterruptedException; } - public class LinkedTransferQueue extends java.util.AbstractQueue implements java.io.Serializable java.util.concurrent.TransferQueue { - ctor public LinkedTransferQueue(); - ctor public LinkedTransferQueue(java.util.Collection<? extends E>); - method public int drainTo(java.util.Collection<? super E>); - method public int drainTo(java.util.Collection<? super E>, int); - method public int getWaitingConsumerCount(); - method public boolean hasWaitingConsumer(); - method public java.util.Iterator<E> iterator(); - method public boolean offer(E, long, java.util.concurrent.TimeUnit); - method public boolean offer(E); - method public E peek(); - method public E poll(long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException; - method public E poll(); - method public void put(E); - method public int remainingCapacity(); - method public int size(); - method public E take() throws java.lang.InterruptedException; - method public void transfer(E) throws java.lang.InterruptedException; - method public boolean tryTransfer(E); - method public boolean tryTransfer(E, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException; - } - - public class Phaser { - ctor public Phaser(); - ctor public Phaser(int); - ctor public Phaser(java.util.concurrent.Phaser); - ctor public Phaser(java.util.concurrent.Phaser, int); - method public int arrive(); - method public int arriveAndAwaitAdvance(); - method public int arriveAndDeregister(); - method public int awaitAdvance(int); - method public int awaitAdvanceInterruptibly(int) throws java.lang.InterruptedException; - method public int awaitAdvanceInterruptibly(int, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException, java.util.concurrent.TimeoutException; - method public int bulkRegister(int); - method public void forceTermination(); - method public int getArrivedParties(); - method public java.util.concurrent.Phaser getParent(); - method public final int getPhase(); - method public int getRegisteredParties(); - method public java.util.concurrent.Phaser getRoot(); - method public int getUnarrivedParties(); - method public boolean isTerminated(); - method protected boolean onAdvance(int, int); - method public int register(); - } - public class PriorityBlockingQueue extends java.util.AbstractQueue implements java.util.concurrent.BlockingQueue java.io.Serializable { ctor public PriorityBlockingQueue(); ctor public PriorityBlockingQueue(int); @@ -48793,22 +48429,6 @@ package java.util.concurrent { method public E take() throws java.lang.InterruptedException; } - public abstract class RecursiveAction extends java.util.concurrent.ForkJoinTask { - ctor public RecursiveAction(); - method protected abstract void compute(); - method protected final boolean exec(); - method public final java.lang.Void getRawResult(); - method protected final void setRawResult(java.lang.Void); - } - - public abstract class RecursiveTask extends java.util.concurrent.ForkJoinTask { - ctor public RecursiveTask(); - method protected abstract V compute(); - method protected final boolean exec(); - method public final V getRawResult(); - method protected final void setRawResult(V); - } - public class RejectedExecutionException extends java.lang.RuntimeException { ctor public RejectedExecutionException(); ctor public RejectedExecutionException(java.lang.String); @@ -48847,14 +48467,12 @@ package java.util.concurrent { method protected java.util.concurrent.RunnableScheduledFuture<V> decorateTask(java.util.concurrent.Callable<V>, java.util.concurrent.RunnableScheduledFuture<V>); method public boolean getContinueExistingPeriodicTasksAfterShutdownPolicy(); method public boolean getExecuteExistingDelayedTasksAfterShutdownPolicy(); - method public boolean getRemoveOnCancelPolicy(); method public java.util.concurrent.ScheduledFuture<?> schedule(java.lang.Runnable, long, java.util.concurrent.TimeUnit); method public java.util.concurrent.ScheduledFuture<V> schedule(java.util.concurrent.Callable<V>, long, java.util.concurrent.TimeUnit); method public java.util.concurrent.ScheduledFuture<?> scheduleAtFixedRate(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit); method public java.util.concurrent.ScheduledFuture<?> scheduleWithFixedDelay(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit); method public void setContinueExistingPeriodicTasksAfterShutdownPolicy(boolean); method public void setExecuteExistingDelayedTasksAfterShutdownPolicy(boolean); - method public void setRemoveOnCancelPolicy(boolean); } public class Semaphore implements java.io.Serializable { @@ -48900,15 +48518,6 @@ package java.util.concurrent { method public abstract java.lang.Thread newThread(java.lang.Runnable); } - public class ThreadLocalRandom extends java.util.Random { - method public static java.util.concurrent.ThreadLocalRandom current(); - method public double nextDouble(double); - method public double nextDouble(double, double); - method public int nextInt(int, int); - method public long nextLong(long); - method public long nextLong(long, long); - } - public class ThreadPoolExecutor extends java.util.concurrent.AbstractExecutorService { ctor public ThreadPoolExecutor(int, int, long, java.util.concurrent.TimeUnit, java.util.concurrent.BlockingQueue<java.lang.Runnable>); ctor public ThreadPoolExecutor(int, int, long, java.util.concurrent.TimeUnit, java.util.concurrent.BlockingQueue<java.lang.Runnable>, java.util.concurrent.ThreadFactory); @@ -48996,14 +48605,6 @@ package java.util.concurrent { ctor public TimeoutException(java.lang.String); } - public abstract interface TransferQueue implements java.util.concurrent.BlockingQueue { - method public abstract int getWaitingConsumerCount(); - method public abstract boolean hasWaitingConsumer(); - method public abstract void transfer(E) throws java.lang.InterruptedException; - method public abstract boolean tryTransfer(E); - method public abstract boolean tryTransfer(E, long, java.util.concurrent.TimeUnit) throws java.lang.InterruptedException; - } - } package java.util.concurrent.atomic { @@ -49213,7 +48814,6 @@ package java.util.concurrent.locks { method public final int getWaitQueueLength(java.util.concurrent.locks.AbstractQueuedLongSynchronizer.ConditionObject); method public final java.util.Collection<java.lang.Thread> getWaitingThreads(java.util.concurrent.locks.AbstractQueuedLongSynchronizer.ConditionObject); method public final boolean hasContended(); - method public final boolean hasQueuedPredecessors(); method public final boolean hasQueuedThreads(); method public final boolean hasWaiters(java.util.concurrent.locks.AbstractQueuedLongSynchronizer.ConditionObject); method protected boolean isHeldExclusively(); @@ -49260,7 +48860,6 @@ package java.util.concurrent.locks { method public final int getWaitQueueLength(java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject); method public final java.util.Collection<java.lang.Thread> getWaitingThreads(java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject); method public final boolean hasContended(); - method public final boolean hasQueuedPredecessors(); method public final boolean hasQueuedThreads(); method public final boolean hasWaiters(java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject); method protected boolean isHeldExclusively(); @@ -50205,10 +49804,8 @@ package java.util.zip { public class ZipFile implements java.io.Closeable { ctor public ZipFile(java.io.File) throws java.io.IOException, java.util.zip.ZipException; - ctor public ZipFile(java.io.File, java.nio.charset.Charset) throws java.io.IOException, java.util.zip.ZipException; ctor public ZipFile(java.lang.String) throws java.io.IOException; ctor public ZipFile(java.io.File, int) throws java.io.IOException; - ctor public ZipFile(java.io.File, int, java.nio.charset.Charset) throws java.io.IOException; method public void close() throws java.io.IOException; method public java.util.Enumeration<? extends java.util.zip.ZipEntry> entries(); method public java.lang.String getComment(); @@ -50262,7 +49859,6 @@ package java.util.zip { public class ZipInputStream extends java.util.zip.InflaterInputStream { ctor public ZipInputStream(java.io.InputStream); - ctor public ZipInputStream(java.io.InputStream, java.nio.charset.Charset); method public void closeEntry() throws java.io.IOException; method protected java.util.zip.ZipEntry createZipEntry(java.lang.String); method public java.util.zip.ZipEntry getNextEntry() throws java.io.IOException; @@ -50310,7 +49906,6 @@ package java.util.zip { public class ZipOutputStream extends java.util.zip.DeflaterOutputStream { ctor public ZipOutputStream(java.io.OutputStream); - ctor public ZipOutputStream(java.io.OutputStream, java.nio.charset.Charset); method public void closeEntry() throws java.io.IOException; method public void putNextEntry(java.util.zip.ZipEntry) throws java.io.IOException; method public void setComment(java.lang.String); @@ -51809,7 +51404,6 @@ package javax.net.ssl { method public abstract boolean getEnableSessionCreation(); method public abstract java.lang.String[] getEnabledCipherSuites(); method public abstract java.lang.String[] getEnabledProtocols(); - method public javax.net.ssl.SSLSession getHandshakeSession(); method public abstract javax.net.ssl.SSLEngineResult.HandshakeStatus getHandshakeStatus(); method public abstract boolean getNeedClientAuth(); method public java.lang.String getPeerHost(); @@ -51883,12 +51477,10 @@ package javax.net.ssl { ctor public SSLParameters(java.lang.String[]); ctor public SSLParameters(java.lang.String[], java.lang.String[]); method public java.lang.String[] getCipherSuites(); - method public java.lang.String getEndpointIdentificationAlgorithm(); method public boolean getNeedClientAuth(); method public java.lang.String[] getProtocols(); method public boolean getWantClientAuth(); method public void setCipherSuites(java.lang.String[]); - method public void setEndpointIdentificationAlgorithm(java.lang.String); method public void setNeedClientAuth(boolean); method public void setProtocols(java.lang.String[]); method public void setWantClientAuth(boolean); @@ -51989,7 +51581,6 @@ package javax.net.ssl { method public abstract boolean getEnableSessionCreation(); method public abstract java.lang.String[] getEnabledCipherSuites(); method public abstract java.lang.String[] getEnabledProtocols(); - method public javax.net.ssl.SSLSession getHandshakeSession(); method public abstract boolean getNeedClientAuth(); method public javax.net.ssl.SSLParameters getSSLParameters(); method public abstract javax.net.ssl.SSLSession getSession(); @@ -52045,14 +51636,6 @@ package javax.net.ssl { method public java.lang.String chooseEngineServerAlias(java.lang.String, java.security.Principal[], javax.net.ssl.SSLEngine); } - public abstract class X509ExtendedTrustManager implements javax.net.ssl.X509TrustManager { - ctor public X509ExtendedTrustManager(); - method public abstract void checkClientTrusted(java.security.cert.X509Certificate[], java.lang.String, java.net.Socket) throws java.security.cert.CertificateException; - method public abstract void checkClientTrusted(java.security.cert.X509Certificate[], java.lang.String, javax.net.ssl.SSLEngine) throws java.security.cert.CertificateException; - method public abstract void checkServerTrusted(java.security.cert.X509Certificate[], java.lang.String, java.net.Socket) throws java.security.cert.CertificateException; - method public abstract void checkServerTrusted(java.security.cert.X509Certificate[], java.lang.String, javax.net.ssl.SSLEngine) throws java.security.cert.CertificateException; - } - public abstract interface X509KeyManager implements javax.net.ssl.KeyManager { method public abstract java.lang.String chooseClientAlias(java.lang.String[], java.security.Principal[], java.net.Socket); method public abstract java.lang.String chooseServerAlias(java.lang.String, java.security.Principal[], java.net.Socket); diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index 5867232..a480219 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -189,7 +189,9 @@ public class AppOpsManager { /** @hide Retrieve current usage stats via {@link UsageStatsManager}. */ public static final int OP_GET_USAGE_STATS = 43; /** @hide */ - public static final int _NUM_OP = 44; + public static final int OP_MUTE_MICROPHONE = 44; + /** @hide */ + public static final int _NUM_OP = 45; /** Access to coarse location information. */ public static final String OPSTR_COARSE_LOCATION = @@ -257,6 +259,7 @@ public class AppOpsManager { OP_COARSE_LOCATION, OP_COARSE_LOCATION, OP_GET_USAGE_STATS, + OP_MUTE_MICROPHONE }; /** @@ -308,6 +311,7 @@ public class AppOpsManager { OPSTR_MONITOR_LOCATION, OPSTR_MONITOR_HIGH_POWER_LOCATION, null, + null, }; /** @@ -358,7 +362,8 @@ public class AppOpsManager { "WAKE_LOCK", "MONITOR_LOCATION", "MONITOR_HIGH_POWER_LOCATION", - "GET_USAGE_STATS" + "GET_USAGE_STATS", + "OP_MUTE_MICROPHONE", }; /** @@ -410,6 +415,7 @@ public class AppOpsManager { null, // no permission for generic location monitoring null, // no permission for high power location monitoring android.Manifest.permission.PACKAGE_USAGE_STATS, + null, // no permission for muting/unmuting microphone }; /** @@ -462,6 +468,7 @@ public class AppOpsManager { null, //MONITOR_LOCATION null, //MONITOR_HIGH_POWER_LOCATION null, //GET_USAGE_STATS + UserManager.DISALLOW_UNMUTE_MICROPHONE, // MUTE_MICROPHONE }; /** @@ -512,6 +519,7 @@ public class AppOpsManager { AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_ALLOWED, AppOpsManager.MODE_IGNORED, // OP_GET_USAGE_STATS + AppOpsManager.MODE_ALLOWED, }; /** @@ -566,6 +574,7 @@ public class AppOpsManager { false, false, false, + false, }; private static HashMap<String, Integer> sOpStrToOp = new HashMap<String, Integer>(); diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 52d4585..ab3bb49 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -118,6 +118,7 @@ import android.print.PrintManager; import android.service.fingerprint.FingerprintManager; import android.service.fingerprint.FingerprintManagerReceiver; import android.service.fingerprint.FingerprintService; +import android.telecomm.TelecommManager; import android.telephony.TelephonyManager; import android.content.ClipboardManager; import android.util.AndroidRuntimeException; @@ -142,6 +143,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.app.IAppOpsService; import com.android.internal.appwidget.IAppWidgetService.Stub; import com.android.internal.os.IDropBoxManagerService; +import com.android.internal.telecomm.ITelecommService; import java.io.File; import java.io.FileInputStream; @@ -554,6 +556,13 @@ class ContextImpl extends Context { return new TelephonyManager(ctx.getOuterContext()); }}); + registerService(TELECOMM_SERVICE, new ServiceFetcher() { + public Object createService(ContextImpl ctx) { + IBinder b = ServiceManager.getService(TELECOMM_SERVICE); + return new TelecommManager(ctx.getOuterContext(), + ITelecommService.Stub.asInterface(b)); + }}); + registerService(UI_MODE_SERVICE, new ServiceFetcher() { public Object createService(ContextImpl ctx) { return new UiModeManager(); diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index ccf8451..fd19b40 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -2035,6 +2035,7 @@ public abstract class Context { AUDIO_SERVICE, MEDIA_ROUTER_SERVICE, TELEPHONY_SERVICE, + TELECOMM_SERVICE, CLIPBOARD_SERVICE, INPUT_METHOD_SERVICE, TEXT_SERVICES_MANAGER_SERVICE, @@ -2163,6 +2164,8 @@ public abstract class Context { * @see android.media.MediaRouter * @see #TELEPHONY_SERVICE * @see android.telephony.TelephonyManager + * @see #TELECOMM_SERVICE + * @see android.telecomm.TelecommManager * @see #INPUT_METHOD_SERVICE * @see android.view.inputmethod.InputMethodManager * @see #UI_MODE_SERVICE @@ -2494,6 +2497,16 @@ public abstract class Context { /** * Use with {@link #getSystemService} to retrieve a + * {@link android.telecomm.TelecommManager} to manage telecomm-related features + * of the device. + * + * @see #getSystemService + * @see android.telecomm.TelecommManager + */ + public static final String TELECOMM_SERVICE = "telecomm"; + + /** + * Use with {@link #getSystemService} to retrieve a * {@link android.text.ClipboardManager} for accessing and modifying * the contents of the global clipboard. * diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 550c1f1..8d9b8d9 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -26,6 +26,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.IntentSender; +import android.content.pm.PackageParser.PackageParserException; import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.graphics.drawable.Drawable; @@ -2873,16 +2874,17 @@ public abstract class PackageManager { DisplayMetrics metrics = new DisplayMetrics(); metrics.setToDefaults(); final File sourceFile = new File(archiveFilePath); - PackageParser.Package pkg = packageParser.parsePackage( - sourceFile, archiveFilePath, metrics, 0); - if (pkg == null) { + try { + PackageParser.Package pkg = packageParser.parseMonolithicPackage(sourceFile, metrics, + 0); + if ((flags & GET_SIGNATURES) != 0) { + packageParser.collectCertificates(pkg, 0); + } + PackageUserState state = new PackageUserState(); + return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0, null, state); + } catch (PackageParserException e) { return null; } - if ((flags & GET_SIGNATURES) != 0) { - packageParser.collectCertificates(pkg, 0); - } - PackageUserState state = new PackageUserState(); - return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0, null, state); } /** diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 4cac7fd..91895ff 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -18,6 +18,7 @@ package android.content.pm; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; +import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK; import android.content.ComponentName; import android.content.Intent; @@ -31,6 +32,7 @@ import android.os.Build; import android.os.Bundle; import android.os.PatternMatcher; import android.os.UserHandle; +import android.text.TextUtils; import android.util.AttributeSet; import android.util.Base64; import android.util.DisplayMetrics; @@ -81,6 +83,8 @@ public class PackageParser { private static final boolean DEBUG_PARSER = false; private static final boolean DEBUG_BACKUP = false; + // TODO: switch outError users to PackageParserException + /** File name in an APK for the Android manifest. */ private static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml"; @@ -207,10 +211,10 @@ public class PackageParser { } } - /* Light weight package info. - * @hide + /** + * Lightweight parsed details about a single APK file. */ - public static class PackageLite { + public static class ApkLite { public final String packageName; public final String splitName; public final int versionCode; @@ -218,7 +222,7 @@ public class PackageParser { public final VerifierInfo[] verifiers; public final Signature[] signatures; - public PackageLite(String packageName, String splitName, int versionCode, + public ApkLite(String packageName, String splitName, int versionCode, int installLocation, List<VerifierInfo> verifiers, Signature[] signatures) { this.packageName = packageName; this.splitName = splitName; @@ -247,6 +251,10 @@ public class PackageParser { mArchiveSourcePath = archiveSourcePath; } + public PackageParser(File archiveSource) { + this(archiveSource.getAbsolutePath()); + } + public void setSeparateProcesses(String[] procs) { mSeparateProcesses = procs; } @@ -255,6 +263,10 @@ public class PackageParser { mOnlyCoreApps = onlyCoreApps; } + private static final boolean isPackageFilename(File file) { + return isPackageFilename(file.getName()); + } + private static final boolean isPackageFilename(String name) { return name.endsWith(".apk"); } @@ -497,26 +509,84 @@ public class PackageParser { public final static int PARSE_IS_PRIVILEGED = 1<<7; public final static int PARSE_GET_SIGNATURES = 1<<8; - public int getParseError() { - return mParseError; + /** + * Parse all APK files under the given directory as a single package. + */ + public Package parseSplitPackage(File apkDir, DisplayMetrics metrics, int flags, + boolean trustedOverlay) throws PackageParserException { + final File[] files = apkDir.listFiles(); + if (ArrayUtils.isEmpty(files)) { + throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK, + "No packages found in split"); + } + + File baseFile = null; + for (File file : files) { + if (file.isFile() && isPackageFilename(file)) { + ApkLite lite = parseApkLite(file.getAbsolutePath(), 0); + if (lite == null) { + throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK, + "Invalid package file: " + file); + } + + if (TextUtils.isEmpty(lite.splitName)) { + baseFile = file; + break; + } + } + } + + if (baseFile == null) { + throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK, + "Missing base APK in " + apkDir); + } + + final Package pkg = parseBaseApk(baseFile, metrics, flags, trustedOverlay); + if (pkg == null) { + throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK, + "Failed to parse base APK: " + baseFile); + } + + for (File file : files) { + if (file.isFile() && isPackageFilename(file) && !file.equals(baseFile)) { + parseSplitApk(pkg, file, metrics, flags, trustedOverlay); + } + } + + // Always use a well-defined sort order + if (pkg.splitCodePaths != null) { + Arrays.sort(pkg.splitCodePaths); + } + + return pkg; + } + + public Package parseMonolithicPackage(File apkFile, DisplayMetrics metrics, int flags) + throws PackageParserException { + return parseMonolithicPackage(apkFile, metrics, flags, false); } - public Package parsePackage(File sourceFile, String destCodePath, - DisplayMetrics metrics, int flags) { - return parsePackage(sourceFile, destCodePath, metrics, flags, false); + public Package parseMonolithicPackage(File apkFile, DisplayMetrics metrics, int flags, + boolean trustedOverlay) throws PackageParserException { + final Package pkg = parseBaseApk(apkFile, metrics, flags, trustedOverlay); + if (pkg != null) { + return pkg; + } else { + throw new PackageParserException(mParseError, "Failed to parse " + apkFile); + } } - public Package parsePackage(File sourceFile, String destCodePath, - DisplayMetrics metrics, int flags, boolean trustedOverlay) { + private Package parseBaseApk(File apkFile, DisplayMetrics metrics, int flags, + boolean trustedOverlay) { mParseError = PackageManager.INSTALL_SUCCEEDED; - mArchiveSourcePath = sourceFile.getPath(); - if (!sourceFile.isFile()) { + mArchiveSourcePath = apkFile.getAbsolutePath(); + if (!apkFile.isFile()) { Slog.w(TAG, "Skipping dir: " + mArchiveSourcePath); mParseError = PackageManager.INSTALL_PARSE_FAILED_NOT_APK; return null; } - if (!isPackageFilename(sourceFile.getName()) + if (!isPackageFilename(apkFile.getName()) && (flags&PARSE_MUST_BE_APK) != 0) { if ((flags&PARSE_IS_SYSTEM) == 0) { // We expect to have non-.apk files in the system dir, @@ -560,13 +630,12 @@ public class PackageParser { Exception errorException = null; try { // XXXX todo: need to figure out correct configuration. - pkg = parsePackage(res, parser, flags, trustedOverlay, errorText); + pkg = parseBaseApk(res, parser, flags, trustedOverlay, errorText); } catch (Exception e) { errorException = e; mParseError = PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION; } - if (pkg == null) { // If we are only parsing core apps, then a null with INSTALL_SUCCEEDED // just means to skip this app so don't make a fuss about it. @@ -590,22 +659,25 @@ public class PackageParser { parser.close(); assmgr.close(); - // Set code and resource paths - pkg.mPath = destCodePath; - pkg.mScanPath = mArchiveSourcePath; - //pkg.applicationInfo.sourceDir = destCodePath; - //pkg.applicationInfo.publicSourceDir = destRes; + pkg.codePath = mArchiveSourcePath; pkg.mSignatures = null; return pkg; } + private void parseSplitApk(Package pkg, File apkFile, DisplayMetrics metrics, int flags, + boolean trustedOverlay) throws PackageParserException { + // TODO: expand split APK parsing + pkg.splitCodePaths = ArrayUtils.appendElement(String.class, pkg.splitCodePaths, + apkFile.getAbsolutePath()); + } + /** * Gathers the {@link ManifestDigest} for {@code pkg} if it exists in the * APK. If it successfully scanned the package and found the * {@code AndroidManifest.xml}, {@code true} is returned. */ - public boolean collectManifestDigest(Package pkg) { + public void collectManifestDigest(Package pkg) throws PackageParserException { try { final StrictJarFile jarFile = new StrictJarFile(mArchiveSourcePath); try { @@ -616,13 +688,19 @@ public class PackageParser { } finally { jarFile.close(); } - return true; } catch (IOException e) { - return false; + throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, + "Failed to collect manifest digest"); + } + } + + public void collectCertificates(Package pkg, int flags) throws PackageParserException { + if (!collectCertificatesInternal(pkg, flags)) { + throw new PackageParserException(mParseError, "Failed to collect certificates"); } } - public boolean collectCertificates(Package pkg, int flags) { + private boolean collectCertificatesInternal(Package pkg, int flags) { pkg.mSignatures = null; WeakReference<byte[]> readBufferRef; @@ -808,7 +886,7 @@ public class PackageParser { * @param flags Special parse flags * @return PackageLite object with package information or null on failure. */ - public static PackageLite parsePackageLite(String packageFilePath, int flags) { + public static ApkLite parseApkLite(String packageFilePath, int flags) { AssetManager assmgr = null; final XmlResourceParser parser; final Resources res; @@ -844,9 +922,9 @@ public class PackageParser { final AttributeSet attrs = parser; final String errors[] = new String[1]; - PackageLite packageLite = null; + ApkLite packageLite = null; try { - packageLite = parsePackageLite(res, parser, attrs, flags, signatures, errors); + packageLite = parseApkLite(res, parser, attrs, flags, signatures, errors); } catch (PackageParserException e) { Slog.w(TAG, packageFilePath, e); } catch (IOException e) { @@ -930,7 +1008,7 @@ public class PackageParser { (splitName != null) ? splitName.intern() : splitName); } - private static PackageLite parsePackageLite(Resources res, XmlPullParser parser, + private static ApkLite parseApkLite(Resources res, XmlPullParser parser, AttributeSet attrs, int flags, Signature[] signatures, String[] outError) throws IOException, XmlPullParserException, PackageParserException { final Pair<String, String> packageSplit = parsePackageSplitNames(parser, attrs, flags); @@ -972,7 +1050,7 @@ public class PackageParser { } } - return new PackageLite(packageSplit.first, packageSplit.second, versionCode, + return new ApkLite(packageSplit.first, packageSplit.second, versionCode, installLocation, verifiers, signatures); } @@ -988,9 +1066,8 @@ public class PackageParser { return new Signature(sig); } - private Package parsePackage( - Resources res, XmlResourceParser parser, int flags, boolean trustedOverlay, - String[] outError) throws XmlPullParserException, IOException { + private Package parseBaseApk(Resources res, XmlResourceParser parser, int flags, + boolean trustedOverlay, String[] outError) throws XmlPullParserException, IOException { AttributeSet attrs = parser; mParseInstrumentationArgs = null; @@ -1019,7 +1096,13 @@ public class PackageParser { } } - final Package pkg = new Package(pkgName, splitName); + if (!TextUtils.isEmpty(splitName)) { + outError[0] = "Expected base APK, but found split " + splitName; + mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME; + return null; + } + + final Package pkg = new Package(pkgName); boolean foundApp = false; TypedArray sa = res.obtainAttributes(attrs, @@ -3580,10 +3663,17 @@ public class PackageParser { return true; } + /** + * Representation of a full package parsed from APK files on disk. A package + * consists of a single base APK, and zero or more split APKs. + */ public final static class Package { public String packageName; - public String splitName; + + // TODO: work towards making these paths invariant + public String codePath; + public String[] splitCodePaths; // For now we only support one application per package. public final ApplicationInfo applicationInfo = new ApplicationInfo(); @@ -3615,9 +3705,6 @@ public class PackageParser { // We store the application meta-data independently to avoid multiple unwanted references public Bundle mAppMetaData = null; - // If this is a 3rd party app, this is the path of the zip file. - public String mPath; - // The version code declared for this package. public int mVersionCode; @@ -3637,10 +3724,6 @@ public class PackageParser { // preferred up order. public int mPreferredOrder = 0; - // For use by the package manager to keep track of the path to the - // file an app came from. - public String mScanPath; - // For use by package manager to keep track of where it needs to do dexopt. public boolean mDexOptNeeded = true; @@ -3700,9 +3783,8 @@ public class PackageParser { public Set<PublicKey> mSigningKeys; public Map<String, Set<PublicKey>> mKeySetMapping; - public Package(String packageName, String splitName) { + public Package(String packageName) { this.packageName = packageName; - this.splitName = splitName; applicationInfo.packageName = packageName; applicationInfo.uid = -1; } diff --git a/core/java/android/hardware/hdmi/IHdmiControlService.aidl b/core/java/android/hardware/hdmi/IHdmiControlService.aidl index a0bf552..559a469 100644 --- a/core/java/android/hardware/hdmi/IHdmiControlService.aidl +++ b/core/java/android/hardware/hdmi/IHdmiControlService.aidl @@ -40,6 +40,6 @@ interface IHdmiControlService { void addDeviceEventListener(IHdmiDeviceEventListener listener); void deviceSelect(int logicalAddress, IHdmiControlCallback callback); void portSelect(int portId, IHdmiControlCallback callback); - void sendKeyEvent(int keyCode); + void sendKeyEvent(int keyCode, boolean isPressed); List<HdmiPortInfo> getPortInfo(); } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 2a5e9fd..06c05ee 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -4537,6 +4537,12 @@ public final class Settings { public static final String SMS_DEFAULT_APPLICATION = "sms_default_application"; /** + * Specifies the package name currently configured to be the primary phone application + * @hide + */ + public static final String PHONE_DEFAULT_APPLICATION = "phone_default_application"; + + /** * Name of a package that the current user has explicitly allowed to see all of that * user's notifications. * diff --git a/core/java/android/service/trust/TrustAgentService.java b/core/java/android/service/trust/TrustAgentService.java index a6cddae..8fa45e6 100644 --- a/core/java/android/service/trust/TrustAgentService.java +++ b/core/java/android/service/trust/TrustAgentService.java @@ -80,6 +80,11 @@ public class TrustAgentService extends Service { private ITrustAgentServiceCallback mCallback; + private Runnable mPendingGrantTrustTask; + + // Lock used to access mPendingGrantTrustTask and mCallback. + private final Object mLock = new Object(); + private Handler mHandler = new Handler() { public void handleMessage(android.os.Message msg) { switch (msg.what) { @@ -127,12 +132,24 @@ public class TrustAgentService extends Service { * @param initiatedByUser indicates that the user has explicitly initiated an action that proves * the user is about to use the device. */ - public final void grantTrust(CharSequence message, long durationMs, boolean initiatedByUser) { - if (mCallback != null) { - try { - mCallback.grantTrust(message.toString(), durationMs, initiatedByUser); - } catch (RemoteException e) { - onError("calling enableTrust()"); + public final void grantTrust( + final CharSequence message, final long durationMs, final boolean initiatedByUser) { + synchronized (mLock) { + if (mCallback != null) { + try { + mCallback.grantTrust(message.toString(), durationMs, initiatedByUser); + } catch (RemoteException e) { + onError("calling enableTrust()"); + } + } else { + // Remember trust has been granted so we can effectively grant it once the service + // is bound. + mPendingGrantTrustTask = new Runnable() { + @Override + public void run() { + grantTrust(message, durationMs, initiatedByUser); + } + }; } } } @@ -141,11 +158,16 @@ public class TrustAgentService extends Service { * Call to revoke trust on the device. */ public final void revokeTrust() { - if (mCallback != null) { - try { - mCallback.revokeTrust(); - } catch (RemoteException e) { - onError("calling revokeTrust()"); + synchronized (mLock) { + if (mPendingGrantTrustTask != null) { + mPendingGrantTrustTask = null; + } + if (mCallback != null) { + try { + mCallback.revokeTrust(); + } catch (RemoteException e) { + onError("calling revokeTrust()"); + } } } } @@ -164,7 +186,13 @@ public class TrustAgentService extends Service { } public void setCallback(ITrustAgentServiceCallback callback) { - mCallback = callback; + synchronized (mLock) { + mCallback = callback; + if (mPendingGrantTrustTask != null) { + mPendingGrantTrustTask.run(); + mPendingGrantTrustTask = null; + } + } } } diff --git a/core/java/android/text/GraphicsOperations.java b/core/java/android/text/GraphicsOperations.java index d426d12..8674c66 100644 --- a/core/java/android/text/GraphicsOperations.java +++ b/core/java/android/text/GraphicsOperations.java @@ -38,7 +38,7 @@ extends CharSequence * {@hide} */ void drawTextRun(Canvas c, int start, int end, int contextStart, int contextEnd, - float x, float y, int flags, Paint p); + float x, float y, boolean isRtl, Paint p); /** * Just like {@link Paint#measureText}. @@ -55,12 +55,12 @@ extends CharSequence * @hide */ float getTextRunAdvances(int start, int end, int contextStart, int contextEnd, - int flags, float[] advances, int advancesIndex, Paint paint); + boolean isRtl, float[] advances, int advancesIndex, Paint paint); /** * Just like {@link Paint#getTextRunCursor}. * @hide */ - int getTextRunCursor(int contextStart, int contextEnd, int flags, int offset, + int getTextRunCursor(int contextStart, int contextEnd, int dir, int offset, int cursorOpt, Paint p); } diff --git a/core/java/android/text/MeasuredText.java b/core/java/android/text/MeasuredText.java index f8e3c83..2415b11 100644 --- a/core/java/android/text/MeasuredText.java +++ b/core/java/android/text/MeasuredText.java @@ -159,18 +159,17 @@ class MeasuredText { mPos = p + len; if (mEasy) { - int flags = mDir == Layout.DIR_LEFT_TO_RIGHT - ? Canvas.DIRECTION_LTR : Canvas.DIRECTION_RTL; - return paint.getTextRunAdvances(mChars, p, len, p, len, flags, mWidths, p); + boolean isRtl = mDir != Layout.DIR_LEFT_TO_RIGHT; + return paint.getTextRunAdvances(mChars, p, len, p, len, isRtl, mWidths, p); } float totalAdvance = 0; int level = mLevels[p]; for (int q = p, i = p + 1, e = p + len;; ++i) { if (i == e || mLevels[i] != level) { - int flags = (level & 0x1) == 0 ? Canvas.DIRECTION_LTR : Canvas.DIRECTION_RTL; + boolean isRtl = (level & 0x1) != 0; totalAdvance += - paint.getTextRunAdvances(mChars, q, i - q, q, i - q, flags, mWidths, q); + paint.getTextRunAdvances(mChars, q, i - q, q, i - q, isRtl, mWidths, q); if (i == e) { break; } diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java index 1d9aa05..6b984d6 100644 --- a/core/java/android/text/SpannableStringBuilder.java +++ b/core/java/android/text/SpannableStringBuilder.java @@ -503,7 +503,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable // Span watchers need to be called after text watchers, which may update the layout sendToSpanWatchers(start, end, newLen - origLen); - return this; + return this; } private static boolean hasNonExclusiveExclusiveSpanAt(CharSequence text, int offset) { @@ -745,7 +745,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable } } - return 0; + return 0; } /** @@ -1117,20 +1117,20 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable * {@hide} */ public void drawTextRun(Canvas c, int start, int end, int contextStart, int contextEnd, - float x, float y, int flags, Paint p) { + float x, float y, boolean isRtl, Paint p) { checkRange("drawTextRun", start, end); int contextLen = contextEnd - contextStart; int len = end - start; if (contextEnd <= mGapStart) { - c.drawTextRun(mText, start, len, contextStart, contextLen, x, y, flags, p); + c.drawTextRun(mText, start, len, contextStart, contextLen, x, y, isRtl, p); } else if (contextStart >= mGapStart) { c.drawTextRun(mText, start + mGapLength, len, contextStart + mGapLength, - contextLen, x, y, flags, p); + contextLen, x, y, isRtl, p); } else { char[] buf = TextUtils.obtain(contextLen); getChars(contextStart, contextEnd, buf, 0); - c.drawTextRun(buf, start - contextStart, len, 0, contextLen, x, y, flags, p); + c.drawTextRun(buf, start - contextStart, len, 0, contextLen, x, y, isRtl, p); TextUtils.recycle(buf); } } @@ -1187,7 +1187,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable * Don't call this yourself -- exists for Paint to use internally. * {@hide} */ - public float getTextRunAdvances(int start, int end, int contextStart, int contextEnd, int flags, + public float getTextRunAdvances(int start, int end, int contextStart, int contextEnd, boolean isRtl, float[] advances, int advancesPos, Paint p) { float ret; @@ -1197,15 +1197,15 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable if (end <= mGapStart) { ret = p.getTextRunAdvances(mText, start, len, contextStart, contextLen, - flags, advances, advancesPos); + isRtl, advances, advancesPos); } else if (start >= mGapStart) { ret = p.getTextRunAdvances(mText, start + mGapLength, len, - contextStart + mGapLength, contextLen, flags, advances, advancesPos); + contextStart + mGapLength, contextLen, isRtl, advances, advancesPos); } else { char[] buf = TextUtils.obtain(contextLen); getChars(contextStart, contextEnd, buf, 0); ret = p.getTextRunAdvances(buf, start - contextStart, len, - 0, contextLen, flags, advances, advancesPos); + 0, contextLen, isRtl, advances, advancesPos); TextUtils.recycle(buf); } @@ -1228,7 +1228,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable * * @param contextStart the start index of the context * @param contextEnd the (non-inclusive) end index of the context - * @param flags either DIRECTION_RTL or DIRECTION_LTR + * @param dir either DIRECTION_RTL or DIRECTION_LTR * @param offset the cursor position to move from * @param cursorOpt how to move the cursor, one of CURSOR_AFTER, * CURSOR_AT_OR_AFTER, CURSOR_BEFORE, @@ -1238,7 +1238,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable * @deprecated This is an internal method, refrain from using it in your code */ @Deprecated - public int getTextRunCursor(int contextStart, int contextEnd, int flags, int offset, + public int getTextRunCursor(int contextStart, int contextEnd, int dir, int offset, int cursorOpt, Paint p) { int ret; @@ -1246,15 +1246,15 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable int contextLen = contextEnd - contextStart; if (contextEnd <= mGapStart) { ret = p.getTextRunCursor(mText, contextStart, contextLen, - flags, offset, cursorOpt); + dir, offset, cursorOpt); } else if (contextStart >= mGapStart) { ret = p.getTextRunCursor(mText, contextStart + mGapLength, contextLen, - flags, offset + mGapLength, cursorOpt) - mGapLength; + dir, offset + mGapLength, cursorOpt) - mGapLength; } else { char[] buf = TextUtils.obtain(contextLen); getChars(contextStart, contextEnd, buf, 0); ret = p.getTextRunCursor(buf, 0, contextLen, - flags, offset - contextStart, cursorOpt) + contextStart; + dir, offset - contextStart, cursorOpt) + contextStart; TextUtils.recycle(buf); } diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java index d892f19..c19cf32 100644 --- a/core/java/android/text/TextLine.java +++ b/core/java/android/text/TextLine.java @@ -664,14 +664,14 @@ class TextLine { } } - int flags = runIsRtl ? Paint.DIRECTION_RTL : Paint.DIRECTION_LTR; + int dir = runIsRtl ? Paint.DIRECTION_RTL : Paint.DIRECTION_LTR; int cursorOpt = after ? Paint.CURSOR_AFTER : Paint.CURSOR_BEFORE; if (mCharsValid) { return wp.getTextRunCursor(mChars, spanStart, spanLimit - spanStart, - flags, offset, cursorOpt); + dir, offset, cursorOpt); } else { return wp.getTextRunCursor(mText, mStart + spanStart, - mStart + spanLimit, flags, mStart + offset, cursorOpt) - mStart; + mStart + spanLimit, dir, mStart + offset, cursorOpt) - mStart; } } @@ -738,15 +738,14 @@ class TextLine { int contextLen = contextEnd - contextStart; if (needWidth || (c != null && (wp.bgColor != 0 || wp.underlineColor != 0 || runIsRtl))) { - int flags = runIsRtl ? Paint.DIRECTION_RTL : Paint.DIRECTION_LTR; if (mCharsValid) { ret = wp.getTextRunAdvances(mChars, start, runLen, - contextStart, contextLen, flags, null, 0); + contextStart, contextLen, runIsRtl, null, 0); } else { int delta = mStart; ret = wp.getTextRunAdvances(mText, delta + start, delta + end, delta + contextStart, delta + contextEnd, - flags, null, 0); + runIsRtl, null, 0); } } @@ -977,16 +976,15 @@ class TextLine { private void drawTextRun(Canvas c, TextPaint wp, int start, int end, int contextStart, int contextEnd, boolean runIsRtl, float x, int y) { - int flags = runIsRtl ? Canvas.DIRECTION_RTL : Canvas.DIRECTION_LTR; if (mCharsValid) { int count = end - start; int contextCount = contextEnd - contextStart; c.drawTextRun(mChars, start, count, contextStart, contextCount, - x, y, flags, wp); + x, y, runIsRtl, wp); } else { int delta = mStart; c.drawTextRun(mText, delta + start, delta + end, - delta + contextStart, delta + contextEnd, x, y, flags, wp); + delta + contextStart, delta + contextEnd, x, y, runIsRtl, wp); } } diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java index 5056097..832d67a 100644 --- a/core/java/android/view/GLES20Canvas.java +++ b/core/java/android/view/GLES20Canvas.java @@ -51,10 +51,10 @@ class GLES20Canvas extends HardwareCanvas { private int mWidth; private int mHeight; - + private float[] mPoint; private float[] mLine; - + private Rect mClipBounds; private RectF mPathBounds; @@ -167,7 +167,7 @@ class GLES20Canvas extends HardwareCanvas { nSetViewport(mRenderer, width, height); } - + private static native void nSetViewport(long renderer, int width, int height); @Override @@ -208,22 +208,22 @@ class GLES20Canvas extends HardwareCanvas { /** * Must match Caches::FlushMode values - * - * @see #flushCaches(int) + * + * @see #flushCaches(int) */ static final int FLUSH_CACHES_LAYERS = 0; - + /** * Must match Caches::FlushMode values - * - * @see #flushCaches(int) + * + * @see #flushCaches(int) */ static final int FLUSH_CACHES_MODERATE = 1; /** * Must match Caches::FlushMode values - * - * @see #flushCaches(int) + * + * @see #flushCaches(int) */ static final int FLUSH_CACHES_FULL = 2; @@ -245,7 +245,7 @@ class GLES20Canvas extends HardwareCanvas { /////////////////////////////////////////////////////////////////////////// // Hardware layer /////////////////////////////////////////////////////////////////////////// - + void drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint) { layer.setLayerPaint(paint); nDrawLayer(mRenderer, layer.getLayer(), x, y); @@ -298,7 +298,7 @@ class GLES20Canvas extends HardwareCanvas { public boolean clipRect(float left, float top, float right, float bottom) { return nClipRect(mRenderer, left, top, right, bottom, Region.Op.INTERSECT.nativeInt); } - + private static native boolean nClipRect(long renderer, float left, float top, float right, float bottom, int op); @@ -311,14 +311,14 @@ class GLES20Canvas extends HardwareCanvas { public boolean clipRect(int left, int top, int right, int bottom) { return nClipRect(mRenderer, left, top, right, bottom, Region.Op.INTERSECT.nativeInt); } - + private static native boolean nClipRect(long renderer, int left, int top, int right, int bottom, int op); @Override public boolean clipRect(Rect rect) { return nClipRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom, - Region.Op.INTERSECT.nativeInt); + Region.Op.INTERSECT.nativeInt); } @Override @@ -360,7 +360,7 @@ class GLES20Canvas extends HardwareCanvas { public boolean quickReject(float left, float top, float right, float bottom, EdgeType type) { return nQuickReject(mRenderer, left, top, right, bottom); } - + private static native boolean nQuickReject(long renderer, float left, float top, float right, float bottom); @@ -385,7 +385,7 @@ class GLES20Canvas extends HardwareCanvas { public void translate(float dx, float dy) { if (dx != 0.0f || dy != 0.0f) nTranslate(mRenderer, dx, dy); } - + private static native void nTranslate(long renderer, float dx, float dy); @Override @@ -399,21 +399,21 @@ class GLES20Canvas extends HardwareCanvas { public void rotate(float degrees) { nRotate(mRenderer, degrees); } - + private static native void nRotate(long renderer, float degrees); @Override public void scale(float sx, float sy) { nScale(mRenderer, sx, sy); } - + private static native void nScale(long renderer, float sx, float sy); @Override public void setMatrix(Matrix matrix) { nSetMatrix(mRenderer, matrix == null ? 0 : matrix.native_instance); } - + private static native void nSetMatrix(long renderer, long matrix); @SuppressWarnings("deprecation") @@ -421,16 +421,16 @@ class GLES20Canvas extends HardwareCanvas { public void getMatrix(Matrix matrix) { nGetMatrix(mRenderer, matrix.native_instance); } - + private static native void nGetMatrix(long renderer, long matrix); @Override public void concat(Matrix matrix) { if (matrix != null) nConcatMatrix(mRenderer, matrix.native_instance); } - + private static native void nConcatMatrix(long renderer, long matrix); - + /////////////////////////////////////////////////////////////////////////// // State management /////////////////////////////////////////////////////////////////////////// @@ -439,14 +439,14 @@ class GLES20Canvas extends HardwareCanvas { public int save() { return nSave(mRenderer, Canvas.CLIP_SAVE_FLAG | Canvas.MATRIX_SAVE_FLAG); } - + @Override public int save(int saveFlags) { return nSave(mRenderer, saveFlags); } private static native int nSave(long renderer, int flags); - + @Override public int saveLayer(RectF bounds, Paint paint, int saveFlags) { if (bounds != null) { @@ -494,12 +494,12 @@ class GLES20Canvas extends HardwareCanvas { private static native int nSaveLayerAlpha(long renderer, float left, float top, float right, float bottom, int alpha, int saveFlags); - + @Override public void restore() { nRestore(mRenderer); } - + private static native void nRestore(long renderer); @Override @@ -508,12 +508,12 @@ class GLES20Canvas extends HardwareCanvas { } private static native void nRestoreToCount(long renderer, int saveCount); - + @Override public int getSaveCount() { return nGetSaveCount(mRenderer); } - + private static native int nGetSaveCount(long renderer); /////////////////////////////////////////////////////////////////////////// @@ -739,7 +739,7 @@ class GLES20Canvas extends HardwareCanvas { public void drawColor(int color, PorterDuff.Mode mode) { nDrawColor(mRenderer, color, mode.nativeInt); } - + private static native void nDrawColor(long renderer, int color, int mode); @Override @@ -930,7 +930,7 @@ class GLES20Canvas extends HardwareCanvas { nDrawText(mRenderer, text, index, count, x, y, paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface); } - + private static native void nDrawText(long renderer, char[] text, int index, int count, float x, float y, int bidiFlags, long paint, long typeface); @@ -997,49 +997,45 @@ class GLES20Canvas extends HardwareCanvas { @Override public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount, - float x, float y, int dir, Paint paint) { + float x, float y, boolean isRtl, Paint paint) { if ((index | count | text.length - index - count) < 0) { throw new IndexOutOfBoundsException(); } - if (dir != DIRECTION_LTR && dir != DIRECTION_RTL) { - throw new IllegalArgumentException("Unknown direction: " + dir); - } - nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y, dir, + nDrawTextRun(mRenderer, text, index, count, contextIndex, contextCount, x, y, isRtl, paint.mNativePaint, paint.mNativeTypeface); } private static native void nDrawTextRun(long renderer, char[] text, int index, int count, - int contextIndex, int contextCount, float x, float y, int dir, long nativePaint, long nativeTypeface); + int contextIndex, int contextCount, float x, float y, boolean isRtl, long nativePaint, long nativeTypeface); @Override public void drawTextRun(CharSequence text, int start, int end, int contextStart, int contextEnd, - float x, float y, int dir, Paint paint) { + float x, float y, boolean isRtl, Paint paint) { if ((start | end | end - start | text.length() - end) < 0) { throw new IndexOutOfBoundsException(); } - int flags = dir == 0 ? 0 : 1; if (text instanceof String || text instanceof SpannedString || text instanceof SpannableString) { nDrawTextRun(mRenderer, text.toString(), start, end, contextStart, - contextEnd, x, y, flags, paint.mNativePaint, paint.mNativeTypeface); + contextEnd, x, y, isRtl, paint.mNativePaint, paint.mNativeTypeface); } else if (text instanceof GraphicsOperations) { ((GraphicsOperations) text).drawTextRun(this, start, end, - contextStart, contextEnd, x, y, flags, paint); + contextStart, contextEnd, x, y, isRtl, paint); } else { int contextLen = contextEnd - contextStart; int len = end - start; char[] buf = TemporaryBuffer.obtain(contextLen); TextUtils.getChars(text, contextStart, contextEnd, buf, 0); nDrawTextRun(mRenderer, buf, start - contextStart, len, 0, contextLen, - x, y, flags, paint.mNativePaint, paint.mNativeTypeface); + x, y, isRtl, paint.mNativePaint, paint.mNativeTypeface); TemporaryBuffer.recycle(buf); } } private static native void nDrawTextRun(long renderer, String text, int start, int end, - int contextStart, int contextEnd, float x, float y, int flags, long nativePaint, long nativeTypeface); + int contextStart, int contextEnd, float x, float y, boolean isRtl, long nativePaint, long nativeTypeface); @Override public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset, diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 41037a5..b9e56f3 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -6116,6 +6116,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ protected boolean fitSystemWindows(Rect insets) { if ((mPrivateFlags3 & PFLAG3_APPLYING_INSETS) == 0) { + if (insets == null) { + // Null insets by definition have already been consumed. + // This call cannot apply insets since there are none to apply, + // so return false. + return false; + } // If we're not in the process of dispatching the newer apply insets call, // that means we're not in the compatibility path. Dispatch into the newer // apply insets path and take things from there. diff --git a/core/java/android/view/ViewAnimationUtils.java b/core/java/android/view/ViewAnimationUtils.java index 3854f34..29e865f 100644 --- a/core/java/android/view/ViewAnimationUtils.java +++ b/core/java/android/view/ViewAnimationUtils.java @@ -23,7 +23,7 @@ import android.animation.ValueAnimator; * Defines common utilities for working with View's animations. * */ -public class ViewAnimationUtils { +public final class ViewAnimationUtils { private ViewAnimationUtils() {} /** * Returns a ValueAnimator which can animate a clipping circle. diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java index ec396aa..470d413 100644 --- a/core/java/android/webkit/WebChromeClient.java +++ b/core/java/android/webkit/WebChromeClient.java @@ -408,7 +408,6 @@ public class WebChromeClient { * @return true if filePathCallback will be invoked, false to use default handling. * * @see FileChooserParams - * @hide For API approval */ public boolean showFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) { @@ -416,11 +415,8 @@ public class WebChromeClient { } /** - * Parameters used in the {@link #showFileChooser(WebView,ValueCallback<String[]>,FileChooserParams)} - * method. - * + * Parameters used in the {@link #showFileChooser} method. * This is intended to be used as a read-only data struct by the application. - * @hide For API approval */ public static class FileChooserParams { // Flags for mode diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 22f5e23..0f51e8b 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -2727,7 +2727,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener /** * Sets whether the soft input method will be made visible when this * TextView gets focused. The default is true. - * @hide */ @android.view.RemotableViewMethod public final void setShowSoftInputOnFocus(boolean show) { @@ -2738,7 +2737,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener /** * Returns whether the soft input method will be made visible when this * TextView gets focused. The default is true. - * @hide */ public final boolean getShowSoftInputOnFocus() { // When there is no Editor, return default true value @@ -9062,11 +9060,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } public void drawTextRun(Canvas c, int start, int end, - int contextStart, int contextEnd, float x, float y, int flags, Paint p) { + int contextStart, int contextEnd, float x, float y, boolean isRtl, Paint p) { int count = end - start; int contextCount = contextEnd - contextStart; c.drawTextRun(mChars, start + mStart, count, contextStart + mStart, - contextCount, x, y, flags, p); + contextCount, x, y, isRtl, p); } public float measureText(int start, int end, Paint p) { @@ -9078,20 +9076,20 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } public float getTextRunAdvances(int start, int end, int contextStart, - int contextEnd, int flags, float[] advances, int advancesIndex, + int contextEnd, boolean isRtl, float[] advances, int advancesIndex, Paint p) { int count = end - start; int contextCount = contextEnd - contextStart; return p.getTextRunAdvances(mChars, start + mStart, count, - contextStart + mStart, contextCount, flags, advances, + contextStart + mStart, contextCount, isRtl, advances, advancesIndex); } - public int getTextRunCursor(int contextStart, int contextEnd, int flags, + public int getTextRunCursor(int contextStart, int contextEnd, int dir, int offset, int cursorOpt, Paint p) { int contextCount = contextEnd - contextStart; return p.getTextRunCursor(mChars, contextStart + mStart, - contextCount, flags, offset + mStart, cursorOpt); + contextCount, dir, offset + mStart, cursorOpt); } } diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java index 2b62552..8ee0a1b 100644 --- a/core/java/android/widget/VideoView.java +++ b/core/java/android/widget/VideoView.java @@ -22,6 +22,7 @@ import android.content.DialogInterface; import android.content.res.Resources; import android.graphics.Canvas; import android.media.AudioManager; +import android.media.ClosedCaptionRenderer; import android.media.MediaFormat; import android.media.MediaPlayer; import android.media.MediaPlayer.OnCompletionListener; @@ -316,6 +317,7 @@ public class VideoView extends SurfaceView context, mMediaPlayer.getMediaTimeProvider(), mMediaPlayer); controller.registerRenderer(new WebVttRenderer(context)); controller.registerRenderer(new TtmlRenderer(context)); + controller.registerRenderer(new ClosedCaptionRenderer(context)); mMediaPlayer.setSubtitleAnchor(controller, this); if (mAudioSession != 0) { diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp index 6de3b9e..a5964c8 100644 --- a/core/jni/android/graphics/Canvas.cpp +++ b/core/jni/android/graphics/Canvas.cpp @@ -882,26 +882,26 @@ public: static void drawText___CIIFFIPaintTypeface(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text, jint index, jint count, - jfloat x, jfloat y, jint flags, + jfloat x, jfloat y, jint bidiFlags, jlong paintHandle, jlong typefaceHandle) { SkCanvas* canvas = getNativeCanvas(canvasHandle); SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); jchar* textArray = env->GetCharArrayElements(text, NULL); - drawTextWithGlyphs(canvas, textArray + index, 0, count, x, y, flags, paint, typeface); + drawTextWithGlyphs(canvas, textArray + index, 0, count, x, y, bidiFlags, paint, typeface); env->ReleaseCharArrayElements(text, textArray, JNI_ABORT); } static void drawText__StringIIFFIPaintTypeface(JNIEnv* env, jobject, jlong canvasHandle, jstring text, jint start, jint end, - jfloat x, jfloat y, jint flags, + jfloat x, jfloat y, jint bidiFlags, jlong paintHandle, jlong typefaceHandle) { SkCanvas* canvas = getNativeCanvas(canvasHandle); SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); const jchar* textArray = env->GetStringChars(text, NULL); - drawTextWithGlyphs(canvas, textArray, start, end, x, y, flags, paint, typeface); + drawTextWithGlyphs(canvas, textArray, start, end, x, y, bidiFlags, paint, typeface); env->ReleaseStringChars(text, textArray); } @@ -951,24 +951,25 @@ public: static void drawTextWithGlyphs(SkCanvas* canvas, const jchar* textArray, int start, int end, - jfloat x, jfloat y, int flags, SkPaint* paint, TypefaceImpl* typeface) { + jfloat x, jfloat y, int bidiFlags, SkPaint* paint, TypefaceImpl* typeface) { jint count = end - start; - drawTextWithGlyphs(canvas, textArray + start, 0, count, count, x, y, flags, paint, typeface); + drawTextWithGlyphs(canvas, textArray + start, 0, count, count, x, y, bidiFlags, paint, + typeface); } static void drawTextWithGlyphs(SkCanvas* canvas, const jchar* textArray, int start, int count, int contextCount, - jfloat x, jfloat y, int flags, SkPaint* paint, TypefaceImpl* typeface) { + jfloat x, jfloat y, int bidiFlags, SkPaint* paint, TypefaceImpl* typeface) { #ifdef USE_MINIKIN Layout layout; - std::string css = MinikinUtils::setLayoutProperties(&layout, paint, flags, typeface); + std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface); layout.doLayout(textArray, start, count, contextCount, css); drawGlyphsToSkia(canvas, paint, layout, x, y); #else sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint, - textArray, start, count, contextCount, flags); + textArray, start, count, contextCount, bidiFlags); if (value == NULL) { return; } @@ -979,7 +980,8 @@ public: x -= value->getTotalAdvance(); } paint->setTextAlign(SkPaint::kLeft_Align); - doDrawGlyphsPos(canvas, value->getGlyphs(), value->getPos(), 0, value->getGlyphsCount(), x, y, flags, paint); + doDrawGlyphsPos(canvas, value->getGlyphs(), value->getPos(), 0, value->getGlyphsCount(), + x, y, paint); doDrawTextDecorations(canvas, x, y, value->getTotalAdvance(), paint); paint->setTextAlign(align); #endif @@ -990,42 +992,37 @@ public: #define kStdUnderline_Offset (1.0f / 9.0f) #define kStdUnderline_Thickness (1.0f / 18.0f) -static void doDrawTextDecorations(SkCanvas* canvas, jfloat x, jfloat y, jfloat length, SkPaint* paint) { - uint32_t flags; - SkDrawFilter* drawFilter = canvas->getDrawFilter(); - if (drawFilter) { - SkPaint paintCopy(*paint); - drawFilter->filter(&paintCopy, SkDrawFilter::kText_Type); - flags = paintCopy.getFlags(); - } else { - flags = paint->getFlags(); - } - if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) { - SkScalar left = x; - SkScalar right = x + length; - float textSize = paint->getTextSize(); - float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f); - if (flags & SkPaint::kUnderlineText_Flag) { - SkScalar top = y + textSize * kStdUnderline_Offset - 0.5f * strokeWidth; - SkScalar bottom = y + textSize * kStdUnderline_Offset + 0.5f * strokeWidth; - canvas->drawRectCoords(left, top, right, bottom, *paint); + static void doDrawTextDecorations(SkCanvas* canvas, jfloat x, jfloat y, jfloat length, + SkPaint* paint) { + uint32_t flags; + SkDrawFilter* drawFilter = canvas->getDrawFilter(); + if (drawFilter) { + SkPaint paintCopy(*paint); + drawFilter->filter(&paintCopy, SkDrawFilter::kText_Type); + flags = paintCopy.getFlags(); + } else { + flags = paint->getFlags(); } - if (flags & SkPaint::kStrikeThruText_Flag) { - SkScalar top = y + textSize * kStdStrikeThru_Offset - 0.5f * strokeWidth; - SkScalar bottom = y + textSize * kStdStrikeThru_Offset + 0.5f * strokeWidth; - canvas->drawRectCoords(left, top, right, bottom, *paint); + if (flags & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag)) { + SkScalar left = x; + SkScalar right = x + length; + float textSize = paint->getTextSize(); + float strokeWidth = fmax(textSize * kStdUnderline_Thickness, 1.0f); + if (flags & SkPaint::kUnderlineText_Flag) { + SkScalar top = y + textSize * kStdUnderline_Offset - 0.5f * strokeWidth; + SkScalar bottom = y + textSize * kStdUnderline_Offset + 0.5f * strokeWidth; + canvas->drawRectCoords(left, top, right, bottom, *paint); + } + if (flags & SkPaint::kStrikeThruText_Flag) { + SkScalar top = y + textSize * kStdStrikeThru_Offset - 0.5f * strokeWidth; + SkScalar bottom = y + textSize * kStdStrikeThru_Offset + 0.5f * strokeWidth; + canvas->drawRectCoords(left, top, right, bottom, *paint); + } } } -} - - static void doDrawGlyphs(SkCanvas* canvas, const jchar* glyphArray, int index, int count, - jfloat x, jfloat y, int flags, SkPaint* paint) { - // Beware: this needs Glyph encoding (already done on the Paint constructor) - canvas->drawText(glyphArray + index * 2, count * 2, x, y, *paint); - } static void doDrawGlyphsPos(SkCanvas* canvas, const jchar* glyphArray, const jfloat* posArray, - int index, int count, jfloat x, jfloat y, int flags, SkPaint* paint) { + int index, int count, jfloat x, jfloat y, SkPaint* paint) { SkPoint* posPtr = new SkPoint[count]; for (int indx = 0; indx < count; indx++) { posPtr[indx].fX = x + posArray[indx * 2]; @@ -1035,33 +1032,35 @@ static void doDrawTextDecorations(SkCanvas* canvas, jfloat x, jfloat y, jfloat l delete[] posPtr; } - static void drawTextRun___CIIIIFFIPaintTypeface( + static void drawTextRun___CIIIIFFZPaintTypeface( JNIEnv* env, jobject, jlong canvasHandle, jcharArray text, jint index, jint count, jint contextIndex, jint contextCount, - jfloat x, jfloat y, jint dirFlags, jlong paintHandle, jlong typefaceHandle) { + jfloat x, jfloat y, jboolean isRtl, jlong paintHandle, jlong typefaceHandle) { SkCanvas* canvas = getNativeCanvas(canvasHandle); SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); + int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR; jchar* chars = env->GetCharArrayElements(text, NULL); drawTextWithGlyphs(canvas, chars + contextIndex, index - contextIndex, - count, contextCount, x, y, dirFlags, paint, typeface); + count, contextCount, x, y, bidiFlags, paint, typeface); env->ReleaseCharArrayElements(text, chars, JNI_ABORT); } - static void drawTextRun__StringIIIIFFIPaintTypeface( + static void drawTextRun__StringIIIIFFZPaintTypeface( JNIEnv* env, jobject obj, jlong canvasHandle, jstring text, jint start, jint end, jint contextStart, jint contextEnd, - jfloat x, jfloat y, jint dirFlags, jlong paintHandle, jlong typefaceHandle) { + jfloat x, jfloat y, jboolean isRtl, jlong paintHandle, jlong typefaceHandle) { SkCanvas* canvas = getNativeCanvas(canvasHandle); SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); + int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR; jint count = end - start; jint contextCount = contextEnd - contextStart; const jchar* chars = env->GetStringChars(text, NULL); drawTextWithGlyphs(canvas, chars + contextStart, start - contextStart, - count, contextCount, x, y, dirFlags, paint, typeface); + count, contextCount, x, y, bidiFlags, paint, typeface); env->ReleaseStringChars(text, chars); } @@ -1268,10 +1267,10 @@ static JNINativeMethod gCanvasMethods[] = { (void*) SkCanvasGlue::drawText___CIIFFIPaintTypeface}, {"native_drawText","(JLjava/lang/String;IIFFIJJ)V", (void*) SkCanvasGlue::drawText__StringIIFFIPaintTypeface}, - {"native_drawTextRun","(J[CIIIIFFIJJ)V", - (void*) SkCanvasGlue::drawTextRun___CIIIIFFIPaintTypeface}, - {"native_drawTextRun","(JLjava/lang/String;IIIIFFIJJ)V", - (void*) SkCanvasGlue::drawTextRun__StringIIIIFFIPaintTypeface}, + {"native_drawTextRun","(J[CIIIIFFZJJ)V", + (void*) SkCanvasGlue::drawTextRun___CIIIIFFZPaintTypeface}, + {"native_drawTextRun","(JLjava/lang/String;IIIIFFZJJ)V", + (void*) SkCanvasGlue::drawTextRun__StringIIIIFFZPaintTypeface}, {"native_drawPosText","(J[CII[FJ)V", (void*) SkCanvasGlue::drawPosText___CII_FPaint}, {"native_drawPosText","(JLjava/lang/String;[FJ)V", diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp index 8b11d31..1e40d94 100644 --- a/core/jni/android/graphics/Paint.cpp +++ b/core/jni/android/graphics/Paint.cpp @@ -707,7 +707,7 @@ public: } static jfloat doTextRunAdvances(JNIEnv *env, SkPaint *paint, TypefaceImpl* typeface, const jchar *text, - jint start, jint count, jint contextCount, jint flags, + jint start, jint count, jint contextCount, jboolean isRtl, jfloatArray advances, jint advancesIndex) { NPE_CHECK_RETURN_ZERO(env, paint); NPE_CHECK_RETURN_ZERO(env, text); @@ -729,14 +729,16 @@ public: jfloat* advancesArray = new jfloat[count]; jfloat totalAdvance = 0; + int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR; + #ifdef USE_MINIKIN Layout layout; - std::string css = MinikinUtils::setLayoutProperties(&layout, paint, flags, typeface); + std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface); layout.doLayout(text, start, count, contextCount, css); layout.getAdvances(advancesArray); totalAdvance = layout.getAdvance(); #else - TextLayout::getTextRunAdvances(paint, text, start, count, contextCount, flags, + TextLayout::getTextRunAdvances(paint, text, start, count, contextCount, bidiFlags, advancesArray, &totalAdvance); #endif @@ -747,28 +749,28 @@ public: return totalAdvance; } - static jfloat getTextRunAdvances___CIIIII_FI(JNIEnv* env, jobject clazz, jlong paintHandle, + static jfloat getTextRunAdvances___CIIIIZ_FI(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jcharArray text, jint index, jint count, jint contextIndex, jint contextCount, - jint flags, jfloatArray advances, jint advancesIndex) { + jboolean isRtl, jfloatArray advances, jint advancesIndex) { SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); jchar* textArray = env->GetCharArrayElements(text, NULL); jfloat result = doTextRunAdvances(env, paint, typeface, textArray + contextIndex, - index - contextIndex, count, contextCount, flags, advances, advancesIndex); + index - contextIndex, count, contextCount, isRtl, advances, advancesIndex); env->ReleaseCharArrayElements(text, textArray, JNI_ABORT); return result; } - static jfloat getTextRunAdvances__StringIIIII_FI(JNIEnv* env, jobject clazz, jlong paintHandle, + static jfloat getTextRunAdvances__StringIIIIZ_FI(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, - jstring text, jint start, jint end, jint contextStart, jint contextEnd, jint flags, + jstring text, jint start, jint end, jint contextStart, jint contextEnd, jboolean isRtl, jfloatArray advances, jint advancesIndex) { SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle); const jchar* textArray = env->GetStringChars(text, NULL); jfloat result = doTextRunAdvances(env, paint, typeface, textArray + contextStart, - start - contextStart, end - start, contextEnd - contextStart, flags, + start - contextStart, end - start, contextEnd - contextStart, isRtl, advances, advancesIndex); env->ReleaseStringChars(text, textArray); return result; @@ -819,21 +821,21 @@ public: } static jint getTextRunCursor___C(JNIEnv* env, jobject clazz, jlong paintHandle, jcharArray text, - jint contextStart, jint contextCount, jint flags, jint offset, jint cursorOpt) { + jint contextStart, jint contextCount, jint dir, jint offset, jint cursorOpt) { SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); jchar* textArray = env->GetCharArrayElements(text, NULL); - jint result = doTextRunCursor(env, paint, textArray, contextStart, contextCount, flags, + jint result = doTextRunCursor(env, paint, textArray, contextStart, contextCount, dir, offset, cursorOpt); env->ReleaseCharArrayElements(text, textArray, JNI_ABORT); return result; } static jint getTextRunCursor__String(JNIEnv* env, jobject clazz, jlong paintHandle, jstring text, - jint contextStart, jint contextEnd, jint flags, jint offset, jint cursorOpt) { + jint contextStart, jint contextEnd, jint dir, jint offset, jint cursorOpt) { SkPaint* paint = reinterpret_cast<SkPaint*>(paintHandle); const jchar* textArray = env->GetStringChars(text, NULL); jint result = doTextRunCursor(env, paint, textArray, contextStart, - contextEnd - contextStart, flags, offset, cursorOpt); + contextEnd - contextStart, dir, offset, cursorOpt); env->ReleaseStringChars(text, textArray); return result; } @@ -1110,10 +1112,10 @@ static JNINativeMethod methods[] = { {"native_breakText","(Ljava/lang/String;ZFI[F)I", (void*) SkPaintGlue::breakTextS}, {"native_getTextWidths","(JJ[CIII[F)I", (void*) SkPaintGlue::getTextWidths___CIII_F}, {"native_getTextWidths","(JJLjava/lang/String;III[F)I", (void*) SkPaintGlue::getTextWidths__StringIII_F}, - {"native_getTextRunAdvances","(JJ[CIIIII[FI)F", - (void*) SkPaintGlue::getTextRunAdvances___CIIIII_FI}, - {"native_getTextRunAdvances","(JJLjava/lang/String;IIIII[FI)F", - (void*) SkPaintGlue::getTextRunAdvances__StringIIIII_FI}, + {"native_getTextRunAdvances","(JJ[CIIIIZ[FI)F", + (void*) SkPaintGlue::getTextRunAdvances___CIIIIZ_FI}, + {"native_getTextRunAdvances","(JJLjava/lang/String;IIIIZ[FI)F", + (void*) SkPaintGlue::getTextRunAdvances__StringIIIIZ_FI}, {"native_getTextGlyphs","(JLjava/lang/String;IIIII[C)I", diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp index 9fa5ec9..4a6e117 100644 --- a/core/jni/android_view_GLES20Canvas.cpp +++ b/core/jni/android_view_GLES20Canvas.cpp @@ -641,16 +641,16 @@ static void renderTextLayout(OpenGLRenderer* renderer, Layout* layout, #endif static void renderText(OpenGLRenderer* renderer, const jchar* text, int count, - jfloat x, jfloat y, int flags, SkPaint* paint, TypefaceImpl* typeface) { + jfloat x, jfloat y, int bidiFlags, SkPaint* paint, TypefaceImpl* typeface) { #ifdef USE_MINIKIN Layout layout; - std::string css = MinikinUtils::setLayoutProperties(&layout, paint, flags, typeface); + std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface); layout.doLayout(text, 0, count, count, css); x += xOffsetForTextAlign(paint, layout.getAdvance()); renderTextLayout(renderer, &layout, x, y, paint); #else sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint, - text, 0, count, count, flags); + text, 0, count, count, bidiFlags); if (value == NULL) { return; } @@ -670,9 +670,9 @@ static void renderText(OpenGLRenderer* renderer, const jchar* text, int count, } static void renderTextOnPath(OpenGLRenderer* renderer, const jchar* text, int count, - SkPath* path, jfloat hOffset, jfloat vOffset, int flags, SkPaint* paint) { + SkPath* path, jfloat hOffset, jfloat vOffset, int bidiFlags, SkPaint* paint) { sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint, - text, 0, count, count, flags); + text, 0, count, count, bidiFlags); if (value == NULL) { return; } @@ -685,16 +685,16 @@ static void renderTextOnPath(OpenGLRenderer* renderer, const jchar* text, int co static void renderTextRun(OpenGLRenderer* renderer, const jchar* text, jint start, jint count, jint contextCount, jfloat x, jfloat y, - int flags, SkPaint* paint, TypefaceImpl* typeface) { + int bidiFlags, SkPaint* paint, TypefaceImpl* typeface) { #ifdef USE_MINIKIN Layout layout; - std::string css = MinikinUtils::setLayoutProperties(&layout, paint, flags, typeface); + std::string css = MinikinUtils::setLayoutProperties(&layout, paint, bidiFlags, typeface); layout.doLayout(text, start, count, contextCount, css); x += xOffsetForTextAlign(paint, layout.getAdvance()); renderTextLayout(renderer, &layout, x, y, paint); #else sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint, - text, start, count, contextCount, flags); + text, start, count, contextCount, bidiFlags); if (value == NULL) { return; } @@ -715,71 +715,72 @@ static void renderTextRun(OpenGLRenderer* renderer, const jchar* text, static void android_view_GLES20Canvas_drawTextArray(JNIEnv* env, jobject clazz, jlong rendererPtr, jcharArray text, jint index, jint count, - jfloat x, jfloat y, jint flags, jlong paintPtr, jlong typefacePtr) { + jfloat x, jfloat y, jint bidiFlags, jlong paintPtr, jlong typefacePtr) { OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); jchar* textArray = env->GetCharArrayElements(text, NULL); SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr); TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefacePtr); - renderText(renderer, textArray + index, count, x, y, flags, paint, typeface); + renderText(renderer, textArray + index, count, x, y, bidiFlags, paint, typeface); env->ReleaseCharArrayElements(text, textArray, JNI_ABORT); } static void android_view_GLES20Canvas_drawText(JNIEnv* env, jobject clazz, jlong rendererPtr, jstring text, jint start, jint end, - jfloat x, jfloat y, jint flags, jlong paintPtr, jlong typefacePtr) { + jfloat x, jfloat y, jint bidiFlags, jlong paintPtr, jlong typefacePtr) { OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); const jchar* textArray = env->GetStringChars(text, NULL); SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr); TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefacePtr); - renderText(renderer, textArray + start, end - start, x, y, flags, paint, typeface); + renderText(renderer, textArray + start, end - start, x, y, bidiFlags, paint, typeface); env->ReleaseStringChars(text, textArray); } static void android_view_GLES20Canvas_drawTextArrayOnPath(JNIEnv* env, jobject clazz, jlong rendererPtr, jcharArray text, jint index, jint count, - jlong pathPtr, jfloat hOffset, jfloat vOffset, jint flags, jlong paintPtr) { + jlong pathPtr, jfloat hOffset, jfloat vOffset, jint bidiFlags, jlong paintPtr) { OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); jchar* textArray = env->GetCharArrayElements(text, NULL); SkPath* path = reinterpret_cast<SkPath*>(pathPtr); SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr); renderTextOnPath(renderer, textArray + index, count, path, - hOffset, vOffset, flags, paint); + hOffset, vOffset, bidiFlags, paint); env->ReleaseCharArrayElements(text, textArray, JNI_ABORT); } static void android_view_GLES20Canvas_drawTextOnPath(JNIEnv* env, jobject clazz, jlong rendererPtr, jstring text, jint start, jint end, - jlong pathPtr, jfloat hOffset, jfloat vOffset, jint flags, jlong paintPtr) { + jlong pathPtr, jfloat hOffset, jfloat vOffset, jint bidiFlags, jlong paintPtr) { OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); const jchar* textArray = env->GetStringChars(text, NULL); SkPath* path = reinterpret_cast<SkPath*>(pathPtr); SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr); renderTextOnPath(renderer, textArray + start, end - start, path, - hOffset, vOffset, flags, paint); + hOffset, vOffset, bidiFlags, paint); env->ReleaseStringChars(text, textArray); } static void android_view_GLES20Canvas_drawTextRunArray(JNIEnv* env, jobject clazz, jlong rendererPtr, jcharArray text, jint index, jint count, - jint contextIndex, jint contextCount, jfloat x, jfloat y, jint dirFlags, + jint contextIndex, jint contextCount, jfloat x, jfloat y, jboolean isRtl, jlong paintPtr, jlong typefacePtr) { OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); jchar* textArray = env->GetCharArrayElements(text, NULL); SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr); TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefacePtr); + int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR; renderTextRun(renderer, textArray + contextIndex, index - contextIndex, - count, contextCount, x, y, dirFlags, paint, typeface); + count, contextCount, x, y, bidiFlags, paint, typeface); env->ReleaseCharArrayElements(text, textArray, JNI_ABORT); } static void android_view_GLES20Canvas_drawTextRun(JNIEnv* env, jobject clazz, jlong rendererPtr, jstring text, jint start, jint end, - jint contextStart, int contextEnd, jfloat x, jfloat y, jint dirFlags, + jint contextStart, int contextEnd, jfloat x, jfloat y, jboolean isRtl, jlong paintPtr, jlong typefacePtr) { OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr); const jchar* textArray = env->GetStringChars(text, NULL); @@ -788,15 +789,16 @@ static void android_view_GLES20Canvas_drawTextRun(JNIEnv* env, jobject clazz, SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr); TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefacePtr); + int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR; renderTextRun(renderer, textArray + contextStart, start - contextStart, - count, contextCount, x, y, dirFlags, paint, typeface); + count, contextCount, x, y, bidiFlags, paint, typeface); env->ReleaseStringChars(text, textArray); } static void renderPosText(OpenGLRenderer* renderer, const jchar* text, int count, - const jfloat* positions, jint dirFlags, SkPaint* paint) { + const jfloat* positions, jint bidiFlags, SkPaint* paint) { sp<TextLayoutValue> value = TextLayoutEngine::getInstance().getValue(paint, - text, 0, count, count, dirFlags); + text, 0, count, count, bidiFlags); if (value == NULL) { return; } @@ -988,8 +990,8 @@ static JNINativeMethod gMethods[] = { { "nDrawTextOnPath", "(JLjava/lang/String;IIJFFIJ)V", (void*) android_view_GLES20Canvas_drawTextOnPath }, - { "nDrawTextRun", "(J[CIIIIFFIJJ)V", (void*) android_view_GLES20Canvas_drawTextRunArray }, - { "nDrawTextRun", "(JLjava/lang/String;IIIIFFIJJ)V", + { "nDrawTextRun", "(J[CIIIIFFZJJ)V", (void*) android_view_GLES20Canvas_drawTextRunArray }, + { "nDrawTextRun", "(JLjava/lang/String;IIIIFFZJJ)V", (void*) android_view_GLES20Canvas_drawTextRun }, { "nDrawPosText", "(J[CII[FJ)V", (void*) android_view_GLES20Canvas_drawPosTextArray }, diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index c58bf04..0cdddba 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -14,46 +14,40 @@ * limitations under the License. */ -#include "android_runtime/AndroidRuntime.h" +#define LOG_TAG "Zygote" // sys/mount.h has to come before linux/fs.h due to redefinition of MS_RDONLY, MS_BIND, etc #include <sys/mount.h> #include <linux/fs.h> #include <grp.h> +#include <fcntl.h> #include <paths.h> #include <signal.h> #include <stdlib.h> +#include <unistd.h> +#include <sys/capability.h> +#include <sys/personality.h> +#include <sys/prctl.h> #include <sys/resource.h> -#include <sys/types.h> #include <sys/stat.h> +#include <sys/types.h> +#include <sys/utsname.h> #include <sys/wait.h> -#include <unistd.h> -#include <fcntl.h> -#include "cutils/fs.h" -#include "cutils/multiuser.h" -#include "cutils/sched_policy.h" -#include "utils/String8.h" + +#include <cutils/fs.h> +#include <cutils/multiuser.h> +#include <cutils/sched_policy.h> +#include <utils/String8.h> +#include <selinux/android.h> + +#include "android_runtime/AndroidRuntime.h" #include "JNIHelp.h" #include "ScopedLocalRef.h" #include "ScopedPrimitiveArray.h" #include "ScopedUtfChars.h" -#if defined(HAVE_PRCTL) -#include <sys/prctl.h> -#endif - -#include <selinux/android.h> - -#if defined(__linux__) -#include <sys/personality.h> -#include <sys/utsname.h> -#if defined(HAVE_ANDROID_OS) -#include <sys/capability.h> -#endif -#endif - namespace { using android::String8; @@ -97,11 +91,9 @@ static void SigChldHandler(int /*signal_number*/) { if (WTERMSIG(status) != SIGKILL) { ALOGI("Process %d exited due to signal (%d)", pid, WTERMSIG(status)); } -#ifdef WCOREDUMP if (WCOREDUMP(status)) { ALOGI("Process %d dumped core.", pid); } -#endif /* ifdef WCOREDUMP */ } // If the just-crashed process is the system_server, bring down zygote @@ -199,8 +191,6 @@ static void SetRLimits(JNIEnv* env, jobjectArray javaRlimits) { } } -#if defined(HAVE_ANDROID_OS) - // The debug malloc library needs to know whether it's the zygote or a child. extern "C" int gMallocLeakZygoteChild; @@ -254,17 +244,6 @@ static void SetSchedulerPolicy(JNIEnv* env) { } } -#else - -static int gMallocLeakZygoteChild = 0; - -static void EnableKeepCapabilities(JNIEnv*) {} -static void DropCapabilitiesBoundingSet(JNIEnv*) {} -static void SetCapabilities(JNIEnv*, int64_t, int64_t) {} -static void SetSchedulerPolicy(JNIEnv*) {} - -#endif - // Create a private mount namespace and bind mount appropriate emulated // storage for the given user. static bool MountEmulatedStorage(uid_t uid, jint mount_mode) { @@ -337,7 +316,6 @@ static bool MountEmulatedStorage(uid_t uid, jint mount_mode) { return true; } -#if defined(__linux__) static bool NeedsNoRandomizeWorkaround() { #if !defined(__arm__) return false; @@ -357,7 +335,6 @@ static bool NeedsNoRandomizeWorkaround() { return (major < 3) || ((major == 3) && (minor < 4)); #endif } -#endif // Utility to close down the Zygote socket file descriptors while // the child is still running as root with Zygote's privileges. Each @@ -474,7 +451,6 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra RuntimeAbort(env); } -#if defined(__linux__) if (NeedsNoRandomizeWorkaround()) { // Work around ARM kernel ASLR lossage (http://b/5817320). int old_personality = personality(0xffffffff); @@ -483,58 +459,49 @@ static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArra ALOGW("personality(%d) failed", new_personality); } } -#endif SetCapabilities(env, permittedCapabilities, effectiveCapabilities); SetSchedulerPolicy(env); -#if defined(HAVE_ANDROID_OS) - { // NOLINT(whitespace/braces) - const char* se_info_c_str = NULL; - ScopedUtfChars* se_info = NULL; - if (java_se_info != NULL) { - se_info = new ScopedUtfChars(env, java_se_info); - se_info_c_str = se_info->c_str(); - if (se_info_c_str == NULL) { - ALOGE("se_info_c_str == NULL"); - RuntimeAbort(env); - } - } - const char* se_name_c_str = NULL; - ScopedUtfChars* se_name = NULL; - if (java_se_name != NULL) { - se_name = new ScopedUtfChars(env, java_se_name); - se_name_c_str = se_name->c_str(); - if (se_name_c_str == NULL) { - ALOGE("se_name_c_str == NULL"); - RuntimeAbort(env); - } - } - rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str); - if (rc == -1) { - ALOGE("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed", uid, - is_system_server, se_info_c_str, se_name_c_str); - RuntimeAbort(env); - } - - // Make it easier to debug audit logs by setting the main thread's name to the - // nice name rather than "app_process". - if (se_info_c_str == NULL && is_system_server) { - se_name_c_str = "system_server"; - } - if (se_info_c_str != NULL) { - SetThreadName(se_name_c_str); - } + const char* se_info_c_str = NULL; + ScopedUtfChars* se_info = NULL; + if (java_se_info != NULL) { + se_info = new ScopedUtfChars(env, java_se_info); + se_info_c_str = se_info->c_str(); + if (se_info_c_str == NULL) { + ALOGE("se_info_c_str == NULL"); + RuntimeAbort(env); + } + } + const char* se_name_c_str = NULL; + ScopedUtfChars* se_name = NULL; + if (java_se_name != NULL) { + se_name = new ScopedUtfChars(env, java_se_name); + se_name_c_str = se_name->c_str(); + if (se_name_c_str == NULL) { + ALOGE("se_name_c_str == NULL"); + RuntimeAbort(env); + } + } + rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str); + if (rc == -1) { + ALOGE("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed", uid, + is_system_server, se_info_c_str, se_name_c_str); + RuntimeAbort(env); + } - delete se_info; - delete se_name; + // Make it easier to debug audit logs by setting the main thread's name to the + // nice name rather than "app_process". + if (se_info_c_str == NULL && is_system_server) { + se_name_c_str = "system_server"; } -#else - UNUSED(is_system_server); - UNUSED(java_se_info); - UNUSED(java_se_name); -#endif + if (se_info_c_str != NULL) { + SetThreadName(se_name_c_str); + } + + delete se_info; + delete se_name; UnsetSigChldHandler(); diff --git a/core/res/res/drawable-hdpi/btn_toggle_off_disabled_focused_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_toggle_off_disabled_focused_holo_dark.9.png Binary files differindex 17acfc5..c5c0e97 100644 --- a/core/res/res/drawable-hdpi/btn_toggle_off_disabled_focused_holo_dark.9.png +++ b/core/res/res/drawable-hdpi/btn_toggle_off_disabled_focused_holo_dark.9.png diff --git a/core/res/res/drawable-hdpi/btn_toggle_off_disabled_focused_holo_light.9.png b/core/res/res/drawable-hdpi/btn_toggle_off_disabled_focused_holo_light.9.png Binary files differindex 17acfc5..c5c0e97 100644 --- a/core/res/res/drawable-hdpi/btn_toggle_off_disabled_focused_holo_light.9.png +++ b/core/res/res/drawable-hdpi/btn_toggle_off_disabled_focused_holo_light.9.png diff --git a/core/res/res/drawable-hdpi/btn_toggle_off_disabled_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_toggle_off_disabled_holo_dark.9.png Binary files differindex 9b8ca22..3b31225 100644 --- a/core/res/res/drawable-hdpi/btn_toggle_off_disabled_holo_dark.9.png +++ b/core/res/res/drawable-hdpi/btn_toggle_off_disabled_holo_dark.9.png diff --git a/core/res/res/drawable-hdpi/btn_toggle_off_disabled_holo_light.9.png b/core/res/res/drawable-hdpi/btn_toggle_off_disabled_holo_light.9.png Binary files differindex 9b8ca22..3b31225 100644 --- a/core/res/res/drawable-hdpi/btn_toggle_off_disabled_holo_light.9.png +++ b/core/res/res/drawable-hdpi/btn_toggle_off_disabled_holo_light.9.png diff --git a/core/res/res/drawable-hdpi/btn_toggle_off_focused_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_toggle_off_focused_holo_dark.9.png Binary files differindex bc20f6c..b65009e 100644 --- a/core/res/res/drawable-hdpi/btn_toggle_off_focused_holo_dark.9.png +++ b/core/res/res/drawable-hdpi/btn_toggle_off_focused_holo_dark.9.png diff --git a/core/res/res/drawable-hdpi/btn_toggle_off_focused_holo_light.9.png b/core/res/res/drawable-hdpi/btn_toggle_off_focused_holo_light.9.png Binary files differindex bc20f6c..b65009e 100644 --- a/core/res/res/drawable-hdpi/btn_toggle_off_focused_holo_light.9.png +++ b/core/res/res/drawable-hdpi/btn_toggle_off_focused_holo_light.9.png diff --git a/core/res/res/drawable-hdpi/btn_toggle_off_normal_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_toggle_off_normal_holo_dark.9.png Binary files differindex 571819b..a2dfcae 100644 --- a/core/res/res/drawable-hdpi/btn_toggle_off_normal_holo_dark.9.png +++ b/core/res/res/drawable-hdpi/btn_toggle_off_normal_holo_dark.9.png diff --git a/core/res/res/drawable-hdpi/btn_toggle_off_normal_holo_light.9.png b/core/res/res/drawable-hdpi/btn_toggle_off_normal_holo_light.9.png Binary files differindex 571819b..c3fda0e 100644 --- a/core/res/res/drawable-hdpi/btn_toggle_off_normal_holo_light.9.png +++ b/core/res/res/drawable-hdpi/btn_toggle_off_normal_holo_light.9.png diff --git a/core/res/res/drawable-hdpi/btn_toggle_on_disabled_focused_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_toggle_on_disabled_focused_holo_dark.9.png Binary files differindex 1f83b5a..bae60a7 100644 --- a/core/res/res/drawable-hdpi/btn_toggle_on_disabled_focused_holo_dark.9.png +++ b/core/res/res/drawable-hdpi/btn_toggle_on_disabled_focused_holo_dark.9.png diff --git a/core/res/res/drawable-hdpi/btn_toggle_on_disabled_focused_holo_light.9.png b/core/res/res/drawable-hdpi/btn_toggle_on_disabled_focused_holo_light.9.png Binary files differindex 1f83b5a..bae60a7 100644 --- a/core/res/res/drawable-hdpi/btn_toggle_on_disabled_focused_holo_light.9.png +++ b/core/res/res/drawable-hdpi/btn_toggle_on_disabled_focused_holo_light.9.png diff --git a/core/res/res/drawable-hdpi/btn_toggle_on_disabled_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_toggle_on_disabled_holo_dark.9.png Binary files differindex 733cf45..a9653b0 100644 --- a/core/res/res/drawable-hdpi/btn_toggle_on_disabled_holo_dark.9.png +++ b/core/res/res/drawable-hdpi/btn_toggle_on_disabled_holo_dark.9.png diff --git a/core/res/res/drawable-hdpi/btn_toggle_on_disabled_holo_light.9.png b/core/res/res/drawable-hdpi/btn_toggle_on_disabled_holo_light.9.png Binary files differindex 733cf45..a9653b0 100644 --- a/core/res/res/drawable-hdpi/btn_toggle_on_disabled_holo_light.9.png +++ b/core/res/res/drawable-hdpi/btn_toggle_on_disabled_holo_light.9.png diff --git a/core/res/res/drawable-hdpi/btn_toggle_on_focused_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_toggle_on_focused_holo_dark.9.png Binary files differindex 2265de4..394cb5e 100644 --- a/core/res/res/drawable-hdpi/btn_toggle_on_focused_holo_dark.9.png +++ b/core/res/res/drawable-hdpi/btn_toggle_on_focused_holo_dark.9.png diff --git a/core/res/res/drawable-hdpi/btn_toggle_on_focused_holo_light.9.png b/core/res/res/drawable-hdpi/btn_toggle_on_focused_holo_light.9.png Binary files differindex 2265de4..394cb5e 100644 --- a/core/res/res/drawable-hdpi/btn_toggle_on_focused_holo_light.9.png +++ b/core/res/res/drawable-hdpi/btn_toggle_on_focused_holo_light.9.png diff --git a/core/res/res/drawable-hdpi/btn_toggle_on_normal_holo_dark.9.png b/core/res/res/drawable-hdpi/btn_toggle_on_normal_holo_dark.9.png Binary files differindex f3ada58..aa23c6e 100644 --- a/core/res/res/drawable-hdpi/btn_toggle_on_normal_holo_dark.9.png +++ b/core/res/res/drawable-hdpi/btn_toggle_on_normal_holo_dark.9.png diff --git a/core/res/res/drawable-hdpi/btn_toggle_on_normal_holo_light.9.png b/core/res/res/drawable-hdpi/btn_toggle_on_normal_holo_light.9.png Binary files differindex f3ada58..028b3b8 100644 --- a/core/res/res/drawable-hdpi/btn_toggle_on_normal_holo_light.9.png +++ b/core/res/res/drawable-hdpi/btn_toggle_on_normal_holo_light.9.png diff --git a/core/res/res/drawable-mdpi/btn_toggle_off_disabled_focused_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_toggle_off_disabled_focused_holo_dark.9.png Binary files differindex 3fdd3bc..4e6d076 100644 --- a/core/res/res/drawable-mdpi/btn_toggle_off_disabled_focused_holo_dark.9.png +++ b/core/res/res/drawable-mdpi/btn_toggle_off_disabled_focused_holo_dark.9.png diff --git a/core/res/res/drawable-mdpi/btn_toggle_off_disabled_focused_holo_light.9.png b/core/res/res/drawable-mdpi/btn_toggle_off_disabled_focused_holo_light.9.png Binary files differindex 3fdd3bc..4e6d076 100644 --- a/core/res/res/drawable-mdpi/btn_toggle_off_disabled_focused_holo_light.9.png +++ b/core/res/res/drawable-mdpi/btn_toggle_off_disabled_focused_holo_light.9.png diff --git a/core/res/res/drawable-mdpi/btn_toggle_off_disabled_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_toggle_off_disabled_holo_dark.9.png Binary files differindex eaa02b3..ca61cb2 100644 --- a/core/res/res/drawable-mdpi/btn_toggle_off_disabled_holo_dark.9.png +++ b/core/res/res/drawable-mdpi/btn_toggle_off_disabled_holo_dark.9.png diff --git a/core/res/res/drawable-mdpi/btn_toggle_off_disabled_holo_light.9.png b/core/res/res/drawable-mdpi/btn_toggle_off_disabled_holo_light.9.png Binary files differindex eaa02b3..ca61cb2 100644 --- a/core/res/res/drawable-mdpi/btn_toggle_off_disabled_holo_light.9.png +++ b/core/res/res/drawable-mdpi/btn_toggle_off_disabled_holo_light.9.png diff --git a/core/res/res/drawable-mdpi/btn_toggle_off_focused_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_toggle_off_focused_holo_dark.9.png Binary files differindex 28c8b94..b5999be 100644 --- a/core/res/res/drawable-mdpi/btn_toggle_off_focused_holo_dark.9.png +++ b/core/res/res/drawable-mdpi/btn_toggle_off_focused_holo_dark.9.png diff --git a/core/res/res/drawable-mdpi/btn_toggle_off_focused_holo_light.9.png b/core/res/res/drawable-mdpi/btn_toggle_off_focused_holo_light.9.png Binary files differindex 28c8b94..b5999be 100644 --- a/core/res/res/drawable-mdpi/btn_toggle_off_focused_holo_light.9.png +++ b/core/res/res/drawable-mdpi/btn_toggle_off_focused_holo_light.9.png diff --git a/core/res/res/drawable-mdpi/btn_toggle_off_normal_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_toggle_off_normal_holo_dark.9.png Binary files differindex 6090cce..8392ac3 100644 --- a/core/res/res/drawable-mdpi/btn_toggle_off_normal_holo_dark.9.png +++ b/core/res/res/drawable-mdpi/btn_toggle_off_normal_holo_dark.9.png diff --git a/core/res/res/drawable-mdpi/btn_toggle_off_normal_holo_light.9.png b/core/res/res/drawable-mdpi/btn_toggle_off_normal_holo_light.9.png Binary files differindex 6090cce..522bafd 100644 --- a/core/res/res/drawable-mdpi/btn_toggle_off_normal_holo_light.9.png +++ b/core/res/res/drawable-mdpi/btn_toggle_off_normal_holo_light.9.png diff --git a/core/res/res/drawable-mdpi/btn_toggle_on_disabled_focused_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_toggle_on_disabled_focused_holo_dark.9.png Binary files differindex 3f2e982..ebb2f8b 100644 --- a/core/res/res/drawable-mdpi/btn_toggle_on_disabled_focused_holo_dark.9.png +++ b/core/res/res/drawable-mdpi/btn_toggle_on_disabled_focused_holo_dark.9.png diff --git a/core/res/res/drawable-mdpi/btn_toggle_on_disabled_focused_holo_light.9.png b/core/res/res/drawable-mdpi/btn_toggle_on_disabled_focused_holo_light.9.png Binary files differindex 3f2e982..ebb2f8b 100644 --- a/core/res/res/drawable-mdpi/btn_toggle_on_disabled_focused_holo_light.9.png +++ b/core/res/res/drawable-mdpi/btn_toggle_on_disabled_focused_holo_light.9.png diff --git a/core/res/res/drawable-mdpi/btn_toggle_on_disabled_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_toggle_on_disabled_holo_dark.9.png Binary files differindex 14b958b..3fa20ca 100644 --- a/core/res/res/drawable-mdpi/btn_toggle_on_disabled_holo_dark.9.png +++ b/core/res/res/drawable-mdpi/btn_toggle_on_disabled_holo_dark.9.png diff --git a/core/res/res/drawable-mdpi/btn_toggle_on_disabled_holo_light.9.png b/core/res/res/drawable-mdpi/btn_toggle_on_disabled_holo_light.9.png Binary files differindex 14b958b..3fa20ca 100644 --- a/core/res/res/drawable-mdpi/btn_toggle_on_disabled_holo_light.9.png +++ b/core/res/res/drawable-mdpi/btn_toggle_on_disabled_holo_light.9.png diff --git a/core/res/res/drawable-mdpi/btn_toggle_on_focused_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_toggle_on_focused_holo_dark.9.png Binary files differindex 4db22d4..6cc59ed 100644 --- a/core/res/res/drawable-mdpi/btn_toggle_on_focused_holo_dark.9.png +++ b/core/res/res/drawable-mdpi/btn_toggle_on_focused_holo_dark.9.png diff --git a/core/res/res/drawable-mdpi/btn_toggle_on_focused_holo_light.9.png b/core/res/res/drawable-mdpi/btn_toggle_on_focused_holo_light.9.png Binary files differindex 4db22d4..6cc59ed 100644 --- a/core/res/res/drawable-mdpi/btn_toggle_on_focused_holo_light.9.png +++ b/core/res/res/drawable-mdpi/btn_toggle_on_focused_holo_light.9.png diff --git a/core/res/res/drawable-mdpi/btn_toggle_on_normal_holo_dark.9.png b/core/res/res/drawable-mdpi/btn_toggle_on_normal_holo_dark.9.png Binary files differindex a11e1c7..a1fcd08 100644 --- a/core/res/res/drawable-mdpi/btn_toggle_on_normal_holo_dark.9.png +++ b/core/res/res/drawable-mdpi/btn_toggle_on_normal_holo_dark.9.png diff --git a/core/res/res/drawable-mdpi/btn_toggle_on_normal_holo_light.9.png b/core/res/res/drawable-mdpi/btn_toggle_on_normal_holo_light.9.png Binary files differindex a11e1c7..c6c0224 100644 --- a/core/res/res/drawable-mdpi/btn_toggle_on_normal_holo_light.9.png +++ b/core/res/res/drawable-mdpi/btn_toggle_on_normal_holo_light.9.png diff --git a/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_focused_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_focused_holo_dark.9.png Binary files differindex c08deab..1e45530 100644 --- a/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_focused_holo_dark.9.png +++ b/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_focused_holo_dark.9.png diff --git a/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_focused_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_focused_holo_light.9.png Binary files differindex c08deab..1e45530 100644 --- a/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_focused_holo_light.9.png +++ b/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_focused_holo_light.9.png diff --git a/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_holo_dark.9.png Binary files differindex 8b1a55c..2c63c5d 100644 --- a/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_holo_dark.9.png +++ b/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_holo_dark.9.png diff --git a/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_holo_light.9.png Binary files differindex 8b1a55c..2c63c5d 100644 --- a/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_holo_light.9.png +++ b/core/res/res/drawable-xhdpi/btn_toggle_off_disabled_holo_light.9.png diff --git a/core/res/res/drawable-xhdpi/btn_toggle_off_focused_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_toggle_off_focused_holo_dark.9.png Binary files differindex 77cd1fa..dd5e26e 100644 --- a/core/res/res/drawable-xhdpi/btn_toggle_off_focused_holo_dark.9.png +++ b/core/res/res/drawable-xhdpi/btn_toggle_off_focused_holo_dark.9.png diff --git a/core/res/res/drawable-xhdpi/btn_toggle_off_focused_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_toggle_off_focused_holo_light.9.png Binary files differindex 77cd1fa..dd5e26e 100644 --- a/core/res/res/drawable-xhdpi/btn_toggle_off_focused_holo_light.9.png +++ b/core/res/res/drawable-xhdpi/btn_toggle_off_focused_holo_light.9.png diff --git a/core/res/res/drawable-xhdpi/btn_toggle_off_normal_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_toggle_off_normal_holo_dark.9.png Binary files differindex e0e3540..aa9b3c5 100644 --- a/core/res/res/drawable-xhdpi/btn_toggle_off_normal_holo_dark.9.png +++ b/core/res/res/drawable-xhdpi/btn_toggle_off_normal_holo_dark.9.png diff --git a/core/res/res/drawable-xhdpi/btn_toggle_off_normal_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_toggle_off_normal_holo_light.9.png Binary files differindex e0e3540..367c25a 100644 --- a/core/res/res/drawable-xhdpi/btn_toggle_off_normal_holo_light.9.png +++ b/core/res/res/drawable-xhdpi/btn_toggle_off_normal_holo_light.9.png diff --git a/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_focused_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_focused_holo_dark.9.png Binary files differindex 324e490..df28ad0 100644 --- a/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_focused_holo_dark.9.png +++ b/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_focused_holo_dark.9.png diff --git a/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_focused_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_focused_holo_light.9.png Binary files differindex 324e490..df28ad0 100644 --- a/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_focused_holo_light.9.png +++ b/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_focused_holo_light.9.png diff --git a/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_holo_dark.9.png Binary files differindex e126cc6..3a27831 100644 --- a/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_holo_dark.9.png +++ b/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_holo_dark.9.png diff --git a/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_holo_light.9.png Binary files differindex e126cc6..3a27831 100644 --- a/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_holo_light.9.png +++ b/core/res/res/drawable-xhdpi/btn_toggle_on_disabled_holo_light.9.png diff --git a/core/res/res/drawable-xhdpi/btn_toggle_on_focused_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_toggle_on_focused_holo_dark.9.png Binary files differindex 4c1f1b9..d68bdf4 100644 --- a/core/res/res/drawable-xhdpi/btn_toggle_on_focused_holo_dark.9.png +++ b/core/res/res/drawable-xhdpi/btn_toggle_on_focused_holo_dark.9.png diff --git a/core/res/res/drawable-xhdpi/btn_toggle_on_focused_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_toggle_on_focused_holo_light.9.png Binary files differindex 4c1f1b9..d68bdf4 100644 --- a/core/res/res/drawable-xhdpi/btn_toggle_on_focused_holo_light.9.png +++ b/core/res/res/drawable-xhdpi/btn_toggle_on_focused_holo_light.9.png diff --git a/core/res/res/drawable-xhdpi/btn_toggle_on_normal_holo_dark.9.png b/core/res/res/drawable-xhdpi/btn_toggle_on_normal_holo_dark.9.png Binary files differindex 219d37b..da03ec9 100644 --- a/core/res/res/drawable-xhdpi/btn_toggle_on_normal_holo_dark.9.png +++ b/core/res/res/drawable-xhdpi/btn_toggle_on_normal_holo_dark.9.png diff --git a/core/res/res/drawable-xhdpi/btn_toggle_on_normal_holo_light.9.png b/core/res/res/drawable-xhdpi/btn_toggle_on_normal_holo_light.9.png Binary files differindex 219d37b..482b249 100644 --- a/core/res/res/drawable-xhdpi/btn_toggle_on_normal_holo_light.9.png +++ b/core/res/res/drawable-xhdpi/btn_toggle_on_normal_holo_light.9.png diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java index 07a6a10..7251e7c 100644 --- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java +++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java @@ -29,6 +29,7 @@ import android.content.IntentFilter; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.PackageParser.PackageParserException; import android.content.res.Resources; import android.content.res.Resources.NotFoundException; import android.net.Uri; @@ -60,7 +61,6 @@ import android.util.Log; import java.io.File; import java.io.IOException; import java.io.InputStream; - import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -303,14 +303,13 @@ public class PackageManagerTests extends AndroidTestCase { return Uri.fromFile(outFile); } - private PackageParser.Package parsePackage(Uri packageURI) { + private PackageParser.Package parsePackage(Uri packageURI) throws PackageParserException { final String archiveFilePath = packageURI.getPath(); PackageParser packageParser = new PackageParser(archiveFilePath); File sourceFile = new File(archiveFilePath); DisplayMetrics metrics = new DisplayMetrics(); metrics.setToDefaults(); - PackageParser.Package pkg = packageParser.parsePackage(sourceFile, archiveFilePath, - metrics, 0); + PackageParser.Package pkg = packageParser.parseMonolithicPackage(sourceFile, metrics, 0); packageParser = null; return pkg; } @@ -579,18 +578,18 @@ public class PackageManagerTests extends AndroidTestCase { PackageParser.Package pkg; - InstallParams(String outFileName, int rawResId) { + InstallParams(String outFileName, int rawResId) throws PackageParserException { this.pkg = getParsedPackage(outFileName, rawResId); - this.packageURI = Uri.fromFile(new File(pkg.mScanPath)); + this.packageURI = Uri.fromFile(new File(pkg.codePath)); } InstallParams(PackageParser.Package pkg) { - this.packageURI = Uri.fromFile(new File(pkg.mScanPath)); + this.packageURI = Uri.fromFile(new File(pkg.codePath)); this.pkg = pkg; } long getApkSize() { - File file = new File(pkg.mScanPath); + File file = new File(pkg.codePath); return file.length(); } } @@ -691,7 +690,8 @@ public class PackageManagerTests extends AndroidTestCase { } } - private PackageParser.Package getParsedPackage(String outFileName, int rawResId) { + private PackageParser.Package getParsedPackage(String outFileName, int rawResId) + throws PackageParserException { PackageManager pm = mContext.getPackageManager(); File filesDir = mContext.getFilesDir(); File outFile = new File(filesDir, outFileName); @@ -1343,7 +1343,7 @@ public class PackageManagerTests extends AndroidTestCase { assertUninstalled(info); } } finally { - File outFile = new File(ip.pkg.mScanPath); + File outFile = new File(ip.pkg.codePath); if (outFile != null && outFile.exists()) { outFile.delete(); } diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk index abb960c..6437e07 100644 --- a/data/fonts/Android.mk +++ b/data/fonts/Android.mk @@ -42,12 +42,21 @@ $(eval $(call create-font-symlink,DroidSerif-Bold.ttf,NotoSerif-Bold.ttf)) $(eval $(call create-font-symlink,DroidSerif-Italic.ttf,NotoSerif-Italic.ttf)) $(eval $(call create-font-symlink,DroidSerif-BoldItalic.ttf,NotoSerif-BoldItalic.ttf)) +extra_font_files := \ + DroidSans.ttf \ + DroidSans-Bold.ttf + ################################ # On space-constrained devices, we include a subset of fonts: ifeq ($(SMALLER_FONT_FOOTPRINT),true) + droidsans_fallback_src := DroidSansFallback.ttf -extra_font_files := DroidSans.ttf DroidSans-Bold.ttf -else + +else # !SMALLER_FONT_FOOTPRINT + +droidsans_fallback_src := DroidSansFallbackFull.ttf + +ifneq ($(EXTENDED_FONT_FOOTPRINT),true) include $(CLEAR_VARS) LOCAL_MODULE := MTLmr3m.ttf LOCAL_SRC_FILES := $(LOCAL_MODULE) @@ -55,12 +64,9 @@ LOCAL_MODULE_CLASS := ETC LOCAL_MODULE_TAGS := optional LOCAL_MODULE_PATH := $(TARGET_OUT)/fonts include $(BUILD_PREBUILT) +extra_font_files += MTLmr3m.ttf +endif # !EXTENDED_FONT_FOOTPRINT -droidsans_fallback_src := DroidSansFallbackFull.ttf -extra_font_files := \ - DroidSans.ttf \ - DroidSans-Bold.ttf \ - MTLmr3m.ttf endif # SMALLER_FONT_FOOTPRINT ################################ diff --git a/data/fonts/fallback_fonts.xml b/data/fonts/fallback_fonts.xml index c2d5afe..1eaae65 100644 --- a/data/fonts/fallback_fonts.xml +++ b/data/fonts/fallback_fonts.xml @@ -219,6 +219,26 @@ </family> <family> <fileset> + <file lang="zh-CN">NotoSansHans-Regular.otf</file> + </fileset> + </family> + <family> + <fileset> + <file lang="zh-TW">NotoSansHant-Regular.otf</file> + </fileset> + </family> + <family> + <fileset> + <file lang="ja">NotoSansJP-Regular.otf</file> + </fileset> + </family> + <family> + <fileset> + <file lang="ko">NotoSansKR-Regular.otf</file> + </fileset> + </family> + <family> + <fileset> <file>NanumGothic.ttf</file> </fileset> </family> diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java index 13789ca..2b36016 100644 --- a/graphics/java/android/graphics/Canvas.java +++ b/graphics/java/android/graphics/Canvas.java @@ -65,11 +65,11 @@ public class Canvas { /** * Used to determine when compatibility scaling is in effect. - * + * * @hide */ protected int mScreenDensity = Bitmap.DENSITY_NONE; - + // Used by native code @SuppressWarnings("UnusedDeclaration") private int mSurfaceFormat; @@ -79,7 +79,7 @@ public class Canvas { * @hide */ public static final int DIRECTION_LTR = 0; - + /** * Flag for drawTextRun indicating right-to-left run direction. * @hide @@ -136,7 +136,7 @@ public class Canvas { /** * Construct a canvas with the specified bitmap to draw into. The bitmap * must be mutable. - * + * * <p>The initial target density of the canvas is the same as the given * bitmap's density. * @@ -177,10 +177,10 @@ public class Canvas { /** * Indicates whether this Canvas uses hardware acceleration. - * + * * Note that this method does not define what type of hardware acceleration * may or may not be used. - * + * * @return True if drawing operations are hardware accelerated, * false otherwise. */ @@ -189,7 +189,7 @@ public class Canvas { } /** - * Specify a bitmap for the canvas to draw into. All canvas state such as + * Specify a bitmap for the canvas to draw into. All canvas state such as * layers, filters, and the save/restore stack are reset with the exception * of the current matrix and clip stack. Additionally, as a side-effect * the canvas' target density is updated to match that of the bitmap. @@ -279,7 +279,7 @@ public class Canvas { * to determine the scaling factor when drawing a bitmap into it. * * @see #setDensity(int) - * @see Bitmap#getDensity() + * @see Bitmap#getDensity() */ public int getDensity() { return mDensity; @@ -295,7 +295,7 @@ public class Canvas { * {@link Bitmap#DENSITY_NONE} to disable bitmap scaling. * * @see #getDensity() - * @see Bitmap#setDensity(int) + * @see Bitmap#setDensity(int) */ public void setDensity(int density) { if (mBitmap != null) { @@ -313,19 +313,19 @@ public class Canvas { * Returns the maximum allowed width for bitmaps drawn with this canvas. * Attempting to draw with a bitmap wider than this value will result * in an error. - * - * @see #getMaximumBitmapHeight() + * + * @see #getMaximumBitmapHeight() */ public int getMaximumBitmapWidth() { return MAXMIMUM_BITMAP_SIZE; } - + /** * Returns the maximum allowed height for bitmaps drawn with this canvas. * Attempting to draw with a bitmap taller than this value will result * in an error. - * - * @see #getMaximumBitmapWidth() + * + * @see #getMaximumBitmapWidth() */ public int getMaximumBitmapHeight() { return MAXMIMUM_BITMAP_SIZE; @@ -357,8 +357,8 @@ public class Canvas { /** clip against the layer's bounds */ public static final int CLIP_TO_LAYER_SAVE_FLAG = 0x10; /** restore everything when restore() is called */ - public static final int ALL_SAVE_FLAG = 0x1F; - + public static final int ALL_SAVE_FLAG = 0x1F; + /** * Saves the current matrix and clip onto a private stack. Subsequent * calls to translate,scale,rotate,skew,concat or clipRect,clipPath @@ -371,7 +371,7 @@ public class Canvas { public int save() { return native_save(mNativeCanvasWrapper, MATRIX_SAVE_FLAG | CLIP_SAVE_FLAG); } - + /** * Based on saveFlags, can save the current matrix and clip onto a private * stack. Subsequent calls to translate,scale,rotate,skew,concat or @@ -589,25 +589,25 @@ public class Canvas { public void concat(@Nullable Matrix matrix) { if (matrix != null) native_concat(mNativeCanvasWrapper, matrix.native_instance); } - + /** * Completely replace the current matrix with the specified matrix. If the * matrix parameter is null, then the current matrix is reset to identity. - * + * * <strong>Note:</strong> it is recommended to use {@link #concat(Matrix)}, * {@link #scale(float, float)}, {@link #translate(float, float)} and * {@link #rotate(float)} instead of this method. * * @param matrix The matrix to replace the current matrix with. If it is * null, set the current matrix to identity. - * - * @see #concat(Matrix) + * + * @see #concat(Matrix) */ public void setMatrix(@Nullable Matrix matrix) { native_setMatrix(mNativeCanvasWrapper, matrix == null ? 0 : matrix.native_instance); } - + /** * Return, in ctm, the current transformation matrix. This does not alter * the matrix in the canvas, but just returns a copy of it. @@ -628,7 +628,7 @@ public class Canvas { getMatrix(m); return m; } - + /** * Modify the current clip with the specified rectangle. * @@ -677,7 +677,7 @@ public class Canvas { return native_clipRect(mNativeCanvasWrapper, rect.left, rect.top, rect.right, rect.bottom, Region.Op.INTERSECT.nativeInt); } - + /** * Modify the current clip with the specified rectangle, which is * expressed in local coordinates. @@ -744,7 +744,7 @@ public class Canvas { public boolean clipPath(@NonNull Path path, @NonNull Region.Op op) { return native_clipPath(mNativeCanvasWrapper, path.ni(), op.nativeInt); } - + /** * Intersect the current clip with the specified path. * @@ -754,7 +754,7 @@ public class Canvas { public boolean clipPath(@NonNull Path path) { return clipPath(path, Region.Op.INTERSECT); } - + /** * Modify the current clip with the specified region. Note that unlike * clipRect() and clipPath() which transform their arguments by the @@ -789,11 +789,11 @@ public class Canvas { public boolean clipRegion(@NonNull Region region) { return clipRegion(region, Region.Op.INTERSECT); } - + public @Nullable DrawFilter getDrawFilter() { return mDrawFilter; } - + public void setDrawFilter(@Nullable DrawFilter filter) { long nativeFilter = 0; if (filter != null) { @@ -814,7 +814,7 @@ public class Canvas { * Antialiased: Treat edges by rounding-out, since they may be antialiased */ AA(1); - + EdgeType(int nativeInt) { this.nativeInt = nativeInt; } @@ -900,7 +900,7 @@ public class Canvas { public boolean getClipBounds(@Nullable Rect bounds) { return native_getClipBounds(mNativeCanvasWrapper, bounds); } - + /** * Retrieve the bounds of the current clip (in local coordinates). * @@ -911,7 +911,7 @@ public class Canvas { getClipBounds(r); return r; } - + /** * Fill the entire canvas' bitmap (restricted to the current clip) with the * specified RGB color, using srcover porterduff mode. @@ -968,7 +968,7 @@ public class Canvas { public void drawPaint(@NonNull Paint paint) { native_drawPaint(mNativeCanvasWrapper, paint.mNativePaint); } - + /** * Draw a series of points. Each point is centered at the coordinate * specified by pts[], and its diameter is specified by the paint's stroke @@ -1065,7 +1065,7 @@ public class Canvas { public void drawRect(@NonNull Rect r, @NonNull Paint paint) { drawRect(r.left, r.top, r.right, r.bottom, paint); } - + /** * Draw the specified Rect using the specified paint. The rectangle will @@ -1111,15 +1111,15 @@ public class Canvas { /** * <p>Draw the specified arc, which will be scaled to fit inside the * specified oval.</p> - * + * * <p>If the start angle is negative or >= 360, the start angle is treated * as start angle modulo 360.</p> - * + * * <p>If the sweep angle is >= 360, then the oval is drawn * completely. Note that this differs slightly from SkPath::arcTo, which * treats the sweep angle modulo 360. If the sweep angle is negative, * the sweep angle is treated as sweep angle modulo 360</p> - * + * * <p>The arc is drawn clockwise. An angle of 0 degrees correspond to the * geometric angle of 0 degrees (3 o'clock on a watch.)</p> * @@ -1197,7 +1197,7 @@ public class Canvas { * @param patch The ninepatch object to render * @param dst The destination rectangle. * @param paint The paint to draw the bitmap with. may be null - * + * * @hide */ public void drawPatch(@NonNull NinePatch patch, @NonNull Rect dst, @Nullable Paint paint) { @@ -1220,7 +1220,7 @@ public class Canvas { /** * Draw the specified bitmap, with its top/left corner at (x,y), using * the specified paint, transformed by the current matrix. - * + * * <p>Note: if the paint contains a maskfilter that generates a mask which * extends beyond the bitmap's original width/height (e.g. BlurMaskFilter), * then the bitmap will be drawn as if it were in a Shader with CLAMP mode. @@ -1230,7 +1230,7 @@ public class Canvas { * <p>If the bitmap and canvas have different densities, this function * will take care of automatically scaling the bitmap to draw at the * same density as the canvas. - * + * * @param bitmap The bitmap to be drawn * @param left The position of the left side of the bitmap being drawn * @param top The position of the top side of the bitmap being drawn @@ -1246,7 +1246,7 @@ public class Canvas { * Draw the specified bitmap, scaling/translating automatically to fill * the destination rectangle. If the source rectangle is not null, it * specifies the subset of the bitmap to draw. - * + * * <p>Note: if the paint contains a maskfilter that generates a mask which * extends beyond the bitmap's original width/height (e.g. BlurMaskFilter), * then the bitmap will be drawn as if it were in a Shader with CLAMP mode. @@ -1257,7 +1257,7 @@ public class Canvas { * This is because the source and destination rectangle coordinate * spaces are in their respective densities, so must already have the * appropriate scaling factor applied. - * + * * @param bitmap The bitmap to be drawn * @param src May be null. The subset of the bitmap to be drawn * @param dst The rectangle that the bitmap will be scaled/translated @@ -1278,7 +1278,7 @@ public class Canvas { * Draw the specified bitmap, scaling/translating automatically to fill * the destination rectangle. If the source rectangle is not null, it * specifies the subset of the bitmap to draw. - * + * * <p>Note: if the paint contains a maskfilter that generates a mask which * extends beyond the bitmap's original width/height (e.g. BlurMaskFilter), * then the bitmap will be drawn as if it were in a Shader with CLAMP mode. @@ -1289,7 +1289,7 @@ public class Canvas { * This is because the source and destination rectangle coordinate * spaces are in their respective densities, so must already have the * appropriate scaling factor applied. - * + * * @param bitmap The bitmap to be drawn * @param src May be null. The subset of the bitmap to be drawn * @param dst The rectangle that the bitmap will be scaled/translated @@ -1305,7 +1305,7 @@ public class Canvas { native_drawBitmap(mNativeCanvasWrapper, bitmap.ni(), src, dst, paint != null ? paint.mNativePaint : 0, mScreenDensity, bitmap.mDensity); } - + /** * Treat the specified array of colors as a bitmap, and draw it. This gives * the same result as first creating a bitmap from the array, and then @@ -1394,7 +1394,7 @@ public class Canvas { throw new ArrayIndexOutOfBoundsException(); } } - + /** * Draw the bitmap through the mesh, where mesh vertices are evenly * distributed across the bitmap. There are meshWidth+1 vertices across, and @@ -1446,7 +1446,7 @@ public class Canvas { TRIANGLES(0), TRIANGLE_STRIP(1), TRIANGLE_FAN(2); - + VertexMode(int nativeInt) { this.nativeInt = nativeInt; } @@ -1456,7 +1456,7 @@ public class Canvas { */ public final int nativeInt; } - + /** * Draw the array of vertices, interpreted as triangles (based on mode). The * verts array is required, and specifies the x,y pairs for each vertex. If @@ -1485,7 +1485,7 @@ public class Canvas { * @param indices If not null, array of indices to reference into the * vertex (texs, colors) array. * @param indexCount number of entries in the indices array (if not null). - * @param paint Specifies the shader to use if the texs array is non-null. + * @param paint Specifies the shader to use if the texs array is non-null. */ public void drawVertices(@NonNull VertexMode mode, int vertexCount, @NonNull float[] verts, int vertOffset, @Nullable float[] texs, int texOffset, @Nullable int[] colors, @@ -1595,7 +1595,7 @@ public class Canvas { * bidi on the provided text, but renders it as a uniform right-to-left or * left-to-right run, as indicated by dir. Alignment of the text is as * determined by the Paint's TextAlign value. - * + * * @param text the text to render * @param index the start of the text to render * @param count the count of chars to render @@ -1606,13 +1606,12 @@ public class Canvas { * + count. * @param x the x position at which to draw the text * @param y the y position at which to draw the text - * @param dir the run direction, either {@link #DIRECTION_LTR} or - * {@link #DIRECTION_RTL}. + * @param isRtl whether the run is in RTL direction * @param paint the paint * @hide */ public void drawTextRun(@NonNull char[] text, int index, int count, int contextIndex, - int contextCount, float x, float y, int dir, @NonNull Paint paint) { + int contextCount, float x, float y, boolean isRtl, @NonNull Paint paint) { if (text == null) { throw new NullPointerException("text is null"); @@ -1623,12 +1622,9 @@ public class Canvas { if ((index | count | text.length - index - count) < 0) { throw new IndexOutOfBoundsException(); } - if (dir != DIRECTION_LTR && dir != DIRECTION_RTL) { - throw new IllegalArgumentException("unknown dir: " + dir); - } native_drawTextRun(mNativeCanvasWrapper, text, index, count, - contextIndex, contextCount, x, y, dir, paint.mNativePaint, paint.mNativeTypeface); + contextIndex, contextCount, x, y, isRtl, paint.mNativePaint, paint.mNativeTypeface); } /** @@ -1644,12 +1640,12 @@ public class Canvas { * position can be used for shaping context. * @param x the x position at which to draw the text * @param y the y position at which to draw the text - * @param dir the run direction, either 0 for LTR or 1 for RTL. + * @param isRtl whether the run is in RTL direction * @param paint the paint * @hide */ public void drawTextRun(@NonNull CharSequence text, int start, int end, int contextStart, - int contextEnd, float x, float y, int dir, @NonNull Paint paint) { + int contextEnd, float x, float y, boolean isRtl, @NonNull Paint paint) { if (text == null) { throw new NullPointerException("text is null"); @@ -1661,22 +1657,20 @@ public class Canvas { throw new IndexOutOfBoundsException(); } - int flags = dir == 0 ? 0 : 1; - if (text instanceof String || text instanceof SpannedString || text instanceof SpannableString) { native_drawTextRun(mNativeCanvasWrapper, text.toString(), start, end, - contextStart, contextEnd, x, y, flags, paint.mNativePaint, paint.mNativeTypeface); + contextStart, contextEnd, x, y, isRtl, paint.mNativePaint, paint.mNativeTypeface); } else if (text instanceof GraphicsOperations) { ((GraphicsOperations) text).drawTextRun(this, start, end, - contextStart, contextEnd, x, y, flags, paint); + contextStart, contextEnd, x, y, isRtl, paint); } else { int contextLen = contextEnd - contextStart; int len = end - start; char[] buf = TemporaryBuffer.obtain(contextLen); TextUtils.getChars(text, contextStart, contextEnd, buf, 0); native_drawTextRun(mNativeCanvasWrapper, buf, start - contextStart, len, - 0, contextLen, x, y, flags, paint.mNativePaint, paint.mNativeTypeface); + 0, contextLen, x, y, isRtl, paint.mNativePaint, paint.mNativeTypeface); TemporaryBuffer.recycle(buf); } } @@ -1684,7 +1678,7 @@ public class Canvas { /** * Draw the text in the array, with each character's origin specified by * the pos array. - * + * * This method does not support glyph composition and decomposition and * should therefore not be used to render complex scripts. * @@ -1708,7 +1702,7 @@ public class Canvas { /** * Draw the text in the array, with each character's origin specified by * the pos array. - * + * * This method does not support glyph composition and decomposition and * should therefore not be used to render complex scripts. * @@ -1776,7 +1770,7 @@ public class Canvas { * <p> * <strong>Note:</strong> This forces the picture to internally call * {@link Picture#endRecording} in order to prepare for playback. - * + * * @param picture The picture to be drawn */ public void drawPicture(@NonNull Picture picture) { @@ -1785,7 +1779,7 @@ public class Canvas { picture.draw(this); restoreToCount(restoreCount); } - + /** * Draw the picture, stretched to fit into the dst rectangle. */ @@ -1798,7 +1792,7 @@ public class Canvas { drawPicture(picture); restore(); } - + /** * Draw the picture, stretched to fit into the dst rectangle. */ @@ -1977,11 +1971,11 @@ public class Canvas { private static native void native_drawTextRun(long nativeCanvas, String text, int start, int end, int contextStart, int contextEnd, - float x, float y, int flags, long nativePaint, long nativeTypeface); + float x, float y, boolean isRtl, long nativePaint, long nativeTypeface); private static native void native_drawTextRun(long nativeCanvas, char[] text, int start, int count, int contextStart, int contextCount, - float x, float y, int flags, long nativePaint, long nativeTypeface); + float x, float y, boolean isRtl, long nativePaint, long nativeTypeface); private static native void native_drawPosText(long nativeCanvas, char[] text, int index, diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index 4268a24..8837955 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -56,7 +56,7 @@ public class Paint { * @hide */ public int mBidiFlags = BIDI_DEFAULT_LTR; - + static final Style[] sStyleArray = { Style.FILL, Style.STROKE, Style.FILL_AND_STROKE }; @@ -202,14 +202,14 @@ public class Paint { /** * Bidi flag to set LTR paragraph direction. - * + * * @hide */ public static final int BIDI_LTR = 0x0; /** * Bidi flag to set RTL paragraph direction. - * + * * @hide */ public static final int BIDI_RTL = 0x1; @@ -217,7 +217,7 @@ public class Paint { /** * Bidi flag to detect paragraph direction via heuristics, defaulting to * LTR. - * + * * @hide */ public static final int BIDI_DEFAULT_LTR = 0x2; @@ -225,21 +225,21 @@ public class Paint { /** * Bidi flag to detect paragraph direction via heuristics, defaulting to * RTL. - * + * * @hide */ public static final int BIDI_DEFAULT_RTL = 0x3; /** * Bidi flag to override direction to all LTR (ignore bidi). - * + * * @hide */ public static final int BIDI_FORCE_LTR = 0x4; /** * Bidi flag to override direction to all RTL (ignore bidi). - * + * * @hide */ public static final int BIDI_FORCE_RTL = 0x5; @@ -331,7 +331,7 @@ public class Paint { * either FILL or STROKE. */ FILL_AND_STROKE (2); - + Style(int nativeInt) { this.nativeInt = nativeInt; } @@ -357,7 +357,7 @@ public class Paint { * of the path. */ SQUARE (2); - + private Cap(int nativeInt) { this.nativeInt = nativeInt; } @@ -381,7 +381,7 @@ public class Paint { * The outer edges of a join meet with a straight line */ BEVEL (2); - + private Join(int nativeInt) { this.nativeInt = nativeInt; } @@ -405,7 +405,7 @@ public class Paint { * The text is drawn to the left of the x,y origin */ RIGHT (2); - + private Align(int nativeInt) { this.nativeInt = nativeInt; } @@ -418,7 +418,7 @@ public class Paint { public Paint() { this(0); } - + /** * Create a new paint with the specified flags. Use setFlags() to change * these after the paint is created. @@ -475,7 +475,7 @@ public class Paint { setTextLocale(Locale.getDefault()); setElegantTextHeight(false); } - + /** * Copy the fields from src into this paint. This is equivalent to calling * get() on all of the src fields, and calling the corresponding set() @@ -529,7 +529,7 @@ public class Paint { /** * Return the bidi flags on the paint. - * + * * @return the bidi flags on the paint * @hide */ @@ -552,7 +552,7 @@ public class Paint { /** * Return the paint's flags. Use the Flag enum to test flag values. - * + * * @return the paint's flags (see enums ending in _Flag for bit masks) */ public native int getFlags(); @@ -587,7 +587,7 @@ public class Paint { public final boolean isAntiAlias() { return (getFlags() & ANTI_ALIAS_FLAG) != 0; } - + /** * Helper for setFlags(), setting or clearing the ANTI_ALIAS_FLAG bit * AntiAliasing smooths out the edges of what is being drawn, but is has @@ -597,7 +597,7 @@ public class Paint { * @param aa true to set the antialias bit in the flags, false to clear it */ public native void setAntiAlias(boolean aa); - + /** * Helper for getFlags(), returning true if DITHER_FLAG bit is set * Dithering affects how colors that are higher precision than the device @@ -611,7 +611,7 @@ public class Paint { public final boolean isDither() { return (getFlags() & DITHER_FLAG) != 0; } - + /** * Helper for setFlags(), setting or clearing the DITHER_FLAG bit * Dithering affects how colors that are higher precision than the device @@ -623,7 +623,7 @@ public class Paint { * @param dither true to set the dithering bit in flags, false to clear it */ public native void setDither(boolean dither); - + /** * Helper for getFlags(), returning true if LINEAR_TEXT_FLAG bit is set * @@ -649,7 +649,7 @@ public class Paint { public final boolean isSubpixelText() { return (getFlags() & SUBPIXEL_TEXT_FLAG) != 0; } - + /** * Helper for setFlags(), setting or clearing the SUBPIXEL_TEXT_FLAG bit * @@ -657,7 +657,7 @@ public class Paint { * flags, false to clear it. */ public native void setSubpixelText(boolean subpixelText); - + /** * Helper for getFlags(), returning true if UNDERLINE_TEXT_FLAG bit is set * @@ -708,7 +708,7 @@ public class Paint { * flags, false to clear it. */ public native void setFakeBoldText(boolean fakeBoldText); - + /** * Whether or not the bitmap filter is activated. * Filtering affects the sampling of bitmaps when they are transformed. @@ -720,13 +720,13 @@ public class Paint { public final boolean isFilterBitmap() { return (getFlags() & FILTER_BITMAP_FLAG) != 0; } - + /** * Helper for setFlags(), setting or clearing the FILTER_BITMAP_FLAG bit. * Filtering affects the sampling of bitmaps when they are transformed. * Filtering does not affect how the colors in the bitmap are converted into * device pixels. That is dependent on dithering and xfermodes. - * + * * @param filter true to set the FILTER_BITMAP_FLAG bit in the paint's * flags, false to clear it. */ @@ -773,7 +773,7 @@ public class Paint { * @param color The new color (including alpha) to set in the paint. */ public native void setColor(int color); - + /** * Helper to getColor() that just returns the color's alpha value. This is * the same as calling getColor() >>> 24. It always returns a value between @@ -1285,7 +1285,7 @@ public class Paint { */ public static class FontMetrics { /** - * The maximum distance above the baseline for the tallest glyph in + * The maximum distance above the baseline for the tallest glyph in * the font at a given text size. */ public float top; @@ -1298,7 +1298,7 @@ public class Paint { */ public float descent; /** - * The maximum distance below the baseline for the lowest glyph in + * The maximum distance below the baseline for the lowest glyph in * the font at a given text size. */ public float bottom; @@ -1307,7 +1307,7 @@ public class Paint { */ public float leading; } - + /** * Return the font's recommended interline spacing, given the Paint's * settings for typeface, textSize, etc. If metrics is not null, return the @@ -1318,7 +1318,7 @@ public class Paint { * @return the font's recommended interline spacing. */ public native float getFontMetrics(FontMetrics metrics); - + /** * Allocates a new FontMetrics object, and then calls getFontMetrics(fm) * with it, returning the object. @@ -1328,7 +1328,7 @@ public class Paint { getFontMetrics(fm); return fm; } - + /** * Convenience method for callers that want to have FontMetrics values as * integers. @@ -1339,7 +1339,7 @@ public class Paint { public int descent; public int bottom; public int leading; - + @Override public String toString() { return "FontMetricsInt: top=" + top + " ascent=" + ascent + " descent=" + descent + " bottom=" + bottom + @@ -1364,7 +1364,7 @@ public class Paint { getFontMetricsInt(fm); return fm; } - + /** * Return the recommend line spacing based on the current typeface and * text size. @@ -1407,7 +1407,7 @@ public class Paint { } private native float native_measureText(char[] text, int index, int count, int bidiFlags); - + /** * Return the width of the text. * @@ -1439,7 +1439,7 @@ public class Paint { } private native float native_measureText(String text, int start, int end, int bidiFlags); - + /** * Return the width of the text. * @@ -1466,7 +1466,7 @@ public class Paint { } private native float native_measureText(String text, int bidiFlags); - + /** * Return the width of the text. * @@ -1503,7 +1503,7 @@ public class Paint { TemporaryBuffer.recycle(buf); return result; } - + /** * Measure the text, stopping early if the measured width exceeds maxWidth. * Return the number of chars that were measured, and if measuredWidth is @@ -1738,7 +1738,7 @@ public class Paint { if (end - start > widths.length) { throw new ArrayIndexOutOfBoundsException(); } - + if (text.length() == 0 || start == end) { return 0; } @@ -1755,7 +1755,7 @@ public class Paint { } return res; } - + /** * Return the advance widths for the characters in the string. * @@ -1816,15 +1816,12 @@ public class Paint { * @hide */ public float getTextRunAdvances(char[] chars, int index, int count, - int contextIndex, int contextCount, int flags, float[] advances, + int contextIndex, int contextCount, boolean isRtl, float[] advances, int advancesIndex) { if (chars == null) { throw new IllegalArgumentException("text cannot be null"); } - if (flags != DIRECTION_LTR && flags != DIRECTION_RTL) { - throw new IllegalArgumentException("unknown flags value: " + flags); - } if ((index | count | contextIndex | contextCount | advancesIndex | (index - contextIndex) | (contextCount - count) | ((contextIndex + contextCount) - (index + count)) @@ -1839,13 +1836,13 @@ public class Paint { } if (!mHasCompatScaling) { return native_getTextRunAdvances(mNativePaint, mNativeTypeface, chars, index, count, - contextIndex, contextCount, flags, advances, advancesIndex); + contextIndex, contextCount, isRtl, advances, advancesIndex); } final float oldSize = getTextSize(); setTextSize(oldSize * mCompatScaling); float res = native_getTextRunAdvances(mNativePaint, mNativeTypeface, chars, index, count, - contextIndex, contextCount, flags, advances, advancesIndex); + contextIndex, contextCount, isRtl, advances, advancesIndex); setTextSize(oldSize); if (advances != null) { @@ -1864,7 +1861,7 @@ public class Paint { * @hide */ public float getTextRunAdvances(CharSequence text, int start, int end, - int contextStart, int contextEnd, int flags, float[] advances, + int contextStart, int contextEnd, boolean isRtl, float[] advances, int advancesIndex) { if (text == null) { @@ -1880,16 +1877,16 @@ public class Paint { if (text instanceof String) { return getTextRunAdvances((String) text, start, end, - contextStart, contextEnd, flags, advances, advancesIndex); + contextStart, contextEnd, isRtl, advances, advancesIndex); } if (text instanceof SpannedString || text instanceof SpannableString) { return getTextRunAdvances(text.toString(), start, end, - contextStart, contextEnd, flags, advances, advancesIndex); + contextStart, contextEnd, isRtl, advances, advancesIndex); } if (text instanceof GraphicsOperations) { return ((GraphicsOperations) text).getTextRunAdvances(start, end, - contextStart, contextEnd, flags, advances, advancesIndex, this); + contextStart, contextEnd, isRtl, advances, advancesIndex, this); } if (text.length() == 0 || end == start) { return 0f; @@ -1900,7 +1897,7 @@ public class Paint { char[] buf = TemporaryBuffer.obtain(contextLen); TextUtils.getChars(text, contextStart, contextEnd, buf, 0); float result = getTextRunAdvances(buf, start - contextStart, len, - 0, contextLen, flags, advances, advancesIndex); + 0, contextLen, isRtl, advances, advancesIndex); TemporaryBuffer.recycle(buf); return result; } @@ -1937,8 +1934,7 @@ public class Paint { * must be <= start * @param contextEnd the index past the last character to use for shaping context, * must be >= end - * @param flags the flags to control the advances, either {@link #DIRECTION_LTR} - * or {@link #DIRECTION_RTL} + * @param isRtl whether the run is in RTL direction * @param advances array to receive the advances, must have room for all advances, * can be null if only total advance is needed * @param advancesIndex the position in advances at which to put the @@ -1948,14 +1944,11 @@ public class Paint { * @hide */ public float getTextRunAdvances(String text, int start, int end, int contextStart, - int contextEnd, int flags, float[] advances, int advancesIndex) { + int contextEnd, boolean isRtl, float[] advances, int advancesIndex) { if (text == null) { throw new IllegalArgumentException("text cannot be null"); } - if (flags != DIRECTION_LTR && flags != DIRECTION_RTL) { - throw new IllegalArgumentException("unknown flags value: " + flags); - } if ((start | end | contextStart | contextEnd | advancesIndex | (end - start) | (start - contextStart) | (contextEnd - end) | (text.length() - contextEnd) @@ -1970,13 +1963,13 @@ public class Paint { if (!mHasCompatScaling) { return native_getTextRunAdvances(mNativePaint, mNativeTypeface, text, start, end, - contextStart, contextEnd, flags, advances, advancesIndex); + contextStart, contextEnd, isRtl, advances, advancesIndex); } final float oldSize = getTextSize(); setTextSize(oldSize * mCompatScaling); float totalAdvance = native_getTextRunAdvances(mNativePaint, mNativeTypeface, text, start, end, - contextStart, contextEnd, flags, advances, advancesIndex); + contextStart, contextEnd, isRtl, advances, advancesIndex); setTextSize(oldSize); if (advances != null) { @@ -2005,7 +1998,7 @@ public class Paint { * @param text the text * @param contextStart the start of the context * @param contextLength the length of the context - * @param flags either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR} + * @param dir either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR} * @param offset the cursor position to move from * @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER}, * {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE}, @@ -2014,7 +2007,7 @@ public class Paint { * @hide */ public int getTextRunCursor(char[] text, int contextStart, int contextLength, - int flags, int offset, int cursorOpt) { + int dir, int offset, int cursorOpt) { int contextEnd = contextStart + contextLength; if (((contextStart | contextEnd | offset | (contextEnd - contextStart) | (offset - contextStart) | (contextEnd - offset) @@ -2024,7 +2017,7 @@ public class Paint { } return native_getTextRunCursor(mNativePaint, text, - contextStart, contextLength, flags, offset, cursorOpt); + contextStart, contextLength, dir, offset, cursorOpt); } /** @@ -2045,7 +2038,7 @@ public class Paint { * @param text the text * @param contextStart the start of the context * @param contextEnd the end of the context - * @param flags either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR} + * @param dir either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR} * @param offset the cursor position to move from * @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER}, * {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE}, @@ -2054,22 +2047,22 @@ public class Paint { * @hide */ public int getTextRunCursor(CharSequence text, int contextStart, - int contextEnd, int flags, int offset, int cursorOpt) { + int contextEnd, int dir, int offset, int cursorOpt) { if (text instanceof String || text instanceof SpannedString || text instanceof SpannableString) { return getTextRunCursor(text.toString(), contextStart, contextEnd, - flags, offset, cursorOpt); + dir, offset, cursorOpt); } if (text instanceof GraphicsOperations) { return ((GraphicsOperations) text).getTextRunCursor( - contextStart, contextEnd, flags, offset, cursorOpt, this); + contextStart, contextEnd, dir, offset, cursorOpt, this); } int contextLen = contextEnd - contextStart; char[] buf = TemporaryBuffer.obtain(contextLen); TextUtils.getChars(text, contextStart, contextEnd, buf, 0); - int result = getTextRunCursor(buf, 0, contextLen, flags, offset - contextStart, cursorOpt); + int result = getTextRunCursor(buf, 0, contextLen, dir, offset - contextStart, cursorOpt); TemporaryBuffer.recycle(buf); return result; } @@ -2092,7 +2085,7 @@ public class Paint { * @param text the text * @param contextStart the start of the context * @param contextEnd the end of the context - * @param flags either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR} + * @param dir either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR} * @param offset the cursor position to move from * @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER}, * {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE}, @@ -2101,7 +2094,7 @@ public class Paint { * @hide */ public int getTextRunCursor(String text, int contextStart, int contextEnd, - int flags, int offset, int cursorOpt) { + int dir, int offset, int cursorOpt) { if (((contextStart | contextEnd | offset | (contextEnd - contextStart) | (offset - contextStart) | (contextEnd - offset) | (text.length() - contextEnd) | cursorOpt) < 0) @@ -2110,7 +2103,7 @@ public class Paint { } return native_getTextRunCursor(mNativePaint, text, - contextStart, contextEnd, flags, offset, cursorOpt); + contextStart, contextEnd, dir, offset, cursorOpt); } /** @@ -2156,7 +2149,7 @@ public class Paint { native_getTextPath(mNativePaint, mNativeTypeface, mBidiFlags, text, start, end, x, y, path.ni()); } - + /** * Return in bounds (allocated by the caller) the smallest rectangle that * encloses all of the characters, with an implied origin at (0,0). @@ -2176,7 +2169,7 @@ public class Paint { } nativeGetStringBounds(mNativePaint, mNativeTypeface, text, start, end, mBidiFlags, bounds); } - + /** * Return in bounds (allocated by the caller) the smallest rectangle that * encloses all of the characters, with an implied origin at (0,0). @@ -2197,7 +2190,7 @@ public class Paint { nativeGetCharArrayBounds(mNativePaint, mNativeTypeface, text, index, count, mBidiFlags, bounds); } - + @Override protected void finalize() throws Throwable { try { @@ -2252,15 +2245,15 @@ public class Paint { private static native float native_getTextRunAdvances(long native_object, long native_typeface, char[] text, int index, int count, int contextIndex, int contextCount, - int flags, float[] advances, int advancesIndex); + boolean isRtl, float[] advances, int advancesIndex); private static native float native_getTextRunAdvances(long native_object, long native_typeface, String text, int start, int end, int contextStart, int contextEnd, - int flags, float[] advances, int advancesIndex); + boolean isRtl, float[] advances, int advancesIndex); private native int native_getTextRunCursor(long native_object, char[] text, - int contextStart, int contextLength, int flags, int offset, int cursorOpt); + int contextStart, int contextLength, int dir, int offset, int cursorOpt); private native int native_getTextRunCursor(long native_object, String text, - int contextStart, int contextEnd, int flags, int offset, int cursorOpt); + int contextStart, int contextEnd, int dir, int offset, int cursorOpt); private static native void native_getTextPath(long native_object, long native_typeface, int bidiFlags, char[] text, int index, int count, float x, float y, long path); diff --git a/graphics/java/android/graphics/drawable/Animatable.java b/graphics/java/android/graphics/drawable/Animatable.java index 9dc62c3..4edfad4 100644 --- a/graphics/java/android/graphics/drawable/Animatable.java +++ b/graphics/java/android/graphics/drawable/Animatable.java @@ -32,7 +32,7 @@ public interface Animatable { /** * Indicates whether the animation is running. - * + * * @return True if the animation is running, false otherwise. */ boolean isRunning(); diff --git a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java index e8024f7..0fd4423 100644 --- a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java @@ -19,6 +19,8 @@ package android.graphics.drawable; import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.ColorFilter; +import android.graphics.PorterDuff.Mode; +import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.Resources.Theme; @@ -88,6 +90,7 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac canvas.restoreToCount(saveCount); } + @Override public void start() { if (!mRunning) { mRunning = true; @@ -95,11 +98,13 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac } } + @Override public void stop() { mRunning = false; unscheduleSelf(this); } + @Override public boolean isRunning() { return mRunning; } @@ -108,10 +113,11 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac unscheduleSelf(this); scheduleSelf(this, SystemClock.uptimeMillis() + mState.mFrameDuration); } - + + @Override public void run() { // TODO: This should be computed in draw(Canvas), based on the amount - // of time since the last frame drawn + // of time since the last frame drawn mCurrentDegrees += mIncrement; if (mCurrentDegrees > (360.0f - mIncrement)) { mCurrentDegrees = 0.0f; @@ -119,7 +125,7 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac invalidateSelf(); nextFrame(); } - + @Override public boolean setVisible(boolean visible, boolean restart) { mState.mDrawable.setVisible(visible, restart); @@ -133,8 +139,8 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac unscheduleSelf(this); } return changed; - } - + } + /** * Returns the drawable rotated by this RotateDrawable. */ @@ -148,7 +154,7 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac | mState.mChangingConfigurations | mState.mDrawable.getChangingConfigurations(); } - + @Override public void setAlpha(int alpha) { mState.mDrawable.setAlpha(alpha); @@ -165,10 +171,16 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac } @Override + public void setTint(ColorStateList tint, Mode tintMode) { + mState.mDrawable.setTint(tint, tintMode); + } + + @Override public int getOpacity() { return mState.mDrawable.getOpacity(); } + @Override public void invalidateDrawable(Drawable who) { final Callback callback = getCallback(); if (callback != null) { @@ -176,6 +188,7 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac } } + @Override public void scheduleDrawable(Drawable who, Runnable what, long when) { final Callback callback = getCallback(); if (callback != null) { @@ -183,6 +196,7 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac } } + @Override public void unscheduleDrawable(Drawable who, Runnable what) { final Callback callback = getCallback(); if (callback != null) { @@ -194,7 +208,7 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac public boolean getPadding(Rect padding) { return mState.mDrawable.getPadding(padding); } - + @Override public boolean isStateful() { return mState.mDrawable.isStateful(); @@ -206,6 +220,16 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac } @Override + protected boolean onLevelChange(int level) { + return mState.mDrawable.setLevel(level); + } + + @Override + protected boolean onStateChange(int[] state) { + return mState.mDrawable.setState(state); + } + + @Override public int getIntrinsicWidth() { return mState.mDrawable.getIntrinsicWidth(); } @@ -231,11 +255,11 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac final TypedArray a = r.obtainAttributes(attrs, R.styleable.AnimatedRotateDrawable); super.inflateWithAttributes(r, parser, a, R.styleable.AnimatedRotateDrawable_visible); - + TypedValue tv = a.peekValue(R.styleable.AnimatedRotateDrawable_pivotX); final boolean pivotXRel = tv.type == TypedValue.TYPE_FRACTION; final float pivotX = pivotXRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat(); - + tv = a.peekValue(R.styleable.AnimatedRotateDrawable_pivotY); final boolean pivotYRel = tv.type == TypedValue.TYPE_FRACTION; final float pivotY = pivotYRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat(); @@ -250,7 +274,7 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac } a.recycle(); - + int outerDepth = parser.getDepth(); int type; while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && @@ -306,7 +330,7 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac Drawable mDrawable; int mChangingConfigurations; - + boolean mPivotXRel; float mPivotX; boolean mPivotYRel; @@ -315,7 +339,7 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac int mFramesCount; private boolean mCanConstantState; - private boolean mCheckedConstantState; + private boolean mCheckedConstantState; public AnimatedRotateState(AnimatedRotateState source, AnimatedRotateDrawable owner, Resources res) { @@ -341,12 +365,12 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac public Drawable newDrawable() { return new AnimatedRotateDrawable(this, null); } - + @Override public Drawable newDrawable(Resources res) { return new AnimatedRotateDrawable(this, res); } - + @Override public int getChangingConfigurations() { return mChangingConfigurations; diff --git a/graphics/java/android/graphics/drawable/AnimationDrawable.java b/graphics/java/android/graphics/drawable/AnimationDrawable.java index 1ee0224..0740761 100644 --- a/graphics/java/android/graphics/drawable/AnimationDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimationDrawable.java @@ -28,7 +28,6 @@ import android.os.SystemClock; import android.util.AttributeSet; /** - * * An object used to create frame-by-frame animations, defined by a series of Drawable objects, * which can be used as a View object's background. * <p> @@ -114,6 +113,7 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An * @see #isRunning() * @see #stop() */ + @Override public void start() { if (!isRunning()) { run(); @@ -127,6 +127,7 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An * @see #isRunning() * @see #start() */ + @Override public void stop() { if (isRunning()) { unscheduleSelf(this); @@ -138,6 +139,7 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An * * @return true if the animation is running, false otherwise */ + @Override public boolean isRunning() { return mAnimating; } @@ -148,6 +150,7 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An * * @see #start() */ + @Override public void run() { nextFrame(false); } @@ -165,41 +168,41 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An public int getNumberOfFrames() { return mAnimationState.getChildCount(); } - + /** * @return The Drawable at the specified frame index */ public Drawable getFrame(int index) { return mAnimationState.getChild(index); } - + /** - * @return The duration in milliseconds of the frame at the + * @return The duration in milliseconds of the frame at the * specified index */ public int getDuration(int i) { return mAnimationState.mDurations[i]; } - + /** * @return True of the animation will play once, false otherwise */ public boolean isOneShot() { return mAnimationState.mOneShot; } - + /** * Sets whether the animation should play once or repeat. - * + * * @param oneShot Pass true if the animation should only play once */ public void setOneShot(boolean oneShot) { mAnimationState.mOneShot = oneShot; } - + /** * Add a frame to the animation - * + * * @param frame The frame to add * @param duration How long in milliseconds the frame should appear */ @@ -209,7 +212,7 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An setFrame(0, true, false); } } - + private void nextFrame(boolean unschedule) { int next = mCurFrame+1; final int N = mAnimationState.getChildCount(); @@ -239,21 +242,21 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An @Override public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme) throws XmlPullParserException, IOException { - + TypedArray a = r.obtainAttributes(attrs, com.android.internal.R.styleable.AnimationDrawable); super.inflateWithAttributes(r, parser, a, com.android.internal.R.styleable.AnimationDrawable_visible); - + mAnimationState.setVariablePadding(a.getBoolean( com.android.internal.R.styleable.AnimationDrawable_variablePadding, false)); - + mAnimationState.mOneShot = a.getBoolean( com.android.internal.R.styleable.AnimationDrawable_oneshot, false); - + a.recycle(); - + int type; final int innerDepth = parser.getDepth()+1; @@ -267,7 +270,7 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An if (depth > innerDepth || !parser.getName().equals("item")) { continue; } - + a = r.obtainAttributes(attrs, com.android.internal.R.styleable.AnimationDrawableItem); int duration = a.getInt( com.android.internal.R.styleable.AnimationDrawableItem_duration, -1); @@ -278,9 +281,9 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An } int drawableRes = a.getResourceId( com.android.internal.R.styleable.AnimationDrawableItem_drawable, 0); - + a.recycle(); - + Drawable dr; if (drawableRes != 0) { dr = r.getDrawable(drawableRes); @@ -295,7 +298,7 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An } dr = Drawable.createFromXmlInner(r, parser, attrs, theme); } - + mAnimationState.addFrame(dr, duration); if (dr != null) { dr.setCallback(this); @@ -342,7 +345,7 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An } public void addFrame(Drawable dr, int dur) { - // Do not combine the following. The array index must be evaluated before + // Do not combine the following. The array index must be evaluated before // the array is accessed because super.addChild(dr) has a side effect on mDurations. int pos = super.addChild(dr); mDurations[pos] = dur; diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java index ef6c085..be940df 100644 --- a/graphics/java/android/graphics/drawable/BitmapDrawable.java +++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java @@ -31,6 +31,7 @@ import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.PorterDuff; import android.graphics.PorterDuff.Mode; +import android.graphics.drawable.ColorDrawable.ColorState; import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; import android.graphics.Shader; @@ -618,9 +619,11 @@ public class BitmapDrawable extends Drawable { @Override public void setTint(ColorStateList tint, PorterDuff.Mode tintMode) { - mBitmapState.mTint = tint; - mBitmapState.mTintMode = tintMode; - computeTintFilter(); + final BitmapState state = mBitmapState; + state.mTint = tint; + state.mTintMode = tintMode; + + mTintFilter = updateTintFilter(mTintFilter, tint, tintMode); invalidateSelf(); } @@ -638,21 +641,6 @@ public class BitmapDrawable extends Drawable { return mBitmapState.mTintMode; } - private void computeTintFilter() { - final BitmapState state = mBitmapState; - if (state.mTint != null && state.mTintMode != null) { - final int color = state.mTint.getColorForState(getState(), 0); - if (mTintFilter != null) { - mTintFilter.setColor(color); - mTintFilter.setMode(state.mTintMode); - } else { - mTintFilter = new PorterDuffColorFilter(color, state.mTintMode); - } - } else { - mTintFilter = null; - } - } - /** * @hide Candidate for future API inclusion */ @@ -679,17 +667,11 @@ public class BitmapDrawable extends Drawable { @Override protected boolean onStateChange(int[] stateSet) { - final ColorStateList tint = mBitmapState.mTint; - if (tint != null) { - final int newColor = tint.getColorForState(stateSet, 0); - final int oldColor = mTintFilter.getColor(); - if (oldColor != newColor) { - mTintFilter.setColor(newColor); - invalidateSelf(); - return true; - } + final BitmapState state = mBitmapState; + if (state.mTint != null && state.mTintMode != null) { + mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode); + return true; } - return false; } @@ -946,7 +928,7 @@ public class BitmapDrawable extends Drawable { mTargetDensity = state.mTargetDensity; } - computeTintFilter(); + updateTintFilter(mTintFilter, state.mTint, state.mTintMode); computeBitmapSize(); } } diff --git a/graphics/java/android/graphics/drawable/ClipDrawable.java b/graphics/java/android/graphics/drawable/ClipDrawable.java index 3ac9972..174de3a 100644 --- a/graphics/java/android/graphics/drawable/ClipDrawable.java +++ b/graphics/java/android/graphics/drawable/ClipDrawable.java @@ -19,10 +19,12 @@ package android.graphics.drawable; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; +import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.Resources.Theme; import android.graphics.*; +import android.graphics.PorterDuff.Mode; import android.view.Gravity; import android.util.AttributeSet; @@ -52,7 +54,7 @@ public class ClipDrawable extends Drawable implements Drawable.Callback { public static final int HORIZONTAL = 1; public static final int VERTICAL = 2; - + ClipDrawable() { this(null, null); } @@ -111,6 +113,7 @@ public class ClipDrawable extends Drawable implements Drawable.Callback { // overrides from Drawable.Callback + @Override public void invalidateDrawable(Drawable who) { final Callback callback = getCallback(); if (callback != null) { @@ -118,6 +121,7 @@ public class ClipDrawable extends Drawable implements Drawable.Callback { } } + @Override public void scheduleDrawable(Drawable who, Runnable what, long when) { final Callback callback = getCallback(); if (callback != null) { @@ -125,6 +129,7 @@ public class ClipDrawable extends Drawable implements Drawable.Callback { } } + @Override public void unscheduleDrawable(Drawable who, Runnable what) { final Callback callback = getCallback(); if (callback != null) { @@ -169,6 +174,11 @@ public class ClipDrawable extends Drawable implements Drawable.Callback { } @Override + public void setTint(ColorStateList tint, Mode tintMode) { + mClipState.mDrawable.setTint(tint, tintMode); + } + + @Override public int getOpacity() { return mClipState.mDrawable.getOpacity(); } @@ -197,7 +207,7 @@ public class ClipDrawable extends Drawable implements Drawable.Callback { @Override public void draw(Canvas canvas) { - + if (mClipState.mDrawable.getLevel() == 0) { return; } diff --git a/graphics/java/android/graphics/drawable/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java index df5ca33..3716182 100644 --- a/graphics/java/android/graphics/drawable/ColorDrawable.java +++ b/graphics/java/android/graphics/drawable/ColorDrawable.java @@ -17,6 +17,8 @@ package android.graphics.drawable; import android.graphics.*; +import android.graphics.PorterDuff.Mode; +import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.Resources.Theme; import android.content.res.TypedArray; @@ -39,9 +41,13 @@ import java.io.IOException; * @attr ref android.R.styleable#ColorDrawable_color */ public class ColorDrawable extends Drawable { + private final Paint mPaint = new Paint(); + @ViewDebug.ExportedProperty(deepExport = true, prefix = "state_") private ColorState mColorState; - private final Paint mPaint = new Paint(); + private ColorStateList mTint; + private PorterDuffColorFilter mTintFilter; + private boolean mMutated; /** @@ -84,9 +90,17 @@ public class ColorDrawable extends Drawable { @Override public void draw(Canvas canvas) { - if ((mColorState.mUseColor >>> 24) != 0) { + final ColorFilter colorFilter = mPaint.getColorFilter(); + if ((mColorState.mUseColor >>> 24) != 0 || colorFilter != null || mTintFilter != null) { + if (colorFilter == null) { + mPaint.setColorFilter(mTintFilter); + } + mPaint.setColor(mColorState.mUseColor); canvas.drawRect(getBounds(), mPaint); + + // Restore original color filter. + mPaint.setColorFilter(colorFilter); } } @@ -141,16 +155,51 @@ public class ColorDrawable extends Drawable { } /** - * Setting a color filter on a ColorDrawable has no effect. + * Sets the color filter applied to this color. + * <p> + * Only supported on version {@link android.os.Build.VERSION_CODES#L} and + * above. Calling this method has no effect on earlier versions. * - * @param colorFilter Ignore. + * @see android.graphics.drawable.Drawable#setColorFilter(ColorFilter) */ @Override public void setColorFilter(ColorFilter colorFilter) { + mPaint.setColorFilter(colorFilter); + } + + @Override + public void setTint(ColorStateList tint, Mode tintMode) { + final ColorState state = mColorState; + if (state.mTint != tint || state.mTintMode != tintMode) { + state.mTint = tint; + state.mTintMode = tintMode; + + mTintFilter = updateTintFilter(mTintFilter, tint, tintMode); + invalidateSelf(); + } + } + + @Override + protected boolean onStateChange(int[] stateSet) { + final ColorState state = mColorState; + if (state.mTint != null && state.mTintMode != null) { + mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode); + return true; + } + return false; + } + + @Override + public boolean isStateful() { + return mTint != null && mTint.isStateful(); } @Override public int getOpacity() { + if (mTintFilter != null || mPaint.getColorFilter() != null) { + return PixelFormat.TRANSLUCENT; + } + switch (mColorState.mUseColor >>> 24) { case 255: return PixelFormat.OPAQUE; @@ -165,8 +214,7 @@ public class ColorDrawable extends Drawable { throws XmlPullParserException, IOException { super.inflate(r, parser, attrs, theme); - final TypedArray a = obtainAttributes( - r, theme, attrs, R.styleable.ColorDrawable); + final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.ColorDrawable); inflateStateFromTypedArray(a); a.recycle(); } @@ -225,21 +273,25 @@ public class ColorDrawable extends Drawable { } final static class ColorState extends ConstantState { + int[] mThemeAttrs; int mBaseColor; // base color, independent of setAlpha() @ViewDebug.ExportedProperty int mUseColor; // basecolor modulated by setAlpha() int mChangingConfigurations; - int[] mThemeAttrs; + ColorStateList mTint; + Mode mTintMode; ColorState() { // Empty constructor. } ColorState(ColorState state) { + mThemeAttrs = state.mThemeAttrs; mBaseColor = state.mBaseColor; mUseColor = state.mUseColor; mChangingConfigurations = state.mChangingConfigurations; - mThemeAttrs = state.mThemeAttrs; + mTint = state.mTint; + mTintMode = state.mTintMode; } @Override @@ -276,6 +328,6 @@ public class ColorDrawable extends Drawable { mColorState = state; } - // No local properties to initialize. + mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode); } } diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java index 6a7757b..cb88e3d 100644 --- a/graphics/java/android/graphics/drawable/Drawable.java +++ b/graphics/java/android/graphics/drawable/Drawable.java @@ -17,13 +17,6 @@ package android.graphics.drawable; import android.annotation.NonNull; -import android.graphics.Insets; -import android.graphics.Xfermode; -import android.os.Trace; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.Resources.Theme; @@ -31,15 +24,19 @@ import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.ColorFilter; +import android.graphics.Insets; import android.graphics.NinePatch; import android.graphics.Outline; import android.graphics.PixelFormat; import android.graphics.PorterDuff; +import android.graphics.PorterDuff.Mode; import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; import android.graphics.Region; -import android.graphics.PorterDuff.Mode; +import android.graphics.Xfermode; +import android.os.Trace; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.StateSet; @@ -47,6 +44,9 @@ import android.util.TypedValue; import android.util.Xml; import android.view.View; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + import java.io.IOException; import java.io.InputStream; import java.lang.ref.WeakReference; @@ -1226,6 +1226,26 @@ public abstract class Drawable { } /** + * Ensures the tint filter is consistent with the current tint color and + * mode. + */ + PorterDuffColorFilter updateTintFilter(PorterDuffColorFilter tintFilter, ColorStateList tint, + PorterDuff.Mode tintMode) { + if (tint == null || tintMode == null) { + return null; + } + + final int color = tint.getColorForState(getState(), Color.TRANSPARENT); + if (tintFilter == null) { + return new PorterDuffColorFilter(color, tintMode); + } + + tintFilter.setColor(color); + tintFilter.setMode(tintMode); + return tintFilter; + } + + /** * Obtains styled attributes from the theme, if available, or unstyled * resources if the theme is null. */ diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java index 2aef39f..8be6eb7 100644 --- a/graphics/java/android/graphics/drawable/DrawableContainer.java +++ b/graphics/java/android/graphics/drawable/DrawableContainer.java @@ -16,6 +16,7 @@ package android.graphics.drawable; +import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.Resources.Theme; import android.graphics.Canvas; @@ -23,6 +24,7 @@ import android.graphics.ColorFilter; import android.graphics.Insets; import android.graphics.PixelFormat; import android.graphics.Rect; +import android.graphics.PorterDuff.Mode; import android.os.SystemClock; import android.util.LayoutDirection; import android.util.SparseArray; @@ -151,7 +153,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { @Override public void setColorFilter(ColorFilter cf) { - mDrawableContainerState.mHasColorFilter = true; + mDrawableContainerState.mHasColorFilter = (cf != null); if (mDrawableContainerState.mColorFilter != cf) { mDrawableContainerState.mColorFilter = cf; @@ -162,6 +164,20 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { } } + @Override + public void setTint(ColorStateList tint, Mode tintMode) { + mDrawableContainerState.mHasTint = (tint != null && tintMode != null); + + if (mDrawableContainerState.mTint != tint || mDrawableContainerState.mTintMode != tintMode) { + mDrawableContainerState.mTint = tint; + mDrawableContainerState.mTintMode = tintMode; + + if (mCurrDrawable != null) { + mCurrDrawable.mutate().setTint(tint, tintMode); + } + } + } + /** * Change the global fade duration when a new drawable is entering * the scene. @@ -396,6 +412,8 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { } if (mDrawableContainerState.mHasColorFilter) { d.setColorFilter(mDrawableContainerState.mColorFilter); + } else if (mDrawableContainerState.mHasTint) { + d.setTint(mDrawableContainerState.mTint, mDrawableContainerState.mTintMode); } d.setVisible(isVisible(), true); d.setDither(mDrawableContainerState.mDither); @@ -566,6 +584,10 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { ColorFilter mColorFilter; boolean mHasColorFilter; + ColorStateList mTint; + Mode mTintMode; + boolean mHasTint; + DrawableContainerState(DrawableContainerState orig, DrawableContainer owner, Resources res) { mOwner = owner; @@ -588,6 +610,9 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { mAutoMirrored = orig.mAutoMirrored; mColorFilter = orig.mColorFilter; mHasColorFilter = orig.mHasColorFilter; + mTint = orig.mTint; + mTintMode = orig.mTintMode; + mHasTint = orig.mHasTint; // Cloning the following values may require creating futures. mConstantPadding = orig.getConstantPadding(); @@ -741,7 +766,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { final int N = mNumChildren; final Drawable[] drawables = mDrawables; for (int i = 0; i < N; i++) { - final Drawable d = drawables[i]; + final Drawable d = drawables[i]; if (d != null) { if (d.canApplyTheme()) { return true; diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java index 9e0ab86..220e81c 100644 --- a/graphics/java/android/graphics/drawable/InsetDrawable.java +++ b/graphics/java/android/graphics/drawable/InsetDrawable.java @@ -19,10 +19,12 @@ package android.graphics.drawable; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; +import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.Resources.Theme; import android.graphics.*; +import android.graphics.PorterDuff.Mode; import android.util.AttributeSet; import android.util.Log; @@ -44,8 +46,7 @@ import java.io.IOException; * @attr ref android.R.styleable#InsetDrawable_insetTop * @attr ref android.R.styleable#InsetDrawable_insetBottom */ -public class InsetDrawable extends Drawable implements Drawable.Callback -{ +public class InsetDrawable extends Drawable implements Drawable.Callback { // Most of this is copied from ScaleDrawable. private InsetState mInsetState; private final Rect mTmpRect = new Rect(); @@ -62,13 +63,13 @@ public class InsetDrawable extends Drawable implements Drawable.Callback public InsetDrawable(Drawable drawable, int insetLeft, int insetTop, int insetRight, int insetBottom) { this(null, null); - + mInsetState.mDrawable = drawable; mInsetState.mInsetLeft = insetLeft; mInsetState.mInsetTop = insetTop; mInsetState.mInsetRight = insetRight; mInsetState.mInsetBottom = insetBottom; - + if (drawable != null) { drawable.setCallback(this); } @@ -78,7 +79,7 @@ public class InsetDrawable extends Drawable implements Drawable.Callback public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme) throws XmlPullParserException, IOException { int type; - + TypedArray a = r.obtainAttributes(attrs, com.android.internal.R.styleable.InsetDrawable); @@ -168,7 +169,7 @@ public class InsetDrawable extends Drawable implements Drawable.Callback | mInsetState.mChangingConfigurations | mInsetState.mDrawable.getChangingConfigurations(); } - + @Override public boolean getPadding(Rect padding) { boolean pad = mInsetState.mDrawable.getPadding(padding); @@ -178,7 +179,7 @@ public class InsetDrawable extends Drawable implements Drawable.Callback padding.top += mInsetState.mInsetTop; padding.bottom += mInsetState.mInsetBottom; - if (pad || (mInsetState.mInsetLeft | mInsetState.mInsetRight | + if (pad || (mInsetState.mInsetLeft | mInsetState.mInsetRight | mInsetState.mInsetTop | mInsetState.mInsetBottom) != 0) { return true; } else { @@ -217,6 +218,11 @@ public class InsetDrawable extends Drawable implements Drawable.Callback mInsetState.mDrawable.setColorFilter(cf); } + @Override + public void setTint(ColorStateList tint, Mode tintMode) { + mInsetState.mDrawable.setTint(tint, tintMode); + } + /** {@hide} */ @Override public void setLayoutDirection(int layoutDirection) { @@ -227,7 +233,7 @@ public class InsetDrawable extends Drawable implements Drawable.Callback public int getOpacity() { return mInsetState.mDrawable.getOpacity(); } - + @Override public boolean isStateful() { return mInsetState.mDrawable.isStateful(); @@ -239,7 +245,12 @@ public class InsetDrawable extends Drawable implements Drawable.Callback onBoundsChange(getBounds()); return changed; } - + + @Override + protected boolean onLevelChange(int level) { + return mInsetState.mDrawable.setLevel(level); + } + @Override protected void onBoundsChange(Rect bounds) { final Rect r = mTmpRect; @@ -321,12 +332,12 @@ public class InsetDrawable extends Drawable implements Drawable.Callback public Drawable newDrawable() { return new InsetDrawable(this, null); } - + @Override public Drawable newDrawable(Resources res) { return new InsetDrawable(this, res); } - + @Override public int getChangingConfigurations() { return mChangingConfigurations; diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java index 27f0a9d..5cea7c9 100644 --- a/graphics/java/android/graphics/drawable/LayerDrawable.java +++ b/graphics/java/android/graphics/drawable/LayerDrawable.java @@ -16,12 +16,14 @@ package android.graphics.drawable; +import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.Resources.Theme; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.PixelFormat; +import android.graphics.PorterDuff.Mode; import android.graphics.Rect; import android.util.AttributeSet; import android.view.View; @@ -630,6 +632,15 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { } } + @Override + public void setTint(ColorStateList tint, Mode tintMode) { + final ChildDrawable[] array = mLayerState.mChildren; + final int N = mLayerState.mNum; + for (int i = 0; i < N; i++) { + array[i].mDrawable.setTint(tint, tintMode); + } + } + /** * Sets the opacity of this drawable directly, instead of collecting the * states from the layers diff --git a/graphics/java/android/graphics/drawable/MaterialProgressDrawable.java b/graphics/java/android/graphics/drawable/MaterialProgressDrawable.java index 9e56f67..c484094 100644 --- a/graphics/java/android/graphics/drawable/MaterialProgressDrawable.java +++ b/graphics/java/android/graphics/drawable/MaterialProgressDrawable.java @@ -27,8 +27,10 @@ import android.graphics.Canvas; import android.graphics.Color; import android.graphics.ColorFilter; import android.graphics.Paint; +import android.graphics.PorterDuffColorFilter; import android.graphics.Paint.Cap; import android.graphics.Paint.Style; +import android.graphics.PorterDuff.Mode; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.RectF; @@ -67,6 +69,7 @@ class MaterialProgressDrawable extends Drawable implements Animatable { private final Ring mRing; private MaterialProgressState mState; + private PorterDuffColorFilter mTintFilter; /** Canvas rotation in degrees. */ private float mRotation; @@ -106,6 +109,8 @@ class MaterialProgressDrawable extends Drawable implements Animatable { float insets = minEdge / 2.0f - state.mInnerRadius; ring.setInsets(insets); } + + mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode); } @Override @@ -118,15 +123,21 @@ class MaterialProgressDrawable extends Drawable implements Animatable { } @Override - protected boolean onStateChange(int[] state) { - boolean changed = super.onStateChange(state); + protected boolean onStateChange(int[] stateSet) { + boolean changed = super.onStateChange(stateSet); - final int color = mState.mColor.getColorForState(state, Color.TRANSPARENT); + final MaterialProgressState state = mState; + final int color = state.mColor.getColorForState(stateSet, Color.TRANSPARENT); if (color != mRing.getColor()) { mRing.setColor(color); changed = true; } + if (state.mTint != null && state.mTintMode != null) { + mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode); + changed = true; + } + return changed; } @@ -223,11 +234,24 @@ class MaterialProgressDrawable extends Drawable implements Animatable { return mRing.getColorFilter(); } + @Override + public void setTint(ColorStateList tint, Mode tintMode) { + if (mState.mTint != tint || mState.mTintMode != tintMode) { + mState.mTint = tint; + mState.mTintMode = tintMode; + + mTintFilter = updateTintFilter(mTintFilter, tint, tintMode); + invalidateSelf(); + } + } + + @SuppressWarnings("unused") private void setRotation(float rotation) { mRotation = rotation; invalidateSelf(); } + @SuppressWarnings("unused") private float getRotation() { return mRotation; } @@ -331,6 +355,8 @@ class MaterialProgressDrawable extends Drawable implements Animatable { private int mWidth = -1; private int mHeight = -1; private ColorStateList mColor = ColorStateList.valueOf(Color.TRANSPARENT); + private ColorStateList mTint = null; + private Mode mTintMode = null; public MaterialProgressState(MaterialProgressState orig) { if (orig != null) { @@ -340,6 +366,8 @@ class MaterialProgressDrawable extends Drawable implements Animatable { mWidth = orig.mWidth; mHeight = orig.mHeight; mColor = orig.mColor; + mTint = orig.mTint; + mTintMode = orig.mTintMode; } } diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java index fea68ee..36ffddd 100644 --- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java +++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java @@ -327,25 +327,12 @@ public class NinePatchDrawable extends Drawable { @Override public void setTint(ColorStateList tint, PorterDuff.Mode tintMode) { - mNinePatchState.mTint = tint; - mNinePatchState.mTintMode = tintMode; - computeTintFilter(); - invalidateSelf(); - } - - private void computeTintFilter() { final NinePatchState state = mNinePatchState; - if (state.mTint != null && state.mTintMode != null) { - final int color = state.mTint.getColorForState(getState(), 0); - if (mTintFilter != null) { - mTintFilter.setColor(color); - mTintFilter.setMode(state.mTintMode); - } else { - mTintFilter = new PorterDuffColorFilter(color, state.mTintMode); - } - } else { - mTintFilter = null; - } + state.mTint = tint; + state.mTintMode = tintMode; + + mTintFilter = updateTintFilter(mTintFilter, tint, tintMode); + invalidateSelf(); } @Override @@ -549,15 +536,10 @@ public class NinePatchDrawable extends Drawable { @Override protected boolean onStateChange(int[] stateSet) { - final ColorStateList tint = mNinePatchState.mTint; - if (tint != null) { - final int newColor = tint.getColorForState(stateSet, 0); - final int oldColor = mTintFilter.getColor(); - if (oldColor != newColor) { - mTintFilter.setColor(newColor); - invalidateSelf(); - return true; - } + final NinePatchState state = mNinePatchState; + if (state.mTint != null && state.mTintMode != null) { + mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode); + return true; } return false; @@ -689,7 +671,7 @@ public class NinePatchDrawable extends Drawable { mPadding = new Rect(state.mPadding); } - computeTintFilter(); + updateTintFilter(mTintFilter, state.mTint, state.mTintMode); setNinePatch(state.mNinePatch); } } diff --git a/graphics/java/android/graphics/drawable/PaintDrawable.java b/graphics/java/android/graphics/drawable/PaintDrawable.java index c71cda1..a82e7b9 100644 --- a/graphics/java/android/graphics/drawable/PaintDrawable.java +++ b/graphics/java/android/graphics/drawable/PaintDrawable.java @@ -35,7 +35,7 @@ public class PaintDrawable extends ShapeDrawable { public PaintDrawable(int color) { getPaint().setColor(color); } - + /** * Specify radius for the corners of the rectangle. If this is > 0, then the * drawable is drawn in a round-rectangle, rather than a rectangle. @@ -51,7 +51,7 @@ public class PaintDrawable extends ShapeDrawable { } setCornerRadii(radii); } - + /** * Specify radii for each of the 4 corners. For each corner, the array * contains 2 values, [X_radius, Y_radius]. The corners are ordered @@ -78,9 +78,9 @@ public class PaintDrawable extends ShapeDrawable { int radius = a.getDimensionPixelSize( com.android.internal.R.styleable.DrawableCorners_radius, 0); setCornerRadius(radius); - + // now check of they have any per-corner radii - + int topLeftRadius = a.getDimensionPixelSize( com.android.internal.R.styleable.DrawableCorners_topLeftRadius, radius); int topRightRadius = a.getDimensionPixelSize( diff --git a/graphics/java/android/graphics/drawable/PictureDrawable.java b/graphics/java/android/graphics/drawable/PictureDrawable.java index cb2d8f6..6dcda1f 100644 --- a/graphics/java/android/graphics/drawable/PictureDrawable.java +++ b/graphics/java/android/graphics/drawable/PictureDrawable.java @@ -25,7 +25,7 @@ import android.graphics.Rect; /** * Drawable subclass that wraps a Picture, allowing the picture to be used - * whereever a Drawable is supported. + * wherever a Drawable is supported. */ public class PictureDrawable extends Drawable { @@ -40,7 +40,7 @@ public class PictureDrawable extends Drawable { public PictureDrawable(Picture picture) { mPicture = picture; } - + /** * Return the picture associated with the drawable. May be null. * @@ -49,7 +49,7 @@ public class PictureDrawable extends Drawable { public Picture getPicture() { return mPicture; } - + /** * Associate a picture with this drawable. The picture may be null. * @@ -58,7 +58,7 @@ public class PictureDrawable extends Drawable { public void setPicture(Picture picture) { mPicture = picture; } - + @Override public void draw(Canvas canvas) { if (mPicture != null) { @@ -86,16 +86,16 @@ public class PictureDrawable extends Drawable { // not sure, so be safe return PixelFormat.TRANSLUCENT; } - + @Override public void setFilterBitmap(boolean filter) {} - + @Override public void setDither(boolean dither) {} - + @Override public void setColorFilter(ColorFilter colorFilter) {} - + @Override public void setAlpha(int alpha) {} } diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java index 06aeb98..8f8fa98 100644 --- a/graphics/java/android/graphics/drawable/RotateDrawable.java +++ b/graphics/java/android/graphics/drawable/RotateDrawable.java @@ -22,6 +22,8 @@ import org.xmlpull.v1.XmlPullParserException; import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.Rect; +import android.graphics.PorterDuff.Mode; +import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.Resources.Theme; @@ -137,6 +139,11 @@ public class RotateDrawable extends Drawable implements Drawable.Callback { } @Override + public void setTint(ColorStateList tint, Mode tintMode) { + mState.mDrawable.setTint(tint, tintMode); + } + + @Override public int getOpacity() { return mState.mDrawable.getOpacity(); } diff --git a/graphics/java/android/graphics/drawable/ScaleDrawable.java b/graphics/java/android/graphics/drawable/ScaleDrawable.java index f090c11..46c92fe 100644 --- a/graphics/java/android/graphics/drawable/ScaleDrawable.java +++ b/graphics/java/android/graphics/drawable/ScaleDrawable.java @@ -19,10 +19,12 @@ package android.graphics.drawable; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; +import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.Resources.Theme; import android.graphics.*; +import android.graphics.PorterDuff.Mode; import android.view.Gravity; import android.util.AttributeSet; @@ -188,6 +190,11 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback { } @Override + public void setTint(ColorStateList tint, Mode tintMode) { + mScaleState.mDrawable.setTint(tint, tintMode); + } + + @Override public int getOpacity() { return mScaleState.mDrawable.getOpacity(); } diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java index 024f77c..981efb8 100644 --- a/graphics/java/android/graphics/drawable/ShapeDrawable.java +++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java @@ -32,6 +32,7 @@ import android.graphics.drawable.shapes.Shape; import android.content.res.Resources.Theme; import android.util.AttributeSet; +import com.android.internal.R; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -74,7 +75,7 @@ public class ShapeDrawable extends Drawable { * ShapeDrawable constructor. */ public ShapeDrawable() { - this((ShapeState) null); + this(new ShapeState(null), null, null); } /** @@ -83,20 +84,11 @@ public class ShapeDrawable extends Drawable { * @param s the Shape that this ShapeDrawable should be */ public ShapeDrawable(Shape s) { - this((ShapeState) null); + this(new ShapeState(null), null, null); mShapeState.mShape = s; } - private ShapeDrawable(ShapeState state) { - mShapeState = new ShapeState(state); - - if (state != null && state.mTint != null) { - final int color = state.mTint.getColorForState(getState(), 0); - mTintFilter = new PorterDuffColorFilter(color, state.mTintMode); - } - } - /** * Returns the Shape of this ShapeDrawable. */ @@ -408,20 +400,8 @@ public class ShapeDrawable extends Drawable { throws XmlPullParserException, IOException { super.inflate(r, parser, attrs, theme); - TypedArray a = r.obtainAttributes(attrs, com.android.internal.R.styleable.ShapeDrawable); - - int color = mShapeState.mPaint.getColor(); - color = a.getColor(com.android.internal.R.styleable.ShapeDrawable_color, color); - mShapeState.mPaint.setColor(color); - - boolean dither = a.getBoolean(com.android.internal.R.styleable.ShapeDrawable_dither, false); - mShapeState.mPaint.setDither(dither); - - setIntrinsicWidth((int) - a.getDimension(com.android.internal.R.styleable.ShapeDrawable_width, 0f)); - setIntrinsicHeight((int) - a.getDimension(com.android.internal.R.styleable.ShapeDrawable_height, 0f)); - + final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.ShapeDrawable); + updateStateFromTypedArray(a); a.recycle(); int type; @@ -441,6 +421,38 @@ public class ShapeDrawable extends Drawable { } } + @Override + public void applyTheme(Theme t) { + super.applyTheme(t); + + final ShapeState state = mShapeState; + if (state == null || state.mThemeAttrs == null) { + return; + } + + final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.ShapeDrawable); + updateStateFromTypedArray(a); + a.recycle(); + } + + private void updateStateFromTypedArray(TypedArray a) { + final ShapeState state = mShapeState; + final Paint paint = state.mPaint; + + int color = paint.getColor(); + color = a.getColor(R.styleable.ShapeDrawable_color, color); + paint.setColor(color); + + boolean dither = paint.isDither(); + dither = a.getBoolean(R.styleable.ShapeDrawable_dither, dither); + paint.setDither(dither); + + setIntrinsicWidth((int) a.getDimension( + R.styleable.ShapeDrawable_width, state.mIntrinsicWidth)); + setIntrinsicHeight((int) a.getDimension( + R.styleable.ShapeDrawable_height, state.mIntrinsicHeight)); + } + private void updateShape() { if (mShapeState.mShape != null) { final Rect r = getBounds(); @@ -498,6 +510,7 @@ public class ShapeDrawable extends Drawable { * Defines the intrinsic properties of this ShapeDrawable's Shape. */ final static class ShapeState extends ConstantState { + int[] mThemeAttrs; int mChangingConfigurations; Paint mPaint; Shape mShape; @@ -511,6 +524,7 @@ public class ShapeDrawable extends Drawable { ShapeState(ShapeState orig) { if (orig != null) { + mThemeAttrs = orig.mThemeAttrs; mPaint = orig.mPaint; mShape = orig.mShape; mTint = orig.mTint; @@ -526,13 +540,23 @@ public class ShapeDrawable extends Drawable { } @Override + public boolean canApplyTheme() { + return mThemeAttrs != null; + } + + @Override public Drawable newDrawable() { - return new ShapeDrawable(this); + return new ShapeDrawable(this, null, null); } @Override public Drawable newDrawable(Resources res) { - return new ShapeDrawable(this); + return new ShapeDrawable(this, res, null); + } + + @Override + public Drawable newDrawable(Resources res, Theme theme) { + return new ShapeDrawable(this, res, theme); } @Override @@ -541,6 +565,17 @@ public class ShapeDrawable extends Drawable { } } + private ShapeDrawable(ShapeState state, Resources res, Theme theme) { + if (theme != null && state.canApplyTheme()) { + mShapeState = new ShapeState(state); + applyTheme(theme); + } else { + mShapeState = state; + } + + mTintFilter = updateTintFilter(mTintFilter, mShapeState.mTint, mShapeState.mTintMode); + } + /** * Base class defines a factory object that is called each time the drawable * is resized (has a new width or height). Its resize() method returns a diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java index b2fac9b..f359fdd 100644 --- a/graphics/java/android/graphics/drawable/StateListDrawable.java +++ b/graphics/java/android/graphics/drawable/StateListDrawable.java @@ -235,10 +235,10 @@ public class StateListDrawable extends DrawableContainer { public Drawable getStateDrawable(int index) { return mStateListState.getChild(index); } - + /** * Gets the index of the drawable with the provided state set. - * + * * @param stateSet the state set to look up * @return the index of the provided state set, or -1 if not found * @hide pending API council @@ -248,7 +248,7 @@ public class StateListDrawable extends DrawableContainer { public int getStateDrawableIndex(int[] stateSet) { return mStateListState.indexOfStateSet(stateSet); } - + @Override public Drawable mutate() { if (!mMutated && super.mutate() == this) { diff --git a/graphics/java/android/graphics/drawable/TransitionDrawable.java b/graphics/java/android/graphics/drawable/TransitionDrawable.java index 622e90b..4380ca4 100644 --- a/graphics/java/android/graphics/drawable/TransitionDrawable.java +++ b/graphics/java/android/graphics/drawable/TransitionDrawable.java @@ -42,20 +42,20 @@ import android.os.SystemClock; public class TransitionDrawable extends LayerDrawable implements Drawable.Callback { /** - * A transition is about to start. + * A transition is about to start. */ private static final int TRANSITION_STARTING = 0; - + /** * The transition has started and the animation is in progress */ private static final int TRANSITION_RUNNING = 1; - + /** * No transition will be applied */ private static final int TRANSITION_NONE = 2; - + /** * The current state of the transition. One of {@link #TRANSITION_STARTING}, * {@link #TRANSITION_RUNNING} and {@link #TRANSITION_NONE} @@ -101,10 +101,10 @@ public class TransitionDrawable extends LayerDrawable implements Drawable.Callba LayerState createConstantState(LayerState state, Resources res) { return new TransitionState((TransitionState) state, this, res); } - + /** * Begin the second layer on top of the first layer. - * + * * @param durationMillis The length of the transition in milliseconds */ public void startTransition(int durationMillis) { @@ -116,7 +116,7 @@ public class TransitionDrawable extends LayerDrawable implements Drawable.Callba mTransitionState = TRANSITION_STARTING; invalidateSelf(); } - + /** * Show only the first layer. */ @@ -184,7 +184,7 @@ public class TransitionDrawable extends LayerDrawable implements Drawable.Callba } break; } - + final int alpha = mAlpha; final boolean crossFade = mCrossFade; final ChildDrawable[] array = mLayerState.mChildren; @@ -217,7 +217,7 @@ public class TransitionDrawable extends LayerDrawable implements Drawable.Callba d.draw(canvas); d.setAlpha(0xFF); } - + if (!done) { invalidateSelf(); } diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java index c531c22..c3c1bca 100644 --- a/graphics/java/android/graphics/drawable/VectorDrawable.java +++ b/graphics/java/android/graphics/drawable/VectorDrawable.java @@ -14,6 +14,7 @@ package android.graphics.drawable; +import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.Resources.Theme; import android.content.res.TypedArray; @@ -25,8 +26,10 @@ import android.graphics.Paint; import android.graphics.Path; import android.graphics.PathMeasure; import android.graphics.PixelFormat; +import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; import android.graphics.Region; +import android.graphics.PorterDuff.Mode; import android.util.ArrayMap; import android.util.AttributeSet; import android.util.Log; @@ -137,6 +140,8 @@ public class VectorDrawable extends Drawable { private final ArrayMap<String, Object> mVGTargetsMap = new ArrayMap<String, Object>(); + private PorterDuffColorFilter mTintFilter; + public VectorDrawable() { mVectorState = new VectorDrawableState(null); } @@ -147,6 +152,9 @@ public class VectorDrawable extends Drawable { if (theme != null && canApplyTheme()) { applyTheme(theme); } + + mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode); + mVectorState.mVPathRenderer.setColorFilter(mTintFilter); } Object getTargetByName(String name) { @@ -182,11 +190,46 @@ public class VectorDrawable extends Drawable { @Override public void setColorFilter(ColorFilter colorFilter) { - mVectorState.mVPathRenderer.setColorFilter(colorFilter); + final VectorDrawableState state = mVectorState; + if (colorFilter != null) { + // Color filter overrides tint. + mTintFilter = null; + } else if (state.mTint != null && state.mTintMode != null) { + // Restore the tint filter, if we need one. + final int color = state.mTint.getColorForState(getState(), Color.TRANSPARENT); + mTintFilter = new PorterDuffColorFilter(color, state.mTintMode); + colorFilter = mTintFilter; + } + + state.mVPathRenderer.setColorFilter(colorFilter); invalidateSelf(); } @Override + public void setTint(ColorStateList tint, Mode tintMode) { + final VectorDrawableState state = mVectorState; + if (state.mTint != tint || state.mTintMode != tintMode) { + state.mTint = tint; + state.mTintMode = tintMode; + + mTintFilter = updateTintFilter(mTintFilter, tint, tintMode); + mVectorState.mVPathRenderer.setColorFilter(mTintFilter); + invalidateSelf(); + } + } + + @Override + protected boolean onStateChange(int[] stateSet) { + final VectorDrawableState state = mVectorState; + if (state.mTint != null && state.mTintMode != null) { + mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode); + mVectorState.mVPathRenderer.setColorFilter(mTintFilter); + return true; + } + return false; + } + + @Override public int getOpacity() { return PixelFormat.TRANSLUCENT; } @@ -397,6 +440,8 @@ public class VectorDrawable extends Drawable { int mChangingConfigurations; VPathRenderer mVPathRenderer; Rect mPadding; + ColorStateList mTint; + Mode mTintMode; public VectorDrawableState(VectorDrawableState copy) { if (copy != null) { @@ -404,6 +449,8 @@ public class VectorDrawable extends Drawable { // TODO: Make sure the constant state are handled correctly. mVPathRenderer = new VPathRenderer(copy.mVPathRenderer); mPadding = new Rect(copy.mPadding); + mTint = copy.mTint; + mTintMode = copy.mTintMode; } } diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp index 60b4b96..1001cae 100644 --- a/libs/hwui/TextureCache.cpp +++ b/libs/hwui/TextureCache.cpp @@ -288,19 +288,19 @@ void TextureCache::generateTexture(const SkBitmap* bitmap, Texture* texture, boo switch (bitmap->config()) { case SkBitmap::kA8_Config: glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - uploadToTexture(resize, GL_ALPHA, bitmap->rowBytesAsPixels(), + uploadToTexture(resize, GL_ALPHA, bitmap->rowBytesAsPixels(), bitmap->bytesPerPixel(), texture->width, texture->height, GL_UNSIGNED_BYTE, bitmap->getPixels()); texture->blend = true; break; case SkBitmap::kRGB_565_Config: glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel()); - uploadToTexture(resize, GL_RGB, bitmap->rowBytesAsPixels(), + uploadToTexture(resize, GL_RGB, bitmap->rowBytesAsPixels(), bitmap->bytesPerPixel(), texture->width, texture->height, GL_UNSIGNED_SHORT_5_6_5, bitmap->getPixels()); texture->blend = false; break; case SkBitmap::kARGB_8888_Config: glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel()); - uploadToTexture(resize, GL_RGBA, bitmap->rowBytesAsPixels(), + uploadToTexture(resize, GL_RGBA, bitmap->rowBytesAsPixels(), bitmap->bytesPerPixel(), texture->width, texture->height, GL_UNSIGNED_BYTE, bitmap->getPixels()); // Do this after calling getPixels() to make sure Skia's deferred // decoding happened @@ -340,27 +340,49 @@ void TextureCache::uploadLoFiTexture(bool resize, const SkBitmap* bitmap, SkCanvas canvas(rgbaBitmap); canvas.drawBitmap(*bitmap, 0.0f, 0.0f, NULL); - uploadToTexture(resize, GL_RGBA, rgbaBitmap.rowBytesAsPixels(), width, height, - GL_UNSIGNED_BYTE, rgbaBitmap.getPixels()); + uploadToTexture(resize, GL_RGBA, rgbaBitmap.rowBytesAsPixels(), rgbaBitmap.bytesPerPixel(), + width, height, GL_UNSIGNED_BYTE, rgbaBitmap.getPixels()); } -void TextureCache::uploadToTexture(bool resize, GLenum format, GLsizei stride, +void TextureCache::uploadToTexture(bool resize, GLenum format, GLsizei stride, GLsizei bpp, GLsizei width, GLsizei height, GLenum type, const GLvoid * data) { - // TODO: With OpenGL ES 2.0 we need to copy the bitmap in a temporary buffer - // if the stride doesn't match the width const bool useStride = stride != width && Extensions::getInstance().hasUnpackRowLength(); - if (useStride) { - glPixelStorei(GL_UNPACK_ROW_LENGTH, stride); - } + if ((stride == width) || useStride) { + if (useStride) { + glPixelStorei(GL_UNPACK_ROW_LENGTH, stride); + } - if (resize) { - glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, data); + if (resize) { + glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, data); + } else { + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, data); + } + + if (useStride) { + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + } } else { - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, data); - } + // With OpenGL ES 2.0 we need to copy the bitmap in a temporary buffer + // if the stride doesn't match the width + + GLvoid * temp = (GLvoid *) malloc(width * height * bpp); + if (!temp) return; + + uint8_t * pDst = (uint8_t *)temp; + uint8_t * pSrc = (uint8_t *)data; + for (GLsizei i = 0; i < height; i++) { + memcpy(pDst, pSrc, width * bpp); + pDst += width * bpp; + pSrc += stride * bpp; + } + + if (resize) { + glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, temp); + } else { + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, temp); + } - if (useStride) { - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + free(temp); } } diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h index e5b5c1a..61db5b0 100644 --- a/libs/hwui/TextureCache.h +++ b/libs/hwui/TextureCache.h @@ -142,7 +142,7 @@ private: void generateTexture(const SkBitmap* bitmap, Texture* texture, bool regenerate = false); void uploadLoFiTexture(bool resize, const SkBitmap* bitmap, uint32_t width, uint32_t height); - void uploadToTexture(bool resize, GLenum format, GLsizei stride, + void uploadToTexture(bool resize, GLenum format, GLsizei stride, GLsizei bpp, GLsizei width, GLsizei height, GLenum type, const GLvoid * data); void init(); diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 6280fde..2f1e11e 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -50,12 +50,6 @@ import java.util.ArrayList; */ public class AudioManager { - // If we should use the new sessions APIs. - private final static boolean USE_SESSIONS = true; - // If we should use the legacy APIs. If both are true information will be - // duplicated through both paths. Currently this flag isn't used. - private final static boolean USE_LEGACY = true; - private final Context mContext; private long mVolumeKeyUpTime; private final boolean mUseMasterVolume; @@ -483,17 +477,8 @@ public class AudioManager { * or {@link KeyEvent#KEYCODE_MEDIA_AUDIO_TRACK}. */ public void dispatchMediaKeyEvent(KeyEvent keyEvent) { - if (USE_SESSIONS) { - MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext); - helper.sendMediaButtonEvent(keyEvent, false); - } else { - IAudioService service = getService(); - try { - service.dispatchMediaKeyEvent(keyEvent); - } catch (RemoteException e) { - Log.e(TAG, "dispatchMediaKeyEvent threw exception ", e); - } - } + MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext); + helper.sendMediaButtonEvent(keyEvent, false); } /** @@ -644,12 +629,8 @@ public class AudioManager { if (mUseMasterVolume) { service.adjustMasterVolume(direction, flags, mContext.getOpPackageName()); } else { - if (USE_SESSIONS) { - MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext); - helper.sendAdjustVolumeBy(USE_DEFAULT_STREAM_TYPE, direction, flags); - } else { - service.adjustVolume(direction, flags, mContext.getOpPackageName()); - } + MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext); + helper.sendAdjustVolumeBy(USE_DEFAULT_STREAM_TYPE, direction, flags); } } catch (RemoteException e) { Log.e(TAG, "Dead object in adjustVolume", e); @@ -679,13 +660,8 @@ public class AudioManager { if (mUseMasterVolume) { service.adjustMasterVolume(direction, flags, mContext.getOpPackageName()); } else { - if (USE_SESSIONS) { - MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext); - helper.sendAdjustVolumeBy(suggestedStreamType, direction, flags); - } else { - service.adjustSuggestedStreamVolume(direction, suggestedStreamType, flags, - mContext.getOpPackageName()); - } + MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext); + helper.sendAdjustVolumeBy(suggestedStreamType, direction, flags); } } catch (RemoteException e) { Log.e(TAG, "Dead object in adjustSuggestedStreamVolume", e); @@ -1425,7 +1401,12 @@ public class AudioManager { * <var>false</var> to turn mute off */ public void setMicrophoneMute(boolean on){ - AudioSystem.muteMicrophone(on); + IAudioService service = getService(); + try { + service.setMicrophoneMute(on, mContext.getOpPackageName()); + } catch (RemoteException e) { + Log.e(TAG, "Dead object in setMicrophoneMute", e); + } } /** @@ -2210,16 +2191,15 @@ public class AudioManager { } IAudioService service = getService(); try { - // pi != null + // pi != null, this is currently still needed to support across + // reboot launching of the last app. service.registerMediaButtonIntent(pi, eventReceiver, eventReceiver == null ? mToken : null); } catch (RemoteException e) { Log.e(TAG, "Dead object in registerMediaButtonIntent"+e); } - if (USE_SESSIONS) { - MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext); - helper.addMediaButtonListener(pi, mContext); - } + MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext); + helper.addMediaButtonListener(pi, mContext); } /** @@ -2293,10 +2273,8 @@ public class AudioManager { } catch (RemoteException e) { Log.e(TAG, "Dead object in unregisterMediaButtonIntent"+e); } - if (USE_SESSIONS) { - MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext); - helper.removeMediaButtonListener(pi); - } + MediaSessionLegacyHelper helper = MediaSessionLegacyHelper.getHelper(mContext); + helper.removeMediaButtonListener(pi); } /** @@ -2310,20 +2288,7 @@ public class AudioManager { if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) { return; } - IAudioService service = getService(); - try { - int rcseId = service.registerRemoteControlClient( - rcClient.getRcMediaIntent(), /* mediaIntent */ - rcClient.getIRemoteControlClient(),/* rcClient */ - // used to match media button event receiver and audio focus - mContext.getPackageName()); /* packageName */ - rcClient.setRcseId(rcseId); - } catch (RemoteException e) { - Log.e(TAG, "Dead object in registerRemoteControlClient"+e); - } - if (USE_SESSIONS) { - rcClient.registerWithSession(MediaSessionLegacyHelper.getHelper(mContext)); - } + rcClient.registerWithSession(MediaSessionLegacyHelper.getHelper(mContext)); } /** @@ -2336,16 +2301,7 @@ public class AudioManager { if ((rcClient == null) || (rcClient.getRcMediaIntent() == null)) { return; } - IAudioService service = getService(); - try { - service.unregisterRemoteControlClient(rcClient.getRcMediaIntent(), /* mediaIntent */ - rcClient.getIRemoteControlClient()); /* rcClient */ - } catch (RemoteException e) { - Log.e(TAG, "Dead object in unregisterRemoteControlClient"+e); - } - if (USE_SESSIONS) { - rcClient.unregisterWithSession(MediaSessionLegacyHelper.getHelper(mContext)); - } + rcClient.unregisterWithSession(MediaSessionLegacyHelper.getHelper(mContext)); } /** @@ -2363,25 +2319,8 @@ public class AudioManager { if (rctlr == null) { return false; } - if (USE_SESSIONS) { - rctlr.startListeningToSessions(); - return true; - } else { - IAudioService service = getService(); - final RemoteController.OnClientUpdateListener l = rctlr.getUpdateListener(); - final ComponentName listenerComponent = new ComponentName(mContext, l.getClass()); - try { - int[] artworkDimensions = rctlr.getArtworkSize(); - boolean reg = service.registerRemoteController(rctlr.getRcDisplay(), - artworkDimensions[0]/* w */, artworkDimensions[1]/* h */, - listenerComponent); - rctlr.setIsRegistered(reg); - return reg; - } catch (RemoteException e) { - Log.e(TAG, "Dead object in registerRemoteController " + e); - return false; - } - } + rctlr.startListeningToSessions(); + return true; } /** @@ -2393,17 +2332,7 @@ public class AudioManager { if (rctlr == null) { return; } - if (USE_SESSIONS) { - rctlr.stopListeningToSessions(); - } else { - IAudioService service = getService(); - try { - service.unregisterRemoteControlDisplay(rctlr.getRcDisplay()); - rctlr.setIsRegistered(false); - } catch (RemoteException e) { - Log.e(TAG, "Dead object in unregisterRemoteControlDisplay " + e); - } - } + rctlr.stopListeningToSessions(); } /** diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index 2f782cc..72f4a58 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -108,8 +108,7 @@ public class AudioService extends IAudioService.Stub { /** Debug volumes */ protected static final boolean DEBUG_VOL = false; - /** Reroute calls to media session apis */ - private static final boolean USE_SESSIONS = true; + /** debug calls to media session apis */ private static final boolean DEBUG_SESSIONS = true; /** Allow volume changes to set ringer mode to silent? */ @@ -1437,6 +1436,16 @@ public class AudioService extends IAudioService.Stub { } } + /** @see AudioManager#setMicrophoneMute(boolean) */ + public void setMicrophoneMute(boolean on, String callingPackage) { + if (mAppOps.noteOp(AppOpsManager.OP_MUTE_MICROPHONE, Binder.getCallingUid(), + callingPackage) != AppOpsManager.MODE_ALLOWED) { + return; + } + + AudioSystem.muteMicrophone(on); + } + /** @see AudioManager#getRingerMode() */ public int getRingerMode() { synchronized(mSettingsLock) { @@ -4474,27 +4483,19 @@ public class AudioService extends IAudioService.Stub { } public void dispatchMediaKeyEvent(KeyEvent keyEvent) { - if (USE_SESSIONS) { - if (DEBUG_SESSIONS) { - int pid = getCallingPid(); - Log.w(TAG, "Call to dispatchMediaKeyEvent from " + pid); - } - MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(keyEvent, false); - } else { - mMediaFocusControl.dispatchMediaKeyEvent(keyEvent); + if (DEBUG_SESSIONS) { + int pid = getCallingPid(); + Log.w(TAG, "Call to dispatchMediaKeyEvent from " + pid); } + MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(keyEvent, false); } public void dispatchMediaKeyEventUnderWakelock(KeyEvent keyEvent) { - if (USE_SESSIONS) { - if (DEBUG_SESSIONS) { - int pid = getCallingPid(); - Log.w(TAG, "Call to dispatchMediaKeyEventUnderWakelock from " + pid); - } - MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(keyEvent, true); - } else { - mMediaFocusControl.dispatchMediaKeyEventUnderWakelock(keyEvent); + if (DEBUG_SESSIONS) { + int pid = getCallingPid(); + Log.w(TAG, "Call to dispatchMediaKeyEventUnderWakelock from " + pid); } + MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(keyEvent, true); } //========================================================================================== diff --git a/media/java/android/media/ClosedCaptionRenderer.java b/media/java/android/media/ClosedCaptionRenderer.java new file mode 100644 index 0000000..ec33c5c --- /dev/null +++ b/media/java/android/media/ClosedCaptionRenderer.java @@ -0,0 +1,1464 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.Typeface; +import android.os.Parcel; +import android.text.ParcelableSpan; +import android.text.Spannable; +import android.text.SpannableStringBuilder; +import android.text.TextPaint; +import android.text.TextUtils; +import android.text.style.CharacterStyle; +import android.text.style.StyleSpan; +import android.text.style.UnderlineSpan; +import android.text.style.UpdateAppearance; +import android.util.AttributeSet; +import android.util.Log; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.view.accessibility.CaptioningManager; +import android.view.accessibility.CaptioningManager.CaptionStyle; +import android.view.accessibility.CaptioningManager.CaptioningChangeListener; +import android.widget.LinearLayout; +import android.widget.TextView; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Vector; + +/** @hide */ +public class ClosedCaptionRenderer extends SubtitleController.Renderer { + private final Context mContext; + private ClosedCaptionWidget mRenderingWidget; + + public ClosedCaptionRenderer(Context context) { + mContext = context; + } + + @Override + public boolean supports(MediaFormat format) { + if (format.containsKey(MediaFormat.KEY_MIME)) { + return format.getString(MediaFormat.KEY_MIME).equals( + MediaPlayer.MEDIA_MIMETYPE_TEXT_CEA_608); + } + return false; + } + + @Override + public SubtitleTrack createTrack(MediaFormat format) { + if (mRenderingWidget == null) { + mRenderingWidget = new ClosedCaptionWidget(mContext); + } + return new ClosedCaptionTrack(mRenderingWidget, format); + } +} + +/** @hide */ +class ClosedCaptionTrack extends SubtitleTrack { + private final ClosedCaptionWidget mRenderingWidget; + private final CCParser mCCParser; + + ClosedCaptionTrack(ClosedCaptionWidget renderingWidget, MediaFormat format) { + super(format); + + mRenderingWidget = renderingWidget; + mCCParser = new CCParser(renderingWidget); + } + + @Override + public void onData(byte[] data, boolean eos, long runID) { + mCCParser.parse(data); + } + + @Override + public RenderingWidget getRenderingWidget() { + return mRenderingWidget; + } + + @Override + public void updateView(Vector<Cue> activeCues) { + // Overriding with NO-OP, CC rendering by-passes this + } +} + +/** + * @hide + * + * CCParser processes CEA-608 closed caption data. + * + * It calls back into OnDisplayChangedListener upon + * display change with styled text for rendering. + * + */ +class CCParser { + public static final int MAX_ROWS = 15; + public static final int MAX_COLS = 32; + + private static final String TAG = "CCParser"; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + + private static final int INVALID = -1; + + // EIA-CEA-608: Table 70 - Control Codes + private static final int RCL = 0x20; + private static final int BS = 0x21; + private static final int AOF = 0x22; + private static final int AON = 0x23; + private static final int DER = 0x24; + private static final int RU2 = 0x25; + private static final int RU3 = 0x26; + private static final int RU4 = 0x27; + private static final int FON = 0x28; + private static final int RDC = 0x29; + private static final int TR = 0x2a; + private static final int RTD = 0x2b; + private static final int EDM = 0x2c; + private static final int CR = 0x2d; + private static final int ENM = 0x2e; + private static final int EOC = 0x2f; + + // Transparent Space + private static final char TS = '\u00A0'; + + // Captioning Modes + private static final int MODE_UNKNOWN = 0; + private static final int MODE_PAINT_ON = 1; + private static final int MODE_ROLL_UP = 2; + private static final int MODE_POP_ON = 3; + private static final int MODE_TEXT = 4; + + private final DisplayListener mListener; + + private int mMode = MODE_PAINT_ON; + private int mRollUpSize = 4; + + private CCMemory mDisplay = new CCMemory(); + private CCMemory mNonDisplay = new CCMemory(); + private CCMemory mTextMem = new CCMemory(); + + CCParser(DisplayListener listener) { + mListener = listener; + } + + void parse(byte[] data) { + CCData[] ccData = CCData.fromByteArray(data); + + for (int i = 0; i < ccData.length; i++) { + if (DEBUG) { + Log.d(TAG, ccData[i].toString()); + } + + if (handleCtrlCode(ccData[i]) + || handleTabOffsets(ccData[i]) + || handlePACCode(ccData[i]) + || handleMidRowCode(ccData[i])) { + continue; + } + + handleDisplayableChars(ccData[i]); + } + } + + interface DisplayListener { + public void onDisplayChanged(SpannableStringBuilder[] styledTexts); + public CaptionStyle getCaptionStyle(); + } + + private CCMemory getMemory() { + // get the CC memory to operate on for current mode + switch (mMode) { + case MODE_POP_ON: + return mNonDisplay; + case MODE_TEXT: + // TODO(chz): support only caption mode for now, + // in text mode, dump everything to text mem. + return mTextMem; + case MODE_PAINT_ON: + case MODE_ROLL_UP: + return mDisplay; + default: + Log.w(TAG, "unrecoginized mode: " + mMode); + } + return mDisplay; + } + + private boolean handleDisplayableChars(CCData ccData) { + if (!ccData.isDisplayableChar()) { + return false; + } + + // Extended char includes 1 automatic backspace + if (ccData.isExtendedChar()) { + getMemory().bs(); + } + + getMemory().writeText(ccData.getDisplayText()); + + if (mMode == MODE_PAINT_ON || mMode == MODE_ROLL_UP) { + updateDisplay(); + } + + return true; + } + + private boolean handleMidRowCode(CCData ccData) { + StyleCode m = ccData.getMidRow(); + if (m != null) { + getMemory().writeMidRowCode(m); + return true; + } + return false; + } + + private boolean handlePACCode(CCData ccData) { + PAC pac = ccData.getPAC(); + + if (pac != null) { + if (mMode == MODE_ROLL_UP) { + getMemory().moveBaselineTo(pac.getRow(), mRollUpSize); + } + getMemory().writePAC(pac); + return true; + } + + return false; + } + + private boolean handleTabOffsets(CCData ccData) { + int tabs = ccData.getTabOffset(); + + if (tabs > 0) { + getMemory().tab(tabs); + return true; + } + + return false; + } + + private boolean handleCtrlCode(CCData ccData) { + int ctrlCode = ccData.getCtrlCode(); + switch(ctrlCode) { + case RCL: + // select pop-on style + mMode = MODE_POP_ON; + break; + case BS: + getMemory().bs(); + break; + case DER: + getMemory().der(); + break; + case RU2: + case RU3: + case RU4: + mRollUpSize = (ctrlCode - 0x23); + // erase memory if currently in other style + if (mMode != MODE_ROLL_UP) { + mDisplay.erase(); + mNonDisplay.erase(); + } + // select roll-up style + mMode = MODE_ROLL_UP; + break; + case FON: + Log.i(TAG, "Flash On"); + break; + case RDC: + // select paint-on style + mMode = MODE_PAINT_ON; + break; + case TR: + mMode = MODE_TEXT; + mTextMem.erase(); + break; + case RTD: + mMode = MODE_TEXT; + break; + case EDM: + // erase display memory + mDisplay.erase(); + updateDisplay(); + break; + case CR: + if (mMode == MODE_ROLL_UP) { + getMemory().rollUp(mRollUpSize); + } else { + getMemory().cr(); + } + if (mMode == MODE_ROLL_UP) { + updateDisplay(); + } + break; + case ENM: + // erase non-display memory + mNonDisplay.erase(); + break; + case EOC: + // swap display/non-display memory + swapMemory(); + // switch to pop-on style + mMode = MODE_POP_ON; + updateDisplay(); + break; + case INVALID: + default: + // not handled + return false; + } + + // handled + return true; + } + + private void updateDisplay() { + if (mListener != null) { + CaptionStyle captionStyle = mListener.getCaptionStyle(); + mListener.onDisplayChanged(mDisplay.getStyledText(captionStyle)); + } + } + + private void swapMemory() { + CCMemory temp = mDisplay; + mDisplay = mNonDisplay; + mNonDisplay = temp; + } + + private static class StyleCode { + static final int COLOR_WHITE = 0; + static final int COLOR_GREEN = 1; + static final int COLOR_BLUE = 2; + static final int COLOR_CYAN = 3; + static final int COLOR_RED = 4; + static final int COLOR_YELLOW = 5; + static final int COLOR_MAGENTA = 6; + static final int COLOR_INVALID = 7; + + static final int STYLE_ITALICS = 0x00000001; + static final int STYLE_UNDERLINE = 0x00000002; + + static final String[] mColorMap = { + "WHITE", "GREEN", "BLUE", "CYAN", "RED", "YELLOW", "MAGENTA", "INVALID" + }; + + final int mStyle; + final int mColor; + + static StyleCode fromByte(byte data2) { + int style = 0; + int color = (data2 >> 1) & 0x7; + + if ((data2 & 0x1) != 0) { + style |= STYLE_UNDERLINE; + } + + if (color == COLOR_INVALID) { + // WHITE ITALICS + color = COLOR_WHITE; + style |= STYLE_ITALICS; + } + + return new StyleCode(style, color); + } + + StyleCode(int style, int color) { + mStyle = style; + mColor = color; + } + + boolean isItalics() { + return (mStyle & STYLE_ITALICS) != 0; + } + + boolean isUnderline() { + return (mStyle & STYLE_UNDERLINE) != 0; + } + + int getColor() { + return mColor; + } + + @Override + public String toString() { + StringBuilder str = new StringBuilder(); + str.append("{"); + str.append(mColorMap[mColor]); + if ((mStyle & STYLE_ITALICS) != 0) { + str.append(", ITALICS"); + } + if ((mStyle & STYLE_UNDERLINE) != 0) { + str.append(", UNDERLINE"); + } + str.append("}"); + + return str.toString(); + } + } + + private static class PAC extends StyleCode { + final int mRow; + final int mCol; + + static PAC fromBytes(byte data1, byte data2) { + int[] rowTable = {11, 1, 3, 12, 14, 5, 7, 9}; + int row = rowTable[data1 & 0x07] + ((data2 & 0x20) >> 5); + int style = 0; + if ((data2 & 1) != 0) { + style |= STYLE_UNDERLINE; + } + if ((data2 & 0x10) != 0) { + // indent code + int indent = (data2 >> 1) & 0x7; + return new PAC(row, indent * 4, style, COLOR_WHITE); + } else { + // style code + int color = (data2 >> 1) & 0x7; + + if (color == COLOR_INVALID) { + // WHITE ITALICS + color = COLOR_WHITE; + style |= STYLE_ITALICS; + } + return new PAC(row, -1, style, color); + } + } + + PAC(int row, int col, int style, int color) { + super(style, color); + mRow = row; + mCol = col; + } + + boolean isIndentPAC() { + return (mCol >= 0); + } + + int getRow() { + return mRow; + } + + int getCol() { + return mCol; + } + + @Override + public String toString() { + return String.format("{%d, %d}, %s", + mRow, mCol, super.toString()); + } + } + + /* CCLineBuilder keeps track of displayable chars, as well as + * MidRow styles and PACs, for a single line of CC memory. + * + * It generates styled text via getStyledText() method. + */ + private static class CCLineBuilder { + private final StringBuilder mDisplayChars; + private final StyleCode[] mMidRowStyles; + private final StyleCode[] mPACStyles; + + CCLineBuilder(String str) { + mDisplayChars = new StringBuilder(str); + mMidRowStyles = new StyleCode[mDisplayChars.length()]; + mPACStyles = new StyleCode[mDisplayChars.length()]; + } + + void setCharAt(int index, char ch) { + mDisplayChars.setCharAt(index, ch); + mMidRowStyles[index] = null; + } + + void setMidRowAt(int index, StyleCode m) { + mDisplayChars.setCharAt(index, ' '); + mMidRowStyles[index] = m; + } + + void setPACAt(int index, PAC pac) { + mPACStyles[index] = pac; + } + + char charAt(int index) { + return mDisplayChars.charAt(index); + } + + int length() { + return mDisplayChars.length(); + } + + void applyStyleSpan( + SpannableStringBuilder styledText, + StyleCode s, int start, int end) { + if (s.isItalics()) { + styledText.setSpan( + new StyleSpan(android.graphics.Typeface.ITALIC), + start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + } + if (s.isUnderline()) { + styledText.setSpan( + new UnderlineSpan(), + start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + } + } + + SpannableStringBuilder getStyledText(CaptionStyle captionStyle) { + SpannableStringBuilder styledText = new SpannableStringBuilder(mDisplayChars); + int start = -1, next = 0; + int styleStart = -1; + StyleCode curStyle = null; + while (next < mDisplayChars.length()) { + StyleCode newStyle = null; + if (mMidRowStyles[next] != null) { + // apply mid-row style change + newStyle = mMidRowStyles[next]; + } else if (mPACStyles[next] != null + && (styleStart < 0 || start < 0)) { + // apply PAC style change, only if: + // 1. no style set, or + // 2. style set, but prev char is none-displayable + newStyle = mPACStyles[next]; + } + if (newStyle != null) { + curStyle = newStyle; + if (styleStart >= 0 && start >= 0) { + applyStyleSpan(styledText, newStyle, styleStart, next); + } + styleStart = next; + } + + if (mDisplayChars.charAt(next) != TS) { + if (start < 0) { + start = next; + } + } else if (start >= 0) { + int expandedStart = mDisplayChars.charAt(start) == ' ' ? start : start - 1; + int expandedEnd = mDisplayChars.charAt(next - 1) == ' ' ? next : next + 1; + styledText.setSpan( + new MutableBackgroundColorSpan(captionStyle.backgroundColor), + expandedStart, expandedEnd, + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + if (styleStart >= 0) { + applyStyleSpan(styledText, curStyle, styleStart, expandedEnd); + } + start = -1; + } + next++; + } + + return styledText; + } + } + + /* + * CCMemory models a console-style display. + */ + private static class CCMemory { + private final String mBlankLine; + private final CCLineBuilder[] mLines = new CCLineBuilder[MAX_ROWS + 2]; + private int mRow; + private int mCol; + + CCMemory() { + char[] blank = new char[MAX_COLS + 2]; + Arrays.fill(blank, TS); + mBlankLine = new String(blank); + } + + void erase() { + // erase all lines + for (int i = 0; i < mLines.length; i++) { + mLines[i] = null; + } + mRow = MAX_ROWS; + mCol = 1; + } + + void der() { + if (mLines[mRow] != null) { + for (int i = 0; i < mCol; i++) { + if (mLines[mRow].charAt(i) != TS) { + for (int j = mCol; j < mLines[mRow].length(); j++) { + mLines[j].setCharAt(j, TS); + } + return; + } + } + mLines[mRow] = null; + } + } + + void tab(int tabs) { + moveCursorByCol(tabs); + } + + void bs() { + moveCursorByCol(-1); + if (mLines[mRow] != null) { + mLines[mRow].setCharAt(mCol, TS); + if (mCol == MAX_COLS - 1) { + // Spec recommendation: + // if cursor was at col 32, move cursor + // back to col 31 and erase both col 31&32 + mLines[mRow].setCharAt(MAX_COLS, TS); + } + } + } + + void cr() { + moveCursorTo(mRow + 1, 1); + } + + void rollUp(int windowSize) { + int i; + for (i = 0; i <= mRow - windowSize; i++) { + mLines[i] = null; + } + int startRow = mRow - windowSize + 1; + if (startRow < 1) { + startRow = 1; + } + for (i = startRow; i < mRow; i++) { + mLines[i] = mLines[i + 1]; + } + for (i = mRow; i < mLines.length; i++) { + // clear base row + mLines[i] = null; + } + // default to col 1, in case PAC is not sent + mCol = 1; + } + + void writeText(String text) { + for (int i = 0; i < text.length(); i++) { + getLineBuffer(mRow).setCharAt(mCol, text.charAt(i)); + moveCursorByCol(1); + } + } + + void writeMidRowCode(StyleCode m) { + getLineBuffer(mRow).setMidRowAt(mCol, m); + moveCursorByCol(1); + } + + void writePAC(PAC pac) { + if (pac.isIndentPAC()) { + moveCursorTo(pac.getRow(), pac.getCol()); + } else { + moveCursorToRow(pac.getRow()); + } + getLineBuffer(mRow).setPACAt(mCol, pac); + } + + SpannableStringBuilder[] getStyledText(CaptionStyle captionStyle) { + ArrayList<SpannableStringBuilder> rows = + new ArrayList<SpannableStringBuilder>(MAX_ROWS); + for (int i = 1; i <= MAX_ROWS; i++) { + rows.add(mLines[i] != null ? + mLines[i].getStyledText(captionStyle) : null); + } + return rows.toArray(new SpannableStringBuilder[MAX_ROWS]); + } + + private static int clamp(int x, int min, int max) { + return x < min ? min : (x > max ? max : x); + } + + private void moveCursorTo(int row, int col) { + mRow = clamp(row, 1, MAX_ROWS); + mCol = clamp(col, 1, MAX_COLS); + } + + private void moveCursorToRow(int row) { + mRow = clamp(row, 1, MAX_ROWS); + } + + private void moveCursorByCol(int col) { + mCol = clamp(mCol + col, 1, MAX_COLS); + } + + private void moveBaselineTo(int baseRow, int windowSize) { + if (mRow == baseRow) { + return; + } + int actualWindowSize = windowSize; + if (baseRow < actualWindowSize) { + actualWindowSize = baseRow; + } + if (mRow < actualWindowSize) { + actualWindowSize = mRow; + } + + int i; + if (baseRow < mRow) { + // copy from bottom to top row + for (i = actualWindowSize - 1; i >= 0; i--) { + mLines[baseRow - i] = mLines[mRow - i]; + } + } else { + // copy from top to bottom row + for (i = 0; i < actualWindowSize; i++) { + mLines[baseRow - i] = mLines[mRow - i]; + } + } + // clear rest of the rows + for (i = 0; i <= baseRow - windowSize; i++) { + mLines[i] = null; + } + for (i = baseRow + 1; i < mLines.length; i++) { + mLines[i] = null; + } + } + + private CCLineBuilder getLineBuffer(int row) { + if (mLines[row] == null) { + mLines[row] = new CCLineBuilder(mBlankLine); + } + return mLines[row]; + } + } + + /* + * CCData parses the raw CC byte pair into displayable chars, + * misc control codes, Mid-Row or Preamble Address Codes. + */ + private static class CCData { + private final byte mType; + private final byte mData1; + private final byte mData2; + + private static final String[] mCtrlCodeMap = { + "RCL", "BS" , "AOF", "AON", + "DER", "RU2", "RU3", "RU4", + "FON", "RDC", "TR" , "RTD", + "EDM", "CR" , "ENM", "EOC", + }; + + private static final String[] mSpecialCharMap = { + "\u00AE", + "\u00B0", + "\u00BD", + "\u00BF", + "\u2122", + "\u00A2", + "\u00A3", + "\u266A", // Eighth note + "\u00E0", + "\u00A0", // Transparent space + "\u00E8", + "\u00E2", + "\u00EA", + "\u00EE", + "\u00F4", + "\u00FB", + }; + + private static final String[] mSpanishCharMap = { + // Spanish and misc chars + "\u00C1", // A + "\u00C9", // E + "\u00D3", // I + "\u00DA", // O + "\u00DC", // U + "\u00FC", // u + "\u2018", // opening single quote + "\u00A1", // inverted exclamation mark + "*", + "'", + "\u2014", // em dash + "\u00A9", // Copyright + "\u2120", // Servicemark + "\u2022", // round bullet + "\u201C", // opening double quote + "\u201D", // closing double quote + // French + "\u00C0", + "\u00C2", + "\u00C7", + "\u00C8", + "\u00CA", + "\u00CB", + "\u00EB", + "\u00CE", + "\u00CF", + "\u00EF", + "\u00D4", + "\u00D9", + "\u00F9", + "\u00DB", + "\u00AB", + "\u00BB" + }; + + private static final String[] mProtugueseCharMap = { + // Portuguese + "\u00C3", + "\u00E3", + "\u00CD", + "\u00CC", + "\u00EC", + "\u00D2", + "\u00F2", + "\u00D5", + "\u00F5", + "{", + "}", + "\\", + "^", + "_", + "|", + "~", + // German and misc chars + "\u00C4", + "\u00E4", + "\u00D6", + "\u00F6", + "\u00DF", + "\u00A5", + "\u00A4", + "\u2502", // vertical bar + "\u00C5", + "\u00E5", + "\u00D8", + "\u00F8", + "\u250C", // top-left corner + "\u2510", // top-right corner + "\u2514", // lower-left corner + "\u2518", // lower-right corner + }; + + static CCData[] fromByteArray(byte[] data) { + CCData[] ccData = new CCData[data.length / 3]; + + for (int i = 0; i < ccData.length; i++) { + ccData[i] = new CCData( + data[i * 3], + data[i * 3 + 1], + data[i * 3 + 2]); + } + + return ccData; + } + + CCData(byte type, byte data1, byte data2) { + mType = type; + mData1 = data1; + mData2 = data2; + } + + int getCtrlCode() { + if ((mData1 == 0x14 || mData1 == 0x1c) + && mData2 >= 0x20 && mData2 <= 0x2f) { + return mData2; + } + return INVALID; + } + + StyleCode getMidRow() { + // only support standard Mid-row codes, ignore + // optional background/foreground mid-row codes + if ((mData1 == 0x11 || mData1 == 0x19) + && mData2 >= 0x20 && mData2 <= 0x2f) { + return StyleCode.fromByte(mData2); + } + return null; + } + + PAC getPAC() { + if ((mData1 & 0x70) == 0x10 + && (mData2 & 0x40) == 0x40 + && ((mData1 & 0x07) != 0 || (mData2 & 0x20) == 0)) { + return PAC.fromBytes(mData1, mData2); + } + return null; + } + + int getTabOffset() { + if ((mData1 == 0x17 || mData1 == 0x1f) + && mData2 >= 0x21 && mData2 <= 0x23) { + return mData2 & 0x3; + } + return 0; + } + + boolean isDisplayableChar() { + return isBasicChar() || isSpecialChar() || isExtendedChar(); + } + + String getDisplayText() { + String str = getBasicChars(); + + if (str == null) { + str = getSpecialChar(); + + if (str == null) { + str = getExtendedChar(); + } + } + + return str; + } + + private String ctrlCodeToString(int ctrlCode) { + return mCtrlCodeMap[ctrlCode - 0x20]; + } + + private boolean isBasicChar() { + return mData1 >= 0x20 && mData1 <= 0x7f; + } + + private boolean isSpecialChar() { + return ((mData1 == 0x11 || mData1 == 0x19) + && mData2 >= 0x30 && mData2 <= 0x3f); + } + + private boolean isExtendedChar() { + return ((mData1 == 0x12 || mData1 == 0x1A + || mData1 == 0x13 || mData1 == 0x1B) + && mData2 >= 0x20 && mData2 <= 0x3f); + } + + private char getBasicChar(byte data) { + char c; + // replace the non-ASCII ones + switch (data) { + case 0x2A: c = '\u00E1'; break; + case 0x5C: c = '\u00E9'; break; + case 0x5E: c = '\u00ED'; break; + case 0x5F: c = '\u00F3'; break; + case 0x60: c = '\u00FA'; break; + case 0x7B: c = '\u00E7'; break; + case 0x7C: c = '\u00F7'; break; + case 0x7D: c = '\u00D1'; break; + case 0x7E: c = '\u00F1'; break; + case 0x7F: c = '\u2588'; break; // Full block + default: c = (char) data; break; + } + return c; + } + + private String getBasicChars() { + if (mData1 >= 0x20 && mData1 <= 0x7f) { + StringBuilder builder = new StringBuilder(2); + builder.append(getBasicChar(mData1)); + if (mData2 >= 0x20 && mData2 <= 0x7f) { + builder.append(getBasicChar(mData2)); + } + return builder.toString(); + } + + return null; + } + + private String getSpecialChar() { + if ((mData1 == 0x11 || mData1 == 0x19) + && mData2 >= 0x30 && mData2 <= 0x3f) { + return mSpecialCharMap[mData2 - 0x30]; + } + + return null; + } + + private String getExtendedChar() { + if ((mData1 == 0x12 || mData1 == 0x1A) + && mData2 >= 0x20 && mData2 <= 0x3f){ + // 1 Spanish/French char + return mSpanishCharMap[mData2 - 0x20]; + } else if ((mData1 == 0x13 || mData1 == 0x1B) + && mData2 >= 0x20 && mData2 <= 0x3f){ + // 1 Portuguese/German/Danish char + return mProtugueseCharMap[mData2 - 0x20]; + } + + return null; + } + + @Override + public String toString() { + String str; + + if (mData1 < 0x10 && mData2 < 0x10) { + // Null Pad, ignore + return String.format("[%d]Null: %02x %02x", mType, mData1, mData2); + } + + int ctrlCode = getCtrlCode(); + if (ctrlCode != INVALID) { + return String.format("[%d]%s", mType, ctrlCodeToString(ctrlCode)); + } + + int tabOffset = getTabOffset(); + if (tabOffset > 0) { + return String.format("[%d]Tab%d", mType, tabOffset); + } + + PAC pac = getPAC(); + if (pac != null) { + return String.format("[%d]PAC: %s", mType, pac.toString()); + } + + StyleCode m = getMidRow(); + if (m != null) { + return String.format("[%d]Mid-row: %s", mType, m.toString()); + } + + if (isDisplayableChar()) { + return String.format("[%d]Displayable: %s (%02x %02x)", + mType, getDisplayText(), mData1, mData2); + } + + return String.format("[%d]Invalid: %02x %02x", mType, mData1, mData2); + } + } +} + +/** + * @hide + * + * MutableBackgroundColorSpan + * + * This is a mutable version of BackgroundSpan to facilitate text + * rendering with edge styles. + * + */ +class MutableBackgroundColorSpan extends CharacterStyle + implements UpdateAppearance, ParcelableSpan { + private int mColor; + + public MutableBackgroundColorSpan(int color) { + mColor = color; + } + public MutableBackgroundColorSpan(Parcel src) { + mColor = src.readInt(); + } + public void setBackgroundColor(int color) { + mColor = color; + } + public int getBackgroundColor() { + return mColor; + } + @Override + public int getSpanTypeId() { + return TextUtils.BACKGROUND_COLOR_SPAN; + } + @Override + public int describeContents() { + return 0; + } + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mColor); + } + @Override + public void updateDrawState(TextPaint ds) { + ds.bgColor = mColor; + } +} + +/** + * Widget capable of rendering CEA-608 closed captions. + * + * @hide + */ +class ClosedCaptionWidget extends ViewGroup implements + SubtitleTrack.RenderingWidget, + CCParser.DisplayListener { + private static final String TAG = "ClosedCaptionWidget"; + + private static final Rect mTextBounds = new Rect(); + private static final String mDummyText = "1234567890123456789012345678901234"; + private static final CaptionStyle DEFAULT_CAPTION_STYLE = CaptionStyle.DEFAULT; + + /** Captioning manager, used to obtain and track caption properties. */ + private final CaptioningManager mManager; + + /** Callback for rendering changes. */ + private OnChangedListener mListener; + + /** Current caption style. */ + private CaptionStyle mCaptionStyle; + + /* Closed caption layout. */ + private CCLayout mClosedCaptionLayout; + + /** Whether a caption style change listener is registered. */ + private boolean mHasChangeListener; + + public ClosedCaptionWidget(Context context) { + this(context, null); + } + + public ClosedCaptionWidget(Context context, AttributeSet attrs) { + this(context, null, 0); + } + + public ClosedCaptionWidget(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + // Cannot render text over video when layer type is hardware. + setLayerType(View.LAYER_TYPE_SOFTWARE, null); + + mManager = (CaptioningManager) context.getSystemService(Context.CAPTIONING_SERVICE); + mCaptionStyle = DEFAULT_CAPTION_STYLE.applyStyle(mManager.getUserStyle()); + + mClosedCaptionLayout = new CCLayout(context); + mClosedCaptionLayout.setCaptionStyle(mCaptionStyle); + addView(mClosedCaptionLayout, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); + + requestLayout(); + } + + @Override + public void setOnChangedListener(OnChangedListener listener) { + mListener = listener; + } + + @Override + public void setSize(int width, int height) { + final int widthSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY); + final int heightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); + + measure(widthSpec, heightSpec); + layout(0, 0, width, height); + } + + @Override + public void setVisible(boolean visible) { + if (visible) { + setVisibility(View.VISIBLE); + } else { + setVisibility(View.GONE); + } + + manageChangeListener(); + } + + @Override + public void onAttachedToWindow() { + super.onAttachedToWindow(); + + manageChangeListener(); + } + + @Override + public void onDetachedFromWindow() { + super.onDetachedFromWindow(); + + manageChangeListener(); + } + + @Override + public void onDisplayChanged(SpannableStringBuilder[] styledTexts) { + mClosedCaptionLayout.update(styledTexts); + + if (mListener != null) { + mListener.onChanged(this); + } + } + + @Override + public CaptionStyle getCaptionStyle() { + return mCaptionStyle; + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + mClosedCaptionLayout.measure(widthMeasureSpec, heightMeasureSpec); + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + mClosedCaptionLayout.layout(l, t, r, b); + } + + /** + * Manages whether this renderer is listening for caption style changes. + */ + private final CaptioningChangeListener mCaptioningListener = new CaptioningChangeListener() { + @Override + public void onUserStyleChanged(CaptionStyle userStyle) { + mCaptionStyle = DEFAULT_CAPTION_STYLE.applyStyle(userStyle); + mClosedCaptionLayout.setCaptionStyle(mCaptionStyle); + } + }; + + private void manageChangeListener() { + final boolean needsListener = isAttachedToWindow() && getVisibility() == View.VISIBLE; + if (mHasChangeListener != needsListener) { + mHasChangeListener = needsListener; + + if (needsListener) { + mManager.addCaptioningChangeListener(mCaptioningListener); + } else { + mManager.removeCaptioningChangeListener(mCaptioningListener); + } + } + } + + private static class CCLineBox extends TextView { + private static final float FONT_PADDING_RATIO = 0.75f; + private static final float EDGE_OUTLINE_RATIO = 0.1f; + private static final float EDGE_SHADOW_RATIO = 0.05f; + private float mOutlineWidth; + private float mShadowRadius; + private float mShadowOffset; + + private int mTextColor = Color.WHITE; + private int mBgColor = Color.BLACK; + private int mEdgeType = CaptionStyle.EDGE_TYPE_NONE; + private int mEdgeColor = Color.TRANSPARENT; + + CCLineBox(Context context) { + super(context); + setGravity(Gravity.CENTER); + setBackgroundColor(Color.TRANSPARENT); + setTextColor(Color.WHITE); + setTypeface(Typeface.MONOSPACE); + setVisibility(View.INVISIBLE); + + final Resources res = getContext().getResources(); + + // get the default (will be updated later during measure) + mOutlineWidth = res.getDimensionPixelSize( + com.android.internal.R.dimen.subtitle_outline_width); + mShadowRadius = res.getDimensionPixelSize( + com.android.internal.R.dimen.subtitle_shadow_radius); + mShadowOffset = res.getDimensionPixelSize( + com.android.internal.R.dimen.subtitle_shadow_offset); + } + + void setCaptionStyle(CaptionStyle captionStyle) { + mTextColor = captionStyle.foregroundColor; + mBgColor = captionStyle.backgroundColor; + mEdgeType = captionStyle.edgeType; + mEdgeColor = captionStyle.edgeColor; + + setTextColor(mTextColor); + if (mEdgeType == CaptionStyle.EDGE_TYPE_DROP_SHADOW) { + setShadowLayer(mShadowRadius, mShadowOffset, mShadowOffset, mEdgeColor); + } else { + setShadowLayer(0, 0, 0, 0); + } + invalidate(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + float fontSize = MeasureSpec.getSize(heightMeasureSpec) + * FONT_PADDING_RATIO; + setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize); + + mOutlineWidth = EDGE_OUTLINE_RATIO * fontSize + 1.0f; + mShadowRadius = EDGE_SHADOW_RATIO * fontSize + 1.0f;; + mShadowOffset = mShadowRadius; + + // set font scale in the X direction to match the required width + setScaleX(1.0f); + getPaint().getTextBounds(mDummyText, 0, mDummyText.length(), mTextBounds); + float actualTextWidth = mTextBounds.width(); + float requiredTextWidth = MeasureSpec.getSize(widthMeasureSpec); + setScaleX(requiredTextWidth / actualTextWidth); + + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + + @Override + protected void onDraw(Canvas c) { + if (mEdgeType == CaptionStyle.EDGE_TYPE_UNSPECIFIED + || mEdgeType == CaptionStyle.EDGE_TYPE_NONE + || mEdgeType == CaptionStyle.EDGE_TYPE_DROP_SHADOW) { + // these edge styles don't require a second pass + super.onDraw(c); + return; + } + + if (mEdgeType == CaptionStyle.EDGE_TYPE_OUTLINE) { + drawEdgeOutline(c); + } else { + // Raised or depressed + drawEdgeRaisedOrDepressed(c); + } + } + + private void drawEdgeOutline(Canvas c) { + TextPaint textPaint = getPaint(); + + Paint.Style previousStyle = textPaint.getStyle(); + Paint.Join previousJoin = textPaint.getStrokeJoin(); + float previousWidth = textPaint.getStrokeWidth(); + + setTextColor(mEdgeColor); + textPaint.setStyle(Paint.Style.FILL_AND_STROKE); + textPaint.setStrokeJoin(Paint.Join.ROUND); + textPaint.setStrokeWidth(mOutlineWidth); + + // Draw outline and background only. + super.onDraw(c); + + // Restore original settings. + setTextColor(mTextColor); + textPaint.setStyle(previousStyle); + textPaint.setStrokeJoin(previousJoin); + textPaint.setStrokeWidth(previousWidth); + + // Remove the background. + setBackgroundSpans(Color.TRANSPARENT); + // Draw foreground only. + super.onDraw(c); + // Restore the background. + setBackgroundSpans(mBgColor); + } + + private void drawEdgeRaisedOrDepressed(Canvas c) { + TextPaint textPaint = getPaint(); + + Paint.Style previousStyle = textPaint.getStyle(); + textPaint.setStyle(Paint.Style.FILL); + + final boolean raised = mEdgeType == CaptionStyle.EDGE_TYPE_RAISED; + final int colorUp = raised ? Color.WHITE : mEdgeColor; + final int colorDown = raised ? mEdgeColor : Color.WHITE; + final float offset = mShadowRadius / 2f; + + // Draw background and text with shadow up + setShadowLayer(mShadowRadius, -offset, -offset, colorUp); + super.onDraw(c); + + // Remove the background. + setBackgroundSpans(Color.TRANSPARENT); + + // Draw text with shadow down + setShadowLayer(mShadowRadius, +offset, +offset, colorDown); + super.onDraw(c); + + // Restore settings + textPaint.setStyle(previousStyle); + + // Restore the background. + setBackgroundSpans(mBgColor); + } + + private void setBackgroundSpans(int color) { + CharSequence text = getText(); + if (text instanceof Spannable) { + Spannable spannable = (Spannable) text; + MutableBackgroundColorSpan[] bgSpans = spannable.getSpans( + 0, spannable.length(), MutableBackgroundColorSpan.class); + for (int i = 0; i < bgSpans.length; i++) { + bgSpans[i].setBackgroundColor(color); + } + } + } + } + + private static class CCLayout extends LinearLayout { + private static final int MAX_ROWS = CCParser.MAX_ROWS; + private static final float SAFE_AREA_RATIO = 0.9f; + + private final CCLineBox[] mLineBoxes = new CCLineBox[MAX_ROWS]; + + CCLayout(Context context) { + super(context); + setGravity(Gravity.START); + setOrientation(LinearLayout.VERTICAL); + for (int i = 0; i < MAX_ROWS; i++) { + mLineBoxes[i] = new CCLineBox(getContext()); + addView(mLineBoxes[i], LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); + } + } + + void setCaptionStyle(CaptionStyle captionStyle) { + for (int i = 0; i < MAX_ROWS; i++) { + mLineBoxes[i].setCaptionStyle(captionStyle); + } + } + + void update(SpannableStringBuilder[] textBuffer) { + for (int i = 0; i < MAX_ROWS; i++) { + if (textBuffer[i] != null) { + mLineBoxes[i].setText(textBuffer[i], TextView.BufferType.SPANNABLE); + mLineBoxes[i].setVisibility(View.VISIBLE); + } else { + mLineBoxes[i].setVisibility(View.INVISIBLE); + } + } + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + int safeWidth = getMeasuredWidth(); + int safeHeight = getMeasuredHeight(); + + // CEA-608 assumes 4:3 video + if (safeWidth * 3 >= safeHeight * 4) { + safeWidth = safeHeight * 4 / 3; + } else { + safeHeight = safeWidth * 3 / 4; + } + safeWidth *= SAFE_AREA_RATIO; + safeHeight *= SAFE_AREA_RATIO; + + int lineHeight = safeHeight / MAX_ROWS; + int lineHeightMeasureSpec = MeasureSpec.makeMeasureSpec( + lineHeight, MeasureSpec.EXACTLY); + int lineWidthMeasureSpec = MeasureSpec.makeMeasureSpec( + safeWidth, MeasureSpec.EXACTLY); + + for (int i = 0; i < MAX_ROWS; i++) { + mLineBoxes[i].measure(lineWidthMeasureSpec, lineHeightMeasureSpec); + } + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + // safe caption area + int viewPortWidth = r - l; + int viewPortHeight = b - t; + int safeWidth, safeHeight; + // CEA-608 assumes 4:3 video + if (viewPortWidth * 3 >= viewPortHeight * 4) { + safeWidth = viewPortHeight * 4 / 3; + safeHeight = viewPortHeight; + } else { + safeWidth = viewPortWidth; + safeHeight = viewPortWidth * 3 / 4; + } + safeWidth *= SAFE_AREA_RATIO; + safeHeight *= SAFE_AREA_RATIO; + int left = (viewPortWidth - safeWidth) / 2; + int top = (viewPortHeight - safeHeight) / 2; + + for (int i = 0; i < MAX_ROWS; i++) { + mLineBoxes[i].layout( + left, + top + safeHeight * i / MAX_ROWS, + left + safeWidth, + top + safeHeight * (i + 1) / MAX_ROWS); + } + } + } +}; diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index ba3cfb6..c29e967 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -78,6 +78,8 @@ interface IAudioService { int getLastAudibleMasterVolume(); + void setMicrophoneMute(boolean on, String callingPackage); + void setRingerMode(int ringerMode); int getRingerMode(); diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index 1b92410..e25714a 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -1649,8 +1649,8 @@ public class MediaPlayer implements SubtitleController.Listener mFormat = MediaFormat.createSubtitleFormat( MEDIA_MIMETYPE_TEXT_SUBRIP, language); } else if (mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) { - mFormat = MediaFormat.createSubtitleFormat( - MEDIA_MIMETYPE_TEXT_VTT, language); + String mime = in.readString(); + mFormat = MediaFormat.createSubtitleFormat(mime, language); mFormat.setInteger(MediaFormat.KEY_IS_AUTOSELECT, in.readInt()); mFormat.setInteger(MediaFormat.KEY_IS_DEFAULT, in.readInt()); mFormat.setInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE, in.readInt()); @@ -1683,12 +1683,40 @@ public class MediaPlayer implements SubtitleController.Listener dest.writeString(getLanguage()); if (mTrackType == MEDIA_TRACK_TYPE_SUBTITLE) { + dest.writeString(mFormat.getString(MediaFormat.KEY_MIME)); dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_AUTOSELECT)); dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_DEFAULT)); dest.writeInt(mFormat.getInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE)); } } + @Override + public String toString() { + StringBuilder out = new StringBuilder(128); + out.append(getClass().getName()); + out.append('{'); + switch (mTrackType) { + case MEDIA_TRACK_TYPE_VIDEO: + out.append("VIDEO"); + break; + case MEDIA_TRACK_TYPE_AUDIO: + out.append("AUDIO"); + break; + case MEDIA_TRACK_TYPE_TIMEDTEXT: + out.append("TIMEDTEXT"); + break; + case MEDIA_TRACK_TYPE_SUBTITLE: + out.append("SUBTITLE"); + break; + default: + out.append("UNKNOWN"); + break; + } + out.append(", " + mFormat.toString()); + out.append("}"); + return out.toString(); + } + /** * Used to read a TrackInfo from a Parcel. */ @@ -1757,6 +1785,12 @@ public class MediaPlayer implements SubtitleController.Listener */ public static final String MEDIA_MIMETYPE_TEXT_VTT = "text/vtt"; + /** + * MIME type for CEA-608 closed caption data. + * @hide + */ + public static final String MEDIA_MIMETYPE_TEXT_CEA_608 = "text/cea-608"; + /* * A helper function to check if the mime type is supported by media framework. */ @@ -1792,16 +1826,11 @@ public class MediaPlayer implements SubtitleController.Listener } SubtitleTrack track = mInbandSubtitleTracks[index]; if (track != null) { - try { - long runID = data.getStartTimeUs() + 1; - // TODO: move conversion into track - track.onData(new String(data.getData(), "UTF-8"), true /* eos */, runID); - track.setRunDiscardTimeMs( - runID, - (data.getStartTimeUs() + data.getDurationUs()) / 1000); - } catch (java.io.UnsupportedEncodingException e) { - Log.w(TAG, "subtitle data for track " + index + " is not UTF-8 encoded: " + e); - } + long runID = data.getStartTimeUs() + 1; + track.onData(data.getData(), true /* eos */, runID); + track.setRunDiscardTimeMs( + runID, + (data.getStartTimeUs() + data.getDurationUs()) / 1000); } } }; @@ -1872,7 +1901,7 @@ public class MediaPlayer implements SubtitleController.Listener } scanner.close(); mOutOfBandSubtitleTracks.add(track); - track.onData(contents, true /* eos */, ~0 /* runID: keep forever */); + track.onData(contents.getBytes(), true /* eos */, ~0 /* runID: keep forever */); return MEDIA_INFO_EXTERNAL_METADATA_UPDATE; } diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java index 1da0215..ddd5b72 100644 --- a/media/java/android/media/MediaRouter.java +++ b/media/java/android/media/MediaRouter.java @@ -60,7 +60,6 @@ import java.util.concurrent.CopyOnWriteArrayList; public class MediaRouter { private static final String TAG = "MediaRouter"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); - private static final boolean USE_SESSIONS = true; static class Static implements DisplayManager.DisplayListener { final Context mAppContext; @@ -2104,11 +2103,7 @@ public class MediaRouter { public void setPlaybackType(int type) { if (mPlaybackType != type) { mPlaybackType = type; - if (USE_SESSIONS) { - configureSessionVolume(); - } else { - setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_PLAYBACK_TYPE, type); - } + configureSessionVolume(); } } @@ -2121,12 +2116,7 @@ public class MediaRouter { public void setVolumeHandling(int volumeHandling) { if (mVolumeHandling != volumeHandling) { mVolumeHandling = volumeHandling; - if (USE_SESSIONS) { - configureSessionVolume(); - } else { - setPlaybackInfoOnRcc( - RemoteControlClient.PLAYBACKINFO_VOLUME_HANDLING, volumeHandling); - } + configureSessionVolume(); } } @@ -2139,12 +2129,8 @@ public class MediaRouter { volume = Math.max(0, Math.min(volume, getVolumeMax())); if (mVolume != volume) { mVolume = volume; - if (USE_SESSIONS) { - if (mSvp != null) { - mSvp.notifyVolumeChanged(); - } - } else { - setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_VOLUME, volume); + if (mSvp != null) { + mSvp.notifyVolumeChanged(); } dispatchRouteVolumeChanged(this); if (mGroup != null) { @@ -2184,11 +2170,7 @@ public class MediaRouter { public void setVolumeMax(int volumeMax) { if (mVolumeMax != volumeMax) { mVolumeMax = volumeMax; - if (USE_SESSIONS) { - configureSessionVolume(); - } else { - setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_VOLUME_MAX, volumeMax); - } + configureSessionVolume(); } } @@ -2199,40 +2181,12 @@ public class MediaRouter { public void setPlaybackStream(int stream) { if (mPlaybackStream != stream) { mPlaybackStream = stream; - if (USE_SESSIONS) { - configureSessionVolume(); - } else { - setPlaybackInfoOnRcc(RemoteControlClient.PLAYBACKINFO_USES_STREAM, stream); - } + configureSessionVolume(); } } private void updatePlaybackInfoOnRcc() { - if (USE_SESSIONS) { - configureSessionVolume(); - } else { - if ((mRcc != null) - && (mRcc.getRcseId() != RemoteControlClient.RCSE_ID_UNREGISTERED)) { - mRcc.setPlaybackInformation( - RemoteControlClient.PLAYBACKINFO_VOLUME_MAX, mVolumeMax); - mRcc.setPlaybackInformation( - RemoteControlClient.PLAYBACKINFO_VOLUME, mVolume); - mRcc.setPlaybackInformation( - RemoteControlClient.PLAYBACKINFO_VOLUME_HANDLING, mVolumeHandling); - mRcc.setPlaybackInformation( - RemoteControlClient.PLAYBACKINFO_USES_STREAM, mPlaybackStream); - mRcc.setPlaybackInformation( - RemoteControlClient.PLAYBACKINFO_PLAYBACK_TYPE, mPlaybackType); - // let AudioService know whom to call when remote volume - // needs to be updated - try { - sStatic.mAudioService.registerRemoteVolumeObserverForRcc( - mRcc.getRcseId() /* rccId */, mRemoteVolObserver /* rvo */); - } catch (RemoteException e) { - Log.e(TAG, "Error registering remote volume observer", e); - } - } - } + configureSessionVolume(); } private void configureSessionVolume() { @@ -2272,12 +2226,6 @@ public class MediaRouter { } } - private void setPlaybackInfoOnRcc(int what, int value) { - if (mRcc != null) { - mRcc.setPlaybackInformation(what, value); - } - } - class SessionVolumeProvider extends RemoteVolumeProvider { public SessionVolumeProvider(int volumeControl, int maxVolume) { diff --git a/media/java/android/media/PlayerRecord.java b/media/java/android/media/PlayerRecord.java index f9708c3..664ddcf 100644 --- a/media/java/android/media/PlayerRecord.java +++ b/media/java/android/media/PlayerRecord.java @@ -56,7 +56,7 @@ class PlayerRecord implements DeathRecipient { */ final private ComponentName mReceiverComponent; - private int mRccId = RemoteControlClient.RCSE_ID_UNREGISTERED; + private int mRccId = -1; /** * A non-null token implies this record tracks a "live" player whose death is being monitored. diff --git a/media/java/android/media/RemoteControlClient.java b/media/java/android/media/RemoteControlClient.java index 0caea5f..73bc61a 100644 --- a/media/java/android/media/RemoteControlClient.java +++ b/media/java/android/media/RemoteControlClient.java @@ -561,6 +561,8 @@ public class RemoteControlClient return; } synchronized (mCacheLock) { + // Still build the old metadata so when creating a new editor + // you get the expected values. // assign the edited data mMetadata = new Bundle(mEditorMetadata); // add the information about editable keys @@ -570,16 +572,6 @@ public class RemoteControlClient } mOriginalArtwork = mEditorArtwork; mEditorArtwork = null; - if (mMetadataChanged & mArtworkChanged) { - // send to remote control display if conditions are met - sendMetadataWithArtwork_syncCacheLock(null, 0, 0); - } else if (mMetadataChanged) { - // send to remote control display if conditions are met - sendMetadata_syncCacheLock(null); - } else if (mArtworkChanged) { - // send to remote control display if conditions are met - sendArtwork_syncCacheLock(null, 0, 0); - } // USE_SESSIONS if (mSession != null && mMetadataBuilder != null) { @@ -687,14 +679,6 @@ public class RemoteControlClient // keep track of when the state change occurred mPlaybackStateChangeTimeMs = SystemClock.elapsedRealtime(); - // send to remote control display if conditions are met - sendPlaybackState_syncCacheLock(null); - // update AudioService - sendAudioServiceNewPlaybackState_syncCacheLock(); - - // handle automatic playback position refreshes - initiateCheckForDrift_syncCacheLock(); - // USE_SESSIONS if (mSession != null) { int pbState = PlaybackState.getStateFromRccState(state); @@ -707,29 +691,7 @@ public class RemoteControlClient } } - private void initiateCheckForDrift_syncCacheLock() { - if (mEventHandler == null) { - return; - } - mEventHandler.removeMessages(MSG_POSITION_DRIFT_CHECK); - if (!mNeedsPositionSync) { - return; - } - if (mPlaybackPositionMs < 0) { - // the current playback state has no known playback position, it's no use - // trying to see if there is any drift at this point - // (this also bypasses this mechanism for older apps that use the old - // setPlaybackState(int) API) - return; - } - if (playbackPositionShouldMove(mPlaybackState)) { - // playback position moving, schedule next position drift check - mEventHandler.sendMessageDelayed( - mEventHandler.obtainMessage(MSG_POSITION_DRIFT_CHECK), - getCheckPeriodFromSpeed(mPlaybackSpeed)); - } - } - + // TODO investigate if we still need position drift checking private void onPositionDriftCheck() { if (DEBUG) { Log.d(TAG, "onPositionDriftCheck()"); } synchronized(mCacheLock) { @@ -781,9 +743,6 @@ public class RemoteControlClient // store locally mTransportControlFlags = transportControlFlags; - // send to remote control display if conditions are met - sendTransportControlInfo_syncCacheLock(null); - // USE_SESSIONS if (mSession != null) { mSessionPlaybackState.setActions(PlaybackState @@ -866,17 +825,7 @@ public class RemoteControlClient */ public void setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener l) { synchronized(mCacheLock) { - int oldCapa = mPlaybackPositionCapabilities; - if (l != null) { - mPlaybackPositionCapabilities |= MEDIA_POSITION_WRITABLE; - } else { - mPlaybackPositionCapabilities &= ~MEDIA_POSITION_WRITABLE; - } mPositionUpdateListener = l; - if (oldCapa != mPlaybackPositionCapabilities) { - // tell RCDs that this RCC's playback position capabilities have changed - sendTransportControlInfo_syncCacheLock(null); - } } } @@ -888,17 +837,7 @@ public class RemoteControlClient */ public void setOnGetPlaybackPositionListener(OnGetPlaybackPositionListener l) { synchronized(mCacheLock) { - int oldCapa = mPlaybackPositionCapabilities; - if (l != null) { - mPlaybackPositionCapabilities |= MEDIA_POSITION_READABLE; - } else { - mPlaybackPositionCapabilities &= ~MEDIA_POSITION_READABLE; - } mPositionProvider = l; - if (oldCapa != mPlaybackPositionCapabilities) { - // tell RCDs that this RCC's playback position capabilities have changed - sendTransportControlInfo_syncCacheLock(null); - } if ((mPositionProvider != null) && (mEventHandler != null) && playbackPositionShouldMove(mPlaybackState)) { // playback position is already moving, but now we have a position provider, @@ -925,124 +864,12 @@ public class RemoteControlClient */ public static int MEDIA_POSITION_WRITABLE = 1 << 1; - private int mPlaybackPositionCapabilities = 0; - /** @hide */ public final static int DEFAULT_PLAYBACK_VOLUME_HANDLING = PLAYBACK_VOLUME_VARIABLE; /** @hide */ // hard-coded to the same number of steps as AudioService.MAX_STREAM_VOLUME[STREAM_MUSIC] public final static int DEFAULT_PLAYBACK_VOLUME = 15; - private int mPlaybackType = PLAYBACK_TYPE_LOCAL; - private int mPlaybackVolumeMax = DEFAULT_PLAYBACK_VOLUME; - private int mPlaybackVolume = DEFAULT_PLAYBACK_VOLUME; - private int mPlaybackVolumeHandling = DEFAULT_PLAYBACK_VOLUME_HANDLING; - private int mPlaybackStream = AudioManager.STREAM_MUSIC; - - /** - * @hide - * Set information describing information related to the playback of media so the system - * can implement additional behavior to handle non-local playback usecases. - * @param what a key to specify the type of information to set. Valid keys are - * {@link #PLAYBACKINFO_PLAYBACK_TYPE}, - * {@link #PLAYBACKINFO_USES_STREAM}, - * {@link #PLAYBACKINFO_VOLUME}, - * {@link #PLAYBACKINFO_VOLUME_MAX}, - * and {@link #PLAYBACKINFO_VOLUME_HANDLING}. - * @param value the value for the supplied information to set. - */ - public void setPlaybackInformation(int what, int value) { - synchronized(mCacheLock) { - switch (what) { - case PLAYBACKINFO_PLAYBACK_TYPE: - if ((value >= PLAYBACK_TYPE_MIN) && (value <= PLAYBACK_TYPE_MAX)) { - if (mPlaybackType != value) { - mPlaybackType = value; - sendAudioServiceNewPlaybackInfo_syncCacheLock(what, value); - } - } else { - Log.w(TAG, "using invalid value for PLAYBACKINFO_PLAYBACK_TYPE"); - } - break; - case PLAYBACKINFO_VOLUME: - if ((value > -1) && (value <= mPlaybackVolumeMax)) { - if (mPlaybackVolume != value) { - mPlaybackVolume = value; - sendAudioServiceNewPlaybackInfo_syncCacheLock(what, value); - } - } else { - Log.w(TAG, "using invalid value for PLAYBACKINFO_VOLUME"); - } - break; - case PLAYBACKINFO_VOLUME_MAX: - if (value > 0) { - if (mPlaybackVolumeMax != value) { - mPlaybackVolumeMax = value; - sendAudioServiceNewPlaybackInfo_syncCacheLock(what, value); - } - } else { - Log.w(TAG, "using invalid value for PLAYBACKINFO_VOLUME_MAX"); - } - break; - case PLAYBACKINFO_USES_STREAM: - if ((value >= 0) && (value < AudioSystem.getNumStreamTypes())) { - mPlaybackStream = value; - } else { - Log.w(TAG, "using invalid value for PLAYBACKINFO_USES_STREAM"); - } - break; - case PLAYBACKINFO_VOLUME_HANDLING: - if ((value >= PLAYBACK_VOLUME_FIXED) && (value <= PLAYBACK_VOLUME_VARIABLE)) { - if (mPlaybackVolumeHandling != value) { - mPlaybackVolumeHandling = value; - sendAudioServiceNewPlaybackInfo_syncCacheLock(what, value); - } - } else { - Log.w(TAG, "using invalid value for PLAYBACKINFO_VOLUME_HANDLING"); - } - break; - default: - // not throwing an exception or returning an error if more keys are to be - // supported in the future - Log.w(TAG, "setPlaybackInformation() ignoring unknown key " + what); - break; - } - } - } - - /** - * @hide - * Return playback information represented as an integer value. - * @param what a key to specify the type of information to retrieve. Valid keys are - * {@link #PLAYBACKINFO_PLAYBACK_TYPE}, - * {@link #PLAYBACKINFO_USES_STREAM}, - * {@link #PLAYBACKINFO_VOLUME}, - * {@link #PLAYBACKINFO_VOLUME_MAX}, - * and {@link #PLAYBACKINFO_VOLUME_HANDLING}. - * @return the current value for the given information type, or - * {@link #PLAYBACKINFO_INVALID_VALUE} if an error occurred or the request is invalid, or - * the value is unknown. - */ - public int getIntPlaybackInformation(int what) { - synchronized(mCacheLock) { - switch (what) { - case PLAYBACKINFO_PLAYBACK_TYPE: - return mPlaybackType; - case PLAYBACKINFO_VOLUME: - return mPlaybackVolume; - case PLAYBACKINFO_VOLUME_MAX: - return mPlaybackVolumeMax; - case PLAYBACKINFO_USES_STREAM: - return mPlaybackStream; - case PLAYBACKINFO_VOLUME_HANDLING: - return mPlaybackVolumeHandling; - default: - Log.e(TAG, "getIntPlaybackInformation() unknown key " + what); - return PLAYBACKINFO_INVALID_VALUE; - } - } - } - /** * Lock for all cached data */ @@ -1102,13 +929,6 @@ public class RemoteControlClient * The current remote control client generation ID across the system, as known by this object */ private int mCurrentClientGenId = -1; - /** - * The remote control client generation ID, the last time it was told it was the current RC. - * If (mCurrentClientGenId == mInternalClientGenId) is true, it means that this remote control - * client is the "focused" one, and that whenever this client's info is updated, it needs to - * send it to the known IRemoteControlDisplay interfaces. - */ - private int mInternalClientGenId = -2; /** * The media button intent description associated with this remote control client @@ -1134,186 +954,18 @@ public class RemoteControlClient private MediaMetadata mMediaMetadata; /** - * A class to encapsulate all the information about a remote control display. - * A RemoteControlClient's metadata and state may be displayed on multiple IRemoteControlDisplay - */ - private class DisplayInfoForClient { - /** may never be null */ - private IRemoteControlDisplay mRcDisplay; - private int mArtworkExpectedWidth; - private int mArtworkExpectedHeight; - private boolean mWantsPositionSync = false; - private boolean mEnabled = true; - - DisplayInfoForClient(IRemoteControlDisplay rcd, int w, int h) { - mRcDisplay = rcd; - mArtworkExpectedWidth = w; - mArtworkExpectedHeight = h; - } - } - - /** - * The list of remote control displays to which this client will send information. - * Accessed and modified synchronized on mCacheLock - */ - private ArrayList<DisplayInfoForClient> mRcDisplays = new ArrayList<DisplayInfoForClient>(1); - - /** * @hide * Accessor to media button intent description (includes target component) */ public PendingIntent getRcMediaIntent() { return mRcMediaIntent; } - /** - * @hide - * Accessor to IRemoteControlClient - */ - public IRemoteControlClient getIRemoteControlClient() { - return mIRCC; - } - - /** - * The IRemoteControlClient implementation - */ - private final IRemoteControlClient mIRCC = new IRemoteControlClient.Stub() { - - //TODO change name to informationRequestForAllDisplays() - public void onInformationRequested(int generationId, int infoFlags) { - // only post messages, we can't block here - if (mEventHandler != null) { - // signal new client - mEventHandler.removeMessages(MSG_NEW_INTERNAL_CLIENT_GEN); - mEventHandler.sendMessage( - mEventHandler.obtainMessage(MSG_NEW_INTERNAL_CLIENT_GEN, - /*arg1*/ generationId, /*arg2, ignored*/ 0)); - // send the information - mEventHandler.removeMessages(MSG_REQUEST_PLAYBACK_STATE); - mEventHandler.removeMessages(MSG_REQUEST_METADATA); - mEventHandler.removeMessages(MSG_REQUEST_TRANSPORTCONTROL); - mEventHandler.removeMessages(MSG_REQUEST_ARTWORK); - mEventHandler.removeMessages(MSG_REQUEST_METADATA_ARTWORK); - mEventHandler.sendMessage( - mEventHandler.obtainMessage(MSG_REQUEST_PLAYBACK_STATE, null)); - mEventHandler.sendMessage( - mEventHandler.obtainMessage(MSG_REQUEST_TRANSPORTCONTROL, null)); - mEventHandler.sendMessage(mEventHandler.obtainMessage(MSG_REQUEST_METADATA_ARTWORK, - 0, 0, null)); - } - } - - public void informationRequestForDisplay(IRemoteControlDisplay rcd, int w, int h) { - // only post messages, we can't block here - if (mEventHandler != null) { - mEventHandler.sendMessage( - mEventHandler.obtainMessage(MSG_REQUEST_TRANSPORTCONTROL, rcd)); - mEventHandler.sendMessage( - mEventHandler.obtainMessage(MSG_REQUEST_PLAYBACK_STATE, rcd)); - if ((w > 0) && (h > 0)) { - mEventHandler.sendMessage( - mEventHandler.obtainMessage(MSG_REQUEST_METADATA_ARTWORK, w, h, rcd)); - } else { - mEventHandler.sendMessage( - mEventHandler.obtainMessage(MSG_REQUEST_METADATA, rcd)); - } - } - } - - public void setCurrentClientGenerationId(int clientGeneration) { - // only post messages, we can't block here - if (mEventHandler != null) { - mEventHandler.removeMessages(MSG_NEW_CURRENT_CLIENT_GEN); - mEventHandler.sendMessage(mEventHandler.obtainMessage( - MSG_NEW_CURRENT_CLIENT_GEN, clientGeneration, 0/*ignored*/)); - } - } - - public void plugRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) { - // only post messages, we can't block here - if ((mEventHandler != null) && (rcd != null)) { - mEventHandler.sendMessage(mEventHandler.obtainMessage( - MSG_PLUG_DISPLAY, w, h, rcd)); - } - } - - public void unplugRemoteControlDisplay(IRemoteControlDisplay rcd) { - // only post messages, we can't block here - if ((mEventHandler != null) && (rcd != null)) { - mEventHandler.sendMessage(mEventHandler.obtainMessage( - MSG_UNPLUG_DISPLAY, rcd)); - } - } - - public void setBitmapSizeForDisplay(IRemoteControlDisplay rcd, int w, int h) { - // only post messages, we can't block here - if ((mEventHandler != null) && (rcd != null)) { - mEventHandler.sendMessage(mEventHandler.obtainMessage( - MSG_UPDATE_DISPLAY_ARTWORK_SIZE, w, h, rcd)); - } - } - - public void setWantsSyncForDisplay(IRemoteControlDisplay rcd, boolean wantsSync) { - // only post messages, we can't block here - if ((mEventHandler != null) && (rcd != null)) { - mEventHandler.sendMessage(mEventHandler.obtainMessage( - MSG_DISPLAY_WANTS_POS_SYNC, wantsSync ? 1 : 0, 0/*arg2 ignored*/, rcd)); - } - } - - public void enableRemoteControlDisplay(IRemoteControlDisplay rcd, boolean enabled) { - // only post messages, we can't block here - if ((mEventHandler != null) && (rcd != null)) { - mEventHandler.sendMessage(mEventHandler.obtainMessage( - MSG_DISPLAY_ENABLE, enabled ? 1 : 0, 0/*arg2 ignored*/, rcd)); - } - } - - public void seekTo(int generationId, long timeMs) { - // only post messages, we can't block here - if (mEventHandler != null) { - mEventHandler.removeMessages(MSG_SEEK_TO); - mEventHandler.sendMessage(mEventHandler.obtainMessage( - MSG_SEEK_TO, generationId /* arg1 */, 0 /* arg2, ignored */, - new Long(timeMs))); - } - } - - public void updateMetadata(int generationId, int key, Rating value) { - // only post messages, we can't block here - if (mEventHandler != null) { - mEventHandler.sendMessage(mEventHandler.obtainMessage( - MSG_UPDATE_METADATA, generationId /* arg1 */, key /* arg2*/, value)); - } - } - }; /** * @hide * Default value for the unique identifier */ public final static int RCSE_ID_UNREGISTERED = -1; - /** - * Unique identifier of the RemoteControlStackEntry in AudioService with which - * this RemoteControlClient is associated. - */ - private int mRcseId = RCSE_ID_UNREGISTERED; - /** - * @hide - * To be only used by AudioManager after it has received the unique id from - * IAudioService.registerRemoteControlClient() - * @param id the unique identifier of the RemoteControlStackEntry in AudioService with which - * this RemoteControlClient is associated. - */ - public void setRcseId(int id) { - mRcseId = id; - } - - /** - * @hide - */ - public int getRcseId() { - return mRcseId; - } // USE_SESSIONS private MediaSession.TransportControlsCallback mTransportListener @@ -1327,31 +979,13 @@ public class RemoteControlClient @Override public void onSetRating(Rating rating) { if ((mTransportControlFlags & FLAG_KEY_MEDIA_RATING) != 0) { - if (mEventHandler != null) { - mEventHandler.sendMessage(mEventHandler.obtainMessage( - MSG_UPDATE_METADATA, mCurrentClientGenId, - MetadataEditor.RATING_KEY_BY_USER, rating)); - } + onUpdateMetadata(mCurrentClientGenId, MetadataEditor.RATING_KEY_BY_USER, rating); } } }; private EventHandler mEventHandler; - private final static int MSG_REQUEST_PLAYBACK_STATE = 1; - private final static int MSG_REQUEST_METADATA = 2; - private final static int MSG_REQUEST_TRANSPORTCONTROL = 3; - private final static int MSG_REQUEST_ARTWORK = 4; - private final static int MSG_NEW_INTERNAL_CLIENT_GEN = 5; - private final static int MSG_NEW_CURRENT_CLIENT_GEN = 6; - private final static int MSG_PLUG_DISPLAY = 7; - private final static int MSG_UNPLUG_DISPLAY = 8; - private final static int MSG_UPDATE_DISPLAY_ARTWORK_SIZE = 9; - private final static int MSG_SEEK_TO = 10; private final static int MSG_POSITION_DRIFT_CHECK = 11; - private final static int MSG_DISPLAY_WANTS_POS_SYNC = 12; - private final static int MSG_UPDATE_METADATA = 13; - private final static int MSG_REQUEST_METADATA_ARTWORK = 14; - private final static int MSG_DISPLAY_ENABLE = 15; private class EventHandler extends Handler { public EventHandler(RemoteControlClient rcc, Looper looper) { @@ -1361,63 +995,9 @@ public class RemoteControlClient @Override public void handleMessage(Message msg) { switch(msg.what) { - case MSG_REQUEST_PLAYBACK_STATE: - synchronized (mCacheLock) { - sendPlaybackState_syncCacheLock((IRemoteControlDisplay)msg.obj); - } - break; - case MSG_REQUEST_METADATA: - synchronized (mCacheLock) { - sendMetadata_syncCacheLock((IRemoteControlDisplay)msg.obj); - } - break; - case MSG_REQUEST_TRANSPORTCONTROL: - synchronized (mCacheLock) { - sendTransportControlInfo_syncCacheLock((IRemoteControlDisplay)msg.obj); - } - break; - case MSG_REQUEST_ARTWORK: - synchronized (mCacheLock) { - sendArtwork_syncCacheLock((IRemoteControlDisplay)msg.obj, - msg.arg1, msg.arg2); - } - break; - case MSG_REQUEST_METADATA_ARTWORK: - synchronized (mCacheLock) { - sendMetadataWithArtwork_syncCacheLock((IRemoteControlDisplay)msg.obj, - msg.arg1, msg.arg2); - } - break; - case MSG_NEW_INTERNAL_CLIENT_GEN: - onNewInternalClientGen(msg.arg1); - break; - case MSG_NEW_CURRENT_CLIENT_GEN: - onNewCurrentClientGen(msg.arg1); - break; - case MSG_PLUG_DISPLAY: - onPlugDisplay((IRemoteControlDisplay)msg.obj, msg.arg1, msg.arg2); - break; - case MSG_UNPLUG_DISPLAY: - onUnplugDisplay((IRemoteControlDisplay)msg.obj); - break; - case MSG_UPDATE_DISPLAY_ARTWORK_SIZE: - onUpdateDisplayArtworkSize((IRemoteControlDisplay)msg.obj, msg.arg1, msg.arg2); - break; - case MSG_SEEK_TO: - onSeekTo(msg.arg1, ((Long)msg.obj).longValue()); - break; case MSG_POSITION_DRIFT_CHECK: onPositionDriftCheck(); break; - case MSG_DISPLAY_WANTS_POS_SYNC: - onDisplayWantsSync((IRemoteControlDisplay)msg.obj, msg.arg1 == 1); - break; - case MSG_UPDATE_METADATA: - onUpdateMetadata(msg.arg1, msg.arg2, msg.obj); - break; - case MSG_DISPLAY_ENABLE: - onDisplayEnable((IRemoteControlDisplay)msg.obj, msg.arg1 == 1); - break; default: Log.e(TAG, "Unknown event " + msg.what + " in RemoteControlClient handler"); } @@ -1425,346 +1005,8 @@ public class RemoteControlClient } //=========================================================== - // Communication with the IRemoteControlDisplay (the displays known to the system) - - private void sendPlaybackState_syncCacheLock(IRemoteControlDisplay target) { - if (mCurrentClientGenId == mInternalClientGenId) { - if (target != null) { - try { - target.setPlaybackState(mInternalClientGenId, - mPlaybackState, mPlaybackStateChangeTimeMs, mPlaybackPositionMs, - mPlaybackSpeed); - } catch (RemoteException e) { - Log.e(TAG, "Error in setPlaybackState() for dead display " + target, e); - } - return; - } - // target == null implies all displays must be updated - final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator(); - while (displayIterator.hasNext()) { - final DisplayInfoForClient di = displayIterator.next(); - if (di.mEnabled) { - try { - di.mRcDisplay.setPlaybackState(mInternalClientGenId, - mPlaybackState, mPlaybackStateChangeTimeMs, mPlaybackPositionMs, - mPlaybackSpeed); - } catch (RemoteException e) { - Log.e(TAG, "Error in setPlaybackState(), dead display " + di.mRcDisplay, e); - displayIterator.remove(); - } - } - } - } - } - - private void sendMetadata_syncCacheLock(IRemoteControlDisplay target) { - if (mCurrentClientGenId == mInternalClientGenId) { - if (target != null) { - try { - target.setMetadata(mInternalClientGenId, mMetadata); - } catch (RemoteException e) { - Log.e(TAG, "Error in setMetadata() for dead display " + target, e); - } - return; - } - // target == null implies all displays must be updated - final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator(); - while (displayIterator.hasNext()) { - final DisplayInfoForClient di = displayIterator.next(); - if (di.mEnabled) { - try { - di.mRcDisplay.setMetadata(mInternalClientGenId, mMetadata); - } catch (RemoteException e) { - Log.e(TAG, "Error in setMetadata(), dead display " + di.mRcDisplay, e); - displayIterator.remove(); - } - } - } - } - } - - private void sendTransportControlInfo_syncCacheLock(IRemoteControlDisplay target) { - if (mCurrentClientGenId == mInternalClientGenId) { - if (target != null) { - try { - target.setTransportControlInfo(mInternalClientGenId, - mTransportControlFlags, mPlaybackPositionCapabilities); - } catch (RemoteException e) { - Log.e(TAG, "Error in setTransportControlFlags() for dead display " + target, - e); - } - return; - } - // target == null implies all displays must be updated - final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator(); - while (displayIterator.hasNext()) { - final DisplayInfoForClient di = displayIterator.next(); - if (di.mEnabled) { - try { - di.mRcDisplay.setTransportControlInfo(mInternalClientGenId, - mTransportControlFlags, mPlaybackPositionCapabilities); - } catch (RemoteException e) { - Log.e(TAG, "Error in setTransportControlFlags(), dead display " + di.mRcDisplay, - e); - displayIterator.remove(); - } - } - } - } - } - - private void sendArtwork_syncCacheLock(IRemoteControlDisplay target, int w, int h) { - // FIXME modify to cache all requested sizes? - if (mCurrentClientGenId == mInternalClientGenId) { - if (target != null) { - final DisplayInfoForClient di = new DisplayInfoForClient(target, w, h); - sendArtworkToDisplay(di); - return; - } - // target == null implies all displays must be updated - final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator(); - while (displayIterator.hasNext()) { - if (!sendArtworkToDisplay(displayIterator.next())) { - displayIterator.remove(); - } - } - } - } - - /** - * Send artwork to an IRemoteControlDisplay. - * @param di encapsulates the IRemoteControlDisplay that will receive the artwork, and its - * dimension requirements. - * @return false if there was an error communicating with the IRemoteControlDisplay. - */ - private boolean sendArtworkToDisplay(DisplayInfoForClient di) { - if ((di.mArtworkExpectedWidth > 0) && (di.mArtworkExpectedHeight > 0)) { - Bitmap artwork = scaleBitmapIfTooBig(mOriginalArtwork, - di.mArtworkExpectedWidth, di.mArtworkExpectedHeight); - try { - di.mRcDisplay.setArtwork(mInternalClientGenId, artwork); - } catch (RemoteException e) { - Log.e(TAG, "Error in sendArtworkToDisplay(), dead display " + di.mRcDisplay, e); - return false; - } - } - return true; - } - - private void sendMetadataWithArtwork_syncCacheLock(IRemoteControlDisplay target, int w, int h) { - // FIXME modify to cache all requested sizes? - if (mCurrentClientGenId == mInternalClientGenId) { - if (target != null) { - try { - if ((w > 0) && (h > 0)) { - Bitmap artwork = scaleBitmapIfTooBig(mOriginalArtwork, w, h); - target.setAllMetadata(mInternalClientGenId, mMetadata, artwork); - } else { - target.setMetadata(mInternalClientGenId, mMetadata); - } - } catch (RemoteException e) { - Log.e(TAG, "Error in set(All)Metadata() for dead display " + target, e); - } - return; - } - // target == null implies all displays must be updated - final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator(); - while (displayIterator.hasNext()) { - final DisplayInfoForClient di = displayIterator.next(); - try { - if (di.mEnabled) { - if ((di.mArtworkExpectedWidth > 0) && (di.mArtworkExpectedHeight > 0)) { - Bitmap artwork = scaleBitmapIfTooBig(mOriginalArtwork, - di.mArtworkExpectedWidth, di.mArtworkExpectedHeight); - di.mRcDisplay.setAllMetadata(mInternalClientGenId, mMetadata, artwork); - } else { - di.mRcDisplay.setMetadata(mInternalClientGenId, mMetadata); - } - } - } catch (RemoteException e) { - Log.e(TAG, "Error when setting metadata, dead display " + di.mRcDisplay, e); - displayIterator.remove(); - } - } - } - } - - //=========================================================== - // Communication with AudioService - - private static IAudioService sService; - - private static IAudioService getService() - { - if (sService != null) { - return sService; - } - IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE); - sService = IAudioService.Stub.asInterface(b); - return sService; - } - - private void sendAudioServiceNewPlaybackInfo_syncCacheLock(int what, int value) { - if (mRcseId == RCSE_ID_UNREGISTERED) { - return; - } - //Log.d(TAG, "sending to AudioService key=" + what + ", value=" + value); - IAudioService service = getService(); - try { - service.setPlaybackInfoForRcc(mRcseId, what, value); - } catch (RemoteException e) { - Log.e(TAG, "Dead object in setPlaybackInfoForRcc", e); - } - } - - private void sendAudioServiceNewPlaybackState_syncCacheLock() { - if (mRcseId == RCSE_ID_UNREGISTERED) { - return; - } - IAudioService service = getService(); - try { - service.setPlaybackStateForRcc(mRcseId, - mPlaybackState, mPlaybackPositionMs, mPlaybackSpeed); - } catch (RemoteException e) { - Log.e(TAG, "Dead object in setPlaybackStateForRcc", e); - } - } - - //=========================================================== // Message handlers - private void onNewInternalClientGen(int clientGeneration) { - synchronized (mCacheLock) { - // this remote control client is told it is the "focused" one: - // it implies that now (mCurrentClientGenId == mInternalClientGenId) is true - mInternalClientGenId = clientGeneration; - } - } - - private void onNewCurrentClientGen(int clientGeneration) { - synchronized (mCacheLock) { - mCurrentClientGenId = clientGeneration; - } - } - - /** pre-condition rcd != null */ - private void onPlugDisplay(IRemoteControlDisplay rcd, int w, int h) { - synchronized(mCacheLock) { - // do we have this display already? - boolean displayKnown = false; - final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator(); - while (displayIterator.hasNext() && !displayKnown) { - final DisplayInfoForClient di = displayIterator.next(); - displayKnown = di.mRcDisplay.asBinder().equals(rcd.asBinder()); - if (displayKnown) { - // this display was known but the change in artwork size will cause the - // artwork to be refreshed - if ((di.mArtworkExpectedWidth != w) || (di.mArtworkExpectedHeight != h)) { - di.mArtworkExpectedWidth = w; - di.mArtworkExpectedHeight = h; - if (!sendArtworkToDisplay(di)) { - displayIterator.remove(); - } - } - } - } - if (!displayKnown) { - mRcDisplays.add(new DisplayInfoForClient(rcd, w, h)); - } - } - } - - /** pre-condition rcd != null */ - private void onUnplugDisplay(IRemoteControlDisplay rcd) { - synchronized(mCacheLock) { - Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator(); - while (displayIterator.hasNext()) { - final DisplayInfoForClient di = displayIterator.next(); - if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) { - displayIterator.remove(); - break; - } - } - // list of RCDs has changed, reevaluate whether position check is still needed - boolean oldNeedsPositionSync = mNeedsPositionSync; - boolean newNeedsPositionSync = false; - displayIterator = mRcDisplays.iterator(); - while (displayIterator.hasNext()) { - final DisplayInfoForClient di = displayIterator.next(); - if (di.mWantsPositionSync) { - newNeedsPositionSync = true; - break; - } - } - mNeedsPositionSync = newNeedsPositionSync; - if (oldNeedsPositionSync != mNeedsPositionSync) { - // update needed? - initiateCheckForDrift_syncCacheLock(); - } - } - } - - /** pre-condition rcd != null */ - private void onUpdateDisplayArtworkSize(IRemoteControlDisplay rcd, int w, int h) { - synchronized(mCacheLock) { - final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator(); - while (displayIterator.hasNext()) { - final DisplayInfoForClient di = displayIterator.next(); - if (di.mRcDisplay.asBinder().equals(rcd.asBinder()) && - ((di.mArtworkExpectedWidth != w) || (di.mArtworkExpectedHeight != h))) { - di.mArtworkExpectedWidth = w; - di.mArtworkExpectedHeight = h; - if (di.mEnabled) { - if (!sendArtworkToDisplay(di)) { - displayIterator.remove(); - } - } - break; - } - } - } - } - - /** pre-condition rcd != null */ - private void onDisplayWantsSync(IRemoteControlDisplay rcd, boolean wantsSync) { - synchronized(mCacheLock) { - boolean oldNeedsPositionSync = mNeedsPositionSync; - boolean newNeedsPositionSync = false; - final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator(); - // go through the list of RCDs and for each entry, check both whether this is the RCD - // that gets upated, and whether the list has one entry that wants position sync - while (displayIterator.hasNext()) { - final DisplayInfoForClient di = displayIterator.next(); - if (di.mEnabled) { - if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) { - di.mWantsPositionSync = wantsSync; - } - if (di.mWantsPositionSync) { - newNeedsPositionSync = true; - } - } - } - mNeedsPositionSync = newNeedsPositionSync; - if (oldNeedsPositionSync != mNeedsPositionSync) { - // update needed? - initiateCheckForDrift_syncCacheLock(); - } - } - } - - /** pre-condition rcd != null */ - private void onDisplayEnable(IRemoteControlDisplay rcd, boolean enable) { - synchronized(mCacheLock) { - final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator(); - while (displayIterator.hasNext()) { - final DisplayInfoForClient di = displayIterator.next(); - if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) { - di.mEnabled = enable; - } - } - } - } - private void onSeekTo(int generationId, long timeMs) { synchronized (mCacheLock) { if ((mCurrentClientGenId == generationId) && (mPositionUpdateListener != null)) { @@ -1785,42 +1027,6 @@ public class RemoteControlClient // Internal utilities /** - * Scale a bitmap to fit the smallest dimension by uniformly scaling the incoming bitmap. - * If the bitmap fits, then do nothing and return the original. - * - * @param bitmap - * @param maxWidth - * @param maxHeight - * @return - */ - - private Bitmap scaleBitmapIfTooBig(Bitmap bitmap, int maxWidth, int maxHeight) { - if (bitmap != null) { - final int width = bitmap.getWidth(); - final int height = bitmap.getHeight(); - if (width > maxWidth || height > maxHeight) { - float scale = Math.min((float) maxWidth / width, (float) maxHeight / height); - int newWidth = Math.round(scale * width); - int newHeight = Math.round(scale * height); - Bitmap.Config newConfig = bitmap.getConfig(); - if (newConfig == null) { - newConfig = Bitmap.Config.ARGB_8888; - } - Bitmap outBitmap = Bitmap.createBitmap(newWidth, newHeight, newConfig); - Canvas canvas = new Canvas(outBitmap); - Paint paint = new Paint(); - paint.setAntiAlias(true); - paint.setFilterBitmap(true); - canvas.drawBitmap(bitmap, null, - new RectF(0, 0, outBitmap.getWidth(), outBitmap.getHeight()), paint); - bitmap = outBitmap; - } - } - return bitmap; - } - - - /** * Returns whether, for the given playback state, the playback position is expected to * be changing. * @param playstate the playback state to evaluate diff --git a/media/java/android/media/SubtitleTrack.java b/media/java/android/media/SubtitleTrack.java index 06063de..b0e182d 100644 --- a/media/java/android/media/SubtitleTrack.java +++ b/media/java/android/media/SubtitleTrack.java @@ -83,7 +83,7 @@ public abstract class SubtitleTrack implements MediaTimeProvider.OnMediaTimeList * indicating the last section of the run. Calls from different * runs must not be intermixed. * - * @param data + * @param data subtitle data byte buffer * @param eos true if this is the last section of the run. * @param runID mostly-unique ID for this run of data. Subtitle cues * with runID of 0 are discarded immediately after @@ -92,10 +92,8 @@ public abstract class SubtitleTrack implements MediaTimeProvider.OnMediaTimeList * with other runID-s are discarded at the end of the * run, which defaults to the latest timestamp of * any of its cues (with this runID). - * - * TODO use ByteBuffer */ - public abstract void onData(String data, boolean eos, long runID); + public abstract void onData(byte[] data, boolean eos, long runID); /** * Called when adding the subtitle rendering widget to the view hierarchy, diff --git a/media/java/android/media/TtmlRenderer.java b/media/java/android/media/TtmlRenderer.java index 0309334..75133c9 100644 --- a/media/java/android/media/TtmlRenderer.java +++ b/media/java/android/media/TtmlRenderer.java @@ -563,28 +563,35 @@ class TtmlTrack extends SubtitleTrack implements TtmlNodeListener { } @Override - public void onData(String data, boolean eos, long runID) { - // implement intermixing restriction for TTML. - synchronized(mParser) { - if (mCurrentRunID != null && runID != mCurrentRunID) { - throw new IllegalStateException( - "Run #" + mCurrentRunID + - " in progress. Cannot process run #" + runID); - } - mCurrentRunID = runID; - mParsingData += data; - if (eos) { - try { - mParser.parse(mParsingData, mCurrentRunID); - } catch (XmlPullParserException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); + public void onData(byte[] data, boolean eos, long runID) { + try { + // TODO: handle UTF-8 conversion properly + String str = new String(data, "UTF-8"); + + // implement intermixing restriction for TTML. + synchronized(mParser) { + if (mCurrentRunID != null && runID != mCurrentRunID) { + throw new IllegalStateException( + "Run #" + mCurrentRunID + + " in progress. Cannot process run #" + runID); + } + mCurrentRunID = runID; + mParsingData += str; + if (eos) { + try { + mParser.parse(mParsingData, mCurrentRunID); + } catch (XmlPullParserException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + finishedRun(runID); + mParsingData = ""; + mCurrentRunID = null; } - finishedRun(runID); - mParsingData = ""; - mCurrentRunID = null; } + } catch (java.io.UnsupportedEncodingException e) { + Log.w(TAG, "subtitle data is not UTF-8 encoded: " + e); } } diff --git a/media/java/android/media/WebVttRenderer.java b/media/java/android/media/WebVttRenderer.java index 7977988..a9374d5 100644 --- a/media/java/android/media/WebVttRenderer.java +++ b/media/java/android/media/WebVttRenderer.java @@ -1001,22 +1001,28 @@ class WebVttTrack extends SubtitleTrack implements WebVttCueListener { } @Override - public void onData(String data, boolean eos, long runID) { - // implement intermixing restriction for WebVTT only for now - synchronized(mParser) { - if (mCurrentRunID != null && runID != mCurrentRunID) { - throw new IllegalStateException( - "Run #" + mCurrentRunID + - " in progress. Cannot process run #" + runID); - } - mCurrentRunID = runID; - mParser.parse(data); - if (eos) { - finishedRun(runID); - mParser.eos(); - mRegions.clear(); - mCurrentRunID = null; + public void onData(byte[] data, boolean eos, long runID) { + try { + String str = new String(data, "UTF-8"); + + // implement intermixing restriction for WebVTT only for now + synchronized(mParser) { + if (mCurrentRunID != null && runID != mCurrentRunID) { + throw new IllegalStateException( + "Run #" + mCurrentRunID + + " in progress. Cannot process run #" + runID); + } + mCurrentRunID = runID; + mParser.parse(str); + if (eos) { + finishedRun(runID); + mParser.eos(); + mRegions.clear(); + mCurrentRunID = null; + } } + } catch (java.io.UnsupportedEncodingException e) { + Log.w(TAG, "subtitle data is not UTF-8 encoded: " + e); } } diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java index ec87c6e..2ed3d73 100644 --- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java +++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java @@ -170,7 +170,7 @@ public class DefaultContainerService extends IntentService { DisplayMetrics metrics = new DisplayMetrics(); metrics.setToDefaults(); - PackageParser.PackageLite pkg = PackageParser.parsePackageLite(packagePath, 0); + PackageParser.ApkLite pkg = PackageParser.parseApkLite(packagePath, 0); if (pkg == null) { Slog.w(TAG, "Failed to parse package"); diff --git a/packages/Keyguard/res/layout/keyguard_status_view.xml b/packages/Keyguard/res/layout/keyguard_status_view.xml index 2917faa..006b1ee 100644 --- a/packages/Keyguard/res/layout/keyguard_status_view.xml +++ b/packages/Keyguard/res/layout/keyguard_status_view.xml @@ -56,7 +56,7 @@ android:layout_height="wrap_content" android:layout_marginTop="@dimen/date_owner_info_margin" android:layout_gravity="center_horizontal" - android:textColor="#99ffffff" + android:textColor="#ccffffff" android:textSize="@dimen/widget_label_font_size" android:ellipsize="marquee" android:singleLine="true" /> diff --git a/packages/Keyguard/res/values-sw600dp/dimens.xml b/packages/Keyguard/res/values-sw600dp/dimens.xml index e9e9b89..69bf44f 100644 --- a/packages/Keyguard/res/values-sw600dp/dimens.xml +++ b/packages/Keyguard/res/values-sw600dp/dimens.xml @@ -63,14 +63,11 @@ <dimen name="keyguard_muliuser_selector_margin">12dp</dimen> <!-- Overload default clock widget parameters --> - <dimen name="widget_big_font_size">96dp</dimen> + <dimen name="widget_big_font_size">120dp</dimen> <dimen name="widget_label_font_size">16sp</dimen> - <dimen name="bottom_text_spacing_digital">-8dp</dimen> + <dimen name="bottom_text_spacing_digital">-16dp</dimen> <!-- EmergencyCarrierArea overlap - amount to overlap the emergency button and carrier text. Should be 0 on devices with plenty of room (e.g. tablets) --> <dimen name="eca_overlap">0dip</dimen> - - <!-- The vertical margin between the date and the owner info. --> - <dimen name="date_owner_info_margin">4dp</dimen> </resources> diff --git a/packages/Keyguard/res/values/dimens.xml b/packages/Keyguard/res/values/dimens.xml index f971522..4b113ff 100644 --- a/packages/Keyguard/res/values/dimens.xml +++ b/packages/Keyguard/res/values/dimens.xml @@ -155,15 +155,15 @@ <dimen name="eca_overlap">-10dip</dimen> <!-- Default clock parameters --> - <dimen name="bottom_text_spacing_digital">-6dp</dimen> + <dimen name="bottom_text_spacing_digital">-10dp</dimen> <dimen name="label_font_size">14dp</dimen> - <dimen name="widget_label_font_size">14sp</dimen> - <dimen name="widget_big_font_size">68dp</dimen> + <dimen name="widget_label_font_size">16sp</dimen> + <dimen name="widget_big_font_size">96dp</dimen> <dimen name="big_font_size">120dp</dimen> <!-- The y translation to apply at the start in appear animations. --> <dimen name="appear_y_translation_start">32dp</dimen> <!-- The vertical margin between the date and the owner info. --> - <dimen name="date_owner_info_margin">2dp</dimen> + <dimen name="date_owner_info_margin">10dp</dimen> </resources> diff --git a/packages/Keyguard/res/values/donottranslate.xml b/packages/Keyguard/res/values/donottranslate.xml index 16f5a3e..78636db 100644 --- a/packages/Keyguard/res/values/donottranslate.xml +++ b/packages/Keyguard/res/values/donottranslate.xml @@ -16,7 +16,7 @@ <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> <!-- Skeleton string format for displaying the date. --> - <string name="abbrev_wday_month_day_no_year">EEEMMMMd</string> + <string name="abbrev_wday_month_day_no_year">EEEEMMMMd</string> <!-- Skeleton string format for displaying the time in 12-hour format. --> <string name="clock_12hr_format">hm</string> diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java index a8b49e2..7918755 100644 --- a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java +++ b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java @@ -130,11 +130,6 @@ public class KeyguardStatusView extends GridLayout { } } - @Override - public boolean hasOverlappingRendering() { - return false; - } - private void updateOwnerInfo() { String ownerInfo = getOwnerInfo(); if (!TextUtils.isEmpty(ownerInfo)) { diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml index 9bf42b2..db5983b 100644 --- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml +++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml @@ -46,7 +46,7 @@ android:id="@+id/keyguard_indication_text" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginBottom="100dp" + android:layout_marginBottom="70dp" android:layout_gravity="bottom|center_horizontal" android:textStyle="italic" android:textColor="#ffffff" diff --git a/packages/SystemUI/res/values-sw600dp-land/config.xml b/packages/SystemUI/res/values-sw600dp-land/config.xml new file mode 100644 index 0000000..f9b01c8 --- /dev/null +++ b/packages/SystemUI/res/values-sw600dp-land/config.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2014 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> +<resources> + <!-- The maximum count of notifications on Keyguard. The rest will be collapsed in an overflow + card. --> + <integer name="keyguard_max_notification_count">3</integer> +</resources> diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml index 326f602..5367fbc 100644 --- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml +++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml @@ -23,5 +23,8 @@ <item name="recents_stack_width_padding_percentage" format="float" type="dimen">0.25</item> <fraction name="keyguard_clock_y_fraction_max">37%</fraction> - <fraction name="keyguard_clock_y_fraction_min">14%</fraction> + <fraction name="keyguard_clock_y_fraction_min">20%</fraction> + + <dimen name="keyguard_clock_notifications_margin_min">36dp</dimen> + <dimen name="keyguard_clock_notifications_margin_max">36dp</dimen> </resources> diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml index 6dea81f..47581a9 100644 --- a/packages/SystemUI/res/values-sw600dp/config.xml +++ b/packages/SystemUI/res/values-sw600dp/config.xml @@ -28,4 +28,8 @@ <!-- The number of columns that the top level tiles span in the QuickSettings --> <integer name="quick_settings_user_time_settings_tile_span">1</integer> + + <!-- The maximum count of notifications on Keyguard. The rest will be collapsed in an overflow + card. --> + <integer name="keyguard_max_notification_count">5</integer> </resources> diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml index 313e2e8..a5e3924 100644 --- a/packages/SystemUI/res/values-sw600dp/dimens.xml +++ b/packages/SystemUI/res/values-sw600dp/dimens.xml @@ -16,8 +16,8 @@ */ --> <resources> - <!-- The width of the notification panel window: 446 + 16 + 16 (padding in the bg drawable) --> - <dimen name="notification_panel_width">478dp</dimen> + <!-- The width of the notification panel window: 400 + 16 + 16 (padding in the bg drawable) --> + <dimen name="notification_panel_width">432dp</dimen> <!-- Gravity for the notification panel --> <!-- 0x31 = top|center_horizontal --> @@ -56,10 +56,10 @@ max value is used when no notifications are displaying, and the min value is when the highest possible number of notifications are showing. --> <fraction name="keyguard_clock_y_fraction_max">34%</fraction> - <fraction name="keyguard_clock_y_fraction_min">25%</fraction> + <fraction name="keyguard_clock_y_fraction_min">24%</fraction> <!-- The margin between the clock and the notifications on Keyguard. See keyguard_clock_height_fraction_* for the difference between min and max.--> - <dimen name="keyguard_clock_notifications_margin_min">36dp</dimen> - <dimen name="keyguard_clock_notifications_margin_max">36dp</dimen> + <dimen name="keyguard_clock_notifications_margin_min">44dp</dimen> + <dimen name="keyguard_clock_notifications_margin_max">44dp</dimen> </resources> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 5ffe3b3..7ed3e29 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -292,12 +292,12 @@ <!-- The fraction of the screen height where the clock on the Keyguard has its center. The max value is used when no notifications are displaying, and the min value is when the highest possible number of notifications are showing. --> - <fraction name="keyguard_clock_y_fraction_max">29.5%</fraction> - <fraction name="keyguard_clock_y_fraction_min">18%</fraction> + <fraction name="keyguard_clock_y_fraction_max">32.5%</fraction> + <fraction name="keyguard_clock_y_fraction_min">19.8%</fraction> <!-- The margin between the clock and the notifications on Keyguard. See keyguard_clock_height_fraction_* for the difference between min and max.--> - <dimen name="keyguard_clock_notifications_margin_min">22dp</dimen> + <dimen name="keyguard_clock_notifications_margin_min">24dp</dimen> <dimen name="keyguard_clock_notifications_margin_max">36dp</dimen> <dimen name="heads_up_window_height">250dp</dimen> @@ -330,6 +330,4 @@ phone hints. --> <dimen name="edge_tap_area_width">48dp</dimen> - <!-- the distance the panel moves up when starting the up motion on Keyguard --> - <dimen name="keyguard_panel_move_up_distance">100dp</dimen> </resources> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 43560a3..c117eba 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -63,7 +63,7 @@ <style name="TextAppearance.StatusBar.Clock" parent="@*android:style/TextAppearance.StatusBar.Icon"> <!-- Note: must be dp to fit in status bar --> <item name="android:textSize">16dp</item> - <item name="android:textStyle">normal</item> + <item name="android:fontFamily">sans-serif-medium</item> <item name="android:textColor">@color/status_bar_clock_color</item> </style> diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java index e8f3745..c3ba349 100644 --- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java +++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java @@ -126,7 +126,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { } private void updateNotification() { - Slog.d(TAG, "updateNotification mWarning=" + mWarning + if (DEBUG) Slog.d(TAG, "updateNotification mWarning=" + mWarning + " mSaver=" + mSaver + " mInvalidCharger=" + mInvalidCharger); if (mInvalidCharger) { showInvalidChargerNotification(); @@ -238,13 +238,13 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { @Override public void dismissLowBatteryWarning() { - Slog.i(TAG, "dismissing low battery warning: level=" + mBatteryLevel); + if (DEBUG) Slog.d(TAG, "dismissing low battery warning: level=" + mBatteryLevel); dismissLowBatteryNotification(); mFallbackDialogs.dismissLowBatteryWarning(); } private void dismissLowBatteryNotification() { - Slog.i(TAG, "dismissing low battery notification"); + if (mWarning) Slog.i(TAG, "dismissing low battery notification"); mWarning = false; updateNotification(); } @@ -307,7 +307,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { } private void dismissInvalidChargerNotification() { - Slog.i(TAG, "dismissing invalid charger notification"); + if (mInvalidCharger) Slog.i(TAG, "dismissing invalid charger notification"); mInvalidCharger = false; updateNotification(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java index db85b14..6a83a5e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java @@ -88,15 +88,13 @@ public class KeyguardClockPositionAlgorithm { public void run(Result result) { int y = getClockY() - mKeyguardStatusHeight/2; - float topAdjustment = getTopExpansionAdjustment(); + float clockAdjustment = getClockYExpansionAdjustment(); float topPaddingAdjMultiplier = getTopPaddingAdjMultiplier(); - result.stackScrollerPaddingAdjustment = (int) (topAdjustment*topPaddingAdjMultiplier); + result.stackScrollerPaddingAdjustment = (int) (clockAdjustment*topPaddingAdjMultiplier); int clockNotificationsPadding = getClockNotificationsPadding() + result.stackScrollerPaddingAdjustment; int padding = y + clockNotificationsPadding; - if (mNotificationCount == 0) { - y += topAdjustment; - } + y += clockAdjustment; result.clockY = y; result.stackScrollerPadding = mKeyguardStatusHeight + padding; result.clockAlpha = getClockAlpha(result.stackScrollerPadding @@ -119,8 +117,8 @@ public class KeyguardClockPositionAlgorithm { return (int) (getClockYFraction() * mHeight); } - private float getTopExpansionAdjustment() { - float rubberbandFactor = getTopExpansionRubberbandFactor(); + private float getClockYExpansionAdjustment() { + float rubberbandFactor = getClockYExpansionRubberbandFactor(); float value = (rubberbandFactor * (mMaxPanelHeight - mExpandedHeight)); float t = value / mMaxPanelHeight; float slowedDownValue = -sSlowDownInterpolator.getInterpolation(t) * SLOW_DOWN_FACTOR @@ -132,7 +130,7 @@ public class KeyguardClockPositionAlgorithm { } } - private float getTopExpansionRubberbandFactor() { + private float getClockYExpansionRubberbandFactor() { float t = getNotificationAmountT(); t = Math.min(t, 1.0f); t = (float) Math.pow(t, 0.3f); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPageSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPageSwipeHelper.java index ca49408..e312d58 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPageSwipeHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardPageSwipeHelper.java @@ -246,9 +246,7 @@ public class KeyguardPageSwipeHelper { private void startHintTranslationAnimations(float target, long duration, Interpolator interpolator) { ArrayList<View> targetViews = mCallback.getTranslationViews(); - int length = targetViews.size(); - for (int i = 0; i < length; i++) { - View targetView = targetViews.get(i); + for (View targetView : targetViews) { targetView.animate() .setDuration(duration) .setInterpolator(interpolator) @@ -261,16 +259,8 @@ public class KeyguardPageSwipeHelper { } private void cancelAnimations() { - ArrayList<View> translatingViews = mCallback.getTranslationViews(); - int length = translatingViews.size(); - for (int i = 0; i < length; i++) { - View target = translatingViews.get(i); - target.animate().cancel(); - } - ArrayList<View> fadingViews = mCallback.getFadingViews(); - length = fadingViews.size(); - for (int i = 0; i < length; i++) { - View target = fadingViews.get(i); + ArrayList<View> targetViews = mCallback.getTranslationViews(); + for (View target : targetViews) { target.animate().cancel(); } View targetView = mTranslation > 0 ? mLeftIcon : mRightIcon; @@ -301,11 +291,6 @@ public class KeyguardPageSwipeHelper { // translation Animation startTranslationAnimations(vel, target); - // fade animations - if (snapBack) { - startFadeInAnimations(); - } - // animate left / right icon startIconAnimation(vel, snapBack, target); @@ -361,20 +346,9 @@ public class KeyguardPageSwipeHelper { mSwipeAnimator = animator; } - private void startFadeInAnimations() { - ArrayList<View> fadingViews = mCallback.getFadingViews(); - int length = fadingViews.size(); - for (int i = 0; i < length; i++) { - View targetView = fadingViews.get(i); - targetView.animate().alpha(1.0f); - } - } - private void startTranslationAnimations(float vel, float target) { ArrayList<View> targetViews = mCallback.getTranslationViews(); - int length = targetViews.size(); - for (int i = 0; i < length; i++) { - View targetView = targetViews.get(i); + for (View targetView : targetViews) { ViewPropertyAnimator animator = targetView.animate(); mFlingAnimationUtils.apply(animator, mTranslation, target, vel); animator.translationX(target); @@ -401,18 +375,8 @@ public class KeyguardPageSwipeHelper { translation = leftSwipePossible() ? translation : Math.min(0, translation); if (translation != mTranslation || isReset) { ArrayList<View> translatedViews = mCallback.getTranslationViews(); - int length = translatedViews.size(); - for (int i = 0; i < length; i++) { - View target = translatedViews.get(i); - target.setTranslationX(translation); - } - float targetAlpha = 1.0f - Math.abs(translation / mMinTranslationAmount); - targetAlpha = Math.max(0.0f, targetAlpha); - ArrayList<View> fadingViews = mCallback.getFadingViews(); - length = fadingViews.size(); - for (int i = 0; i < length; i++) { - View view = fadingViews.get(i); - view.setAlpha(targetAlpha); + for (View view : translatedViews) { + view.setTranslationX(translation); } if (translation == 0.0f) { boolean animate = !isReset; @@ -530,8 +494,6 @@ public class KeyguardPageSwipeHelper { ArrayList<View> getTranslationViews(); - ArrayList<View> getFadingViews(); - View getLeftIcon(); View getCenterIcon(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index 5c686fc..34179cb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -108,7 +108,6 @@ public class NotificationPanelView extends PanelView implements private KeyguardBottomAreaView mKeyguardBottomArea; private boolean mBlockTouches; private ArrayList<View> mSwipeTranslationViews = new ArrayList<>(); - private ArrayList<View> mSwipeFadingViews = new ArrayList<>(); public NotificationPanelView(Context context, AttributeSet attrs) { super(context, attrs); @@ -153,7 +152,7 @@ public class NotificationPanelView extends PanelView implements android.R.interpolator.fast_out_linear_in); mKeyguardBottomArea = (KeyguardBottomAreaView) findViewById(R.id.keyguard_bottom_area); mSwipeTranslationViews.add(mNotificationStackScroller); - mSwipeFadingViews.add(mKeyguardStatusView); + mSwipeTranslationViews.add(mKeyguardStatusView); mPageSwiper = new KeyguardPageSwipeHelper(this, getContext()); } @@ -696,11 +695,6 @@ public class NotificationPanelView extends PanelView implements } @Override - protected boolean hasNotifications() { - return mNotificationStackScroller.getNotGoneChildCount() > 0; - } - - @Override protected int getMaxPanelHeight() { // TODO: Figure out transition for collapsing when QS is open, adjust height here. int emptyBottomMargin = mNotificationStackScroller.getEmptyBottomMargin(); @@ -964,11 +958,6 @@ public class NotificationPanelView extends PanelView implements } @Override - public ArrayList<View> getFadingViews() { - return mSwipeFadingViews; - } - - @Override public View getLeftIcon() { return getLayoutDirection() == LAYOUT_DIRECTION_RTL ? mKeyguardBottomArea.getCameraImageView() diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java index 08305dc..1f3098d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -30,8 +30,6 @@ import android.view.ViewConfiguration; import android.view.ViewTreeObserver; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; -import android.view.animation.LinearInterpolator; -import android.view.animation.PathInterpolator; import android.widget.FrameLayout; import com.android.systemui.R; @@ -45,8 +43,6 @@ public abstract class PanelView extends FrameLayout { public static final boolean DEBUG = PanelBar.DEBUG; public static final String TAG = PanelView.class.getSimpleName(); - private static final long KEYGUARD_MOVE_UP_LENGTH = 300; - private final void logf(String fmt, Object... args) { Log.v(TAG, (mViewName != null ? (mViewName + ": ") : "") + String.format(fmt, args)); } @@ -66,9 +62,6 @@ public abstract class PanelView extends FrameLayout { protected int mTouchSlop; protected boolean mHintAnimationRunning; private boolean mOverExpandedBeforeFling; - private boolean mKeyguardMovingUp; - private int mKeyguardMoveUpDistance; - private float mKeyguardFingerHeight; private ValueAnimator mHeightAnimator; private ObjectAnimator mPeekAnimator; @@ -89,8 +82,6 @@ public abstract class PanelView extends FrameLayout { private Interpolator mLinearOutSlowInInterpolator; private Interpolator mBounceInterpolator; - private Interpolator mKeyguardMoveUpInterpolator; - private final Interpolator mLinearInterpolator = new LinearInterpolator(); protected void onExpandingFinished() { mBar.onExpandingFinished(); @@ -118,7 +109,6 @@ public abstract class PanelView extends FrameLayout { mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context, android.R.interpolator.fast_out_slow_in); mBounceInterpolator = new BounceInterpolator(); - mKeyguardMoveUpInterpolator = new PathInterpolator(0.6f, 0f, 0.4f, 1f); } protected void loadDimens() { @@ -130,8 +120,6 @@ public abstract class PanelView extends FrameLayout { mTouchSlop = configuration.getScaledTouchSlop(); mHintDistance = res.getDimension(R.dimen.hint_move_distance); mEdgeTapAreaWidth = res.getDimensionPixelSize(R.dimen.edge_tap_area_width); - mKeyguardMoveUpDistance = - res.getDimensionPixelSize(R.dimen.keyguard_panel_move_up_distance); } private void trackMovement(MotionEvent event) { @@ -229,13 +217,8 @@ public abstract class PanelView extends FrameLayout { mJustPeeked = false; } if (!mJustPeeked && (!waitForTouchSlop || mTracking)) { - if (mStatusBar.getBarState() == StatusBarState.KEYGUARD && - !hasNotifications()) { - setExpandedHeightKeyguard(newHeight); - } else { - setExpandedHeightInternal(newHeight); - mBar.panelExpansionChanged(PanelView.this, mExpandedFraction); - } + setExpandedHeightInternal(newHeight); + mBar.panelExpansionChanged(PanelView.this, mExpandedFraction); } trackMovement(event); @@ -264,56 +247,10 @@ public abstract class PanelView extends FrameLayout { return !waitForTouchSlop || mTracking; } - protected abstract boolean hasNotifications(); - - private void setExpandedHeightKeyguard(float newHeight) { - mKeyguardFingerHeight = newHeight; - if (newHeight < getMaxPanelHeight() && !mKeyguardMovingUp) { - mKeyguardMovingUp = true; - ValueAnimator anim = createHeightAnimator( - getMaxPanelHeight() - mKeyguardMoveUpDistance); - anim.setDuration(KEYGUARD_MOVE_UP_LENGTH); - anim.setInterpolator(mKeyguardMoveUpInterpolator); - anim.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mHeightAnimator = null; - } - }); - mHeightAnimator = anim; - anim.start(); - postOnAnimationDelayed(new Runnable() { - @Override - public void run() { - if (mKeyguardFingerHeight < mExpandedHeight && mHeightAnimator != null - && mKeyguardMovingUp) { - mHeightAnimator.cancel(); - float target = getMaxPanelHeight() - 1.75f * mKeyguardMoveUpDistance; - float diff = mExpandedHeight - target; - ValueAnimator anim = createHeightAnimator(target); - float velocity = 2.5f * mKeyguardMoveUpDistance / - (KEYGUARD_MOVE_UP_LENGTH / 1000f); - anim.setInterpolator(mLinearInterpolator); - anim.setDuration(Math.max(0, (long) (diff / velocity * 1000f))); - anim.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mHeightAnimator = null; - } - }); - mHeightAnimator = anim; - anim.start(); - } - } - }, KEYGUARD_MOVE_UP_LENGTH / 2); - } - } - protected abstract boolean hasConflictingGestures(); protected void onTrackingStopped(boolean expand) { mTracking = false; - mKeyguardMovingUp = false; mBar.onTrackingStopped(PanelView.this, expand); } @@ -444,9 +381,6 @@ public abstract class PanelView extends FrameLayout { protected void fling(float vel, boolean expand) { cancelPeek(); - if (mHeightAnimator != null) { - mHeightAnimator.cancel(); - } float target = expand ? getMaxPanelHeight() : 0.0f; if (target == mExpandedHeight || getOverExpansionAmount() > 0f && expand) { onExpandingFinished(); 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 b23992d..1da7dab 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -2532,6 +2532,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, repositionNavigationBar(); updateExpandedViewPos(EXPANDED_LEAVE_ALONE); updateShowSearchHoldoff(); + updateRowStates(); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java index 94472a3..4e1b686 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -241,11 +241,12 @@ public class NotificationStackScrollLayout extends ViewGroup mBottomStackPeekSize = context.getResources() .getDimensionPixelSize(R.dimen.bottom_stack_peek_amount); mStackScrollAlgorithm = new StackScrollAlgorithm(context); + mStackScrollAlgorithm.setDimmed(mAmbientState.isDimmed()); mPaddingBetweenElementsDimmed = context.getResources() .getDimensionPixelSize(R.dimen.notification_padding_dimmed); mPaddingBetweenElementsNormal = context.getResources() .getDimensionPixelSize(R.dimen.notification_padding); - updatePadding(false); + updatePadding(mAmbientState.isDimmed()); int minHeight = getResources().getDimensionPixelSize(R.dimen.notification_min_height); int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_max_height); mExpandHelper = new ExpandHelper(getContext(), this, diff --git a/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java b/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java index b2ecb61..4ad45a8 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java +++ b/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java @@ -40,9 +40,6 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler { private static String TAG = "PhoneFallbackEventHandler"; private static final boolean DEBUG = false; - // Use the new sessions APIs - private static final boolean USE_SESSIONS = true; - Context mContext; View mView; @@ -294,21 +291,7 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler { } private void handleMediaKeyEvent(KeyEvent keyEvent) { - if (USE_SESSIONS) { - MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(keyEvent, false); - } else { - IAudioService audioService = IAudioService.Stub.asInterface( - ServiceManager.checkService(Context.AUDIO_SERVICE)); - if (audioService != null) { - try { - audioService.dispatchMediaKeyEvent(keyEvent); - } catch (RemoteException e) { - Log.e(TAG, "dispatchMediaKeyEvent threw exception " + e); - } - } else { - Slog.w(TAG, "Unable to find IAudioService for media key event."); - } - } + MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(keyEvent, false); } } diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index 5598972..bc2671011 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -144,9 +144,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { static final boolean ENABLE_CAR_DOCK_HOME_CAPTURE = true; static final boolean ENABLE_DESK_DOCK_HOME_CAPTURE = false; - // Whether to use the new Session APIs - static final boolean USE_SESSIONS = true; - static final int SHORT_PRESS_POWER_NOTHING = 0; static final int SHORT_PRESS_POWER_GO_TO_SLEEP = 1; static final int SHORT_PRESS_POWER_REALLY_GO_TO_SLEEP = 2; @@ -3974,6 +3971,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { * controlled by this device, or through remote submix). */ boolean isMusicActive() { + final AudioManager am = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE); if (am == null) { Log.w(TAG, "isMusicActive: couldn't get AudioManager reference"); @@ -3982,43 +3980,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { return am.isLocalOrRemoteMusicActive(); } - /** - * Tell the audio service to adjust the volume appropriate to the event. - * @param keycode - */ - void handleVolumeKey(int stream, int keycode) { - IAudioService audioService = getAudioService(); - if (audioService == null) { - return; - } - try { - // when audio is playing locally, we shouldn't have to hold a wake lock - // during the call, but we do it as a precaution for the rare possibility - // that the music stops right before we call this. - // Otherwise we might also be in a remote playback case. - // TODO: Actually handle MUTE. - mBroadcastWakeLock.acquire(); - if (stream == AudioSystem.STREAM_MUSIC) { - audioService.adjustLocalOrRemoteStreamVolume(stream, - keycode == KeyEvent.KEYCODE_VOLUME_UP - ? AudioManager.ADJUST_RAISE - : AudioManager.ADJUST_LOWER, - mContext.getOpPackageName()); - } else { - audioService.adjustStreamVolume(stream, - keycode == KeyEvent.KEYCODE_VOLUME_UP - ? AudioManager.ADJUST_RAISE - : AudioManager.ADJUST_LOWER, - 0, - mContext.getOpPackageName()); - } - } catch (RemoteException e) { - Log.w(TAG, "IAudioService.adjust*StreamVolume() threw RemoteException " + e); - } finally { - mBroadcastWakeLock.release(); - } - } - final Object mScreenshotLock = new Object(); ServiceConnection mScreenshotConnection = null; @@ -4201,16 +4162,20 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (telephonyManager.isOffhook() && (result & ACTION_PASS_TO_USER) == 0) { // If we are in call but we decided not to pass the key to - // the application, handle the volume change here. - handleVolumeKey(AudioManager.STREAM_VOICE_CALL, keyCode); + // the application, just pass it to the session service. + + MediaSessionLegacyHelper.getHelper(mContext) + .sendMediaButtonEvent(event, true); break; } } - if (isMusicActive() && (result & ACTION_PASS_TO_USER) == 0) { - // If music is playing but we decided not to pass the key to the - // application, handle the volume change here. - handleVolumeKey(AudioManager.STREAM_MUSIC, keyCode); + if ((result & ACTION_PASS_TO_USER) == 0) { + // If we aren't passing to the user and no one else + // handled it send it to the session manager to figure + // out. + MediaSessionLegacyHelper.getHelper(mContext) + .sendMediaButtonEvent(event, true); break; } } @@ -4459,18 +4424,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { void dispatchMediaKeyWithWakeLockToAudioService(KeyEvent event) { if (ActivityManagerNative.isSystemReady()) { - if (USE_SESSIONS) { - MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(event, true); - } else { - IAudioService audioService = getAudioService(); - if (audioService != null) { - try { - audioService.dispatchMediaKeyEventUnderWakelock(event); - } catch (RemoteException e) { - Log.e(TAG, "dispatchMediaKeyEvent threw exception " + e); - } - } - } + MediaSessionLegacyHelper.getHelper(mContext).sendMediaButtonEvent(event, true); } } diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java index e2a8ca2..07c9048 100644 --- a/services/core/java/com/android/server/BluetoothManagerService.java +++ b/services/core/java/com/android/server/BluetoothManagerService.java @@ -308,6 +308,10 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } public IBluetooth registerAdapter(IBluetoothManagerCallback callback){ + if (callback == null) { + Log.w(TAG, "Callback is null in registerAdapter"); + return null; + } Message msg = mHandler.obtainMessage(MESSAGE_REGISTER_ADAPTER); msg.obj = callback; mHandler.sendMessage(msg); @@ -317,6 +321,10 @@ class BluetoothManagerService extends IBluetoothManager.Stub { } public void unregisterAdapter(IBluetoothManagerCallback callback) { + if (callback == null) { + Log.w(TAG, "Callback is null in unregisterAdapter"); + return; + } mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); Message msg = mHandler.obtainMessage(MESSAGE_UNREGISTER_ADAPTER); diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index 5fffada..eb356e9 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -897,7 +897,7 @@ public final class HdmiControlService extends SystemService { } @Override - public void sendKeyEvent(int keyCode) { + public void sendKeyEvent(int keyCode, boolean isPressed) { // TODO: Implement this } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 06732ca..825dc84 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -2268,16 +2268,15 @@ public class NotificationManagerService extends SystemService { // lock on mNotificationList int indexOfNotificationLocked(String key) { - NotificationRecord r = mNotificationsByKey.get(key); - if (r == null) { - return -1; + final int N = mNotificationList.size(); + for (int i = 0; i < N; i++) { + if (key.equals(mNotificationList.get(i).getKey())) { + return i; + } } - int index = Collections.binarySearch(mNotificationList, r, mRankingComparator); - // Guarantee to return -1 when not found. - return (index >= 0) ? index : -1; + return -1; } - private void updateNotificationPulse() { synchronized (mNotificationList) { updateLightsLocked(); diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 3ed73f7..dd33771 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -28,7 +28,7 @@ import android.content.pm.IPackageInstallerSession; import android.content.pm.PackageInstallerParams; import android.content.pm.PackageManager; import android.content.pm.PackageParser; -import android.content.pm.PackageParser.PackageLite; +import android.content.pm.PackageParser.ApkLite; import android.content.pm.Signature; import android.os.Build; import android.os.Bundle; @@ -297,7 +297,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { // Verify that all staged packages are internally consistent for (File file : files) { - final PackageLite info = PackageParser.parsePackageLite(file.getAbsolutePath(), + final ApkLite info = PackageParser.parseApkLite(file.getAbsolutePath(), PackageParser.PARSE_GET_SIGNATURES); if (info == null) { throw new InstallFailedException(INSTALL_FAILED_INVALID_APK, @@ -356,7 +356,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { "Missing existing base package for " + mPackageName); } - final PackageLite info = PackageParser.parsePackageLite(app.sourceDir, + final ApkLite info = PackageParser.parseApkLite(app.sourceDir, PackageParser.PARSE_GET_SIGNATURES); if (info == null) { throw new InstallFailedException(INSTALL_FAILED_INVALID_APK, diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 2394a6c..1209386 100755 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -93,6 +93,7 @@ import android.content.pm.PackageInfoLite; import android.content.pm.PackageInstallerParams; import android.content.pm.PackageManager; import android.content.pm.PackageParser.ActivityIntentInfo; +import android.content.pm.PackageParser.PackageParserException; import android.content.pm.PackageParser; import android.content.pm.PackageStats; import android.content.pm.PackageUserState; @@ -136,6 +137,7 @@ import android.system.ErrnoException; import android.system.Os; import android.system.StructStat; import android.text.TextUtils; +import android.util.ArraySet; import android.util.AtomicFile; import android.util.DisplayMetrics; import android.util.EventLog; @@ -412,9 +414,6 @@ public class PackageManagerService extends IPackageManager.Stub { final HashMap<String, SharedLibraryEntry> mSharedLibraries = new HashMap<String, SharedLibraryEntry>(); - // Temporary for building the final shared libraries for an .apk. - String[] mTmpSharedLibraries = null; - // These are the features this devices supports that were read from the // etc/permissions.xml file. final HashMap<String, FeatureInfo> mAvailableFeatures = @@ -2243,8 +2242,7 @@ public class PackageManagerService extends IPackageManager.Stub { if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) == 0) { return null; } - // TODO: teach about reading split name - pkg = new PackageParser.Package(packageName, null); + pkg = new PackageParser.Package(packageName); pkg.applicationInfo.packageName = packageName; pkg.applicationInfo.flags = ps.pkgFlags | ApplicationInfo.FLAG_IS_DATA_ONLY; pkg.applicationInfo.publicSourceDir = ps.resourcePathString; @@ -4072,19 +4070,19 @@ public class PackageManagerService extends IPackageManager.Stub { private boolean createIdmapForPackagePairLI(PackageParser.Package pkg, PackageParser.Package opkg) { if (!opkg.mTrustedOverlay) { - Slog.w(TAG, "Skipping target and overlay pair " + pkg.mScanPath + " and " + - opkg.mScanPath + ": overlay not trusted"); + Slog.w(TAG, "Skipping target and overlay pair " + pkg.codePath + " and " + + opkg.codePath + ": overlay not trusted"); return false; } HashMap<String, PackageParser.Package> overlaySet = mOverlays.get(pkg.packageName); if (overlaySet == null) { - Slog.e(TAG, "was about to create idmap for " + pkg.mScanPath + " and " + - opkg.mScanPath + " but target package has no known overlays"); + Slog.e(TAG, "was about to create idmap for " + pkg.codePath + " and " + + opkg.codePath + " but target package has no known overlays"); return false; } final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid); - if (mInstaller.idmap(pkg.mScanPath, opkg.mScanPath, sharedGid) != 0) { - Slog.e(TAG, "Failed to generate idmap for " + pkg.mScanPath + " and " + opkg.mScanPath); + if (mInstaller.idmap(pkg.codePath, opkg.codePath, sharedGid) != 0) { + Slog.e(TAG, "Failed to generate idmap for " + pkg.codePath + " and " + opkg.codePath); return false; } PackageParser.Package[] overlayArray = @@ -4179,8 +4177,10 @@ public class PackageManagerService extends IPackageManager.Stub { Log.i(TAG, srcFile.toString() + " changed; collecting certs"); } - if (!pp.collectCertificates(pkg, parseFlags)) { - mLastScanError = pp.getParseError(); + try { + pp.collectCertificates(pkg, parseFlags); + } catch (PackageParserException e) { + mLastScanError = e.error; return false; } return true; @@ -4199,11 +4199,13 @@ public class PackageManagerService extends IPackageManager.Stub { PackageParser pp = new PackageParser(scanPath); pp.setSeparateProcesses(mSeparateProcesses); pp.setOnlyCoreApps(mOnlyCore); - final PackageParser.Package pkg = pp.parsePackage(scanFile, - scanPath, mMetrics, parseFlags, (scanMode & SCAN_TRUSTED_OVERLAY) != 0); - if (pkg == null) { - mLastScanError = pp.getParseError(); + final PackageParser.Package pkg; + try { + pkg = pp.parseMonolithicPackage(scanFile, mMetrics, parseFlags, + (scanMode & SCAN_TRUSTED_OVERLAY) != 0); + } catch (PackageParserException e) { + mLastScanError = e.error; return null; } @@ -4370,12 +4372,13 @@ public class PackageManagerService extends IPackageManager.Stub { Slog.e(TAG, "Resource path not set for pkg : " + pkg.packageName); } } else { - resPath = pkg.mScanPath; + resPath = pkg.codePath; } - codePath = pkg.mScanPath; + codePath = pkg.codePath; // Set application objects path explicitly. - setApplicationInfoPaths(pkg, codePath, resPath); + pkg.applicationInfo.sourceDir = codePath; + pkg.applicationInfo.publicSourceDir = resPath; // Note that we invoke the following method only if we are about to unpack an application PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanMode | SCAN_UPDATE_SIGNATURE, currentTime, user, abiOverride); @@ -4400,13 +4403,6 @@ public class PackageManagerService extends IPackageManager.Stub { return scannedPkg; } - private static void setApplicationInfoPaths(PackageParser.Package pkg, String destCodePath, - String destResPath) { - pkg.mPath = pkg.mScanPath = destCodePath; - pkg.applicationInfo.sourceDir = destCodePath; - pkg.applicationInfo.publicSourceDir = destResPath; - } - private static String fixProcessName(String defProcessName, String processName, int uid) { if (processName == null) { @@ -4632,7 +4628,7 @@ public class PackageManagerService extends IPackageManager.Stub { boolean performed = false; if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) { - String path = pkg.mScanPath; + String path = pkg.codePath; try { boolean isDexOptNeededInternal = DexFile.isDexOptNeededInternal(path, pkg.packageName, @@ -4805,11 +4801,11 @@ public class PackageManagerService extends IPackageManager.Stub { return res; } - private int addSharedLibraryLPw(final SharedLibraryEntry file, int num, + private void addSharedLibraryLPw(ArraySet<String> usesLibraryFiles, SharedLibraryEntry file, PackageParser.Package changingLib) { if (file.path != null) { - mTmpSharedLibraries[num] = file.path; - return num+1; + usesLibraryFiles.add(file.path); + return; } PackageParser.Package p = mPackages.get(file.apk); if (changingLib != null && changingLib.packageName.equals(file.apk)) { @@ -4822,16 +4818,8 @@ public class PackageManagerService extends IPackageManager.Stub { } } if (p != null) { - String path = p.mPath; - for (int i=0; i<num; i++) { - if (mTmpSharedLibraries[i].equals(path)) { - return num; - } - } - mTmpSharedLibraries[num] = p.mPath; - return num+1; + usesLibraryFiles.add(p.codePath); } - return num; } private boolean updateSharedLibrariesLPw(PackageParser.Package pkg, @@ -4845,11 +4833,7 @@ public class PackageManagerService extends IPackageManager.Stub { } if (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null) { - if (mTmpSharedLibraries == null || - mTmpSharedLibraries.length < mSharedLibraries.size()) { - mTmpSharedLibraries = new String[mSharedLibraries.size()]; - } - int num = 0; + final ArraySet<String> usesLibraryFiles = new ArraySet<>(); int N = pkg.usesLibraries != null ? pkg.usesLibraries.size() : 0; for (int i=0; i<N; i++) { final SharedLibraryEntry file = mSharedLibraries.get(pkg.usesLibraries.get(i)); @@ -4860,7 +4844,7 @@ public class PackageManagerService extends IPackageManager.Stub { mLastScanError = PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY; return false; } - num = addSharedLibraryLPw(file, num, changingLib); + addSharedLibraryLPw(usesLibraryFiles, file, changingLib); } N = pkg.usesOptionalLibraries != null ? pkg.usesOptionalLibraries.size() : 0; for (int i=0; i<N; i++) { @@ -4870,13 +4854,12 @@ public class PackageManagerService extends IPackageManager.Stub { + " desires unavailable shared library " + pkg.usesOptionalLibraries.get(i) + "; ignoring!"); } else { - num = addSharedLibraryLPw(file, num, changingLib); + addSharedLibraryLPw(usesLibraryFiles, file, changingLib); } } - if (num > 0) { - pkg.usesLibraryFiles = new String[num]; - System.arraycopy(mTmpSharedLibraries, 0, - pkg.usesLibraryFiles, 0, num); + N = usesLibraryFiles.size(); + if (N > 0) { + pkg.usesLibraryFiles = usesLibraryFiles.toArray(new String[N]); } else { pkg.usesLibraryFiles = null; } @@ -4922,7 +4905,7 @@ public class PackageManagerService extends IPackageManager.Stub { private PackageParser.Package scanPackageLI(PackageParser.Package pkg, int parseFlags, int scanMode, long currentTime, UserHandle user, String abiOverride) { - File scanFile = new File(pkg.mScanPath); + final File scanFile = new File(pkg.codePath); if (scanFile == null || pkg.applicationInfo.sourceDir == null || pkg.applicationInfo.publicSourceDir == null) { // Bail out. The resource and code paths haven't been set. @@ -5360,7 +5343,7 @@ public class PackageManagerService extends IPackageManager.Stub { pkgSetting.uidError = uidError; } - String path = scanFile.getPath(); + final String path = scanFile.getPath(); /* Note: We don't want to unpack the native binaries for * system applications, unless they have been updated * (the binaries are already under /system/lib). @@ -5491,7 +5474,6 @@ public class PackageManagerService extends IPackageManager.Stub { handle.close(); } } - pkg.mScanPath = path; if ((scanMode&SCAN_BOOTING) == 0 && pkgSetting.sharedUser != null) { // We don't do this here during boot because we can do it all @@ -5636,7 +5618,7 @@ public class PackageManagerService extends IPackageManager.Stub { synchronized (mPackages) { // We don't expect installation to fail beyond this point, if ((scanMode&SCAN_MONITOR) != 0) { - mAppDirs.put(pkg.mPath, pkg); + mAppDirs.put(pkg.codePath, pkg); } // Add the new setting to mSettings mSettings.insertPackageSettingLPw(pkgSetting, pkg); @@ -6257,8 +6239,8 @@ public class PackageManagerService extends IPackageManager.Stub { // writer synchronized (mPackages) { mPackages.remove(pkg.applicationInfo.packageName); - if (pkg.mPath != null) { - mAppDirs.remove(pkg.mPath); + if (pkg.codePath != null) { + mAppDirs.remove(pkg.codePath); } cleanPackageDataStructuresLILPw(pkg, chatty); } @@ -9825,7 +9807,7 @@ public class PackageManagerService extends IPackageManager.Stub { res.returnCode = PackageManager.INSTALL_FAILED_ALREADY_EXISTS; return; } - if (mPackages.containsKey(pkgName) || mAppDirs.containsKey(pkg.mPath)) { + if (mPackages.containsKey(pkgName) || mAppDirs.containsKey(pkg.codePath)) { // Don't allow installation over an existing package with the same name. Slog.w(TAG, "Attempt to re-install " + pkgName + " without first uninstalling."); @@ -9837,15 +9819,12 @@ public class PackageManagerService extends IPackageManager.Stub { PackageParser.Package newPackage = scanPackageLI(pkg, parseFlags, scanMode, System.currentTimeMillis(), user, abiOverride); if (newPackage == null) { - Slog.w(TAG, "Package couldn't be installed in " + pkg.mPath); + Slog.w(TAG, "Package couldn't be installed in " + pkg.codePath); if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) { res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK; } } else { - updateSettingsLI(newPackage, - installerPackageName, - null, null, - res); + updateSettingsLI(null, newPackage, installerPackageName, null, null, res); // delete the partially installed application. the data directory will have to be // restored if it was already existing if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) { @@ -9930,15 +9909,13 @@ public class PackageManagerService extends IPackageManager.Stub { newPackage = scanPackageLI(pkg, parseFlags, scanMode | SCAN_UPDATE_TIME, System.currentTimeMillis(), user, abiOverride); if (newPackage == null) { - Slog.w(TAG, "Package couldn't be installed in " + pkg.mPath); + Slog.w(TAG, "Package couldn't be installed in " + pkg.codePath); if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) { res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK; } } else { - updateSettingsLI(newPackage, - installerPackageName, - allUsers, perUserInstalled, - res); + updateSettingsLI(deletedPackage, newPackage, installerPackageName, allUsers, + perUserInstalled, res); updatedSettings = true; } } @@ -9959,7 +9936,7 @@ public class PackageManagerService extends IPackageManager.Stub { // package that we deleted. if (deletedPkg) { if (DEBUG_INSTALL) Slog.d(TAG, "Install failed, reinstalling: " + deletedPackage); - File restoreFile = new File(deletedPackage.mPath); + File restoreFile = new File(deletedPackage.codePath); // Parse old package boolean oldOnSd = isExternal(deletedPackage); int oldParseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY | @@ -10044,7 +10021,7 @@ public class PackageManagerService extends IPackageManager.Stub { pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; newPackage = scanPackageLI(pkg, parseFlags, scanMode, 0, user, abiOverride); if (newPackage == null) { - Slog.w(TAG, "Package couldn't be installed in " + pkg.mPath); + Slog.w(TAG, "Package couldn't be installed in " + pkg.codePath); if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) { res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK; } @@ -10064,7 +10041,8 @@ public class PackageManagerService extends IPackageManager.Stub { } if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) { - updateSettingsLI(newPackage, installerPackageName, allUsers, perUserInstalled, res); + updateSettingsLI(deletedPackage, newPackage, installerPackageName, allUsers, + perUserInstalled, res); updatedSettings = true; } } @@ -10090,12 +10068,21 @@ public class PackageManagerService extends IPackageManager.Stub { } // Utility method used to move dex files during install. - private int moveDexFilesLI(PackageParser.Package newPackage) { - if ((newPackage.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) { + private int moveDexFilesLI(PackageParser.Package oldPackage, PackageParser.Package newPackage) { + // TODO: extend to handle splits + if ((newPackage.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0) { final String instructionSet = getAppInstructionSet(newPackage.applicationInfo); - int retCode = mInstaller.movedex(newPackage.mScanPath, newPackage.mPath, - instructionSet); - if (retCode != 0) { + + boolean moveSuccess = false; + if (oldPackage != null + && (oldPackage.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0) { + if (mInstaller.movedex(oldPackage.codePath, newPackage.codePath, instructionSet) + == 0) { + moveSuccess = true; + } + } + + if (!moveSuccess) { /* * Programs may be lazily run through dexopt, so the * source may not exist. However, something seems to @@ -10104,17 +10091,19 @@ public class PackageManagerService extends IPackageManager.Stub { * remove the target to make sure there isn't a stale * file from a previous version of the package. */ + if (oldPackage != null) { + mInstaller.rmdex(oldPackage.codePath, instructionSet); + } + mInstaller.rmdex(newPackage.codePath, instructionSet); newPackage.mDexOptNeeded = true; - mInstaller.rmdex(newPackage.mScanPath, instructionSet); - mInstaller.rmdex(newPackage.mPath, instructionSet); } } return PackageManager.INSTALL_SUCCEEDED; } - private void updateSettingsLI(PackageParser.Package newPackage, String installerPackageName, - int[] allUsers, boolean[] perUserInstalled, - PackageInstalledInfo res) { + private void updateSettingsLI(PackageParser.Package oldPackage, + PackageParser.Package newPackage, String installerPackageName, int[] allUsers, + boolean[] perUserInstalled, PackageInstalledInfo res) { String pkgName = newPackage.packageName; synchronized (mPackages) { //write settings. the installStatus will be incomplete at this stage. @@ -10124,13 +10113,13 @@ public class PackageManagerService extends IPackageManager.Stub { mSettings.writeLPr(); } - if ((res.returnCode = moveDexFilesLI(newPackage)) + if ((res.returnCode = moveDexFilesLI(oldPackage, newPackage)) != PackageManager.INSTALL_SUCCEEDED) { // Discontinue if moving dex files failed. return; } - if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + newPackage.mPath); + if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + newPackage.codePath); synchronized (mPackages) { updatePermissionsLPw(newPackage.packageName, newPackage, @@ -10197,12 +10186,16 @@ public class PackageManagerService extends IPackageManager.Stub { | (onSd ? PackageParser.PARSE_ON_SDCARD : 0); PackageParser pp = new PackageParser(tmpPackageFile.getPath()); pp.setSeparateProcesses(mSeparateProcesses); - final PackageParser.Package pkg = pp.parsePackage(tmpPackageFile, - null, mMetrics, parseFlags); - if (pkg == null) { - res.returnCode = pp.getParseError(); + + final PackageParser.Package pkg; + try { + pkg = pp.parseMonolithicPackage(tmpPackageFile, mMetrics, + parseFlags); + } catch (PackageParserException e) { + res.returnCode = e.error; return; } + String pkgName = res.name = pkg.packageName; if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY) != 0) { if ((pFlags&PackageManager.INSTALL_ALLOW_TEST) == 0) { @@ -10210,8 +10203,11 @@ public class PackageManagerService extends IPackageManager.Stub { return; } } - if (!pp.collectCertificates(pkg, parseFlags)) { - res.returnCode = pp.getParseError(); + + try { + pp.collectCertificates(pkg, parseFlags); + } catch (PackageParserException e) { + res.returnCode = e.error; return; } @@ -10316,7 +10312,9 @@ public class PackageManagerService extends IPackageManager.Stub { return; } // Set application objects path explicitly after the rename - setApplicationInfoPaths(pkg, args.getCodePath(), args.getResourcePath()); + pkg.codePath = args.getCodePath(); + pkg.applicationInfo.sourceDir = args.getCodePath(); + pkg.applicationInfo.publicSourceDir = args.getResourcePath(); pkg.applicationInfo.nativeLibraryDir = args.getNativeLibraryPath(); if (replace) { replacePackageLI(pkg, parseFlags, scanMode, args.user, @@ -11196,7 +11194,7 @@ public class PackageManagerService extends IPackageManager.Stub { publicSrcDir = applicationInfo.publicSourceDir; } } - int res = mInstaller.getSizeInfo(packageName, userHandle, p.mPath, libDirPath, + int res = mInstaller.getSizeInfo(packageName, userHandle, p.codePath, libDirPath, publicSrcDir, asecPath, getAppInstructionSetFromSettings(ps), pStats); if (res < 0) { @@ -12829,7 +12827,7 @@ public class PackageManagerService extends IPackageManager.Stub { + " Aborting move and returning error"); returnCode = PackageManager.MOVE_FAILED_INTERNAL_ERROR; } else { - final String oldCodePath = pkg.mPath; + final String oldCodePath = pkg.codePath; final String newCodePath = mp.targetArgs.getCodePath(); final String newResPath = mp.targetArgs.getResourcePath(); final String newNativePath = mp.targetArgs @@ -12859,18 +12857,20 @@ public class PackageManagerService extends IPackageManager.Stub { } if (returnCode == PackageManager.MOVE_SUCCEEDED) { - pkg.mPath = newCodePath; + PackageParser.Package oldPackage = new PackageParser.Package( + pkg.packageName); + oldPackage.codePath = pkg.codePath; + pkg.codePath = newCodePath; // Move dex files around - if (moveDexFilesLI(pkg) != PackageManager.INSTALL_SUCCEEDED) { + if (moveDexFilesLI(oldPackage, pkg) != PackageManager.INSTALL_SUCCEEDED) { // Moving of dex files failed. Set // error code and abort move. - pkg.mPath = pkg.mScanPath; + pkg.codePath = oldPackage.codePath; returnCode = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE; } } if (returnCode == PackageManager.MOVE_SUCCEEDED) { - pkg.mScanPath = newCodePath; pkg.applicationInfo.sourceDir = newCodePath; pkg.applicationInfo.publicSourceDir = newResPath; pkg.applicationInfo.nativeLibraryDir = newNativePath; diff --git a/telecomm/java/android/telecomm/PhoneApplication.java b/telecomm/java/android/telecomm/PhoneApplication.java new file mode 100644 index 0000000..1da54e0 --- /dev/null +++ b/telecomm/java/android/telecomm/PhoneApplication.java @@ -0,0 +1,183 @@ +package android.telecomm; + +import android.annotation.SystemApi; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ActivityInfo; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.provider.Settings; +import android.text.TextUtils; +import android.util.Log; + +import com.android.internal.telecomm.ITelecommService; + +import java.util.ArrayList; +import java.util.List; + +/** + * Class for managing the primary phone application that will receive incoming calls, and be allowed + * to make emergency outgoing calls. + * + * @hide + */ +public class PhoneApplication { + private static final String TAG = PhoneApplication.class.getSimpleName(); + private static final String TELECOMM_SERVICE_NAME = "telecomm"; + + /** + * Sets the specified package name as the default phone application. The caller of this method + * needs to have permission to write to secure settings. + * + * @hide + * */ + @SystemApi + public static void setDefaultPhoneApplication(String packageName, Context context) { + // Get old package name + String oldPackageName = Settings.Secure.getString(context.getContentResolver(), + Settings.Secure.PHONE_DEFAULT_APPLICATION); + + if (packageName != null && oldPackageName != null && packageName.equals(oldPackageName)) { + // No change + return; + } + + // Only make the change if the new package belongs to a valid phone application + List<ComponentName> componentNames = getInstalledPhoneApplications(context); + ComponentName foundComponent = null; + for (ComponentName componentName : componentNames) { + if (TextUtils.equals(componentName.getPackageName(), packageName)) { + foundComponent = componentName; + break; + } + } + + if (foundComponent != null) { + // Update the secure setting. + Settings.Secure.putString(context.getContentResolver(), + Settings.Secure.PHONE_DEFAULT_APPLICATION, foundComponent.getPackageName()); + } + } + + /** + * Returns the installed phone application that will be used to receive incoming calls, and is + * allowed to make emergency calls. + * + * The application will be returned in order of preference: + * 1) User selected phone application (if still installed) + * 2) Pre-installed system dialer (if not disabled) + * 3) Null + * + * @hide + * */ + @SystemApi + public static ComponentName getDefaultPhoneApplication(Context context) { + String defaultPackageName = Settings.Secure.getString(context.getContentResolver(), + Settings.Secure.PHONE_DEFAULT_APPLICATION); + + final List<ComponentName> componentNames = getInstalledPhoneApplications(context); + if (!TextUtils.isEmpty(defaultPackageName)) { + for (ComponentName componentName : componentNames) { + if (TextUtils.equals(componentName.getPackageName(), defaultPackageName)) { + return componentName; + } + } + } + + // No user-set dialer found, fallback to system dialer + ComponentName systemDialer = null; + try { + systemDialer = getTelecommService().getSystemPhoneApplication(); + } catch (RemoteException e) { + Log.e(TAG, "Error calling ITelecommService#getSystemPhoneApplication", e); + return null; + } + + if (systemDialer == null) { + // No system dialer configured at build time + return null; + } + + // Verify that the system dialer has not been disabled. + return getComponentName(componentNames, systemDialer.getPackageName()); + } + + /** + * Returns a list of installed and available phone applications. + * + * In order to appear in the list, a phone application must implement an intent-filter with + * the DIAL intent for the following schemes: + * + * 1) Empty scheme + * 2) tel Uri scheme + * + * @hide + **/ + @SystemApi + public static List<ComponentName> getInstalledPhoneApplications(Context context) { + PackageManager packageManager = context.getPackageManager(); + + // Get the list of apps registered for the DIAL intent with empty scheme + Intent intent = new Intent(Intent.ACTION_DIAL); + List<ResolveInfo> resolveInfoList = packageManager.queryIntentActivities(intent, 0); + + List<ComponentName> componentNames = new ArrayList<ComponentName> (); + + for (ResolveInfo resolveInfo : resolveInfoList) { + final ActivityInfo activityInfo = resolveInfo.activityInfo; + if (activityInfo == null) { + continue; + } + final ComponentName componentName = + new ComponentName(activityInfo.packageName, activityInfo.name); + componentNames.add(componentName); + } + + // TODO: Filter for apps that don't handle DIAL intent with tel scheme + return componentNames; + } + + /** + * Returns the {@link ComponentName} for the installed phone application for a given package + * name. + * + * @param context A valid context. + * @param packageName to retrieve the {@link ComponentName} for. + * + * @return The {@link ComponentName} for the installed phone application corresponding to the + * package name, or null if none is found. + * + * @hide + */ + @SystemApi + public static ComponentName getPhoneApplicationForPackageName(Context context, + String packageName) { + return getComponentName(getInstalledPhoneApplications(context), packageName); + } + + /** + * Returns the component from a list of application components that corresponds to the package + * name. + * + * @param componentNames A list of component names + * @param packageName The package name to look for + * @return The {@link ComponentName} that matches the provided packageName, or null if not + * found. + */ + private static ComponentName getComponentName(List<ComponentName> componentNames, + String packageName) { + for (ComponentName componentName : componentNames) { + if (TextUtils.equals(packageName, componentName.getPackageName())) { + return componentName; + } + } + return null; + } + + private static ITelecommService getTelecommService() { + return ITelecommService.Stub.asInterface(ServiceManager.getService(TELECOMM_SERVICE_NAME)); + } +} diff --git a/telecomm/java/android/telecomm/TelecommConstants.java b/telecomm/java/android/telecomm/TelecommConstants.java index 8300c92..4ca878e 100644 --- a/telecomm/java/android/telecomm/TelecommConstants.java +++ b/telecomm/java/android/telecomm/TelecommConstants.java @@ -55,6 +55,21 @@ public final class TelecommConstants { public static final String ACTION_CALL_SERVICE_SELECTOR = CallServiceSelector.class.getName(); /** + * Activity action: Ask the user to change the default phone application. This will show a + * dialog that asks the user whether they want to replace the current default phone application + * with the one defined in {@link #EXTRA_PACKAGE_NAME}. + */ + public static final String ACTION_CHANGE_DEFAULT_PHONE = + "android.telecomm.ACTION_CHANGE_DEFAULT_PHONE"; + + /** + * The PackageName string passed in as an extra for {@link #ACTION_CHANGE_DEFAULT_PHONE}. + * + * @see #ACTION_CHANGE_DEFAULT_PHONE + */ + public static final String EXTRA_PACKAGE_NAME = "package"; + + /** * Extra for {@link #ACTION_INCOMING_CALL} containing the {@link CallServiceDescriptor} that * describes the call service to use for the incoming call. */ diff --git a/telecomm/java/android/telecomm/TelecommManager.java b/telecomm/java/android/telecomm/TelecommManager.java new file mode 100644 index 0000000..a97e7e4 --- /dev/null +++ b/telecomm/java/android/telecomm/TelecommManager.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.telecomm; + +import android.content.Context; + +import com.android.internal.telecomm.ITelecommService; + +/** + * Provides access to Telecomm-related functionality. + */ +public class TelecommManager { + private static final String TAG = "TelecommManager"; + + private final Context mContext; + private final ITelecommService mService; + + /** @hide */ + public TelecommManager(Context context, ITelecommService service) { + Context appContext = context.getApplicationContext(); + if (appContext != null) { + mContext = appContext; + } else { + mContext = context; + } + + mService = service; + } + + /** {@hide} */ + public static TelecommManager from(Context context) { + return (TelecommManager) context.getSystemService(Context.TELECOMM_SERVICE); + } +} diff --git a/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl b/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl index 0e94ffb..638b86a 100644 --- a/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl +++ b/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl @@ -16,6 +16,8 @@ package com.android.internal.telecomm; +import android.content.ComponentName; + /** * Interface used to interact with Telecomm. Mostly this is used by TelephonyManager for passing * commands that were previously handled by ITelephony. @@ -38,4 +40,9 @@ interface ITelecommService { * @param showDialpad if true, make the dialpad visible initially. */ void showCallScreen(boolean showDialpad); + + /** + * Returns the component name of the phone application installed on the system partition. + */ + ComponentName getSystemPhoneApplication(); } diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index aaee99f..50bbb1e 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -1414,6 +1414,9 @@ public class TelephonyManager { // FIXME the argument to pass is subId ?? public int getSimState(int slotId) { long[] subId = SubscriptionManager.getSubId(slotId); + if (subId == null) { + return SIM_STATE_ABSENT; + } // FIXME Do not use a property to determine SIM_STATE, call // appropriate method on some object. String prop = diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java index 54ac71e..33ccad5 100644 --- a/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java +++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java @@ -493,7 +493,8 @@ public class WifiPasspointCredential implements Parcelable { } if (this.mType.equals("TLS")) { result = this.mRealm.equals(other.mRealm) && - this.mHomeSpFqdn.equals(other.mHomeSpFqdn); + this.mHomeSpFqdn.equals(other.mHomeSpFqdn) && + this.mClientCert.equals(other.mClientCert); } if (this.mType.equals("SIM")) { result = this.mMcc.equals(other.mMcc) && diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.java index 9fccf0a..f84ac88 100644 --- a/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.java +++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.java @@ -16,10 +16,18 @@ package android.net.wifi.passpoint; +import android.net.wifi.WifiConfiguration; +import android.net.wifi.ScanResult; import android.os.Parcelable; import android.os.Parcel; +import android.security.Credentials; import android.util.Log; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.List; + + /** @hide */ public class WifiPasspointPolicy implements Parcelable { @@ -43,6 +51,20 @@ public class WifiPasspointPolicy implements Parcelable { private int mRestriction;// Permitted values are "HomeSP", "RoamingPartner", or "Unrestricted" private boolean mIsHomeSp; + private final String INT_PRIVATE_KEY = "private_key"; + private final String INT_PHASE2 = "phase2"; + private final String INT_PASSWORD = "password"; + private final String INT_IDENTITY = "identity"; + private final String INT_EAP = "eap"; + private final String INT_CLIENT_CERT = "client_cert"; + private final String INT_CA_CERT = "ca_cert"; + private final String INT_ANONYMOUS_IDENTITY = "anonymous_identity"; + private final String INT_SIM_SLOT = "sim_slot"; + private final String INT_ENTERPRISEFIELD_NAME ="android.net.wifi.WifiConfiguration$EnterpriseField"; + private final String ISO8601DATEFORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'"; + private final String ENTERPRISE_PHASE2_MSCHAPV2 = "auth=MSCHAPV2"; + private final String ENTERPRISE_PHASE2_MSCHAP = "auth=MSCHAP"; + /** @hide */ public WifiPasspointPolicy(String name, String ssid, String bssid, WifiPasspointCredential pc, @@ -89,7 +111,7 @@ public class WifiPasspointPolicy implements Parcelable { } /** @hide */ - public boolean getHomeSp() { + public boolean isHomeSp() { return mIsHomeSp; } @@ -121,6 +143,142 @@ public class WifiPasspointPolicy implements Parcelable { return mRoamingPriority; } + public WifiConfiguration createWifiConfiguration() { + WifiConfiguration wfg = new WifiConfiguration(); + if (mBssid != null) { + Log.d(TAG, "create bssid:" + mBssid); + wfg.BSSID = mBssid; + } + + if (mSsid != null) { + Log.d(TAG, "create ssid:" + mSsid); + wfg.SSID = mSsid; + } + //TODO: 1. add pmf configuration + // 2. add ocsp configuration + // 3. add eap-sim configuration + /*Key management*/ + wfg.status = WifiConfiguration.Status.ENABLED; + wfg.allowedKeyManagement.clear(); + wfg.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP); + wfg.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X); + + /*Group Ciphers*/ + wfg.allowedGroupCiphers.clear(); + wfg.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP); + wfg.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP); + + /*Protocols*/ + wfg.allowedProtocols.clear(); + wfg.allowedProtocols.set(WifiConfiguration.Protocol.RSN); + wfg.allowedProtocols.set(WifiConfiguration.Protocol.WPA); + + Class[] enterpriseFieldArray = WifiConfiguration.class.getClasses(); + Class<?> enterpriseFieldClass = null; + + + for(Class<?> myClass : enterpriseFieldArray) { + if(myClass.getName().equals(INT_ENTERPRISEFIELD_NAME)) { + enterpriseFieldClass = myClass; + break; + } + } + Log.d(TAG, "class chosen " + enterpriseFieldClass.getName() ); + + + Field anonymousId = null, caCert = null, clientCert = null, + eap = null, identity = null, password = null, + phase2 = null, privateKey = null; + + Field[] fields = WifiConfiguration.class.getFields(); + + + for (Field tempField : fields) { + if (tempField.getName().trim().equals(INT_ANONYMOUS_IDENTITY)) { + anonymousId = tempField; + Log.d(TAG, "field " + anonymousId.getName() ); + } else if (tempField.getName().trim().equals(INT_CA_CERT)) { + caCert = tempField; + } else if (tempField.getName().trim().equals(INT_CLIENT_CERT)) { + clientCert = tempField; + Log.d(TAG, "field " + clientCert.getName() ); + } else if (tempField.getName().trim().equals(INT_EAP)) { + eap = tempField; + Log.d(TAG, "field " + eap.getName() ); + } else if (tempField.getName().trim().equals(INT_IDENTITY)) { + identity = tempField; + Log.d(TAG, "field " + identity.getName() ); + } else if (tempField.getName().trim().equals(INT_PASSWORD)) { + password = tempField; + Log.d(TAG, "field " + password.getName() ); + } else if (tempField.getName().trim().equals(INT_PHASE2)) { + phase2 = tempField; + Log.d(TAG, "field " + phase2.getName() ); + + } else if (tempField.getName().trim().equals(INT_PRIVATE_KEY)) { + privateKey = tempField; + } + } + + + Method setValue = null; + + for(Method m: enterpriseFieldClass.getMethods()) { + if(m.getName().trim().equals("setValue")) { + Log.d(TAG, "method " + m.getName() ); + setValue = m; + break; + } + } + + try { + // EAP + String eapmethod = mCredential.getType(); + Log.d(TAG, "eapmethod:" + eapmethod); + setValue.invoke(eap.get(wfg), eapmethod); + + // Username, password, EAP Phase 2 + if ("TTLS".equals(eapmethod)) { + setValue.invoke(phase2.get(wfg), ENTERPRISE_PHASE2_MSCHAPV2); + setValue.invoke(identity.get(wfg), mCredential.getUserName()); + setValue.invoke(password.get(wfg), mCredential.getPassword()); + setValue.invoke(anonymousId.get(wfg), "anonymous@" + mCredential.getRealm()); + } + + // EAP CA Certificate + String cacertificate = null; + String rootCA = mCredential.getCaRootCertPath(); + if (rootCA == null){ + cacertificate = null; + } else { + cacertificate = "keystore://" + Credentials.WIFI + "HS20" + Credentials.CA_CERTIFICATE + rootCA; + } + Log.d(TAG, "cacertificate:" + cacertificate); + setValue.invoke(caCert.get(wfg), cacertificate); + + //User certificate + if ("TLS".equals(eapmethod)) { + String usercertificate = null; + String privatekey = null; + String clientCertPath = mCredential.getClientCertPath(); + if (clientCertPath != null){ + privatekey = "keystore://" + Credentials.WIFI + "HS20" + Credentials.USER_PRIVATE_KEY + clientCertPath; + usercertificate = "keystore://" + Credentials.WIFI + "HS20" + Credentials.USER_CERTIFICATE + clientCertPath; + } + Log.d(TAG, "privatekey:" + privatekey); + Log.d(TAG, "usercertificate:" + usercertificate); + if (privatekey != null && usercertificate != null) { + setValue.invoke(privateKey.get(wfg), privatekey); + setValue.invoke(clientCert.get(wfg), usercertificate); + } + } + } catch (Exception e) { + Log.d(TAG, "createWifiConfiguration err:" + e); + } + + return wfg; + } + /** {@inheritDoc} @hide */ public int compareTo(WifiPasspointPolicy another) { Log.d(TAG, "this:" + this); @@ -128,11 +286,11 @@ public class WifiPasspointPolicy implements Parcelable { if (another == null) { return -1; - } else if (this.mIsHomeSp == true && another.getHomeSp() == false) { + } else if (this.mIsHomeSp == true && another.isHomeSp() == false) { //home sp priority is higher then roaming Log.d(TAG, "compare HomeSP first, this is HomeSP, another isn't"); return -1; - } else if ((this.mIsHomeSp == true && another.getHomeSp() == true)) { + } else if ((this.mIsHomeSp == true && another.isHomeSp() == true)) { Log.d(TAG, "both HomeSP"); //if both home sp, compare credential priority if (this.mCredentialPriority < another.getCredentialPriority()) { @@ -160,7 +318,7 @@ public class WifiPasspointPolicy implements Parcelable { } else { return 1; } - } else if ((this.mIsHomeSp == false && another.getHomeSp() == false)) { + } else if ((this.mIsHomeSp == false && another.isHomeSp() == false)) { Log.d(TAG, "both RoamingSp"); //if both roaming sp, compare roaming priority(preferredRoamingPartnerList/<X+>/priority) if (this.mRoamingPriority < another.getRoamingPriority()) { |