Merge "Introduce FontsContract.fetchFonts and expose URI for watching." into oc-dev
diff --git a/api/current.txt b/api/current.txt
index 2924707..0873990 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -210,6 +210,7 @@
public static final class R.attr {
ctor public R.attr();
field public static final int __removed1 = 16844099; // 0x1010543
+ field public static final int __removed2 = 16844104; // 0x1010548
field public static final int absListViewStyle = 16842858; // 0x101006a
field public static final int accessibilityEventTypes = 16843648; // 0x1010380
field public static final int accessibilityFeedbackType = 16843650; // 0x1010382
@@ -471,6 +472,7 @@
field public static final deprecated int dayOfWeekBackground = 16843924; // 0x1010494
field public static final deprecated int dayOfWeekTextAppearance = 16843925; // 0x1010495
field public static final int debuggable = 16842767; // 0x101000f
+ field public static final int defaultFocusHighlightEnabled = 16844133; // 0x1010565
field public static final int defaultHeight = 16844021; // 0x10104f5
field public static final int defaultToDeviceProtectedStorage = 16844036; // 0x1010504
field public static final int defaultValue = 16843245; // 0x10101ed
@@ -1269,7 +1271,6 @@
field public static final int summaryOff = 16843248; // 0x10101f0
field public static final int summaryOn = 16843247; // 0x10101ef
field public static final int supportsAssist = 16844016; // 0x10104f0
- field public static final int supportsDismissingWindow = 16844104; // 0x1010548
field public static final int supportsLaunchVoiceAssistFromKeyguard = 16844017; // 0x10104f1
field public static final int supportsLocalInteraction = 16844047; // 0x101050f
field public static final int supportsPictureInPicture = 16844023; // 0x10104f7
@@ -10632,6 +10633,7 @@
field public static final java.lang.String FEATURE_AUDIO_LOW_LATENCY = "android.hardware.audio.low_latency";
field public static final java.lang.String FEATURE_AUDIO_OUTPUT = "android.hardware.audio.output";
field public static final java.lang.String FEATURE_AUDIO_PRO = "android.hardware.audio.pro";
+ field public static final java.lang.String FEATURE_AUTOFILL = "android.software.autofill";
field public static final java.lang.String FEATURE_AUTOMOTIVE = "android.hardware.type.automotive";
field public static final java.lang.String FEATURE_BACKUP = "android.software.backup";
field public static final java.lang.String FEATURE_BLUETOOTH = "android.hardware.bluetooth";
@@ -21808,24 +21810,19 @@
field public static final int STOP_VIDEO_RECORDING = 3; // 0x3
}
- public final class MediaCas {
+ public final class MediaCas implements java.lang.AutoCloseable {
ctor public MediaCas(int) throws android.media.MediaCasException.UnsupportedCasException;
- method public void closeSession(byte[]);
+ method public void close();
method public static android.media.MediaCas.PluginDescriptor[] enumeratePlugins();
method public static boolean isSystemIdSupported(int);
- method public byte[] openSession(int) throws android.media.MediaCasException;
- method public byte[] openSession(int, int) throws android.media.MediaCasException;
- method public void processEcm(byte[], byte[], int, int) throws android.media.MediaCasException;
- method public void processEcm(byte[], byte[]) throws android.media.MediaCasException;
+ method public android.media.MediaCas.Session openSession() throws android.media.MediaCasException;
method public void processEmm(byte[], int, int) throws android.media.MediaCasException;
method public void processEmm(byte[]) throws android.media.MediaCasException;
method public void provision(java.lang.String) throws android.media.MediaCasException;
method public void refreshEntitlements(int, byte[]) throws android.media.MediaCasException;
- method public void release();
method public void sendEvent(int, int, byte[]) throws android.media.MediaCasException;
method public void setEventListener(android.media.MediaCas.EventListener, android.os.Handler);
method public void setPrivateData(byte[]) throws android.media.MediaCasException;
- method public void setSessionPrivateData(byte[], byte[]) throws android.media.MediaCasException;
}
public static abstract interface MediaCas.EventListener {
@@ -21837,6 +21834,13 @@
method public int getSystemId();
}
+ public final class MediaCas.Session implements java.lang.AutoCloseable {
+ method public void close();
+ method public void processEcm(byte[], int, int) throws android.media.MediaCasException;
+ method public void processEcm(byte[]) throws android.media.MediaCasException;
+ method public void setPrivateData(byte[]) throws android.media.MediaCasException;
+ }
+
public class MediaCasException extends java.lang.Exception {
}
@@ -22280,12 +22284,12 @@
method public abstract int readAt(long, byte[], int, int) throws java.io.IOException;
}
- public final class MediaDescrambler {
+ public final class MediaDescrambler implements java.lang.AutoCloseable {
ctor public MediaDescrambler(int) throws android.media.MediaCasException.UnsupportedCasException;
- method public final int descramble(java.nio.ByteBuffer, int, java.nio.ByteBuffer, int, android.media.MediaCodec.CryptoInfo);
- method public final void release();
+ method public void close();
+ method public final int descramble(java.nio.ByteBuffer, java.nio.ByteBuffer, android.media.MediaCodec.CryptoInfo);
method public final boolean requiresSecureDecoderComponent(java.lang.String);
- method public final void setMediaCasSession(byte[]);
+ method public final void setMediaCasSession(android.media.MediaCas.Session);
}
public class MediaDescription implements android.os.Parcelable {
@@ -22423,6 +22427,7 @@
ctor public MediaExtractor();
method public boolean advance();
method public long getCachedDuration();
+ method public android.media.MediaExtractor.CasInfo getCasInfo(int);
method public android.media.DrmInitData getDrmInitData();
method public android.media.MediaMetricsSet getMetrics();
method public java.util.Map<java.util.UUID, byte[]> getPsshInfo();
@@ -22454,6 +22459,11 @@
field public static final int SEEK_TO_PREVIOUS_SYNC = 0; // 0x0
}
+ public static final class MediaExtractor.CasInfo {
+ method public android.media.MediaCas.Session getSession();
+ method public int getSystemId();
+ }
+
public final class MediaFormat {
ctor public MediaFormat();
method public final boolean containsKey(java.lang.String);
@@ -40139,7 +40149,8 @@
method public boolean hasIccCard();
method public boolean iccCloseLogicalChannel(int);
method public byte[] iccExchangeSimIO(int, int, int, int, int, java.lang.String);
- method public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(java.lang.String);
+ method public deprecated android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(java.lang.String);
+ method public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(java.lang.String, int);
method public java.lang.String iccTransmitApduBasicChannel(int, int, int, int, int, java.lang.String);
method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, java.lang.String);
method public boolean isConcurrentVoiceAndDataSupported();
@@ -42650,7 +42661,7 @@
method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String, java.lang.String[], android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter);
field public static final int ALL = 15; // 0xf
field public static final int EMAIL_ADDRESSES = 2; // 0x2
- field public static final int MAP_ADDRESSES = 8; // 0x8
+ field public static final deprecated int MAP_ADDRESSES = 8; // 0x8
field public static final int PHONE_NUMBERS = 4; // 0x4
field public static final int WEB_URLS = 1; // 0x1
field public static final android.text.util.Linkify.MatchFilter sPhoneNumberMatchFilter;
@@ -45361,6 +45372,7 @@
method public java.lang.CharSequence getContentDescription();
method public final android.content.Context getContext();
method protected android.view.ContextMenu.ContextMenuInfo getContextMenuInfo();
+ method public final boolean getDefaultFocusHighlightEnabled();
method public static int getDefaultSize(int, int);
method public android.view.Display getDisplay();
method public final int[] getDrawableState();
@@ -45679,6 +45691,7 @@
method public void setClipToOutline(boolean);
method public void setContentDescription(java.lang.CharSequence);
method public void setContextClickable(boolean);
+ method public void setDefaultFocusHighlightEnabled(boolean);
method public void setDrawingCacheBackgroundColor(int);
method public void setDrawingCacheEnabled(boolean);
method public void setDrawingCacheQuality(int);
@@ -48920,7 +48933,7 @@
method public void documentHasImages(android.os.Message);
method public static void enableSlowWholeDocumentDraw();
method public void evaluateJavascript(java.lang.String, android.webkit.ValueCallback<java.lang.String>);
- method public static java.lang.String findAddress(java.lang.String);
+ method public static deprecated java.lang.String findAddress(java.lang.String);
method public deprecated int findAll(java.lang.String);
method public void findAllAsync(java.lang.String);
method public void findNext(boolean);
diff --git a/api/system-current.txt b/api/system-current.txt
index 8f53d82..5cd3b0a 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -326,6 +326,7 @@
public static final class R.attr {
ctor public R.attr();
field public static final int __removed1 = 16844099; // 0x1010543
+ field public static final int __removed2 = 16844104; // 0x1010548
field public static final int absListViewStyle = 16842858; // 0x101006a
field public static final int accessibilityEventTypes = 16843648; // 0x1010380
field public static final int accessibilityFeedbackType = 16843650; // 0x1010382
@@ -587,6 +588,7 @@
field public static final deprecated int dayOfWeekBackground = 16843924; // 0x1010494
field public static final deprecated int dayOfWeekTextAppearance = 16843925; // 0x1010495
field public static final int debuggable = 16842767; // 0x101000f
+ field public static final int defaultFocusHighlightEnabled = 16844133; // 0x1010565
field public static final int defaultHeight = 16844021; // 0x10104f5
field public static final int defaultToDeviceProtectedStorage = 16844036; // 0x1010504
field public static final int defaultValue = 16843245; // 0x10101ed
@@ -1389,7 +1391,6 @@
field public static final int summaryOff = 16843248; // 0x10101f0
field public static final int summaryOn = 16843247; // 0x10101ef
field public static final int supportsAssist = 16844016; // 0x10104f0
- field public static final int supportsDismissingWindow = 16844104; // 0x1010548
field public static final int supportsLaunchVoiceAssistFromKeyguard = 16844017; // 0x10104f1
field public static final int supportsLocalInteraction = 16844047; // 0x101050f
field public static final int supportsPictureInPicture = 16844023; // 0x10104f7
@@ -3982,6 +3983,7 @@
method public android.app.PendingIntent getRunningServiceControlPanel(android.content.ComponentName) throws java.lang.SecurityException;
method public java.util.List<android.app.ActivityManager.RunningServiceInfo> getRunningServices(int) throws java.lang.SecurityException;
method public deprecated java.util.List<android.app.ActivityManager.RunningTaskInfo> getRunningTasks(int) throws java.lang.SecurityException;
+ method public int getUidImportance(int);
method public deprecated boolean isInLockTaskMode();
method public boolean isLowRamDevice();
method public static boolean isRunningInTestHarness();
@@ -11319,6 +11321,7 @@
field public static final java.lang.String FEATURE_AUDIO_LOW_LATENCY = "android.hardware.audio.low_latency";
field public static final java.lang.String FEATURE_AUDIO_OUTPUT = "android.hardware.audio.output";
field public static final java.lang.String FEATURE_AUDIO_PRO = "android.hardware.audio.pro";
+ field public static final java.lang.String FEATURE_AUTOFILL = "android.software.autofill";
field public static final java.lang.String FEATURE_AUTOMOTIVE = "android.hardware.type.automotive";
field public static final java.lang.String FEATURE_BACKUP = "android.software.backup";
field public static final java.lang.String FEATURE_BLUETOOTH = "android.hardware.bluetooth";
@@ -23636,24 +23639,19 @@
field public static final int STOP_VIDEO_RECORDING = 3; // 0x3
}
- public final class MediaCas {
+ public final class MediaCas implements java.lang.AutoCloseable {
ctor public MediaCas(int) throws android.media.MediaCasException.UnsupportedCasException;
- method public void closeSession(byte[]);
+ method public void close();
method public static android.media.MediaCas.PluginDescriptor[] enumeratePlugins();
method public static boolean isSystemIdSupported(int);
- method public byte[] openSession(int) throws android.media.MediaCasException;
- method public byte[] openSession(int, int) throws android.media.MediaCasException;
- method public void processEcm(byte[], byte[], int, int) throws android.media.MediaCasException;
- method public void processEcm(byte[], byte[]) throws android.media.MediaCasException;
+ method public android.media.MediaCas.Session openSession() throws android.media.MediaCasException;
method public void processEmm(byte[], int, int) throws android.media.MediaCasException;
method public void processEmm(byte[]) throws android.media.MediaCasException;
method public void provision(java.lang.String) throws android.media.MediaCasException;
method public void refreshEntitlements(int, byte[]) throws android.media.MediaCasException;
- method public void release();
method public void sendEvent(int, int, byte[]) throws android.media.MediaCasException;
method public void setEventListener(android.media.MediaCas.EventListener, android.os.Handler);
method public void setPrivateData(byte[]) throws android.media.MediaCasException;
- method public void setSessionPrivateData(byte[], byte[]) throws android.media.MediaCasException;
}
public static abstract interface MediaCas.EventListener {
@@ -23665,6 +23663,13 @@
method public int getSystemId();
}
+ public final class MediaCas.Session implements java.lang.AutoCloseable {
+ method public void close();
+ method public void processEcm(byte[], int, int) throws android.media.MediaCasException;
+ method public void processEcm(byte[]) throws android.media.MediaCasException;
+ method public void setPrivateData(byte[]) throws android.media.MediaCasException;
+ }
+
public class MediaCasException extends java.lang.Exception {
}
@@ -24108,12 +24113,12 @@
method public abstract int readAt(long, byte[], int, int) throws java.io.IOException;
}
- public final class MediaDescrambler {
+ public final class MediaDescrambler implements java.lang.AutoCloseable {
ctor public MediaDescrambler(int) throws android.media.MediaCasException.UnsupportedCasException;
- method public final int descramble(java.nio.ByteBuffer, int, java.nio.ByteBuffer, int, android.media.MediaCodec.CryptoInfo);
- method public final void release();
+ method public void close();
+ method public final int descramble(java.nio.ByteBuffer, java.nio.ByteBuffer, android.media.MediaCodec.CryptoInfo);
method public final boolean requiresSecureDecoderComponent(java.lang.String);
- method public final void setMediaCasSession(byte[]);
+ method public final void setMediaCasSession(android.media.MediaCas.Session);
}
public class MediaDescription implements android.os.Parcelable {
@@ -24251,6 +24256,7 @@
ctor public MediaExtractor();
method public boolean advance();
method public long getCachedDuration();
+ method public android.media.MediaExtractor.CasInfo getCasInfo(int);
method public android.media.DrmInitData getDrmInitData();
method public android.media.MediaMetricsSet getMetrics();
method public java.util.Map<java.util.UUID, byte[]> getPsshInfo();
@@ -24282,6 +24288,11 @@
field public static final int SEEK_TO_PREVIOUS_SYNC = 0; // 0x0
}
+ public static final class MediaExtractor.CasInfo {
+ method public android.media.MediaCas.Session getSession();
+ method public int getSystemId();
+ }
+
public final class MediaFormat {
ctor public MediaFormat();
method public final boolean containsKey(java.lang.String);
@@ -43638,7 +43649,8 @@
method public boolean hasIccCard();
method public boolean iccCloseLogicalChannel(int);
method public byte[] iccExchangeSimIO(int, int, int, int, int, java.lang.String);
- method public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(java.lang.String);
+ method public deprecated android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(java.lang.String);
+ method public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(java.lang.String, int);
method public java.lang.String iccTransmitApduBasicChannel(int, int, int, int, int, java.lang.String);
method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, java.lang.String);
method public boolean isConcurrentVoiceAndDataSupported();
@@ -46205,7 +46217,7 @@
method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String, java.lang.String[], android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter);
field public static final int ALL = 15; // 0xf
field public static final int EMAIL_ADDRESSES = 2; // 0x2
- field public static final int MAP_ADDRESSES = 8; // 0x8
+ field public static final deprecated int MAP_ADDRESSES = 8; // 0x8
field public static final int PHONE_NUMBERS = 4; // 0x4
field public static final int WEB_URLS = 1; // 0x1
field public static final android.text.util.Linkify.MatchFilter sPhoneNumberMatchFilter;
@@ -48917,6 +48929,7 @@
method public java.lang.CharSequence getContentDescription();
method public final android.content.Context getContext();
method protected android.view.ContextMenu.ContextMenuInfo getContextMenuInfo();
+ method public final boolean getDefaultFocusHighlightEnabled();
method public static int getDefaultSize(int, int);
method public android.view.Display getDisplay();
method public final int[] getDrawableState();
@@ -49235,6 +49248,7 @@
method public void setClipToOutline(boolean);
method public void setContentDescription(java.lang.CharSequence);
method public void setContextClickable(boolean);
+ method public void setDefaultFocusHighlightEnabled(boolean);
method public void setDrawingCacheBackgroundColor(int);
method public void setDrawingCacheEnabled(boolean);
method public void setDrawingCacheQuality(int);
@@ -52572,7 +52586,7 @@
method public void documentHasImages(android.os.Message);
method public static void enableSlowWholeDocumentDraw();
method public void evaluateJavascript(java.lang.String, android.webkit.ValueCallback<java.lang.String>);
- method public static java.lang.String findAddress(java.lang.String);
+ method public static deprecated java.lang.String findAddress(java.lang.String);
method public deprecated int findAll(java.lang.String);
method public void findAllAsync(java.lang.String);
method public void findNext(boolean);
diff --git a/api/test-current.txt b/api/test-current.txt
index cc219d4..c65d8da 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -210,6 +210,7 @@
public static final class R.attr {
ctor public R.attr();
field public static final int __removed1 = 16844099; // 0x1010543
+ field public static final int __removed2 = 16844104; // 0x1010548
field public static final int absListViewStyle = 16842858; // 0x101006a
field public static final int accessibilityEventTypes = 16843648; // 0x1010380
field public static final int accessibilityFeedbackType = 16843650; // 0x1010382
@@ -471,6 +472,7 @@
field public static final deprecated int dayOfWeekBackground = 16843924; // 0x1010494
field public static final deprecated int dayOfWeekTextAppearance = 16843925; // 0x1010495
field public static final int debuggable = 16842767; // 0x101000f
+ field public static final int defaultFocusHighlightEnabled = 16844133; // 0x1010565
field public static final int defaultHeight = 16844021; // 0x10104f5
field public static final int defaultToDeviceProtectedStorage = 16844036; // 0x1010504
field public static final int defaultValue = 16843245; // 0x10101ed
@@ -1269,7 +1271,6 @@
field public static final int summaryOff = 16843248; // 0x10101f0
field public static final int summaryOn = 16843247; // 0x10101ef
field public static final int supportsAssist = 16844016; // 0x10104f0
- field public static final int supportsDismissingWindow = 16844104; // 0x1010548
field public static final int supportsLaunchVoiceAssistFromKeyguard = 16844017; // 0x10104f1
field public static final int supportsLocalInteraction = 16844047; // 0x101050f
field public static final int supportsPictureInPicture = 16844023; // 0x10104f7
@@ -3849,6 +3850,7 @@
method public android.app.PendingIntent getRunningServiceControlPanel(android.content.ComponentName) throws java.lang.SecurityException;
method public java.util.List<android.app.ActivityManager.RunningServiceInfo> getRunningServices(int) throws java.lang.SecurityException;
method public deprecated java.util.List<android.app.ActivityManager.RunningTaskInfo> getRunningTasks(int) throws java.lang.SecurityException;
+ method public int getUidImportance(int);
method public deprecated boolean isInLockTaskMode();
method public boolean isLowRamDevice();
method public static boolean isRunningInTestHarness();
@@ -10671,6 +10673,7 @@
field public static final java.lang.String FEATURE_AUDIO_LOW_LATENCY = "android.hardware.audio.low_latency";
field public static final java.lang.String FEATURE_AUDIO_OUTPUT = "android.hardware.audio.output";
field public static final java.lang.String FEATURE_AUDIO_PRO = "android.hardware.audio.pro";
+ field public static final java.lang.String FEATURE_AUTOFILL = "android.software.autofill";
field public static final java.lang.String FEATURE_AUTOMOTIVE = "android.hardware.type.automotive";
field public static final java.lang.String FEATURE_BACKUP = "android.software.backup";
field public static final java.lang.String FEATURE_BLUETOOTH = "android.hardware.bluetooth";
@@ -14027,6 +14030,7 @@
method public boolean getPadding(android.graphics.Rect);
method public int[] getState();
method public android.graphics.Region getTransparentRegion();
+ method public boolean hasFocusStateSpecified();
method public void inflate(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
method public void inflate(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
method public void invalidateSelf();
@@ -21921,24 +21925,19 @@
field public static final int STOP_VIDEO_RECORDING = 3; // 0x3
}
- public final class MediaCas {
+ public final class MediaCas implements java.lang.AutoCloseable {
ctor public MediaCas(int) throws android.media.MediaCasException.UnsupportedCasException;
- method public void closeSession(byte[]);
+ method public void close();
method public static android.media.MediaCas.PluginDescriptor[] enumeratePlugins();
method public static boolean isSystemIdSupported(int);
- method public byte[] openSession(int) throws android.media.MediaCasException;
- method public byte[] openSession(int, int) throws android.media.MediaCasException;
- method public void processEcm(byte[], byte[], int, int) throws android.media.MediaCasException;
- method public void processEcm(byte[], byte[]) throws android.media.MediaCasException;
+ method public android.media.MediaCas.Session openSession() throws android.media.MediaCasException;
method public void processEmm(byte[], int, int) throws android.media.MediaCasException;
method public void processEmm(byte[]) throws android.media.MediaCasException;
method public void provision(java.lang.String) throws android.media.MediaCasException;
method public void refreshEntitlements(int, byte[]) throws android.media.MediaCasException;
- method public void release();
method public void sendEvent(int, int, byte[]) throws android.media.MediaCasException;
method public void setEventListener(android.media.MediaCas.EventListener, android.os.Handler);
method public void setPrivateData(byte[]) throws android.media.MediaCasException;
- method public void setSessionPrivateData(byte[], byte[]) throws android.media.MediaCasException;
}
public static abstract interface MediaCas.EventListener {
@@ -21950,6 +21949,13 @@
method public int getSystemId();
}
+ public final class MediaCas.Session implements java.lang.AutoCloseable {
+ method public void close();
+ method public void processEcm(byte[], int, int) throws android.media.MediaCasException;
+ method public void processEcm(byte[]) throws android.media.MediaCasException;
+ method public void setPrivateData(byte[]) throws android.media.MediaCasException;
+ }
+
public class MediaCasException extends java.lang.Exception {
}
@@ -22393,12 +22399,12 @@
method public abstract int readAt(long, byte[], int, int) throws java.io.IOException;
}
- public final class MediaDescrambler {
+ public final class MediaDescrambler implements java.lang.AutoCloseable {
ctor public MediaDescrambler(int) throws android.media.MediaCasException.UnsupportedCasException;
- method public final int descramble(java.nio.ByteBuffer, int, java.nio.ByteBuffer, int, android.media.MediaCodec.CryptoInfo);
- method public final void release();
+ method public void close();
+ method public final int descramble(java.nio.ByteBuffer, java.nio.ByteBuffer, android.media.MediaCodec.CryptoInfo);
method public final boolean requiresSecureDecoderComponent(java.lang.String);
- method public final void setMediaCasSession(byte[]);
+ method public final void setMediaCasSession(android.media.MediaCas.Session);
}
public class MediaDescription implements android.os.Parcelable {
@@ -22536,6 +22542,7 @@
ctor public MediaExtractor();
method public boolean advance();
method public long getCachedDuration();
+ method public android.media.MediaExtractor.CasInfo getCasInfo(int);
method public android.media.DrmInitData getDrmInitData();
method public android.media.MediaMetricsSet getMetrics();
method public java.util.Map<java.util.UUID, byte[]> getPsshInfo();
@@ -22567,6 +22574,11 @@
field public static final int SEEK_TO_PREVIOUS_SYNC = 0; // 0x0
}
+ public static final class MediaExtractor.CasInfo {
+ method public android.media.MediaCas.Session getSession();
+ method public int getSystemId();
+ }
+
public final class MediaFormat {
ctor public MediaFormat();
method public final boolean containsKey(java.lang.String);
@@ -40339,7 +40351,8 @@
method public boolean hasIccCard();
method public boolean iccCloseLogicalChannel(int);
method public byte[] iccExchangeSimIO(int, int, int, int, int, java.lang.String);
- method public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(java.lang.String);
+ method public deprecated android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(java.lang.String);
+ method public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(java.lang.String, int);
method public java.lang.String iccTransmitApduBasicChannel(int, int, int, int, int, java.lang.String);
method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, java.lang.String);
method public boolean isConcurrentVoiceAndDataSupported();
@@ -42854,7 +42867,7 @@
method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String, java.lang.String[], android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter);
field public static final int ALL = 15; // 0xf
field public static final int EMAIL_ADDRESSES = 2; // 0x2
- field public static final int MAP_ADDRESSES = 8; // 0x8
+ field public static final deprecated int MAP_ADDRESSES = 8; // 0x8
field public static final int PHONE_NUMBERS = 4; // 0x4
field public static final int WEB_URLS = 1; // 0x1
field public static final android.text.util.Linkify.MatchFilter sPhoneNumberMatchFilter;
@@ -45732,6 +45745,7 @@
method public java.lang.CharSequence getContentDescription();
method public final android.content.Context getContext();
method protected android.view.ContextMenu.ContextMenuInfo getContextMenuInfo();
+ method public final boolean getDefaultFocusHighlightEnabled();
method public static int getDefaultSize(int, int);
method public android.view.Display getDisplay();
method public final int[] getDrawableState();
@@ -46054,6 +46068,7 @@
method public void setClipToOutline(boolean);
method public void setContentDescription(java.lang.CharSequence);
method public void setContextClickable(boolean);
+ method public void setDefaultFocusHighlightEnabled(boolean);
method public void setDrawingCacheBackgroundColor(int);
method public void setDrawingCacheEnabled(boolean);
method public void setDrawingCacheQuality(int);
@@ -49303,7 +49318,7 @@
method public void documentHasImages(android.os.Message);
method public static void enableSlowWholeDocumentDraw();
method public void evaluateJavascript(java.lang.String, android.webkit.ValueCallback<java.lang.String>);
- method public static java.lang.String findAddress(java.lang.String);
+ method public static deprecated java.lang.String findAddress(java.lang.String);
method public deprecated int findAll(java.lang.String);
method public void findAllAsync(java.lang.String);
method public void findNext(boolean);
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index bfcad1b..1bcfb22 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -580,6 +580,11 @@
}
}
+ /**
+ * Wait until either {@link #restoreFinished} or {@link #restoreStarting} is called.
+ * Once one is called, it clears the internal flag again, so that the same observer intance
+ * can be reused for a next operation.
+ */
public void waitForCompletion() {
// The restoreFinished() callback will throw the 'done' flag; we
// just sit and wait on that notification.
@@ -590,6 +595,7 @@
} catch (InterruptedException ex) {
}
}
+ done = false;
}
}
}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 06291ab..74822d1 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -4521,12 +4521,20 @@
*/
public void startActivityForResultAsUser(Intent intent, int requestCode,
@Nullable Bundle options, UserHandle user) {
+ startActivityForResultAsUser(intent, mEmbeddedID, requestCode, options, user);
+ }
+
+ /**
+ * @hide Implement to provide correct calling token.
+ */
+ public void startActivityForResultAsUser(Intent intent, String resultWho, int requestCode,
+ @Nullable Bundle options, UserHandle user) {
if (mParent != null) {
throw new RuntimeException("Can't be called from a child");
}
options = transferSpringboardActivityOptions(options);
Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity(
- this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode,
+ this, mMainThread.getApplicationThread(), mToken, resultWho, intent, requestCode,
options, user);
if (ar != null) {
mMainThread.sendActivityResult(
@@ -4563,7 +4571,7 @@
options = transferSpringboardActivityOptions(options);
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
- this, mMainThread.getApplicationThread(), mToken, this,
+ this, mMainThread.getApplicationThread(), mToken, mEmbeddedID,
intent, -1, options, user);
if (ar != null) {
mMainThread.sendActivityResult(
@@ -5092,6 +5100,15 @@
/**
* @hide
*/
+ public void startActivityAsUserFromFragment(@NonNull Fragment fragment,
+ @RequiresPermission Intent intent, int requestCode, @Nullable Bundle options,
+ UserHandle user) {
+ startActivityForResultAsUser(intent, fragment.mWho, requestCode, options, user);
+ }
+
+ /**
+ * @hide
+ */
@Override
public void startActivityForResult(
String who, Intent intent, int requestCode, @Nullable Bundle options) {
@@ -7463,6 +7480,14 @@
}
@Override
+ public void onStartActivityAsUserFromFragment(
+ Fragment fragment, Intent intent, int requestCode, Bundle options,
+ UserHandle user) {
+ Activity.this.startActivityAsUserFromFragment(
+ fragment, intent, requestCode, options, user);
+ }
+
+ @Override
public void onStartIntentSenderFromFragment(Fragment fragment, IntentSender intent,
int requestCode, @Nullable Intent fillInIntent, int flagsMask, int flagsValues,
int extraFlags, Bundle options) throws IntentSender.SendIntentException {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index aede1bb..80482ca 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -3387,6 +3387,26 @@
}
/**
+ * Return the importance of a given uid, based on the processes that are
+ * currently running. The return value is one of the importance constants defined
+ * in {@link RunningAppProcessInfo}, giving you the highest importance of all the
+ * processes that this uid has running. If there are no processes
+ * running its code, {@link RunningAppProcessInfo#IMPORTANCE_GONE} is returned.
+ * @hide
+ */
+ @SystemApi @TestApi
+ @RequiresPermission(Manifest.permission.PACKAGE_USAGE_STATS)
+ public int getUidImportance(int uid) {
+ try {
+ int procState = getService().getUidProcessState(uid,
+ mContext.getOpPackageName());
+ return RunningAppProcessInfo.procStateToImportance(procState);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Callback to get reports about changes to the importance of a uid. Use with
* {@link #addOnUidImportanceListener}.
* @hide
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index a3c123f..6487e67 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -34,6 +34,7 @@
import android.os.Looper;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.UserHandle;
import android.transition.Transition;
import android.transition.TransitionInflater;
import android.transition.TransitionSet;
@@ -1188,6 +1189,19 @@
}
/**
+ * @hide
+ * Call {@link Activity#startActivityForResultAsUser(Intent, int, UserHandle)} from the
+ * fragment's containing Activity.
+ */
+ public void startActivityForResultAsUser(
+ Intent intent, int requestCode, Bundle options, UserHandle user) {
+ if (mHost == null) {
+ throw new IllegalStateException("Fragment " + this + " not attached to Activity");
+ }
+ mHost.onStartActivityAsUserFromFragment(this, intent, requestCode, options, user);
+ }
+
+ /**
* Call {@link Activity#startIntentSenderForResult(IntentSender, int, Intent, int, int, int,
* Bundle)} from the fragment's containing Activity.
*/
diff --git a/core/java/android/app/FragmentHostCallback.java b/core/java/android/app/FragmentHostCallback.java
index 41a885e..fb60e07 100644
--- a/core/java/android/app/FragmentHostCallback.java
+++ b/core/java/android/app/FragmentHostCallback.java
@@ -23,6 +23,7 @@
import android.content.IntentSender;
import android.os.Bundle;
import android.os.Handler;
+import android.os.UserHandle;
import android.util.ArrayMap;
import android.view.LayoutInflater;
import android.view.View;
@@ -146,6 +147,20 @@
}
/**
+ * @hide
+ * Starts a new {@link Activity} from the given fragment.
+ * See {@link Activity#startActivityForResult(Intent, int)}.
+ */
+ public void onStartActivityAsUserFromFragment(Fragment fragment, Intent intent, int requestCode,
+ Bundle options, UserHandle userHandle) {
+ if (requestCode != -1) {
+ throw new IllegalStateException(
+ "Starting activity with a requestCode requires a FragmentActivity host");
+ }
+ mContext.startActivityAsUser(intent, userHandle);
+ }
+
+ /**
* Starts a new {@link IntentSender} from the given fragment.
* See {@link Activity#startIntentSender(IntentSender, Intent, int, int, int, Bundle)}.
*/
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 79c2f1e..595ad35 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -463,6 +463,7 @@
* etc.
*/
void keyguardGoingAway(int flags);
+ int getUidProcessState(int uid, in String callingPackage);
void registerUidObserver(in IUidObserver observer, int which, int cutpoint,
String callingPackage);
void unregisterUidObserver(in IUidObserver observer);
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index d546f27..9377d35 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1779,7 +1779,7 @@
* {@hide}
*/
public ActivityResult execStartActivity(
- Context who, IBinder contextThread, IBinder token, Activity target,
+ Context who, IBinder contextThread, IBinder token, String resultWho,
Intent intent, int requestCode, Bundle options, UserHandle user) {
IApplicationThread whoThread = (IApplicationThread) contextThread;
if (mActivityMonitors != null) {
@@ -1810,7 +1810,7 @@
int result = ActivityManager.getService()
.startActivityAsUser(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
- token, target != null ? target.mEmbeddedID : null,
+ token, resultWho,
requestCode, 0, null, options, user.getIdentifier());
checkStartActivityResult(result, intent);
} catch (RemoteException e) {
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 4572578..19f7426 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -641,7 +641,8 @@
new CachedServiceFetcher<PrintManager>() {
@Override
public PrintManager createService(ContextImpl ctx) throws ServiceNotFoundException {
- IBinder iBinder = ServiceManager.getServiceOrThrow(Context.PRINT_SERVICE);
+ // Get the services without throwing as this is an optional feature
+ IBinder iBinder = ServiceManager.getService(Context.PRINT_SERVICE);
IPrintManager service = IPrintManager.Stub.asInterface(iBinder);
return new PrintManager(ctx.getOuterContext(), service, UserHandle.myUserId(),
UserHandle.getAppId(Process.myUid()));
@@ -652,8 +653,9 @@
@Override
public CompanionDeviceManager createService(ContextImpl ctx)
throws ServiceNotFoundException {
+ // Get the services without throwing as this is an optional feature
IBinder iBinder =
- ServiceManager.getServiceOrThrow(Context.COMPANION_DEVICE_SERVICE);
+ ServiceManager.getService(Context.COMPANION_DEVICE_SERVICE);
ICompanionDeviceManager service =
ICompanionDeviceManager.Stub.asInterface(iBinder);
return new CompanionDeviceManager(service, ctx);
@@ -833,7 +835,8 @@
new CachedServiceFetcher<AutofillManager>() {
@Override
public AutofillManager createService(ContextImpl ctx) throws ServiceNotFoundException {
- IBinder b = ServiceManager.getServiceOrThrow(Context.AUTOFILL_MANAGER_SERVICE);
+ // Get the services without throwing as this is an optional feature
+ IBinder b = ServiceManager.getService(Context.AUTOFILL_MANAGER_SERVICE);
IAutoFillManager service = IAutoFillManager.Stub.asInterface(b);
return new AutofillManager(ctx.getOuterContext(), service);
}});
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 4bd44c1..c7a0da5 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2404,6 +2404,15 @@
/**
* Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
+ * The device supports autofill of user credentials, addresses, credit cards, etc
+ * via integration with {@link android.service.autofill.AutofillService autofill
+ * providers}.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_AUTOFILL = "android.software.autofill";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
* The device implements headtracking suitable for a VR device.
*/
@SdkConstant(SdkConstantType.FEATURE)
diff --git a/core/java/android/content/res/ColorStateList.java b/core/java/android/content/res/ColorStateList.java
index a46db06..faf2381 100644
--- a/core/java/android/content/res/ColorStateList.java
+++ b/core/java/android/content/res/ColorStateList.java
@@ -91,7 +91,7 @@
* file. An item with no state spec is considered to match any set of states and is generally
* useful as a final item to be used as a default.
* <p>
- * If an item with no state spec if placed before other items, those items
+ * If an item with no state spec is placed before other items, those items
* will be ignored.
*
* <a name="ItemAttributes"></a>
@@ -521,6 +521,15 @@
}
/**
+ * Return whether the state spec list has at least one item explicitly specifying
+ * {@link android.R.attr#state_focused}.
+ * @hide
+ */
+ public boolean hasFocusStateSpecified() {
+ return StateSet.containsAttribute(mStateSpecs, R.attr.state_focused);
+ }
+
+ /**
* Indicates whether this color state list is opaque, which means that every
* color returned from {@link #getColorForState(int[], int)} has an alpha
* value of 255.
diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java
index b1f6421..c6bbf48 100644
--- a/core/java/android/os/Vibrator.java
+++ b/core/java/android/os/Vibrator.java
@@ -19,6 +19,7 @@
import android.app.ActivityThread;
import android.content.Context;
import android.media.AudioAttributes;
+import android.util.Log;
/**
* Class that operates the vibrator on the device.
@@ -30,6 +31,7 @@
* {@link Context#getSystemService} with {@link Context#VIBRATOR_SERVICE} as the argument.
*/
public abstract class Vibrator {
+ private static final String TAG = "Vibrator";
private final String mPackageName;
@@ -90,9 +92,14 @@
*/
@Deprecated
public void vibrate(long milliseconds, AudioAttributes attributes) {
- VibrationEffect effect =
- VibrationEffect.createOneShot(milliseconds, VibrationEffect.DEFAULT_AMPLITUDE);
- vibrate(effect, attributes);
+ try {
+ // This ignores all exceptions to stay compatible with pre-O implementations.
+ VibrationEffect effect =
+ VibrationEffect.createOneShot(milliseconds, VibrationEffect.DEFAULT_AMPLITUDE);
+ vibrate(effect, attributes);
+ } catch (IllegalArgumentException iae) {
+ Log.e(TAG, "Failed to create VibrationEffect", iae);
+ }
}
/**
@@ -150,12 +157,17 @@
*/
@Deprecated
public void vibrate(long[] pattern, int repeat, AudioAttributes attributes) {
- // This call needs to continue throwing ArrayIndexOutOfBoundsException for compatibility
- // purposes, whereas VibrationEffect throws an IllegalArgumentException.
+ // This call needs to continue throwing ArrayIndexOutOfBoundsException but ignore all other
+ // exceptions for compatibility purposes
if (repeat < -1 || repeat >= pattern.length) {
throw new ArrayIndexOutOfBoundsException();
}
- vibrate(VibrationEffect.createWaveform(pattern, repeat), attributes);
+
+ try {
+ vibrate(VibrationEffect.createWaveform(pattern, repeat), attributes);
+ } catch (IllegalArgumentException iae) {
+ Log.e(TAG, "Failed to create VibrationEffect", iae);
+ }
}
public void vibrate(VibrationEffect vibe) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index b037ee5..6c46f2e 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4125,6 +4125,7 @@
INSTANT_APP_SETTINGS.add(HAPTIC_FEEDBACK_ENABLED);
INSTANT_APP_SETTINGS.add(TIME_12_24);
INSTANT_APP_SETTINGS.add(SOUND_EFFECTS_ENABLED);
+ INSTANT_APP_SETTINGS.add(ACCELEROMETER_ROTATION);
}
/**
@@ -7094,6 +7095,7 @@
INSTANT_APP_SETTINGS.add(ANDROID_ID);
INSTANT_APP_SETTINGS.add(PACKAGE_VERIFIER_USER_CONSENT);
+ INSTANT_APP_SETTINGS.add(ALLOW_MOCK_LOCATION);
}
/**
@@ -10331,6 +10333,7 @@
INSTANT_APP_SETTINGS.add(TRANSITION_ANIMATION_SCALE);
INSTANT_APP_SETTINGS.add(ANIMATOR_DURATION_SCALE);
INSTANT_APP_SETTINGS.add(DEBUG_VIEW_ATTRIBUTES);
+ INSTANT_APP_SETTINGS.add(WTF_IS_FATAL);
}
/**
diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java
index 3117f98..eab0d4c 100644
--- a/core/java/android/service/autofill/FillResponse.java
+++ b/core/java/android/service/autofill/FillResponse.java
@@ -309,7 +309,6 @@
return this;
}
-
/**
* Builds a new {@link FillResponse} instance. You must provide at least
* one dataset or some savable ids or an authentication with a presentation
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index b47fce8..a233ba1 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -1030,24 +1030,17 @@
* the paragraph's primary direction.
*/
public float getPrimaryHorizontal(int offset) {
- return getPrimaryHorizontal(offset, false /* not clamped */,
- true /* getNewLineStartPosOnLineBreak */);
+ return getPrimaryHorizontal(offset, false /* not clamped */);
}
/**
* Get the primary horizontal position for the specified text offset, but
* optionally clamp it so that it doesn't exceed the width of the layout.
- *
- * @param offset the offset to get horizontal position
- * @param clamped whether to clamp the position by using the width of this layout.
- * @param getNewLineStartPosOnLineBreak whether to get the start position of new line when the
- * offset is at automatic line break.
* @hide
*/
- public float getPrimaryHorizontal(int offset, boolean clamped,
- boolean getNewLineStartPosOnLineBreak) {
+ public float getPrimaryHorizontal(int offset, boolean clamped) {
boolean trailing = primaryIsTrailingPrevious(offset);
- return getHorizontal(offset, trailing, clamped, getNewLineStartPosOnLineBreak);
+ return getHorizontal(offset, trailing, clamped);
}
/**
@@ -1056,37 +1049,26 @@
* the direction other than the paragraph's primary direction.
*/
public float getSecondaryHorizontal(int offset) {
- return getSecondaryHorizontal(offset, false /* not clamped */,
- true /* getNewLineStartPosOnLineBreak */);
+ return getSecondaryHorizontal(offset, false /* not clamped */);
}
/**
* Get the secondary horizontal position for the specified text offset, but
* optionally clamp it so that it doesn't exceed the width of the layout.
- *
- * @param offset the offset to get horizontal position
- * @param clamped whether to clamp the position by using the width of this layout.
- * @param getNewLineStartPosOnLineBreak whether to get the start position of new line when the
- * offset is at automatic line break.
* @hide
*/
- public float getSecondaryHorizontal(int offset, boolean clamped,
- boolean getNewLineStartPosOnLineBreak) {
+ public float getSecondaryHorizontal(int offset, boolean clamped) {
boolean trailing = primaryIsTrailingPrevious(offset);
- return getHorizontal(offset, !trailing, clamped, getNewLineStartPosOnLineBreak);
+ return getHorizontal(offset, !trailing, clamped);
}
- private float getHorizontal(int offset, boolean primary,
- boolean getNewLineStartPosOnLineBreak) {
- return primary ? getPrimaryHorizontal(offset, false /* not clamped */,
- getNewLineStartPosOnLineBreak)
- : getSecondaryHorizontal(offset, false /* not clamped */,
- getNewLineStartPosOnLineBreak);
+ private float getHorizontal(int offset, boolean primary) {
+ return primary ? getPrimaryHorizontal(offset) : getSecondaryHorizontal(offset);
}
- private float getHorizontal(int offset, boolean trailing, boolean clamped,
- boolean getNewLineStartPosOnLineBreak) {
- final int line = getLineForOffset(offset, getNewLineStartPosOnLineBreak);
+ private float getHorizontal(int offset, boolean trailing, boolean clamped) {
+ int line = getLineForOffset(offset);
+
return getHorizontal(offset, trailing, line, clamped);
}
@@ -1300,10 +1282,6 @@
* beyond the end of the text, you get the last line.
*/
public int getLineForOffset(int offset) {
- return getLineForOffset(offset, true);
- }
-
- private int getLineForOffset(int offset, boolean getNewLineOnLineBreak) {
int high = getLineCount(), low = -1, guess;
while (high - low > 1) {
@@ -1318,10 +1296,6 @@
if (low < 0) {
return 0;
} else {
- if (!getNewLineOnLineBreak && low > 0 && getLineStart(low) == offset
- && mText.charAt(offset - 1) != '\n') {
- return low - 1;
- }
return low;
}
}
@@ -1357,14 +1331,14 @@
false, null);
final int max;
- if (line != getLineCount() - 1 && mText.charAt(lineEndOffset - 1) == '\n') {
+ if (line == getLineCount() - 1) {
+ max = lineEndOffset;
+ } else {
max = tl.getOffsetToLeftRightOf(lineEndOffset - lineStartOffset,
!isRtlCharAt(lineEndOffset - 1)) + lineStartOffset;
- } else {
- max = lineEndOffset;
}
int best = lineStartOffset;
- float bestdist = Math.abs(getHorizontal(best, primary, true) - horiz);
+ float bestdist = Math.abs(getHorizontal(best, primary) - horiz);
for (int i = 0; i < dirs.mDirections.length; i += 2) {
int here = lineStartOffset + dirs.mDirections[i];
@@ -1380,9 +1354,7 @@
guess = (high + low) / 2;
int adguess = getOffsetAtStartOf(guess);
- if (getHorizontal(adguess, primary,
- adguess == lineStartOffset || adguess != lineEndOffset) * swap
- >= horiz * swap) {
+ if (getHorizontal(adguess, primary) * swap >= horiz * swap) {
high = guess;
} else {
low = guess;
@@ -1396,11 +1368,9 @@
int aft = tl.getOffsetToLeftRightOf(low - lineStartOffset, isRtl) + lineStartOffset;
low = tl.getOffsetToLeftRightOf(aft - lineStartOffset, !isRtl) + lineStartOffset;
if (low >= here && low < there) {
- float dist = Math.abs(getHorizontal(low, primary,
- low == lineStartOffset || low != lineEndOffset) - horiz);
+ float dist = Math.abs(getHorizontal(low, primary) - horiz);
if (aft < there) {
- float other = Math.abs(getHorizontal(aft, primary,
- aft == lineStartOffset || aft != lineEndOffset) - horiz);
+ float other = Math.abs(getHorizontal(aft, primary) - horiz);
if (other < dist) {
dist = other;
@@ -1415,8 +1385,7 @@
}
}
- float dist = Math.abs(getHorizontal(here, primary,
- here == lineStartOffset || here != lineEndOffset) - horiz);
+ float dist = Math.abs(getHorizontal(here, primary) - horiz);
if (dist < bestdist) {
bestdist = dist;
@@ -1424,10 +1393,10 @@
}
}
- float dist = Math.abs(getHorizontal(max, primary,
- max == lineStartOffset || max != lineEndOffset) - horiz);
+ float dist = Math.abs(getHorizontal(max, primary) - horiz);
if (dist <= bestdist) {
+ bestdist = dist;
best = max;
}
@@ -1621,9 +1590,8 @@
int bottom = getLineTop(line+1);
boolean clamped = shouldClampCursor(line);
- float h1 = getPrimaryHorizontal(point, clamped, true) - 0.5f;
- float h2 = isLevelBoundary(point)
- ? getSecondaryHorizontal(point, clamped, true) - 0.5f : h1;
+ float h1 = getPrimaryHorizontal(point, clamped) - 0.5f;
+ float h2 = isLevelBoundary(point) ? getSecondaryHorizontal(point, clamped) - 0.5f : h1;
int caps = TextKeyListener.getMetaState(editingBuffer, TextKeyListener.META_SHIFT_ON) |
TextKeyListener.getMetaState(editingBuffer, TextKeyListener.META_SELECTING);
@@ -1740,7 +1708,8 @@
}
int startline = getLineForOffset(start);
- int endline = getLineForOffset(end, false);
+ int endline = getLineForOffset(end);
+
int top = getLineTop(startline);
int bottom = getLineBottom(endline);
diff --git a/core/java/android/text/util/Linkify.java b/core/java/android/text/util/Linkify.java
index 7e6eb49..0f85159 100644
--- a/core/java/android/text/util/Linkify.java
+++ b/core/java/android/text/util/Linkify.java
@@ -88,7 +88,11 @@
* {@link android.webkit.WebView#findAddress(String) findAddress()} method in
* {@link android.webkit.WebView} for finding addresses, which has various
* limitations.
+ *
+ * @deprecated See {@link android.webkit.WebView#findAddress(String) findAddress()}
+ * for more explanation.
*/
+ @Deprecated
public static final int MAP_ADDRESSES = 0x08;
/**
diff --git a/core/java/android/util/StateSet.java b/core/java/android/util/StateSet.java
index 051de8a..4bbc0f8 100644
--- a/core/java/android/util/StateSet.java
+++ b/core/java/android/util/StateSet.java
@@ -228,6 +228,29 @@
return true;
}
+ /**
+ * Check whether a list of state specs has an attribute specified.
+ * @param stateSpecs a list of state specs we're checking.
+ * @param attr an attribute we're looking for.
+ * @return {@code true} if the attribute is contained in the state specs.
+ * @hide
+ */
+ public static boolean containsAttribute(int[][] stateSpecs, int attr) {
+ if (stateSpecs != null) {
+ for (int[] spec : stateSpecs) {
+ if (spec == null) {
+ break;
+ }
+ for (int specAttr : spec) {
+ if (specAttr == attr || -specAttr == attr) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
public static int[] trimStateSet(int[] states, int newSize) {
if (states.length == newSize) {
return states;
diff --git a/core/java/android/view/FocusFinder.java b/core/java/android/view/FocusFinder.java
index f3c2421..7792939 100644
--- a/core/java/android/view/FocusFinder.java
+++ b/core/java/android/view/FocusFinder.java
@@ -21,8 +21,7 @@
import android.content.pm.PackageManager;
import android.graphics.Rect;
import android.util.ArrayMap;
-import android.util.SparseArray;
-import android.util.SparseBooleanArray;
+import android.util.ArraySet;
import java.util.ArrayList;
import java.util.Collections;
@@ -54,9 +53,11 @@
final Rect mOtherRect = new Rect();
final Rect mBestCandidateRect = new Rect();
private final UserSpecifiedFocusComparator mUserSpecifiedFocusComparator =
- new UserSpecifiedFocusComparator((v) -> v.getNextFocusForwardId());
+ new UserSpecifiedFocusComparator((r, v) -> isValidId(v.getNextFocusForwardId())
+ ? v.findUserSetNextFocus(r, View.FOCUS_FORWARD) : null);
private final UserSpecifiedFocusComparator mUserSpecifiedClusterComparator =
- new UserSpecifiedFocusComparator((v) -> v.getNextClusterForwardId());
+ new UserSpecifiedFocusComparator((r, v) -> isValidId(v.getNextClusterForwardId())
+ ? v.findUserSetNextKeyboardNavigationCluster(r, View.FOCUS_FORWARD) : null);
private final FocusComparator mFocusComparator = new FocusComparator();
private final ArrayList<View> mTempList = new ArrayList<View>();
@@ -258,7 +259,7 @@
@View.FocusDirection int direction) {
try {
// Note: This sort is stable.
- mUserSpecifiedClusterComparator.setFocusables(clusters);
+ mUserSpecifiedClusterComparator.setFocusables(clusters, root);
Collections.sort(clusters, mUserSpecifiedClusterComparator);
} finally {
mUserSpecifiedClusterComparator.recycle();
@@ -283,7 +284,7 @@
View focused, Rect focusedRect, int direction) {
try {
// Note: This sort is stable.
- mUserSpecifiedFocusComparator.setFocusables(focusables);
+ mUserSpecifiedFocusComparator.setFocusables(focusables, root);
Collections.sort(focusables, mUserSpecifiedFocusComparator);
} finally {
mUserSpecifiedFocusComparator.recycle();
@@ -823,56 +824,55 @@
* specified focus chains (eg. no nextFocusForward attributes defined), this should be a no-op.
*/
private static final class UserSpecifiedFocusComparator implements Comparator<View> {
- private final SparseArray<View> mFocusables = new SparseArray<View>();
- private final SparseBooleanArray mIsConnectedTo = new SparseBooleanArray();
+ private final ArrayMap<View, View> mNextFoci = new ArrayMap<>();
+ private final ArraySet<View> mIsConnectedTo = new ArraySet<>();
private final ArrayMap<View, View> mHeadsOfChains = new ArrayMap<View, View>();
private final ArrayMap<View, Integer> mOriginalOrdinal = new ArrayMap<>();
- private final NextIdGetter mNextIdGetter;
+ private final NextFocusGetter mNextFocusGetter;
+ private View mRoot;
- public interface NextIdGetter {
- int get(View view);
+ public interface NextFocusGetter {
+ View get(View root, View view);
}
- UserSpecifiedFocusComparator(NextIdGetter nextIdGetter) {
- mNextIdGetter = nextIdGetter;
+ UserSpecifiedFocusComparator(NextFocusGetter nextFocusGetter) {
+ mNextFocusGetter = nextFocusGetter;
}
public void recycle() {
- mFocusables.clear();
+ mRoot = null;
mHeadsOfChains.clear();
mIsConnectedTo.clear();
mOriginalOrdinal.clear();
+ mNextFoci.clear();
}
- public void setFocusables(List<View> focusables) {
- for (int i = focusables.size() - 1; i >= 0; i--) {
- final View view = focusables.get(i);
- final int id = view.getId();
- if (isValidId(id)) {
- mFocusables.put(id, view);
- }
- final int nextId = mNextIdGetter.get(view);
- if (isValidId(nextId)) {
- mIsConnectedTo.put(nextId, true);
- }
- }
-
- for (int i = focusables.size() - 1; i >= 0; i--) {
- final View view = focusables.get(i);
- final int nextId = mNextIdGetter.get(view);
- if (isValidId(nextId) && !mIsConnectedTo.get(view.getId())) {
- setHeadOfChain(view);
- }
- }
-
+ public void setFocusables(List<View> focusables, View root) {
+ mRoot = root;
for (int i = 0; i < focusables.size(); ++i) {
mOriginalOrdinal.put(focusables.get(i), i);
}
+
+ for (int i = focusables.size() - 1; i >= 0; i--) {
+ final View view = focusables.get(i);
+ final View next = mNextFocusGetter.get(mRoot, view);
+ if (next != null && mOriginalOrdinal.containsKey(next)) {
+ mNextFoci.put(view, next);
+ mIsConnectedTo.add(next);
+ }
+ }
+
+ for (int i = focusables.size() - 1; i >= 0; i--) {
+ final View view = focusables.get(i);
+ final View next = mNextFoci.get(view);
+ if (next != null && !mIsConnectedTo.contains(view)) {
+ setHeadOfChain(view);
+ }
+ }
}
private void setHeadOfChain(View head) {
- for (View view = head; view != null;
- view = mFocusables.get(mNextIdGetter.get(view))) {
+ for (View view = head; view != null; view = mNextFoci.get(view)) {
final View otherHead = mHeadsOfChains.get(view);
if (otherHead != null) {
if (otherHead == head) {
@@ -900,7 +900,7 @@
return -1; // first is the head, it should be first
} else if (second == firstHead) {
return 1; // second is the head, it should be first
- } else if (isValidId(mNextIdGetter.get(first))) {
+ } else if (mNextFoci.get(first) != null) {
return -1; // first is not the end of the chain
} else {
return 1; // first is end of chain
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 1cb563f..3b15456 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -55,6 +55,8 @@
private static native void nativeSetAnimationTransaction();
private static native void nativeSetLayer(long nativeObject, int zorder);
+ private static native void nativeSetRelativeLayer(long nativeObject, IBinder relativeTo,
+ int zorder);
private static native void nativeSetPosition(long nativeObject, float x, float y);
private static native void nativeSetGeometryAppliesWithResize(long nativeObject);
private static native void nativeSetSize(long nativeObject, int w, int h);
@@ -461,6 +463,11 @@
nativeSetLayer(mNativeObject, zorder);
}
+ public void setRelativeLayer(IBinder relativeTo, int zorder) {
+ checkNotReleased();
+ nativeSetRelativeLayer(mNativeObject, relativeTo, zorder);
+ }
+
public void setPosition(float x, float y) {
checkNotReleased();
nativeSetPosition(mNativeObject, x, y);
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 076b33c..1a71679 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -93,7 +93,7 @@
* artifacts may occur on previous versions of the platform when its window is
* positioned asynchronously.</p>
*/
-public class SurfaceView extends View {
+public class SurfaceView extends View implements ViewRootImpl.WindowStoppedCallback {
private static final String TAG = "SurfaceView";
private static final boolean DEBUG = false;
@@ -169,6 +169,8 @@
boolean mWindowVisibility = false;
boolean mLastWindowVisibility = false;
boolean mViewVisibility = false;
+ boolean mWindowStopped = false;
+
int mRequestedWidth = -1;
int mRequestedHeight = -1;
/* Set SurfaceView's format to 565 by default to maintain backward
@@ -226,12 +228,27 @@
return mSurfaceHolder;
}
+ private void updateRequestedVisibility() {
+ mRequestedVisible = mViewVisibility && mWindowVisibility && !mWindowStopped;
+ }
+
+ /** @hide */
+ @Override
+ public void windowStopped(boolean stopped) {
+ mWindowStopped = stopped;
+ updateRequestedVisibility();
+ updateSurface();
+ }
+
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
+
+ getViewRootImpl().addWindowStoppedCallback(this);
+
mParent.requestTransparentRegion(this);
mViewVisibility = getVisibility() == VISIBLE;
- mRequestedVisible = mViewVisibility && mWindowVisibility;
+ updateRequestedVisibility();
mAttachedToWindow = true;
if (!mGlobalListenersAdded) {
@@ -246,7 +263,7 @@
protected void onWindowVisibilityChanged(int visibility) {
super.onWindowVisibilityChanged(visibility);
mWindowVisibility = visibility == VISIBLE;
- mRequestedVisible = mWindowVisibility && mViewVisibility;
+ updateRequestedVisibility();
updateSurface();
}
@@ -254,7 +271,7 @@
public void setVisibility(int visibility) {
super.setVisibility(visibility);
mViewVisibility = visibility == VISIBLE;
- boolean newRequestedVisible = mWindowVisibility && mViewVisibility;
+ boolean newRequestedVisible = mWindowVisibility && mViewVisibility && !mWindowStopped;
if (newRequestedVisible != mRequestedVisible) {
// our base class (View) invalidates the layout only when
// we go from/to the GONE state. However, SurfaceView needs
@@ -278,6 +295,8 @@
@Override
protected void onDetachedFromWindow() {
+ getViewRootImpl().removeWindowStoppedCallback(this);
+
mAttachedToWindow = false;
if (mGlobalListenersAdded) {
ViewTreeObserver observer = getViewTreeObserver();
@@ -299,6 +318,7 @@
mSurfaceControl = null;
mHaveFrame = false;
+
super.onDetachedFromWindow();
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index a09db9c..9072bf9 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3920,6 +3920,14 @@
private int mBackgroundResource;
private boolean mBackgroundSizeChanged;
+ /** The default focus highlight.
+ * @see #mDefaultFocusHighlightEnabled
+ * @see Drawable#hasFocusStateSpecified()
+ */
+ private Drawable mDefaultFocusHighlight;
+ private Drawable mDefaultFocusHighlightCache;
+ private boolean mDefaultFocusHighlightSizeChanged;
+
private String mTransitionName;
static class TintInfo {
@@ -4102,6 +4110,12 @@
*/
int mNextClusterForwardId = View.NO_ID;
+ /**
+ * Whether this View should use a default focus highlight when it gets focused but doesn't
+ * have {@link android.R.attr#state_focused} defined in its background.
+ */
+ boolean mDefaultFocusHighlightEnabled = true;
+
private CheckForLongPress mPendingCheckForLongPress;
private CheckForTap mPendingCheckForTap = null;
private PerformClick mPerformClick;
@@ -5086,6 +5100,11 @@
setImportantForAutofill(a.getInt(attr, IMPORTANT_FOR_AUTOFILL_AUTO));
}
break;
+ case R.styleable.View_defaultFocusHighlightEnabled:
+ if (a.peekValue(attr) != null) {
+ setDefaultFocusHighlightEnabled(a.getBoolean(attr, true));
+ }
+ break;
}
}
@@ -6800,6 +6819,9 @@
AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
}
+ // Here we check whether we still need the default focus highlight, and switch it on/off.
+ switchDefaultFocusHighlight();
+
InputMethodManager imm = InputMethodManager.peekInstance();
if (!gainFocus) {
if (isPressed()) {
@@ -9986,6 +10008,33 @@
}
/**
+ * Sets whether this View should use a default focus highlight when it gets focused but doesn't
+ * have {@link android.R.attr#state_focused} defined in its background.
+ *
+ * @param defaultFocusHighlightEnabled {@code true} to set this view to use a default focus
+ * highlight, {@code false} otherwise.
+ *
+ * @attr ref android.R.styleable#View_defaultFocusHighlightEnabled
+ */
+ public void setDefaultFocusHighlightEnabled(boolean defaultFocusHighlightEnabled) {
+ mDefaultFocusHighlightEnabled = defaultFocusHighlightEnabled;
+ }
+
+ /**
+
+ /**
+ * Returns whether this View should use a default focus highlight when it gets focused but
+ * doesn't have {@link android.R.attr#state_focused} defined in its background.
+ *
+ * @return True if this View should use a default focus highlight.
+ * @attr ref android.R.styleable#View_defaultFocusHighlightEnabled
+ */
+ @ViewDebug.ExportedProperty(category = "defaultFocusHighlightEnabled")
+ public final boolean getDefaultFocusHighlightEnabled() {
+ return mDefaultFocusHighlightEnabled;
+ }
+
+ /**
* If a user manually specified the next view id for a particular direction,
* use the root to look up the view.
* @param root The root view of the hierarchy containing this view.
@@ -11752,6 +11801,10 @@
if (dr != null && isVisible != dr.isVisible()) {
dr.setVisible(isVisible, false);
}
+ final Drawable hl = mDefaultFocusHighlight;
+ if (hl != null && isVisible != hl.isVisible()) {
+ hl.setVisible(isVisible, false);
+ }
final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null;
if (fg != null && isVisible != fg.isVisible()) {
fg.setVisible(isVisible, false);
@@ -12965,6 +13018,7 @@
if ((changed & DRAW_MASK) != 0) {
if ((mViewFlags & WILL_NOT_DRAW) != 0) {
if (mBackground != null
+ || mDefaultFocusHighlight != null
|| (mForegroundInfo != null && mForegroundInfo.mDrawable != null)) {
mPrivateFlags &= ~PFLAG_SKIP_DRAW;
} else {
@@ -13036,6 +13090,7 @@
}
mBackgroundSizeChanged = true;
+ mDefaultFocusHighlightSizeChanged = true;
if (mForegroundInfo != null) {
mForegroundInfo.mBoundsChanged = true;
}
@@ -13927,6 +13982,7 @@
invalidate(true);
}
mBackgroundSizeChanged = true;
+ mDefaultFocusHighlightSizeChanged = true;
if (mForegroundInfo != null) {
mForegroundInfo.mBoundsChanged = true;
}
@@ -13995,6 +14051,7 @@
invalidate(true);
}
mBackgroundSizeChanged = true;
+ mDefaultFocusHighlightSizeChanged = true;
if (mForegroundInfo != null) {
mForegroundInfo.mBoundsChanged = true;
}
@@ -14057,6 +14114,7 @@
invalidate(true);
}
mBackgroundSizeChanged = true;
+ mDefaultFocusHighlightSizeChanged = true;
if (mForegroundInfo != null) {
mForegroundInfo.mBoundsChanged = true;
}
@@ -14116,6 +14174,7 @@
invalidate(true);
}
mBackgroundSizeChanged = true;
+ mDefaultFocusHighlightSizeChanged = true;
if (mForegroundInfo != null) {
mForegroundInfo.mBoundsChanged = true;
}
@@ -18720,6 +18779,9 @@
// Step 6, draw decorations (foreground, scrollbars)
onDrawForeground(canvas);
+ // Step 7, draw the default focus highlight
+ drawDefaultFocusHighlight(canvas);
+
if (debugDraw()) {
debugDrawFocus(canvas);
}
@@ -19278,6 +19340,7 @@
mPrivateFlags |= drawn;
mBackgroundSizeChanged = true;
+ mDefaultFocusHighlightSizeChanged = true;
if (mForegroundInfo != null) {
mForegroundInfo.mBoundsChanged = true;
}
@@ -19429,6 +19492,9 @@
if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) {
mForegroundInfo.mDrawable.setLayoutDirection(layoutDirection);
}
+ if (mDefaultFocusHighlight != null) {
+ mDefaultFocusHighlight.setLayoutDirection(layoutDirection);
+ }
mPrivateFlags2 |= PFLAG2_DRAWABLE_RESOLVED;
onResolveDrawables(layoutDirection);
}
@@ -19487,7 +19553,8 @@
// Avoid verifying the scroll bar drawable so that we don't end up in
// an invalidation loop. This effectively prevents the scroll bar
// drawable from triggering invalidations and scheduling runnables.
- return who == mBackground || (mForegroundInfo != null && mForegroundInfo.mDrawable == who);
+ return who == mBackground || (mForegroundInfo != null && mForegroundInfo.mDrawable == who)
+ || (mDefaultFocusHighlight == who);
}
/**
@@ -19511,6 +19578,11 @@
changed |= bg.setState(state);
}
+ final Drawable hl = mDefaultFocusHighlight;
+ if (hl != null && hl.isStateful()) {
+ changed |= hl.setState(state);
+ }
+
final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null;
if (fg != null && fg.isStateful()) {
changed |= fg.setState(state);
@@ -19550,6 +19622,9 @@
if (mBackground != null) {
mBackground.setHotspot(x, y);
}
+ if (mDefaultFocusHighlight != null) {
+ mDefaultFocusHighlight.setHotspot(x, y);
+ }
if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) {
mForegroundInfo.mDrawable.setHotspot(x, y);
}
@@ -19586,6 +19661,106 @@
}
/**
+ * Create a default focus highlight if it doesn't exist.
+ * @return a default focus highlight.
+ */
+ private Drawable getDefaultFocusHighlightDrawable() {
+ if (mDefaultFocusHighlightCache == null) {
+ if (mContext != null) {
+ final int[] attrs = new int[] { android.R.attr.selectableItemBackground };
+ final TypedArray ta = mContext.obtainStyledAttributes(attrs);
+ mDefaultFocusHighlightCache = ta.getDrawable(0);
+ ta.recycle();
+ }
+ }
+ return mDefaultFocusHighlightCache;
+ }
+
+ /**
+ * Set the current default focus highlight.
+ * @param highlight the highlight drawable, or {@code null} if it's no longer needed.
+ */
+ private void setDefaultFocusHighlight(Drawable highlight) {
+ mDefaultFocusHighlight = highlight;
+ mDefaultFocusHighlightSizeChanged = true;
+ if (highlight != null) {
+ if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) {
+ mPrivateFlags &= ~PFLAG_SKIP_DRAW;
+ }
+ highlight.setLayoutDirection(getLayoutDirection());
+ if (highlight.isStateful()) {
+ highlight.setState(getDrawableState());
+ }
+ if (isAttachedToWindow()) {
+ highlight.setVisible(getWindowVisibility() == VISIBLE && isShown(), false);
+ }
+ // Set callback last, since the view may still be initializing.
+ highlight.setCallback(this);
+ } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null
+ && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) {
+ mPrivateFlags |= PFLAG_SKIP_DRAW;
+ }
+ requestLayout();
+ invalidate();
+ }
+
+ /**
+ * Check whether we need to draw a default focus highlight when this view gets focused,
+ * which requires:
+ * <ul>
+ * <li>In the background, {@link android.R.attr#state_focused} is not defined.</li>
+ * <li>This view is not in touch mode.</li>
+ * <li>This view doesn't opt out for a default focus highlight, via
+ * {@link #setDefaultFocusHighlightEnabled(boolean)}.</li>
+ * <li>This view is attached to window.</li>
+ * </ul>
+ * @return {@code true} if a default focus highlight is needed.
+ */
+ private boolean isDefaultFocusHighlightNeeded(Drawable background) {
+ final boolean hasFocusStateSpecified = background == null || !background.isStateful()
+ || !background.hasFocusStateSpecified();
+ return !isInTouchMode() && getDefaultFocusHighlightEnabled() && hasFocusStateSpecified
+ && isAttachedToWindow();
+ }
+
+ /**
+ * When this view is focused, switches on/off the default focused highlight.
+ * <p>
+ * This always happens when this view is focused, and only at this moment the default focus
+ * highlight can be visible.
+ */
+ private void switchDefaultFocusHighlight() {
+ if (isFocused()) {
+ final boolean needed = isDefaultFocusHighlightNeeded(mBackground);
+ final boolean active = mDefaultFocusHighlight != null;
+ if (needed && !active) {
+ setDefaultFocusHighlight(getDefaultFocusHighlightDrawable());
+ } else if (!needed && active) {
+ // The highlight is no longer needed, so tear it down.
+ setDefaultFocusHighlight(null);
+ }
+ }
+ }
+
+ /**
+ * Draw the default focus highlight onto the canvas.
+ * @param canvas the canvas where we're drawing the highlight.
+ */
+ private void drawDefaultFocusHighlight(Canvas canvas) {
+ if (mDefaultFocusHighlight != null) {
+ if (mDefaultFocusHighlightSizeChanged) {
+ mDefaultFocusHighlightSizeChanged = false;
+ final int l = mScrollX;
+ final int r = l + mRight - mLeft;
+ final int t = mScrollY;
+ final int b = t + mBottom - mTop;
+ mDefaultFocusHighlight.setBounds(l, t, r, b);
+ }
+ mDefaultFocusHighlight.draw(canvas);
+ }
+ }
+
+ /**
* Return an array of resource IDs of the drawable states representing the
* current state of the view.
*
@@ -19725,6 +19900,9 @@
if (mStateListAnimator != null) {
mStateListAnimator.jumpToCurrentState();
}
+ if (mDefaultFocusHighlight != null) {
+ mDefaultFocusHighlight.jumpToCurrentState();
+ }
if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) {
mForegroundInfo.mDrawable.jumpToCurrentState();
}
@@ -19869,6 +20047,7 @@
/* Remove the background */
mBackground = null;
if ((mViewFlags & WILL_NOT_DRAW) != 0
+ && (mDefaultFocusHighlight == null)
&& (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) {
mPrivateFlags |= PFLAG_SKIP_DRAW;
}
@@ -20060,7 +20239,8 @@
}
// Set callback last, since the view may still be initializing.
foreground.setCallback(this);
- } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null) {
+ } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null
+ && (mDefaultFocusHighlight == null)) {
mPrivateFlags |= PFLAG_SKIP_DRAW;
}
requestLayout();
@@ -21875,6 +22055,11 @@
// Similarly, we remove the foreground drawable's non-transparent parts.
applyDrawableToTransparentRegion(mForegroundInfo.mDrawable, region);
}
+ if (mDefaultFocusHighlight != null
+ && mDefaultFocusHighlight.getOpacity() != PixelFormat.TRANSPARENT) {
+ // Similarly, we remove the default focus highlight's non-transparent parts.
+ applyDrawableToTransparentRegion(mDefaultFocusHighlight, region);
+ }
}
}
return true;
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 574137b..4def0d0 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -35,7 +35,7 @@
* Defines the width of the horizontal scrollbar and the height of the vertical scrollbar in
* dips
*/
- private static final int SCROLL_BAR_SIZE = 4;
+ private static final int SCROLL_BAR_SIZE = 10;
/**
* Duration of the fade when scrollbars fade away in milliseconds
@@ -354,8 +354,7 @@
mEdgeSlop = (int) (sizeAndDensity * EDGE_SLOP + 0.5f);
mFadingEdgeLength = (int) (sizeAndDensity * FADING_EDGE_LENGTH + 0.5f);
- mScrollbarSize = res.getDimensionPixelSize(
- com.android.internal.R.dimen.config_scrollbarSize);
+ mScrollbarSize = (int) (density * SCROLL_BAR_SIZE + 0.5f);
mDoubleTapSlop = (int) (sizeAndDensity * DOUBLE_TAP_SLOP + 0.5f);
mWindowTouchSlop = (int) (sizeAndDensity * WINDOW_TOUCH_SLOP + 0.5f);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 58ef0af..a7ececf 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1249,6 +1249,19 @@
mIsAmbientMode = ambient;
}
+ interface WindowStoppedCallback {
+ public void windowStopped(boolean stopped);
+ }
+ private final ArrayList<WindowStoppedCallback> mWindowStoppedCallbacks = new ArrayList<>();
+
+ void addWindowStoppedCallback(WindowStoppedCallback c) {
+ mWindowStoppedCallbacks.add(c);
+ }
+
+ void removeWindowStoppedCallback(WindowStoppedCallback c) {
+ mWindowStoppedCallbacks.remove(c);
+ }
+
void setWindowStopped(boolean stopped) {
if (mStopped != stopped) {
mStopped = stopped;
@@ -1264,6 +1277,10 @@
renderer.destroyHardwareResources(mView);
}
}
+
+ for (int i = 0; i < mWindowStoppedCallbacks.size(); i++) {
+ mWindowStoppedCallbacks.get(i).windowStopped(stopped);
+ }
}
}
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index ba004b96..e85a658 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -192,6 +192,9 @@
* {@hide}
*/
public void onCreate(Bundle savedInstanceState) {
+ if (!hasAutofillFeature()) {
+ return;
+ }
synchronized (mLock) {
mLastAutofilledData = savedInstanceState.getParcelable(LAST_AUTOFILLED_DATA_TAG);
@@ -237,6 +240,9 @@
* {@hide}
*/
public void onAttachedToWindow(@NonNull IBinder windowToken) {
+ if (!hasAutofillFeature()) {
+ return;
+ }
synchronized (mLock) {
if (mSessionId == NO_SESSION) {
return;
@@ -258,6 +264,9 @@
* {@hide}
*/
public void onSaveInstanceState(Bundle outState) {
+ if (!hasAutofillFeature()) {
+ return;
+ }
synchronized (mLock) {
if (mSessionId != NO_SESSION) {
outState.putInt(SESSION_ID_TAG, mSessionId);
@@ -278,6 +287,9 @@
* @return whether autofill is enabled for the current user.
*/
public boolean isEnabled() {
+ if (!hasAutofillFeature()) {
+ return false;
+ }
synchronized (mLock) {
ensureServiceClientAddedIfNeededLocked();
return mEnabled;
@@ -294,6 +306,9 @@
* @param view view requesting the new autofill context.
*/
public void requestAutofill(@NonNull View view) {
+ if (!hasAutofillFeature()) {
+ return;
+ }
synchronized (mLock) {
ensureServiceClientAddedIfNeededLocked();
@@ -320,6 +335,9 @@
* @param bounds child boundaries, relative to the top window.
*/
public void requestAutofill(@NonNull View view, int childId, @NonNull Rect bounds) {
+ if (!hasAutofillFeature()) {
+ return;
+ }
synchronized (mLock) {
ensureServiceClientAddedIfNeededLocked();
@@ -339,6 +357,9 @@
* @param view {@link View} that was entered.
*/
public void notifyViewEntered(@NonNull View view) {
+ if (!hasAutofillFeature()) {
+ return;
+ }
AutofillCallback callback = null;
synchronized (mLock) {
ensureServiceClientAddedIfNeededLocked();
@@ -372,6 +393,9 @@
* @param view {@link View} that was exited.
*/
public void notifyViewExited(@NonNull View view) {
+ if (!hasAutofillFeature()) {
+ return;
+ }
synchronized (mLock) {
ensureServiceClientAddedIfNeededLocked();
@@ -392,6 +416,9 @@
* @param bounds child boundaries, relative to the top window.
*/
public void notifyViewEntered(@NonNull View view, int childId, @NonNull Rect bounds) {
+ if (!hasAutofillFeature()) {
+ return;
+ }
AutofillCallback callback = null;
synchronized (mLock) {
ensureServiceClientAddedIfNeededLocked();
@@ -426,6 +453,9 @@
* @param childId id identifying the virtual child inside the view.
*/
public void notifyViewExited(@NonNull View view, int childId) {
+ if (!hasAutofillFeature()) {
+ return;
+ }
synchronized (mLock) {
ensureServiceClientAddedIfNeededLocked();
@@ -444,6 +474,9 @@
* @param view view whose value changed.
*/
public void notifyValueChanged(View view) {
+ if (!hasAutofillFeature()) {
+ return;
+ }
AutofillId id = null;
boolean valueWasRead = false;
AutofillValue value = null;
@@ -486,7 +519,6 @@
}
}
-
/**
* Called to indicate the value of an autofillable virtual {@link View} changed.
*
@@ -495,6 +527,9 @@
* @param value new value of the child.
*/
public void notifyValueChanged(View view, int childId, AutofillValue value) {
+ if (!hasAutofillFeature()) {
+ return;
+ }
synchronized (mLock) {
if (!mEnabled || mSessionId == NO_SESSION) {
return;
@@ -512,6 +547,9 @@
* call this method after the form is submitted and another page is rendered.
*/
public void commit() {
+ if (!hasAutofillFeature()) {
+ return;
+ }
synchronized (mLock) {
if (!mEnabled && mSessionId == NO_SESSION) {
return;
@@ -528,6 +566,9 @@
* call this method if the user does not post the form but moves to another form in this page.
*/
public void cancel() {
+ if (!hasAutofillFeature()) {
+ return;
+ }
synchronized (mLock) {
if (!mEnabled && mSessionId == NO_SESSION) {
return;
@@ -542,6 +583,9 @@
* will be disabled.
*/
public void disableOwnedAutofillServices() {
+ if (!hasAutofillFeature()) {
+ return;
+ }
try {
mService.disableOwnedAutofillServices(mContext.getUserId());
} catch (RemoteException e) {
@@ -558,6 +602,9 @@
/** @hide */
public void onAuthenticationResult(Intent data) {
+ if (!hasAutofillFeature()) {
+ return;
+ }
// TODO(b/33197203): the result code is being ignored, so this method is not reliably
// handling the cases where it's not RESULT_OK: it works fine if the service does not
// set the EXTRA_AUTHENTICATION_RESULT extra, but it could cause weird results if the
@@ -672,6 +719,9 @@
* @param callback callback to receive events.
*/
public void registerCallback(@Nullable AutofillCallback callback) {
+ if (!hasAutofillFeature()) {
+ return;
+ }
synchronized (mLock) {
if (callback == null) return;
@@ -694,6 +744,9 @@
* @param callback callback to stop receiving events.
*/
public void unregisterCallback(@Nullable AutofillCallback callback) {
+ if (!hasAutofillFeature()) {
+ return;
+ }
synchronized (mLock) {
if (callback == null || mCallback == null || callback != mCallback) return;
@@ -871,6 +924,10 @@
return view;
}
+ private boolean hasAutofillFeature() {
+ return mService != null;
+ }
+
/**
* Callback for auto-fill related events.
*
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index 71809bd..f0645b8 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -57,7 +57,6 @@
* @attr ref android.R.styleable#InputMethod_settingsActivity
* @attr ref android.R.styleable#InputMethod_isDefault
* @attr ref android.R.styleable#InputMethod_supportsSwitchingToNextInputMethod
- * @attr ref android.R.styleable#InputMethod_supportsDismissingWindow
*/
public final class InputMethodInfo implements Parcelable {
static final String TAG = "InputMethodInfo";
@@ -105,11 +104,6 @@
private final boolean mSupportsSwitchingToNextInputMethod;
/**
- * The flag whether this IME supports ways to dismiss its window (e.g. dismiss button.)
- */
- private final boolean mSupportsDismissingWindow;
-
- /**
* @param service the {@link ResolveInfo} corresponds in which the IME is implemented.
* @return a unique ID to be returned by {@link #getId()}. We have used
* {@link ComponentName#flattenToShortString()} for this purpose (and it is already
@@ -151,7 +145,6 @@
mId = computeId(service);
boolean isAuxIme = true;
boolean supportsSwitchingToNextInputMethod = false; // false as default
- boolean supportsDismissingWindow = false; // false as default
mForceDefault = false;
PackageManager pm = context.getPackageManager();
@@ -191,8 +184,6 @@
supportsSwitchingToNextInputMethod = sa.getBoolean(
com.android.internal.R.styleable.InputMethod_supportsSwitchingToNextInputMethod,
false);
- supportsDismissingWindow = sa.getBoolean(
- com.android.internal.R.styleable.InputMethod_supportsDismissingWindow, false);
sa.recycle();
final int depth = parser.getDepth();
@@ -263,7 +254,6 @@
mIsDefaultResId = isDefaultResId;
mIsAuxIme = isAuxIme;
mSupportsSwitchingToNextInputMethod = supportsSwitchingToNextInputMethod;
- mSupportsDismissingWindow = supportsDismissingWindow;
}
InputMethodInfo(Parcel source) {
@@ -272,7 +262,6 @@
mIsDefaultResId = source.readInt();
mIsAuxIme = source.readInt() == 1;
mSupportsSwitchingToNextInputMethod = source.readInt() == 1;
- mSupportsDismissingWindow = source.readInt() == 1;
mService = ResolveInfo.CREATOR.createFromParcel(source);
mSubtypes = new InputMethodSubtypeArray(source);
mForceDefault = false;
@@ -285,8 +274,7 @@
CharSequence label, String settingsActivity) {
this(buildDummyResolveInfo(packageName, className, label), false /* isAuxIme */,
settingsActivity, null /* subtypes */, 0 /* isDefaultResId */,
- false /* forceDefault */, true /* supportsSwitchingToNextInputMethod */,
- true /* supportsDismissingWindow */);
+ false /* forceDefault */, true /* supportsSwitchingToNextInputMethod */);
}
/**
@@ -297,8 +285,7 @@
String settingsActivity, List<InputMethodSubtype> subtypes, int isDefaultResId,
boolean forceDefault) {
this(ri, isAuxIme, settingsActivity, subtypes, isDefaultResId, forceDefault,
- true /* supportsSwitchingToNextInputMethod */,
- true /* supportsDismissingWindow */);
+ true /* supportsSwitchingToNextInputMethod */);
}
/**
@@ -307,7 +294,7 @@
*/
public InputMethodInfo(ResolveInfo ri, boolean isAuxIme, String settingsActivity,
List<InputMethodSubtype> subtypes, int isDefaultResId, boolean forceDefault,
- boolean supportsSwitchingToNextInputMethod, boolean supportsDismissingWindow) {
+ boolean supportsSwitchingToNextInputMethod) {
final ServiceInfo si = ri.serviceInfo;
mService = ri;
mId = new ComponentName(si.packageName, si.name).flattenToShortString();
@@ -317,7 +304,6 @@
mSubtypes = new InputMethodSubtypeArray(subtypes);
mForceDefault = forceDefault;
mSupportsSwitchingToNextInputMethod = supportsSwitchingToNextInputMethod;
- mSupportsDismissingWindow = supportsDismissingWindow;
}
private static ResolveInfo buildDummyResolveInfo(String packageName, String className,
@@ -458,8 +444,7 @@
public void dump(Printer pw, String prefix) {
pw.println(prefix + "mId=" + mId
+ " mSettingsActivityName=" + mSettingsActivityName
- + " mSupportsSwitchingToNextInputMethod=" + mSupportsSwitchingToNextInputMethod
- + " mSupportsDismissingWindow=" + mSupportsDismissingWindow);
+ + " mSupportsSwitchingToNextInputMethod=" + mSupportsSwitchingToNextInputMethod);
pw.println(prefix + "mIsDefaultResId=0x"
+ Integer.toHexString(mIsDefaultResId));
pw.println(prefix + "Service:");
@@ -512,14 +497,6 @@
}
/**
- * @return true if this input method supports ways to dismiss its window.
- * @hide
- */
- public boolean supportsDismissingWindow() {
- return mSupportsDismissingWindow;
- }
-
- /**
* Used to package this object into a {@link Parcel}.
*
* @param dest The {@link Parcel} to be written.
@@ -532,7 +509,6 @@
dest.writeInt(mIsDefaultResId);
dest.writeInt(mIsAuxIme ? 1 : 0);
dest.writeInt(mSupportsSwitchingToNextInputMethod ? 1 : 0);
- dest.writeInt(mSupportsDismissingWindow ? 1 : 0);
mService.writeToParcel(dest, flags);
mSubtypes.writeToParcel(dest);
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 6213a63..9202889 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1731,7 +1731,14 @@
*
* @param addr the string to search for addresses
* @return the address, or if no address is found, null
+ *
+ * @deprecated findAddress is deprecated. It only supports a subset of US
+ * addresses and has a high false positive rate. Calling findAddress also causes
+ * WebView to be loaded into the app, which significantly increases memory usage
+ * if the app doesn't already use WebView. Use {@link TextClassifier} instead for
+ * classifying text and finding addresses.
*/
+ @Deprecated
public static String findAddress(String addr) {
// TODO: Rewrite this in Java so it is not needed to start up chromium
// Could also be deprecated
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index faa2310..4fb7b19 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -1915,11 +1915,10 @@
}
boolean clamped = layout.shouldClampCursor(line);
- updateCursorPosition(0, top, middle, layout.getPrimaryHorizontal(offset, clamped, true));
+ updateCursorPosition(0, top, middle, layout.getPrimaryHorizontal(offset, clamped));
if (mCursorCount == 2) {
- updateCursorPosition(1, middle, bottom,
- layout.getSecondaryHorizontal(offset, clamped, true));
+ updateCursorPosition(1, middle, bottom, layout.getSecondaryHorizontal(offset, clamped));
}
}
@@ -4340,7 +4339,7 @@
updateSelection(offset);
addPositionToTouchUpFilter(offset);
}
- final int line = getLineForOffset(layout, offset);
+ final int line = layout.getLineForOffset(offset);
mPrevLine = line;
mPositionX = getCursorHorizontalPosition(layout, offset) - mHotspotX
@@ -4367,15 +4366,6 @@
return (int) (getHorizontal(layout, offset) - 0.5f);
}
- /**
- * @param layout Text layout.
- * @param offset Character offset for the cursor.
- * @return The line the cursor should be at.
- */
- int getLineForOffset(Layout layout, int offset) {
- return layout.getLineForOffset(offset);
- }
-
@Override
public void updatePosition(int parentPositionX, int parentPositionY,
boolean parentPositionChanged, boolean parentScrolled) {
@@ -4804,7 +4794,7 @@
|| !isStartHandle() && initialOffset <= anotherHandleOffset) {
// Handles have crossed, bound it to the first selected line and
// adjust by word / char as normal.
- currLine = getLineForOffset(layout, anotherHandleOffset, !isStartHandle());
+ currLine = layout.getLineForOffset(anotherHandleOffset);
initialOffset = getOffsetAtCoordinate(layout, currLine, x);
}
@@ -4876,18 +4866,14 @@
if (isExpanding) {
// User is increasing the selection.
int wordBoundary = isStartHandle() ? wordStart : wordEnd;
- final boolean atLineBoundary = layout.getLineStart(currLine) == offset
- || layout.getLineEnd(currLine) == offset;
- final boolean atWordBoundary = getWordIteratorWithText().isBoundary(offset);
- final boolean snapToWord = !(atLineBoundary && atWordBoundary)
- && (!mInWord
- || (isStartHandle() ? currLine < mPrevLine : currLine > mPrevLine))
- && atRtl == isAtRtlRun(layout, wordBoundary);
+ final boolean snapToWord = (!mInWord
+ || (isStartHandle() ? currLine < mPrevLine : currLine > mPrevLine))
+ && atRtl == isAtRtlRun(layout, wordBoundary);
if (snapToWord) {
// Sometimes words can be broken across lines (Chinese, hyphenation).
// We still snap to the word boundary but we only use the letters on the
// current line to determine if the user is far enough into the word to snap.
- if (getLineForOffset(layout, wordBoundary) != currLine) {
+ if (layout.getLineForOffset(wordBoundary) != currLine) {
wordBoundary = isStartHandle()
? layout.getLineStart(currLine) : layout.getLineEnd(currLine);
}
@@ -5035,29 +5021,12 @@
}
private float getHorizontal(@NonNull Layout layout, int offset, boolean startHandle) {
- final int line = getLineForOffset(layout, offset);
+ final int line = layout.getLineForOffset(offset);
final int offsetToCheck = startHandle ? offset : Math.max(offset - 1, 0);
final boolean isRtlChar = layout.isRtlCharAt(offsetToCheck);
final boolean isRtlParagraph = layout.getParagraphDirection(line) == -1;
return (isRtlChar == isRtlParagraph)
- ? layout.getPrimaryHorizontal(offset, false, startHandle)
- : layout.getSecondaryHorizontal(offset, false, startHandle);
- }
-
- @Override
- public int getLineForOffset(@NonNull Layout layout, int offset) {
- return getLineForOffset(layout, offset, isStartHandle());
- }
-
- private int getLineForOffset(@NonNull Layout layout, int offset, boolean startHandle) {
- final int line = layout.getLineForOffset(offset);
- if (!startHandle && line > 0 && layout.getLineStart(line) == offset
- && mTextView.getText().charAt(offset - 1) != '\n') {
- // If end handle is at a line break in a paragraph, the handle should be at the
- // previous line.
- return line - 1;
- }
- return line;
+ ? layout.getPrimaryHorizontal(offset) : layout.getSecondaryHorizontal(offset);
}
@Override
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index fcab703..9a8131e 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -8470,7 +8470,7 @@
// right where it is most likely to be annoying.
final boolean clamped = grav > 0;
// FIXME: Is it okay to truncate this, or should we round?
- final int x = (int) layout.getPrimaryHorizontal(offset, clamped, true);
+ final int x = (int) layout.getPrimaryHorizontal(offset, clamped);
final int top = layout.getLineTop(line);
final int bottom = layout.getLineTop(line + 1);
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index 3a31b37..35d4ba8 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -38,6 +38,7 @@
int checkPackage(int uid, String packageName);
List<AppOpsManager.PackageOps> getPackagesForOps(in int[] ops);
List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName, in int[] ops);
+ List<AppOpsManager.PackageOps> getUidOps(int uid, in int[] ops);
void setUidMode(int code, int uid, int mode);
void setMode(int code, int uid, String packageName, int mode);
void resetAllModes(int reqUserId, String reqPackageName);
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index abcd1e7..1aed501 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -192,18 +192,12 @@
if (env->IsInstanceOf(excep, gErrorOffsets.mClass)) {
/*
- * It's an Error: Reraise the exception, detach this thread, and
- * wait for the fireworks. Die even more blatantly after a minute
- * if the gentler attempt doesn't do the trick.
- *
- * The GetJavaVM function isn't on the "approved" list of JNI calls
- * that can be made while an exception is pending, so we want to
- * get the VM ptr, throw the exception, and then detach the thread.
+ * It's an Error: Reraise the exception and ask the runtime to abort.
+ * This will dump the pending exception as well as all thread traces
+ * to the log.
*/
env->Throw(excep);
- env->ExceptionDescribe();
- ALOGE("Forcefully exiting");
- exit(1);
+ env->FatalError("java.lang.Error thrown during binder transaction.");
}
bail:
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index dc365b4..8b82314 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -289,6 +289,14 @@
}
}
+static void nativeSetRelativeLayer(JNIEnv* env, jclass clazz, jlong nativeObject,
+ jobject relativeTo, jint zorder) {
+ auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+ sp<IBinder> handle = ibinderForJavaObject(env, relativeTo);
+
+ ctrl->setRelativeLayer(handle, zorder);
+}
+
static void nativeSetPosition(JNIEnv* env, jclass clazz, jlong nativeObject, jfloat x, jfloat y) {
SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
status_t err = ctrl->setPosition(x, y);
@@ -774,6 +782,8 @@
(void*)nativeSetAnimationTransaction },
{"nativeSetLayer", "(JI)V",
(void*)nativeSetLayer },
+ {"nativeSetRelativeLayer", "(JLandroid/os/IBinder;I)V",
+ (void*)nativeSetRelativeLayer },
{"nativeSetPosition", "(JFF)V",
(void*)nativeSetPosition },
{"nativeSetGeometryAppliesWithResize", "(J)V",
diff --git a/core/res/res/drawable/scrollbar_handle_material.xml b/core/res/res/drawable/scrollbar_handle_material.xml
index f020112..33efbba 100644
--- a/core/res/res/drawable/scrollbar_handle_material.xml
+++ b/core/res/res/drawable/scrollbar_handle_material.xml
@@ -19,4 +19,7 @@
android:shape="rectangle">
<solid
android:color="#84ffffff" />
+ <size
+ android:width="4dp"
+ android:height="4dp" />
</shape>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index d26d952..5ede1c9 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2953,6 +2953,9 @@
See {@link android.view.View#setFocusedByDefault(boolean)}. -->
<attr name="focusedByDefault" format="boolean" />
+ <!-- Whether this View should use a default focus highlight when it gets focused but
+ doesn't have {@link android.R.attr#state_focused} defined in its background. -->
+ <attr name="defaultFocusHighlightEnabled" format="boolean" />
</declare-styleable>
<!-- Attributes that can be assigned to a tag for a particular View. -->
@@ -3214,18 +3217,7 @@
and subtype in order to provide the consistent user experience in switching
between IMEs and subtypes. -->
<attr name="supportsSwitchingToNextInputMethod" format="boolean" />
- <!-- Set to true if this input method supports ways to dismiss the windows assigned to
- the input method (for example, a dismiss button rendered by the input method itself). The
- System UI may optimize the UI by not showing system-level dismiss button if this
- value is true.
- <p> Must be a boolean value, either "true" or "false". The default value is "false".
- <p> This may also be a reference to a resource (in the form "@[package:]type:name")
- or theme attribute (in the form "?[package:]type:name") containing a value of this
- type.
- <p> A UI element that dismisses the input method window should report
- {@link android.view.accessibility.AccessibilityNodeInfo#ACTION_DISMISS} action, so
- that accessibility services can handle it accordingly. -->
- <attr name="supportsDismissingWindow" format="boolean" />
+ <attr name="__removed2" format="boolean" />
</declare-styleable>
<!-- This is the subtype of InputMethod. Subtype can describe locales (for example, en_US and
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 860c631..45dccb6 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1881,10 +1881,6 @@
<!-- Amount of time in ms the user needs to press the relevant key to bring up the global actions dialog -->
<integer name="config_globalActionsKeyTimeout">500</integer>
- <!-- Default width of a vertical scrollbar and height of a horizontal scrollbar.
- Takes effect only if the scrollbar drawables have no intrinsic size. -->
- <dimen name="config_scrollbarSize">4dp</dimen>
-
<!-- Distance that should be scrolled, per axis value, in response to a horizontal
{@link MotionEvent#ACTION_SCROLL} event. -->
<dimen name="config_horizontalScrollFactor">64dp</dimen>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index f364e70..c3f8846 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2785,7 +2785,7 @@
<public name="focusedByDefault" />
<public name="appCategory" />
<public name="autoSizeMaxTextSize" />
- <public name="supportsDismissingWindow" />
+ <public name="__removed2" />
<public name="restartOnConfigChanges" />
<public name="certDigest" />
<public name="splitName" />
@@ -2814,6 +2814,7 @@
<public name="iconTintMode" />
<public name="maxAspectRatio"/>
<public name="iconSpaceReserved"/>
+ <public name="defaultFocusHighlightEnabled" />
</public-group>
<public-group type="style" first-id="0x010302e0">
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 8bbb929..2ae2ca0 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -322,6 +322,7 @@
<item name="scrollbars">vertical</item>
<item name="fadingEdge">vertical</item>
<item name="fastScrollStyle">?attr/fastScrollStyle</item>
+ <item name="defaultFocusHighlightEnabled">false</item>
</style>
<style name="Widget.GestureOverlayView">
@@ -538,6 +539,7 @@
<item name="gravity">center_vertical</item>
<item name="breakStrategy">simple</item>
<item name="hyphenationFrequency">normal</item>
+ <item name="defaultFocusHighlightEnabled">false</item>
</style>
<style name="Widget.ExpandableListView" parent="Widget.ListView">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 78f971f..44a4af7 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -434,7 +434,6 @@
<java-symbol type="dimen" name="config_viewConfigurationTouchSlop" />
<java-symbol type="dimen" name="config_viewMinFlingVelocity" />
<java-symbol type="dimen" name="config_viewMaxFlingVelocity" />
- <java-symbol type="dimen" name="config_scrollbarSize" />
<java-symbol type="dimen" name="config_horizontalScrollFactor" />
<java-symbol type="dimen" name="config_verticalScrollFactor" />
<java-symbol type="dimen" name="config_scrollFactor" />
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 9911d9d..e0b4ec5 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -748,12 +748,12 @@
<!-- @hide DeviceDefault theme for a window that should use Settings theme colors
but has a full dark palette. ONLY USED FOR QUICK SETTINGS THEME -->
- <style name="Theme.DeviceDefault.QuickSettings" parent="Theme.Material">
+ <style name="Theme.DeviceDefault.QuickSettings" parent="Theme.DeviceDefault.Light">
<!-- Color palette -->
- <item name="colorPrimary">@color/primary_device_default_settings</item>
- <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
- <item name="colorSecondary">@color/secondary_device_default_settings</item>
- <item name="colorAccent">@color/accent_device_default_dark</item>
+ <item name="colorPrimary">@color/primary_device_default_settings_light</item>
+ <item name="colorPrimaryDark">@color/primary_dark_device_default_settings_light</item>
+ <item name="colorSecondary">@color/secondary_device_default_settings_light</item>
+ <item name="colorAccent">@color/accent_device_default_light</item>
<item name="colorControlNormal">?attr/textColorPrimary</item>
</style>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 9dafa7a..86abe97 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -214,7 +214,7 @@
<!-- Scrollbar attributes -->
<item name="scrollbarFadeDuration">250</item>
<item name="scrollbarDefaultDelayBeforeFade">400</item>
- <item name="scrollbarSize">@dimen/config_scrollbarSize</item>
+ <item name="scrollbarSize">10dp</item>
<item name="scrollbarThumbHorizontal">@drawable/scrollbar_handle_material</item>
<item name="scrollbarThumbVertical">@drawable/config_scrollbarThumbVertical</item>
<item name="scrollbarTrackHorizontal">@null</item>
@@ -582,7 +582,7 @@
<!-- Scrollbar attributes -->
<item name="scrollbarFadeDuration">250</item>
<item name="scrollbarDefaultDelayBeforeFade">400</item>
- <item name="scrollbarSize">@dimen/config_scrollbarSize</item>
+ <item name="scrollbarSize">10dp</item>
<item name="scrollbarThumbHorizontal">@drawable/scrollbar_handle_material</item>
<item name="scrollbarThumbVertical">@drawable/config_scrollbarThumbVertical</item>
<item name="scrollbarTrackHorizontal">@null</item>
diff --git a/core/tests/coretests/res/xml/ime_meta_dismiss.xml b/core/tests/coretests/res/xml/ime_meta_dismiss.xml
deleted file mode 100644
index 59f8ecc..0000000
--- a/core/tests/coretests/res/xml/ime_meta_dismiss.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- Copyright (C) 2017 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.
--->
-
-<input-method
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:settingsActivity="com.android.inputmethod.latin.settings.SettingsActivity"
- android:supportsDismissingWindow="true"
->
- <subtype
- android:label="subtype1"
- android:imeSubtypeLocale="en_US"
- android:imeSubtypeMode="keyboard" />
-</input-method>
diff --git a/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java b/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java
index 23dc80f..13cef52 100644
--- a/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java
@@ -51,12 +51,10 @@
final InputMethodInfo imi = buildInputMethodForTest(R.xml.ime_meta);
assertThat(imi.supportsSwitchingToNextInputMethod(), is(false));
- assertThat(imi.supportsDismissingWindow(), is(false));
final InputMethodInfo clone = cloneViaParcel(imi);
assertThat(clone.supportsSwitchingToNextInputMethod(), is(false));
- assertThat(clone.supportsDismissingWindow(), is(false));
}
@Test
@@ -70,17 +68,6 @@
assertThat(clone.supportsSwitchingToNextInputMethod(), is(true));
}
- @Test
- public void testSupportsDismissingWindow() throws Exception {
- final InputMethodInfo imi = buildInputMethodForTest(R.xml.ime_meta_dismiss);
-
- assertThat(imi.supportsDismissingWindow(), is(true));
-
- final InputMethodInfo clone = cloneViaParcel(imi);
-
- assertThat(clone.supportsDismissingWindow(), is(true));
- }
-
private InputMethodInfo buildInputMethodForTest(final @XmlRes int metaDataRes)
throws Exception {
final Context context = InstrumentationRegistry.getContext();
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
index 7edab008..3029134 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
@@ -26,7 +26,6 @@
import static android.widget.espresso.TextViewActions.Handle;
import static android.widget.espresso.TextViewActions.longPressAndDragOnText;
import static android.widget.espresso.TextViewActions.longPressOnTextAtIndex;
-import static android.widget.espresso.TextViewAssertions.handleIsOnLine;
import static android.widget.espresso.TextViewAssertions.hasInsertionPointerAtIndex;
import static android.widget.espresso.TextViewAssertions.hasSelection;
import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarIsDisplayed;
@@ -448,26 +447,6 @@
onView(withId(R.id.textview)).check(hasSelection("abcd\nefg\nhijk\nlmn\nopqr"));
}
- public void testSelectionHandles_multiLine_japanese() throws Exception {
- final TextView textView = (TextView) getActivity().findViewById(R.id.textview);
- final StringBuilder builder = new StringBuilder();
- for (int i = 0; i < 100; ++i) {
- builder.append("\u3042\u3044\u3046\u3048\u304A");
- onView(withId(R.id.textview)).perform(replaceText(builder.toString()));
- final int lineEnd = textView.getLayout().getLineEnd(0);
- if (lineEnd < builder.length()) {
- break;
- }
- }
- onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(3));
-
- final int lineEnd = textView.getLayout().getLineEnd(0);
- onHandleView(com.android.internal.R.id.selection_end_handle)
- .perform(dragHandle(textView, Handle.SELECTION_END, lineEnd, true, false));
- onHandleView(com.android.internal.R.id.selection_end_handle)
- .check(handleIsOnLine(textView, 0));
- }
-
public void testSelectionHandles_multiLine_rtl() throws Exception {
// Arabic text.
final String text = "\u062A\u062B\u062C\n" + "\u062D\u062E\u062F\n"
diff --git a/core/tests/coretests/src/android/widget/espresso/TextViewActions.java b/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
index 1e88712..335d021 100644
--- a/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
+++ b/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
@@ -331,37 +331,15 @@
*/
public static ViewAction dragHandle(TextView textView, Handle handleType, int endIndex,
boolean primary) {
- return dragHandle(textView, handleType, endIndex, primary, true);
- }
-
- /**
- * Returns an action that tap then drags on the handle from the current position to endIndex on
- * the TextView.<br>
- * <br>
- * View constraints:
- * <ul>
- * <li>must be a TextView's drag-handle displayed on screen
- * <ul>
- *
- * @param textView TextView the handle is on
- * @param handleType Type of the handle
- * @param endIndex The index of the TextView's text to end the drag at
- * @param primary whether to use primary direction to get coordinate form index when endIndex is
- * at a direction boundary.
- * @param getNewLineStartPosOnLineBreak whether to use new line start coordinate on a line break
- * within a paragraph.
- */
- public static ViewAction dragHandle(TextView textView, Handle handleType, int endIndex,
- boolean primary, boolean getNewLineStartPosOnLineBreak) {
return actionWithAssertions(
new DragAction(
DragAction.Drag.TAP,
new CurrentHandleCoordinates(textView),
- new HandleCoordinates(textView, handleType, endIndex, primary,
- getNewLineStartPosOnLineBreak),
+ new HandleCoordinates(textView, handleType, endIndex, primary),
Press.FINGER,
Editor.HandleView.class));
}
+
/**
* A provider of the x, y coordinates of the handle dragging point.
*/
@@ -424,16 +402,13 @@
private final Handle mHandleType;
private final int mIndex;
private final boolean mPrimary;
- private final boolean mGetNewLineStartPosOnLineBreak;
private final String mActionDescription;
- public HandleCoordinates(TextView textView, Handle handleType, int index, boolean primary,
- boolean getNewLineStartPosOnLineBreak) {
+ public HandleCoordinates(TextView textView, Handle handleType, int index, boolean primary) {
mTextView = textView;
mHandleType = handleType;
mIndex = index;
mPrimary = primary;
- mGetNewLineStartPosOnLineBreak = getNewLineStartPosOnLineBreak;
mActionDescription = "Could not locate " + handleType.toString()
+ " handle that points text index: " + index
+ " (" + (primary ? "primary" : "secondary" ) + ")";
@@ -470,10 +445,9 @@
final float currentX = handleView.getHorizontal(layout, currentOffset);
final float currentY = layout.getLineTop(currentLine);
final float[] currentCoordinates =
- convertToScreenCoordinates(mTextView, currentX, currentY);
+ TextCoordinates.convertToScreenCoordinates(mTextView, currentX, currentY);
final float[] targetCoordinates =
- (new TextCoordinates(mIndex, mPrimary, mGetNewLineStartPosOnLineBreak))
- .calculateCoordinates(mTextView);
+ (new TextCoordinates(mIndex, mPrimary)).calculateCoordinates(mTextView);
final Rect bounds = new Rect();
view.getBoundsOnScreen(bounds);
final Rect visibleDisplayBounds = new Rect();
@@ -511,27 +485,23 @@
private final int mIndex;
private final boolean mPrimary;
- private final boolean mGetNewLineStartPosOnLineBreak;
private final String mActionDescription;
public TextCoordinates(int index) {
- this(index, true, true);
+ this(index, true);
}
- public TextCoordinates(int index, boolean primary, boolean getNewLineStartPosOnLineBreak) {
+ public TextCoordinates(int index, boolean primary) {
mIndex = index;
mPrimary = primary;
- mGetNewLineStartPosOnLineBreak = getNewLineStartPosOnLineBreak;
mActionDescription = "Could not locate text at index: " + mIndex
- + " (" + (primary ? "primary" : "secondary" )
- + ", mGetNewLineStartPosOnLineBreak: " + mGetNewLineStartPosOnLineBreak + ")";
+ + " (" + (primary ? "primary" : "secondary" ) + ")";
}
@Override
public float[] calculateCoordinates(View view) {
try {
- return locateTextAtIndex((TextView) view, mIndex, mPrimary,
- mGetNewLineStartPosOnLineBreak);
+ return locateTextAtIndex((TextView) view, mIndex, mPrimary);
} catch (ClassCastException e) {
throw new PerformException.Builder()
.withActionDescription(mActionDescription)
@@ -550,38 +520,30 @@
/**
* @throws StringIndexOutOfBoundsException
*/
- private float[] locateTextAtIndex(TextView textView, int index, boolean primary,
- boolean getNewLineStartPosOnLineBreak) {
+ private float[] locateTextAtIndex(TextView textView, int index, boolean primary) {
if (index < 0 || index > textView.getText().length()) {
throw new StringIndexOutOfBoundsException(index);
}
final Layout layout = textView.getLayout();
-
- int line = layout.getLineForOffset(index);
- if (!getNewLineStartPosOnLineBreak && line > 0 && layout.getLineStart(line) == index
- && textView.getText().charAt(index - 1) != '\n') {
- line = line - 1;
- }
+ final int line = layout.getLineForOffset(index);
return convertToScreenCoordinates(textView,
- (primary ? layout.getPrimaryHorizontal(index, false,
- getNewLineStartPosOnLineBreak)
- : layout.getSecondaryHorizontal(index, false,
- getNewLineStartPosOnLineBreak)),
+ (primary ? layout.getPrimaryHorizontal(index)
+ : layout.getSecondaryHorizontal(index)),
layout.getLineTop(line));
}
- }
- /**
- * Convert TextView's local coordinates to on screen coordinates.
- * @param textView the TextView
- * @param x local horizontal coordinate
- * @param y local vertical coordinate
- * @return
- */
- public static float[] convertToScreenCoordinates(TextView textView, float x, float y) {
- final int[] xy = new int[2];
- textView.getLocationOnScreen(xy);
- return new float[]{ x + textView.getTotalPaddingLeft() - textView.getScrollX() + xy[0],
- y + textView.getTotalPaddingTop() - textView.getScrollY() + xy[1] };
+ /**
+ * Convert TextView's local coordinates to on screen coordinates.
+ * @param textView the TextView
+ * @param x local horizontal coordinate
+ * @param y local vertical coordinate
+ * @return
+ */
+ public static float[] convertToScreenCoordinates(TextView textView, float x, float y) {
+ final int[] xy = new int[2];
+ textView.getLocationOnScreen(xy);
+ return new float[]{ x + textView.getTotalPaddingLeft() - textView.getScrollX() + xy[0],
+ y + textView.getTotalPaddingTop() - textView.getScrollY() + xy[1] };
+ }
}
}
diff --git a/core/tests/coretests/src/android/widget/espresso/TextViewAssertions.java b/core/tests/coretests/src/android/widget/espresso/TextViewAssertions.java
index fef84f4..6e44cd8 100644
--- a/core/tests/coretests/src/android/widget/espresso/TextViewAssertions.java
+++ b/core/tests/coretests/src/android/widget/espresso/TextViewAssertions.java
@@ -28,14 +28,11 @@
import android.support.test.espresso.ViewAssertion;
import android.view.View;
import android.widget.EditText;
-import android.widget.Editor;
import android.widget.TextView;
import junit.framework.AssertionFailedError;
import org.hamcrest.Matcher;
-import com.android.ex.editstyledtext.EditStyledText.EditModeActions.TextViewAction;
-
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -140,14 +137,6 @@
}
/**
- * Returns a {@link ViewAssertion} that asserts that the TextView selection handle is on the
- * specified line.
- */
- public static ViewAssertion handleIsOnLine(TextView tv, int line) {
- return new SelectionHandlePositionAssertion(tv, line);
- }
-
- /**
* A {@link ViewAssertion} to check the selected text in a {@link TextView}.
*/
private static final class TextSelectionAssertion implements ViewAssertion {
@@ -227,31 +216,4 @@
closeTo(0f, 1f));
}
}
- /**
- * {@link ViewAssertion} to check that TextView selection handle is on a given line.
- */
- static class SelectionHandlePositionAssertion implements ViewAssertion {
- private TextView mTextView;
- private int mLine;
- private SelectionHandlePositionAssertion(TextView tv, int line) {
- mTextView = tv;
- mLine = line;
- }
-
- @Override
- public void check(View view, NoMatchingViewException exception) {
- if (!(view instanceof Editor.HandleView)) {
- throw new AssertionFailedError("View should be an instance of Editor.HandleView");
- }
- final Editor.HandleView handleView = (Editor.HandleView) view;
- final Rect bounds = new Rect();
- handleView.getBoundsOnScreen(bounds);
- final float bottom = mTextView.getLayout().getLineBottom(mLine);
- final float[] pos =
- TextViewActions.convertToScreenCoordinates(mTextView, 0, bottom);
-
- assertThat("Cursor should be on the line " + mLine, Double.valueOf(bounds.top),
- closeTo(pos[1], 1f));
- }
- }
}
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodSubtypeSwitchingControllerTest.java b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodSubtypeSwitchingControllerTest.java
index 686f75b..515e558 100644
--- a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodSubtypeSwitchingControllerTest.java
+++ b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodSubtypeSwitchingControllerTest.java
@@ -75,8 +75,7 @@
}
final InputMethodInfo imi = new InputMethodInfo(ri, DUMMY_IS_AUX_IME,
DUMMY_SETTING_ACTIVITY_NAME, subtypes, DUMMY_IS_DEFAULT_RES_ID,
- DUMMY_FORCE_DEFAULT, supportsSwitchingToNextInputMethod,
- false /* supportsDismissingWindow */);
+ DUMMY_FORCE_DEFAULT, supportsSwitchingToNextInputMethod);
if (subtypes == null) {
items.add(new ImeSubtypeListItem(imeName, null /* variableName */, imi,
NOT_A_SUBTYPE_ID, null, SYSTEM_LOCALE));
@@ -112,8 +111,7 @@
.build());
final InputMethodInfo imi = new InputMethodInfo(ri, DUMMY_IS_AUX_IME,
DUMMY_SETTING_ACTIVITY_NAME, subtypes, DUMMY_IS_DEFAULT_RES_ID,
- DUMMY_FORCE_DEFAULT, true /* supportsSwitchingToNextInputMethod */,
- false /* supportsDismissingWindow */);
+ DUMMY_FORCE_DEFAULT, true /* supportsSwitchingToNextInputMethod */);
return new ImeSubtypeListItem(imeName, subtypeName, imi, subtypeIndex, subtypeLocale,
systemLocale);
}
diff --git a/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java b/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java
index 643c0da..6dfe03d 100644
--- a/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java
+++ b/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java
@@ -728,6 +728,12 @@
return mLayerState.isStateful();
}
+ /** @hide */
+ @Override
+ public boolean hasFocusStateSpecified() {
+ return mLayerState.hasFocusStateSpecified();
+ }
+
@Override
protected boolean onStateChange(int[] state) {
boolean changed = false;
@@ -1035,6 +1041,17 @@
return isStateful;
}
+ public final boolean hasFocusStateSpecified() {
+ final ChildDrawable[] array = mChildren;
+ for (int i = 0; i < N_CHILDREN; i++) {
+ final Drawable dr = array[i].mDrawable;
+ if (dr != null && dr.hasFocusStateSpecified()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
public final boolean canConstantState() {
final ChildDrawable[] array = mChildren;
for (int i = 0; i < N_CHILDREN; i++) {
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index 6deeb0d..5004667 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -737,6 +737,12 @@
|| super.isStateful();
}
+ /** @hide */
+ @Override
+ public boolean hasFocusStateSpecified() {
+ return mBitmapState.mTint != null && mBitmapState.mTint.hasFocusStateSpecified();
+ }
+
@Override
public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
throws XmlPullParserException, IOException {
diff --git a/graphics/java/android/graphics/drawable/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java
index 7524cac..559e3d3 100644
--- a/graphics/java/android/graphics/drawable/ColorDrawable.java
+++ b/graphics/java/android/graphics/drawable/ColorDrawable.java
@@ -207,6 +207,12 @@
return mColorState.mTint != null && mColorState.mTint.isStateful();
}
+ /** @hide */
+ @Override
+ public boolean hasFocusStateSpecified() {
+ return mColorState.mTint != null && mColorState.mTint.hasFocusStateSpecified();
+ }
+
@Override
public int getOpacity() {
if (mTintFilter != null || mPaint.getColorFilter() != null) {
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 850f40e..44fb1c7 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -26,6 +26,7 @@
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.TestApi;
import android.content.pm.ActivityInfo.Config;
import android.content.res.ColorStateList;
import android.content.res.Resources;
@@ -713,6 +714,25 @@
}
/**
+ * Indicates whether this drawable has at least one state spec explicitly
+ * specifying {@link android.R.attr#state_focused}.
+ *
+ * <p>Note: A View uses a {@link Drawable} instance as its background and it
+ * changes its appearance based on a state. On keyboard devices, it should
+ * specify its {@link android.R.attr#state_focused} to make sure the user
+ * knows which view is holding the focus.</p>
+ *
+ * @return {@code true} if {@link android.R.attr#state_focused} is specified
+ * for this drawable.
+ *
+ * @hide
+ */
+ @TestApi
+ public boolean hasFocusStateSpecified() {
+ return false;
+ }
+
+ /**
* Specify a set of states for the drawable. These are use-case specific,
* so see the relevant documentation. As an example, the background for
* widgets like Button understand the following states:
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index a491d7e..aa4cd9c 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -242,6 +242,18 @@
return mDrawableContainerState.isStateful();
}
+ /** @hide */
+ @Override
+ public boolean hasFocusStateSpecified() {
+ if (mCurrDrawable != null) {
+ return mCurrDrawable.hasFocusStateSpecified();
+ }
+ if (mLastDrawable != null) {
+ return mLastDrawable.hasFocusStateSpecified();
+ }
+ return false;
+ }
+
@Override
public void setAutoMirrored(boolean mirrored) {
if (mDrawableContainerState.mAutoMirrored != mirrored) {
diff --git a/graphics/java/android/graphics/drawable/DrawableWrapper.java b/graphics/java/android/graphics/drawable/DrawableWrapper.java
index 5887939..431b63b 100644
--- a/graphics/java/android/graphics/drawable/DrawableWrapper.java
+++ b/graphics/java/android/graphics/drawable/DrawableWrapper.java
@@ -323,6 +323,12 @@
return mDrawable != null && mDrawable.isStateful();
}
+ /** @hide */
+ @Override
+ public boolean hasFocusStateSpecified() {
+ return mDrawable != null && mDrawable.hasFocusStateSpecified();
+ }
+
@Override
protected boolean onStateChange(int[] state) {
if (mDrawable != null && mDrawable.isStateful()) {
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 7aad7df..6c3aea2 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -987,6 +987,15 @@
|| (s.mTint != null && s.mTint.isStateful());
}
+ /** @hide */
+ @Override
+ public boolean hasFocusStateSpecified() {
+ final GradientState s = mGradientState;
+ return (s.mSolidColors != null && s.mSolidColors.hasFocusStateSpecified())
+ || (s.mStrokeColors != null && s.mStrokeColors.hasFocusStateSpecified())
+ || (s.mTint != null && s.mTint.hasFocusStateSpecified());
+ }
+
@Override
public @Config int getChangingConfigurations() {
return super.getChangingConfigurations() | mGradientState.getChangingConfigurations();
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index b159f0f..4725c2c 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -1476,6 +1476,12 @@
return mLayerState.isStateful();
}
+ /** @hide */
+ @Override
+ public boolean hasFocusStateSpecified() {
+ return mLayerState.hasFocusStateSpecified();
+ }
+
@Override
protected boolean onStateChange(int[] state) {
boolean changed = false;
@@ -2117,6 +2123,18 @@
return isStateful;
}
+ public final boolean hasFocusStateSpecified() {
+ final int N = mNumChildren;
+ final ChildDrawable[] array = mChildren;
+ for (int i = 0; i < N; i++) {
+ final Drawable dr = array[i].mDrawable;
+ if (dr != null && dr.hasFocusStateSpecified()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
public final boolean canConstantState() {
final ChildDrawable[] array = mChildren;
final int N = mNumChildren;
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index c7183d9..1790020 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -574,6 +574,12 @@
return super.isStateful() || (s.mTint != null && s.mTint.isStateful());
}
+ /** @hide */
+ @Override
+ public boolean hasFocusStateSpecified() {
+ return mNinePatchState.mTint != null && mNinePatchState.mTint.hasFocusStateSpecified();
+ }
+
final static class NinePatchState extends ConstantState {
@Config int mChangingConfigurations;
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index f83c160..bfd0604 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -377,6 +377,12 @@
return true;
}
+ /** @hide */
+ @Override
+ public boolean hasFocusStateSpecified() {
+ return true;
+ }
+
/**
* Sets the ripple color.
*
diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java
index 6758607..c43899b 100644
--- a/graphics/java/android/graphics/drawable/ShapeDrawable.java
+++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java
@@ -352,6 +352,12 @@
return super.isStateful() || (s.mTint != null && s.mTint.isStateful());
}
+ /** @hide */
+ @Override
+ public boolean hasFocusStateSpecified() {
+ return mShapeState.mTint != null && mShapeState.mTint.hasFocusStateSpecified();
+ }
+
/**
* Subclasses override this to parse custom subelements. If you handle it,
* return true, else return <em>super.inflateTag(...)</em>.
diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java
index 64a9eb5..c98f160 100644
--- a/graphics/java/android/graphics/drawable/StateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/StateListDrawable.java
@@ -90,6 +90,12 @@
return true;
}
+ /** @hide */
+ @Override
+ public boolean hasFocusStateSpecified() {
+ return mStateListState.hasFocusStateSpecified();
+ }
+
@Override
protected boolean onStateChange(int[] stateSet) {
final boolean changed = super.onStateChange(stateSet);
@@ -342,6 +348,10 @@
return -1;
}
+ boolean hasFocusStateSpecified() {
+ return StateSet.containsAttribute(mStateSets, R.attr.state_focused);
+ }
+
@Override
public Drawable newDrawable() {
return new StateListDrawable(this, null);
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index a1539b8..41e5af1 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -413,6 +413,12 @@
return super.isStateful() || (mVectorState != null && mVectorState.isStateful());
}
+ /** @hide */
+ @Override
+ public boolean hasFocusStateSpecified() {
+ return mVectorState != null && mVectorState.hasFocusStateSpecified();
+ }
+
@Override
protected boolean onStateChange(int[] stateSet) {
boolean changed = false;
@@ -976,6 +982,11 @@
|| (mRootGroup != null && mRootGroup.isStateful());
}
+ public boolean hasFocusStateSpecified() {
+ return mTint != null && mTint.hasFocusStateSpecified()
+ || (mRootGroup != null && mRootGroup.hasFocusStateSpecified());
+ }
+
void setViewportSize(float viewportWidth, float viewportHeight) {
mViewportWidth = viewportWidth;
mViewportHeight = viewportHeight;
@@ -1326,6 +1337,21 @@
}
@Override
+ public boolean hasFocusStateSpecified() {
+ boolean result = false;
+
+ final ArrayList<VObject> children = mChildren;
+ for (int i = 0, count = children.size(); i < count; i++) {
+ final VObject child = children.get(i);
+ if (child.isStateful()) {
+ result |= child.hasFocusStateSpecified();
+ }
+ }
+
+ return result;
+ }
+
+ @Override
int getNativeSize() {
// Return the native allocation needed for the subtree.
int size = NATIVE_ALLOCATION_SIZE;
@@ -1569,6 +1595,11 @@
}
@Override
+ public boolean hasFocusStateSpecified() {
+ return false;
+ }
+
+ @Override
int getNativeSize() {
return NATIVE_ALLOCATION_SIZE;
}
@@ -1819,6 +1850,14 @@
}
@Override
+ public boolean hasFocusStateSpecified() {
+ return (mStrokeColors != null && mStrokeColors instanceof ColorStateList &&
+ ((ColorStateList) mStrokeColors).hasFocusStateSpecified()) &&
+ (mFillColors != null && mFillColors instanceof ColorStateList &&
+ ((ColorStateList) mFillColors).hasFocusStateSpecified());
+ }
+
+ @Override
int getNativeSize() {
return NATIVE_ALLOCATION_SIZE;
}
@@ -2116,6 +2155,7 @@
abstract void applyTheme(Theme t);
abstract boolean onStateChange(int[] state);
abstract boolean isStateful();
+ abstract boolean hasFocusStateSpecified();
abstract int getNativeSize();
abstract Property getProperty(String propertyName);
}
diff --git a/media/java/android/media/MediaCas.java b/media/java/android/media/MediaCas.java
index 611fdd1..ce50cc8 100644
--- a/media/java/android/media/MediaCas.java
+++ b/media/java/android/media/MediaCas.java
@@ -51,12 +51,13 @@
* management messages) can be distributed out-of-band, or in-band with the stream.
* <p>
* To descramble elementary streams, the app first calls {@link #openSession} to
- * generate a sessionId that will uniquely identify a session. A session provides
- * a context for subsequent key updates and descrambling activities. The ECMs
- * (Entitlement control messages) are sent to the session via method {@link #processEcm}.
+ * generate a {@link Session} object that will uniquely identify a session. A session
+ * provides a context for subsequent key updates and descrambling activities. The ECMs
+ * (Entitlement control messages) are sent to the session via method
+ * {@link Session#processEcm}.
* <p>
* The app next constructs a MediaDescrambler object, and initializes it with the
- * sessionId using {@link MediaDescrambler#setMediaCasSession}. This ties the
+ * session using {@link MediaDescrambler#setMediaCasSession}. This ties the
* descrambler to the session, and the descrambler can then be used to descramble
* content secured with the session's key, either during extraction, or during decoding
* with {@link android.media.MediaCodec}.
@@ -79,19 +80,20 @@
* If the app uses {@link MediaExtractor}, it can delegate the CAS session
* management to MediaExtractor by calling {@link MediaExtractor#setMediaCas}.
* MediaExtractor will take over and call {@link #openSession}, {@link #processEmm}
- * and/or {@link #processEcm}, etc.. if necessary.
+ * and/or {@link Session#processEcm}, etc.. if necessary.
* <p>
* When using {@link MediaExtractor}, the app would still need a MediaDescrambler
* to use with {@link MediaCodec} if the licensing requires a secure decoder. The
- * sessionId of the descrambler can be retrieved by {@link MediaExtractor#getDrmInitData}
- * and used to initialize a MediaDescrambler object for MediaCodec.
+ * session associated with the descrambler of a track can be retrieved by calling
+ * {@link MediaExtractor#getCasInfo}, and used to initialize a MediaDescrambler
+ * object for MediaCodec.
* <p>
* <h3>Listeners</h3>
* <p>The app may register a listener to receive events from the CA system using
* method {@link #setEventListener}. The exact format of the event is scheme-specific
* and is not specified by this API.
*/
-public final class MediaCas {
+public final class MediaCas implements AutoCloseable {
private static final String TAG = "MediaCas";
private final ParcelableCasData mCasData = new ParcelableCasData();
private ICas mICas;
@@ -229,6 +231,106 @@
}
/**
+ * Class for an open session with the CA system.
+ */
+ public final class Session implements AutoCloseable {
+ final byte[] mSessionId;
+
+ Session(@NonNull byte[] sessionId) {
+ mSessionId = sessionId;
+ }
+
+ /**
+ * Set the private data for a session.
+ *
+ * @param data byte array of the private data.
+ *
+ * @throws IllegalStateException if the MediaCas instance is not valid.
+ * @throws MediaCasException for CAS-specific errors.
+ * @throws MediaCasStateException for CAS-specific state exceptions.
+ */
+ public void setPrivateData(@NonNull byte[] data)
+ throws MediaCasException {
+ validateInternalStates();
+
+ try {
+ mICas.setSessionPrivateData(mSessionId, data);
+ } catch (ServiceSpecificException e) {
+ MediaCasException.throwExceptions(e);
+ } catch (RemoteException e) {
+ cleanupAndRethrowIllegalState();
+ }
+ }
+
+
+ /**
+ * Send a received ECM packet to the specified session of the CA system.
+ *
+ * @param data byte array of the ECM data.
+ * @param offset position within data where the ECM data begins.
+ * @param length length of the data (starting from offset).
+ *
+ * @throws IllegalStateException if the MediaCas instance is not valid.
+ * @throws MediaCasException for CAS-specific errors.
+ * @throws MediaCasStateException for CAS-specific state exceptions.
+ */
+ public void processEcm(@NonNull byte[] data, int offset, int length)
+ throws MediaCasException {
+ validateInternalStates();
+
+ try {
+ mCasData.set(data, offset, length);
+ mICas.processEcm(mSessionId, mCasData);
+ } catch (ServiceSpecificException e) {
+ MediaCasException.throwExceptions(e);
+ } catch (RemoteException e) {
+ cleanupAndRethrowIllegalState();
+ }
+ }
+
+ /**
+ * Send a received ECM packet to the specified session of the CA system.
+ * This is similar to {@link Session#processEcm(byte[], int, int)}
+ * except that the entire byte array is sent.
+ *
+ * @param data byte array of the ECM data.
+ *
+ * @throws IllegalStateException if the MediaCas instance is not valid.
+ * @throws MediaCasException for CAS-specific errors.
+ * @throws MediaCasStateException for CAS-specific state exceptions.
+ */
+ public void processEcm(@NonNull byte[] data) throws MediaCasException {
+ processEcm(data, 0, data.length);
+ }
+
+ /**
+ * Close the session.
+ *
+ * @throws IllegalStateException if the MediaCas instance is not valid.
+ * @throws MediaCasStateException for CAS-specific state exceptions.
+ */
+ @Override
+ public void close() {
+ validateInternalStates();
+
+ try {
+ mICas.closeSession(mSessionId);
+ } catch (ServiceSpecificException e) {
+ MediaCasStateException.throwExceptions(e);
+ } catch (RemoteException e) {
+ cleanupAndRethrowIllegalState();
+ }
+ }
+ }
+
+ Session createFromSessionId(byte[] sessionId) {
+ if (sessionId == null || sessionId.length == 0) {
+ return null;
+ }
+ return new Session(sessionId);
+ }
+
+ /**
* Class for parceling CAS plugin descriptors over IMediaCasService binder.
*/
static class ParcelableCasPluginDescriptor
@@ -404,21 +506,20 @@
}
/**
- * Open a session for the specified program.
+ * Open a session to descramble one or more streams scrambled by the
+ * conditional access system.
*
- * @param programNumber program_number of the program (as in ISO/IEC13818-1).
- *
- * @return session id of the newly opened session.
+ * @return session the newly opened session.
*
* @throws IllegalStateException if the MediaCas instance is not valid.
* @throws MediaCasException for CAS-specific errors.
* @throws MediaCasStateException for CAS-specific state exceptions.
*/
- public byte[] openSession(int programNumber) throws MediaCasException {
+ public Session openSession() throws MediaCasException {
validateInternalStates();
try {
- return mICas.openSession(programNumber);
+ return createFromSessionId(mICas.openSession());
} catch (ServiceSpecificException e) {
MediaCasException.throwExceptions(e);
} catch (RemoteException e) {
@@ -428,118 +529,6 @@
}
/**
- * Open a session for the specified stream.
- *
- * @param programNumber program_number of the stream (as in ISO/IEC13818-1).
- * @param elementaryPID elementary_PID of the stream (as in ISO/IEC13818-1).
- *
- * @return session id of the newly opened session.
- *
- * @throws IllegalStateException if the MediaCas instance is not valid.
- * @throws MediaCasException for CAS-specific errors.
- * @throws MediaCasStateException for CAS-specific state exceptions.
- */
- public byte[] openSession(int programNumber, int elementaryPID)
- throws MediaCasException {
- validateInternalStates();
-
- try {
- return mICas.openSessionForStream(programNumber, elementaryPID);
- } catch (ServiceSpecificException e) {
- MediaCasException.throwExceptions(e);
- } catch (RemoteException e) {
- cleanupAndRethrowIllegalState();
- }
- return null;
- }
-
- /**
- * Close the specified session.
- *
- * @param sessionId the session to be closed.
- *
- * @throws IllegalStateException if the MediaCas instance is not valid.
- * @throws MediaCasStateException for CAS-specific state exceptions.
- */
- public void closeSession(@NonNull byte[] sessionId) {
- validateInternalStates();
-
- try {
- mICas.closeSession(sessionId);
- } catch (ServiceSpecificException e) {
- MediaCasStateException.throwExceptions(e);
- } catch (RemoteException e) {
- cleanupAndRethrowIllegalState();
- }
- }
-
- /**
- * Set the private data for a session.
- *
- * @param sessionId the session for which the private data is intended.
- * @param data byte array of the private data.
- *
- * @throws IllegalStateException if the MediaCas instance is not valid.
- * @throws MediaCasException for CAS-specific errors.
- * @throws MediaCasStateException for CAS-specific state exceptions.
- */
- public void setSessionPrivateData(@NonNull byte[] sessionId, @NonNull byte[] data)
- throws MediaCasException {
- validateInternalStates();
-
- try {
- mICas.setSessionPrivateData(sessionId, data);
- } catch (ServiceSpecificException e) {
- MediaCasException.throwExceptions(e);
- } catch (RemoteException e) {
- cleanupAndRethrowIllegalState();
- }
- }
-
- /**
- * Send a received ECM packet to the specified session of the CA system.
- *
- * @param sessionId the session for which the ECM is intended.
- * @param data byte array of the ECM data.
- * @param offset position within data where the ECM data begins.
- * @param length length of the data (starting from offset).
- *
- * @throws IllegalStateException if the MediaCas instance is not valid.
- * @throws MediaCasException for CAS-specific errors.
- * @throws MediaCasStateException for CAS-specific state exceptions.
- */
- public void processEcm(@NonNull byte[] sessionId, @NonNull byte[] data,
- int offset, int length) throws MediaCasException {
- validateInternalStates();
-
- try {
- mCasData.set(data, offset, length);
- mICas.processEcm(sessionId, mCasData);
- } catch (ServiceSpecificException e) {
- MediaCasException.throwExceptions(e);
- } catch (RemoteException e) {
- cleanupAndRethrowIllegalState();
- }
- }
-
- /**
- * Send a received ECM packet to the specified session of the CA system.
- * This is similar to {@link #processEcm(byte[], byte[], int, int)}
- * except that the entire byte array is sent.
- *
- * @param sessionId the session for which the ECM is intended.
- * @param data byte array of the ECM data.
- *
- * @throws IllegalStateException if the MediaCas instance is not valid.
- * @throws MediaCasException for CAS-specific errors.
- * @throws MediaCasStateException for CAS-specific state exceptions.
- */
- public void processEcm(@NonNull byte[] sessionId, @NonNull byte[] data)
- throws MediaCasException {
- processEcm(sessionId, data, 0, data.length);
- }
-
- /**
* Send a received EMM packet to the CA system.
*
* @param data byte array of the EMM data.
@@ -650,10 +639,8 @@
}
}
- /**
- * Release the MediaCas instance.
- */
- public void release() {
+ @Override
+ public void close() {
if (mICas != null) {
try {
mICas.release();
@@ -666,6 +653,6 @@
@Override
protected void finalize() {
- release();
+ close();
}
}
\ No newline at end of file
diff --git a/media/java/android/media/MediaDescrambler.java b/media/java/android/media/MediaDescrambler.java
index 2dd1097..b75b7dd 100644
--- a/media/java/android/media/MediaDescrambler.java
+++ b/media/java/android/media/MediaDescrambler.java
@@ -38,7 +38,7 @@
* Scrambling schemes are identified by 16-bit unsigned integer as in CA_system_id.
*
*/
-public final class MediaDescrambler {
+public final class MediaDescrambler implements AutoCloseable {
private static final String TAG = "MediaDescrambler";
private IDescrambler mIDescrambler;
@@ -141,17 +141,17 @@
* android.media.MediaCodec#queueSecureInputBuffer} by specifying even
* or odd key in the {@link android.media.MediaCodec.CryptoInfo#key} field.
*
- * @param sessionId the MediaCas sessionId to associate with this
+ * @param session the MediaCas session to associate with this
* MediaDescrambler instance.
*
* @throws IllegalStateException if the descrambler instance is not valid.
* @throws MediaCasStateException for CAS-specific state exceptions.
*/
- public final void setMediaCasSession(@NonNull byte[] sessionId) {
+ public final void setMediaCasSession(@NonNull MediaCas.Session session) {
validateInternalStates();
try {
- mIDescrambler.setMediaCasSession(sessionId);
+ mIDescrambler.setMediaCasSession(session.mSessionId);
} catch (ServiceSpecificException e) {
MediaCasStateException.throwExceptions(e);
} catch (RemoteException e) {
@@ -163,11 +163,10 @@
* Descramble a ByteBuffer of data described by a
* {@link android.media.MediaCodec.CryptoInfo} structure.
*
- * @param srcBuf ByteBuffer containing the scrambled data.
- * @param srcPos position within src where the scrambled data starts.
- * @param dstBuf ByteBuffer to descramble into. If null, descrambling will happen
- * in-place and src will be used as dst.
- * @param dstPos position within dst to put the descrambled data.
+ * @param srcBuf ByteBuffer containing the scrambled data, which starts at
+ * srcBuf.position().
+ * @param dstBuf ByteBuffer to hold the descrambled data, which starts at
+ * dstBuf.position().
* @param cryptoInfo a {@link android.media.MediaCodec.CryptoInfo} structure
* describing the subsamples contained in src.
*
@@ -178,7 +177,7 @@
* @throws MediaCasStateException for CAS-specific state exceptions.
*/
public final int descramble(
- @NonNull ByteBuffer srcBuf, int srcPos, ByteBuffer dstBuf, int dstPos,
+ @NonNull ByteBuffer srcBuf, @NonNull ByteBuffer dstBuf,
@NonNull MediaCodec.CryptoInfo cryptoInfo) {
validateInternalStates();
@@ -208,14 +207,16 @@
cryptoInfo.numSubSamples,
cryptoInfo.numBytesOfClearData,
cryptoInfo.numBytesOfEncryptedData,
- srcBuf, srcPos, dstBuf, dstPos);
+ srcBuf, srcBuf.position(), srcBuf.limit(),
+ dstBuf, dstBuf.position(), dstBuf.limit());
} catch (ServiceSpecificException e) {
MediaCasStateException.throwExceptions(e);
}
return -1;
}
- public final void release() {
+ @Override
+ public void close() {
if (mIDescrambler != null) {
try {
mIDescrambler.release();
@@ -229,7 +230,7 @@
@Override
protected void finalize() {
- release();
+ close();
}
private static native final void native_init();
@@ -237,7 +238,8 @@
private native final void native_release();
private native final int native_descramble(
byte key, int numSubSamples, int[] numBytesOfClearData, int[] numBytesOfEncryptedData,
- @NonNull ByteBuffer srcBuf, int srcOffset, ByteBuffer dstBuf, int dstOffset);
+ @NonNull ByteBuffer srcBuf, int srcOffset, int srcLimit,
+ ByteBuffer dstBuf, int dstOffset, int dstLimit);
static {
System.loadLibrary("media_jni");
diff --git a/media/java/android/media/MediaExtractor.java b/media/java/android/media/MediaExtractor.java
index 2ed6668..a0a6a1e 100644
--- a/media/java/android/media/MediaExtractor.java
+++ b/media/java/android/media/MediaExtractor.java
@@ -259,11 +259,71 @@
* @param mediaCas the MediaCas object to use.
*/
public final void setMediaCas(@NonNull MediaCas mediaCas) {
+ mMediaCas = mediaCas;
nativeSetMediaCas(mediaCas.getBinder());
}
private native final void nativeSetMediaCas(@NonNull IBinder casBinder);
+ /**
+ * Describes the conditional access system used to scramble a track.
+ */
+ public static final class CasInfo {
+ private final int mSystemId;
+ private final MediaCas.Session mSession;
+
+ CasInfo(int systemId, @Nullable MediaCas.Session session) {
+ mSystemId = systemId;
+ mSession = session;
+ }
+
+ /**
+ * Retrieves the system id of the conditional access system.
+ *
+ * @return CA system id of the CAS used to scramble the track.
+ */
+ public int getSystemId() {
+ return mSystemId;
+ }
+
+ /**
+ * Retrieves the {@link MediaCas.Session} associated with a track. The
+ * session is needed to initialize a descrambler in order to decode the
+ * scrambled track.
+ * <p>
+ * @see MediaDescrambler#setMediaCasSession
+ * <p>
+ * @return a {@link MediaCas.Session} object associated with a track.
+ */
+ public MediaCas.Session getSession() {
+ return mSession;
+ }
+ }
+
+ /**
+ * Retrieves the information about the conditional access system used to scramble
+ * a track.
+ *
+ * @param index of the track.
+ * @return an {@link CasInfo} object describing the conditional access system.
+ */
+ public CasInfo getCasInfo(int index) {
+ Map<String, Object> formatMap = getTrackFormatNative(index);
+ if (formatMap.containsKey(MediaFormat.KEY_CA_SYSTEM_ID)) {
+ int systemId = ((Integer)formatMap.get(MediaFormat.KEY_CA_SYSTEM_ID)).intValue();
+ MediaCas.Session session = null;
+ if (mMediaCas != null && formatMap.containsKey(MediaFormat.KEY_CA_SESSION_ID)) {
+ ByteBuffer buf = (ByteBuffer) formatMap.get(MediaFormat.KEY_CA_SESSION_ID);
+ buf.rewind();
+ final byte[] sessionId = new byte[buf.remaining()];
+ buf.get(sessionId);
+ session = mMediaCas.createFromSessionId(sessionId);
+ }
+ return new CasInfo(systemId, session);
+ }
+ return null;
+ }
+
@Override
protected void finalize() {
native_finalize();
@@ -307,31 +367,6 @@
return initDataMap.get(schemeUuid);
}
};
- } else if (formatMap.containsKey("mime")
- && "video/mp2ts".equals(formatMap.get("mime"))) {
- final Map<UUID, DrmInitData.SchemeInitData> initDataMap =
- new HashMap<UUID, DrmInitData.SchemeInitData>();
-
- int numTracks = getTrackCount();
- for (int i = 0; i < numTracks; ++i) {
- Map<String, Object> trackFormatMap = getTrackFormatNative(i);
- if (!trackFormatMap.containsKey("cas")) {
- continue;
- }
- ByteBuffer buf = (ByteBuffer) trackFormatMap.get("cas");
- buf.rewind();
- final byte[] data = new byte[buf.remaining()];
- buf.get(data);
- initDataMap.put(new UUID(0, i), new DrmInitData.SchemeInitData("cas", data));
- }
- if (initDataMap.isEmpty()) {
- return null;
- }
- return new DrmInitData() {
- public SchemeInitData get(UUID schemeUuid) {
- return initDataMap.get(schemeUuid);
- }
- };
} else {
int numTracks = getTrackCount();
for (int i = 0; i < numTracks; ++i) {
@@ -349,8 +384,8 @@
}
};
}
- return null;
}
+ return null;
}
/**
@@ -680,5 +715,7 @@
native_init();
}
+ private MediaCas mMediaCas;
+
private long mNativeContext;
}
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index e77c00b..ed5f7d8 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -767,6 +767,29 @@
*/
public static final String KEY_TRACK_ID = "track-id";
+ /**
+ * A key describing the system id of the conditional access system used to scramble
+ * a media track.
+ * <p>
+ * This key is set by {@link MediaExtractor} if the track is scrambled with a conditional
+ * access system.
+ * <p>
+ * The associated value is an integer.
+ * @hide
+ */
+ public static final String KEY_CA_SYSTEM_ID = "ca-system-id";
+
+ /**
+ * A key describing the {@link MediaCas.Session} object associated with a media track.
+ * <p>
+ * This key is set by {@link MediaExtractor} if the track is scrambled with a conditional
+ * access system.
+ * <p>
+ * The associated value is a ByteBuffer.
+ * @hide
+ */
+ public static final String KEY_CA_SESSION_ID = "ca-session-id";
+
/* package private */ MediaFormat(Map<String, Object> map) {
mMap = map;
}
diff --git a/media/jni/android_media_MediaDescrambler.cpp b/media/jni/android_media_MediaDescrambler.cpp
index f031dbb..85d33b7 100644
--- a/media/jni/android_media_MediaDescrambler.cpp
+++ b/media/jni/android_media_MediaDescrambler.cpp
@@ -54,11 +54,10 @@
}
static status_t getBufferAndSize(
- JNIEnv *env, jobject byteBuf, jint offset, size_t length,
+ JNIEnv *env, jobject byteBuf, jint offset, jint limit, size_t length,
void **outPtr, jbyteArray *outByteArray) {
void *ptr = env->GetDirectBufferAddress(byteBuf);
- size_t bufSize;
jbyteArray byteArray = NULL;
ScopedLocalRef<jclass> byteBufClass(env, env->FindClass("java/nio/ByteBuffer"));
@@ -78,13 +77,9 @@
jboolean isCopy;
ptr = env->GetByteArrayElements(byteArray, &isCopy);
-
- bufSize = (size_t) env->GetArrayLength(byteArray);
- } else {
- bufSize = (size_t) env->GetDirectBufferCapacity(byteBuf);
}
- if (length + offset > bufSize) {
+ if ((jint)length + offset > limit) {
if (byteArray != NULL) {
env->ReleaseByteArrayElements(byteArray, (jbyte *)ptr, 0);
}
@@ -294,7 +289,8 @@
static jint android_media_MediaDescrambler_native_descramble(
JNIEnv *env, jobject thiz, jbyte key, jint numSubSamples,
jintArray numBytesOfClearDataObj, jintArray numBytesOfEncryptedDataObj,
- jobject srcBuf, jint srcOffset, jobject dstBuf, jint dstOffset) {
+ jobject srcBuf, jint srcOffset, jint srcLimit,
+ jobject dstBuf, jint dstOffset, jint dstLimit) {
sp<JDescrambler> descrambler = getDescrambler(env, thiz);
if (descrambler == NULL) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
@@ -307,7 +303,7 @@
numBytesOfEncryptedDataObj, &subSamples);
if (totalLength < 0) {
jniThrowException(env, "java/lang/IllegalArgumentException",
- "Invalid sub sample info!");
+ "Invalid subsample info!");
return -1;
}
@@ -315,16 +311,23 @@
void *srcPtr = NULL, *dstPtr = NULL;
jbyteArray srcArray = NULL, dstArray = NULL;
status_t err = getBufferAndSize(
- env, srcBuf, srcOffset, totalLength, &srcPtr, &srcArray);
+ env, srcBuf, srcOffset, srcLimit, totalLength, &srcPtr, &srcArray);
if (err == OK) {
if (dstBuf == NULL) {
dstPtr = srcPtr;
} else {
err = getBufferAndSize(
- env, dstBuf, dstOffset, totalLength, &dstPtr, &dstArray);
+ env, dstBuf, dstOffset, dstLimit, totalLength, &dstPtr, &dstArray);
}
}
+
+ if (err != OK) {
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "Invalid buffer offset and/or size for subsamples!");
+ return -1;
+ }
+
Status status;
if (err == OK) {
status = descrambler->descramble(
@@ -394,7 +397,7 @@
(void *)android_media_MediaDescrambler_native_init },
{ "native_setup", "(Landroid/os/IBinder;)V",
(void *)android_media_MediaDescrambler_native_setup },
- { "native_descramble", "(BI[I[ILjava/nio/ByteBuffer;ILjava/nio/ByteBuffer;I)I",
+ { "native_descramble", "(BI[I[ILjava/nio/ByteBuffer;IILjava/nio/ByteBuffer;II)I",
(void *)android_media_MediaDescrambler_native_descramble },
};
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
index e60b5a9..db88f2c 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
@@ -509,7 +509,7 @@
final DeviceToolkit toolkit =
new DeviceToolkit(mMtpManager, mResolver, mDatabase, device);
mDeviceToolkits.put(deviceId, toolkit);
- mIntentSender.sendUpdateNotificationIntent(device);
+ mIntentSender.sendUpdateNotificationIntent(getOpenedDeviceRecordsCache());
try {
mRootScanner.resume().await();
} catch (InterruptedException error) {
@@ -524,9 +524,9 @@
void closeDevice(int deviceId) throws IOException, InterruptedException {
synchronized (mDeviceListLock) {
closeDeviceInternal(deviceId);
+ mIntentSender.sendUpdateNotificationIntent(getOpenedDeviceRecordsCache());
}
mRootScanner.resume();
- mIntentSender.sendUpdateNotificationIntent(null);
}
MtpDeviceRecord[] getOpenedDeviceRecordsCache() {
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsService.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsService.java
index 664d3c9..fa1a12030 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsService.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsService.java
@@ -16,13 +16,17 @@
package com.android.mtp;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.Notification;
import android.app.Service;
import android.app.NotificationManager;
-import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
+import android.os.Parcelable;
import android.service.notification.StatusBarNotification;
+import android.util.Log;
+import com.android.internal.util.Preconditions;
import java.util.HashSet;
import java.util.Set;
@@ -33,7 +37,8 @@
*/
public class MtpDocumentsService extends Service {
static final String ACTION_UPDATE_NOTIFICATION = "com.android.mtp.UPDATE_NOTIFICATION";
- static final String EXTRA_DEVICE = "device";
+ static final String EXTRA_DEVICE_IDS = "deviceIds";
+ static final String EXTRA_DEVICE_NOTIFICATIONS = "deviceNotifications";
private NotificationManager mNotificationManager;
@@ -53,7 +58,12 @@
public int onStartCommand(Intent intent, int flags, int startId) {
// If intent is null, the service was restarted.
if (intent == null || ACTION_UPDATE_NOTIFICATION.equals(intent.getAction())) {
- return updateForegroundState() ? START_STICKY : START_NOT_STICKY;
+ final int[] ids = intent.hasExtra(EXTRA_DEVICE_IDS) ?
+ intent.getExtras().getIntArray(EXTRA_DEVICE_IDS) : null;
+ final Notification[] notifications = intent.hasExtra(EXTRA_DEVICE_NOTIFICATIONS) ?
+ castToNotifications(intent.getExtras().getParcelableArray(
+ EXTRA_DEVICE_NOTIFICATIONS)) : null;
+ return updateForegroundState(ids, notifications) ? START_STICKY : START_NOT_STICKY;
}
return START_NOT_STICKY;
}
@@ -62,35 +72,38 @@
* Updates the foreground state of the service.
* @return Whether the service is foreground or not.
*/
- private boolean updateForegroundState() {
- final MtpDocumentsProvider provider = MtpDocumentsProvider.getInstance();
+ private boolean updateForegroundState(
+ @Nullable int[] ids, @Nullable Notification[] notifications) {
final Set<Integer> openedNotification = new HashSet<>();
- boolean hasForegroundNotification = false;
+ final int size = ids != null ? ids.length : 0;
+ if (size != 0) {
+ Preconditions.checkArgument(ids != null);
+ Preconditions.checkArgument(notifications != null);
+ Preconditions.checkArgument(ids.length == notifications.length);
+ }
+
+ for (int i = 0; i < size; i++) {
+ if (i == 0) {
+ // Mark this service as foreground with the notification so that the process is
+ // not killed by the system while a MTP device is opened.
+ startForeground(ids[i], notifications[i]);
+ } else {
+ // Only one notification can be shown as a foreground notification. We need to
+ // show the rest as normal notification.
+ mNotificationManager.notify(ids[i], notifications[i]);
+ }
+ openedNotification.add(ids[i]);
+ }
final StatusBarNotification[] activeNotifications =
mNotificationManager.getActiveNotifications();
-
- for (final MtpDeviceRecord record : provider.getOpenedDeviceRecordsCache()) {
- openedNotification.add(record.deviceId);
- if (!hasForegroundNotification) {
- // Mark this service as foreground with the notification so that the process is not
- // killed by the system while a MTP device is opened.
- startForeground(record.deviceId, createNotification(this, record));
- hasForegroundNotification = true;
- } else {
- // Only one notification can be shown as a foreground notification. We need to show
- // the rest as normal notification.
- mNotificationManager.notify(record.deviceId, createNotification(this, record));
- }
- }
-
for (final StatusBarNotification notification : activeNotifications) {
if (!openedNotification.contains(notification.getId())) {
mNotificationManager.cancel(notification.getId());
}
}
- if (!hasForegroundNotification) {
+ if (size == 0) {
// There is no opened device.
stopForeground(true /* removeNotification */);
stopSelf();
@@ -100,17 +113,12 @@
return true;
}
- public static Notification createNotification(Context context, MtpDeviceRecord device) {
- final String title = context.getResources().getString(
- R.string.accessing_notification_title,
- device.name);
- return new Notification.Builder(context)
- .setLocalOnly(true)
- .setContentTitle(title)
- .setSmallIcon(com.android.internal.R.drawable.stat_sys_data_usb)
- .setCategory(Notification.CATEGORY_SYSTEM)
- .setPriority(Notification.PRIORITY_LOW)
- .setFlag(Notification.FLAG_NO_CLEAR, true)
- .build();
+ private static @NonNull Notification[] castToNotifications(@NonNull Parcelable[] src) {
+ Preconditions.checkNotNull(src);
+ final Notification[] notifications = new Notification[src.length];
+ for (int i = 0; i < src.length; i++) {
+ notifications[i] = (Notification) src[i];
+ }
+ return notifications;
}
}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/ServiceIntentSender.java b/packages/MtpDocumentsProvider/src/com/android/mtp/ServiceIntentSender.java
index d8c3d35..c5292b8 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/ServiceIntentSender.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/ServiceIntentSender.java
@@ -16,11 +16,12 @@
package com.android.mtp;
-import android.annotation.Nullable;
-import android.app.NotificationManager;
+import android.annotation.NonNull;
+import android.app.Notification;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import com.android.internal.util.Preconditions;
/**
* Sends intent to MtpDocumentsService.
@@ -34,20 +35,38 @@
/**
* Notify the change of opened device set.
- * @param record If a new device is opened, pass the device record. If a device is closed, pass
- * null.
+ * @param records List of opened devices. Can be empty.
*/
- void sendUpdateNotificationIntent(@Nullable MtpDeviceRecord record) {
+ void sendUpdateNotificationIntent(@NonNull MtpDeviceRecord[] records) {
+ Preconditions.checkNotNull(records);
final Intent intent = new Intent(MtpDocumentsService.ACTION_UPDATE_NOTIFICATION);
intent.setComponent(new ComponentName(mContext, MtpDocumentsService.class));
- final NotificationManager manager = mContext.getSystemService(NotificationManager.class);
- if (record != null) {
- manager.startServiceInForeground(
- intent,
- record.deviceId,
- MtpDocumentsService.createNotification(mContext, record));
+ if (records.length != 0) {
+ final int[] ids = new int[records.length];
+ final Notification[] notifications = new Notification[records.length];
+ for (int i = 0; i < records.length; i++) {
+ ids[i] = records[i].deviceId;
+ notifications[i] = createNotification(mContext, records[i]);
+ }
+ intent.putExtra(MtpDocumentsService.EXTRA_DEVICE_IDS, ids);
+ intent.putExtra(MtpDocumentsService.EXTRA_DEVICE_NOTIFICATIONS, notifications);
+ mContext.startForegroundService(intent);
} else {
mContext.startService(intent);
}
}
+
+ private static Notification createNotification(Context context, MtpDeviceRecord device) {
+ final String title = context.getResources().getString(
+ R.string.accessing_notification_title,
+ device.name);
+ return new Notification.Builder(context)
+ .setLocalOnly(true)
+ .setContentTitle(title)
+ .setSmallIcon(com.android.internal.R.drawable.stat_sys_data_usb)
+ .setCategory(Notification.CATEGORY_SYSTEM)
+ .setPriority(Notification.PRIORITY_LOW)
+ .setFlag(Notification.FLAG_NO_CLEAR, true)
+ .build();
+ }
}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestServiceIntentSender.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestServiceIntentSender.java
index 74dd429..ed2dc38 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestServiceIntentSender.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestServiceIntentSender.java
@@ -16,13 +16,11 @@
package com.android.mtp;
-import android.annotation.Nullable;
-
class TestServiceIntentSender extends ServiceIntentSender {
TestServiceIntentSender() {
super(null);
}
@Override
- void sendUpdateNotificationIntent(@Nullable MtpDeviceRecord record) {}
+ void sendUpdateNotificationIntent(MtpDeviceRecord[] record) {}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index 78ad34a..0ab296e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -186,6 +186,11 @@
TypedArray ta = context.obtainStyledAttributes(new int[]{attr});
float alpha = ta.getFloat(0, 0);
ta.recycle();
+ return applyAlpha(alpha, inputColor);
+ }
+
+ @ColorInt
+ public static int applyAlpha(float alpha, int inputColor) {
alpha *= Color.alpha(inputColor);
return Color.argb((int) (alpha), Color.red(inputColor), Color.green(inputColor),
Color.blue(inputColor));
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AppRestrictionsHelperTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AppRestrictionsHelperTest.java
index 85b04c8..820231e 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AppRestrictionsHelperTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AppRestrictionsHelperTest.java
@@ -159,14 +159,14 @@
for (String pkg : defaultImes) {
final ResolveInfo ri = createResolveInfoForSystemApp(pkg);
final InputMethodInfo inputMethodInfo = new InputMethodInfo(
- ri, false, null, null, 0, true, true, false);
+ ri, false, null, null, 0, true, true);
inputMethods.add(inputMethodInfo);
addInstalledApp(ri);
}
for (String pkg : otherImes) {
final ResolveInfo ri = createResolveInfoForSystemApp(pkg);
final InputMethodInfo inputMethodInfo = new InputMethodInfo(
- ri, false, null, null, 0, false, true, false);
+ ri, false, null, null, 0, false, true);
inputMethods.add(inputMethodInfo);
addInstalledApp(ri);
}
diff --git a/packages/Shell/res/values-b+sr+Latn/strings.xml b/packages/Shell/res/values-b+sr+Latn/strings.xml
index 5809bfc..805aed6 100644
--- a/packages/Shell/res/values-b+sr+Latn/strings.xml
+++ b/packages/Shell/res/values-b+sr+Latn/strings.xml
@@ -23,7 +23,9 @@
<string name="bugreport_updating_title" msgid="4423539949559634214">"Dodaju se detalji u izveštaj o grešci"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Sačekajte..."</string>
<string name="bugreport_finished_text" product="watch" msgid="1223616207145252689">"Izveštaj o grešci će se uskoro pojaviti na telefonu"</string>
+ <string name="bugreport_finished_text" product="tv" msgid="5758325479058638893">"Izaberite da biste delili izveštaj o grešci"</string>
<string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Dodirnite da biste delili izveštaj o grešci"</string>
+ <string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"Izaberite da biste delili izveštaj o grešci bez snimka ekrana ili sačekajte da se napravi snimak ekrana"</string>
<string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Dodirnite za deljenje izveštaja o grešci bez snimka ekrana ili sačekajte da se napravi snimak ekrana"</string>
<string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Dodirnite za deljenje izveštaja o grešci bez snimka ekrana ili sačekajte da se napravi snimak ekrana"</string>
<string name="bugreport_confirm" msgid="5917407234515812495">"Izveštaji o greškama sadrže podatke iz različitih sistemskih datoteka evidencije, koji obuhvataju lične i privatne podatke (poput korišćenja aplikacija i podataka o lokaciji). Delite izveštaje o greškama samo sa aplikacijama i ljudima u koje imate poverenja."</string>
diff --git a/packages/Shell/res/values-be/strings.xml b/packages/Shell/res/values-be/strings.xml
index f69317c..bea1c30 100644
--- a/packages/Shell/res/values-be/strings.xml
+++ b/packages/Shell/res/values-be/strings.xml
@@ -23,7 +23,9 @@
<string name="bugreport_updating_title" msgid="4423539949559634214">"Дадаванне падрабязнасцей да справаздачы пра памылкі"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Калі ласка, пачакайце..."</string>
<string name="bugreport_finished_text" product="watch" msgid="1223616207145252689">"Паведамленне пра памылку хутка з\'явіцца на тэлефоне"</string>
+ <string name="bugreport_finished_text" product="tv" msgid="5758325479058638893">"Выберыце, каб абагуліць справаздачу пра памылку"</string>
<string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Дакраніцеся, каб абагуліць сваю справаздачу пра памылку"</string>
+ <string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"Выберыце, каб абагуліць справаздачу пра памылку без здымка экрана, або чакайце атрымання здымка"</string>
<string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Краніце, каб абагуліць справаздачу пра памылку без здымка экрана, або чакайце атрымання здымка."</string>
<string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Краніце, каб абагуліць справаздачу пра памылку без здымка экрана, або чакайце атрымання здымка."</string>
<string name="bugreport_confirm" msgid="5917407234515812495">"Справаздачы пра памылкі ўтрымліваюць даныя з розных файлаў журналаў сістэмы, якія могуць уключаць даныя, што вы лічыце канфідэнцыяльнымі (напрыклад, пра выкарыстанне праграм і даныя аб месцазнаходжанні). Абагульвайце справаздачы пра памылкі толькі з тымі людзьмі і праграмамі, якім вы давяраеце."</string>
diff --git a/packages/Shell/res/values-bs/strings.xml b/packages/Shell/res/values-bs/strings.xml
index 8815e94..fab8063 100644
--- a/packages/Shell/res/values-bs/strings.xml
+++ b/packages/Shell/res/values-bs/strings.xml
@@ -23,7 +23,9 @@
<string name="bugreport_updating_title" msgid="4423539949559634214">"Dodavanje detalja u izvještaj o greškama"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"Pričekajte..."</string>
<string name="bugreport_finished_text" product="watch" msgid="1223616207145252689">"Izvještaj o greškama će se ubrzo pojaviti na ekranu"</string>
+ <string name="bugreport_finished_text" product="tv" msgid="5758325479058638893">"Odaberite da podijelite izvještaj o greškama"</string>
<string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Dodirnite da biste podijelili izvještaj o grešci"</string>
+ <string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"Odaberite da podijelite izvještaj o greškama bez snimka ekrana ili sačekajte da snimak bude gotov"</string>
<string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Dodirnite da podijelite izveštaj o greškama bez snimka ekrana ili sačekajte da snimak bude gotov"</string>
<string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Dodirnite da podijelite izveštaj o greškama bez snimka ekrana ili sačekajte da snimak bude gotov"</string>
<string name="bugreport_confirm" msgid="5917407234515812495">"Izvještaji o greškama sadrže podatke iz raznih zapisnika sistema koji mogu sadržavati lične i privatne informacije koje smatrate osjetljivima (poput podataka o upotrebi aplikacije ili podataka o lokaciji). Izvještaje o greškama dijelite samo sa aplikacijama i osobama kojima vjerujete."</string>
diff --git a/packages/SystemUI/res/drawable/qs_background_primary.xml b/packages/SystemUI/res/drawable/qs_background_primary.xml
index 8ea9e06..0bdbc5f 100644
--- a/packages/SystemUI/res/drawable/qs_background_primary.xml
+++ b/packages/SystemUI/res/drawable/qs_background_primary.xml
@@ -15,6 +15,6 @@
-->
<inset xmlns:android="http://schemas.android.com/apk/res/android">
<shape>
- <solid android:color="?android:attr/colorPrimary"/>
+ <solid android:color="?android:attr/colorPrimaryDark"/>
</shape>
</inset>
diff --git a/packages/SystemUI/res/layout/qs_divider.xml b/packages/SystemUI/res/layout/qs_divider.xml
index 660e4af..39d48ea 100644
--- a/packages/SystemUI/res/layout/qs_divider.xml
+++ b/packages/SystemUI/res/layout/qs_divider.xml
@@ -16,6 +16,5 @@
<View xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="1dp"
- android:layout_marginStart="16dp"
- android:layout_marginEnd="16dp"
+ android:alpha=".12"
android:background="?android:attr/colorForeground" />
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index d68487c..eeb28c8 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1895,6 +1895,13 @@
<!-- Tuner string -->
<string name="default_theme" translatable="false">Default</string>
+ <!-- Title for notification & dialog that the user's phone last shut down because it got too hot. [CHAR LIMIT=30] -->
+ <string name="thermal_shutdown_title">Phone turned off due to heat</string>
+ <!-- Message body for notification that user's phone last shut down because it got too hot. [CHAR LIMIT=100] -->
+ <string name="thermal_shutdown_message">Your phone is now running normally</string>
+ <!-- Text body for dialog alerting user that their phone last shut down bewcause it got too hot. [CHAR LIMIT=300] -->
+ <string name="thermal_shutdown_dialog_message">Your phone was too hot, so it turned off to cool down. Your phone is now running normally.\n\nYour phone may get too hot if you:\n\t• Use resource-intensive apps (such as gaming, video, or navigation apps)\n\t• Download or upload large files\n\t• Use your phone in high temperatures</string>
+
<!-- Title for notification (and dialog) that user's phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=30] -->
<string name="high_temp_title">Phone is getting warm</string>
<!-- Message body for notification that user's phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=100] -->
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 2e6116d..38485c7 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -32,6 +32,7 @@
import android.widget.LinearLayout;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.plugins.qs.DetailAdapter;
@@ -118,7 +119,8 @@
protected void addDivider() {
mDivider = LayoutInflater.from(mContext).inflate(R.layout.qs_divider, this, false);
- mDivider.setBackgroundColor(getColorForState(mContext, Tile.STATE_INACTIVE));
+ mDivider.setBackgroundColor(Utils.applyAlpha(mDivider.getAlpha(),
+ getColorForState(mContext, Tile.STATE_ACTIVE)));
addView(mDivider);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index d0d6f61..7518527 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -21,15 +21,19 @@
import android.graphics.Rect;
import android.support.annotation.VisibleForTesting;
import android.util.AttributeSet;
+import android.view.View;
import android.widget.RelativeLayout;
+import android.widget.TextClock;
import com.android.settingslib.Utils;
import com.android.systemui.BatteryMeterView;
import com.android.systemui.Dependency;
import com.android.systemui.R;
+import com.android.systemui.R.id;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.qs.QSDetail.Callback;
import com.android.systemui.statusbar.SignalClusterView;
+import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver;
public class QuickStatusBarHeader extends RelativeLayout {
@@ -63,19 +67,27 @@
updateResources();
// Set the light/dark theming on the header status UI to match the current theme.
- SignalClusterView cluster = findViewById(R.id.signal_cluster);
int colorForeground = Utils.getColorAttr(getContext(), android.R.attr.colorForeground);
float intensity = colorForeground == Color.WHITE ? 0 : 1;
- cluster.onDarkChanged(new Rect(0, 0, 0, 0), intensity, colorForeground);
+ Rect tintArea = new Rect(0, 0, 0, 0);
+
+ applyDarkness(R.id.signal_cluster, tintArea, intensity, colorForeground);
+ applyDarkness(R.id.battery, tintArea, intensity, colorForeground);
+ applyDarkness(R.id.clock, tintArea, intensity, colorForeground);
BatteryMeterView battery = findViewById(R.id.battery);
battery.setForceShowPercent(true);
- int colorSecondary = Utils.getColorAttr(getContext(), android.R.attr.textColorSecondary);
- battery.setRawColors(colorForeground, colorSecondary);
mActivityStarter = Dependency.get(ActivityStarter.class);
}
+ private void applyDarkness(int id, Rect tintArea, float intensity, int color) {
+ View v = findViewById(id);
+ if (v instanceof DarkReceiver) {
+ ((DarkReceiver) v).onDarkChanged(tintArea, intensity, color);
+ }
+ }
+
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index df2a9fb..6781c16 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -22,6 +22,7 @@
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_ACTION;
import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
+import android.R.attr;
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
@@ -342,9 +343,9 @@
Utils.getColorAttr(context, android.R.attr.textColorTertiary));
case Tile.STATE_INACTIVE:
return Utils.getDisabled(context,
- Utils.getColorAttr(context, android.R.attr.colorForeground));
+ Utils.getColorAttr(context, android.R.attr.textColorSecondary));
case Tile.STATE_ACTIVE:
- return Utils.getColorAttr(context, android.R.attr.colorForeground);
+ return Utils.getColorAttr(context, attr.textColorSecondary);
default:
Log.e("QSTile", "Invalid state " + state);
return 0;
diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto
index c4a2831..65cc17e 100644
--- a/proto/src/system_messages.proto
+++ b/proto/src/system_messages.proto
@@ -173,6 +173,9 @@
// Package: android
NOTE_ACCOUNT_CREDENTIAL_PERMISSION = 38;
+ // Inform the user their phone recently shut down due to high temperature
+ NOTE_THERMAL_SHUTDOWN = 39;
+
// ADD_NEW_IDS_ABOVE_THIS_LINE
// Legacy IDs with arbitrary values appear below
// Legacy IDs existed as stable non-conflicting constants prior to the O release
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 0488d22..0003941 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -2036,10 +2036,16 @@
}
if (!shortcutServiceIsInstalled) {
userState.mServiceToEnableWithShortcut = null;
- Settings.Secure.putStringForUser(mContext.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, null, userState.mUserId);
- Settings.Secure.putIntForUser(mContext.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED, 0, userState.mUserId);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ Settings.Secure.putStringForUser(mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, null, userState.mUserId);
+
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_SHORTCUT_ENABLED, 0, userState.mUserId);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
}
}
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index dcf6fd7..1a5ec61 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -416,6 +416,29 @@
return resOps;
}
+ private ArrayList<AppOpsManager.OpEntry> collectOps(SparseIntArray uidOps, int[] ops) {
+ ArrayList<AppOpsManager.OpEntry> resOps = null;
+ if (ops == null) {
+ resOps = new ArrayList<>();
+ for (int j=0; j<uidOps.size(); j++) {
+ resOps.add(new AppOpsManager.OpEntry(uidOps.keyAt(j), uidOps.valueAt(j),
+ 0, 0, 0, -1, null));
+ }
+ } else {
+ for (int j=0; j<ops.length; j++) {
+ int index = uidOps.indexOfKey(ops[j]);
+ if (index >= 0) {
+ if (resOps == null) {
+ resOps = new ArrayList<>();
+ }
+ resOps.add(new AppOpsManager.OpEntry(uidOps.keyAt(index), uidOps.valueAt(index),
+ 0, 0, 0, -1, null));
+ }
+ }
+ }
+ return resOps;
+ }
+
@Override
public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
@@ -473,6 +496,27 @@
}
}
+ @Override
+ public List<AppOpsManager.PackageOps> getUidOps(int uid, int[] ops) {
+ mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
+ Binder.getCallingPid(), Binder.getCallingUid(), null);
+ synchronized (this) {
+ UidState uidState = getUidStateLocked(uid, false);
+ if (uidState == null) {
+ return null;
+ }
+ ArrayList<AppOpsManager.OpEntry> resOps = collectOps(uidState.opModes, ops);
+ if (resOps == null) {
+ return null;
+ }
+ ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
+ AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
+ null, uidState.uid, resOps);
+ res.add(resPackage);
+ return res;
+ }
+ }
+
private void pruneOp(Op op, int uid, String packageName) {
if (op.time == 0 && op.rejectTime == 0) {
Ops ops = getOpsRawLocked(uid, packageName, false);
@@ -1669,6 +1713,7 @@
int op;
int mode;
int packageUid;
+ int nonpackageUid;
Shell(IAppOpsService iface, AppOpsService internal) {
mInterface = iface;
@@ -1790,15 +1835,59 @@
if (userId == UserHandle.USER_CURRENT) {
userId = ActivityManager.getCurrentUser();
}
- if ("root".equals(packageName)) {
- packageUid = 0;
- } else {
- packageUid = AppGlobals.getPackageManager().getPackageUid(packageName,
- PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
+ nonpackageUid = -1;
+ try {
+ nonpackageUid = Integer.parseInt(packageName);
+ } catch (NumberFormatException e) {
}
- if (packageUid < 0) {
- err.println("Error: No UID for " + packageName + " in user " + userId);
- return -1;
+ if (nonpackageUid == -1 && packageName.length() > 1 && packageName.charAt(0) == 'u'
+ && packageName.indexOf('.') < 0) {
+ int i = 1;
+ while (i < packageName.length() && packageName.charAt(i) >= '0'
+ && packageName.charAt(i) <= '9') {
+ i++;
+ }
+ if (i > 1 && i < packageName.length()) {
+ String userStr = packageName.substring(1, i);
+ try {
+ int user = Integer.parseInt(userStr);
+ char type = packageName.charAt(i);
+ i++;
+ int startTypeVal = i;
+ while (i < packageName.length() && packageName.charAt(i) >= '0'
+ && packageName.charAt(i) <= '9') {
+ i++;
+ }
+ if (i > startTypeVal) {
+ String typeValStr = packageName.substring(startTypeVal, i);
+ try {
+ int typeVal = Integer.parseInt(typeValStr);
+ if (type == 'a') {
+ nonpackageUid = UserHandle.getUid(user,
+ typeVal + Process.FIRST_APPLICATION_UID);
+ } else if (type == 's') {
+ nonpackageUid = UserHandle.getUid(user, typeVal);
+ }
+ } catch (NumberFormatException e) {
+ }
+ }
+ } catch (NumberFormatException e) {
+ }
+ }
+ }
+ if (nonpackageUid != -1) {
+ packageName = null;
+ } else {
+ if ("root".equals(packageName)) {
+ packageUid = 0;
+ } else {
+ packageUid = AppGlobals.getPackageManager().getPackageUid(packageName,
+ PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
+ }
+ if (packageUid < 0) {
+ err.println("Error: No UID for " + packageName + " in user " + userId);
+ return -1;
+ }
}
return 0;
}
@@ -1814,9 +1903,9 @@
pw.println("AppOps service (appops) commands:");
pw.println(" help");
pw.println(" Print this help text.");
- pw.println(" set [--user <USER_ID>] <PACKAGE> <OP> <MODE>");
+ pw.println(" set [--user <USER_ID>] <PACKAGE | UID> <OP> <MODE>");
pw.println(" Set the mode for a particular application and operation.");
- pw.println(" get [--user <USER_ID>] <PACKAGE> [<OP>]");
+ pw.println(" get [--user <USER_ID>] <PACKAGE | UID> [<OP>]");
pw.println(" Return the mode for a particular application and optional operation.");
pw.println(" query-op [--user <USER_ID>] <OP> [<MODE>]");
pw.println(" Print all packages that currently have the given op in the given mode.");
@@ -1858,7 +1947,12 @@
return -1;
}
- shell.mInterface.setMode(shell.op, shell.packageUid, shell.packageName, mode);
+ if (shell.packageName != null) {
+ shell.mInterface.setMode(shell.op, shell.packageUid, shell.packageName,
+ mode);
+ } else {
+ shell.mInterface.setUidMode(shell.op, shell.nonpackageUid, mode);
+ }
return 0;
}
case "get": {
@@ -1867,9 +1961,16 @@
return res;
}
- List<AppOpsManager.PackageOps> ops = shell.mInterface.getOpsForPackage(
- shell.packageUid, shell.packageName,
- shell.op != AppOpsManager.OP_NONE ? new int[] {shell.op} : null);
+ List<AppOpsManager.PackageOps> ops;
+ if (shell.packageName != null) {
+ ops = shell.mInterface.getOpsForPackage(
+ shell.packageUid, shell.packageName,
+ shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
+ } else {
+ ops = shell.mInterface.getUidOps(
+ shell.nonpackageUid,
+ shell.op != AppOpsManager.OP_NONE ? new int[]{shell.op} : null);
+ }
if (ops == null || ops.size() <= 0) {
pw.println("No operations.");
return 0;
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 7dd75df..c77820b 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -324,7 +324,7 @@
if (callerApp == null) {
throw new SecurityException(
"Unable to find app for caller " + caller
- + " (pid=" + Binder.getCallingPid()
+ + " (pid=" + callingPid
+ ") when starting service " + service);
}
callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
@@ -353,29 +353,24 @@
// If this isn't a direct-to-foreground start, check our ability to kick off an
// arbitrary service
if (!r.startRequested && !fgRequired) {
- final long token = Binder.clearCallingIdentity();
- try {
- // Before going further -- if this app is not allowed to start services in the
- // background, then at this point we aren't going to let it period.
- final int allowed = mAm.getAppStartModeLocked(r.appInfo.uid, r.packageName,
- r.appInfo.targetSdkVersion, callingPid, false, false);
- if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
- Slog.w(TAG, "Background start not allowed: service "
- + service + " to " + r.name.flattenToShortString()
- + " from pid=" + callingPid + " uid=" + callingUid
- + " pkg=" + callingPackage);
- if (allowed == ActivityManager.APP_START_MODE_DELAYED) {
- // In this case we are silently disabling the app, to disrupt as
- // little as possible existing apps.
- return null;
- }
- // This app knows it is in the new model where this operation is not
- // allowed, so tell it what has happened.
- UidRecord uidRec = mAm.mActiveUids.get(r.appInfo.uid);
- return new ComponentName("?", "app is in background uid " + uidRec);
+ // Before going further -- if this app is not allowed to start services in the
+ // background, then at this point we aren't going to let it period.
+ final int allowed = mAm.getAppStartModeLocked(r.appInfo.uid, r.packageName,
+ r.appInfo.targetSdkVersion, callingPid, false, false);
+ if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
+ Slog.w(TAG, "Background start not allowed: service "
+ + service + " to " + r.name.flattenToShortString()
+ + " from pid=" + callingPid + " uid=" + callingUid
+ + " pkg=" + callingPackage);
+ if (allowed == ActivityManager.APP_START_MODE_DELAYED) {
+ // In this case we are silently disabling the app, to disrupt as
+ // little as possible existing apps.
+ return null;
}
- } finally {
- Binder.restoreCallingIdentity(token);
+ // This app knows it is in the new model where this operation is not
+ // allowed, so tell it what has happened.
+ UidRecord uidRec = mAm.mActiveUids.get(r.appInfo.uid);
+ return new ComponentName("?", "app is in background uid " + uidRec);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 82d5439..3094f1a 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5243,10 +5243,10 @@
}
private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
- IBinder threadBinder = thread.asBinder();
+ final IBinder threadBinder = thread.asBinder();
// Find the application record.
for (int i=mLruProcesses.size()-1; i>=0; i--) {
- ProcessRecord rec = mLruProcesses.get(i);
+ final ProcessRecord rec = mLruProcesses.get(i);
if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
return i;
}
@@ -5261,7 +5261,27 @@
}
int appIndex = getLRURecordIndexForAppLocked(thread);
- return appIndex >= 0 ? mLruProcesses.get(appIndex) : null;
+ if (appIndex >= 0) {
+ return mLruProcesses.get(appIndex);
+ }
+
+ // Validation: if it isn't in the LRU list, it shouldn't exist, but let's
+ // double-check that.
+ final IBinder threadBinder = thread.asBinder();
+ final ArrayMap<String, SparseArray<ProcessRecord>> pmap = mProcessNames.getMap();
+ for (int i = pmap.size()-1; i >= 0; i--) {
+ final SparseArray<ProcessRecord> procs = pmap.valueAt(i);
+ for (int j = procs.size()-1; j >= 0; j--) {
+ final ProcessRecord proc = procs.valueAt(j);
+ if (proc.thread != null && proc.thread.asBinder() == threadBinder) {
+ Slog.wtf(TAG, "getRecordForApp: exists in name list but not in LRU list: "
+ + proc);
+ return proc;
+ }
+ }
+ }
+
+ return null;
}
final void doLowMemReportIfNeededLocked(ProcessRecord dyingProc) {
@@ -7803,7 +7823,7 @@
// Activity supports picture-in-picture, now check that we can enter PiP at this
// point, if it is
if (!r.checkEnterPictureInPictureState("enterPictureInPictureMode",
- false /* noThrow */)) {
+ false /* noThrow */, false /* beforeStopping */)) {
return false;
}
@@ -13025,6 +13045,19 @@
}
@Override
+ public int getUidProcessState(int uid, String callingPackage) {
+ if (!hasUsageStatsPermission(callingPackage)) {
+ enforceCallingPermission(android.Manifest.permission.PACKAGE_USAGE_STATS,
+ "getUidProcessState");
+ }
+
+ synchronized (this) {
+ UidRecord uidRec = mActiveUids.get(uid);
+ return uidRec != null ? uidRec.curProcState : ActivityManager.PROCESS_STATE_NONEXISTENT;
+ }
+ }
+
+ @Override
public void registerUidObserver(IUidObserver observer, int which, int cutpoint,
String callingPackage) {
if (!hasUsageStatsPermission(callingPackage)) {
@@ -17861,10 +17894,14 @@
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
- ComponentName res = mServices.startServiceLocked(caller, service,
- resolvedType, id, notification, callingPid, callingUid,
- requireForeground, callingPackage, userId);
- Binder.restoreCallingIdentity(origId);
+ ComponentName res;
+ try {
+ res = mServices.startServiceLocked(caller, service,
+ resolvedType, id, notification, callingPid, callingUid,
+ requireForeground, callingPackage, userId);
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
return res;
}
}
@@ -17876,9 +17913,13 @@
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
"startServiceInPackage: " + service + " type=" + resolvedType);
final long origId = Binder.clearCallingIdentity();
- ComponentName res = mServices.startServiceLocked(null, service,
- resolvedType, 0, null, -1, uid, fgRequired, callingPackage, userId);
- Binder.restoreCallingIdentity(origId);
+ ComponentName res;
+ try {
+ res = mServices.startServiceLocked(null, service,
+ resolvedType, 0, null, -1, uid, fgRequired, callingPackage, userId);
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
return res;
}
}
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index cfbd2b5..276b267 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -423,11 +423,11 @@
pw.print("\"");
pw.print(" primaryColor=");
pw.println(Integer.toHexString(taskDescription.getPrimaryColor()));
- pw.print(" backgroundColor=");
+ pw.print(prefix + " backgroundColor=");
pw.println(Integer.toHexString(taskDescription.getBackgroundColor()));
- pw.print(" statusBarColor=");
+ pw.print(prefix + " statusBarColor=");
pw.println(Integer.toHexString(taskDescription.getStatusBarColor()));
- pw.print(" navigationBarColor=");
+ pw.print(prefix + " navigationBarColor=");
pw.println(Integer.toHexString(taskDescription.getNavigationBarColor()));
}
if (iconFilename == null && taskDescription.getIcon() != null) {
@@ -1163,10 +1163,13 @@
}
/**
+ * @param beforeStopping Whether this check is for an auto-enter-pip operation, that is to say
+ * the activity has requested to enter PiP when it would otherwise be stopped.
+ *
* @return whether this activity is currently allowed to enter PIP, throwing an exception if
* the activity is not currently visible and {@param noThrow} is not set.
*/
- boolean checkEnterPictureInPictureState(String caller, boolean noThrow) {
+ boolean checkEnterPictureInPictureState(String caller, boolean noThrow, boolean beforeStopping) {
// Check app-ops and see if PiP is supported for this package
if (!checkEnterPictureInPictureAppOpsState()) {
return false;
@@ -1177,17 +1180,24 @@
return false;
}
- boolean isCurrentAppLocked = mStackSupervisor.getLockTaskModeState() != LOCK_TASK_MODE_NONE;
boolean isKeyguardLocked = service.isKeyguardLocked();
+ boolean isCurrentAppLocked = mStackSupervisor.getLockTaskModeState() != LOCK_TASK_MODE_NONE;
boolean hasPinnedStack = mStackSupervisor.getStack(PINNED_STACK_ID) != null;
// Don't return early if !isNotLocked, since we want to throw an exception if the activity
// is in an incorrect state
boolean isNotLockedOrOnKeyguard = !isKeyguardLocked && !isCurrentAppLocked;
+
+ // We don't allow auto-PiP when something else is already pipped.
+ if (beforeStopping && hasPinnedStack) {
+ return false;
+ }
+
switch (state) {
case RESUMED:
// When visible, allow entering PiP if the app is not locked. If it is over the
// keyguard, then we will prompt to unlock in the caller before entering PiP.
- return !isCurrentAppLocked;
+ return !isCurrentAppLocked &&
+ (supportsPictureInPictureWhilePausing || !beforeStopping);
case PAUSING:
case PAUSED:
// When pausing, then only allow enter PiP as in the resume state, and in addition,
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 0e033d2..b998314 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -65,7 +65,6 @@
import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
import static com.android.server.am.ActivityRecord.ASSISTANT_ACTIVITY_TYPE;
import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
-import static com.android.server.am.ActivityStack.ActivityState.STOPPED;
import static com.android.server.am.ActivityStackSupervisor.FindTaskResult;
import static com.android.server.am.ActivityStackSupervisor.ON_TOP;
import static com.android.server.am.ActivityStackSupervisor.PAUSE_IMMEDIATELY;
@@ -1167,8 +1166,6 @@
final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
final ActivityRecord r = activities.get(activityNdx);
- // TODO(b/37244415): This just wrong. We should also be moving PAUSED activities to
- // the stopped state when we are sleeping.
if (r.state == ActivityState.STOPPING || r.state == ActivityState.STOPPED
|| r.state == ActivityState.PAUSED || r.state == ActivityState.PAUSING) {
r.setSleeping(true);
@@ -1803,15 +1800,6 @@
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
"Skipping: already visible at " + r);
- if (r.state == STOPPED) {
- // In this case the activity is visible, but in the stopped state.
- // This sometimes happens if the activity is behind the lockscreen.
- // Restart the activity to the paused or resumed state since we want
- // it to be in the visible state now.
- makeVisibleAndRestartIfNeeded(starting, configChanges, isTop,
- resumeNextActivity, r);
- }
-
if (r.handleAlreadyVisible()) {
resumeNextActivity = false;
}
@@ -2001,10 +1989,10 @@
// keeping the screen frozen.
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Making invisible: " + r + " " + r.state);
try {
- r.setVisible(false);
switch (r.state) {
case STOPPING:
case STOPPED:
+ r.setVisible(false);
if (r.app != null && r.app.thread != null) {
if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
"Scheduling invisibility: " + r);
@@ -2023,6 +2011,7 @@
// This case created for transitioning activities from
// translucent to opaque {@link Activity#convertToOpaque}.
if (visibleBehind == r) {
+ r.setVisible(false);
releaseBackgroundResources(r);
} else {
// If this activity is in a state where it can currently enter
@@ -2030,7 +2019,18 @@
// the activity tries to enterPictureInPictureMode() later. Otherwise,
// we will try and stop the activity next time idle is processed.
final boolean canEnterPictureInPicture = r.checkEnterPictureInPictureState(
- "makeInvisible", true /* noThrow */);
+ "makeInvisible", true /* noThrow */, true /* beforeStopping */);
+
+ if (canEnterPictureInPicture) {
+ // We set r.visible=false so that Stop will later
+ // call setVisible for us. In this case
+ // we don't want to call setVisible(false) to avoid
+ // notifying the client of this intermittent invisible
+ // state.
+ r.visible = false;
+ } else {
+ r.setVisible(false);
+ }
addToStopping(r, true /* scheduleIdle */,
canEnterPictureInPicture /* idleDelayed */);
}
@@ -3973,6 +3973,19 @@
task.isOverHomeStack()) {
mStackSupervisor.moveHomeStackTaskToTop(reason);
}
+
+ if (onlyHasTaskOverlays) {
+ // When destroying a task, tell the supervisor to remove it so that any activity it
+ // has can be cleaned up correctly. This is currently the only place where we remove
+ // a task with the DESTROYING mode, so instead of passing the onlyHasTaskOverlays
+ // state into removeTask(), we just clear the task here before the other residual
+ // work.
+ // TODO: If the callers to removeTask() changes such that we have multiple places
+ // where we are destroying the task, move this back into removeTask()
+ mStackSupervisor.removeTaskByIdLocked(task.taskId, false /* killProcess */,
+ !REMOVE_FROM_RECENTS, PAUSE_IMMEDIATELY);
+ task.removeWindowContainer();
+ }
removeTask(task, reason, REMOVE_TASK_MODE_DESTROYING);
}
cleanUpActivityServicesLocked(r);
@@ -5032,14 +5045,6 @@
* {@link #REMOVE_TASK_MODE_MOVING}, {@link #REMOVE_TASK_MODE_MOVING_TO_TOP}.
*/
void removeTask(TaskRecord task, String reason, int mode) {
- if (mode == REMOVE_TASK_MODE_DESTROYING) {
- // When destroying a task, tell the supervisor to remove it so that any activity it has
- // can be cleaned up correctly
- mStackSupervisor.removeTaskByIdLocked(task.taskId, false /* killProcess */,
- !REMOVE_FROM_RECENTS, PAUSE_IMMEDIATELY);
- task.removeWindowContainer();
- }
-
for (ActivityRecord record : task.mActivities) {
onActivityRemovedFromStack(record);
}
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 88de8a5..68e25c3 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1477,12 +1477,11 @@
stack.minimalResumeActivityLocked(r);
} else {
// This activity is not starting in the resumed state... which should look like we asked
- // it to resume+pause (but remain visible), and it has done so and reported back the
+ // it to pause+stop (but remain visible), and it has done so and reported back the
// current icicle and other state.
if (DEBUG_STATES) Slog.v(TAG_STATES,
"Moving to PAUSED: " + r + " (starting in paused state)");
r.state = PAUSED;
- r.stopped = false;
}
// Launch the new version setup screen if needed. We do this -after-
@@ -3090,7 +3089,6 @@
}
}
mGoingToSleepActivities.clear();
- ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
}
void activitySleptLocked(ActivityRecord r) {
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index dd3d4e0..baa71d7 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -16,6 +16,8 @@
package com.android.server.am;
+import android.content.pm.IPackageManager;
+import android.content.pm.PermissionInfo;
import android.os.Trace;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -795,6 +797,31 @@
.sendToTarget();
}
+ /**
+ * Return true if all given permissions are signature-only perms.
+ */
+ final boolean isSignaturePerm(String[] perms) {
+ if (perms == null) {
+ return false;
+ }
+ IPackageManager pm = AppGlobals.getPackageManager();
+ for (int i = perms.length-1; i >= 0; i--) {
+ try {
+ PermissionInfo pi = pm.getPermissionInfo(perms[i], 0);
+ if ((pi.protectionLevel & (PermissionInfo.PROTECTION_MASK_BASE
+ | PermissionInfo.PROTECTION_FLAG_PRIVILEGED))
+ != PermissionInfo.PROTECTION_SIGNATURE) {
+ // If this a signature permission and NOT allowed for privileged apps, it
+ // is okay... otherwise, nope!
+ return false;
+ }
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+ return true;
+ }
+
final void processNextBroadcast(boolean fromMsg) {
synchronized(mService) {
BroadcastRecord r;
@@ -1246,7 +1273,8 @@
|| (r.intent.getComponent() == null
&& r.intent.getPackage() == null
&& ((r.intent.getFlags()
- & Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND) == 0))) {
+ & Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND) == 0)
+ && !isSignaturePerm(r.requiredPermissions))) {
mService.addBackgroundCheckViolationLocked(r.intent.getAction(),
component.getPackageName());
Slog.w(TAG, "Background execution not allowed: receiving "
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 2e499f1..9157c4e 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -2992,7 +2992,12 @@
// Skip if it had no restrictions to begin with
if ((oldRules & MASK_ALL_NETWORKS) == 0) continue;
}
- updateRulesForPowerRestrictionsUL(uid, oldRules, paroled);
+ final int newUidRules = updateRulesForPowerRestrictionsUL(uid, oldRules, paroled);
+ if (newUidRules == RULE_NONE) {
+ mUidRules.delete(uid);
+ } else {
+ mUidRules.put(uid, newUidRules);
+ }
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index b043230..b7d3173 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -376,7 +376,20 @@
pw.println(prefix + "fullscreenIntent=" + notification.fullScreenIntent);
pw.println(prefix + "contentIntent=" + notification.contentIntent);
pw.println(prefix + "deleteIntent=" + notification.deleteIntent);
- pw.println(prefix + "tickerText=" + notification.tickerText);
+
+ pw.print(prefix + "tickerText=");
+ if (!TextUtils.isEmpty(notification.tickerText)) {
+ final String ticker = notification.tickerText.toString();
+ if (redact) {
+ // if the string is long enough, we allow ourselves a few bytes for debugging
+ pw.print(ticker.length() > 16 ? ticker.substring(0,8) : "");
+ pw.println("...");
+ } else {
+ pw.println(ticker);
+ }
+ } else {
+ pw.println("null");
+ }
pw.println(prefix + "contentView=" + notification.contentView);
pw.println(prefix + String.format("color=0x%08x", notification.color));
pw.println(prefix + "timeout=" + TimeUtils.formatForLogging(notification.getTimeout()));
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 818c3ad..0e1f485 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -71,6 +71,7 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -754,12 +755,17 @@
// restarted before we received USER_REMOVED. Remove data for
// users that will not exist after the system is ready.
- final List<UserInfo> deadUsers = getDeadUsers();
- final int N = deadUsers.size();
- for (int i = 0; i < N; i++) {
- final UserInfo deadUser = deadUsers.get(i);
- final int userId = deadUser.getUserHandle().getIdentifier();
- mSettings.removeUser(userId);
+ final List<UserInfo> liveUsers = mUserManager.getUsers(true /*excludeDying*/);
+ final int[] liveUserIds = new int[liveUsers.size()];
+ for (int i = 0; i < liveUsers.size(); i++) {
+ liveUserIds[i] = liveUsers.get(i).getUserHandle().getIdentifier();
+ }
+ Arrays.sort(liveUserIds);
+
+ for (int userId : mSettings.getUsers()) {
+ if (Arrays.binarySearch(liveUserIds, userId) < 0) {
+ mSettings.removeUser(userId);
+ }
}
} catch (IOException | XmlPullParserException e) {
Slog.e(TAG, "failed to restore overlay state", e);
@@ -767,13 +773,6 @@
}
}
- private List<UserInfo> getDeadUsers() {
- final List<UserInfo> users = mUserManager.getUsers(false);
- final List<UserInfo> onlyLiveUsers = mUserManager.getUsers(true);
- users.removeAll(onlyLiveUsers);
- return users;
- }
-
private static final class PackageManagerHelper implements
OverlayManagerServiceImpl.PackageManagerHelper {
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index b203674..5196c66 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -109,6 +109,10 @@
if (overlayPackage.isStaticOverlay ||
mDefaultOverlays.contains(overlayPackage.packageName)) {
// Enable this overlay by default.
+ if (DEBUG) {
+ Slog.d(TAG, "Enabling overlay " + overlayPackage.packageName
+ + " for user " + newUserId + " by default");
+ }
mSettings.setEnabled(overlayPackage.packageName, newUserId, true);
}
} else {
diff --git a/services/core/java/com/android/server/om/OverlayManagerSettings.java b/services/core/java/com/android/server/om/OverlayManagerSettings.java
index 72979f6..2f83793 100644
--- a/services/core/java/com/android/server/om/OverlayManagerSettings.java
+++ b/services/core/java/com/android/server/om/OverlayManagerSettings.java
@@ -16,11 +16,15 @@
package com.android.server.om;
+import static com.android.server.om.OverlayManagerService.DEBUG;
+import static com.android.server.om.OverlayManagerService.TAG;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.om.OverlayInfo;
import android.util.AndroidRuntimeException;
import android.util.ArrayMap;
+import android.util.Slog;
import android.util.Xml;
import com.android.internal.util.FastXmlSerializer;
@@ -185,6 +189,10 @@
for (int i = 0; i < mItems.size(); i++) {
final SettingsItem item = mItems.get(i);
if (item.getUserId() == userId) {
+ if (DEBUG) {
+ Slog.d(TAG, "Removing overlay " + item.mPackageName + " for user " + userId
+ + " from settings because user was removed");
+ }
mItems.remove(i);
removed = true;
i--;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index c51e87b..c25ab37 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -220,6 +220,7 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Base64;
+import android.util.BootTimingsTraceLog;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.ExceptionUtils;
@@ -2722,15 +2723,18 @@
UserHandle.USER_SYSTEM, storageFlags, true /* migrateAppData */,
true /* onlyCoreApps */);
mPrepareAppDataFuture = SystemServerInitThreadPool.get().submit(() -> {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "fixup");
+ BootTimingsTraceLog traceLog = new BootTimingsTraceLog("SystemServerTimingAsync",
+ Trace.TRACE_TAG_PACKAGE_MANAGER);
+ traceLog.traceBegin("AppDataFixup");
try {
mInstaller.fixupAppData(StorageManager.UUID_PRIVATE_INTERNAL,
StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
} catch (InstallerException e) {
Slog.w(TAG, "Trouble fixing GIDs", e);
}
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ traceLog.traceEnd();
+ traceLog.traceBegin("AppDataPrepare");
if (deferPackages == null || deferPackages.isEmpty()) {
return;
}
@@ -2751,6 +2755,7 @@
count++;
}
}
+ traceLog.traceEnd();
Slog.i(TAG, "Deferred reconcileAppsData finished " + count + " packages");
}, "prepareAppData");
@@ -5721,9 +5726,6 @@
Intent intent, List<ResolveInfo> resolvedActivities, int userId,
boolean skipPackageCheck) {
final int callingUser = UserHandle.getCallingUserId();
- if (callingUser != UserHandle.USER_SYSTEM) {
- return false;
- }
if (mInstantAppResolverConnection == null) {
return false;
}
@@ -6334,19 +6336,24 @@
Slog.v(TAG, "Adding ephemeral installer to the ResolveInfo list");
}
final ResolveInfo ephemeralInstaller = new ResolveInfo(mInstantAppInstallerInfo);
- ephemeralInstaller.activityInfo = new ActivityInfo(mInstantAppInstallerActivity);
- ephemeralInstaller.activityInfo.launchToken = auxiliaryResponse.token;
- ephemeralInstaller.auxiliaryInfo = auxiliaryResponse;
- // make sure this resolver is the default
- ephemeralInstaller.isDefault = true;
- ephemeralInstaller.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
- | IntentFilter.MATCH_ADJUSTMENT_NORMAL;
- // add a non-generic filter
- ephemeralInstaller.filter = new IntentFilter(intent.getAction());
- ephemeralInstaller.filter.addDataPath(
- intent.getData().getPath(), PatternMatcher.PATTERN_LITERAL);
- ephemeralInstaller.instantAppAvailable = true;
- result.add(ephemeralInstaller);
+ final PackageSetting ps =
+ mSettings.mPackages.get(mInstantAppInstallerActivity.packageName);
+ if (ps != null) {
+ ephemeralInstaller.activityInfo = PackageParser.generateActivityInfo(
+ mInstantAppInstallerActivity, 0, ps.readUserState(userId), userId);
+ ephemeralInstaller.activityInfo.launchToken = auxiliaryResponse.token;
+ ephemeralInstaller.auxiliaryInfo = auxiliaryResponse;
+ // make sure this resolver is the default
+ ephemeralInstaller.isDefault = true;
+ ephemeralInstaller.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
+ | IntentFilter.MATCH_ADJUSTMENT_NORMAL;
+ // add a non-generic filter
+ ephemeralInstaller.filter = new IntentFilter(intent.getAction());
+ ephemeralInstaller.filter.addDataPath(
+ intent.getData().getPath(), PatternMatcher.PATTERN_LITERAL);
+ ephemeralInstaller.instantAppAvailable = true;
+ result.add(ephemeralInstaller);
+ }
}
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index a60dae7..cf597b05 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -46,6 +46,8 @@
import android.os.PowerSaveState;
import android.os.Process;
import android.os.RemoteException;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.Trace;
@@ -4027,6 +4029,14 @@
}
private final class BinderService extends IPowerManager.Stub {
+ @Override
+ public void onShellCommand(FileDescriptor in, FileDescriptor out,
+ FileDescriptor err, String[] args, ShellCallback callback,
+ ResultReceiver resultReceiver) {
+ (new PowerManagerShellCommand(this)).exec(
+ this, in, out, err, args, callback, resultReceiver);
+ }
+
@Override // Binder call
public void acquireWakeLockWithUid(IBinder lock, int flags, String tag,
String packageName, int uid) {
diff --git a/services/core/java/com/android/server/power/PowerManagerShellCommand.java b/services/core/java/com/android/server/power/PowerManagerShellCommand.java
new file mode 100644
index 0000000..46115d8
--- /dev/null
+++ b/services/core/java/com/android/server/power/PowerManagerShellCommand.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.power;
+
+import android.content.Intent;
+import android.os.IPowerManager;
+import android.os.RemoteException;
+import android.os.ShellCommand;
+
+import java.io.PrintWriter;
+
+class PowerManagerShellCommand extends ShellCommand {
+ private static final int LOW_POWER_MODE_ON = 1;
+
+ final IPowerManager mInterface;
+
+ PowerManagerShellCommand(IPowerManager service) {
+ mInterface = service;
+ }
+
+ @Override
+ public int onCommand(String cmd) {
+ if (cmd == null) {
+ return handleDefaultCommands(cmd);
+ }
+
+ final PrintWriter pw = getOutPrintWriter();
+ try {
+ switch(cmd) {
+ case "set-mode":
+ return runSetMode();
+ default:
+ return handleDefaultCommands(cmd);
+ }
+ } catch (RemoteException e) {
+ pw.println("Remote exception: " + e);
+ }
+ return -1;
+ }
+
+ private int runSetMode() throws RemoteException {
+ final PrintWriter pw = getOutPrintWriter();
+ int mode = -1;
+ try {
+ mode = Integer.parseInt(getNextArgRequired());
+ } catch (RuntimeException ex) {
+ pw.println("Error: " + ex.toString());
+ return -1;
+ }
+ mInterface.setPowerSaveMode(mode == LOW_POWER_MODE_ON);
+ return 0;
+ }
+
+ @Override
+ public void onHelp() {
+ final PrintWriter pw = getOutPrintWriter();
+ pw.println("Power manager (power) commands:");
+ pw.println(" help");
+ pw.println(" Print this help text.");
+ pw.println("");
+ pw.println(" set-mode MODE");
+ pw.println(" sets the power mode of the device to MODE.");
+ pw.println(" 1 turns low power mode on and 0 turns low power mode off.");
+ pw.println();
+ Intent.printIntentArgsHelp(pw , "");
+ }
+}
diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java
index 0b90bad..bde2111 100644
--- a/services/core/java/com/android/server/wm/AppWindowContainerController.java
+++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java
@@ -715,6 +715,10 @@
@Override
public String toString() {
- return "{AppWindowContainerController token=" + mToken + "}";
+ return "AppWindowContainerController{"
+ + " token=" + mToken
+ + " mContainer=" + mContainer
+ + " mListener=" + mListener
+ + "}";
}
}
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index f4f6b63..1fb34eb 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -1550,6 +1550,9 @@
if (mPendingRelaunchCount != 0) {
pw.print(prefix); pw.print("mPendingRelaunchCount="); pw.println(mPendingRelaunchCount);
}
+ if (getController() != null) {
+ pw.print(prefix); pw.print("controller="); pw.println(getController());
+ }
}
@Override
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 8098eea..979af7e 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -50,6 +50,7 @@
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
@@ -4411,4 +4412,14 @@
nowGone = true;
}
}
+
+ boolean usesRelativeZOrdering() {
+ if (!isChildWindow()) {
+ return false;
+ } else if (mAttrs.type == TYPE_APPLICATION_MEDIA_OVERLAY) {
+ return true;
+ } else {
+ return false;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index a7f6db1..ae17d08 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -714,7 +714,16 @@
}
// Start a new transaction and apply position & offset.
- mSurfaceController.setPositionAndLayer(mTmpSize.left, mTmpSize.top, getLayerStack(), mAnimLayer);
+
+ mService.openSurfaceTransaction();
+ try {
+ mSurfaceController.setPositionInTransaction(mTmpSize.left, mTmpSize.top, false);
+ mSurfaceController.setLayerStackInTransaction(getLayerStack());
+ mSurfaceController.setLayer(mAnimLayer);
+ } finally {
+ mService.closeSurfaceTransaction();
+ }
+
mLastHidden = true;
if (WindowManagerService.localLOGV) Slog.v(TAG, "Created surface " + this);
@@ -1521,12 +1530,13 @@
+ "," + mDsDy + "*" + w.mVScale + "]", false);
boolean prepared =
- mSurfaceController.prepareToShowInTransaction(mShownAlpha, mAnimLayer,
+ mSurfaceController.prepareToShowInTransaction(mShownAlpha,
mDsDx * w.mHScale * mExtraHScale,
mDtDx * w.mVScale * mExtraVScale,
mDtDy * w.mHScale * mExtraHScale,
mDsDy * w.mVScale * mExtraVScale,
recoveringMemory);
+ mSurfaceController.setLayer(mAnimLayer);
if (prepared && mLastHidden && mDrawState == HAS_DRAWN) {
if (showSurfaceRobustlyLocked()) {
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index adf4501..edbdf8b 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -163,32 +163,6 @@
}
}
- void setPositionAndLayer(float left, float top, int layerStack, int layer) {
- mService.openSurfaceTransaction();
- try {
- mSurfaceX = left;
- mSurfaceY = top;
-
- try {
- if (SHOW_TRANSACTIONS) logSurface(
- "POS (setPositionAndLayer) @ (" + left + "," + top + ")", null);
- mSurfaceControl.setPosition(left, top);
- mSurfaceControl.setLayerStack(layerStack);
-
- mSurfaceControl.setLayer(layer);
- mSurfaceControl.setAlpha(0);
- setShown(false);
- } catch (RuntimeException e) {
- Slog.w(TAG, "Error creating surface in " + this, e);
- mAnimator.reclaimSomeSurfaceMemory("create-init", true);
- }
- } finally {
- mService.closeSurfaceTransaction();
- if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
- "<<< CLOSE TRANSACTION setPositionAndLayer");
- }
- }
-
void destroyInTransaction() {
if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
Slog.i(TAG, "Destroying surface " + this + " called by " + Debug.getCallers(8));
@@ -269,7 +243,15 @@
if (mSurfaceControl != null) {
mService.openSurfaceTransaction();
try {
- mSurfaceControl.setLayer(layer);
+ if (mAnimator.mWin.usesRelativeZOrdering()) {
+ mSurfaceControl.setRelativeLayer(
+ mAnimator.mWin.getParentWindow()
+ .mWinAnimator.mSurfaceController.mSurfaceControl.getHandle(),
+ -1);
+ } else {
+ mSurfaceLayer = layer;
+ mSurfaceControl.setLayer(layer);
+ }
} finally {
mService.closeSurfaceTransaction();
}
@@ -363,15 +345,13 @@
return false;
}
- boolean prepareToShowInTransaction(float alpha, int layer,
+ boolean prepareToShowInTransaction(float alpha,
float dsdx, float dtdx, float dsdy,
float dtdy, boolean recoveringMemory) {
if (mSurfaceControl != null) {
try {
mSurfaceAlpha = alpha;
mSurfaceControl.setAlpha(alpha);
- mSurfaceLayer = layer;
- mSurfaceControl.setLayer(layer);
mLastDsdx = dsdx;
mLastDtdx = dtdx;
mLastDsdy = dsdy;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index e47da55..67f1a0a 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1541,9 +1541,11 @@
mSystemServiceManager.startService(RetailDemoModeService.class);
traceEnd();
- traceBeginAndSlog("StartAutoFillService");
- mSystemServiceManager.startService(AUTO_FILL_MANAGER_SERVICE_CLASS);
- traceEnd();
+ if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOFILL)) {
+ traceBeginAndSlog("StartAutoFillService");
+ mSystemServiceManager.startService(AUTO_FILL_MANAGER_SERVICE_CLASS);
+ traceEnd();
+ }
// It is now time to start up the app processes...
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 77da897..f9b754b 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -3650,9 +3650,28 @@
*
* @param AID Application id. See ETSI 102.221 and 101.220.
* @return an IccOpenLogicalChannelResponse object.
+ * @deprecated Replaced by {@link #iccOpenLogicalChannel(String, int)}
*/
+ @Deprecated
public IccOpenLogicalChannelResponse iccOpenLogicalChannel(String AID) {
- return iccOpenLogicalChannel(getSubId(), AID);
+ return iccOpenLogicalChannel(getSubId(), AID, -1);
+ }
+
+ /**
+ * Opens a logical channel to the ICC card.
+ *
+ * Input parameters equivalent to TS 27.007 AT+CCHO command.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+ * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+ *
+ * @param AID Application id. See ETSI 102.221 and 101.220.
+ * @param p2 P2 parameter (described in ISO 7816-4).
+ * @return an IccOpenLogicalChannelResponse object.
+ */
+ public IccOpenLogicalChannelResponse iccOpenLogicalChannel(String AID, int p2) {
+ return iccOpenLogicalChannel(getSubId(), AID, p2);
}
/**
@@ -3666,14 +3685,15 @@
*
* @param subId The subscription to use.
* @param AID Application id. See ETSI 102.221 and 101.220.
+ * @param p2 P2 parameter (described in ISO 7816-4).
* @return an IccOpenLogicalChannelResponse object.
* @hide
*/
- public IccOpenLogicalChannelResponse iccOpenLogicalChannel(int subId, String AID) {
+ public IccOpenLogicalChannelResponse iccOpenLogicalChannel(int subId, String AID, int p2) {
try {
ITelephony telephony = getITelephony();
if (telephony != null)
- return telephony.iccOpenLogicalChannel(subId, AID);
+ return telephony.iccOpenLogicalChannel(subId, AID, p2);
} catch (RemoteException ex) {
} catch (NullPointerException ex) {
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index db7e417..13a25ca5 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -623,9 +623,10 @@
*
* @param subId The subscription to use.
* @param AID Application id. See ETSI 102.221 and 101.220.
+ * @param p2 P2 parameter (described in ISO 7816-4).
* @return an IccOpenLogicalChannelResponse object.
*/
- IccOpenLogicalChannelResponse iccOpenLogicalChannel(int subId, String AID);
+ IccOpenLogicalChannelResponse iccOpenLogicalChannel(int subId, String AID, int p2);
/**
* Closes a previously opened logical channel to the ICC card.
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index 6e0809e..3d76439 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -87,6 +87,7 @@
Maybe<std::string> generate_java_class_path;
Maybe<std::string> custom_java_package;
std::set<std::string> extra_java_packages;
+ Maybe<std::string> generate_text_symbols_path;
Maybe<std::string> generate_proguard_rules_path;
Maybe<std::string> generate_main_dex_proguard_rules_path;
bool generate_non_final_ids = false;
@@ -837,8 +838,8 @@
}
bool WriteJavaFile(ResourceTable* table, const StringPiece& package_name_to_generate,
- const StringPiece& out_package,
- const JavaClassGeneratorOptions& java_options) {
+ const StringPiece& out_package, const JavaClassGeneratorOptions& java_options,
+ const Maybe<std::string> out_text_symbols_path = {}) {
if (!options_.generate_java_class_path) {
return true;
}
@@ -861,8 +862,20 @@
return false;
}
+ std::unique_ptr<std::ofstream> fout_text;
+ if (out_text_symbols_path) {
+ fout_text =
+ util::make_unique<std::ofstream>(out_text_symbols_path.value(), std::ofstream::binary);
+ if (!*fout_text) {
+ context_->GetDiagnostics()->Error(
+ DiagMessage() << "failed writing to '" << out_text_symbols_path.value()
+ << "': " << android::base::SystemErrorCodeToString(errno));
+ return false;
+ }
+ }
+
JavaClassGenerator generator(context_, table, java_options);
- if (!generator.Generate(package_name_to_generate, out_package, &fout)) {
+ if (!generator.Generate(package_name_to_generate, out_package, &fout, fout_text.get())) {
context_->GetDiagnostics()->Error(DiagMessage(out_path) << generator.getError());
return false;
}
@@ -1683,7 +1696,8 @@
std::move(packages_to_callback);
}
- if (!WriteJavaFile(&final_table_, actual_package, output_package, options)) {
+ if (!WriteJavaFile(&final_table_, actual_package, output_package, options,
+ options_.generate_text_symbols_path)) {
return 1;
}
}
@@ -1785,9 +1799,9 @@
.OptionalSwitch("-z", "Require localization of strings marked 'suggested'.",
&require_localization)
.OptionalFlagList("-c",
- "Comma separated list of configurations to include. The default\n"
- "is all configurations.",
- &configs)
+ "Comma separated list of configurations to include. The default\n"
+ "is all configurations.",
+ &configs)
.OptionalFlag("--preferred-density",
"Selects the closest matching density and strips out all others.",
&preferred_density)
@@ -1841,6 +1855,10 @@
.OptionalFlagList("--add-javadoc-annotation",
"Adds a JavaDoc annotation to all generated Java classes.",
&options.javadoc_annotations)
+ .OptionalFlag("--output-text-symbols",
+ "Generates a text file containing the resource symbols of the R class in\n"
+ "the specified folder.",
+ &options.generate_text_symbols_path)
.OptionalSwitch("--auto-add-overlay",
"Allows the addition of new resources in overlays without\n"
"<add-resource> tags.",
diff --git a/tools/aapt2/java/JavaClassGenerator.cpp b/tools/aapt2/java/JavaClassGenerator.cpp
index 68bdb95..a8226c0 100644
--- a/tools/aapt2/java/JavaClassGenerator.cpp
+++ b/tools/aapt2/java/JavaClassGenerator.cpp
@@ -22,6 +22,7 @@
#include <sstream>
#include <tuple>
+#include "android-base/errors.h"
#include "android-base/logging.h"
#include "android-base/stringprintf.h"
#include "androidfw/StringPiece.h"
@@ -227,7 +228,8 @@
const Styleable& styleable,
const StringPiece& package_name_to_generate,
ClassDefinition* out_class_def,
- MethodDefinition* out_rewrite_method) {
+ MethodDefinition* out_rewrite_method,
+ std::ostream* out_r_txt) {
const std::string array_field_name = TransformToFieldName(name.entry);
std::unique_ptr<ResourceArrayMember> array_def =
util::make_unique<ResourceArrayMember>(array_field_name);
@@ -328,10 +330,25 @@
array_def->GetCommentBuilder()->AppendComment(styleable_comment.str());
}
+ if (out_r_txt != nullptr) {
+ *out_r_txt << "int[] styleable " << array_field_name << " {";
+ }
+
// Add the ResourceIds to the array member.
- for (const StyleableAttr& styleable_attr : sorted_attributes) {
- const ResourceId id = styleable_attr.attr_ref->id.value_or_default(ResourceId(0));
+ for (size_t i = 0; i < attr_count; i++) {
+ const ResourceId id = sorted_attributes[i].attr_ref->id.value_or_default(ResourceId(0));
array_def->AddElement(id);
+
+ if (out_r_txt != nullptr) {
+ if (i != 0) {
+ *out_r_txt << ",";
+ }
+ *out_r_txt << " " << id;
+ }
+ }
+
+ if (out_r_txt != nullptr) {
+ *out_r_txt << " }\n";
}
// Add the Styleable array to the Styleable class.
@@ -386,6 +403,11 @@
attr_processor->AppendComment(
StringPrintf("@attr name %s:%s", package_name.data(), attr_name.entry.data()));
+ if (out_r_txt != nullptr) {
+ *out_r_txt << StringPrintf("int styleable %s %d\n", sorted_attributes[i].field_name.data(),
+ (int)i);
+ }
+
out_class_def->AddMember(std::move(index_member));
}
@@ -406,7 +428,8 @@
void JavaClassGenerator::ProcessResource(const ResourceNameRef& name, const ResourceId& id,
const ResourceEntry& entry, ClassDefinition* out_class_def,
- MethodDefinition* out_rewrite_method) {
+ MethodDefinition* out_rewrite_method,
+ std::ostream* out_r_txt) {
const std::string field_name = TransformToFieldName(name.entry);
std::unique_ptr<ResourceMember> resource_member =
util::make_unique<ResourceMember>(field_name, id);
@@ -434,6 +457,10 @@
out_class_def->AddMember(std::move(resource_member));
+ if (out_r_txt != nullptr) {
+ *out_r_txt << "int " << name.type << " " << field_name << " " << id << "\n";
+ }
+
if (out_rewrite_method != nullptr) {
const StringPiece& type_str = ToString(name.type);
out_rewrite_method->AppendStatement(StringPrintf("%s.%s = (%s.%s & 0x00ffffff) | (p << 24);",
@@ -470,7 +497,8 @@
const ResourceTablePackage& package,
const ResourceTableType& type,
ClassDefinition* out_type_class_def,
- MethodDefinition* out_rewrite_method_def) {
+ MethodDefinition* out_rewrite_method_def,
+ std::ostream* out_r_txt) {
for (const auto& entry : type.entries) {
const Maybe<std::string> unmangled_name =
UnmangleResource(package.name, package_name_to_generate, *entry);
@@ -505,15 +533,17 @@
static_cast<const Styleable*>(entry->values.front()->value.get());
ProcessStyleable(resource_name, id, *styleable, package_name_to_generate, out_type_class_def,
- out_rewrite_method_def);
+ out_rewrite_method_def, out_r_txt);
} else {
- ProcessResource(resource_name, id, *entry, out_type_class_def, out_rewrite_method_def);
+ ProcessResource(resource_name, id, *entry, out_type_class_def, out_rewrite_method_def,
+ out_r_txt);
}
}
return true;
}
-bool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate, std::ostream* out) {
+bool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate, std::ostream* out,
+ std::ostream* out_r_txt) {
return Generate(package_name_to_generate, package_name_to_generate, out);
}
@@ -527,8 +557,8 @@
}
bool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate,
- const StringPiece& out_package_name,
- std::ostream* out) {
+ const StringPiece& out_package_name, std::ostream* out,
+ std::ostream* out_r_txt) {
ClassDefinition r_class("R", ClassQualifier::kNone, true);
std::unique_ptr<MethodDefinition> rewrite_method;
@@ -558,7 +588,7 @@
std::unique_ptr<ClassDefinition> class_def = util::make_unique<ClassDefinition>(
ToString(type->type), ClassQualifier::kStatic, force_creation_if_empty);
if (!ProcessType(package_name_to_generate, *package, *type, class_def.get(),
- rewrite_method.get())) {
+ rewrite_method.get(), out_r_txt)) {
return false;
}
@@ -567,7 +597,7 @@
const ResourceTableType* priv_type = package->FindType(ResourceType::kAttrPrivate);
if (priv_type) {
if (!ProcessType(package_name_to_generate, *package, *priv_type, class_def.get(),
- rewrite_method.get())) {
+ rewrite_method.get(), out_r_txt)) {
return false;
}
}
@@ -597,6 +627,16 @@
}
out->flush();
+
+ if (out_r_txt != nullptr) {
+ out_r_txt->flush();
+
+ if (!*out_r_txt) {
+ error_ = android::base::SystemErrorCodeToString(errno);
+ return false;
+ }
+ }
+
return true;
}
diff --git a/tools/aapt2/java/JavaClassGenerator.h b/tools/aapt2/java/JavaClassGenerator.h
index 4510430..18746ff 100644
--- a/tools/aapt2/java/JavaClassGenerator.h
+++ b/tools/aapt2/java/JavaClassGenerator.h
@@ -59,7 +59,7 @@
std::vector<std::string> javadoc_annotations;
};
-// Generates the R.java file for a resource table.
+// Generates the R.java file for a resource table and optionally an R.txt file.
class JavaClassGenerator {
public:
JavaClassGenerator(IAaptContext* context, ResourceTable* table,
@@ -69,10 +69,12 @@
// All symbols technically belong to a single package, but linked libraries will
// have their names mangled, denoting that they came from a different package.
// We need to generate these symbols in a separate file. Returns true on success.
- bool Generate(const android::StringPiece& package_name_to_generate, std::ostream* out);
+ bool Generate(const android::StringPiece& package_name_to_generate, std::ostream* out,
+ std::ostream* out_r_txt = nullptr);
bool Generate(const android::StringPiece& package_name_to_generate,
- const android::StringPiece& output_package_name, std::ostream* out);
+ const android::StringPiece& output_package_name, std::ostream* out,
+ std::ostream* out_r_txt = nullptr);
const std::string& getError() const;
@@ -88,13 +90,14 @@
bool ProcessType(const android::StringPiece& package_name_to_generate,
const ResourceTablePackage& package, const ResourceTableType& type,
- ClassDefinition* out_type_class_def, MethodDefinition* out_rewrite_method_def);
+ ClassDefinition* out_type_class_def, MethodDefinition* out_rewrite_method_def,
+ std::ostream* out_r_txt);
// Writes a resource to the R.java file, optionally writing out a rewrite rule for its package
// ID if `out_rewrite_method` is not nullptr.
void ProcessResource(const ResourceNameRef& name, const ResourceId& id,
const ResourceEntry& entry, ClassDefinition* out_class_def,
- MethodDefinition* out_rewrite_method);
+ MethodDefinition* out_rewrite_method, std::ostream* out_r_txt);
// Writes a styleable resource to the R.java file, optionally writing out a rewrite rule for
// its package ID if `out_rewrite_method` is not nullptr.
@@ -102,7 +105,8 @@
void ProcessStyleable(const ResourceNameRef& name, const ResourceId& id,
const Styleable& styleable,
const android::StringPiece& package_name_to_generate,
- ClassDefinition* out_class_def, MethodDefinition* out_rewrite_method);
+ ClassDefinition* out_class_def, MethodDefinition* out_rewrite_method,
+ std::ostream* out_r_txt);
IAaptContext* context_;
ResourceTable* table_;