Merge "WindowManager: Take care with Surface lifetime during relayout to invisible." into oc-dev
diff --git a/Android.mk b/Android.mk
index 991d185..9072e3b 100644
--- a/Android.mk
+++ b/Android.mk
@@ -908,7 +908,6 @@
ext \
icu4j \
framework \
- telephony-common \
voip-common
framework_docs_LOCAL_JAVA_LIBRARIES := \
diff --git a/api/current.txt b/api/current.txt
index 8baca12..7a01e1a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -362,7 +362,7 @@
field public static final int canControlMagnification = 16844039; // 0x1010507
field public static final int canPerformGestures = 16844045; // 0x101050d
field public static final int canRecord = 16844060; // 0x101051c
- field public static final int canRequestEnhancedWebAccessibility = 16843736; // 0x10103d8
+ field public static final deprecated int canRequestEnhancedWebAccessibility = 16843736; // 0x10103d8
field public static final int canRequestFilterKeyEvents = 16843737; // 0x10103d9
field public static final int canRequestTouchExplorationMode = 16843735; // 0x10103d7
field public static final int canRetrieveWindowContent = 16843653; // 0x1010385
@@ -2837,7 +2837,7 @@
field public static final int CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES = 64; // 0x40
field public static final int CAPABILITY_CAN_CONTROL_MAGNIFICATION = 16; // 0x10
field public static final int CAPABILITY_CAN_PERFORM_GESTURES = 32; // 0x20
- field public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 4; // 0x4
+ field public static final deprecated int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 4; // 0x4
field public static final int CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS = 8; // 0x8
field public static final int CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 2; // 0x2
field public static final int CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT = 1; // 0x1
@@ -2855,7 +2855,7 @@
field public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 2; // 0x2
field public static final int FLAG_REPORT_VIEW_IDS = 16; // 0x10
field public static final int FLAG_REQUEST_ACCESSIBILITY_BUTTON = 256; // 0x100
- field public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 8; // 0x8
+ field public static final deprecated int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 8; // 0x8
field public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 32; // 0x20
field public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 4; // 0x4
field public static final int FLAG_RETRIEVE_INTERACTIVE_WINDOWS = 64; // 0x40
@@ -3635,7 +3635,6 @@
method public boolean isInMultiWindowMode();
method public boolean isInPictureInPictureMode();
method public boolean isLocalVoiceInteractionSupported();
- method public boolean isOverlayWithDecorCaptionEnabled();
method public boolean isTaskRoot();
method public boolean isVoiceInteraction();
method public boolean isVoiceInteractionRoot();
@@ -3760,7 +3759,6 @@
method public void setImmersive(boolean);
method public void setIntent(android.content.Intent);
method public final void setMediaController(android.media.session.MediaController);
- method public void setOverlayWithDecorCaptionEnabled(boolean);
method public void setPictureInPictureArgs(android.app.PictureInPictureArgs);
method public final deprecated void setProgress(int);
method public final deprecated void setProgressBarIndeterminate(boolean);
@@ -5125,6 +5123,7 @@
method public int getBadgeIconType();
method public java.lang.String getChannel();
method public java.lang.String getGroup();
+ method public int getGroupAlertBehavior();
method public android.graphics.drawable.Icon getLargeIcon();
method public java.lang.CharSequence getSettingsText();
method public java.lang.String getShortcutId();
@@ -5200,6 +5199,9 @@
field public static final int FLAG_ONGOING_EVENT = 2; // 0x2
field public static final int FLAG_ONLY_ALERT_ONCE = 8; // 0x8
field public static final deprecated int FLAG_SHOW_LIGHTS = 1; // 0x1
+ field public static final int GROUP_ALERT_ALL = 0; // 0x0
+ field public static final int GROUP_ALERT_CHILDREN = 2; // 0x2
+ field public static final int GROUP_ALERT_SUMMARY = 1; // 0x1
field public static final java.lang.String INTENT_CATEGORY_NOTIFICATION_PREFERENCES = "android.intent.category.NOTIFICATION_PREFERENCES";
field public static final deprecated int PRIORITY_DEFAULT = 0; // 0x0
field public static final deprecated int PRIORITY_HIGH = 1; // 0x1
@@ -5346,6 +5348,7 @@
method public android.app.Notification.Builder setExtras(android.os.Bundle);
method public android.app.Notification.Builder setFullScreenIntent(android.app.PendingIntent, boolean);
method public android.app.Notification.Builder setGroup(java.lang.String);
+ method public android.app.Notification.Builder setGroupAlertBehavior(int);
method public android.app.Notification.Builder setGroupSummary(boolean);
method public android.app.Notification.Builder setLargeIcon(android.graphics.Bitmap);
method public android.app.Notification.Builder setLargeIcon(android.graphics.drawable.Icon);
@@ -13779,7 +13782,6 @@
}
public class Typeface {
- method public static deprecated void create(android.graphics.fonts.FontRequest, android.graphics.Typeface.FontRequestCallback);
method public static android.graphics.Typeface create(java.lang.String, int);
method public static android.graphics.Typeface create(android.graphics.Typeface, int);
method public static android.graphics.Typeface createFromAsset(android.content.res.AssetManager, java.lang.String);
@@ -13814,17 +13816,6 @@
method public android.graphics.Typeface.Builder setWeight(int);
}
- public static abstract deprecated interface Typeface.FontRequestCallback {
- method public abstract void onTypefaceRequestFailed(int);
- method public abstract void onTypefaceRetrieved(android.graphics.Typeface);
- field public static final int FAIL_REASON_FONT_LOAD_ERROR = -3; // 0xfffffffd
- field public static final int FAIL_REASON_FONT_NOT_FOUND = 1; // 0x1
- field public static final int FAIL_REASON_FONT_UNAVAILABLE = 2; // 0x2
- field public static final int FAIL_REASON_MALFORMED_QUERY = 3; // 0x3
- field public static final int FAIL_REASON_PROVIDER_NOT_FOUND = -1; // 0xffffffff
- field public static final int FAIL_REASON_WRONG_CERTIFICATES = -2; // 0xfffffffe
- }
-
public class Xfermode {
ctor public Xfermode();
}
@@ -23646,7 +23637,7 @@
public static final class VolumeShaper.Configuration implements android.os.Parcelable {
method public int describeContents();
- method public double getDurationMillis();
+ method public long getDuration();
method public int getInterpolatorType();
method public static int getMaximumCurvePoints();
method public float[] getTimes();
@@ -23672,7 +23663,7 @@
method public android.media.VolumeShaper.Configuration.Builder scaleToEndVolume(float);
method public android.media.VolumeShaper.Configuration.Builder scaleToStartVolume(float);
method public android.media.VolumeShaper.Configuration.Builder setCurve(float[], float[]);
- method public android.media.VolumeShaper.Configuration.Builder setDurationMillis(double);
+ method public android.media.VolumeShaper.Configuration.Builder setDuration(long);
method public android.media.VolumeShaper.Configuration.Builder setInterpolatorType(int);
}
@@ -26740,10 +26731,10 @@
field public static final android.os.Parcelable.Creator<android.net.wifi.aware.Characteristics> CREATOR;
}
- public class DiscoverySession {
+ public class DiscoverySession implements java.lang.AutoCloseable {
+ method public void close();
method public android.net.NetworkSpecifier createNetworkSpecifierOpen(android.net.wifi.aware.PeerHandle);
method public android.net.NetworkSpecifier createNetworkSpecifierPassphrase(android.net.wifi.aware.PeerHandle, java.lang.String);
- method public void destroy();
method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[]);
}
@@ -26795,8 +26786,6 @@
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.net.wifi.aware.SubscribeConfig> CREATOR;
- field public static final int MATCH_STYLE_ALL = 1; // 0x1
- field public static final int MATCH_STYLE_FIRST_ONLY = 0; // 0x0
field public static final int SUBSCRIBE_TYPE_ACTIVE = 1; // 0x1
field public static final int SUBSCRIBE_TYPE_PASSIVE = 0; // 0x0
}
@@ -26805,7 +26794,6 @@
ctor public SubscribeConfig.Builder();
method public android.net.wifi.aware.SubscribeConfig build();
method public android.net.wifi.aware.SubscribeConfig.Builder setMatchFilter(java.util.List<byte[]>);
- method public android.net.wifi.aware.SubscribeConfig.Builder setMatchStyle(int);
method public android.net.wifi.aware.SubscribeConfig.Builder setServiceName(java.lang.String);
method public android.net.wifi.aware.SubscribeConfig.Builder setServiceSpecificInfo(byte[]);
method public android.net.wifi.aware.SubscribeConfig.Builder setSubscribeType(int);
@@ -26827,10 +26815,10 @@
field public static final int WIFI_AWARE_DATA_PATH_ROLE_RESPONDER = 1; // 0x1
}
- public class WifiAwareSession {
+ public class WifiAwareSession implements java.lang.AutoCloseable {
+ method public void close();
method public android.net.NetworkSpecifier createNetworkSpecifierOpen(int, byte[]);
method public android.net.NetworkSpecifier createNetworkSpecifierPassphrase(int, byte[], java.lang.String);
- method public void destroy();
method public void publish(android.net.wifi.aware.PublishConfig, android.net.wifi.aware.DiscoverySessionCallback, android.os.Handler);
method public void subscribe(android.net.wifi.aware.SubscribeConfig, android.net.wifi.aware.DiscoverySessionCallback, android.os.Handler);
}
@@ -34945,6 +34933,7 @@
field public static final java.lang.String ACTION_PRIVACY_SETTINGS = "android.settings.PRIVACY_SETTINGS";
field public static final java.lang.String ACTION_QUICK_LAUNCH_SETTINGS = "android.settings.QUICK_LAUNCH_SETTINGS";
field public static final java.lang.String ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
+ field public static final java.lang.String ACTION_REQUEST_SET_AUTOFILL_SERVICE = "android.settings.REQUEST_SET_AUTOFILL_SERVICE";
field public static final java.lang.String ACTION_SEARCH_SETTINGS = "android.search.action.SEARCH_SETTINGS";
field public static final java.lang.String ACTION_SECURITY_SETTINGS = "android.settings.SECURITY_SETTINGS";
field public static final java.lang.String ACTION_SETTINGS = "android.settings.SETTINGS";
@@ -37036,15 +37025,12 @@
public abstract class AutofillService extends android.app.Service {
ctor public AutofillService();
- method public final deprecated void disableSelf();
method public final android.service.autofill.FillEventHistory getFillEventHistory();
method public final android.os.IBinder onBind(android.content.Intent);
method public void onConnected();
method public void onDisconnected();
- method public void onFillRequest(android.service.autofill.FillRequest, android.os.CancellationSignal, android.service.autofill.FillCallback);
- method public abstract deprecated void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, int, android.os.CancellationSignal, android.service.autofill.FillCallback);
- method public void onSaveRequest(android.service.autofill.SaveRequest, android.service.autofill.SaveCallback);
- method public abstract deprecated void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.service.autofill.SaveCallback);
+ method public abstract void onFillRequest(android.service.autofill.FillRequest, android.os.CancellationSignal, android.service.autofill.FillCallback);
+ method public abstract void onSaveRequest(android.service.autofill.SaveRequest, android.service.autofill.SaveCallback);
field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutofillService";
field public static final java.lang.String SERVICE_META_DATA = "android.autofill";
}
@@ -37118,7 +37104,6 @@
method public android.service.autofill.FillResponse build();
method public android.service.autofill.FillResponse.Builder setAuthentication(android.view.autofill.AutofillId[], android.content.IntentSender, android.widget.RemoteViews);
method public android.service.autofill.FillResponse.Builder setClientState(android.os.Bundle);
- method public deprecated android.service.autofill.FillResponse.Builder setExtras(android.os.Bundle);
method public android.service.autofill.FillResponse.Builder setIgnoredIds(android.view.autofill.AutofillId...);
method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo);
}
@@ -40240,10 +40225,12 @@
method public void sendDialerSpecialCode(java.lang.String);
method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
method public void sendUssdRequest(java.lang.String, android.telephony.TelephonyManager.UssdResponseCallback, android.os.Handler);
+ method public void sendVisualVoicemailSms(java.lang.String, int, java.lang.String, android.app.PendingIntent);
method public void setDataEnabled(boolean);
method public boolean setLine1NumberForDisplay(java.lang.String, java.lang.String);
method public boolean setOperatorBrandOverride(java.lang.String);
method public boolean setPreferredNetworkTypeToGlobal();
+ method public void setVisualVoicemailSmsFilterSettings(android.telephony.VisualVoicemailSmsFilterSettings);
method public boolean setVoiceMailNumber(java.lang.String, java.lang.String);
method public void setVoicemailRingtoneUri(android.telecom.PhoneAccountHandle, android.net.Uri);
method public void setVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle, boolean);
@@ -40334,8 +40321,6 @@
method public abstract void onSimRemoved(android.telephony.VisualVoicemailService.VisualVoicemailTask, android.telecom.PhoneAccountHandle);
method public abstract void onSmsReceived(android.telephony.VisualVoicemailService.VisualVoicemailTask, android.telephony.VisualVoicemailSms);
method public abstract void onStopped(android.telephony.VisualVoicemailService.VisualVoicemailTask);
- method public static final void sendVisualVoicemailSms(android.content.Context, android.telecom.PhoneAccountHandle, java.lang.String, short, java.lang.String, android.app.PendingIntent);
- method public static final void setSmsFilterSettings(android.content.Context, android.telecom.PhoneAccountHandle, android.telephony.VisualVoicemailSmsFilterSettings);
field public static final java.lang.String SERVICE_INTERFACE = "android.telephony.VisualVoicemailService";
}
@@ -47157,7 +47142,9 @@
public final class AccessibilityManager {
method public boolean addAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener);
+ method public void addAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener, android.os.Handler);
method public boolean addTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener);
+ method public void addTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener, android.os.Handler);
method public deprecated java.util.List<android.content.pm.ServiceInfo> getAccessibilityServiceList();
method public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int);
method public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getInstalledAccessibilityServiceList();
@@ -47838,6 +47825,8 @@
method public void cancel();
method public void commit();
method public void disableOwnedAutofillServices();
+ method public boolean hasEnabledAutofillServices();
+ method public boolean isAutofillSupported();
method public boolean isEnabled();
method public void notifyValueChanged(android.view.View);
method public void notifyValueChanged(android.view.View, int, android.view.autofill.AutofillValue);
@@ -47852,7 +47841,6 @@
field public static final java.lang.String EXTRA_ASSIST_STRUCTURE = "android.view.autofill.extra.ASSIST_STRUCTURE";
field public static final java.lang.String EXTRA_AUTHENTICATION_RESULT = "android.view.autofill.extra.AUTHENTICATION_RESULT";
field public static final java.lang.String EXTRA_DATA_EXTRAS = "android.view.autofill.extra.DATA_EXTRAS";
- field public static final deprecated int FLAG_MANUAL_REQUEST = 1; // 0x1
}
public static abstract class AutofillManager.AutofillCallback {
diff --git a/api/removed.txt b/api/removed.txt
index dc9c54e..73dd096 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -1,7 +1,6 @@
package android.app {
public class Notification implements android.os.Parcelable {
- method public deprecated int getBadgeIcon();
method public deprecated void setLatestEventInfo(android.content.Context, java.lang.CharSequence, java.lang.CharSequence, android.app.PendingIntent);
}
diff --git a/api/system-current.txt b/api/system-current.txt
index bb653fe..6c5931e 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -481,7 +481,7 @@
field public static final int canControlMagnification = 16844039; // 0x1010507
field public static final int canPerformGestures = 16844045; // 0x101050d
field public static final int canRecord = 16844060; // 0x101051c
- field public static final int canRequestEnhancedWebAccessibility = 16843736; // 0x10103d8
+ field public static final deprecated int canRequestEnhancedWebAccessibility = 16843736; // 0x10103d8
field public static final int canRequestFilterKeyEvents = 16843737; // 0x10103d9
field public static final int canRequestTouchExplorationMode = 16843735; // 0x10103d7
field public static final int canRetrieveWindowContent = 16843653; // 0x1010385
@@ -2965,7 +2965,7 @@
field public static final int CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES = 64; // 0x40
field public static final int CAPABILITY_CAN_CONTROL_MAGNIFICATION = 16; // 0x10
field public static final int CAPABILITY_CAN_PERFORM_GESTURES = 32; // 0x20
- field public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 4; // 0x4
+ field public static final deprecated int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 4; // 0x4
field public static final int CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS = 8; // 0x8
field public static final int CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 2; // 0x2
field public static final int CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT = 1; // 0x1
@@ -2983,7 +2983,7 @@
field public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 2; // 0x2
field public static final int FLAG_REPORT_VIEW_IDS = 16; // 0x10
field public static final int FLAG_REQUEST_ACCESSIBILITY_BUTTON = 256; // 0x100
- field public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 8; // 0x8
+ field public static final deprecated int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 8; // 0x8
field public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 32; // 0x20
field public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 4; // 0x4
field public static final int FLAG_RETRIEVE_INTERACTIVE_WINDOWS = 64; // 0x40
@@ -3767,7 +3767,6 @@
method public boolean isInMultiWindowMode();
method public boolean isInPictureInPictureMode();
method public boolean isLocalVoiceInteractionSupported();
- method public boolean isOverlayWithDecorCaptionEnabled();
method public boolean isTaskRoot();
method public boolean isVoiceInteraction();
method public boolean isVoiceInteractionRoot();
@@ -3894,7 +3893,6 @@
method public void setImmersive(boolean);
method public void setIntent(android.content.Intent);
method public final void setMediaController(android.media.session.MediaController);
- method public void setOverlayWithDecorCaptionEnabled(boolean);
method public void setPictureInPictureArgs(android.app.PictureInPictureArgs);
method public final deprecated void setProgress(int);
method public final deprecated void setProgressBarIndeterminate(boolean);
@@ -5305,6 +5303,7 @@
method public int getBadgeIconType();
method public java.lang.String getChannel();
method public java.lang.String getGroup();
+ method public int getGroupAlertBehavior();
method public android.graphics.drawable.Icon getLargeIcon();
method public static java.lang.Class<? extends android.app.Notification.Style> getNotificationStyleClass(java.lang.String);
method public java.lang.CharSequence getSettingsText();
@@ -5384,6 +5383,9 @@
field public static final int FLAG_ONGOING_EVENT = 2; // 0x2
field public static final int FLAG_ONLY_ALERT_ONCE = 8; // 0x8
field public static final deprecated int FLAG_SHOW_LIGHTS = 1; // 0x1
+ field public static final int GROUP_ALERT_ALL = 0; // 0x0
+ field public static final int GROUP_ALERT_CHILDREN = 2; // 0x2
+ field public static final int GROUP_ALERT_SUMMARY = 1; // 0x1
field public static final java.lang.String INTENT_CATEGORY_NOTIFICATION_PREFERENCES = "android.intent.category.NOTIFICATION_PREFERENCES";
field public static final deprecated int PRIORITY_DEFAULT = 0; // 0x0
field public static final deprecated int PRIORITY_HIGH = 1; // 0x1
@@ -5530,6 +5532,7 @@
method public android.app.Notification.Builder setExtras(android.os.Bundle);
method public android.app.Notification.Builder setFullScreenIntent(android.app.PendingIntent, boolean);
method public android.app.Notification.Builder setGroup(java.lang.String);
+ method public android.app.Notification.Builder setGroupAlertBehavior(int);
method public android.app.Notification.Builder setGroupSummary(boolean);
method public android.app.Notification.Builder setLargeIcon(android.graphics.Bitmap);
method public android.app.Notification.Builder setLargeIcon(android.graphics.drawable.Icon);
@@ -14554,7 +14557,6 @@
}
public class Typeface {
- method public static deprecated void create(android.graphics.fonts.FontRequest, android.graphics.Typeface.FontRequestCallback);
method public static android.graphics.Typeface create(java.lang.String, int);
method public static android.graphics.Typeface create(android.graphics.Typeface, int);
method public static android.graphics.Typeface createFromAsset(android.content.res.AssetManager, java.lang.String);
@@ -14589,17 +14591,6 @@
method public android.graphics.Typeface.Builder setWeight(int);
}
- public static abstract deprecated interface Typeface.FontRequestCallback {
- method public abstract void onTypefaceRequestFailed(int);
- method public abstract void onTypefaceRetrieved(android.graphics.Typeface);
- field public static final int FAIL_REASON_FONT_LOAD_ERROR = -3; // 0xfffffffd
- field public static final int FAIL_REASON_FONT_NOT_FOUND = 1; // 0x1
- field public static final int FAIL_REASON_FONT_UNAVAILABLE = 2; // 0x2
- field public static final int FAIL_REASON_MALFORMED_QUERY = 3; // 0x3
- field public static final int FAIL_REASON_PROVIDER_NOT_FOUND = -1; // 0xffffffff
- field public static final int FAIL_REASON_WRONG_CERTIFICATES = -2; // 0xfffffffe
- }
-
public class Xfermode {
ctor public Xfermode();
}
@@ -25494,7 +25485,7 @@
public static final class VolumeShaper.Configuration implements android.os.Parcelable {
method public int describeContents();
- method public double getDurationMillis();
+ method public long getDuration();
method public int getInterpolatorType();
method public static int getMaximumCurvePoints();
method public float[] getTimes();
@@ -25520,7 +25511,7 @@
method public android.media.VolumeShaper.Configuration.Builder scaleToEndVolume(float);
method public android.media.VolumeShaper.Configuration.Builder scaleToStartVolume(float);
method public android.media.VolumeShaper.Configuration.Builder setCurve(float[], float[]);
- method public android.media.VolumeShaper.Configuration.Builder setDurationMillis(double);
+ method public android.media.VolumeShaper.Configuration.Builder setDuration(long);
method public android.media.VolumeShaper.Configuration.Builder setInterpolatorType(int);
}
@@ -27968,13 +27959,13 @@
ctor public deprecated NetworkRecommendationProvider(android.os.Handler);
ctor public NetworkRecommendationProvider(android.content.Context, java.util.concurrent.Executor);
method public final android.os.IBinder getBinder();
- method public abstract void onRequestRecommendation(android.net.RecommendationRequest, android.net.NetworkRecommendationProvider.ResultCallback);
+ method public deprecated void onRequestRecommendation(android.net.RecommendationRequest, android.net.NetworkRecommendationProvider.ResultCallback);
method public abstract void onRequestScores(android.net.NetworkKey[]);
- field public static final java.lang.String EXTRA_RECOMMENDATION_RESULT = "android.net.extra.RECOMMENDATION_RESULT";
- field public static final java.lang.String EXTRA_SEQUENCE = "android.net.extra.SEQUENCE";
+ field public static final deprecated java.lang.String EXTRA_RECOMMENDATION_RESULT = "android.net.extra.RECOMMENDATION_RESULT";
+ field public static final deprecated java.lang.String EXTRA_SEQUENCE = "android.net.extra.SEQUENCE";
}
- public static class NetworkRecommendationProvider.ResultCallback {
+ public static deprecated class NetworkRecommendationProvider.ResultCallback {
method public void onResult(android.net.RecommendationResult);
}
@@ -28041,7 +28032,7 @@
field public static final android.os.Parcelable.Creator<android.net.ProxyInfo> CREATOR;
}
- public final class RecommendationRequest implements android.os.Parcelable {
+ public final deprecated class RecommendationRequest implements android.os.Parcelable {
ctor protected RecommendationRequest(android.os.Parcel);
method public int describeContents();
method public android.net.wifi.WifiConfiguration[] getConnectableConfigs();
@@ -28056,7 +28047,7 @@
field public static final android.os.Parcelable.Creator<android.net.RecommendationRequest> CREATOR;
}
- public static final class RecommendationRequest.Builder {
+ public static final deprecated class RecommendationRequest.Builder {
ctor public RecommendationRequest.Builder();
method public android.net.RecommendationRequest build();
method public android.net.RecommendationRequest.Builder setConnectableConfigs(android.net.wifi.WifiConfiguration[]);
@@ -28066,7 +28057,7 @@
method public android.net.RecommendationRequest.Builder setScanResults(android.net.wifi.ScanResult[]);
}
- public final class RecommendationResult implements android.os.Parcelable {
+ public final deprecated class RecommendationResult implements android.os.Parcelable {
method public static android.net.RecommendationResult createConnectRecommendation(android.net.wifi.WifiConfiguration);
method public static android.net.RecommendationResult createDoNotConnectRecommendation();
method public int describeContents();
@@ -29484,11 +29475,11 @@
field public static final android.os.Parcelable.Creator<android.net.wifi.aware.Characteristics> CREATOR;
}
- public class DiscoverySession {
+ public class DiscoverySession implements java.lang.AutoCloseable {
+ method public void close();
method public android.net.NetworkSpecifier createNetworkSpecifierOpen(android.net.wifi.aware.PeerHandle);
method public android.net.NetworkSpecifier createNetworkSpecifierPassphrase(android.net.wifi.aware.PeerHandle, java.lang.String);
method public android.net.NetworkSpecifier createNetworkSpecifierPmk(android.net.wifi.aware.PeerHandle, byte[]);
- method public void destroy();
method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[]);
}
@@ -29540,8 +29531,6 @@
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.net.wifi.aware.SubscribeConfig> CREATOR;
- field public static final int MATCH_STYLE_ALL = 1; // 0x1
- field public static final int MATCH_STYLE_FIRST_ONLY = 0; // 0x0
field public static final int SUBSCRIBE_TYPE_ACTIVE = 1; // 0x1
field public static final int SUBSCRIBE_TYPE_PASSIVE = 0; // 0x0
}
@@ -29550,7 +29539,6 @@
ctor public SubscribeConfig.Builder();
method public android.net.wifi.aware.SubscribeConfig build();
method public android.net.wifi.aware.SubscribeConfig.Builder setMatchFilter(java.util.List<byte[]>);
- method public android.net.wifi.aware.SubscribeConfig.Builder setMatchStyle(int);
method public android.net.wifi.aware.SubscribeConfig.Builder setServiceName(java.lang.String);
method public android.net.wifi.aware.SubscribeConfig.Builder setServiceSpecificInfo(byte[]);
method public android.net.wifi.aware.SubscribeConfig.Builder setSubscribeType(int);
@@ -29572,11 +29560,11 @@
field public static final int WIFI_AWARE_DATA_PATH_ROLE_RESPONDER = 1; // 0x1
}
- public class WifiAwareSession {
+ public class WifiAwareSession implements java.lang.AutoCloseable {
+ method public void close();
method public android.net.NetworkSpecifier createNetworkSpecifierOpen(int, byte[]);
method public android.net.NetworkSpecifier createNetworkSpecifierPassphrase(int, byte[], java.lang.String);
method public android.net.NetworkSpecifier createNetworkSpecifierPmk(int, byte[], byte[]);
- method public void destroy();
method public void publish(android.net.wifi.aware.PublishConfig, android.net.wifi.aware.DiscoverySessionCallback, android.os.Handler);
method public void subscribe(android.net.wifi.aware.SubscribeConfig, android.net.wifi.aware.DiscoverySessionCallback, android.os.Handler);
}
@@ -38038,6 +38026,7 @@
field public static final java.lang.String ACTION_PRIVACY_SETTINGS = "android.settings.PRIVACY_SETTINGS";
field public static final java.lang.String ACTION_QUICK_LAUNCH_SETTINGS = "android.settings.QUICK_LAUNCH_SETTINGS";
field public static final java.lang.String ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
+ field public static final java.lang.String ACTION_REQUEST_SET_AUTOFILL_SERVICE = "android.settings.REQUEST_SET_AUTOFILL_SERVICE";
field public static final java.lang.String ACTION_SEARCH_SETTINGS = "android.search.action.SEARCH_SETTINGS";
field public static final java.lang.String ACTION_SECURITY_SETTINGS = "android.settings.SECURITY_SETTINGS";
field public static final java.lang.String ACTION_SETTINGS = "android.settings.SETTINGS";
@@ -38098,7 +38087,6 @@
field public static final java.lang.String BOOT_COUNT = "boot_count";
field public static final java.lang.String CONTACT_METADATA_SYNC_ENABLED = "contact_metadata_sync_enabled";
field public static final android.net.Uri CONTENT_URI;
- field public static final java.lang.String CURATE_SAVED_OPEN_NETWORKS = "curate_saved_open_networks";
field public static final java.lang.String DATA_ROAMING = "data_roaming";
field public static final java.lang.String DEBUG_APP = "debug_app";
field public static final java.lang.String DEVELOPMENT_SETTINGS_ENABLED = "development_settings_enabled";
@@ -40152,15 +40140,12 @@
public abstract class AutofillService extends android.app.Service {
ctor public AutofillService();
- method public final deprecated void disableSelf();
method public final android.service.autofill.FillEventHistory getFillEventHistory();
method public final android.os.IBinder onBind(android.content.Intent);
method public void onConnected();
method public void onDisconnected();
- method public void onFillRequest(android.service.autofill.FillRequest, android.os.CancellationSignal, android.service.autofill.FillCallback);
- method public abstract deprecated void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, int, android.os.CancellationSignal, android.service.autofill.FillCallback);
- method public void onSaveRequest(android.service.autofill.SaveRequest, android.service.autofill.SaveCallback);
- method public abstract deprecated void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.service.autofill.SaveCallback);
+ method public abstract void onFillRequest(android.service.autofill.FillRequest, android.os.CancellationSignal, android.service.autofill.FillCallback);
+ method public abstract void onSaveRequest(android.service.autofill.SaveRequest, android.service.autofill.SaveCallback);
field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutofillService";
field public static final java.lang.String SERVICE_META_DATA = "android.autofill";
}
@@ -40234,7 +40219,6 @@
method public android.service.autofill.FillResponse build();
method public android.service.autofill.FillResponse.Builder setAuthentication(android.view.autofill.AutofillId[], android.content.IntentSender, android.widget.RemoteViews);
method public android.service.autofill.FillResponse.Builder setClientState(android.os.Bundle);
- method public deprecated android.service.autofill.FillResponse.Builder setExtras(android.os.Bundle);
method public android.service.autofill.FillResponse.Builder setIgnoredIds(android.view.autofill.AutofillId...);
method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo);
}
@@ -43735,6 +43719,7 @@
method public java.lang.String getSubscriberId();
method public java.util.List<android.telephony.TelephonyHistogram> getTelephonyHistograms();
method public java.lang.String getVisualVoicemailPackageName();
+ method public android.os.Bundle getVisualVoicemailSettings();
method public java.lang.String getVoiceMailAlphaTag();
method public java.lang.String getVoiceMailNumber();
method public int getVoiceNetworkType();
@@ -43770,6 +43755,7 @@
method public void sendDialerSpecialCode(java.lang.String);
method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
method public void sendUssdRequest(java.lang.String, android.telephony.TelephonyManager.UssdResponseCallback, android.os.Handler);
+ method public void sendVisualVoicemailSms(java.lang.String, int, java.lang.String, android.app.PendingIntent);
method public int setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>);
method public void setDataEnabled(boolean);
method public void setDataEnabled(int, boolean);
@@ -43779,6 +43765,7 @@
method public boolean setRadio(boolean);
method public boolean setRadioPower(boolean);
method public deprecated void setVisualVoicemailEnabled(android.telecom.PhoneAccountHandle, boolean);
+ method public void setVisualVoicemailSmsFilterSettings(android.telephony.VisualVoicemailSmsFilterSettings);
method public boolean setVoiceMailNumber(java.lang.String, java.lang.String);
method public void setVoicemailRingtoneUri(android.telecom.PhoneAccountHandle, android.net.Uri);
method public void setVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle, boolean);
@@ -43826,7 +43813,9 @@
field public static final java.lang.String EXTRA_STATE_IDLE;
field public static final java.lang.String EXTRA_STATE_OFFHOOK;
field public static final java.lang.String EXTRA_STATE_RINGING;
+ field public static final java.lang.String EXTRA_VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL = "android.telephony.extra.VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL";
field public static final java.lang.String EXTRA_VOICEMAIL_NUMBER = "android.telephony.extra.VOICEMAIL_NUMBER";
+ field public static final java.lang.String EXTRA_VOICEMAIL_SCRAMBLED_PIN_STRING = "android.telephony.extra.VOICEMAIL_SCRAMBLED_PIN_STRING";
field public static final java.lang.String METADATA_HIDE_VOICEMAIL_SETTINGS_MENU = "android.telephony.HIDE_VOICEMAIL_SETTINGS_MENU";
field public static final int NETWORK_TYPE_1xRTT = 7; // 0x7
field public static final int NETWORK_TYPE_CDMA = 4; // 0x4
@@ -50740,7 +50729,9 @@
public final class AccessibilityManager {
method public boolean addAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener);
+ method public void addAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener, android.os.Handler);
method public boolean addTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener);
+ method public void addTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener, android.os.Handler);
method public deprecated java.util.List<android.content.pm.ServiceInfo> getAccessibilityServiceList();
method public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int);
method public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getInstalledAccessibilityServiceList();
@@ -51421,6 +51412,8 @@
method public void cancel();
method public void commit();
method public void disableOwnedAutofillServices();
+ method public boolean hasEnabledAutofillServices();
+ method public boolean isAutofillSupported();
method public boolean isEnabled();
method public void notifyValueChanged(android.view.View);
method public void notifyValueChanged(android.view.View, int, android.view.autofill.AutofillValue);
@@ -51435,7 +51428,6 @@
field public static final java.lang.String EXTRA_ASSIST_STRUCTURE = "android.view.autofill.extra.ASSIST_STRUCTURE";
field public static final java.lang.String EXTRA_AUTHENTICATION_RESULT = "android.view.autofill.extra.AUTHENTICATION_RESULT";
field public static final java.lang.String EXTRA_DATA_EXTRAS = "android.view.autofill.extra.DATA_EXTRAS";
- field public static final deprecated int FLAG_MANUAL_REQUEST = 1; // 0x1
}
public static abstract class AutofillManager.AutofillCallback {
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 4862bb7..ed81363 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -1,7 +1,6 @@
package android.app {
public class Notification implements android.os.Parcelable {
- method public deprecated int getBadgeIcon();
method public deprecated void setLatestEventInfo(android.content.Context, java.lang.CharSequence, java.lang.CharSequence, android.app.PendingIntent);
}
diff --git a/api/test-current.txt b/api/test-current.txt
index eac5b80..c00795d 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -362,7 +362,7 @@
field public static final int canControlMagnification = 16844039; // 0x1010507
field public static final int canPerformGestures = 16844045; // 0x101050d
field public static final int canRecord = 16844060; // 0x101051c
- field public static final int canRequestEnhancedWebAccessibility = 16843736; // 0x10103d8
+ field public static final deprecated int canRequestEnhancedWebAccessibility = 16843736; // 0x10103d8
field public static final int canRequestFilterKeyEvents = 16843737; // 0x10103d9
field public static final int canRequestTouchExplorationMode = 16843735; // 0x10103d7
field public static final int canRetrieveWindowContent = 16843653; // 0x1010385
@@ -2837,7 +2837,7 @@
field public static final int CAPABILITY_CAN_CAPTURE_FINGERPRINT_GESTURES = 64; // 0x40
field public static final int CAPABILITY_CAN_CONTROL_MAGNIFICATION = 16; // 0x10
field public static final int CAPABILITY_CAN_PERFORM_GESTURES = 32; // 0x20
- field public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 4; // 0x4
+ field public static final deprecated int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 4; // 0x4
field public static final int CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS = 8; // 0x8
field public static final int CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 2; // 0x2
field public static final int CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT = 1; // 0x1
@@ -2855,7 +2855,7 @@
field public static final int FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 2; // 0x2
field public static final int FLAG_REPORT_VIEW_IDS = 16; // 0x10
field public static final int FLAG_REQUEST_ACCESSIBILITY_BUTTON = 256; // 0x100
- field public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 8; // 0x8
+ field public static final deprecated int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 8; // 0x8
field public static final int FLAG_REQUEST_FILTER_KEY_EVENTS = 32; // 0x20
field public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 4; // 0x4
field public static final int FLAG_RETRIEVE_INTERACTIVE_WINDOWS = 64; // 0x40
@@ -3637,7 +3637,6 @@
method public boolean isInMultiWindowMode();
method public boolean isInPictureInPictureMode();
method public boolean isLocalVoiceInteractionSupported();
- method public boolean isOverlayWithDecorCaptionEnabled();
method public boolean isTaskRoot();
method public boolean isVoiceInteraction();
method public boolean isVoiceInteractionRoot();
@@ -3762,7 +3761,6 @@
method public void setImmersive(boolean);
method public void setIntent(android.content.Intent);
method public final void setMediaController(android.media.session.MediaController);
- method public void setOverlayWithDecorCaptionEnabled(boolean);
method public void setPictureInPictureArgs(android.app.PictureInPictureArgs);
method public final deprecated void setProgress(int);
method public final deprecated void setProgressBarIndeterminate(boolean);
@@ -5138,6 +5136,7 @@
method public int getBadgeIconType();
method public java.lang.String getChannel();
method public java.lang.String getGroup();
+ method public int getGroupAlertBehavior();
method public android.graphics.drawable.Icon getLargeIcon();
method public java.lang.CharSequence getSettingsText();
method public java.lang.String getShortcutId();
@@ -5213,6 +5212,9 @@
field public static final int FLAG_ONGOING_EVENT = 2; // 0x2
field public static final int FLAG_ONLY_ALERT_ONCE = 8; // 0x8
field public static final deprecated int FLAG_SHOW_LIGHTS = 1; // 0x1
+ field public static final int GROUP_ALERT_ALL = 0; // 0x0
+ field public static final int GROUP_ALERT_CHILDREN = 2; // 0x2
+ field public static final int GROUP_ALERT_SUMMARY = 1; // 0x1
field public static final java.lang.String INTENT_CATEGORY_NOTIFICATION_PREFERENCES = "android.intent.category.NOTIFICATION_PREFERENCES";
field public static final deprecated int PRIORITY_DEFAULT = 0; // 0x0
field public static final deprecated int PRIORITY_HIGH = 1; // 0x1
@@ -5359,6 +5361,7 @@
method public android.app.Notification.Builder setExtras(android.os.Bundle);
method public android.app.Notification.Builder setFullScreenIntent(android.app.PendingIntent, boolean);
method public android.app.Notification.Builder setGroup(java.lang.String);
+ method public android.app.Notification.Builder setGroupAlertBehavior(int);
method public android.app.Notification.Builder setGroupSummary(boolean);
method public android.app.Notification.Builder setLargeIcon(android.graphics.Bitmap);
method public android.app.Notification.Builder setLargeIcon(android.graphics.drawable.Icon);
@@ -13821,7 +13824,6 @@
}
public class Typeface {
- method public static deprecated void create(android.graphics.fonts.FontRequest, android.graphics.Typeface.FontRequestCallback);
method public static android.graphics.Typeface create(java.lang.String, int);
method public static android.graphics.Typeface create(android.graphics.Typeface, int);
method public static android.graphics.Typeface createFromAsset(android.content.res.AssetManager, java.lang.String);
@@ -13856,17 +13858,6 @@
method public android.graphics.Typeface.Builder setWeight(int);
}
- public static abstract deprecated interface Typeface.FontRequestCallback {
- method public abstract void onTypefaceRequestFailed(int);
- method public abstract void onTypefaceRetrieved(android.graphics.Typeface);
- field public static final int FAIL_REASON_FONT_LOAD_ERROR = -3; // 0xfffffffd
- field public static final int FAIL_REASON_FONT_NOT_FOUND = 1; // 0x1
- field public static final int FAIL_REASON_FONT_UNAVAILABLE = 2; // 0x2
- field public static final int FAIL_REASON_MALFORMED_QUERY = 3; // 0x3
- field public static final int FAIL_REASON_PROVIDER_NOT_FOUND = -1; // 0xffffffff
- field public static final int FAIL_REASON_WRONG_CERTIFICATES = -2; // 0xfffffffe
- }
-
public class Xfermode {
ctor public Xfermode();
}
@@ -23754,7 +23745,7 @@
public static final class VolumeShaper.Configuration implements android.os.Parcelable {
method public int describeContents();
- method public double getDurationMillis();
+ method public long getDuration();
method public int getInterpolatorType();
method public static int getMaximumCurvePoints();
method public float[] getTimes();
@@ -23780,7 +23771,7 @@
method public android.media.VolumeShaper.Configuration.Builder scaleToEndVolume(float);
method public android.media.VolumeShaper.Configuration.Builder scaleToStartVolume(float);
method public android.media.VolumeShaper.Configuration.Builder setCurve(float[], float[]);
- method public android.media.VolumeShaper.Configuration.Builder setDurationMillis(double);
+ method public android.media.VolumeShaper.Configuration.Builder setDuration(long);
method public android.media.VolumeShaper.Configuration.Builder setInterpolatorType(int);
}
@@ -26848,10 +26839,10 @@
field public static final android.os.Parcelable.Creator<android.net.wifi.aware.Characteristics> CREATOR;
}
- public class DiscoverySession {
+ public class DiscoverySession implements java.lang.AutoCloseable {
+ method public void close();
method public android.net.NetworkSpecifier createNetworkSpecifierOpen(android.net.wifi.aware.PeerHandle);
method public android.net.NetworkSpecifier createNetworkSpecifierPassphrase(android.net.wifi.aware.PeerHandle, java.lang.String);
- method public void destroy();
method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[]);
}
@@ -26903,8 +26894,6 @@
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.net.wifi.aware.SubscribeConfig> CREATOR;
- field public static final int MATCH_STYLE_ALL = 1; // 0x1
- field public static final int MATCH_STYLE_FIRST_ONLY = 0; // 0x0
field public static final int SUBSCRIBE_TYPE_ACTIVE = 1; // 0x1
field public static final int SUBSCRIBE_TYPE_PASSIVE = 0; // 0x0
}
@@ -26913,7 +26902,6 @@
ctor public SubscribeConfig.Builder();
method public android.net.wifi.aware.SubscribeConfig build();
method public android.net.wifi.aware.SubscribeConfig.Builder setMatchFilter(java.util.List<byte[]>);
- method public android.net.wifi.aware.SubscribeConfig.Builder setMatchStyle(int);
method public android.net.wifi.aware.SubscribeConfig.Builder setServiceName(java.lang.String);
method public android.net.wifi.aware.SubscribeConfig.Builder setServiceSpecificInfo(byte[]);
method public android.net.wifi.aware.SubscribeConfig.Builder setSubscribeType(int);
@@ -26935,10 +26923,10 @@
field public static final int WIFI_AWARE_DATA_PATH_ROLE_RESPONDER = 1; // 0x1
}
- public class WifiAwareSession {
+ public class WifiAwareSession implements java.lang.AutoCloseable {
+ method public void close();
method public android.net.NetworkSpecifier createNetworkSpecifierOpen(int, byte[]);
method public android.net.NetworkSpecifier createNetworkSpecifierPassphrase(int, byte[], java.lang.String);
- method public void destroy();
method public void publish(android.net.wifi.aware.PublishConfig, android.net.wifi.aware.DiscoverySessionCallback, android.os.Handler);
method public void subscribe(android.net.wifi.aware.SubscribeConfig, android.net.wifi.aware.DiscoverySessionCallback, android.os.Handler);
}
@@ -35082,6 +35070,7 @@
field public static final java.lang.String ACTION_PRIVACY_SETTINGS = "android.settings.PRIVACY_SETTINGS";
field public static final java.lang.String ACTION_QUICK_LAUNCH_SETTINGS = "android.settings.QUICK_LAUNCH_SETTINGS";
field public static final java.lang.String ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS = "android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
+ field public static final java.lang.String ACTION_REQUEST_SET_AUTOFILL_SERVICE = "android.settings.REQUEST_SET_AUTOFILL_SERVICE";
field public static final java.lang.String ACTION_SEARCH_SETTINGS = "android.search.action.SEARCH_SETTINGS";
field public static final java.lang.String ACTION_SECURITY_SETTINGS = "android.settings.SECURITY_SETTINGS";
field public static final java.lang.String ACTION_SETTINGS = "android.settings.SETTINGS";
@@ -37190,15 +37179,12 @@
public abstract class AutofillService extends android.app.Service {
ctor public AutofillService();
- method public final deprecated void disableSelf();
method public final android.service.autofill.FillEventHistory getFillEventHistory();
method public final android.os.IBinder onBind(android.content.Intent);
method public void onConnected();
method public void onDisconnected();
- method public void onFillRequest(android.service.autofill.FillRequest, android.os.CancellationSignal, android.service.autofill.FillCallback);
- method public abstract deprecated void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, int, android.os.CancellationSignal, android.service.autofill.FillCallback);
- method public void onSaveRequest(android.service.autofill.SaveRequest, android.service.autofill.SaveCallback);
- method public abstract deprecated void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.service.autofill.SaveCallback);
+ method public abstract void onFillRequest(android.service.autofill.FillRequest, android.os.CancellationSignal, android.service.autofill.FillCallback);
+ method public abstract void onSaveRequest(android.service.autofill.SaveRequest, android.service.autofill.SaveCallback);
field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutofillService";
field public static final java.lang.String SERVICE_META_DATA = "android.autofill";
}
@@ -37272,7 +37258,6 @@
method public android.service.autofill.FillResponse build();
method public android.service.autofill.FillResponse.Builder setAuthentication(android.view.autofill.AutofillId[], android.content.IntentSender, android.widget.RemoteViews);
method public android.service.autofill.FillResponse.Builder setClientState(android.os.Bundle);
- method public deprecated android.service.autofill.FillResponse.Builder setExtras(android.os.Bundle);
method public android.service.autofill.FillResponse.Builder setIgnoredIds(android.view.autofill.AutofillId...);
method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo);
}
@@ -40435,10 +40420,12 @@
method public void sendDialerSpecialCode(java.lang.String);
method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
method public void sendUssdRequest(java.lang.String, android.telephony.TelephonyManager.UssdResponseCallback, android.os.Handler);
+ method public void sendVisualVoicemailSms(java.lang.String, int, java.lang.String, android.app.PendingIntent);
method public void setDataEnabled(boolean);
method public boolean setLine1NumberForDisplay(java.lang.String, java.lang.String);
method public boolean setOperatorBrandOverride(java.lang.String);
method public boolean setPreferredNetworkTypeToGlobal();
+ method public void setVisualVoicemailSmsFilterSettings(android.telephony.VisualVoicemailSmsFilterSettings);
method public boolean setVoiceMailNumber(java.lang.String, java.lang.String);
method public void setVoicemailRingtoneUri(android.telecom.PhoneAccountHandle, android.net.Uri);
method public void setVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle, boolean);
@@ -40529,8 +40516,6 @@
method public abstract void onSimRemoved(android.telephony.VisualVoicemailService.VisualVoicemailTask, android.telecom.PhoneAccountHandle);
method public abstract void onSmsReceived(android.telephony.VisualVoicemailService.VisualVoicemailTask, android.telephony.VisualVoicemailSms);
method public abstract void onStopped(android.telephony.VisualVoicemailService.VisualVoicemailTask);
- method public static final void sendVisualVoicemailSms(android.content.Context, android.telecom.PhoneAccountHandle, java.lang.String, short, java.lang.String, android.app.PendingIntent);
- method public static final void setSmsFilterSettings(android.content.Context, android.telecom.PhoneAccountHandle, android.telephony.VisualVoicemailSmsFilterSettings);
field public static final java.lang.String SERVICE_INTERFACE = "android.telephony.VisualVoicemailService";
}
@@ -47534,7 +47519,9 @@
public final class AccessibilityManager {
method public boolean addAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener);
+ method public void addAccessibilityStateChangeListener(android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener, android.os.Handler);
method public boolean addTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener);
+ method public void addTouchExplorationStateChangeListener(android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener, android.os.Handler);
method public deprecated java.util.List<android.content.pm.ServiceInfo> getAccessibilityServiceList();
method public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int);
method public java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getInstalledAccessibilityServiceList();
@@ -48217,6 +48204,8 @@
method public void cancel();
method public void commit();
method public void disableOwnedAutofillServices();
+ method public boolean hasEnabledAutofillServices();
+ method public boolean isAutofillSupported();
method public boolean isEnabled();
method public void notifyValueChanged(android.view.View);
method public void notifyValueChanged(android.view.View, int, android.view.autofill.AutofillValue);
@@ -48231,7 +48220,6 @@
field public static final java.lang.String EXTRA_ASSIST_STRUCTURE = "android.view.autofill.extra.ASSIST_STRUCTURE";
field public static final java.lang.String EXTRA_AUTHENTICATION_RESULT = "android.view.autofill.extra.AUTHENTICATION_RESULT";
field public static final java.lang.String EXTRA_DATA_EXTRAS = "android.view.autofill.extra.DATA_EXTRAS";
- field public static final deprecated int FLAG_MANUAL_REQUEST = 1; // 0x1
}
public static abstract class AutofillManager.AutofillCallback {
diff --git a/api/test-removed.txt b/api/test-removed.txt
index dc9c54e..73dd096 100644
--- a/api/test-removed.txt
+++ b/api/test-removed.txt
@@ -1,7 +1,6 @@
package android.app {
public class Notification implements android.os.Parcelable {
- method public deprecated int getBadgeIcon();
method public deprecated void setLatestEventInfo(android.content.Context, java.lang.CharSequence, java.lang.CharSequence, android.app.PendingIntent);
}
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 5937dd9..3cda489 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -95,9 +95,7 @@
public static final int CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 0x00000002;
/**
- * Capability: This accessibility service can request enhanced web accessibility
- * enhancements. For example, installing scripts to make app content more accessible.
- * @see android.R.styleable#AccessibilityService_canRequestEnhancedWebAccessibility
+ * @deprecated No longer used
*/
public static final int CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 0x00000004;
@@ -237,22 +235,7 @@
public static final int FLAG_REQUEST_TOUCH_EXPLORATION_MODE = 0x0000004;
/**
- * This flag requests from the system to enable web accessibility enhancing
- * extensions. Such extensions aim to provide improved accessibility support
- * for content presented in a {@link android.webkit.WebView}. An example of such
- * an extension is injecting JavaScript from a secure source. The system will enable
- * enhanced web accessibility if there is at least one accessibility service
- * that has this flag set. Hence, clearing this flag does not guarantee that the
- * device will not have enhanced web accessibility enabled since there may be
- * another enabled service that requested it.
- * <p>
- * Services that want to set this flag have to declare this capability
- * in their meta-data by setting the attribute {@link android.R.attr
- * #canRequestEnhancedWebAccessibility canRequestEnhancedWebAccessibility} to
- * true, otherwise this flag will be ignored. For how to declare the meta-data
- * of a service refer to {@value AccessibilityService#SERVICE_META_DATA}.
- * </p>
- * @see android.R.styleable#AccessibilityService_canRequestEnhancedWebAccessibility
+ * @deprecated No longer used
*/
public static final int FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY = 0x00000008;
@@ -526,10 +509,6 @@
mCapabilities |= CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION;
}
if (asAttributes.getBoolean(com.android.internal.R.styleable
- .AccessibilityService_canRequestEnhancedWebAccessibility, false)) {
- mCapabilities |= CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY;
- }
- if (asAttributes.getBoolean(com.android.internal.R.styleable
.AccessibilityService_canRequestFilterKeyEvents, false)) {
mCapabilities |= CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS;
}
@@ -659,7 +638,6 @@
*
* @see #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT
* @see #CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION
- * @see #CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY
* @see #CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS
* @see #CAPABILITY_CAN_CONTROL_MAGNIFICATION
* @see #CAPABILITY_CAN_PERFORM_GESTURES
@@ -676,7 +654,6 @@
*
* @see #CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT
* @see #CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION
- * @see #CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY
* @see #CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS
* @see #CAPABILITY_CAN_CONTROL_MAGNIFICATION
* @see #CAPABILITY_CAN_PERFORM_GESTURES
@@ -1074,10 +1051,6 @@
new CapabilityInfo(CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION,
R.string.capability_title_canRequestTouchExploration,
R.string.capability_desc_canRequestTouchExploration));
- sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY,
- new CapabilityInfo(CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY,
- R.string.capability_title_canRequestEnhancedWebAccessibility,
- R.string.capability_desc_canRequestEnhancedWebAccessibility));
sAvailableCapabilityInfos.put(CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS,
new CapabilityInfo(CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS,
R.string.capability_title_canRequestFilterKeyEvents,
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index b320d5d..06b09c0 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -345,7 +345,13 @@
"android.accounts.LOGIN_ACCOUNTS_CHANGED";
/**
- * Action sent as a broadcast Intent by the AccountsService when any account is removed.
+ * Action sent as a broadcast Intent by the AccountsService when any account is removed
+ * or renamed. Only applications which were able to see the account will receive the intent.
+ * Intent extra will include the following fields:
+ * <ul>
+ * <li> {@link #KEY_ACCOUNT_NAME} - the name of the removed account
+ * <li> {@link #KEY_ACCOUNT_TYPE} - the type of the account
+ * </ul>
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
@BroadcastBehavior(includeBackground = true)
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index e4d2d13..cdfb52b1 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -696,9 +696,6 @@
private static final String TAG = "Activity";
private static final boolean DEBUG_LIFECYCLE = false;
- // TODO(b/33197203): set to false once stable
- private static final boolean DEBUG_AUTO_FILL = true;
-
/** Standard activity result: operation canceled. */
public static final int RESULT_CANCELED = 0;
/** Standard activity result: operation succeeded. */
@@ -7323,6 +7320,7 @@
* @return True if caption is displayed on content, false if it pushes the content down.
*
* @see #setOverlayWithDecorCaptionEnabled(boolean)
+ * @hide
*/
public boolean isOverlayWithDecorCaptionEnabled() {
return mWindow.isOverlayWithDecorCaptionEnabled();
@@ -7334,6 +7332,7 @@
* This affects only freeform windows since they display the caption and only the main
* window of the activity. The caption is used to drag the window around and also shows
* maximize and close action buttons.
+ * @hide
*/
public void setOverlayWithDecorCaptionEnabled(boolean enabled) {
mWindow.setOverlayWithDecorCaptionEnabled(enabled);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 5022d7d..46ce94f 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3004,7 +3004,7 @@
// - it needs an IAutoFillCallback
boolean forAutofill = cmd.requestType == ActivityManager.ASSIST_CONTEXT_AUTOFILL;
- // TODO(b/33197203): decide if lastSessionId logic applies to autofill sessions
+ // TODO: decide if lastSessionId logic applies to autofill sessions
if (mLastSessionId != cmd.sessionId) {
// Clear the existing structures
mLastSessionId = cmd.sessionId;
@@ -3032,8 +3032,6 @@
if (cmd.requestType == ActivityManager.ASSIST_CONTEXT_FULL || forAutofill) {
structure = new AssistStructure(r.activity, forAutofill);
Intent activityIntent = r.activity.getIntent();
- // TODO(b/33197203): re-evaluate conditions below for autofill. In particular,
- // FLAG_SECURE might be allowed on AUTO_FILL but not on AUTO_FILL_SAVE)
boolean notSecure = r.window == null ||
(r.window.getAttributes().flags
& WindowManager.LayoutParams.FLAG_SECURE) == 0;
@@ -3059,7 +3057,7 @@
structure = new AssistStructure();
}
- // TODO(b/33197203): decide if lastSessionId logic applies to autofill sessions
+ // TODO: decide if lastSessionId logic applies to autofill sessions
structure.setAcquisitionStartTime(startTime);
structure.setAcquisitionEndTime(SystemClock.uptimeMillis());
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 2b4fb19..e53e3da 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1106,6 +1106,45 @@
private String mShortcutId;
private CharSequence mSettingsText;
+ /** @hide */
+ @IntDef(prefix = { "GROUP_ALERT_" }, value = {
+ GROUP_ALERT_ALL, GROUP_ALERT_CHILDREN, GROUP_ALERT_SUMMARY
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface GroupAlertBehavior {}
+
+ /**
+ * Constant for {@link Builder#setGroupAlertBehavior(int)}, meaning that all notifications in a
+ * group with sound or vibration ought to make sound or vibrate (respectively), so this
+ * notification will not be muted when it is in a group.
+ */
+ public static final int GROUP_ALERT_ALL = 0;
+
+ /**
+ * Constant for {@link Builder#setGroupAlertBehavior(int)}, meaning that all children
+ * notification in a group should be silenced (no sound or vibration) even if they are posted
+ * to a {@link NotificationChannel} that has sound and/or vibration. Use this constant to
+ * mute this notification if this notification is a group child.
+ *
+ * <p> For example, you might want to use this constant if you post a number of children
+ * notifications at once (say, after a periodic sync), and only need to notify the user
+ * audibly once.
+ */
+ public static final int GROUP_ALERT_SUMMARY = 1;
+
+ /**
+ * Constant for {@link Builder#setGroupAlertBehavior(int)}, meaning that the summary
+ * notification in a group should be silenced (no sound or vibration) even if they are
+ * posted to a {@link NotificationChannel} that has sound and/or vibration. Use this constant
+ * to mute this notification if this notification is a group summary.
+ *
+ * <p>For example, you might want to use this constant if only the children notifications
+ * in your group have content and the summary is only used to visually group notifications.
+ */
+ public static final int GROUP_ALERT_CHILDREN = 2;
+
+ private int mGroupAlertBehavior = GROUP_ALERT_ALL;
+
/**
* If this notification is being shown as a badge, always show as a number.
*/
@@ -1878,6 +1917,8 @@
if (parcel.readInt() != 0) {
mSettingsText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(parcel);
}
+
+ mGroupAlertBehavior = parcel.readInt();
}
@Override
@@ -1990,6 +2031,7 @@
that.mShortcutId = this.mShortcutId;
that.mBadgeIcon = this.mBadgeIcon;
that.mSettingsText = this.mSettingsText;
+ that.mGroupAlertBehavior = this.mGroupAlertBehavior;
if (!heavy) {
that.lightenPayload(); // will clean out extras
@@ -2266,6 +2308,8 @@
} else {
parcel.writeInt(0);
}
+
+ parcel.writeInt(mGroupAlertBehavior);
}
/**
@@ -2471,17 +2515,6 @@
}
/**
- * @removed
- * Returns what icon should be shown for this notification if it is being displayed in a
- * Launcher that supports badging. Will be one of {@link #BADGE_ICON_NONE},
- * {@link #BADGE_ICON_SMALL}, or {@link #BADGE_ICON_LARGE}.
- */
- @Deprecated
- public int getBadgeIcon() {
- return mBadgeIcon;
- }
-
- /**
* Returns what icon should be shown for this notification if it is being displayed in a
* Launcher that supports badging. Will be one of {@link #BADGE_ICON_NONE},
* {@link #BADGE_ICON_SMALL}, or {@link #BADGE_ICON_LARGE}.
@@ -2506,6 +2539,15 @@
}
/**
+ * Returns which type of notifications in a group are responsible for audibly alerting the
+ * user. See {@link #GROUP_ALERT_ALL}, {@link #GROUP_ALERT_CHILDREN},
+ * {@link #GROUP_ALERT_SUMMARY}.
+ */
+ public @GroupAlertBehavior int getGroupAlertBehavior() {
+ return mGroupAlertBehavior;
+ }
+
+ /**
* The small icon representing this notification in the status bar and content view.
*
* @return the small icon representing this notification.
@@ -2753,6 +2795,19 @@
}
/**
+ * Sets the group alert behavior for this notification. Use this method to mute this
+ * notification if alerts for this notification's group should be handled by a different
+ * notification. This is only applicable for notifications that belong to a
+ * {@link #setGroup(String) group}.
+ *
+ * <p> The default value is {@link #GROUP_ALERT_ALL}.</p>
+ */
+ public Builder setGroupAlertBehavior(@GroupAlertBehavior int groupAlertBehavior) {
+ mN.mGroupAlertBehavior = groupAlertBehavior;
+ return this;
+ }
+
+ /**
* Specifies the channel the notification should be delivered on.
*/
public Builder setChannel(String channelId) {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 82ad825..a939eb0 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2972,9 +2972,9 @@
* profile.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
- * @param timeoutMs The new timeout, after which the user will have to unlock with strong
- * authentication method. A value of 0 means the admin is not participating in
- * controlling the timeout.
+ * @param timeoutMs The new timeout in milliseconds, after which the user will have to unlock
+ * with strong authentication method. A value of 0 means the admin is not participating
+ * in controlling the timeout.
* The minimum and maximum timeouts are platform-defined and are typically 1 hour and
* 72 hours, respectively. Though discouraged, the admin may choose to require strong
* auth at all times using {@link #KEYGUARD_DISABLE_FINGERPRINT} and/or
@@ -3004,7 +3004,7 @@
*
* @param admin The name of the admin component to check, or {@code null} to aggregate
* accross all participating admins.
- * @return The timeout or 0 if not configured for the provided admin.
+ * @return The timeout in milliseconds or 0 if not configured for the provided admin.
*/
public long getRequiredStrongAuthTimeout(@Nullable ComponentName admin) {
return getRequiredStrongAuthTimeout(admin, myUserId());
@@ -7681,6 +7681,8 @@
*
* <p> Backup service is off by default when device owner is present.
*
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param enabled {@code true} to enable the backup service, {@code false} to disable it.
* @throws SecurityException if {@code admin} is not a device owner.
*/
public void setBackupServiceEnabled(@NonNull ComponentName admin, boolean enabled) {
diff --git a/core/java/android/app/admin/SystemUpdateInfo.java b/core/java/android/app/admin/SystemUpdateInfo.java
index 6bb9f2d..fa31273 100644
--- a/core/java/android/app/admin/SystemUpdateInfo.java
+++ b/core/java/android/app/admin/SystemUpdateInfo.java
@@ -89,8 +89,9 @@
}
/**
- * Gets time when the update was first available.
- * @return Time as given by {@link System#currentTimeMillis()}
+ * Gets time when the update was first available in milliseconds since midnight, January 1,
+ * 1970 UTC.
+ * @return Time in milliseconds as given by {@link System#currentTimeMillis()}
*/
public long getReceivedTime() {
return mReceivedTime;
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 7c1bcf0..d757f3e 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -600,7 +600,7 @@
String mIdType;
String mIdEntry;
- // TODO(b/33197203): once we have more flags, it might be better to store the individual
+ // TODO: once we have more flags, it might be better to store the individual
// fields (viewId and childId) of the field.
AutofillId mAutofillId;
@View.AutofillType int mAutofillType = View.AUTOFILL_TYPE_NONE;
@@ -639,7 +639,7 @@
static final int FLAGS_CONTEXT_CLICKABLE = 0x00004000;
static final int FLAGS_OPAQUE = 0x00008000;
- // TODO(b/33197203): autofill data is made of many fields and ideally we should verify
+ // TODO: autofill data is made of many fields and ideally we should verify
// one-by-one to optimize what's sent over, but there isn't enough flag bits for that, we'd
// need to create a 'flags2' or 'autoFillFlags' field and add these flags there.
// So, to keep thinkg simpler for now, let's just use on flag for all of them...
@@ -1043,8 +1043,6 @@
*/
public void updateAutofillValue(AutofillValue value) {
mAutofillValue = value;
- // TODO(b/33197203, b/33802548): decide whether to set text as well (so it would work
- // with "legacy" views) or just the autofill value
if (value.isText()) {
mText.mText = value.getTextValue();
}
diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java
index 9f35e85..6327f34 100644
--- a/core/java/android/appwidget/AppWidgetManager.java
+++ b/core/java/android/appwidget/AppWidgetManager.java
@@ -712,12 +712,13 @@
*
* @param profile The profile for which to get providers. Passing null is equivalent
* to querying for only the calling user.
- * @return The installed providers.
+ * @return The installed providers, or an empty list if none are found for the given user.
*
* @see android.os.Process#myUserHandle()
* @see android.os.UserManager#getUserProfiles()
*/
- public List<AppWidgetProviderInfo> getInstalledProvidersForProfile(@Nullable UserHandle profile) {
+ public @NonNull List<AppWidgetProviderInfo> getInstalledProvidersForProfile(
+ @Nullable UserHandle profile) {
if (mService == null) {
return Collections.emptyList();
}
@@ -735,13 +736,20 @@
* equivalent to {@link #getInstalledProvidersForProfile(UserHandle)}.
* @param profile The profile for which to get providers. Passing null is equivalent
* to querying for only the calling user.
- * @return The installed providers.
+ * @return The installed providers, or an empty list if none are found for the given
+ * package and user.
+ * @throws NullPointerException if the provided package name is null
*
* @see android.os.Process#myUserHandle()
* @see android.os.UserManager#getUserProfiles()
*/
- public List<AppWidgetProviderInfo> getInstalledProvidersForPackage(@Nullable String packageName,
- @Nullable UserHandle profile) {
+ public @NonNull List<AppWidgetProviderInfo> getInstalledProvidersForPackage(
+ @NonNull String packageName, @Nullable UserHandle profile) {
+ if (packageName == null) {
+ throw new NullPointerException("A non-null package must be passed to this method. " +
+ "If you want all widgets regardless of package, see " +
+ "getInstalledProvidersForProfile(UserHandle)");
+ }
if (mService == null) {
return Collections.emptyList();
}
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index e50b2a9..fac9e13 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -118,6 +118,9 @@
* association is no longer relevant to avoid unnecessary battery and/or data drain resulting
* from special privileges that the association provides</p>
*
+ * <p>Calling this API requires a uses-feature
+ * {@link PackageManager#FEATURE_COMPANION_DEVICE_SETUP} declaration in the manifest</p>
+ *
* @param request specific details about this request
* @param callback will be called once there's at least one device found for user to choose from
* @param handler A handler to control which thread the callback will be delivered on, or null,
@@ -160,6 +163,9 @@
}
/**
+ * <p>Calling this API requires a uses-feature
+ * {@link PackageManager#FEATURE_COMPANION_DEVICE_SETUP} declaration in the manifest</p>
+ *
* @return a list of MAC addresses of devices that have been previously associated with the
* current app. You can use these with {@link #disassociate}
*/
@@ -184,6 +190,9 @@
* association is no longer relevant to avoid unnecessary battery and/or data drain resulting
* from special privileges that the association provides</p>
*
+ * <p>Calling this API requires a uses-feature
+ * {@link PackageManager#FEATURE_COMPANION_DEVICE_SETUP} declaration in the manifest</p>
+ *
* @param deviceMacAddress the MAC address of device to disassociate from this app
*/
public void disassociate(@NonNull String deviceMacAddress) {
@@ -206,6 +215,9 @@
* are allowed.
*
* Your app must have an association with a device before calling this API
+ *
+ * <p>Calling this API requires a uses-feature
+ * {@link PackageManager#FEATURE_COMPANION_DEVICE_SETUP} declaration in the manifest</p>
*/
public void requestNotificationAccess(ComponentName component) {
if (!checkFeaturePresent()) {
@@ -226,6 +238,9 @@
*
* Your app must have an association with a device before calling this API
*
+ * <p>Calling this API requires a uses-feature
+ * {@link PackageManager#FEATURE_COMPANION_DEVICE_SETUP} declaration in the manifest</p>
+ *
* @param component the name of the component
* @return whether the given component has the notification listener permission
*/
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 1f78bff..8609351 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -145,7 +145,12 @@
private static final boolean DEBUG_PARSER = false;
private static final boolean DEBUG_BACKUP = false;
- private static final boolean MULTI_PACKAGE_APK_ENABLED = false;
+ private static final String PROPERTY_CHILD_PACKAGES_ENABLED =
+ "persist.sys.child_packages_enabled";
+
+ private static final boolean MULTI_PACKAGE_APK_ENABLED =
+ SystemProperties.getBoolean(PROPERTY_CHILD_PACKAGES_ENABLED, false);
+
private static final int MAX_PACKAGES_PER_APK = 5;
public static final int APK_SIGNING_UNKNOWN = 0;
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index 10c4cb3..f5ad5cc 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -322,7 +322,10 @@
if (sensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) {
synchronized(mTriggerListeners) {
- for (TriggerEventListener l: mTriggerListeners.keySet()) {
+ HashMap<TriggerEventListener, TriggerEventQueue> triggerListeners =
+ new HashMap<TriggerEventListener, TriggerEventQueue>(mTriggerListeners);
+
+ for (TriggerEventListener l: triggerListeners.keySet()) {
if (DEBUG_DYNAMIC_SENSOR){
Log.i(TAG, "removed trigger listener" + l.toString() +
" due to sensor disconnection");
@@ -332,7 +335,10 @@
}
} else {
synchronized(mSensorListeners) {
- for (SensorEventListener l: mSensorListeners.keySet()) {
+ HashMap<SensorEventListener, SensorEventQueue> sensorListeners =
+ new HashMap<SensorEventListener, SensorEventQueue>(mSensorListeners);
+
+ for (SensorEventListener l: sensorListeners.keySet()) {
if (DEBUG_DYNAMIC_SENSOR){
Log.i(TAG, "removed event listener" + l.toString() +
" due to sensor disconnection");
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 1cf8f03..279d73d 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -1662,9 +1662,13 @@
* <p>The output images for request B may have contents captured before the output images for
* request A, and the result metadata for request B may be older than the result metadata for
* request A.</p>
- * <p>Note that when enableZsl is <code>true</code>, it is not guaranteed to get output images captured in the
- * past for requests with STILL_CAPTURE capture intent.</p>
- * <p>The value of enableZsl in capture templates is always <code>false</code> if present.</p>
+ * <p>Note that when enableZsl is <code>true</code>, it is not guaranteed to get output images captured in
+ * the past for requests with STILL_CAPTURE capture intent.</p>
+ * <p>For applications targeting SDK versions O and newer, the value of enableZsl in
+ * TEMPLATE_STILL_CAPTURE template may be <code>true</code>. The value in other templates is always
+ * <code>false</code> if present.</p>
+ * <p>For applications targeting SDK versions older than O, the value of enableZsl in all
+ * capture templates is always <code>false</code> if present.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*
* @see CaptureRequest#CONTROL_CAPTURE_INTENT
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 419e3e2..aedfc4b 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -2167,9 +2167,13 @@
* <p>The output images for request B may have contents captured before the output images for
* request A, and the result metadata for request B may be older than the result metadata for
* request A.</p>
- * <p>Note that when enableZsl is <code>true</code>, it is not guaranteed to get output images captured in the
- * past for requests with STILL_CAPTURE capture intent.</p>
- * <p>The value of enableZsl in capture templates is always <code>false</code> if present.</p>
+ * <p>Note that when enableZsl is <code>true</code>, it is not guaranteed to get output images captured in
+ * the past for requests with STILL_CAPTURE capture intent.</p>
+ * <p>For applications targeting SDK versions O and newer, the value of enableZsl in
+ * TEMPLATE_STILL_CAPTURE template may be <code>true</code>. The value in other templates is always
+ * <code>false</code> if present.</p>
+ * <p>For applications targeting SDK versions older than O, the value of enableZsl in all
+ * capture templates is always <code>false</code> if present.</p>
* <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
*
* @see CaptureRequest#CONTROL_CAPTURE_INTENT
diff --git a/core/java/android/net/INetworkRecommendationProvider.aidl b/core/java/android/net/INetworkRecommendationProvider.aidl
index 052c92c..cde0185 100644
--- a/core/java/android/net/INetworkRecommendationProvider.aidl
+++ b/core/java/android/net/INetworkRecommendationProvider.aidl
@@ -17,8 +17,6 @@
package android.net;
import android.net.NetworkKey;
-import android.net.RecommendationRequest;
-import android.os.IRemoteCallback;
/**
* The service responsible for answering network recommendation requests.
@@ -27,20 +25,6 @@
oneway interface INetworkRecommendationProvider {
/**
- * Request a recommendation for the best network to connect to
- * taking into account the inputs from the {@link RecommendationRequest}.
- *
- * @param request a {@link RecommendationRequest} instance containing the details of the request
- * @param callback a {@link IRemoteCallback} instance to invoke when the recommendation
- * is available
- * @param sequence an internal number used for tracking the request
- * @hide
- */
- void requestRecommendation(in RecommendationRequest request,
- in IRemoteCallback callback,
- int sequence);
-
- /**
* Request scoring for networks.
*
* Implementations should use {@link NetworkScoreManager#updateScores(ScoredNetwork[])} to
diff --git a/core/java/android/net/INetworkScoreService.aidl b/core/java/android/net/INetworkScoreService.aidl
index 362ea9d..73e52c8 100644
--- a/core/java/android/net/INetworkScoreService.aidl
+++ b/core/java/android/net/INetworkScoreService.aidl
@@ -19,10 +19,7 @@
import android.net.INetworkScoreCache;
import android.net.NetworkKey;
import android.net.NetworkScorerAppData;
-import android.net.RecommendationRequest;
-import android.net.RecommendationResult;
import android.net.ScoredNetwork;
-import android.os.RemoteCallback;
/**
* A service for updating network scores from a network scorer application.
@@ -81,16 +78,6 @@
void unregisterNetworkScoreCache(int networkType, INetworkScoreCache scoreCache);
/**
- * Request a recommendation for the best network to connect to
- * taking into account the inputs from the {@link RecommendationRequest}.
- *
- * @param request a {@link RecommendationRequest} instance containing the details of the request
- * @return a {@link RecommendationResult} containing the recommended network to connect to
- * @throws SecurityException if the caller is not the system
- */
- RecommendationResult requestRecommendation(in RecommendationRequest request);
-
- /**
* Request scoring for networks.
*
* Implementations should delegate to the registered network recommendation provider or
@@ -119,18 +106,6 @@
* scorer.
*/
String getActiveScorerPackage();
-
- /**
- * Request a recommendation for the best network to connect to
- * taking into account the inputs from the {@link RecommendationRequest}.
- *
- * @param request a {@link RecommendationRequest} instance containing the details of the request
- * @param remoteCallback a {@link RemoteCallback} instance to invoke when the recommendation
- * is available.
- * @throws SecurityException if the caller is not the system
- */
- oneway void requestRecommendationAsync(in RecommendationRequest request,
- in RemoteCallback remoteCallback);
/**
* Returns metadata about the active scorer or <code>null</code> if there is no active scorer.
diff --git a/core/java/android/net/NetworkRecommendationProvider.java b/core/java/android/net/NetworkRecommendationProvider.java
index af0459d..1eaa1f9 100644
--- a/core/java/android/net/NetworkRecommendationProvider.java
+++ b/core/java/android/net/NetworkRecommendationProvider.java
@@ -39,10 +39,14 @@
public abstract class NetworkRecommendationProvider {
private static final String TAG = "NetworkRecProvider";
private static final boolean VERBOSE = Build.IS_DEBUGGABLE && Log.isLoggable(TAG, Log.VERBOSE);
- /** The key into the callback Bundle where the RecommendationResult will be found. */
+ /** The key into the callback Bundle where the RecommendationResult will be found.
+ * @deprecated to be removed.
+ */
public static final String EXTRA_RECOMMENDATION_RESULT =
"android.net.extra.RECOMMENDATION_RESULT";
- /** The key into the callback Bundle where the sequence will be found. */
+ /** The key into the callback Bundle where the sequence will be found.
+ * @deprecated to be removed.
+ */
public static final String EXTRA_SEQUENCE = "android.net.extra.SEQUENCE";
private final IBinder mService;
@@ -77,9 +81,9 @@
* @param callback a {@link ResultCallback} instance. When a {@link RecommendationResult} is
* available it must be passed into
* {@link ResultCallback#onResult(RecommendationResult)}.
+ * @deprecated to be removed.
*/
- public abstract void onRequestRecommendation(RecommendationRequest request,
- ResultCallback callback);
+ public void onRequestRecommendation(RecommendationRequest request, ResultCallback callback) {}
/**
* Invoked when network scores have been requested.
@@ -101,6 +105,8 @@
/**
* A callback implementing applications should invoke when a {@link RecommendationResult}
* is available.
+ *
+ * @deprecated to be removed.
*/
public static class ResultCallback {
private final IRemoteCallback mCallback;
@@ -176,23 +182,6 @@
}
@Override
- public void requestRecommendation(final RecommendationRequest request,
- final IRemoteCallback callback, final int sequence) throws RemoteException {
- enforceCallingPermission();
- if (VERBOSE) Log.v(TAG, "requestRecommendation(seq=" + sequence + ")");
- execute(new Runnable() {
- @Override
- public void run() {
- if (VERBOSE) {
- Log.v(TAG, "requestRecommendation(seq=" + sequence + ") running...");
- }
- ResultCallback resultCallback = new ResultCallback(callback, sequence);
- onRequestRecommendation(request, resultCallback);
- }
- });
- }
-
- @Override
public void requestScores(final NetworkKey[] networks) throws RemoteException {
enforceCallingPermission();
if (networks != null && networks.length > 0) {
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index 29483cd..eeb426a 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -428,14 +428,11 @@
* @throws SecurityException if the caller does not hold the
* {@link android.Manifest.permission#REQUEST_NETWORK_SCORES} permission.
* @hide
+ * @deprecated to be removed.
*/
public RecommendationResult requestRecommendation(RecommendationRequest request)
throws SecurityException {
- try {
- return mService.requestRecommendation(request);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return null;
}
/**
@@ -452,43 +449,4 @@
throw e.rethrowFromSystemServer();
}
}
-
- /**
- * Request a recommendation for which network to connect to.
- *
- * <p>The callback will be run on the thread associated with provided {@link Handler}.
- *
- * @param request a {@link RecommendationRequest} instance containing additional
- * request details
- * @param handler a {@link Handler} instance representing the thread to complete the future on.
- * If null the responding binder thread will be used.
- * @return a {@link CompletableFuture} instance that will eventually receive the
- * {@link RecommendationResult}.
- * @throws SecurityException
- * @hide
- */
- public CompletableFuture<RecommendationResult> requestRecommendation(
- final @NonNull RecommendationRequest request,
- final @Nullable Handler handler) {
- Preconditions.checkNotNull(request, "RecommendationRequest cannot be null.");
-
- final CompletableFuture<RecommendationResult> futureResult =
- new CompletableFuture<>();
-
- RemoteCallback remoteCallback = new RemoteCallback(new RemoteCallback.OnResultListener() {
- @Override
- public void onResult(Bundle data) {
- RecommendationResult result = data.getParcelable(EXTRA_RECOMMENDATION_RESULT);
- futureResult.complete(result);
- }
- }, handler);
-
- try {
- mService.requestRecommendationAsync(request, remoteCallback);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
-
- return futureResult;
- }
}
diff --git a/core/java/android/net/RecommendationRequest.aidl b/core/java/android/net/RecommendationRequest.aidl
deleted file mode 100644
index 76497b8..0000000
--- a/core/java/android/net/RecommendationRequest.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2016, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-parcelable RecommendationRequest;
diff --git a/core/java/android/net/RecommendationRequest.java b/core/java/android/net/RecommendationRequest.java
index 9f97c5a..45ee3a5 100644
--- a/core/java/android/net/RecommendationRequest.java
+++ b/core/java/android/net/RecommendationRequest.java
@@ -30,6 +30,7 @@
*
* @see {@link NetworkScoreManager#requestRecommendation(RecommendationRequest)}.
* @hide
+ * @deprecated to be removed.
*/
@SystemApi
public final class RecommendationRequest implements Parcelable {
@@ -43,6 +44,7 @@
/**
* Builder class for constructing {@link RecommendationRequest} instances.
* @hide
+ * @deprecated to be removed.
*/
@SystemApi
public static final class Builder {
diff --git a/core/java/android/net/RecommendationResult.aidl b/core/java/android/net/RecommendationResult.aidl
deleted file mode 100644
index f36995b..0000000
--- a/core/java/android/net/RecommendationResult.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2016, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-parcelable RecommendationResult;
diff --git a/core/java/android/net/RecommendationResult.java b/core/java/android/net/RecommendationResult.java
index 70cf09c..ce4d83a 100644
--- a/core/java/android/net/RecommendationResult.java
+++ b/core/java/android/net/RecommendationResult.java
@@ -31,6 +31,7 @@
*
* @see {@link NetworkScoreManager#requestRecommendation(RecommendationRequest)}.
* @hide
+ * @deprecated to be removed.
*/
@SystemApi
public final class RecommendationResult implements Parcelable {
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index 7496cb2..2179bd4 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -17,8 +17,6 @@
package android.preference;
import android.annotation.CallSuper;
-import com.android.internal.util.CharSequences;
-
import android.annotation.DrawableRes;
import android.annotation.LayoutRes;
import android.annotation.Nullable;
@@ -42,6 +40,8 @@
import android.widget.ListView;
import android.widget.TextView;
+import com.android.internal.util.CharSequences;
+
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@@ -650,7 +650,11 @@
final View imageFrame = view.findViewById(com.android.internal.R.id.icon_frame);
if (imageFrame != null) {
- imageFrame.setVisibility(mIcon != null ? View.VISIBLE : View.GONE);
+ if (mIcon != null) {
+ imageFrame.setVisibility(View.VISIBLE);
+ } else {
+ imageFrame.setVisibility(mIconSpaceReserved ? View.INVISIBLE : View.GONE);
+ }
}
if (mShouldDisableView) {
diff --git a/core/java/android/provider/FontsContract.java b/core/java/android/provider/FontsContract.java
index 068628a..e68c7bb 100644
--- a/core/java/android/provider/FontsContract.java
+++ b/core/java/android/provider/FontsContract.java
@@ -33,7 +33,6 @@
import android.database.Cursor;
import android.graphics.Typeface;
import android.graphics.fonts.FontRequest;
-import android.graphics.fonts.FontResult;
import android.graphics.fonts.FontVariationAxis;
import android.net.Uri;
import android.os.Bundle;
@@ -43,6 +42,7 @@
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.ResultReceiver;
+import android.util.ArraySet;
import android.util.Log;
import android.util.LruCache;
@@ -64,6 +64,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Set;
/**
* Utility class to deal with Font ContentProviders.
@@ -181,6 +182,8 @@
private Handler mHandler;
@GuardedBy("mLock")
private HandlerThread mThread;
+ @GuardedBy("mLock")
+ private Set<String> mInQueueSet;
private static final LruCache<String, Typeface> sTypefaceCache = new LruCache<>(16);
@@ -330,81 +333,54 @@
mThread.quitSafely();
mThread = null;
mHandler = null;
+ mInQueueSet = null;
}
}
}
};
/** @hide */
- public void getFont(FontRequest request, ResultReceiver receiver) {
+ public Typeface getFontOrWarmUpCache(FontRequest request) {
+ final String id = request.getIdentifier();
+ Typeface cachedTypeface = sTypefaceCache.get(id);
+ if (cachedTypeface != null) {
+ return cachedTypeface;
+ }
+
+ // Unfortunately the typeface is not available at this time, but requesting from the font
+ // provider takes too much time. For now, request the font data to ensure it is in the cache
+ // next time and return.
synchronized (mLock) {
if (mHandler == null) {
mThread = new HandlerThread("fonts", Process.THREAD_PRIORITY_BACKGROUND);
mThread.start();
mHandler = new Handler(mThread.getLooper());
+ mInQueueSet = new ArraySet<String>();
}
+ if (mInQueueSet.contains(id)) {
+ return null; // Already requested.
+ }
+ mInQueueSet.add(id);
mHandler.post(() -> {
- ProviderInfo providerInfo;
- try {
- providerInfo = getProvider(mPackageManager, request);
- if (providerInfo == null) {
- receiver.send(RESULT_CODE_PROVIDER_NOT_FOUND, null);
- return;
- }
- } catch (PackageManager.NameNotFoundException e) {
- receiver.send(RESULT_CODE_PROVIDER_NOT_FOUND, null);
- return;
+ synchronized (mLock) {
+ mInQueueSet.remove(id);
}
- FontInfo[] fonts;
try {
- fonts = getFontFromProvider(mContext, request, providerInfo.authority,
- null /* cancellation signal */);
- } catch (InvalidFormatException e) {
- receiver.send(RESULT_CODE_PROVIDER_NOT_FOUND, null);
- return;
- }
-
- ArrayList<FontResult> result = new ArrayList<>();
- int resultCode = -1;
- for (FontInfo font : fonts) {
- try {
- resultCode = font.getResultCode();
- if (resultCode != Columns.RESULT_CODE_OK) {
- if (resultCode < 0) {
- // Negative values are reserved for the internal errors.
- resultCode = Columns.RESULT_CODE_FONT_NOT_FOUND;
- }
- for (int i = 0; i < result.size(); ++i) {
- try {
- result.get(i).getFileDescriptor().close();
- } catch (IOException e) {
- // Ignore, as we are closing fds for cleanup.
- }
- }
- receiver.send(resultCode, null);
- return;
+ FontFamilyResult result = fetchFonts(mContext, null, request);
+ if (result.getStatusCode() == FontFamilyResult.STATUS_OK) {
+ Typeface typeface = buildTypeface(mContext, null, result.getFonts());
+ if (typeface != null) {
+ sTypefaceCache.put(id, typeface);
}
- ParcelFileDescriptor pfd = mContext.getContentResolver().openFileDescriptor(
- font.getUri(), "r");
- result.add(new FontResult(pfd, font.getTtcIndex(),
- FontVariationAxis.toFontVariationSettings(font.getAxes()),
- font.getWeight(), font.isItalic()));
- } catch (FileNotFoundException e) {
- Log.e(TAG, "FileNotFoundException raised when interacting with content "
- + "provider " + providerInfo.authority, e);
}
+ } catch (NameNotFoundException e) {
+ // Ignore.
}
- if (!result.isEmpty()) {
- Bundle bundle = new Bundle();
- bundle.putParcelableArrayList(PARCEL_FONT_RESULTS, result);
- receiver.send(Columns.RESULT_CODE_OK, bundle);
- return;
- }
- receiver.send(Columns.RESULT_CODE_FONT_NOT_FOUND, null);
});
mHandler.removeCallbacks(mReplaceDispatcherThreadRunnable);
mHandler.postDelayed(mReplaceDispatcherThreadRunnable, THREAD_RENEWAL_THRESHOLD_MS);
}
+ return null;
}
/**
@@ -452,16 +428,14 @@
public FontRequestCallback() {}
/**
- * Called then a Typeface request done via {@link Typeface#create(FontRequest,
- * FontRequestCallback)} is complete. Note that this method will not be called if
- * {@link #onTypefaceRequestFailed(int)} is called instead.
+ * Called then a Typeface request done via {@link #requestFont} is complete. Note that this
+ * method will not be called if {@link #onTypefaceRequestFailed(int)} is called instead.
* @param typeface The Typeface object retrieved.
*/
public void onTypefaceRetrieved(Typeface typeface) {}
/**
- * Called when a Typeface request done via {@link Typeface#create(FontRequest,
- * FontRequestCallback)} fails.
+ * Called when a Typeface request done via {@link #requestFont}} fails.
* @param reason One of {@link #FAIL_REASON_PROVIDER_NOT_FOUND},
* {@link #FAIL_REASON_FONT_NOT_FOUND},
* {@link #FAIL_REASON_FONT_LOAD_ERROR},
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 0884480..69371be 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1398,6 +1398,26 @@
public static final String ACTION_ENTERPRISE_PRIVACY_SETTINGS
= "android.settings.ENTERPRISE_PRIVACY_SETTINGS";
+ /**
+ * Activity Action: Show screen that let user select its Autofill Service.
+ * <p>
+ * Input: Intent's data URI set with an application name, using the
+ * "package" schema (like "package:com.my.app").
+ *
+ * <p>
+ * Output: {@link android.app.Activity#RESULT_OK} if user selected an Autofill Service belonging
+ * to the caller package.
+ *
+ * <p>
+ * <b>NOTE: </b> applications should call
+ * {@link android.view.autofill.AutofillManager#hasEnabledAutofillServices()} and
+ * {@link android.view.autofill.AutofillManager#isAutofillSupported()} first, and only
+ * broadcast this intent if they return {@code false} and {@code true} respectively.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_REQUEST_SET_AUTOFILL_SERVICE =
+ "android.settings.REQUEST_SET_AUTOFILL_SERVICE";
+
// End of Intent actions for Settings
/**
@@ -5555,76 +5575,6 @@
"high_text_contrast_enabled";
/**
- * If injection of accessibility enhancing JavaScript screen-reader
- * is enabled.
- * <p>
- * Note: The JavaScript based screen-reader is served by the
- * Google infrastructure and enable users with disabilities to
- * efficiently navigate in and explore web content.
- * </p>
- * <p>
- * This property represents a boolean value.
- * </p>
- * @hide
- */
- public static final String ACCESSIBILITY_SCRIPT_INJECTION =
- "accessibility_script_injection";
-
- /**
- * The URL for the injected JavaScript based screen-reader used
- * for providing accessibility of content in WebView.
- * <p>
- * Note: The JavaScript based screen-reader is served by the
- * Google infrastructure and enable users with disabilities to
- * efficiently navigate in and explore web content.
- * </p>
- * <p>
- * This property represents a string value.
- * </p>
- * @hide
- */
- public static final String ACCESSIBILITY_SCREEN_READER_URL =
- "accessibility_script_injection_url";
-
- /**
- * Key bindings for navigation in built-in accessibility support for web content.
- * <p>
- * Note: These key bindings are for the built-in accessibility navigation for
- * web content which is used as a fall back solution if JavaScript in a WebView
- * is not enabled or the user has not opted-in script injection from Google.
- * </p>
- * <p>
- * The bindings are separated by semi-colon. A binding is a mapping from
- * a key to a sequence of actions (for more details look at
- * android.webkit.AccessibilityInjector). A key is represented as the hexademical
- * string representation of an integer obtained from a meta state (optional) shifted
- * sixteen times left and bitwise ored with a key code. An action is represented
- * as a hexademical string representation of an integer where the first two digits
- * are navigation action index, the second, the third, and the fourth digit pairs
- * represent the action arguments. The separate actions in a binding are colon
- * separated. The key and the action sequence it maps to are separated by equals.
- * </p>
- * <p>
- * For example, the binding below maps the DPAD right button to traverse the
- * current navigation axis once without firing an accessibility event and to
- * perform the same traversal again but to fire an event:
- * <code>
- * 0x16=0x01000100:0x01000101;
- * </code>
- * </p>
- * <p>
- * The goal of this binding is to enable dynamic rebinding of keys to
- * navigation actions for web content without requiring a framework change.
- * </p>
- * <p>
- * This property represents a string value.
- * </p>
- * @hide
- */
- public static final String ACCESSIBILITY_WEB_CONTENT_KEY_BINDINGS =
- "accessibility_web_content_key_bindings";
-
- /**
* Setting that specifies whether the display magnification is enabled via a system-wide
* triple tap gesture. Display magnifications allows the user to zoom in the display content
* and is targeted to low vision users. The current magnification scale is controlled by
@@ -6994,8 +6944,6 @@
ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED,
ACCESSIBILITY_DISPLAY_MAGNIFICATION_NAVBAR_ENABLED,
ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE,
- ACCESSIBILITY_SCRIPT_INJECTION,
- ACCESSIBILITY_WEB_CONTENT_KEY_BINDINGS,
ENABLED_ACCESSIBILITY_SERVICES,
ENABLED_NOTIFICATION_LISTENERS,
ENABLED_VR_LISTENERS,
@@ -8352,16 +8300,6 @@
"network_recommendations_package";
/**
- * Value to specify if the Wi-Fi Framework should defer to
- * {@link com.android.server.NetworkScoreService} for evaluating saved open networks.
- *
- * Type: int (0 for false, 1 for true)
- * @hide
- */
- @SystemApi
- public static final String CURATE_SAVED_OPEN_NETWORKS = "curate_saved_open_networks";
-
- /**
* The package name of the application that connect and secures high quality open wifi
* networks automatically.
*
@@ -8376,6 +8314,7 @@
*
* Type: long
* @hide
+ * @deprecated to be removed
*/
public static final String NETWORK_RECOMMENDATION_REQUEST_TIMEOUT_MS =
"network_recommendation_request_timeout_ms";
@@ -9877,7 +9816,6 @@
CHARGING_SOUNDS_ENABLED,
USB_MASS_STORAGE_ENABLED,
NETWORK_RECOMMENDATIONS_ENABLED,
- CURATE_SAVED_OPEN_NETWORKS,
WIFI_WAKEUP_ENABLED,
WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
USE_OPEN_WIFI_PACKAGE,
diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java
index 813c54f..cb47c10 100644
--- a/core/java/android/service/autofill/AutofillService.java
+++ b/core/java/android/service/autofill/AutofillService.java
@@ -36,9 +36,6 @@
import java.util.List;
-//TODO(b/33197203): improve javadoc (of both class and methods); in particular, make sure the
-//life-cycle (and how state could be maintained on server-side) is well documented.
-
/**
* Top-level service of the current autofill service for a given user.
*
@@ -50,19 +47,6 @@
/**
* The {@link Intent} that must be declared as handled by the service.
* To be supported, the service must also require the
- * {@link android.Manifest.permission#BIND_AUTO_FILL} permission so
- * that other applications can not abuse it.
- *
- * @hide
- * @deprecated TODO(b/35956626): remove once clients use AutofillService
- */
- @Deprecated
- @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
- public static final String OLD_SERVICE_INTERFACE = "android.service.autofill.AutoFillService";
-
- /**
- * The {@link Intent} that must be declared as handled by the service.
- * To be supported, the service must also require the
* {@link android.Manifest.permission#BIND_AUTOFILL} permission so
* that other applications can not abuse it.
*/
@@ -82,18 +66,12 @@
*/
public static final String SERVICE_META_DATA = "android.autofill";
- // Internal extras
- /** @hide */
- public static final String EXTRA_SESSION_ID = "android.service.autofill.extra.SESSION_ID";
-
// Handler messages.
private static final int MSG_CONNECT = 1;
private static final int MSG_DISCONNECT = 2;
private static final int MSG_ON_FILL_REQUEST = 3;
private static final int MSG_ON_SAVE_REQUEST = 4;
- private static final int UNUSED_ARG = -1;
-
private final IAutoFillService mInterface = new IAutoFillService.Stub() {
@Override
public void onConnectedStateChanged(boolean connected) {
@@ -136,7 +114,13 @@
final IFillCallback callback = (IFillCallback) args.arg3;
final FillCallback fillCallback = new FillCallback(callback, request.getId());
args.recycle();
- onFillRequest(request, cancellation, fillCallback);
+ // TODO(b/37563972): temporary try-catch hack to support old method
+ try {
+ onFillRequest(request, cancellation, fillCallback);
+ } catch (AbstractMethodError e) {
+ onFillRequest(request.getStructure(), request.getClientState(),
+ request.getFlags(), cancellation, fillCallback);
+ }
break;
} case MSG_ON_SAVE_REQUEST: {
final SomeArgs args = (SomeArgs) msg.obj;
@@ -144,7 +128,14 @@
final ISaveCallback callback = (ISaveCallback) args.arg2;
final SaveCallback saveCallback = new SaveCallback(callback);
args.recycle();
- onSaveRequest(request, saveCallback);
+ // TODO(b/37563972): temporary try-catch hack to support old method
+ try {
+ onSaveRequest(request, saveCallback);
+ } catch (AbstractMethodError e) {
+ final List<FillContext> contexts = request.getFillContexts();
+ onSaveRequest(contexts.get(contexts.size() - 1).getStructure(),
+ request.getClientState(), saveCallback);
+ }
break;
} case MSG_DISCONNECT: {
onDisconnected();
@@ -170,8 +161,7 @@
@Override
public final IBinder onBind(Intent intent) {
- if (SERVICE_INTERFACE.equals(intent.getAction())
- || OLD_SERVICE_INTERFACE.equals(intent.getAction())) {
+ if (SERVICE_INTERFACE.equals(intent.getAction())) {
return mInterface.asBinder();
}
Log.w(TAG, "Tried to bind to wrong intent: " + intent);
@@ -202,11 +192,8 @@
* handling this fill request in order to save resources.
* @param callback object used to notify the result of the request.
*/
- public void onFillRequest(@NonNull FillRequest request,
- @NonNull CancellationSignal cancellationSignal, @NonNull FillCallback callback) {
- onFillRequest(request.getStructure(), request.getClientState(), request.getFlags(),
- cancellationSignal, callback);
- }
+ public abstract void onFillRequest(@NonNull FillRequest request,
+ @NonNull CancellationSignal cancellationSignal, @NonNull FillCallback callback);
/**
* Called by the Android system do decide if an {@link Activity} can be autofilled by the
@@ -229,6 +216,8 @@
* this to notify you that the fill result is no longer needed and you should stop
* handling this fill request in order to save resources.
* @param callback object used to notify the result of the request.
+ *
+ * @hide
*/
@Deprecated
public abstract void onFillRequest(@NonNull AssistStructure structure, @Nullable Bundle data,
@@ -246,11 +235,8 @@
* See {@link FillResponse} for examples of multiple-sections requests.
* @param callback object used to notify the result of the request.
*/
- public void onSaveRequest(@NonNull SaveRequest request, @NonNull SaveCallback callback) {
- final List<FillContext> contexts = request.getFillContexts();
- onSaveRequest(contexts.get(contexts.size() - 1).getStructure(),
- request.getClientState(), callback);
- }
+ public abstract void onSaveRequest(@NonNull SaveRequest request,
+ @NonNull SaveCallback callback);
/**
* Called when user requests service to save the fields of an {@link Activity}.
@@ -267,6 +253,8 @@
* conserve resources.
* See {@link FillResponse} for examples of multiple-sections requests.
* @param callback object used to notify the result of the request.
+ *
+ * @hide
*/
@Deprecated
public abstract void onSaveRequest(@NonNull AssistStructure structure, @Nullable Bundle data,
@@ -280,9 +268,9 @@
public void onDisconnected() {
}
+ /** @hide */
@Deprecated
public final void disableSelf() {
- // TODO(b/33197203): Remove when GCore has migrated off this API
getSystemService(AutofillManager.class).disableOwnedAutofillServices();
}
diff --git a/core/java/android/service/autofill/FillRequest.java b/core/java/android/service/autofill/FillRequest.java
index aa6db4d..49f348c 100644
--- a/core/java/android/service/autofill/FillRequest.java
+++ b/core/java/android/service/autofill/FillRequest.java
@@ -39,8 +39,6 @@
* @see AutofillService#onFillRequest(FillRequest, CancellationSignal, FillCallback)
*/
public final class FillRequest implements Parcelable {
- private static AtomicInteger sIdCounter = new AtomicInteger();
-
/**
* Indicates autofill was explicitly requested by the user.
*/
@@ -58,12 +56,6 @@
private final @NonNull AssistStructure mStructure;
private final @Nullable Bundle mClientState;
- /** @hide */
- public FillRequest(@NonNull AssistStructure structure,
- @Nullable Bundle clientState, @RequestFlags int flags) {
- this(sIdCounter.incrementAndGet(), structure, clientState, flags);
- }
-
private FillRequest(@NonNull Parcel parcel) {
mId = parcel.readInt();
mStructure = parcel.readParcelable(null);
@@ -71,7 +63,8 @@
mFlags = parcel.readInt();
}
- private FillRequest(int id, @NonNull AssistStructure structure,
+ /** @hide */
+ public FillRequest(int id, @NonNull AssistStructure structure,
@Nullable Bundle clientState, @RequestFlags int flags) {
mId = id;
mFlags = Preconditions.checkFlagsArgument(flags, FLAG_MANUAL_REQUEST);
diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java
index 68ce0b5..2afb1f4 100644
--- a/core/java/android/service/autofill/FillResponse.java
+++ b/core/java/android/service/autofill/FillResponse.java
@@ -242,7 +242,7 @@
public @NonNull Builder setAuthentication(@NonNull AutofillId[] ids,
@Nullable IntentSender authentication, @Nullable RemoteViews presentation) {
throwIfDestroyed();
- // TODO(b/33197203): assert ids is not null nor empty once old version is removed
+ // TODO(b/37424539): assert ids is not null nor empty once old version is removed
if (authentication == null ^ presentation == null) {
throw new IllegalArgumentException("authentication and presentation"
+ " must be both non-null or null");
@@ -254,7 +254,7 @@
}
/**
- * TODO(b/33197203): will be removed once clients use the version that takes ids
+ * TODO(b/37424539): will be removed once clients use the version that takes ids
* @hide
* @deprecated
*/
@@ -311,6 +311,7 @@
/**
* @deprecated Use {@link #setClientState(Bundle)} instead.
+ * @hide
*/
@Deprecated
public Builder setExtras(@Nullable Bundle extras) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index bcf0b90..d42c6db 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -7381,17 +7381,20 @@
* optimal implementation providing this data.
*/
public void onProvideVirtualStructure(ViewStructure structure) {
- onProvideVirtualStructureForAssistOrAutofill(structure, false);
+ AccessibilityNodeProvider provider = getAccessibilityNodeProvider();
+ if (provider != null) {
+ AccessibilityNodeInfo info = createAccessibilityNodeInfo();
+ structure.setChildCount(1);
+ ViewStructure root = structure.newChild(0);
+ populateVirtualStructure(root, provider, info);
+ info.recycle();
+ }
}
/**
* Called when assist structure is being retrieved from a view as part of an autofill request
* to generate additional virtual structure under this view.
*
- * <p>The default implementation uses {@link #getAccessibilityNodeProvider()} to try to
- * generate this from the view's virtual accessibility nodes, if any. You can override this
- * for a more optimal implementation providing this data.
- *
* <p>When implementing this method, subclasses must follow the rules below:
*
* <ol>
@@ -7415,27 +7418,10 @@
* @param flags optional flags (currently {@code 0}).
*/
public void onProvideAutofillVirtualStructure(ViewStructure structure, int flags) {
- onProvideVirtualStructureForAssistOrAutofill(structure, true);
- }
-
- private void onProvideVirtualStructureForAssistOrAutofill(ViewStructure structure,
- boolean forAutofill) {
- if (forAutofill) {
- setAutofillId(structure);
- }
- // NOTE: currently flags are only used for AutoFill; if they're used for Assist as well,
- // this method should take a boolean with the type of request.
- AccessibilityNodeProvider provider = getAccessibilityNodeProvider();
- if (provider != null) {
- AccessibilityNodeInfo info = createAccessibilityNodeInfo();
- structure.setChildCount(1);
- ViewStructure root = structure.newChild(0);
- if (forAutofill) {
- setAutofillId(root);
- }
- populateVirtualStructure(root, provider, info, forAutofill);
- info.recycle();
- }
+ // TODO(b/36171235): need a way to let apps set the ViewStructure without forcing them
+ // to call super() (in case they override both this method and dispatchProvide....
+ // Perhaps the best solution would simply make setAutofillId(ViewStructure) public.
+ setAutofillId(structure);
}
/**
@@ -7652,7 +7638,7 @@
}
private void populateVirtualStructure(ViewStructure structure,
- AccessibilityNodeProvider provider, AccessibilityNodeInfo info, boolean forAutofill) {
+ AccessibilityNodeProvider provider, AccessibilityNodeInfo info) {
structure.setId(AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()),
null, null, null);
Rect rect = structure.getTempRect();
@@ -7690,10 +7676,7 @@
CharSequence cname = info.getClassName();
structure.setClassName(cname != null ? cname.toString() : null);
structure.setContentDescription(info.getContentDescription());
- if (!forAutofill && (info.getText() != null || info.getError() != null)) {
- // TODO(b/33197203) (b/33269702): when sanitized, try to use the Accessibility API to
- // just set sanitized values (like text coming from resource files), rather than not
- // setting it at all.
+ if ((info.getText() != null || info.getError() != null)) {
structure.setText(info.getText(), info.getTextSelectionStart(),
info.getTextSelectionEnd());
}
@@ -7704,12 +7687,7 @@
AccessibilityNodeInfo cinfo = provider.createAccessibilityNodeInfo(
AccessibilityNodeInfo.getVirtualDescendantId(info.getChildId(i)));
ViewStructure child = structure.newChild(i);
- if (forAutofill) {
- // TODO(b/33197203): add CTS test to autofill virtual children based on
- // Accessibility API.
- child.setAutofillId(structure, i);
- }
- populateVirtualStructure(child, provider, cinfo, forAutofill);
+ populateVirtualStructure(child, provider, cinfo);
cinfo.recycle();
}
}
@@ -9598,13 +9576,10 @@
*
* @return Returns {@code false} if assist data collection for autofill is not blocked,
* else {@code true}.
- *
- * TODO(b/33197203): update / remove javadoc tags below
- * @see #setAssistBlocked(boolean)
- * @attr ref android.R.styleable#View_assistBlocked
*/
public boolean isAutofillBlocked() {
- return false; // TODO(b/33197203): properly implement it
+ // TODO(b/36171235): properly implement it using isImportantForAutofill()
+ return false;
}
/**
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 9ecced6..1f13220 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -435,8 +435,9 @@
AccessibilityInteractionController mAccessibilityInteractionController;
- AccessibilityInteractionConnectionManager mAccessibilityInteractionConnectionManager;
- HighContrastTextManager mHighContrastTextManager;
+ final AccessibilityInteractionConnectionManager mAccessibilityInteractionConnectionManager =
+ new AccessibilityInteractionConnectionManager();
+ final HighContrastTextManager mHighContrastTextManager;
SendWindowContentChangedAccessibilityEvent mSendWindowContentChangedAccessibilityEvent;
@@ -496,13 +497,11 @@
mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this,
context);
mAccessibilityManager = AccessibilityManager.getInstance(context);
- mAccessibilityInteractionConnectionManager =
- new AccessibilityInteractionConnectionManager();
mAccessibilityManager.addAccessibilityStateChangeListener(
- mAccessibilityInteractionConnectionManager);
+ mAccessibilityInteractionConnectionManager, mHandler);
mHighContrastTextManager = new HighContrastTextManager();
mAccessibilityManager.addHighTextContrastStateChangeListener(
- mHighContrastTextManager);
+ mHighContrastTextManager, mHandler);
mViewConfiguration = ViewConfiguration.get(context);
mDensity = context.getResources().getDisplayMetrics().densityDpi;
mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi;
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 6c884c4..dfb0095 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -37,6 +37,7 @@
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.util.ArrayMap;
import android.util.Log;
import android.view.IWindow;
import android.view.View;
@@ -47,7 +48,6 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
/**
* System level service that serves as an event dispatch for {@link AccessibilityEvent}s,
@@ -137,17 +137,18 @@
boolean mIsHighTextContrastEnabled;
- private final CopyOnWriteArrayList<AccessibilityStateChangeListener>
- mAccessibilityStateChangeListeners = new CopyOnWriteArrayList<>();
+ private final ArrayMap<AccessibilityStateChangeListener, Handler>
+ mAccessibilityStateChangeListeners = new ArrayMap<>();
- private final CopyOnWriteArrayList<TouchExplorationStateChangeListener>
- mTouchExplorationStateChangeListeners = new CopyOnWriteArrayList<>();
+ private final ArrayMap<TouchExplorationStateChangeListener, Handler>
+ mTouchExplorationStateChangeListeners = new ArrayMap<>();
- private final CopyOnWriteArrayList<HighTextContrastChangeListener>
- mHighTextContrastStateChangeListeners = new CopyOnWriteArrayList<>();
+ private final ArrayMap<HighTextContrastChangeListener, Handler>
+ mHighTextContrastStateChangeListeners = new ArrayMap<>();
- private final CopyOnWriteArrayList<AccessibilityServicesStateChangeListener>
- mServicesStateChangeListeners = new CopyOnWriteArrayList<>();
+ private final ArrayMap<AccessibilityServicesStateChangeListener, Handler>
+ mServicesStateChangeListeners = new ArrayMap<>();
+
/**
* Listener for the system accessibility state. To listen for changes to the
* accessibility state on the device, implement this interface and register
@@ -229,7 +230,21 @@
@Override
public void notifyServicesStateChanged() {
- mHandler.obtainMessage(MyCallback.MSG_NOTIFY_SERVICES_STATE_CHANGED).sendToTarget();
+ final ArrayMap<AccessibilityServicesStateChangeListener, Handler> listeners;
+ synchronized (mLock) {
+ if (mServicesStateChangeListeners.isEmpty()) {
+ return;
+ }
+ listeners = new ArrayMap<>(mServicesStateChangeListeners);
+ }
+
+ int numListeners = listeners.size();
+ for (int i = 0; i < numListeners; i++) {
+ final AccessibilityServicesStateChangeListener listener =
+ mServicesStateChangeListeners.keyAt(i);
+ mServicesStateChangeListeners.valueAt(i).post(() -> listener
+ .onAccessibilityServicesStateChanged(AccessibilityManager.this));
+ }
}
@Override
@@ -565,73 +580,118 @@
/**
* Registers an {@link AccessibilityStateChangeListener} for changes in
- * the global accessibility state of the system.
+ * the global accessibility state of the system. Equivalent to calling
+ * {@link #addAccessibilityStateChangeListener(AccessibilityStateChangeListener, Handler)}
+ * with a null handler.
*
* @param listener The listener.
- * @return True if successfully registered.
+ * @return Always returns {@code true}.
*/
public boolean addAccessibilityStateChangeListener(
@NonNull AccessibilityStateChangeListener listener) {
- // Final CopyOnWriteArrayList - no lock needed.
- return mAccessibilityStateChangeListeners.add(listener);
+ addAccessibilityStateChangeListener(listener, null);
+ return true;
+ }
+
+ /**
+ * Registers an {@link AccessibilityStateChangeListener} for changes in
+ * the global accessibility state of the system. If the listener has already been registered,
+ * the handler used to call it back is updated.
+ *
+ * @param listener The listener.
+ * @param handler The handler on which the listener should be called back, or {@code null}
+ * for a callback on the process's main handler.
+ */
+ public void addAccessibilityStateChangeListener(
+ @NonNull AccessibilityStateChangeListener listener, @Nullable Handler handler) {
+ synchronized (mLock) {
+ mAccessibilityStateChangeListeners
+ .put(listener, (handler == null) ? mHandler : handler);
+ }
}
/**
* Unregisters an {@link AccessibilityStateChangeListener}.
*
* @param listener The listener.
- * @return True if successfully unregistered.
+ * @return True if the listener was previously registered.
*/
public boolean removeAccessibilityStateChangeListener(
@NonNull AccessibilityStateChangeListener listener) {
- // Final CopyOnWriteArrayList - no lock needed.
- return mAccessibilityStateChangeListeners.remove(listener);
+ synchronized (mLock) {
+ int index = mAccessibilityStateChangeListeners.indexOfKey(listener);
+ mAccessibilityStateChangeListeners.remove(listener);
+ return (index >= 0);
+ }
}
/**
* Registers a {@link TouchExplorationStateChangeListener} for changes in
- * the global touch exploration state of the system.
+ * the global touch exploration state of the system. Equivalent to calling
+ * {@link #addTouchExplorationStateChangeListener(TouchExplorationStateChangeListener, Handler)}
+ * with a null handler.
*
* @param listener The listener.
- * @return True if successfully registered.
+ * @return Always returns {@code true}.
*/
public boolean addTouchExplorationStateChangeListener(
@NonNull TouchExplorationStateChangeListener listener) {
- // Final CopyOnWriteArrayList - no lock needed.
- return mTouchExplorationStateChangeListeners.add(listener);
+ addTouchExplorationStateChangeListener(listener, null);
+ return true;
+ }
+
+ /**
+ * Registers an {@link TouchExplorationStateChangeListener} for changes in
+ * the global touch exploration state of the system. If the listener has already been
+ * registered, the handler used to call it back is updated.
+ *
+ * @param listener The listener.
+ * @param handler The handler on which the listener should be called back, or {@code null}
+ * for a callback on the process's main handler.
+ */
+ public void addTouchExplorationStateChangeListener(
+ @NonNull TouchExplorationStateChangeListener listener, @Nullable Handler handler) {
+ synchronized (mLock) {
+ mTouchExplorationStateChangeListeners
+ .put(listener, (handler == null) ? mHandler : handler);
+ }
}
/**
* Unregisters a {@link TouchExplorationStateChangeListener}.
*
* @param listener The listener.
- * @return True if successfully unregistered.
+ * @return True if listener was previously registered.
*/
public boolean removeTouchExplorationStateChangeListener(
@NonNull TouchExplorationStateChangeListener listener) {
- // Final CopyOnWriteArrayList - no lock needed.
- return mTouchExplorationStateChangeListeners.remove(listener);
+ synchronized (mLock) {
+ int index = mTouchExplorationStateChangeListeners.indexOfKey(listener);
+ mTouchExplorationStateChangeListeners.remove(listener);
+ return (index >= 0);
+ }
}
/**
* Registers a {@link AccessibilityServicesStateChangeListener}.
*
* @param listener The listener.
- * @return True if successfully registered.
- *
+ * @param handler The handler on which the listener should be called back, or {@code null}
+ * for a callback on the process's main handler.
* @hide
*/
public void addAccessibilityServicesStateChangeListener(
- @NonNull AccessibilityServicesStateChangeListener listener) {
- // Final CopyOnWriteArrayList - no lock needed.
- mServicesStateChangeListeners.add(listener);
+ @NonNull AccessibilityServicesStateChangeListener listener, @Nullable Handler handler) {
+ synchronized (mLock) {
+ mServicesStateChangeListeners
+ .put(listener, (handler == null) ? mHandler : handler);
+ }
}
/**
* Unregisters a {@link AccessibilityServicesStateChangeListener}.
*
* @param listener The listener.
- * @return True if successfully unregistered.
*
* @hide
*/
@@ -646,28 +706,29 @@
* the global high text contrast state of the system.
*
* @param listener The listener.
- * @return True if successfully registered.
*
* @hide
*/
- public boolean addHighTextContrastStateChangeListener(
- @NonNull HighTextContrastChangeListener listener) {
- // Final CopyOnWriteArrayList - no lock needed.
- return mHighTextContrastStateChangeListeners.add(listener);
+ public void addHighTextContrastStateChangeListener(
+ @NonNull HighTextContrastChangeListener listener, @Nullable Handler handler) {
+ synchronized (mLock) {
+ mHighTextContrastStateChangeListeners
+ .put(listener, (handler == null) ? mHandler : handler);
+ }
}
/**
* Unregisters a {@link HighTextContrastChangeListener}.
*
* @param listener The listener.
- * @return True if successfully unregistered.
*
* @hide
*/
- public boolean removeHighTextContrastStateChangeListener(
+ public void removeHighTextContrastStateChangeListener(
@NonNull HighTextContrastChangeListener listener) {
- // Final CopyOnWriteArrayList - no lock needed.
- return mHighTextContrastStateChangeListeners.remove(listener);
+ synchronized (mLock) {
+ mHighTextContrastStateChangeListeners.remove(listener);
+ }
}
/**
@@ -732,15 +793,15 @@
mIsHighTextContrastEnabled = highTextContrastEnabled;
if (wasEnabled != enabled) {
- mHandler.sendEmptyMessage(MyCallback.MSG_NOTIFY_ACCESSIBILITY_STATE_CHANGED);
+ notifyAccessibilityStateChanged();
}
if (wasTouchExplorationEnabled != touchExplorationEnabled) {
- mHandler.sendEmptyMessage(MyCallback.MSG_NOTIFY_EXPLORATION_STATE_CHANGED);
+ notifyTouchExplorationStateChanged();
}
if (wasHighTextContrastEnabled != highTextContrastEnabled) {
- mHandler.sendEmptyMessage(MyCallback.MSG_NOTIFY_HIGH_TEXT_CONTRAST_STATE_CHANGED);
+ notifyHighTextContrastStateChanged();
}
}
@@ -932,81 +993,78 @@
/**
* Notifies the registered {@link AccessibilityStateChangeListener}s.
*/
- private void handleNotifyAccessibilityStateChanged() {
+ private void notifyAccessibilityStateChanged() {
final boolean isEnabled;
+ final ArrayMap<AccessibilityStateChangeListener, Handler> listeners;
synchronized (mLock) {
+ if (mAccessibilityStateChangeListeners.isEmpty()) {
+ return;
+ }
isEnabled = mIsEnabled;
+ listeners = new ArrayMap<>(mAccessibilityStateChangeListeners);
}
- // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
- for (AccessibilityStateChangeListener listener : mAccessibilityStateChangeListeners) {
- listener.onAccessibilityStateChanged(isEnabled);
+
+ int numListeners = listeners.size();
+ for (int i = 0; i < numListeners; i++) {
+ final AccessibilityStateChangeListener listener =
+ mAccessibilityStateChangeListeners.keyAt(i);
+ mAccessibilityStateChangeListeners.valueAt(i)
+ .post(() -> listener.onAccessibilityStateChanged(isEnabled));
}
}
/**
* Notifies the registered {@link TouchExplorationStateChangeListener}s.
*/
- private void handleNotifyTouchExplorationStateChanged() {
+ private void notifyTouchExplorationStateChanged() {
final boolean isTouchExplorationEnabled;
+ final ArrayMap<TouchExplorationStateChangeListener, Handler> listeners;
synchronized (mLock) {
+ if (mTouchExplorationStateChangeListeners.isEmpty()) {
+ return;
+ }
isTouchExplorationEnabled = mIsTouchExplorationEnabled;
+ listeners = new ArrayMap<>(mTouchExplorationStateChangeListeners);
}
- // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
- for (TouchExplorationStateChangeListener listener :mTouchExplorationStateChangeListeners) {
- listener.onTouchExplorationStateChanged(isTouchExplorationEnabled);
+
+ int numListeners = listeners.size();
+ for (int i = 0; i < numListeners; i++) {
+ final TouchExplorationStateChangeListener listener =
+ mTouchExplorationStateChangeListeners.keyAt(i);
+ mTouchExplorationStateChangeListeners.valueAt(i)
+ .post(() -> listener.onTouchExplorationStateChanged(isTouchExplorationEnabled));
}
}
/**
* Notifies the registered {@link HighTextContrastChangeListener}s.
*/
- private void handleNotifyHighTextContrastStateChanged() {
+ private void notifyHighTextContrastStateChanged() {
final boolean isHighTextContrastEnabled;
+ final ArrayMap<HighTextContrastChangeListener, Handler> listeners;
synchronized (mLock) {
+ if (mHighTextContrastStateChangeListeners.isEmpty()) {
+ return;
+ }
isHighTextContrastEnabled = mIsHighTextContrastEnabled;
+ listeners = new ArrayMap<>(mHighTextContrastStateChangeListeners);
}
- // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
- for (HighTextContrastChangeListener listener : mHighTextContrastStateChangeListeners) {
- listener.onHighTextContrastStateChanged(isHighTextContrastEnabled);
- }
- }
- /**
- * Notifies the registered {@link AccessibilityServicesStateChangeListener}s.
- */
- private void handleNotifyServicesStateChanged() {
- // Listeners are a final CopyOnWriteArrayList, hence no lock needed.
- for (AccessibilityServicesStateChangeListener listener : mServicesStateChangeListeners) {
- listener.onAccessibilityServicesStateChanged(this);
+ int numListeners = listeners.size();
+ for (int i = 0; i < numListeners; i++) {
+ final HighTextContrastChangeListener listener =
+ mHighTextContrastStateChangeListeners.keyAt(i);
+ mHighTextContrastStateChangeListeners.valueAt(i)
+ .post(() -> listener.onHighTextContrastStateChanged(isHighTextContrastEnabled));
}
}
private final class MyCallback implements Handler.Callback {
- public static final int MSG_NOTIFY_ACCESSIBILITY_STATE_CHANGED = 1;
- public static final int MSG_NOTIFY_EXPLORATION_STATE_CHANGED = 2;
- public static final int MSG_NOTIFY_HIGH_TEXT_CONTRAST_STATE_CHANGED = 3;
- public static final int MSG_SET_STATE = 4;
- public static final int MSG_NOTIFY_SERVICES_STATE_CHANGED = 5;
+ public static final int MSG_SET_STATE = 1;
@Override
public boolean handleMessage(Message message) {
switch (message.what) {
- case MSG_NOTIFY_ACCESSIBILITY_STATE_CHANGED: {
- handleNotifyAccessibilityStateChanged();
- } break;
-
- case MSG_NOTIFY_EXPLORATION_STATE_CHANGED: {
- handleNotifyTouchExplorationStateChanged();
- } break;
-
- case MSG_NOTIFY_HIGH_TEXT_CONTRAST_STATE_CHANGED: {
- handleNotifyHighTextContrastStateChanged();
- } break;
-
- case MSG_NOTIFY_SERVICES_STATE_CHANGED: {
- handleNotifyServicesStateChanged();
- } break;
-
case MSG_SET_STATE: {
// See comment at mClient
final int state = message.arg1;
diff --git a/core/java/android/view/autofill/AutofillId.java b/core/java/android/view/autofill/AutofillId.java
index d678015..268f7f3 100644
--- a/core/java/android/view/autofill/AutofillId.java
+++ b/core/java/android/view/autofill/AutofillId.java
@@ -30,7 +30,6 @@
private final boolean mVirtual;
private final int mVirtualId;
- // TODO(b/33197203): use factory and cache values, since they're immutable
/** @hide */
public AutofillId(int id) {
mVirtual = false;
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 981be21..caf188d 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -51,12 +51,10 @@
import java.util.Objects;
/**
- * App entry point to the AutoFill Framework.
+ * App entry point to the Autofill Framework.
*
* <p>It is safe to call into this from any thread.
*/
-// TODO(b/33197203): improve this javadoc
-//TODO(b/33197203): restrict manager calls to activity
public final class AutofillManager {
private static final String TAG = "AutofillManager";
@@ -101,17 +99,15 @@
static final String SESSION_ID_TAG = "android:sessionId";
static final String LAST_AUTOFILLED_DATA_TAG = "android:lastAutoFilledData";
- // Public flags start from the lowest bit
/**
- * Indicates autofill was explicitly requested by the user.
- *
* @deprecated Use {@link android.service.autofill.FillRequest#FLAG_MANUAL_REQUEST}
+ * @hide
*/
- // TODO(b/33197203): remove (and change value of private flags)
+ // TODO(b/37563972): remove (and change value of private flags)
@Deprecated
public static final int FLAG_MANUAL_REQUEST = 0x1;
- // Private flags start from the highest bit
+ // TODO(b/37563972): start from 0x1 once FLAG_MANUAL_REQUEST is gone
/** @hide */ public static final int FLAG_START_SESSION = 0x80000000;
/** @hide */ public static final int FLAG_VIEW_ENTERED = 0x40000000;
/** @hide */ public static final int FLAG_VIEW_EXITED = 0x20000000;
@@ -663,6 +659,39 @@
}
}
+ /**
+ * Returns {@code true} if the calling application provides a {@link AutofillService} that is
+ * enabled for the current user, or {@code false} otherwise.
+ */
+ public boolean hasEnabledAutofillServices() {
+ if (mService == null) return false;
+
+ try {
+ return mService.isServiceEnabled(mContext.getUserId(), mContext.getPackageName());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns {@code true} if Autofill is supported for this user.
+ *
+ * <p>Autofill is typically supported, but it could be unsupported in cases like:
+ * <ol>
+ * <li>Low-end devices.
+ * <li>Device policy rules that forbid its usage.
+ * </ol>
+ */
+ public boolean isAutofillSupported() {
+ if (mService == null) return false;
+
+ try {
+ return mService.isServiceSupported(mContext.getUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
private AutofillClient getClientLocked() {
if (mContext instanceof AutofillClient) {
return (AutofillClient) mContext;
@@ -675,7 +704,7 @@
if (!hasAutofillFeature()) {
return;
}
- // TODO(b/33197203): the result code is being ignored, so this method is not reliably
+ // TODO: 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
// service set the extra and returned RESULT_CANCELED...
@@ -1323,8 +1352,6 @@
@Override
public void autofill(int sessionId, IBinder windowToken, List<AutofillId> ids,
List<AutofillValue> values) {
- // TODO(b/33197203): must keep the dataset so subsequent calls pass the same
- // dataset.extras to service
final AutofillManager afm = mAfm.get();
if (afm != null) {
afm.mContext.getMainThreadHandler().post(
diff --git a/core/java/android/view/autofill/AutofillValue.java b/core/java/android/view/autofill/AutofillValue.java
index e2dd7fe..b1a9d90 100644
--- a/core/java/android/view/autofill/AutofillValue.java
+++ b/core/java/android/view/autofill/AutofillValue.java
@@ -252,7 +252,6 @@
*
* <p>See {@link View#AUTOFILL_TYPE_TEXT} for more info.
*/
- // TODO(b/33197203): use cache
public static AutofillValue forText(@Nullable CharSequence value) {
return value == null ? null : new AutofillValue(AUTOFILL_TYPE_TEXT, value);
}
diff --git a/core/java/android/view/autofill/Helper.java b/core/java/android/view/autofill/Helper.java
index aa94de0..2b25ae7 100644
--- a/core/java/android/view/autofill/Helper.java
+++ b/core/java/android/view/autofill/Helper.java
@@ -25,7 +25,8 @@
/** @hide */
public final class Helper {
- public static final boolean DEBUG = true; // TODO(b/33197203): set to false when stable
+ // TODO(b/36141126): set to false and remove guard from places that should always be on
+ public static final boolean DEBUG = true;
public static final boolean VERBOSE = false;
public static final String REDACTED = "[REDACTED]";
diff --git a/core/java/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl
index df777c4..9417bd0 100644
--- a/core/java/android/view/autofill/IAutoFillManager.aidl
+++ b/core/java/android/view/autofill/IAutoFillManager.aidl
@@ -44,4 +44,6 @@
void setAuthenticationResult(in Bundle data, int sessionId, int userId);
void setHasCallback(int sessionId, int userId, boolean hasIt);
void disableOwnedAutofillServices(int userId);
+ boolean isServiceSupported(int userId);
+ boolean isServiceEnabled(int userId, String packageName);
}
diff --git a/core/java/android/webkit/WebViewZygote.java b/core/java/android/webkit/WebViewZygote.java
index 2123deb..b519ec9 100644
--- a/core/java/android/webkit/WebViewZygote.java
+++ b/core/java/android/webkit/WebViewZygote.java
@@ -40,6 +40,7 @@
private static final String WEBVIEW_ZYGOTE_SERVICE_32 = "webview_zygote32";
private static final String WEBVIEW_ZYGOTE_SERVICE_64 = "webview_zygote64";
+ private static final String WEBVIEW_ZYGOTE_SOCKET = "webview_zygote";
/**
* Lock object that protects all other static members.
@@ -202,7 +203,7 @@
}
try {
- sZygote = new ZygoteProcess("webview_zygote", null);
+ sZygote = new ZygoteProcess(WEBVIEW_ZYGOTE_SOCKET, null);
// All the work below is usually done by LoadedApk, but the zygote can't talk to
// PackageManager or construct a LoadedApk since it's single-threaded pre-fork, so
@@ -217,6 +218,8 @@
final String zip = (zipPaths.size() == 1) ? zipPaths.get(0) :
TextUtils.join(File.pathSeparator, zipPaths);
+ waitForZygote();
+
Log.d(LOGTAG, "Preloading package " + zip + " " + librarySearchPath);
sZygote.preloadPackageForAbi(zip, librarySearchPath, sPackageCacheKey,
Build.SUPPORTED_ABIS[0]);
@@ -225,4 +228,25 @@
sZygote = null;
}
}
+
+ /**
+ * Wait until a connection to the Zygote can be established.
+ */
+ private static void waitForZygote() {
+ while (true) {
+ try {
+ final ZygoteProcess.ZygoteState zs =
+ ZygoteProcess.ZygoteState.connect(WEBVIEW_ZYGOTE_SOCKET);
+ zs.close();
+ break;
+ } catch (IOException ioe) {
+ Log.w(LOGTAG, "Got error connecting to zygote, retrying. msg= " + ioe.getMessage());
+ }
+
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException ie) {
+ }
+ }
+ }
}
diff --git a/core/java/android/widget/AbsSpinner.java b/core/java/android/widget/AbsSpinner.java
index f80c9e6..816c949 100644
--- a/core/java/android/widget/AbsSpinner.java
+++ b/core/java/android/widget/AbsSpinner.java
@@ -491,8 +491,6 @@
return AbsSpinner.class.getName();
}
- // TODO(b/33197203): add unit/CTS tests for auto-fill methods (and make sure they handle enable)
-
@Override
public void autofill(AutofillValue value) {
if (!isEnabled()) return;
diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java
index c7ba7b5..0762b15 100644
--- a/core/java/android/widget/CompoundButton.java
+++ b/core/java/android/widget/CompoundButton.java
@@ -574,8 +574,6 @@
stream.addProperty("checked", isChecked());
}
- // TODO(b/33197203): add unit/CTS tests for autofill methods (and make sure they handle enable)
-
@Override
public void onProvideAutofillStructure(ViewStructure structure, int flags) {
super.onProvideAutofillStructure(structure, flags);
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index 463ff58..0dce079 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -764,8 +764,6 @@
void onValidationChanged(boolean valid);
}
- // TODO(b/33197203): add unit/CTS tests for autofill methods (and make sure they handle enable)
-
@Override
public void dispatchProvideAutofillStructure(ViewStructure structure, int flags) {
// This view is self-sufficient for autofill, so it needs to call
diff --git a/core/java/android/widget/RadioGroup.java b/core/java/android/widget/RadioGroup.java
index 08e6575..5c4d4d2 100644
--- a/core/java/android/widget/RadioGroup.java
+++ b/core/java/android/widget/RadioGroup.java
@@ -417,8 +417,6 @@
}
}
- // TODO(b/33197203): add unit/CTS tests for autofill methods (and make sure they handle enable)
-
@Override
public void onProvideAutofillStructure(ViewStructure structure, int flags) {
super.onProvideAutofillStructure(structure, flags);
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 036b391..e534233 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -413,6 +413,30 @@
recalculateMemoryUsage();
}
+ private static class RemoteViewsContextWrapper extends ContextWrapper {
+ private final Context mContextForResources;
+
+ RemoteViewsContextWrapper(Context context, Context contextForResources) {
+ super(context);
+ mContextForResources = contextForResources;
+ }
+
+ @Override
+ public Resources getResources() {
+ return mContextForResources.getResources();
+ }
+
+ @Override
+ public Resources.Theme getTheme() {
+ return mContextForResources.getTheme();
+ }
+
+ @Override
+ public String getPackageName() {
+ return mContextForResources.getPackageName();
+ }
+ }
+
private class SetEmptyView extends Action {
int viewId;
int emptyViewId;
@@ -3240,20 +3264,7 @@
// still returns the current users userId so settings like data / time formats
// are loaded without requiring cross user persmissions.
final Context contextForResources = getContextForResources(context);
- Context inflationContext = new ContextWrapper(context) {
- @Override
- public Resources getResources() {
- return contextForResources.getResources();
- }
- @Override
- public Resources.Theme getTheme() {
- return contextForResources.getTheme();
- }
- @Override
- public String getPackageName() {
- return contextForResources.getPackageName();
- }
- };
+ Context inflationContext = new RemoteViewsContextWrapper(context, contextForResources);
LayoutInflater inflater = (LayoutInflater)
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
diff --git a/core/java/android/widget/SimpleAdapter.java b/core/java/android/widget/SimpleAdapter.java
index 57e2ece..9190117 100644
--- a/core/java/android/widget/SimpleAdapter.java
+++ b/core/java/android/widget/SimpleAdapter.java
@@ -320,9 +320,6 @@
return mFilter;
}
- // TODO(b/33197203): implement getAutofillOptions
-
-
/**
* This class can be used by external clients of SimpleAdapter to bind
* values to views.
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index f42d6c8..399cfac 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -10170,8 +10170,6 @@
structure.setInputType(getInputType());
}
- // TODO(b/33197203): add unit/CTS tests for autofill methods
-
boolean canRequestAutofill() {
final AutofillManager afm = mContext.getSystemService(AutofillManager.class);
if (afm != null) {
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index fb00c4392..df99fb4 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -519,8 +519,6 @@
}
}
- // TODO(b/33197203): add unit/CTS tests for autofill methods (and make sure they handle enable)
-
@Override
public void dispatchProvideAutofillStructure(ViewStructure structure, int flags) {
// This view is self-sufficient for autofill, so it needs to call
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index 2c8e4e0..73886a7 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -169,6 +169,13 @@
}
/**
+ * Length of the given array or 0 if it's null.
+ */
+ public static int size(@Nullable Object[] array) {
+ return array == null ? 0 : array.length;
+ }
+
+ /**
* Checks that value is present as at least one of the elements of the array.
* @param array the array to check in
* @param value the value to check for
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 96285cd..ceb3cc8 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -234,6 +234,7 @@
libseccomp_policy \
libselinux \
libcrypto \
+ libgrallocusage \
LOCAL_SHARED_LIBRARIES := \
libmemtrack \
diff --git a/core/jni/android_hardware_HardwareBuffer.cpp b/core/jni/android_hardware_HardwareBuffer.cpp
index ed0ab60..4b31c91 100644
--- a/core/jni/android_hardware_HardwareBuffer.cpp
+++ b/core/jni/android_hardware_HardwareBuffer.cpp
@@ -34,6 +34,7 @@
#include <private/gui/ComposerService.h>
#include <hardware/gralloc1.h>
+#include <grallocusage/GrallocUsageConversion.h>
#include "core_jni_helpers.h"
@@ -85,7 +86,7 @@
&producerUsage, &consumerUsage, usage, 0);
sp<GraphicBuffer> buffer = new GraphicBuffer(width, height, pixelFormat, layers,
- producerUsage, consumerUsage,
+ android_convertGralloc1To0Usage(producerUsage, consumerUsage),
std::string("HardwareBuffer pid [") + std::to_string(getpid()) +"]");
status_t error = buffer->initCheck();
if (error < 0) {
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index b95258b..6000fb5 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -685,11 +685,14 @@
// Grant CAP_WAKE_ALARM to the Bluetooth process.
// Additionally, allow bluetooth to open packet sockets so it can start the DHCP client.
+ // Grant CAP_SYS_NICE to allow Bluetooth to set RT priority for
+ // audio-related threads.
// TODO: consider making such functionality an RPC to netd.
if (multiuser_get_app_id(uid) == AID_BLUETOOTH) {
capabilities |= (1LL << CAP_WAKE_ALARM);
capabilities |= (1LL << CAP_NET_RAW);
capabilities |= (1LL << CAP_NET_BIND_SERVICE);
+ capabilities |= (1LL << CAP_SYS_NICE);
}
// Grant CAP_BLOCK_SUSPEND to processes that belong to GID "wakelock"
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 6e790a7..3e11368 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3426,7 +3426,9 @@
<flag name="flagIncludeNotImportantViews" value="0x00000002" />
<!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE}. -->
<flag name="flagRequestTouchExplorationMode" value="0x00000004" />
- <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY}. -->
+ <!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY}.
+ Not used by the framework.
+ -->
<flag name="flagRequestEnhancedWebAccessibility" value="0x00000008" />
<!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_REPORT_VIEW_IDS}. -->
<flag name="flagReportViewIds" value="0x00000010" />
@@ -3457,12 +3459,8 @@
-->
<attr name="canRequestTouchExplorationMode" format="boolean" />
<!-- Attribute whether the accessibility service wants to be able to request enhanced
- web accessibility enhancements. For example, installing scripts to make app
- content more accessible.
- <p>
- Required to allow setting the {@link android.accessibilityservice
- #AccessibilityServiceInfo#FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY} flag.
- </p>
+ web accessibility enhancements.
+ {@deprecated Not used by the framework}
-->
<attr name="canRequestEnhancedWebAccessibility" format="boolean" />
<!-- Attribute whether the accessibility service wants to be able to request to
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index a5181fe..35b12ff 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -713,13 +713,6 @@
<string name="capability_desc_canRequestTouchExploration">Tapped items will be spoken aloud
and the screen can be explored using gestures.</string>
- <!-- Title for the capability of an accessibility service to request enhanced web accessibility. -->
- <string name="capability_title_canRequestEnhancedWebAccessibility">Turn on enhanced web
- accessibility</string>
- <!-- Description for the capability of an accessibility service to request enhanced web accessibility. -->
- <string name="capability_desc_canRequestEnhancedWebAccessibility">Scripts may be installed to
- make app content more accessible.</string>
-
<!-- Title for the capability of an accessibility service to request to filter key events. -->
<string name="capability_title_canRequestFilterKeyEvents">Observe text you type</string>
<!-- Description for the capability of an accessibility service to request to filter key events. -->
diff --git a/core/tests/coretests/src/android/net/NetworkRecommendationProviderTest.java b/core/tests/coretests/src/android/net/NetworkRecommendationProviderTest.java
index 497bc5c..ff9816a 100644
--- a/core/tests/coretests/src/android/net/NetworkRecommendationProviderTest.java
+++ b/core/tests/coretests/src/android/net/NetworkRecommendationProviderTest.java
@@ -1,26 +1,19 @@
package android.net;
-import static android.net.NetworkRecommendationProvider.EXTRA_RECOMMENDATION_RESULT;
-import static android.net.NetworkRecommendationProvider.EXTRA_SEQUENCE;
-
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertSame;
import static junit.framework.Assert.fail;
-import static junit.framework.TestCase.assertEquals;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import android.Manifest.permission;
import android.content.Context;
-import android.os.Bundle;
-import android.os.IRemoteCallback;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
@@ -35,11 +28,9 @@
*/
@RunWith(AndroidJUnit4.class)
public class NetworkRecommendationProviderTest {
- @Mock private IRemoteCallback mMockRemoteCallback;
@Mock private Context mContext;
private NetworkRecProvider mRecProvider;
private INetworkRecommendationProvider mStub;
- private CountDownLatch mRecRequestLatch;
private CountDownLatch mScoreRequestLatch;
private NetworkKey[] mTestNetworkKeys;
@@ -48,10 +39,8 @@
MockitoAnnotations.initMocks(this);
Executor executor = Executors.newSingleThreadExecutor();
- mRecRequestLatch = new CountDownLatch(1);
mScoreRequestLatch = new CountDownLatch(1);
- mRecProvider = new NetworkRecProvider(mContext, executor, mRecRequestLatch,
- mScoreRequestLatch);
+ mRecProvider = new NetworkRecProvider(mContext, executor, mScoreRequestLatch);
mStub = INetworkRecommendationProvider.Stub.asInterface(mRecProvider.getBinder());
mTestNetworkKeys = new NetworkKey[2];
mTestNetworkKeys[0] = new NetworkKey(new WifiKey("\"ssid_01\"", "00:00:00:00:00:11"));
@@ -59,69 +48,6 @@
}
@Test
- public void testRecommendationRequestReceived() throws Exception {
- final RecommendationRequest request = new RecommendationRequest.Builder().build();
- final int sequence = 100;
- mStub.requestRecommendation(request, mMockRemoteCallback, sequence);
-
- // wait for onRequestRecommendation() to be called in our impl below.
- mRecRequestLatch.await(200, TimeUnit.MILLISECONDS);
- NetworkRecommendationProvider.ResultCallback expectedResultCallback =
- new NetworkRecommendationProvider.ResultCallback(mMockRemoteCallback, sequence);
- assertEquals(request, mRecProvider.mCapturedRequest);
- assertEquals(expectedResultCallback, mRecProvider.mCapturedCallback);
- }
-
- @Test
- public void testRecommendationRequest_permissionsEnforced() throws Exception {
- final RecommendationRequest request = new RecommendationRequest.Builder().build();
- final int sequence = 100;
- Mockito.doThrow(new SecurityException())
- .when(mContext)
- .enforceCallingOrSelfPermission(eq(permission.REQUEST_NETWORK_SCORES), anyString());
-
- try {
- mStub.requestRecommendation(request, mMockRemoteCallback, sequence);
- fail("SecurityException expected.");
- } catch (SecurityException e) {
- // expected
- }
- }
-
- @Test
- public void testResultCallbackOnResult() throws Exception {
- final int sequence = 100;
- final NetworkRecommendationProvider.ResultCallback callback =
- new NetworkRecommendationProvider.ResultCallback(mMockRemoteCallback, sequence);
-
- final RecommendationResult result = RecommendationResult.createDoNotConnectRecommendation();
- callback.onResult(result);
-
- final ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
- Mockito.verify(mMockRemoteCallback).sendResult(bundleCaptor.capture());
- Bundle capturedBundle = bundleCaptor.getValue();
- assertEquals(sequence, capturedBundle.getInt(EXTRA_SEQUENCE));
- assertSame(result, capturedBundle.getParcelable(EXTRA_RECOMMENDATION_RESULT));
- }
-
- @Test
- public void testResultCallbackOnResult_runTwice_throwsException() throws Exception {
- final int sequence = 100;
- final NetworkRecommendationProvider.ResultCallback callback =
- new NetworkRecommendationProvider.ResultCallback(mMockRemoteCallback, sequence);
-
- final RecommendationResult result = RecommendationResult.createDoNotConnectRecommendation();
- callback.onResult(result);
-
- try {
- callback.onResult(result);
- fail("Callback ran more than once.");
- } catch (IllegalStateException e) {
- // expected
- }
- }
-
- @Test
public void testScoreRequestReceived() throws Exception {
mStub.requestScores(mTestNetworkKeys);
@@ -162,28 +88,15 @@
}
private static class NetworkRecProvider extends NetworkRecommendationProvider {
- private final CountDownLatch mRecRequestLatch;
private final CountDownLatch mScoreRequestLatch;
- RecommendationRequest mCapturedRequest;
- ResultCallback mCapturedCallback;
NetworkKey[] mCapturedNetworks;
- NetworkRecProvider(Context context, Executor executor, CountDownLatch recRequestLatch,
- CountDownLatch networkRequestLatch) {
+ NetworkRecProvider(Context context, Executor executor, CountDownLatch networkRequestLatch) {
super(context, executor);
- mRecRequestLatch = recRequestLatch;
mScoreRequestLatch = networkRequestLatch;
}
@Override
- public void onRequestRecommendation(RecommendationRequest request,
- ResultCallback callback) {
- mCapturedRequest = request;
- mCapturedCallback = callback;
- mRecRequestLatch.countDown();
- }
-
- @Override
public void onRequestScores(NetworkKey[] networks) {
mCapturedNetworks = networks;
mScoreRequestLatch.countDown();
diff --git a/core/tests/coretests/src/android/net/RecommendationRequestTest.java b/core/tests/coretests/src/android/net/RecommendationRequestTest.java
deleted file mode 100644
index e2e6883..0000000
--- a/core/tests/coretests/src/android/net/RecommendationRequestTest.java
+++ /dev/null
@@ -1,116 +0,0 @@
-package android.net;
-
-import android.net.wifi.ScanResult;
-import android.net.wifi.WifiConfiguration;
-import android.os.Parcel;
-import android.os.SystemClock;
-import android.test.AndroidTestCase;
-
-public class RecommendationRequestTest extends AndroidTestCase {
- private ScanResult[] mScanResults;
- private WifiConfiguration mDefaultConfig;
- private WifiConfiguration mConnectedConfig;
- private WifiConfiguration[] mConnectableConfigs;
- private int mLastSelectedNetworkId;
- private long mLastSelectedNetworkTimestamp;
-
- @Override
- public void setUp() throws Exception {
- mScanResults = new ScanResult[2];
- mScanResults[0] = new ScanResult();
- mScanResults[1] = new ScanResult(
- "ssid",
- "bssid",
- 0L /*hessid*/,
- 1 /*anqpDominId*/,
- "caps",
- 2 /*level*/,
- 3 /*frequency*/,
- 4L /*tsf*/,
- 5 /*distCm*/,
- 6 /*distSdCm*/,
- 7 /*channelWidth*/,
- 8 /*centerFreq0*/,
- 9 /*centerFreq1*/,
- false /*is80211McRTTResponder*/);
- mDefaultConfig = new WifiConfiguration();
- mDefaultConfig.SSID = "default_config";
- mConnectedConfig = new WifiConfiguration();
- mConnectedConfig.SSID = "connected_config";
- mConnectableConfigs = new WifiConfiguration[] {mDefaultConfig, mConnectedConfig};
- mLastSelectedNetworkId = 5;
- mLastSelectedNetworkTimestamp = SystemClock.elapsedRealtime();
- }
-
- public void testParceling() throws Exception {
- RecommendationRequest request = new RecommendationRequest.Builder()
- .setDefaultWifiConfig(mDefaultConfig)
- .setScanResults(mScanResults)
- .setConnectedWifiConfig(mConnectedConfig)
- .setConnectableConfigs(mConnectableConfigs)
- .setLastSelectedNetwork(mLastSelectedNetworkId, mLastSelectedNetworkTimestamp)
- .build();
-
- RecommendationRequest parceled = passThroughParcel(request);
- assertEquals(request.getDefaultWifiConfig().SSID,
- parceled.getDefaultWifiConfig().SSID);
- assertEquals(request.getConnectedConfig().SSID,
- parceled.getConnectedConfig().SSID);
- ScanResult[] parceledScanResults = parceled.getScanResults();
- assertNotNull(parceledScanResults);
- assertEquals(mScanResults.length, parceledScanResults.length);
- for (int i = 0; i < mScanResults.length; i++) {
- assertEquals(mScanResults[i].SSID, parceledScanResults[i].SSID);
- }
- WifiConfiguration[] parceledConfigs = parceled.getConnectableConfigs();
- for (int i = 0; i < parceledConfigs.length; i++) {
- assertEquals(mConnectableConfigs[i].SSID, parceledConfigs[i].SSID);
- }
- assertEquals(mLastSelectedNetworkId, parceled.getLastSelectedNetworkId());
- assertEquals(mLastSelectedNetworkTimestamp, parceled.getLastSelectedNetworkTimestamp());
- }
-
- public void testParceling_nullScanResults() throws Exception {
- RecommendationRequest request = new RecommendationRequest.Builder()
- .setDefaultWifiConfig(mDefaultConfig)
- .build();
-
- RecommendationRequest parceled = passThroughParcel(request);
- ScanResult[] parceledScanResults = parceled.getScanResults();
- assertNull(parceledScanResults);
- }
-
- public void testParceling_nullWifiConfigArray() throws Exception {
- RecommendationRequest request = new RecommendationRequest.Builder()
- .setDefaultWifiConfig(mDefaultConfig)
- .build();
-
- RecommendationRequest parceled = passThroughParcel(request);
- WifiConfiguration[] parceledConfigs = parceled.getConnectableConfigs();
- assertNull(parceledConfigs);
- }
-
- public void testParceling_unsetLastSelectedNetwork() throws Exception {
- RecommendationRequest request = new RecommendationRequest.Builder()
- .build();
-
- RecommendationRequest parceled = passThroughParcel(request);
-
- assertEquals(-1, parceled.getLastSelectedNetworkId());
- assertEquals(0, parceled.getLastSelectedNetworkTimestamp());
- }
-
- private RecommendationRequest passThroughParcel(RecommendationRequest request) {
- Parcel p = Parcel.obtain();
- RecommendationRequest output = null;
- try {
- request.writeToParcel(p, 0);
- p.setDataPosition(0);
- output = RecommendationRequest.CREATOR.createFromParcel(p);
- } finally {
- p.recycle();
- }
- assertNotNull(output);
- return output;
- }
-}
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index d7887d3..38ab865 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -376,7 +376,6 @@
private static final Set<String> BACKUP_BLACKLISTED_SECURE_SETTINGS =
newHashSet(
- Settings.Secure.ACCESSIBILITY_SCREEN_READER_URL,
Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
Settings.Secure.ALLOWED_GEOLOCATION_ORIGINS,
Settings.Secure.ALWAYS_ON_VPN_APP,
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 86ab3dc..344f3c8 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -181,9 +181,6 @@
<allow-in-power-save package="com.android.cellbroadcastreceiver" />
<allow-in-power-save package="com.android.shell" />
- <!-- STOPSHIP(b/36856786): Revert this once it is fixed properly -->
- <allow-in-power-save package="com.google.android.apps.enterprise.dmagent" />
-
<!-- These are the packages that are white-listed to be able to run as system user -->
<system-user-whitelisted-app package="com.android.settings" />
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 115c77f..42fd5d8 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -31,7 +31,6 @@
import android.content.res.AssetManager;
import android.graphics.FontListParser;
import android.graphics.fonts.FontRequest;
-import android.graphics.fonts.FontResult;
import android.graphics.fonts.FontVariationAxis;
import android.graphics.fonts.FontVariationAxis.InvalidFormatException;
import android.net.Uri;
@@ -102,8 +101,6 @@
new LongSparseArray<>(3);
@GuardedBy("sLock")
private static FontsContract sFontsContract;
- @GuardedBy("sLock")
- private static Handler sHandler;
/**
* Cache for Typeface objects dynamically loaded from assets. Currently max size is 16.
@@ -205,16 +202,9 @@
public static Typeface createFromResources(
FamilyResourceEntry entry, AssetManager mgr, String path) {
if (sFallbackFonts != null) {
- Typeface typeface = findFromCache(mgr, path);
- if (typeface != null) return typeface;
-
if (entry instanceof ProviderResourceEntry) {
final ProviderResourceEntry providerEntry = (ProviderResourceEntry) entry;
// Downloadable font
- typeface = findFromCache(providerEntry.getAuthority(), providerEntry.getQuery());
- if (typeface != null) {
- return typeface;
- }
List<List<String>> givenCerts = providerEntry.getCerts();
List<List<byte[]>> certs = new ArrayList<>();
if (givenCerts != null) {
@@ -229,11 +219,15 @@
}
// Downloaded font and it wasn't cached, request it again and return a
// default font instead (nothing we can do now).
- create(new FontRequest(providerEntry.getAuthority(), providerEntry.getPackage(),
- providerEntry.getQuery(), certs), NO_OP_REQUEST_CALLBACK);
- return DEFAULT;
+ FontRequest request = new FontRequest(providerEntry.getAuthority(),
+ providerEntry.getPackage(), providerEntry.getQuery(), certs);
+ Typeface typeface = sFontsContract.getFontOrWarmUpCache(request);
+ return typeface == null ? DEFAULT : typeface;
}
+ Typeface typeface = findFromCache(mgr, path);
+ if (typeface != null) return typeface;
+
// family is FontFamilyFilesResourceEntry
final FontFamilyFilesResourceEntry filesEntry =
(FontFamilyFilesResourceEntry) entry;
@@ -291,215 +285,11 @@
synchronized (sLock) {
if (sFontsContract == null) {
sFontsContract = new FontsContract(context);
- sHandler = new Handler();
}
}
}
/**
- * Create a typeface object given a font request. The font will be asynchronously fetched,
- * therefore the result is delivered to the given callback. See {@link FontRequest}.
- * Only one of the methods in callback will be invoked, depending on whether the request
- * succeeds or fails. These calls will happen on the main thread.
- * @param request A {@link FontRequest} object that identifies the provider and query for the
- * request. May not be null.
- * @param callback A callback that will be triggered when results are obtained. May not be null.
- */
- @Deprecated
- public static void create(@NonNull FontRequest request, @NonNull FontRequestCallback callback) {
- // Check the cache first
- // TODO: would the developer want to avoid a cache hit and always ask for the freshest
- // result?
- Typeface cachedTypeface = findFromCache(
- request.getProviderAuthority(), request.getQuery());
- if (cachedTypeface != null) {
- sHandler.post(() -> callback.onTypefaceRetrieved(cachedTypeface));
- return;
- }
- synchronized (sLock) {
- if (sFontsContract == null) {
- throw new RuntimeException("Context not initialized, can't query provider");
- }
- final ResultReceiver receiver = new ResultReceiver(null) {
- @Override
- public void onReceiveResult(int resultCode, Bundle resultData) {
- sHandler.post(() -> receiveResult(request, callback, resultCode, resultData));
- }
- };
- sFontsContract.getFont(request, receiver);
- }
- }
-
- private static Typeface findFromCache(String providerAuthority, String query) {
- synchronized (sDynamicTypefaceCache) {
- final String key = createProviderUid(providerAuthority, query);
- Typeface typeface = sDynamicTypefaceCache.get(key);
- if (typeface != null) {
- return typeface;
- }
- }
- return null;
- }
-
- private static void receiveResult(FontRequest request, FontRequestCallback callback,
- int resultCode, Bundle resultData) {
- Typeface cachedTypeface = findFromCache(
- request.getProviderAuthority(), request.getQuery());
- if (cachedTypeface != null) {
- // We already know the result.
- // Probably the requester requests the same font again in a short interval.
- callback.onTypefaceRetrieved(cachedTypeface);
- return;
- }
- if (resultCode != FontsContract.Columns.RESULT_CODE_OK) {
- callback.onTypefaceRequestFailed(resultCode);
- return;
- }
- if (resultData == null) {
- callback.onTypefaceRequestFailed(
- FontRequestCallback.FAIL_REASON_FONT_NOT_FOUND);
- return;
- }
- List<FontResult> resultList =
- resultData.getParcelableArrayList(FontsContract.PARCEL_FONT_RESULTS);
- if (resultList == null || resultList.isEmpty()) {
- callback.onTypefaceRequestFailed(
- FontRequestCallback.FAIL_REASON_FONT_NOT_FOUND);
- return;
- }
- FontFamily fontFamily = new FontFamily();
- for (int i = 0; i < resultList.size(); ++i) {
- FontResult result = resultList.get(i);
- ParcelFileDescriptor fd = result.getFileDescriptor();
- if (fd == null) {
- callback.onTypefaceRequestFailed(
- FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR);
- return;
- }
- try (FileInputStream is = new FileInputStream(fd.getFileDescriptor())) {
- FileChannel fileChannel = is.getChannel();
- long fontSize = fileChannel.size();
- ByteBuffer fontBuffer = fileChannel.map(
- FileChannel.MapMode.READ_ONLY, 0, fontSize);
- int weight = result.getWeight();
- int italic = result.getItalic() ? STYLE_ITALIC : STYLE_NORMAL;
- FontVariationAxis[] axes = null;
- try {
- axes = FontVariationAxis.fromFontVariationSettings(
- result.getFontVariationSettings());
- } catch (FontVariationAxis.InvalidFormatException e) {
- // TODO: Nice to pass FontVariationAxis[] directly instead of string.
- }
- if (!fontFamily.addFontFromBuffer(fontBuffer, result.getTtcIndex(),
- axes, weight, italic)) {
- Log.e(TAG, "Error creating font " + request.getQuery());
- callback.onTypefaceRequestFailed(
- FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR);
- return;
- }
- } catch (IOException e) {
- Log.e(TAG, "Error reading font " + request.getQuery(), e);
- callback.onTypefaceRequestFailed(
- FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR);
- return;
- } finally {
- IoUtils.closeQuietly(fd);
- }
- }
- if (!fontFamily.freeze()) {
- callback.onTypefaceRequestFailed(
- FontRequestCallback.FAIL_REASON_FONT_LOAD_ERROR);
- return;
- }
- Typeface typeface = Typeface.createFromFamiliesWithDefault(
- new FontFamily[] { fontFamily },
- RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE);
- synchronized (sDynamicTypefaceCache) {
- String key = createProviderUid(request.getProviderAuthority(), request.getQuery());
- sDynamicTypefaceCache.put(key, typeface);
- }
- callback.onTypefaceRetrieved(typeface);
- }
-
- /**
- * Interface used to receive asynchronously fetched typefaces.
- */
- @Deprecated
- public interface FontRequestCallback {
- /**
- * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the given
- * provider was not found on the device.
- */
- int FAIL_REASON_PROVIDER_NOT_FOUND = FontsContract.RESULT_CODE_PROVIDER_NOT_FOUND;
- /**
- * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the given
- * provider must be authenticated and the given certificates do not match its signature.
- */
- int FAIL_REASON_WRONG_CERTIFICATES = FontsContract.RESULT_CODE_WRONG_CERTIFICATES;
- /**
- * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the font
- * returned by the provider was not loaded properly.
- */
- int FAIL_REASON_FONT_LOAD_ERROR = -3;
- /**
- * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the font
- * provider did not return any results for the given query.
- */
- int FAIL_REASON_FONT_NOT_FOUND = FontsContract.Columns.RESULT_CODE_FONT_NOT_FOUND;
- /**
- * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the font
- * provider found the queried font, but it is currently unavailable.
- */
- int FAIL_REASON_FONT_UNAVAILABLE = FontsContract.Columns.RESULT_CODE_FONT_UNAVAILABLE;
- /**
- * Constant returned by {@link #onTypefaceRequestFailed(int)} signaling that the given
- * query was not supported by the provider.
- */
- int FAIL_REASON_MALFORMED_QUERY = FontsContract.Columns.RESULT_CODE_MALFORMED_QUERY;
-
- /** @hide */
- @IntDef({ FAIL_REASON_PROVIDER_NOT_FOUND, FAIL_REASON_FONT_LOAD_ERROR,
- FAIL_REASON_FONT_NOT_FOUND, FAIL_REASON_FONT_UNAVAILABLE,
- FAIL_REASON_MALFORMED_QUERY })
- @Retention(RetentionPolicy.SOURCE)
- @interface FontRequestFailReason {}
-
- /**
- * Called then a Typeface request done via {@link Typeface#create(FontRequest,
- * FontRequestCallback)} is complete. Note that this method will not be called if
- * {@link #onTypefaceRequestFailed(int)} is called instead.
- * @param typeface The Typeface object retrieved.
- */
- void onTypefaceRetrieved(Typeface typeface);
-
- /**
- * Called when a Typeface request done via {@link Typeface#create(FontRequest,
- * FontRequestCallback)} fails.
- * @param reason May be one of {@link #FAIL_REASON_PROVIDER_NOT_FOUND},
- * {@link #FAIL_REASON_FONT_NOT_FOUND},
- * {@link #FAIL_REASON_FONT_LOAD_ERROR},
- * {@link #FAIL_REASON_FONT_UNAVAILABLE} or
- * {@link #FAIL_REASON_MALFORMED_QUERY} if returned by the system. May also be
- * a positive value greater than 0 defined by the font provider as an
- * additional error code. Refer to the provider's documentation for more
- * information on possible returned error codes.
- */
- void onTypefaceRequestFailed(@FontRequestFailReason int reason);
- }
-
- private static final FontRequestCallback NO_OP_REQUEST_CALLBACK = new FontRequestCallback() {
- @Override
- public void onTypefaceRetrieved(Typeface typeface) {
- // Do nothing.
- }
-
- @Override
- public void onTypefaceRequestFailed(@FontRequestFailReason int reason) {
- // Do nothing.
- }
- };
-
- /**
* A builder class for creating new Typeface instance.
*
* <p>
diff --git a/graphics/java/android/graphics/fonts/FontResult.java b/graphics/java/android/graphics/fonts/FontResult.java
deleted file mode 100644
index 20e736e..0000000
--- a/graphics/java/android/graphics/fonts/FontResult.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * 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 android.graphics.fonts;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.graphics.Paint;
-import android.os.Parcel;
-import android.os.ParcelFileDescriptor;
-import android.os.Parcelable;
-
-import com.android.internal.util.Preconditions;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-
-/**
- * Results returned from a Font Provider to the system.
- * @hide
- */
-public final class FontResult implements Parcelable {
- private final ParcelFileDescriptor mFileDescriptor;
- private final int mTtcIndex;
- private final String mFontVariationSettings;
- private final int mWeight;
- private final boolean mItalic;
-
- /**
- * Creates a FontResult with all the information needed about a provided font.
- * @param fileDescriptor A ParcelFileDescriptor pointing to the font file. This shoult point to
- * a real file or shared memory, as the client will mmap the given file
- * descriptor. Pipes, sockets and other non-mmap-able file descriptors
- * will fail to load in the client application.
- * @param ttcIndex If providing a TTC_INDEX file, the index to point to. Otherwise, 0.
- * @param fontVariationSettings If providing a variation font, the settings for it. May be null.
- * @param weight An integer that indicates the font weight.
- * @param italic A boolean that indicates the font is italic style or not.
- */
- public FontResult(@NonNull ParcelFileDescriptor fileDescriptor, int ttcIndex,
- @Nullable String fontVariationSettings, int weight, boolean italic) {
- mFileDescriptor = Preconditions.checkNotNull(fileDescriptor);
- mTtcIndex = ttcIndex;
- mFontVariationSettings = fontVariationSettings;
- mWeight = weight;
- mItalic = italic;
- }
-
- public ParcelFileDescriptor getFileDescriptor() {
- return mFileDescriptor;
- }
-
- public int getTtcIndex() {
- return mTtcIndex;
- }
-
- public String getFontVariationSettings() {
- return mFontVariationSettings;
- }
-
- public int getWeight() {
- return mWeight;
- }
-
- public boolean getItalic() {
- return mItalic;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeParcelable(mFileDescriptor, flags);
- dest.writeInt(mTtcIndex);
- dest.writeString(mFontVariationSettings);
- dest.writeInt(mWeight);
- dest.writeBoolean(mItalic);
- }
-
- private FontResult(Parcel in) {
- mFileDescriptor = in.readParcelable(null);
- mTtcIndex = in.readInt();
- mFontVariationSettings = in.readString();
- mWeight = in.readInt();
- mItalic = in.readBoolean();
- }
-
- public static final Parcelable.Creator<FontResult> CREATOR =
- new Parcelable.Creator<FontResult>() {
- @Override
- public FontResult createFromParcel(Parcel in) {
- return new FontResult(in);
- }
-
- @Override
- public FontResult[] newArray(int size) {
- return new FontResult[size];
- }
- };
-}
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 00d786a..244d6e5 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -93,6 +93,16 @@
*/
public static final int FLAG_ENCRYPTED = 1;
+ /**
+ * A private flag that's only available to system server to indicate that this key is part of
+ * device encryption flow so it receives special treatment from keystore. For example this key
+ * will not be super encrypted, and it will be stored separately under an unique UID instead
+ * of the caller UID i.e. SYSTEM.
+ *
+ * Need to be in sync with KeyStoreFlag in system/security/keystore/include/keystore/keystore.h
+ */
+ public static final int FLAG_CRITICAL_TO_DEVICE_ENCRYPTION = 1 << 3;
+
// States
public enum State { UNLOCKED, LOCKED, UNINITIALIZED };
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
index 64b10ab..bab4010 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
@@ -351,6 +351,9 @@
}
} else if (param instanceof KeyProtection) {
spec = (KeyProtection) param;
+ if (spec.isCriticalToDeviceEncryption()) {
+ flags |= KeyStore.FLAG_CRITICAL_TO_DEVICE_ENCRYPTION;
+ }
} else {
throw new KeyStoreException(
"Unsupported protection parameter class:" + param.getClass().getName()
@@ -719,6 +722,10 @@
} catch (IllegalArgumentException | IllegalStateException e) {
throw new KeyStoreException(e);
}
+ int flags = 0;
+ if (params.isCriticalToDeviceEncryption()) {
+ flags |= KeyStore.FLAG_CRITICAL_TO_DEVICE_ENCRYPTION;
+ }
Credentials.deleteAllTypesForAlias(mKeyStore, entryAlias, mUid);
String keyAliasInKeystore = Credentials.USER_SECRET_KEY + entryAlias;
@@ -728,7 +735,7 @@
KeymasterDefs.KM_KEY_FORMAT_RAW,
keyMaterial,
mUid,
- 0, // flags
+ flags,
new KeyCharacteristics());
if (errorCode != KeyStore.NO_ERROR) {
throw new KeyStoreException("Failed to import secret key. Keystore error code: "
diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java
index 2592a97..2eb0663 100644
--- a/keystore/java/android/security/keystore/KeyProtection.java
+++ b/keystore/java/android/security/keystore/KeyProtection.java
@@ -227,6 +227,7 @@
private final boolean mUserAuthenticationValidWhileOnBody;
private final boolean mInvalidatedByBiometricEnrollment;
private final long mBoundToSecureUserId;
+ private final boolean mCriticalToDeviceEncryption;
private KeyProtection(
Date keyValidityStart,
@@ -242,7 +243,8 @@
int userAuthenticationValidityDurationSeconds,
boolean userAuthenticationValidWhileOnBody,
boolean invalidatedByBiometricEnrollment,
- long boundToSecureUserId) {
+ long boundToSecureUserId,
+ boolean criticalToDeviceEncryption) {
mKeyValidityStart = Utils.cloneIfNotNull(keyValidityStart);
mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(keyValidityForOriginationEnd);
mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(keyValidityForConsumptionEnd);
@@ -259,6 +261,7 @@
mUserAuthenticationValidWhileOnBody = userAuthenticationValidWhileOnBody;
mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment;
mBoundToSecureUserId = boundToSecureUserId;
+ mCriticalToDeviceEncryption = criticalToDeviceEncryption;
}
/**
@@ -458,6 +461,16 @@
}
/**
+ * Return whether this key is critical to the device encryption flow.
+ *
+ * @see android.security.KeyStore#FLAG_CRITICAL_TO_DEVICE_ENCRYPTION
+ * @hide
+ */
+ public boolean isCriticalToDeviceEncryption() {
+ return mCriticalToDeviceEncryption;
+ }
+
+ /**
* Builder of {@link KeyProtection} instances.
*/
public final static class Builder {
@@ -477,6 +490,7 @@
private boolean mInvalidatedByBiometricEnrollment = true;
private long mBoundToSecureUserId = GateKeeper.INVALID_SECURE_USER_ID;
+ private boolean mCriticalToDeviceEncryption = false;
/**
* Creates a new instance of the {@code Builder}.
*
@@ -817,6 +831,20 @@
}
/**
+ * Set whether this key is critical to the device encryption flow
+ *
+ * This is a special flag only available to system servers to indicate the current key
+ * is part of the device encryption flow.
+ *
+ * @see android.security.KeyStore#FLAG_CRITICAL_TO_DEVICE_ENCRYPTION
+ * @hide
+ */
+ public Builder setCriticalToDeviceEncryption(boolean critical) {
+ mCriticalToDeviceEncryption = critical;
+ return this;
+ }
+
+ /**
* Builds an instance of {@link KeyProtection}.
*
* @throws IllegalArgumentException if a required field is missing
@@ -837,7 +865,8 @@
mUserAuthenticationValidityDurationSeconds,
mUserAuthenticationValidWhileOnBody,
mInvalidatedByBiometricEnrollment,
- mBoundToSecureUserId);
+ mBoundToSecureUserId,
+ mCriticalToDeviceEncryption);
}
}
}
diff --git a/media/java/android/media/VolumeShaper.java b/media/java/android/media/VolumeShaper.java
index 1dda6a4..8f4721f 100644
--- a/media/java/android/media/VolumeShaper.java
+++ b/media/java/android/media/VolumeShaper.java
@@ -301,7 +301,7 @@
.setInterpolatorType(INTERPOLATOR_TYPE_LINEAR)
.setCurve(new float[] {0.f, 1.f} /* times */,
new float[] {0.f, 1.f} /* volumes */)
- .setDurationMillis(1000.)
+ .setDuration(1000)
.build();
/**
@@ -314,7 +314,7 @@
.setInterpolatorType(INTERPOLATOR_TYPE_CUBIC)
.setCurve(new float[] {0.f, 1.f} /* times */,
new float[] {0.f, 1.f} /* volumes */)
- .setDurationMillis(1000.)
+ .setDuration(1000)
.build();
/**
@@ -348,12 +348,12 @@
SINE_RAMP = new VolumeShaper.Configuration.Builder()
.setInterpolatorType(INTERPOLATOR_TYPE_CUBIC)
.setCurve(times, sines)
- .setDurationMillis(1000.)
+ .setDuration(1000)
.build();
SCURVE_RAMP = new VolumeShaper.Configuration.Builder()
.setInterpolatorType(INTERPOLATOR_TYPE_CUBIC)
.setCurve(times, scurve)
- .setDurationMillis(1000.)
+ .setDuration(1000)
.build();
}
@@ -569,8 +569,9 @@
/**
* Returns the duration of the volume shape in milliseconds.
*/
- public double getDurationMillis() {
- return mDurationMs;
+ public long getDuration() {
+ // casting is safe here as the duration was set as a long in the Builder
+ return (long) mDurationMs;
}
/**
@@ -700,7 +701,7 @@
* .setInterpolatorType(VolumeShaper.Configuration.INTERPOLATOR_TYPE_LINEAR)
* .setCurve(new float[] { 0.f, 1.f }, // times
* new float[] { 0.f, 1.f }) // volumes
- * .setDurationMillis(1000.)
+ * .setDuration(1000)
* .build();
* </pre>
* <p>
@@ -731,7 +732,7 @@
mId = configuration.getId();
mOptionFlags = configuration.getAllOptionFlags();
mInterpolatorType = configuration.getInterpolatorType();
- mDurationMs = configuration.getDurationMillis();
+ mDurationMs = configuration.getDuration();
mTimes = configuration.getTimes().clone();
mVolumes = configuration.getVolumes().clone();
}
@@ -810,12 +811,12 @@
* @throws IllegalArgumentException if {@code durationMillis}
* is not strictly positive.
*/
- public @NonNull Builder setDurationMillis(double durationMillis) {
- if (durationMillis <= 0.) {
+ public @NonNull Builder setDuration(long durationMillis) {
+ if (durationMillis <= 0) {
throw new IllegalArgumentException(
"duration: " + durationMillis + " not positive");
}
- mDurationMs = durationMillis;
+ mDurationMs = (double) durationMillis;
return this;
}
@@ -833,7 +834,7 @@
* time (x) coordinates should be monotonically increasing, from 0.f to 1.f;
* volume (y) coordinates must be within 0.f to 1.f.
* <p>
- * The time scale is set by {@link #setDurationMillis}.
+ * The time scale is set by {@link #setDuration}.
* <p>
* @param times an array of float values representing
* the time line of the volume curve.
diff --git a/packages/CompanionDeviceManager/res/values/strings.xml b/packages/CompanionDeviceManager/res/values/strings.xml
index 43a92b6..c4372eb 100644
--- a/packages/CompanionDeviceManager/res/values/strings.xml
+++ b/packages/CompanionDeviceManager/res/values/strings.xml
@@ -20,9 +20,9 @@
<string name="app_label">Companion Device Manager</string>
<!-- Title of the device selection dialog. -->
- <string name="chooser_title">Link with <strong><xliff:g id="app_name" example="Android Wear">%1$s</xliff:g></strong> via Bluetooth?</string>
+ <string name="chooser_title">Link with <strong><xliff:g id="app_name" example="Android Wear">%1$s</xliff:g></strong></string>
<!-- Title of the device pairing confirmation dialog. -->
- <string name="confirmation_title">Link <strong><xliff:g id="app_name" example="Android Wear">%1$s</xliff:g></strong> with <strong><xliff:g id="device_name" example="ASUS ZenWatch 2">%2$s</xliff:g></strong> via Bluetooth?</string>
+ <string name="confirmation_title">Link <strong><xliff:g id="app_name" example="Android Wear">%1$s</xliff:g></strong> with <strong><xliff:g id="device_name" example="ASUS ZenWatch 2">%2$s</xliff:g></strong></string>
</resources>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index e15df14..044392c 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -130,6 +130,12 @@
<!-- Bluetooth settings. The user-visible string that is used whenever referring to the SAP profile (sharing SIM card). -->
<string name="bluetooth_profile_sap">SIM Access</string>
+ <!-- Bluetooth settings. The user-visible string for the setting controlling whether to use a high-quality codec if the device supports it, along with the name of the codec (eg AAC, LDAC, aptX) -->
+ <string name="bluetooth_profile_a2dp_high_quality">Use high quality audio: <xliff:g id="codec_name">%1$s</xliff:g></string>
+
+ <!-- Bluetooth settings. Similar to bluetooth_profile_a2dp_high_quality, but used when the device supports high quality audio but we don't know which codec that will be used. -->
+ <string name="bluetooth_profile_a2dp_high_quality_unknown_codec">Use high quality audio</string>
+
<!-- Bluetooth settings. Connection options screen. The summary for the A2DP checkbox preference when A2DP is connected. -->
<string name="bluetooth_a2dp_profile_summary_connected">Connected to media audio</string>
<!-- Bluetooth settings. Connection options screen. The summary for the headset checkbox preference when headset is connected. -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
index af247bd..a0eadd0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
@@ -17,6 +17,7 @@
import android.annotation.LayoutRes;
import android.annotation.Nullable;
+import android.app.ActionBar;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -27,7 +28,6 @@
import android.content.res.TypedArray;
import android.os.AsyncTask;
import android.os.Bundle;
-import android.provider.Settings;
import android.util.ArraySet;
import android.util.Log;
import android.view.LayoutInflater;
@@ -117,14 +117,6 @@
super.onPause();
}
- /**
- * Gets the name of the intent action of the default setting app. Used to launch setting app
- * when Settings Home is clicked.
- */
- public String getSettingAction() {
- return Settings.ACTION_SETTINGS;
- }
-
public void addCategoryListener(CategoryListener listener) {
mCategoryListeners.add(listener);
}
@@ -142,7 +134,7 @@
@Override
public void setContentView(@LayoutRes int layoutResID) {
- final ViewGroup parent = (ViewGroup) findViewById(R.id.content_frame);
+ final ViewGroup parent = findViewById(R.id.content_frame);
if (parent != null) {
parent.removeAllViews();
}
@@ -159,11 +151,14 @@
((ViewGroup) findViewById(R.id.content_frame)).addView(view, params);
}
- public void showMenuIcon() {
- getActionBar().setDisplayHomeAsUpEnabled(true);
+ private void showMenuIcon() {
+ final ActionBar actionBar = getActionBar();
+ if (actionBar != null) {
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ }
}
- protected void onCategoriesChanged() {
+ private void onCategoriesChanged() {
final int N = mCategoryListeners.size();
for (int i = 0; i < N; i++) {
mCategoryListeners.get(i).onCategoriesChanged();
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawer/SettingsDrawerActivityTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawer/SettingsDrawerActivityTest.java
index 752b5b0..003f905 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawer/SettingsDrawerActivityTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawer/SettingsDrawerActivityTest.java
@@ -16,7 +16,12 @@
package com.android.settingslib.drawer;
-import android.app.Activity;
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist;
+import static android.support.test.espresso.assertion.ViewAssertions.matches;
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.withContentDescription;
+
import android.app.Instrumentation;
import android.content.Intent;
import android.support.test.InstrumentationRegistry;
@@ -24,23 +29,12 @@
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
-import com.android.settingslib.R;
-
-import com.google.common.truth.Truth;
-
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.MockitoAnnotations;
-import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist;
-import static android.support.test.espresso.assertion.ViewAssertions.matches;
-import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
-import static android.support.test.espresso.matcher.ViewMatchers.withContentDescription;
-import static com.google.common.truth.Truth.assertThat;
-
@RunWith(AndroidJUnit4.class)
@SmallTest
public class SettingsDrawerActivityTest {
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index a8629f8..e9dadc5 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -94,49 +94,9 @@
<!-- Default for Settings.Secure.SYNC_PARENT_SOUNDS -->
<bool name="def_sync_parent_sounds">true</bool>
- <!-- Default for Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION -->
- <bool name="def_accessibility_script_injection">false</bool>
-
<!-- Default for Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD -->
<bool name="def_accessibility_speak_password">true</bool>
- <!-- Default for Settings.Secure.ACCESSIBILITY_WEB_CONTENT_KEY_BINDINGS -->
- <string name="def_accessibility_web_content_key_bindings" translatable="false">
- <!-- DPAD/Trackball UP - traverse previous on current axis and send an event. -->
- 0x13=0x01000100;
- <!-- DPAD/Trackball DOWN - traverse next on current axis and send an event. -->
- 0x14=0x01010100;
- <!-- DPAD/Trackball LEFT - traverse previous on the character navigation axis and send event. -->
- 0x15=0x02000001;
- <!-- DPAD/Trackball RIGHT - traverse next on the character navigation axis end send event. -->
- 0x16=0x02010001;
- <!-- Alt+DPAD/Trackball UP - go to the top of the document. -->
- 0x200000013=0x02000601;
- <!-- Alt+DPAD/Trackball DOWN - go to the bottom of the document. -->
- 0x200000014=0x02010601;
- <!-- Alt+DPAD/Trackball LEFT - transition from an axis to another and sends an event.-->
- <!-- Axis transitions: 2 -> 1; -->
- 0x200000015=0x03020101;
- <!-- Alt+DPAD/Trackball RIGHT - transition from an axis to another and sends an event. -->
- <!-- Axis transitions: 1 -> 2; -->
- 0x200000016=0x03010201;
- <!-- Alt+g - go to the previous heading and send an event. -->
- 0x200000023=0x02000301;
- <!-- Alt+h - go to the next heading and send an event. -->
- 0x200000024=0x02010301;
- <!-- Alt+COMMA - transition to sentence navigation axis and send an event. -->
- <!-- Axis transitions: 7 -> 2; -->
- 0x200000037=0x03070201;
- <!-- Alt+PERIOD - transition to default web view behavior axis and send an event. -->
- <!-- Axis transitions: 0 -> 7; 1 - > 7; 2 -> 7; -->
- 0x200000038=0x03000701:0x03010701:0x03020701;
- </string>
-
- <!-- Default for Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION_URL -->
- <string name="def_accessibility_screen_reader_url" translatable="false">
- https://ssl.gstatic.com/accessibility/javascript/android/AndroidVox_v1.js
- </string>
-
<!-- Default for Settings.Secure.TOUCH_EXPLORATION_ENABLED -->
<bool name="def_touch_exploration_enabled">false</bool>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index a645a56..b777d41 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -820,27 +820,8 @@
if (upgradeVersion == 57) {
/*
- * New settings to:
- * 1. Enable injection of accessibility scripts in WebViews.
- * 2. Define the key bindings for traversing web content in WebViews.
+ * No longer initializing deleted setting ACCESSIBILITY_SCRIPT_INJECTION.
*/
- db.beginTransaction();
- SQLiteStatement stmt = null;
- try {
- stmt = db.compileStatement("INSERT INTO secure(name,value)"
- + " VALUES(?,?);");
- loadBooleanSetting(stmt, Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION,
- R.bool.def_accessibility_script_injection);
- stmt.close();
- stmt = db.compileStatement("INSERT INTO secure(name,value)"
- + " VALUES(?,?);");
- loadStringSetting(stmt, Settings.Secure.ACCESSIBILITY_WEB_CONTENT_KEY_BINDINGS,
- R.string.def_accessibility_web_content_key_bindings);
- db.setTransactionSuccessful();
- } finally {
- db.endTransaction();
- if (stmt != null) stmt.close();
- }
upgradeVersion = 58;
}
@@ -1085,18 +1066,7 @@
}
if (upgradeVersion == 74) {
- // URL from which WebView loads a JavaScript based screen-reader.
- db.beginTransaction();
- SQLiteStatement stmt = null;
- try {
- stmt = db.compileStatement("INSERT INTO secure(name,value) VALUES(?,?);");
- loadStringSetting(stmt, Settings.Secure.ACCESSIBILITY_SCREEN_READER_URL,
- R.string.def_accessibility_screen_reader_url);
- db.setTransactionSuccessful();
- } finally {
- db.endTransaction();
- if (stmt != null) stmt.close();
- }
+ // No longer using URL from which WebView loads a JavaScript based screen-reader.
upgradeVersion = 75;
}
if (upgradeVersion == 75) {
@@ -1147,19 +1117,7 @@
}
if (upgradeVersion == 78) {
- // The JavaScript based screen-reader URL changes in JellyBean.
- db.beginTransaction();
- SQLiteStatement stmt = null;
- try {
- stmt = db.compileStatement("INSERT OR REPLACE INTO secure(name,value)"
- + " VALUES(?,?);");
- loadStringSetting(stmt, Settings.Secure.ACCESSIBILITY_SCREEN_READER_URL,
- R.string.def_accessibility_screen_reader_url);
- db.setTransactionSuccessful();
- } finally {
- db.endTransaction();
- if (stmt != null) stmt.close();
- }
+ // ACCESSIBILITY_SCREEN_READER_URL has been removed
upgradeVersion = 79;
}
@@ -2443,12 +2401,6 @@
loadBooleanSetting(stmt, Settings.Secure.MOUNT_UMS_NOTIFY_ENABLED,
R.bool.def_mount_ums_notify_enabled);
- loadBooleanSetting(stmt, Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION,
- R.bool.def_accessibility_script_injection);
-
- loadStringSetting(stmt, Settings.Secure.ACCESSIBILITY_WEB_CONTENT_KEY_BINDINGS,
- R.string.def_accessibility_web_content_key_bindings);
-
loadIntegerSetting(stmt, Settings.Secure.LONG_PRESS_TIMEOUT,
R.integer.def_long_press_timeout_millis);
@@ -2458,9 +2410,6 @@
loadBooleanSetting(stmt, Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD,
R.bool.def_accessibility_speak_password);
- loadStringSetting(stmt, Settings.Secure.ACCESSIBILITY_SCREEN_READER_URL,
- R.string.def_accessibility_screen_reader_url);
-
if (SystemProperties.getBoolean("ro.lockscreen.disable.default", false) == true) {
loadSetting(stmt, Settings.System.LOCKSCREEN_DISABLED, "1");
} else {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index 1c51773..d1d59b2 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -238,7 +238,6 @@
// these features working after the restore.
switch (name) {
case Settings.Secure.ACCESSIBILITY_ENABLED:
- case Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION:
case Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD:
case Settings.Secure.TOUCH_EXPLORATION_ENABLED:
case Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED:
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index bac694f..885573e 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1057,15 +1057,6 @@
Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED,
SecureSettingsProto.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED);
dumpSetting(s, p,
- Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION,
- SecureSettingsProto.ACCESSIBILITY_SCRIPT_INJECTION);
- dumpSetting(s, p,
- Settings.Secure.ACCESSIBILITY_SCREEN_READER_URL,
- SecureSettingsProto.ACCESSIBILITY_SCREEN_READER_URL);
- dumpSetting(s, p,
- Settings.Secure.ACCESSIBILITY_WEB_CONTENT_KEY_BINDINGS,
- SecureSettingsProto.ACCESSIBILITY_WEB_CONTENT_KEY_BINDINGS);
- dumpSetting(s, p,
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED,
SecureSettingsProto.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED);
dumpSetting(s, p,
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 55f32d7..bf39bc4 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -22,9 +22,6 @@
android:sharedUserId="android.uid.systemui"
coreApp="true">
- <protected-broadcast android:name="com.android.systemui.action.PLUGIN_CHANGED" />
-
-
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java
index a8daed5..f663315 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java
@@ -155,10 +155,6 @@
new ComponentName(info.mPackage, info.mClass),
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
- final String pkg = info.mPackage;
- final Intent intent = new Intent(PluginManager.PLUGIN_CHANGED,
- pkg != null ? Uri.fromParts("package", pkg, null) : null);
- mContext.sendBroadcast(intent);
}
public <T> boolean dependsOn(Plugin p, Class<T> cls) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 143d934..7bc591f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -192,8 +192,9 @@
// and the old last stack active time, they were not visible and in the
// TaskStack so we don't need to remove any associated TaskViews but we do
// need to load the task id's from the system
- RecentsTaskLoadPlan loadPlan = Recents.getTaskLoader().createLoadPlan(ctx);
- loadPlan.preloadRawTasks(false /* includeFrontMostExcludedTask */);
+ RecentsTaskLoader loader = Recents.getTaskLoader();
+ RecentsTaskLoadPlan loadPlan = loader.createLoadPlan(ctx);
+ loader.preloadRawTasks(loadPlan, false /* includeFrontMostExcludedTask */);
List<ActivityManager.RecentTaskInfo> tasks = loadPlan.getRawTasks();
for (int i = tasks.size() - 1; i >= 0; i--) {
ActivityManager.RecentTaskInfo task = tasks.get(i);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 164138e..53a9eae 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -108,36 +108,39 @@
* task stacks and update recents accordingly.
*/
class TaskStackListenerImpl extends TaskStackListener {
+
@Override
- public void onTaskStackChanged() {
+ public void onTaskStackChangedBackground() {
// Preloads the next task
RecentsConfiguration config = Recents.getConfiguration();
if (config.svelteLevel == RecentsConfiguration.SVELTE_NONE) {
- RecentsTaskLoader loader = Recents.getTaskLoader();
- SystemServicesProxy ssp = Recents.getSystemServices();
- ActivityManager.RunningTaskInfo runningTaskInfo = ssp.getRunningTask();
// Load the next task only if we aren't svelte
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ ActivityManager.RunningTaskInfo runningTaskInfo = ssp.getRunningTask();
+ RecentsTaskLoader loader = Recents.getTaskLoader();
RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
loader.preloadTasks(plan, -1, false /* includeFrontMostExcludedTask */);
- RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
+
// This callback is made when a new activity is launched and the old one is paused
// so ignore the current activity and try and preload the thumbnail for the
// previous one.
- if (runningTaskInfo != null) {
- launchOpts.runningTaskId = runningTaskInfo.id;
+ VisibilityReport visibilityReport;
+ synchronized (mDummyStackView) {
+ mDummyStackView.setTasks(plan.getTaskStack(), false /* allowNotify */);
+ updateDummyStackViewLayout(plan.getTaskStack(),
+ getWindowRect(null /* windowRectOverride */));
+
+ // Launched from app is always the worst case (in terms of how many
+ // thumbnails/tasks visible)
+ RecentsActivityLaunchState launchState = new RecentsActivityLaunchState();
+ launchState.launchedFromApp = true;
+ mDummyStackView.updateLayoutAlgorithm(true /* boundScroll */, launchState);
+ visibilityReport = mDummyStackView.computeStackVisibilityReport();
}
- mDummyStackView.setTasks(plan.getTaskStack(), false /* allowNotify */);
- updateDummyStackViewLayout(plan.getTaskStack(),
- getWindowRect(null /* windowRectOverride */));
- // Launched from app is always the worst case (in terms of how many thumbnails/tasks
- // visible)
- RecentsActivityLaunchState launchState = new RecentsActivityLaunchState();
- launchState.launchedFromApp = true;
- mDummyStackView.updateLayoutAlgorithm(true /* boundScroll */, launchState);
-
- VisibilityReport visibilityReport = mDummyStackView.computeStackVisibilityReport();
+ RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
+ launchOpts.runningTaskId = runningTaskInfo != null ? runningTaskInfo.id : -1;
launchOpts.numVisibleTasks = visibilityReport.numVisibleTasks;
launchOpts.numVisibleTaskThumbnails = visibilityReport.numVisibleThumbnails;
launchOpts.onlyLoadForCache = true;
@@ -221,9 +224,10 @@
}
public void onConfigurationChanged() {
- Resources res = mContext.getResources();
reloadResources();
- mDummyStackView.reloadOnConfigurationChange();
+ synchronized (mDummyStackView) {
+ mDummyStackView.reloadOnConfigurationChange();
+ }
}
/**
@@ -393,7 +397,6 @@
RecentsTaskLoader loader = Recents.getTaskLoader();
sInstanceLoadPlan = loader.createLoadPlan(mContext);
- sInstanceLoadPlan.preloadRawTasks(!isHomeStackVisible.value);
loader.preloadTasks(sInstanceLoadPlan, runningTask.id, !isHomeStackVisible.value);
TaskStack stack = sInstanceLoadPlan.getTaskStack();
if (stack.getTaskCount() > 0) {
@@ -633,16 +636,18 @@
calculateWindowStableInsets(systemInsets, windowRect);
windowRect.offsetTo(0, 0);
- TaskStackLayoutAlgorithm stackLayout = mDummyStackView.getStackAlgorithm();
+ synchronized (mDummyStackView) {
+ TaskStackLayoutAlgorithm stackLayout = mDummyStackView.getStackAlgorithm();
- // Rebind the header bar and draw it for the transition
- stackLayout.setSystemInsets(systemInsets);
- if (stack != null) {
- stackLayout.getTaskStackBounds(displayRect, windowRect, systemInsets.top,
- systemInsets.left, systemInsets.right, mTaskStackBounds);
- stackLayout.reset();
- stackLayout.initialize(displayRect, windowRect, mTaskStackBounds,
- TaskStackLayoutAlgorithm.StackState.getStackStateForStack(stack));
+ // Rebind the header bar and draw it for the transition
+ stackLayout.setSystemInsets(systemInsets);
+ if (stack != null) {
+ stackLayout.getTaskStackBounds(displayRect, windowRect, systemInsets.top,
+ systemInsets.left, systemInsets.right, mTaskStackBounds);
+ stackLayout.reset();
+ stackLayout.initialize(displayRect, windowRect, mTaskStackBounds,
+ TaskStackLayoutAlgorithm.StackState.getStackStateForStack(stack));
+ }
}
}
@@ -663,47 +668,52 @@
*/
private void updateHeaderBarLayout(TaskStack stack, Rect windowRectOverride) {
Rect windowRect = getWindowRect(windowRectOverride);
- updateDummyStackViewLayout(stack, windowRect);
- if (stack != null) {
- TaskStackLayoutAlgorithm stackLayout = mDummyStackView.getStackAlgorithm();
- mDummyStackView.setTasks(stack, false /* allowNotifyStackChanges */);
- // Get the width of a task view so that we know how wide to draw the header bar.
- int taskViewWidth = 0;
- if (mDummyStackView.useGridLayout()) {
- TaskGridLayoutAlgorithm gridLayout = mDummyStackView.getGridAlgorithm();
- gridLayout.initialize(windowRect);
- taskViewWidth = (int) gridLayout.getTransform(0 /* taskIndex */,
- stack.getTaskCount(), new TaskViewTransform(), stackLayout).rect.width();
- } else {
- Rect taskViewBounds = stackLayout.getUntransformedTaskViewBounds();
- if (!taskViewBounds.isEmpty()) {
- taskViewWidth = taskViewBounds.width();
+ int taskViewWidth = 0;
+ boolean useGridLayout = false;
+ synchronized (mDummyStackView) {
+ useGridLayout = mDummyStackView.useGridLayout();
+ updateDummyStackViewLayout(stack, windowRect);
+ if (stack != null) {
+ TaskStackLayoutAlgorithm stackLayout = mDummyStackView.getStackAlgorithm();
+ mDummyStackView.setTasks(stack, false /* allowNotifyStackChanges */);
+ // Get the width of a task view so that we know how wide to draw the header bar.
+ if (useGridLayout) {
+ TaskGridLayoutAlgorithm gridLayout = mDummyStackView.getGridAlgorithm();
+ gridLayout.initialize(windowRect);
+ taskViewWidth = (int) gridLayout.getTransform(0 /* taskIndex */,
+ stack.getTaskCount(), new TaskViewTransform(),
+ stackLayout).rect.width();
+ } else {
+ Rect taskViewBounds = stackLayout.getUntransformedTaskViewBounds();
+ if (!taskViewBounds.isEmpty()) {
+ taskViewWidth = taskViewBounds.width();
+ }
}
}
+ }
- if (taskViewWidth > 0) {
- synchronized (mHeaderBarLock) {
- if (mHeaderBar.getMeasuredWidth() != taskViewWidth ||
- mHeaderBar.getMeasuredHeight() != mTaskBarHeight) {
- if (mDummyStackView.useGridLayout()) {
- mHeaderBar.setShouldDarkenBackgroundColor(true);
- mHeaderBar.setNoUserInteractionState();
- }
- mHeaderBar.forceLayout();
- mHeaderBar.measure(
- MeasureSpec.makeMeasureSpec(taskViewWidth, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(mTaskBarHeight, MeasureSpec.EXACTLY));
+ if (stack != null && taskViewWidth > 0) {
+ synchronized (mHeaderBarLock) {
+ if (mHeaderBar.getMeasuredWidth() != taskViewWidth ||
+ mHeaderBar.getMeasuredHeight() != mTaskBarHeight) {
+ if (useGridLayout) {
+ mHeaderBar.setShouldDarkenBackgroundColor(true);
+ mHeaderBar.setNoUserInteractionState();
}
- mHeaderBar.layout(0, 0, taskViewWidth, mTaskBarHeight);
+ mHeaderBar.forceLayout();
+ mHeaderBar.measure(
+ MeasureSpec.makeMeasureSpec(taskViewWidth, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(mTaskBarHeight, MeasureSpec.EXACTLY));
}
+ mHeaderBar.layout(0, 0, taskViewWidth, mTaskBarHeight);
+ }
- // Update the transition bitmap to match the new header bar height
- if (mThumbTransitionBitmapCache == null ||
- (mThumbTransitionBitmapCache.getWidth() != taskViewWidth) ||
- (mThumbTransitionBitmapCache.getHeight() != mTaskBarHeight)) {
- mThumbTransitionBitmapCache = Bitmap.createBitmap(taskViewWidth,
- mTaskBarHeight, Bitmap.Config.ARGB_8888);
- }
+ // Update the transition bitmap to match the new header bar height
+ if (mThumbTransitionBitmapCache == null ||
+ (mThumbTransitionBitmapCache.getWidth() != taskViewWidth) ||
+ (mThumbTransitionBitmapCache.getHeight() != mTaskBarHeight)) {
+ mThumbTransitionBitmapCache = Bitmap.createBitmap(taskViewWidth,
+ mTaskBarHeight, Bitmap.Config.ARGB_8888);
}
}
}
@@ -764,16 +774,21 @@
* Creates the activity options for an app->recents transition.
*/
private ActivityOptions getThumbnailTransitionActivityOptions(
- ActivityManager.RunningTaskInfo runningTask, TaskStackView stackView,
- Rect windowOverrideRect) {
+ ActivityManager.RunningTaskInfo runningTask, Rect windowOverrideRect) {
if (runningTask != null && runningTask.stackId == FREEFORM_WORKSPACE_STACK_ID) {
ArrayList<AppTransitionAnimationSpec> specs = new ArrayList<>();
- ArrayList<Task> tasks = stackView.getStack().getStackTasks();
- TaskStackLayoutAlgorithm stackLayout = stackView.getStackAlgorithm();
- TaskStackViewScroller stackScroller = stackView.getScroller();
+ ArrayList<Task> tasks;
+ TaskStackLayoutAlgorithm stackLayout;
+ TaskStackViewScroller stackScroller;
- stackView.updateLayoutAlgorithm(true /* boundScroll */);
- stackView.updateToInitialState();
+ synchronized (mDummyStackView) {
+ tasks = mDummyStackView.getStack().getStackTasks();
+ stackLayout = mDummyStackView.getStackAlgorithm();
+ stackScroller = mDummyStackView.getScroller();
+
+ mDummyStackView.updateLayoutAlgorithm(true /* boundScroll */);
+ mDummyStackView.updateToInitialState();
+ }
for (int i = tasks.size() - 1; i >= 0; i--) {
Task task = tasks.get(i);
@@ -795,7 +810,7 @@
} else {
// Update the destination rect
Task toTask = new Task();
- TaskViewTransform toTransform = getThumbnailTransitionTransform(stackView, toTask,
+ TaskViewTransform toTransform = getThumbnailTransitionTransform(mDummyStackView, toTask,
windowOverrideRect);
Bitmap thumbnail = drawThumbnailTransitionBitmap(toTask, toTransform,
mThumbTransitionBitmapCache);
@@ -919,8 +934,10 @@
updateHeaderBarLayout(stack, windowOverrideRect);
// Prepare the dummy stack for the transition
- TaskStackLayoutAlgorithm.VisibilityReport stackVr =
- mDummyStackView.computeStackVisibilityReport();
+ TaskStackLayoutAlgorithm.VisibilityReport stackVr;
+ synchronized (mDummyStackView) {
+ stackVr = mDummyStackView.computeStackVisibilityReport();
+ }
// Update the remaining launch state
launchState.launchedNumVisibleTasks = stackVr.numVisibleTasks;
@@ -936,8 +953,7 @@
opts = getUnknownTransitionActivityOptions();
} else if (useThumbnailTransition) {
// Try starting with a thumbnail transition
- opts = getThumbnailTransitionActivityOptions(runningTask, mDummyStackView,
- windowOverrideRect);
+ opts = getThumbnailTransitionActivityOptions(runningTask, windowOverrideRect);
} else {
// If there is no thumbnail transition, but is launching from home into recents, then
// use a quick home transition
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 2f12282..a9e1f61 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -61,6 +61,7 @@
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.SystemProperties;
+import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
@@ -149,6 +150,10 @@
* to reduce IPC calls from system services. These callbacks will be called on the main thread.
*/
public abstract static class TaskStackListener {
+ /**
+ * NOTE: This call is made of the thread that the binder call comes in on.
+ */
+ public void onTaskStackChangedBackground() { }
public void onTaskStackChanged() { }
public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot) { }
public void onActivityPinned(String packageName) { }
@@ -187,8 +192,20 @@
* This simply passes callbacks to listeners through {@link H}.
* */
private android.app.TaskStackListener mTaskStackListener = new android.app.TaskStackListener() {
+
+ private final List<SystemServicesProxy.TaskStackListener> mTmpListeners = new ArrayList<>();
+
@Override
public void onTaskStackChanged() throws RemoteException {
+ // Call the task changed callback for the non-ui thread listeners first
+ synchronized (mTaskStackListeners) {
+ mTmpListeners.clear();
+ mTmpListeners.addAll(mTaskStackListeners);
+ }
+ for (int i = mTmpListeners.size() - 1; i >= 0; i--) {
+ mTmpListeners.get(i).onTaskStackChangedBackground();
+ }
+
mHandler.removeMessages(H.ON_TASK_STACK_CHANGED);
mHandler.sendEmptyMessage(H.ON_TASK_STACK_CHANGED);
}
@@ -309,10 +326,7 @@
* Returns the single instance of the {@link SystemServicesProxy}.
* This should only be called on the main thread.
*/
- public static SystemServicesProxy getInstance(Context context) {
- if (!Looper.getMainLooper().isCurrentThread()) {
- throw new RuntimeException("Must be called on the UI thread");
- }
+ public static synchronized SystemServicesProxy getInstance(Context context) {
if (sSystemServicesProxy == null) {
sSystemServicesProxy = new SystemServicesProxy(context);
}
@@ -1136,13 +1150,15 @@
public void registerTaskStackListener(TaskStackListener listener) {
if (mIam == null) return;
- mTaskStackListeners.add(listener);
- if (mTaskStackListeners.size() == 1) {
- // Register mTaskStackListener to IActivityManager only once if needed.
- try {
- mIam.registerTaskStackListener(mTaskStackListener);
- } catch (Exception e) {
- Log.w(TAG, "Failed to call registerTaskStackListener", e);
+ synchronized (mTaskStackListeners) {
+ mTaskStackListeners.add(listener);
+ if (mTaskStackListeners.size() == 1) {
+ // Register mTaskStackListener to IActivityManager only once if needed.
+ try {
+ mIam.registerTaskStackListener(mTaskStackListener);
+ } catch (Exception e) {
+ Log.w(TAG, "Failed to call registerTaskStackListener", e);
+ }
}
}
}
@@ -1245,74 +1261,80 @@
@Override
public void handleMessage(Message msg) {
- switch (msg.what) {
- case ON_TASK_STACK_CHANGED: {
- for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
- mTaskStackListeners.get(i).onTaskStackChanged();
+ synchronized (mTaskStackListeners) {
+ switch (msg.what) {
+ case ON_TASK_STACK_CHANGED: {
+ Trace.beginSection("onTaskStackChanged");
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onTaskStackChanged();
+ }
+ Trace.endSection();
+ break;
}
- break;
- }
- case ON_TASK_SNAPSHOT_CHANGED: {
- for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
- mTaskStackListeners.get(i).onTaskSnapshotChanged(msg.arg1,
- (TaskSnapshot) msg.obj);
+ case ON_TASK_SNAPSHOT_CHANGED: {
+ Trace.beginSection("onTaskSnapshotChanged");
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onTaskSnapshotChanged(msg.arg1,
+ (TaskSnapshot) msg.obj);
+ }
+ Trace.endSection();
+ break;
}
- break;
- }
- case ON_ACTIVITY_PINNED: {
- for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
- mTaskStackListeners.get(i).onActivityPinned((String) msg.obj);
+ case ON_ACTIVITY_PINNED: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onActivityPinned((String) msg.obj);
+ }
+ break;
}
- break;
- }
- case ON_ACTIVITY_UNPINNED: {
- for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
- mTaskStackListeners.get(i).onActivityUnpinned();
+ case ON_ACTIVITY_UNPINNED: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onActivityUnpinned();
+ }
+ break;
}
- break;
- }
- case ON_PINNED_ACTIVITY_RESTART_ATTEMPT: {
- for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
- mTaskStackListeners.get(i).onPinnedActivityRestartAttempt();
+ case ON_PINNED_ACTIVITY_RESTART_ATTEMPT: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onPinnedActivityRestartAttempt();
+ }
+ break;
}
- break;
- }
- case ON_PINNED_STACK_ANIMATION_STARTED: {
- for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
- mTaskStackListeners.get(i).onPinnedStackAnimationStarted();
+ case ON_PINNED_STACK_ANIMATION_STARTED: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onPinnedStackAnimationStarted();
+ }
+ break;
}
- break;
- }
- case ON_PINNED_STACK_ANIMATION_ENDED: {
- for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
- mTaskStackListeners.get(i).onPinnedStackAnimationEnded();
+ case ON_PINNED_STACK_ANIMATION_ENDED: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onPinnedStackAnimationEnded();
+ }
+ break;
}
- break;
- }
- case ON_ACTIVITY_FORCED_RESIZABLE: {
- for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
- mTaskStackListeners.get(i).onActivityForcedResizable(
- (String) msg.obj, msg.arg1, msg.arg2);
+ case ON_ACTIVITY_FORCED_RESIZABLE: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onActivityForcedResizable(
+ (String) msg.obj, msg.arg1, msg.arg2);
+ }
+ break;
}
- break;
- }
- case ON_ACTIVITY_DISMISSING_DOCKED_STACK: {
- for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
- mTaskStackListeners.get(i).onActivityDismissingDockedStack();
+ case ON_ACTIVITY_DISMISSING_DOCKED_STACK: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onActivityDismissingDockedStack();
+ }
+ break;
}
- break;
- }
- case ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED: {
- for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
- mTaskStackListeners.get(i).onActivityLaunchOnSecondaryDisplayFailed();
+ case ON_ACTIVITY_LAUNCH_ON_SECONDARY_DISPLAY_FAILED: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onActivityLaunchOnSecondaryDisplayFailed();
+ }
+ break;
}
- break;
- }
- case ON_TASK_PROFILE_LOCKED: {
- for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
- mTaskStackListeners.get(i).onTaskProfileLocked(msg.arg1, msg.arg2);
+ case ON_TASK_PROFILE_LOCKED: {
+ for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+ mTaskStackListeners.get(i).onTaskProfileLocked(msg.arg1, msg.arg2);
+ }
+ break;
}
- break;
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
index 78c71a1..4b53cd1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -103,8 +103,10 @@
/**
* An optimization to preload the raw list of tasks. The raw tasks are saved in least-recent
* to most-recent order.
+ *
+ * Note: Do not lock, callers should synchronize on the loader before making this call.
*/
- public synchronized void preloadRawTasks(boolean includeFrontMostExcludedTask) {
+ void preloadRawTasks(boolean includeFrontMostExcludedTask) {
int currentUserId = UserHandle.USER_CURRENT;
updateCurrentQuietProfilesCache(currentUserId);
SystemServicesProxy ssp = Recents.getSystemServices();
@@ -123,8 +125,11 @@
* The tasks will be ordered by:
* - least-recent to most-recent stack tasks
* - least-recent to most-recent freeform tasks
+ *
+ * Note: Do not lock, since this can be calling back to the loader, which separately also drives
+ * this call (callers should synchronize on the loader before making this call).
*/
- public synchronized void preloadPlan(RecentsTaskLoader loader, int runningTaskId,
+ void preloadPlan(RecentsTaskLoader loader, int runningTaskId,
boolean includeFrontMostExcludedTask) {
Resources res = mContext.getResources();
ArrayList<Task> allTasks = new ArrayList<>();
@@ -223,8 +228,11 @@
/**
* Called to apply the actual loading based on the specified conditions.
+ *
+ * Note: Do not lock, since this can be calling back to the loader, which separately also drives
+ * this call (callers should synchronize on the loader before making this call).
*/
- public synchronized void executePlan(Options opts, RecentsTaskLoader loader) {
+ void executePlan(Options opts, RecentsTaskLoader loader) {
Resources res = mContext.getResources();
// Iterate through each of the tasks and load them according to the load conditions.
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
index 5e78b61..0b4498c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -31,6 +31,7 @@
import android.util.Log;
import android.util.LruCache;
+import com.android.internal.annotations.GuardedBy;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsConfiguration;
@@ -243,7 +244,9 @@
private final TaskResourceLoadQueue mLoadQueue;
private final BackgroundTaskLoader mLoader;
private final HighResThumbnailLoader mHighResThumbnailLoader;
+ @GuardedBy("this")
private final TaskKeyStrongCache<ThumbnailData> mThumbnailCache = new TaskKeyStrongCache<>();
+ @GuardedBy("this")
private final TaskKeyStrongCache<ThumbnailData> mTempCache = new TaskKeyStrongCache<>();
private final int mMaxThumbnailCacheSize;
private final int mMaxIconCacheSize;
@@ -318,14 +321,20 @@
return plan;
}
+ /** Preloads raw recents tasks using the specified plan to store the output. */
+ public synchronized void preloadRawTasks(RecentsTaskLoadPlan plan,
+ boolean includeFrontMostExcludedTask) {
+ plan.preloadRawTasks(includeFrontMostExcludedTask);
+ }
+
/** Preloads recents tasks using the specified plan to store the output. */
- public void preloadTasks(RecentsTaskLoadPlan plan, int runningTaskId,
+ public synchronized void preloadTasks(RecentsTaskLoadPlan plan, int runningTaskId,
boolean includeFrontMostExcludedTask) {
plan.preloadPlan(this, runningTaskId, includeFrontMostExcludedTask);
}
/** Begins loading the heavy task data according to the specified options. */
- public void loadTasks(Context context, RecentsTaskLoadPlan plan,
+ public synchronized void loadTasks(Context context, RecentsTaskLoadPlan plan,
RecentsTaskLoadPlan.Options opts) {
if (opts == null) {
throw new RuntimeException("Requires load options");
@@ -380,8 +389,7 @@
* Handles signals from the system, trimming memory when requested to prevent us from running
* out of memory.
*/
- public void onTrimMemory(int level) {
- RecentsConfiguration config = Recents.getConfiguration();
+ public synchronized void onTrimMemory(int level) {
switch (level) {
case ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN:
// Stop the loader immediately when the UI is no longer visible
@@ -516,7 +524,7 @@
/**
* Returns the cached thumbnail if the task key is not expired, updating the cache if it is.
*/
- ThumbnailData getAndUpdateThumbnail(Task.TaskKey taskKey, boolean loadIfNotCached,
+ synchronized ThumbnailData getAndUpdateThumbnail(Task.TaskKey taskKey, boolean loadIfNotCached,
boolean storeInCache) {
SystemServicesProxy ssp = Recents.getSystemServices();
@@ -616,12 +624,15 @@
}
}
- public void dump(String prefix, PrintWriter writer) {
+ public synchronized void dump(String prefix, PrintWriter writer) {
String innerPrefix = prefix + " ";
writer.print(prefix); writer.println(TAG);
writer.print(prefix); writer.println("Icon Cache");
mIconCache.dump(innerPrefix, writer);
+ writer.print(prefix); writer.println("Thumbnail Cache");
mThumbnailCache.dump(innerPrefix, writer);
+ writer.print(prefix); writer.println("Temp Thumbnail Cache");
+ mTempCache.dump(innerPrefix, writer);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 32e3df6..18a9bab 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -1711,6 +1711,13 @@
}
}
+ private void clearPrefetchingTask() {
+ if (mPrefetchingTask != null) {
+ Recents.getTaskLoader().unloadTaskData(mPrefetchingTask);
+ }
+ mPrefetchingTask = null;
+ }
+
/**** TaskViewCallbacks Implementation ****/
@Override
@@ -2201,6 +2208,13 @@
if (!event.visible && mTaskViewFocusFrame != null) {
mTaskViewFocusFrame.moveGridTaskViewFocus(null);
}
+ if (!event.visible) {
+ List<TaskView> taskViews = new ArrayList<>(getTaskViews());
+ for (int i = 0; i < taskViews.size(); i++) {
+ mViewPool.returnViewToPool(taskViews.get(i));
+ }
+ clearPrefetchingTask();
+ }
}
public void reloadOnConfigurationChange() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
index 4dec6c7..2cf06c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
@@ -262,17 +262,15 @@
private boolean hasImportanceChanged() {
return mSingleNotificationChannel != null &&
+ mChannelEnabledSwitch != null &&
mStartingUserImportance != getSelectedImportance();
}
private void saveImportance() {
- if (mSingleNotificationChannel == null) {
+ if (!hasImportanceChanged()) {
return;
}
- int selectedImportance = getSelectedImportance();
- if (selectedImportance == mStartingUserImportance) {
- return;
- }
+ final int selectedImportance = getSelectedImportance();
MetricsLogger.action(mContext, MetricsEvent.ACTION_SAVE_IMPORTANCE,
selectedImportance - mStartingUserImportance);
mSingleNotificationChannel.setImportance(selectedImportance);
@@ -386,7 +384,7 @@
@Override
public boolean willBeRemoved() {
- return !mChannelEnabledSwitch.isChecked();
+ return mChannelEnabledSwitch != null && !mChannelEnabledSwitch.isChecked();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityManagerWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityManagerWrapper.java
index dfa5cbd..6a573f5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityManagerWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessibilityManagerWrapper.java
@@ -19,7 +19,7 @@
import android.view.accessibility.AccessibilityManager.AccessibilityServicesStateChangeListener;
/**
- * For mocking because AccessibilyManager is final for some reason...
+ * For mocking because AccessibilityManager is final for some reason...
*/
public class AccessibilityManagerWrapper implements
CallbackController<AccessibilityServicesStateChangeListener> {
@@ -32,7 +32,7 @@
@Override
public void addCallback(AccessibilityServicesStateChangeListener listener) {
- mAccessibilityManager.addAccessibilityServicesStateChangeListener(listener);
+ mAccessibilityManager.addAccessibilityServicesStateChangeListener(listener, null);
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
index 907928f..2b14b31 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
@@ -778,4 +778,9 @@
enabledSwitch.setChecked(true);
assertEquals(View.VISIBLE, settingsLink.getVisibility());
}
+
+ @Test
+ public void testWillBeRemovedReturnsFalseBeforeBind() throws Exception {
+ assertFalse(mNotificationInfo.willBeRemoved());
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
index 8808988..f516d74 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BluetoothControllerImplTest.java
@@ -20,7 +20,9 @@
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothProfile;
+import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.testing.TestableLooper.RunWithLooper;
import com.android.settingslib.bluetooth.BluetoothEventManager;
import com.android.settingslib.bluetooth.CachedBluetoothDevice;
@@ -31,10 +33,13 @@
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
import java.util.ArrayList;
import java.util.List;
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
public class BluetoothControllerImplTest extends SysuiTestCase {
private LocalBluetoothManager mMockBluetoothManager;
@@ -47,7 +52,7 @@
@Before
public void setup() throws Exception {
- mTestableLooper = new TestableLooper();
+ mTestableLooper = TestableLooper.get(this);
mMockBluetoothManager = mDependency.injectMockDependency(LocalBluetoothManager.class);
mDevices = new ArrayList<>();
mMockDeviceManager = mock(CachedBluetoothDeviceManager.class);
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 0003941..b6dfdd1 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -775,7 +775,6 @@
if ((flags & UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES) == 0) {
// Set the temporary state, and use it instead of settings
userState.mIsTouchExplorationEnabled = false;
- userState.mIsEnhancedWebAccessibilityEnabled = false;
userState.mIsDisplayMagnificationEnabled = false;
userState.mIsNavBarMagnificationEnabled = false;
userState.mIsAutoclickEnabled = false;
@@ -826,7 +825,6 @@
}
userState.mIsTouchExplorationEnabled = touchExplorationEnabled;
- userState.mIsEnhancedWebAccessibilityEnabled = false;
userState.mIsDisplayMagnificationEnabled = false;
userState.mIsNavBarMagnificationEnabled = false;
userState.mIsAutoclickEnabled = false;
@@ -1727,7 +1725,6 @@
updateFilterKeyEventsLocked(userState);
updateTouchExplorationLocked(userState);
updatePerformGesturesLocked(userState);
- updateEnhancedWebAccessibilityLocked(userState);
updateDisplayDaltonizerLocked(userState);
updateDisplayInversionLocked(userState);
updateMagnificationLocked(userState);
@@ -1846,7 +1843,6 @@
somethingChanged |= readTouchExplorationGrantedAccessibilityServicesLocked(userState);
somethingChanged |= readTouchExplorationEnabledSettingLocked(userState);
somethingChanged |= readHighTextContrastEnabledSettingLocked(userState);
- somethingChanged |= readEnhancedWebAccessibilityEnabledChangedLocked(userState);
somethingChanged |= readMagnificationEnabledSettingsLocked(userState);
somethingChanged |= readAutoclickEnabledSettingLocked(userState);
somethingChanged |= readAccessibilityShortcutSettingLocked(userState);
@@ -1907,17 +1903,6 @@
return false;
}
- private boolean readEnhancedWebAccessibilityEnabledChangedLocked(UserState userState) {
- final boolean enhancedWeAccessibilityEnabled = Settings.Secure.getIntForUser(
- mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION,
- 0, userState.mUserId) == 1;
- if (enhancedWeAccessibilityEnabled != userState.mIsEnhancedWebAccessibilityEnabled) {
- userState.mIsEnhancedWebAccessibilityEnabled = enhancedWeAccessibilityEnabled;
- return true;
- }
- return false;
- }
-
private boolean readHighTextContrastEnabledSettingLocked(UserState userState) {
final boolean highTextContrastEnabled = Settings.Secure.getIntForUser(
mContext.getContentResolver(),
@@ -2084,40 +2069,6 @@
return false;
}
- private void updateEnhancedWebAccessibilityLocked(UserState userState) {
- boolean enabled = false;
- final int serviceCount = userState.mBoundServices.size();
- for (int i = 0; i < serviceCount; i++) {
- Service service = userState.mBoundServices.get(i);
- if (canRequestAndRequestsEnhancedWebAccessibilityLocked(service)) {
- enabled = true;
- break;
- }
- }
- if (enabled != userState.mIsEnhancedWebAccessibilityEnabled) {
- userState.mIsEnhancedWebAccessibilityEnabled = enabled;
- final long identity = Binder.clearCallingIdentity();
- try {
- Settings.Secure.putIntForUser(mContext.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, enabled ? 1 : 0,
- userState.mUserId);
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
- }
-
- private boolean canRequestAndRequestsEnhancedWebAccessibilityLocked(Service service) {
- if (!service.canReceiveEventsLocked() || !service.mRequestEnhancedWebAccessibility ) {
- return false;
- }
- if (service.mIsAutomation || (service.mAccessibilityServiceInfo.getCapabilities()
- & AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY) != 0) {
- return true;
- }
- return false;
- }
-
private void updateDisplayDaltonizerLocked(UserState userState) {
DisplayAdjustmentUtils.applyDaltonizerSetting(mContext, userState.mUserId);
}
@@ -2697,8 +2648,6 @@
boolean mRequestTouchExplorationMode;
- boolean mRequestEnhancedWebAccessibility;
-
boolean mRequestFilterKeyEvents;
boolean mRetrieveInteractiveWindows;
@@ -2854,8 +2803,6 @@
mRequestTouchExplorationMode = (info.flags
& AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0;
- mRequestEnhancedWebAccessibility = (info.flags
- & AccessibilityServiceInfo.FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY) != 0;
mRequestFilterKeyEvents = (info.flags
& AccessibilityServiceInfo.FLAG_REQUEST_FILTER_KEY_EVENTS) != 0;
mRetrieveInteractiveWindows = (info.flags
@@ -4933,7 +4880,6 @@
public boolean mIsTouchExplorationEnabled;
public boolean mIsTextHighContrastEnabled;
- public boolean mIsEnhancedWebAccessibilityEnabled;
public boolean mIsDisplayMagnificationEnabled;
public boolean mIsNavBarMagnificationEnabled;
public boolean mIsAutoclickEnabled;
@@ -5002,7 +4948,6 @@
mEnabledServices.clear();
mTouchExplorationGrantedServices.clear();
mIsTouchExplorationEnabled = false;
- mIsEnhancedWebAccessibilityEnabled = false;
mIsDisplayMagnificationEnabled = false;
mIsNavBarMagnificationEnabled = false;
mServiceAssignedToAccessibilityButton = null;
@@ -5051,9 +4996,6 @@
private final Uri mTouchExplorationGrantedAccessibilityServicesUri = Settings.Secure
.getUriFor(Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES);
- private final Uri mEnhancedWebAccessibilityUri = Settings.Secure
- .getUriFor(Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION);
-
private final Uri mDisplayInversionEnabledUri = Settings.Secure.getUriFor(
Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);
@@ -5093,8 +5035,6 @@
contentResolver.registerContentObserver(
mTouchExplorationGrantedAccessibilityServicesUri,
false, this, UserHandle.USER_ALL);
- contentResolver.registerContentObserver(mEnhancedWebAccessibilityUri,
- false, this, UserHandle.USER_ALL);
contentResolver.registerContentObserver(
mDisplayInversionEnabledUri, false, this, UserHandle.USER_ALL);
contentResolver.registerContentObserver(
@@ -5144,10 +5084,6 @@
if (readTouchExplorationGrantedAccessibilityServicesLocked(userState)) {
onUserStateChangedLocked(userState);
}
- } else if (mEnhancedWebAccessibilityUri.equals(uri)) {
- if (readEnhancedWebAccessibilityEnabledChangedLocked(userState)) {
- onUserStateChangedLocked(userState);
- }
} else if (mDisplayDaltonizerEnabledUri.equals(uri)
|| mDisplayDaltonizerUri.equals(uri)) {
updateDisplayDaltonizerLocked(userState);
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 1b5b2c6..88adbf4 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -73,6 +73,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* Entry point service for autofill management.
@@ -81,7 +82,6 @@
* {@link AutofillManagerServiceImpl} per user; the real work is done by
* {@link AutofillManagerServiceImpl} itself.
*/
-// TODO(b/33197203): Handle removing of packages
public final class AutofillManagerService extends SystemService {
private static final String TAG = "AutofillManagerService";
@@ -109,10 +109,8 @@
@GuardedBy("mLock")
private final SparseBooleanArray mDisabledUsers = new SparseBooleanArray();
- // TODO(b/33197203): set a different max (or disable it) on low-memory devices.
private final LocalLog mRequestsHistory = new LocalLog(20);
- // TODO(b/33197203): is this still needed?
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -376,7 +374,6 @@
public int startSession(IBinder activityToken, IBinder windowToken, IBinder appCallback,
AutofillId autofillId, Rect bounds, AutofillValue value, int userId,
boolean hasCallback, int flags, String packageName) {
- // TODO(b/33197203): make sure it's called by resumed / focused activity
activityToken = Preconditions.checkNotNull(activityToken, "activityToken");
appCallback = Preconditions.checkNotNull(appCallback, "appCallback");
@@ -487,6 +484,22 @@
}
@Override
+ public boolean isServiceSupported(int userId) {
+ synchronized (mLock) {
+ return !mDisabledUsers.get(userId);
+ }
+ }
+
+ @Override
+ public boolean isServiceEnabled(int userId, String packageName) {
+ synchronized (mLock) {
+ final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
+ if (service == null) return false;
+ return Objects.equals(packageName, service.getPackageName());
+ }
+ }
+
+ @Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
synchronized (mLock) {
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 85fc580..238cdd5 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -16,9 +16,6 @@
package com.android.server.autofill;
-import static android.service.autofill.AutofillService.EXTRA_SESSION_ID;
-import static android.service.voice.VoiceInteractionSession.KEY_RECEIVER_EXTRAS;
-import static android.service.voice.VoiceInteractionSession.KEY_STRUCTURE;
import static android.view.autofill.AutofillManager.FLAG_START_SESSION;
import static android.view.autofill.AutofillManager.NO_SESSION;
@@ -27,10 +24,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.Activity;
-import android.app.ActivityManager;
import android.app.AppGlobals;
-import android.app.assist.AssistStructure;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -50,7 +44,6 @@
import android.service.autofill.AutofillServiceInfo;
import android.service.autofill.FillEventHistory;
import android.service.autofill.FillEventHistory.Event;
-import android.service.autofill.FillRequest;
import android.service.autofill.FillResponse;
import android.service.autofill.IAutoFillService;
import android.text.TextUtils;
@@ -66,7 +59,6 @@
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.HandlerCaller;
-import com.android.internal.os.IResultReceiver;
import com.android.server.autofill.ui.AutoFillUI;
import java.io.PrintWriter;
@@ -120,8 +112,6 @@
* <p>They're kept until the {@link AutofillService} finished handling a request, an error
* occurs, or the session times out.
*/
- // TODO(b/33197203): need to make sure service is bound while callback is pending and/or
- // use WeakReference
@GuardedBy("mLock")
private final SparseArray<Session> mSessions = new SparseArray<>();
@@ -129,59 +119,6 @@
@GuardedBy("mLock")
private FillEventHistory mEventHistory;
- /**
- * Receiver of assist data from the app's {@link Activity}.
- */
- private final IResultReceiver mAssistReceiver = new IResultReceiver.Stub() {
- @Override
- public void send(int resultCode, Bundle resultData) throws RemoteException {
- if (VERBOSE) {
- Slog.v(TAG, "resultCode on mAssistReceiver: " + resultCode);
- }
-
- final AssistStructure structure = resultData.getParcelable(KEY_STRUCTURE);
- if (structure == null) {
- Slog.wtf(TAG, "no assist structure for id " + resultCode);
- return;
- }
-
- final Bundle receiverExtras = resultData.getBundle(KEY_RECEIVER_EXTRAS);
- if (receiverExtras == null) {
- Slog.wtf(TAG, "No " + KEY_RECEIVER_EXTRAS + " on receiver");
- return;
- }
-
- final int sessionId = receiverExtras.getInt(EXTRA_SESSION_ID);
- final Session session;
- synchronized (mLock) {
- session = mSessions.get(sessionId);
- if (session == null) {
- Slog.w(TAG, "no server session for " + sessionId);
- return;
- }
- // TODO(b/33197203): since service is fetching the data (to use for save later),
- // we should optimize what's sent (for example, remove layout containers,
- // color / font info, etc...)
- session.setStructureLocked(structure);
- }
-
-
- // TODO(b/33197203, b/33269702): Must fetch the data so it's available later on
- // handleSave(), even if if the activity is gone by then, but structure.ensureData()
- // gives a ONE_WAY warning because system_service could block on app calls.
- // We need to change AssistStructure so it provides a "one-way" writeToParcel()
- // method that sends all the data
- structure.ensureData();
-
- // Sanitize structure before it's sent to service.
- structure.sanitizeForParceling(true);
-
- // TODO(b/33197203): Need to pipe the bundle
- FillRequest request = new FillRequest(structure, null, session.mFlags);
- session.mRemoteFillService.onFillRequest(request);
- }
- };
-
AutofillManagerServiceImpl(Context context, Object lock, LocalLog requestsHistory,
int userId, AutoFillUI ui, boolean disabled) {
mContext = context;
@@ -193,11 +130,10 @@
}
CharSequence getServiceName() {
- if (mInfo == null) {
+ final String packageName = getPackageName();
+ if (packageName == null) {
return null;
}
- final ComponentName serviceComponent = mInfo.getServiceInfo().getComponentName();
- final String packageName = serviceComponent.getPackageName();
try {
final PackageManager pm = mContext.getPackageManager();
@@ -209,6 +145,14 @@
}
}
+ String getPackageName() {
+ if (mInfo == null) {
+ return null;
+ }
+ final ComponentName serviceComponent = mInfo.getServiceInfo().getComponentName();
+ return serviceComponent.getPackageName();
+ }
+
private String getComponentNameFromSettings() {
return Settings.Secure.getStringForUser(
mContext.getContentResolver(), Settings.Secure.AUTOFILL_SERVICE, mUserId);
@@ -398,28 +342,6 @@
mInfo.getServiceInfo().getComponentName(), packageName);
mSessions.put(newSession.id, newSession);
- /*
- * TODO(b/33197203): apply security checks below:
- * - checks if disabled by secure settings / device policy
- * - log operation using noteOp()
- * - check flags
- * - display disclosure if needed
- */
- try {
- final Bundle receiverExtras = new Bundle();
- receiverExtras.putInt(EXTRA_SESSION_ID, sessionId);
- final long identity = Binder.clearCallingIdentity();
- try {
- if (!ActivityManager.getService().requestAutofillData(mAssistReceiver,
- receiverExtras, activityToken)) {
- Slog.w(TAG, "failed to request autofill data for " + activityToken);
- }
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- } catch (RemoteException e) {
- // Should not happen, it's a local call.
- }
return newSession;
}
diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
index 70e97c4..5964172 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -16,7 +16,12 @@
package com.android.server.autofill;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.assist.AssistStructure;
+import android.app.assist.AssistStructure.ViewNode;
import android.os.Bundle;
+import android.view.autofill.AutofillId;
import java.util.Arrays;
import java.util.Objects;
@@ -24,7 +29,8 @@
final class Helper {
- static final boolean DEBUG = true; // TODO(b/33197203): set to false when stable
+ // TODO(b/36141126): set to false and remove guard from places that should always be on
+ static final boolean DEBUG = true;
static final boolean VERBOSE = false;
static void append(StringBuilder builder, Bundle bundle) {
@@ -52,4 +58,37 @@
private Helper() {
throw new UnsupportedOperationException("contains static members only");
}
+
+ static ViewNode findViewNodeById(@NonNull AssistStructure structure, @NonNull AutofillId id) {
+ final int size = structure.getWindowNodeCount();
+ for (int i = 0; i < size; i++) {
+ final AssistStructure.WindowNode window = structure.getWindowNodeAt(i);
+ final ViewNode root = window.getRootViewNode();
+ if (id.equals(root.getAutofillId())) {
+ return root;
+ }
+ final ViewNode child = findViewNodeById(root, id);
+ if (child != null) {
+ return child;
+ }
+ }
+ return null;
+ }
+
+ static ViewNode findViewNodeById(@NonNull ViewNode parent, @NonNull AutofillId id) {
+ final int childrenSize = parent.getChildCount();
+ if (childrenSize > 0) {
+ for (int i = 0; i < childrenSize; i++) {
+ final ViewNode child = parent.getChildAt(i);
+ if (id.equals(child.getAutofillId())) {
+ return child;
+ }
+ final ViewNode grandChild = findViewNodeById(child, id);
+ if (grandChild != null && id.equals(grandChild.getAutofillId())) {
+ return grandChild;
+ }
+ }
+ }
+ return null;
+ }
}
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index 4d0f380..432a092 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -134,6 +134,23 @@
mCallbacks.onServiceDied(this);
}
+ /**
+ * Cancel the currently pending request.
+ *
+ * <p>This can be used when the request is unnecessary or will be superceeded by a request that
+ * will soon be queued.
+ */
+ public void cancelCurrentRequest() {
+ if (mDestroyed) {
+ return;
+ }
+
+ if (mPendingRequest != null) {
+ mPendingRequest.cancel();
+ mPendingRequest = null;
+ }
+ }
+
public void onFillRequest(@NonNull FillRequest request) {
cancelScheduledUnbind();
final PendingFillRequest pendingRequest = new PendingFillRequest(request, this);
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 4bc3872..a00a397 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -18,6 +18,8 @@
package com.android.server.autofill;
import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
+import static android.service.voice.VoiceInteractionSession.KEY_RECEIVER_EXTRAS;
+import static android.service.voice.VoiceInteractionSession.KEY_STRUCTURE;
import static android.view.autofill.AutofillManager.FLAG_START_SESSION;
import static android.view.autofill.AutofillManager.FLAG_VALUE_CHANGED;
import static android.view.autofill.AutofillManager.FLAG_VIEW_ENTERED;
@@ -25,19 +27,22 @@
import static com.android.server.autofill.Helper.DEBUG;
import static com.android.server.autofill.Helper.VERBOSE;
+import static com.android.server.autofill.Helper.findViewNodeById;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.Activity;
+import android.app.ActivityManager;
import android.app.assist.AssistStructure;
import android.app.assist.AssistStructure.AutofillOverlay;
import android.app.assist.AssistStructure.ViewNode;
-import android.app.assist.AssistStructure.WindowNode;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
import android.graphics.Rect;
import android.metrics.LogMaker;
+import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcelable;
@@ -64,14 +69,16 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.os.HandlerCaller;
+import com.android.internal.os.IResultReceiver;
+import com.android.internal.util.ArrayUtils;
import com.android.server.autofill.ui.AutoFillUI;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* A session for a given activity.
@@ -85,14 +92,12 @@
* to fill the activity but it requires authentication first, that response need to be held
* until the user authenticates or it times out.
*/
-// TODO(b/33197203): make sure sessions are removed (and tested by CTS):
-// - On all authentication scenarios.
-// - When user does not interact back after a while.
-// - When service is unbound.
final class Session implements RemoteFillService.FillServiceCallbacks, ViewState.Listener,
AutoFillUI.AutoFillUiCallback {
private static final String TAG = "AutofillSession";
+ private static final String EXTRA_REQUEST_ID = "android.service.autofill.extra.REQUEST_ID";
+
private final AutofillManagerServiceImpl mService;
private final HandlerCaller mHandlerCaller;
private final Object mLock;
@@ -100,6 +105,8 @@
private final MetricsLogger mMetricsLogger = new MetricsLogger();
+ private static AtomicInteger sIdCounter = new AtomicInteger();
+
/** Id of the session */
public final int id;
@@ -127,8 +134,7 @@
@GuardedBy("mLock")
private IAutoFillManagerClient mClient;
- @GuardedBy("mLock")
- RemoteFillService mRemoteFillService;
+ private final RemoteFillService mRemoteFillService;
@GuardedBy("mLock")
private SparseArray<FillResponse> mResponses;
@@ -167,7 +173,124 @@
/**
* Flags used to start the session.
*/
- int mFlags;
+ private final int mFlags;
+
+ /**
+ * Receiver of assist data from the app's {@link Activity}.
+ */
+ private final IResultReceiver mAssistReceiver = new IResultReceiver.Stub() {
+ @Override
+ public void send(int resultCode, Bundle resultData) throws RemoteException {
+ if (VERBOSE) {
+ Slog.v(TAG, "resultCode on mAssistReceiver: " + resultCode);
+ }
+
+ final AssistStructure structure = resultData.getParcelable(KEY_STRUCTURE);
+ if (structure == null) {
+ Slog.wtf(TAG, "no assist structure for id " + resultCode);
+ return;
+ }
+
+ final Bundle receiverExtras = resultData.getBundle(KEY_RECEIVER_EXTRAS);
+ if (receiverExtras == null) {
+ Slog.wtf(TAG, "No " + KEY_RECEIVER_EXTRAS + " on receiver");
+ return;
+ }
+
+ final int requestId = receiverExtras.getInt(EXTRA_REQUEST_ID);
+
+ if (DEBUG) {
+ Slog.d(TAG, "New structure for requestId " + requestId + ": " + structure);
+ }
+
+ synchronized (mLock) {
+ // TODO(b/35708678): Must fetch the data so it's available later on handleSave(),
+ // even if if the activity is gone by then, but structure .ensureData() gives a
+ // ONE_WAY warning because system_service could block on app calls. We need to
+ // change AssistStructure so it provides a "one-way" writeToParcel() method that
+ // sends all the data
+ structure.ensureData();
+
+ // Sanitize structure before it's sent to service.
+ structure.sanitizeForParceling(true);
+
+ mStructure = structure;
+ }
+
+ fillStructureWithAllowedValues(mStructure);
+
+ FillRequest request = new FillRequest(requestId, mStructure, mClientState, mFlags);
+ mRemoteFillService.onFillRequest(request);
+ }
+ };
+
+ /**
+ * Updates values of the nodes in the structure so that:
+ * - proper node is focused
+ * - autofillValue is sent back to service when it was previously autofilled
+ *
+ * @param structure The structure to be filled
+ */
+ private void fillStructureWithAllowedValues(@NonNull AssistStructure structure) {
+ final int numViewStates = mViewStates.size();
+ for (int i = 0; i < numViewStates; i++) {
+ final ViewState viewState = mViewStates.valueAt(i);
+
+ final ViewNode node = findViewNodeById(structure, viewState.id);
+ if (node == null) {
+ if (DEBUG) {
+ Slog.w(TAG, "fillStructureWithAllowedValues(): no node for " + viewState.id);
+ }
+ continue;
+ }
+
+ final AutofillValue initialValue = viewState.getInitialValue();
+ final AutofillValue filledValue = viewState.getAutofilledValue();
+ final AutofillOverlay overlay = new AutofillOverlay();
+ if (filledValue != null && !filledValue.equals(initialValue)) {
+ overlay.value = filledValue;
+ }
+ if (mCurrentViewId != null) {
+ overlay.focused = mCurrentViewId.equals(viewState.id);
+ }
+
+ node.setAutofillOverlay(overlay);
+ }
+ }
+
+ /**
+ * Reads a new structure and then request a new fill response from the fill service.
+ */
+ private void requestNewFillResponseLocked() {
+ final int requestId = sIdCounter.getAndIncrement();
+
+ if (DEBUG) {
+ Slog.d(TAG, "Requesting structure for requestId " + requestId);
+ }
+
+ // If the focus changes very quickly before the first request is returned each focus change
+ // triggers a new partition and we end up with many duplicate partitions. This is
+ // enhanced as the focus change can be much faster than the taking of the assist structure.
+ // Hence remove the currently queued request and replace it with the one queued after the
+ // structure is taken. This causes only one fill request per bust of focus changes.
+ mRemoteFillService.cancelCurrentRequest();
+
+ try {
+ final Bundle receiverExtras = new Bundle();
+ receiverExtras.putInt(EXTRA_REQUEST_ID, requestId);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ if (!ActivityManager.getService().requestAutofillData(mAssistReceiver,
+ receiverExtras, mActivityToken)) {
+ Slog.w(TAG, "failed to request autofill data for " + mActivityToken);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ } catch (RemoteException e) {
+ // Should not happen, it's a local call.
+ }
+ }
Session(@NonNull AutofillManagerServiceImpl service, @NonNull AutoFillUI ui,
@NonNull Context context, @NonNull HandlerCaller handlerCaller, int userId,
@@ -251,7 +374,7 @@
}
synchronized (mLock) {
if (response.getAuthentication() != null) {
- // TODO(b/33197203 , b/35707731): make sure it's ignored if there is one already
+ // TODO(b/37424539): proper implementation
mResponseWaitingAuth = response;
}
processResponseLocked(response, requestId);
@@ -326,7 +449,7 @@
// FillServiceCallbacks
@Override
public void onServiceDied(RemoteFillService service) {
- // TODO(b/33197203): implement
+ // TODO(b/337565347): implement
}
// AutoFillUiCallback
@@ -437,10 +560,6 @@
mHasCallback = hasIt;
}
- public void setStructureLocked(AssistStructure structure) {
- mStructure = structure;
- }
-
/**
* Shows the save UI, when session can be saved.
*
@@ -579,7 +698,7 @@
continue;
}
final AutofillId id = entry.getKey();
- final ViewNode node = findViewNodeByIdLocked(id);
+ final ViewNode node = findViewNodeById(mStructure, id);
if (node == null) {
Slog.w(TAG, "callSaveLocked(): did not find node with id " + id);
continue;
@@ -599,7 +718,7 @@
mStructure.dump();
}
- // TODO(b/33197203): Implement partitioning properly
+ // TODO(b/37426206): Implement partitioning properly
final int lastResponseIdx = getLastResponseIndex();
final int requestId = mResponses.keyAt(lastResponseIdx);
final FillContext fillContext = new FillContext(requestId, mStructure);
@@ -610,24 +729,61 @@
mRemoteFillService.onSaveRequest(saveRequest);
}
+ /**
+ * Determines if a new partition should be started for an id.
+ *
+ * @param id The id of the view that is entered
+ *
+ * @return {@code true} iff a new partition should be started
+ */
+ private boolean shouldStartNewPartitionLocked(@NonNull AutofillId id) {
+ if (mResponses == null) {
+ return true;
+ }
+
+ final int numResponses = mResponses.size();
+ for (int responseNum = 0; responseNum < numResponses; responseNum++) {
+ final FillResponse response = mResponses.valueAt(responseNum);
+
+ if (ArrayUtils.contains(response.getIgnoredIds(), id)) {
+ return false;
+ }
+
+ final SaveInfo saveInfo = response.getSaveInfo();
+ if (saveInfo != null) {
+ if (ArrayUtils.contains(saveInfo.getOptionalIds(), id)
+ || ArrayUtils.contains(saveInfo.getRequiredIds(), id)) {
+ return false;
+ }
+ }
+
+ final ArrayList<Dataset> datasets = response.getDatasets();
+ if (datasets != null) {
+ final int numDatasets = datasets.size();
+
+ for (int dataSetNum = 0; dataSetNum < numDatasets; dataSetNum++) {
+ final ArrayList fields = datasets.get(dataSetNum).getFieldIds();
+
+ if (fields != null && fields.contains(id)) {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
void updateLocked(AutofillId id, Rect virtualBounds, AutofillValue value, int flags) {
ViewState viewState = mViewStates.get(id);
if (viewState == null) {
- if ((flags & (FLAG_START_SESSION | FLAG_VALUE_CHANGED)) != 0) {
+ if ((flags & (FLAG_START_SESSION | FLAG_VALUE_CHANGED | FLAG_VIEW_ENTERED)) != 0) {
if (DEBUG) {
Slog.d(TAG, "Creating viewState for " + id + " on " + getFlagAsString(flags));
}
viewState = new ViewState(this, id, value, this, ViewState.STATE_INITIAL);
mViewStates.put(id, viewState);
- } else if (mStructure != null && (flags & FLAG_VIEW_ENTERED) != 0) {
- if (isIgnoredLocked(id)) {
- if (DEBUG) {
- Slog.d(TAG, "Not starting partition for ignored view id " + id);
- }
- return;
- }
- viewState = startPartitionLocked(id, value);
} else {
if (VERBOSE) Slog.v(TAG, "Ignored " + getFlagAsString(flags) + " for " + id);
return;
@@ -639,6 +795,7 @@
mCurrentViewId = viewState.id;
viewState.update(value, virtualBounds);
viewState.setState(ViewState.STATE_STARTED_SESSION);
+ requestNewFillResponseLocked();
return;
}
@@ -668,6 +825,19 @@
}
if ((flags & FLAG_VIEW_ENTERED) != 0) {
+ if (shouldStartNewPartitionLocked(id)) {
+ // TODO(b/37424539): proper implementation
+ if (mResponseWaitingAuth != null && ((flags & FLAG_START_SESSION) == 0)) {
+ viewState.setState(ViewState.STATE_WAITING_RESPONSE_AUTH);
+ } else if ((flags & FLAG_START_SESSION) == 0){
+ if (DEBUG) {
+ Slog.d(TAG, "Starting partition for view id " + viewState.id);
+ }
+ viewState.setState(ViewState.STATE_STARTED_PARTITION);
+ requestNewFillResponseLocked();
+ }
+ }
+
// Remove the UI if the ViewState has changed.
if (mCurrentViewId != viewState.id) {
mUi.hideFillUi(mCurrentViewId != null ? mCurrentViewId : null);
@@ -691,49 +861,6 @@
Slog.w(TAG, "updateLocked(): unknown flags " + flags + ": " + getFlagAsString(flags));
}
- private ViewState startPartitionLocked(AutofillId id, AutofillValue value) {
- // TODO(b/33197203 , b/35707731): temporary workaround until partitioning supports auth
- if (mResponseWaitingAuth != null) {
- final ViewState viewState =
- new ViewState(this, id, value, this, ViewState.STATE_WAITING_RESPONSE_AUTH);
- mViewStates.put(id, viewState);
- return viewState;
- }
- if (DEBUG) {
- Slog.d(TAG, "Starting partition for view id " + id);
- }
- final ViewState newViewState =
- new ViewState(this, id, value, this,ViewState.STATE_STARTED_PARTITION);
- mViewStates.put(id, newViewState);
-
- // Must update value of nodes so:
- // - proper node is focused
- // - autofillValue is sent back to service when it was previously autofilled
- for (int i = 0; i < mViewStates.size(); i++) {
- final ViewState viewState = mViewStates.valueAt(i);
-
- final ViewNode node = findViewNodeByIdLocked(viewState.id);
- if (node == null) {
- Slog.w(TAG, "startPartitionLocked(): no node for " + viewState.id);
- continue;
- }
-
- final AutofillValue initialValue = viewState.getInitialValue();
- final AutofillValue filledValue = viewState.getAutofilledValue();
- final AutofillOverlay overlay = new AutofillOverlay();
- if (filledValue != null && !filledValue.equals(initialValue)) {
- overlay.value = filledValue;
- }
- overlay.focused = id.equals(viewState.id);
- node.setAutofillOverlay(overlay);
- }
-
- FillRequest request = new FillRequest(mStructure, mClientState, 0);
- mRemoteFillService.onFillRequest(request);
-
- return newViewState;
- }
-
@Override
public void onFillReady(FillResponse response, AutofillId filledId,
@Nullable AutofillValue value) {
@@ -751,11 +878,6 @@
private void notifyUnavailableToClient() {
synchronized (mLock) {
- if (mCurrentViewId == null) {
- // TODO(b/33197203): temporary sanity check; should never happen
- Slog.w(TAG, "notifyUnavailable(): mCurrentViewId is null");
- return;
- }
if (!mHasCallback) return;
try {
mClient.notifyNoFillUi(id, mWindowToken, mCurrentViewId);
@@ -922,7 +1044,7 @@
}
// ...or handle authentication.
- // TODO(b/33197203 , b/35707731): make sure it's ignored if there is one already
+ // TODO(b/37424539): proper implementation
mService.setDatasetAuthenticationSelected(dataset.getId());
mDatasetWaitingAuth = dataset;
setViewStatesLocked(null, dataset, ViewState.STATE_WAITING_DATASET_AUTH);
@@ -958,23 +1080,6 @@
}
}
- private boolean isIgnoredLocked(@NonNull AutofillId id) {
- if (mResponses == null) return false;
-
- for (int i = mResponses.size() - 1; i >= 0; i--) {
- final FillResponse response = mResponses.valueAt(i);
- final AutofillId[] ignoredIds = response.getIgnoredIds();
- if (ignoredIds == null) continue;
- for (int j = 0; j < ignoredIds.length; j++) {
- final AutofillId ignoredId = ignoredIds[j];
- if (ignoredId != null && ignoredId.equals(id)) {
- return true;
- }
- }
- }
- return false;
- }
-
void dumpLocked(String prefix, PrintWriter pw) {
pw.print(prefix); pw.print("id: "); pw.println(id);
pw.print(prefix); pw.print("uid: "); pw.println(uid);
@@ -992,7 +1097,7 @@
}
if (VERBOSE) {
pw.print(prefix); pw.print("mStructure: " );
- // TODO(b/33197203): add method do dump AssistStructure on pw
+ // TODO: add method on AssistStructure to dump on pw
if (mStructure != null) {
pw.println("look at logcat" );
mStructure.dump(); // dumps to logcat
@@ -1027,39 +1132,6 @@
}
}
- private ViewNode findViewNodeByIdLocked(AutofillId id) {
- final int size = mStructure.getWindowNodeCount();
- for (int i = 0; i < size; i++) {
- final WindowNode window = mStructure.getWindowNodeAt(i);
- final ViewNode root = window.getRootViewNode();
- if (id.equals(root.getAutofillId())) {
- return root;
- }
- final ViewNode child = findViewNodeByIdLocked(root, id);
- if (child != null) {
- return child;
- }
- }
- return null;
- }
-
- private ViewNode findViewNodeByIdLocked(ViewNode parent, AutofillId id) {
- final int childrenSize = parent.getChildCount();
- if (childrenSize > 0) {
- for (int i = 0; i < childrenSize; i++) {
- final ViewNode child = parent.getChildAt(i);
- if (id.equals(child.getAutofillId())) {
- return child;
- }
- final ViewNode grandChild = findViewNodeByIdLocked(child, id);
- if (grandChild != null && id.equals(grandChild.getAutofillId())) {
- return grandChild;
- }
- }
- }
- return null;
- }
-
void destroyLocked() {
mRemoteFillService.destroy();
mUi.setCallback(null);
diff --git a/services/autofill/java/com/android/server/autofill/ViewState.java b/services/autofill/java/com/android/server/autofill/ViewState.java
index ea5f113..3967f59 100644
--- a/services/autofill/java/com/android/server/autofill/ViewState.java
+++ b/services/autofill/java/com/android/server/autofill/ViewState.java
@@ -61,7 +61,7 @@
public static final int STATE_STARTED_PARTITION = 0x20;
/** User select a dataset in this view, but service must authenticate first. */
public static final int STATE_WAITING_DATASET_AUTH = 0x40;
- // TODO(b/33197203 , b/35707731): temporary workaround until partitioning supports auth
+ // TODO(b/37424539): temporary workaround until partitioning supports auth
public static final int STATE_WAITING_RESPONSE_AUTH = 0x80;
public final AutofillId id;
@@ -151,9 +151,9 @@
mState &= ~state;
}
- // TODO(b/33197203): need to refactor / rename / document this method to make it clear that
- // it can change the value and update the UI; similarly, should replace code that
- // directly sets mAutoFilLValue to use encapsulation.
+ // TODO: refactor / rename / document this method (and maybeCallOnFillReady) to make it clear
+ // that it can change the value and update the UI; similarly, should replace code that
+ // directly sets mAutofillValue to use encapsulation.
void update(@Nullable AutofillValue autofillValue, @Nullable Rect virtualBounds) {
if (autofillValue != null) {
mCurrentValue = autofillValue;
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index b68e3b1..bb47e5b 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -117,7 +117,7 @@
final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
content.measure(widthMeasureSpec, heightMeasureSpec);
decor.setOnClickListener(v -> mCallback.onResponsePicked(response));
- // TODO(b/33197203 , b/36660292): temporary limiting maximum height and minimum width
+ // TODO(b/37567439): temporary limiting maximum height and minimum width
mContentWidth = Math.max(content.getMeasuredWidth(), 1000);
mContentHeight = Math.min(content.getMeasuredHeight(), 500);
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 41b70a1..9bb0f86 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -36,6 +36,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.content.pm.FeatureInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.NetworkPolicyManager;
@@ -203,13 +204,15 @@
checkNotNull(request, "Request cannot be null");
checkNotNull(callback, "Callback cannot be null");
checkCallerIsSystemOr(callingPackage);
+ int userId = getCallingUserId();
+ checkUsesFeature(callingPackage, userId);
final long callingIdentity = Binder.clearCallingIdentity();
try {
- //TODO bindServiceAsUser
- getContext().bindService(
+ getContext().bindServiceAsUser(
new Intent().setComponent(SERVICE_TO_BIND_TO),
createServiceConnection(request, callback, callingPackage),
- Context.BIND_AUTO_CREATE);
+ Context.BIND_AUTO_CREATE,
+ UserHandle.of(userId));
} finally {
Binder.restoreCallingIdentity(callingIdentity);
}
@@ -219,6 +222,7 @@
public List<String> getAssociations(String callingPackage, int userId)
throws RemoteException {
checkCallerIsSystemOr(callingPackage, userId);
+ checkUsesFeature(callingPackage, getCallingUserId());
return CollectionUtils.map(
readAllAssociations(userId, callingPackage),
a -> a.deviceAddress);
@@ -230,6 +234,7 @@
throws RemoteException {
checkNotNull(deviceMacAddress);
checkCallerIsSystemOr(callingPackage);
+ checkUsesFeature(callingPackage, getCallingUserId());
updateAssociations(associations -> CollectionUtils.remove(associations,
new Association(getCallingUserId(), deviceMacAddress, callingPackage)));
}
@@ -282,12 +287,25 @@
private void checkCanCallNotificationApi(String callingPackage) throws RemoteException {
checkCallerIsSystemOr(callingPackage);
- checkState(!ArrayUtils.isEmpty(readAllAssociations(getCallingUserId(), callingPackage)),
+ int userId = getCallingUserId();
+ checkState(!ArrayUtils.isEmpty(readAllAssociations(userId, callingPackage)),
"App must have an association before calling this API");
+ checkUsesFeature(callingPackage, userId);
+ }
+
+ private void checkUsesFeature(String pkg, int userId) {
+ FeatureInfo[] reqFeatures = getPackageInfo(pkg, userId).reqFeatures;
+ String requiredFeature = PackageManager.FEATURE_COMPANION_DEVICE_SETUP;
+ int numFeatures = ArrayUtils.size(reqFeatures);
+ for (int i = 0; i < numFeatures; i++) {
+ if (requiredFeature.equals(reqFeatures[i].name)) return;
+ }
+ throw new IllegalStateException("Must declare uses-feature "
+ + requiredFeature
+ + " in manifest to use this API");
}
}
-
private int getCallingUserId() {
return UserHandle.getUserId(Binder.getCallingUid());
}
@@ -398,7 +416,9 @@
return Binder.withCleanCallingIdentity(() -> {
try {
return getContext().getPackageManager().getPackageInfoAsUser(
- packageName, PackageManager.GET_PERMISSIONS, userId);
+ packageName,
+ PackageManager.GET_PERMISSIONS | PackageManager.GET_CONFIGURATIONS,
+ userId);
} catch (PackageManager.NameNotFoundException e) {
Slog.e(LOG_TAG, "Failed to get PackageInfo for package " + packageName, e);
return null;
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index d25b3cc..114d761 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -16,9 +16,6 @@
package com.android.server;
-import static android.net.NetworkRecommendationProvider.EXTRA_RECOMMENDATION_RESULT;
-import static android.net.NetworkRecommendationProvider.EXTRA_SEQUENCE;
-
import android.Manifest.permission;
import android.annotation.Nullable;
import android.content.BroadcastReceiver;
@@ -36,8 +33,6 @@
import android.net.NetworkKey;
import android.net.NetworkScoreManager;
import android.net.NetworkScorerAppData;
-import android.net.RecommendationRequest;
-import android.net.RecommendationResult;
import android.net.ScoredNetwork;
import android.net.Uri;
import android.net.wifi.ScanResult;
@@ -46,24 +41,18 @@
import android.net.wifi.WifiScanner;
import android.os.Binder;
import android.os.Build;
-import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
-import android.os.IRemoteCallback;
import android.os.Looper;
import android.os.Message;
import android.os.Process;
-import android.os.RemoteCallback;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.provider.Settings;
import android.provider.Settings.Global;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
-import android.util.Pair;
-import android.util.TimedRemoteCaller;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -80,9 +69,6 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.concurrent.TimeoutException;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Supplier;
@@ -99,7 +85,6 @@
private final Context mContext;
private final NetworkScorerAppManager mNetworkScorerAppManager;
- private final AtomicReference<RequestRecommendationCaller> mReqRecommendationCallerRef;
@GuardedBy("mScoreCaches")
private final Map<Integer, RemoteCallbackList<INetworkScoreCache>> mScoreCaches;
/** Lock used to update mPackageMonitor when scorer package changes occur. */
@@ -113,7 +98,6 @@
private NetworkScorerPackageMonitor mPackageMonitor;
@GuardedBy("mServiceConnectionLock")
private ScoringServiceConnection mServiceConnection;
- private volatile long mRecommendationRequestTimeoutMs;
private BroadcastReceiver mUserIntentReceiver = new BroadcastReceiver() {
@Override
@@ -256,9 +240,6 @@
mContext.registerReceiverAsUser(
mUserIntentReceiver, UserHandle.SYSTEM, filter, null /* broadcastPermission*/,
null /* scheduler */);
- mReqRecommendationCallerRef = new AtomicReference<>(
- new RequestRecommendationCaller(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS));
- mRecommendationRequestTimeoutMs = TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS;
mHandler = new ServiceHandler(looper);
mContentObserver = new DispatchingContentObserver(context, mHandler);
mServiceConnProducer = serviceConnProducer;
@@ -295,10 +276,6 @@
mContentObserver.observe(packageNameUri,
ServiceHandler.MSG_RECOMMENDATIONS_PACKAGE_CHANGED);
- final Uri timeoutUri = Global.getUriFor(Global.NETWORK_RECOMMENDATION_REQUEST_TIMEOUT_MS);
- mContentObserver.observe(timeoutUri,
- ServiceHandler.MSG_RECOMMENDATION_REQUEST_TIMEOUT_CHANGED);
-
final Uri settingUri = Global.getUriFor(Global.NETWORK_RECOMMENDATIONS_ENABLED);
mContentObserver.observe(settingUri,
ServiceHandler.MSG_RECOMMENDATION_ENABLED_SETTING_CHANGED);
@@ -827,87 +804,6 @@
}
@Override
- public RecommendationResult requestRecommendation(RecommendationRequest request) {
- mContext.enforceCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES, TAG);
- throwIfCalledOnMainThread();
- final long token = Binder.clearCallingIdentity();
- try {
- final INetworkRecommendationProvider provider = getRecommendationProvider();
- if (provider != null) {
- try {
- final RequestRecommendationCaller caller = mReqRecommendationCallerRef.get();
- return caller.getRecommendationResult(provider, request);
- } catch (RemoteException | TimeoutException e) {
- Log.w(TAG, "Failed to request a recommendation.", e);
- // TODO: 12/15/16 - Keep track of failures.
- }
- }
-
- if (DBG) {
- Log.d(TAG, "Returning the default network recommendation.");
- }
-
- if (request != null && request.getDefaultWifiConfig() != null) {
- return RecommendationResult.createConnectRecommendation(
- request.getDefaultWifiConfig());
- }
- return RecommendationResult.createDoNotConnectRecommendation();
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- /**
- * Request a recommendation for the best network to connect to
- * taking into account the inputs from the {@link RecommendationRequest}.
- *
- * @param request a {@link RecommendationRequest} instance containing the details of the request
- * @param remoteCallback a {@link IRemoteCallback} instance to invoke when the recommendation
- * is available.
- * @throws SecurityException if the caller is not the system
- */
- @Override
- public void requestRecommendationAsync(RecommendationRequest request,
- RemoteCallback remoteCallback) {
- mContext.enforceCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES, TAG);
-
- final OneTimeCallback oneTimeCallback = new OneTimeCallback(remoteCallback);
- final Pair<RecommendationRequest, OneTimeCallback> pair =
- Pair.create(request, oneTimeCallback);
- final Message timeoutMsg = mHandler.obtainMessage(
- ServiceHandler.MSG_RECOMMENDATION_REQUEST_TIMEOUT, pair);
- final INetworkRecommendationProvider provider = getRecommendationProvider();
- final long token = Binder.clearCallingIdentity();
- try {
- if (provider != null) {
- try {
- mHandler.sendMessageDelayed(timeoutMsg, mRecommendationRequestTimeoutMs);
- provider.requestRecommendation(request, new IRemoteCallback.Stub() {
- @Override
- public void sendResult(Bundle data) throws RemoteException {
- // Remove the timeout message
- mHandler.removeMessages(timeoutMsg.what, pair);
- oneTimeCallback.sendResult(data);
- }
- }, 0 /*sequence*/);
- return;
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to request a recommendation.", e);
- // TODO: 12/15/16 - Keep track of failures.
- // Remove the timeout message
- mHandler.removeMessages(timeoutMsg.what, pair);
- // Will fall through and send back the default recommendation.
- }
- }
- } finally {
- Binder.restoreCallingIdentity(token);
- }
-
- // Else send back the default recommendation.
- sendDefaultRecommendationResponse(request, oneTimeCallback);
- }
-
- @Override
public boolean requestScores(NetworkKey[] networks) {
mContext.enforceCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES, TAG);
final long token = Binder.clearCallingIdentity();
@@ -941,7 +837,6 @@
return;
}
writer.println("Current scorer: " + currentScorer);
- writer.println("RecommendationRequestTimeoutMs: " + mRecommendationRequestTimeoutMs);
sendCacheUpdateCallback(new BiConsumer<INetworkScoreCache, Object>() {
@Override
@@ -996,12 +891,6 @@
}
}
- private void throwIfCalledOnMainThread() {
- if (Thread.currentThread() == mContext.getMainLooper().getThread()) {
- throw new RuntimeException("Cannot invoke on the main thread");
- }
- }
-
@Nullable
private INetworkRecommendationProvider getRecommendationProvider() {
synchronized (mServiceConnectionLock) {
@@ -1012,19 +901,6 @@
return null;
}
- @VisibleForTesting
- public void refreshRecommendationRequestTimeoutMs() {
- final ContentResolver cr = mContext.getContentResolver();
- long timeoutMs = Settings.Global.getLong(cr,
- Global.NETWORK_RECOMMENDATION_REQUEST_TIMEOUT_MS, -1L /*default*/);
- if (timeoutMs < 0) {
- timeoutMs = TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS;
- }
- if (DBG) Log.d(TAG, "Updating the recommendation request timeout to " + timeoutMs + " ms");
- mRecommendationRequestTimeoutMs = timeoutMs;
- mReqRecommendationCallerRef.set(new RequestRecommendationCaller(timeoutMs));
- }
-
// The class and methods need to be public for Mockito to work.
@VisibleForTesting
public static class ScoringServiceConnection implements ServiceConnection {
@@ -1114,93 +990,10 @@
}
}
- /**
- * Executes the async requestRecommendation() call with a timeout.
- */
- private static final class RequestRecommendationCaller
- extends TimedRemoteCaller<RecommendationResult> {
- private final IRemoteCallback mCallback;
-
- RequestRecommendationCaller(long callTimeoutMillis) {
- super(callTimeoutMillis);
- mCallback = new IRemoteCallback.Stub() {
- @Override
- public void sendResult(Bundle data) throws RemoteException {
- final RecommendationResult result =
- data.getParcelable(EXTRA_RECOMMENDATION_RESULT);
- final int sequence = data.getInt(EXTRA_SEQUENCE, -1);
- if (VERBOSE) Log.v(TAG, "callback received for sequence " + sequence);
- onRemoteMethodResult(result, sequence);
- }
- };
- }
-
- /**
- * Runs the requestRecommendation() call on the given {@link INetworkRecommendationProvider}
- * instance.
- *
- * @param target the {@link INetworkRecommendationProvider} to request a recommendation
- * from
- * @param request the {@link RecommendationRequest} from the calling client
- * @return a {@link RecommendationResult} from the provider
- * @throws RemoteException if the call failed
- * @throws TimeoutException if the call took longer than the set timeout
- */
- RecommendationResult getRecommendationResult(INetworkRecommendationProvider target,
- RecommendationRequest request) throws RemoteException, TimeoutException {
- final int sequence = onBeforeRemoteCall();
- if (VERBOSE) Log.v(TAG, "getRecommendationResult() seq=" + sequence);
- target.requestRecommendation(request, mCallback, sequence);
- return getResultTimed(sequence);
- }
- }
-
- /**
- * A wrapper around {@link RemoteCallback} that guarantees
- * {@link RemoteCallback#sendResult(Bundle)} will be invoked at most once.
- */
- @VisibleForTesting
- public static final class OneTimeCallback {
- private final RemoteCallback mRemoteCallback;
- private final AtomicBoolean mCallbackRun;
-
- public OneTimeCallback(RemoteCallback remoteCallback) {
- mRemoteCallback = remoteCallback;
- mCallbackRun = new AtomicBoolean(false);
- }
-
- public void sendResult(Bundle data) {
- if (mCallbackRun.compareAndSet(false, true)) {
- mRemoteCallback.sendResult(data);
- }
- }
- }
-
- private static void sendDefaultRecommendationResponse(RecommendationRequest request,
- OneTimeCallback remoteCallback) {
- if (DBG) {
- Log.d(TAG, "Returning the default network recommendation.");
- }
-
- final RecommendationResult result;
- if (request != null && request.getDefaultWifiConfig() != null) {
- result = RecommendationResult.createConnectRecommendation(
- request.getDefaultWifiConfig());
- } else {
- result = RecommendationResult.createDoNotConnectRecommendation();
- }
-
- final Bundle data = new Bundle();
- data.putParcelable(EXTRA_RECOMMENDATION_RESULT, result);
- remoteCallback.sendResult(data);
- }
-
@VisibleForTesting
public final class ServiceHandler extends Handler {
- public static final int MSG_RECOMMENDATION_REQUEST_TIMEOUT = 1;
- public static final int MSG_RECOMMENDATIONS_PACKAGE_CHANGED = 2;
- public static final int MSG_RECOMMENDATION_REQUEST_TIMEOUT_CHANGED = 3;
- public static final int MSG_RECOMMENDATION_ENABLED_SETTING_CHANGED = 4;
+ public static final int MSG_RECOMMENDATIONS_PACKAGE_CHANGED = 1;
+ public static final int MSG_RECOMMENDATION_ENABLED_SETTING_CHANGED = 2;
public ServiceHandler(Looper looper) {
super(looper);
@@ -1210,26 +1003,11 @@
public void handleMessage(Message msg) {
final int what = msg.what;
switch (what) {
- case MSG_RECOMMENDATION_REQUEST_TIMEOUT:
- if (DBG) {
- Log.d(TAG, "Network recommendation request timed out.");
- }
- final Pair<RecommendationRequest, OneTimeCallback> pair =
- (Pair<RecommendationRequest, OneTimeCallback>) msg.obj;
- final RecommendationRequest request = pair.first;
- final OneTimeCallback remoteCallback = pair.second;
- sendDefaultRecommendationResponse(request, remoteCallback);
- break;
-
case MSG_RECOMMENDATIONS_PACKAGE_CHANGED:
case MSG_RECOMMENDATION_ENABLED_SETTING_CHANGED:
refreshBinding();
break;
- case MSG_RECOMMENDATION_REQUEST_TIMEOUT_CHANGED:
- refreshRecommendationRequestTimeoutMs();
- break;
-
default:
Log.w(TAG,"Unknown message: " + what);
}
diff --git a/services/core/java/com/android/server/SyntheticPasswordCrypto.java b/services/core/java/com/android/server/SyntheticPasswordCrypto.java
index 12d91c5..71ab2a5 100644
--- a/services/core/java/com/android/server/SyntheticPasswordCrypto.java
+++ b/services/core/java/com/android/server/SyntheticPasswordCrypto.java
@@ -139,12 +139,14 @@
keyStore.load(null);
KeyProtection.Builder builder = new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT)
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
- .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE);
+ .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+ .setCriticalToDeviceEncryption(true);
if (sid != 0) {
builder.setUserAuthenticationRequired(true)
.setBoundToSpecificSecureUserId(sid)
.setUserAuthenticationValidityDurationSeconds(USER_AUTHENTICATION_VALIDITY);
}
+
keyStore.setEntry(keyAlias,
new KeyStore.SecretKeyEntry(secretKey),
builder.build());
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index adb55b9..018e41b 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -112,6 +112,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
@@ -752,10 +753,12 @@
synchronized (accounts.dbLock) {
synchronized (accounts.cacheLock) {
Map<String, Integer> packagesToVisibility;
+ List<String> accountRemovedReceivers;
if (notify) {
if (isSpecialPackageKey(packageName)) {
packagesToVisibility =
getRequestingPackages(account, accounts);
+ accountRemovedReceivers = getAccountRemovedReceivers(account, accounts);
} else {
if (!packageExistsForUser(packageName, accounts.userId)) {
return false; // package is not installed.
@@ -763,15 +766,20 @@
packagesToVisibility = new HashMap<>();
packagesToVisibility.put(packageName,
resolveAccountVisibility(account, packageName, accounts));
+ accountRemovedReceivers = new ArrayList<>();
+ if (shouldNotifyPackageOnAccountRemoval(account, packageName, accounts)) {
+ accountRemovedReceivers.add(packageName);
+ }
}
} else {
- // Notifications will not be send.
+ // Notifications will not be send - only used during add account.
if (!isSpecialPackageKey(packageName) &&
!packageExistsForUser(packageName, accounts.userId)) {
// package is not installed and not meta value.
return false;
}
- packagesToVisibility = new HashMap<>();
+ packagesToVisibility = Collections.emptyMap();
+ accountRemovedReceivers = Collections.emptyList();
}
if (!updateAccountVisibilityLocked(account, packageName, newVisibility, accounts)) {
@@ -781,11 +789,14 @@
if (notify) {
for (Entry<String, Integer> packageToVisibility : packagesToVisibility
.entrySet()) {
- if (packageToVisibility.getValue()
- != AccountManager.VISIBILITY_NOT_VISIBLE) {
+ if (shouldNotifyOnVisibilityChange(packageToVisibility.getValue(),
+ resolveAccountVisibility(account, packageName, accounts))) {
notifyPackage(packageToVisibility.getKey(), accounts);
}
}
+ for (String packageNameToNotify : accountRemovedReceivers) {
+ sendAccountRemovedBroadcast(account, packageNameToNotify, accounts.userId);
+ }
sendAccountsChangedBroadcast(accounts.userId);
}
return true;
@@ -889,10 +900,11 @@
// Send notification to all packages which can potentially see the account
private void sendNotificationAccountUpdated(Account account, UserAccounts accounts) {
Map<String, Integer> packagesToVisibility = getRequestingPackages(account, accounts);
- // packages with VISIBILITY_USER_MANAGED_NOT_VISIBL still get notification.
- // Should we notify VISIBILITY_NOT_VISIBLE packages when account is added?
+
for (Entry<String, Integer> packageToVisibility : packagesToVisibility.entrySet()) {
- if (packageToVisibility.getValue() != AccountManager.VISIBILITY_NOT_VISIBLE) {
+ if ((packageToVisibility.getValue() != AccountManager.VISIBILITY_NOT_VISIBLE)
+ && (packageToVisibility.getValue()
+ != AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE)) {
notifyPackage(packageToVisibility.getKey(), accounts);
}
}
@@ -931,6 +943,44 @@
return result;
}
+ // Returns a list of packages listening to ACTION_ACCOUNT_REMOVED able to see the account.
+ private List<String> getAccountRemovedReceivers(Account account, UserAccounts accounts) {
+ Intent intent = new Intent(AccountManager.ACTION_ACCOUNT_REMOVED);
+ intent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+ List<ResolveInfo> receivers =
+ mPackageManager.queryBroadcastReceiversAsUser(intent, 0, accounts.userId);
+ List<String> result = new ArrayList<>();
+ if (receivers == null) {
+ return result;
+ }
+ for (ResolveInfo resolveInfo: receivers) {
+ String packageName = resolveInfo.activityInfo.applicationInfo.packageName;
+ int visibility = resolveAccountVisibility(account, packageName, accounts);
+ if (visibility == AccountManager.VISIBILITY_VISIBLE
+ || visibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE) {
+ result.add(packageName);
+ }
+ }
+ return result;
+ }
+
+ // Returns true if given package is listening to ACTION_ACCOUNT_REMOVED and can see the account.
+ private boolean shouldNotifyPackageOnAccountRemoval(Account account,
+ String packageName, UserAccounts accounts) {
+ int visibility = resolveAccountVisibility(account, packageName, accounts);
+ if (visibility != AccountManager.VISIBILITY_VISIBLE
+ && visibility != AccountManager.VISIBILITY_USER_MANAGED_VISIBLE) {
+ return false;
+ }
+
+ Intent intent = new Intent(AccountManager.ACTION_ACCOUNT_REMOVED);
+ intent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+ intent.setPackage(packageName);
+ List<ResolveInfo> receivers =
+ mPackageManager.queryBroadcastReceiversAsUser(intent, 0, accounts.userId);
+ return (receivers != null && receivers.size() > 0);
+ }
+
private boolean packageExistsForUser(String packageName, int userId) {
try {
long identityToken = clearCallingIdentity();
@@ -959,9 +1009,12 @@
mContext.sendBroadcastAsUser(ACCOUNTS_CHANGED_INTENT, new UserHandle(userId));
}
- private void sendAccountRemovedBroadcast(int userId) {
+ private void sendAccountRemovedBroadcast(Account account, String packageName, int userId) {
Intent intent = new Intent(AccountManager.ACTION_ACCOUNT_REMOVED);
intent.setFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+ intent.setPackage(packageName);
+ intent.putExtra(AccountManager.KEY_ACCOUNT_NAME, account.name);
+ intent.putExtra(AccountManager.KEY_ACCOUNT_TYPE, account.type);
mContext.sendBroadcastAsUser(intent, new UserHandle(userId));
}
@@ -1087,6 +1140,8 @@
+ "'s registered authenticator no longer exist.");
Map<String, Integer> packagesToVisibility =
getRequestingPackages(account, accounts);
+ List<String> accountRemovedReceivers =
+ getAccountRemovedReceivers(account, accounts);
accountsDb.beginTransaction();
try {
accountsDb.deleteDeAccount(accountId);
@@ -1112,12 +1167,14 @@
for (Entry<String, Integer> packageToVisibility :
packagesToVisibility.entrySet()) {
- if (packageToVisibility.getValue()
- != AccountManager.VISIBILITY_NOT_VISIBLE) {
+ if (shouldNotifyOnVisibilityChange(packageToVisibility.getValue(),
+ AccountManager.VISIBILITY_NOT_VISIBLE)) {
notifyPackage(packageToVisibility.getKey(), accounts);
}
}
- sendAccountRemovedBroadcast(accounts.userId);
+ for (String packageName : accountRemovedReceivers) {
+ sendAccountRemovedBroadcast(account, packageName, accounts.userId);
+ }
} else {
ArrayList<String> accountNames = accountNamesByType.get(account.type);
if (accountNames == null) {
@@ -1147,6 +1204,14 @@
}
}
+ private boolean shouldNotifyOnVisibilityChange(int oldVisibility, int newVisibility) {
+ boolean oldVisible = (oldVisibility == AccountManager.VISIBILITY_VISIBLE) ||
+ (oldVisibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
+ boolean newVisible = (newVisibility == AccountManager.VISIBILITY_VISIBLE) ||
+ (newVisibility == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
+ return oldVisible == newVisible;
+ }
+
private SparseBooleanArray getUidsOfInstalledOrUpdatedPackagesAsUser(int userId) {
// Get the UIDs of all apps that might have data on the device. We want
// to preserve user data if the app might otherwise be storing data.
@@ -1911,6 +1976,8 @@
}
synchronized (accounts.dbLock) {
synchronized (accounts.cacheLock) {
+ List<String> accountRemovedReceivers =
+ getAccountRemovedReceivers(accountToRename, accounts);
accounts.accountsDb.beginTransaction();
Account renamedAccount = new Account(newName, accountToRename.type);
if ((accounts.accountsDb.findCeAccountId(renamedAccount) >= 0)) {
@@ -1978,7 +2045,9 @@
sendNotificationAccountUpdated(resultAccount, accounts);
sendAccountsChangedBroadcast(accounts.userId);
- sendAccountRemovedBroadcast(accounts.userId);
+ for (String packageName : accountRemovedReceivers) {
+ sendAccountRemovedBroadcast(accountToRename, packageName, accounts.userId);
+ }
}
}
return resultAccount;
@@ -2181,6 +2250,8 @@
synchronized (accounts.cacheLock) {
Map<String, Integer> packagesToVisibility = getRequestingPackages(account,
accounts);
+ List<String> accountRemovedReceivers =
+ getAccountRemovedReceivers(account, accounts);
accounts.accountsDb.beginTransaction();
// Set to a dummy value, this will only be used if the database
// transaction succeeds.
@@ -2206,15 +2277,18 @@
removeAccountFromCacheLocked(accounts, account);
for (Entry<String, Integer> packageToVisibility : packagesToVisibility
.entrySet()) {
- if (packageToVisibility.getValue()
- != AccountManager.VISIBILITY_NOT_VISIBLE) {
+ if ((packageToVisibility.getValue() == AccountManager.VISIBILITY_VISIBLE)
+ || (packageToVisibility.getValue()
+ == AccountManager.VISIBILITY_USER_MANAGED_VISIBLE)) {
notifyPackage(packageToVisibility.getKey(), accounts);
}
}
// Only broadcast LOGIN_ACCOUNTS_CHANGED if a change occurred.
sendAccountsChangedBroadcast(accounts.userId);
- sendAccountRemovedBroadcast(accounts.userId);
+ for (String packageName : accountRemovedReceivers) {
+ sendAccountRemovedBroadcast(account, packageName, accounts.userId);
+ }
String action = userUnlocked ? AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE
: AccountsDb.DEBUG_ACTION_ACCOUNT_REMOVE_DE;
logRecord(action, AccountsDb.TABLE_ACCOUNTS, accountId, accounts);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index d99601c..45c2054 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -19146,6 +19146,12 @@
case android.security.KeyChain.ACTION_TRUST_STORE_CHANGED:
mHandler.sendEmptyMessage(HANDLE_TRUST_STORAGE_UPDATE_MSG);
break;
+ case "com.android.launcher.action.INSTALL_SHORTCUT":
+ // As of O, we no longer support this broadcasts, even for pre-O apps.
+ // Apps should now be using ShortcutManager.pinRequestShortcut().
+ Log.w(TAG, "Broadcast " + action
+ + " no longer supported. It will not be delivered.");
+ return ActivityManager.BROADCAST_SUCCESS;
}
if (Intent.ACTION_PACKAGE_ADDED.equals(action) ||
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 6e84ed6..3e0734f 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -274,11 +274,13 @@
// completed
boolean preserveWindowOnDeferredRelaunch; // activity windows are preserved on deferred relaunch
int configChangeFlags; // which config values have changed
- boolean keysPaused; // has key dispatching been paused for it?
+ private boolean keysPaused; // has key dispatching been paused for it?
int launchMode; // the launch mode activity attribute.
boolean visible; // does this activity's window need to be shown?
boolean visibleIgnoringKeyguard; // is this activity visible, ignoring the fact that Keyguard
// might hide this activity?
+ private boolean mDeferHidingClient; // If true we told WM to defer reporting to the client
+ // process that it is hidden.
boolean sleeping; // have we told the activity to sleep?
boolean nowVisible; // is this activity's window visible?
boolean idle; // has the activity gone idle?
@@ -523,6 +525,9 @@
else TimeUtils.formatDuration(lastVisibleTime, now, pw);
pw.println();
}
+ if (mDeferHidingClient) {
+ pw.println(prefix + "mDeferHidingClient=" + mDeferHidingClient);
+ }
if (deferRelaunchUntilPaused || configChangeFlags != 0) {
pw.print(prefix); pw.print("deferRelaunchUntilPaused="); pw.print(deferRelaunchUntilPaused);
pw.print(" configChangeFlags=");
@@ -1567,18 +1572,31 @@
return mWindowContainerController.screenshotApplications(getDisplayId(), w, h, scale);
}
+ void setDeferHidingClient(boolean deferHidingClient) {
+ if (mDeferHidingClient == deferHidingClient) {
+ return;
+ }
+ mDeferHidingClient = deferHidingClient;
+ if (!mDeferHidingClient && !visible) {
+ // Hiding the client is no longer deferred and the app isn't visible still, go ahead and
+ // update the visibility.
+ setVisibility(false);
+ }
+ }
+
void setVisibility(boolean visible) {
- mWindowContainerController.setVisibility(visible);
+ mWindowContainerController.setVisibility(visible, mDeferHidingClient);
}
// TODO: Look into merging with #setVisibility()
void setVisible(boolean newVisible) {
visible = newVisible;
+ mDeferHidingClient = !visible && mDeferHidingClient;
if (!visible && mUpdateTaskThumbnailWhenHidden) {
updateThumbnailLocked(screenshotActivityLocked(), null /* description */);
mUpdateTaskThumbnailWhenHidden = false;
}
- mWindowContainerController.setVisibility(visible);
+ setVisibility(visible);
final ArrayList<ActivityContainer> containers = mChildContainers;
for (int containerNdx = containers.size() - 1; containerNdx >= 0; --containerNdx) {
final ActivityContainer container = containers.get(containerNdx);
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index c3f346b..728a3b9 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1406,6 +1406,8 @@
prev.state = STOPPING;
} else if ((!prev.visible && !hasVisibleBehindActivity())
|| mService.isSleepingOrShuttingDownLocked()) {
+ // Clear out any deferred client hide we might currently have.
+ prev.setDeferHidingClient(false);
// If we were visible then resumeTopActivities will release resources before
// stopping.
addToStopping(prev, true /* scheduleIdle */, false /* idleDelayed */);
@@ -2024,11 +2026,12 @@
try {
final boolean canEnterPictureInPicture = r.checkEnterPictureInPictureState(
"makeInvisible", true /* noThrow */, true /* beforeStopping */);
- // We don't want to call setVisible(false) to avoid notifying the client of this
- // intermittent invisible state if it can enter Pip and isn't stopped or stopping.
- if (!canEnterPictureInPicture || r.state == STOPPING || r.state == STOPPED) {
- r.setVisible(false);
- }
+ // Defer telling the client it is hidden if it can enter Pip and isn't current stopped
+ // or stopping. This gives it a chance to enter Pip in onPause().
+ final boolean deferHidingClient = canEnterPictureInPicture
+ && r.state != STOPPING && r.state != STOPPED;
+ r.setDeferHidingClient(deferHidingClient);
+ r.setVisible(false);
switch (r.state) {
case STOPPING:
@@ -2053,15 +2056,6 @@
if (visibleBehind == r) {
releaseBackgroundResources(r);
} else {
- // If this activity is in a state where it can currently enter
- // picture-in-picture, then don't immediately schedule the idle now in case
- // the activity tries to enterPictureInPictureMode() later. Otherwise,
- // we will try and stop the activity next time idle is processed.
-
- if (canEnterPictureInPicture) {
- // We set r.visible=false so that Stop will later call setVisible for us
- r.visible = false;
- }
addToStopping(r, true /* scheduleIdle */,
canEnterPictureInPicture /* idleDelayed */);
}
@@ -2343,20 +2337,22 @@
mStackSupervisor.setLaunchSource(next.info.applicationInfo.uid);
- final boolean prevCanPip = prev != null && prev.checkEnterPictureInPictureState(
- "resumeTopActivity", true /* noThrow */, userLeaving /* beforeStopping */);
+ boolean lastResumedCanPip = false;
+ final ActivityStack lastFocusedStack = mStackSupervisor.getLastStack();
+ if (lastFocusedStack != null && lastFocusedStack != this) {
+ // So, why aren't we using prev here??? See the param comment on the method. prev doesn't
+ // represent the last resumed activity. However, the last focus stack does if it isn't null.
+ final ActivityRecord lastResumed = lastFocusedStack.mResumedActivity;
+ lastResumedCanPip = lastResumed != null && lastResumed.checkEnterPictureInPictureState(
+ "resumeTopActivity", true /* noThrow */, userLeaving /* beforeStopping */);
+ }
// If the flag RESUME_WHILE_PAUSING is set, then continue to schedule the previous activity
// to be paused, while at the same time resuming the new resume activity only if the
// previous activity can't go into Pip since we want to give Pip activities a chance to
// enter Pip before resuming the next activity.
- final boolean resumeWhilePausing = (next.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0;
- // TODO: This would be go to have however, the various call points that pass in
- // prev need to be corrected first. In some cases the prev is equal to the next e.g. launch
- // an app from home. And, is come other cases it is null e.g. press home button after
- // launching an app. The doc on the method says prev. is null expect for the case we are
- // coming from pause. We need to see if that is a valid thing and also if all the code in
- // this method using prev. are setup to function like that.
- //&& !prevCanPip;
+ final boolean resumeWhilePausing = (next.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0
+ && !lastResumedCanPip;
+
boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, next, false);
if (mResumedActivity != null) {
if (DEBUG_STATES) Slog.d(TAG_STATES,
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index dc636e5..056fec5 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -2212,11 +2212,6 @@
/** Returns the bounds that should be used to launch this task. */
Rect getLaunchBounds() {
- // If we're over lockscreen, forget about stack bounds and use fullscreen.
- if (mService.mStackSupervisor.mKeyguardController.isKeyguardShowing()) {
- return null;
- }
-
if (mStack == null) {
return null;
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index eea5473..457cf87 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -6044,8 +6044,8 @@
(AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
updateDefaultStreamOverrideDelay(accessibilityManager.isTouchExplorationEnabled());
updateA11yVolumeAlias(accessibilityManager.isAccessibilityVolumeStreamActive());
- accessibilityManager.addTouchExplorationStateChangeListener(this);
- accessibilityManager.addAccessibilityServicesStateChangeListener(this);
+ accessibilityManager.addTouchExplorationStateChangeListener(this, null);
+ accessibilityManager.addAccessibilityServicesStateChangeListener(this, null);
}
//---------------------------------------------------------------------------------
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index 9eda929..b0f84fe 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -46,32 +46,28 @@
public final class PlaybackActivityMonitor
implements AudioPlaybackConfiguration.PlayerDeathMonitor, PlayerFocusEnforcer {
- public final static String TAG = "AudioService.PlaybackActivityMonitor";
+ public static final String TAG = "AudioService.PlaybackActivityMonitor";
- private final static boolean DEBUG = false;
- private final static int VOLUME_SHAPER_SYSTEM_DUCK_ID = 1;
+ private static final boolean DEBUG = false;
+ private static final int VOLUME_SHAPER_SYSTEM_DUCK_ID = 1;
- private final VolumeShaper.Configuration DUCK_VSHAPE =
+ private static final VolumeShaper.Configuration DUCK_VSHAPE =
new VolumeShaper.Configuration.Builder()
.setId(VOLUME_SHAPER_SYSTEM_DUCK_ID)
.setCurve(new float[] { 0.f, 1.f } /* times */,
new float[] { 1.f, 0.2f } /* volumes */)
.setOptionFlags(VolumeShaper.Configuration.OPTION_FLAG_CLOCK_TIME)
- .setDurationMillis(MediaFocusControl.getFocusRampTimeMs(
+ .setDuration(MediaFocusControl.getFocusRampTimeMs(
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_NOTIFICATION)
.build()))
.build();
- private final VolumeShaper.Configuration DUCK_ID =
+ private static final VolumeShaper.Configuration DUCK_ID =
new VolumeShaper.Configuration(VOLUME_SHAPER_SYSTEM_DUCK_ID);
- private final VolumeShaper.Operation PLAY_CREATE_IF_NEEDED =
+ private static final VolumeShaper.Operation PLAY_CREATE_IF_NEEDED =
new VolumeShaper.Operation.Builder(VolumeShaper.Operation.PLAY)
.createIfNeeded()
.build();
- private final VolumeShaper.Operation TERMINATE =
- new VolumeShaper.Operation.Builder()
- .terminate()
- .build();
private final ArrayList<PlayMonitorClient> mClients = new ArrayList<PlayMonitorClient>();
// a public client is one that needs an anonymized version of the playback configurations, we
@@ -166,14 +162,7 @@
synchronized(mPlayerLock) {
final AudioPlaybackConfiguration apc = mPlayers.get(new Integer(piid));
if (checkConfigurationCaller(piid, apc, binderUid)) {
- try {
- apc.getPlayerProxy().applyVolumeShaper(
- DUCK_ID,
- TERMINATE);
- } catch (Exception e) { /* silent failure, happens with binder failure */ }
mPlayers.remove(new Integer(piid));
- } else {
- Log.e(TAG, "Error releasing player " + piid);
}
}
}
@@ -206,16 +195,16 @@
}
/**
- * Check that piid and uid are valid for the given configuration.
+ * Check that piid and uid are valid for the given valid configuration.
* @param piid the piid of the player.
* @param apc the configuration found for this piid.
* @param binderUid actual uid of client trying to signal a player state/event/attributes.
- * @return true if the call is valid and the change should proceed, false otherwise.
+ * @return true if the call is valid and the change should proceed, false otherwise. Always
+ * returns false when apc is null.
*/
private static boolean checkConfigurationCaller(int piid,
final AudioPlaybackConfiguration apc, int binderUid) {
if (apc == null) {
- Log.e(TAG, "Invalid operation: unknown player " + piid);
return false;
} else if ((binderUid != 0) && (apc.getClientUid() != binderUid)) {
Log.e(TAG, "Forbidden operation from uid " + binderUid + " for player " + piid);
@@ -509,7 +498,7 @@
/**
* Inner class to track clients that want to be notified of playback updates
*/
- private final static class PlayMonitorClient implements IBinder.DeathRecipient {
+ private static final class PlayMonitorClient implements IBinder.DeathRecipient {
// can afford to be static because only one PlaybackActivityMonitor ever instantiated
static PlaybackActivityMonitor sListenerDeathMonitor;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 02b93a2..1e7d076 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -3659,10 +3659,7 @@
}
hasValidVibrate = vibration != null;
- // We can alert, and we're allowed to alert, but if the developer asked us to only do
- // it once, and we already have, then don't.
- if (!(record.isUpdate
- && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0)) {
+ if (!shouldMuteNotificationLocked(record)) {
sendAccessibilityEvent(notification, record.sbn.getPackageName());
if (hasValidSound) {
@@ -3716,6 +3713,24 @@
}
}
+ boolean shouldMuteNotificationLocked(final NotificationRecord record) {
+ final Notification notification = record.getNotification();
+ if(record.isUpdate
+ && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0) {
+ return true;
+ }
+ if (record.sbn.isGroup()) {
+ if (notification.isGroupSummary()
+ && notification.getGroupAlertBehavior() == Notification.GROUP_ALERT_CHILDREN) {
+ return true;
+ } else if (notification.isGroupChild()
+ && notification.getGroupAlertBehavior() == Notification.GROUP_ALERT_SUMMARY) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private boolean playSound(final NotificationRecord record, Uri soundUri) {
boolean looping = (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
// do not play notifications if there is a user of exclusive audio focus
diff --git a/services/core/java/com/android/server/os/SchedulingPolicyService.java b/services/core/java/com/android/server/os/SchedulingPolicyService.java
index a8bb809..46be232 100644
--- a/services/core/java/com/android/server/os/SchedulingPolicyService.java
+++ b/services/core/java/com/android/server/os/SchedulingPolicyService.java
@@ -20,6 +20,7 @@
import android.os.Binder;
import android.os.ISchedulingPolicyService;
import android.os.Process;
+import android.util.Log;
/**
* The implementation of the scheduling policy service interface.
@@ -50,16 +51,24 @@
// since if not the case then the getThreadGroupLeader() test will also fail.
if (!isPermitted() || prio < PRIORITY_MIN ||
prio > PRIORITY_MAX || Process.getThreadGroupLeader(tid) != pid) {
- return PackageManager.PERMISSION_DENIED;
+ return PackageManager.PERMISSION_DENIED;
+ }
+ if (Binder.getCallingUid() != Process.BLUETOOTH_UID) {
+ try {
+ // make good use of our CAP_SYS_NICE capability
+ Process.setThreadGroup(tid, !isForApp ?
+ Process.THREAD_GROUP_AUDIO_SYS : Process.THREAD_GROUP_AUDIO_APP);
+ } catch (RuntimeException e) {
+ Log.e(TAG, "Failed setThreadGroup: " + e);
+ return PackageManager.PERMISSION_DENIED;
+ }
}
try {
- // make good use of our CAP_SYS_NICE capability
- Process.setThreadGroup(tid, !isForApp ?
- Process.THREAD_GROUP_AUDIO_SYS : Process.THREAD_GROUP_AUDIO_APP);
// must be in this order or it fails the schedulability constraint
Process.setThreadScheduler(tid, Process.SCHED_FIFO | Process.SCHED_RESET_ON_FORK,
- prio);
+ prio);
} catch (RuntimeException e) {
+ Log.e(TAG, "Failed setThreadScheduler: " + e);
return PackageManager.PERMISSION_DENIED;
}
return PackageManager.PERMISSION_GRANTED;
@@ -74,6 +83,7 @@
switch (Binder.getCallingUid()) {
case Process.AUDIOSERVER_UID: // fastcapture, fastmixer
case Process.CAMERASERVER_UID: // camera high frame rate recording
+ case Process.BLUETOOTH_UID: // Bluetooth audio playback
return true;
default:
return false;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index d0a28f9..4aa19ee 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -7683,6 +7683,7 @@
}
// instant application; filter out non-exposed provider
if (instantAppPkgName != null
+ && !isInstantApp
&& (provider.info.flags & ProviderInfo.FLAG_VISIBLE_TO_EPHEMERAL) == 0) {
return null;
}
@@ -14117,9 +14118,6 @@
synchronized (mPackages) {
boolean result = mSettings.setDefaultBrowserPackageNameLPw(packageName, userId);
if (packageName != null) {
- result |= updateIntentVerificationStatus(packageName,
- PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS,
- userId);
mDefaultPermissionPolicy.grantDefaultPermissionsToDefaultBrowserLPr(
packageName, userId);
}
@@ -18588,6 +18586,7 @@
destroyAppDataLIF(pkg, userId,
StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
destroyAppProfilesLIF(pkg, userId);
+ clearDefaultBrowserIfNeededForUser(ps.name, userId);
removeKeystoreDataIfNeeded(nextUserId, ps.appId);
schedulePackageCleaning(ps.name, nextUserId, false);
synchronized (mPackages) {
@@ -19309,12 +19308,18 @@
}
}
+ /** Clears state for all users, and touches intent filter verification policy */
void clearDefaultBrowserIfNeeded(String packageName) {
for (int oneUserId : sUserManager.getUserIds()) {
- String defaultBrowserPackageName = getDefaultBrowserPackageName(oneUserId);
- if (TextUtils.isEmpty(defaultBrowserPackageName)) continue;
+ clearDefaultBrowserIfNeededForUser(packageName, oneUserId);
+ }
+ }
+
+ private void clearDefaultBrowserIfNeededForUser(String packageName, int userId) {
+ final String defaultBrowserPackageName = getDefaultBrowserPackageName(userId);
+ if (!TextUtils.isEmpty(defaultBrowserPackageName)) {
if (packageName.equals(defaultBrowserPackageName)) {
- setDefaultBrowserPackageName(null, oneUserId);
+ setDefaultBrowserPackageName(null, userId);
}
}
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 554deae..cea031e 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -1386,7 +1386,11 @@
if (userId == UserHandle.USER_ALL) {
return false;
}
- mDefaultBrowserApp.put(userId, packageName);
+ if (packageName != null) {
+ mDefaultBrowserApp.put(userId, packageName);
+ } else {
+ mDefaultBrowserApp.remove(userId);
+ }
writePackageRestrictionsLPr(userId);
return true;
}
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index 39a1573..860b241 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -656,16 +656,12 @@
false, mOverlayToken, null, oldUserId);
}
- if (!mVrModeEnabled) {
- return;
- }
-
// Apply the restrictions for the current user based on vr state
String[] exemptions = (exemptedPackage == null) ? new String[0] :
new String[] { exemptedPackage };
appOpsManager.setUserRestrictionForUser(AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
- true, mOverlayToken, exemptions, newUserId);
+ mVrModeEnabled, mOverlayToken, exemptions, newUserId);
}
private void updateDependentAppOpsLocked(String newVrServicePackage, int newUserId,
diff --git a/services/core/java/com/android/server/wm/AppWindowContainerController.java b/services/core/java/com/android/server/wm/AppWindowContainerController.java
index 292734d..c625cbe 100644
--- a/services/core/java/com/android/server/wm/AppWindowContainerController.java
+++ b/services/core/java/com/android/server/wm/AppWindowContainerController.java
@@ -323,7 +323,7 @@
}
}
- public void setVisibility(boolean visible) {
+ public void setVisibility(boolean visible, boolean deferHidingClient) {
synchronized(mWindowMap) {
if (mContainer == null) {
Slog.w(TAG_WM, "Attempted to set visibility of non-existing app token: "
@@ -342,6 +342,7 @@
mService.mClosingApps.remove(wtoken);
wtoken.waitingToShow = false;
wtoken.hiddenRequested = !visible;
+ wtoken.mDeferHidingClient = deferHidingClient;
if (!visible) {
// If the app is dead while it was visible, we kept its dead window on screen.
@@ -368,15 +369,12 @@
wtoken.waitingToShow = true;
}
- if (wtoken.clientHidden) {
- // In the case where we are making an app visible
- // but holding off for a transition, we still need
- // to tell the client to make its windows visible so
- // they get drawn. Otherwise, we will wait on
- // performing the transition until all windows have
- // been drawn, they never will be, and we are sad.
- wtoken.clientHidden = false;
- wtoken.sendAppVisibilityToClients();
+ if (wtoken.isClientHidden()) {
+ // In the case where we are making an app visible but holding off for a
+ // transition, we still need to tell the client to make its windows visible
+ // so they get drawn. Otherwise, we will wait on performing the transition
+ // until all windows have been drawn, they never will be, and we are sad.
+ wtoken.setClientHidden(false);
}
}
wtoken.requestUpdateWallpaperIfNeeded();
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 847545a..3c2dfa5 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -129,7 +129,11 @@
boolean hiddenRequested;
// Have we told the window clients to hide themselves?
- boolean clientHidden;
+ private boolean mClientHidden;
+
+ // If true we will defer setting mClientHidden to true and reporting to the client that it is
+ // hidden.
+ boolean mDeferHidingClient;
// Last visibility state we reported to the app token.
boolean reportedVisible;
@@ -312,16 +316,25 @@
}
}
+ boolean isClientHidden() {
+ return mClientHidden;
+ }
+
+ void setClientHidden(boolean hideClient) {
+ if (mClientHidden == hideClient || (hideClient && mDeferHidingClient)) {
+ return;
+ }
+ mClientHidden = hideClient;
+ sendAppVisibilityToClients();
+ }
+
boolean setVisibility(WindowManager.LayoutParams lp,
boolean visible, int transit, boolean performLayout, boolean isVoiceInteraction) {
boolean delayed = false;
inPendingTransaction = false;
- if (clientHidden == visible) {
- clientHidden = !visible;
- sendAppVisibilityToClients();
- }
+ setClientHidden(!visible);
// Allow for state changes and animation to be applied if:
// * token is transitioning visibility state
@@ -1165,10 +1178,7 @@
hidden = false;
hiddenRequested = false;
}
- if (clientHidden != fromToken.clientHidden) {
- clientHidden = fromToken.clientHidden;
- sendAppVisibilityToClients();
- }
+ setClientHidden(fromToken.mClientHidden);
fromToken.mAppAnimator.transferCurrentAnimation(
mAppAnimator, tStartingWindow.mWinAnimator);
@@ -1533,10 +1543,9 @@
pw.print(prefix); pw.print("task="); pw.println(getTask());
pw.print(prefix); pw.print(" mFillsParent="); pw.print(mFillsParent);
pw.print(" mOrientation="); pw.println(mOrientation);
- pw.print(prefix); pw.print("hiddenRequested="); pw.print(hiddenRequested);
- pw.print(" clientHidden="); pw.print(clientHidden);
- pw.print(" reportedDrawn="); pw.print(reportedDrawn);
- pw.print(" reportedVisible="); pw.println(reportedVisible);
+ pw.println(prefix + "hiddenRequested=" + hiddenRequested + " mClientHidden=" + mClientHidden
+ + ((mDeferHidingClient) ? " mDeferHidingClient=" + mDeferHidingClient : "")
+ + " reportedDrawn=" + reportedDrawn + " reportedVisible=" + reportedVisible);
if (paused) {
pw.print(prefix); pw.print("paused="); pw.println(paused);
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 1823610..e2f313a 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -2245,7 +2245,7 @@
wsa.destroySurface();
mService.mForceRemoves.add(w);
mTmpWindow = w;
- } else if (w.mAppToken != null && w.mAppToken.clientHidden) {
+ } else if (w.mAppToken != null && w.mAppToken.isClientHidden()) {
Slog.w(TAG_WM, "LEAKED SURFACE (app token hidden): "
+ w + " surface=" + wsa.mSurfaceController
+ " token=" + w.mAppToken
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 4262d12..bc749e1 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -439,7 +439,7 @@
for (int i = mChildren.size() - 1; i >= 0; i--) {
final AppWindowToken token = mChildren.get(i);
// skip hidden (or about to hide) apps
- if (token.mIsExiting || token.clientHidden || token.hiddenRequested) {
+ if (token.mIsExiting || token.isClientHidden() || token.hiddenRequested) {
continue;
}
final WindowState win = token.findMainWindow();
@@ -607,7 +607,7 @@
for (int i = mChildren.size() - 1; i >= 0; i--) {
final AppWindowToken token = mChildren.get(i);
// skip hidden (or about to hide) apps
- if (!token.mIsExiting && !token.clientHidden && !token.hiddenRequested) {
+ if (!token.mIsExiting && !token.isClientHidden() && !token.hiddenRequested) {
return token;
}
}
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 1feb743..da7a9f0 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -733,10 +733,17 @@
outTempTaskBounds.setEmpty();
// When the home stack is resizable, should always have the same stack and task bounds
- if (mStackId == HOME_STACK_ID && findHomeTask().isResizeable()) {
- // Calculate the home stack bounds when in docked mode
- getDisplayContent().mDividerControllerLocked
- .getHomeStackBoundsInDockedMode(outStackBounds);
+ if (mStackId == HOME_STACK_ID) {
+ if (findHomeTask().isResizeable()) {
+ // Calculate the home stack bounds when in docked mode and the home stack is
+ // resizeable.
+ getDisplayContent().mDividerControllerLocked
+ .getHomeStackBoundsInDockedMode(outStackBounds);
+ } else {
+ // Home stack isn't resizeable, so don't specify stack bounds.
+ outStackBounds.setEmpty();
+ }
+
outTempTaskBounds.set(outStackBounds);
return;
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index f59fc66..6cde53a 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1470,7 +1470,7 @@
if (mInTouchMode) {
res |= WindowManagerGlobal.ADD_FLAG_IN_TOUCH_MODE;
}
- if (win.mAppToken == null || !win.mAppToken.clientHidden) {
+ if (win.mAppToken == null || !win.mAppToken.isClientHidden()) {
res |= WindowManagerGlobal.ADD_FLAG_APP_VISIBLE;
}
@@ -1950,7 +1950,7 @@
}
if (viewVisibility == View.VISIBLE &&
(win.mAppToken == null || win.mAttrs.type == TYPE_APPLICATION_STARTING
- || !win.mAppToken.clientHidden)) {
+ || !win.mAppToken.isClientHidden())) {
result = win.relayoutVisibleWindow(mergedConfiguration, result, attrChanges,
oldVisibility);
try {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index aa703c2..67516c1 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1399,7 +1399,7 @@
* @return true if the window should be considered while evaluating allDrawn flags.
*/
boolean mightAffectAllDrawn(boolean visibleOnly) {
- final boolean isViewVisible = (mAppToken == null || !mAppToken.clientHidden)
+ final boolean isViewVisible = (mAppToken == null || !mAppToken.isClientHidden())
&& (mViewVisibility == View.VISIBLE) && !mWindowRemovalAllowed;
return (isOnScreen() && (!visibleOnly || isViewVisible)
|| mWinAnimator.mAttrType == TYPE_BASE_APPLICATION
@@ -2312,7 +2312,7 @@
* interacts with it.
*/
boolean shouldKeepVisibleDeadAppWindow() {
- if (!isWinVisibleLw() || mAppToken == null || mAppToken.clientHidden) {
+ if (!isWinVisibleLw() || mAppToken == null || mAppToken.isClientHidden()) {
// Not a visible app window or the app isn't dead.
return false;
}
@@ -2570,12 +2570,24 @@
void sendAppVisibilityToClients() {
super.sendAppVisibilityToClients();
- final boolean clientHidden = mAppToken.clientHidden;
+ final boolean clientHidden = mAppToken.isClientHidden();
if (mAttrs.type == TYPE_APPLICATION_STARTING && clientHidden) {
// Don't hide the starting window.
return;
}
+ if (clientHidden) {
+ // Once we are notifying the client that it's visibility has changed, we need to prevent
+ // it from destroying child surfaces until the animation has finished. We do this by
+ // detaching any surface control the client added from the client.
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ final WindowState c = mChildren.get(i);
+ c.mWinAnimator.detachChildren();
+ }
+
+ mWinAnimator.detachChildren();
+ }
+
try {
if (DEBUG_VISIBILITY) Slog.v(TAG,
"Setting visibility of " + this + ": " + (!clientHidden));
diff --git a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
index 1106006..d4904f5 100644
--- a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -15,6 +15,9 @@
*/
package com.android.server.notification;
+import static android.app.Notification.GROUP_ALERT_ALL;
+import static android.app.Notification.GROUP_ALERT_CHILDREN;
+import static android.app.Notification.GROUP_ALERT_SUMMARY;
import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static junit.framework.Assert.assertFalse;
@@ -188,17 +191,24 @@
private NotificationRecord getCustomLightsNotification() {
return getNotificationRecord(mId, false /* insistent */, true /* once */,
false /* noisy */, true /* buzzy*/, true /* lights */,
- true /* defaultVibration */, true /* defaultSound */, false /* defaultLights */);
+ true /* defaultVibration */, true /* defaultSound */, false /* defaultLights */,
+ null, Notification.GROUP_ALERT_ALL);
}
private NotificationRecord getNotificationRecord(int id, boolean insistent, boolean once,
boolean noisy, boolean buzzy, boolean lights) {
- return getNotificationRecord(id, insistent, once, noisy, buzzy, lights, true, true, true);
+ return getNotificationRecord(id, insistent, once, noisy, buzzy, lights, true, true, true,
+ null, Notification.GROUP_ALERT_ALL);
+ }
+
+ private NotificationRecord getBeepyNotificationRecord(String groupKey, int groupAlertBehavior) {
+ return getNotificationRecord(mId, false, false, true, false, false, true, true, true,
+ groupKey, groupAlertBehavior);
}
private NotificationRecord getNotificationRecord(int id, boolean insistent, boolean once,
boolean noisy, boolean buzzy, boolean lights, boolean defaultVibration,
- boolean defaultSound, boolean defaultLights) {
+ boolean defaultSound, boolean defaultLights, String groupKey, int groupAlertBehavior) {
NotificationChannel channel =
new NotificationChannel("test", "test", IMPORTANCE_HIGH);
final Builder builder = new Builder(getContext())
@@ -239,6 +249,9 @@
}
builder.setDefaults(defaults);
+ builder.setGroup(groupKey);
+ builder.setGroupAlertBehavior(groupAlertBehavior);
+
Notification n = builder.build();
if (insistent) {
n.flags |= Notification.FLAG_INSISTENT;
@@ -546,7 +559,7 @@
}
@Test
- public void testInsistenteVibrate() throws Exception {
+ public void testInsistentVibrate() throws Exception {
NotificationRecord r = getInsistentBuzzyNotification();
mService.buzzBeepBlinkLocked(r);
@@ -568,6 +581,71 @@
}
@Test
+ public void testGroupAlertSummarySilenceChild() throws Exception {
+ NotificationRecord child = getBeepyNotificationRecord("a", GROUP_ALERT_SUMMARY);
+
+ mService.buzzBeepBlinkLocked(child);
+
+ verifyNeverBeep();
+ }
+
+ @Test
+ public void testGroupAlertSummaryNoSilenceSummary() throws Exception {
+ NotificationRecord summary = getBeepyNotificationRecord("a", GROUP_ALERT_SUMMARY);
+ summary.getNotification().flags |= Notification.FLAG_GROUP_SUMMARY;
+
+ mService.buzzBeepBlinkLocked(summary);
+
+ verifyBeepLooped();
+ }
+
+ @Test
+ public void testGroupAlertSummaryNoSilenceNonGroupChild() throws Exception {
+ NotificationRecord nonGroup = getBeepyNotificationRecord(null, GROUP_ALERT_SUMMARY);
+
+ mService.buzzBeepBlinkLocked(nonGroup);
+
+ verifyBeepLooped();
+ }
+
+ @Test
+ public void testGroupAlertChildSilenceSummary() throws Exception {
+ NotificationRecord summary = getBeepyNotificationRecord("a", GROUP_ALERT_CHILDREN);
+ summary.getNotification().flags |= Notification.FLAG_GROUP_SUMMARY;
+
+ mService.buzzBeepBlinkLocked(summary);
+
+ verifyNeverBeep();
+ }
+
+ @Test
+ public void testGroupAlertChildNoSilenceChild() throws Exception {
+ NotificationRecord child = getBeepyNotificationRecord("a", GROUP_ALERT_CHILDREN);
+
+ mService.buzzBeepBlinkLocked(child);
+
+ verifyBeepLooped();
+ }
+
+ @Test
+ public void testGroupAlertChildNoSilenceNonGroupSummary() throws Exception {
+ NotificationRecord nonGroup = getBeepyNotificationRecord(null, GROUP_ALERT_CHILDREN);
+
+ mService.buzzBeepBlinkLocked(nonGroup);
+
+ verifyBeepLooped();
+ }
+
+ @Test
+ public void testGroupAlertAllNoSilenceGroup() throws Exception {
+ NotificationRecord group = getBeepyNotificationRecord("a", GROUP_ALERT_ALL);
+
+ mService.buzzBeepBlinkLocked(group);
+
+ verifyBeepLooped();
+ }
+
+ @Test
public void testHonorAlertOnlyOnceForBuzz() throws Exception {
NotificationRecord r = getBuzzyNotification();
NotificationRecord s = getBuzzyOnceNotification();
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
index 92534a1..d057eb5 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -53,9 +53,10 @@
import android.os.UserHandle;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
-import android.support.test.annotation.UiThreadTest;
import android.support.test.InstrumentationRegistry;
+import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.testing.TestableLooper.RunWithLooper;
import java.util.ArrayList;
import java.util.Arrays;
@@ -63,6 +64,7 @@
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
@@ -70,6 +72,8 @@
import com.android.server.lights.Light;
import com.android.server.lights.LightsManager;
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
public class NotificationManagerServiceTest {
private static final long WAIT_FOR_IDLE_TIMEOUT = 2;
private static final String TEST_CHANNEL_ID = "NotificationManagerServiceTestChannelId";
@@ -109,7 +113,6 @@
}
@Before
- @UiThreadTest
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mNotificationManagerService = new TestableNotificationManagerService(mContext);
@@ -124,7 +127,7 @@
final LightsManager mockLightsManager = mock(LightsManager.class);
when(mockLightsManager.getLight(anyInt())).thenReturn(mock(Light.class));
// Use this testable looper.
- mTestableLooper = new TestableLooper(false);
+ mTestableLooper = TestableLooper.get(this);
mListener = mNotificationListeners.new ManagedServiceInfo(
null, new ComponentName(PKG, "test_class"), uid, true, null, 0);
@@ -165,7 +168,6 @@
}
@Test
- @UiThreadTest
public void testCreateNotificationChannels_SingleChannel() throws Exception {
final NotificationChannel channel =
new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_DEFAULT);
@@ -177,7 +179,6 @@
}
@Test
- @UiThreadTest
public void testCreateNotificationChannels_NullChannelThrowsException() throws Exception {
try {
mBinderService.createNotificationChannels("test_pkg",
@@ -189,7 +190,6 @@
}
@Test
- @UiThreadTest
public void testCreateNotificationChannels_TwoChannels() throws Exception {
final NotificationChannel channel1 =
new NotificationChannel("id1", "name", NotificationManager.IMPORTANCE_DEFAULT);
@@ -202,7 +202,6 @@
}
@Test
- @UiThreadTest
public void testCreateNotificationChannels_SecondCreateDoesNotChangeImportance()
throws Exception {
final NotificationChannel channel =
@@ -221,7 +220,6 @@
}
@Test
- @UiThreadTest
public void testCreateNotificationChannels_IdenticalChannelsInListIgnoresSecond()
throws Exception {
final NotificationChannel channel1 =
@@ -236,7 +234,6 @@
}
@Test
- @UiThreadTest
public void testBlockedNotifications_suspended() throws Exception {
NotificationUsageStats usageStats = mock(NotificationUsageStats.class);
when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(true);
@@ -249,7 +246,6 @@
}
@Test
- @UiThreadTest
public void testBlockedNotifications_blockedChannel() throws Exception {
NotificationUsageStats usageStats = mock(NotificationUsageStats.class);
when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
@@ -263,7 +259,6 @@
}
@Test
- @UiThreadTest
public void testBlockedNotifications_blockedApp() throws Exception {
NotificationUsageStats usageStats = mock(NotificationUsageStats.class);
when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
@@ -277,7 +272,6 @@
}
@Test
- @UiThreadTest
public void testEnqueueNotificationWithTag_PopulatesGetActiveNotifications() throws Exception {
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
generateNotificationRecord(null).getNotification(), 0);
@@ -288,7 +282,6 @@
}
@Test
- @UiThreadTest
public void testCancelNotificationImmediatelyAfterEnqueue() throws Exception {
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
generateNotificationRecord(null).getNotification(), 0);
@@ -300,7 +293,6 @@
}
@Test
- @UiThreadTest
public void testCancelNotificationWhilePostedAndEnqueued() throws Exception {
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
generateNotificationRecord(null).getNotification(), 0);
@@ -315,7 +307,6 @@
}
@Test
- @UiThreadTest
public void testCancelNotificationsFromListenerImmediatelyAfterEnqueue() throws Exception {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
@@ -328,7 +319,6 @@
}
@Test
- @UiThreadTest
public void testCancelAllNotificationsImmediatelyAfterEnqueue() throws Exception {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
@@ -341,7 +331,6 @@
}
@Test
- @UiThreadTest
public void testCancelAllNotifications_IgnoreForegroundService() throws Exception {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
sbn.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
@@ -355,7 +344,6 @@
}
@Test
- @UiThreadTest
public void testCancelAllNotifications_IgnoreOtherPackages() throws Exception {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
sbn.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
@@ -369,7 +357,6 @@
}
@Test
- @UiThreadTest
public void testCancelAllNotifications_NullPkgRemovesAll() throws Exception {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
@@ -382,7 +369,6 @@
}
@Test
- @UiThreadTest
public void testCancelAllNotifications_NullPkgIgnoresUserAllNotifications() throws Exception {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
@@ -396,7 +382,6 @@
}
@Test
- @UiThreadTest
public void testRemoveForegroundServiceFlag_ImmediatelyAfterEnqueue() throws Exception {
final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
sbn.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
@@ -411,7 +396,6 @@
}
@Test
- @UiThreadTest
public void testTvExtenderChannelOverride_onTv() throws Exception {
mNotificationManagerService.setIsTelevision(true);
mNotificationManagerService.setRankingHelper(mRankingHelper);
@@ -427,7 +411,6 @@
}
@Test
- @UiThreadTest
public void testTvExtenderChannelOverride_notOnTv() throws Exception {
mNotificationManagerService.setIsTelevision(false);
mNotificationManagerService.setRankingHelper(mRankingHelper);
@@ -443,7 +426,6 @@
}
@Test
- @UiThreadTest
public void testCreateChannelNotifyListener() throws Exception {
List<String> associations = new ArrayList<>();
associations.add("a");
@@ -469,7 +451,6 @@
}
@Test
- @UiThreadTest
public void testCreateChannelGroupNotifyListener() throws Exception {
List<String> associations = new ArrayList<>();
associations.add("a");
@@ -490,7 +471,6 @@
}
@Test
- @UiThreadTest
public void testUpdateChannelNotifyListener() throws Exception {
List<String> associations = new ArrayList<>();
associations.add("a");
@@ -509,7 +489,6 @@
}
@Test
- @UiThreadTest
public void testDeleteChannelNotifyListener() throws Exception {
List<String> associations = new ArrayList<>();
associations.add("a");
@@ -526,7 +505,6 @@
}
@Test
- @UiThreadTest
public void testDeleteChannelGroupNotifyListener() throws Exception {
List<String> associations = new ArrayList<>();
associations.add("a");
@@ -543,7 +521,6 @@
}
@Test
- @UiThreadTest
public void testUpdateNotificationChannelFromPrivilegedListener_success() throws Exception {
mNotificationManagerService.setRankingHelper(mRankingHelper);
List<String> associations = new ArrayList<>();
@@ -561,7 +538,6 @@
}
@Test
- @UiThreadTest
public void testUpdateNotificationChannelFromPrivilegedListener_noAccess() throws Exception {
mNotificationManagerService.setRankingHelper(mRankingHelper);
List<String> associations = new ArrayList<>();
@@ -583,7 +559,6 @@
}
@Test
- @UiThreadTest
public void testUpdateNotificationChannelFromPrivilegedListener_badUser() throws Exception {
mNotificationManagerService.setRankingHelper(mRankingHelper);
List<String> associations = new ArrayList<>();
@@ -609,7 +584,6 @@
}
@Test
- @UiThreadTest
public void testGetNotificationChannelFromPrivilegedListener_success() throws Exception {
mNotificationManagerService.setRankingHelper(mRankingHelper);
List<String> associations = new ArrayList<>();
@@ -624,7 +598,6 @@
}
@Test
- @UiThreadTest
public void testGetNotificationChannelFromPrivilegedListener_noAccess() throws Exception {
mNotificationManagerService.setRankingHelper(mRankingHelper);
List<String> associations = new ArrayList<>();
@@ -643,7 +616,6 @@
}
@Test
- @UiThreadTest
public void testGetNotificationChannelFromPrivilegedListener_badUser() throws Exception {
mNotificationManagerService.setRankingHelper(mRankingHelper);
List<String> associations = new ArrayList<>();
@@ -666,7 +638,6 @@
}
@Test
- @UiThreadTest
public void testGetNotificationChannelGroupsFromPrivilegedListener_success() throws Exception {
mNotificationManagerService.setRankingHelper(mRankingHelper);
List<String> associations = new ArrayList<>();
@@ -680,7 +651,6 @@
}
@Test
- @UiThreadTest
public void testGetNotificationChannelGroupsFromPrivilegedListener_noAccess() throws Exception {
mNotificationManagerService.setRankingHelper(mRankingHelper);
List<String> associations = new ArrayList<>();
@@ -698,7 +668,6 @@
}
@Test
- @UiThreadTest
public void testGetNotificationChannelGroupsFromPrivilegedListener_badUser() throws Exception {
mNotificationManagerService.setRankingHelper(mRankingHelper);
List<String> associations = new ArrayList<>();
@@ -719,7 +688,6 @@
}
@Test
- @UiThreadTest
public void testHasCompanionDevice_failure() throws Exception {
when(mCompanionMgr.getAssociations(anyString(), anyInt())).thenThrow(
new IllegalArgumentException());
@@ -727,7 +695,6 @@
}
@Test
- @UiThreadTest
public void testHasCompanionDevice_noService() throws Exception {
mNotificationManagerService = new TestableNotificationManagerService(mContext);
diff --git a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
index 985e5ea..c78488f 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
@@ -16,25 +16,18 @@
package com.android.server;
-import static android.net.NetworkRecommendationProvider.EXTRA_RECOMMENDATION_RESULT;
-import static android.net.NetworkRecommendationProvider.EXTRA_SEQUENCE;
import static android.net.NetworkScoreManager.CACHE_FILTER_NONE;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertNotNull;
-import static junit.framework.Assert.assertSame;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyListOf;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
-import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
@@ -55,8 +48,6 @@
import android.net.NetworkKey;
import android.net.NetworkScoreManager;
import android.net.NetworkScorerAppData;
-import android.net.RecommendationRequest;
-import android.net.RecommendationResult;
import android.net.ScoredNetwork;
import android.net.Uri;
import android.net.WifiKey;
@@ -69,13 +60,11 @@
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
-import android.os.IRemoteCallback;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.provider.Settings;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.MediumTest;
import android.support.test.runner.AndroidJUnit4;
@@ -145,9 +134,6 @@
private ContentResolver mContentResolver;
private NetworkScoreService mNetworkScoreService;
- private RecommendationRequest mRecommendationRequest;
- private RemoteCallback mRemoteCallback;
- private OnResultListener mOnResultListener;
private HandlerThread mHandlerThread;
private List<ScanResult> mScanResults;
@@ -177,13 +163,6 @@
WifiConfiguration configuration = new WifiConfiguration();
configuration.SSID = "NetworkScoreServiceTest_SSID";
configuration.BSSID = "NetworkScoreServiceTest_BSSID";
- mRecommendationRequest = new RecommendationRequest.Builder()
- .setDefaultWifiConfig(configuration).build();
- mOnResultListener = new OnResultListener();
- mRemoteCallback = new RemoteCallback(mOnResultListener);
- Settings.Global.putLong(mContentResolver,
- Settings.Global.NETWORK_RECOMMENDATION_REQUEST_TIMEOUT_MS, -1L);
- mNetworkScoreService.refreshRecommendationRequestTimeoutMs();
populateScanResults();
}
@@ -215,7 +194,6 @@
verify(mNetworkScorerAppManager).updateState();
verify(mNetworkScorerAppManager).migrateNetworkScorerAppSettingIfNeeded();
verify(mServiceConnection).bind(mContext);
-
}
@Test
@@ -256,160 +234,6 @@
}
@Test
- public void testRequestRecommendation_noPermission() throws Exception {
- doThrow(new SecurityException()).when(mContext)
- .enforceCallingOrSelfPermission(eq(permission.REQUEST_NETWORK_SCORES),
- anyString());
- try {
- mNetworkScoreService.requestRecommendation(mRecommendationRequest);
- fail("REQUEST_NETWORK_SCORES not enforced.");
- } catch (SecurityException e) {
- // expected
- }
- }
-
- @Test
- public void testRequestRecommendation_mainThread() throws Exception {
- when(mContext.getMainLooper()).thenReturn(Looper.myLooper());
- try {
- mNetworkScoreService.requestRecommendation(mRecommendationRequest);
- fail("requestRecommendation run on main thread.");
- } catch (RuntimeException e) {
- // expected
- }
- }
-
- @Test
- public void testRequestRecommendation_providerNotConnected() throws Exception {
- when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper());
-
- final RecommendationResult result =
- mNetworkScoreService.requestRecommendation(mRecommendationRequest);
- assertNotNull(result);
- assertEquals(mRecommendationRequest.getDefaultWifiConfig(),
- result.getWifiConfiguration());
- }
-
- @Test
- public void testRequestRecommendation_providerThrowsRemoteException() throws Exception {
- when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper());
- doThrow(new RemoteException()).when(mRecommendationProvider)
- .requestRecommendation(eq(mRecommendationRequest), isA(IRemoteCallback.class),
- anyInt());
- mNetworkScoreService.onUserUnlocked(0);
-
- final RecommendationResult result =
- mNetworkScoreService.requestRecommendation(mRecommendationRequest);
- assertNotNull(result);
- assertEquals(mRecommendationRequest.getDefaultWifiConfig(),
- result.getWifiConfiguration());
- }
-
- @Test
- public void testRequestRecommendation_resultReturned() throws Exception {
- when(mContext.getMainLooper()).thenReturn(Looper.getMainLooper());
- final WifiConfiguration wifiConfiguration = new WifiConfiguration();
- wifiConfiguration.SSID = "testRequestRecommendation_resultReturned_SSID";
- wifiConfiguration.BSSID = "testRequestRecommendation_resultReturned_BSSID";
- final RecommendationResult providerResult = RecommendationResult
- .createConnectRecommendation(wifiConfiguration);
- final Bundle bundle = new Bundle();
- bundle.putParcelable(EXTRA_RECOMMENDATION_RESULT, providerResult);
- doAnswer(invocation -> {
- bundle.putInt(EXTRA_SEQUENCE, invocation.getArgument(2));
- invocation.<IRemoteCallback>getArgument(1).sendResult(bundle);
- return null;
- }).when(mRecommendationProvider)
- .requestRecommendation(eq(mRecommendationRequest), isA(IRemoteCallback.class),
- anyInt());
- mNetworkScoreService.onUserUnlocked(0);
-
- final RecommendationResult result =
- mNetworkScoreService.requestRecommendation(mRecommendationRequest);
- assertNotNull(result);
- assertEquals(providerResult.getWifiConfiguration().SSID,
- result.getWifiConfiguration().SSID);
- assertEquals(providerResult.getWifiConfiguration().BSSID,
- result.getWifiConfiguration().BSSID);
- }
-
- @Test
- public void testRequestRecommendationAsync_noPermission() throws Exception {
- doThrow(new SecurityException()).when(mContext)
- .enforceCallingOrSelfPermission(eq(permission.REQUEST_NETWORK_SCORES),
- anyString());
- try {
- mNetworkScoreService.requestRecommendationAsync(mRecommendationRequest,
- mRemoteCallback);
- fail("REQUEST_NETWORK_SCORES not enforced.");
- } catch (SecurityException e) {
- // expected
- }
- }
-
- @Test
- public void testRequestRecommendationAsync_providerNotConnected() throws Exception {
- mNetworkScoreService.requestRecommendationAsync(mRecommendationRequest,
- mRemoteCallback);
- boolean callbackRan = mOnResultListener.countDownLatch.await(3, TimeUnit.SECONDS);
- assertTrue(callbackRan);
- verifyZeroInteractions(mRecommendationProvider);
- }
-
- @Test
- public void testRequestRecommendationAsync_requestTimesOut() throws Exception {
- mNetworkScoreService.onUserUnlocked(0);
- Settings.Global.putLong(mContentResolver,
- Settings.Global.NETWORK_RECOMMENDATION_REQUEST_TIMEOUT_MS, 1L);
- mNetworkScoreService.refreshRecommendationRequestTimeoutMs();
- mNetworkScoreService.requestRecommendationAsync(mRecommendationRequest,
- mRemoteCallback);
- boolean callbackRan = mOnResultListener.countDownLatch.await(3, TimeUnit.SECONDS);
- assertTrue(callbackRan);
- verify(mRecommendationProvider).requestRecommendation(eq(mRecommendationRequest),
- isA(IRemoteCallback.Stub.class), anyInt());
-
- assertTrue(mOnResultListener.receivedBundle.containsKey(EXTRA_RECOMMENDATION_RESULT));
- RecommendationResult result =
- mOnResultListener.receivedBundle.getParcelable(EXTRA_RECOMMENDATION_RESULT);
- assertTrue(result.hasRecommendation());
- assertEquals(mRecommendationRequest.getDefaultWifiConfig().SSID,
- result.getWifiConfiguration().SSID);
- }
-
- @Test
- public void testRequestRecommendationAsync_requestSucceeds() throws Exception {
- mNetworkScoreService.onUserUnlocked(0);
- final Bundle bundle = new Bundle();
- doAnswer(invocation -> {
- invocation.<IRemoteCallback>getArgument(1).sendResult(bundle);
- return null;
- }).when(mRecommendationProvider)
- .requestRecommendation(eq(mRecommendationRequest), isA(IRemoteCallback.class),
- anyInt());
-
- mNetworkScoreService.requestRecommendationAsync(mRecommendationRequest,
- mRemoteCallback);
- boolean callbackRan = mOnResultListener.countDownLatch.await(3, TimeUnit.SECONDS);
- assertTrue(callbackRan);
- // If it's not the same instance then something else ran the callback.
- assertSame(bundle, mOnResultListener.receivedBundle);
- }
-
- @Test
- public void testRequestRecommendationAsync_requestThrowsRemoteException() throws Exception {
- mNetworkScoreService.onUserUnlocked(0);
- doThrow(new RemoteException()).when(mRecommendationProvider)
- .requestRecommendation(eq(mRecommendationRequest), isA(IRemoteCallback.class),
- anyInt());
-
- mNetworkScoreService.requestRecommendationAsync(mRecommendationRequest,
- mRemoteCallback);
- boolean callbackRan = mOnResultListener.countDownLatch.await(3, TimeUnit.SECONDS);
- assertTrue(callbackRan);
- }
-
- @Test
public void dispatchingContentObserver_nullUri() throws Exception {
NetworkScoreService.DispatchingContentObserver observer =
new NetworkScoreService.DispatchingContentObserver(mContext, null /*handler*/);
@@ -435,15 +259,6 @@
}
@Test
- public void oneTimeCallback_multipleCallbacks() throws Exception {
- NetworkScoreService.OneTimeCallback callback =
- new NetworkScoreService.OneTimeCallback(mRemoteCallback);
- callback.sendResult(null);
- callback.sendResult(null);
- assertEquals(1, mOnResultListener.resultCount);
- }
-
- @Test
public void testUpdateScores_notActiveScorer() {
bindToScorer(false /*callerIsScorer*/);
@@ -1088,19 +903,6 @@
mNetworkScoreService.onUserUnlocked(0);
}
- private static class OnResultListener implements RemoteCallback.OnResultListener {
- private final CountDownLatch countDownLatch = new CountDownLatch(1);
- private int resultCount;
- private Bundle receivedBundle;
-
- @Override
- public void onResult(Bundle result) {
- countDownLatch.countDown();
- resultCount++;
- receivedBundle = result;
- }
- }
-
private static class CountDownHandler extends Handler {
CountDownLatch latch = new CountDownLatch(1);
int receivedWhat;
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
index 20839c5..36e9b3f8 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
@@ -22,6 +22,7 @@
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.nullable;
import static org.mockito.Mockito.times;
@@ -80,6 +81,7 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
+import java.util.HashMap;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
@@ -2443,7 +2445,6 @@
@SmallTest
public void testGetAccountsByFeaturesError() throws Exception {
unlockSystemUser();
-
mAms.addAccountExplicitly(AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, "p11", null);
mAms.addAccountExplicitly(AccountManagerServiceTestFixtures.ACCOUNT_ERROR, "p12", null);
@@ -2511,28 +2512,37 @@
updateBroadcastCounters(2);
assertEquals(mVisibleAccountsChangedBroadcasts, 0); // broadcast was not sent
assertEquals(mLoginAccountsChangedBroadcasts, 2);
- assertEquals(mAccountRemovedBroadcasts, 0);
}
@SmallTest
public void testRegisterAccountListenerWithAddingTwoAccounts() throws Exception {
unlockSystemUser();
+
+ HashMap<String, Integer> visibility = new HashMap<>();
+ visibility.put(AccountManagerServiceTestFixtures.CALLER_PACKAGE,
+ AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
+
mAms.registerAccountListener(
new String [] {AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1},
- "testpackage"); // opPackageName
- mAms.addAccountExplicitly(AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, "p11", null);
+ AccountManagerServiceTestFixtures.CALLER_PACKAGE);
+ mAms.addAccountExplicitlyWithVisibility(
+ AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, "p11", null, visibility);
mAms.unregisterAccountListener(
new String [] {AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1},
- "testpackage"); // opPackageName
- mAms.addAccountExplicitly(
- AccountManagerServiceTestFixtures.ACCOUNT_INTERVENE, "p11", null);
+ AccountManagerServiceTestFixtures.CALLER_PACKAGE);
+
+ addAccountRemovedReceiver(AccountManagerServiceTestFixtures.CALLER_PACKAGE);
+ mAms.addAccountExplicitlyWithVisibility(
+ AccountManagerServiceTestFixtures.ACCOUNT_INTERVENE, "p11", null, visibility);
updateBroadcastCounters(3);
assertEquals(mVisibleAccountsChangedBroadcasts, 1);
assertEquals(mLoginAccountsChangedBroadcasts, 2);
+ assertEquals(mAccountRemovedBroadcasts, 0);
mAms.removeAccountInternal(AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS);
- mAms.registerAccountListener( null /* accountTypes */, "testpackage");
+ mAms.registerAccountListener( null /* accountTypes */,
+ AccountManagerServiceTestFixtures.CALLER_PACKAGE);
mAms.removeAccountInternal(AccountManagerServiceTestFixtures.ACCOUNT_INTERVENE);
updateBroadcastCounters(8);
@@ -2544,6 +2554,13 @@
@SmallTest
public void testRegisterAccountListenerForThreePackages() throws Exception {
unlockSystemUser();
+
+ addAccountRemovedReceiver("testpackage1");
+ HashMap<String, Integer> visibility = new HashMap<>();
+ visibility.put("testpackage1", AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
+ visibility.put("testpackage2", AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
+ visibility.put("testpackage3", AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
+
mAms.registerAccountListener(
new String [] {AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1},
"testpackage1"); // opPackageName
@@ -2553,7 +2570,8 @@
mAms.registerAccountListener(
new String [] {AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1},
"testpackage3"); // opPackageName
- mAms.addAccountExplicitly(AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, "p11", null);
+ mAms.addAccountExplicitlyWithVisibility(
+ AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, "p11", null, visibility);
updateBroadcastCounters(4);
assertEquals(mVisibleAccountsChangedBroadcasts, 3);
assertEquals(mLoginAccountsChangedBroadcasts, 1);
@@ -2572,13 +2590,47 @@
mAms.addAccountExplicitly(
AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS_TYPE_2, "p11", null);
- updateBroadcastCounters(9);
+ updateBroadcastCounters(8);
assertEquals(mVisibleAccountsChangedBroadcasts, 5);
assertEquals(mLoginAccountsChangedBroadcasts, 3);
assertEquals(mAccountRemovedBroadcasts, 1);
}
@SmallTest
+ public void testRegisterAccountListenerForAddingAccountWithVisibility() throws Exception {
+ unlockSystemUser();
+
+ HashMap<String, Integer> visibility = new HashMap<>();
+ visibility.put("testpackage1", AccountManager.VISIBILITY_NOT_VISIBLE);
+ visibility.put("testpackage2", AccountManager.VISIBILITY_USER_MANAGED_NOT_VISIBLE);
+ visibility.put("testpackage3", AccountManager.VISIBILITY_USER_MANAGED_VISIBLE);
+
+ addAccountRemovedReceiver("testpackage1");
+ mAms.registerAccountListener(
+ new String [] {AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1},
+ "testpackage1"); // opPackageName
+ mAms.registerAccountListener(
+ new String [] {AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1},
+ "testpackage2"); // opPackageName
+ mAms.registerAccountListener(
+ new String [] {AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1},
+ "testpackage3"); // opPackageName
+ mAms.addAccountExplicitlyWithVisibility(
+ AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS, "p11", null, visibility);
+
+ updateBroadcastCounters(2);
+ assertEquals(mVisibleAccountsChangedBroadcasts, 1);
+ assertEquals(mLoginAccountsChangedBroadcasts, 1);
+
+ mAms.removeAccountInternal(AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS);
+
+ updateBroadcastCounters(4);
+ assertEquals(mVisibleAccountsChangedBroadcasts, 2);
+ assertEquals(mLoginAccountsChangedBroadcasts, 2);
+ assertEquals(mAccountRemovedBroadcasts, 0); // account was never visible.
+ }
+
+ @SmallTest
public void testRegisterAccountListenerCredentialsUpdate() throws Exception {
unlockSystemUser();
mAms.registerAccountListener(
@@ -2609,21 +2661,31 @@
mLoginAccountsChangedBroadcasts = 0;
mAccountRemovedBroadcasts = 0;
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
- verify(mMockContext, times(expectedBroadcasts)).sendBroadcastAsUser(captor.capture(),
+ verify(mMockContext, atLeast(expectedBroadcasts)).sendBroadcastAsUser(captor.capture(),
any(UserHandle.class));
for (Intent intent : captor.getAllValues()) {
if (AccountManager.ACTION_VISIBLE_ACCOUNTS_CHANGED.equals(intent.getAction())) {
mVisibleAccountsChangedBroadcasts++;
- }
- if (AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION.equals(intent.getAction())) {
+ } else if (AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION.equals(intent.getAction())) {
mLoginAccountsChangedBroadcasts++;
- }
- if (AccountManager.ACTION_ACCOUNT_REMOVED.equals(intent.getAction())) {
+ } else if (AccountManager.ACTION_ACCOUNT_REMOVED.equals(intent.getAction())) {
mAccountRemovedBroadcasts++;
}
}
}
+ private void addAccountRemovedReceiver(String packageName) {
+ ResolveInfo resolveInfo = new ResolveInfo();
+ resolveInfo.activityInfo = new ActivityInfo();
+ resolveInfo.activityInfo.applicationInfo = new ApplicationInfo();
+ resolveInfo.activityInfo.applicationInfo.packageName = packageName;
+
+ List<ResolveInfo> accountRemovedReceivers = new ArrayList<>();
+ accountRemovedReceivers.add(resolveInfo);
+ when(mMockPackageManager.queryBroadcastReceiversAsUser(any(Intent.class), anyInt(),
+ anyInt())).thenReturn(accountRemovedReceivers);
+ }
+
@SmallTest
public void testConcurrencyReadWrite() throws Exception {
// Test 2 threads calling getAccounts and 1 thread setAuthToken
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 85f84ba..3aeaa29 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -45,6 +45,7 @@
import android.service.carrier.CarrierIdentifier;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
+import android.telephony.VisualVoicemailService.VisualVoicemailTask;
import android.telephony.ims.feature.ImsFeature;
import android.util.Log;
@@ -877,6 +878,30 @@
public static final String VVM_TYPE_CVVM = "vvm_type_cvvm";
/**
+ * Key in bundle returned by {@link #getVisualVoicemailPackageName()}, indicating whether visual
+ * voicemail was enabled or disabled by the user. If the user never explicitly changed this
+ * setting, this key will not exist.
+ *
+ * @see #getVisualVoicemailSettings()
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL =
+ "android.telephony.extra.VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL";
+
+ /**
+ * Key in bundle returned by {@link #getVisualVoicemailPackageName()}, indicating the voicemail
+ * access PIN scrambled during the auto provisioning process. The user is expected to reset
+ * their PIN if this value is not {@code null}.
+ *
+ * @see #getVisualVoicemailSettings()
+ * @hide
+ */
+ @SystemApi
+ public static final String EXTRA_VOICEMAIL_SCRAMBLED_PIN_STRING =
+ "android.telephony.extra.VOICEMAIL_SCRAMBLED_PIN_STRING";
+
+ /**
* @hide
*/
public static final String USSD_RESPONSE = "USSD_RESPONSE";
@@ -2746,6 +2771,33 @@
return false;
}
+ /**
+ * Returns an opaque bundle of settings formerly used by the visual voicemail client for the
+ * subscription ID pinned to the TelephonyManager, or {@code null} if the subscription ID is
+ * invalid. This method allows the system dialer to migrate settings out of the pre-O visual
+ * voicemail client in telephony.
+ *
+ * <p>Requires the caller to be the system dialer.
+ *
+ * @see #KEY_VISUAL_VOICEMAIL_ENABLED_BY_USER_BOOL
+ * @see #KEY_VOICEMAIL_SCRAMBLED_PIN_STRING
+ *
+ * @hide
+ */
+ @SystemApi
+ @Nullable
+ public Bundle getVisualVoicemailSettings(){
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony
+ .getVisualVoicemailSettings(mContext.getOpPackageName(), mSubId);
+ }
+ } catch (RemoteException ex) {
+ } catch (NullPointerException ex) {
+ }
+ return null;
+ }
/**
* Returns the package responsible of processing visual voicemail for the subscription ID pinned
@@ -2774,6 +2826,54 @@
}
/**
+ * Set the visual voicemail SMS filter settings for the subscription ID pinned
+ * to the TelephonyManager.
+ * When the filter is enabled, {@link
+ * VisualVoicemailService#onSmsReceived(VisualVoicemailTask, VisualVoicemailSms)} will be
+ * called when a SMS matching the settings is received. The caller should have
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} and implement a
+ * VisualVoicemailService.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ *
+ * @param settings The settings for the filter, or {@code null} to disable the filter.
+ */
+ public void setVisualVoicemailSmsFilterSettings(VisualVoicemailSmsFilterSettings settings) {
+ if (settings == null) {
+ disableVisualVoicemailSmsFilter(mSubId);
+ } else {
+ enableVisualVoicemailSmsFilter(mSubId, settings);
+ }
+ }
+
+ /**
+ * Send a visual voicemail SMS. The caller must be the current default dialer.
+ * A {@link VisualVoicemailService} uses this method to send a command via SMS to the carrier's
+ * visual voicemail server. Some examples for carriers using the OMTP standard include
+ * activating and deactivating visual voicemail, or requesting the current visual voicemail
+ * provisioning status. See the OMTP Visual Voicemail specification for more information on the
+ * format of these SMS messages.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#SEND_SMS SEND_SMS}
+ *
+ * @param number The destination number.
+ * @param port The destination port for data SMS, or 0 for text SMS.
+ * @param text The message content. For data sms, it will be encoded as a UTF-8 byte stream.
+ * @param sentIntent The sent intent passed to the {@link SmsManager}
+ *
+ * @throws SecurityException if the caller is not the current default dialer
+ *
+ * @see SmsManager#sendDataMessage(String, String, short, byte[], PendingIntent, PendingIntent)
+ * @see SmsManager#sendTextMessage(String, String, String, PendingIntent, PendingIntent)
+ */
+ public void sendVisualVoicemailSms(String number, int port, String text,
+ PendingIntent sentIntent) {
+ sendVisualVoicemailSmsForSubscriber(mSubId, number, port, text, sentIntent);
+ }
+
+ /**
* Enables the visual voicemail SMS filter for a phone account. When the filter is
* enabled, Incoming SMS messages matching the OMTP VVM SMS interface will be redirected to the
* visual voicemail client with
diff --git a/telephony/java/android/telephony/VisualVoicemailService.java b/telephony/java/android/telephony/VisualVoicemailService.java
index e211f76..fe30eb7 100644
--- a/telephony/java/android/telephony/VisualVoicemailService.java
+++ b/telephony/java/android/telephony/VisualVoicemailService.java
@@ -18,6 +18,7 @@
import android.annotation.MainThread;
import android.annotation.SdkConstant;
+import android.annotation.SystemApi;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
@@ -199,7 +200,8 @@
/**
* Called when a SMS matching the {@link VisualVoicemailSmsFilterSettings} set by
- * {@link #setSmsFilterSettings(Context, PhoneAccountHandle, VisualVoicemailSmsFilterSettings)}
+ * {@link TelephonyManager#setVisualVoicemailSmsFilterSettings(VisualVoicemailSmsFilterSettings)
+ * }
* is received.
*
* @param task The task representing this event. {@link VisualVoicemailTask#finish()} must be
@@ -240,8 +242,11 @@
*
* @param phoneAccountHandle The account to apply the settings to.
* @param settings The settings for the filter, or {@code null} to disable the filter.
+ *
+ * @hide
*/
- public final static void setSmsFilterSettings(Context context,
+ @SystemApi
+ public static final void setSmsFilterSettings(Context context,
PhoneAccountHandle phoneAccountHandle,
VisualVoicemailSmsFilterSettings settings) {
TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class);
@@ -269,8 +274,11 @@
*
* @see SmsManager#sendDataMessage(String, String, short, byte[], PendingIntent, PendingIntent)
* @see SmsManager#sendTextMessage(String, String, String, PendingIntent, PendingIntent)
+ *
+ * @hide
*/
- public final static void sendVisualVoicemailSms(Context context,
+ @SystemApi
+ public static final void sendVisualVoicemailSms(Context context,
PhoneAccountHandle phoneAccountHandle, String number,
short port, String text, PendingIntent sentIntent) {
TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class);
diff --git a/telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.java b/telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.java
index 56a8c62..8ed96a3 100644
--- a/telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.java
+++ b/telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.java
@@ -38,7 +38,7 @@
* <p>Use {@link android.telephony.VisualVoicemailSmsFilterSettings.Builder} to construct this
* class.
*
- * @see VisualVoicemailService#setSmsFilterSettings(Context, PhoneAccountHandle, VisualVoicemailSmsFilterSettings)
+ * @see TelephonyManager#setVisualVoicemailSmsFilterSettings(VisualVoicemailSmsFilterSettings)
*/
public final class VisualVoicemailSmsFilterSettings implements Parcelable {
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index dd08f67..da333ae 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -498,6 +498,8 @@
*/
boolean isConcurrentVoiceAndDataAllowed(int subId);
+ Bundle getVisualVoicemailSettings(String callingPackage, int subId);
+
String getVisualVoicemailPackageName(String callingPackage, int subId);
// Not oneway, caller needs to make sure the vaule is set before receiving a SMS
diff --git a/tests/testables/src/android/testing/AndroidTestingRunner.java b/tests/testables/src/android/testing/AndroidTestingRunner.java
index 816ed03..a425f70 100644
--- a/tests/testables/src/android/testing/AndroidTestingRunner.java
+++ b/tests/testables/src/android/testing/AndroidTestingRunner.java
@@ -18,7 +18,7 @@
import android.support.test.internal.runner.junit4.statement.RunBefores;
import android.support.test.internal.runner.junit4.statement.UiThreadStatement;
-import android.testing.TestableLooper.LooperStatement;
+import android.testing.TestableLooper.LooperFrameworkMethod;
import android.testing.TestableLooper.RunWithLooper;
import org.junit.After;
@@ -30,6 +30,7 @@
import org.junit.runners.model.InitializationError;
import org.junit.runners.model.Statement;
+import java.util.ArrayList;
import java.util.List;
/**
@@ -49,28 +50,21 @@
@Override
protected Statement methodInvoker(FrameworkMethod method, Object test) {
- return shouldRunOnUiThread(method) ? new UiThreadStatement(
- methodInvokerInt(method, test), true) : methodInvokerInt(method, test);
- }
-
- protected Statement methodInvokerInt(FrameworkMethod method, Object test) {
- RunWithLooper annotation = method.getAnnotation(RunWithLooper.class);
- if (annotation == null) annotation = mKlass.getAnnotation(RunWithLooper.class);
- if (annotation != null) {
- return new LooperStatement(super.methodInvoker(method, test),
- annotation.setAsMainLooper(), test);
- }
- return super.methodInvoker(method, test);
+ method = looperWrap(method, test, method);
+ final Statement statement = super.methodInvoker(method, test);
+ return shouldRunOnUiThread(method) ? new UiThreadStatement(statement, true) : statement;
}
protected Statement withBefores(FrameworkMethod method, Object target, Statement statement) {
- List befores = this.getTestClass().getAnnotatedMethods(Before.class);
+ List befores = looperWrap(method, target,
+ this.getTestClass().getAnnotatedMethods(Before.class));
return befores.isEmpty() ? statement : new RunBefores(method, statement,
befores, target);
}
protected Statement withAfters(FrameworkMethod method, Object target, Statement statement) {
- List afters = this.getTestClass().getAnnotatedMethods(After.class);
+ List afters = looperWrap(method, target,
+ this.getTestClass().getAnnotatedMethods(After.class));
return afters.isEmpty() ? statement : new RunAfters(method, statement, afters,
target);
}
@@ -88,6 +82,30 @@
return annotation == null ? 0L : annotation.timeout();
}
+ protected List<FrameworkMethod> looperWrap(FrameworkMethod method, Object test,
+ List<FrameworkMethod> methods) {
+ RunWithLooper annotation = method.getAnnotation(RunWithLooper.class);
+ if (annotation == null) annotation = mKlass.getAnnotation(RunWithLooper.class);
+ if (annotation != null) {
+ methods = new ArrayList<>(methods);
+ for (int i = 0; i < methods.size(); i++) {
+ methods.set(i, LooperFrameworkMethod.get(methods.get(i),
+ annotation.setAsMainLooper(), test));
+ }
+ }
+ return methods;
+ }
+
+ protected FrameworkMethod looperWrap(FrameworkMethod method, Object test,
+ FrameworkMethod base) {
+ RunWithLooper annotation = method.getAnnotation(RunWithLooper.class);
+ if (annotation == null) annotation = mKlass.getAnnotation(RunWithLooper.class);
+ if (annotation != null) {
+ return LooperFrameworkMethod.get(base, annotation.setAsMainLooper(), test);
+ }
+ return base;
+ }
+
public boolean shouldRunOnUiThread(FrameworkMethod method) {
if (mKlass.getAnnotation(UiThreadTest.class) != null) {
return true;
diff --git a/tests/testables/src/android/testing/TestableLooper.java b/tests/testables/src/android/testing/TestableLooper.java
index 8a33cf9..9eddc51 100644
--- a/tests/testables/src/android/testing/TestableLooper.java
+++ b/tests/testables/src/android/testing/TestableLooper.java
@@ -15,20 +15,21 @@
package android.testing;
import android.os.Handler;
+import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.MessageQueue;
+import android.os.TestLooperManager;
+import android.support.test.InstrumentationRegistry;
import android.util.ArrayMap;
-import org.junit.runners.model.Statement;
+import org.junit.runners.model.FrameworkMethod;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
-import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
-import java.lang.reflect.Method;
import java.util.Map;
/**
@@ -38,65 +39,35 @@
*/
public class TestableLooper {
- private final Method mNext;
- private final Method mRecycleUnchecked;
-
private Looper mLooper;
private MessageQueue mQueue;
private boolean mMain;
private Object mOriginalMain;
private MessageHandler mMessageHandler;
- private int mParsedCount;
private Handler mHandler;
- private Message mEmptyMessage;
+ private Runnable mEmptyMessage;
+ private TestLooperManager mQueueWrapper;
- public TestableLooper() throws Exception {
- this(true);
+ public TestableLooper(Looper l) throws Exception {
+ this(InstrumentationRegistry.getInstrumentation().acquireLooperManager(l), l);
}
- public TestableLooper(boolean setMyLooper) throws Exception {
- setupQueue(setMyLooper);
- mNext = mQueue.getClass().getDeclaredMethod("next");
- mNext.setAccessible(true);
- mRecycleUnchecked = Message.class.getDeclaredMethod("recycleUnchecked");
- mRecycleUnchecked.setAccessible(true);
+ private TestableLooper(TestLooperManager wrapper, Looper l) throws Exception {
+ mQueueWrapper = wrapper;
+ setupQueue(l);
+ }
+
+ private TestableLooper(Looper looper, boolean b) throws Exception {
+ setupQueue(looper);
}
public Looper getLooper() {
return mLooper;
}
- private void clearLooper() throws NoSuchFieldException, IllegalAccessException {
- Field field = Looper.class.getDeclaredField("sThreadLocal");
- field.setAccessible(true);
- ThreadLocal<Looper> sThreadLocal = (ThreadLocal<Looper>) field.get(null);
- sThreadLocal.set(null);
- }
-
- private boolean setForCurrentThread() throws NoSuchFieldException, IllegalAccessException {
- if (Looper.myLooper() != mLooper) {
- Field field = Looper.class.getDeclaredField("sThreadLocal");
- field.setAccessible(true);
- ThreadLocal<Looper> sThreadLocal = (ThreadLocal<Looper>) field.get(null);
- sThreadLocal.set(mLooper);
- return true;
- }
- return false;
- }
-
- private void setupQueue(boolean setMyLooper) throws Exception {
- if (setMyLooper) {
- clearLooper();
- Looper.prepare();
- mLooper = Looper.myLooper();
- } else {
- Constructor<Looper> constructor = Looper.class.getDeclaredConstructor(
- boolean.class);
- constructor.setAccessible(true);
- mLooper = constructor.newInstance(true);
- }
-
+ private void setupQueue(Looper l) throws Exception {
+ mLooper = l;
mQueue = mLooper.getQueue();
mHandler = new Handler(mLooper);
}
@@ -121,9 +92,7 @@
* tests.
*/
public void destroy() throws NoSuchFieldException, IllegalAccessException {
- if (Looper.myLooper() == mLooper) {
- clearLooper();
- }
+ mQueueWrapper.release();
if (mMain && mOriginalMain != null) {
Field field = mLooper.getClass().getDeclaredField("sMainLooper");
field.setAccessible(true);
@@ -156,34 +125,35 @@
private int processQueuedMessages() {
int count = 0;
- mEmptyMessage = mHandler.obtainMessage(1);
- mHandler.sendMessageDelayed(mEmptyMessage, 1);
+ mEmptyMessage = () -> { };
+ mHandler.post(mEmptyMessage);
+ waitForMessage(mQueueWrapper, mHandler, mEmptyMessage);
while (parseMessageInt()) count++;
return count;
}
private boolean parseMessageInt() {
try {
- Message result = (Message) mNext.invoke(mQueue);
+ Message result = mQueueWrapper.next();
if (result != null) {
// This is a break message.
- if (result == mEmptyMessage) {
- mRecycleUnchecked.invoke(result);
+ if (result.getCallback() == mEmptyMessage) {
+ mQueueWrapper.recycle(result);
return false;
}
if (mMessageHandler != null) {
if (mMessageHandler.onMessageHandled(result)) {
result.getTarget().dispatchMessage(result);
- mRecycleUnchecked.invoke(result);
+ mQueueWrapper.recycle(result);
} else {
- mRecycleUnchecked.invoke(result);
+ mQueueWrapper.recycle(result);
// Message handler indicated it doesn't want us to continue.
return false;
}
} else {
result.getTarget().dispatchMessage(result);
- mRecycleUnchecked.invoke(result);
+ mQueueWrapper.recycle(result);
}
} else {
// No messages, don't continue parsing
@@ -199,10 +169,14 @@
* Runs an executable with myLooper set and processes all messages added.
*/
public void runWithLooper(RunnableWithException runnable) throws Exception {
- boolean set = setForCurrentThread();
- runnable.run();
+ new Handler(getLooper()).post(() -> {
+ try {
+ runnable.run();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ });
processAllMessages();
- if (set) clearLooper();
}
public interface RunnableWithException {
@@ -215,39 +189,132 @@
boolean setAsMainLooper() default false;
}
+ private static void waitForMessage(TestLooperManager queueWrapper, Handler handler,
+ Runnable execute) {
+ for (int i = 0; i < 10; i++) {
+ if (!queueWrapper.hasMessages(handler, null, execute)) {
+ try {
+ Thread.sleep(1);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+ if (!queueWrapper.hasMessages(handler, null, execute)) {
+ throw new RuntimeException("Message didn't queue...");
+ }
+ }
+
private static final Map<Object, TestableLooper> sLoopers = new ArrayMap<>();
public static TestableLooper get(Object test) {
return sLoopers.get(test);
}
- public static class LooperStatement extends Statement {
- private final boolean mSetAsMain;
- private final Statement mBase;
- private final TestableLooper mLooper;
+ public static class LooperFrameworkMethod extends FrameworkMethod {
+ private HandlerThread mHandlerThread;
- public LooperStatement(Statement base, boolean setAsMain, Object test) {
- mBase = base;
+ private final TestableLooper mTestableLooper;
+ private final Looper mLooper;
+ private final Handler mHandler;
+
+ public LooperFrameworkMethod(FrameworkMethod base, boolean setAsMain, Object test) {
+ super(base.getMethod());
try {
- mLooper = new TestableLooper(false);
- sLoopers.put(test, mLooper);
- mSetAsMain = setAsMain;
+ mLooper = setAsMain ? Looper.getMainLooper() : createLooper();
+ mTestableLooper = new TestableLooper(mLooper, false);
} catch (Exception e) {
throw new RuntimeException(e);
}
+ sLoopers.put(test, mTestableLooper);
+ mHandler = new Handler(mLooper);
+ }
+
+ public LooperFrameworkMethod(TestableLooper other, FrameworkMethod base) {
+ super(base.getMethod());
+ mLooper = other.mLooper;
+ mTestableLooper = other;
+ mHandler = new Handler(mLooper);
+ }
+
+ public static FrameworkMethod get(FrameworkMethod base, boolean setAsMain, Object test) {
+ if (sLoopers.containsKey(test)) {
+ return new LooperFrameworkMethod(sLoopers.get(test), base);
+ }
+ return new LooperFrameworkMethod(base, setAsMain, test);
}
@Override
- public void evaluate() throws Throwable {
- mLooper.setForCurrentThread();
- if (mSetAsMain) {
- mLooper.setAsMainLooper();
+ public Object invokeExplosively(Object target, Object... params) throws Throwable {
+ if (Looper.myLooper() == mLooper) {
+ // Already on the right thread from another statement, just execute then.
+ return super.invokeExplosively(target, params);
+ }
+ boolean set = mTestableLooper.mQueueWrapper == null;
+ if (set) {
+ mTestableLooper.mQueueWrapper = InstrumentationRegistry.getInstrumentation()
+ .acquireLooperManager(mLooper);
+ }
+ try {
+ Object[] ret = new Object[1];
+ // Run the execution on the looper thread.
+ Runnable execute = () -> {
+ try {
+ ret[0] = super.invokeExplosively(target, params);
+ } catch (Throwable throwable) {
+ throw new LooperException(throwable);
+ }
+ };
+ Message m = Message.obtain(mHandler, execute);
+
+ // Dispatch our message.
+ try {
+ mTestableLooper.mQueueWrapper.execute(m);
+ } catch (LooperException e) {
+ throw e.getSource();
+ } catch (RuntimeException re) {
+ // If the TestLooperManager has to post, it will wrap what it throws in a
+ // RuntimeException, make sure we grab the actual source.
+ if (re.getCause() instanceof LooperException) {
+ throw ((LooperException) re.getCause()).getSource();
+ } else {
+ throw re.getCause();
+ }
+ } finally {
+ m.recycle();
+ }
+ return ret[0];
+ } finally {
+ if (set) {
+ mTestableLooper.mQueueWrapper.release();
+ mTestableLooper.mQueueWrapper = null;
+ }
+ }
+ }
+
+ private Looper createLooper() {
+ // TODO: Find way to share these.
+ mHandlerThread = new HandlerThread(TestableLooper.class.getSimpleName());
+ mHandlerThread.start();
+ return mHandlerThread.getLooper();
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ super.finalize();
+ if (mHandlerThread != null) {
+ mHandlerThread.quit();
+ }
+ }
+
+ private static class LooperException extends RuntimeException {
+ private final Throwable mSource;
+
+ public LooperException(Throwable t) {
+ mSource = t;
}
- try {
- mBase.evaluate();
- } finally {
- mLooper.destroy();
+ public Throwable getSource() {
+ return mSource;
}
}
}
diff --git a/tests/testables/tests/src/android/testing/TestableLooperTest.java b/tests/testables/tests/src/android/testing/TestableLooperTest.java
index 18e5fff..12f1d0a 100644
--- a/tests/testables/tests/src/android/testing/TestableLooperTest.java
+++ b/tests/testables/tests/src/android/testing/TestableLooperTest.java
@@ -24,17 +24,16 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.testing.TestableLooper.MessageHandler;
import android.testing.TestableLooper.RunWithLooper;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
@RunWith(AndroidTestingRunner.class)
@RunWithLooper
public class TestableLooperTest {
@@ -46,11 +45,6 @@
mTestableLooper = TestableLooper.get(this);
}
- @After
- public void tearDown() throws Exception {
- mTestableLooper.destroy();
- }
-
@Test
public void testMessageExecuted() throws Exception {
Handler h = new Handler();
@@ -133,39 +127,23 @@
@Test
public void testMainLooper() throws Exception {
assertNotEquals(Looper.myLooper(), Looper.getMainLooper());
-
- Looper originalMain = Looper.getMainLooper();
- mTestableLooper.setAsMainLooper();
- assertEquals(Looper.myLooper(), Looper.getMainLooper());
- Runnable r = mock(Runnable.class);
-
- new Handler(Looper.getMainLooper()).post(r);
- mTestableLooper.processAllMessages();
-
- verify(r).run();
- mTestableLooper.destroy();
-
- assertEquals(originalMain, Looper.getMainLooper());
- }
-
- @Test
- public void testNotMyLooper() throws Exception {
- TestableLooper looper = new TestableLooper(false);
-
- assertEquals(Looper.myLooper(), mTestableLooper.getLooper());
- assertNotEquals(Looper.myLooper(), looper.getLooper());
-
Runnable r = mock(Runnable.class);
Runnable r2 = mock(Runnable.class);
- new Handler().post(r);
- new Handler(looper.getLooper()).post(r2);
+ TestableLooper testableLooper = new TestableLooper(Looper.getMainLooper());
- looper.processAllMessages();
- verify(r2).run();
- verify(r, never()).run();
+ try {
+ testableLooper.setMessageHandler(m -> {
+ if (m.getCallback() == r) return true;
+ return false;
+ });
+ new Handler(Looper.getMainLooper()).post(r);
+ testableLooper.processAllMessages();
- mTestableLooper.processAllMessages();
- verify(r).run();
+ verify(r).run();
+ verify(r2, never()).run();
+ } finally {
+ testableLooper.destroy();
+ }
}
@Test
diff --git a/tools/aapt2/cmd/Compile.cpp b/tools/aapt2/cmd/Compile.cpp
index 578a8fb..b93c6ec 100644
--- a/tools/aapt2/cmd/Compile.cpp
+++ b/tools/aapt2/cmd/Compile.cpp
@@ -365,6 +365,21 @@
return true;
}
+static bool IsValidFile(IAaptContext* context, const StringPiece& input_path) {
+ const file::FileType file_type = file::GetFileType(input_path);
+ if (file_type != file::FileType::kRegular && file_type != file::FileType::kSymlink) {
+ if (file_type == file::FileType::kDirectory) {
+ context->GetDiagnostics()->Error(DiagMessage(input_path)
+ << "resource file cannot be a directory");
+ } else {
+ context->GetDiagnostics()->Error(DiagMessage(input_path)
+ << "not a valid resource file");
+ }
+ return false;
+ }
+ return true;
+}
+
static bool CompileXml(IAaptContext* context, const CompileOptions& options,
const ResourcePathData& path_data, IArchiveWriter* writer,
const std::string& output_path) {
@@ -569,7 +584,8 @@
std::string error_str;
Maybe<android::FileMap> f = file::MmapPath(path_data.source.path, &error_str);
if (!f) {
- context->GetDiagnostics()->Error(DiagMessage(path_data.source) << error_str);
+ context->GetDiagnostics()->Error(DiagMessage(path_data.source) << "failed to mmap file: "
+ << error_str);
return false;
}
@@ -582,6 +598,11 @@
class CompileContext : public IAaptContext {
public:
+ PackageType GetPackageType() override {
+ // Every compilation unit starts as an app and then gets linked as potentially something else.
+ return PackageType::kApp;
+ }
+
void SetVerbose(bool val) {
verbose_ = val;
}
@@ -692,6 +713,11 @@
context.GetDiagnostics()->Note(DiagMessage(path_data.source) << "processing");
}
+ if (!IsValidFile(&context, path_data.source.path)) {
+ error = true;
+ continue;
+ }
+
if (path_data.resource_dir == "values") {
// Overwrite the extension.
path_data.extension = "arsc";
diff --git a/tools/aapt2/cmd/Diff.cpp b/tools/aapt2/cmd/Diff.cpp
index fdc89b2..1a6f348 100644
--- a/tools/aapt2/cmd/Diff.cpp
+++ b/tools/aapt2/cmd/Diff.cpp
@@ -31,6 +31,11 @@
DiffContext() : name_mangler_({}), symbol_table_(&name_mangler_) {
}
+ PackageType GetPackageType() override {
+ // Doesn't matter.
+ return PackageType::kApp;
+ }
+
const std::string& GetCompilationPackage() override {
return empty_;
}
diff --git a/tools/aapt2/cmd/Dump.cpp b/tools/aapt2/cmd/Dump.cpp
index 1bbfb28..57c4574 100644
--- a/tools/aapt2/cmd/Dump.cpp
+++ b/tools/aapt2/cmd/Dump.cpp
@@ -144,6 +144,11 @@
class DumpContext : public IAaptContext {
public:
+ PackageType GetPackageType() override {
+ // Doesn't matter.
+ return PackageType::kApp;
+ }
+
IDiagnostics* GetDiagnostics() override {
return &diagnostics_;
}
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index b86188f..258516d 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -65,16 +65,7 @@
namespace aapt {
-// The type of package to build.
-enum class PackageType {
- kApp,
- kSharedLib,
- kStaticLib,
-};
-
struct LinkOptions {
- PackageType package_type = PackageType::kApp;
-
std::string output_path;
std::string manifest_path;
std::vector<std::string> include_paths;
@@ -130,6 +121,14 @@
LinkContext() : name_mangler_({}), symbols_(&name_mangler_) {
}
+ PackageType GetPackageType() override {
+ return package_type_;
+ }
+
+ void SetPackageType(PackageType type) {
+ package_type_ = type;
+ }
+
IDiagnostics* GetDiagnostics() override {
return &diagnostics_;
}
@@ -181,6 +180,7 @@
private:
DISALLOW_COPY_AND_ASSIGN(LinkContext);
+ PackageType package_type_ = PackageType::kApp;
StdErrDiagnostics diagnostics_;
NameMangler name_mangler_;
std::string compilation_package_;
@@ -627,7 +627,7 @@
std::string error_str;
std::unique_ptr<ResourceTable> include_static = LoadStaticLibrary(path, &error_str);
if (include_static) {
- if (options_.package_type != PackageType::kStaticLib) {
+ if (context_->GetPackageType() != PackageType::kStaticLib) {
// Can't include static libraries when not building a static library (they have no IDs
// assigned).
context_->GetDiagnostics()->Error(
@@ -1300,7 +1300,7 @@
*/
bool WriteApk(IArchiveWriter* writer, proguard::KeepSet* keep_set, xml::XmlResource* manifest,
ResourceTable* table) {
- const bool keep_raw_values = options_.package_type == PackageType::kStaticLib;
+ const bool keep_raw_values = context_->GetPackageType() == PackageType::kStaticLib;
bool result =
FlattenXml(manifest, "AndroidManifest.xml", {}, keep_raw_values, writer, context_);
if (!result) {
@@ -1325,7 +1325,7 @@
return false;
}
- if (options_.package_type == PackageType::kStaticLib) {
+ if (context_->GetPackageType() == PackageType::kStaticLib) {
if (!FlattenTableToPb(table, writer)) {
return false;
}
@@ -1374,7 +1374,7 @@
context_->SetPackageId(0x01);
// Verify we're building a regular app.
- if (options_.package_type != PackageType::kApp) {
+ if (context_->GetPackageType() != PackageType::kApp) {
context_->GetDiagnostics()->Error(
DiagMessage() << "package 'android' can only be built as a regular app");
return 1;
@@ -1414,7 +1414,7 @@
return 1;
}
- if (options_.package_type != PackageType::kStaticLib) {
+ if (context_->GetPackageType() != PackageType::kStaticLib) {
PrivateAttributeMover mover;
if (!mover.Consume(context_, &final_table_)) {
context_->GetDiagnostics()->Error(DiagMessage() << "failed moving private attributes");
@@ -1469,7 +1469,7 @@
return 1;
}
- if (options_.package_type == PackageType::kStaticLib) {
+ if (context_->GetPackageType() == PackageType::kStaticLib) {
if (!options_.products.empty()) {
context_->GetDiagnostics()->Warn(DiagMessage()
<< "can't select products when building static library");
@@ -1490,7 +1490,7 @@
}
}
- if (options_.package_type != PackageType::kStaticLib && context_->GetMinSdkVersion() > 0) {
+ if (context_->GetPackageType() != PackageType::kStaticLib && context_->GetMinSdkVersion() > 0) {
if (context_->IsVerbose()) {
context_->GetDiagnostics()->Note(DiagMessage()
<< "collapsing resource versions for minimum SDK "
@@ -1514,7 +1514,7 @@
proguard::KeepSet proguard_keep_set;
proguard::KeepSet proguard_main_dex_keep_set;
- if (options_.package_type == PackageType::kStaticLib) {
+ if (context_->GetPackageType() == PackageType::kStaticLib) {
if (options_.table_splitter_options.config_filter != nullptr ||
!options_.table_splitter_options.preferred_densities.empty()) {
context_->GetDiagnostics()->Warn(DiagMessage()
@@ -1641,11 +1641,12 @@
template_options.types = JavaClassGeneratorOptions::SymbolTypes::kAll;
template_options.javadoc_annotations = options_.javadoc_annotations;
- if (options_.package_type == PackageType::kStaticLib || options_.generate_non_final_ids) {
+ if (context_->GetPackageType() == PackageType::kStaticLib ||
+ options_.generate_non_final_ids) {
template_options.use_final = false;
}
- if (options_.package_type == PackageType::kSharedLib) {
+ if (context_->GetPackageType() == PackageType::kSharedLib) {
template_options.use_final = false;
template_options.rewrite_callback_options = OnResourcesLoadedCallbackOptions{};
}
@@ -1922,18 +1923,18 @@
}
if (shared_lib) {
- options.package_type = PackageType::kSharedLib;
+ context.SetPackageType(PackageType::kSharedLib);
context.SetPackageId(0x00);
} else if (static_lib) {
- options.package_type = PackageType::kStaticLib;
+ context.SetPackageType(PackageType::kStaticLib);
context.SetPackageId(kAppPackageId);
} else {
- options.package_type = PackageType::kApp;
+ context.SetPackageType(PackageType::kApp);
context.SetPackageId(kAppPackageId);
}
if (package_id) {
- if (options.package_type != PackageType::kApp) {
+ if (context.GetPackageType() != PackageType::kApp) {
context.GetDiagnostics()->Error(
DiagMessage() << "can't specify --package-id when not building a regular app");
return 1;
@@ -2000,7 +2001,7 @@
}
}
- if (options.package_type != PackageType::kStaticLib && stable_id_file_path) {
+ if (context.GetPackageType() != PackageType::kStaticLib && stable_id_file_path) {
if (!LoadStableIdMap(context.GetDiagnostics(), stable_id_file_path.value(),
&options.stable_id_map)) {
return 1;
@@ -2015,7 +2016,7 @@
".3gpp2", ".amr", ".awb", ".wma", ".wmv", ".webm", ".mkv"});
// Turn off auto versioning for static-libs.
- if (options.package_type == PackageType::kStaticLib) {
+ if (context.GetPackageType() == PackageType::kStaticLib) {
options.no_auto_version = true;
options.no_version_vectors = true;
options.no_version_transitions = true;
diff --git a/tools/aapt2/cmd/Optimize.cpp b/tools/aapt2/cmd/Optimize.cpp
index e99ee8a..78ed49b 100644
--- a/tools/aapt2/cmd/Optimize.cpp
+++ b/tools/aapt2/cmd/Optimize.cpp
@@ -59,6 +59,14 @@
class OptimizeContext : public IAaptContext {
public:
+ OptimizeContext() = default;
+
+ PackageType GetPackageType() override {
+ // Not important here. Using anything other than kApp adds EXTRA validation, which we want to
+ // avoid.
+ return PackageType::kApp;
+ }
+
IDiagnostics* GetDiagnostics() override {
return &diagnostics_;
}
@@ -99,6 +107,8 @@
}
private:
+ DISALLOW_COPY_AND_ASSIGN(OptimizeContext);
+
StdErrDiagnostics diagnostics_;
bool verbose_ = false;
int sdk_version_ = 0;
diff --git a/tools/aapt2/flatten/TableFlattener.cpp b/tools/aapt2/flatten/TableFlattener.cpp
index 3098458..d44b3e0 100644
--- a/tools/aapt2/flatten/TableFlattener.cpp
+++ b/tools/aapt2/flatten/TableFlattener.cpp
@@ -230,15 +230,18 @@
ResTable_package* pkg_header = pkg_writer.StartChunk<ResTable_package>(RES_TABLE_PACKAGE_TYPE);
pkg_header->id = util::HostToDevice32(package_->id.value());
- if (package_->name.size() >= arraysize(pkg_header->name)) {
+ // AAPT truncated the package name, so do the same.
+ // Shared libraries require full package names, so don't truncate theirs.
+ if (context_->GetPackageType() != PackageType::kApp &&
+ package_->name.size() >= arraysize(pkg_header->name)) {
diag_->Error(DiagMessage() << "package name '" << package_->name
- << "' is too long");
+ << "' is too long. "
+ "Shared libraries cannot have truncated package names");
return false;
}
// Copy the package name in device endianness.
- strcpy16_htod(pkg_header->name, arraysize(pkg_header->name),
- util::Utf8ToUtf16(package_->name));
+ strcpy16_htod(pkg_header->name, arraysize(pkg_header->name), util::Utf8ToUtf16(package_->name));
// Serialize the types. We do this now so that our type and key strings
// are populated. We write those first.
diff --git a/tools/aapt2/flatten/TableFlattener_test.cpp b/tools/aapt2/flatten/TableFlattener_test.cpp
index 4196187..8dff3a2 100644
--- a/tools/aapt2/flatten/TableFlattener_test.cpp
+++ b/tools/aapt2/flatten/TableFlattener_test.cpp
@@ -411,4 +411,40 @@
EXPECT_EQ(0x03u, entries.valueAt(idx));
}
+TEST_F(TableFlattenerTest, LongPackageNameIsTruncated) {
+ std::string kPackageName(256, 'F');
+
+ std::unique_ptr<IAaptContext> context =
+ test::ContextBuilder().SetCompilationPackage(kPackageName).SetPackageId(0x7f).Build();
+ std::unique_ptr<ResourceTable> table =
+ test::ResourceTableBuilder()
+ .SetPackageId(kPackageName, 0x7f)
+ .AddSimple(kPackageName + ":id/foo", ResourceId(0x7f010000))
+ .Build();
+
+ ResTable result;
+ ASSERT_TRUE(Flatten(context.get(), {}, table.get(), &result));
+
+ ASSERT_EQ(1u, result.getBasePackageCount());
+ EXPECT_EQ(127u, result.getBasePackageName(0).size());
+}
+
+TEST_F(TableFlattenerTest, LongSharedLibraryPackageNameIsIllegal) {
+ std::string kPackageName(256, 'F');
+
+ std::unique_ptr<IAaptContext> context = test::ContextBuilder()
+ .SetCompilationPackage(kPackageName)
+ .SetPackageId(0x7f)
+ .SetPackageType(PackageType::kSharedLib)
+ .Build();
+ std::unique_ptr<ResourceTable> table =
+ test::ResourceTableBuilder()
+ .SetPackageId(kPackageName, 0x7f)
+ .AddSimple(kPackageName + ":id/foo", ResourceId(0x7f010000))
+ .Build();
+
+ ResTable result;
+ ASSERT_FALSE(Flatten(context.get(), {}, table.get(), &result));
+}
+
} // namespace aapt
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index 0c19c7a..27ab22b 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -333,7 +333,7 @@
// Provider actions.
application_action["provider"] = component_action;
application_action["provider"]["grant-uri-permissions"];
- application_action["provider"]["path-permissions"];
+ application_action["provider"]["path-permission"];
return true;
}
diff --git a/tools/aapt2/process/IResourceTableConsumer.h b/tools/aapt2/process/IResourceTableConsumer.h
index 4526a79..30dad802 100644
--- a/tools/aapt2/process/IResourceTableConsumer.h
+++ b/tools/aapt2/process/IResourceTableConsumer.h
@@ -32,9 +32,17 @@
class ResourceTable;
class SymbolTable;
+// The type of package to build.
+enum class PackageType {
+ kApp,
+ kSharedLib,
+ kStaticLib,
+};
+
struct IAaptContext {
virtual ~IAaptContext() = default;
+ virtual PackageType GetPackageType() = 0;
virtual SymbolTable* GetExternalSymbols() = 0;
virtual IDiagnostics* GetDiagnostics() = 0;
virtual const std::string& GetCompilationPackage() = 0;
diff --git a/tools/aapt2/test/Context.h b/tools/aapt2/test/Context.h
index 557cd1b..29d1838 100644
--- a/tools/aapt2/test/Context.h
+++ b/tools/aapt2/test/Context.h
@@ -35,9 +35,17 @@
public:
Context() : name_mangler_({}), symbols_(&name_mangler_), min_sdk_version_(0) {}
- SymbolTable* GetExternalSymbols() override { return &symbols_; }
+ PackageType GetPackageType() override {
+ return package_type_;
+ }
- IDiagnostics* GetDiagnostics() override { return &diagnostics_; }
+ SymbolTable* GetExternalSymbols() override {
+ return &symbols_;
+ }
+
+ IDiagnostics* GetDiagnostics() override {
+ return &diagnostics_;
+ }
const std::string& GetCompilationPackage() override {
CHECK(bool(compilation_package_)) << "package name not set";
@@ -49,17 +57,24 @@
return package_id_.value();
}
- NameMangler* GetNameMangler() override { return &name_mangler_; }
+ NameMangler* GetNameMangler() override {
+ return &name_mangler_;
+ }
- bool IsVerbose() override { return false; }
+ bool IsVerbose() override {
+ return false;
+ }
- int GetMinSdkVersion() override { return min_sdk_version_; }
+ int GetMinSdkVersion() override {
+ return min_sdk_version_;
+ }
private:
DISALLOW_COPY_AND_ASSIGN(Context);
friend class ContextBuilder;
+ PackageType package_type_ = PackageType::kApp;
Maybe<std::string> compilation_package_;
Maybe<uint8_t> package_id_;
StdErrDiagnostics diagnostics_;
@@ -70,6 +85,11 @@
class ContextBuilder {
public:
+ ContextBuilder& SetPackageType(PackageType type) {
+ context_->package_type_ = type;
+ return *this;
+ }
+
ContextBuilder& SetCompilationPackage(const android::StringPiece& package) {
context_->compilation_package_ = package.to_string();
return *this;
@@ -123,15 +143,16 @@
return *this;
}
- std::unique_ptr<ISymbolSource> Build() { return std::move(symbol_source_); }
+ std::unique_ptr<ISymbolSource> Build() {
+ return std::move(symbol_source_);
+ }
private:
class StaticSymbolSource : public ISymbolSource {
public:
StaticSymbolSource() = default;
- std::unique_ptr<SymbolTable::Symbol> FindByName(
- const ResourceName& name) override {
+ std::unique_ptr<SymbolTable::Symbol> FindByName(const ResourceName& name) override {
auto iter = name_map_.find(name);
if (iter != name_map_.end()) {
return CloneSymbol(iter->second);
@@ -153,12 +174,10 @@
private:
std::unique_ptr<SymbolTable::Symbol> CloneSymbol(SymbolTable::Symbol* sym) {
- std::unique_ptr<SymbolTable::Symbol> clone =
- util::make_unique<SymbolTable::Symbol>();
+ std::unique_ptr<SymbolTable::Symbol> clone = util::make_unique<SymbolTable::Symbol>();
clone->id = sym->id;
if (sym->attribute) {
- clone->attribute =
- std::unique_ptr<Attribute>(sym->attribute->Clone(nullptr));
+ clone->attribute = std::unique_ptr<Attribute>(sym->attribute->Clone(nullptr));
}
clone->is_public = sym->is_public;
return clone;
@@ -167,8 +186,7 @@
DISALLOW_COPY_AND_ASSIGN(StaticSymbolSource);
};
- std::unique_ptr<StaticSymbolSource> symbol_source_ =
- util::make_unique<StaticSymbolSource>();
+ std::unique_ptr<StaticSymbolSource> symbol_source_ = util::make_unique<StaticSymbolSource>();
};
} // namespace test
diff --git a/tools/aapt2/unflatten/BinaryResourceParser.cpp b/tools/aapt2/unflatten/BinaryResourceParser.cpp
index 20a4531..42786b5 100644
--- a/tools/aapt2/unflatten/BinaryResourceParser.cpp
+++ b/tools/aapt2/unflatten/BinaryResourceParser.cpp
@@ -22,6 +22,7 @@
#include "android-base/logging.h"
#include "android-base/macros.h"
+#include "android-base/stringprintf.h"
#include "androidfw/ResourceTypes.h"
#include "androidfw/TypeWrappers.h"
@@ -37,6 +38,8 @@
using namespace android;
+using android::base::StringPrintf;
+
namespace {
/*
@@ -87,26 +90,35 @@
bool BinaryResourceParser::Parse() {
ResChunkPullParser parser(data_, data_len_);
- bool error = false;
- while (ResChunkPullParser::IsGoodEvent(parser.Next())) {
- if (parser.chunk()->type != android::RES_TABLE_TYPE) {
- context_->GetDiagnostics()->Warn(DiagMessage(source_)
- << "unknown chunk of type '"
- << (int)parser.chunk()->type << "'");
- continue;
- }
-
- if (!ParseTable(parser.chunk())) {
- error = true;
- }
- }
-
- if (parser.event() == ResChunkPullParser::Event::kBadDocument) {
- context_->GetDiagnostics()->Error(
- DiagMessage(source_) << "corrupt resource table: " << parser.error());
+ if (!ResChunkPullParser::IsGoodEvent(parser.Next())) {
+ context_->GetDiagnostics()->Error(DiagMessage(source_)
+ << "corrupt resources.arsc: " << parser.error());
return false;
}
- return !error;
+
+ if (parser.chunk()->type != android::RES_TABLE_TYPE) {
+ context_->GetDiagnostics()->Error(DiagMessage(source_)
+ << StringPrintf("unknown chunk of type 0x%02x",
+ (int)parser.chunk()->type));
+ return false;
+ }
+
+ if (!ParseTable(parser.chunk())) {
+ return false;
+ }
+
+ if (parser.Next() != ResChunkPullParser::Event::kEndDocument) {
+ if (parser.event() == ResChunkPullParser::Event::kBadDocument) {
+ context_->GetDiagnostics()->Warn(
+ DiagMessage(source_) << "invalid chunk trailing RES_TABLE_TYPE: " << parser.error());
+ } else {
+ context_->GetDiagnostics()->Warn(
+ DiagMessage(source_) << StringPrintf(
+ "unexpected chunk of type 0x%02x trailing RES_TABLE_TYPE",
+ (int)parser.chunk()->type));
+ }
+ }
+ return true;
}
/**
diff --git a/tools/aapt2/unflatten/ResChunkPullParser.cpp b/tools/aapt2/unflatten/ResChunkPullParser.cpp
index 5d71ff3..8d92bd9 100644
--- a/tools/aapt2/unflatten/ResChunkPullParser.cpp
+++ b/tools/aapt2/unflatten/ResChunkPullParser.cpp
@@ -16,9 +16,11 @@
#include "unflatten/ResChunkPullParser.h"
+#include <inttypes.h>
#include <cstddef>
#include "android-base/logging.h"
+#include "android-base/stringprintf.h"
#include "androidfw/ResourceTypes.h"
#include "util/Util.h"
@@ -26,6 +28,13 @@
namespace aapt {
using android::ResChunk_header;
+using android::base::StringPrintf;
+
+static std::string ChunkHeaderDump(const ResChunk_header* header) {
+ return StringPrintf("(type=%02" PRIx16 " header_size=%" PRIu16 " size=%" PRIu32 ")",
+ util::DeviceToHost16(header->type), util::DeviceToHost16(header->headerSize),
+ util::DeviceToHost32(header->size));
+}
ResChunkPullParser::Event ResChunkPullParser::Next() {
if (!IsGoodEvent(event_)) {
@@ -53,18 +62,17 @@
return (event_ = Event::kBadDocument);
}
- if (util::DeviceToHost16(current_chunk_->headerSize) <
- sizeof(ResChunk_header)) {
+ if (util::DeviceToHost16(current_chunk_->headerSize) < sizeof(ResChunk_header)) {
error_ = "chunk has too small header";
current_chunk_ = nullptr;
return (event_ = Event::kBadDocument);
} else if (util::DeviceToHost32(current_chunk_->size) <
util::DeviceToHost16(current_chunk_->headerSize)) {
- error_ = "chunk's total size is smaller than header";
+ error_ = "chunk's total size is smaller than header " + ChunkHeaderDump(current_chunk_);
current_chunk_ = nullptr;
return (event_ = Event::kBadDocument);
} else if (offset + util::DeviceToHost32(current_chunk_->size) > len_) {
- error_ = "chunk's data extends past the end of the document";
+ error_ = "chunk's data extends past the end of the document " + ChunkHeaderDump(current_chunk_);
current_chunk_ = nullptr;
return (event_ = Event::kBadDocument);
}
diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py
index 3fedea2..53501f9 100644
--- a/tools/apilint/apilint.py
+++ b/tools/apilint/apilint.py
@@ -259,14 +259,19 @@
def verify_constants(clazz):
"""All static final constants must be FOO_NAME style."""
if re.match("android\.R\.[a-z]+", clazz.fullname): return
+ if clazz.fullname.startswith("android.os.Build"): return
+ if clazz.fullname == "android.system.OsConstants": return
+ req = ["java.lang.String","byte","short","int","long","float","double","boolean","char"]
for f in clazz.fields:
if "static" in f.split and "final" in f.split:
if re.match("[A-Z0-9_]+", f.name) is None:
error(clazz, f, "C2", "Constant field names must be FOO_NAME")
- elif f.typ != "java.lang.String":
+ if f.typ != "java.lang.String":
if f.name.startswith("MIN_") or f.name.startswith("MAX_"):
warn(clazz, f, "C8", "If min/max could change in future, make them dynamic methods")
+ if f.typ in req and f.value is None:
+ error(clazz, f, None, "All constants must be defined at compile time")
def verify_enums(clazz):
@@ -352,6 +357,7 @@
if f.value is None: continue
if f.name.startswith("EXTRA_"): continue
if f.name == "SERVICE_INTERFACE" or f.name == "PROVIDER_INTERFACE": continue
+ if "INTERACTION" in f.name: continue
if "static" in f.split and "final" in f.split and f.typ == "java.lang.String":
if "_ACTION" in f.name or "ACTION_" in f.name or ".action." in f.value.lower():
@@ -447,10 +453,14 @@
"android.app.Notification",
"android.content.pm.ActivityInfo",
"android.content.pm.ApplicationInfo",
+ "android.content.pm.ComponentInfo",
+ "android.content.pm.ResolveInfo",
"android.content.pm.FeatureGroupInfo",
"android.content.pm.InstrumentationInfo",
"android.content.pm.PackageInfo",
"android.content.pm.PackageItemInfo",
+ "android.content.res.Configuration",
+ "android.graphics.BitmapFactory.Options",
"android.os.Message",
"android.system.StructPollfd",
]
@@ -786,6 +796,10 @@
for c in clazz.ctors:
error(clazz, c, None, "Managers must always be obtained from Context; no direct constructors")
+ for m in clazz.methods:
+ if m.typ == clazz.fullname:
+ error(clazz, m, None, "Managers must always be obtained from Context")
+
def verify_boxed(clazz):
"""Verifies that methods avoid boxed primitives."""
@@ -812,17 +826,19 @@
def verify_static_utils(clazz):
"""Verifies that helper classes can't be constructed."""
if clazz.fullname.startswith("android.opengl"): return
- if re.match("android\.R\.[a-z]+", clazz.fullname): return
+ if clazz.fullname.startswith("android.R"): return
- if len(clazz.fields) > 0: return
- if len(clazz.methods) == 0: return
+ # Only care about classes with default constructors
+ if len(clazz.ctors) == 1 and len(clazz.ctors[0].args) == 0:
+ test = []
+ test.extend(clazz.fields)
+ test.extend(clazz.methods)
- for m in clazz.methods:
- if "static" not in m.split:
- return
+ if len(test) == 0: return
+ for t in test:
+ if "static" not in t.split:
+ return
- # At this point, we have no fields, and all methods are static
- if len(clazz.ctors) > 0:
error(clazz, None, None, "Fully-static utility classes must not have constructor")
@@ -920,6 +936,9 @@
if len(m.args) > 1 and m.args[0] != "android.content.Context":
if "android.content.Context" in m.args[1:]:
error(clazz, m, "M3", "Context is distinct, so it must be the first argument")
+ if len(m.args) > 1 and m.args[0] != "android.content.ContentResolver":
+ if "android.content.ContentResolver" in m.args[1:]:
+ error(clazz, m, "M3", "ContentResolver is distinct, so it must be the first argument")
def verify_listener_last(clazz):
@@ -1001,6 +1020,112 @@
warn(clazz, None, None, "Abstract inner classes should be static to improve testability")
+def verify_runtime_exceptions(clazz):
+ """Verifies that runtime exceptions aren't listed in throws."""
+
+ banned = [
+ "java.lang.NullPointerException",
+ "java.lang.ClassCastException",
+ "java.lang.IndexOutOfBoundsException",
+ "java.lang.reflect.UndeclaredThrowableException",
+ "java.lang.reflect.MalformedParametersException",
+ "java.lang.reflect.MalformedParameterizedTypeException",
+ "java.lang.invoke.WrongMethodTypeException",
+ "java.lang.EnumConstantNotPresentException",
+ "java.lang.IllegalMonitorStateException",
+ "java.lang.SecurityException",
+ "java.lang.UnsupportedOperationException",
+ "java.lang.annotation.AnnotationTypeMismatchException",
+ "java.lang.annotation.IncompleteAnnotationException",
+ "java.lang.TypeNotPresentException",
+ "java.lang.IllegalStateException",
+ "java.lang.ArithmeticException",
+ "java.lang.IllegalArgumentException",
+ "java.lang.ArrayStoreException",
+ "java.lang.NegativeArraySizeException",
+ "java.util.MissingResourceException",
+ "java.util.EmptyStackException",
+ "java.util.concurrent.CompletionException",
+ "java.util.concurrent.RejectedExecutionException",
+ "java.util.IllformedLocaleException",
+ "java.util.ConcurrentModificationException",
+ "java.util.NoSuchElementException",
+ "java.io.UncheckedIOException",
+ "java.time.DateTimeException",
+ "java.security.ProviderException",
+ "java.nio.BufferUnderflowException",
+ "java.nio.BufferOverflowException",
+ ]
+
+ test = []
+ test.extend(clazz.ctors)
+ test.extend(clazz.methods)
+
+ for t in test:
+ if " throws " not in t.raw: continue
+ throws = t.raw[t.raw.index(" throws "):]
+ for b in banned:
+ if b in throws:
+ error(clazz, t, None, "Methods must not mention RuntimeException subclasses in throws clauses")
+
+
+def verify_error(clazz):
+ """Verifies that we always use Exception instead of Error."""
+ if not clazz.extends: return
+ if clazz.extends.endswith("Error"):
+ error(clazz, None, None, "Trouble must be reported through an Exception, not Error")
+ if clazz.extends.endswith("Exception") and not clazz.name.endswith("Exception"):
+ error(clazz, None, None, "Exceptions must be named FooException")
+
+
+def verify_units(clazz):
+ """Verifies that we use consistent naming for units."""
+
+ # If we find K, recommend replacing with V
+ bad = {
+ "Ns": "Nanos",
+ "Ms": "Millis or Micros",
+ "Sec": "Seconds", "Secs": "Seconds",
+ "Hr": "Hours", "Hrs": "Hours",
+ "Mo": "Months", "Mos": "Months",
+ "Yr": "Years", "Yrs": "Years",
+ "Byte": "Bytes", "Space": "Bytes",
+ }
+
+ for m in clazz.methods:
+ if m.typ not in ["short","int","long"]: continue
+ for k, v in bad.iteritems():
+ if m.name.endswith(k):
+ error(clazz, m, None, "Expected method name units to be " + v)
+ if m.name.endswith("Nanos") or m.name.endswith("Micros"):
+ warn(clazz, m, None, "Returned time values are strongly encouraged to be in milliseconds unless you need the extra precision")
+ if m.name.endswith("Seconds"):
+ error(clazz, m, None, "Returned time values must be in milliseconds")
+
+ for m in clazz.methods:
+ typ = m.typ
+ if typ == "void":
+ if len(m.args) != 1: continue
+ typ = m.args[0]
+
+ if m.name.endswith("Fraction") and typ != "float":
+ error(clazz, m, None, "Fractions must use floats")
+ if m.name.endswith("Percentage") and typ != "int":
+ error(clazz, m, None, "Percentage must use ints")
+
+
+def verify_closable(clazz):
+ """Verifies that classes are AutoClosable."""
+ if "implements java.lang.AutoCloseable" in clazz.raw: return
+ if "implements java.io.Closeable" in clazz.raw: return
+
+ for m in clazz.methods:
+ if len(m.args) > 0: continue
+ if m.name in ["close","release","destroy","finish","finalize","disconnect","shutdown","stop","free","quit"]:
+ warn(clazz, m, None, "Classes that release resources should implement AutoClosable and CloseGuard")
+ return
+
+
def examine_clazz(clazz):
"""Find all style issues in the given class."""
if clazz.pkg.name.startswith("java"): return
@@ -1048,6 +1173,10 @@
verify_files(clazz)
verify_manager_list(clazz)
verify_abstract_inner(clazz)
+ verify_runtime_exceptions(clazz)
+ verify_error(clazz)
+ verify_units(clazz)
+ verify_closable(clazz)
def examine_stream(stream):
diff --git a/tools/fonts/fontchain_lint.py b/tools/fonts/fontchain_lint.py
index f5b9042..c0475ee 100755
--- a/tools/fonts/fontchain_lint.py
+++ b/tools/fonts/fontchain_lint.py
@@ -428,7 +428,8 @@
_text_variation_sequences, _emoji_variation_sequences = sequences
_emoji_sequences = parse_unicode_datafile(
path.join(ucd_path, 'emoji-sequences.txt'))
-
+ _emoji_sequences.update(parse_unicode_datafile(
+ path.join(ucd_path, 'additions', 'emoji-sequences.txt')))
_emoji_zwj_sequences = parse_unicode_datafile(
path.join(ucd_path, 'emoji-zwj-sequences.txt'))
_emoji_zwj_sequences.update(parse_unicode_datafile(
diff --git a/wifi/java/android/net/wifi/aware/DiscoverySession.java b/wifi/java/android/net/wifi/aware/DiscoverySession.java
index bf5c42b..c7e1fc7 100644
--- a/wifi/java/android/net/wifi/aware/DiscoverySession.java
+++ b/wifi/java/android/net/wifi/aware/DiscoverySession.java
@@ -38,10 +38,10 @@
* {@link #createNetworkSpecifierOpen(PeerHandle)} or
* {@link #createNetworkSpecifierPassphrase(PeerHandle, String)}.
* </ul>
- * The {@link #destroy()} method must be called to destroy discovery sessions once they are
+ * The {@link #close()} method must be called to destroy discovery sessions once they are
* no longer needed.
*/
-public class DiscoverySession {
+public class DiscoverySession implements AutoCloseable {
private static final String TAG = "DiscoverySession";
private static final boolean DBG = false;
private static final boolean VDBG = false; // STOPSHIP if true
@@ -96,7 +96,8 @@
* exception is a session for which we received a termination callback,
* {@link DiscoverySessionCallback#onSessionTerminated()}.
*/
- public void destroy() {
+ @Override
+ public void close() {
WifiAwareManager mgr = mMgr.get();
if (mgr == null) {
Log.w(TAG, "destroy: called post GC on WifiAwareManager");
@@ -131,7 +132,7 @@
try {
if (!mTerminated) {
mCloseGuard.warnIfOpen();
- destroy();
+ close();
}
} finally {
super.finalize();
diff --git a/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java b/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java
index 334205b..d8667e6 100644
--- a/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java
+++ b/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java
@@ -84,7 +84,7 @@
/**
* Called when a discovery session (publish or subscribe) terminates. Termination may be due
- * to user-request (either directly through {@link DiscoverySession#destroy()} or
+ * to user-request (either directly through {@link DiscoverySession#close()} or
* application-specified expiration, e.g. {@link PublishConfig.Builder#setTtlSec(int)}
* or {@link SubscribeConfig.Builder#setTtlSec(int)}).
*/
diff --git a/wifi/java/android/net/wifi/aware/PublishConfig.java b/wifi/java/android/net/wifi/aware/PublishConfig.java
index 1ce12f3..0f1e992 100644
--- a/wifi/java/android/net/wifi/aware/PublishConfig.java
+++ b/wifi/java/android/net/wifi/aware/PublishConfig.java
@@ -314,7 +314,7 @@
* {@link #setTerminateNotificationEnabled(boolean)} disables the callback].
* <p>
* Optional. 0 by default - indicating the session doesn't terminate on its own.
- * Session will be terminated when {@link DiscoverySession#destroy()} is
+ * Session will be terminated when {@link DiscoverySession#close()} is
* called.
*
* @param ttlSec Lifetime of a publish session in seconds.
diff --git a/wifi/java/android/net/wifi/aware/SubscribeConfig.java b/wifi/java/android/net/wifi/aware/SubscribeConfig.java
index 97a6a3f..31e7e8e 100644
--- a/wifi/java/android/net/wifi/aware/SubscribeConfig.java
+++ b/wifi/java/android/net/wifi/aware/SubscribeConfig.java
@@ -61,27 +61,6 @@
public static final int SUBSCRIBE_TYPE_ACTIVE = 1;
/** @hide */
- @IntDef({
- MATCH_STYLE_FIRST_ONLY, MATCH_STYLE_ALL })
- @Retention(RetentionPolicy.SOURCE)
- public @interface MatchStyles {
- }
-
- /**
- * Specifies that only the first match of a set of identical matches (same
- * publish) will be reported to the subscriber. Configuration is done using
- * {@link SubscribeConfig.Builder#setMatchStyle(int)}.
- */
- public static final int MATCH_STYLE_FIRST_ONLY = 0;
-
- /**
- * Specifies that all matches of a set of identical matches (same publish)
- * will be reported to the subscriber. Configuration is done using
- * {@link SubscribeConfig.Builder#setMatchStyle(int)}.
- */
- public static final int MATCH_STYLE_ALL = 1;
-
- /** @hide */
public final byte[] mServiceName;
/** @hide */
@@ -97,21 +76,17 @@
public final int mTtlSec;
/** @hide */
- public final int mMatchStyle;
-
- /** @hide */
public final boolean mEnableTerminateNotification;
/** @hide */
public SubscribeConfig(byte[] serviceName, byte[] serviceSpecificInfo, byte[] matchFilter,
- int subscribeType, int ttlSec, int matchStyle,
+ int subscribeType, int ttlSec,
boolean enableTerminateNotification) {
mServiceName = serviceName;
mServiceSpecificInfo = serviceSpecificInfo;
mMatchFilter = matchFilter;
mSubscribeType = subscribeType;
mTtlSec = ttlSec;
- mMatchStyle = matchStyle;
mEnableTerminateNotification = enableTerminateNotification;
}
@@ -121,8 +96,8 @@
(mServiceSpecificInfo == null) ? "null" : HexEncoding.encode(mServiceSpecificInfo))
+ ", mMatchFilter=" + (new TlvBufferUtils.TlvIterable(0, 1,
mMatchFilter)).toString() + ", mSubscribeType=" + mSubscribeType
- + ", mTtlSec=" + mTtlSec + ", mMatchType="
- + mMatchStyle + ", mEnableTerminateNotification=" + mEnableTerminateNotification
+ + ", mTtlSec=" + mTtlSec
+ + ", mEnableTerminateNotification=" + mEnableTerminateNotification
+ "]";
}
@@ -138,7 +113,6 @@
dest.writeByteArray(mMatchFilter);
dest.writeInt(mSubscribeType);
dest.writeInt(mTtlSec);
- dest.writeInt(mMatchStyle);
dest.writeInt(mEnableTerminateNotification ? 1 : 0);
}
@@ -155,11 +129,10 @@
byte[] matchFilter = in.createByteArray();
int subscribeType = in.readInt();
int ttlSec = in.readInt();
- int matchStyle = in.readInt();
boolean enableTerminateNotification = in.readInt() != 0;
return new SubscribeConfig(serviceName, ssi, matchFilter, subscribeType,
- ttlSec, matchStyle, enableTerminateNotification);
+ ttlSec, enableTerminateNotification);
}
};
@@ -178,7 +151,7 @@
return Arrays.equals(mServiceName, lhs.mServiceName) && Arrays.equals(mServiceSpecificInfo,
lhs.mServiceSpecificInfo) && Arrays.equals(mMatchFilter, lhs.mMatchFilter)
&& mSubscribeType == lhs.mSubscribeType
- && mTtlSec == lhs.mTtlSec && mMatchStyle == lhs.mMatchStyle
+ && mTtlSec == lhs.mTtlSec
&& mEnableTerminateNotification == lhs.mEnableTerminateNotification;
}
@@ -191,7 +164,6 @@
result = 31 * result + Arrays.hashCode(mMatchFilter);
result = 31 * result + mSubscribeType;
result = 31 * result + mTtlSec;
- result = 31 * result + mMatchStyle;
result = 31 * result + (mEnableTerminateNotification ? 1 : 0);
return result;
@@ -217,10 +189,6 @@
if (mTtlSec < 0) {
throw new IllegalArgumentException("Invalid ttlSec - must be non-negative");
}
- if (mMatchStyle != MATCH_STYLE_FIRST_ONLY && mMatchStyle != MATCH_STYLE_ALL) {
- throw new IllegalArgumentException(
- "Invalid matchType - must be MATCH_FIRST_ONLY or MATCH_ALL");
- }
if (characteristics != null) {
int maxServiceNameLength = characteristics.getMaxServiceNameLength();
@@ -252,7 +220,6 @@
private byte[] mMatchFilter;
private int mSubscribeType = SUBSCRIBE_TYPE_PASSIVE;
private int mTtlSec = 0;
- private int mMatchStyle = MATCH_STYLE_ALL;
private boolean mEnableTerminateNotification = true;
/**
@@ -346,7 +313,7 @@
* {@link DiscoverySessionCallback#onSessionTerminated()}.
* <p>
* Optional. 0 by default - indicating the session doesn't terminate on its own.
- * Session will be terminated when {@link DiscoverySession#destroy()} is
+ * Session will be terminated when {@link DiscoverySession#close()} is
* called.
*
* @param ttlSec Lifetime of a subscribe session in seconds.
@@ -363,28 +330,6 @@
}
/**
- * Sets the match style of the subscription - how are matches from a
- * single match session (corresponding to the same publish action on the
- * peer) reported to the host (using the
- * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle, byte[],
- * java.util.List)}). The options are: only report the first match and ignore the rest
- * {@link SubscribeConfig#MATCH_STYLE_FIRST_ONLY} or report every single
- * match {@link SubscribeConfig#MATCH_STYLE_ALL} (the default).
- *
- * @param matchStyle The reporting style for the discovery match.
- * @return The builder to facilitate chaining
- * {@code builder.setXXX(..).setXXX(..)}.
- */
- public Builder setMatchStyle(@MatchStyles int matchStyle) {
- if (matchStyle != MATCH_STYLE_FIRST_ONLY && matchStyle != MATCH_STYLE_ALL) {
- throw new IllegalArgumentException(
- "Invalid matchType - must be MATCH_FIRST_ONLY or MATCH_ALL");
- }
- mMatchStyle = matchStyle;
- return this;
- }
-
- /**
* Configure whether a subscribe terminate notification
* {@link DiscoverySessionCallback#onSessionTerminated()} is reported
* back to the callback.
@@ -406,7 +351,7 @@
*/
public SubscribeConfig build() {
return new SubscribeConfig(mServiceName, mServiceSpecificInfo, mMatchFilter,
- mSubscribeType, mTtlSec, mMatchStyle,
+ mSubscribeType, mTtlSec,
mEnableTerminateNotification);
}
}
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
index 3fcbd4b..d3ed792 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
@@ -82,7 +82,7 @@
* discovery or connection setup only after receiving confirmation that Aware attach
* succeeded - {@link AttachCallback#onAttached(WifiAwareSession)}. When an
* application is finished using Aware it <b>must</b> use the
- * {@link WifiAwareSession#destroy()} API to indicate to the Aware service that the device
+ * {@link WifiAwareSession#close()} API to indicate to the Aware service that the device
* may detach from the Aware cluster. The device will actually disable Aware once the last
* application detaches.
* <p>
@@ -104,7 +104,7 @@
* also be used to send messages using the
* {@link DiscoverySession#sendMessage(PeerHandle, int, byte[])} APIs. When an
* application is finished with a discovery session it <b>must</b> terminate it using the
- * {@link DiscoverySession#destroy()} API.
+ * {@link DiscoverySession#close()} API.
* <p>
* Creating connections between Aware devices is managed by the standard
* {@link ConnectivityManager#requestNetwork(NetworkRequest,
@@ -215,7 +215,7 @@
* create connections to peers. The device will attach to an existing cluster if it can find
* one or create a new cluster (if it is the first to enable Aware in its vicinity). Results
* (e.g. successful attach to a cluster) are provided to the {@code attachCallback} object.
- * An application <b>must</b> call {@link WifiAwareSession#destroy()} when done with the
+ * An application <b>must</b> call {@link WifiAwareSession#close()} when done with the
* Wi-Fi Aware object.
* <p>
* Note: a Aware cluster is a shared resource - if the device is already attached to a cluster
@@ -237,7 +237,7 @@
* create connections to peers. The device will attach to an existing cluster if it can find
* one or create a new cluster (if it is the first to enable Aware in its vicinity). Results
* (e.g. successful attach to a cluster) are provided to the {@code attachCallback} object.
- * An application <b>must</b> call {@link WifiAwareSession#destroy()} when done with the
+ * An application <b>must</b> call {@link WifiAwareSession#close()} when done with the
* Wi-Fi Aware object.
* <p>
* Note: a Aware cluster is a shared resource - if the device is already attached to a cluster
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareSession.java b/wifi/java/android/net/wifi/aware/WifiAwareSession.java
index ac3a6bb..4e060d5 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareSession.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareSession.java
@@ -33,7 +33,7 @@
* This class represents a Wi-Fi Aware session - an attachment to the Wi-Fi Aware service through
* which the app can execute discovery operations.
*/
-public class WifiAwareSession {
+public class WifiAwareSession implements AutoCloseable {
private static final String TAG = "WifiAwareSession";
private static final boolean DBG = false;
private static final boolean VDBG = false; // STOPSHIP if true
@@ -67,7 +67,7 @@
* An application may re-attach after a destroy using
* {@link WifiAwareManager#attach(AttachCallback, Handler)} .
*/
- public void destroy() {
+ public void close() {
WifiAwareManager mgr = mMgr.get();
if (mgr == null) {
Log.w(TAG, "destroy: called post GC on WifiAwareManager");
@@ -85,7 +85,7 @@
try {
if (!mTerminated) {
mCloseGuard.warnIfOpen();
- destroy();
+ close();
}
} finally {
super.finalize();
@@ -110,7 +110,7 @@
* on the {@code callback} object. The resulting publish session can be modified using
* {@link PublishDiscoverySession#updatePublish(PublishConfig)}.
* <p>
- * An application must use the {@link DiscoverySession#destroy()} to
+ * An application must use the {@link DiscoverySession#close()} to
* terminate the publish discovery session once it isn't needed. This will free
* resources as well terminate any on-air transmissions.
* <p>The application must have the {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}
@@ -156,7 +156,7 @@
* on the {@code callback} object. The resulting subscribe session can be modified using
* {@link SubscribeDiscoverySession#updateSubscribe(SubscribeConfig)}.
* <p>
- * An application must use the {@link DiscoverySession#destroy()} to
+ * An application must use the {@link DiscoverySession#close()} to
* terminate the subscribe discovery session once it isn't needed. This will free
* resources as well terminate any on-air transmissions.
* <p>The application must have the {@link android.Manifest.permission#ACCESS_COARSE_LOCATION}
diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
index 72a6a7a..694b911 100644
--- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
@@ -150,7 +150,7 @@
inOrder.verify(mockAwareService).publish(eq(clientId), eq(publishConfig), any());
// (3) disconnect
- session.destroy();
+ session.close();
inOrder.verify(mockAwareService).disconnect(eq(clientId), eq(binder.getValue()));
// (4) try publishing again - fails silently
@@ -329,7 +329,7 @@
inOrder.verify(mockSessionCallback).onSessionConfigFailed();
// (5) terminate
- publishSession.getValue().destroy();
+ publishSession.getValue().close();
mMockLooper.dispatchAll();
inOrder.verify(mockAwareService).terminateSession(clientId, sessionId);
@@ -466,7 +466,7 @@
inOrder.verify(mockSessionCallback).onSessionConfigFailed();
// (5) terminate
- subscribeSession.getValue().destroy();
+ subscribeSession.getValue().close();
mMockLooper.dispatchAll();
inOrder.verify(mockAwareService).terminateSession(clientId, sessionId);
@@ -687,8 +687,6 @@
collector.checkThat("mSubscribeType", subscribeConfig.mSubscribeType,
equalTo(SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE));
collector.checkThat("mTtlSec", subscribeConfig.mTtlSec, equalTo(0));
- collector.checkThat("mMatchStyle", subscribeConfig.mMatchStyle,
- equalTo(SubscribeConfig.MATCH_STYLE_ALL));
collector.checkThat("mEnableTerminateNotification",
subscribeConfig.mEnableTerminateNotification, equalTo(true));
}
@@ -701,14 +699,13 @@
final int subscribeType = SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE;
final int subscribeCount = 10;
final int subscribeTtl = 15;
- final int matchStyle = SubscribeConfig.MATCH_STYLE_FIRST_ONLY;
final boolean enableTerminateNotification = false;
SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().setServiceName(serviceName)
.setServiceSpecificInfo(serviceSpecificInfo.getBytes()).setMatchFilter(
new TlvBufferUtils.TlvIterable(0, 1, matchFilter).toList())
.setSubscribeType(subscribeType)
- .setTtlSec(subscribeTtl).setMatchStyle(matchStyle)
+ .setTtlSec(subscribeTtl)
.setTerminateNotificationEnabled(enableTerminateNotification).build();
collector.checkThat("mServiceName", serviceName.getBytes(),
@@ -719,7 +716,6 @@
collector.checkThat("mSubscribeType", subscribeType,
equalTo(subscribeConfig.mSubscribeType));
collector.checkThat("mTtlSec", subscribeTtl, equalTo(subscribeConfig.mTtlSec));
- collector.checkThat("mMatchStyle", matchStyle, equalTo(subscribeConfig.mMatchStyle));
collector.checkThat("mEnableTerminateNotification", enableTerminateNotification,
equalTo(subscribeConfig.mEnableTerminateNotification));
}
@@ -730,16 +726,14 @@
final String serviceSpecificInfo = "long arbitrary string with some info";
final byte[] matchFilter = { 1, 16, 1, 22 };
final int subscribeType = SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE;
- final int subscribeCount = 10;
final int subscribeTtl = 15;
- final int matchStyle = SubscribeConfig.MATCH_STYLE_FIRST_ONLY;
final boolean enableTerminateNotification = true;
SubscribeConfig subscribeConfig = new SubscribeConfig.Builder().setServiceName(serviceName)
.setServiceSpecificInfo(serviceSpecificInfo.getBytes()).setMatchFilter(
new TlvBufferUtils.TlvIterable(0, 1, matchFilter).toList())
.setSubscribeType(subscribeType)
- .setTtlSec(subscribeTtl).setMatchStyle(matchStyle)
+ .setTtlSec(subscribeTtl)
.setTerminateNotificationEnabled(enableTerminateNotification).build();
Parcel parcelW = Parcel.obtain();
@@ -765,14 +759,6 @@
new SubscribeConfig.Builder().setTtlSec(-100);
}
- /**
- * Validate that a bad match style configuration throws an exception.
- */
- @Test(expected = IllegalArgumentException.class)
- public void testSubscribeConfigBuilderBadMatchStyle() {
- new SubscribeConfig.Builder().setMatchStyle(10);
- }
-
/*
* PublishConfig Tests
*/