Merge "[webview] Rename force dark WebView settings."
diff --git a/Android.bp b/Android.bp
index b4ce5de..4e7aa5f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -110,7 +110,6 @@
"core/java/android/app/role/IOnRoleHoldersChangedListener.aidl",
"core/java/android/app/role/IRoleController.aidl",
"core/java/android/app/role/IRoleManager.aidl",
- "core/java/android/app/role/IRoleManagerCallback.aidl",
"core/java/android/app/slice/ISliceManager.aidl",
"core/java/android/app/slice/ISliceListener.aidl",
"core/java/android/app/timedetector/ITimeDetectorService.aidl",
diff --git a/api/current.txt b/api/current.txt
index 8e2c863..f329a38 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5262,7 +5262,7 @@
method public int describeContents();
method public boolean getAllowSystemGeneratedContextualActions();
method public int getBadgeIconType();
- method public android.app.Notification.BubbleMetadata getBubbleMetadata();
+ method @Nullable public android.app.Notification.BubbleMetadata getBubbleMetadata();
method public String getChannelId();
method public String getGroup();
method public int getGroupAlertBehavior();
@@ -5479,25 +5479,25 @@
public static final class Notification.BubbleMetadata implements android.os.Parcelable {
method public int describeContents();
method public boolean getAutoExpandBubble();
- method public android.app.PendingIntent getDeleteIntent();
+ method @Nullable public android.app.PendingIntent getDeleteIntent();
method public int getDesiredHeight();
- method public android.graphics.drawable.Icon getIcon();
- method public android.app.PendingIntent getIntent();
+ method @NonNull public android.graphics.drawable.Icon getIcon();
+ method @NonNull public android.app.PendingIntent getIntent();
method public boolean getSuppressInitialNotification();
method @Deprecated public CharSequence getTitle();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.Notification.BubbleMetadata> CREATOR;
}
- public static class Notification.BubbleMetadata.Builder {
+ public static final class Notification.BubbleMetadata.Builder {
ctor public Notification.BubbleMetadata.Builder();
- method public android.app.Notification.BubbleMetadata build();
- method public android.app.Notification.BubbleMetadata.Builder setAutoExpandBubble(boolean);
- method public android.app.Notification.BubbleMetadata.Builder setDeleteIntent(android.app.PendingIntent);
- method public android.app.Notification.BubbleMetadata.Builder setDesiredHeight(int);
- method public android.app.Notification.BubbleMetadata.Builder setIcon(android.graphics.drawable.Icon);
- method public android.app.Notification.BubbleMetadata.Builder setIntent(android.app.PendingIntent);
- method public android.app.Notification.BubbleMetadata.Builder setSuppressInitialNotification(boolean);
+ method @NonNull public android.app.Notification.BubbleMetadata build();
+ method @NonNull public android.app.Notification.BubbleMetadata.Builder setAutoExpandBubble(boolean);
+ method @NonNull public android.app.Notification.BubbleMetadata.Builder setDeleteIntent(@Nullable android.app.PendingIntent);
+ method @NonNull public android.app.Notification.BubbleMetadata.Builder setDesiredHeight(int);
+ method @NonNull public android.app.Notification.BubbleMetadata.Builder setIcon(@NonNull android.graphics.drawable.Icon);
+ method @NonNull public android.app.Notification.BubbleMetadata.Builder setIntent(@NonNull android.app.PendingIntent);
+ method @NonNull public android.app.Notification.BubbleMetadata.Builder setSuppressInitialNotification(boolean);
method @Deprecated public android.app.Notification.BubbleMetadata.Builder setTitle(CharSequence);
}
@@ -5522,7 +5522,7 @@
method @NonNull public android.app.Notification.Builder setAllowSystemGeneratedContextualActions(boolean);
method @NonNull public android.app.Notification.Builder setAutoCancel(boolean);
method @NonNull public android.app.Notification.Builder setBadgeIconType(int);
- method @NonNull public android.app.Notification.Builder setBubbleMetadata(android.app.Notification.BubbleMetadata);
+ method @NonNull public android.app.Notification.Builder setBubbleMetadata(@Nullable android.app.Notification.BubbleMetadata);
method @NonNull public android.app.Notification.Builder setCategory(String);
method @NonNull public android.app.Notification.Builder setChannelId(String);
method @NonNull public android.app.Notification.Builder setChronometerCountDown(boolean);
@@ -6752,7 +6752,8 @@
method public void setDelegatedScopes(@NonNull android.content.ComponentName, @NonNull String, @NonNull java.util.List<java.lang.String>);
method public void setDeviceOwnerLockScreenInfo(@NonNull android.content.ComponentName, CharSequence);
method public void setEndUserSessionMessage(@NonNull android.content.ComponentName, @Nullable CharSequence);
- method public int setGlobalPrivateDns(@NonNull android.content.ComponentName, int, @Nullable String);
+ method public int setGlobalPrivateDnsModeOpportunistic(@NonNull android.content.ComponentName);
+ method @WorkerThread public int setGlobalPrivateDnsModeSpecifiedHost(@NonNull android.content.ComponentName, @NonNull String);
method public void setGlobalSetting(@NonNull android.content.ComponentName, String, String);
method public void setKeepUninstalledPackages(@Nullable android.content.ComponentName, @NonNull java.util.List<java.lang.String>);
method public boolean setKeyPairCertificate(@Nullable android.content.ComponentName, @NonNull String, @NonNull java.util.List<java.security.cert.Certificate>, boolean);
@@ -7731,6 +7732,7 @@
field public static final int ACTIVITY_STOPPED = 23; // 0x17
field public static final int CONFIGURATION_CHANGE = 5; // 0x5
field public static final int DEVICE_SHUTDOWN = 26; // 0x1a
+ field public static final int DEVICE_STARTUP = 27; // 0x1b
field public static final int FOREGROUND_SERVICE_START = 19; // 0x13
field public static final int FOREGROUND_SERVICE_STOP = 20; // 0x14
field public static final int KEYGUARD_HIDDEN = 18; // 0x12
@@ -12282,6 +12284,7 @@
method public final void flushLayoutCache();
method @NonNull public android.content.res.XmlResourceParser getAnimation(@AnimatorRes @AnimRes int) throws android.content.res.Resources.NotFoundException;
method public final android.content.res.AssetManager getAssets();
+ method @AnyRes public static int getAttributeSetSourceResId(@Nullable android.util.AttributeSet);
method public boolean getBoolean(@BoolRes int) throws android.content.res.Resources.NotFoundException;
method @Deprecated @ColorInt public int getColor(@ColorRes int) throws android.content.res.Resources.NotFoundException;
method @ColorInt public int getColor(@ColorRes int, @Nullable android.content.res.Resources.Theme) throws android.content.res.Resources.NotFoundException;
@@ -14248,7 +14251,7 @@
method @NonNull public static android.graphics.Insets subtract(@NonNull android.graphics.Insets, @NonNull android.graphics.Insets);
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.graphics.Insets> CREATOR;
- field public static final android.graphics.Insets NONE;
+ field @NonNull public static final android.graphics.Insets NONE;
field public final int bottom;
field public final int left;
field public final int right;
@@ -29942,6 +29945,8 @@
method public int getLinkSpeed();
method public String getMacAddress();
method public int getNetworkId();
+ method @Nullable public String getPasspointFqdn();
+ method @Nullable public String getPasspointProviderFriendlyName();
method public int getRssi();
method @IntRange(from=0xffffffff) public int getRxLinkSpeedMbps();
method public String getSSID();
@@ -30187,7 +30192,7 @@
}
public final class ParcelablePeerHandle extends android.net.wifi.aware.PeerHandle implements android.os.Parcelable {
- ctor public ParcelablePeerHandle(android.net.wifi.aware.PeerHandle);
+ ctor public ParcelablePeerHandle(@NonNull android.net.wifi.aware.PeerHandle);
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.aware.ParcelablePeerHandle> CREATOR;
@@ -30255,16 +30260,6 @@
field public static final int WIFI_AWARE_DATA_PATH_ROLE_RESPONDER = 1; // 0x1
}
- public static final class WifiAwareManager.NetworkSpecifierBuilder {
- ctor public WifiAwareManager.NetworkSpecifierBuilder();
- method @NonNull public android.net.NetworkSpecifier build();
- method @NonNull public android.net.wifi.aware.WifiAwareManager.NetworkSpecifierBuilder setDiscoverySession(@NonNull android.net.wifi.aware.DiscoverySession);
- method @NonNull public android.net.wifi.aware.WifiAwareManager.NetworkSpecifierBuilder setPeerHandle(@NonNull android.net.wifi.aware.PeerHandle);
- method @NonNull public android.net.wifi.aware.WifiAwareManager.NetworkSpecifierBuilder setPort(int);
- method @NonNull public android.net.wifi.aware.WifiAwareManager.NetworkSpecifierBuilder setPskPassphrase(@NonNull String);
- method @NonNull public android.net.wifi.aware.WifiAwareManager.NetworkSpecifierBuilder setTransportProtocol(int);
- }
-
public final class WifiAwareNetworkInfo implements android.os.Parcelable android.net.TransportInfo {
method public int describeContents();
method @Nullable public java.net.Inet6Address getPeerIpv6Addr();
@@ -30274,6 +30269,22 @@
field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.aware.WifiAwareNetworkInfo> CREATOR;
}
+ public final class WifiAwareNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.aware.WifiAwareNetworkSpecifier> CREATOR;
+ }
+
+ public static final class WifiAwareNetworkSpecifier.Builder {
+ ctor public WifiAwareNetworkSpecifier.Builder();
+ method @NonNull public android.net.wifi.aware.WifiAwareNetworkSpecifier build();
+ method @NonNull public android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder setDiscoverySession(@NonNull android.net.wifi.aware.DiscoverySession);
+ method @NonNull public android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder setPeerHandle(@NonNull android.net.wifi.aware.PeerHandle);
+ method @NonNull public android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder setPort(int);
+ method @NonNull public android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder setPskPassphrase(@NonNull String);
+ method @NonNull public android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder setTransportProtocol(int);
+ }
+
public class WifiAwareSession implements java.lang.AutoCloseable {
method public void close();
method public android.net.NetworkSpecifier createNetworkSpecifierOpen(int, @NonNull byte[]);
@@ -35485,6 +35496,7 @@
field public static final String DISALLOW_CONFIG_VPN = "no_config_vpn";
field public static final String DISALLOW_CONFIG_WIFI = "no_config_wifi";
field public static final String DISALLOW_CONTENT_CAPTURE = "no_content_capture";
+ field public static final String DISALLOW_CONTENT_SUGGESTIONS = "no_content_suggestions";
field public static final String DISALLOW_CREATE_WINDOWS = "no_create_windows";
field public static final String DISALLOW_CROSS_PROFILE_COPY_PASTE = "no_cross_profile_copy_paste";
field public static final String DISALLOW_DATA_ROAMING = "no_data_roaming";
@@ -43968,7 +43980,6 @@
field public static final String EXTRA_INCOMING_CALL_EXTRAS = "android.telecom.extra.INCOMING_CALL_EXTRAS";
field public static final String EXTRA_INCOMING_VIDEO_STATE = "android.telecom.extra.INCOMING_VIDEO_STATE";
field public static final String EXTRA_IS_DEFAULT_CALL_SCREENING_APP = "android.telecom.extra.IS_DEFAULT_CALL_SCREENING_APP";
- field public static final String EXTRA_IS_ENABLED = "android.telecom.extra.IS_ENABLED";
field public static final String EXTRA_NOTIFICATION_COUNT = "android.telecom.extra.NOTIFICATION_COUNT";
field public static final String EXTRA_NOTIFICATION_PHONE_NUMBER = "android.telecom.extra.NOTIFICATION_PHONE_NUMBER";
field public static final String EXTRA_OUTGOING_CALL_EXTRAS = "android.telecom.extra.OUTGOING_CALL_EXTRAS";
@@ -45078,14 +45089,14 @@
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @WorkerThread public android.os.PersistableBundle getCarrierConfig();
method public int getCarrierIdFromSimMccMnc();
method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public android.telephony.CellLocation getCellLocation();
- method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @Nullable public java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>> getCurrentEmergencyNumberList();
- method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @Nullable public java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>> getCurrentEmergencyNumberList(int);
method public int getDataActivity();
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public int getDataNetworkType();
method public int getDataState();
method @Deprecated @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getDeviceId();
method @Deprecated @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public String getDeviceId(int);
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getDeviceSoftwareVersion();
+ method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @NonNull public java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>> getEmergencyNumberList();
+ method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) @NonNull public java.util.Map<java.lang.Integer,java.util.List<android.telephony.emergency.EmergencyNumber>> getEmergencyNumberList(int);
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String[] getForbiddenPlmns();
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getGroupIdLevel1();
method public String getIccAuthentication(int, int, String);
@@ -45137,9 +45148,9 @@
method public String iccTransmitApduBasicChannel(int, int, int, int, int, String);
method public String iccTransmitApduLogicalChannel(int, int, int, int, int, int, String);
method public boolean isConcurrentVoiceAndDataSupported();
- method public boolean isCurrentEmergencyNumber(@NonNull String);
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean isDataEnabled();
method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataRoamingEnabled();
+ method public boolean isEmergencyNumber(@NonNull String);
method public boolean isHearingAidCompatibilitySupported();
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isMultisimSupported();
method public boolean isNetworkRoaming();
@@ -45459,15 +45470,13 @@
public final class EmergencyNumber implements java.lang.Comparable<android.telephony.emergency.EmergencyNumber> android.os.Parcelable {
method public int compareTo(@NonNull android.telephony.emergency.EmergencyNumber);
method public int describeContents();
- method public String getCountryIso();
+ method @NonNull public String getCountryIso();
method public int getEmergencyCallRouting();
- method public int getEmergencyNumberSourceBitmask();
- method public java.util.List<java.lang.Integer> getEmergencyNumberSources();
- method public java.util.List<java.lang.Integer> getEmergencyServiceCategories();
- method public int getEmergencyServiceCategoryBitmask();
+ method @NonNull public java.util.List<java.lang.Integer> getEmergencyNumberSources();
+ method @NonNull public java.util.List<java.lang.Integer> getEmergencyServiceCategories();
method @NonNull public java.util.List<java.lang.String> getEmergencyUrns();
- method public String getMnc();
- method public String getNumber();
+ method @NonNull public String getMnc();
+ method @NonNull public String getNumber();
method public boolean isFromSources(int);
method public boolean isInEmergencyServiceCategories(int);
method public void writeToParcel(android.os.Parcel, int);
@@ -50072,7 +50081,7 @@
}
public class Surface implements android.os.Parcelable {
- ctor public Surface(android.view.SurfaceControl);
+ ctor public Surface(@NonNull android.view.SurfaceControl);
ctor public Surface(android.graphics.SurfaceTexture);
method public int describeContents();
method public boolean isValid();
@@ -50106,10 +50115,10 @@
public static class SurfaceControl.Builder {
ctor public SurfaceControl.Builder();
- method public android.view.SurfaceControl build();
- method public android.view.SurfaceControl.Builder setBufferSize(@IntRange(from=0) int, @IntRange(from=0) int);
+ method @NonNull public android.view.SurfaceControl build();
+ method @NonNull public android.view.SurfaceControl.Builder setBufferSize(@IntRange(from=0) int, @IntRange(from=0) int);
method @NonNull public android.view.SurfaceControl.Builder setFormat(int);
- method public android.view.SurfaceControl.Builder setName(String);
+ method @NonNull public android.view.SurfaceControl.Builder setName(@NonNull String);
method @NonNull public android.view.SurfaceControl.Builder setOpaque(boolean);
method @NonNull public android.view.SurfaceControl.Builder setParent(@Nullable android.view.SurfaceControl);
}
@@ -50838,8 +50847,8 @@
method public final boolean startDragAndDrop(android.content.ClipData, android.view.View.DragShadowBuilder, Object, int);
method public boolean startNestedScroll(int);
method public void stopNestedScroll();
- method public void transformMatrixToGlobal(android.graphics.Matrix);
- method public void transformMatrixToLocal(android.graphics.Matrix);
+ method public void transformMatrixToGlobal(@NonNull android.graphics.Matrix);
+ method public void transformMatrixToLocal(@NonNull android.graphics.Matrix);
method public void unscheduleDrawable(@NonNull android.graphics.drawable.Drawable, @NonNull Runnable);
method public void unscheduleDrawable(android.graphics.drawable.Drawable);
method public final void updateDragShadow(android.view.View.DragShadowBuilder);
@@ -53459,11 +53468,6 @@
package android.view.inspector {
- public class GeneratedInspectionCompanionProvider implements android.view.inspector.InspectionCompanionProvider {
- ctor public GeneratedInspectionCompanionProvider();
- method @Nullable public <T> android.view.inspector.InspectionCompanion<T> provide(@NonNull Class<T>);
- }
-
public interface InspectionCompanion<T> {
method @Nullable public default String getNodeName();
method public void mapProperties(@NonNull android.view.inspector.PropertyMapper);
@@ -53544,6 +53548,11 @@
ctor public PropertyReader.PropertyTypeMismatchException(int, @NonNull String, @NonNull String);
}
+ public class StaticInspectionCompanionProvider implements android.view.inspector.InspectionCompanionProvider {
+ ctor public StaticInspectionCompanionProvider();
+ method @Nullable public <T> android.view.inspector.InspectionCompanion<T> provide(@NonNull Class<T>);
+ }
+
public final class WindowInspector {
method @NonNull public static java.util.List<android.view.View> getGlobalWindowViews();
}
@@ -53615,7 +53624,6 @@
method public int describeContents();
method @Nullable public String getCallingPackageName();
method @NonNull public java.util.List<android.view.textclassifier.ConversationActions.Message> getConversation();
- method @Nullable public String getConversationId();
method @Nullable public java.util.List<java.lang.String> getHints();
method @IntRange(from=0xffffffff) public int getMaxSuggestions();
method @NonNull public android.view.textclassifier.TextClassifier.EntityConfig getTypeConfig();
@@ -53628,7 +53636,6 @@
public static final class ConversationActions.Request.Builder {
ctor public ConversationActions.Request.Builder(@NonNull java.util.List<android.view.textclassifier.ConversationActions.Message>);
method @NonNull public android.view.textclassifier.ConversationActions.Request build();
- method @NonNull public android.view.textclassifier.ConversationActions.Request.Builder setConversationId(@Nullable String);
method @NonNull public android.view.textclassifier.ConversationActions.Request.Builder setHints(@Nullable java.util.List<java.lang.String>);
method @NonNull public android.view.textclassifier.ConversationActions.Request.Builder setMaxSuggestions(@IntRange(from=0xffffffff) int);
method @NonNull public android.view.textclassifier.ConversationActions.Request.Builder setTypeConfig(@Nullable android.view.textclassifier.TextClassifier.EntityConfig);
@@ -54712,8 +54719,8 @@
method @NonNull public static ClassLoader getWebViewClassLoader();
method public android.webkit.WebViewClient getWebViewClient();
method @NonNull public android.os.Looper getWebViewLooper();
- method @Nullable public android.webkit.WebViewRenderer getWebViewRenderer();
- method @Nullable public android.webkit.WebViewRendererClient getWebViewRendererClient();
+ method @Nullable public android.webkit.WebViewRenderProcess getWebViewRenderProcess();
+ method @Nullable public android.webkit.WebViewRenderProcessClient getWebViewRenderProcessClient();
method public void goBack();
method public void goBackOrForward(int);
method public void goForward();
@@ -54763,8 +54770,8 @@
method public void setWebChromeClient(android.webkit.WebChromeClient);
method public static void setWebContentsDebuggingEnabled(boolean);
method public void setWebViewClient(android.webkit.WebViewClient);
- method public void setWebViewRendererClient(@NonNull java.util.concurrent.Executor, @NonNull android.webkit.WebViewRendererClient);
- method public void setWebViewRendererClient(@Nullable android.webkit.WebViewRendererClient);
+ method public void setWebViewRenderProcessClient(@NonNull java.util.concurrent.Executor, @NonNull android.webkit.WebViewRenderProcessClient);
+ method public void setWebViewRenderProcessClient(@Nullable android.webkit.WebViewRenderProcessClient);
method @Deprecated public boolean shouldDelayChildPressedState();
method @Deprecated public boolean showFindDialog(@Nullable String, boolean);
method public static void startSafeBrowsing(@NonNull android.content.Context, @Nullable android.webkit.ValueCallback<java.lang.Boolean>);
@@ -54880,14 +54887,15 @@
method @Deprecated public android.webkit.WebView getWebView();
}
- public abstract class WebViewRenderer {
+ public abstract class WebViewRenderProcess {
+ ctor public WebViewRenderProcess();
method public abstract boolean terminate();
}
- public abstract class WebViewRendererClient {
- ctor public WebViewRendererClient();
- method public abstract void onRendererResponsive(@NonNull android.webkit.WebView, @Nullable android.webkit.WebViewRenderer);
- method public abstract void onRendererUnresponsive(@NonNull android.webkit.WebView, @Nullable android.webkit.WebViewRenderer);
+ public abstract class WebViewRenderProcessClient {
+ ctor public WebViewRenderProcessClient();
+ method public abstract void onRenderProcessResponsive(@NonNull android.webkit.WebView, @Nullable android.webkit.WebViewRenderProcess);
+ method public abstract void onRenderProcessUnresponsive(@NonNull android.webkit.WebView, @Nullable android.webkit.WebViewRenderProcess);
}
}
@@ -56265,7 +56273,7 @@
method public String[] getDisplayedValues();
method public int getMaxValue();
method public int getMinValue();
- method public int getSelectionDividerHeight();
+ method @Px public int getSelectionDividerHeight();
method @ColorInt public int getTextColor();
method @FloatRange(from=0.0, fromInclusive=false) public float getTextSize();
method public int getValue();
diff --git a/api/system-current.txt b/api/system-current.txt
index 4d340a2..beacace 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1118,37 +1118,31 @@
public abstract class RoleControllerService extends android.app.Service {
ctor public RoleControllerService();
- method public abstract void onAddRoleHolder(@NonNull String, @NonNull String, int, @NonNull android.app.role.RoleManagerCallback);
+ method @WorkerThread public abstract boolean onAddRoleHolder(@NonNull String, @NonNull String, int);
method @Nullable public final android.os.IBinder onBind(@Nullable android.content.Intent);
- method public abstract void onClearRoleHolders(@NonNull String, int, @NonNull android.app.role.RoleManagerCallback);
- method public abstract void onGrantDefaultRoles(@NonNull android.app.role.RoleManagerCallback);
+ method @WorkerThread public abstract boolean onClearRoleHolders(@NonNull String, int);
+ method @WorkerThread public abstract boolean onGrantDefaultRoles();
method public abstract boolean onIsApplicationQualifiedForRole(@NonNull String, @NonNull String);
method public abstract boolean onIsRoleVisible(@NonNull String);
- method public abstract void onRemoveRoleHolder(@NonNull String, @NonNull String, int, @NonNull android.app.role.RoleManagerCallback);
- method public abstract void onSmsKillSwitchToggled(boolean);
+ method @WorkerThread public abstract boolean onRemoveRoleHolder(@NonNull String, @NonNull String, int);
field public static final String SERVICE_INTERFACE = "android.app.role.RoleControllerService";
}
public final class RoleManager {
method @RequiresPermission(android.Manifest.permission.OBSERVE_ROLE_HOLDERS) public void addOnRoleHoldersChangedListenerAsUser(@NonNull java.util.concurrent.Executor, @NonNull android.app.role.OnRoleHoldersChangedListener, @NonNull android.os.UserHandle);
- method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void addRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull android.app.role.RoleManagerCallback);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void addRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public boolean addRoleHolderFromController(@NonNull String, @NonNull String);
- method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void clearRoleHoldersAsUser(@NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull android.app.role.RoleManagerCallback);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void clearRoleHoldersAsUser(@NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @NonNull @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public java.util.List<java.lang.String> getHeldRolesFromController(@NonNull String);
method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public java.util.List<java.lang.String> getRoleHolders(@NonNull String);
method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public java.util.List<java.lang.String> getRoleHoldersAsUser(@NonNull String, @NonNull android.os.UserHandle);
method @RequiresPermission(android.Manifest.permission.OBSERVE_ROLE_HOLDERS) public void removeOnRoleHoldersChangedListenerAsUser(@NonNull android.app.role.OnRoleHoldersChangedListener, @NonNull android.os.UserHandle);
- method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void removeRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull android.app.role.RoleManagerCallback);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void removeRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public boolean removeRoleHolderFromController(@NonNull String, @NonNull String);
method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public void setRoleNamesFromController(@NonNull java.util.List<java.lang.String>);
field public static final int MANAGE_HOLDERS_FLAG_DONT_KILL_APP = 1; // 0x1
}
- public interface RoleManagerCallback {
- method public void onFailure();
- method public void onSuccess();
- }
-
}
package android.app.usage {
@@ -1576,6 +1570,7 @@
method public boolean getAllocateAggressive();
method @Deprecated public boolean getAllowDowngrade();
method public boolean getDontKillApp();
+ method public boolean getEnableRollback();
method @Nullable public String[] getGrantedRuntimePermissions();
method public boolean getInstallAsFullApp(boolean);
method public boolean getInstallAsInstantApp(boolean);
@@ -1587,7 +1582,7 @@
method @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE) public void setAllocateAggressive(boolean);
method @Deprecated public void setAllowDowngrade(boolean);
method public void setDontKillApp(boolean);
- method public void setEnableRollback();
+ method public void setEnableRollback(boolean);
method @RequiresPermission(android.Manifest.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS) public void setGrantedRuntimePermissions(String[]);
method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setInstallAsApex();
method public void setInstallAsInstantApp(boolean);
@@ -1822,18 +1817,18 @@
public final class PackageRollbackInfo implements android.os.Parcelable {
method public int describeContents();
- method public String getPackageName();
- method public android.content.pm.VersionedPackage getVersionRolledBackFrom();
- method public android.content.pm.VersionedPackage getVersionRolledBackTo();
+ method @NonNull public String getPackageName();
+ method @NonNull public android.content.pm.VersionedPackage getVersionRolledBackFrom();
+ method @NonNull public android.content.pm.VersionedPackage getVersionRolledBackTo();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.content.rollback.PackageRollbackInfo> CREATOR;
}
public final class RollbackInfo implements android.os.Parcelable {
method public int describeContents();
- method public java.util.List<android.content.pm.VersionedPackage> getCausePackages();
+ method @NonNull public java.util.List<android.content.pm.VersionedPackage> getCausePackages();
method public int getCommittedSessionId();
- method public java.util.List<android.content.rollback.PackageRollbackInfo> getPackages();
+ method @NonNull public java.util.List<android.content.rollback.PackageRollbackInfo> getPackages();
method public int getRollbackId();
method public boolean isStaged();
method public void writeToParcel(android.os.Parcel, int);
@@ -1843,7 +1838,7 @@
public final class RollbackManager {
method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void commitRollback(int, @NonNull java.util.List<android.content.pm.VersionedPackage>, @NonNull android.content.IntentSender);
method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void expireRollbackForPackage(@NonNull String);
- method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks();
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks();
method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getRecentlyCommittedRollbacks();
method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void reloadPersistedData();
field public static final String EXTRA_STATUS = "android.content.rollback.extra.STATUS";
@@ -4739,8 +4734,6 @@
}
public class WifiInfo implements android.os.Parcelable {
- method @Nullable public String getFqdn();
- method @Nullable public String getProviderFriendlyName();
method public boolean isOsuAp();
method public boolean isPasspointAp();
}
@@ -4981,8 +4974,8 @@
method @Deprecated public android.net.NetworkSpecifier createNetworkSpecifierPmk(@NonNull android.net.wifi.aware.PeerHandle, @NonNull byte[]);
}
- public static final class WifiAwareManager.NetworkSpecifierBuilder {
- method @NonNull public android.net.wifi.aware.WifiAwareManager.NetworkSpecifierBuilder setPmk(@NonNull byte[]);
+ public static final class WifiAwareNetworkSpecifier.Builder {
+ method @NonNull public android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder setPmk(@NonNull byte[]);
}
public class WifiAwareSession implements java.lang.AutoCloseable {
@@ -5190,7 +5183,7 @@
method @Nullable public Object onTransactStarted(@NonNull android.os.IBinder, int);
}
- public class BugreportManager {
+ public final class BugreportManager {
method @RequiresPermission(android.Manifest.permission.DUMP) public void cancelBugreport();
method @RequiresPermission(android.Manifest.permission.DUMP) public void startBugreport(@NonNull android.os.ParcelFileDescriptor, @Nullable android.os.ParcelFileDescriptor, @NonNull android.os.BugreportParams, @NonNull java.util.concurrent.Executor, @NonNull android.os.BugreportManager.BugreportCallback);
}
@@ -5199,7 +5192,7 @@
ctor public BugreportManager.BugreportCallback();
method public void onError(int);
method public void onFinished();
- method public void onProgress(float);
+ method public void onProgress(@FloatRange(from=0.0f, to=100.0f) float);
field public static final int BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS = 5; // 0x5
field public static final int BUGREPORT_ERROR_INVALID_INPUT = 1; // 0x1
field public static final int BUGREPORT_ERROR_RUNTIME = 2; // 0x2
@@ -5208,7 +5201,7 @@
}
public final class BugreportParams {
- ctor public BugreportParams(@android.os.BugreportParams.BugreportMode int);
+ ctor public BugreportParams(int);
method public int getMode();
field public static final int BUGREPORT_MODE_FULL = 0; // 0x0
field public static final int BUGREPORT_MODE_INTERACTIVE = 1; // 0x1
@@ -5218,9 +5211,6 @@
field public static final int BUGREPORT_MODE_WIFI = 5; // 0x5
}
- @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) @IntDef(prefix={"BUGREPORT_MODE_"}, value={android.os.BugreportParams.BUGREPORT_MODE_FULL, android.os.BugreportParams.BUGREPORT_MODE_INTERACTIVE, android.os.BugreportParams.BUGREPORT_MODE_REMOTE, android.os.BugreportParams.BUGREPORT_MODE_WEAR, android.os.BugreportParams.BUGREPORT_MODE_TELEPHONY, android.os.BugreportParams.BUGREPORT_MODE_WIFI}) public static @interface BugreportParams.BugreportMode {
- }
-
public static class Build.VERSION {
field public static final String PREVIEW_SDK_FINGERPRINT;
}
@@ -5610,7 +5600,6 @@
}
public class UserManager {
- method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean canSwitchUsers();
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void clearSeedAccountData();
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.os.UserHandle getProfileParent(@NonNull android.os.UserHandle);
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getSeedAccountName();
@@ -5620,6 +5609,7 @@
method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.graphics.Bitmap getUserIcon();
method @Deprecated @android.os.UserManager.UserRestrictionSource @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public int getUserRestrictionSource(String, android.os.UserHandle);
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public java.util.List<android.os.UserManager.EnforcingUser> getUserRestrictionSources(String, android.os.UserHandle);
+ method @RequiresPermission(allOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public int getUserSwitchability();
method public boolean hasRestrictedProfiles();
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isAdminUser();
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isGuestUser();
@@ -5627,7 +5617,7 @@
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isManagedProfile(int);
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isPrimaryUser();
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isRestrictedProfile();
- method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean removeUser(android.os.UserHandle);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean removeUser(@NonNull android.os.UserHandle);
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setUserIcon(@NonNull android.graphics.Bitmap);
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setUserName(@Nullable String);
field public static final String ACTION_USER_RESTRICTIONS_CHANGED = "android.os.action.USER_RESTRICTIONS_CHANGED";
@@ -5637,6 +5627,10 @@
field public static final int RESTRICTION_SOURCE_DEVICE_OWNER = 2; // 0x2
field public static final int RESTRICTION_SOURCE_PROFILE_OWNER = 4; // 0x4
field public static final int RESTRICTION_SOURCE_SYSTEM = 1; // 0x1
+ field public static final int SWITCHABILITY_STATUS_OK = 0; // 0x0
+ field public static final int SWITCHABILITY_STATUS_SYSTEM_USER_LOCKED = 4; // 0x4
+ field public static final int SWITCHABILITY_STATUS_USER_IN_CALL = 1; // 0x1
+ field public static final int SWITCHABILITY_STATUS_USER_SWITCH_DISALLOWED = 2; // 0x2
}
public static final class UserManager.EnforcingUser implements android.os.Parcelable {
@@ -5853,6 +5847,7 @@
}
public final class DeviceConfig {
+ method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static void addOnPropertiesChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertiesChangedListener);
method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static void addOnPropertyChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertyChangedListener);
method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static boolean getBoolean(String, String, boolean);
method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static float getFloat(String, String, float);
@@ -5860,7 +5855,8 @@
method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static long getLong(String, String, long);
method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static String getProperty(String, String);
method @RequiresPermission(android.Manifest.permission.READ_DEVICE_CONFIG) public static String getString(String, String, String);
- method public static void removeOnPropertyChangedListener(android.provider.DeviceConfig.OnPropertyChangedListener);
+ method public static void removeOnPropertiesChangedListener(@NonNull android.provider.DeviceConfig.OnPropertiesChangedListener);
+ method public static void removeOnPropertyChangedListener(@NonNull android.provider.DeviceConfig.OnPropertyChangedListener);
method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static void resetToDefaults(int, @Nullable String);
method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperty(String, String, String, boolean);
field public static final String NAMESPACE_ACTIVITY_MANAGER = "activity_manager";
@@ -5895,8 +5891,11 @@
field public static final String NAMESPACE = "intelligence_attention";
}
+ public static interface DeviceConfig.OnPropertiesChangedListener {
+ method public void onPropertiesChanged(@NonNull android.provider.DeviceConfig.Properties);
+ }
+
public static interface DeviceConfig.OnPropertyChangedListener {
- method public default void onPropertiesChanged(@NonNull android.provider.DeviceConfig.Properties);
method public void onPropertyChanged(String, String, String);
}
@@ -8067,10 +8066,10 @@
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoiceActivationState();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handlePinMmi(String);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean handlePinMmiForSubscriber(int, String);
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isCurrentPotentialEmergencyNumber(@NonNull String);
method public boolean isDataConnectivityPossible();
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isIdle();
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isOffhook();
+ method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isPotentialEmergencyNumber(@NonNull String);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRadioOn();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isRebootRequiredForModemConfigChange();
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRinging();
@@ -8212,6 +8211,7 @@
}
public final class DataProfile implements android.os.Parcelable {
+ method public int describeContents();
method @NonNull public String getApn();
method public int getAuthType();
method public int getBearerBitmap();
@@ -8229,6 +8229,8 @@
method public boolean isEnabled();
method public boolean isPersistent();
method public boolean isPreferred();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.data.DataProfile> CREATOR;
field public static final int TYPE_3GPP = 1; // 0x1
field public static final int TYPE_3GPP2 = 2; // 0x2
field public static final int TYPE_COMMON = 0; // 0x0
@@ -8460,7 +8462,7 @@
method public static int getCallTypeFromVideoState(int);
method public int getEmergencyCallRouting();
method public int getEmergencyServiceCategories();
- method public java.util.List<java.lang.String> getEmergencyUrns();
+ method @NonNull public java.util.List<java.lang.String> getEmergencyUrns();
method public android.telephony.ims.ImsStreamMediaProfile getMediaProfile();
method public int getRestrictCause();
method public int getServiceType();
@@ -8478,7 +8480,7 @@
method public void setEmergencyCallRouting(int);
method public void setEmergencyCallTesting(boolean);
method public void setEmergencyServiceCategories(int);
- method public void setEmergencyUrns(java.util.List<java.lang.String>);
+ method public void setEmergencyUrns(@NonNull java.util.List<java.lang.String>);
method public void setHasKnownUserIntentEmergency(boolean);
method public void updateCallExtras(android.telephony.ims.ImsCallProfile);
method public void updateCallType(android.telephony.ims.ImsCallProfile);
@@ -9846,8 +9848,8 @@
method public int getVisibleTitleHeight();
method public android.webkit.WebChromeClient getWebChromeClient();
method public android.webkit.WebViewClient getWebViewClient();
- method public android.webkit.WebViewRenderer getWebViewRenderer();
- method public android.webkit.WebViewRendererClient getWebViewRendererClient();
+ method @Nullable public android.webkit.WebViewRenderProcess getWebViewRenderProcess();
+ method @Nullable public android.webkit.WebViewRenderProcessClient getWebViewRenderProcessClient();
method public android.view.View getZoomControls();
method public void goBack();
method public void goBackOrForward(int);
@@ -9897,7 +9899,7 @@
method public void setVerticalScrollbarOverlay(boolean);
method public void setWebChromeClient(android.webkit.WebChromeClient);
method public void setWebViewClient(android.webkit.WebViewClient);
- method public void setWebViewRendererClient(@Nullable java.util.concurrent.Executor, @Nullable android.webkit.WebViewRendererClient);
+ method public void setWebViewRenderProcessClient(@Nullable java.util.concurrent.Executor, @Nullable android.webkit.WebViewRenderProcessClient);
method public boolean showFindDialog(String, boolean);
method public void stopLoading();
method public boolean zoomBy(float);
@@ -9979,10 +9981,6 @@
field public final android.content.pm.Signature[] signatures;
}
- public abstract class WebViewRenderer {
- ctor public WebViewRenderer();
- }
-
public final class WebViewUpdateService {
method public static android.webkit.WebViewProviderInfo[] getAllWebViewPackages();
method public static String getCurrentWebViewPackageName();
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 7e04469..18d0ec0 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -60,6 +60,14 @@
}
+package android.content.pm {
+
+ public static class PackageInstaller.SessionParams implements android.os.Parcelable {
+ method @Deprecated public void setEnableRollback();
+ }
+
+}
+
package android.location {
public class LocationManager {
diff --git a/api/test-current.txt b/api/test-current.txt
index b0e8df8..97f5ffe 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -512,24 +512,19 @@
public final class RoleManager {
method @RequiresPermission("android.permission.OBSERVE_ROLE_HOLDERS") public void addOnRoleHoldersChangedListenerAsUser(@NonNull java.util.concurrent.Executor, @NonNull android.app.role.OnRoleHoldersChangedListener, @NonNull android.os.UserHandle);
- method @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public void addRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull android.app.role.RoleManagerCallback);
+ method @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public void addRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public boolean addRoleHolderFromController(@NonNull String, @NonNull String);
- method @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public void clearRoleHoldersAsUser(@NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull android.app.role.RoleManagerCallback);
+ method @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public void clearRoleHoldersAsUser(@NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @NonNull @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public java.util.List<java.lang.String> getHeldRolesFromController(@NonNull String);
method @NonNull @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public java.util.List<java.lang.String> getRoleHolders(@NonNull String);
method @NonNull @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public java.util.List<java.lang.String> getRoleHoldersAsUser(@NonNull String, @NonNull android.os.UserHandle);
method @RequiresPermission("android.permission.OBSERVE_ROLE_HOLDERS") public void removeOnRoleHoldersChangedListenerAsUser(@NonNull android.app.role.OnRoleHoldersChangedListener, @NonNull android.os.UserHandle);
- method @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public void removeRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull android.app.role.RoleManagerCallback);
+ method @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public void removeRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public boolean removeRoleHolderFromController(@NonNull String, @NonNull String);
method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public void setRoleNamesFromController(@NonNull java.util.List<java.lang.String>);
field public static final int MANAGE_HOLDERS_FLAG_DONT_KILL_APP = 1; // 0x1
}
- public interface RoleManagerCallback {
- method public void onFailure();
- method public void onSuccess();
- }
-
}
package android.app.usage {
@@ -2007,6 +2002,7 @@
}
public final class DeviceConfig {
+ method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static void addOnPropertiesChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertiesChangedListener);
method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static void addOnPropertyChangedListener(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.provider.DeviceConfig.OnPropertyChangedListener);
method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static boolean getBoolean(String, String, boolean);
method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static float getFloat(String, String, float);
@@ -2014,15 +2010,19 @@
method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static long getLong(String, String, long);
method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static String getProperty(String, String);
method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static String getString(String, String, String);
- method public static void removeOnPropertyChangedListener(android.provider.DeviceConfig.OnPropertyChangedListener);
+ method public static void removeOnPropertiesChangedListener(@NonNull android.provider.DeviceConfig.OnPropertiesChangedListener);
+ method public static void removeOnPropertyChangedListener(@NonNull android.provider.DeviceConfig.OnPropertyChangedListener);
method @RequiresPermission("android.permission.WRITE_DEVICE_CONFIG") public static void resetToDefaults(int, @Nullable String);
method @RequiresPermission("android.permission.WRITE_DEVICE_CONFIG") public static boolean setProperty(String, String, String, boolean);
field public static final String NAMESPACE_AUTOFILL = "autofill";
field public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture";
}
+ public static interface DeviceConfig.OnPropertiesChangedListener {
+ method public void onPropertiesChanged(@NonNull android.provider.DeviceConfig.Properties);
+ }
+
public static interface DeviceConfig.OnPropertyChangedListener {
- method public default void onPropertiesChanged(@NonNull android.provider.DeviceConfig.Properties);
method public void onPropertyChanged(String, String, String);
}
diff --git a/cmds/idmap2/idmap2/Scan.cpp b/cmds/idmap2/idmap2/Scan.cpp
index e5f6223..e85f132 100644
--- a/cmds/idmap2/idmap2/Scan.cpp
+++ b/cmds/idmap2/idmap2/Scan.cpp
@@ -38,7 +38,10 @@
using android::idmap2::CommandLineOptions;
using android::idmap2::Idmap;
-using android::idmap2::PoliciesToBitmask;
+using android::idmap2::kPolicyProduct;
+using android::idmap2::kPolicyPublic;
+using android::idmap2::kPolicySystem;
+using android::idmap2::kPolicyVendor;
using android::idmap2::PolicyBitmask;
using android::idmap2::PolicyFlags;
using android::idmap2::Result;
@@ -87,20 +90,22 @@
return std::make_unique<std::vector<std::string>>(paths.cbegin(), paths.cend());
}
-PolicyBitmask PolicyForPath(const std::string& apk_path) {
- static const std::vector<std::pair<std::string, PolicyBitmask>> values = {
- {"/product/", PolicyFlags::POLICY_PRODUCT_PARTITION},
- {"/system/", PolicyFlags::POLICY_SYSTEM_PARTITION},
- {"/vendor/", PolicyFlags::POLICY_VENDOR_PARTITION},
+std::vector<std::string> PoliciesForPath(const std::string& apk_path) {
+ static const std::vector<std::pair<std::string, std::string>> values = {
+ {"/product/", kPolicyProduct},
+ {"/system/", kPolicySystem},
+ {"/vendor/", kPolicyVendor},
};
+ std::vector<std::string> fulfilled_policies = {kPolicyPublic};
for (auto const& pair : values) {
if (apk_path.compare(0, pair.first.size(), pair.first) == 0) {
- return pair.second | PolicyFlags::POLICY_PUBLIC;
+ fulfilled_policies.emplace_back(pair.second);
+ break;
}
}
- return PolicyFlags::POLICY_PUBLIC;
+ return fulfilled_policies;
}
} // namespace
@@ -161,21 +166,17 @@
continue;
}
- PolicyBitmask fulfilled_policies;
+ std::vector<std::string> fulfilled_policies;
if (!override_policies.empty()) {
- auto conv_result = PoliciesToBitmask(override_policies);
- if (conv_result) {
- fulfilled_policies = *conv_result;
- } else {
- out_error << "error: " << conv_result.GetErrorMessage() << std::endl;
- return false;
- }
+ fulfilled_policies = override_policies;
} else {
- fulfilled_policies = PolicyForPath(path);
+ fulfilled_policies = PoliciesForPath(path);
}
bool ignore_overlayable = false;
- if ((fulfilled_policies & PolicyFlags::POLICY_VENDOR_PARTITION) != 0 && !VendorIsQOrLater()) {
+ if (std::find(fulfilled_policies.begin(), fulfilled_policies.end(), kPolicyVendor) !=
+ fulfilled_policies.end() &&
+ !VendorIsQOrLater()) {
// If the overlay is on a pre-Q vendor partition, do not enforce overlayable
// restrictions on this overlay because the pre-Q platform has no understanding of
// overlayable.
@@ -185,7 +186,7 @@
std::string idmap_path = Idmap::CanonicalIdmapPathFor(output_directory, path);
// Sort the static overlays in ascending priority order
- InputOverlay input{path, idmap_path, overlay_info->priority, override_policies,
+ InputOverlay input{path, idmap_path, overlay_info->priority, fulfilled_policies,
ignore_overlayable};
interesting_apks.insert(
std::lower_bound(interesting_apks.begin(), interesting_apks.end(), input), input);
@@ -211,8 +212,8 @@
}
for (const std::string& policy : overlay.policies) {
- verify_args.emplace_back("--policy");
- verify_args.emplace_back(policy);
+ create_args.emplace_back("--policy");
+ create_args.emplace_back(policy);
}
if (!Create(create_args, out_error)) {
diff --git a/cmds/idmap2/include/idmap2/Policies.h b/cmds/idmap2/include/idmap2/Policies.h
index 911d3f2..cd76b84 100644
--- a/cmds/idmap2/include/idmap2/Policies.h
+++ b/cmds/idmap2/include/idmap2/Policies.h
@@ -27,13 +27,21 @@
namespace android::idmap2 {
+constexpr const char* kPolicyPublic = "public";
+constexpr const char* kPolicyProduct = "product";
+constexpr const char* kPolicySystem = "system";
+constexpr const char* kPolicyVendor = "vendor";
+constexpr const char* kPolicySignature = "signature";
+
using PolicyFlags = ResTable_overlayable_policy_header::PolicyFlags;
using PolicyBitmask = uint32_t;
-// Parses a the string representation of a set of policies into a bitmask. The format of the string
-// is the same as for the <policy> element.
+// Parses the string representations of policies into a bitmask.
Result<PolicyBitmask> PoliciesToBitmask(const std::vector<std::string>& policies);
+// Retrieves the string representations of policies in the bitmask.
+std::vector<std::string> BitmaskToPolicies(const PolicyBitmask& bitmask);
+
} // namespace android::idmap2
#endif // IDMAP2_INCLUDE_IDMAP2_POLICIES_H_
diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp
index 889d731..a7d180c 100644
--- a/cmds/idmap2/libidmap2/Idmap.cpp
+++ b/cmds/idmap2/libidmap2/Idmap.cpp
@@ -285,24 +285,58 @@
return std::move(idmap);
}
-bool CheckOverlayable(const LoadedPackage& target_package,
- const utils::OverlayManifestInfo& overlay_info,
- const PolicyBitmask& fulfilled_policies, const ResourceId& resid) {
+std::string ConcatPolicies(const std::vector<std::string>& policies) {
+ std::string message;
+ for (const std::string& policy : policies) {
+ if (message.empty()) {
+ message.append(policy);
+ } else {
+ message.append(policy);
+ message.append("|");
+ }
+ }
+
+ return message;
+}
+
+Result<Unit> CheckOverlayable(const LoadedPackage& target_package,
+ const utils::OverlayManifestInfo& overlay_info,
+ const PolicyBitmask& fulfilled_policies, const ResourceId& resid) {
+ static constexpr const PolicyBitmask sDefaultPolicies =
+ PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_VENDOR_PARTITION |
+ PolicyFlags::POLICY_PRODUCT_PARTITION | PolicyFlags::POLICY_SIGNATURE;
+
+ // If the resource does not have an overlayable definition, allow the resource to be overlaid if
+ // the overlay is preinstalled or signed with the same signature as the target.
+ if (!target_package.DefinesOverlayable()) {
+ return (sDefaultPolicies & fulfilled_policies) != 0
+ ? Result<Unit>({})
+ : Error(
+ "overlay must be preinstalled or signed with the same signature as the "
+ "target");
+ }
+
const OverlayableInfo* overlayable_info = target_package.GetOverlayableInfo(resid);
if (overlayable_info == nullptr) {
- // If the resource does not have an overlayable definition, allow the resource to be overlaid.
- // Once overlayable enforcement is turned on, this check will return false.
- return !target_package.DefinesOverlayable();
+ // Do not allow non-overlayable resources to be overlaid.
+ return Error("resource has no overlayable declaration");
}
if (overlay_info.target_name != overlayable_info->name) {
// If the overlay supplies a target overlayable name, the resource must belong to the
// overlayable defined with the specified name to be overlaid.
- return false;
+ return Error("<overlay> android:targetName '%s' does not match overlayable name '%s'",
+ overlay_info.target_name.c_str(), overlayable_info->name.c_str());
}
// Enforce policy restrictions if the resource is declared as overlayable.
- return (overlayable_info->policy_flags & fulfilled_policies) != 0;
+ if ((overlayable_info->policy_flags & fulfilled_policies) == 0) {
+ return Error("overlay with policies '%s' does not fulfill any overlayable policies '%s'",
+ ConcatPolicies(BitmaskToPolicies(fulfilled_policies)).c_str(),
+ ConcatPolicies(BitmaskToPolicies(overlayable_info->policy_flags)).c_str());
+ }
+
+ return Result<Unit>({});
}
std::unique_ptr<const Idmap> Idmap::FromApkAssets(
@@ -418,16 +452,26 @@
continue;
}
- if (enforce_overlayable &&
- !CheckOverlayable(*target_pkg, *overlay_info, fulfilled_policies, target_resid)) {
- LOG(WARNING) << "overlay \"" << overlay_apk_path << "\" is not allowed to overlay resource \""
- << full_name << "\"" << std::endl;
- continue;
+ if (!enforce_overlayable) {
+ Result<Unit> success =
+ CheckOverlayable(*target_pkg, *overlay_info, fulfilled_policies, target_resid);
+ if (!success) {
+ LOG(WARNING) << "overlay \"" << overlay_apk_path
+ << "\" is not allowed to overlay resource \"" << full_name
+ << "\": " << success.GetErrorMessage();
+ continue;
+ }
}
matching_resources.Add(target_resid, overlay_resid);
}
+ if (matching_resources.Map().empty()) {
+ out_error << "overlay \"" << overlay_apk_path << "\" does not successfully overlay any resource"
+ << std::endl;
+ return nullptr;
+ }
+
// encode idmap data
std::unique_ptr<IdmapData> data(new IdmapData());
const auto types_end = matching_resources.Map().cend();
diff --git a/cmds/idmap2/libidmap2/Policies.cpp b/cmds/idmap2/libidmap2/Policies.cpp
index c6ba87d..7c45556 100644
--- a/cmds/idmap2/libidmap2/Policies.cpp
+++ b/cmds/idmap2/libidmap2/Policies.cpp
@@ -30,12 +30,13 @@
namespace {
const std::map<android::StringPiece, PolicyFlags> kStringToFlag = {
- {"public", PolicyFlags::POLICY_PUBLIC},
- {"product", PolicyFlags::POLICY_PRODUCT_PARTITION},
- {"system", PolicyFlags::POLICY_SYSTEM_PARTITION},
- {"vendor", PolicyFlags::POLICY_VENDOR_PARTITION},
- {"signature", PolicyFlags::POLICY_SIGNATURE},
+ {kPolicyPublic, PolicyFlags::POLICY_PUBLIC},
+ {kPolicyProduct, PolicyFlags::POLICY_PRODUCT_PARTITION},
+ {kPolicySystem, PolicyFlags::POLICY_SYSTEM_PARTITION},
+ {kPolicyVendor, PolicyFlags::POLICY_VENDOR_PARTITION},
+ {kPolicySignature, PolicyFlags::POLICY_SIGNATURE},
};
+
} // namespace
Result<PolicyBitmask> PoliciesToBitmask(const std::vector<std::string>& policies) {
@@ -52,4 +53,29 @@
return Result<PolicyBitmask>(bitmask);
}
+std::vector<std::string> BitmaskToPolicies(const PolicyBitmask& bitmask) {
+ std::vector<std::string> policies;
+ if ((bitmask & PolicyFlags::POLICY_PUBLIC) != 0) {
+ policies.emplace_back(kPolicyPublic);
+ }
+
+ if ((bitmask & PolicyFlags::POLICY_PRODUCT_PARTITION) != 0) {
+ policies.emplace_back(kPolicyProduct);
+ }
+
+ if ((bitmask & PolicyFlags::POLICY_SYSTEM_PARTITION) != 0) {
+ policies.emplace_back(kPolicySystem);
+ }
+
+ if ((bitmask & PolicyFlags::POLICY_VENDOR_PARTITION) != 0) {
+ policies.emplace_back(kPolicyVendor);
+ }
+
+ if ((bitmask & PolicyFlags::POLICY_SIGNATURE) != 0) {
+ policies.emplace_back(kPolicySignature);
+ }
+
+ return policies;
+}
+
} // namespace android::idmap2
diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp
index bbfbad9..8d65428 100644
--- a/cmds/idmap2/tests/IdmapTests.cpp
+++ b/cmds/idmap2/tests/IdmapTests.cpp
@@ -173,20 +173,27 @@
ASSERT_THAT(idmap, IsNull());
}
-TEST(IdmapTests, CreateIdmapFromApkAssets) {
- const std::string target_apk_path(GetTestDataPath() + "/target/target.apk");
- std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
+void CreateIdmap(const StringPiece& target_apk_path, const StringPiece& overlay_apk_path,
+ const PolicyBitmask& fulfilled_policies, bool enforce_overlayable,
+ std::unique_ptr<const Idmap>* out_idmap) {
+ std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path.to_string());
ASSERT_THAT(target_apk, NotNull());
- const std::string overlay_apk_path(GetTestDataPath() + "/overlay/overlay.apk");
- std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
+ std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path.to_string());
ASSERT_THAT(overlay_apk, NotNull());
std::stringstream error;
- std::unique_ptr<const Idmap> idmap =
- Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
- PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true, error);
- ASSERT_THAT(idmap, NotNull());
+ *out_idmap =
+ Idmap::FromApkAssets(target_apk_path.to_string(), *target_apk, overlay_apk_path.to_string(),
+ *overlay_apk, fulfilled_policies, enforce_overlayable, error);
+}
+
+TEST(IdmapTests, CreateIdmapFromApkAssets) {
+ std::unique_ptr<const Idmap> idmap;
+ std::string target_apk_path = GetTestDataPath() + "/target/target.apk";
+ std::string overlay_apk_path = GetTestDataPath() + "/overlay/overlay.apk";
+ CreateIdmap(target_apk_path, overlay_apk_path, PolicyFlags::POLICY_PUBLIC,
+ /* enforce_overlayable */ true, &idmap);
ASSERT_THAT(idmap->GetHeader(), NotNull());
ASSERT_EQ(idmap->GetHeader()->GetMagic(), 0x504d4449U);
@@ -226,19 +233,12 @@
// Overlays should abide by all overlayable restrictions if enforcement of overlayable is enabled.
TEST(IdmapOverlayableTests, CreateIdmapFromApkAssetsPolicySystemPublic) {
- const std::string target_apk_path(GetTestDataPath() + "/target/target.apk");
- std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
- ASSERT_THAT(target_apk, NotNull());
-
- const std::string overlay_apk_path(GetTestDataPath() + "/system-overlay/system-overlay.apk");
- std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
- ASSERT_THAT(overlay_apk, NotNull());
-
- std::stringstream error;
- std::unique_ptr<const Idmap> idmap =
- Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
- PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC,
- /* enforce_overlayable */ true, error);
+ std::unique_ptr<const Idmap> idmap;
+ std::string target_apk_path = GetTestDataPath() + "/target/target.apk";
+ std::string overlay_apk_path = GetTestDataPath() + "/system-overlay/system-overlay.apk";
+ CreateIdmap(target_apk_path, overlay_apk_path,
+ PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC,
+ /* enforce_overlayable */ true, &idmap);
ASSERT_THAT(idmap, NotNull());
const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData();
@@ -263,21 +263,12 @@
}
TEST(IdmapOverlayableTests, CreateIdmapFromApkAssetsPolicySignature) {
- const std::string target_apk_path(GetTestDataPath() + "/target/target.apk");
- std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
- ASSERT_THAT(target_apk, NotNull());
-
- const std::string overlay_apk_path(GetTestDataPath() +
- "/signature-overlay/signature-overlay.apk");
- std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
- ASSERT_THAT(overlay_apk, NotNull());
-
- uint32_t policy_flags = PolicyFlags::POLICY_PUBLIC | PolicyFlags::POLICY_SIGNATURE;
-
- std::stringstream error;
- std::unique_ptr<const Idmap> idmap =
- Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
- policy_flags, /* enforce_overlayable */ true, error);
+ std::unique_ptr<const Idmap> idmap;
+ std::string target_apk_path = GetTestDataPath() + "/target/target.apk";
+ std::string overlay_apk_path = GetTestDataPath() + "/signature-overlay/signature-overlay.apk";
+ CreateIdmap(target_apk_path, overlay_apk_path,
+ PolicyFlags::POLICY_PUBLIC | PolicyFlags::POLICY_SIGNATURE,
+ /* enforce_overlayable */ true, &idmap);
ASSERT_THAT(idmap, NotNull());
const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData();
@@ -298,52 +289,15 @@
ASSERT_EQ(types[0]->GetEntry(0), 0x0000U); // string/policy_signature
}
-TEST(IdmapOverlayableTests, CreateIdmapFromApkAssetsPolicySignatureNotFulfilled) {
- const std::string target_apk_path(GetTestDataPath() + "/target/target.apk");
- std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
- ASSERT_THAT(target_apk, NotNull());
-
- const std::string overlay_apk_path(GetTestDataPath() +
- "/signature-overlay/signature-overlay.apk");
- std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
- ASSERT_THAT(overlay_apk, NotNull());
-
- uint32_t policy_flags = PolicyFlags::POLICY_PUBLIC;
-
- std::stringstream error;
- std::unique_ptr<const Idmap> idmap =
- Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
- policy_flags, /* enforce_overlayable */ true, error);
- ASSERT_THAT(idmap, NotNull());
-
- const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData();
- ASSERT_EQ(dataBlocks.size(), 1U);
-
- const std::unique_ptr<const IdmapData>& data = dataBlocks[0];
-
- ASSERT_EQ(data->GetHeader()->GetTargetPackageId(), 0x7fU);
- ASSERT_EQ(data->GetHeader()->GetTypeCount(), 0U);
-
- const std::vector<std::unique_ptr<const IdmapData::TypeEntry>>& types = data->GetTypeEntries();
- ASSERT_EQ(types.size(), 0U); // can't overlay, so contains nothing
-}
-
// Overlays should abide by all overlayable restrictions if enforcement of overlayable is enabled.
TEST(IdmapOverlayableTests, CreateIdmapFromApkAssetsPolicySystemPublicInvalid) {
- const std::string target_apk_path(GetTestDataPath() + "/target/target.apk");
- std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
- ASSERT_THAT(target_apk, NotNull());
-
- const std::string overlay_apk_path(GetTestDataPath() +
- "/system-overlay-invalid/system-overlay-invalid.apk");
- std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
- ASSERT_THAT(overlay_apk, NotNull());
-
- std::stringstream error;
- std::unique_ptr<const Idmap> idmap =
- Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
- PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC,
- /* enforce_overlayable */ true, error);
+ std::unique_ptr<const Idmap> idmap;
+ std::string target_apk_path = GetTestDataPath() + "/target/target.apk";
+ std::string overlay_apk_path =
+ GetTestDataPath() + "/system-overlay-invalid/system-overlay-invalid.apk";
+ CreateIdmap(target_apk_path, overlay_apk_path,
+ PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC,
+ /* enforce_overlayable */ true, &idmap);
ASSERT_THAT(idmap, NotNull());
const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData();
@@ -369,20 +323,13 @@
// Overlays should ignore all overlayable restrictions if enforcement of overlayable is disabled.
TEST(IdmapOverlayableTests, CreateIdmapFromApkAssetsPolicySystemPublicInvalidIgnoreOverlayable) {
- const std::string target_apk_path(GetTestDataPath() + "/target/target.apk");
- std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
- ASSERT_THAT(target_apk, NotNull());
-
- const std::string overlay_apk_path(GetTestDataPath() +
- "/system-overlay-invalid/system-overlay-invalid.apk");
- std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
- ASSERT_THAT(overlay_apk, NotNull());
-
- std::stringstream error;
- std::unique_ptr<const Idmap> idmap =
- Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
- PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC,
- /* enforce_overlayable */ false, error);
+ std::unique_ptr<const Idmap> idmap;
+ std::string target_apk_path = GetTestDataPath() + "/target/target.apk";
+ std::string overlay_apk_path =
+ GetTestDataPath() + "/system-overlay-invalid/system-overlay-invalid.apk";
+ CreateIdmap(target_apk_path, overlay_apk_path,
+ PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC,
+ /* enforce_overlayable */ false, &idmap);
ASSERT_THAT(idmap, NotNull());
const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData();
@@ -409,63 +356,13 @@
ASSERT_EQ(types[0]->GetEntry(6), 0x0006U); // string/policy_system_vendor
}
-// The resources of APKs that do not include an overlayable declaration should not restrict what
-// resources can be overlaid.
-TEST(IdmapOverlayableTests, CreateIdmapFromApkAssetsNoDefinedOverlayable) {
- const std::string target_apk_path(GetTestDataPath() + "/target/target-no-overlayable.apk");
- std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
- ASSERT_THAT(target_apk, NotNull());
-
- const std::string overlay_apk_path(GetTestDataPath() +
- "/system-overlay-invalid/system-overlay-invalid.apk");
- std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
- ASSERT_THAT(overlay_apk, NotNull());
-
- std::stringstream error;
- std::unique_ptr<const Idmap> idmap =
- Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
- PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true, error);
- ASSERT_THAT(idmap, NotNull());
-
- const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData();
- ASSERT_EQ(dataBlocks.size(), 1U);
-
- const std::unique_ptr<const IdmapData>& data = dataBlocks[0];
-
- ASSERT_EQ(data->GetHeader()->GetTargetPackageId(), 0x7fU);
- ASSERT_EQ(data->GetHeader()->GetTypeCount(), 1U);
-
- const std::vector<std::unique_ptr<const IdmapData::TypeEntry>>& types = data->GetTypeEntries();
- ASSERT_EQ(types.size(), 1U);
-
- ASSERT_EQ(types[0]->GetTargetTypeId(), 0x02U);
- ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U);
- ASSERT_EQ(types[0]->GetEntryCount(), 7U);
- ASSERT_EQ(types[0]->GetEntryOffset(), 3U);
- ASSERT_EQ(types[0]->GetEntry(0), 0x0000U); // string/not_overlayable
- ASSERT_EQ(types[0]->GetEntry(1), 0x0001U); // string/other
- ASSERT_EQ(types[0]->GetEntry(2), 0x0002U); // string/policy_product
- ASSERT_EQ(types[0]->GetEntry(3), 0x0003U); // string/policy_public
- ASSERT_EQ(types[0]->GetEntry(4), 0x0004U); // string/string/policy_signature
- ASSERT_EQ(types[0]->GetEntry(5), 0x0005U); // string/policy_system
- ASSERT_EQ(types[0]->GetEntry(6), 0x0006U); // string/policy_system_vendor
-}
-
-// The resources of APKs that do not include an overlayable declaration should not restrict what
-// resources can be overlaid.
+// Overlays that do not specify a target <overlayable> can overlay resources defined as overlayable.
TEST(IdmapOverlayableTests, CreateIdmapFromApkAssetsNoDefinedOverlayableAndNoTargetName) {
- const std::string target_apk_path(GetTestDataPath() + "/target/target-no-overlayable.apk");
- std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
- ASSERT_THAT(target_apk, NotNull());
-
- const std::string overlay_apk_path(GetTestDataPath() + "/overlay/overlay-no-name.apk");
- std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
- ASSERT_THAT(overlay_apk, NotNull());
-
- std::stringstream error;
- std::unique_ptr<const Idmap> idmap =
- Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
- PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true, error);
+ std::unique_ptr<const Idmap> idmap;
+ std::string target_apk_path = GetTestDataPath() + "/target/target-no-overlayable.apk";
+ std::string overlay_apk_path = GetTestDataPath() + "/overlay/overlay-no-name.apk";
+ CreateIdmap(target_apk_path, overlay_apk_path, PolicyFlags::POLICY_PUBLIC,
+ /* enforce_overlayable */ false, &idmap);
ASSERT_THAT(idmap, NotNull());
const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData();
@@ -483,16 +380,81 @@
ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U);
ASSERT_EQ(types[0]->GetEntryCount(), 1U);
ASSERT_EQ(types[0]->GetEntryOffset(), 0U);
- ASSERT_EQ(types[0]->GetEntry(0), 0x0000U);
+ ASSERT_EQ(types[0]->GetEntry(0), 0x0000U); // string/int1
ASSERT_EQ(types[1]->GetTargetTypeId(), 0x02U);
ASSERT_EQ(types[1]->GetOverlayTypeId(), 0x02U);
ASSERT_EQ(types[1]->GetEntryCount(), 4U);
ASSERT_EQ(types[1]->GetEntryOffset(), 10U);
- ASSERT_EQ(types[1]->GetEntry(0), 0x0000U);
- ASSERT_EQ(types[1]->GetEntry(1), kNoEntry);
- ASSERT_EQ(types[1]->GetEntry(2), 0x0001U);
- ASSERT_EQ(types[1]->GetEntry(3), 0x0002U);
+ ASSERT_EQ(types[1]->GetEntry(0), 0x0000U); // string/str1
+ ASSERT_EQ(types[1]->GetEntry(1), kNoEntry); // string/str2
+ ASSERT_EQ(types[1]->GetEntry(2), 0x0001U); // string/str3
+ ASSERT_EQ(types[1]->GetEntry(3), 0x0002U); // string/str4
+}
+
+// Overlays that are not pre-installed and are not signed with the same signature as the target
+// cannot overlay packages that have not defined overlayable resources.
+TEST(IdmapOverlayableTests, CreateIdmapFromApkAssetsDefaultPoliciesPublicFail) {
+ std::unique_ptr<const Idmap> idmap;
+ std::string target_apk_path = GetTestDataPath() + "/target/target-no-overlayable.apk";
+ std::string overlay_apk_path = GetTestDataPath() + "/overlay/overlay-no-name.apk";
+ CreateIdmap(target_apk_path, overlay_apk_path, PolicyFlags::POLICY_PUBLIC,
+ /* enforce_overlayable */ true, &idmap);
+ ASSERT_THAT(idmap, IsNull());
+}
+
+// Overlays that are pre-installed or are signed with the same signature as the target can overlay
+// packages that have not defined overlayable resources.
+TEST(IdmapOverlayableTests, CreateIdmapFromApkAssetsDefaultPolicies) {
+ std::unique_ptr<const Idmap> idmap;
+ std::string target_apk_path = GetTestDataPath() + "/target/target-no-overlayable.apk";
+ std::string overlay_apk_path =
+ GetTestDataPath() + "/system-overlay-invalid/system-overlay-invalid.apk";
+
+ auto CheckEntries = [&]() -> void {
+ const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData();
+ ASSERT_EQ(dataBlocks.size(), 1U);
+
+ const std::unique_ptr<const IdmapData>& data = dataBlocks[0];
+
+ ASSERT_EQ(data->GetHeader()->GetTargetPackageId(), 0x7fU);
+ ASSERT_EQ(data->GetHeader()->GetTypeCount(), 1U);
+
+ const std::vector<std::unique_ptr<const IdmapData::TypeEntry>>& types = data->GetTypeEntries();
+ ASSERT_EQ(types.size(), 1U);
+
+ ASSERT_EQ(types[0]->GetTargetTypeId(), 0x02U);
+ ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U);
+ ASSERT_EQ(types[0]->GetEntryCount(), 7U);
+ ASSERT_EQ(types[0]->GetEntryOffset(), 3U);
+ ASSERT_EQ(types[0]->GetEntry(0), 0x0000U); // string/not_overlayable
+ ASSERT_EQ(types[0]->GetEntry(1), 0x0001U); // string/other
+ ASSERT_EQ(types[0]->GetEntry(2), 0x0002U); // string/policy_product
+ ASSERT_EQ(types[0]->GetEntry(3), 0x0003U); // string/policy_public
+ ASSERT_EQ(types[0]->GetEntry(4), 0x0004U); // string/string/policy_signature
+ ASSERT_EQ(types[0]->GetEntry(5), 0x0005U); // string/policy_system
+ ASSERT_EQ(types[0]->GetEntry(6), 0x0006U); // string/policy_system_vendor
+ };
+
+ CreateIdmap(target_apk_path, overlay_apk_path, PolicyFlags::POLICY_SIGNATURE,
+ /* enforce_overlayable */ true, &idmap);
+ ASSERT_THAT(idmap, NotNull());
+ CheckEntries();
+
+ CreateIdmap(target_apk_path, overlay_apk_path, PolicyFlags::POLICY_PRODUCT_PARTITION,
+ /* enforce_overlayable */ true, &idmap);
+ ASSERT_THAT(idmap, NotNull());
+ CheckEntries();
+
+ CreateIdmap(target_apk_path, overlay_apk_path, PolicyFlags::POLICY_SYSTEM_PARTITION,
+ /* enforce_overlayable */ true, &idmap);
+ ASSERT_THAT(idmap, NotNull());
+ CheckEntries();
+
+ CreateIdmap(target_apk_path, overlay_apk_path, PolicyFlags::POLICY_VENDOR_PARTITION,
+ /* enforce_overlayable */ true, &idmap);
+ ASSERT_THAT(idmap, NotNull());
+ CheckEntries();
}
TEST(IdmapTests, FailToCreateIdmapFromApkAssetsIfPathTooLong) {
diff --git a/cmds/idmap2/tests/data/overlay/build b/cmds/idmap2/tests/data/overlay/build
index e879f44..68b9f50 100755
--- a/cmds/idmap2/tests/data/overlay/build
+++ b/cmds/idmap2/tests/data/overlay/build
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-FRAMEWORK_RES_APK="${ANDROID_BUILD_TOP}/out/target/common/obj/APPS/framework-res_intermediates/package-export.apk"
+FRAMEWORK_RES_APK=${ANDROID_BUILD_TOP}/prebuilts/sdk/current/public/android.jar
aapt2 compile --dir res -o compiled.flata
diff --git a/cmds/idmap2/tests/data/overlay/overlay-no-name.apk b/cmds/idmap2/tests/data/overlay/overlay-no-name.apk
index 7d23c09..6425190 100644
--- a/cmds/idmap2/tests/data/overlay/overlay-no-name.apk
+++ b/cmds/idmap2/tests/data/overlay/overlay-no-name.apk
Binary files differ
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 03806fa..a8a34d2 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -3177,6 +3177,7 @@
* Returns the bubble metadata that will be used to display app content in a floating window
* over the existing foreground activity.
*/
+ @Nullable
public BubbleMetadata getBubbleMetadata() {
return mBubbleMetadata;
}
@@ -3568,7 +3569,7 @@
* collapsed state, the bubble intent will be invoked and displayed.</b>
*/
@NonNull
- public Builder setBubbleMetadata(BubbleMetadata data) {
+ public Builder setBubbleMetadata(@Nullable BubbleMetadata data) {
mN.mBubbleMetadata = data;
return this;
}
@@ -8562,6 +8563,7 @@
/**
* @return the pending intent used to populate the floating window for this bubble.
*/
+ @NonNull
public PendingIntent getIntent() {
return mPendingIntent;
}
@@ -8569,6 +8571,7 @@
/**
* @return the pending intent to send when the bubble is dismissed by a user, if one exists.
*/
+ @Nullable
public PendingIntent getDeleteIntent() {
return mDeleteIntent;
}
@@ -8583,9 +8586,11 @@
public CharSequence getTitle() {
return "";
}
+
/**
* @return the icon that will be displayed for this bubble when it is collapsed.
*/
+ @NonNull
public Icon getIcon() {
return mIcon;
}
@@ -8654,7 +8659,7 @@
/**
* Builder to construct a {@link BubbleMetadata} object.
*/
- public static class Builder {
+ public static final class Builder {
private PendingIntent mPendingIntent;
private Icon mIcon;
@@ -8672,7 +8677,8 @@
* Sets the intent that will be used when the bubble is expanded. This will display the
* app content in a floating window over the existing foreground activity.
*/
- public BubbleMetadata.Builder setIntent(PendingIntent intent) {
+ @NonNull
+ public BubbleMetadata.Builder setIntent(@NonNull PendingIntent intent) {
if (intent == null) {
throw new IllegalArgumentException("Bubble requires non-null pending intent");
}
@@ -8700,7 +8706,8 @@
* If your app produces multiple bubbles, the image should be unique for each of them.
* </p>
*/
- public BubbleMetadata.Builder setIcon(Icon icon) {
+ @NonNull
+ public BubbleMetadata.Builder setIcon(@NonNull Icon icon) {
if (icon == null) {
throw new IllegalArgumentException("Bubbles require non-null icon");
}
@@ -8713,6 +8720,7 @@
* {@link #setIntent(PendingIntent)}, this height may not be respected if there is not
* enough space on the screen or if the provided height is too small to be useful.
*/
+ @NonNull
public BubbleMetadata.Builder setDesiredHeight(int height) {
mDesiredHeight = Math.max(height, 0);
return this;
@@ -8729,6 +8737,7 @@
* <p>Generally this flag should only be set if the user has performed an action to
* request or create a bubble.</p>
*/
+ @NonNull
public BubbleMetadata.Builder setAutoExpandBubble(boolean shouldExpand) {
setFlag(FLAG_AUTO_EXPAND_BUBBLE, shouldExpand);
return this;
@@ -8745,6 +8754,7 @@
* <p>Generally this flag should only be set if the user has performed an action to
* request or create a bubble.</p>
*/
+ @NonNull
public BubbleMetadata.Builder setSuppressInitialNotification(
boolean shouldSupressNotif) {
setFlag(FLAG_SUPPRESS_INITIAL_NOTIFICATION, shouldSupressNotif);
@@ -8754,7 +8764,8 @@
/**
* Sets an optional intent to send when this bubble is explicitly removed by the user.
*/
- public BubbleMetadata.Builder setDeleteIntent(PendingIntent deleteIntent) {
+ @NonNull
+ public BubbleMetadata.Builder setDeleteIntent(@Nullable PendingIntent deleteIntent) {
mDeleteIntent = deleteIntent;
return this;
}
@@ -8764,6 +8775,7 @@
* <p>Will throw {@link IllegalStateException} if required fields have not been set
* on this builder.</p>
*/
+ @NonNull
public BubbleMetadata build() {
if (mPendingIntent == null) {
throw new IllegalStateException("Must supply pending intent to bubble");
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 095d014..7cdd227 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -84,7 +84,6 @@
import android.service.restrictions.RestrictionsReceiver;
import android.telephony.TelephonyManager;
import android.telephony.data.ApnSetting;
-import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
@@ -2210,7 +2209,7 @@
PRIVATE_DNS_SET_ERROR_FAILURE_SETTING
})
@Retention(RetentionPolicy.SOURCE)
- public @interface SetPrivateDnsModeResultConstants {}
+ public @interface PrivateDnsModeErrorCodes {}
/**
* Activity action: Starts the administrator to get the mode for the provisioning.
@@ -10450,13 +10449,41 @@
}
/**
- * Sets the global Private DNS mode and host to be used.
+ * Sets the global Private DNS mode to opportunistic.
* May only be called by the device owner.
*
- * <p>Note that in case a Private DNS resolver is specified, the method is blocking as it
- * will perform a connectivity check to the resolver, to ensure it is valid. Because of that,
- * the method should not be called on any thread that relates to user interaction, such as the
- * UI thread.
+ * <p>In this mode, the DNS subsystem will attempt a TLS handshake to the network-supplied
+ * resolver prior to attempting name resolution in cleartext.
+ *
+ * @param admin which {@link DeviceAdminReceiver} this request is associated with.
+ *
+ * @return {@code PRIVATE_DNS_SET_SUCCESS} if the mode was set successfully, or
+ * {@code PRIVATE_DNS_SET_ERROR_FAILURE_SETTING} if it could not be set.
+ *
+ * @throws SecurityException if the caller is not the device owner.
+ */
+ public @PrivateDnsModeErrorCodes int setGlobalPrivateDnsModeOpportunistic(
+ @NonNull ComponentName admin) {
+ throwIfParentInstance("setGlobalPrivateDnsModeOpportunistic");
+
+ if (mService == null) {
+ return PRIVATE_DNS_SET_ERROR_FAILURE_SETTING;
+ }
+
+ try {
+ return mService.setGlobalPrivateDns(admin, PRIVATE_DNS_MODE_OPPORTUNISTIC, null);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Sets the global Private DNS host to be used.
+ * May only be called by the device owner.
+ *
+ * <p>Note that the method is blocking as it will perform a connectivity check to the resolver,
+ * to ensure it is valid. Because of that, the method should not be called on any thread that
+ * relates to user interaction, such as the UI thread.
*
* <p>In case a VPN is used in conjunction with Private DNS resolver, the Private DNS resolver
* must be reachable both from within and outside the VPN. Otherwise, the device may lose
@@ -10464,41 +10491,35 @@
* VPN.
*
* @param admin which {@link DeviceAdminReceiver} this request is associated with.
- * @param mode Which mode to set - either {@code PRIVATE_DNS_MODE_OPPORTUNISTIC} or
- * {@code PRIVATE_DNS_MODE_PROVIDER_HOSTNAME}.
- * Since the opportunistic mode defaults to ordinary DNS lookups, the
- * option to turn it completely off is not available, so this method
- * may not be called with {@code PRIVATE_DNS_MODE_OFF}.
- * @param privateDnsHost The hostname of a server that implements DNS over TLS (RFC7858), if
- * {@code PRIVATE_DNS_MODE_PROVIDER_HOSTNAME} was specified as the mode,
- * null otherwise.
+ * @param privateDnsHost The hostname of a server that implements DNS over TLS (RFC7858).
*
- * @return One of the values in {@link SetPrivateDnsModeResultConstants}.
+ * @return {@code PRIVATE_DNS_SET_SUCCESS} if the mode was set successfully,
+ * {@code PRIVATE_DNS_SET_ERROR_FAILURE_SETTING} if it could not be set or
+ * {@code PRIVATE_DNS_SET_ERROR_HOST_NOT_SERVING} if the specified host does not
+ * implement RFC7858.
*
- * @throws IllegalArgumentException in the following cases: if a {@code privateDnsHost} was
- * provided but the mode was not {@code PRIVATE_DNS_MODE_PROVIDER_HOSTNAME}, if the mode
- * specified was {@code PRIVATE_DNS_MODE_PROVIDER_HOSTNAME} but {@code privateDnsHost} does
- * not look like a valid hostname, or if the mode specified is not one of the two valid modes.
+ * @throws IllegalArgumentException if the {@code privateDnsHost} is not a valid hostname.
*
* @throws SecurityException if the caller is not the device owner.
*/
- public int setGlobalPrivateDns(@NonNull ComponentName admin,
- @PrivateDnsMode int mode, @Nullable String privateDnsHost) {
- throwIfParentInstance("setGlobalPrivateDns");
+ @WorkerThread public @PrivateDnsModeErrorCodes int setGlobalPrivateDnsModeSpecifiedHost(
+ @NonNull ComponentName admin, @NonNull String privateDnsHost) {
+ throwIfParentInstance("setGlobalPrivateDnsModeSpecifiedHost");
+ Preconditions.checkNotNull(privateDnsHost, "dns resolver is null");
if (mService == null) {
return PRIVATE_DNS_SET_ERROR_FAILURE_SETTING;
}
- if (mode == PRIVATE_DNS_MODE_PROVIDER_HOSTNAME && !TextUtils.isEmpty(privateDnsHost)
- && NetworkUtils.isWeaklyValidatedHostname(privateDnsHost)) {
+ if (NetworkUtils.isWeaklyValidatedHostname(privateDnsHost)) {
if (!PrivateDnsConnectivityChecker.canConnectToPrivateDnsServer(privateDnsHost)) {
return PRIVATE_DNS_SET_ERROR_HOST_NOT_SERVING;
}
}
try {
- return mService.setGlobalPrivateDns(admin, mode, privateDnsHost);
+ return mService.setGlobalPrivateDns(
+ admin, PRIVATE_DNS_MODE_PROVIDER_HOSTNAME, privateDnsHost);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/role/IRoleController.aidl b/core/java/android/app/role/IRoleController.aidl
index e8f6ce2..a472eac 100644
--- a/core/java/android/app/role/IRoleController.aidl
+++ b/core/java/android/app/role/IRoleController.aidl
@@ -16,7 +16,6 @@
package android.app.role;
-import android.app.role.IRoleManagerCallback;
import android.os.RemoteCallback;
/**
@@ -24,20 +23,20 @@
*/
oneway interface IRoleController {
- void onGrantDefaultRoles(in IRoleManagerCallback callback);
+ void grantDefaultRoles(in RemoteCallback callback);
void onAddRoleHolder(in String roleName, in String packageName, int flags,
- in IRoleManagerCallback callback);
+ in RemoteCallback callback);
void onRemoveRoleHolder(in String roleName, in String packageName, int flags,
- in IRoleManagerCallback callback);
+ in RemoteCallback callback);
- void onClearRoleHolders(in String roleName, int flags, in IRoleManagerCallback callback);
+ void onClearRoleHolders(in String roleName, int flags, in RemoteCallback callback);
void onSmsKillSwitchToggled(boolean enabled);
void isApplicationQualifiedForRole(in String roleName, in String packageName,
- in RemoteCallback callback);
+ in RemoteCallback callback);
void isRoleVisible(in String roleName, in RemoteCallback callback);
}
diff --git a/core/java/android/app/role/IRoleManager.aidl b/core/java/android/app/role/IRoleManager.aidl
index 76dbf7e..d8cea28 100644
--- a/core/java/android/app/role/IRoleManager.aidl
+++ b/core/java/android/app/role/IRoleManager.aidl
@@ -17,8 +17,8 @@
package android.app.role;
import android.app.role.IOnRoleHoldersChangedListener;
-import android.app.role.IRoleManagerCallback;
import android.os.Bundle;
+import android.os.RemoteCallback;
import android.telephony.IFinancialSmsCallback;
/**
@@ -33,13 +33,13 @@
List<String> getRoleHoldersAsUser(in String roleName, int userId);
void addRoleHolderAsUser(in String roleName, in String packageName, int flags, int userId,
- in IRoleManagerCallback callback);
+ in RemoteCallback callback);
void removeRoleHolderAsUser(in String roleName, in String packageName, int flags, int userId,
- in IRoleManagerCallback callback);
+ in RemoteCallback callback);
void clearRoleHoldersAsUser(in String roleName, int flags, int userId,
- in IRoleManagerCallback callback);
+ in RemoteCallback callback);
void addOnRoleHoldersChangedListenerAsUser(IOnRoleHoldersChangedListener listener, int userId);
@@ -55,6 +55,7 @@
List<String> getHeldRolesFromController(in String packageName);
String getDefaultSmsPackage(int userId);
+
/**
* Get filtered SMS messages for financial app.
*/
diff --git a/core/java/android/app/role/IRoleManagerCallback.aidl b/core/java/android/app/role/IRoleManagerCallback.aidl
deleted file mode 100644
index c0f8eea..0000000
--- a/core/java/android/app/role/IRoleManagerCallback.aidl
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2018 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.app.role;
-
-/**
- * @hide
- */
-oneway interface IRoleManagerCallback {
-
- void onSuccess();
-
- void onFailure();
-}
diff --git a/core/java/android/app/role/RoleControllerManager.java b/core/java/android/app/role/RoleControllerManager.java
index 2edc526..e96c9a5 100644
--- a/core/java/android/app/role/RoleControllerManager.java
+++ b/core/java/android/app/role/RoleControllerManager.java
@@ -52,11 +52,6 @@
private static final String LOG_TAG = RoleControllerManager.class.getSimpleName();
- /**
- * The key for retrieving the result from a bundle.
- */
- public static final String KEY_RESULT = "android.app.role.RoleControllerManager.key.RESULT";
-
private static final Object sRemoteServicesLock = new Object();
/**
* Global remote services (per user) used by all {@link RoleControllerManager managers}.
@@ -90,35 +85,37 @@
}
/**
- * @see RoleControllerService#onGrantDefaultRoles(RoleManagerCallback)
+ * @see RoleControllerService#onGrantDefaultRoles()
*/
- public void onGrantDefaultRoles(@NonNull IRoleManagerCallback callback) {
- mRemoteService.scheduleRequest(new OnGrantDefaultRolesRequest(mRemoteService, callback));
+ public void grantDefaultRoles(@NonNull @CallbackExecutor Executor executor,
+ @NonNull Consumer<Boolean> callback) {
+ mRemoteService.scheduleRequest(new GrantDefaultRolesRequest(mRemoteService, executor,
+ callback));
}
/**
- * @see RoleControllerService#onAddRoleHolder(String, String, int, RoleManagerCallback)
+ * @see RoleControllerService#onAddRoleHolder(String, String, int)
*/
public void onAddRoleHolder(@NonNull String roleName, @NonNull String packageName,
- @RoleManager.ManageHoldersFlags int flags, @NonNull IRoleManagerCallback callback) {
+ @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) {
mRemoteService.scheduleRequest(new OnAddRoleHolderRequest(mRemoteService, roleName,
packageName, flags, callback));
}
/**
- * @see RoleControllerService#onRemoveRoleHolder(String, String, int, RoleManagerCallback)
+ * @see RoleControllerService#onRemoveRoleHolder(String, String, int)
*/
public void onRemoveRoleHolder(@NonNull String roleName, @NonNull String packageName,
- @RoleManager.ManageHoldersFlags int flags, @NonNull IRoleManagerCallback callback) {
+ @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) {
mRemoteService.scheduleRequest(new OnRemoveRoleHolderRequest(mRemoteService, roleName,
packageName, flags, callback));
}
/**
- * @see RoleControllerService#onClearRoleHolders(String, int, RoleManagerCallback)
+ * @see RoleControllerService#onClearRoleHolders(String, int)
*/
public void onClearRoleHolders(@NonNull String roleName,
- @RoleManager.ManageHoldersFlags int flags, @NonNull IRoleManagerCallback callback) {
+ @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) {
mRemoteService.scheduleRequest(new OnClearRoleHoldersRequest(mRemoteService, roleName,
flags, callback));
}
@@ -210,68 +207,55 @@
}
/**
- * Request for {@link #onGrantDefaultRoles(IRoleManagerCallback)}.
+ * Request for {@link #grantDefaultRoles(Executor, Consumer)}.
*/
- private static final class OnGrantDefaultRolesRequest
+ private static final class GrantDefaultRolesRequest
extends AbstractRemoteService.PendingRequest<RemoteService, IRoleController> {
@NonNull
- private final IRoleManagerCallback mCallback;
+ private final Executor mExecutor;
+ @NonNull
+ private final Consumer<Boolean> mCallback;
@NonNull
- private final IRoleManagerCallback mRemoteCallback;
+ private final RemoteCallback mRemoteCallback;
- private OnGrantDefaultRolesRequest(@NonNull RemoteService service,
- @NonNull IRoleManagerCallback callback) {
+ private GrantDefaultRolesRequest(@NonNull RemoteService service,
+ @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) {
super(service);
+ mExecutor = executor;
mCallback = callback;
- mRemoteCallback = new IRoleManagerCallback.Stub() {
- @Override
- public void onSuccess() throws RemoteException {
- long token = Binder.clearCallingIdentity();
- try {
- mCallback.onSuccess();
- } finally {
- Binder.restoreCallingIdentity(token);
- finish();
- }
+ mRemoteCallback = new RemoteCallback(result -> mExecutor.execute(() -> {
+ long token = Binder.clearCallingIdentity();
+ try {
+ boolean successful = result != null;
+ mCallback.accept(successful);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ finish();
}
- @Override
- public void onFailure() throws RemoteException {
- long token = Binder.clearCallingIdentity();
- try {
- mCallback.onSuccess();
- } finally {
- Binder.restoreCallingIdentity(token);
- finish();
- }
- }
- };
+ }));
}
@Override
protected void onTimeout(@NonNull RemoteService remoteService) {
- try {
- mCallback.onFailure();
- } catch (RemoteException e) {
- Log.e(LOG_TAG, "Error calling onFailure() on callback", e);
- }
+ mExecutor.execute(() -> mCallback.accept(false));
}
@Override
public void run() {
try {
- getService().getServiceInterface().onGrantDefaultRoles(mRemoteCallback);
+ getService().getServiceInterface().grantDefaultRoles(mRemoteCallback);
} catch (RemoteException e) {
- Log.e(LOG_TAG, "Error calling onGrantDefaultRoles()", e);
+ Log.e(LOG_TAG, "Error calling grantDefaultRoles()", e);
}
}
}
/**
- * Request for {@link #onAddRoleHolder(String, String, int, IRoleManagerCallback)}.
+ * Request for {@link #onAddRoleHolder(String, String, int, RemoteCallback)}.
*/
private static final class OnAddRoleHolderRequest
extends AbstractRemoteService.PendingRequest<RemoteService, IRoleController> {
@@ -283,14 +267,14 @@
@RoleManager.ManageHoldersFlags
private final int mFlags;
@NonNull
- private final IRoleManagerCallback mCallback;
+ private final RemoteCallback mCallback;
@NonNull
- private final IRoleManagerCallback mRemoteCallback;
+ private final RemoteCallback mRemoteCallback;
private OnAddRoleHolderRequest(@NonNull RemoteService service, @NonNull String roleName,
@NonNull String packageName, @RoleManager.ManageHoldersFlags int flags,
- @NonNull IRoleManagerCallback callback) {
+ @NonNull RemoteCallback callback) {
super(service);
mRoleName = roleName;
@@ -298,37 +282,20 @@
mFlags = flags;
mCallback = callback;
- mRemoteCallback = new IRoleManagerCallback.Stub() {
- @Override
- public void onSuccess() throws RemoteException {
- long token = Binder.clearCallingIdentity();
- try {
- mCallback.onSuccess();
- } finally {
- Binder.restoreCallingIdentity(token);
- finish();
- }
+ mRemoteCallback = new RemoteCallback(result -> {
+ long token = Binder.clearCallingIdentity();
+ try {
+ mCallback.sendResult(result);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ finish();
}
- @Override
- public void onFailure() throws RemoteException {
- long token = Binder.clearCallingIdentity();
- try {
- mCallback.onSuccess();
- } finally {
- Binder.restoreCallingIdentity(token);
- finish();
- }
- }
- };
+ });
}
@Override
protected void onTimeout(@NonNull RemoteService remoteService) {
- try {
- mCallback.onFailure();
- } catch (RemoteException e) {
- Log.e(LOG_TAG, "Error calling onFailure() on callback", e);
- }
+ mCallback.sendResult(null);
}
@Override
@@ -343,7 +310,7 @@
}
/**
- * Request for {@link #onRemoveRoleHolder(String, String, int, IRoleManagerCallback)}.
+ * Request for {@link #onRemoveRoleHolder(String, String, int, RemoteCallback)}.
*/
private static final class OnRemoveRoleHolderRequest
extends AbstractRemoteService.PendingRequest<RemoteService, IRoleController> {
@@ -355,14 +322,14 @@
@RoleManager.ManageHoldersFlags
private final int mFlags;
@NonNull
- private final IRoleManagerCallback mCallback;
+ private final RemoteCallback mCallback;
@NonNull
- private final IRoleManagerCallback mRemoteCallback;
+ private final RemoteCallback mRemoteCallback;
private OnRemoveRoleHolderRequest(@NonNull RemoteService service, @NonNull String roleName,
@NonNull String packageName, @RoleManager.ManageHoldersFlags int flags,
- @NonNull IRoleManagerCallback callback) {
+ @NonNull RemoteCallback callback) {
super(service);
mRoleName = roleName;
@@ -370,37 +337,20 @@
mFlags = flags;
mCallback = callback;
- mRemoteCallback = new IRoleManagerCallback.Stub() {
- @Override
- public void onSuccess() throws RemoteException {
- long token = Binder.clearCallingIdentity();
- try {
- mCallback.onSuccess();
- } finally {
- Binder.restoreCallingIdentity(token);
- finish();
- }
+ mRemoteCallback = new RemoteCallback(result -> {
+ long token = Binder.clearCallingIdentity();
+ try {
+ mCallback.sendResult(result);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ finish();
}
- @Override
- public void onFailure() throws RemoteException {
- long token = Binder.clearCallingIdentity();
- try {
- mCallback.onSuccess();
- } finally {
- Binder.restoreCallingIdentity(token);
- finish();
- }
- }
- };
+ });
}
@Override
protected void onTimeout(@NonNull RemoteService remoteService) {
- try {
- mCallback.onFailure();
- } catch (RemoteException e) {
- Log.e(LOG_TAG, "Error calling onFailure() on callback", e);
- }
+ mCallback.sendResult(null);
}
@Override
@@ -415,7 +365,7 @@
}
/**
- * Request for {@link #onClearRoleHolders(String, int, IRoleManagerCallback)}.
+ * Request for {@link #onClearRoleHolders(String, int, RemoteCallback)}.
*/
private static final class OnClearRoleHoldersRequest
extends AbstractRemoteService.PendingRequest<RemoteService, IRoleController> {
@@ -425,50 +375,33 @@
@RoleManager.ManageHoldersFlags
private final int mFlags;
@NonNull
- private final IRoleManagerCallback mCallback;
+ private final RemoteCallback mCallback;
@NonNull
- private final IRoleManagerCallback mRemoteCallback;
+ private final RemoteCallback mRemoteCallback;
private OnClearRoleHoldersRequest(@NonNull RemoteService service, @NonNull String roleName,
- @RoleManager.ManageHoldersFlags int flags, @NonNull IRoleManagerCallback callback) {
+ @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) {
super(service);
mRoleName = roleName;
mFlags = flags;
mCallback = callback;
- mRemoteCallback = new IRoleManagerCallback.Stub() {
- @Override
- public void onSuccess() throws RemoteException {
- long token = Binder.clearCallingIdentity();
- try {
- mCallback.onSuccess();
- } finally {
- Binder.restoreCallingIdentity(token);
- finish();
- }
+ mRemoteCallback = new RemoteCallback(result -> {
+ long token = Binder.clearCallingIdentity();
+ try {
+ mCallback.sendResult(result);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ finish();
}
- @Override
- public void onFailure() throws RemoteException {
- long token = Binder.clearCallingIdentity();
- try {
- mCallback.onSuccess();
- } finally {
- Binder.restoreCallingIdentity(token);
- finish();
- }
- }
- };
+ });
}
@Override
protected void onTimeout(@NonNull RemoteService remoteService) {
- try {
- mCallback.onFailure();
- } catch (RemoteException e) {
- Log.e(LOG_TAG, "Error calling onFailure() on callback", e);
- }
+ mCallback.sendResult(null);
}
@Override
@@ -535,7 +468,7 @@
mRemoteCallback = new RemoteCallback(result -> mExecutor.execute(() -> {
long token = Binder.clearCallingIdentity();
try {
- boolean qualified = result != null && result.getBoolean(KEY_RESULT);
+ boolean qualified = result != null;
mCallback.accept(qualified);
} finally {
Binder.restoreCallingIdentity(token);
@@ -587,7 +520,7 @@
mRemoteCallback = new RemoteCallback(result -> mExecutor.execute(() -> {
long token = Binder.clearCallingIdentity();
try {
- boolean visible = result != null && result.getBoolean(KEY_RESULT);
+ boolean visible = result != null;
mCallback.accept(visible);
} finally {
Binder.restoreCallingIdentity(token);
diff --git a/core/java/android/app/role/RoleControllerService.java b/core/java/android/app/role/RoleControllerService.java
index 47be385..312761d 100644
--- a/core/java/android/app/role/RoleControllerService.java
+++ b/core/java/android/app/role/RoleControllerService.java
@@ -20,16 +20,20 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.annotation.WorkerThread;
import android.app.Service;
import android.content.Intent;
+import android.os.Binder;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
import android.os.IBinder;
+import android.os.Process;
import android.os.RemoteCallback;
-import android.os.RemoteException;
import android.os.UserHandle;
-import android.util.Log;
import com.android.internal.util.Preconditions;
+import com.android.internal.util.function.pooled.PooledLambda;
import java.util.concurrent.Executor;
@@ -45,59 +49,102 @@
@SystemApi
public abstract class RoleControllerService extends Service {
- private static final String LOG_TAG = RoleControllerService.class.getSimpleName();
-
/**
* The {@link Intent} that must be declared as handled by the service.
*/
public static final String SERVICE_INTERFACE = "android.app.role.RoleControllerService";
+ private HandlerThread mWorkerThread;
+ private Handler mWorkerHandler;
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+
+ mWorkerThread = new HandlerThread(RoleControllerService.class.getSimpleName());
+ mWorkerThread.start();
+ mWorkerHandler = new Handler(mWorkerThread.getLooper());
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+
+ mWorkerThread.quitSafely();
+ }
+
@Nullable
@Override
public final IBinder onBind(@Nullable Intent intent) {
return new IRoleController.Stub() {
@Override
- public void onGrantDefaultRoles(IRoleManagerCallback callback) {
+ public void grantDefaultRoles(RemoteCallback callback) {
+ enforceCallerSystemUid("grantDefaultRoles");
+
Preconditions.checkNotNull(callback, "callback cannot be null");
- RoleControllerService.this.onGrantDefaultRoles(new RoleManagerCallbackDelegate(
+
+ mWorkerHandler.sendMessage(PooledLambda.obtainMessage(
+ RoleControllerService::grantDefaultRoles, RoleControllerService.this,
callback));
}
@Override
public void onAddRoleHolder(String roleName, String packageName, int flags,
- IRoleManagerCallback callback) {
+ RemoteCallback callback) {
+ enforceCallerSystemUid("onAddRoleHolder");
+
Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
Preconditions.checkStringNotEmpty(packageName,
"packageName cannot be null or empty");
Preconditions.checkNotNull(callback, "callback cannot be null");
- RoleControllerService.this.onAddRoleHolder(roleName, packageName, flags,
- new RoleManagerCallbackDelegate(callback));
+
+ mWorkerHandler.sendMessage(PooledLambda.obtainMessage(
+ RoleControllerService::onAddRoleHolder, RoleControllerService.this,
+ roleName, packageName, flags, callback));
}
@Override
public void onRemoveRoleHolder(String roleName, String packageName, int flags,
- IRoleManagerCallback callback) {
+ RemoteCallback callback) {
+ enforceCallerSystemUid("onRemoveRoleHolder");
+
Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
Preconditions.checkStringNotEmpty(packageName,
"packageName cannot be null or empty");
Preconditions.checkNotNull(callback, "callback cannot be null");
- RoleControllerService.this.onRemoveRoleHolder(roleName, packageName, flags,
- new RoleManagerCallbackDelegate(callback));
+
+ mWorkerHandler.sendMessage(PooledLambda.obtainMessage(
+ RoleControllerService::onRemoveRoleHolder, RoleControllerService.this,
+ roleName, packageName, flags, callback));
}
@Override
- public void onClearRoleHolders(String roleName, int flags,
- IRoleManagerCallback callback) {
+ public void onClearRoleHolders(String roleName, int flags, RemoteCallback callback) {
+ enforceCallerSystemUid("onClearRoleHolders");
+
Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
Preconditions.checkNotNull(callback, "callback cannot be null");
- RoleControllerService.this.onClearRoleHolders(roleName, flags,
- new RoleManagerCallbackDelegate(callback));
+
+ mWorkerHandler.sendMessage(PooledLambda.obtainMessage(
+ RoleControllerService::onClearRoleHolders, RoleControllerService.this,
+ roleName, flags, callback));
}
@Override
- public void onSmsKillSwitchToggled(boolean smsRestrictionEnabled) {
- RoleControllerService.this.onSmsKillSwitchToggled(smsRestrictionEnabled);
+ public void onSmsKillSwitchToggled(boolean enabled) {
+ enforceCallerSystemUid("onSmsKillSwitchToggled");
+
+ mWorkerHandler.sendMessage(PooledLambda.obtainMessage(
+ RoleControllerService::onSmsKillSwitchToggled, RoleControllerService.this,
+ enabled));
+ }
+
+ private void enforceCallerSystemUid(@NonNull String methodName) {
+ if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ throw new SecurityException("Only the system process can call " + methodName
+ + "()");
+ }
}
@Override
@@ -111,9 +158,7 @@
Preconditions.checkNotNull(callback, "callback cannot be null");
boolean qualified = onIsApplicationQualifiedForRole(roleName, packageName);
- Bundle result = new Bundle();
- result.putBoolean(RoleControllerManager.KEY_RESULT, qualified);
- callback.sendResult(result);
+ callback.sendResult(qualified ? Bundle.EMPTY : null);
}
@Override
@@ -124,22 +169,44 @@
Preconditions.checkNotNull(callback, "callback cannot be null");
boolean visible = onIsRoleVisible(roleName);
- Bundle result = new Bundle();
- result.putBoolean(RoleControllerManager.KEY_RESULT, visible);
- callback.sendResult(result);
+ callback.sendResult(visible ? Bundle.EMPTY : null);
}
};
}
+ private void grantDefaultRoles(@NonNull RemoteCallback callback) {
+ boolean successful = onGrantDefaultRoles();
+ callback.sendResult(successful ? Bundle.EMPTY : null);
+ }
+
+ private void onAddRoleHolder(@NonNull String roleName, @NonNull String packageName,
+ @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) {
+ boolean successful = onAddRoleHolder(roleName, packageName, flags);
+ callback.sendResult(successful ? Bundle.EMPTY : null);
+ }
+
+ private void onRemoveRoleHolder(@NonNull String roleName, @NonNull String packageName,
+ @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) {
+ boolean successful = onRemoveRoleHolder(roleName, packageName, flags);
+ callback.sendResult(successful ? Bundle.EMPTY : null);
+ }
+
+ private void onClearRoleHolders(@NonNull String roleName,
+ @RoleManager.ManageHoldersFlags int flags, @NonNull RemoteCallback callback) {
+ boolean successful = onClearRoleHolders(roleName, flags);
+ callback.sendResult(successful ? Bundle.EMPTY : null);
+ }
+
/**
* Called by system to grant default permissions and roles.
* <p>
* This is typically when creating a new user or upgrading either system or
* permission controller package
*
- * @param callback the callback for whether this call is successful
+ * @return whether this call was successful
*/
- public abstract void onGrantDefaultRoles(@NonNull RoleManagerCallback callback);
+ @WorkerThread
+ public abstract boolean onGrantDefaultRoles();
/**
* Add a specific application to the holders of a role. If the role is exclusive, the previous
@@ -151,13 +218,15 @@
* @param roleName the name of the role to add the role holder for
* @param packageName the package name of the application to add to the role holders
* @param flags optional behavior flags
- * @param callback the callback for whether this call is successful
+ *
+ * @return whether this call was successful
*
* @see RoleManager#addRoleHolderAsUser(String, String, int, UserHandle, Executor,
- * RoleManagerCallback)
+ * RemoteCallback)
*/
- public abstract void onAddRoleHolder(@NonNull String roleName, @NonNull String packageName,
- @RoleManager.ManageHoldersFlags int flags, @NonNull RoleManagerCallback callback);
+ @WorkerThread
+ public abstract boolean onAddRoleHolder(@NonNull String roleName, @NonNull String packageName,
+ @RoleManager.ManageHoldersFlags int flags);
/**
* Remove a specific application from the holders of a role.
@@ -165,33 +234,39 @@
* @param roleName the name of the role to remove the role holder for
* @param packageName the package name of the application to remove from the role holders
* @param flags optional behavior flags
- * @param callback the callback for whether this call is successful
+ *
+ * @return whether this call was successful
*
* @see RoleManager#removeRoleHolderAsUser(String, String, int, UserHandle, Executor,
- * RoleManagerCallback)
+ * RemoteCallback)
*/
- public abstract void onRemoveRoleHolder(@NonNull String roleName, @NonNull String packageName,
- @RoleManager.ManageHoldersFlags int flags, @NonNull RoleManagerCallback callback);
+ @WorkerThread
+ public abstract boolean onRemoveRoleHolder(@NonNull String roleName,
+ @NonNull String packageName, @RoleManager.ManageHoldersFlags int flags);
/**
* Remove all holders of a role.
*
* @param roleName the name of the role to remove role holders for
* @param flags optional behavior flags
- * @param callback the callback for whether this call is successful
*
- * @see RoleManager#clearRoleHoldersAsUser(String, int, UserHandle, Executor,
- * RoleManagerCallback)
+ * @return whether this call was successful
+ *
+ * @see RoleManager#clearRoleHoldersAsUser(String, int, UserHandle, Executor, RemoteCallback)
*/
- public abstract void onClearRoleHolders(@NonNull String roleName,
- @RoleManager.ManageHoldersFlags int flags, @NonNull RoleManagerCallback callback);
+ @WorkerThread
+ public abstract boolean onClearRoleHolders(@NonNull String roleName,
+ @RoleManager.ManageHoldersFlags int flags);
/**
* Cleanup appop/permissions state in response to sms kill switch toggle
*
* @param enabled whether kill switch was turned on
+ *
+ * @hide
*/
//STOPSHIP: remove this api before shipping a final version
+ @WorkerThread
public abstract void onSmsKillSwitchToggled(boolean enabled);
/**
@@ -213,31 +288,4 @@
* @return whether the role should be visible to user
*/
public abstract boolean onIsRoleVisible(@NonNull String roleName);
-
- private static class RoleManagerCallbackDelegate implements RoleManagerCallback {
-
- private IRoleManagerCallback mCallback;
-
- RoleManagerCallbackDelegate(IRoleManagerCallback callback) {
- mCallback = callback;
- }
-
- @Override
- public void onSuccess() {
- try {
- mCallback.onSuccess();
- } catch (RemoteException e) {
- Log.e(LOG_TAG, "Error calling onSuccess() callback");
- }
- }
-
- @Override
- public void onFailure() {
- try {
- mCallback.onFailure();
- } catch (RemoteException e) {
- Log.e(LOG_TAG, "Error calling onFailure() callback");
- }
- }
- }
}
diff --git a/core/java/android/app/role/RoleManager.java b/core/java/android/app/role/RoleManager.java
index a663498..d1f8ed2 100644
--- a/core/java/android/app/role/RoleManager.java
+++ b/core/java/android/app/role/RoleManager.java
@@ -30,6 +30,7 @@
import android.content.Intent;
import android.os.Binder;
import android.os.Process;
+import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
@@ -42,6 +43,7 @@
import java.util.List;
import java.util.concurrent.Executor;
+import java.util.function.Consumer;
/**
* This class provides information about and manages roles.
@@ -315,9 +317,9 @@
*
* @return a list of package names of the role holders, or an empty list if none.
*
- * @see #addRoleHolderAsUser(String, String, int, UserHandle, Executor, RoleManagerCallback)
- * @see #removeRoleHolderAsUser(String, String, int, UserHandle, Executor, RoleManagerCallback)
- * @see #clearRoleHoldersAsUser(String, int, UserHandle, Executor, RoleManagerCallback)
+ * @see #addRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer)
+ * @see #removeRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer)
+ * @see #clearRoleHoldersAsUser(String, int, UserHandle, Executor, Consumer)
*
* @hide
*/
@@ -351,8 +353,8 @@
* @param callback the callback for whether this call is successful
*
* @see #getRoleHoldersAsUser(String, UserHandle)
- * @see #removeRoleHolderAsUser(String, String, int, UserHandle, Executor, RoleManagerCallback)
- * @see #clearRoleHoldersAsUser(String, int, UserHandle, Executor, RoleManagerCallback)
+ * @see #removeRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer)
+ * @see #clearRoleHoldersAsUser(String, int, UserHandle, Executor, Consumer)
*
* @hide
*/
@@ -361,7 +363,7 @@
@TestApi
public void addRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName,
@ManageHoldersFlags int flags, @NonNull UserHandle user,
- @CallbackExecutor @NonNull Executor executor, @NonNull RoleManagerCallback callback) {
+ @CallbackExecutor @NonNull Executor executor, @NonNull Consumer<Boolean> callback) {
Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
Preconditions.checkNotNull(user, "user cannot be null");
@@ -369,7 +371,7 @@
Preconditions.checkNotNull(callback, "callback cannot be null");
try {
mService.addRoleHolderAsUser(roleName, packageName, flags, user.getIdentifier(),
- new RoleManagerCallbackDelegate(executor, callback));
+ createRemoteCallback(executor, callback));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -390,8 +392,8 @@
* @param callback the callback for whether this call is successful
*
* @see #getRoleHoldersAsUser(String, UserHandle)
- * @see #addRoleHolderAsUser(String, String, int, UserHandle, Executor, RoleManagerCallback)
- * @see #clearRoleHoldersAsUser(String, int, UserHandle, Executor, RoleManagerCallback)
+ * @see #addRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer)
+ * @see #clearRoleHoldersAsUser(String, int, UserHandle, Executor, Consumer)
*
* @hide
*/
@@ -400,7 +402,7 @@
@TestApi
public void removeRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName,
@ManageHoldersFlags int flags, @NonNull UserHandle user,
- @CallbackExecutor @NonNull Executor executor, @NonNull RoleManagerCallback callback) {
+ @CallbackExecutor @NonNull Executor executor, @NonNull Consumer<Boolean> callback) {
Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
Preconditions.checkNotNull(user, "user cannot be null");
@@ -408,7 +410,7 @@
Preconditions.checkNotNull(callback, "callback cannot be null");
try {
mService.removeRoleHolderAsUser(roleName, packageName, flags, user.getIdentifier(),
- new RoleManagerCallbackDelegate(executor, callback));
+ createRemoteCallback(executor, callback));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -428,8 +430,8 @@
* @param callback the callback for whether this call is successful
*
* @see #getRoleHoldersAsUser(String, UserHandle)
- * @see #addRoleHolderAsUser(String, String, int, UserHandle, Executor, RoleManagerCallback)
- * @see #removeRoleHolderAsUser(String, String, int, UserHandle, Executor, RoleManagerCallback)
+ * @see #addRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer)
+ * @see #removeRoleHolderAsUser(String, String, int, UserHandle, Executor, Consumer)
*
* @hide
*/
@@ -438,19 +440,33 @@
@TestApi
public void clearRoleHoldersAsUser(@NonNull String roleName, @ManageHoldersFlags int flags,
@NonNull UserHandle user, @CallbackExecutor @NonNull Executor executor,
- @NonNull RoleManagerCallback callback) {
+ @NonNull Consumer<Boolean> callback) {
Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
Preconditions.checkNotNull(user, "user cannot be null");
Preconditions.checkNotNull(executor, "executor cannot be null");
Preconditions.checkNotNull(callback, "callback cannot be null");
try {
mService.clearRoleHoldersAsUser(roleName, flags, user.getIdentifier(),
- new RoleManagerCallbackDelegate(executor, callback));
+ createRemoteCallback(executor, callback));
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
+ @NonNull
+ private static RemoteCallback createRemoteCallback(@NonNull Executor executor,
+ @NonNull Consumer<Boolean> callback) {
+ return new RemoteCallback(result -> executor.execute(() -> {
+ boolean successful = result != null;
+ long token = Binder.clearCallingIdentity();
+ try {
+ callback.accept(successful);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }));
+ }
+
/**
* Add a listener to observe role holder changes
* <p>
@@ -669,40 +685,6 @@
}
}
- private static class RoleManagerCallbackDelegate extends IRoleManagerCallback.Stub {
-
- @NonNull
- private final Executor mExecutor;
- @NonNull
- private final RoleManagerCallback mCallback;
-
- RoleManagerCallbackDelegate(@NonNull Executor executor,
- @NonNull RoleManagerCallback callback) {
- mExecutor = executor;
- mCallback = callback;
- }
-
- @Override
- public void onSuccess() {
- long token = Binder.clearCallingIdentity();
- try {
- mExecutor.execute(mCallback::onSuccess);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- @Override
- public void onFailure() {
- long token = Binder.clearCallingIdentity();
- try {
- mExecutor.execute(mCallback::onFailure);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
- }
-
private static class OnRoleHoldersChangedListenerDelegate
extends IOnRoleHoldersChangedListener.Stub {
diff --git a/core/java/android/app/role/RoleManagerCallback.java b/core/java/android/app/role/RoleManagerCallback.java
deleted file mode 100644
index a92ef32..0000000
--- a/core/java/android/app/role/RoleManagerCallback.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2018 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.app.role;
-
-import android.annotation.SystemApi;
-import android.annotation.TestApi;
-
-import java.util.concurrent.CompletableFuture;
-
-/**
- * Callback for a {@link RoleManager} request.
- *
- * @hide
- */
-@SystemApi
-@TestApi
-public interface RoleManagerCallback {
-
- /**
- * Signals a success.
- */
- void onSuccess();
-
- /**
- * Signals a failure.
- */
- void onFailure();
-
- /** @hide */
- class Future extends CompletableFuture<Void> implements RoleManagerCallback {
-
- @Override
- public void onSuccess() {
- complete(null);
- }
-
- @Override
- public void onFailure() {
- completeExceptionally(new RuntimeException());
- }
- }
-}
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index 0d0e466..b3d01fd 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -254,18 +254,32 @@
public static final int FLUSH_TO_DISK = 25;
/**
- * An event type denoting that the device underwent a shutdown process.
+ * An event type denoting that the Android runtime underwent a shutdown process.
* A DEVICE_SHUTDOWN event should be treated as if all started activities and foreground
* services are now stopped and no explicit {@link #ACTIVITY_STOPPED} and
* {@link #FOREGROUND_SERVICE_STOP} events will be generated for them.
+ *
+ * <p>The DEVICE_SHUTDOWN timestamp is actually the last time UsageStats database is
+ * persisted before the actual shutdown. Events (if there are any) between this timestamp
+ * and the actual shutdown is not persisted in the database. So any open events without
+ * matching close events between DEVICE_SHUTDOWN and {@link #DEVICE_STARTUP} should be
+ * ignored because the closing time is unknown.</p>
*/
public static final int DEVICE_SHUTDOWN = 26;
/**
+ * An event type denoting that the Android runtime started up. This could be after a
+ * shutdown or a runtime restart. Any open events without matching close events between
+ * {@link #DEVICE_SHUTDOWN} and DEVICE_STARTUP should be ignored because the closing time is
+ * unknown.
+ */
+ public static final int DEVICE_STARTUP = 27;
+
+ /**
* Keep in sync with the greatest event type value.
* @hide
*/
- public static final int MAX_EVENT_TYPE = 26;
+ public static final int MAX_EVENT_TYPE = 27;
/** @hide */
public static final int FLAG_IS_PACKAGE_INSTANT_APP = 1 << 0;
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index d758c4d..7b4dd19 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1448,14 +1448,33 @@
/**
* Request that rollbacks be enabled for the given upgrade.
+ *
+ * @removed
+ * @deprecated use {@link #setEnableRollback(boolean)} instead.
* @hide
*/
+ @Deprecated
@SystemApi
public void setEnableRollback() {
installFlags |= PackageManager.INSTALL_ENABLE_ROLLBACK;
}
/**
+ * Request that rollbacks be enabled or disabled for the given upgrade.
+ *
+ * @param enable set to {@code true} to enable, {@code false} to disable
+ * @hide
+ */
+ @SystemApi
+ public void setEnableRollback(boolean enable) {
+ if (enable) {
+ installFlags |= PackageManager.INSTALL_ENABLE_ROLLBACK;
+ } else {
+ installFlags &= ~PackageManager.INSTALL_ENABLE_ROLLBACK;
+ }
+ }
+
+ /**
* @deprecated use {@link #setRequestDowngrade(boolean)}.
* {@hide}
*/
@@ -2058,6 +2077,16 @@
}
/**
+ * Return whether rollback is enabled or disabled for the given upgrade.
+ *
+ * @hide
+ */
+ @SystemApi
+ public boolean getEnableRollback() {
+ return (installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0;
+ }
+
+ /**
* Get the value set in {@link SessionParams#setAllocateAggressive(boolean)}.
*
* @hide
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index c4a574a..89c0690 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1843,7 +1843,8 @@
}
}
- final boolean extractNativeLibsDefault = targetSdkVersion < Build.VERSION_CODES.Q;
+ // TODO: flip the default based on targetSdkVersion when possible. See b/128335904.
+ final boolean extractNativeLibsDefault = true;
final boolean extractNativeLibs = (extractNativeLibsProvided != null)
? extractNativeLibsProvided : extractNativeLibsDefault;
@@ -3718,11 +3719,10 @@
ai.flags |= ApplicationInfo.FLAG_MULTIARCH;
}
- final boolean extractNativeLibsDefault =
- owner.applicationInfo.targetSdkVersion < Build.VERSION_CODES.Q;
+ // TODO: flip the default based on targetSdkVersion when possible. See b/128335904.
if (sa.getBoolean(
com.android.internal.R.styleable.AndroidManifestApplication_extractNativeLibs,
- extractNativeLibsDefault)) {
+ true)) {
ai.flags |= ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS;
}
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index c855d45..6729242 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -1396,9 +1396,11 @@
/**
+ * Returns the resource ID of the resource that was used to create this AttributeSet.
+ *
* @param set AttributeSet for which we want to find the source.
- * @return The resource id for the source that is backing the given AttributeSet
- * @hide
+ * @return The resource ID for the source that is backing the given AttributeSet or
+ * {@link Resources#ID_NULL} if the AttributeSet is {@code null}.
*/
@AnyRes
public static int getAttributeSetSourceResId(@Nullable AttributeSet set) {
diff --git a/core/java/android/content/rollback/PackageRollbackInfo.java b/core/java/android/content/rollback/PackageRollbackInfo.java
index 03810f5..c0414fc 100644
--- a/core/java/android/content/rollback/PackageRollbackInfo.java
+++ b/core/java/android/content/rollback/PackageRollbackInfo.java
@@ -89,6 +89,7 @@
/**
* Returns the name of the package to roll back from.
*/
+ @NonNull
public String getPackageName() {
return mVersionRolledBackFrom.getPackageName();
}
@@ -96,6 +97,7 @@
/**
* Returns the version of the package rolled back from.
*/
+ @NonNull
public VersionedPackage getVersionRolledBackFrom() {
return mVersionRolledBackFrom;
}
@@ -103,6 +105,7 @@
/**
* Returns the version of the package rolled back to.
*/
+ @NonNull
public VersionedPackage getVersionRolledBackTo() {
return mVersionRolledBackTo;
}
diff --git a/core/java/android/content/rollback/RollbackInfo.java b/core/java/android/content/rollback/RollbackInfo.java
index 29b99e0..a363718 100644
--- a/core/java/android/content/rollback/RollbackInfo.java
+++ b/core/java/android/content/rollback/RollbackInfo.java
@@ -16,6 +16,7 @@
package android.content.rollback;
+import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.content.pm.VersionedPackage;
import android.os.Parcel;
@@ -72,6 +73,7 @@
/**
* Returns the list of package that are rolled back.
*/
+ @NonNull
public List<PackageRollbackInfo> getPackages() {
return mPackages;
}
@@ -105,6 +107,7 @@
* As provided to {@link #commitRollback} when the rollback was committed.
* This is only applicable for rollbacks that have been committed.
*/
+ @NonNull
public List<VersionedPackage> getCausePackages() {
return mCausePackages;
}
diff --git a/core/java/android/content/rollback/RollbackManager.java b/core/java/android/content/rollback/RollbackManager.java
index c043491..4e8c254 100644
--- a/core/java/android/content/rollback/RollbackManager.java
+++ b/core/java/android/content/rollback/RollbackManager.java
@@ -57,6 +57,7 @@
* MANAGE_ROLLBACKS permission.
*/
@RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
+ @NonNull
public List<RollbackInfo> getAvailableRollbacks() {
try {
return mBinder.getAvailableRollbacks().getList();
diff --git a/core/java/android/net/IpMemoryStore.java b/core/java/android/net/IpMemoryStore.java
index b35f097..2f4d9bc 100644
--- a/core/java/android/net/IpMemoryStore.java
+++ b/core/java/android/net/IpMemoryStore.java
@@ -171,4 +171,9 @@
throw e.rethrowFromSystemServer();
}
}
+
+ /** Gets an instance of the memory store */
+ public static IpMemoryStore getMemoryStore(final Context context) {
+ return (IpMemoryStore) context.getSystemService(Context.IP_MEMORY_STORE_SERVICE);
+ }
}
diff --git a/core/java/android/os/BatterySaverPolicyConfig.java b/core/java/android/os/BatterySaverPolicyConfig.java
index af7d11d..bda4e27 100644
--- a/core/java/android/os/BatterySaverPolicyConfig.java
+++ b/core/java/android/os/BatterySaverPolicyConfig.java
@@ -476,10 +476,6 @@
*/
@NonNull
public BatterySaverPolicyConfig build() {
- if (!mEnableAdjustBrightness && Float.compare(1f, mAdjustBrightnessFactor) != 0) {
- throw new IllegalArgumentException("Brightness adjustment factor changed without "
- + "enabling brightness adjustment");
- }
return new BatterySaverPolicyConfig(this);
}
}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index b7e65b9..e4277e4 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -4761,6 +4761,9 @@
sb.append(")");
pw.println(sb.toString());
+ printControllerActivity(pw, sb, prefix, CELLULAR_CONTROLLER_NAME,
+ getModemControllerActivity(), which);
+
pw.print(" Cellular data received: "); pw.println(formatBytesLocked(mobileRxTotalBytes));
pw.print(" Cellular data sent: "); pw.println(formatBytesLocked(mobileTxTotalBytes));
pw.print(" Cellular packets received: "); pw.println(mobileRxTotalPackets);
@@ -4818,9 +4821,6 @@
if (!didOne) sb.append(" (no activity)");
pw.println(sb.toString());
- printControllerActivity(pw, sb, prefix, CELLULAR_CONTROLLER_NAME,
- getModemControllerActivity(), which);
-
pw.print(prefix);
sb.setLength(0);
sb.append(prefix);
@@ -4837,6 +4837,9 @@
sb.append(")");
pw.println(sb.toString());
+ printControllerActivity(pw, sb, prefix, WIFI_CONTROLLER_NAME,
+ getWifiControllerActivity(), which);
+
pw.print(" Wifi data received: "); pw.println(formatBytesLocked(wifiRxTotalBytes));
pw.print(" Wifi data sent: "); pw.println(formatBytesLocked(wifiTxTotalBytes));
pw.print(" Wifi packets received: "); pw.println(wifiRxTotalPackets);
@@ -4914,9 +4917,6 @@
if (!didOne) sb.append(" (no activity)");
pw.println(sb.toString());
- printControllerActivity(pw, sb, prefix, WIFI_CONTROLLER_NAME,
- getWifiControllerActivity(), which);
-
pw.print(prefix);
sb.setLength(0);
sb.append(prefix);
@@ -4949,8 +4949,10 @@
pw.print(prefix);
sb.setLength(0);
sb.append(prefix);
- sb.append(" Battery Drain (mAh): ");
- sb.append(Double.toString(((double) gpsBatteryDrainMaMs)/(3600 * 1000)));
+ sb.append(" GPS Battery Drain: ");
+ sb.append(new DecimalFormat("#.##").format(
+ ((double) gpsBatteryDrainMaMs) / (3600 * 1000)));
+ sb.append("mAh");
pw.println(sb.toString());
}
diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java
index 684369a..672624c 100644
--- a/core/java/android/os/BugreportManager.java
+++ b/core/java/android/os/BugreportManager.java
@@ -17,6 +17,7 @@
package android.os;
import android.annotation.CallbackExecutor;
+import android.annotation.FloatRange;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -39,7 +40,7 @@
*/
@SystemApi
@SystemService(Context.BUGREPORT_SERVICE)
-public class BugreportManager {
+public final class BugreportManager {
private final Context mContext;
private final IDumpstate mBinder;
@@ -90,7 +91,7 @@
* Called when there is a progress update.
* @param progress the progress in [0.0, 100.0]
*/
- public void onProgress(float progress) {}
+ public void onProgress(@FloatRange(from = 0f, to = 100f) float progress) {}
/**
* Called when taking bugreport resulted in an error.
diff --git a/core/java/android/os/BugreportParams.java b/core/java/android/os/BugreportParams.java
index 3871375..279ccae 100644
--- a/core/java/android/os/BugreportParams.java
+++ b/core/java/android/os/BugreportParams.java
@@ -41,6 +41,7 @@
/**
* Defines acceptable types of bugreports.
+ * @hide
*/
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = { "BUGREPORT_MODE_" }, value = {
diff --git a/core/java/android/os/UpdateEngine.java b/core/java/android/os/UpdateEngine.java
index 1df3dad..5cf3b97 100644
--- a/core/java/android/os/UpdateEngine.java
+++ b/core/java/android/os/UpdateEngine.java
@@ -39,8 +39,9 @@
*
* The APIs defined in this class and UpdateEngineCallback class must be in
* sync with the ones in
- * system/update_engine/binder_bindings/android/os/IUpdateEngine.aidl and
- * system/update_engine/binder_bindings/android/os/IUpdateEngineCallback.aidl.
+ * {@code system/update_engine/binder_bindings/android/os/IUpdateEngine.aidl}
+ * and
+ * {@code system/update_engine/binder_bindings/android/os/IUpdateEngineCallback.aidl}.
*
* {@hide}
*/
@@ -51,39 +52,150 @@
private static final String UPDATE_ENGINE_SERVICE = "android.os.UpdateEngineService";
/**
- * Error code from the update engine. Values must agree with the ones in
- * system/update_engine/common/error_code.h.
+ * Error codes from update engine upon finishing a call to
+ * {@link applyPayload}. Values will be passed via the callback function
+ * {@link UpdateEngineCallback#onPayloadApplicationComplete}. Values must
+ * agree with the ones in {@code system/update_engine/common/error_code.h}.
*/
public static final class ErrorCodeConstants {
+ /**
+ * Error code: a request finished successfully.
+ */
public static final int SUCCESS = 0;
+ /**
+ * Error code: a request failed due to a generic error.
+ */
public static final int ERROR = 1;
+ /**
+ * Error code: an update failed to apply due to filesystem copier
+ * error.
+ */
public static final int FILESYSTEM_COPIER_ERROR = 4;
+ /**
+ * Error code: an update failed to apply due to an error in running
+ * post-install hooks.
+ */
public static final int POST_INSTALL_RUNNER_ERROR = 5;
+ /**
+ * Error code: an update failed to apply due to a mismatching payload.
+ *
+ * <p>For example, the given payload uses a feature that's not
+ * supported by the current update engine.
+ */
public static final int PAYLOAD_MISMATCHED_TYPE_ERROR = 6;
+ /**
+ * Error code: an update failed to apply due to an error in opening
+ * devices.
+ */
public static final int INSTALL_DEVICE_OPEN_ERROR = 7;
+ /**
+ * Error code: an update failed to apply due to an error in opening
+ * kernel device.
+ */
public static final int KERNEL_DEVICE_OPEN_ERROR = 8;
+ /**
+ * Error code: an update failed to apply due to an error in fetching
+ * the payload.
+ *
+ * <p>For example, this could be a result of bad network connection
+ * when streaming an update.
+ */
public static final int DOWNLOAD_TRANSFER_ERROR = 9;
+ /**
+ * Error code: an update failed to apply due to a mismatch in payload
+ * hash.
+ *
+ * <p>Update engine does sanity checks for the given payload and its
+ * metadata.
+ */
public static final int PAYLOAD_HASH_MISMATCH_ERROR = 10;
+
+ /**
+ * Error code: an update failed to apply due to a mismatch in payload
+ * size.
+ */
public static final int PAYLOAD_SIZE_MISMATCH_ERROR = 11;
+
+ /**
+ * Error code: an update failed to apply due to failing to verify
+ * payload signatures.
+ */
public static final int DOWNLOAD_PAYLOAD_VERIFICATION_ERROR = 12;
+
+ /**
+ * Error code: an update failed to apply due to a downgrade in payload
+ * timestamp.
+ *
+ * <p>The timestamp of a build is encoded into the payload, which will
+ * be enforced during install to prevent downgrading a device.
+ */
public static final int PAYLOAD_TIMESTAMP_ERROR = 51;
+
+ /**
+ * Error code: an update has been applied successfully but the new slot
+ * hasn't been set to active.
+ *
+ * <p>It indicates a successful finish of calling {@link #applyPayload} with
+ * {@code SWITCH_SLOT_ON_REBOOT=0}. See {@link #applyPayload}.
+ */
public static final int UPDATED_BUT_NOT_ACTIVE = 52;
}
/**
- * Update status code from the update engine. Values must agree with the
- * ones in system/update_engine/client_library/include/update_engine/update_status.h.
+ * Status codes for update engine. Values must agree with the ones in
+ * {@code system/update_engine/client_library/include/update_engine/update_status.h}.
*/
public static final class UpdateStatusConstants {
+ /**
+ * Update status code: update engine is in idle state.
+ */
public static final int IDLE = 0;
+
+ /**
+ * Update status code: update engine is checking for update.
+ */
public static final int CHECKING_FOR_UPDATE = 1;
+
+ /**
+ * Update status code: an update is available.
+ */
public static final int UPDATE_AVAILABLE = 2;
+
+ /**
+ * Update status code: update engine is downloading an update.
+ */
public static final int DOWNLOADING = 3;
+
+ /**
+ * Update status code: update engine is verifying an update.
+ */
public static final int VERIFYING = 4;
+
+ /**
+ * Update status code: update engine is finalizing an update.
+ */
public static final int FINALIZING = 5;
+
+ /**
+ * Update status code: an update has been applied and is pending for
+ * reboot.
+ */
public static final int UPDATED_NEED_REBOOT = 6;
+
+ /**
+ * Update status code: update engine is reporting an error event.
+ */
public static final int REPORTING_ERROR_EVENT = 7;
+
+ /**
+ * Update status code: update engine is attempting to rollback an
+ * update.
+ */
public static final int ATTEMPTING_ROLLBACK = 8;
+
+ /**
+ * Update status code: update engine is in disabled state.
+ */
public static final int DISABLED = 9;
}
@@ -178,6 +290,18 @@
* "METADATA_SIZE=70604"
* };
* </pre>
+ *
+ * <p>The callback functions registered via {@code #bind} will be called
+ * during and at the end of the payload application.
+ *
+ * <p>By default the newly updated slot will be set active upon
+ * successfully finishing an update. Device will attempt to boot into the
+ * new slot on next reboot. This behavior can be customized by specifying
+ * {@code SWITCH_SLOT_ON_REBOOT=0} in {@code headerKeyValuePairs}, which
+ * allows the caller to later determine a good time to boot into the new
+ * slot. Calling {@code applyPayload} again with the same payload but with
+ * {@code SWITCH_SLOT_ON_REBOOT=1} will do the minimal work to set the new
+ * slot active, after verifying its integrity.
*/
public void applyPayload(String url, long offset, long size, String[] headerKeyValuePairs) {
try {
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 4263377..185df5e 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -25,6 +25,7 @@
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
+import android.annotation.UnsupportedAppUsage;
import android.annotation.UserIdInt;
import android.annotation.WorkerThread;
import android.app.Activity;
@@ -954,6 +955,21 @@
public static final String DISALLOW_CONTENT_CAPTURE = "no_content_capture";
/**
+ * Specifies if the current user is able to receive content suggestions for selections based on
+ * the contents of their screen.
+ *
+ * <p>Device owner and profile owner can set this restriction. When it is set by device owner,
+ * only the target user will be affected.
+ *
+ * <p>The default value is <code>false</code>.
+ *
+ * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+ * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_CONTENT_SUGGESTIONS = "no_content_suggestions";
+
+ /**
* Specifies if user switching is blocked on the current user.
*
* <p> This restriction can only be set by the device owner, it will be applied to all users.
@@ -1102,6 +1118,47 @@
public static final int USER_CREATION_FAILED_NO_MORE_USERS = Activity.RESULT_FIRST_USER + 1;
/**
+ * Indicates that users are switchable.
+ * @hide
+ */
+ @SystemApi
+ public static final int SWITCHABILITY_STATUS_OK = 0;
+
+ /**
+ * Indicated that the user is in a phone call.
+ * @hide
+ */
+ @SystemApi
+ public static final int SWITCHABILITY_STATUS_USER_IN_CALL = 1 << 0;
+
+ /**
+ * Indicates that user switching is disallowed ({@link #DISALLOW_USER_SWITCH} is set).
+ * @hide
+ */
+ @SystemApi
+ public static final int SWITCHABILITY_STATUS_USER_SWITCH_DISALLOWED = 1 << 1;
+
+ /**
+ * Indicates that the system user is locked and user switching is not allowed.
+ * @hide
+ */
+ @SystemApi
+ public static final int SWITCHABILITY_STATUS_SYSTEM_USER_LOCKED = 1 << 2;
+
+ /**
+ * Result returned in {@link #getUserSwitchability()} indicating user swichability.
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = { "SWITCHABILITY_STATUS_" }, value = {
+ SWITCHABILITY_STATUS_OK,
+ SWITCHABILITY_STATUS_USER_IN_CALL,
+ SWITCHABILITY_STATUS_USER_SWITCH_DISALLOWED,
+ SWITCHABILITY_STATUS_SYSTEM_USER_LOCKED
+ })
+ public @interface UserSwitchabilityResult {}
+
+ /**
* Indicates user operation is successful.
*/
public static final int USER_OPERATION_SUCCESS = 0;
@@ -1223,14 +1280,13 @@
}
/**
- * Returns whether switching users is currently allowed.
- * <p>For instance switching users is not allowed if the current user is in a phone call,
- * system user hasn't been unlocked yet, or {@link #DISALLOW_USER_SWITCH} is set.
+ * @deprecated use {@link #getUserSwitchability()} instead.
+ *
+ * @removed
* @hide
*/
- @SystemApi
- @RequiresPermission(anyOf = {android.Manifest.permission.MANAGE_USERS,
- android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true)
+ @Deprecated
+ @UnsupportedAppUsage
public boolean canSwitchUsers() {
boolean allowUserSwitchingWhenSystemUserLocked = Settings.Global.getInt(
mContext.getContentResolver(),
@@ -1244,6 +1300,42 @@
}
/**
+ * Returns whether switching users is currently allowed.
+ * <p>
+ * Switching users is not allowed in the following cases:
+ * <li>the user is in a phone call</li>
+ * <li>{@link #DISALLOW_USER_SWITCH} is set</li>
+ * <li>system user hasn't been unlocked yet</li>
+ *
+ * @return A {@link UserSwitchabilityResult} flag indicating if the user is switchable.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(allOf = {Manifest.permission.READ_PHONE_STATE,
+ android.Manifest.permission.MANAGE_USERS,
+ android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true)
+ public @UserSwitchabilityResult int getUserSwitchability() {
+ final boolean allowUserSwitchingWhenSystemUserLocked = Settings.Global.getInt(
+ mContext.getContentResolver(),
+ Settings.Global.ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED, 0) != 0;
+ final boolean systemUserUnlocked = isUserUnlocked(UserHandle.SYSTEM);
+ final TelephonyManager tm =
+ (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+
+ int flags = SWITCHABILITY_STATUS_OK;
+ if (tm.getCallState() != TelephonyManager.CALL_STATE_IDLE) {
+ flags |= SWITCHABILITY_STATUS_USER_IN_CALL;
+ }
+ if (hasUserRestriction(DISALLOW_USER_SWITCH)) {
+ flags |= SWITCHABILITY_STATUS_USER_SWITCH_DISALLOWED;
+ }
+ if (!allowUserSwitchingWhenSystemUserLocked && !systemUserUnlocked) {
+ flags |= SWITCHABILITY_STATUS_SYSTEM_USER_LOCKED;
+ }
+ return flags;
+ }
+
+ /**
* Returns the user handle for the user that this process is running under.
*
* @return the user handle of this process.
@@ -2655,11 +2747,16 @@
* Removes a user and all associated data.
*
* @param user the user that needs to be removed.
+ * @return {@code true} if the user was successfully removed, {@code false} otherwise.
+ * @throws IllegalArgumentException if {@code user} is {@code null}
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.MANAGE_USERS)
- public boolean removeUser(UserHandle user) {
+ public boolean removeUser(@NonNull UserHandle user) {
+ if (user == null) {
+ throw new IllegalArgumentException("user cannot be null");
+ }
return removeUser(user.getIdentifier());
}
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 0ac7c37..e4593e5 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -30,6 +30,7 @@
import android.database.ContentObserver;
import android.net.Uri;
import android.provider.Settings.ResetMode;
+import android.util.ArrayMap;
import android.util.Pair;
import com.android.internal.annotations.GuardedBy;
@@ -398,8 +399,11 @@
private static final Object sLock = new Object();
@GuardedBy("sLock")
- private static Map<OnPropertyChangedListener, Pair<String, Executor>> sListeners =
- new HashMap<>();
+ private static ArrayMap<OnPropertyChangedListener, Pair<String, Executor>> sSingleListeners =
+ new ArrayMap<>();
+ @GuardedBy("sLock")
+ private static ArrayMap<OnPropertiesChangedListener, Pair<String, Executor>> sListeners =
+ new ArrayMap<>();
@GuardedBy("sLock")
private static Map<String, Pair<ContentObserver, Integer>> sNamespaces = new HashMap<>();
@@ -597,20 +601,58 @@
@NonNull String namespace,
@NonNull @CallbackExecutor Executor executor,
@NonNull OnPropertyChangedListener onPropertyChangedListener) {
- // TODO enforce READ_DEVICE_CONFIG permission
synchronized (sLock) {
- Pair<String, Executor> oldNamespace = sListeners.get(onPropertyChangedListener);
+ Pair<String, Executor> oldNamespace = sSingleListeners.get(onPropertyChangedListener);
if (oldNamespace == null) {
// Brand new listener, add it to the list.
- sListeners.put(onPropertyChangedListener, new Pair<>(namespace, executor));
+ sSingleListeners.put(onPropertyChangedListener, new Pair<>(namespace, executor));
incrementNamespace(namespace);
} else if (namespace.equals(oldNamespace.first)) {
// Listener is already registered for this namespace, update executor just in case.
- sListeners.put(onPropertyChangedListener, new Pair<>(namespace, executor));
+ sSingleListeners.put(onPropertyChangedListener, new Pair<>(namespace, executor));
} else {
// Update this listener from an old namespace to the new one.
- decrementNamespace(sListeners.get(onPropertyChangedListener).first);
- sListeners.put(onPropertyChangedListener, new Pair<>(namespace, executor));
+ decrementNamespace(sSingleListeners.get(onPropertyChangedListener).first);
+ sSingleListeners.put(onPropertyChangedListener, new Pair<>(namespace, executor));
+ incrementNamespace(namespace);
+ }
+ }
+ }
+
+ /**
+ * Add a listener for property changes.
+ * <p>
+ * This listener will be called whenever properties in the specified namespace change. Callbacks
+ * will be made on the specified executor. Future calls to this method with the same listener
+ * will replace the old namespace and executor. Remove the listener entirely by calling
+ * {@link #removeOnPropertiesChangedListener(OnPropertiesChangedListener)}.
+ *
+ * @param namespace The namespace containing properties to monitor.
+ * @param executor The executor which will be used to run callbacks.
+ * @param onPropertiesChangedListener The listener to add.
+ * @hide
+ * @see #removeOnPropertiesChangedListener(OnPropertiesChangedListener)
+ */
+ @SystemApi
+ @TestApi
+ @RequiresPermission(READ_DEVICE_CONFIG)
+ public static void addOnPropertiesChangedListener(
+ @NonNull String namespace,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull OnPropertiesChangedListener onPropertiesChangedListener) {
+ synchronized (sLock) {
+ Pair<String, Executor> oldNamespace = sListeners.get(onPropertiesChangedListener);
+ if (oldNamespace == null) {
+ // Brand new listener, add it to the list.
+ sListeners.put(onPropertiesChangedListener, new Pair<>(namespace, executor));
+ incrementNamespace(namespace);
+ } else if (namespace.equals(oldNamespace.first)) {
+ // Listener is already registered for this namespace, update executor just in case.
+ sListeners.put(onPropertiesChangedListener, new Pair<>(namespace, executor));
+ } else {
+ // Update this listener from an old namespace to the new one.
+ decrementNamespace(sListeners.get(onPropertiesChangedListener).first);
+ sListeners.put(onPropertiesChangedListener, new Pair<>(namespace, executor));
incrementNamespace(namespace);
}
}
@@ -627,11 +669,33 @@
@SystemApi
@TestApi
public static void removeOnPropertyChangedListener(
- OnPropertyChangedListener onPropertyChangedListener) {
+ @NonNull OnPropertyChangedListener onPropertyChangedListener) {
+ Preconditions.checkNotNull(onPropertyChangedListener);
synchronized (sLock) {
- if (sListeners.containsKey(onPropertyChangedListener)) {
- decrementNamespace(sListeners.get(onPropertyChangedListener).first);
- sListeners.remove(onPropertyChangedListener);
+ if (sSingleListeners.containsKey(onPropertyChangedListener)) {
+ decrementNamespace(sSingleListeners.get(onPropertyChangedListener).first);
+ sSingleListeners.remove(onPropertyChangedListener);
+ }
+ }
+ }
+
+ /**
+ * Remove a listener for property changes. The listener will receive no further notification of
+ * property changes.
+ *
+ * @param onPropertiesChangedListener The listener to remove.
+ * @hide
+ * @see #addOnPropertiesChangedListener(String, Executor, OnPropertiesChangedListener)
+ */
+ @SystemApi
+ @TestApi
+ public static void removeOnPropertiesChangedListener(
+ @NonNull OnPropertiesChangedListener onPropertiesChangedListener) {
+ Preconditions.checkNotNull(onPropertiesChangedListener);
+ synchronized (sLock) {
+ if (sListeners.containsKey(onPropertiesChangedListener)) {
+ decrementNamespace(sListeners.get(onPropertiesChangedListener).first);
+ sListeners.remove(onPropertiesChangedListener);
}
}
}
@@ -700,14 +764,30 @@
final String name = pathSegments.get(2);
final String value = getProperty(namespace, name);
synchronized (sLock) {
- for (final OnPropertyChangedListener listener : sListeners.keySet()) {
- if (namespace.equals(sListeners.get(listener).first)) {
- sListeners.get(listener).second.execute(new Runnable() {
+ // OnPropertiesChangedListeners
+ for (int i = 0; i < sListeners.size(); i++) {
+ if (namespace.equals(sListeners.valueAt(i).first)) {
+ final int j = i;
+ sListeners.valueAt(i).second.execute(new Runnable() {
@Override
public void run() {
Map<String, String> propertyMap = new HashMap(1);
propertyMap.put(name, value);
- listener.onPropertiesChanged(new Properties(namespace, propertyMap));
+ sListeners.keyAt(j)
+ .onPropertiesChanged(new Properties(namespace, propertyMap));
+ }
+
+ });
+ }
+ }
+ // OnPropertyChangedListeners
+ for (int i = 0; i < sSingleListeners.size(); i++) {
+ if (namespace.equals(sSingleListeners.valueAt(i).first)) {
+ final int j = i;
+ sSingleListeners.valueAt(i).second.execute(new Runnable() {
+ @Override
+ public void run() {
+ sSingleListeners.keyAt(j).onPropertyChanged(namespace, name, value);
}
});
@@ -717,7 +797,7 @@
}
/**
- * Interface for monitoring to properties.
+ * Interface for monitoring single property changes.
* <p>
* Override {@link #onPropertyChanged(String, String, String)} to handle callbacks for changes.
*
@@ -734,22 +814,25 @@
* @param value The new value of the property which has changed.
*/
void onPropertyChanged(String namespace, String name, String value);
+ }
+ /**
+ * Interface for monitoring changes to properties.
+ * <p>
+ * Override {@link #onPropertiesChanged(Properties)} to handle callbacks for changes.
+ *
+ * @hide
+ */
+ @SystemApi
+ @TestApi
+ public interface OnPropertiesChangedListener {
/**
* Called when one or more properties have changed.
*
* @param properties Contains the complete collection of properties which have changed for a
- * single namespace.
+ * single namespace.
*/
- default void onPropertiesChanged(@NonNull Properties properties) {
- // During the transitional period, this method calls the old one to ensure legacy
- // callers continue to function as expected. Ignore this if you are implementing it for
- // yourself.
- String namespace = properties.getNamespace();
- for (String name : properties.getKeyset()) {
- onPropertyChanged(namespace, name, properties.getString(name, null));
- }
- }
+ void onPropertiesChanged(@NonNull Properties properties);
}
/**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 5f36373..4836e6c 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1686,14 +1686,7 @@
* Input: Nothing.
*
* <p>
- * Output: {@link android.app.Activity#RESULT_OK} if user enabled Content Capture,
- * {@link android.app.Activity#RESULT_CANCELED} if user disabled it, cancelled, or if the caller
- * is not the Content Capture service associated with the user.
- *
- * <p>
- * <b>NOTE: </b> Caller should call
- * {@link android.view.contentcapture.ContentCaptureManager#isContentCaptureFeatureEnabled()}
- * first to check whether the feature is already enabled.
+ * Output: Nothing
*
* @hide
*/
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
index 87bdfe0..780b576 100644
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -373,7 +373,10 @@
args.recycle();
Adjustment adjustment = onNotificationEnqueued(sbn, channel);
if (adjustment != null) {
- if (!isBound()) return;
+ if (!isBound()) {
+ Log.w(TAG, "MSG_ON_NOTIFICATION_ENQUEUED: service not bound, skip.");
+ return;
+ }
try {
getNotificationInterface().applyEnqueuedAdjustmentFromAssistant(
mWrapper, adjustment);
diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index 4315100..cc74e1a 100644
--- a/core/java/android/service/notification/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -63,9 +63,6 @@
private Context mContext; // used for inflation & icon expansion
- // Contains the basic logging data of the notification.
- private LogMaker mLogMaker;
-
/** @hide */
public StatusBarNotification(String pkg, String opPkg, int id,
String tag, int uid, int initialPid, Notification notification, UserHandle user,
@@ -404,24 +401,15 @@
* @hide
*/
public LogMaker getLogMaker() {
- if (mLogMaker == null) {
- // Initialize fields that only change on update (so a new record).
- mLogMaker = new LogMaker(MetricsEvent.VIEW_UNKNOWN)
- .setPackageName(getPackageName())
+ return new LogMaker(MetricsEvent.VIEW_UNKNOWN).setPackageName(getPackageName())
.addTaggedData(MetricsEvent.NOTIFICATION_ID, getId())
.addTaggedData(MetricsEvent.NOTIFICATION_TAG, getTag())
- .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_ID, getChannelIdLogTag());
- }
- // Reset fields that can change between updates, or are used by multiple logs.
- return mLogMaker
- .clearCategory()
- .clearType()
- .clearSubtype()
- .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_ID, getGroupLogTag())
- .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_SUMMARY,
- getNotification().isGroupSummary() ? 1 : 0)
- .addTaggedData(MetricsProto.MetricsEvent.FIELD_NOTIFICATION_CATEGORY,
- getNotification().category);
+ .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_CHANNEL_ID, getChannelIdLogTag())
+ .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_ID, getGroupLogTag())
+ .addTaggedData(MetricsEvent.FIELD_NOTIFICATION_GROUP_SUMMARY,
+ getNotification().isGroupSummary() ? 1 : 0)
+ .addTaggedData(MetricsProto.MetricsEvent.FIELD_NOTIFICATION_CATEGORY,
+ getNotification().category);
}
private String getGroupLogTag() {
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index 1382fbc..2d7e179 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -142,6 +142,10 @@
&& legacyContentInsets != null && legacyStableInsets != null) {
WindowInsets.assignCompatInsets(typeInsetsMap, legacyContentInsets);
WindowInsets.assignCompatInsets(typeMaxInsetsMap, legacyStableInsets);
+
+ // TODO: set system gesture insets based on actual system gesture area.
+ typeInsetsMap[Type.indexOf(Type.systemGestures())] = Insets.of(legacyContentInsets);
+ typeMaxInsetsMap[Type.indexOf(Type.systemGestures())] = Insets.of(legacyContentInsets);
}
for (int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
InsetsSource source = mSources.get(type);
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index 6ff699e..cb64ab1 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -17,6 +17,7 @@
package android.view;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.UnsupportedAppUsage;
import android.content.res.CompatibilityInfo.Translator;
import android.graphics.Canvas;
@@ -193,7 +194,7 @@
*
* @param from The SurfaceControl to assosciate this Surface with
*/
- public Surface(SurfaceControl from) {
+ public Surface(@NonNull SurfaceControl from) {
copyFrom(from);
}
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 5e2aaae..998ad2a 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -459,6 +459,7 @@
* Construct a new {@link SurfaceControl} with the set parameters. The builder
* remains valid.
*/
+ @NonNull
public SurfaceControl build() {
if (mWidth < 0 || mHeight < 0) {
throw new IllegalArgumentException(
@@ -477,7 +478,8 @@
*
* @param name A name to identify the Surface in debugging.
*/
- public Builder setName(String name) {
+ @NonNull
+ public Builder setName(@NonNull String name) {
mName = name;
return this;
}
@@ -488,6 +490,7 @@
* @param width The buffer width in pixels.
* @param height The buffer height in pixels.
*/
+ @NonNull
public Builder setBufferSize(@IntRange(from = 0) int width,
@IntRange(from = 0) int height) {
if (width < 0 || height < 0) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 2479497..7fcce6d 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -24116,7 +24116,7 @@
*
* @param matrix input matrix to modify
*/
- public void transformMatrixToGlobal(Matrix matrix) {
+ public void transformMatrixToGlobal(@NonNull Matrix matrix) {
final ViewParent parent = mParent;
if (parent instanceof View) {
final View vp = (View) parent;
@@ -24141,7 +24141,7 @@
*
* @param matrix input matrix to modify
*/
- public void transformMatrixToLocal(Matrix matrix) {
+ public void transformMatrixToLocal(@NonNull Matrix matrix) {
final ViewParent parent = mParent;
if (parent instanceof View) {
final View vp = (View) parent;
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index f3bbca3..f1a992c 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -27,6 +27,7 @@
import static android.view.WindowInsets.Type.all;
import static android.view.WindowInsets.Type.compatSystemInsets;
import static android.view.WindowInsets.Type.indexOf;
+import static android.view.WindowInsets.Type.systemGestures;
import android.annotation.IntDef;
import android.annotation.IntRange;
@@ -220,6 +221,8 @@
}
Insets[] typeInsetMap = new Insets[SIZE];
assignCompatInsets(typeInsetMap, insets);
+ // TODO: set system gesture insets based on actual system gesture area.
+ typeInsetMap[indexOf(systemGestures())] = Insets.of(insets);
return typeInsetMap;
}
@@ -229,7 +232,6 @@
static void assignCompatInsets(Insets[] typeInsetMap, Rect insets) {
typeInsetMap[indexOf(TOP_BAR)] = Insets.of(0, insets.top, 0, 0);
typeInsetMap[indexOf(SIDE_BARS)] = Insets.of(insets.left, 0, insets.right, insets.bottom);
- typeInsetMap[indexOf(SYSTEM_GESTURES)] = Insets.of(insets);
}
private static boolean[] createCompatVisibilityMap(@Nullable Insets[] typeInsetMap) {
@@ -675,6 +677,7 @@
public String toString() {
return "WindowInsets{systemWindowInsets=" + getSystemWindowInsets()
+ " stableInsets=" + getStableInsets()
+ + " sysGestureInsets=" + getSystemGestureInsets()
+ (mDisplayCutout != null ? " cutout=" + mDisplayCutout : "")
+ (isRound() ? " round" : "")
+ "}";
diff --git a/core/java/android/view/inspector/GeneratedInspectionCompanionProvider.java b/core/java/android/view/inspector/StaticInspectionCompanionProvider.java
similarity index 76%
rename from core/java/android/view/inspector/GeneratedInspectionCompanionProvider.java
rename to core/java/android/view/inspector/StaticInspectionCompanionProvider.java
index d4b7e85..42a892d 100644
--- a/core/java/android/view/inspector/GeneratedInspectionCompanionProvider.java
+++ b/core/java/android/view/inspector/StaticInspectionCompanionProvider.java
@@ -20,15 +20,15 @@
import android.annotation.Nullable;
/**
- * An inspection companion provider that loads pre-generated inspection companions
+ * An inspection companion provider that finds companions as inner classes or generated code.
*
* @see android.processor.view.inspector.PlatformInspectableProcessor
*/
-public class GeneratedInspectionCompanionProvider implements InspectionCompanionProvider {
+public class StaticInspectionCompanionProvider implements InspectionCompanionProvider {
/**
- * The suffix used for the generated class
+ * The suffix used for the generated classes and inner classes
*/
- private static final String COMPANION_SUFFIX = "$$InspectionCompanion";
+ private static final String COMPANION_SUFFIX = "$InspectionCompanion";
@Override
@Nullable
@@ -39,7 +39,12 @@
try {
final Class<InspectionCompanion<T>> companionClass =
(Class<InspectionCompanion<T>>) cls.getClassLoader().loadClass(companionName);
- return companionClass.newInstance();
+
+ if (InspectionCompanion.class.isAssignableFrom(companionClass)) {
+ return companionClass.newInstance();
+ } else {
+ return null;
+ }
} catch (ClassNotFoundException e) {
return null;
} catch (IllegalAccessException e) {
diff --git a/core/java/android/view/textclassifier/ConversationActions.java b/core/java/android/view/textclassifier/ConversationActions.java
index 78ed9bf..dc75212 100644
--- a/core/java/android/view/textclassifier/ConversationActions.java
+++ b/core/java/android/view/textclassifier/ConversationActions.java
@@ -318,19 +318,15 @@
private final List<String> mHints;
@Nullable
private String mCallingPackageName;
- @Nullable
- private final String mConversationId;
private Request(
@NonNull List<Message> conversation,
@NonNull TextClassifier.EntityConfig typeConfig,
int maxSuggestions,
- String conversationId,
@Nullable @Hint List<String> hints) {
mConversation = Preconditions.checkNotNull(conversation);
mTypeConfig = Preconditions.checkNotNull(typeConfig);
mMaxSuggestions = maxSuggestions;
- mConversationId = conversationId;
mHints = hints;
}
@@ -339,7 +335,6 @@
in.readParcelableList(conversation, null);
TextClassifier.EntityConfig typeConfig = in.readParcelable(null);
int maxSuggestions = in.readInt();
- String conversationId = in.readString();
List<String> hints = new ArrayList<>();
in.readStringList(hints);
String callingPackageName = in.readString();
@@ -348,7 +343,6 @@
conversation,
typeConfig,
maxSuggestions,
- conversationId,
hints);
request.setCallingPackageName(callingPackageName);
return request;
@@ -359,7 +353,6 @@
parcel.writeParcelableList(mConversation, flags);
parcel.writeParcelable(mTypeConfig, flags);
parcel.writeInt(mMaxSuggestions);
- parcel.writeString(mConversationId);
parcel.writeStringList(mHints);
parcel.writeString(mCallingPackageName);
}
@@ -403,16 +396,6 @@
return mMaxSuggestions;
}
- /**
- * Return an unique identifier of the conversation that is generating actions for. This
- * identifier is unique within the calling package only, so use it with
- * {@link #getCallingPackageName()}.
- */
- @Nullable
- public String getConversationId() {
- return mConversationId;
- }
-
/** Returns an immutable list of hints */
@Nullable
@Hint
@@ -448,8 +431,6 @@
private TextClassifier.EntityConfig mTypeConfig;
private int mMaxSuggestions = -1;
@Nullable
- private String mConversationId;
- @Nullable
@Hint
private List<String> mHints;
@@ -490,15 +471,6 @@
return this;
}
- /**
- * Sets an unique identifier of the conversation that is generating actions for.
- */
- @NonNull
- public Builder setConversationId(@Nullable String conversationId) {
- mConversationId = conversationId;
- return this;
- }
-
/** Builds the {@link Request} object. */
@NonNull
public Request build() {
@@ -508,7 +480,6 @@
? new TextClassifier.EntityConfig.Builder().build()
: mTypeConfig,
mMaxSuggestions,
- mConversationId,
mHints == null
? Collections.emptyList()
: Collections.unmodifiableList(mHints));
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 3555822..034cabd 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1704,7 +1704,7 @@
/**
- * Gets the WebView renderer associated with this WebView.
+ * Gets a handle to the WebView renderer process associated with this WebView.
*
* <p>In {@link android.os.Build.VERSION_CODES#O} and above, WebView may
* run in "multiprocess" mode. In multiprocess mode, rendering of web
@@ -1717,67 +1717,70 @@
* handle to the renderer process associated with the WebView, which can
* be used to control the renderer process.
*
- * @return the {@link WebViewRenderer} renderer handle associated
+ * @return the {@link WebViewRenderProcess} renderer handle associated
* with this {@link WebView}, or {@code null} if
* WebView is not runing in multiprocess mode.
*/
@Nullable
- public WebViewRenderer getWebViewRenderer() {
+ public WebViewRenderProcess getWebViewRenderProcess() {
checkThread();
- return mProvider.getWebViewRenderer();
+ return mProvider.getWebViewRenderProcess();
}
/**
* Sets the renderer client object associated with this WebView.
*
* <p>The renderer client encapsulates callbacks relevant to WebView renderer
- * state. See {@link WebViewRendererClient} for details.
+ * state. See {@link WebViewRenderProcessClient} for details.
*
* <p>Although many WebView instances may share a single underlying
* renderer, and renderers may live either in the application
* process, or in a sandboxed process that is isolated from the
- * application process, instances of {@link WebViewRendererClient}
+ * application process, instances of {@link WebViewRenderProcessClient}
* are set per-WebView. Callbacks represent renderer events from
* the perspective of this WebView, and may or may not be correlated
* with renderer events affecting other WebViews.
*
- * @param executor the Executor on which {@link WebViewRendererClient} callbacks will execute.
- * @param webViewRendererClient the {@link WebViewRendererClient} object.
+ * @param executor the Executor on which {@link WebViewRenderProcessClient}
+ * callbacks will execute.
+ * @param webViewRenderProcessClient the {@link WebViewRenderProcessClient}
+ * object.
*/
- public void setWebViewRendererClient(
+ public void setWebViewRenderProcessClient(
@NonNull @CallbackExecutor Executor executor,
- @NonNull WebViewRendererClient webViewRendererClient) {
+ @NonNull WebViewRenderProcessClient webViewRenderProcessClient) {
checkThread();
- mProvider.setWebViewRendererClient(executor, webViewRendererClient);
+ mProvider.setWebViewRenderProcessClient(
+ executor, webViewRenderProcessClient);
}
/**
* Sets the renderer client object associated with this WebView.
*
- * See {@link #setWebViewRendererClient(Executor,WebViewRendererClient)} for details.
+ * See {@link #setWebViewRenderProcessClient(Executor,WebViewRenderProcessClient)} for details.
*
- * <p> {@link WebViewRendererClient} callbacks will run on the thread that this WebView was
+ * <p> {@link WebViewRenderProcessClient} callbacks will run on the thread that this WebView was
* initialized on.
*
- * @param webViewRendererClient the {@link WebViewRendererClient} object.
+ * @param webViewRenderProcessClient the {@link WebViewRenderProcessClient} object.
*/
- public void setWebViewRendererClient(
- @Nullable WebViewRendererClient webViewRendererClient) {
+ public void setWebViewRenderProcessClient(
+ @Nullable WebViewRenderProcessClient webViewRenderProcessClient) {
checkThread();
- mProvider.setWebViewRendererClient(null, webViewRendererClient);
+ mProvider.setWebViewRenderProcessClient(null, webViewRenderProcessClient);
}
/**
* Gets the renderer client object associated with this WebView.
*
- * @return the {@link WebViewRendererClient} object associated with this WebView, if one has
- * been set via {@link #setWebViewRendererClient(WebViewRendererClient)} or {@code null}
- * otherwise.
+ * @return the {@link WebViewRenderProcessClient} object associated with this WebView, if one
+ * has been set via {@link #setWebViewRenderProcessClient(WebViewRenderProcessClient)}
+ * or {@code null} otherwise.
*/
@Nullable
- public WebViewRendererClient getWebViewRendererClient() {
+ public WebViewRenderProcessClient getWebViewRenderProcessClient() {
checkThread();
- return mProvider.getWebViewRendererClient();
+ return mProvider.getWebViewRenderProcessClient();
}
/**
diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java
index 090640e..150fa88 100644
--- a/core/java/android/webkit/WebViewClient.java
+++ b/core/java/android/webkit/WebViewClient.java
@@ -102,9 +102,11 @@
/**
* Notify the host application that a page has finished loading. This method
- * is called only for main frame. When onPageFinished() is called, the
- * rendering picture may not be updated yet. To get the notification for the
- * new Picture, use {@link WebView.PictureListener#onNewPicture}.
+ * is called only for main frame. Receiving an {@code onPageFinished()} callback does not
+ * guarantee that the next frame drawn by WebView will reflect the state of the DOM at this
+ * point. In order to be notified that the current DOM state is ready to be rendered, request a
+ * visual state callback with {@link WebView#postVisualStateCallback} and wait for the supplied
+ * callback to be triggered.
*
* @param view The WebView that is initiating the callback.
* @param url The url of the page.
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index 4c8f72a..010c0b7 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -238,13 +238,15 @@
public WebViewClient getWebViewClient();
- public WebViewRenderer getWebViewRenderer();
+ @Nullable
+ public WebViewRenderProcess getWebViewRenderProcess();
- public void setWebViewRendererClient(
+ public void setWebViewRenderProcessClient(
@Nullable Executor executor,
- @Nullable WebViewRendererClient client);
+ @Nullable WebViewRenderProcessClient client);
- public WebViewRendererClient getWebViewRendererClient();
+ @Nullable
+ public WebViewRenderProcessClient getWebViewRenderProcessClient();
public void setDownloadListener(DownloadListener listener);
diff --git a/core/java/android/webkit/WebViewRenderer.java b/core/java/android/webkit/WebViewRenderProcess.java
similarity index 82%
rename from core/java/android/webkit/WebViewRenderer.java
rename to core/java/android/webkit/WebViewRenderProcess.java
index fc38cd9..1be2210 100644
--- a/core/java/android/webkit/WebViewRenderer.java
+++ b/core/java/android/webkit/WebViewRenderProcess.java
@@ -16,12 +16,10 @@
package android.webkit;
-import android.annotation.SystemApi;
-
/**
- * WebViewRenderer provides an opaque handle to a {@link WebView} renderer.
+ * WebViewRenderProcess provides an opaque handle to a {@link WebView} renderer.
*/
-public abstract class WebViewRenderer {
+public abstract class WebViewRenderProcess {
/**
* Cause this renderer to terminate.
*
@@ -38,11 +36,6 @@
*/
public abstract boolean terminate();
- /**
- * This class cannot be created by applications.
- * @hide
- */
- @SystemApi
- public WebViewRenderer() {
+ public WebViewRenderProcess() {
}
}
diff --git a/core/java/android/webkit/WebViewRendererClient.java b/core/java/android/webkit/WebViewRenderProcessClient.java
similarity index 66%
rename from core/java/android/webkit/WebViewRendererClient.java
rename to core/java/android/webkit/WebViewRenderProcessClient.java
index 2fadf54..24b8fb5 100644
--- a/core/java/android/webkit/WebViewRendererClient.java
+++ b/core/java/android/webkit/WebViewRenderProcessClient.java
@@ -22,14 +22,14 @@
/**
* Used to receive callbacks on {@link WebView} renderer events.
*
- * WebViewRendererClient instances may be set or retrieved via {@link
- * WebView#setWebViewRendererClient(WebViewRendererClient)} and {@link
- * WebView#getWebViewRendererClient()}.
+ * WebViewRenderProcessClient instances may be set or retrieved via {@link
+ * WebView#setWebViewRenderProcessClient(WebViewRenderProcessClient)} and {@link
+ * WebView#getWebViewRenderProcessClient()}.
*
* Instances may be attached to multiple WebViews, and thus a single renderer event may cause
* a callback to be called multiple times with different WebView parameters.
*/
-public abstract class WebViewRendererClient {
+public abstract class WebViewRenderProcessClient {
/**
* Called when the renderer currently associated with {@code view} becomes unresponsive as a
* result of a long running blocking task such as the execution of JavaScript.
@@ -40,8 +40,11 @@
*
* <p>This callback will continue to be called at regular intervals as long as the renderer
* remains unresponsive. If the renderer becomes responsive again, {@link
- * WebViewRendererClient#onRendererResponsive} will be called once, and this method will not
- * subsequently be called unless another period of unresponsiveness is detected.
+ * WebViewRenderProcessClient#onRenderProcessResponsive} will be called once, and this method
+ * will not subsequently be called unless another period of unresponsiveness is detected.
+ *
+ * <p>The minimum interval between successive calls to {@code onRenderProcessUnresponsive} is 5
+ * seconds.
*
* <p>No action is taken by WebView as a result of this method call. Applications may
* choose to terminate the associated renderer via the object that is passed to this callback,
@@ -50,28 +53,28 @@
* with the same renderer. Failure to do so will result in application termination.
*
* @param view The {@link WebView} for which unresponsiveness was detected.
- * @param renderer The {@link WebViewRenderer} that has become unresponsive,
+ * @param renderer The {@link WebViewRenderProcess} that has become unresponsive,
* or {@code null} if WebView is running in single process mode.
*/
- public abstract void onRendererUnresponsive(
- @NonNull WebView view, @Nullable WebViewRenderer renderer);
+ public abstract void onRenderProcessUnresponsive(
+ @NonNull WebView view, @Nullable WebViewRenderProcess renderer);
/**
* Called once when an unresponsive renderer currently associated with {@code view} becomes
* responsive.
*
* <p>After a WebView renderer becomes unresponsive, which is notified to the application by
- * {@link WebViewRendererClient#onRendererUnresponsive}, it is possible for the blocking
- * renderer task to complete, returning the renderer to a responsive state. In that case,
- * this method is called once to indicate responsiveness.
+ * {@link WebViewRenderProcessClient#onRenderProcessUnresponsive}, it is possible for the
+ * blocking renderer task to complete, returning the renderer to a responsive state. In that
+ * case, this method is called once to indicate responsiveness.
*
* <p>No action is taken by WebView as a result of this method call.
*
* @param view The {@link WebView} for which responsiveness was detected.
*
- * @param renderer The {@link WebViewRenderer} that has become responsive, or {@code null} if
- * WebView is running in single process mode.
+ * @param renderer The {@link WebViewRenderProcess} that has become responsive, or {@code null}
+ * if WebView is running in single process mode.
*/
- public abstract void onRendererResponsive(
- @NonNull WebView view, @Nullable WebViewRenderer renderer);
+ public abstract void onRenderProcessResponsive(
+ @NonNull WebView view, @Nullable WebViewRenderProcess renderer);
}
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index dad2669..685e8de 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -1587,6 +1587,7 @@
* others.
* @return The height of the divider
*/
+ @Px
public int getSelectionDividerHeight() {
return mSelectionDividerHeight;
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 17ed2a0..c095376 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -1687,8 +1687,21 @@
*
* @return a unique 64-bit token handle which is needed to refer to this token later.
*/
- public long addEscrowToken(byte[] token, int userId) {
- return getLockSettingsInternal().addEscrowToken(token, userId);
+ public long addEscrowToken(byte[] token, int userId,
+ @Nullable EscrowTokenStateChangeCallback callback) {
+ return getLockSettingsInternal().addEscrowToken(token, userId, callback);
+ }
+
+ /**
+ * Callback interface to notify when an added escrow token has been activated.
+ */
+ public interface EscrowTokenStateChangeCallback {
+ /**
+ * The method to be called when the token is activated.
+ * @param handle 64 bit handle corresponding to the escrow token
+ * @param userid user for whom the escrow token has been added
+ */
+ void onEscrowTokenActivated(long handle, int userid);
}
/**
diff --git a/core/java/com/android/internal/widget/LockSettingsInternal.java b/core/java/com/android/internal/widget/LockSettingsInternal.java
index 90397df..d459bfb 100644
--- a/core/java/com/android/internal/widget/LockSettingsInternal.java
+++ b/core/java/com/android/internal/widget/LockSettingsInternal.java
@@ -29,15 +29,18 @@
* or change user password.
*
* After adding, if the user currently has lockscreen password, he will need to perform a
- * confirm credential operation in order to activate the token for future use. If the user
+ * confirm credential operation in order to activate the token for future use.
+ * Once the token is activated, the callback that is passed here is called. If the user
* has no secure lockscreen, then the token is activated immediately.
*
* @return a unique 64-bit token handle which is needed to refer to this token later.
*/
- public abstract long addEscrowToken(byte[] token, int userId);
+ public abstract long addEscrowToken(byte[] token, int userId,
+ LockPatternUtils.EscrowTokenStateChangeCallback callback);
/**
* Remove an escrow token.
+ *
* @return true if the given handle refers to a valid token previously returned from
* {@link #addEscrowToken}, whether it's active or not. return false otherwise.
*/
@@ -51,6 +54,7 @@
/**
* Set the lock credential.
+ *
* @return true if password is set.
*/
public abstract boolean setLockCredentialWithToken(byte[] credential, int type,
diff --git a/core/java/com/android/internal/widget/MediaNotificationView.java b/core/java/com/android/internal/widget/MediaNotificationView.java
index de86d92..e7d240a 100644
--- a/core/java/com/android/internal/widget/MediaNotificationView.java
+++ b/core/java/com/android/internal/widget/MediaNotificationView.java
@@ -126,6 +126,9 @@
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (mImagePushIn > 0) {
+ if (this.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
+ mImagePushIn *= -1;
+ }
mRightIcon.layout(mRightIcon.getLeft() + mImagePushIn, mRightIcon.getTop(),
mRightIcon.getRight() + mImagePushIn, mRightIcon.getBottom());
}
diff --git a/core/res/res/layout/notification_material_media_seekbar.xml b/core/res/res/layout/notification_material_media_seekbar.xml
index c23ca83..4aa8acc 100644
--- a/core/res/res/layout/notification_material_media_seekbar.xml
+++ b/core/res/res/layout/notification_material_media_seekbar.xml
@@ -50,7 +50,7 @@
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_marginStart="@dimen/notification_content_margin_start"
- android:gravity="left"
+ android:gravity="start"
/>
<TextView android:id="@+id/notification_media_total_time"
@@ -59,7 +59,7 @@
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginEnd="@dimen/notification_content_margin_end"
- android:gravity="right"
+ android:gravity="end"
/>
</FrameLayout>
</LinearLayout>
\ No newline at end of file
diff --git a/core/res/res/values-night/values.xml b/core/res/res/values-night/values.xml
index a2ad3b9..4e6b712 100644
--- a/core/res/res/values-night/values.xml
+++ b/core/res/res/values-night/values.xml
@@ -24,6 +24,7 @@
<item name="colorError">@color/error_color_device_default_dark</item>
<item name="colorControlNormal">?attr/textColorPrimary</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
+ <item name="forceDarkAllowed">false</item>
<!-- QS panel background -->
<item name="colorBackgroundFloating">@color/black</item>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index b7f594e..bfb6d24 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1950,7 +1950,7 @@
<!-- The name of the package that will hold the browser role by default. -->
<string name="config_defaultBrowser" translatable="false">@string/default_browser</string>
<!-- The name of the package that will hold the dialer role by default. -->
- <string name="config_defaultDialer" translatable="false">com.android.phone</string>
+ <string name="config_defaultDialer" translatable="false">com.android.dialer</string>
<!-- The name of the package that will hold the SMS role by default. -->
<string name="config_defaultSms" translatable="false">@string/default_sms_application</string>
<!-- Whether the default emergency settings should be shown. -->
@@ -3943,4 +3943,8 @@
<!-- The default peak refresh rate for a given device. Change this value if you want to allow
for higher refresh rates to be automatically used out of the box -->
<integer name="config_defaultPeakRefreshRate">60</integer>
+
+ <!-- The type of the light sensor to be used by the display framework for things like
+ auto-brightness. If unset, then it just gets the default sensor of type TYPE_LIGHT. -->
+ <string name="config_displayLightSensorType" translatable="false" />
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 6671ff8..05cf419 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -280,9 +280,9 @@
<!-- WFC, summary for Disabled -->
<string name="wifi_calling_off_summary">Off</string>
<!-- WFC, summary for Wi-Fi Preferred -->
- <string name="wfc_mode_wifi_preferred_summary">Wi-Fi preferred</string>
+ <string name="wfc_mode_wifi_preferred_summary">Call over Wi-Fi</string>
<!-- WFC, summary for Mobile data Preferred -->
- <string name="wfc_mode_cellular_preferred_summary">Mobile preferred</string>
+ <string name="wfc_mode_cellular_preferred_summary">Call over mobile network</string>
<!-- WFC, summary for Wi-Fi Only -->
<string name="wfc_mode_wifi_only_summary">Wi-Fi only</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 96a3d96..c7e19c5 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3693,5 +3693,9 @@
<java-symbol type="string" name="mime_type_presentation" />
<java-symbol type="string" name="mime_type_presentation_ext" />
+ <!-- For high refresh rate displays -->
<java-symbol type="integer" name="config_defaultPeakRefreshRate" />
+
+ <!-- For Auto-Brightness -->
+ <java-symbol type="string" name="config_displayLightSensorType" />
</resources>
diff --git a/core/tests/coretests/src/android/provider/DeviceConfigTest.java b/core/tests/coretests/src/android/provider/DeviceConfigTest.java
index d100f40..04fa524 100644
--- a/core/tests/coretests/src/android/provider/DeviceConfigTest.java
+++ b/core/tests/coretests/src/android/provider/DeviceConfigTest.java
@@ -16,6 +16,7 @@
package android.provider;
+import static android.provider.DeviceConfig.OnPropertiesChangedListener;
import static android.provider.DeviceConfig.OnPropertyChangedListener;
import static com.google.common.truth.Truth.assertThat;
@@ -224,29 +225,31 @@
}
@Test
- public void testListener_propertiesCallback() throws InterruptedException {
+ public void testOnPropertiesChangedListener() throws InterruptedException {
final CountDownLatch countDownLatch = new CountDownLatch(1);
- OnPropertyChangedListener changeListener = new OnPropertyChangedListener() {
- public void onPropertyChanged(String namespace, String name, String value) {
- // ignore legacy callback
- }
-
- @Override
- public void onPropertiesChanged(DeviceConfig.Properties properties) {
- assertThat(properties.getNamespace()).isEqualTo(sNamespace);
- assertThat(properties.getKeyset().size()).isEqualTo(1);
- assertThat(properties.getKeyset()).contains(sKey);
- assertThat(properties.getString(sKey, "default_value")).isEqualTo(sValue);
- countDownLatch.countDown();
- }
+ OnPropertiesChangedListener changeListener = (properties) -> {
+ assertThat(properties.getNamespace()).isEqualTo(sNamespace);
+ assertThat(properties.getKeyset()).contains(sKey);
+ assertThat(properties.getString(sKey, "default_value")).isEqualTo(sValue);
+ countDownLatch.countDown();
};
- testListener(countDownLatch, changeListener);
+ try {
+ DeviceConfig.addOnPropertiesChangedListener(sNamespace,
+ ActivityThread.currentApplication().getMainExecutor(), changeListener);
+ DeviceConfig.setProperty(sNamespace, sKey, sValue, false);
+ assertThat(countDownLatch.await(
+ WAIT_FOR_PROPERTY_CHANGE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)).isTrue();
+ } catch (InterruptedException e) {
+ Assert.fail(e.getMessage());
+ } finally {
+ DeviceConfig.removeOnPropertiesChangedListener(changeListener);
+ }
}
@Test
- public void testListener_legacyCallback() throws InterruptedException {
+ public void testOnPropertyChangedListener() throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(1);
OnPropertyChangedListener changeListener = (namespace, name, value) -> {
@@ -256,12 +259,6 @@
countDownLatch.countDown();
};
- testListener(countDownLatch, changeListener);
-
- }
-
- private void testListener(CountDownLatch countDownLatch,
- OnPropertyChangedListener changeListener) {
try {
DeviceConfig.addOnPropertyChangedListener(sNamespace,
ActivityThread.currentApplication().getMainExecutor(), changeListener);
@@ -273,6 +270,7 @@
} finally {
DeviceConfig.removeOnPropertyChangedListener(changeListener);
}
+
}
private static boolean deleteViaContentProvider(String namespace, String key) {
diff --git a/core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java b/core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java
index c99777b..0f32a82 100644
--- a/core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java
+++ b/core/tests/coretests/src/android/service/notification/StatusBarNotificationTest.java
@@ -89,6 +89,17 @@
assertNull(logMaker.getTaggedData(MetricsEvent.FIELD_NOTIFICATION_CATEGORY));
}
+ /** Verify that modifying the returned logMaker won't leave stale data behind for
+ * the next caller.*/
+ @Test
+ public void testLogMakerNoStaleData() {
+ StatusBarNotification sbn = getNotification(PKG, GROUP_ID_1, CHANNEL_ID);
+ final LogMaker logMaker = sbn.getLogMaker();
+ int extraTag = MetricsEvent.FIELD_NOTIFICATION_CHANNEL_GROUP_ID; // An arbitrary new tag
+ logMaker.addTaggedData(extraTag, 1);
+ assertNull(sbn.getLogMaker().getTaggedData(extraTag));
+ }
+
@Test
public void testLogMakerWithCategory() {
Notification.Builder builder = getNotificationBuilder(GROUP_ID_1, CHANNEL_ID)
diff --git a/graphics/java/android/graphics/Insets.java b/graphics/java/android/graphics/Insets.java
index c6dc239..1e03c53 100644
--- a/graphics/java/android/graphics/Insets.java
+++ b/graphics/java/android/graphics/Insets.java
@@ -30,7 +30,7 @@
*
*/
public final class Insets implements Parcelable {
- public static final Insets NONE = new Insets(0, 0, 0, 0);
+ public static final @NonNull Insets NONE = new Insets(0, 0, 0, 0);
public final int left;
public final int top;
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 793dd8d..4f1b2a4 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -69,6 +69,7 @@
"libminikin",
"libandroidfw",
"libcrypto",
+ "libsync",
],
static_libs: [
"libEGL_blobCache",
@@ -180,6 +181,7 @@
"renderthread/EglManager.cpp",
"renderthread/ReliableSurface.cpp",
"renderthread/VulkanManager.cpp",
+ "renderthread/VulkanSurface.cpp",
"renderthread/RenderProxy.cpp",
"renderthread/RenderTask.cpp",
"renderthread/RenderThread.cpp",
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index a15ff22..c174c24 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -19,8 +19,6 @@
#include "renderstate/RenderState.h"
#include "utils/Color.h"
-#include <SkToSRGBColorFilter.h>
-
namespace android {
namespace uirenderer {
diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp
index 2ffda83..fe633e9 100644
--- a/libs/hwui/Readback.cpp
+++ b/libs/hwui/Readback.cpp
@@ -20,7 +20,6 @@
#include "renderthread/EglManager.h"
#include "renderthread/VulkanManager.h"
-#include <SkToSRGBColorFilter.h>
#include <gui/Surface.h>
#include <ui/Fence.h>
#include <ui/GraphicBuffer.h>
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index 87cffb5..edde6d3 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -55,20 +55,8 @@
}
Frame SkiaVulkanPipeline::getFrame() {
- LOG_ALWAYS_FATAL_IF(mVkSurface == nullptr,
- "drawRenderNode called on a context with no surface!");
-
- SkSurface* backBuffer = mVkManager.getBackbufferSurface(&mVkSurface);
- LOG_ALWAYS_FATAL_IF(mVkSurface == nullptr,
- "drawRenderNode called on a context with an invalid surface");
- if (backBuffer == nullptr) {
- SkDebugf("failed to get backbuffer");
- return Frame(-1, -1, 0);
- }
-
- Frame frame(mVkSurface->windowWidth(), mVkSurface->windowHeight(),
- mVkManager.getAge(mVkSurface));
- return frame;
+ LOG_ALWAYS_FATAL_IF(mVkSurface == nullptr, "getFrame() called on a context with no surface!");
+ return mVkManager.dequeueNextBuffer(mVkSurface);
}
bool SkiaVulkanPipeline::draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
@@ -77,13 +65,13 @@
bool opaque, const LightInfo& lightInfo,
const std::vector<sp<RenderNode>>& renderNodes,
FrameInfoVisualizer* profiler) {
- sk_sp<SkSurface> backBuffer = mVkSurface->getBackBufferSurface();
+ sk_sp<SkSurface> backBuffer = mVkSurface->getCurrentSkSurface();
if (backBuffer.get() == nullptr) {
return false;
}
SkiaPipeline::updateLighting(lightGeometry, lightInfo);
renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds,
- backBuffer, mVkSurface->preTransform());
+ backBuffer, mVkSurface->getCurrentPreTransform());
ShaderCache::get().onVkFrameFlushed(mRenderThread.getGrContext());
layerUpdateQueue->clear();
@@ -113,7 +101,7 @@
currentFrameInfo->markSwapBuffers();
if (*requireSwap) {
- mVkManager.swapBuffers(mVkSurface);
+ mVkManager.swapBuffers(mVkSurface, screenDirty);
}
return *requireSwap;
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
index 2c24edd..77a7ab1 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
@@ -18,6 +18,7 @@
#include "SkiaPipeline.h"
#include "renderthread/VulkanManager.h"
+#include "renderthread/VulkanSurface.h"
#include "renderstate/RenderState.h"
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 5af660c..d4c6eae 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -16,6 +16,7 @@
#include "VulkanManager.h"
+#include <android/sync.h>
#include <gui/Surface.h>
#include "Properties.h"
@@ -23,6 +24,7 @@
#include "renderstate/RenderState.h"
#include "utils/FatVector.h"
+#include <GrBackendSemaphore.h>
#include <GrBackendSurface.h>
#include <GrContext.h>
#include <GrTypes.h>
@@ -142,6 +144,7 @@
GET_INST_PROC(GetPhysicalDeviceProperties);
GET_INST_PROC(GetPhysicalDeviceQueueFamilyProperties);
GET_INST_PROC(GetPhysicalDeviceFeatures2);
+ GET_INST_PROC(GetPhysicalDeviceImageFormatProperties2);
GET_INST_PROC(CreateDevice);
GET_INST_PROC(EnumerateDeviceExtensionProperties);
GET_INST_PROC(CreateAndroidSurfaceKHR);
@@ -318,11 +321,6 @@
GET_DEV_PROC(GetDeviceQueue);
GET_DEV_PROC(DeviceWaitIdle);
GET_DEV_PROC(DestroyDevice);
- GET_DEV_PROC(CreateSwapchainKHR);
- GET_DEV_PROC(DestroySwapchainKHR);
- GET_DEV_PROC(GetSwapchainImagesKHR);
- GET_DEV_PROC(AcquireNextImageKHR);
- GET_DEV_PROC(QueuePresentKHR);
GET_DEV_PROC(CreateCommandPool);
GET_DEV_PROC(DestroyCommandPool);
GET_DEV_PROC(AllocateCommandBuffers);
@@ -426,201 +424,102 @@
};
}
-// Returns the next BackbufferInfo to use for the next draw. The function will make sure all
-// previous uses have finished before returning.
-VulkanSurface::BackbufferInfo* VulkanManager::getAvailableBackbuffer(VulkanSurface* surface) {
- SkASSERT(surface->mBackbuffers);
+Frame VulkanManager::dequeueNextBuffer(VulkanSurface* surface) {
- ++surface->mCurrentBackbufferIndex;
- if (surface->mCurrentBackbufferIndex > surface->mImageCount) {
- surface->mCurrentBackbufferIndex = 0;
+ VulkanSurface::NativeBufferInfo* bufferInfo = surface->dequeueNativeBuffer();
+
+ if (bufferInfo == nullptr) {
+ ALOGE("VulkanSurface::dequeueNativeBuffer called with an invalid surface!");
+ return Frame(-1, -1, 0);
}
- VulkanSurface::BackbufferInfo* backbuffer =
- surface->mBackbuffers + surface->mCurrentBackbufferIndex;
+ LOG_ALWAYS_FATAL_IF(!bufferInfo->dequeued);
- // Before we reuse a backbuffer, make sure its fences have all signaled so that we can safely
- // reuse its commands buffers.
- VkResult res = mWaitForFences(mDevice, 2, backbuffer->mUsageFences, true, UINT64_MAX);
- if (res != VK_SUCCESS) {
- return nullptr;
+ if (bufferInfo->dequeue_fence != -1) {
+ int fence_clone = dup(bufferInfo->dequeue_fence);
+ if (fence_clone == -1) {
+ ALOGE("dup(fence) failed, stalling until signalled: %s (%d)", strerror(errno), errno);
+ sync_wait(bufferInfo->dequeue_fence, -1 /* forever */);
+ } else {
+ VkSemaphoreCreateInfo semaphoreInfo;
+ semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
+ semaphoreInfo.pNext = nullptr;
+ semaphoreInfo.flags = 0;
+ VkSemaphore semaphore;
+ VkResult err = mCreateSemaphore(mDevice, &semaphoreInfo, nullptr, &semaphore);
+ LOG_ALWAYS_FATAL_IF(VK_SUCCESS != err, "Failed to create import semaphore, err: %d",
+ err);
+
+ VkImportSemaphoreFdInfoKHR importInfo;
+ importInfo.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR;
+ importInfo.pNext = nullptr;
+ importInfo.semaphore = semaphore;
+ importInfo.flags = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT;
+ importInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
+ importInfo.fd = fence_clone;
+
+ err = mImportSemaphoreFdKHR(mDevice, &importInfo);
+ LOG_ALWAYS_FATAL_IF(VK_SUCCESS != err, "Failed to import semaphore, err: %d", err);
+
+ GrBackendSemaphore backendSemaphore;
+ backendSemaphore.initVulkan(semaphore);
+ bufferInfo->skSurface->wait(1, &backendSemaphore);
+ }
}
- return backbuffer;
+ int bufferAge = (mSwapBehavior == SwapBehavior::Discard) ? 0 : surface->getCurrentBuffersAge();
+ return Frame(surface->logicalWidth(), surface->logicalHeight(), bufferAge);
}
-static SkMatrix getPreTransformMatrix(int width, int height,
- VkSurfaceTransformFlagBitsKHR transform) {
- switch (transform) {
- case VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR:
- return SkMatrix::I();
- case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR:
- return SkMatrix::MakeAll(0, -1, height, 1, 0, 0, 0, 0, 1);
- case VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR:
- return SkMatrix::MakeAll(-1, 0, width, 0, -1, height, 0, 0, 1);
- case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR:
- return SkMatrix::MakeAll(0, 1, 0, -1, 0, width, 0, 0, 1);
- case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR:
- return SkMatrix::MakeAll(-1, 0, width, 0, 1, 0, 0, 0, 1);
- case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR:
- return SkMatrix::MakeAll(0, -1, height, -1, 0, width, 0, 0, 1);
- case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR:
- return SkMatrix::MakeAll(1, 0, 0, 0, -1, height, 0, 0, 1);
- case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR:
- return SkMatrix::MakeAll(0, 1, 0, 1, 0, 0, 0, 0, 1);
- default:
- LOG_ALWAYS_FATAL("Unsupported pre transform of swapchain.");
- }
- return SkMatrix::I();
-}
-
-
-SkSurface* VulkanManager::getBackbufferSurface(VulkanSurface** surfaceOut) {
- // Recreate VulkanSurface, if ANativeWindow has been resized.
- VulkanSurface* surface = *surfaceOut;
- int windowWidth = 0, windowHeight = 0;
- ANativeWindow* window = surface->mNativeWindow;
- window->query(window, NATIVE_WINDOW_WIDTH, &windowWidth);
- window->query(window, NATIVE_WINDOW_HEIGHT, &windowHeight);
- if (windowWidth != surface->mWindowWidth || windowHeight != surface->mWindowHeight) {
- ColorMode colorMode = surface->mColorMode;
- sk_sp<SkColorSpace> colorSpace = surface->mColorSpace;
- SkColorType colorType = surface->mColorType;
- GrContext* grContext = surface->mGrContext;
- destroySurface(surface);
- *surfaceOut = createSurface(window, colorMode, colorSpace, colorType, grContext);
- surface = *surfaceOut;
- if (!surface) {
- return nullptr;
- }
+void VulkanManager::swapBuffers(VulkanSurface* surface, const SkRect& dirtyRect) {
+ if (CC_UNLIKELY(Properties::waitForGpuCompletion)) {
+ ATRACE_NAME("Finishing GPU work");
+ mDeviceWaitIdle(mDevice);
}
- VulkanSurface::BackbufferInfo* backbuffer = getAvailableBackbuffer(surface);
- SkASSERT(backbuffer);
+ VkExportSemaphoreCreateInfo exportInfo;
+ exportInfo.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO;
+ exportInfo.pNext = nullptr;
+ exportInfo.handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
- VkResult res;
+ VkSemaphoreCreateInfo semaphoreInfo;
+ semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
+ semaphoreInfo.pNext = &exportInfo;
+ semaphoreInfo.flags = 0;
+ VkSemaphore semaphore;
+ VkResult err = mCreateSemaphore(mDevice, &semaphoreInfo, nullptr, &semaphore);
+ ALOGE_IF(VK_SUCCESS != err, "VulkanManager::swapBuffers(): Failed to create semaphore");
- res = mResetFences(mDevice, 2, backbuffer->mUsageFences);
- SkASSERT(VK_SUCCESS == res);
+ GrBackendSemaphore backendSemaphore;
+ backendSemaphore.initVulkan(semaphore);
- // The acquire will signal the attached mAcquireSemaphore. We use this to know the image has
- // finished presenting and that it is safe to begin sending new commands to the returned image.
- res = mAcquireNextImageKHR(mDevice, surface->mSwapchain, UINT64_MAX,
- backbuffer->mAcquireSemaphore, VK_NULL_HANDLE,
- &backbuffer->mImageIndex);
+ VulkanSurface::NativeBufferInfo* bufferInfo = surface->getCurrentBufferInfo();
- if (VK_ERROR_SURFACE_LOST_KHR == res) {
- // need to figure out how to create a new vkSurface without the platformData*
- // maybe use attach somehow? but need a Window
- return nullptr;
- }
- if (VK_ERROR_OUT_OF_DATE_KHR == res || VK_SUBOPTIMAL_KHR == res) {
- // tear swapchain down and try again
- if (!createSwapchain(surface)) {
- return nullptr;
- }
- backbuffer = getAvailableBackbuffer(surface);
- res = mResetFences(mDevice, 2, backbuffer->mUsageFences);
- SkASSERT(VK_SUCCESS == res);
+ int fenceFd = -1;
+ GrSemaphoresSubmitted submitted =
+ bufferInfo->skSurface->flush(SkSurface::BackendSurfaceAccess::kPresent,
+ SkSurface::kNone_FlushFlags, 1, &backendSemaphore);
+ if (submitted == GrSemaphoresSubmitted::kYes) {
+ VkSemaphoreGetFdInfoKHR getFdInfo;
+ getFdInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR;
+ getFdInfo.pNext = nullptr;
+ getFdInfo.semaphore = semaphore;
+ getFdInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
- // acquire the image
- res = mAcquireNextImageKHR(mDevice, surface->mSwapchain, UINT64_MAX,
- backbuffer->mAcquireSemaphore, VK_NULL_HANDLE,
- &backbuffer->mImageIndex);
-
- if (VK_SUCCESS != res) {
- return nullptr;
- }
+ err = mGetSemaphoreFdKHR(mDevice, &getFdInfo, &fenceFd);
+ ALOGE_IF(VK_SUCCESS != err, "VulkanManager::swapBuffers(): Failed to get semaphore Fd");
+ } else {
+ ALOGE("VulkanManager::swapBuffers(): Semaphore submission failed");
+ mQueueWaitIdle(mGraphicsQueue);
}
- // set up layout transfer from initial to color attachment
- VkImageLayout layout = surface->mImageInfos[backbuffer->mImageIndex].mImageLayout;
- SkASSERT(VK_IMAGE_LAYOUT_UNDEFINED == layout || VK_IMAGE_LAYOUT_PRESENT_SRC_KHR == layout);
- VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
- VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
- VkAccessFlags srcAccessMask = 0;
- VkAccessFlags dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
- VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+ surface->presentCurrentBuffer(dirtyRect, fenceFd);
- VkImageMemoryBarrier imageMemoryBarrier = {
- VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType
- NULL, // pNext
- srcAccessMask, // outputMask
- dstAccessMask, // inputMask
- layout, // oldLayout
- VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // newLayout
- mPresentQueueIndex, // srcQueueFamilyIndex
- mGraphicsQueueIndex, // dstQueueFamilyIndex
- surface->mImages[backbuffer->mImageIndex], // image
- {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1} // subresourceRange
- };
- mResetCommandBuffer(backbuffer->mTransitionCmdBuffers[0], 0);
-
- VkCommandBufferBeginInfo info;
- memset(&info, 0, sizeof(VkCommandBufferBeginInfo));
- info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
- info.flags = 0;
- mBeginCommandBuffer(backbuffer->mTransitionCmdBuffers[0], &info);
-
- mCmdPipelineBarrier(backbuffer->mTransitionCmdBuffers[0], srcStageMask, dstStageMask, 0, 0,
- nullptr, 0, nullptr, 1, &imageMemoryBarrier);
-
- mEndCommandBuffer(backbuffer->mTransitionCmdBuffers[0]);
-
- VkPipelineStageFlags waitDstStageFlags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
- // insert the layout transfer into the queue and wait on the acquire
- VkSubmitInfo submitInfo;
- memset(&submitInfo, 0, sizeof(VkSubmitInfo));
- submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
- submitInfo.waitSemaphoreCount = 1;
- // Wait to make sure aquire semaphore set above has signaled.
- submitInfo.pWaitSemaphores = &backbuffer->mAcquireSemaphore;
- submitInfo.pWaitDstStageMask = &waitDstStageFlags;
- submitInfo.commandBufferCount = 1;
- submitInfo.pCommandBuffers = &backbuffer->mTransitionCmdBuffers[0];
- submitInfo.signalSemaphoreCount = 0;
-
- // Attach first fence to submission here so we can track when the command buffer finishes.
- mQueueSubmit(mGraphicsQueue, 1, &submitInfo, backbuffer->mUsageFences[0]);
-
- // We need to notify Skia that we changed the layout of the wrapped VkImage
- sk_sp<SkSurface> skSurface = surface->mImageInfos[backbuffer->mImageIndex].mSurface;
- GrBackendRenderTarget backendRT = skSurface->getBackendRenderTarget(
- SkSurface::kFlushRead_BackendHandleAccess);
- if (!backendRT.isValid()) {
- SkASSERT(backendRT.isValid());
- return nullptr;
- }
- backendRT.setVkImageLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
-
- surface->mPreTransform = getPreTransformMatrix(surface->windowWidth(),
- surface->windowHeight(),
- surface->mTransform);
-
- surface->mBackbuffer = std::move(skSurface);
- return surface->mBackbuffer.get();
-}
-
-void VulkanManager::destroyBuffers(VulkanSurface* surface) {
- if (surface->mBackbuffers) {
- for (uint32_t i = 0; i < surface->mImageCount + 1; ++i) {
- mWaitForFences(mDevice, 2, surface->mBackbuffers[i].mUsageFences, true, UINT64_MAX);
- surface->mBackbuffers[i].mImageIndex = -1;
- mDestroySemaphore(mDevice, surface->mBackbuffers[i].mAcquireSemaphore, nullptr);
- mDestroySemaphore(mDevice, surface->mBackbuffers[i].mRenderSemaphore, nullptr);
- mFreeCommandBuffers(mDevice, mCommandPool, 2,
- surface->mBackbuffers[i].mTransitionCmdBuffers);
- mDestroyFence(mDevice, surface->mBackbuffers[i].mUsageFences[0], 0);
- mDestroyFence(mDevice, surface->mBackbuffers[i].mUsageFences[1], 0);
- }
- }
-
- delete[] surface->mBackbuffers;
- surface->mBackbuffers = nullptr;
- delete[] surface->mImageInfos;
- surface->mImageInfos = nullptr;
- delete[] surface->mImages;
- surface->mImages = nullptr;
+ // Exporting a semaphore with copy transference via vkGetSemaphoreFdKHR, has the same effect of
+ // destroying the semaphore and creating a new one with the same handle, and the payloads
+ // ownership is move to the Fd we created. Thus the semaphore is in a state that we can delete
+ // it and we don't need to wait on the command buffer we submitted to finish.
+ mDestroySemaphore(mDevice, semaphore, nullptr);
}
void VulkanManager::destroySurface(VulkanSurface* surface) {
@@ -630,271 +529,9 @@
}
mDeviceWaitIdle(mDevice);
- destroyBuffers(surface);
-
- if (VK_NULL_HANDLE != surface->mSwapchain) {
- mDestroySwapchainKHR(mDevice, surface->mSwapchain, nullptr);
- surface->mSwapchain = VK_NULL_HANDLE;
- }
-
- if (VK_NULL_HANDLE != surface->mVkSurface) {
- mDestroySurfaceKHR(mInstance, surface->mVkSurface, nullptr);
- surface->mVkSurface = VK_NULL_HANDLE;
- }
delete surface;
}
-void VulkanManager::createBuffers(VulkanSurface* surface, VkFormat format, VkExtent2D extent) {
- mGetSwapchainImagesKHR(mDevice, surface->mSwapchain, &surface->mImageCount, nullptr);
- SkASSERT(surface->mImageCount);
- surface->mImages = new VkImage[surface->mImageCount];
- mGetSwapchainImagesKHR(mDevice, surface->mSwapchain, &surface->mImageCount, surface->mImages);
-
- SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
-
- // set up initial image layouts and create surfaces
- surface->mImageInfos = new VulkanSurface::ImageInfo[surface->mImageCount];
- for (uint32_t i = 0; i < surface->mImageCount; ++i) {
- GrVkImageInfo info;
- info.fImage = surface->mImages[i];
- info.fAlloc = GrVkAlloc();
- info.fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
- info.fFormat = format;
- info.fLevelCount = 1;
-
- GrBackendRenderTarget backendRT(extent.width, extent.height, 0, 0, info);
-
- VulkanSurface::ImageInfo& imageInfo = surface->mImageInfos[i];
- imageInfo.mSurface = SkSurface::MakeFromBackendRenderTarget(
- surface->mGrContext, backendRT, kTopLeft_GrSurfaceOrigin,
- surface->mColorType, surface->mColorSpace, &props);
- }
-
- SkASSERT(mCommandPool != VK_NULL_HANDLE);
-
- // set up the backbuffers
- VkSemaphoreCreateInfo semaphoreInfo;
- memset(&semaphoreInfo, 0, sizeof(VkSemaphoreCreateInfo));
- semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
- semaphoreInfo.pNext = nullptr;
- semaphoreInfo.flags = 0;
- VkCommandBufferAllocateInfo commandBuffersInfo;
- memset(&commandBuffersInfo, 0, sizeof(VkCommandBufferAllocateInfo));
- commandBuffersInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
- commandBuffersInfo.pNext = nullptr;
- commandBuffersInfo.commandPool = mCommandPool;
- commandBuffersInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
- commandBuffersInfo.commandBufferCount = 2;
- VkFenceCreateInfo fenceInfo;
- memset(&fenceInfo, 0, sizeof(VkFenceCreateInfo));
- fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
- fenceInfo.pNext = nullptr;
- fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
-
- // we create one additional backbuffer structure here, because we want to
- // give the command buffers they contain a chance to finish before we cycle back
- surface->mBackbuffers = new VulkanSurface::BackbufferInfo[surface->mImageCount + 1];
- for (uint32_t i = 0; i < surface->mImageCount + 1; ++i) {
- SkDEBUGCODE(VkResult res);
- surface->mBackbuffers[i].mImageIndex = -1;
- SkDEBUGCODE(res =) mCreateSemaphore(mDevice, &semaphoreInfo, nullptr,
- &surface->mBackbuffers[i].mAcquireSemaphore);
- SkDEBUGCODE(res =) mCreateSemaphore(mDevice, &semaphoreInfo, nullptr,
- &surface->mBackbuffers[i].mRenderSemaphore);
- SkDEBUGCODE(res =) mAllocateCommandBuffers(mDevice, &commandBuffersInfo,
- surface->mBackbuffers[i].mTransitionCmdBuffers);
- SkDEBUGCODE(res =) mCreateFence(mDevice, &fenceInfo, nullptr,
- &surface->mBackbuffers[i].mUsageFences[0]);
- SkDEBUGCODE(res =) mCreateFence(mDevice, &fenceInfo, nullptr,
- &surface->mBackbuffers[i].mUsageFences[1]);
- SkASSERT(VK_SUCCESS == res);
- }
- surface->mCurrentBackbufferIndex = surface->mImageCount;
-}
-
-bool VulkanManager::createSwapchain(VulkanSurface* surface) {
- // check for capabilities
- VkSurfaceCapabilitiesKHR caps;
- VkResult res = mGetPhysicalDeviceSurfaceCapabilitiesKHR(mPhysicalDevice,
- surface->mVkSurface, &caps);
- if (VK_SUCCESS != res) {
- return false;
- }
-
- uint32_t surfaceFormatCount;
- res = mGetPhysicalDeviceSurfaceFormatsKHR(mPhysicalDevice, surface->mVkSurface,
- &surfaceFormatCount, nullptr);
- if (VK_SUCCESS != res) {
- return false;
- }
-
- FatVector<VkSurfaceFormatKHR, 4> surfaceFormats(surfaceFormatCount);
- res = mGetPhysicalDeviceSurfaceFormatsKHR(mPhysicalDevice, surface->mVkSurface,
- &surfaceFormatCount, surfaceFormats.data());
- if (VK_SUCCESS != res) {
- return false;
- }
-
- uint32_t presentModeCount;
- res = mGetPhysicalDeviceSurfacePresentModesKHR(mPhysicalDevice,
- surface->mVkSurface, &presentModeCount, nullptr);
- if (VK_SUCCESS != res) {
- return false;
- }
-
- FatVector<VkPresentModeKHR, VK_PRESENT_MODE_RANGE_SIZE_KHR> presentModes(presentModeCount);
- res = mGetPhysicalDeviceSurfacePresentModesKHR(mPhysicalDevice,
- surface->mVkSurface, &presentModeCount,
- presentModes.data());
- if (VK_SUCCESS != res) {
- return false;
- }
-
- if (!SkToBool(caps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)) {
- return false;
- }
- VkSurfaceTransformFlagBitsKHR transform;
- if (SkToBool(caps.supportedTransforms & caps.currentTransform) &&
- !SkToBool(caps.currentTransform & VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR)) {
- transform = caps.currentTransform;
- } else {
- transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
- }
-
- VkExtent2D extent = caps.currentExtent;
- // clamp width; to handle currentExtent of -1 and protect us from broken hints
- if (extent.width < caps.minImageExtent.width) {
- extent.width = caps.minImageExtent.width;
- }
- SkASSERT(extent.width <= caps.maxImageExtent.width);
- // clamp height
- if (extent.height < caps.minImageExtent.height) {
- extent.height = caps.minImageExtent.height;
- }
- SkASSERT(extent.height <= caps.maxImageExtent.height);
-
- VkExtent2D swapExtent = extent;
- if (transform == VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR ||
- transform == VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR ||
- transform == VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR ||
- transform == VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR) {
- swapExtent.width = extent.height;
- swapExtent.height = extent.width;
- }
-
- surface->mWindowWidth = extent.width;
- surface->mWindowHeight = extent.height;
-
- uint32_t imageCount = std::max<uint32_t>(3, caps.minImageCount);
- if (caps.maxImageCount > 0 && imageCount > caps.maxImageCount) {
- // Application must settle for fewer images than desired:
- imageCount = caps.maxImageCount;
- }
-
- // Currently Skia requires the images to be color attchments and support all transfer
- // operations.
- VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
- VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
- VK_IMAGE_USAGE_TRANSFER_DST_BIT;
- SkASSERT((caps.supportedUsageFlags & usageFlags) == usageFlags);
-
- SkASSERT(caps.supportedCompositeAlpha &
- (VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR | VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR));
- VkCompositeAlphaFlagBitsKHR composite_alpha =
- (caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)
- ? VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR
- : VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
-
- VkFormat surfaceFormat = VK_FORMAT_R8G8B8A8_UNORM;
- VkColorSpaceKHR colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
- if (surface->mColorType == SkColorType::kRGBA_F16_SkColorType) {
- surfaceFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
- }
-
- if (surface->mColorMode == ColorMode::WideColorGamut) {
- skcms_Matrix3x3 surfaceGamut;
- LOG_ALWAYS_FATAL_IF(!surface->mColorSpace->toXYZD50(&surfaceGamut),
- "Could not get gamut matrix from color space");
- if (memcmp(&surfaceGamut, &SkNamedGamut::kSRGB, sizeof(surfaceGamut)) == 0) {
- colorSpace = VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT;
- } else if (memcmp(&surfaceGamut, &SkNamedGamut::kDCIP3, sizeof(surfaceGamut)) == 0) {
- colorSpace = VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT;
- } else {
- LOG_ALWAYS_FATAL("Unreachable: unsupported wide color space.");
- }
- }
-
- bool foundSurfaceFormat = false;
- for (uint32_t i = 0; i < surfaceFormatCount; ++i) {
- if (surfaceFormat == surfaceFormats[i].format
- && colorSpace == surfaceFormats[i].colorSpace) {
- foundSurfaceFormat = true;
- break;
- }
- }
-
- if (!foundSurfaceFormat) {
- return false;
- }
-
- // FIFO is always available and will match what we do on GL so just pick that here.
- VkPresentModeKHR mode = VK_PRESENT_MODE_FIFO_KHR;
-
- VkSwapchainCreateInfoKHR swapchainCreateInfo;
- memset(&swapchainCreateInfo, 0, sizeof(VkSwapchainCreateInfoKHR));
- swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
- swapchainCreateInfo.surface = surface->mVkSurface;
- swapchainCreateInfo.minImageCount = imageCount;
- swapchainCreateInfo.imageFormat = surfaceFormat;
- swapchainCreateInfo.imageColorSpace = colorSpace;
- swapchainCreateInfo.imageExtent = swapExtent;
- swapchainCreateInfo.imageArrayLayers = 1;
- swapchainCreateInfo.imageUsage = usageFlags;
-
- uint32_t queueFamilies[] = {mGraphicsQueueIndex, mPresentQueueIndex};
- if (mGraphicsQueueIndex != mPresentQueueIndex) {
- swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
- swapchainCreateInfo.queueFamilyIndexCount = 2;
- swapchainCreateInfo.pQueueFamilyIndices = queueFamilies;
- } else {
- swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
- swapchainCreateInfo.queueFamilyIndexCount = 0;
- swapchainCreateInfo.pQueueFamilyIndices = nullptr;
- }
-
- swapchainCreateInfo.preTransform = transform;
- swapchainCreateInfo.compositeAlpha = composite_alpha;
- swapchainCreateInfo.presentMode = mode;
- swapchainCreateInfo.clipped = true;
- swapchainCreateInfo.oldSwapchain = surface->mSwapchain;
-
- res = mCreateSwapchainKHR(mDevice, &swapchainCreateInfo, nullptr, &surface->mSwapchain);
- if (VK_SUCCESS != res) {
- return false;
- }
-
- surface->mTransform = transform;
-
- // destroy the old swapchain
- if (swapchainCreateInfo.oldSwapchain != VK_NULL_HANDLE) {
- mDeviceWaitIdle(mDevice);
-
- destroyBuffers(surface);
-
- mDestroySwapchainKHR(mDevice, swapchainCreateInfo.oldSwapchain, nullptr);
- }
-
- createBuffers(surface, surfaceFormat, swapExtent);
-
- // The window content is not updated (frozen) until a buffer of the window size is received.
- // This prevents temporary stretching of the window after it is resized, but before the first
- // buffer with new size is enqueued.
- native_window_set_scaling_mode(surface->mNativeWindow, NATIVE_WINDOW_SCALING_MODE_FREEZE);
-
- return true;
-}
-
VulkanSurface* VulkanManager::createSurface(ANativeWindow* window, ColorMode colorMode,
sk_sp<SkColorSpace> surfaceColorSpace,
SkColorType surfaceColorType,
@@ -904,185 +541,8 @@
return nullptr;
}
- VulkanSurface* surface = new VulkanSurface(colorMode, window, surfaceColorSpace,
- surfaceColorType, grContext);
-
- VkAndroidSurfaceCreateInfoKHR surfaceCreateInfo;
- memset(&surfaceCreateInfo, 0, sizeof(VkAndroidSurfaceCreateInfoKHR));
- surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
- surfaceCreateInfo.pNext = nullptr;
- surfaceCreateInfo.flags = 0;
- surfaceCreateInfo.window = window;
-
- VkResult res = mCreateAndroidSurfaceKHR(mInstance, &surfaceCreateInfo, nullptr,
- &surface->mVkSurface);
- if (VK_SUCCESS != res) {
- delete surface;
- return nullptr;
- }
-
- SkDEBUGCODE(VkBool32 supported; res = mGetPhysicalDeviceSurfaceSupportKHR(
- mPhysicalDevice, mPresentQueueIndex, surface->mVkSurface, &supported);
- // All physical devices and queue families on Android must be capable of
- // presentation with any native window.
- SkASSERT(VK_SUCCESS == res && supported););
-
- if (!createSwapchain(surface)) {
- destroySurface(surface);
- return nullptr;
- }
-
- return surface;
-}
-
-// Helper to know which src stage flags we need to set when transitioning to the present layout
-static VkPipelineStageFlags layoutToPipelineSrcStageFlags(const VkImageLayout layout) {
- if (VK_IMAGE_LAYOUT_GENERAL == layout) {
- return VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
- } else if (VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == layout ||
- VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL == layout) {
- return VK_PIPELINE_STAGE_TRANSFER_BIT;
- } else if (VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL == layout) {
- return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
- } else if (VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL == layout ||
- VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL == layout) {
- return VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
- } else if (VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == layout) {
- return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
- } else if (VK_IMAGE_LAYOUT_PREINITIALIZED == layout) {
- return VK_PIPELINE_STAGE_HOST_BIT;
- }
-
- SkASSERT(VK_IMAGE_LAYOUT_UNDEFINED == layout);
- return VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
-}
-
-// Helper to know which src access mask we need to set when transitioning to the present layout
-static VkAccessFlags layoutToSrcAccessMask(const VkImageLayout layout) {
- VkAccessFlags flags = 0;
- if (VK_IMAGE_LAYOUT_GENERAL == layout) {
- flags = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
- VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT |
- VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_HOST_WRITE_BIT |
- VK_ACCESS_HOST_READ_BIT;
- } else if (VK_IMAGE_LAYOUT_PREINITIALIZED == layout) {
- flags = VK_ACCESS_HOST_WRITE_BIT;
- } else if (VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL == layout) {
- flags = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
- } else if (VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL == layout) {
- flags = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
- } else if (VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL == layout) {
- flags = VK_ACCESS_TRANSFER_WRITE_BIT;
- } else if (VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == layout) {
- flags = VK_ACCESS_TRANSFER_READ_BIT;
- } else if (VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == layout) {
- flags = VK_ACCESS_SHADER_READ_BIT;
- }
- return flags;
-}
-
-void VulkanManager::swapBuffers(VulkanSurface* surface) {
- if (CC_UNLIKELY(Properties::waitForGpuCompletion)) {
- ATRACE_NAME("Finishing GPU work");
- mDeviceWaitIdle(mDevice);
- }
-
- SkASSERT(surface->mBackbuffers);
- VulkanSurface::BackbufferInfo* backbuffer =
- surface->mBackbuffers + surface->mCurrentBackbufferIndex;
-
- SkSurface* skSurface = surface->mImageInfos[backbuffer->mImageIndex].mSurface.get();
- GrBackendRenderTarget backendRT = skSurface->getBackendRenderTarget(
- SkSurface::kFlushRead_BackendHandleAccess);
- SkASSERT(backendRT.isValid());
-
- GrVkImageInfo imageInfo;
- SkAssertResult(backendRT.getVkImageInfo(&imageInfo));
-
- // Check to make sure we never change the actually wrapped image
- SkASSERT(imageInfo.fImage == surface->mImages[backbuffer->mImageIndex]);
-
- // We need to transition the image to VK_IMAGE_LAYOUT_PRESENT_SRC_KHR and make sure that all
- // previous work is complete for before presenting. So we first add the necessary barrier here.
- VkImageLayout layout = imageInfo.fImageLayout;
- VkPipelineStageFlags srcStageMask = layoutToPipelineSrcStageFlags(layout);
- VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
- VkAccessFlags srcAccessMask = layoutToSrcAccessMask(layout);
- VkAccessFlags dstAccessMask = 0;
-
- VkImageMemoryBarrier imageMemoryBarrier = {
- VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType
- NULL, // pNext
- srcAccessMask, // outputMask
- dstAccessMask, // inputMask
- layout, // oldLayout
- VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, // newLayout
- mGraphicsQueueIndex, // srcQueueFamilyIndex
- mPresentQueueIndex, // dstQueueFamilyIndex
- surface->mImages[backbuffer->mImageIndex], // image
- {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1} // subresourceRange
- };
-
- mResetCommandBuffer(backbuffer->mTransitionCmdBuffers[1], 0);
- VkCommandBufferBeginInfo info;
- memset(&info, 0, sizeof(VkCommandBufferBeginInfo));
- info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
- info.flags = 0;
- mBeginCommandBuffer(backbuffer->mTransitionCmdBuffers[1], &info);
- mCmdPipelineBarrier(backbuffer->mTransitionCmdBuffers[1], srcStageMask, dstStageMask, 0, 0,
- nullptr, 0, nullptr, 1, &imageMemoryBarrier);
- mEndCommandBuffer(backbuffer->mTransitionCmdBuffers[1]);
-
- surface->mImageInfos[backbuffer->mImageIndex].mImageLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
-
- // insert the layout transfer into the queue and wait on the acquire
- VkSubmitInfo submitInfo;
- memset(&submitInfo, 0, sizeof(VkSubmitInfo));
- submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
- submitInfo.waitSemaphoreCount = 0;
- submitInfo.pWaitDstStageMask = 0;
- submitInfo.commandBufferCount = 1;
- submitInfo.pCommandBuffers = &backbuffer->mTransitionCmdBuffers[1];
- submitInfo.signalSemaphoreCount = 1;
- // When this command buffer finishes we will signal this semaphore so that we know it is now
- // safe to present the image to the screen.
- submitInfo.pSignalSemaphores = &backbuffer->mRenderSemaphore;
-
- // Attach second fence to submission here so we can track when the command buffer finishes.
- mQueueSubmit(mGraphicsQueue, 1, &submitInfo, backbuffer->mUsageFences[1]);
-
- // Submit present operation to present queue. We use a semaphore here to make sure all rendering
- // to the image is complete and that the layout has been change to present on the graphics
- // queue.
- const VkPresentInfoKHR presentInfo = {
- VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, // sType
- NULL, // pNext
- 1, // waitSemaphoreCount
- &backbuffer->mRenderSemaphore, // pWaitSemaphores
- 1, // swapchainCount
- &surface->mSwapchain, // pSwapchains
- &backbuffer->mImageIndex, // pImageIndices
- NULL // pResults
- };
-
- mQueuePresentKHR(mPresentQueue, &presentInfo);
-
- surface->mBackbuffer.reset();
- surface->mImageInfos[backbuffer->mImageIndex].mLastUsed = surface->mCurrentTime;
- surface->mImageInfos[backbuffer->mImageIndex].mInvalid = false;
- surface->mCurrentTime++;
-}
-
-int VulkanManager::getAge(VulkanSurface* surface) {
- SkASSERT(surface->mBackbuffers);
- VulkanSurface::BackbufferInfo* backbuffer =
- surface->mBackbuffers + surface->mCurrentBackbufferIndex;
- if (mSwapBehavior == SwapBehavior::Discard ||
- surface->mImageInfos[backbuffer->mImageIndex].mInvalid) {
- return 0;
- }
- uint16_t lastUsed = surface->mImageInfos[backbuffer->mImageIndex].mLastUsed;
- return surface->mCurrentTime - lastUsed;
+ return VulkanSurface::Create(window, colorMode, surfaceColorType, surfaceColorSpace, grContext,
+ *this);
}
bool VulkanManager::setupDummyCommandBuffer() {
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index 95c9630..c3d2891 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -28,7 +28,9 @@
#include <ui/Fence.h>
#include <utils/StrongPointer.h>
#include <vk/GrVkBackendContext.h>
+#include "Frame.h"
#include "IRenderPipeline.h"
+#include "VulkanSurface.h"
class GrVkExtensions;
@@ -38,66 +40,6 @@
class RenderThread;
-class VulkanSurface {
-public:
- VulkanSurface(ColorMode colorMode, ANativeWindow* window, sk_sp<SkColorSpace> colorSpace,
- SkColorType colorType, GrContext* grContext)
- : mColorMode(colorMode), mNativeWindow(window), mColorSpace(colorSpace),
- mColorType(colorType), mGrContext(grContext) {}
-
- sk_sp<SkSurface> getBackBufferSurface() { return mBackbuffer; }
-
- // The width and height are are the logical width and height for when submitting draws to the
- // surface. In reality if the window is rotated the underlying VkImage may have the width and
- // height swapped.
- int windowWidth() const { return mWindowWidth; }
- int windowHeight() const { return mWindowHeight; }
-
- SkMatrix& preTransform() { return mPreTransform; }
-
-private:
- friend class VulkanManager;
- struct BackbufferInfo {
- uint32_t mImageIndex; // image this is associated with
- VkSemaphore mAcquireSemaphore; // we signal on this for acquisition of image
- VkSemaphore mRenderSemaphore; // we wait on this for rendering to be done
- VkCommandBuffer
- mTransitionCmdBuffers[2]; // to transition layout between present and render
- // We use these fences to make sure the above Command buffers have finished their work
- // before attempting to reuse them or destroy them.
- VkFence mUsageFences[2];
- };
-
- struct ImageInfo {
- VkImageLayout mImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- sk_sp<SkSurface> mSurface;
- uint16_t mLastUsed = 0;
- bool mInvalid = true;
- };
-
- sk_sp<SkSurface> mBackbuffer;
-
- VkSurfaceKHR mVkSurface = VK_NULL_HANDLE;
- VkSwapchainKHR mSwapchain = VK_NULL_HANDLE;
-
- BackbufferInfo* mBackbuffers = nullptr;
- uint32_t mCurrentBackbufferIndex;
-
- uint32_t mImageCount;
- VkImage* mImages = nullptr;
- ImageInfo* mImageInfos;
- uint16_t mCurrentTime = 0;
- ColorMode mColorMode;
- ANativeWindow* mNativeWindow;
- int mWindowWidth = 0;
- int mWindowHeight = 0;
- sk_sp<SkColorSpace> mColorSpace;
- SkColorType mColorType;
- VkSurfaceTransformFlagBitsKHR mTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
- SkMatrix mPreTransform;
- GrContext* mGrContext;
-};
-
// This class contains the shared global Vulkan objects, such as VkInstance, VkDevice and VkQueue,
// which are re-used by CanvasContext. This class is created once and should be used by all vulkan
// windowing contexts. The VulkanManager must be initialized before use.
@@ -114,33 +56,19 @@
// Quick check to see if the VulkanManager has been initialized.
bool hasVkContext() { return mDevice != VK_NULL_HANDLE; }
- // Given a window this creates a new VkSurfaceKHR and VkSwapchain and stores them inside a new
- // VulkanSurface object which is returned.
+ // Create and destroy functions for wrapping an ANativeWindow in a VulkanSurface
VulkanSurface* createSurface(ANativeWindow* window, ColorMode colorMode,
sk_sp<SkColorSpace> surfaceColorSpace,
SkColorType surfaceColorType,
GrContext* grContext);
-
- // Destroy the VulkanSurface and all associated vulkan objects.
void destroySurface(VulkanSurface* surface);
+ Frame dequeueNextBuffer(VulkanSurface* surface);
+ void swapBuffers(VulkanSurface* surface, const SkRect& dirtyRect);
+
// Cleans up all the global state in the VulkanManger.
void destroy();
- // No work is needed to make a VulkanSurface current, and all functions require that a
- // VulkanSurface is passed into them so we just return true here.
- bool isCurrent(VulkanSurface* surface) { return true; }
-
- int getAge(VulkanSurface* surface);
-
- // Returns an SkSurface which wraps the next image returned from vkAcquireNextImageKHR. It also
- // will transition the VkImage from a present layout to color attachment so that it can be used
- // by the client for drawing.
- SkSurface* getBackbufferSurface(VulkanSurface** surface);
-
- // Presents the current VkImage.
- void swapBuffers(VulkanSurface* surface);
-
// Inserts a wait on fence command into the Vulkan command buffer.
status_t fenceWait(sp<Fence>& fence);
@@ -153,17 +81,10 @@
sk_sp<GrContext> createContext(const GrContextOptions& options);
private:
+ friend class VulkanSurface;
// Sets up the VkInstance and VkDevice objects. Also fills out the passed in
// VkPhysicalDeviceFeatures struct.
void setupDevice(GrVkExtensions&, VkPhysicalDeviceFeatures2&);
-
- void destroyBuffers(VulkanSurface* surface);
-
- bool createSwapchain(VulkanSurface* surface);
- void createBuffers(VulkanSurface* surface, VkFormat format, VkExtent2D extent);
-
- VulkanSurface::BackbufferInfo* getAvailableBackbuffer(VulkanSurface* surface);
-
bool setupDummyCommandBuffer();
// simple wrapper class that exists only to initialize a pointer to NULL
@@ -190,13 +111,6 @@
VkPtr<PFN_vkGetPhysicalDeviceSurfaceFormatsKHR> mGetPhysicalDeviceSurfaceFormatsKHR;
VkPtr<PFN_vkGetPhysicalDeviceSurfacePresentModesKHR> mGetPhysicalDeviceSurfacePresentModesKHR;
- VkPtr<PFN_vkCreateSwapchainKHR> mCreateSwapchainKHR;
- VkPtr<PFN_vkDestroySwapchainKHR> mDestroySwapchainKHR;
- VkPtr<PFN_vkGetSwapchainImagesKHR> mGetSwapchainImagesKHR;
- VkPtr<PFN_vkAcquireNextImageKHR> mAcquireNextImageKHR;
- VkPtr<PFN_vkQueuePresentKHR> mQueuePresentKHR;
- VkPtr<PFN_vkCreateSharedSwapchainsKHR> mCreateSharedSwapchainsKHR;
-
// Instance Functions
VkPtr<PFN_vkEnumerateInstanceVersion> mEnumerateInstanceVersion;
VkPtr<PFN_vkEnumerateInstanceExtensionProperties> mEnumerateInstanceExtensionProperties;
@@ -207,6 +121,7 @@
VkPtr<PFN_vkGetPhysicalDeviceProperties> mGetPhysicalDeviceProperties;
VkPtr<PFN_vkGetPhysicalDeviceQueueFamilyProperties> mGetPhysicalDeviceQueueFamilyProperties;
VkPtr<PFN_vkGetPhysicalDeviceFeatures2> mGetPhysicalDeviceFeatures2;
+ VkPtr<PFN_vkGetPhysicalDeviceImageFormatProperties2> mGetPhysicalDeviceImageFormatProperties2;
VkPtr<PFN_vkCreateDevice> mCreateDevice;
VkPtr<PFN_vkEnumerateDeviceExtensionProperties> mEnumerateDeviceExtensionProperties;
diff --git a/libs/hwui/renderthread/VulkanSurface.cpp b/libs/hwui/renderthread/VulkanSurface.cpp
new file mode 100644
index 0000000..c03c3a8
--- /dev/null
+++ b/libs/hwui/renderthread/VulkanSurface.cpp
@@ -0,0 +1,536 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#include "VulkanSurface.h"
+
+#include <algorithm>
+#include <SkSurface.h>
+
+#include "VulkanManager.h"
+#include "utils/TraceUtils.h"
+#include "utils/Color.h"
+
+namespace android {
+namespace uirenderer {
+namespace renderthread {
+
+static bool IsTransformSupported(int transform) {
+ // For now, only support pure rotations, not flip or flip-and-rotate, until we have
+ // more time to test them and build sample code. As far as I know we never actually
+ // use anything besides pure rotations anyway.
+ return transform == 0
+ || transform == NATIVE_WINDOW_TRANSFORM_ROT_90
+ || transform == NATIVE_WINDOW_TRANSFORM_ROT_180
+ || transform == NATIVE_WINDOW_TRANSFORM_ROT_270;
+}
+
+static int InvertTransform(int transform) {
+ switch (transform) {
+ case NATIVE_WINDOW_TRANSFORM_ROT_90:
+ return NATIVE_WINDOW_TRANSFORM_ROT_270;
+ case NATIVE_WINDOW_TRANSFORM_ROT_180:
+ return NATIVE_WINDOW_TRANSFORM_ROT_180;
+ case NATIVE_WINDOW_TRANSFORM_ROT_270:
+ return NATIVE_WINDOW_TRANSFORM_ROT_90;
+ default:
+ return 0;
+ }
+}
+
+static int ConvertVkTransformToNative(VkSurfaceTransformFlagsKHR transform) {
+ switch (transform) {
+ case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR:
+ return NATIVE_WINDOW_TRANSFORM_ROT_270;
+ case VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR:
+ return NATIVE_WINDOW_TRANSFORM_ROT_180;
+ case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR:
+ return NATIVE_WINDOW_TRANSFORM_ROT_90;
+ case VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR:
+ case VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR:
+ default:
+ return 0;
+ }
+}
+
+static SkMatrix GetPreTransformMatrix(SkISize windowSize, int transform) {
+ const int width = windowSize.width();
+ const int height = windowSize.height();
+
+ switch (transform) {
+ case 0:
+ return SkMatrix::I();
+ case NATIVE_WINDOW_TRANSFORM_ROT_90:
+ return SkMatrix::MakeAll(0, -1, height, 1, 0, 0, 0, 0, 1);
+ case NATIVE_WINDOW_TRANSFORM_ROT_180:
+ return SkMatrix::MakeAll(-1, 0, width, 0, -1, height, 0, 0, 1);
+ case NATIVE_WINDOW_TRANSFORM_ROT_270:
+ return SkMatrix::MakeAll(0, 1, 0, -1, 0, width, 0, 0, 1);
+ default:
+ LOG_ALWAYS_FATAL("Unsupported Window Transform (%d)", transform);
+ }
+ return SkMatrix::I();
+}
+
+void VulkanSurface::ComputeWindowSizeAndTransform(WindowInfo* windowInfo, const SkISize& minSize,
+ const SkISize& maxSize) {
+ SkISize& windowSize = windowInfo->size;
+
+ // clamp width & height to handle currentExtent of -1 and protect us from broken hints
+ if (windowSize.width() < minSize.width() || windowSize.width() > maxSize.width()
+ || windowSize.height() < minSize.height() || windowSize.height() > maxSize.height()) {
+ int width = std::min(maxSize.width(), std::max(minSize.width(), windowSize.width()));
+ int height = std::min(maxSize.height(), std::max(minSize.height(), windowSize.height()));
+ ALOGE("Invalid Window Dimensions [%d, %d]; clamping to [%d, %d]",
+ windowSize.width(), windowSize.height(), width, height);
+ windowSize.set(width, height);
+ }
+
+ windowInfo->actualSize = windowSize;
+ if (windowInfo->transform & HAL_TRANSFORM_ROT_90) {
+ windowInfo->actualSize.set(windowSize.height(), windowSize.width());
+ }
+
+ windowInfo->preTransform = GetPreTransformMatrix(windowInfo->size, windowInfo->transform);
+}
+
+static bool ResetNativeWindow(ANativeWindow* window) {
+ // -- Reset the native window --
+ // The native window might have been used previously, and had its properties
+ // changed from defaults. That will affect the answer we get for queries
+ // like MIN_UNDEQUEUED_BUFFERS. Reset to a known/default state before we
+ // attempt such queries.
+
+ int err = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
+ if (err != 0) {
+ ALOGW("native_window_api_connect failed: %s (%d)", strerror(-err), err);
+ return false;
+ }
+
+ // this will match what we do on GL so pick that here.
+ err = window->setSwapInterval(window, 1);
+ if (err != 0) {
+ ALOGW("native_window->setSwapInterval(1) failed: %s (%d)", strerror(-err), err);
+ return false;
+ }
+
+ err = native_window_set_shared_buffer_mode(window, false);
+ if (err != 0) {
+ ALOGW("native_window_set_shared_buffer_mode(false) failed: %s (%d)", strerror(-err), err);
+ return false;
+ }
+
+ err = native_window_set_auto_refresh(window, false);
+ if (err != 0) {
+ ALOGW("native_window_set_auto_refresh(false) failed: %s (%d)", strerror(-err), err);
+ return false;
+ }
+
+ return true;
+}
+
+class VkSurfaceAutoDeleter {
+public:
+ VkSurfaceAutoDeleter(VkInstance instance, VkSurfaceKHR surface,
+ PFN_vkDestroySurfaceKHR destroySurfaceKHR)
+ : mInstance(instance)
+ , mSurface(surface)
+ , mDestroySurfaceKHR(destroySurfaceKHR) {}
+ ~VkSurfaceAutoDeleter() {
+ destroy();
+ }
+
+ void destroy() {
+ if (mSurface != VK_NULL_HANDLE) {
+ mDestroySurfaceKHR(mInstance, mSurface, nullptr);
+ mSurface = VK_NULL_HANDLE;
+ }
+ }
+
+private:
+ VkInstance mInstance;
+ VkSurfaceKHR mSurface;
+ PFN_vkDestroySurfaceKHR mDestroySurfaceKHR;
+};
+
+VulkanSurface* VulkanSurface::Create(ANativeWindow* window, ColorMode colorMode,
+ SkColorType colorType, sk_sp<SkColorSpace> colorSpace,
+ GrContext* grContext, const VulkanManager& vkManager) {
+
+ VkAndroidSurfaceCreateInfoKHR surfaceCreateInfo;
+ memset(&surfaceCreateInfo, 0, sizeof(VkAndroidSurfaceCreateInfoKHR));
+ surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
+ surfaceCreateInfo.pNext = nullptr;
+ surfaceCreateInfo.flags = 0;
+ surfaceCreateInfo.window = window;
+
+ VkSurfaceKHR vkSurface = VK_NULL_HANDLE;
+ VkResult res = vkManager.mCreateAndroidSurfaceKHR(vkManager.mInstance, &surfaceCreateInfo,
+ nullptr, &vkSurface);
+ if (VK_SUCCESS != res) {
+ ALOGE("VulkanSurface::Create() vkCreateAndroidSurfaceKHR failed (%d)", res);
+ return nullptr;
+ }
+
+ VkSurfaceAutoDeleter vkSurfaceDeleter(vkManager.mInstance, vkSurface,
+ vkManager.mDestroySurfaceKHR);
+
+ SkDEBUGCODE(VkBool32 supported; res = vkManager.mGetPhysicalDeviceSurfaceSupportKHR(
+ vkManager.mPhysicalDevice, vkManager.mPresentQueueIndex, vkSurface, &supported);
+ // All physical devices and queue families on Android must be capable of
+ // presentation with any native window.
+ SkASSERT(VK_SUCCESS == res && supported););
+
+ // check for capabilities
+ VkSurfaceCapabilitiesKHR caps;
+ res = vkManager.mGetPhysicalDeviceSurfaceCapabilitiesKHR(vkManager.mPhysicalDevice, vkSurface,
+ &caps);
+ if (VK_SUCCESS != res) {
+ ALOGE("VulkanSurface::Create() vkGetPhysicalDeviceSurfaceCapabilitiesKHR failed (%d)", res);
+ return nullptr;
+ }
+
+ LOG_ALWAYS_FATAL_IF(0 == (caps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR));
+
+ /*
+ * We must destroy the VK Surface before attempting to update the window as doing so after
+ * will cause the native window to be modified in unexpected ways.
+ */
+ vkSurfaceDeleter.destroy();
+
+ /*
+ * Populate Window Info struct
+ */
+ WindowInfo windowInfo;
+
+ windowInfo.transform = ConvertVkTransformToNative(caps.supportedTransforms);
+ windowInfo.size = SkISize::Make(caps.currentExtent.width, caps.currentExtent.height);
+
+ const SkISize minSize = SkISize::Make(caps.minImageExtent.width, caps.minImageExtent.height);
+ const SkISize maxSize = SkISize::Make(caps.maxImageExtent.width, caps.maxImageExtent.height);
+ ComputeWindowSizeAndTransform(&windowInfo, minSize, maxSize);
+
+ windowInfo.bufferCount = std::max<uint32_t>(VulkanSurface::sMaxBufferCount, caps.minImageCount);
+ if (caps.maxImageCount > 0 && windowInfo.bufferCount > caps.maxImageCount) {
+ // Application must settle for fewer images than desired:
+ windowInfo.bufferCount = caps.maxImageCount;
+ }
+
+ // Currently Skia requires the images to be color attachments and support all transfer
+ // operations.
+ VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
+ VK_IMAGE_USAGE_SAMPLED_BIT |
+ VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
+ VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+ LOG_ALWAYS_FATAL_IF((caps.supportedUsageFlags & usageFlags) != usageFlags);
+
+ windowInfo.dataspace = HAL_DATASPACE_V0_SRGB;
+ if (colorMode == ColorMode::WideColorGamut) {
+ skcms_Matrix3x3 surfaceGamut;
+ LOG_ALWAYS_FATAL_IF(!colorSpace->toXYZD50(&surfaceGamut),
+ "Could not get gamut matrix from color space");
+ if (memcmp(&surfaceGamut, &SkNamedGamut::kSRGB, sizeof(surfaceGamut)) == 0) {
+ windowInfo.dataspace = HAL_DATASPACE_V0_SCRGB;
+ } else if (memcmp(&surfaceGamut, &SkNamedGamut::kDCIP3, sizeof(surfaceGamut)) == 0) {
+ windowInfo.dataspace = HAL_DATASPACE_DISPLAY_P3;
+ } else {
+ LOG_ALWAYS_FATAL("Unreachable: unsupported wide color space.");
+ }
+ }
+
+ windowInfo.pixelFormat = ColorTypeToPixelFormat(colorType);
+ VkFormat vkPixelFormat = VK_FORMAT_R8G8B8A8_UNORM;
+ if (windowInfo.pixelFormat == PIXEL_FORMAT_RGBA_FP16) {
+ vkPixelFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
+ }
+
+ uint64_t producerUsage =
+ AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER | AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
+ uint64_t consumerUsage;
+ native_window_get_consumer_usage(window, &consumerUsage);
+ windowInfo.windowUsageFlags = consumerUsage | producerUsage;
+
+ /*
+ * Now we attempt to modify the window!
+ */
+ if (!UpdateWindow(window, windowInfo)) {
+ return nullptr;
+ }
+
+ return new VulkanSurface(window, windowInfo, minSize, maxSize, grContext);
+}
+
+bool VulkanSurface::UpdateWindow(ANativeWindow* window, const WindowInfo& windowInfo) {
+ ATRACE_CALL();
+
+ if (!ResetNativeWindow(window)) {
+ return false;
+ }
+
+ // -- Configure the native window --
+ int err = native_window_set_buffers_format(window, windowInfo.pixelFormat);
+ if (err != 0) {
+ ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_format(%d) failed: %s (%d)",
+ windowInfo.pixelFormat, strerror(-err), err);
+ return false;
+ }
+
+ err = native_window_set_buffers_data_space(window, windowInfo.dataspace);
+ if (err != 0) {
+ ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_data_space(%d) "
+ "failed: %s (%d)", windowInfo.dataspace, strerror(-err), err);
+ return false;
+ }
+
+ const SkISize& size = windowInfo.actualSize;
+ err = native_window_set_buffers_dimensions(window, size.width(), size.height());
+ if (err != 0) {
+ ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_dimensions(%d,%d) "
+ "failed: %s (%d)", size.width(), size.height(), strerror(-err), err);
+ return false;
+ }
+
+ // native_window_set_buffers_transform() expects the transform the app is requesting that
+ // the compositor perform during composition. With native windows, pre-transform works by
+ // rendering with the same transform the compositor is applying (as in Vulkan), but
+ // then requesting the inverse transform, so that when the compositor does
+ // it's job the two transforms cancel each other out and the compositor ends
+ // up applying an identity transform to the app's buffer.
+ err = native_window_set_buffers_transform(window, InvertTransform(windowInfo.transform));
+ if (err != 0) {
+ ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_transform(%d) "
+ "failed: %s (%d)", windowInfo.transform, strerror(-err), err);
+ return false;
+ }
+
+ // Vulkan defaults to NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW, but this is different than
+ // HWUI's expectation
+ err = native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_FREEZE);
+ if (err != 0) {
+ ALOGE("VulkanSurface::UpdateWindow() native_window_set_scaling_mode(SCALE_TO_WINDOW) "
+ "failed: %s (%d)", strerror(-err), err);
+ return false;
+ }
+
+ // Lower layer insists that we have at least two buffers.
+ err = native_window_set_buffer_count(window, std::max(2, windowInfo.bufferCount));
+ if (err != 0) {
+ ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffer_count(%d) failed: %s (%d)",
+ windowInfo.bufferCount, strerror(-err), err);
+ return false;
+ }
+
+ err = native_window_set_usage(window, windowInfo.windowUsageFlags);
+ if (err != 0) {
+ ALOGE("VulkanSurface::UpdateWindow() native_window_set_usage failed: %s (%d)",
+ strerror(-err), err);
+ return false;
+ }
+
+ return err == 0;
+}
+
+VulkanSurface::VulkanSurface(ANativeWindow* window, const WindowInfo& windowInfo,
+ SkISize minWindowSize, SkISize maxWindowSize, GrContext* grContext)
+ : mNativeWindow(window)
+ , mWindowInfo(windowInfo)
+ , mGrContext(grContext)
+ , mMinWindowSize(minWindowSize)
+ , mMaxWindowSize(maxWindowSize) { }
+
+VulkanSurface::~VulkanSurface() {
+ releaseBuffers();
+
+ // release the native window to be available for use by other clients
+ int err = native_window_api_disconnect(mNativeWindow.get(), NATIVE_WINDOW_API_EGL);
+ ALOGW_IF(err != 0, "native_window_api_disconnect failed: %s (%d)", strerror(-err), err);
+}
+
+void VulkanSurface::releaseBuffers() {
+ for (uint32_t i = 0; i < VulkanSurface::sMaxBufferCount; i++) {
+ VulkanSurface::NativeBufferInfo& bufferInfo = mNativeBuffers[i];
+
+ if (bufferInfo.buffer.get() != nullptr && bufferInfo.dequeued) {
+ int err = mNativeWindow->cancelBuffer(mNativeWindow.get(), bufferInfo.buffer.get(),
+ bufferInfo.dequeue_fence);
+ if (err != 0) {
+ ALOGE("cancelBuffer[%u] failed during destroy: %s (%d)", i, strerror(-err), err);
+ }
+ bufferInfo.dequeued = false;
+
+ if (bufferInfo.dequeue_fence >= 0) {
+ close(bufferInfo.dequeue_fence);
+ bufferInfo.dequeue_fence = -1;
+ }
+ }
+
+ LOG_ALWAYS_FATAL_IF(bufferInfo.dequeued);
+ LOG_ALWAYS_FATAL_IF(bufferInfo.dequeue_fence != -1);
+
+ bufferInfo.skSurface.reset();
+ bufferInfo.buffer.clear();
+ bufferInfo.hasValidContents = false;
+ bufferInfo.lastPresentedCount = 0;
+ }
+}
+
+VulkanSurface::NativeBufferInfo* VulkanSurface::dequeueNativeBuffer() {
+ // Set the dequeue index to invalid in case of error and only reset it to the correct
+ // value at the end of the function if everything dequeued correctly.
+ mDequeuedIndex = -1;
+
+ //check if the native window has been resized or rotated and update accordingly
+ SkISize newSize = SkISize::MakeEmpty();
+ int transformHint = 0;
+ mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_WIDTH, &newSize.fWidth);
+ mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_HEIGHT, &newSize.fHeight);
+ mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_TRANSFORM_HINT, &transformHint);
+ if (newSize != mWindowInfo.actualSize || transformHint != mWindowInfo.transform) {
+ WindowInfo newWindowInfo = mWindowInfo;
+ newWindowInfo.size = newSize;
+ newWindowInfo.transform = IsTransformSupported(transformHint) ? transformHint : 0;
+ ComputeWindowSizeAndTransform(&newWindowInfo, mMinWindowSize, mMaxWindowSize);
+
+ int err = 0;
+ if (newWindowInfo.actualSize != mWindowInfo.actualSize) {
+ // reset the native buffers and update the window
+ err = native_window_set_buffers_dimensions(mNativeWindow.get(),
+ newWindowInfo.actualSize.width(),
+ newWindowInfo.actualSize.height());
+ if (err != 0) {
+ ALOGE("native_window_set_buffers_dimensions(%d,%d) failed: %s (%d)",
+ newWindowInfo.actualSize.width(),
+ newWindowInfo.actualSize.height(), strerror(-err), err);
+ return nullptr;
+ }
+ // reset the NativeBufferInfo (including SkSurface) associated with the old buffers. The
+ // new NativeBufferInfo storage will be populated lazily as we dequeue each new buffer.
+ releaseBuffers();
+ // TODO should we ask the nativewindow to allocate buffers?
+ }
+
+ if (newWindowInfo.transform != mWindowInfo.transform) {
+ err = native_window_set_buffers_transform(mNativeWindow.get(),
+ InvertTransform(newWindowInfo.transform));
+ if (err != 0) {
+ ALOGE("native_window_set_buffers_transform(%d) failed: %s (%d)",
+ newWindowInfo.transform, strerror(-err), err);
+ newWindowInfo.transform = mWindowInfo.transform;
+ ComputeWindowSizeAndTransform(&newWindowInfo, mMinWindowSize, mMaxWindowSize);
+ }
+ }
+
+ mWindowInfo = newWindowInfo;
+ }
+
+ ANativeWindowBuffer* buffer;
+ int fence_fd;
+ int err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buffer, &fence_fd);
+ if (err != 0) {
+ ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err);
+ return nullptr;
+ }
+
+ uint32_t idx;
+ for (idx = 0; idx < mWindowInfo.bufferCount; idx++) {
+ if (mNativeBuffers[idx].buffer.get() == buffer) {
+ mNativeBuffers[idx].dequeued = true;
+ mNativeBuffers[idx].dequeue_fence = fence_fd;
+ break;
+ } else if (mNativeBuffers[idx].buffer.get() == nullptr) {
+ // increasing the number of buffers we have allocated
+ mNativeBuffers[idx].buffer = buffer;
+ mNativeBuffers[idx].dequeued = true;
+ mNativeBuffers[idx].dequeue_fence = fence_fd;
+ break;
+ }
+ }
+ if (idx == mWindowInfo.bufferCount) {
+ ALOGE("dequeueBuffer returned unrecognized buffer");
+ mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer, fence_fd);
+ return nullptr;
+ }
+
+ VulkanSurface::NativeBufferInfo* bufferInfo = &mNativeBuffers[idx];
+
+ if (bufferInfo->skSurface.get() == nullptr) {
+ bufferInfo->skSurface =
+ SkSurface::MakeFromAHardwareBuffer(mGrContext,
+ ANativeWindowBuffer_getHardwareBuffer(bufferInfo->buffer.get()),
+ kTopLeft_GrSurfaceOrigin, DataSpaceToColorSpace(mWindowInfo.dataspace),
+ nullptr);
+ if (bufferInfo->skSurface.get() == nullptr) {
+ ALOGE("SkSurface::MakeFromAHardwareBuffer failed");
+ mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer, fence_fd);
+ return nullptr;
+ }
+ }
+
+ mDequeuedIndex = idx;
+ return bufferInfo;
+}
+
+bool VulkanSurface::presentCurrentBuffer(const SkRect& dirtyRect, int semaphoreFd) {
+ if (!dirtyRect.isEmpty()) {
+ SkRect transformedRect;
+ mWindowInfo.preTransform.mapRect(&transformedRect, dirtyRect);
+
+ SkIRect transformedIRect;
+ transformedRect.roundOut(&transformedIRect);
+ transformedIRect.intersect(0, 0, mWindowInfo.size.fWidth, mWindowInfo.size.fHeight);
+
+ // map to bottom-left coordinate system
+ android_native_rect_t aRect;
+ aRect.left = transformedIRect.x();
+ aRect.top = mWindowInfo.size.fHeight - (transformedIRect.y() + transformedIRect.height());
+ aRect.right = aRect.left + transformedIRect.width();
+ aRect.bottom = aRect.top - transformedIRect.height();
+
+ int err = native_window_set_surface_damage(mNativeWindow.get(), &aRect, 1);
+ ALOGE_IF(err != 0, "native_window_set_surface_damage failed: %s (%d)", strerror(-err), err);
+ }
+
+ VulkanSurface::NativeBufferInfo& currentBuffer = mNativeBuffers[mDequeuedIndex];
+ int queuedFd = (semaphoreFd != -1) ? semaphoreFd : currentBuffer.dequeue_fence;
+ int err = mNativeWindow->queueBuffer(mNativeWindow.get(), currentBuffer.buffer.get(), queuedFd);
+
+ currentBuffer.dequeued = false;
+ // queueBuffer always closes fence, even on error
+ if (err != 0) {
+ ALOGE("queueBuffer failed: %s (%d)", strerror(-err), err);
+ mNativeWindow->cancelBuffer(mNativeWindow.get(), currentBuffer.buffer.get(),
+ currentBuffer.dequeue_fence);
+ } else {
+ currentBuffer.hasValidContents = true;
+ currentBuffer.lastPresentedCount = mPresentCount;
+ mPresentCount++;
+ }
+
+ if (currentBuffer.dequeue_fence >= 0) {
+ close(currentBuffer.dequeue_fence);
+ currentBuffer.dequeue_fence = -1;
+ }
+
+ return err == 0;
+}
+
+int VulkanSurface::getCurrentBuffersAge() {
+ VulkanSurface::NativeBufferInfo& currentBuffer = mNativeBuffers[mDequeuedIndex];
+ return currentBuffer.hasValidContents ? (mPresentCount - currentBuffer.lastPresentedCount) : 0;
+}
+
+} /* namespace renderthread */
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/renderthread/VulkanSurface.h b/libs/hwui/renderthread/VulkanSurface.h
new file mode 100644
index 0000000..4fd9cd2
--- /dev/null
+++ b/libs/hwui/renderthread/VulkanSurface.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+#pragma once
+
+#include <system/graphics.h>
+#include <system/window.h>
+#include <vulkan/vulkan.h>
+
+#include <SkSize.h>
+#include <SkRefCnt.h>
+
+#include "IRenderPipeline.h"
+
+class SkSurface;
+
+namespace android {
+namespace uirenderer {
+namespace renderthread {
+
+class VulkanManager;
+
+class VulkanSurface {
+public:
+ static VulkanSurface* Create(ANativeWindow* window,
+ ColorMode colorMode,
+ SkColorType colorType,
+ sk_sp<SkColorSpace> colorSpace,
+ GrContext* grContext,
+ const VulkanManager& vkManager);
+ ~VulkanSurface();
+
+ sk_sp<SkSurface> getCurrentSkSurface() { return mNativeBuffers[mDequeuedIndex].skSurface; }
+ const SkMatrix& getCurrentPreTransform() { return mWindowInfo.preTransform; }
+
+private:
+ /*
+ * All structs/methods in this private section are specifically for use by the VulkanManager
+ *
+ */
+ friend VulkanManager;
+ struct NativeBufferInfo {
+ sk_sp<SkSurface> skSurface;
+ sp<ANativeWindowBuffer> buffer;
+ // The fence is only valid when the buffer is dequeued, and should be
+ // -1 any other time. When valid, we own the fd, and must ensure it is
+ // closed: either by closing it explicitly when queueing the buffer,
+ // or by passing ownership e.g. to ANativeWindow::cancelBuffer().
+ int dequeue_fence = -1;
+ bool dequeued = false;
+ uint32_t lastPresentedCount = 0;
+ bool hasValidContents = false;
+ };
+
+ NativeBufferInfo* dequeueNativeBuffer();
+ NativeBufferInfo* getCurrentBufferInfo() { return &mNativeBuffers[mDequeuedIndex]; }
+ bool presentCurrentBuffer(const SkRect& dirtyRect, int semaphoreFd);
+
+ // The width and height are are the logical width and height for when submitting draws to the
+ // surface. In reality if the window is rotated the underlying window may have the width and
+ // height swapped.
+ int logicalWidth() const { return mWindowInfo.size.width(); }
+ int logicalHeight() const { return mWindowInfo.size.height(); }
+ int getCurrentBuffersAge();
+
+private:
+ /*
+ * All code below this line while logically available to VulkanManager should not be treated
+ * as private to this class.
+ *
+ */
+ static constexpr int sMaxBufferCount = 3;
+
+ struct WindowInfo {
+ SkISize size;
+ PixelFormat pixelFormat;
+ android_dataspace dataspace;
+ int transform;
+ int bufferCount;
+ uint64_t windowUsageFlags;
+
+ // size of the ANativeWindow if the inverse of transform requires us to swap width/height
+ SkISize actualSize;
+ // transform to be applied to the SkSurface to map the coordinates to the provided transform
+ SkMatrix preTransform;
+ };
+
+ VulkanSurface(ANativeWindow* window,
+ const WindowInfo& windowInfo,
+ SkISize minWindowSize,
+ SkISize maxWindowSize,
+ GrContext* grContext);
+ static bool UpdateWindow(ANativeWindow* window,
+ const WindowInfo& windowInfo);
+ static void ComputeWindowSizeAndTransform(WindowInfo* windowInfo,
+ const SkISize& minSize,
+ const SkISize& maxSize);
+ void releaseBuffers();
+
+ NativeBufferInfo mNativeBuffers[VulkanSurface::sMaxBufferCount];
+
+ sp<ANativeWindow> mNativeWindow;
+ WindowInfo mWindowInfo;
+ GrContext* mGrContext;
+
+ int mDequeuedIndex = -1;
+ uint32_t mPresentCount = 0;
+
+ const SkISize mMinWindowSize;
+ const SkISize mMaxWindowSize;
+};
+
+} /* namespace renderthread */
+} /* namespace uirenderer */
+} /* namespace android */
\ No newline at end of file
diff --git a/packages/ExtServices/src/android/ext/services/notification/AssistantSettings.java b/packages/ExtServices/src/android/ext/services/notification/AssistantSettings.java
index ba361c4..46288bb 100644
--- a/packages/ExtServices/src/android/ext/services/notification/AssistantSettings.java
+++ b/packages/ExtServices/src/android/ext/services/notification/AssistantSettings.java
@@ -22,7 +22,6 @@
import android.os.Handler;
import android.provider.DeviceConfig;
import android.provider.Settings;
-import android.text.TextUtils;
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
@@ -128,17 +127,17 @@
}
private void updateFromDeviceConfigFlags() {
- mGenerateReplies = DeviceConfigHelper.getBoolean(
+ mGenerateReplies = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES, DEFAULT_GENERATE_REPLIES);
- mGenerateActions = DeviceConfigHelper.getBoolean(
+ mGenerateActions = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS, DEFAULT_GENERATE_ACTIONS);
- mMaxMessagesToExtract = DeviceConfigHelper.getInteger(
+ mMaxMessagesToExtract = DeviceConfig.getInt(DeviceConfig.NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.NAS_MAX_MESSAGES_TO_EXTRACT,
DEFAULT_MAX_MESSAGES_TO_EXTRACT);
- mMaxSuggestions = DeviceConfigHelper.getInteger(
+ mMaxSuggestions = DeviceConfig.getInt(DeviceConfig.NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.NAS_MAX_SUGGESTIONS, DEFAULT_MAX_SUGGESTIONS);
mOnUpdateRunnable.run();
@@ -170,34 +169,6 @@
mOnUpdateRunnable.run();
}
- static class DeviceConfigHelper {
-
- static int getInteger(String key, int defaultValue) {
- String value = getValue(key);
- if (TextUtils.isEmpty(value)) {
- return defaultValue;
- }
- try {
- return Integer.parseInt(value);
- } catch (NumberFormatException ex) {
- return defaultValue;
- }
- }
-
- static boolean getBoolean(String key, boolean defaultValue) {
- String value = getValue(key);
- if (TextUtils.isEmpty(value)) {
- return defaultValue;
- }
- return Boolean.parseBoolean(value);
- }
-
- private static String getValue(String key) {
- return DeviceConfig.getProperty(
- DeviceConfig.NAMESPACE_SYSTEMUI, key);
- }
- }
-
public interface Factory {
AssistantSettings createAndRegister(Handler handler, ContentResolver resolver, int userId,
Runnable onUpdateRunnable);
diff --git a/packages/ExtServices/tests/src/android/ext/services/notification/AssistantSettingsTest.java b/packages/ExtServices/tests/src/android/ext/services/notification/AssistantSettingsTest.java
index 293b5b8..ad52e2b 100644
--- a/packages/ExtServices/tests/src/android/ext/services/notification/AssistantSettingsTest.java
+++ b/packages/ExtServices/tests/src/android/ext/services/notification/AssistantSettingsTest.java
@@ -120,7 +120,7 @@
}
@Test
- public void testGenerateRepliesEmptyFlag() {
+ public void testGenerateRepliesNullFlag() {
runWithShellPermissionIdentity(() -> setProperty(
DeviceConfig.NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES,
@@ -136,12 +136,12 @@
runWithShellPermissionIdentity(() -> setProperty(
DeviceConfig.NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES,
- "",
+ null,
false /* makeDefault */));
mAssistantSettings.onDeviceConfigPropertyChanged(
DeviceConfig.NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.NAS_GENERATE_REPLIES,
- "");
+ null);
// Go back to the default value.
assertTrue(mAssistantSettings.mGenerateReplies);
@@ -178,7 +178,7 @@
}
@Test
- public void testGenerateActionsEmptyFlag() {
+ public void testGenerateActionsNullFlag() {
runWithShellPermissionIdentity(() -> setProperty(
DeviceConfig.NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS,
@@ -194,12 +194,12 @@
runWithShellPermissionIdentity(() -> setProperty(
DeviceConfig.NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS,
- "",
+ null,
false /* makeDefault */));
mAssistantSettings.onDeviceConfigPropertyChanged(
DeviceConfig.NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.NAS_GENERATE_ACTIONS,
- "");
+ null);
// Go back to the default value.
assertTrue(mAssistantSettings.mGenerateActions);
diff --git a/packages/NetworkStack/Android.bp b/packages/NetworkStack/Android.bp
index f210840..190247a 100644
--- a/packages/NetworkStack/Android.bp
+++ b/packages/NetworkStack/Android.bp
@@ -14,12 +14,11 @@
// limitations under the License.
//
-// Library including the network stack, used to compile the network stack app, or linked into the
-// system server on devices that run the stack there
-java_library {
- name: "NetworkStackLib",
+// Library including the network stack, used to compile both variants of the network stack
+android_library {
+ name: "NetworkStackBase",
sdk_version: "system_current",
- installable: true,
+ min_sdk_version: "28",
srcs: [
"src/**/*.java",
":framework-networkstack-shared-srcs",
@@ -29,7 +28,24 @@
"netd_aidl_interface-java",
"networkstack-aidl-interfaces-java",
"datastallprotosnano",
- ]
+ ],
+ manifest: "AndroidManifestBase.xml",
+}
+
+// Non-updatable in-process network stack for devices not using the module
+android_app {
+ name: "InProcessNetworkStack",
+ sdk_version: "system_current",
+ min_sdk_version: "28",
+ certificate: "platform",
+ privileged: true,
+ static_libs: [
+ "NetworkStackBase",
+ ],
+ jarjar_rules: "jarjar-rules-shared.txt",
+ // The permission configuration *must* be included to ensure security of the device
+ required: ["NetworkStackPermissionStub"],
+ manifest: "AndroidManifest_InProcess.xml",
}
// Updatable network stack packaged as an application
@@ -40,9 +56,10 @@
certificate: "networkstack",
privileged: true,
static_libs: [
- "NetworkStackLib"
+ "NetworkStackBase"
],
jarjar_rules: "jarjar-rules-shared.txt",
- manifest: "AndroidManifest.xml",
+ // The permission configuration *must* be included to ensure security of the device
required: ["NetworkStackPermissionStub"],
+ manifest: "AndroidManifest.xml",
}
diff --git a/packages/NetworkStack/AndroidManifest.xml b/packages/NetworkStack/AndroidManifest.xml
index 003f1e5..a90db11 100644
--- a/packages/NetworkStack/AndroidManifest.xml
+++ b/packages/NetworkStack/AndroidManifest.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
/*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2019 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.
@@ -18,30 +18,14 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.networkstack"
- android:sharedUserId="android.uid.networkstack"
- android:versionCode="11"
- android:versionName="Q-initial">
- <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28" />
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
- <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
- <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
+ android:sharedUserId="android.uid.networkstack">
<!-- Signature permission defined in NetworkStackStub -->
<uses-permission android:name="android.permission.MAINLINE_NETWORK_STACK" />
- <!-- Send latency broadcast as current user -->
- <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
- <uses-permission android:name="android.permission.WAKE_LOCK" />
- <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
- <application
- android:label="NetworkStack"
- android:defaultToDeviceProtectedStorage="true"
- android:directBootAware="true"
- android:usesCleartextTraffic="true">
+ <application>
<service android:name="com.android.server.NetworkStackService">
<intent-filter>
<action android:name="android.net.INetworkStackConnector"/>
</intent-filter>
</service>
</application>
-</manifest>
+</manifest>
\ No newline at end of file
diff --git a/packages/NetworkStack/AndroidManifestBase.xml b/packages/NetworkStack/AndroidManifestBase.xml
new file mode 100644
index 0000000..621d30c
--- /dev/null
+++ b/packages/NetworkStack/AndroidManifestBase.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2019 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.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.networkstack"
+ android:versionCode="11"
+ android:versionName="Q-initial">
+ <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28" />
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+ <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
+ <!-- Send latency broadcast as current user -->
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
+ <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
+ <application
+ android:label="NetworkStack"
+ android:defaultToDeviceProtectedStorage="true"
+ android:directBootAware="true"
+ android:usesCleartextTraffic="true">
+ </application>
+</manifest>
diff --git a/packages/NetworkStack/AndroidManifest_InProcess.xml b/packages/NetworkStack/AndroidManifest_InProcess.xml
new file mode 100644
index 0000000..48fcecd
--- /dev/null
+++ b/packages/NetworkStack/AndroidManifest_InProcess.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2019 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.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.networkstack.inprocess"
+ android:sharedUserId="android.uid.system"
+ android:process="system">
+ <application>
+ <service android:name="com.android.server.NetworkStackService" android:process="system">
+ <intent-filter>
+ <action android:name="android.net.INetworkStackConnector.InProcess"/>
+ </intent-filter>
+ </service>
+ </application>
+</manifest>
\ No newline at end of file
diff --git a/packages/NetworkStack/tests/Android.bp b/packages/NetworkStack/tests/Android.bp
index e64f284..aadf99e 100644
--- a/packages/NetworkStack/tests/Android.bp
+++ b/packages/NetworkStack/tests/Android.bp
@@ -23,7 +23,7 @@
static_libs: [
"androidx.test.rules",
"mockito-target-extended-minus-junit4",
- "NetworkStackLib",
+ "NetworkStackBase",
"testables",
],
libs: [
diff --git a/packages/SettingsLib/res/drawable/ic_smartphone.xml b/packages/SettingsLib/res/drawable/ic_smartphone.xml
new file mode 100644
index 0000000..84a96da
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_smartphone.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2019 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:width="24dp"
+ android:height="24dp"
+ android:tint="?android:attr/colorControlNormal">
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0 0h24v24H0z" />
+ <path
+ android:fillColor="#000000"
+ android:pathData="M17 1.01L7 1c-1.1 0-2 0.9-2 2v18c0 1.1 0.9 2 2 2h10c1.1 0 2 -0.9 2-2V3c0-1.1 -0.9-1.99-2-1.99zM17 19H7V5h10v14z" />
+</vector>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index c60e8c3..bf97d77 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -937,7 +937,7 @@
<string name="power_remaining_duration_only_enhanced">About <xliff:g id="time_remaining">%1$s</xliff:g> left based on your usage</string>
<!-- [CHAR_LIMIT=60] Label for battery level chart when discharging with duration and using enhanced estimate -->
<string name="power_discharging_duration_enhanced">About <xliff:g id="time_remaining">%1$s</xliff:g> left based on your usage (<xliff:g id="level">%2$s</xliff:g>)</string>
- <!-- [CHAR_LIMIT=40] Short label for estimated remaining duration of battery charging/discharging -->
+ <!-- [CHAR_LIMIT=20] Short label for estimated remaining duration of battery charging/discharging -->
<string name="power_remaining_duration_only_short"><xliff:g id="time_remaining">%1$s</xliff:g></string>
<!-- [CHAR_LIMIT=100] Label for enhanced estimated time that phone will run out of battery -->
@@ -948,7 +948,7 @@
<string name="power_discharge_by">Should last until about <xliff:g id="time">%1$s</xliff:g> (<xliff:g id="level">%2$s</xliff:g>)</string>
<!-- [CHAR_LIMIT=100] Label for estimated time that phone will run out of battery -->
<string name="power_discharge_by_only">Should last until about <xliff:g id="time">%1$s</xliff:g></string>
- <!-- [CHAR_LIMIT=100] Label for estimated time that phone will run out of battery -->
+ <!-- [CHAR_LIMIT=20] Label for estimated time that phone will run out of battery -->
<string name="power_discharge_by_only_short">Until <xliff:g id="time" example="12 PM">%1$s</xliff:g></string>
<!-- [CHAR_LIMIT=100] Extend the battery life past a certain time -->
<string name="power_suggestion_extend_battery">Extend battery life past <xliff:g id="time" example="12 PM">%1$s</xliff:g></string>
@@ -1153,6 +1153,6 @@
<!-- The notice header of Third-party licenses. not translatable -->
<string name="notice_header" translatable="false"></string>
- <!-- Name of the phone device [CHAR LIMIT=NONE] -->
- <string name="media_transfer_phone_device_name">Phone speaker</string>
+ <!-- Name of the this device. [CHAR LIMIT=30] -->
+ <string name="media_transfer_this_device_name">This device</string>
</resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
index 6d0e3ac..3092b99 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
@@ -16,6 +16,7 @@
package com.android.settingslib.media;
import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.util.Log;
@@ -42,6 +43,11 @@
}
@Override
+ public String getSummary() {
+ return mCachedDevice.getConnectionSummary();
+ }
+
+ @Override
public int getIcon() {
//TODO(b/117129183): This is not final icon for bluetooth device, just for demo.
return com.android.internal.R.drawable.ic_bt_headphones_a2dp;
@@ -86,4 +92,10 @@
}
return false;
}
+
+ @Override
+ public boolean isConnected() {
+ return mCachedDevice.getBondState() == BluetoothDevice.BOND_BONDED
+ && mCachedDevice.isConnected();
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaManager.java
index fa2dd88..3a738d2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaManager.java
@@ -41,6 +41,9 @@
private static final String TAG = "BluetoothMediaManager";
+ private final DeviceAttributeChangeCallback mDeviceAttributeChangeCallback =
+ new DeviceAttributeChangeCallback();
+
private LocalBluetoothManager mLocalBluetoothManager;
private LocalBluetoothProfileManager mProfileManager;
private CachedBluetoothDeviceManager mCachedBluetoothDeviceManager;
@@ -65,7 +68,10 @@
mLocalBluetoothManager.getEventManager().registerCallback(this);
buildBluetoothDeviceList();
dispatchDeviceListAdded();
+ addServiceListenerIfNecessary();
+ }
+ private void addServiceListenerIfNecessary() {
// The profile may not ready when calling startScan().
// Device status are all disconnected since profiles are not ready to connected.
// In this case, we observe onServiceConnected() in LocalBluetoothProfileManager.
@@ -78,18 +84,18 @@
private void buildBluetoothDeviceList() {
mMediaDevices.clear();
- addConnectedA2dpDevices();
- addConnectedHearingAidDevices();
+ addConnectableA2dpDevices();
+ addConnectableHearingAidDevices();
}
- private void addConnectedA2dpDevices() {
+ private void addConnectableA2dpDevices() {
final A2dpProfile a2dpProfile = mProfileManager.getA2dpProfile();
if (a2dpProfile == null) {
- Log.w(TAG, "addConnectedA2dpDevices() a2dp profile is null!");
+ Log.w(TAG, "addConnectableA2dpDevices() a2dp profile is null!");
return;
}
- final List<BluetoothDevice> devices = a2dpProfile.getConnectedDevices();
+ final List<BluetoothDevice> devices = a2dpProfile.getConnectableDevices();
for (BluetoothDevice device : devices) {
final CachedBluetoothDevice cachedDevice =
@@ -100,10 +106,12 @@
continue;
}
- Log.d(TAG, "addConnectedA2dpDevices() device : " + cachedDevice.getName()
- + ", is connected : " + cachedDevice.isConnected());
+ Log.d(TAG, "addConnectableA2dpDevices() device : " + cachedDevice.getName()
+ + ", is connected : " + cachedDevice.isConnected()
+ + ", is preferred : " + a2dpProfile.isPreferred(device));
- if (cachedDevice.isConnected()) {
+ if (a2dpProfile.isPreferred(device)
+ && BluetoothDevice.BOND_BONDED == cachedDevice.getBondState()) {
addMediaDevice(cachedDevice);
}
}
@@ -111,15 +119,15 @@
mIsA2dpProfileReady = a2dpProfile.isProfileReady();
}
- private void addConnectedHearingAidDevices() {
+ private void addConnectableHearingAidDevices() {
final HearingAidProfile hapProfile = mProfileManager.getHearingAidProfile();
if (hapProfile == null) {
- Log.w(TAG, "addConnectedA2dpDevices() hap profile is null!");
+ Log.w(TAG, "addConnectableHearingAidDevices() hap profile is null!");
return;
}
final List<Long> devicesHiSyncIds = new ArrayList<>();
- final List<BluetoothDevice> devices = hapProfile.getConnectedDevices();
+ final List<BluetoothDevice> devices = hapProfile.getConnectableDevices();
for (BluetoothDevice device : devices) {
final CachedBluetoothDevice cachedDevice =
@@ -130,13 +138,16 @@
continue;
}
- Log.d(TAG, "addConnectedHearingAidDevices() device : " + cachedDevice.getName()
- + ", is connected : " + cachedDevice.isConnected());
+ Log.d(TAG, "addConnectableHearingAidDevices() device : " + cachedDevice.getName()
+ + ", is connected : " + cachedDevice.isConnected()
+ + ", is preferred : " + hapProfile.isPreferred(device));
+
final long hiSyncId = hapProfile.getHiSyncId(device);
// device with same hiSyncId should not be shown in the UI.
// So do not add it into connectedDevices.
- if (!devicesHiSyncIds.contains(hiSyncId) && cachedDevice.isConnected()) {
+ if (!devicesHiSyncIds.contains(hiSyncId) && hapProfile.isPreferred(device)
+ && BluetoothDevice.BOND_BONDED == cachedDevice.getBondState()) {
devicesHiSyncIds.add(hiSyncId);
addMediaDevice(cachedDevice);
}
@@ -149,6 +160,7 @@
MediaDevice mediaDevice = findMediaDevice(MediaDeviceUtils.getId(cachedDevice));
if (mediaDevice == null) {
mediaDevice = new BluetoothMediaDevice(mContext, cachedDevice);
+ cachedDevice.registerCallback(mDeviceAttributeChangeCallback);
mLastAddedDevice = mediaDevice;
mMediaDevices.add(mediaDevice);
}
@@ -157,6 +169,14 @@
@Override
public void stopScan() {
mLocalBluetoothManager.getEventManager().unregisterCallback(this);
+ unregisterDeviceAttributeChangeCallback();
+ }
+
+ private void unregisterDeviceAttributeChangeCallback() {
+ for (MediaDevice device : mMediaDevices) {
+ ((BluetoothMediaDevice) device).getCachedDevice()
+ .unregisterCallback(mDeviceAttributeChangeCallback);
+ }
}
@Override
@@ -164,12 +184,13 @@
if (BluetoothAdapter.STATE_ON == bluetoothState) {
buildBluetoothDeviceList();
dispatchDeviceListAdded();
+ addServiceListenerIfNecessary();
} else if (BluetoothAdapter.STATE_OFF == bluetoothState) {
final List<MediaDevice> removeDevicesList = new ArrayList<>();
for (MediaDevice device : mMediaDevices) {
- if (device instanceof BluetoothMediaDevice) {
- removeDevicesList.add(device);
- }
+ ((BluetoothMediaDevice) device).getCachedDevice()
+ .unregisterCallback(mDeviceAttributeChangeCallback);
+ removeDevicesList.add(device);
}
mMediaDevices.removeAll(removeDevicesList);
dispatchDeviceListRemoved(removeDevicesList);
@@ -212,6 +233,7 @@
private void removeMediaDevice(CachedBluetoothDevice cachedDevice) {
final MediaDevice mediaDevice = findMediaDevice(MediaDeviceUtils.getId(cachedDevice));
if (mediaDevice != null) {
+ cachedDevice.unregisterCallback(mDeviceAttributeChangeCallback);
mLastRemovedDevice = mediaDevice;
mMediaDevices.remove(mediaDevice);
}
@@ -230,12 +252,17 @@
Log.d(TAG, "onProfileConnectionStateChanged() device: " + cachedDevice
+ ", state: " + state + ", bluetoothProfile: " + bluetoothProfile);
- if (isCachedDeviceConnected(cachedDevice)) {
- addMediaDevice(cachedDevice);
- dispatchDeviceAdded(cachedDevice);
- } else {
+ updateMediaDeviceListIfNecessary(cachedDevice);
+ }
+
+ private void updateMediaDeviceListIfNecessary(CachedBluetoothDevice cachedDevice) {
+ if (BluetoothDevice.BOND_NONE == cachedDevice.getBondState()) {
removeMediaDevice(cachedDevice);
dispatchDeviceRemoved(cachedDevice);
+ } else {
+ if (findMediaDevice(MediaDeviceUtils.getId(cachedDevice)) != null) {
+ dispatchDataChanged();
+ }
}
}
@@ -243,13 +270,7 @@
public void onAclConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) {
Log.d(TAG, "onAclConnectionStateChanged() device: " + cachedDevice + ", state: " + state);
- if (isCachedDeviceConnected(cachedDevice)) {
- addMediaDevice(cachedDevice);
- dispatchDeviceAdded(cachedDevice);
- } else {
- removeMediaDevice(cachedDevice);
- dispatchDeviceRemoved(cachedDevice);
- }
+ updateMediaDeviceListIfNecessary(cachedDevice);
}
@Override
@@ -281,4 +302,16 @@
public void onServiceDisconnected() {
}
+
+ /**
+ * This callback is for update {@link BluetoothMediaDevice} summary when
+ * {@link CachedBluetoothDevice} connection state is changed.
+ */
+ private class DeviceAttributeChangeCallback implements CachedBluetoothDevice.Callback {
+
+ @Override
+ public void onDeviceAttributesChanged() {
+ dispatchDataChanged();
+ }
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java
index 99d9d1c..95f3d3d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java
@@ -41,6 +41,11 @@
}
@Override
+ public String getSummary() {
+ return null;
+ }
+
+ @Override
public int getIcon() {
//TODO(b/121083246): This is not final icon for cast device, just for demo.
return com.android.internal.R.drawable.ic_settings_print;
@@ -63,4 +68,9 @@
public void disconnect() {
//TODO(b/121083246): disconnected last select device
}
+
+ @Override
+ public boolean isConnected() {
+ return true;
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
index 44d945a..4e16c66 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
@@ -58,7 +58,6 @@
private Context mContext;
private BluetoothMediaManager mBluetoothMediaManager;
- private InfoMediaManager mInfoMediaManager;
private LocalBluetoothManager mLocalBluetoothManager;
@VisibleForTesting
@@ -97,7 +96,6 @@
mBluetoothMediaManager =
new BluetoothMediaManager(context, mLocalBluetoothManager, notification);
- mInfoMediaManager = new InfoMediaManager(context, packageName, notification);
}
@VisibleForTesting
@@ -106,7 +104,6 @@
mContext = context;
mLocalBluetoothManager = localBluetoothManager;
mBluetoothMediaManager = bluetoothMediaManager;
- mInfoMediaManager = infoMediaManager;
}
/**
@@ -115,6 +112,15 @@
*/
public void connectDevice(MediaDevice connectDevice) {
final MediaDevice device = getMediaDeviceById(mMediaDevices, connectDevice.getId());
+ if (device instanceof BluetoothMediaDevice) {
+ final CachedBluetoothDevice cachedDevice =
+ ((BluetoothMediaDevice) device).getCachedDevice();
+ if (!cachedDevice.isConnected() && !cachedDevice.isBusy()) {
+ cachedDevice.connect(true);
+ return;
+ }
+ }
+
if (device == mCurrentConnectedDevice) {
Log.d(TAG, "connectDevice() this device all ready connected! : " + device.getName());
return;
@@ -150,9 +156,7 @@
public void startScan() {
mMediaDevices.clear();
mBluetoothMediaManager.registerCallback(mMediaDeviceCallback);
- mInfoMediaManager.registerCallback(mMediaDeviceCallback);
mBluetoothMediaManager.startScan();
- mInfoMediaManager.startScan();
}
private void addPhoneDeviceIfNecessary() {
@@ -186,9 +190,7 @@
*/
public void stopScan() {
mBluetoothMediaManager.unregisterCallback(mMediaDeviceCallback);
- mInfoMediaManager.unregisterCallback(mMediaDeviceCallback);
mBluetoothMediaManager.stopScan();
- mInfoMediaManager.stopScan();
}
/**
@@ -252,9 +254,17 @@
}
addPhoneDeviceIfNecessary();
mCurrentConnectedDevice = updateCurrentConnectedDevice();
+ updatePhoneMediaDeviceSummary();
dispatchDeviceListUpdate();
}
+ private void updatePhoneMediaDeviceSummary() {
+ if (mPhoneDevice != null) {
+ ((PhoneMediaDevice) mPhoneDevice)
+ .updateSummary(mCurrentConnectedDevice == mPhoneDevice);
+ }
+ }
+
@Override
public void onDeviceRemoved(MediaDevice device) {
if (mMediaDevices.contains(device)) {
@@ -272,21 +282,22 @@
}
@Override
- public void onDeviceAttributesChanged() {
- dispatchDeviceListUpdate();
- }
-
- @Override
public void onConnectedDeviceChanged(String id) {
final MediaDevice connectDevice = getMediaDeviceById(mMediaDevices, id);
if (connectDevice == mCurrentConnectedDevice) {
- Log.d(TAG, "onConnectedDeviceChanged() this device all ready connected! : "
- + connectDevice.getName());
+ Log.d(TAG, "onConnectedDeviceChanged() this device all ready connected!");
return;
}
mCurrentConnectedDevice = connectDevice;
+ updatePhoneMediaDeviceSummary();
+ dispatchDeviceListUpdate();
+ }
+ @Override
+ public void onDeviceAttributesChanged() {
+ addPhoneDeviceIfNecessary();
+ removePhoneMediaDeviceIfNecessary();
dispatchDeviceListUpdate();
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
index f35c30e..9b9e803 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
@@ -34,9 +34,9 @@
MediaDeviceType.TYPE_BLUETOOTH_DEVICE,
MediaDeviceType.TYPE_PHONE_DEVICE})
public @interface MediaDeviceType {
- int TYPE_CAST_DEVICE = 1;
- int TYPE_BLUETOOTH_DEVICE = 2;
- int TYPE_PHONE_DEVICE = 3;
+ int TYPE_PHONE_DEVICE = 1;
+ int TYPE_CAST_DEVICE = 2;
+ int TYPE_BLUETOOTH_DEVICE = 3;
}
private int mConnectedRecord;
@@ -63,6 +63,13 @@
public abstract String getName();
/**
+ * Get summary from MediaDevice.
+ *
+ * @return summary of MediaDevice.
+ */
+ public abstract String getSummary();
+
+ /**
* Get resource id of MediaDevice.
*
* @return resource id of MediaDevice.
@@ -94,6 +101,13 @@
public abstract void disconnect();
/**
+ * According the MediaDevice type to check whether we are connected to this MediaDevice.
+ *
+ * @return Whether it is connected.
+ */
+ public abstract boolean isConnected();
+
+ /**
* Rules:
* 1. If there is one of the connected devices identified as a carkit, this carkit will
* be always on the top of the device list. Rule 2 and Rule 3 can’t overrule this rule.
@@ -103,9 +117,11 @@
* 3. For devices with usage record.
* The most recent used one + device group with usage info sorted by how many times the
* device has been used.
+ * 4. Phone device always in the top and the connected Bluetooth devices, cast devices and
+ * phone device will be always above on the disconnect Bluetooth devices.
*
- * So the device list will look like 4 slots ranked as below.
- * Rule 1 + the most recently used device + Rule 3 + Rule 2
+ * So the device list will look like 5 slots ranked as below.
+ * Rule 4 + Rule 1 + the most recently used device + Rule 3 + Rule 2
* Any slot could be empty. And available device will belong to one of the slots.
*
* @return a negative integer, zero, or a positive integer
@@ -113,6 +129,21 @@
*/
@Override
public int compareTo(MediaDevice another) {
+ // Check Bluetooth device is have same connection state
+ if (isConnected() ^ another.isConnected()) {
+ if (isConnected()) {
+ return -1;
+ } else {
+ return 1;
+ }
+ }
+
+ // Phone device always in the top.
+ if (mType == MediaDeviceType.TYPE_PHONE_DEVICE) {
+ return -1;
+ } else if (another.mType == MediaDeviceType.TYPE_PHONE_DEVICE) {
+ return 1;
+ }
// Check carkit
if (isCarKitDevice()) {
return -1;
@@ -138,7 +169,7 @@
final String s2 = another.getName();
return s1.compareToIgnoreCase(s2);
}
- // Both devices have never been used, the priority is Cast > Bluetooth > Phone
+ // Both devices have never been used, the priority is Phone > Cast > Bluetooth
return mType - another.mType;
}
@@ -149,4 +180,13 @@
protected boolean isCarKitDevice() {
return false;
}
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof MediaDevice)) {
+ return false;
+ }
+ final MediaDevice otherDevice = (MediaDevice) obj;
+ return otherDevice.getId().equals(getId());
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java
index 2c3a96c..7898982 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaManager.java
@@ -117,6 +117,14 @@
}
}
+ protected void dispatchDataChanged() {
+ synchronized (mCallbacks) {
+ for (MediaDeviceCallback callback : mCallbacks) {
+ callback.onDeviceAttributesChanged();
+ }
+ }
+ }
+
/**
* Callback for notifying device is added, removed and attributes changed.
*/
@@ -150,15 +158,16 @@
void onDeviceListRemoved(List<MediaDevice> devices);
/**
- * Callback for notifying MediaDevice attributes is changed.
- */
- void onDeviceAttributesChanged();
-
- /**
* Callback for notifying connected MediaDevice is changed.
*
* @param id the id of MediaDevice
*/
void onConnectedDeviceChanged(String id);
+
+ /**
+ * Callback for notifying that MediaDevice attributes
+ * (e.g: device name, connection state, subtitle) is changed.
+ */
+ void onDeviceAttributesChanged();
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
index 8ec2a7f..da140aa 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/PhoneMediaDevice.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.util.Log;
+import com.android.settingslib.R;
import com.android.settingslib.bluetooth.A2dpProfile;
import com.android.settingslib.bluetooth.HearingAidProfile;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
@@ -34,6 +35,7 @@
private LocalBluetoothProfileManager mProfileManager;
private LocalBluetoothManager mLocalBluetoothManager;
+ private String mSummary = "";
PhoneMediaDevice(Context context, LocalBluetoothManager localBluetoothManager) {
super(context, MediaDeviceType.TYPE_PHONE_DEVICE);
@@ -45,14 +47,17 @@
@Override
public String getName() {
- return mContext
- .getString(com.android.settingslib.R.string.media_transfer_phone_device_name);
+ return mContext.getString(R.string.media_transfer_this_device_name);
+ }
+
+ @Override
+ public String getSummary() {
+ return mSummary;
}
@Override
public int getIcon() {
- //TODO(b/117129183): This is not final icon for phone device, just for demo.
- return com.android.internal.R.drawable.ic_phone;
+ return R.drawable.ic_smartphone;
}
@Override
@@ -69,6 +74,7 @@
if (hapProfile != null && a2dpProfile != null) {
isConnected = hapProfile.setActiveDevice(null) && a2dpProfile.setActiveDevice(null);
+ updateSummary(true);
setConnectedRecord();
}
Log.d(TAG, "connect() device : " + getName() + ", is selected : " + isConnected);
@@ -77,6 +83,20 @@
@Override
public void disconnect() {
- //TODO(b/117129183): disconnected last select device
+ updateSummary(false);
+ }
+
+ @Override
+ public boolean isConnected() {
+ return true;
+ }
+
+ /**
+ * According current active device is {@link PhoneMediaDevice} or not to update summary.
+ */
+ public void updateSummary(boolean isActive) {
+ mSummary = isActive
+ ? mContext.getString(R.string.bluetooth_active_no_battery_level)
+ : "";
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java b/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java
index 5600dd2..7046d23 100644
--- a/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java
+++ b/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java
@@ -223,12 +223,19 @@
}
private static String getRegularTimeRemainingShortString(Context context, long drainTimeMs) {
- // Get the time remaining rounded to the nearest 15 min
- final long roundedTimeMs = roundTimeToNearestThreshold(drainTimeMs, FIFTEEN_MINUTES_MILLIS);
- CharSequence timeString = StringUtil.formatElapsedTime(context, roundedTimeMs,
- false /* withSeconds */);
+ // Get the time of day we think device will die rounded to the nearest 15 min.
+ final long roundedTimeOfDayMs =
+ roundTimeToNearestThreshold(
+ System.currentTimeMillis() + drainTimeMs,
+ FIFTEEN_MINUTES_MILLIS);
- return context.getString(R.string.power_remaining_duration_only_short, timeString);
+ // convert the time to a properly formatted string.
+ String skeleton = android.text.format.DateFormat.getTimeFormatString(context);
+ DateFormat fmt = DateFormat.getInstanceForSkeleton(skeleton);
+ Date date = Date.from(Instant.ofEpochMilli(roundedTimeOfDayMs));
+ CharSequence timeString = fmt.format(date);
+
+ return context.getString(R.string.power_discharge_by_only_short, timeString);
}
public static long convertUsToMs(long timeUs) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index d9b4885..59fbb72 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -1076,7 +1076,7 @@
return (info.isOsuAp() && mOsuStatus != null);
} else if (info.isPasspointAp() || isPasspoint()) {
return (info.isPasspointAp() && isPasspoint()
- && TextUtils.equals(info.getFqdn(), mConfig.FQDN));
+ && TextUtils.equals(info.getPasspointFqdn(), mConfig.FQDN));
}
if (networkId != WifiConfiguration.INVALID_NETWORK_ID) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
index 3c10688..2ab369c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java
@@ -118,7 +118,7 @@
mWifiInfo = mWifiManager.getConnectionInfo();
if (mWifiInfo != null) {
if (mWifiInfo.isPasspointAp() || mWifiInfo.isOsuAp()) {
- ssid = mWifiInfo.getProviderFriendlyName();
+ ssid = mWifiInfo.getPasspointProviderFriendlyName();
} else {
ssid = getValidSsid(mWifiInfo);
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaDeviceTest.java
index e5d1b18..e0e2fd6 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaDeviceTest.java
@@ -20,6 +20,7 @@
import static org.mockito.Mockito.when;
+import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
@@ -66,4 +67,20 @@
assertThat(mBluetoothMediaDevice.connect()).isFalse();
}
+
+ @Test
+ public void isCachedBluetoothDeviceConnected_deviceConnected_returnTrue() {
+ when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+ when(mDevice.isConnected()).thenReturn(true);
+
+ assertThat(mBluetoothMediaDevice.isConnected()).isTrue();
+ }
+
+ @Test
+ public void isCachedBluetoothDeviceConnected_deviceNotConnected_returnFalse() {
+ when(mDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+ when(mDevice.isConnected()).thenReturn(false);
+
+ assertThat(mBluetoothMediaDevice.isConnected()).isFalse();
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaManagerTest.java
index a20e22b..48449f2 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/BluetoothMediaManagerTest.java
@@ -87,15 +87,16 @@
}
@Test
- public void startScan_haveA2dpProfileConnectedBluetoothDevice_shouldAddDevice() {
+ public void startScan_haveA2dpProfileDeviceIsPreferredAndBonded_shouldAddDevice() {
final List<BluetoothDevice> devices = new ArrayList<>();
final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
final BluetoothDevice bluetoothDevice = mock(BluetoothDevice.class);
devices.add(bluetoothDevice);
- when(mA2dpProfile.getConnectedDevices()).thenReturn(devices);
+ when(mA2dpProfile.getConnectableDevices()).thenReturn(devices);
when(mCachedDeviceManager.findDevice(bluetoothDevice)).thenReturn(cachedDevice);
- when(cachedDevice.isConnected()).thenReturn(true);
+ when(cachedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+ when(mA2dpProfile.isPreferred(bluetoothDevice)).thenReturn(true);
assertThat(mMediaManager.mMediaDevices).isEmpty();
mMediaManager.startScan();
@@ -103,15 +104,16 @@
}
@Test
- public void startScan_haveA2dpProfileDisconnectedBluetoothDevice_shouldNotAddDevice() {
+ public void startScan_haveA2dpProfileDeviceIsPreferredAndBondNone_shouldNotAddDevice() {
final List<BluetoothDevice> devices = new ArrayList<>();
final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
final BluetoothDevice bluetoothDevice = mock(BluetoothDevice.class);
devices.add(bluetoothDevice);
- when(mA2dpProfile.getConnectedDevices()).thenReturn(devices);
+ when(mA2dpProfile.getConnectableDevices()).thenReturn(devices);
when(mCachedDeviceManager.findDevice(bluetoothDevice)).thenReturn(cachedDevice);
- when(cachedDevice.isConnected()).thenReturn(false);
+ when(cachedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_NONE);
+ when(mA2dpProfile.isPreferred(bluetoothDevice)).thenReturn(true);
assertThat(mMediaManager.mMediaDevices).isEmpty();
mMediaManager.startScan();
@@ -122,7 +124,7 @@
public void startScan_noA2dpProfileBluetoothDevice_shouldNotAddDevice() {
final List<BluetoothDevice> devices = new ArrayList<>();
- when(mA2dpProfile.getConnectedDevices()).thenReturn(devices);
+ when(mA2dpProfile.getConnectableDevices()).thenReturn(devices);
assertThat(mMediaManager.mMediaDevices).isEmpty();
mMediaManager.startScan();
@@ -130,15 +132,16 @@
}
@Test
- public void startScan_haveHapProfileConnectedBluetoothDevice_shouldAddDevice() {
+ public void startScan_haveHapProfileDeviceIsPreferredAndBonded_shouldAddDevice() {
final List<BluetoothDevice> devices = new ArrayList<>();
final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
final BluetoothDevice bluetoothDevice = mock(BluetoothDevice.class);
devices.add(bluetoothDevice);
- when(mHapProfile.getConnectedDevices()).thenReturn(devices);
+ when(mHapProfile.getConnectableDevices()).thenReturn(devices);
when(mCachedDeviceManager.findDevice(bluetoothDevice)).thenReturn(cachedDevice);
- when(cachedDevice.isConnected()).thenReturn(true);
+ when(cachedDevice.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+ when(mHapProfile.isPreferred(bluetoothDevice)).thenReturn(true);
assertThat(mMediaManager.mMediaDevices).isEmpty();
mMediaManager.startScan();
@@ -149,7 +152,7 @@
public void startScan_noHapProfileBluetoothDevice_shouldNotAddDevice() {
final List<BluetoothDevice> devices = new ArrayList<>();
- when(mHapProfile.getConnectedDevices()).thenReturn(devices);
+ when(mHapProfile.getConnectableDevices()).thenReturn(devices);
assertThat(mMediaManager.mMediaDevices).isEmpty();
mMediaManager.startScan();
@@ -230,9 +233,14 @@
public void onBluetoothStateChanged_bluetoothStateIsOff_callOnDeviceListRemoved() {
final BluetoothMediaDevice device1 = mock(BluetoothMediaDevice.class);
final BluetoothMediaDevice device2 = mock(BluetoothMediaDevice.class);
+ final CachedBluetoothDevice cachedDevice1 = mock(CachedBluetoothDevice.class);
+ final CachedBluetoothDevice cachedDevice2 = mock(CachedBluetoothDevice.class);
mMediaManager.mMediaDevices.add(device1);
mMediaManager.mMediaDevices.add(device2);
+ when(device1.getCachedDevice()).thenReturn(cachedDevice1);
+ when(device2.getCachedDevice()).thenReturn(cachedDevice2);
+
mMediaManager.registerCallback(mCallback);
mMediaManager.onBluetoothStateChanged(BluetoothAdapter.STATE_OFF);
@@ -311,28 +319,30 @@
}
@Test
- public void onProfileConnectionStateChanged_cachedDeviceIsConnect_callOnDeviceAdded() {
- final CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
-
- when(device.isConnectedHearingAidDevice()).thenReturn(true);
- when(device.isConnectedA2dpDevice()).thenReturn(true);
-
- assertThat(mMediaManager.mMediaDevices).isEmpty();
- mMediaManager.registerCallback(mCallback);
- mMediaManager.onProfileConnectionStateChanged(device, 0, 0);
-
- assertThat(mMediaManager.mMediaDevices).hasSize(1);
- verify(mCallback).onDeviceAdded(any());
- }
-
- @Test
- public void onProfileConnectionStateChanged_cachedDeviceIsDisconnect_callOnDeviceRemoved() {
+ public void onProfileConnectionStateChanged_cachedDeviceIsBonded_callDeviceAttributesChanged() {
final CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
final BluetoothMediaDevice bluetoothMediaDevice = mock(BluetoothMediaDevice.class);
mMediaManager.mMediaDevices.add(bluetoothMediaDevice);
- when(device.isConnectedHearingAidDevice()).thenReturn(false);
- when(device.isConnectedA2dpDevice()).thenReturn(false);
+ when(device.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+ when(device.getAddress()).thenReturn(TEST_ADDRESS);
+ when(bluetoothMediaDevice.getId()).thenReturn(TEST_ADDRESS);
+
+ assertThat(mMediaManager.mMediaDevices).hasSize(1);
+ mMediaManager.registerCallback(mCallback);
+ mMediaManager.onProfileConnectionStateChanged(device, 0, 0);
+
+ assertThat(mMediaManager.mMediaDevices).hasSize(1);
+ verify(mCallback).onDeviceAttributesChanged();
+ }
+
+ @Test
+ public void onProfileConnectionStateChanged_cachedDeviceIsBondNone_callOnDeviceRemoved() {
+ final CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
+ final BluetoothMediaDevice bluetoothMediaDevice = mock(BluetoothMediaDevice.class);
+ mMediaManager.mMediaDevices.add(bluetoothMediaDevice);
+
+ when(device.getBondState()).thenReturn(BluetoothDevice.BOND_NONE);
when(device.getAddress()).thenReturn(TEST_ADDRESS);
when(bluetoothMediaDevice.getId()).thenReturn(TEST_ADDRESS);
@@ -345,28 +355,30 @@
}
@Test
- public void onAclConnectionStateChanged_cachedDeviceIsConnect_callOnDeviceAdded() {
- final CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
-
- when(device.isConnectedHearingAidDevice()).thenReturn(true);
- when(device.isConnectedA2dpDevice()).thenReturn(true);
-
- assertThat(mMediaManager.mMediaDevices).isEmpty();
- mMediaManager.registerCallback(mCallback);
- mMediaManager.onAclConnectionStateChanged(device, 0);
-
- assertThat(mMediaManager.mMediaDevices).hasSize(1);
- verify(mCallback).onDeviceAdded(any());
- }
-
- @Test
- public void onAclConnectionStateChanged_cachedDeviceIsDisconnect_callOnDeviceRemoved() {
+ public void onAclConnectionStateChanged_cachedDeviceIsBonded_callDeviceAttributesChanged() {
final CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
final BluetoothMediaDevice bluetoothMediaDevice = mock(BluetoothMediaDevice.class);
mMediaManager.mMediaDevices.add(bluetoothMediaDevice);
- when(device.isConnectedHearingAidDevice()).thenReturn(false);
- when(device.isConnectedA2dpDevice()).thenReturn(false);
+ when(device.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+ when(device.getAddress()).thenReturn(TEST_ADDRESS);
+ when(bluetoothMediaDevice.getId()).thenReturn(TEST_ADDRESS);
+
+ assertThat(mMediaManager.mMediaDevices).hasSize(1);
+ mMediaManager.registerCallback(mCallback);
+ mMediaManager.onAclConnectionStateChanged(device, 0);
+
+ assertThat(mMediaManager.mMediaDevices).hasSize(1);
+ verify(mCallback).onDeviceAttributesChanged();
+ }
+
+ @Test
+ public void onAclConnectionStateChanged_cachedDeviceIsBondNone_callOnDeviceRemoved() {
+ final CachedBluetoothDevice device = mock(CachedBluetoothDevice.class);
+ final BluetoothMediaDevice bluetoothMediaDevice = mock(BluetoothMediaDevice.class);
+ mMediaManager.mMediaDevices.add(bluetoothMediaDevice);
+
+ when(device.getBondState()).thenReturn(BluetoothDevice.BOND_NONE);
when(device.getAddress()).thenReturn(TEST_ADDRESS);
when(bluetoothMediaDevice.getId()).thenReturn(TEST_ADDRESS);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
index 3556814..98bb74a 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java
@@ -28,6 +28,7 @@
import android.content.Context;
import com.android.settingslib.bluetooth.A2dpProfile;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
import com.android.settingslib.bluetooth.HearingAidProfile;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
@@ -113,6 +114,23 @@
}
@Test
+ public void connectDevice_bluetoothDeviceNotConnected_connectBluetoothDevice() {
+ final MediaDevice device = mock(BluetoothMediaDevice.class);
+ final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class);
+ mLocalMediaManager.mMediaDevices.add(device);
+
+ when(device.getId()).thenReturn(TEST_DEVICE_ID_1);
+ when(((BluetoothMediaDevice) device).getCachedDevice()).thenReturn(cachedDevice);
+ when(cachedDevice.isConnected()).thenReturn(false);
+ when(cachedDevice.isBusy()).thenReturn(false);
+
+ mLocalMediaManager.registerCallback(mCallback);
+ mLocalMediaManager.connectDevice(device);
+
+ verify(cachedDevice).connect(true);
+ }
+
+ @Test
public void getMediaDeviceById_idExist_shouldReturnMediaDevice() {
final MediaDevice device1 = mock(MediaDevice.class);
final MediaDevice device2 = mock(MediaDevice.class);
@@ -322,15 +340,6 @@
}
@Test
- public void onDeviceAttributesChanged_shouldDispatchDeviceListUpdate() {
- mLocalMediaManager.registerCallback(mCallback);
-
- mLocalMediaManager.mMediaDeviceCallback.onDeviceAttributesChanged();
-
- verify(mCallback).onDeviceListUpdate(any());
- }
-
- @Test
public void onConnectedDeviceChanged_connectedAndCurrentDeviceAreDifferent_notifyThemChanged() {
final MediaDevice device1 = mock(MediaDevice.class);
final MediaDevice device2 = mock(MediaDevice.class);
@@ -366,4 +375,13 @@
verify(mCallback, never()).onDeviceListUpdate(any());
}
+
+ @Test
+ public void onDeviceAttributesChanged_shouldDispatchDeviceListUpdate() {
+ mLocalMediaManager.registerCallback(mCallback);
+
+ mLocalMediaManager.mMediaDeviceCallback.onDeviceAttributesChanged();
+
+ verify(mCallback).onDeviceListUpdate(any());
+ }
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java
index fc514f0..23d2c74 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java
@@ -114,6 +114,12 @@
when(mCachedDevice1.getDevice()).thenReturn(mDevice1);
when(mCachedDevice2.getDevice()).thenReturn(mDevice2);
when(mCachedDevice3.getDevice()).thenReturn(mDevice3);
+ when(mCachedDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+ when(mCachedDevice1.isConnected()).thenReturn(true);
+ when(mCachedDevice2.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+ when(mCachedDevice2.isConnected()).thenReturn(true);
+ when(mCachedDevice3.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
+ when(mCachedDevice3.isConnected()).thenReturn(true);
when(mRouteInfo1.getId()).thenReturn(ROUTER_ID_1);
when(mRouteInfo2.getId()).thenReturn(ROUTER_ID_2);
when(mRouteInfo3.getId()).thenReturn(ROUTER_ID_3);
@@ -158,12 +164,25 @@
}
@Test
- public void compareTo_carKit_phone_carKitFirst() {
+ public void compareTo_carKit_phone_phoneFirst() {
when(mDevice1.getBluetoothClass()).thenReturn(mCarkitClass);
- mMediaDevices.add(mPhoneMediaDevice);
mMediaDevices.add(mBluetoothMediaDevice1);
+ mMediaDevices.add(mPhoneMediaDevice);
+ assertThat(mMediaDevices.get(0)).isEqualTo(mBluetoothMediaDevice1);
+ Collections.sort(mMediaDevices, COMPARATOR);
assertThat(mMediaDevices.get(0)).isEqualTo(mPhoneMediaDevice);
+ }
+
+ @Test
+ public void compareTo_carKitIsDisConnected_nonCarKitBluetooth_nonCarKitBluetoothFirst() {
+ when(mDevice1.getBluetoothClass()).thenReturn(mHeadreeClass);
+ when(mDevice2.getBluetoothClass()).thenReturn(mCarkitClass);
+ when(mCachedDevice2.isConnected()).thenReturn(false);
+ mMediaDevices.add(mBluetoothMediaDevice1);
+ mMediaDevices.add(mBluetoothMediaDevice2);
+
+ assertThat(mMediaDevices.get(0)).isEqualTo(mBluetoothMediaDevice1);
Collections.sort(mMediaDevices, COMPARATOR);
assertThat(mMediaDevices.get(0)).isEqualTo(mBluetoothMediaDevice1);
}
@@ -178,6 +197,7 @@
Collections.sort(mMediaDevices, COMPARATOR);
assertThat(mMediaDevices.get(0)).isEqualTo(mBluetoothMediaDevice2);
}
+
@Test
public void compareTo_connectionRecord_sortByRecord() {
mMediaDevices.add(mBluetoothMediaDevice1);
@@ -196,6 +216,25 @@
}
@Test
+ public void compareTo_sortByRecord_connectedDeviceFirst() {
+ mMediaDevices.add(mBluetoothMediaDevice1);
+ mMediaDevices.add(mBluetoothMediaDevice2);
+ when(mCachedDevice2.isConnected()).thenReturn(false);
+
+ mBluetoothMediaDevice1.connect();
+ mBluetoothMediaDevice2.connect();
+ mBluetoothMediaDevice2.connect();
+ // Reset last selected record
+ ConnectionRecordManager.getInstance().setConnectionRecord(mContext, null, 0);
+
+ assertThat(mMediaDevices.get(0)).isEqualTo(mBluetoothMediaDevice1);
+ assertThat(mMediaDevices.get(1)).isEqualTo(mBluetoothMediaDevice2);
+ Collections.sort(mMediaDevices, COMPARATOR);
+ assertThat(mMediaDevices.get(0)).isEqualTo(mBluetoothMediaDevice1);
+ assertThat(mMediaDevices.get(1)).isEqualTo(mBluetoothMediaDevice2);
+ }
+
+ @Test
public void compareTo_info_bluetooth_infoFirst() {
mMediaDevices.add(mBluetoothMediaDevice1);
mMediaDevices.add(mInfoMediaDevice1);
@@ -206,13 +245,13 @@
}
@Test
- public void compareTo_bluetooth_phone_bluetoothFirst() {
- mMediaDevices.add(mPhoneMediaDevice);
+ public void compareTo_bluetooth_phone_phoneFirst() {
mMediaDevices.add(mBluetoothMediaDevice1);
+ mMediaDevices.add(mPhoneMediaDevice);
- assertThat(mMediaDevices.get(0)).isEqualTo(mPhoneMediaDevice);
- Collections.sort(mMediaDevices, COMPARATOR);
assertThat(mMediaDevices.get(0)).isEqualTo(mBluetoothMediaDevice1);
+ Collections.sort(mMediaDevices, COMPARATOR);
+ assertThat(mMediaDevices.get(0)).isEqualTo(mPhoneMediaDevice);
}
@Test
@@ -235,6 +274,17 @@
assertThat(mMediaDevices.get(0)).isEqualTo(mBluetoothMediaDevice1);
}
+ @Test
+ public void compareTo_sortByAlphabet_connectDeviceFirst() {
+ mMediaDevices.add(mBluetoothMediaDevice2);
+ mMediaDevices.add(mBluetoothMediaDevice1);
+ when(mCachedDevice1.isConnected()).thenReturn(false);
+
+ assertThat(mMediaDevices.get(0)).isEqualTo(mBluetoothMediaDevice2);
+ Collections.sort(mMediaDevices, COMPARATOR);
+ assertThat(mMediaDevices.get(0)).isEqualTo(mBluetoothMediaDevice2);
+ }
+
// 1.mInfoMediaDevice1: Last Selected device
// 2.mBluetoothMediaDevice1: CarKit device
// 3.mInfoMediaDevice2: * 2 times usage
@@ -242,7 +292,7 @@
// 5.mBluetoothMediaDevice2: * 2 times usage
// 6.mBluetoothMediaDevice3: * 1 time usage
// 7.mPhoneMediaDevice: * 0 time usage
- // Order: 2 -> 1 -> 3 -> 5 -> 4 -> 6 -> 7
+ // Order: 7 -> 2 -> 1 -> 3 -> 5 -> 4 -> 6
@Test
public void compareTo_mixedDevices_carKitFirst() {
when(mDevice1.getBluetoothClass()).thenReturn(mCarkitClass);
@@ -264,13 +314,55 @@
mInfoMediaDevice1.connect();
Collections.sort(mMediaDevices, COMPARATOR);
- assertThat(mMediaDevices.get(0)).isEqualTo(mBluetoothMediaDevice1);
+ assertThat(mMediaDevices.get(0)).isEqualTo(mPhoneMediaDevice);
+ assertThat(mMediaDevices.get(1)).isEqualTo(mBluetoothMediaDevice1);
+ assertThat(mMediaDevices.get(2)).isEqualTo(mInfoMediaDevice1);
+ assertThat(mMediaDevices.get(3)).isEqualTo(mInfoMediaDevice2);
+ assertThat(mMediaDevices.get(4)).isEqualTo(mBluetoothMediaDevice2);
+ assertThat(mMediaDevices.get(5)).isEqualTo(mInfoMediaDevice3);
+ assertThat(mMediaDevices.get(6)).isEqualTo(mBluetoothMediaDevice3);
+ }
+
+ // 1.mInfoMediaDevice1: Last Selected device
+ // 2.mBluetoothMediaDevice1: CarKit device not connected
+ // 3.mInfoMediaDevice2: * 2 times usage
+ // 4.mInfoMediaDevice3: * 1 time usage
+ // 5.mBluetoothMediaDevice2: * 4 times usage not connected
+ // 6.mBluetoothMediaDevice3: * 1 time usage
+ // 7.mPhoneMediaDevice: * 0 time usage
+ // Order: 7 -> 1 -> 3 -> 4 -> 6 -> 2 -> 5
+ @Test
+ public void compareTo_mixedDevices_connectDeviceFirst() {
+ when(mDevice1.getBluetoothClass()).thenReturn(mCarkitClass);
+ when(mDevice2.getBluetoothClass()).thenReturn(mHeadreeClass);
+ when(mDevice3.getBluetoothClass()).thenReturn(mHeadreeClass);
+ when(mCachedDevice1.isConnected()).thenReturn(false);
+ when(mCachedDevice2.isConnected()).thenReturn(false);
+ mMediaDevices.add(mBluetoothMediaDevice1);
+ mMediaDevices.add(mBluetoothMediaDevice2);
+ mMediaDevices.add(mBluetoothMediaDevice3);
+ mMediaDevices.add(mInfoMediaDevice1);
+ mMediaDevices.add(mInfoMediaDevice2);
+ mMediaDevices.add(mInfoMediaDevice3);
+ mMediaDevices.add(mPhoneMediaDevice);
+ mBluetoothMediaDevice3.connect();
+ mBluetoothMediaDevice2.connect();
+ mBluetoothMediaDevice2.connect();
+ mBluetoothMediaDevice2.connect();
+ mBluetoothMediaDevice2.connect();
+ mInfoMediaDevice3.connect();
+ mInfoMediaDevice2.connect();
+ mInfoMediaDevice2.connect();
+ mInfoMediaDevice1.connect();
+
+ Collections.sort(mMediaDevices, COMPARATOR);
+ assertThat(mMediaDevices.get(0)).isEqualTo(mPhoneMediaDevice);
assertThat(mMediaDevices.get(1)).isEqualTo(mInfoMediaDevice1);
assertThat(mMediaDevices.get(2)).isEqualTo(mInfoMediaDevice2);
- assertThat(mMediaDevices.get(3)).isEqualTo(mBluetoothMediaDevice2);
- assertThat(mMediaDevices.get(4)).isEqualTo(mInfoMediaDevice3);
- assertThat(mMediaDevices.get(5)).isEqualTo(mBluetoothMediaDevice3);
- assertThat(mMediaDevices.get(6)).isEqualTo(mPhoneMediaDevice);
+ assertThat(mMediaDevices.get(3)).isEqualTo(mInfoMediaDevice3);
+ assertThat(mMediaDevices.get(4)).isEqualTo(mBluetoothMediaDevice3);
+ assertThat(mMediaDevices.get(5)).isEqualTo(mBluetoothMediaDevice1);
+ assertThat(mMediaDevices.get(6)).isEqualTo(mBluetoothMediaDevice2);
}
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaManagerTest.java
index 98eccb5..ead2be4 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaManagerTest.java
@@ -111,6 +111,15 @@
}
@Test
+ public void dispatchDataChanged_registerCallback_shouldDispatchCallback() {
+ mMediaManager.registerCallback(mCallback);
+
+ mMediaManager.dispatchDataChanged();
+
+ verify(mCallback).onDeviceAttributesChanged();
+ }
+
+ @Test
public void findMediaDevice_idExist_shouldReturnMediaDevice() {
mMediaManager.mMediaDevices.add(mDevice);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
index 5ba33f5..50a6a9d 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/PhoneMediaDeviceTest.java
@@ -23,6 +23,7 @@
import android.bluetooth.BluetoothDevice;
import android.content.Context;
+import com.android.settingslib.R;
import com.android.settingslib.bluetooth.A2dpProfile;
import com.android.settingslib.bluetooth.HearingAidProfile;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
@@ -97,4 +98,19 @@
assertThat(mPhoneMediaDevice.connect()).isFalse();
}
+
+ @Test
+ public void updateSummary_isActiveIsTrue_returnActiveString() {
+ mPhoneMediaDevice.updateSummary(true);
+
+ assertThat(mPhoneMediaDevice.getSummary())
+ .isEqualTo(mContext.getString(R.string.bluetooth_active_no_battery_level));
+ }
+
+ @Test
+ public void updateSummary_notActive_returnEmpty() {
+ mPhoneMediaDevice.updateSummary(false);
+
+ assertThat(mPhoneMediaDevice.getSummary()).isEmpty();
+ }
}
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index f54f716..c83cb59 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -872,9 +872,6 @@
<!-- Global actions grid layout -->
<dimen name="global_actions_grid_side_margin">4dp</dimen>
- <!-- Global actions panel -->
- <dimen name="global_actions_panel_top_margin">85dp</dimen>
-
<!-- The maximum offset in either direction that elements are moved horizontally to prevent
burn-in on AOD. -->
<dimen name="burn_in_prevention_offset_x">8dp</dimen>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index b985b6b..4adece9 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -287,7 +287,6 @@
<item name="*android:lockPatternStyle">@style/LockPatternStyle</item>
<item name="passwordStyle">@style/PasswordTheme</item>
<item name="backgroundProtectedStyle">@style/BackgroundProtectedStyle</item>
- <item name="android:forceDarkAllowed">false</item>
<!-- Needed for MediaRoute chooser dialog -->
<item name="*android:isLightTheme">false</item>
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 9b44066..b07f909 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -1557,8 +1557,6 @@
new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
- panelParams.topMargin = mContext.getResources().getDimensionPixelSize(
- com.android.systemui.R.dimen.global_actions_panel_top_margin);
panelContainer.addView(panelView, panelParams);
return panelContainer;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
index 7cbe1a3..059c3f6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
@@ -22,10 +22,12 @@
import android.app.NotificationManager;
import android.content.Context;
import android.database.ContentObserver;
+import android.hardware.display.AmbientDisplayConfiguration;
import android.os.Bundle;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.UserHandle;
import android.provider.Settings;
import android.service.dreams.DreamService;
import android.service.dreams.IDreamManager;
@@ -54,6 +56,7 @@
private final StatusBarStateController mStatusBarStateController =
Dependency.get(StatusBarStateController.class);
private final NotificationFilter mNotificationFilter = Dependency.get(NotificationFilter.class);
+ private final AmbientDisplayConfiguration mAmbientDisplayConfiguration;
private final Context mContext;
private final PowerManager mPowerManager;
@@ -73,17 +76,20 @@
this(context,
(PowerManager) context.getSystemService(Context.POWER_SERVICE),
IDreamManager.Stub.asInterface(
- ServiceManager.checkService(DreamService.DREAM_SERVICE)));
+ ServiceManager.checkService(DreamService.DREAM_SERVICE)),
+ new AmbientDisplayConfiguration(context));
}
@VisibleForTesting
protected NotificationInterruptionStateProvider(
Context context,
PowerManager powerManager,
- IDreamManager dreamManager) {
+ IDreamManager dreamManager,
+ AmbientDisplayConfiguration ambientDisplayConfiguration) {
mContext = context;
mPowerManager = powerManager;
mDreamManager = dreamManager;
+ mAmbientDisplayConfiguration = ambientDisplayConfiguration;
}
/** Sets up late-binding dependencies for this component. */
@@ -232,6 +238,13 @@
public boolean shouldPulse(NotificationEntry entry) {
StatusBarNotification sbn = entry.notification;
+ if (!mAmbientDisplayConfiguration.pulseOnNotificationEnabled(UserHandle.USER_CURRENT)) {
+ if (DEBUG) {
+ Log.d(TAG, "No pulsing: disabled by setting: " + sbn.getKey());
+ }
+ return false;
+ }
+
if (!getShadeController().isDozing()) {
if (DEBUG) {
Log.d(TAG, "No pulsing: not dozing: " + sbn.getKey());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 265fa2c..1949bad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -90,6 +90,10 @@
*/
public static final float GRADIENT_SCRIM_ALPHA = 0.2f;
/**
+ * Scrim opacity when the phone is about to wake-up.
+ */
+ public static final float AOD2_SCRIM_ALPHA = 0.6f;
+ /**
* A scrim varies its opacity based on a busyness factor, for example
* how many notifications are currently visible.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index ccf5e4e..2f161d5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -133,11 +133,10 @@
|| mPulseReason == DozeLog.PULSE_REASON_DOCKING
|| mPulseReason == DozeLog.PULSE_REASON_INTENT) {
mCurrentBehindAlpha = previousState.getBehindAlpha();
- mCurrentBehindTint = Color.BLACK;
} else {
- mCurrentBehindAlpha = mScrimBehindAlphaKeyguard;
- mCurrentBehindTint = Color.TRANSPARENT;
+ mCurrentBehindAlpha = ScrimController.AOD2_SCRIM_ALPHA;
}
+ mCurrentBehindTint = Color.BLACK;
mBlankScreen = mDisplayRequiresBlanking;
}
},
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 1832265..60b1659 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -3881,7 +3881,7 @@
return;
}
- boolean passiveAuthInterrupt = reason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN;
+ boolean passiveAuthInterrupt = reason == DozeLog.PULSE_REASON_NOTIFICATION;
// Set the state to pulsing, so ScrimController will know what to do once we ask it to
// execute the transition. The pulse callback will then be invoked when the scrims
// are black, indicating that StatusBar is ready to present the rest of the UI.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 7e5c3db..539851f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -232,7 +232,7 @@
// Back scrim should be semi-transparent so the user can see the wallpaper
// Pulse callback should have been invoked
assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_SEMI_TRANSPARENT);
- assertScrimTint(mScrimBehind, false /* tinted */);
+ assertScrimTint(mScrimBehind, true /* tinted */);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index f8bfc54..1ded6c9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -41,6 +41,7 @@
import android.app.StatusBarManager;
import android.app.trust.TrustManager;
import android.content.Context;
+import android.hardware.display.AmbientDisplayConfiguration;
import android.hardware.fingerprint.FingerprintManager;
import android.metrics.LogMaker;
import android.os.Binder;
@@ -169,6 +170,8 @@
private NotificationLogger.ExpansionStateLogger mExpansionStateLogger;
@Mock
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ @Mock
+ private AmbientDisplayConfiguration mAmbientDisplayConfiguration;
private TestableStatusBar mStatusBar;
private FakeMetricsLogger mMetricsLogger;
@@ -205,7 +208,7 @@
mNotificationInterruptionStateProvider =
new TestableNotificationInterruptionStateProvider(mContext, mPowerManager,
- mDreamManager);
+ mDreamManager, mAmbientDisplayConfiguration);
mDependency.injectTestDependency(NotificationInterruptionStateProvider.class,
mNotificationInterruptionStateProvider);
mDependency.injectMockDependency(NavigationBarController.class);
@@ -641,10 +644,10 @@
@Test
public void testPulseWhileDozing_notifyAuthInterrupt() {
HashSet<Integer> reasonsWantingAuth = new HashSet<>(
- Collections.singletonList(DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN));
+ Collections.singletonList(DozeLog.PULSE_REASON_NOTIFICATION));
HashSet<Integer> reasonsSkippingAuth = new HashSet<>(
Arrays.asList(DozeLog.PULSE_REASON_INTENT,
- DozeLog.PULSE_REASON_NOTIFICATION,
+ DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN,
DozeLog.PULSE_REASON_SENSOR_SIGMOTION,
DozeLog.REASON_SENSOR_PICKUP,
DozeLog.REASON_SENSOR_DOUBLE_TAP,
@@ -832,8 +835,9 @@
public TestableNotificationInterruptionStateProvider(
Context context,
PowerManager powerManager,
- IDreamManager dreamManager) {
- super(context, powerManager, dreamManager);
+ IDreamManager dreamManager,
+ AmbientDisplayConfiguration ambientDisplayConfiguration) {
+ super(context, powerManager, dreamManager, ambientDisplayConfiguration);
mUseHeadsUp = true;
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java
index 043b832..00d87c3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java
@@ -22,6 +22,7 @@
import static org.mockito.Mockito.when;
import android.os.SystemClock;
+import android.testing.TestableLooper;
import android.view.MotionEvent;
import androidx.test.filters.SmallTest;
@@ -35,13 +36,12 @@
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
+@TestableLooper.RunWithLooper
@SmallTest
-@Ignore
public class StatusBarWindowViewTest extends SysuiTestCase {
private StatusBarWindowView mView;
@@ -62,7 +62,6 @@
}
@Test
- @Ignore
public void testDragDownHelperCalledWhenDraggingDown() throws Exception {
when(Dependency.get(StatusBarStateController.class).getState())
.thenReturn(StatusBarState.SHADE);
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index f106ced..9f049cf 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -1798,6 +1798,9 @@
// Prediction horizon (in second) of Wifi usability score provided by external
// system app
optional int32 last_prediction_horizon_sec = 12 [default = -1];
+
+ // Whether screen status is on when WifiIsUnusableEvent happens.
+ optional bool screen_on = 13 [default = false];
}
message PasspointProfileTypeCount {
diff --git a/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java
index 58dbea4..69b4672 100644
--- a/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java
+++ b/services/contentsuggestions/java/com/android/server/contentsuggestions/ContentSuggestionsManagerService.java
@@ -32,6 +32,7 @@
import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.os.UserHandle;
+import android.os.UserManager;
import android.util.Slog;
import com.android.server.LocalServices;
@@ -63,7 +64,8 @@
public ContentSuggestionsManagerService(Context context) {
super(context, new FrameworkResourcesServiceNameResolver(context,
- com.android.internal.R.string.config_defaultContentSuggestionsService), null);
+ com.android.internal.R.string.config_defaultContentSuggestionsService),
+ UserManager.DISALLOW_CONTENT_SUGGESTIONS);
mActivityTaskManagerInternal = LocalServices.getService(ActivityTaskManagerInternal.class);
}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 9fa0053..d6fdbe3 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -1803,7 +1803,7 @@
synchronized (mRecords) {
TelephonyManager tm = (TelephonyManager) mContext.getSystemService(
Context.TELEPHONY_SERVICE);
- mEmergencyNumberList = tm.getCurrentEmergencyNumberList();
+ mEmergencyNumberList = tm.getEmergencyNumberList();
for (Record r : mRecords) {
if (r.matchPhoneStateListenerEvent(
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 5cca159..5d0fa26 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -111,6 +111,8 @@
// intensity level. It's important that we apply the scaling on the delta between the two so
// that the default intensity level applies no scaling to application provided effects.
private final SparseArray<ScaleLevel> mScaleLevels;
+ private final LinkedList<VibrationInfo> mPreviousRingVibrations;
+ private final LinkedList<VibrationInfo> mPreviousNotificationVibrations;
private final LinkedList<VibrationInfo> mPreviousVibrations;
private final int mPreviousVibrationsLimit;
private final boolean mAllowPriorityVibrationsInLowPowerMode;
@@ -354,6 +356,8 @@
mAllowPriorityVibrationsInLowPowerMode = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_allowPriorityVibrationsInLowPowerMode);
+ mPreviousRingVibrations = new LinkedList<>();
+ mPreviousNotificationVibrations = new LinkedList<>();
mPreviousVibrations = new LinkedList<>();
IntentFilter filter = new IntentFilter();
@@ -620,10 +624,19 @@
}
private void addToPreviousVibrationsLocked(Vibration vib) {
- if (mPreviousVibrations.size() > mPreviousVibrationsLimit) {
- mPreviousVibrations.removeFirst();
+ final LinkedList<VibrationInfo> previousVibrations;
+ if (vib.isRingtone()) {
+ previousVibrations = mPreviousRingVibrations;
+ } else if (vib.isNotification()) {
+ previousVibrations = mPreviousNotificationVibrations;
+ } else {
+ previousVibrations = mPreviousVibrations;
}
- mPreviousVibrations.addLast(vib.toInfo());
+
+ if (previousVibrations.size() > mPreviousVibrationsLimit) {
+ previousVibrations.removeFirst();
+ }
+ previousVibrations.addLast(vib.toInfo());
}
@Override // Binder call
@@ -1355,6 +1368,18 @@
pw.println(" mNotificationIntensity=" + mNotificationIntensity);
pw.println(" mRingIntensity=" + mRingIntensity);
pw.println("");
+ pw.println(" Previous ring vibrations:");
+ for (VibrationInfo info : mPreviousRingVibrations) {
+ pw.print(" ");
+ pw.println(info.toString());
+ }
+
+ pw.println(" Previous notification vibrations:");
+ for (VibrationInfo info : mPreviousNotificationVibrations) {
+ pw.print(" ");
+ pw.println(info.toString());
+ }
+
pw.println(" Previous vibrations:");
for (VibrationInfo info : mPreviousVibrations) {
pw.print(" ");
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 85322d6..57ce98c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -1674,8 +1674,9 @@
int runSwitchUser(PrintWriter pw) throws RemoteException {
UserManager userManager = mInternal.mContext.getSystemService(UserManager.class);
- if (!userManager.canSwitchUsers()) {
- getErrPrintWriter().println("Error: disallowed switching user");
+ final int userSwitchable = userManager.getUserSwitchability();
+ if (userSwitchable != UserManager.SWITCHABILITY_STATUS_OK) {
+ getErrPrintWriter().println("Error: " + userSwitchable);
return -1;
}
String user = getNextArgRequired();
diff --git a/services/core/java/com/android/server/am/BroadcastDispatcher.java b/services/core/java/com/android/server/am/BroadcastDispatcher.java
index b0b1840..d029482 100644
--- a/services/core/java/com/android/server/am/BroadcastDispatcher.java
+++ b/services/core/java/com/android/server/am/BroadcastDispatcher.java
@@ -450,6 +450,8 @@
return mCurrentBroadcast;
}
+ final boolean someQueued = !mOrderedBroadcasts.isEmpty();
+
BroadcastRecord next = null;
if (!mAlarmBroadcasts.isEmpty()) {
next = popLocked(mAlarmBroadcasts);
@@ -459,10 +461,18 @@
}
if (next == null && !mDeferredBroadcasts.isEmpty()) {
+ // We're going to deliver either:
+ // 1. the next "overdue" deferral; or
+ // 2. the next ordinary ordered broadcast; *or*
+ // 3. the next not-yet-overdue deferral.
+
for (int i = 0; i < mDeferredBroadcasts.size(); i++) {
Deferrals d = mDeferredBroadcasts.get(i);
- if (now < d.deferUntil) {
- // No more deferrals due
+ if (now < d.deferUntil && someQueued) {
+ // stop looking when we haven't hit the next time-out boundary
+ // but only if we have un-deferred broadcasts waiting,
+ // otherwise we can deliver whatever deferred broadcast
+ // is next available.
break;
}
@@ -483,7 +493,7 @@
}
}
- if (next == null && !mOrderedBroadcasts.isEmpty()) {
+ if (next == null && someQueued) {
next = mOrderedBroadcasts.remove(0);
if (DEBUG_BROADCAST_DEFERRAL) {
Slog.i(TAG, "Next broadcast from main queue: " + next);
diff --git a/services/core/java/com/android/server/connectivity/PacManager.java b/services/core/java/com/android/server/connectivity/PacManager.java
index 9789688..1ac09ad 100644
--- a/services/core/java/com/android/server/connectivity/PacManager.java
+++ b/services/core/java/com/android/server/connectivity/PacManager.java
@@ -70,9 +70,8 @@
private static final long MAX_PAC_SIZE = 20 * 1000 * 1000;
// Return values for #setCurrentProxyScriptUrl
- enum ToSendOrNotToSendBroadcast {
- DONT_SEND_BROADCAST, DO_SEND_BROADCAST
- }
+ public static final boolean DONT_SEND_BROADCAST = false;
+ public static final boolean DO_SEND_BROADCAST = true;
private String mCurrentPac;
@GuardedBy("mProxyLock")
@@ -176,11 +175,11 @@
* @param proxy Proxy information that is about to be broadcast.
* @return Returns whether the broadcast should be sent : either DO_ or DONT_SEND_BROADCAST
*/
- synchronized ToSendOrNotToSendBroadcast setCurrentProxyScriptUrl(ProxyInfo proxy) {
+ synchronized boolean setCurrentProxyScriptUrl(ProxyInfo proxy) {
if (!Uri.EMPTY.equals(proxy.getPacFileUrl())) {
if (proxy.getPacFileUrl().equals(mPacUrl) && (proxy.getPort() > 0)) {
// Allow to send broadcast, nothing to do.
- return ToSendOrNotToSendBroadcast.DO_SEND_BROADCAST;
+ return DO_SEND_BROADCAST;
}
mPacUrl = proxy.getPacFileUrl();
mCurrentDelay = DELAY_1;
@@ -188,7 +187,7 @@
mHasDownloaded = false;
getAlarmManager().cancel(mPacRefreshIntent);
bind();
- return ToSendOrNotToSendBroadcast.DONT_SEND_BROADCAST;
+ return DONT_SEND_BROADCAST;
} else {
getAlarmManager().cancel(mPacRefreshIntent);
synchronized (mProxyLock) {
@@ -204,7 +203,7 @@
}
}
}
- return ToSendOrNotToSendBroadcast.DO_SEND_BROADCAST;
+ return DO_SEND_BROADCAST;
}
}
diff --git a/services/core/java/com/android/server/connectivity/ProxyTracker.java b/services/core/java/com/android/server/connectivity/ProxyTracker.java
index a671287..e715890 100644
--- a/services/core/java/com/android/server/connectivity/ProxyTracker.java
+++ b/services/core/java/com/android/server/connectivity/ProxyTracker.java
@@ -208,8 +208,7 @@
public void sendProxyBroadcast() {
final ProxyInfo defaultProxy = getDefaultProxy();
final ProxyInfo proxyInfo = null != defaultProxy ? defaultProxy : new ProxyInfo("", 0, "");
- if (mPacManager.setCurrentProxyScriptUrl(proxyInfo)
- == PacManager.ToSendOrNotToSendBroadcast.DONT_SEND_BROADCAST) {
+ if (mPacManager.setCurrentProxyScriptUrl(proxyInfo) == PacManager.DONT_SEND_BROADCAST) {
return;
}
if (DBG) Slog.d(TAG, "sending Proxy Broadcast for " + proxyInfo);
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 1f28a6c..6d7dff5 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -216,7 +216,7 @@
private PackageManager mPackageManager;
public AutomaticBrightnessController(Callbacks callbacks, Looper looper,
- SensorManager sensorManager, BrightnessMappingStrategy mapper,
+ SensorManager sensorManager, Sensor lightSensor, BrightnessMappingStrategy mapper,
int lightSensorWarmUpTime, int brightnessMin, int brightnessMax, float dozeScaleFactor,
int lightSensorRate, int initialLightSensorRate, long brighteningLightDebounceConfig,
long darkeningLightDebounceConfig, boolean resetAmbientLuxAfterWarmUpConfig,
@@ -249,7 +249,7 @@
new AmbientLightRingBuffer(mNormalLightSensorRate, mAmbientLightHorizon);
if (!DEBUG_PRETEND_LIGHT_SENSOR_ABSENT) {
- mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
+ mLightSensor = lightSensor;
}
mActivityTaskManager = ActivityTaskManager.getService();
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index af4db07..b0d8813 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -664,6 +664,12 @@
private void updateDisplayModes(int displayId) {
Display d = mContext.getSystemService(DisplayManager.class).getDisplay(displayId);
+ if (d == null) {
+ // We can occasionally get a display added or changed event for a display that was
+ // subsequently removed, which means this returns null. Check this case and bail
+ // out early; if it gets re-attached we'll eventually get another call back for it.
+ return;
+ }
DisplayInfo info = new DisplayInfo();
d.getDisplayInfo(info);
boolean changed = false;
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 74cda9d..b79ead0 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -44,6 +44,7 @@
import android.os.Trace;
import android.os.UserHandle;
import android.provider.Settings;
+import android.text.TextUtils;
import android.util.MathUtils;
import android.util.Slog;
import android.util.TimeUtils;
@@ -58,6 +59,7 @@
import com.android.server.policy.WindowManagerPolicy;
import java.io.PrintWriter;
+import java.util.List;
/**
* Controls the power state of the display.
@@ -474,10 +476,14 @@
int shortTermModelTimeout = resources.getInteger(
com.android.internal.R.integer.config_autoBrightnessShortTermModelTimeout);
+ String lightSensorType = resources.getString(
+ com.android.internal.R.string.config_displayLightSensorType);
+ Sensor lightSensor = findDisplayLightSensor(lightSensorType);
+
mBrightnessMapper = BrightnessMappingStrategy.create(resources);
if (mBrightnessMapper != null) {
mAutomaticBrightnessController = new AutomaticBrightnessController(this,
- handler.getLooper(), sensorManager, mBrightnessMapper,
+ handler.getLooper(), sensorManager, lightSensor, mBrightnessMapper,
lightSensorWarmUpTimeConfig, mScreenBrightnessRangeMinimum,
mScreenBrightnessRangeMaximum, dozeScaleFactor, lightSensorRate,
initialLightSensorRate, brighteningLightDebounce, darkeningLightDebounce,
@@ -530,6 +536,19 @@
mDisplayWhiteBalanceController = displayWhiteBalanceController;
}
+ private Sensor findDisplayLightSensor(String sensorType) {
+ if (!TextUtils.isEmpty(sensorType)) {
+ List<Sensor> sensors = mSensorManager.getSensorList(Sensor.TYPE_ALL);
+ for (int i = 0; i < sensors.size(); i++) {
+ Sensor sensor = sensors.get(i);
+ if (sensorType.equals(sensor.getStringType())) {
+ return sensor;
+ }
+ }
+ }
+ return mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
+ }
+
/**
* Returns true if the proximity sensor screen-off function is available.
*/
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 2c361e1..150303a 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -4690,9 +4690,11 @@
private int handleShellCommandEnableDisableInputMethod(
@NonNull ShellCommand shellCommand, boolean enabled) {
final String id = shellCommand.getNextArgRequired();
-
final boolean previouslyEnabled;
synchronized (mMethodMap) {
+ if (!userHasDebugPriv(mSettings.getCurrentUserId(), shellCommand)) {
+ return ShellCommandResult.SUCCESS;
+ }
previouslyEnabled = setInputMethodEnabledLocked(id, enabled);
}
final PrintWriter pr = shellCommand.getOutPrintWriter();
@@ -4714,6 +4716,9 @@
private int handleShellCommandSetInputMethod(@NonNull ShellCommand shellCommand) {
final String id = shellCommand.getNextArgRequired();
synchronized (mMethodMap) {
+ if (!userHasDebugPriv(mSettings.getCurrentUserId(), shellCommand)) {
+ return ShellCommandResult.SUCCESS;
+ }
setInputMethodLocked(id, NOT_A_SUBTYPE_ID);
}
final PrintWriter pr = shellCommand.getOutPrintWriter();
@@ -4732,6 +4737,9 @@
@ShellCommandResult
private int handleShellCommandResetInputMethod(@NonNull ShellCommand shellCommand) {
synchronized (mMethodMap) {
+ if (!userHasDebugPriv(mSettings.getCurrentUserId(), shellCommand)) {
+ return ShellCommandResult.SUCCESS;
+ }
final String nextIme;
final List<InputMethodInfo> nextEnabledImes;
hideCurrentInputLocked(0, null);
@@ -4769,6 +4777,22 @@
}
}
+ /**
+ * @param userId the actual user handle obtained by {@link UserHandle#getIdentifier()}
+ * and *not* pseudo ids like {@link UserHandle#USER_ALL etc}.
+ * @return {@code true} if userId has debugging privileges.
+ * i.e. {@link UserManager#DISALLOW_DEBUGGING_FEATURES} is {@code false}.
+ */
+ private boolean userHasDebugPriv(int userId, final ShellCommand shellCommand) {
+ if (mUserManager.hasUserRestriction(
+ UserManager.DISALLOW_DEBUGGING_FEATURES, UserHandle.of(userId))) {
+ shellCommand.getErrPrintWriter().println("User #" + userId
+ + " is restricted with DISALLOW_DEBUGGING_FEATURES.");
+ return false;
+ }
+ return true;
+ }
+
private static final class InputMethodPrivilegedOperationsImpl
extends IInputMethodPrivilegedOperations.Stub {
private final InputMethodManagerService mImms;
diff --git a/services/core/java/com/android/server/location/GnssConfiguration.java b/services/core/java/com/android/server/location/GnssConfiguration.java
index 91b5234..0e9ee40 100644
--- a/services/core/java/com/android/server/location/GnssConfiguration.java
+++ b/services/core/java/com/android/server/location/GnssConfiguration.java
@@ -52,7 +52,6 @@
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- //TODO(b/33112647): Create gps_debug.conf with commented career parameters.
private static final String DEBUG_PROPERTIES_FILE = "/etc/gps_debug.conf";
// config.xml properties
@@ -191,8 +190,6 @@
return Collections.EMPTY_LIST;
}
- // TODO(b/122856486): Validate proxy app names so that a system app or some popular app
- // with location permission is not specified as a proxy app.
ArrayList proxyApps = new ArrayList(proxyAppsArray.length);
for (String proxyApp : proxyAppsArray) {
proxyApps.add(proxyApp);
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 29030fa..c173d66 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -67,6 +67,7 @@
import android.util.Log;
import android.util.StatsLog;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IBatteryStats;
import com.android.internal.location.GpsNetInitiatedHandler;
import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification;
@@ -890,12 +891,14 @@
return GPS_POSITION_MODE_STANDALONE;
}
- private boolean handleEnable() {
- if (DEBUG) Log.d(TAG, "handleEnable");
+ @GuardedBy("mLock")
+ private void handleEnableLocked() {
+ if (DEBUG) Log.d(TAG, "handleEnableLocked");
boolean inited = native_init();
if (inited) {
+ mEnabled = true;
mSupportsXtra = native_supports_xtra();
// TODO: remove the following native calls if we can make sure they are redundant.
@@ -912,15 +915,16 @@
mGnssNavigationMessageProvider.onGpsEnabledChanged();
mGnssBatchingProvider.enable();
} else {
+ mEnabled = false;
Log.w(TAG, "Failed to enable location provider");
}
-
- return inited;
}
- private void handleDisable() {
- if (DEBUG) Log.d(TAG, "handleDisable");
+ @GuardedBy("mLock")
+ private void handleDisableLocked() {
+ if (DEBUG) Log.d(TAG, "handleDisableLocked");
+ mEnabled = false;
updateClientUids(new WorkSource());
stopNavigating();
mAlarmManager.cancel(mWakeupIntent);
@@ -946,10 +950,9 @@
}
if (enabled) {
- mEnabled = handleEnable();
+ handleEnableLocked();
} else {
- mEnabled = false;
- handleDisable();
+ handleDisableLocked();
}
}
}
diff --git a/services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java b/services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java
index 90d16cb..c06b03b 100644
--- a/services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java
+++ b/services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java
@@ -373,8 +373,8 @@
networkAttributes = new NetworkAttributes();
networkAttributes.mCapabilities = capabilities;
- // TODO(b/119278134): The synchronous method ConnectivityManager.getNetworkInfo() must
- // not be called inside the asynchronous ConnectivityManager.NetworkCallback methods.
+ // TODO: The synchronous method ConnectivityManager.getNetworkInfo() should not be called
+ // inside the asynchronous ConnectivityManager.NetworkCallback methods.
NetworkInfo info = mConnMgr.getNetworkInfo(network);
if (info != null) {
networkAttributes.mApn = info.getExtraInfo();
@@ -387,8 +387,8 @@
}
private void handleSuplConnectionAvailable(Network network) {
- // TODO(b/119278134): The synchronous method ConnectivityManager.getNetworkInfo() must
- // not be called inside the asynchronous ConnectivityManager.NetworkCallback methods.
+ // TODO: The synchronous method ConnectivityManager.getNetworkInfo() should not be called
+ // inside the asynchronous ConnectivityManager.NetworkCallback methods.
NetworkInfo info = mConnMgr.getNetworkInfo(network);
String apn = null;
if (info != null) {
@@ -509,8 +509,8 @@
}
}
- // TODO(25876485): Delete this method when all devices upgrade to HAL @2.0::IAGnssCallback
- // interface which does not require setting route to host.
+ // TODO: Delete this method when all devices upgrade to HAL @2.0::IAGnssCallback
+ // interface which does not require setting route to host.
private void setRouting() {
boolean result = mConnMgr.requestRouteToHostAddress(
ConnectivityManager.TYPE_MOBILE_SUPL,
diff --git a/services/core/java/com/android/server/location/GnssVisibilityControl.java b/services/core/java/com/android/server/location/GnssVisibilityControl.java
index 20f872a..24ee389 100644
--- a/services/core/java/com/android/server/location/GnssVisibilityControl.java
+++ b/services/core/java/com/android/server/location/GnssVisibilityControl.java
@@ -18,7 +18,6 @@
import android.annotation.SuppressLint;
import android.app.AppOpsManager;
-import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -32,11 +31,11 @@
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.Log;
import android.util.StatsLog;
import java.util.Arrays;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -76,9 +75,9 @@
private boolean mIsDeviceLocationSettingsEnabled;
// Number of non-framework location access proxy apps is expected to be small (< 5).
- private static final int HASH_MAP_INITIAL_CAPACITY_PROXY_APP_TO_LOCATION_PERMISSIONS = 7;
- private HashMap<String, Boolean> mProxyAppToLocationPermissions = new HashMap<>(
- HASH_MAP_INITIAL_CAPACITY_PROXY_APP_TO_LOCATION_PERMISSIONS);
+ private static final int ARRAY_MAP_INITIAL_CAPACITY_PROXY_APP_TO_LOCATION_PERMISSIONS = 7;
+ private ArrayMap<String, Boolean> mProxyAppToLocationPermissions = new ArrayMap<>(
+ ARRAY_MAP_INITIAL_CAPACITY_PROXY_APP_TO_LOCATION_PERMISSIONS);
private PackageManager.OnPermissionsChangedListener mOnPermissionsChangedListener =
uid -> runOnHandler(() -> handlePermissionsChanged(uid));
@@ -97,10 +96,6 @@
}
void updateProxyApps(List<String> nfwLocationAccessProxyApps) {
- // NOTE: This class doesn't explicitly register and listen for SIM_STATE_CHANGED event
- // but rather piggy backs on the GnssLocationProvider SIM_STATE_CHANGED handling
- // so that the order of processing is preserved. GnssLocationProvider should
- // first load the new config parameters for the new SIM and then call this method.
runOnHandler(() -> handleUpdateProxyApps(nfwLocationAccessProxyApps));
}
@@ -246,15 +241,7 @@
// Represents NfwNotification structure in IGnssVisibilityControlCallback.hal
private static class NfwNotification {
- private static final String KEY_PROTOCOL_STACK = "ProtocolStack";
- private static final String KEY_OTHER_PROTOCOL_STACK_NAME = "OtherProtocolStackName";
- private static final String KEY_REQUESTOR = "Requestor";
- private static final String KEY_REQUESTOR_ID = "RequestorId";
- private static final String KEY_RESPONSE_TYPE = "ResponseType";
- private static final String KEY_IN_EMERGENCY_MODE = "InEmergencyMode";
- private static final String KEY_IS_CACHED_LOCATION = "IsCachedLocation";
-
- // This must match with NfwResponseType enum in IGnssVisibilityControlCallback.hal.
+ // These must match with NfwResponseType enum in IGnssVisibilityControlCallback.hal.
private static final byte NFW_RESPONSE_TYPE_REJECTED = 0;
private static final byte NFW_RESPONSE_TYPE_ACCEPTED_NO_LOCATION_PROVIDED = 1;
private static final byte NFW_RESPONSE_TYPE_ACCEPTED_LOCATION_PROVIDED = 2;
@@ -281,30 +268,14 @@
mIsCachedLocation = isCachedLocation;
}
- private void copyFieldsToIntent(Intent intent) {
- intent.putExtra(KEY_PROTOCOL_STACK, mProtocolStack);
- if (!TextUtils.isEmpty(mOtherProtocolStackName)) {
- intent.putExtra(KEY_OTHER_PROTOCOL_STACK_NAME, mOtherProtocolStackName);
- }
- intent.putExtra(KEY_REQUESTOR, mRequestor);
- if (!TextUtils.isEmpty(mRequestorId)) {
- intent.putExtra(KEY_REQUESTOR_ID, mRequestorId);
- }
- intent.putExtra(KEY_RESPONSE_TYPE, mResponseType);
- intent.putExtra(KEY_IN_EMERGENCY_MODE, mInEmergencyMode);
- if (mResponseType == NFW_RESPONSE_TYPE_ACCEPTED_LOCATION_PROVIDED) {
- intent.putExtra(KEY_IS_CACHED_LOCATION, mIsCachedLocation);
- }
- }
-
@SuppressLint("DefaultLocale")
public String toString() {
return String.format(
- "[Notification] proxyAppPackageName: %s, protocolStack: %d"
- + ", otherProtocolStackName: %s, requestor: %d, requestorId: %s"
- + ", responseType: %d, inEmergencyMode: %b, isCachedLocation: %b",
- mProxyAppPackageName, mProtocolStack, mOtherProtocolStackName,
- mRequestor, mRequestorId, mResponseType, mInEmergencyMode, mIsCachedLocation);
+ "{proxyAppPackageName: %s, protocolStack: %d, otherProtocolStackName: %s, "
+ + "requestor: %d, requestorId: %s, responseType: %s, inEmergencyMode:"
+ + " %b, isCachedLocation: %b}",
+ mProxyAppPackageName, mProtocolStack, mOtherProtocolStackName, mRequestor,
+ mRequestorId, getResponseTypeAsString(), mInEmergencyMode, mIsCachedLocation);
}
private String getResponseTypeAsString() {
@@ -405,7 +376,7 @@
}
private void handleNfwNotification(NfwNotification nfwNotification) {
- if (DEBUG) Log.d(TAG, nfwNotification.toString());
+ if (DEBUG) Log.d(TAG, "Non-framework location access notification: " + nfwNotification);
final String proxyAppPackageName = nfwNotification.mProxyAppPackageName;
Boolean isLocationPermissionEnabled = mProxyAppToLocationPermissions.get(
@@ -421,39 +392,27 @@
logEvent(nfwNotification, isPermissionMismatched);
if (TextUtils.isEmpty(proxyAppPackageName)) {
- Log.e(TAG, "ProxyAppPackageName field is not set. Not sending intent to proxy app for "
- + nfwNotification);
+ Log.e(TAG, "ProxyAppPackageName field is not set. AppOps service not notified "
+ + "for non-framework location access notification: " + nfwNotification);
return;
}
if (isLocationPermissionEnabled == null) {
- // App is not in the configured list.
- Log.e(TAG, "Could not find proxy app with name: " + proxyAppPackageName + " in the "
+ Log.w(TAG, "Could not find proxy app with name: " + proxyAppPackageName + " in the "
+ "value specified for config parameter: "
- + GnssConfiguration.CONFIG_NFW_PROXY_APPS + ". Not sending intent to proxy app"
- + " for " + nfwNotification);
- return;
- }
-
- // Send intent to non-framework location proxy app with notification information.
- final Intent intent = new Intent(
- proxyAppPackageName + NFW_INTENT_ACTION_NFW_LOCATION_ACCESS_SUFFIX);
- final String proxAppActivityName =
- proxyAppPackageName + NFW_PROXY_APP_PKG_ACTIVITY_NAME_SUFFIX;
- intent.setClassName(proxyAppPackageName, proxAppActivityName);
- intent.setType(NFW_INTENT_TYPE);
- nfwNotification.copyFieldsToIntent(intent);
-
- // Check if the proxy app is still installed.
- final Integer clsAppUid = getApplicationUid(proxyAppPackageName);
- if (clsAppUid == null || intent.resolveActivity(mPackageManager) == null) {
- Log.i(TAG, "Proxy application " + proxyAppPackageName + " and/or activity "
- + proxAppActivityName + " is not found. Not sending"
- + " intent to proxy app for " + nfwNotification);
+ + GnssConfiguration.CONFIG_NFW_PROXY_APPS + ". AppOps service not notified "
+ + "for non-framework location access notification: " + nfwNotification);
return;
}
// Display location icon attributed to this proxy app.
+ final Integer clsAppUid = getApplicationUid(proxyAppPackageName);
+ if (clsAppUid == null) {
+ Log.e(TAG, "Proxy app " + proxyAppPackageName + " is not found. AppOps service not "
+ + "notified for non-framework location access notification: "
+ + nfwNotification);
+ return;
+ }
mAppOps.noteOpNoThrow(AppOpsManager.OP_FINE_LOCATION, clsAppUid, proxyAppPackageName);
// Log proxy app permission mismatch between framework and GNSS HAL.
@@ -461,18 +420,8 @@
Log.w(TAG, "Permission mismatch. Framework proxy app " + proxyAppPackageName
+ " location permission is set to " + isLocationPermissionEnabled
+ " but GNSS non-framework location access response type is "
- + nfwNotification.getResponseTypeAsString() + " for " + nfwNotification);
- }
-
- // Notify proxy app.
- try {
- if (DEBUG) {
- Log.d(TAG, "Sending non-framework location access notification intent: " + intent);
- }
- mContext.startActivityAsUser(intent, UserHandle.getUserHandleForUid(clsAppUid));
- } catch (ActivityNotFoundException e) {
- Log.w(TAG, "Activity not found. Failed to send non-framework location access"
- + " notification intent to proxy app activity: " + proxAppActivityName);
+ + nfwNotification.getResponseTypeAsString() + " for notification: "
+ + nfwNotification);
}
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index b6995db..a53ab84 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -21,6 +21,7 @@
import static android.content.Context.KEYGUARD_SERVICE;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChangeCallback;
import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_ENABLED_KEY;
import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_HANDLE_KEY;
import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT;
@@ -2648,7 +2649,8 @@
}
}
- private long addEscrowToken(byte[] token, int userId) throws RemoteException {
+ private long addEscrowToken(byte[] token, int userId, EscrowTokenStateChangeCallback callback)
+ throws RemoteException {
if (DEBUG) Slog.d(TAG, "addEscrowToken: user=" + userId);
synchronized (mSpManager) {
enableSyntheticPasswordLocked();
@@ -2672,7 +2674,7 @@
throw new SecurityException("Escrow token is disabled on the current user");
}
}
- long handle = mSpManager.createTokenBasedSyntheticPassword(token, userId);
+ long handle = mSpManager.createTokenBasedSyntheticPassword(token, userId, callback);
if (auth != null) {
mSpManager.activateTokenBasedSyntheticPassword(handle, auth, userId);
}
@@ -2943,9 +2945,10 @@
private final class LocalService extends LockSettingsInternal {
@Override
- public long addEscrowToken(byte[] token, int userId) {
+ public long addEscrowToken(byte[] token, int userId,
+ EscrowTokenStateChangeCallback callback) {
try {
- return LockSettingsService.this.addEscrowToken(token, userId);
+ return LockSettingsService.this.addEscrowToken(token, userId, callback);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
index dbcfbcd..142ad53 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
@@ -16,6 +16,8 @@
package com.android.server.locksettings;
+import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChangeCallback;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.admin.DevicePolicyManager;
@@ -281,6 +283,7 @@
byte[] secdiscardableOnDisk;
byte[] weaverSecret;
byte[] aggregatedSecret;
+ EscrowTokenStateChangeCallback mCallback;
}
private final Context mContext;
@@ -746,7 +749,12 @@
private ArrayMap<Integer, ArrayMap<Long, TokenData>> tokenMap = new ArrayMap<>();
- public long createTokenBasedSyntheticPassword(byte[] token, int userId) {
+ /**
+ * Create a token based Synthetic password for the given user.
+ * @return
+ */
+ public long createTokenBasedSyntheticPassword(byte[] token, int userId,
+ @Nullable EscrowTokenStateChangeCallback changeCallback) {
long handle = generateHandle();
if (!tokenMap.containsKey(userId)) {
tokenMap.put(userId, new ArrayMap<>());
@@ -762,6 +770,7 @@
tokenData.weaverSecret = null;
}
tokenData.aggregatedSecret = transformUnderSecdiscardable(token, secdiscardable);
+ tokenData.mCallback = changeCallback;
tokenMap.get(userId).put(handle, tokenData);
return handle;
@@ -810,6 +819,9 @@
createSyntheticPasswordBlob(handle, SYNTHETIC_PASSWORD_TOKEN_BASED, authToken,
tokenData.aggregatedSecret, 0L, userId);
tokenMap.get(userId).remove(handle);
+ if (tokenData.mCallback != null) {
+ tokenData.mCallback.onEscrowTokenActivated(handle, userId);
+ }
return true;
}
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index 7a87a57..0c0c23a 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -1112,7 +1112,7 @@
binder.linkToDeath(info, 0);
added = mServices.add(info);
} catch (RemoteException e) {
- // already dead
+ Slog.e(TAG, "Failed to linkToDeath, already dead", e);
}
}
if (added) {
@@ -1144,6 +1144,11 @@
}
}
}
+
+ @Override
+ public void onNullBinding(ComponentName name) {
+ Slog.v(TAG, "onNullBinding() called with: name = [" + name + "]");
+ }
};
if (!mContext.bindServiceAsUser(intent,
serviceConnection,
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index d25360a..88e697c 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -251,7 +251,6 @@
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
-import java.util.function.Predicate;
/** {@hide} */
public class NotificationManagerService extends SystemService {
@@ -759,7 +758,7 @@
synchronized (mNotificationLock) {
NotificationRecord r = mNotificationsByKey.get(key);
if (r == null) {
- Log.w(TAG, "No notification with key: " + key);
+ Slog.w(TAG, "No notification with key: " + key);
return;
}
final long now = System.currentTimeMillis();
@@ -789,7 +788,7 @@
synchronized (mNotificationLock) {
NotificationRecord r = mNotificationsByKey.get(key);
if (r == null) {
- Log.w(TAG, "No notification with key: " + key);
+ Slog.w(TAG, "No notification with key: " + key);
return;
}
final long now = System.currentTimeMillis();
@@ -3133,7 +3132,7 @@
synchronized (mNotificationLock) {
final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token);
if (info.supportsProfiles()) {
- Log.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
+ Slog.e(TAG, "Ignoring deprecated cancelNotification(pkg, tag, id) "
+ "from " + info.component
+ " use cancelNotification(key) instead.");
} else {
@@ -4553,7 +4552,7 @@
+ ", incomingUserId=" + incomingUserId
+ ", notificationUid=" + notificationUid
+ ", notification=" + notification;
- Log.e(TAG, noChannelStr);
+ Slog.e(TAG, noChannelStr);
boolean appNotificationsOff = mPreferencesHelper.getImportance(pkg, notificationUid)
== NotificationManager.IMPORTANCE_NONE;
@@ -4650,7 +4649,7 @@
android.Manifest.permission.USE_FULL_SCREEN_INTENT, pkg);
if (fullscreenIntentPermission != PERMISSION_GRANTED) {
notification.fullScreenIntent = null;
- Log.w(TAG, "Package " + pkg +
+ Slog.w(TAG, "Package " + pkg +
": Use of fullScreenIntent requires the USE_FULL_SCREEN_INTENT permission");
}
}
@@ -5179,7 +5178,7 @@
// Ignore summary updates because we don't display most of the information.
if (r.sbn.isGroup() && r.sbn.getNotification().isGroupSummary()) {
if (DEBUG_INTERRUPTIVENESS) {
- Log.v(TAG, "INTERRUPTIVENESS: "
+ Slog.v(TAG, "INTERRUPTIVENESS: "
+ r.getKey() + " is not interruptive: summary");
}
return false;
@@ -5187,7 +5186,7 @@
if (old == null) {
if (DEBUG_INTERRUPTIVENESS) {
- Log.v(TAG, "INTERRUPTIVENESS: "
+ Slog.v(TAG, "INTERRUPTIVENESS: "
+ r.getKey() + " is interruptive: new notification");
}
return true;
@@ -5195,7 +5194,7 @@
if (r == null) {
if (DEBUG_INTERRUPTIVENESS) {
- Log.v(TAG, "INTERRUPTIVENESS: "
+ Slog.v(TAG, "INTERRUPTIVENESS: "
+ r.getKey() + " is not interruptive: null");
}
return false;
@@ -5206,7 +5205,7 @@
if (oldN.extras == null || newN.extras == null) {
if (DEBUG_INTERRUPTIVENESS) {
- Log.v(TAG, "INTERRUPTIVENESS: "
+ Slog.v(TAG, "INTERRUPTIVENESS: "
+ r.getKey() + " is not interruptive: no extras");
}
return false;
@@ -5216,7 +5215,7 @@
// consider them one 'session'. Count them for everything else.
if ((r.sbn.getNotification().flags & FLAG_FOREGROUND_SERVICE) != 0) {
if (DEBUG_INTERRUPTIVENESS) {
- Log.v(TAG, "INTERRUPTIVENESS: "
+ Slog.v(TAG, "INTERRUPTIVENESS: "
+ r.getKey() + " is not interruptive: foreground service");
}
return false;
@@ -5226,11 +5225,11 @@
final String newTitle = String.valueOf(newN.extras.get(Notification.EXTRA_TITLE));
if (!Objects.equals(oldTitle, newTitle)) {
if (DEBUG_INTERRUPTIVENESS) {
- Log.v(TAG, "INTERRUPTIVENESS: "
+ Slog.v(TAG, "INTERRUPTIVENESS: "
+ r.getKey() + " is interruptive: changed title");
- Log.v(TAG, "INTERRUPTIVENESS: " + String.format(" old title: %s (%s@0x%08x)",
+ Slog.v(TAG, "INTERRUPTIVENESS: " + String.format(" old title: %s (%s@0x%08x)",
oldTitle, oldTitle.getClass(), oldTitle.hashCode()));
- Log.v(TAG, "INTERRUPTIVENESS: " + String.format(" new title: %s (%s@0x%08x)",
+ Slog.v(TAG, "INTERRUPTIVENESS: " + String.format(" new title: %s (%s@0x%08x)",
newTitle, newTitle.getClass(), newTitle.hashCode()));
}
return true;
@@ -5240,18 +5239,18 @@
final String newText = String.valueOf(newN.extras.get(Notification.EXTRA_TEXT));
if (!Objects.equals(oldText, newText)) {
if (DEBUG_INTERRUPTIVENESS) {
- Log.v(TAG, "INTERRUPTIVENESS: "
+ Slog.v(TAG, "INTERRUPTIVENESS: "
+ r.getKey() + " is interruptive: changed text");
- Log.v(TAG, "INTERRUPTIVENESS: " + String.format(" old text: %s (%s@0x%08x)",
+ Slog.v(TAG, "INTERRUPTIVENESS: " + String.format(" old text: %s (%s@0x%08x)",
oldText, oldText.getClass(), oldText.hashCode()));
- Log.v(TAG, "INTERRUPTIVENESS: " + String.format(" new text: %s (%s@0x%08x)",
+ Slog.v(TAG, "INTERRUPTIVENESS: " + String.format(" new text: %s (%s@0x%08x)",
newText, newText.getClass(), newText.hashCode()));
}
return true;
}
if (oldN.hasCompletedProgress() != newN.hasCompletedProgress()) {
if (DEBUG_INTERRUPTIVENESS) {
- Log.v(TAG, "INTERRUPTIVENESS: "
+ Slog.v(TAG, "INTERRUPTIVENESS: "
+ r.getKey() + " is interruptive: completed progress");
}
return true;
@@ -5259,7 +5258,7 @@
// Actions
if (Notification.areActionsVisiblyDifferent(oldN, newN)) {
if (DEBUG_INTERRUPTIVENESS) {
- Log.v(TAG, "INTERRUPTIVENESS: "
+ Slog.v(TAG, "INTERRUPTIVENESS: "
+ r.getKey() + " is interruptive: changed actions");
}
return true;
@@ -5272,7 +5271,7 @@
// Style based comparisons
if (Notification.areStyledNotificationsVisiblyDifferent(oldB, newB)) {
if (DEBUG_INTERRUPTIVENESS) {
- Log.v(TAG, "INTERRUPTIVENESS: "
+ Slog.v(TAG, "INTERRUPTIVENESS: "
+ r.getKey() + " is interruptive: styles differ");
}
return true;
@@ -5281,7 +5280,7 @@
// Remote views
if (Notification.areRemoteViewsChanged(oldB, newB)) {
if (DEBUG_INTERRUPTIVENESS) {
- Log.v(TAG, "INTERRUPTIVENESS: "
+ Slog.v(TAG, "INTERRUPTIVENESS: "
+ r.getKey() + " is interruptive: remoteviews differ");
}
return true;
@@ -5510,12 +5509,12 @@
// Ignore summary updates because we don't display most of the information.
if (record.sbn.isGroup() && record.sbn.getNotification().isGroupSummary()) {
if (DEBUG_INTERRUPTIVENESS) {
- Log.v(TAG, "INTERRUPTIVENESS: "
+ Slog.v(TAG, "INTERRUPTIVENESS: "
+ record.getKey() + " is not interruptive: summary");
}
} else {
if (DEBUG_INTERRUPTIVENESS) {
- Log.v(TAG, "INTERRUPTIVENESS: "
+ Slog.v(TAG, "INTERRUPTIVENESS: "
+ record.getKey() + " is interruptive: alerted");
}
record.setInterruptive(true);
@@ -6603,7 +6602,7 @@
String pkg = r.sbn.getPackageName();
if (pkg == null) {
- if (DBG) Log.e(TAG, "No package for group summary: " + r.getKey());
+ if (DBG) Slog.e(TAG, "No package for group summary: " + r.getKey());
return;
}
@@ -6862,7 +6861,7 @@
return;
}
} catch (RemoteException re) {
- if (DBG) Log.e(TAG, "Unable to confirm if it's safe to skip category "
+ if (DBG) Slog.e(TAG, "Unable to confirm if it's safe to skip category "
+ "restrictions check thus the check will be done anyway");
}
if (Notification.CATEGORY_CAR_EMERGENCY.equals(notification.category)
@@ -7104,7 +7103,7 @@
canUseManagedServices = false;
}
} catch (RemoteException e) {
- Log.e(TAG, "can't talk to pm", e);
+ Slog.e(TAG, "can't talk to pm", e);
}
}
@@ -7247,21 +7246,29 @@
try {
assistant.onNotificationsSeen(keys);
} catch (RemoteException ex) {
- Log.e(TAG, "unable to notify assistant (seen): " + assistant, ex);
+ Slog.e(TAG, "unable to notify assistant (seen): " + assistant, ex);
}
}
@GuardedBy("mNotificationLock")
private void onNotificationEnqueuedLocked(final NotificationRecord r) {
+ final boolean debug = isVerboseLogEnabled();
+ if (debug) {
+ Slog.v(TAG, "onNotificationEnqueuedLocked() called with: r = [" + r + "]");
+ }
final StatusBarNotification sbn = r.sbn;
notifyAssistantLocked(
sbn,
true /* sameUserOnly */,
(assistant, sbnHolder) -> {
try {
+ if (debug) {
+ Slog.v(TAG,
+ "calling onNotificationEnqueuedWithChannel " + sbnHolder);
+ }
assistant.onNotificationEnqueuedWithChannel(sbnHolder, r.getChannel());
} catch (RemoteException ex) {
- Log.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
+ Slog.e(TAG, "unable to notify assistant (enqueued): " + assistant, ex);
}
});
}
@@ -7279,7 +7286,7 @@
try {
assistant.onNotificationExpansionChanged(key, isUserAction, isExpanded);
} catch (RemoteException ex) {
- Log.e(TAG, "unable to notify assistant (expanded): " + assistant, ex);
+ Slog.e(TAG, "unable to notify assistant (expanded): " + assistant, ex);
}
});
}
@@ -7295,7 +7302,7 @@
try {
assistant.onNotificationDirectReply(key);
} catch (RemoteException ex) {
- Log.e(TAG, "unable to notify assistant (expanded): " + assistant, ex);
+ Slog.e(TAG, "unable to notify assistant (expanded): " + assistant, ex);
}
});
}
@@ -7316,7 +7323,7 @@
? NotificationAssistantService.SOURCE_FROM_ASSISTANT
: NotificationAssistantService.SOURCE_FROM_APP);
} catch (RemoteException ex) {
- Log.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
+ Slog.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
}
});
}
@@ -7338,7 +7345,7 @@
? NotificationAssistantService.SOURCE_FROM_ASSISTANT
: NotificationAssistantService.SOURCE_FROM_APP);
} catch (RemoteException ex) {
- Log.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
+ Slog.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
}
});
}
@@ -7358,7 +7365,7 @@
assistant.onNotificationSnoozedUntilContext(
sbnHolder, snoozeCriterionId);
} catch (RemoteException ex) {
- Log.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
+ Slog.e(TAG, "unable to notify assistant (snoozed): " + assistant, ex);
}
});
}
@@ -7380,9 +7387,19 @@
TrimCache trimCache = new TrimCache(sbn);
// There should be only one, but it's a list, so while we enforce
// singularity elsewhere, we keep it general here, to avoid surprises.
+
+ final boolean debug = isVerboseLogEnabled();
+ if (debug) {
+ Slog.v(TAG,
+ "notifyAssistantLocked() called with: sbn = [" + sbn + "], sameUserOnly = ["
+ + sameUserOnly + "], callback = [" + callback + "]");
+ }
for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
boolean sbnVisible = isVisibleToListener(sbn, info)
&& (!sameUserOnly || info.isSameUser(sbn.getUserId()));
+ if (debug) {
+ Slog.v(TAG, "notifyAssistantLocked info=" + info + " snbVisible=" + sbnVisible);
+ }
if (!sbnVisible) {
continue;
}
@@ -7436,6 +7453,10 @@
}
}
}
+
+ private boolean isVerboseLogEnabled() {
+ return Log.isLoggable("notification_assistant", Log.VERBOSE);
+ }
}
public class NotificationListeners extends ManagedServices {
@@ -7530,7 +7551,7 @@
try {
listener.onStatusBarIconsBehaviorChanged(hideSilentStatusIcons);
} catch (RemoteException ex) {
- Log.e(TAG, "unable to notify listener "
+ Slog.e(TAG, "unable to notify listener "
+ "(hideSilentStatusIcons): " + listener, ex);
}
});
@@ -7824,7 +7845,7 @@
try {
listener.onNotificationPosted(sbnHolder, rankingUpdate);
} catch (RemoteException ex) {
- Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
+ Slog.e(TAG, "unable to notify listener (posted): " + listener, ex);
}
}
@@ -7838,7 +7859,7 @@
try {
listener.onNotificationRemoved(sbnHolder, rankingUpdate, stats, reason);
} catch (RemoteException ex) {
- Log.e(TAG, "unable to notify listener (removed): " + listener, ex);
+ Slog.e(TAG, "unable to notify listener (removed): " + listener, ex);
}
}
@@ -7848,7 +7869,7 @@
try {
listener.onNotificationRankingUpdate(rankingUpdate);
} catch (RemoteException ex) {
- Log.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
+ Slog.e(TAG, "unable to notify listener (ranking update): " + listener, ex);
}
}
@@ -7857,7 +7878,7 @@
try {
listener.onListenerHintsChanged(hints);
} catch (RemoteException ex) {
- Log.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
+ Slog.e(TAG, "unable to notify listener (listener hints): " + listener, ex);
}
}
@@ -7867,7 +7888,7 @@
try {
listener.onInterruptionFilterChanged(interruptionFilter);
} catch (RemoteException ex) {
- Log.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
+ Slog.e(TAG, "unable to notify listener (interruption filter): " + listener, ex);
}
}
@@ -7878,7 +7899,7 @@
try {
listener.onNotificationChannelModification(pkg, user, channel, modificationType);
} catch (RemoteException ex) {
- Log.e(TAG, "unable to notify listener (channel changed): " + listener, ex);
+ Slog.e(TAG, "unable to notify listener (channel changed): " + listener, ex);
}
}
@@ -7889,7 +7910,7 @@
try {
listener.onNotificationChannelGroupModification(pkg, user, group, modificationType);
} catch (RemoteException ex) {
- Log.e(TAG, "unable to notify listener (channel group changed): " + listener, ex);
+ Slog.e(TAG, "unable to notify listener (channel group changed): " + listener, ex);
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 48818f5..46ce4bf 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -637,25 +637,17 @@
final ArrayList<String> people =
adjustment.getSignals().getStringArrayList(Adjustment.KEY_PEOPLE);
setPeopleOverride(people);
- MetricsLogger.action(getAdjustmentLogMaker()
- .addTaggedData(MetricsEvent.ADJUSTMENT_KEY_PEOPLE, people.size()));
}
if (signals.containsKey(Adjustment.KEY_SNOOZE_CRITERIA)) {
final ArrayList<SnoozeCriterion> snoozeCriterionList =
adjustment.getSignals().getParcelableArrayList(
Adjustment.KEY_SNOOZE_CRITERIA);
setSnoozeCriteria(snoozeCriterionList);
- MetricsLogger.action(getAdjustmentLogMaker()
- .addTaggedData(MetricsEvent.ADJUSTMENT_KEY_SNOOZE_CRITERIA,
- snoozeCriterionList.size()));
}
if (signals.containsKey(Adjustment.KEY_GROUP_KEY)) {
final String groupOverrideKey =
adjustment.getSignals().getString(Adjustment.KEY_GROUP_KEY);
setOverrideGroupKey(groupOverrideKey);
- MetricsLogger.action(getAdjustmentLogMaker()
- .addTaggedData(MetricsEvent.ADJUSTMENT_KEY_GROUP_KEY,
- groupOverrideKey));
}
if (signals.containsKey(Adjustment.KEY_USER_SENTIMENT)) {
// Only allow user sentiment update from assistant if user hasn't already
@@ -664,32 +656,20 @@
&& (getChannel().getUserLockedFields() & USER_LOCKED_IMPORTANCE) == 0) {
setUserSentiment(adjustment.getSignals().getInt(
Adjustment.KEY_USER_SENTIMENT, USER_SENTIMENT_NEUTRAL));
- MetricsLogger.action(getAdjustmentLogMaker()
- .addTaggedData(MetricsEvent.ADJUSTMENT_KEY_USER_SENTIMENT,
- getUserSentiment()));
}
}
if (signals.containsKey(Adjustment.KEY_CONTEXTUAL_ACTIONS)) {
setSystemGeneratedSmartActions(
signals.getParcelableArrayList(Adjustment.KEY_CONTEXTUAL_ACTIONS));
- MetricsLogger.action(getAdjustmentLogMaker()
- .addTaggedData(MetricsEvent.ADJUSTMENT_KEY_SMART_ACTIONS,
- getSystemGeneratedSmartActions().size()));
}
if (signals.containsKey(Adjustment.KEY_TEXT_REPLIES)) {
setSmartReplies(signals.getCharSequenceArrayList(Adjustment.KEY_TEXT_REPLIES));
- MetricsLogger.action(getAdjustmentLogMaker()
- .addTaggedData(MetricsEvent.ADJUSTMENT_KEY_SMART_REPLIES,
- getSmartReplies().size()));
}
if (signals.containsKey(Adjustment.KEY_IMPORTANCE)) {
int importance = signals.getInt(Adjustment.KEY_IMPORTANCE);
importance = Math.max(IMPORTANCE_UNSPECIFIED, importance);
importance = Math.min(IMPORTANCE_HIGH, importance);
setAssistantImportance(importance);
- MetricsLogger.action(getAdjustmentLogMaker()
- .addTaggedData(MetricsEvent.ADJUSTMENT_KEY_IMPORTANCE,
- importance));
}
}
// We have now gotten all the information out of the adjustments and can forget them.
@@ -1280,12 +1260,6 @@
return getLogMaker().setCategory(MetricsEvent.NOTIFICATION_ITEM);
}
- public LogMaker getAdjustmentLogMaker() {
- return getLogMaker()
- .setCategory(MetricsEvent.NOTIFICATION_ITEM)
- .setType(MetricsEvent.TYPE_NOTIFICATION_ASSISTANT_ADJUSTMENT);
- }
-
@VisibleForTesting
static final class Light {
public final int color;
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 22a85eb..4ee6eaf 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -35,6 +35,7 @@
import android.content.pm.ParceledListSlice;
import android.content.pm.Signature;
import android.content.rollback.IRollbackManager;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -117,9 +118,11 @@
final PackageInfo packageInfo = mApexManager.getActivePackage(packageName);
if (packageInfo == null) {
- // TODO: What is the right thing to do here ? This implies there's no active package
- // with the given name. This should never be the case in production (where we only
- // accept updates to existing APEXes) but may be required for testing.
+ // Only allow installing new apexes if on a debuggable build.
+ if (!Build.IS_DEBUGGABLE) {
+ Slog.w(TAG, "Attempted to install new apex " + packageName + " on user build");
+ return false;
+ }
return true;
}
@@ -498,19 +501,21 @@
Slog.w(TAG, "Cannot abort applied session!");
return;
}
- if (isStagedSessionFinalized(session.sessionId)) {
- Slog.w(TAG, "Cannot abort session because it is not active or APEXD is not reachable");
- return;
- }
-
- mApexManager.abortActiveSession();
-
abortSession(session);
+
+ boolean hasApex = sessionContainsApex(session);
+ if (hasApex) {
+ ApexSessionInfo apexSession = mApexManager.getStagedSessionInfo(session.sessionId);
+ if (apexSession == null || isApexSessionFinalized(apexSession)) {
+ Slog.w(TAG,
+ "Cannot abort session because it is not active or APEXD is not reachable");
+ return;
+ }
+ mApexManager.abortActiveSession();
+ }
}
- private boolean isStagedSessionFinalized(int sessionId) {
- ApexSessionInfo session = mApexManager.getStagedSessionInfo(sessionId);
-
+ private boolean isApexSessionFinalized(ApexSessionInfo session) {
/* checking if the session is in a final state, i.e., not active anymore */
return session.isUnknown || session.isActivationFailed || session.isSuccess
|| session.isRolledBack;
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 7e4365d..ae4ff03 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -120,6 +120,7 @@
UserManager.DISALLOW_UNMUTE_DEVICE,
UserManager.DISALLOW_AUTOFILL,
UserManager.DISALLOW_CONTENT_CAPTURE,
+ UserManager.DISALLOW_CONTENT_SUGGESTIONS,
UserManager.DISALLOW_USER_SWITCH,
UserManager.DISALLOW_UNIFIED_PASSWORD,
UserManager.DISALLOW_CONFIG_LOCATION,
diff --git a/services/core/java/com/android/server/power/ThermalManagerService.java b/services/core/java/com/android/server/power/ThermalManagerService.java
index 7d03d82..16d11ef 100644
--- a/services/core/java/com/android/server/power/ThermalManagerService.java
+++ b/services/core/java/com/android/server/power/ThermalManagerService.java
@@ -89,9 +89,6 @@
@GuardedBy("mLock")
private ArrayMap<String, Temperature> mTemperatureMap = new ArrayMap<>();
- /** Local PMS handle. */
- private final PowerManager mPowerManager;
-
/** HAL wrapper. */
private ThermalHalWrapper mHalWrapper;
@@ -109,7 +106,6 @@
@VisibleForTesting
ThermalManagerService(Context context, @Nullable ThermalHalWrapper halWrapper) {
super(context);
- mPowerManager = context.getSystemService(PowerManager.class);
mHalWrapper = halWrapper;
// Initialize to invalid to send status onActivityManagerReady
mStatus = INVALID_THROTTLING;
@@ -254,10 +250,11 @@
}
}
- private void shutdownIfNeededLocked(Temperature temperature) {
+ private void shutdownIfNeeded(Temperature temperature) {
if (temperature.getStatus() != Temperature.THROTTLING_SHUTDOWN) {
return;
}
+ final PowerManager powerManager = getContext().getSystemService(PowerManager.class);
switch (temperature.getType()) {
case Temperature.TYPE_CPU:
// Fall through
@@ -266,17 +263,17 @@
case Temperature.TYPE_NPU:
// Fall through
case Temperature.TYPE_SKIN:
- mPowerManager.shutdown(false, PowerManager.SHUTDOWN_THERMAL_STATE, false);
+ powerManager.shutdown(false, PowerManager.SHUTDOWN_THERMAL_STATE, false);
break;
case Temperature.TYPE_BATTERY:
- mPowerManager.shutdown(false, PowerManager.SHUTDOWN_BATTERY_THERMAL_STATE, false);
+ powerManager.shutdown(false, PowerManager.SHUTDOWN_BATTERY_THERMAL_STATE, false);
break;
}
}
private void onTemperatureChanged(Temperature temperature, boolean sendStatus) {
+ shutdownIfNeeded(temperature);
synchronized (mLock) {
- shutdownIfNeededLocked(temperature);
Temperature old = mTemperatureMap.put(temperature.getName(), temperature);
if (old != null) {
if (old.getStatus() != temperature.getStatus()) {
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index 059e6d7..f4e10ed 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -27,7 +27,6 @@
import android.app.AppOpsManager;
import android.app.role.IOnRoleHoldersChangedListener;
import android.app.role.IRoleManager;
-import android.app.role.IRoleManagerCallback;
import android.app.role.RoleControllerManager;
import android.app.role.RoleManager;
import android.content.BroadcastReceiver;
@@ -245,14 +244,11 @@
// Run grants again
Slog.i(LOG_TAG, "Granting default permissions...");
CompletableFuture<Void> result = new CompletableFuture<>();
- getOrCreateControllerService(userId).onGrantDefaultRoles(
- new IRoleManagerCallback.Stub() {
- @Override
- public void onSuccess() {
+ getOrCreateControllerService(userId).grantDefaultRoles(FgThread.getExecutor(),
+ successful -> {
+ if (successful) {
result.complete(null);
- }
- @Override
- public void onFailure() {
+ } else {
result.completeExceptionally(new RuntimeException());
}
});
@@ -434,11 +430,12 @@
@Override
public boolean isRoleHeld(@NonNull String roleName, @NonNull String packageName) {
- Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
- Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
int callingUid = getCallingUid();
mAppOpsManager.checkPackage(callingUid, packageName);
+ Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
+ Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
+
int userId = UserHandle.getUserId(callingUid);
ArraySet<String> roleHolders = getOrCreateUserState(userId).getRoleHolders(roleName);
if (roleHolders == null) {
@@ -450,7 +447,6 @@
@NonNull
@Override
public List<String> getRoleHoldersAsUser(@NonNull String roleName, @UserIdInt int userId) {
- Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
if (!mUserManagerInternal.exists(userId)) {
Slog.e(LOG_TAG, "user " + userId + " does not exist");
return Collections.emptyList();
@@ -459,6 +455,8 @@
getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
"getRoleHoldersAsUser");
+ Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
+
ArraySet<String> roleHolders = getOrCreateUserState(userId).getRoleHolders(roleName);
if (roleHolders == null) {
return Collections.emptyList();
@@ -469,10 +467,7 @@
@Override
public void addRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName,
@RoleManager.ManageHoldersFlags int flags, @UserIdInt int userId,
- @NonNull IRoleManagerCallback callback) {
- Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
- Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
- Preconditions.checkNotNull(callback, "callback cannot be null");
+ @NonNull RemoteCallback callback) {
if (!mUserManagerInternal.exists(userId)) {
Slog.e(LOG_TAG, "user " + userId + " does not exist");
return;
@@ -481,6 +476,10 @@
getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
"addRoleHolderAsUser");
+ Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
+ Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
+ Preconditions.checkNotNull(callback, "callback cannot be null");
+
getOrCreateControllerService(userId).onAddRoleHolder(roleName, packageName, flags,
callback);
}
@@ -488,10 +487,7 @@
@Override
public void removeRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName,
@RoleManager.ManageHoldersFlags int flags, @UserIdInt int userId,
- @NonNull IRoleManagerCallback callback) {
- Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
- Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
- Preconditions.checkNotNull(callback, "callback cannot be null");
+ @NonNull RemoteCallback callback) {
if (!mUserManagerInternal.exists(userId)) {
Slog.e(LOG_TAG, "user " + userId + " does not exist");
return;
@@ -500,6 +496,10 @@
getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
"removeRoleHolderAsUser");
+ Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
+ Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
+ Preconditions.checkNotNull(callback, "callback cannot be null");
+
getOrCreateControllerService(userId).onRemoveRoleHolder(roleName, packageName, flags,
callback);
}
@@ -507,9 +507,7 @@
@Override
public void clearRoleHoldersAsUser(@NonNull String roleName,
@RoleManager.ManageHoldersFlags int flags, @UserIdInt int userId,
- @NonNull IRoleManagerCallback callback) {
- Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
- Preconditions.checkNotNull(callback, "callback cannot be null");
+ @NonNull RemoteCallback callback) {
if (!mUserManagerInternal.exists(userId)) {
Slog.e(LOG_TAG, "user " + userId + " does not exist");
return;
@@ -518,13 +516,15 @@
getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
"clearRoleHoldersAsUser");
+ Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
+ Preconditions.checkNotNull(callback, "callback cannot be null");
+
getOrCreateControllerService(userId).onClearRoleHolders(roleName, flags, callback);
}
@Override
public void addOnRoleHoldersChangedListenerAsUser(
@NonNull IOnRoleHoldersChangedListener listener, @UserIdInt int userId) {
- Preconditions.checkNotNull(listener, "listener cannot be null");
if (userId != UserHandle.USER_ALL && !mUserManagerInternal.exists(userId)) {
Slog.e(LOG_TAG, "user " + userId + " does not exist");
return;
@@ -533,6 +533,8 @@
getContext().enforceCallingOrSelfPermission(Manifest.permission.OBSERVE_ROLE_HOLDERS,
"addOnRoleHoldersChangedListenerAsUser");
+ Preconditions.checkNotNull(listener, "listener cannot be null");
+
RemoteCallbackList<IOnRoleHoldersChangedListener> listeners = getOrCreateListeners(
userId);
listeners.register(listener);
@@ -541,7 +543,6 @@
@Override
public void removeOnRoleHoldersChangedListenerAsUser(
@NonNull IOnRoleHoldersChangedListener listener, @UserIdInt int userId) {
- Preconditions.checkNotNull(listener, "listener cannot be null");
if (userId != UserHandle.USER_ALL && !mUserManagerInternal.exists(userId)) {
Slog.e(LOG_TAG, "user " + userId + " does not exist");
return;
@@ -550,6 +551,8 @@
getContext().enforceCallingOrSelfPermission(Manifest.permission.OBSERVE_ROLE_HOLDERS,
"removeOnRoleHoldersChangedListenerAsUser");
+ Preconditions.checkNotNull(listener, "listener cannot be null");
+
RemoteCallbackList<IOnRoleHoldersChangedListener> listeners = getListeners(userId);
if (listener == null) {
return;
@@ -559,11 +562,12 @@
@Override
public void setRoleNamesFromController(@NonNull List<String> roleNames) {
- Preconditions.checkNotNull(roleNames, "roleNames cannot be null");
getContext().enforceCallingOrSelfPermission(
RoleManager.PERMISSION_MANAGE_ROLES_FROM_CONTROLLER,
"setRoleNamesFromController");
+ Preconditions.checkNotNull(roleNames, "roleNames cannot be null");
+
int userId = UserHandle.getCallingUserId();
getOrCreateUserState(userId).setRoleNames(roleNames);
}
@@ -571,12 +575,13 @@
@Override
public boolean addRoleHolderFromController(@NonNull String roleName,
@NonNull String packageName) {
- Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
- Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
getContext().enforceCallingOrSelfPermission(
RoleManager.PERMISSION_MANAGE_ROLES_FROM_CONTROLLER,
"addRoleHolderFromController");
+ Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
+ Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
+
int userId = UserHandle.getCallingUserId();
return getOrCreateUserState(userId).addRoleHolder(roleName, packageName);
}
@@ -584,23 +589,25 @@
@Override
public boolean removeRoleHolderFromController(@NonNull String roleName,
@NonNull String packageName) {
- Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
- Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
getContext().enforceCallingOrSelfPermission(
RoleManager.PERMISSION_MANAGE_ROLES_FROM_CONTROLLER,
"removeRoleHolderFromController");
+ Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
+ Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
+
int userId = UserHandle.getCallingUserId();
return getOrCreateUserState(userId).removeRoleHolder(roleName, packageName);
}
@Override
public List<String> getHeldRolesFromController(@NonNull String packageName) {
- Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
getContext().enforceCallingOrSelfPermission(
RoleManager.PERMISSION_MANAGE_ROLES_FROM_CONTROLLER,
"getRolesHeldFromController");
+ Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
+
int userId = UserHandle.getCallingUserId();
return getOrCreateUserState(userId).getHeldRoles(packageName);
}
@@ -728,16 +735,14 @@
@Override
public boolean setDefaultBrowser(@Nullable String packageName, @UserIdInt int userId) {
CompletableFuture<Void> future = new CompletableFuture<>();
- IRoleManagerCallback callback = new IRoleManagerCallback.Stub() {
- @Override
- public void onSuccess() {
+ RemoteCallback callback = new RemoteCallback(result -> {
+ boolean successful = result != null;
+ if (successful) {
future.complete(null);
- }
- @Override
- public void onFailure() {
+ } else {
future.completeExceptionally(new RuntimeException());
}
- };
+ });
if (packageName != null) {
getOrCreateControllerService(userId).onAddRoleHolder(RoleManager.ROLE_BROWSER,
packageName, 0, callback);
@@ -756,14 +761,12 @@
@Override
public void setDefaultBrowserAsync(@Nullable String packageName, @UserIdInt int userId) {
- IRoleManagerCallback callback = new IRoleManagerCallback.Stub() {
- @Override
- public void onSuccess() {}
- @Override
- public void onFailure() {
+ RemoteCallback callback = new RemoteCallback(result -> {
+ boolean successful = result != null;
+ if (!successful) {
Slog.e(LOG_TAG, "Failed to set default browser: " + packageName);
}
- };
+ });
if (packageName != null) {
getOrCreateControllerService(userId).onAddRoleHolder(RoleManager.ROLE_BROWSER,
packageName, 0, callback);
@@ -785,14 +788,12 @@
@Override
public void setDefaultHomeAsync(@Nullable String packageName, @UserIdInt int userId) {
- IRoleManagerCallback callback = new IRoleManagerCallback.Stub() {
- @Override
- public void onSuccess() {}
- @Override
- public void onFailure() {
+ RemoteCallback callback = new RemoteCallback(result -> {
+ boolean successful = result != null;
+ if (!successful) {
Slog.e(LOG_TAG, "Failed to set default home: " + packageName);
}
- };
+ });
if (packageName != null) {
getOrCreateControllerService(userId).onAddRoleHolder(RoleManager.ROLE_HOME,
packageName, 0, callback);
diff --git a/services/core/java/com/android/server/role/RoleManagerShellCommand.java b/services/core/java/com/android/server/role/RoleManagerShellCommand.java
index 00021d7..b26a070 100644
--- a/services/core/java/com/android/server/role/RoleManagerShellCommand.java
+++ b/services/core/java/com/android/server/role/RoleManagerShellCommand.java
@@ -19,7 +19,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.role.IRoleManager;
-import android.app.role.IRoleManagerCallback;
+import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.ShellCommand;
import android.os.UserHandle;
@@ -38,14 +38,23 @@
mRoleManager = roleManager;
}
- private class Callback extends IRoleManagerCallback.Stub {
+ private class CallbackFuture extends CompletableFuture<Void> {
@NonNull
- private final CompletableFuture<Void> mResult = new CompletableFuture<>();
+ public RemoteCallback createCallback() {
+ return new RemoteCallback(result -> {
+ boolean successful = result != null;
+ if (successful) {
+ complete(null);
+ } else {
+ completeExceptionally(new RuntimeException("Failed"));
+ }
+ });
+ }
public int waitForResult() {
try {
- mResult.get(5, TimeUnit.SECONDS);
+ get(5, TimeUnit.SECONDS);
return 0;
} catch (Exception e) {
getErrPrintWriter().println("Error: see logcat for details.\n"
@@ -53,16 +62,6 @@
return -1;
}
}
-
- @Override
- public void onSuccess() {
- mResult.complete(null);
- }
-
- @Override
- public void onFailure() {
- mResult.completeExceptionally(new RuntimeException("Failed"));
- }
}
@Override
@@ -112,9 +111,10 @@
String packageName = getNextArgRequired();
int flags = getFlagsMaybe();
- Callback callback = new Callback();
- mRoleManager.addRoleHolderAsUser(roleName, packageName, flags, userId, callback);
- return callback.waitForResult();
+ CallbackFuture future = new CallbackFuture();
+ mRoleManager.addRoleHolderAsUser(roleName, packageName, flags, userId,
+ future.createCallback());
+ return future.waitForResult();
}
private int runRemoveRoleHolder() throws RemoteException {
@@ -123,9 +123,10 @@
String packageName = getNextArgRequired();
int flags = getFlagsMaybe();
- Callback callback = new Callback();
- mRoleManager.removeRoleHolderAsUser(roleName, packageName, flags, userId, callback);
- return callback.waitForResult();
+ CallbackFuture future = new CallbackFuture();
+ mRoleManager.removeRoleHolderAsUser(roleName, packageName, flags, userId,
+ future.createCallback());
+ return future.waitForResult();
}
private int runClearRoleHolders() throws RemoteException {
@@ -133,9 +134,9 @@
String roleName = getNextArgRequired();
int flags = getFlagsMaybe();
- Callback callback = new Callback();
- mRoleManager.clearRoleHoldersAsUser(roleName, flags, userId, callback);
- return callback.waitForResult();
+ CallbackFuture future = new CallbackFuture();
+ mRoleManager.clearRoleHoldersAsUser(roleName, flags, userId, future.createCallback());
+ return future.waitForResult();
}
@Override
diff --git a/services/core/java/com/android/server/rollback/TEST_MAPPING b/services/core/java/com/android/server/rollback/TEST_MAPPING
index 6be93a0..921b754 100644
--- a/services/core/java/com/android/server/rollback/TEST_MAPPING
+++ b/services/core/java/com/android/server/rollback/TEST_MAPPING
@@ -5,6 +5,14 @@
},
{
"name": "StagedRollbackTest"
+ },
+ {
+ "name": "FrameworksServicesTests",
+ "options": [
+ {
+ "include-filter": "com.android.server.rollback"
+ }
+ ]
}
]
}
diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
index 28fee4e..4614355 100644
--- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java
+++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
@@ -43,8 +43,6 @@
import android.util.Log;
import android.util.Slog;
-import com.android.internal.policy.IKeyguardDismissCallback;
-
import java.util.Collections;
import java.util.List;
@@ -495,6 +493,21 @@
}
}
+ /**
+ * @see android.service.trust.TrustAgentService#onTokenStateReceived()
+ *
+ */
+ public void onEscrowTokenActivated(long handle, int userId) {
+ if (DEBUG) Slog.d(TAG, "onEscrowTokenActivated: " + handle + " user: " + userId);
+ if (mTrustAgentService != null) {
+ try {
+ mTrustAgentService.onTokenStateReceived(handle,
+ TrustAgentService.TOKEN_STATE_ACTIVE);
+ } catch (RemoteException e) {
+ onError(e);
+ }
+ }
+ }
private void setCallback(ITrustAgentServiceCallback callback) {
try {
if (mTrustAgentService != null) {
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index c7044a1..3a39053 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -409,7 +409,10 @@
}
public long addEscrowToken(byte[] token, int userId) {
- return mLockPatternUtils.addEscrowToken(token, userId);
+ return mLockPatternUtils.addEscrowToken(token, userId,
+ (long handle, int userid) -> {
+ dispatchEscrowTokenActivatedLocked(handle, userid);
+ });
}
public boolean removeEscrowToken(long handle, int userId) {
@@ -662,6 +665,15 @@
}
}
+ private void dispatchEscrowTokenActivatedLocked(long handle, int userId) {
+ for (int i = 0; i < mActiveAgents.size(); i++) {
+ AgentInfo agent = mActiveAgents.valueAt(i);
+ if (agent.userId == userId) {
+ agent.agent.onEscrowTokenActivated(handle, userId);
+ }
+ }
+ }
+
void updateDevicePolicyFeatures() {
boolean changed = false;
for (int i = 0; i < mActiveAgents.size(); i++) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 36251f5..d7922b15 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -13352,8 +13352,8 @@
if (policy.mPasswordTokenHandle != 0) {
mLockPatternUtils.removeEscrowToken(policy.mPasswordTokenHandle, userHandle);
}
-
- policy.mPasswordTokenHandle = mLockPatternUtils.addEscrowToken(token, userHandle);
+ policy.mPasswordTokenHandle = mLockPatternUtils.addEscrowToken(token,
+ userHandle, /*EscrowTokenStateChangeCallback*/ null);
saveSettingsLocked(userHandle);
return policy.mPasswordTokenHandle != 0;
} finally {
diff --git a/services/net/java/android/net/NetworkStackClient.java b/services/net/java/android/net/NetworkStackClient.java
index eed01ae..a8f4a77 100644
--- a/services/net/java/android/net/NetworkStackClient.java
+++ b/services/net/java/android/net/NetworkStackClient.java
@@ -42,7 +42,6 @@
import com.android.internal.annotations.GuardedBy;
import java.io.PrintWriter;
-import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
/**
@@ -53,6 +52,7 @@
private static final String TAG = NetworkStackClient.class.getSimpleName();
private static final int NETWORKSTACK_TIMEOUT_MS = 10_000;
+ private static final String IN_PROCESS_SUFFIX = ".InProcess";
private static NetworkStackClient sInstance;
@@ -175,42 +175,50 @@
public void start(Context context) {
log("Starting network stack");
mNetworkStackStartRequested = true;
- // Try to bind in-process if the library is available
- IBinder connector = null;
- try {
- final Class service = Class.forName(
- "com.android.server.NetworkStackService",
- true /* initialize */,
- context.getClassLoader());
- connector = (IBinder) service.getMethod("makeConnector", Context.class)
- .invoke(null, context);
- } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
- logWtf("Could not create network stack connector from NetworkStackService", e);
- // TODO: crash/reboot system here ?
- return;
- } catch (ClassNotFoundException e) {
- // Normal behavior if stack is provided by the app: fall through
+
+ final PackageManager pm = context.getPackageManager();
+
+ // Try to bind in-process if the device was shipped with an in-process version
+ Intent intent = getNetworkStackIntent(pm, true /* inSystemProcess */);
+
+ // Otherwise use the updatable module version
+ if (intent == null) {
+ intent = getNetworkStackIntent(pm, false /* inSystemProcess */);
+ log("Starting network stack process");
+ } else {
+ log("Starting network stack in-process");
}
- // In-process network stack. Add the service to the service manager here.
- if (connector != null) {
- log("Registering in-process network stack connector");
- registerNetworkStackService(connector);
- return;
- }
- // Start the network stack process. The service will be added to the service manager in
- // NetworkStackConnection.onServiceConnected().
- log("Starting network stack process");
- final Intent intent = new Intent(INetworkStackConnector.class.getName());
- final ComponentName comp = intent.resolveSystemService(context.getPackageManager(), 0);
- intent.setComponent(comp);
-
- if (comp == null) {
- logWtf("Could not resolve the network stack with " + intent, null);
+ if (intent == null) {
+ logWtf("Could not resolve the network stack", null);
// TODO: crash/reboot system server ?
return;
}
- final PackageManager pm = context.getPackageManager();
+
+ // Start the network stack. The service will be added to the service manager in
+ // NetworkStackConnection.onServiceConnected().
+ if (!context.bindServiceAsUser(intent, new NetworkStackConnection(),
+ Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.SYSTEM)) {
+ logWtf("Could not bind to network stack with " + intent, null);
+ return;
+ // TODO: crash/reboot system server if no network stack after a timeout ?
+ }
+
+ log("Network stack service start requested");
+ }
+
+ @Nullable
+ private Intent getNetworkStackIntent(@NonNull PackageManager pm, boolean inSystemProcess) {
+ final String baseAction = INetworkStackConnector.class.getName();
+ final Intent intent =
+ new Intent(inSystemProcess ? baseAction + IN_PROCESS_SUFFIX : baseAction);
+ final ComponentName comp = intent.resolveSystemService(pm, 0);
+
+ if (comp == null) {
+ return null;
+ }
+ intent.setComponent(comp);
+
int uid = -1;
try {
uid = pm.getPackageUidAsUser(comp.getPackageName(), UserHandle.USER_SYSTEM);
@@ -218,25 +226,27 @@
logWtf("Network stack package not found", e);
// Fall through
}
- if (uid != Process.NETWORK_STACK_UID) {
+
+ final int expectedUid = inSystemProcess ? Process.SYSTEM_UID : Process.NETWORK_STACK_UID;
+ if (uid != expectedUid) {
throw new SecurityException("Invalid network stack UID: " + uid);
}
+ if (!inSystemProcess) {
+ checkNetworkStackPermission(pm, comp);
+ }
+
+ return intent;
+ }
+
+ private void checkNetworkStackPermission(
+ @NonNull PackageManager pm, @NonNull ComponentName comp) {
final int hasPermission =
pm.checkPermission(PERMISSION_MAINLINE_NETWORK_STACK, comp.getPackageName());
if (hasPermission != PERMISSION_GRANTED) {
throw new SecurityException(
"Network stack does not have permission " + PERMISSION_MAINLINE_NETWORK_STACK);
}
-
- if (!context.bindServiceAsUser(intent, new NetworkStackConnection(),
- Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.SYSTEM)) {
- logWtf("Could not bind to network stack in-process, or in app with " + intent, null);
- return;
- // TODO: crash/reboot system server if no network stack after a timeout ?
- }
-
- log("Network stack service start requested");
}
private void log(@NonNull String message) {
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 4293247..039a4b7 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -29,6 +29,7 @@
import static android.os.UserManagerInternal.CAMERA_DISABLED_LOCALLY;
import static android.os.UserManagerInternal.CAMERA_NOT_DISABLED;
+import static com.android.internal.widget.LockPatternUtils.EscrowTokenStateChangeCallback;
import static com.android.server.testutils.TestUtils.assertExpectException;
import static org.mockito.Matchers.any;
@@ -4157,8 +4158,9 @@
final byte[] token = new byte[32];
final long handle = 123456;
final String password = "password";
- when(getServices().lockPatternUtils.addEscrowToken(eq(token), eq(UserHandle.USER_SYSTEM)))
- .thenReturn(handle);
+ when(getServices().lockPatternUtils.addEscrowToken(eq(token), eq(UserHandle.USER_SYSTEM),
+ nullable(EscrowTokenStateChangeCallback.class)))
+ .thenReturn(handle);
assertTrue(dpm.setResetPasswordToken(admin1, token));
// test password activation
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
index d343ac1..77515258 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
@@ -338,7 +338,7 @@
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
- long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID);
+ long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null);
assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
mService.verifyCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0,
@@ -367,7 +367,7 @@
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
- long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID);
+ long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null);
assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
mService.verifyCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
@@ -393,7 +393,7 @@
initializeCredentialUnderSP(password, PRIMARY_USER_ID);
final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID);
- long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID);
+ long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null);
assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
mService.verifyCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
@@ -417,7 +417,7 @@
throws RemoteException {
final String token = "some-high-entropy-secure-token";
enableSyntheticPassword();
- long handle = mLocalService.addEscrowToken(token.getBytes(), PRIMARY_USER_ID);
+ long handle = mLocalService.addEscrowToken(token.getBytes(), PRIMARY_USER_ID, null);
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
assertTrue(hasSyntheticPassword(PRIMARY_USER_ID));
@@ -427,7 +427,7 @@
throws RemoteException {
final String token = "some-high-entropy-secure-token";
initializeCredentialUnderSP(null, PRIMARY_USER_ID);
- long handle = mLocalService.addEscrowToken(token.getBytes(), PRIMARY_USER_ID);
+ long handle = mLocalService.addEscrowToken(token.getBytes(), PRIMARY_USER_ID, null);
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID));
assertTrue(hasSyntheticPassword(PRIMARY_USER_ID));
@@ -443,7 +443,7 @@
PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
enableSyntheticPassword();
- long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID);
+ long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null);
// Token not activated immediately since user password exists
assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
// Activate token (password gets migrated to SP at the same time)
@@ -461,7 +461,7 @@
mHasSecureLockScreen = false;
enableSyntheticPassword();
- long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID);
+ long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID, null);
assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
try {
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index 3ebc6ad..e9edba5 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -185,6 +185,18 @@
}
@MediumTest
+ public void testRemoveUserByHandle_ThrowsException() {
+ synchronized (mUserRemoveLock) {
+ try {
+ mUserManager.removeUser(null);
+ fail("Expected IllegalArgumentException on passing in a null UserHandle.");
+ } catch (IllegalArgumentException expected) {
+ // Do nothing - exception is expected.
+ }
+ }
+ }
+
+ @MediumTest
public void testAddGuest() throws Exception {
UserInfo userInfo1 = createUser("Guest 1", UserInfo.FLAG_GUEST);
UserInfo userInfo2 = createUser("Guest 2", UserInfo.FLAG_GUEST);
@@ -520,6 +532,12 @@
}
}
+ public void testGetUserSwitchability() {
+ int userSwitchable = mUserManager.getUserSwitchability();
+ assertEquals("Expected users to be switchable", UserManager.SWITCHABILITY_STATUS_OK,
+ userSwitchable);
+ }
+
@LargeTest
public void testSwitchUser() {
ActivityManager am = getContext().getSystemService(ActivityManager.class);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index d202e16..032eba1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -270,7 +270,7 @@
WindowTestUtils.TestAppWindowToken createTestAppWindowToken(DisplayContent dc, int
windowingMode, int activityType) {
return createTestAppWindowToken(dc, windowingMode, activityType,
- true /*skipOnParentChanged */);
+ false /*skipOnParentChanged */);
}
WindowTestUtils.TestAppWindowToken createTestAppWindowToken(DisplayContent dc, int
diff --git a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
index 2907021..2fc6efa 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ZOrderingTests.java
@@ -74,7 +74,7 @@
public SurfaceControl.Transaction setLayer(SurfaceControl sc, int layer) {
mRelativeLayersForControl.remove(sc);
mLayersForControl.put(sc, layer);
- return super.setLayer(sc, layer);
+ return this;
}
@Override
@@ -83,7 +83,7 @@
int layer) {
mRelativeLayersForControl.put(sc, relativeTo);
mLayersForControl.put(sc, layer);
- return super.setRelativeLayer(sc, relativeTo, layer);
+ return this;
}
private int getLayer(SurfaceControl sc) {
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index b9a5676..9498e16 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -17,6 +17,7 @@
package com.android.server.usage;
import static android.app.usage.UsageEvents.Event.DEVICE_SHUTDOWN;
+import static android.app.usage.UsageEvents.Event.DEVICE_STARTUP;
import static android.app.usage.UsageStatsManager.INTERVAL_BEST;
import static android.app.usage.UsageStatsManager.INTERVAL_COUNT;
import static android.app.usage.UsageStatsManager.INTERVAL_DAILY;
@@ -137,15 +138,18 @@
// During system reboot, add a DEVICE_SHUTDOWN event to the end of event list, the timestamp
// is last time UsageStatsDatabase is persisted to disk.
+ // Also add a DEVICE_STARTUP event with current system timestamp.
final IntervalStats currentDailyStats = mCurrentStats[INTERVAL_DAILY];
if (currentDailyStats != null) {
- final int size = currentDailyStats.events.size();
- if (size == 0 || currentDailyStats.events.get(size - 1).mEventType != DEVICE_SHUTDOWN) {
- // The last event in event list is not DEVICE_SHUTDOWN, then we insert one.
- final Event event = new Event(DEVICE_SHUTDOWN, currentDailyStats.lastTimeSaved);
- event.mPackage = Event.DEVICE_EVENT_PACKAGE_NAME;
- currentDailyStats.addEvent(event);
- }
+ // File system timestamp only has precision of 1 second, add 1000ms to make up
+ // for the loss of round up.
+ final Event shutdownEvent =
+ new Event(DEVICE_SHUTDOWN, currentDailyStats.lastTimeSaved + 1000);
+ shutdownEvent.mPackage = Event.DEVICE_EVENT_PACKAGE_NAME;
+ currentDailyStats.addEvent(shutdownEvent);
+ final Event startupEvent = new Event(DEVICE_STARTUP, currentTimeMillis);
+ startupEvent.mPackage = Event.DEVICE_EVENT_PACKAGE_NAME;
+ currentDailyStats.addEvent(startupEvent);
}
if (mDatabase.isNewUpdate()) {
@@ -956,6 +960,8 @@
return "KEYGUARD_HIDDEN";
case Event.DEVICE_SHUTDOWN:
return "DEVICE_SHUTDOWN";
+ case Event.DEVICE_STARTUP:
+ return "DEVICE_STARTUP";
default:
return "UNKNOWN_TYPE_" + eventType;
}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index b9440eb..ad1e3ef 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -1389,6 +1389,16 @@
resetCurAssistant(userHandle);
initForUser(userHandle);
switchImplementationIfNeededLocked(true);
+
+ Context context = getContext();
+ context.getSystemService(RoleManager.class).clearRoleHoldersAsUser(
+ RoleManager.ROLE_ASSISTANT, 0, UserHandle.of(userHandle),
+ context.getMainExecutor(), successful -> {
+ if (!successful) {
+ Slog.e(TAG,
+ "Failed to clear default assistant for force stop");
+ }
+ });
}
} else if (hitRec && doit) {
// We are just force-stopping the current recognizer, which is not
diff --git a/telecomm/java/android/telecom/DefaultDialerManager.java b/telecomm/java/android/telecom/DefaultDialerManager.java
index e43b2b7..5b806a6 100644
--- a/telecomm/java/android/telecom/DefaultDialerManager.java
+++ b/telecomm/java/android/telecom/DefaultDialerManager.java
@@ -16,7 +16,6 @@
import android.app.ActivityManager;
import android.app.role.RoleManager;
-import android.app.role.RoleManagerCallback;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
@@ -34,9 +33,11 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
+import java.util.function.Consumer;
/**
* Class for managing the default dialer application that will receive incoming calls, and be
@@ -75,11 +76,18 @@
int user) {
long identity = Binder.clearCallingIdentity();
try {
- RoleManagerCallback.Future cb = new RoleManagerCallback.Future();
+ CompletableFuture<Void> future = new CompletableFuture<>();
+ Consumer<Boolean> callback = successful -> {
+ if (successful) {
+ future.complete(null);
+ } else {
+ future.completeExceptionally(new RuntimeException());
+ }
+ };
context.getSystemService(RoleManager.class).addRoleHolderAsUser(
RoleManager.ROLE_DIALER, packageName, 0, UserHandle.of(user),
- AsyncTask.THREAD_POOL_EXECUTOR, cb);
- cb.get(5, TimeUnit.SECONDS);
+ AsyncTask.THREAD_POOL_EXECUTOR, callback);
+ future.get(5, TimeUnit.SECONDS);
return true;
} catch (InterruptedException | ExecutionException | TimeoutException e) {
Slog.e(TAG, "Failed to set default dialer to " + packageName + " for user " + user, e);
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 7688ac6..52c5425 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -25,7 +25,6 @@
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
-import android.app.role.RoleManagerCallback;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -478,12 +477,6 @@
"android.telecom.extra.START_CALL_WITH_RTT";
/**
- * A boolean extra set to indicate whether an app is eligible to be bound to when there are
- * ongoing calls on the device.
- */
- public static final String EXTRA_IS_ENABLED = "android.telecom.extra.IS_ENABLED";
-
- /**
* A boolean meta-data value indicating whether an {@link InCallService} implements an
* in-call user interface. Dialer implementations (see {@link #getDefaultDialerPackage()}) which
* would also like to replace the in-call interface should set this meta-data to {@code true} in
@@ -1221,8 +1214,8 @@
*
* @hide
* @deprecated Use
- * {@link android.app.role.RoleManager#addRoleHolderAsUser(String, String, UserHandle, Executor,
- * RoleManagerCallback)} instead.
+ * {@link android.app.role.RoleManager#addRoleHolderAsUser(String, String, int, UserHandle,
+ * Executor, java.util.function.Consumer)} instead.
*/
@SystemApi
@Deprecated
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
old mode 100644
new mode 100755
index 5262cf8..d79a168
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2653,6 +2653,18 @@
*/
public static final String KEY_USE_USIM_BOOL = "use_usim_bool";
+ /**
+ * Determines whether the carrier wants to cancel the cs reject notification automatically
+ * when the voice registration state changes.
+ * If true, the notification will be automatically removed
+ * when the voice registration state changes.
+ * If false, the notification will persist until the user dismisses it,
+ * the SIM is removed, or the device is rebooted.
+ * @hide
+ */
+ public static final String KEY_AUTO_CANCEL_CS_REJECT_NOTIFICATION =
+ "carrier_auto_cancel_cs_notification";
+
/** The default value for every variable. */
private final static PersistableBundle sDefaults;
@@ -3039,6 +3051,7 @@
});
sDefaults.putStringArray(KEY_EMERGENCY_NUMBER_PREFIX_STRING_ARRAY, new String[0]);
sDefaults.putBoolean(KEY_USE_USIM_BOOL, false);
+ sDefaults.putBoolean(KEY_AUTO_CANCEL_CS_REJECT_NOTIFICATION, false);
}
/**
diff --git a/telephony/java/android/telephony/CellSignalStrengthGsm.java b/telephony/java/android/telephony/CellSignalStrengthGsm.java
index 3dea6f4..0aeb0f6 100644
--- a/telephony/java/android/telephony/CellSignalStrengthGsm.java
+++ b/telephony/java/android/telephony/CellSignalStrengthGsm.java
@@ -151,6 +151,17 @@
}
/**
+ * Return the Received Signal Strength Indicator
+ *
+ * @return the RSSI in dBm (-113, -51) or
+ * {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE}.
+ * @hide
+ */
+ public int getRssi() {
+ return mRssi;
+ }
+
+ /**
* Return the Bit Error Rate
*
* @return the bit error rate (0-7, 99) as defined in TS 27.007 8.5 or
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 4dcb410..549c044 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -25,12 +25,11 @@
import android.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.Intent;
-import android.content.res.Resources;
import android.database.Cursor;
import android.location.CountryDetector;
import android.net.Uri;
-import android.os.SystemProperties;
import android.os.PersistableBundle;
+import android.os.SystemProperties;
import android.provider.Contacts;
import android.provider.ContactsContract;
import android.telecom.PhoneAccount;
@@ -1738,7 +1737,7 @@
* @return true if the number is in the list of emergency numbers
* listed in the RIL / SIM, otherwise return false.
*
- * @deprecated Please use {@link TelephonyManager#isCurrentEmergencyNumber(String)} instead.
+ * @deprecated Please use {@link TelephonyManager#isEmergencyNumber(String)} instead.
*/
@Deprecated
public static boolean isEmergencyNumber(String number) {
@@ -1754,7 +1753,7 @@
* @return true if the number is in the list of emergency numbers
* listed in the RIL / SIM, otherwise return false.
*
- * @deprecated Please use {@link TelephonyManager#isCurrentEmergencyNumber(String)}
+ * @deprecated Please use {@link TelephonyManager#isEmergencyNumber(String)}
* instead.
*
* @hide
@@ -1785,7 +1784,7 @@
* listed in the RIL / SIM, *or* if the number starts with the
* same digits as any of those emergency numbers.
*
- * @deprecated Please use {@link TelephonyManager#isCurrentPotentialEmergencyNumber(String)}
+ * @deprecated Please use {@link TelephonyManager#isPotentialEmergencyNumber(String)}
* instead.
*
* @hide
@@ -1814,7 +1813,7 @@
* listed in the RIL / SIM, *or* if the number starts with the
* same digits as any of those emergency numbers.
*
- * @deprecated Please use {@link TelephonyManager#isCurrentPotentialEmergencyNumber(String)}
+ * @deprecated Please use {@link TelephonyManager#isPotentialEmergencyNumber(String)}
* instead.
*
* @hide
@@ -1883,7 +1882,7 @@
* @return if the number is an emergency number for the specific country, then return true,
* otherwise false
*
- * @deprecated Please use {@link TelephonyManager#isCurrentEmergencyNumber(String)}
+ * @deprecated Please use {@link TelephonyManager#isEmergencyNumber(String)}
* instead.
*
* @hide
@@ -1903,7 +1902,7 @@
* @return if the number is an emergency number for the specific country, then return true,
* otherwise false
*
- * @deprecated Please use {@link TelephonyManager#isCurrentEmergencyNumber(String)}
+ * @deprecated Please use {@link TelephonyManager#isEmergencyNumber(String)}
* instead.
*
* @hide
@@ -1934,7 +1933,7 @@
* country, *or* if the number starts with the same digits as
* any of those emergency numbers.
*
- * @deprecated Please use {@link TelephonyManager#isCurrentPotentialEmergencyNumber(String)}
+ * @deprecated Please use {@link TelephonyManager#isPotentialEmergencyNumber(String)}
* instead.
*
* @hide
@@ -1964,7 +1963,7 @@
* country, *or* if the number starts with the same digits as
* any of those emergency numbers.
*
- * @deprecated Please use {@link TelephonyManager#isCurrentPotentialEmergencyNumber(String)}
+ * @deprecated Please use {@link TelephonyManager#isPotentialEmergencyNumber(String)}
* instead.
*
* @hide
@@ -2017,7 +2016,7 @@
private static boolean isEmergencyNumberInternal(int subId, String number,
String defaultCountryIso,
boolean useExactMatch) {
- return TelephonyManager.getDefault().isCurrentEmergencyNumber(number);
+ return TelephonyManager.getDefault().isEmergencyNumber(number);
}
/**
@@ -2028,7 +2027,7 @@
* @return true if the specified number is an emergency number for the country the user
* is currently in.
*
- * @deprecated Please use {@link TelephonyManager#isCurrentEmergencyNumber(String)}
+ * @deprecated Please use {@link TelephonyManager#isEmergencyNumber(String)}
* instead.
*/
@Deprecated
@@ -2045,7 +2044,7 @@
* @return true if the specified number is an emergency number for the country the user
* is currently in.
*
- * @deprecated Please use {@link TelephonyManager#isCurrentEmergencyNumber(String)}
+ * @deprecated Please use {@link TelephonyManager#isEmergencyNumber(String)}
* instead.
*
* @hide
@@ -2079,7 +2078,7 @@
*
* @see android.location.CountryDetector
*
- * @deprecated Please use {@link TelephonyManager#isCurrentPotentialEmergencyNumber(String)}
+ * @deprecated Please use {@link TelephonyManager#isPotentialEmergencyNumber(String)}
* instead.
*
* @hide
@@ -2110,7 +2109,7 @@
* @return true if the specified number is an emergency number for a local country, based on the
* CountryDetector.
*
- * @deprecated Please use {@link TelephonyManager#isCurrentPotentialEmergencyNumber(String)}
+ * @deprecated Please use {@link TelephonyManager#isPotentialEmergencyNumber(String)}
* instead.
*
* @hide
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 9ca5717..16dafd6 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -96,6 +96,7 @@
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -10030,18 +10031,21 @@
* a SecurityException if the caller does not have the permission.
*/
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
- @Nullable
- public Map<Integer, List<EmergencyNumber>> getCurrentEmergencyNumberList() {
+ @NonNull
+ public Map<Integer, List<EmergencyNumber>> getEmergencyNumberList() {
+ Map<Integer, List<EmergencyNumber>> emergencyNumberList = new HashMap<>();
try {
ITelephony telephony = getITelephony();
- if (telephony == null) {
- return null;
+ if (telephony != null) {
+ return telephony.getEmergencyNumberList(mContext.getOpPackageName());
+ } else {
+ throw new IllegalStateException("telephony service is null.");
}
- return telephony.getCurrentEmergencyNumberList(mContext.getOpPackageName());
} catch (RemoteException ex) {
- Log.e(TAG, "getCurrentEmergencyNumberList RemoteException", ex);
+ Log.e(TAG, "getEmergencyNumberList RemoteException", ex);
+ ex.rethrowAsRuntimeException();
}
- return null;
+ return emergencyNumberList;
}
/**
@@ -10080,31 +10084,34 @@
* a SecurityException if the caller does not have the permission.
*/
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
- @Nullable
- public Map<Integer, List<EmergencyNumber>> getCurrentEmergencyNumberList(
+ @NonNull
+ public Map<Integer, List<EmergencyNumber>> getEmergencyNumberList(
@EmergencyServiceCategories int categories) {
+ Map<Integer, List<EmergencyNumber>> emergencyNumberList = new HashMap<>();
try {
ITelephony telephony = getITelephony();
- if (telephony == null) {
- return null;
- }
- Map<Integer, List<EmergencyNumber>> numberMap = telephony
- .getCurrentEmergencyNumberList(mContext.getOpPackageName());
- if (numberMap != null) {
- for (Integer subscriptionId : numberMap.keySet()) {
- List<EmergencyNumber> numberList = numberMap.get(subscriptionId);
- for (EmergencyNumber number : numberList) {
- if (!number.isInEmergencyServiceCategories(categories)) {
- numberList.remove(number);
+ if (telephony != null) {
+ emergencyNumberList = telephony.getEmergencyNumberList(
+ mContext.getOpPackageName());
+ if (emergencyNumberList != null) {
+ for (Integer subscriptionId : emergencyNumberList.keySet()) {
+ List<EmergencyNumber> numberList = emergencyNumberList.get(subscriptionId);
+ for (EmergencyNumber number : numberList) {
+ if (!number.isInEmergencyServiceCategories(categories)) {
+ numberList.remove(number);
+ }
}
}
}
+ return emergencyNumberList;
+ } else {
+ throw new IllegalStateException("telephony service is null.");
}
- return numberMap;
} catch (RemoteException ex) {
- Log.e(TAG, "getCurrentEmergencyNumberList with Categories RemoteException", ex);
+ Log.e(TAG, "getEmergencyNumberList with Categories RemoteException", ex);
+ ex.rethrowAsRuntimeException();
}
- return null;
+ return emergencyNumberList;
}
/**
@@ -10118,15 +10125,17 @@
* @return {@code true} if the given number is an emergency number based on current locale,
* sim, modem and network; {@code false} otherwise.
*/
- public boolean isCurrentEmergencyNumber(@NonNull String number) {
+ public boolean isEmergencyNumber(@NonNull String number) {
try {
ITelephony telephony = getITelephony();
- if (telephony == null) {
- return false;
+ if (telephony != null) {
+ return telephony.isEmergencyNumber(number, true);
+ } else {
+ throw new IllegalStateException("telephony service is null.");
}
- return telephony.isCurrentEmergencyNumber(number, true);
} catch (RemoteException ex) {
- Log.e(TAG, "isCurrentEmergencyNumber RemoteException", ex);
+ Log.e(TAG, "isEmergencyNumber RemoteException", ex);
+ ex.rethrowAsRuntimeException();
}
return false;
}
@@ -10155,15 +10164,17 @@
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- public boolean isCurrentPotentialEmergencyNumber(@NonNull String number) {
+ public boolean isPotentialEmergencyNumber(@NonNull String number) {
try {
ITelephony telephony = getITelephony();
- if (telephony == null) {
- return false;
+ if (telephony != null) {
+ return telephony.isEmergencyNumber(number, false);
+ } else {
+ throw new IllegalStateException("telephony service is null.");
}
- return telephony.isCurrentEmergencyNumber(number, false);
} catch (RemoteException ex) {
- Log.e(TAG, "isCurrentEmergencyNumber RemoteException", ex);
+ Log.e(TAG, "isEmergencyNumber RemoteException", ex);
+ ex.rethrowAsRuntimeException();
}
return false;
}
diff --git a/telephony/java/android/telephony/data/DataProfile.java b/telephony/java/android/telephony/data/DataProfile.java
index 332aae1..bcb47f7 100644
--- a/telephony/java/android/telephony/data/DataProfile.java
+++ b/telephony/java/android/telephony/data/DataProfile.java
@@ -243,7 +243,6 @@
*/
public boolean isPreferred() { return mPreferred; }
- /** @hide */
@Override
public int describeContents() {
return 0;
@@ -266,7 +265,6 @@
return (o == this || toString().equals(o.toString()));
}
- /** @hide */
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mProfileId);
@@ -288,7 +286,6 @@
dest.writeBoolean(mPreferred);
}
- /** @hide */
public static final @android.annotation.NonNull Parcelable.Creator<DataProfile> CREATOR =
new Parcelable.Creator<DataProfile>() {
@Override
diff --git a/telephony/java/android/telephony/emergency/EmergencyNumber.java b/telephony/java/android/telephony/emergency/EmergencyNumber.java
index 5373c38..173f4ed 100644
--- a/telephony/java/android/telephony/emergency/EmergencyNumber.java
+++ b/telephony/java/android/telephony/emergency/EmergencyNumber.java
@@ -302,7 +302,7 @@
*
* @return the dialing number.
*/
- public String getNumber() {
+ public @NonNull String getNumber() {
return mNumber;
}
@@ -311,7 +311,7 @@
*
* @return the country code string (lowercase character) in ISO 3166 format.
*/
- public String getCountryIso() {
+ public @NonNull String getCountryIso() {
return mCountryIso;
}
@@ -320,7 +320,7 @@
*
* @return the Mobile Network Code of the emergency number.
*/
- public String getMnc() {
+ public @NonNull String getMnc() {
return mMnc;
}
@@ -328,6 +328,8 @@
* Returns the bitmask of emergency service categories of the emergency number.
*
* @return bitmask of the emergency service categories
+ *
+ * @hide
*/
public @EmergencyServiceCategories int getEmergencyServiceCategoryBitmask() {
return mEmergencyServiceCategoryBitmask;
@@ -357,7 +359,7 @@
*
* @return a list of the emergency service categories
*/
- public List<Integer> getEmergencyServiceCategories() {
+ public @NonNull List<Integer> getEmergencyServiceCategories() {
List<Integer> categories = new ArrayList<>();
if (serviceUnspecified()) {
categories.add(EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED);
@@ -384,7 +386,7 @@
* number does not have a specified emergency Uniform Resource Name.
*/
public @NonNull List<String> getEmergencyUrns() {
- return mEmergencyUrns;
+ return Collections.unmodifiableList(mEmergencyUrns);
}
/**
@@ -421,6 +423,8 @@
* Returns the bitmask of the sources of the emergency number.
*
* @return bitmask of the emergency number sources
+ *
+ * @hide
*/
public @EmergencyNumberSources int getEmergencyNumberSourceBitmask() {
return mEmergencyNumberSourceBitmask;
@@ -431,7 +435,7 @@
*
* @return a list of emergency number sources
*/
- public List<Integer> getEmergencyNumberSources() {
+ public @NonNull List<Integer> getEmergencyNumberSources() {
List<Integer> sources = new ArrayList<>();
for (Integer source : EMERGENCY_NUMBER_SOURCE_SET) {
if ((mEmergencyNumberSourceBitmask & source) == source) {
diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java
index 793ac3c..751ce9d 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -17,6 +17,7 @@
package android.telephony.ims;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
import android.os.Bundle;
@@ -842,7 +843,7 @@
* 3gpp 22.101, Section 10 - Emergency Calls.
*/
@VisibleForTesting
- public void setEmergencyUrns(List<String> emergencyUrns) {
+ public void setEmergencyUrns(@NonNull List<String> emergencyUrns) {
mEmergencyUrns = emergencyUrns;
}
@@ -916,7 +917,7 @@
* Reference: 3gpp 24.503, Section 5.1.6.8.1 - General;
* 3gpp 22.101, Section 10 - Emergency Calls.
*/
- public List<String> getEmergencyUrns() {
+ public @NonNull List<String> getEmergencyUrns() {
return mEmergencyUrns;
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index c6fa22b..122747a65 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1773,12 +1773,12 @@
/**
* Return the emergency number list from all the active subscriptions.
*/
- Map getCurrentEmergencyNumberList(String callingPackage);
+ Map getEmergencyNumberList(String callingPackage);
/**
* Identify if the number is emergency number, based on all the active subscriptions.
*/
- boolean isCurrentEmergencyNumber(String number, boolean exactMatch);
+ boolean isEmergencyNumber(String number, boolean exactMatch);
/**
* Return a list of certs in hex string from loaded carrier privileges access rules.
diff --git a/telephony/java/com/android/internal/telephony/SmsApplication.java b/telephony/java/com/android/internal/telephony/SmsApplication.java
index 7478a00..ef7c605 100644
--- a/telephony/java/com/android/internal/telephony/SmsApplication.java
+++ b/telephony/java/com/android/internal/telephony/SmsApplication.java
@@ -19,7 +19,6 @@
import android.Manifest.permission;
import android.app.AppOpsManager;
import android.app.role.RoleManager;
-import android.app.role.RoleManagerCallback;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -51,9 +50,11 @@
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
+import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
+import java.util.function.Consumer;
/**
* Class for managing the primary application that we will deliver SMS/MMS messages to
@@ -634,12 +635,19 @@
}
// Update the setting.
- RoleManagerCallback.Future res = new RoleManagerCallback.Future();
+ CompletableFuture<Void> future = new CompletableFuture<>();
+ Consumer<Boolean> callback = successful -> {
+ if (successful) {
+ future.complete(null);
+ } else {
+ future.completeExceptionally(new RuntimeException());
+ }
+ };
context.getSystemService(RoleManager.class).addRoleHolderAsUser(
RoleManager.ROLE_SMS, applicationData.mPackageName, 0, UserHandle.of(userId),
- AsyncTask.THREAD_POOL_EXECUTOR, res);
+ AsyncTask.THREAD_POOL_EXECUTOR, callback);
try {
- res.get(5, TimeUnit.SECONDS);
+ future.get(5, TimeUnit.SECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
Log.e(LOG_TAG, "Exception while adding sms role holder " + applicationData, e);
return;
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
index ed8a533..a03fae0 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
@@ -165,9 +165,7 @@
PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
PackageInstaller.SessionParams.MODE_FULL_INSTALL);
- if (enableRollback) {
- params.setEnableRollback();
- }
+ params.setEnableRollback(enableRollback);
int sessionId = packageInstaller.createSession(params);
session = packageInstaller.openSession(sessionId);
@@ -224,11 +222,9 @@
if (staged) {
multiPackageParams.setStaged();
}
- if (enableRollback) {
- // TODO: Do we set this on the parent params, the child params, or
- // both?
- multiPackageParams.setEnableRollback();
- }
+ // TODO: Do we set this on the parent params, the child params, or
+ // both?
+ multiPackageParams.setEnableRollback(enableRollback);
int multiPackageId = packageInstaller.createSession(multiPackageParams);
PackageInstaller.Session multiPackage = packageInstaller.openSession(multiPackageId);
@@ -242,9 +238,7 @@
if (resourceName.endsWith(".apex")) {
params.setInstallAsApex();
}
- if (enableRollback) {
- params.setEnableRollback();
- }
+ params.setEnableRollback(enableRollback);
int sessionId = packageInstaller.createSession(params);
session = packageInstaller.openSession(sessionId);
diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp
index 251ca0c..5336141 100644
--- a/tools/aapt2/ResourceParser_test.cpp
+++ b/tools/aapt2/ResourceParser_test.cpp
@@ -183,11 +183,11 @@
EXPECT_THAT(str->untranslatable_sections, IsEmpty());
// Preserve non-ASCII whitespace including extended ASCII characters
- EXPECT_TRUE(TestParse(R"(<string name="foo3"> Hello </string>)"));
+ EXPECT_TRUE(TestParse(R"(<string name="foo3"> Hello World </string>)"));
str = test::GetValue<String>(&table_, "string/foo3");
ASSERT_THAT(str, NotNull());
- EXPECT_THAT(*str->value, StrEq("\xC2\xA0Hello\xC2\xA0"));
+ EXPECT_THAT(*str->value, StrEq("\xC2\xA0Hello\xE2\x80\xAFWorld\xC2\xA0"));
EXPECT_THAT(str->untranslatable_sections, IsEmpty());
EXPECT_TRUE(TestParse(R"(<string name="foo4">2005年6月1日</string>)"));
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index f0e4d9e..a571aee 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -40,8 +40,6 @@
namespace aapt {
namespace ResourceUtils {
-constexpr int32_t kNonBreakingSpace = 0xa0;
-
Maybe<ResourceName> ToResourceName(
const android::ResTable::resource_name& name_in) {
// TODO: Remove this when ResTable and AssetManager(1) are removed from AAPT2
@@ -854,7 +852,8 @@
Utf8Iterator iter(text);
while (iter.HasNext()) {
char32_t codepoint = iter.Next();
- if (!preserve_spaces_ && !quote_ && codepoint != kNonBreakingSpace && iswspace(codepoint)) {
+ if (!preserve_spaces_ && !quote_ && (codepoint <= std::numeric_limits<char>::max())
+ && isspace(static_cast<char>(codepoint))) {
if (!last_codepoint_was_space_) {
// Emit a space if it's the first.
xml_string_.text += ' ';
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java
index 44d88bb..6f6c1aa 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/InspectionCompanionGenerator.java
@@ -97,7 +97,7 @@
/**
* The suffix of the generated class name after the class's binary name.
*/
- private static final String GENERATED_CLASS_SUFFIX = "$$InspectionCompanion";
+ private static final String GENERATED_CLASS_SUFFIX = "$InspectionCompanion";
/**
* The null resource ID, copied to avoid a host dependency on platform code.
diff --git a/tools/processors/view_inspector/src/java/android/processor/view/inspector/PlatformInspectableProcessor.java b/tools/processors/view_inspector/src/java/android/processor/view/inspector/PlatformInspectableProcessor.java
index 01d9430..fd142c6 100644
--- a/tools/processors/view_inspector/src/java/android/processor/view/inspector/PlatformInspectableProcessor.java
+++ b/tools/processors/view_inspector/src/java/android/processor/view/inspector/PlatformInspectableProcessor.java
@@ -34,6 +34,7 @@
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
+import javax.lang.model.util.ElementFilter;
/**
@@ -127,13 +128,38 @@
final InspectableClassModel model = modelMap.computeIfAbsent(
classElement.get().getQualifiedName().toString(),
- k -> new InspectableClassModel(ClassName.get(classElement.get())));
+ k -> {
+ if (hasNestedInspectionCompanion(classElement.get())) {
+ fail(
+ String.format(
+ "Class %s already has an inspection companion.",
+ classElement.get().getQualifiedName().toString()),
+ element);
+ }
+ return new InspectableClassModel(ClassName.get(classElement.get()));
+ });
processor.process(element, model);
}
}
/**
+ * Determine if a class has a nested class named {@code InspectionCompanion}.
+ *
+ * @param typeElement A type element representing the class to check
+ * @return f the class contains a class named {@code InspectionCompanion}
+ */
+ private static boolean hasNestedInspectionCompanion(TypeElement typeElement) {
+ for (TypeElement nestedClass : ElementFilter.typesIn(typeElement.getEnclosedElements())) {
+ if (nestedClass.getSimpleName().toString().equals("InspectionCompanion")) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
* Get the nearest enclosing class if there is one.
*
* If {@param element} represents a class, it will be returned wrapped in an optional.
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/FieldProperty.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/FieldProperty.java.txt
index a44c43e..9a0fe5b 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/FieldProperty.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/FieldProperty.java.txt
@@ -12,7 +12,7 @@
* Generated by {@link android.processor.view.inspector.InspectionCompanionGenerator}
* on behalf of {@link android.processor.view.inspector.InspectionCompanionGeneratorTest}.
*/
-public final class TestNode$$InspectionCompanion implements InspectionCompanion<TestNode> {
+public final class TestNode$InspectionCompanion implements InspectionCompanion<TestNode> {
/**
* Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
*/
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntEnum.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntEnum.java.txt
index 764aa8b..b491de1 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntEnum.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntEnum.java.txt
@@ -13,7 +13,7 @@
* Generated by {@link android.processor.view.inspector.InspectionCompanionGenerator}
* on behalf of {@link android.processor.view.inspector.InspectionCompanionGeneratorTest}.
*/
-public final class TestNode$$InspectionCompanion implements InspectionCompanion<TestNode> {
+public final class TestNode$InspectionCompanion implements InspectionCompanion<TestNode> {
/**
* Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
*/
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntFlag.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntFlag.java.txt
index 75f2813..7d18058 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntFlag.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/IntFlag.java.txt
@@ -12,7 +12,7 @@
* Generated by {@link android.processor.view.inspector.InspectionCompanionGenerator}
* on behalf of {@link android.processor.view.inspector.InspectionCompanionGeneratorTest}.
*/
-public final class TestNode$$InspectionCompanion implements InspectionCompanion<TestNode> {
+public final class TestNode$InspectionCompanion implements InspectionCompanion<TestNode> {
/**
* Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
*/
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NestedClass.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NestedClass.java.txt
index 0cac462..dc27abb 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NestedClass.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NestedClass.java.txt
@@ -11,7 +11,7 @@
* Generated by {@link android.processor.view.inspector.InspectionCompanionGenerator}
* on behalf of {@link android.processor.view.inspector.InspectionCompanionGeneratorTest}.
*/
-public final class Outer$Inner$$InspectionCompanion implements InspectionCompanion<Outer.Inner> {
+public final class Outer$Inner$InspectionCompanion implements InspectionCompanion<Outer.Inner> {
/**
* Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
*/
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NoAttributeId.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NoAttributeId.java.txt
index ce0f867..738bcd3 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NoAttributeId.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NoAttributeId.java.txt
@@ -11,7 +11,7 @@
* Generated by {@link android.processor.view.inspector.InspectionCompanionGenerator}
* on behalf of {@link android.processor.view.inspector.InspectionCompanionGeneratorTest}.
*/
-public final class TestNode$$InspectionCompanion implements InspectionCompanion<TestNode> {
+public final class TestNode$InspectionCompanion implements InspectionCompanion<TestNode> {
/**
* Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
*/
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NodeName.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NodeName.java.txt
index f7357fe..82dd66e 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NodeName.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/NodeName.java.txt
@@ -12,7 +12,7 @@
* Generated by {@link android.processor.view.inspector.InspectionCompanionGenerator}
* on behalf of {@link android.processor.view.inspector.InspectionCompanionGeneratorTest}.
*/
-public final class TestNode$$InspectionCompanion implements InspectionCompanion<TestNode> {
+public final class TestNode$InspectionCompanion implements InspectionCompanion<TestNode> {
/**
* Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
*/
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SimpleProperties.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SimpleProperties.java.txt
index 556d8dd..08ea696 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SimpleProperties.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SimpleProperties.java.txt
@@ -12,7 +12,7 @@
* Generated by {@link android.processor.view.inspector.InspectionCompanionGenerator}
* on behalf of {@link android.processor.view.inspector.InspectionCompanionGeneratorTest}.
*/
-public final class TestNode$$InspectionCompanion implements InspectionCompanion<TestNode> {
+public final class TestNode$InspectionCompanion implements InspectionCompanion<TestNode> {
/**
* Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
*/
diff --git a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SuppliedAttributeId.java.txt b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SuppliedAttributeId.java.txt
index d72cdd5..3bfa78a 100644
--- a/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SuppliedAttributeId.java.txt
+++ b/tools/processors/view_inspector/test/resources/android/processor/view/inspector/InspectionCompanionGeneratorTest/SuppliedAttributeId.java.txt
@@ -11,7 +11,7 @@
* Generated by {@link android.processor.view.inspector.InspectionCompanionGenerator}
* on behalf of {@link android.processor.view.inspector.InspectionCompanionGeneratorTest}.
*/
-public final class TestNode$$InspectionCompanion implements InspectionCompanion<TestNode> {
+public final class TestNode$InspectionCompanion implements InspectionCompanion<TestNode> {
/**
* Set by {@link #mapProperties(PropertyMapper)} once properties have been mapped.
*/
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index ee60408..0b55794 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -539,9 +539,10 @@
mFqdn = fqdn;
}
- /** {@hide} */
- @SystemApi
- public @Nullable String getFqdn() {
+ /**
+ * Returns the Fully Qualified Domain Name of the network if it is a Passpoint network.
+ */
+ public @Nullable String getPasspointFqdn() {
return mFqdn;
}
@@ -550,9 +551,10 @@
mProviderFriendlyName = providerFriendlyName;
}
- /** {@hide} */
- @SystemApi
- public @Nullable String getProviderFriendlyName() {
+ /**
+ * Returns the Provider Friendly Name of the network if it is a Passpoint network.
+ */
+ public @Nullable String getPasspointProviderFriendlyName() {
return mProviderFriendlyName;
}
diff --git a/wifi/java/android/net/wifi/aware/DiscoverySession.java b/wifi/java/android/net/wifi/aware/DiscoverySession.java
index a47e70b..d97f6fb 100644
--- a/wifi/java/android/net/wifi/aware/DiscoverySession.java
+++ b/wifi/java/android/net/wifi/aware/DiscoverySession.java
@@ -36,7 +36,7 @@
* <ul>
* <li>Sending messages: {@link #sendMessage(PeerHandle, int, byte[])} method.
* <li>Creating a network-specifier when requesting a Aware connection using
- * {@link WifiAwareManager.NetworkSpecifierBuilder}.
+ * {@link WifiAwareNetworkSpecifier.Builder}.
* </ul>
* <p>
* The {@link #close()} method must be called to destroy discovery sessions once they are
@@ -270,7 +270,7 @@
* <p>
* To set up an encrypted link use the
* {@link #createNetworkSpecifierPassphrase(PeerHandle, String)} API.
- * @deprecated Use the replacement {@link WifiAwareManager.NetworkSpecifierBuilder}.
+ * @deprecated Use the replacement {@link WifiAwareNetworkSpecifier.Builder}.
*
* @param peerHandle The peer's handle obtained through
* {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle, byte[], java.util.List)}
@@ -320,7 +320,7 @@
* <p>
* Note: per the Wi-Fi Aware specification the roles are fixed - a Subscriber is an INITIATOR
* and a Publisher is a RESPONDER.
- * @deprecated Use the replacement {@link WifiAwareManager.NetworkSpecifierBuilder}.
+ * @deprecated Use the replacement {@link WifiAwareNetworkSpecifier.Builder}.
*
* @param peerHandle The peer's handle obtained through
* {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle,
@@ -380,7 +380,7 @@
* <p>
* Note: per the Wi-Fi Aware specification the roles are fixed - a Subscriber is an INITIATOR
* and a Publisher is a RESPONDER.
- * @deprecated Use the replacement {@link WifiAwareManager.NetworkSpecifierBuilder}.
+ * @deprecated Use the replacement {@link WifiAwareNetworkSpecifier.Builder}.
*
* @param peerHandle The peer's handle obtained through
* {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle,
diff --git a/wifi/java/android/net/wifi/aware/ParcelablePeerHandle.java b/wifi/java/android/net/wifi/aware/ParcelablePeerHandle.java
index ce67abf..ca473db 100644
--- a/wifi/java/android/net/wifi/aware/ParcelablePeerHandle.java
+++ b/wifi/java/android/net/wifi/aware/ParcelablePeerHandle.java
@@ -16,6 +16,7 @@
package android.net.wifi.aware;
+import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
@@ -29,7 +30,7 @@
*
* @param peerHandle The {@link PeerHandle} to be made parcelable.
*/
- public ParcelablePeerHandle(PeerHandle peerHandle) {
+ public ParcelablePeerHandle(@NonNull PeerHandle peerHandle) {
super(peerHandle.peerId);
}
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
index 1a5cd5a..c9b0b12 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
@@ -21,7 +21,6 @@
import android.annotation.Nullable;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
-import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.content.Context;
import android.net.ConnectivityManager;
@@ -35,7 +34,6 @@
import android.os.Message;
import android.os.Process;
import android.os.RemoteException;
-import android.text.TextUtils;
import android.util.Log;
import libcore.util.HexEncoding;
@@ -59,7 +57,7 @@
* {@link WifiAwareSession#subscribe(SubscribeConfig, DiscoverySessionCallback, Handler)}.
* <li>Create a Aware network specifier to be used with
* {@link ConnectivityManager#requestNetwork(NetworkRequest, ConnectivityManager.NetworkCallback)}
- * to set-up a Aware connection with a peer. Refer to {@link NetworkSpecifierBuilder}.
+ * to set-up a Aware connection with a peer. Refer to {@link WifiAwareNetworkSpecifier.Builder}.
* </ul>
* <p>
* Aware may not be usable when Wi-Fi is disabled (and other conditions). To validate that
@@ -108,7 +106,7 @@
* <li>{@link NetworkRequest.Builder#addTransportType(int)} of
* {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
* <li>{@link NetworkRequest.Builder#setNetworkSpecifier(String)} using
- * {@link NetworkSpecifierBuilder}.
+ * {@link WifiAwareNetworkSpecifier.Builder}.
* </ul>
*/
@SystemService(Context.WIFI_AWARE_SERVICE)
@@ -408,7 +406,7 @@
if (!WifiAwareUtils.isLegacyVersion(mContext, Build.VERSION_CODES.Q)) {
throw new UnsupportedOperationException(
- "API not deprecated - use WifiAwareManager.NetworkSpecifierBuilder");
+ "API not deprecated - use WifiAwareNetworkSpecifier.Builder");
}
if (role != WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
@@ -813,198 +811,4 @@
mOriginalCallback.onSessionTerminated();
}
}
-
- /**
- * A builder class for a Wi-Fi Aware network specifier to set up an Aware connection with a
- * peer.
- * <p>
- * Note that all Wi-Fi Aware connection specifier objects must call the
- * {@link NetworkSpecifierBuilder#setDiscoverySession(DiscoverySession)} to specify the context
- * within which the connection is created, and
- * {@link NetworkSpecifierBuilder#setPeerHandle(PeerHandle)} to specify the peer to which the
- * connection is created.
- */
- public static final class NetworkSpecifierBuilder {
- private DiscoverySession mDiscoverySession;
- private PeerHandle mPeerHandle;
- private String mPskPassphrase;
- private byte[] mPmk;
- private int mPort = 0; // invalid value
- private int mTransportProtocol = -1; // invalid value
-
- /**
- * Configure the {@link PublishDiscoverySession} or {@link SubscribeDiscoverySession}
- * discovery session in whose context the connection is created.
- * <p>
- * Note: this method must be called for any connection request!
- *
- * @param discoverySession A Wi-Fi Aware discovery session.
- * @return the current {@link NetworkSpecifierBuilder} builder, enabling chaining of builder
- * methods.
- */
- public @NonNull NetworkSpecifierBuilder setDiscoverySession(
- @NonNull DiscoverySession discoverySession) {
- if (discoverySession == null) {
- throw new IllegalArgumentException("Non-null discoverySession required");
- }
- mDiscoverySession = discoverySession;
- return this;
- }
-
- /**
- * Configure the {@link PeerHandle} of the peer to which the Wi-Fi Aware connection is
- * requested. The peer is discovered through Wi-Fi Aware discovery,
- * <p>
- * Note: this method must be called for any connection request!
- *
- * @param peerHandle The peer's handle obtained through
- * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle, byte[], java.util.List)}
- * or
- * {@link DiscoverySessionCallback#onMessageReceived(PeerHandle, byte[])}.
- * @return the current {@link NetworkSpecifierBuilder} builder, enabling chaining of builder
- * methods.
- */
- public @NonNull NetworkSpecifierBuilder setPeerHandle(@NonNull PeerHandle peerHandle) {
- if (peerHandle == null) {
- throw new IllegalArgumentException("Non-null peerHandle required");
- }
- mPeerHandle = peerHandle;
- return this;
- }
-
- /**
- * Configure the PSK Passphrase for the Wi-Fi Aware connection being requested. This method
- * is optional - if not called, then an Open (unencrypted) connection will be created.
- *
- * @param pskPassphrase The (optional) passphrase to be used to encrypt the link.
- * @return the current {@link NetworkSpecifierBuilder} builder, enabling chaining of builder
- * methods.
- */
- public @NonNull NetworkSpecifierBuilder setPskPassphrase(@NonNull String pskPassphrase) {
- if (!WifiAwareUtils.validatePassphrase(pskPassphrase)) {
- throw new IllegalArgumentException("Passphrase must meet length requirements");
- }
- mPskPassphrase = pskPassphrase;
- return this;
- }
-
- /**
- * Configure the PMK for the Wi-Fi Aware connection being requested. This method
- * is optional - if not called, then an Open (unencrypted) connection will be created.
- *
- * @param pmk A PMK (pairwise master key, see IEEE 802.11i) specifying the key to use for
- * encrypting the data-path. Use the {@link #setPskPassphrase(String)} to
- * specify a Passphrase.
- * @return the current {@link NetworkSpecifierBuilder} builder, enabling chaining of builder
- * methods.
- * @hide
- */
- @SystemApi
- public @NonNull NetworkSpecifierBuilder setPmk(@NonNull byte[] pmk) {
- if (!WifiAwareUtils.validatePmk(pmk)) {
- throw new IllegalArgumentException("PMK must 32 bytes");
- }
- mPmk = pmk;
- return this;
- }
-
- /**
- * Configure the port number which will be used to create a connection over this link. This
- * configuration should only be done on the server device, e.g. the device creating the
- * {@link java.net.ServerSocket}.
- * <p>Notes:
- * <ul>
- * <li>The server device must be the Publisher device!
- * <li>The port information can only be specified on secure links, specified using
- * {@link #setPskPassphrase(String)}.
- * </ul>
- *
- * @param port A positive integer indicating the port to be used for communication.
- * @return the current {@link NetworkSpecifierBuilder} builder, enabling chaining of builder
- * methods.
- */
- public @NonNull NetworkSpecifierBuilder setPort(int port) {
- if (port <= 0 || port > 65535) {
- throw new IllegalArgumentException("The port must be a positive value (0, 65535]");
- }
- mPort = port;
- return this;
- }
-
- /**
- * Configure the transport protocol which will be used to create a connection over this
- * link. This configuration should only be done on the server device, e.g. the device
- * creating the {@link java.net.ServerSocket} for TCP.
- * <p>Notes:
- * <ul>
- * <li>The server device must be the Publisher device!
- * <li>The transport protocol information can only be specified on secure links,
- * specified using {@link #setPskPassphrase(String)}.
- * </ul>
- * The transport protocol number is assigned by the Internet Assigned Numbers Authority
- * (IANA) https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml.
- *
- * @param transportProtocol The transport protocol to be used for communication.
- * @return the current {@link NetworkSpecifierBuilder} builder, enabling chaining of builder
- * methods.
- */
- public @NonNull NetworkSpecifierBuilder setTransportProtocol(int transportProtocol) {
- if (transportProtocol < 0 || transportProtocol > 255) {
- throw new IllegalArgumentException(
- "The transport protocol must be in range [0, 255]");
- }
- mTransportProtocol = transportProtocol;
- return this;
- }
-
- /**
- * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)}
- * for a WiFi Aware connection (link) to the specified peer. The
- * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to
- * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
- * <p> The default builder constructor will initialize a NetworkSpecifier which requests an
- * open (non-encrypted) link. To request an encrypted link use the
- * {@link #setPskPassphrase(String)} builder method.
- *
- * @return A {@link NetworkSpecifier} to be used to construct
- * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} to pass
- * to {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,
- * android.net.ConnectivityManager.NetworkCallback)}
- * [or other varieties of that API].
- */
- public @NonNull NetworkSpecifier build() {
- if (mDiscoverySession == null) {
- throw new IllegalStateException("Null discovery session!?");
- }
- if (mPskPassphrase != null & mPmk != null) {
- throw new IllegalStateException(
- "Can only specify a Passphrase or a PMK - not both!");
- }
-
- int role = mDiscoverySession instanceof SubscribeDiscoverySession
- ? WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
- : WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER;
-
- if (mPort != 0 || mTransportProtocol != -1) {
- if (role != WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER) {
- throw new IllegalStateException(
- "Port and transport protocol information can only "
- + "be specified on the Publisher device (which is the server");
- }
- if (TextUtils.isEmpty(mPskPassphrase) && mPmk == null) {
- throw new IllegalStateException("Port and transport protocol information can "
- + "only be specified on a secure link");
- }
- }
-
- if (role == WIFI_AWARE_DATA_PATH_ROLE_INITIATOR && mPeerHandle == null) {
- throw new IllegalStateException("Null peerHandle!?");
- }
-
- return new WifiAwareNetworkSpecifier(
- WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_IB, role,
- mDiscoverySession.mClientId, mDiscoverySession.mSessionId, mPeerHandle.peerId,
- null, mPmk, mPskPassphrase, mPort, mTransportProtocol, Process.myUid());
- }
- }
}
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareNetworkInfo.java b/wifi/java/android/net/wifi/aware/WifiAwareNetworkInfo.java
index 020cb56..fd26817b 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareNetworkInfo.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareNetworkInfo.java
@@ -75,7 +75,7 @@
/**
* Get the port number to be used to create a network connection to the Wi-Fi Aware peer.
* The port information is provided by the app running on the peer which requested the
- * connection, using the {@link WifiAwareManager.NetworkSpecifierBuilder#setPort(int)}.
+ * connection, using the {@link WifiAwareNetworkSpecifier.Builder#setPort(int)}.
*
* @return A port number on the peer. A value of 0 indicates that no port was specified by the
* peer.
@@ -88,7 +88,7 @@
* Get the transport protocol to be used to communicate over a network connection to the Wi-Fi
* Aware peer. The transport protocol is provided by the app running on the peer which requested
* the connection, using the
- * {@link WifiAwareManager.NetworkSpecifierBuilder#setTransportProtocol(int)}.
+ * {@link WifiAwareNetworkSpecifier.Builder#setTransportProtocol(int)}.
* <p>
* The transport protocol number is assigned by the Internet Assigned Numbers Authority
* (IANA) https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml.
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java b/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java
index 59f534a..b225116 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java
@@ -16,9 +16,15 @@
package android.net.wifi.aware;
+import static android.net.wifi.aware.WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
import android.net.NetworkSpecifier;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.Process;
+import android.text.TextUtils;
import java.util.Arrays;
import java.util.Objects;
@@ -29,8 +35,6 @@
* {@link WifiAwareSession#createNetworkSpecifierOpen(int, byte[])} or
* {@link DiscoverySession#createNetworkSpecifierOpen(PeerHandle)} or their secure (Passphrase)
* versions.
- *
- * @hide
*/
public final class WifiAwareNetworkSpecifier extends NetworkSpecifier implements Parcelable {
/**
@@ -138,6 +142,8 @@
* device they all get the same link. However, the link is only set up on the first request -
* hence only the first can transmit the port information. But we don't want to expose that
* information to other apps. Limiting to secure links would (usually) imply single app usage.
+ *
+ * @hide
*/
public final int transportProtocol;
@@ -292,4 +298,197 @@
throw new SecurityException("mismatched UIDs");
}
}
+
+ /**
+ * A builder class for a Wi-Fi Aware network specifier to set up an Aware connection with a
+ * peer.
+ * <p>
+ * Note that all Wi-Fi Aware connection specifier objects must call the
+ * {@link Builder#setDiscoverySession(DiscoverySession)} to specify the context
+ * within which the connection is created, and
+ * {@link Builder#setPeerHandle(PeerHandle)} to specify the peer to which the
+ * connection is created.
+ */
+ public static final class Builder {
+ private DiscoverySession mDiscoverySession;
+ private PeerHandle mPeerHandle;
+ private String mPskPassphrase;
+ private byte[] mPmk;
+ private int mPort = 0; // invalid value
+ private int mTransportProtocol = -1; // invalid value
+
+ /**
+ * Configure the {@link PublishDiscoverySession} or {@link SubscribeDiscoverySession}
+ * discovery session in whose context the connection is created.
+ * <p>
+ * Note: this method must be called for any connection request!
+ *
+ * @param discoverySession A Wi-Fi Aware discovery session.
+ * @return the current {@link Builder} builder, enabling chaining of builder
+ * methods.
+ */
+ public @NonNull Builder setDiscoverySession(@NonNull DiscoverySession discoverySession) {
+ if (discoverySession == null) {
+ throw new IllegalArgumentException("Non-null discoverySession required");
+ }
+ mDiscoverySession = discoverySession;
+ return this;
+ }
+
+ /**
+ * Configure the {@link PeerHandle} of the peer to which the Wi-Fi Aware connection is
+ * requested. The peer is discovered through Wi-Fi Aware discovery,
+ * <p>
+ * Note: this method must be called for any connection request!
+ *
+ * @param peerHandle The peer's handle obtained through
+ * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle, byte[], java.util.List)}
+ * or
+ * {@link DiscoverySessionCallback#onMessageReceived(PeerHandle, byte[])}.
+ * @return the current {@link Builder} builder, enabling chaining of builder
+ * methods.
+ */
+ public @NonNull Builder setPeerHandle(@NonNull PeerHandle peerHandle) {
+ if (peerHandle == null) {
+ throw new IllegalArgumentException("Non-null peerHandle required");
+ }
+ mPeerHandle = peerHandle;
+ return this;
+ }
+
+ /**
+ * Configure the PSK Passphrase for the Wi-Fi Aware connection being requested. This method
+ * is optional - if not called, then an Open (unencrypted) connection will be created.
+ *
+ * @param pskPassphrase The (optional) passphrase to be used to encrypt the link.
+ * @return the current {@link Builder} builder, enabling chaining of builder
+ * methods.
+ */
+ public @NonNull Builder setPskPassphrase(@NonNull String pskPassphrase) {
+ if (!WifiAwareUtils.validatePassphrase(pskPassphrase)) {
+ throw new IllegalArgumentException("Passphrase must meet length requirements");
+ }
+ mPskPassphrase = pskPassphrase;
+ return this;
+ }
+
+ /**
+ * Configure the PMK for the Wi-Fi Aware connection being requested. This method
+ * is optional - if not called, then an Open (unencrypted) connection will be created.
+ *
+ * @param pmk A PMK (pairwise master key, see IEEE 802.11i) specifying the key to use for
+ * encrypting the data-path. Use the {@link #setPskPassphrase(String)} to
+ * specify a Passphrase.
+ * @return the current {@link Builder} builder, enabling chaining of builder
+ * methods.
+ * @hide
+ */
+ @SystemApi
+ public @NonNull Builder setPmk(@NonNull byte[] pmk) {
+ if (!WifiAwareUtils.validatePmk(pmk)) {
+ throw new IllegalArgumentException("PMK must 32 bytes");
+ }
+ mPmk = pmk;
+ return this;
+ }
+
+ /**
+ * Configure the port number which will be used to create a connection over this link. This
+ * configuration should only be done on the server device, e.g. the device creating the
+ * {@link java.net.ServerSocket}.
+ * <p>Notes:
+ * <ul>
+ * <li>The server device must be the Publisher device!
+ * <li>The port information can only be specified on secure links, specified using
+ * {@link #setPskPassphrase(String)}.
+ * </ul>
+ *
+ * @param port A positive integer indicating the port to be used for communication.
+ * @return the current {@link Builder} builder, enabling chaining of builder
+ * methods.
+ */
+ public @NonNull Builder setPort(int port) {
+ if (port <= 0 || port > 65535) {
+ throw new IllegalArgumentException("The port must be a positive value (0, 65535]");
+ }
+ mPort = port;
+ return this;
+ }
+
+ /**
+ * Configure the transport protocol which will be used to create a connection over this
+ * link. This configuration should only be done on the server device, e.g. the device
+ * creating the {@link java.net.ServerSocket} for TCP.
+ * <p>Notes:
+ * <ul>
+ * <li>The server device must be the Publisher device!
+ * <li>The transport protocol information can only be specified on secure links,
+ * specified using {@link #setPskPassphrase(String)}.
+ * </ul>
+ * The transport protocol number is assigned by the Internet Assigned Numbers Authority
+ * (IANA) https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml.
+ *
+ * @param transportProtocol The transport protocol to be used for communication.
+ * @return the current {@link Builder} builder, enabling chaining of builder
+ * methods.
+ */
+ public @NonNull Builder setTransportProtocol(int transportProtocol) {
+ if (transportProtocol < 0 || transportProtocol > 255) {
+ throw new IllegalArgumentException(
+ "The transport protocol must be in range [0, 255]");
+ }
+ mTransportProtocol = transportProtocol;
+ return this;
+ }
+
+ /**
+ * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)}
+ * for a WiFi Aware connection (link) to the specified peer. The
+ * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to
+ * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
+ * <p> The default builder constructor will initialize a NetworkSpecifier which requests an
+ * open (non-encrypted) link. To request an encrypted link use the
+ * {@link #setPskPassphrase(String)} builder method.
+ *
+ * @return A {@link NetworkSpecifier} to be used to construct
+ * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} to pass
+ * to {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,
+ * android.net.ConnectivityManager.NetworkCallback)}
+ * [or other varieties of that API].
+ */
+ public @NonNull WifiAwareNetworkSpecifier build() {
+ if (mDiscoverySession == null) {
+ throw new IllegalStateException("Null discovery session!?");
+ }
+ if (mPskPassphrase != null & mPmk != null) {
+ throw new IllegalStateException(
+ "Can only specify a Passphrase or a PMK - not both!");
+ }
+
+ int role = mDiscoverySession instanceof SubscribeDiscoverySession
+ ? WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
+ : WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER;
+
+ if (mPort != 0 || mTransportProtocol != -1) {
+ if (role != WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER) {
+ throw new IllegalStateException(
+ "Port and transport protocol information can only "
+ + "be specified on the Publisher device (which is the server");
+ }
+ if (TextUtils.isEmpty(mPskPassphrase) && mPmk == null) {
+ throw new IllegalStateException("Port and transport protocol information can "
+ + "only be specified on a secure link");
+ }
+ }
+
+ if (role == WIFI_AWARE_DATA_PATH_ROLE_INITIATOR && mPeerHandle == null) {
+ throw new IllegalStateException("Null peerHandle!?");
+ }
+
+ return new WifiAwareNetworkSpecifier(
+ WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_IB, role,
+ mDiscoverySession.mClientId, mDiscoverySession.mSessionId, mPeerHandle.peerId,
+ null, mPmk, mPskPassphrase, mPort, mTransportProtocol, Process.myUid());
+ }
+ }
}
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareSession.java b/wifi/java/android/net/wifi/aware/WifiAwareSession.java
index 245b304..3c97813 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareSession.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareSession.java
@@ -213,7 +213,7 @@
* This API is targeted for applications which can obtain the peer MAC address using OOB
* (out-of-band) discovery. Aware discovery does not provide the MAC address of the peer -
* when using Aware discovery use the alternative network specifier method -
- * {@link android.net.wifi.aware.WifiAwareManager.NetworkSpecifierBuilder}.
+ * {@link android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder}.
* <p>
* To set up an encrypted link use the
* {@link #createNetworkSpecifierPassphrase(int, byte[], String)} API.
@@ -254,7 +254,7 @@
* This API is targeted for applications which can obtain the peer MAC address using OOB
* (out-of-band) discovery. Aware discovery does not provide the MAC address of the peer -
* when using Aware discovery use the alternative network specifier method -
- * {@link android.net.wifi.aware.WifiAwareManager.NetworkSpecifierBuilder}.
+ * {@link android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder}.
*
* @param role The role of this device:
* {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_INITIATOR} or
@@ -300,7 +300,7 @@
* This API is targeted for applications which can obtain the peer MAC address using OOB
* (out-of-band) discovery. Aware discovery does not provide the MAC address of the peer -
* when using Aware discovery use the alternative network specifier method -
- * {@link android.net.wifi.aware.WifiAwareManager.NetworkSpecifierBuilder}.
+ * {@link android.net.wifi.aware.WifiAwareNetworkSpecifier.Builder}.
*
* @param role The role of this device:
* {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_INITIATOR} or
diff --git a/wifi/tests/src/android/net/wifi/WifiInfoTest.java b/wifi/tests/src/android/net/wifi/WifiInfoTest.java
index b303496..0ce5d66 100644
--- a/wifi/tests/src/android/net/wifi/WifiInfoTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiInfoTest.java
@@ -70,7 +70,7 @@
assertTrue(readWifiInfo.isOsuAp());
assertTrue(readWifiInfo.isPasspointAp());
assertEquals(TEST_PACKAGE_NAME, readWifiInfo.getNetworkSuggestionOrSpecifierPackageName());
- assertEquals(TEST_FQDN, readWifiInfo.getFqdn());
- assertEquals(TEST_PROVIDER_NAME, readWifiInfo.getProviderFriendlyName());
+ assertEquals(TEST_FQDN, readWifiInfo.getPasspointFqdn());
+ assertEquals(TEST_PROVIDER_NAME, readWifiInfo.getPasspointProviderFriendlyName());
}
}
diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
index 3cc96bf..657a338 100644
--- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
@@ -958,9 +958,8 @@
WifiAwareNetworkSpecifier ns =
(WifiAwareNetworkSpecifier) publishSession.getValue().createNetworkSpecifierOpen(
peerHandle);
- WifiAwareNetworkSpecifier nsb = (WifiAwareNetworkSpecifier) new WifiAwareManager
- .NetworkSpecifierBuilder().setDiscoverySession(publishSession.getValue())
- .setPeerHandle(peerHandle).build();
+ WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder().setDiscoverySession(
+ publishSession.getValue()).setPeerHandle(peerHandle).build();
// validate format
collector.checkThat("role", WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER,
@@ -980,9 +979,9 @@
// (4) request an encrypted (PMK) network specifier from the session
ns = (WifiAwareNetworkSpecifier) publishSession.getValue().createNetworkSpecifierPmk(
peerHandle, pmk);
- nsb = (WifiAwareNetworkSpecifier) new WifiAwareManager.NetworkSpecifierBuilder()
- .setDiscoverySession(publishSession.getValue()).setPeerHandle(peerHandle)
- .setPmk(pmk).setPort(port).setTransportProtocol(transportProtocol).build();
+ nsb = new WifiAwareNetworkSpecifier.Builder().setDiscoverySession(
+ publishSession.getValue()).setPeerHandle(peerHandle).setPmk(pmk).setPort(
+ port).setTransportProtocol(transportProtocol).build();
// validate format
collector.checkThat("role", WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER,
@@ -1006,10 +1005,9 @@
(WifiAwareNetworkSpecifier) publishSession.getValue()
.createNetworkSpecifierPassphrase(
peerHandle, passphrase);
- nsb = (WifiAwareNetworkSpecifier) new WifiAwareManager.NetworkSpecifierBuilder()
- .setDiscoverySession(publishSession.getValue()).setPeerHandle(peerHandle)
- .setPskPassphrase(passphrase).setPort(port).setTransportProtocol(transportProtocol)
- .build();
+ nsb = new WifiAwareNetworkSpecifier.Builder().setDiscoverySession(
+ publishSession.getValue()).setPeerHandle(peerHandle).setPskPassphrase(
+ passphrase).setPort(port).setTransportProtocol(transportProtocol).build();
// validate format
collector.checkThat("role", WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER,
@@ -1257,14 +1255,14 @@
// (3) create network specifier
if (doPmk) {
if (useBuilder) {
- new WifiAwareManager.NetworkSpecifierBuilder().setDiscoverySession(
+ new WifiAwareNetworkSpecifier.Builder().setDiscoverySession(
publishSession.getValue()).setPeerHandle(peerHandle).setPmk(pmk).build();
} else {
publishSession.getValue().createNetworkSpecifierPmk(peerHandle, pmk);
}
} else {
if (useBuilder) {
- new WifiAwareManager.NetworkSpecifierBuilder().setDiscoverySession(
+ new WifiAwareNetworkSpecifier.Builder().setDiscoverySession(
publishSession.getValue()).setPeerHandle(peerHandle).setPskPassphrase(
passphrase).build();
} else {
@@ -1355,10 +1353,8 @@
DiscoverySession publishSession = executeSessionStartup(true);
- WifiAwareNetworkSpecifier nsb =
- (WifiAwareNetworkSpecifier) new WifiAwareManager.NetworkSpecifierBuilder()
- .setDiscoverySession(publishSession).setPeerHandle(peerHandle)
- .setPmk(pmk).setPort(port).build();
+ WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder().setDiscoverySession(
+ publishSession).setPeerHandle(peerHandle).setPmk(pmk).setPort(port).build();
}
/**
@@ -1372,10 +1368,8 @@
DiscoverySession publishSession = executeSessionStartup(true);
- WifiAwareNetworkSpecifier nsb =
- (WifiAwareNetworkSpecifier) new WifiAwareManager.NetworkSpecifierBuilder()
- .setDiscoverySession(publishSession).setPeerHandle(peerHandle)
- .setPort(port).build();
+ WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder().setDiscoverySession(
+ publishSession).setPeerHandle(peerHandle).setPort(port).build();
}
/**
@@ -1389,10 +1383,8 @@
DiscoverySession subscribeSession = executeSessionStartup(false);
- WifiAwareNetworkSpecifier nsb =
- (WifiAwareNetworkSpecifier) new WifiAwareManager.NetworkSpecifierBuilder()
- .setDiscoverySession(subscribeSession).setPeerHandle(peerHandle)
- .setPort(port).build();
+ WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder().setDiscoverySession(
+ subscribeSession).setPeerHandle(peerHandle).setPort(port).build();
}
/**
@@ -1411,8 +1403,7 @@
DiscoverySession publishSession = executeSessionStartup(true);
try {
- WifiAwareNetworkSpecifier nsb =
- (WifiAwareNetworkSpecifier) new WifiAwareManager.NetworkSpecifierBuilder()
+ WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder()
.setDiscoverySession(publishSession).setPeerHandle(peerHandle)
.setPmk(pmk).setTransportProtocol(tpNegative).build();
assertTrue("No exception on negative transport protocol!", false);
@@ -1420,23 +1411,19 @@
// nop - exception is correct!
}
try {
- WifiAwareNetworkSpecifier nsb =
- (WifiAwareNetworkSpecifier) new WifiAwareManager.NetworkSpecifierBuilder()
+ WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder()
.setDiscoverySession(publishSession).setPeerHandle(peerHandle)
.setPmk(pmk).setTransportProtocol(tpTooLarge).build();
assertTrue("No exception on >255 transport protocol!", false);
} catch (IllegalArgumentException e) {
// nop - exception is correct!
}
- WifiAwareNetworkSpecifier nsb =
- (WifiAwareNetworkSpecifier) new WifiAwareManager.NetworkSpecifierBuilder()
+ WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder()
.setDiscoverySession(publishSession).setPeerHandle(peerHandle)
.setPmk(pmk).setTransportProtocol(tpSmallest).build();
- nsb =
- (WifiAwareNetworkSpecifier) new WifiAwareManager.NetworkSpecifierBuilder()
- .setDiscoverySession(
- publishSession).setPeerHandle(peerHandle).setPmk(
- pmk).setTransportProtocol(tpLargest).build();
+ nsb = new WifiAwareNetworkSpecifier.Builder().setDiscoverySession(
+ publishSession).setPeerHandle(peerHandle).setPmk(pmk).setTransportProtocol(
+ tpLargest).build();
}
/**
@@ -1450,8 +1437,7 @@
DiscoverySession publishSession = executeSessionStartup(true);
- WifiAwareNetworkSpecifier nsb =
- (WifiAwareNetworkSpecifier) new WifiAwareManager.NetworkSpecifierBuilder()
+ WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder()
.setDiscoverySession(publishSession).setPeerHandle(peerHandle)
.setTransportProtocol(transportProtocol).build();
}
@@ -1467,8 +1453,7 @@
DiscoverySession subscribeSession = executeSessionStartup(false);
- WifiAwareNetworkSpecifier nsb =
- (WifiAwareNetworkSpecifier) new WifiAwareManager.NetworkSpecifierBuilder()
+ WifiAwareNetworkSpecifier nsb = new WifiAwareNetworkSpecifier.Builder()
.setDiscoverySession(subscribeSession).setPeerHandle(peerHandle)
.setTransportProtocol(transportProtocol).build();
}