Merge "Update boot classpath and system server profiles"
diff --git a/api/current.txt b/api/current.txt
index 0176c68..f1b5459 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);
@@ -12284,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;
@@ -29944,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();
@@ -35493,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";
@@ -49197,7 +49201,6 @@
method public final boolean isFunctionPressed();
method public static final boolean isGamepadButton(int);
method public final boolean isLongPress();
- method public static final boolean isMediaSessionKey(int);
method public final boolean isMetaPressed();
method public static boolean isModifierKey(int);
method public final boolean isNumLockOn();
@@ -50077,7 +50080,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();
@@ -50111,10 +50114,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);
}
@@ -54512,7 +54515,7 @@
method public abstract boolean getDomStorageEnabled();
method public abstract String getFantasyFontFamily();
method public abstract String getFixedFontFamily();
- method public int getForceDarkMode();
+ method public int getForceDark();
method public abstract boolean getJavaScriptCanOpenWindowsAutomatically();
method public abstract boolean getJavaScriptEnabled();
method public abstract android.webkit.WebSettings.LayoutAlgorithm getLayoutAlgorithm();
@@ -54559,7 +54562,7 @@
method @Deprecated public abstract void setEnableSmoothTransition(boolean);
method public abstract void setFantasyFontFamily(String);
method public abstract void setFixedFontFamily(String);
- method public void setForceDarkMode(int);
+ method public void setForceDark(int);
method @Deprecated public abstract void setGeolocationDatabasePath(String);
method public abstract void setGeolocationEnabled(boolean);
method public abstract void setJavaScriptCanOpenWindowsAutomatically(boolean);
@@ -54590,9 +54593,9 @@
method public abstract void setUserAgentString(@Nullable String);
method public abstract boolean supportMultipleWindows();
method public abstract boolean supportZoom();
- field public static final int FORCE_DARK_AUTO = 0; // 0x0
- field public static final int FORCE_DARK_OFF = -1; // 0xffffffff
- field public static final int FORCE_DARK_ON = 1; // 0x1
+ field public static final int FORCE_DARK_AUTO = 1; // 0x1
+ field public static final int FORCE_DARK_OFF = 0; // 0x0
+ field public static final int FORCE_DARK_ON = 2; // 0x2
field public static final int LOAD_CACHE_ELSE_NETWORK = 1; // 0x1
field public static final int LOAD_CACHE_ONLY = 3; // 0x3
field public static final int LOAD_DEFAULT = -1; // 0xffffffff
@@ -54715,8 +54718,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();
@@ -54766,8 +54769,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>);
@@ -54883,14 +54886,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);
}
}
diff --git a/api/system-current.txt b/api/system-current.txt
index 232144f..04bddc1 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -231,7 +231,6 @@
}
public static final class R.dimen {
- field public static final int config_mediaMetadataBitmapMaxSize = 17104904; // 0x1050008
field public static final int config_restrictedIconSize = 17104903; // 0x1050007
}
@@ -3495,7 +3494,6 @@
field public static final int AUDIOFOCUS_FLAG_DELAY_OK = 1; // 0x1
field public static final int AUDIOFOCUS_FLAG_LOCK = 4; // 0x4
field public static final int AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS = 2; // 0x2
- field public static final int FLAG_FROM_KEY = 65536; // 0x10000
field public static final int SUCCESS = 0; // 0x0
}
@@ -4734,8 +4732,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();
}
@@ -5602,7 +5598,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();
@@ -5612,6 +5607,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();
@@ -5619,7 +5615,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";
@@ -5629,6 +5625,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 {
@@ -9846,8 +9846,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 +9897,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 +9979,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/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/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/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/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/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/KeyEvent.java b/core/java/android/view/KeyEvent.java
index f700d32..87dd5b4 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -1806,28 +1806,6 @@
}
/**
- * Returns whether this key will be sent to the
- * {@link android.media.session.MediaSession.Callback} if not handled.
- */
- public static final boolean isMediaSessionKey(int keyCode) {
- switch (keyCode) {
- case KeyEvent.KEYCODE_MEDIA_PLAY:
- case KeyEvent.KEYCODE_MEDIA_PAUSE:
- case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
- case KeyEvent.KEYCODE_MUTE:
- case KeyEvent.KEYCODE_HEADSETHOOK:
- case KeyEvent.KEYCODE_MEDIA_STOP:
- case KeyEvent.KEYCODE_MEDIA_NEXT:
- case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
- case KeyEvent.KEYCODE_MEDIA_REWIND:
- case KeyEvent.KEYCODE_MEDIA_RECORD:
- case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
- return true;
- }
- return false;
- }
-
- /**
* Returns true if the specified keycode is a gamepad button.
* @return True if the keycode is a gamepad button, such as {@link #KEYCODE_BUTTON_A}.
*/
@@ -1886,6 +1864,30 @@
}
}
+ /**
+ * Returns whether this key will be sent to the
+ * {@link android.media.session.MediaSession.Callback} if not handled.
+ *
+ * @hide
+ */
+ public static final boolean isMediaSessionKey(int keyCode) {
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_MEDIA_PLAY:
+ case KeyEvent.KEYCODE_MEDIA_PAUSE:
+ case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
+ case KeyEvent.KEYCODE_MUTE:
+ case KeyEvent.KEYCODE_HEADSETHOOK:
+ case KeyEvent.KEYCODE_MEDIA_STOP:
+ case KeyEvent.KEYCODE_MEDIA_NEXT:
+ case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+ case KeyEvent.KEYCODE_MEDIA_REWIND:
+ case KeyEvent.KEYCODE_MEDIA_RECORD:
+ case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
+ return true;
+ }
+ return false;
+ }
+
/** Is this a system key? System keys can not be used for menu shortcuts.
* @hide
*/
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/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/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 8b98469..494eb03 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -231,34 +231,34 @@
FORCE_DARK_ON
})
@Retention(RetentionPolicy.SOURCE)
- public @interface ForceDarkMode {}
+ public @interface ForceDark {}
/**
- * Used with {@link #setForceDarkMode}
+ * Used with {@link #setForceDark}
*
* Disable force dark, irrespective of the force dark mode of the WebView parent. In this mode,
* WebView content will always be rendered as-is, regardless of whether native views are being
* automatically darkened.
*/
- public static final int FORCE_DARK_OFF = -1;
+ public static final int FORCE_DARK_OFF = 0;
/**
- * Used with {@link #setForceDarkMode}
+ * Used with {@link #setForceDark}
*
* Enable force dark, dependent on the state of the WebView parent. If the WebView parent view
* is being automatically rendered in dark mode, then WebView content will be rendered so as to
* emulate a dark theme. WebViews that are not attached to the view hierarchy will not be
* inverted.
*/
- public static final int FORCE_DARK_AUTO = 0;
+ public static final int FORCE_DARK_AUTO = 1;
/**
- * Used with {@link #setForceDarkMode}
+ * Used with {@link #setForceDark}
*
* Unconditionally enable force dark. In this mode WebView content will always be rendered so
* as to emulate a dark theme.
*/
- public static final int FORCE_DARK_ON = +1;
+ public static final int FORCE_DARK_ON = 2;
/**
* Enables dumping the pages navigation cache to a text file. The default
@@ -1467,7 +1467,7 @@
/**
* Set the force dark mode for this WebView.
*/
- public void setForceDarkMode(@ForceDarkMode int forceDarkMode) {
+ public void setForceDark(@ForceDark int forceDark) {
// Stub implementation to satisfy Roboelectrc shadows that don't override this yet.
}
@@ -1476,7 +1476,7 @@
*
* @return the currently set force dark mode.
*/
- public @ForceDarkMode int getForceDarkMode() {
+ public @ForceDark int getForceDark() {
// Stub implementation to satisfy Roboelectrc shadows that don't override this yet.
return FORCE_DARK_AUTO;
}
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/res/res/values/public.xml b/core/res/res/values/public.xml
index 840cd63..3505994 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3006,8 +3006,6 @@
<public-group type="dimen" first-id="0x01050007">
<!-- @hide @SystemApi -->
<public name="config_restrictedIconSize" />
- <!-- @hide @SystemApi -->
- <public name="config_mediaMetadataBitmapMaxSize" />
</public-group>
<public-group type="color" first-id="0x0106001c">
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/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index d4c6eae..6dacc7a 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -81,7 +81,9 @@
mDevice = VK_NULL_HANDLE;
mPhysicalDevice = VK_NULL_HANDLE;
mInstance = VK_NULL_HANDLE;
+ mInstanceExtensionsOwner.clear();
mInstanceExtensions.clear();
+ mDeviceExtensionsOwner.clear();
mDeviceExtensions.clear();
free_features_extensions_structs(mPhysicalDeviceFeatures2);
mPhysicalDeviceFeatures2 = {};
@@ -106,18 +108,18 @@
uint32_t extensionCount = 0;
err = mEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
LOG_ALWAYS_FATAL_IF(VK_SUCCESS != err);
- std::unique_ptr<VkExtensionProperties[]> extensions(
- new VkExtensionProperties[extensionCount]);
- err = mEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.get());
+ mInstanceExtensionsOwner.resize(extensionCount);
+ err = mEnumerateInstanceExtensionProperties(nullptr, &extensionCount,
+ mInstanceExtensionsOwner.data());
LOG_ALWAYS_FATAL_IF(VK_SUCCESS != err);
bool hasKHRSurfaceExtension = false;
bool hasKHRAndroidSurfaceExtension = false;
- for (uint32_t i = 0; i < extensionCount; ++i) {
- mInstanceExtensions.push_back(extensions[i].extensionName);
- if (!strcmp(extensions[i].extensionName, VK_KHR_SURFACE_EXTENSION_NAME)) {
+ for (const VkExtensionProperties& extension : mInstanceExtensionsOwner) {
+ mInstanceExtensions.push_back(extension.extensionName);
+ if (!strcmp(extension.extensionName, VK_KHR_SURFACE_EXTENSION_NAME)) {
hasKHRSurfaceExtension = true;
}
- if (!strcmp(extensions[i].extensionName,VK_KHR_ANDROID_SURFACE_EXTENSION_NAME)) {
+ if (!strcmp(extension.extensionName, VK_KHR_ANDROID_SURFACE_EXTENSION_NAME)) {
hasKHRAndroidSurfaceExtension = true;
}
}
@@ -196,15 +198,14 @@
err = mEnumerateDeviceExtensionProperties(mPhysicalDevice, nullptr, &extensionCount,
nullptr);
LOG_ALWAYS_FATAL_IF(VK_SUCCESS != err);
- std::unique_ptr<VkExtensionProperties[]> extensions(
- new VkExtensionProperties[extensionCount]);
+ mDeviceExtensionsOwner.resize(extensionCount);
err = mEnumerateDeviceExtensionProperties(mPhysicalDevice, nullptr, &extensionCount,
- extensions.get());
+ mDeviceExtensionsOwner.data());
LOG_ALWAYS_FATAL_IF(VK_SUCCESS != err);
bool hasKHRSwapchainExtension = false;
- for (uint32_t i = 0; i < extensionCount; ++i) {
- mDeviceExtensions.push_back(extensions[i].extensionName);
- if (!strcmp(extensions[i].extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME)) {
+ for (const VkExtensionProperties& extension : mDeviceExtensionsOwner) {
+ mDeviceExtensions.push_back(extension.extensionName);
+ if (!strcmp(extension.extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME)) {
hasKHRSwapchainExtension = true;
}
}
@@ -217,6 +218,7 @@
}
return vkGetInstanceProcAddr(instance, proc_name);
};
+
grExtensions.init(getProc, mInstance, mPhysicalDevice, mInstanceExtensions.size(),
mInstanceExtensions.data(), mDeviceExtensions.size(), mDeviceExtensions.data());
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index c3d2891..c2d1802 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -76,6 +76,8 @@
status_t createReleaseFence(sp<Fence>& nativeFence);
// Returned pointers are owned by VulkanManager.
+ // An instance of VkFunctorInitParams returned from getVkFunctorInitParams refers to
+ // the internal state of VulkanManager: VulkanManager must be alive to use the returned value.
VkFunctorInitParams getVkFunctorInitParams() const;
sk_sp<GrContext> createContext(const GrContextOptions& options);
@@ -164,7 +166,9 @@
// Variables saved to populate VkFunctorInitParams.
static const uint32_t mAPIVersion = VK_MAKE_VERSION(1, 1, 0);
+ std::vector<VkExtensionProperties> mInstanceExtensionsOwner;
std::vector<const char*> mInstanceExtensions;
+ std::vector<VkExtensionProperties> mDeviceExtensionsOwner;
std::vector<const char*> mDeviceExtensions;
VkPhysicalDeviceFeatures2 mPhysicalDeviceFeatures2{};
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 669baea..7783a4d 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -553,8 +553,7 @@
* request is from a hardware key press. (e.g. {@link MediaController}).
* @hide
*/
- @SystemApi
- public static final int FLAG_FROM_KEY = 1 << 16;
+ public static final int FLAG_FROM_KEY = 1 << 12;
// The iterator of TreeMap#entrySet() returns the entries in ascending key order.
private static final TreeMap<Integer, String> FLAG_NAMES = new TreeMap<>();
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index e0cb86e..c4f8b79 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -166,7 +166,7 @@
SessionLink sessionLink = manager.createSession(cbLink, tag, sessionInfo);
mImpl = new MediaSessionEngine(context, sessionLink, cbLink);
mMaxBitmapSize = context.getResources().getDimensionPixelSize(
- android.R.dimen.config_mediaMetadataBitmapMaxSize);
+ com.android.internal.R.dimen.config_mediaMetadataBitmapMaxSize);
} catch (RuntimeException e) {
throw new RuntimeException("Remote error creating session.", e);
}
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/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/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 cbbee39..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);
@@ -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/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/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/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/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/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/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/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/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/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());
}
}