Merge "Fix notif posting from shell when adb root"
diff --git a/Android.bp b/Android.bp
index a587372..a7ce917 100644
--- a/Android.bp
+++ b/Android.bp
@@ -327,6 +327,7 @@
"android.hardware.cas-V1.1-java",
"android.hardware.cas-V1.0-java",
"android.hardware.contexthub-V1.0-java",
+ "android.hardware.gnss-V1.0-java",
"android.hardware.health-V1.0-java-constants",
"android.hardware.radio-V1.0-java",
"android.hardware.radio-V1.1-java",
diff --git a/TEST_MAPPING b/TEST_MAPPING
new file mode 100644
index 0000000..1e0b58e
--- /dev/null
+++ b/TEST_MAPPING
@@ -0,0 +1,12 @@
+{
+ "presubmit": [
+ {
+ "name": "FrameworksUiServicesTests",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ }
+ ]
+}
diff --git a/apex/appsearch/framework/java/android/app/TEST_MAPPING b/apex/appsearch/framework/java/android/app/TEST_MAPPING
new file mode 100644
index 0000000..12188f8
--- /dev/null
+++ b/apex/appsearch/framework/java/android/app/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "imports": [
+ {
+ "path": "frameworks/base/apex/appsearch/service/java/com/android/server/appsearch"
+ }
+ ]
+}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/TEST_MAPPING b/apex/appsearch/service/java/com/android/server/appsearch/TEST_MAPPING
new file mode 100644
index 0000000..08811f8
--- /dev/null
+++ b/apex/appsearch/service/java/com/android/server/appsearch/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsAppSearchTestCases"
+ },
+ {
+ "name": "FrameworksServicesTests",
+ "options": [
+ {
+ "include-filter": "com.android.server.appsearch"
+ }
+ ]
+ }
+ ]
+}
diff --git a/apex/permission/Android.bp b/apex/permission/Android.bp
index 0274814..5945fb3 100644
--- a/apex/permission/Android.bp
+++ b/apex/permission/Android.bp
@@ -14,9 +14,12 @@
apex {
name: "com.android.permission",
-
+ defaults: ["com.android.permission-defaults"],
manifest: "apex_manifest.json",
+}
+apex_defaults {
+ name: "com.android.permission-defaults",
key: "com.android.permission.key",
certificate: ":com.android.permission.certificate",
}
diff --git a/apex/permission/testing/Android.bp b/apex/permission/testing/Android.bp
new file mode 100644
index 0000000..f8978dc
--- /dev/null
+++ b/apex/permission/testing/Android.bp
@@ -0,0 +1,25 @@
+// 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.
+
+apex {
+ name: "test_com.android.permission",
+ visibility: [
+ "//system/apex/tests",
+ ],
+ defaults: ["com.android.permission-defaults"],
+ manifest: "test_manifest.json",
+ file_contexts: ":com.android.permission-file_contexts",
+ // Test APEX, should never be installed
+ installable: false,
+}
diff --git a/apex/permission/testing/test_manifest.json b/apex/permission/testing/test_manifest.json
new file mode 100644
index 0000000..bc19a9e
--- /dev/null
+++ b/apex/permission/testing/test_manifest.json
@@ -0,0 +1,4 @@
+{
+ "name": "com.android.permission",
+ "version": 2147483647
+}
diff --git a/api/current.txt b/api/current.txt
index 09006a5..bab334b 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1865,6 +1865,7 @@
field public static final int accessibilityActionPageLeft = 16908360; // 0x1020048
field public static final int accessibilityActionPageRight = 16908361; // 0x1020049
field public static final int accessibilityActionPageUp = 16908358; // 0x1020046
+ field public static final int accessibilityActionPressAndHold = 16908362; // 0x102004a
field public static final int accessibilityActionScrollDown = 16908346; // 0x102003a
field public static final int accessibilityActionScrollLeft = 16908345; // 0x1020039
field public static final int accessibilityActionScrollRight = 16908347; // 0x102003b
@@ -11556,8 +11557,11 @@
field public static final int STATUS_FAILURE_ABORTED = 3; // 0x3
field public static final int STATUS_FAILURE_BLOCKED = 2; // 0x2
field public static final int STATUS_FAILURE_CONFLICT = 5; // 0x5
+ field public static final int STATUS_FAILURE_ILLEGAL_STATE = 9; // 0x9
field public static final int STATUS_FAILURE_INCOMPATIBLE = 7; // 0x7
field public static final int STATUS_FAILURE_INVALID = 4; // 0x4
+ field public static final int STATUS_FAILURE_NAME_NOT_FOUND = 8; // 0x8
+ field public static final int STATUS_FAILURE_SECURITY = 10; // 0xa
field public static final int STATUS_FAILURE_STORAGE = 6; // 0x6
field public static final int STATUS_PENDING_USER_ACTION = -1; // 0xffffffff
field public static final int STATUS_SUCCESS = 0; // 0x0
@@ -11579,6 +11583,7 @@
method public void removeChildSessionId(int);
method public void removeSplit(@NonNull String) throws java.io.IOException;
method public void setStagingProgress(float);
+ method public void transfer(@NonNull String, @NonNull android.content.IntentSender) throws android.content.pm.PackageManager.NameNotFoundException;
method public void transfer(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
}
@@ -22956,6 +22961,7 @@
method public int getAccumulatedDeltaRangeState();
method public double getAccumulatedDeltaRangeUncertaintyMeters();
method public double getAutomaticGainControlLevelDb();
+ method @FloatRange(from=0, to=50) public double getBasebandCn0DbHz();
method @Deprecated public long getCarrierCycles();
method public float getCarrierFrequencyHz();
method @Deprecated public double getCarrierPhase();
@@ -22973,6 +22979,7 @@
method public int getSvid();
method public double getTimeOffsetNanos();
method public boolean hasAutomaticGainControlLevelDb();
+ method public boolean hasBasebandCn0DbHz();
method @Deprecated public boolean hasCarrierCycles();
method public boolean hasCarrierFrequencyHz();
method @Deprecated public boolean hasCarrierPhase();
@@ -52811,6 +52818,7 @@
field public static final String ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT = "ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT";
field public static final String ACTION_ARGUMENT_MOVE_WINDOW_X = "ACTION_ARGUMENT_MOVE_WINDOW_X";
field public static final String ACTION_ARGUMENT_MOVE_WINDOW_Y = "ACTION_ARGUMENT_MOVE_WINDOW_Y";
+ field public static final String ACTION_ARGUMENT_PRESS_HOLD_DURATION_MILLIS_INT = "android.view.accessibility.action.ARGUMENT_PRESS_HOLD_DURATION_MILLIS_INT";
field public static final String ACTION_ARGUMENT_PROGRESS_VALUE = "android.view.accessibility.action.ARGUMENT_PROGRESS_VALUE";
field public static final String ACTION_ARGUMENT_ROW_INT = "android.view.accessibility.action.ARGUMENT_ROW_INT";
field public static final String ACTION_ARGUMENT_SELECTION_END_INT = "ACTION_ARGUMENT_SELECTION_END_INT";
@@ -52878,6 +52886,7 @@
field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_PAGE_RIGHT;
field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_PAGE_UP;
field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_PASTE;
+ field @NonNull public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_PRESS_AND_HOLD;
field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY;
field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_PREVIOUS_HTML_ELEMENT;
field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_SCROLL_BACKWARD;
diff --git a/api/system-current.txt b/api/system-current.txt
index 189585e..7f0050c 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -58,7 +58,7 @@
field public static final String CLEAR_APP_USER_DATA = "android.permission.CLEAR_APP_USER_DATA";
field public static final String CONFIGURE_DISPLAY_BRIGHTNESS = "android.permission.CONFIGURE_DISPLAY_BRIGHTNESS";
field public static final String CONFIGURE_WIFI_DISPLAY = "android.permission.CONFIGURE_WIFI_DISPLAY";
- field public static final String CONNECTIVITY_INTERNAL = "android.permission.CONNECTIVITY_INTERNAL";
+ field @Deprecated public static final String CONNECTIVITY_INTERNAL = "android.permission.CONNECTIVITY_INTERNAL";
field public static final String CONNECTIVITY_USE_RESTRICTED_NETWORKS = "android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS";
field public static final String CONTROL_DISPLAY_COLOR_TRANSFORMS = "android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS";
field public static final String CONTROL_DISPLAY_SATURATION = "android.permission.CONTROL_DISPLAY_SATURATION";
@@ -126,6 +126,7 @@
field public static final String MODIFY_QUIET_MODE = "android.permission.MODIFY_QUIET_MODE";
field public static final String MOVE_PACKAGE = "android.permission.MOVE_PACKAGE";
field public static final String NETWORK_CARRIER_PROVISIONING = "android.permission.NETWORK_CARRIER_PROVISIONING";
+ field public static final String NETWORK_FACTORY = "android.permission.NETWORK_FACTORY";
field public static final String NETWORK_MANAGED_PROVISIONING = "android.permission.NETWORK_MANAGED_PROVISIONING";
field public static final String NETWORK_SCAN = "android.permission.NETWORK_SCAN";
field public static final String NETWORK_SETTINGS = "android.permission.NETWORK_SETTINGS";
@@ -135,6 +136,7 @@
field public static final String NOTIFICATION_DURING_SETUP = "android.permission.NOTIFICATION_DURING_SETUP";
field public static final String NOTIFY_TV_INPUTS = "android.permission.NOTIFY_TV_INPUTS";
field public static final String OBSERVE_APP_USAGE = "android.permission.OBSERVE_APP_USAGE";
+ field public static final String OBSERVE_NETWORK_POLICY = "android.permission.OBSERVE_NETWORK_POLICY";
field public static final String OBSERVE_ROLE_HOLDERS = "android.permission.OBSERVE_ROLE_HOLDERS";
field public static final String OPEN_ACCESSIBILITY_DETAILS_SETTINGS = "android.permission.OPEN_ACCESSIBILITY_DETAILS_SETTINGS";
field public static final String OVERRIDE_WIFI_CONFIG = "android.permission.OVERRIDE_WIFI_CONFIG";
@@ -4342,7 +4344,7 @@
public class ConnectivityManager {
method @NonNull @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD) public android.net.SocketKeepalive createNattKeepalive(@NonNull android.net.Network, @NonNull android.os.ParcelFileDescriptor, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
method @NonNull @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD) public android.net.SocketKeepalive createSocketKeepalive(@NonNull android.net.Network, @NonNull java.net.Socket, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
- method @RequiresPermission(android.Manifest.permission.LOCAL_MAC_ADDRESS) public String getCaptivePortalServerUrl();
+ method @Deprecated @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public String getCaptivePortalServerUrl();
method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void getLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEntitlementResultListener);
method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported();
method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
@@ -5521,6 +5523,7 @@
method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void updateInterfaceIpState(@Nullable String, int);
method @RequiresPermission(android.Manifest.permission.WIFI_UPDATE_USABILITY_STATS_SCORE) public void updateWifiUsabilityScore(int, int, int);
field public static final String ACTION_LINK_CONFIGURATION_CHANGED = "android.net.wifi.LINK_CONFIGURATION_CHANGED";
+ field @RequiresPermission(android.Manifest.permission.NETWORK_CARRIER_PROVISIONING) public static final String ACTION_NETWORK_SETTINGS_RESET = "android.net.wifi.action.NETWORK_SETTINGS_RESET";
field public static final String ACTION_PASSPOINT_LAUNCH_OSU_VIEW = "android.net.wifi.action.PASSPOINT_LAUNCH_OSU_VIEW";
field public static final String ACTION_REQUEST_DISABLE = "android.net.wifi.action.REQUEST_DISABLE";
field public static final String ACTION_REQUEST_ENABLE = "android.net.wifi.action.REQUEST_ENABLE";
@@ -6047,6 +6050,7 @@
public final class BugreportManager {
method @RequiresPermission(android.Manifest.permission.DUMP) public void cancelBugreport();
+ method @RequiresPermission(android.Manifest.permission.DUMP) public void requestBugreport(@NonNull android.os.BugreportParams, @Nullable CharSequence, @Nullable CharSequence);
method @RequiresPermission(android.Manifest.permission.DUMP) public void startBugreport(@NonNull android.os.ParcelFileDescriptor, @Nullable android.os.ParcelFileDescriptor, @NonNull android.os.BugreportParams, @NonNull java.util.concurrent.Executor, @NonNull android.os.BugreportManager.BugreportCallback);
}
@@ -6492,6 +6496,7 @@
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.os.PersistableBundle getSeedAccountOptions();
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getSeedAccountType();
method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public long[] getSerialNumbersOfUsers(boolean);
+ method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public java.util.List<android.os.UserHandle> getUserHandles(boolean);
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED}) 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);
@@ -7026,6 +7031,7 @@
field public static final String ACTION_ACCESSIBILITY_DETAILS_SETTINGS = "android.settings.ACCESSIBILITY_DETAILS_SETTINGS";
field public static final String ACTION_ENTERPRISE_PRIVACY_SETTINGS = "android.settings.ENTERPRISE_PRIVACY_SETTINGS";
field public static final String ACTION_LOCATION_CONTROLLER_EXTRA_PACKAGE_SETTINGS = "android.settings.LOCATION_CONTROLLER_EXTRA_PACKAGE_SETTINGS";
+ field public static final String ACTION_MANAGE_APP_OVERLAY_PERMISSION = "android.settings.MANAGE_APP_OVERLAY_PERMISSION";
field public static final String ACTION_MANAGE_DOMAIN_URLS = "android.settings.MANAGE_DOMAIN_URLS";
field public static final String ACTION_MANAGE_MORE_DEFAULT_APPS_SETTINGS = "android.settings.MANAGE_MORE_DEFAULT_APPS_SETTINGS";
field public static final String ACTION_NOTIFICATION_POLICY_ACCESS_DETAIL_SETTINGS = "android.settings.NOTIFICATION_POLICY_ACCESS_DETAIL_SETTINGS";
diff --git a/api/test-current.txt b/api/test-current.txt
index 9ac789e..cf93410 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1086,6 +1086,7 @@
ctor public GnssMeasurement();
method public void reset();
method public void resetAutomaticGainControlLevel();
+ method public void resetBasebandCn0DbHz();
method @Deprecated public void resetCarrierCycles();
method public void resetCarrierFrequencyHz();
method @Deprecated public void resetCarrierPhase();
@@ -1097,6 +1098,7 @@
method public void setAccumulatedDeltaRangeState(int);
method public void setAccumulatedDeltaRangeUncertaintyMeters(double);
method public void setAutomaticGainControlLevelInDb(double);
+ method public void setBasebandCn0DbHz(double);
method @Deprecated public void setCarrierCycles(long);
method public void setCarrierFrequencyHz(float);
method @Deprecated public void setCarrierPhase(double);
@@ -1754,6 +1756,7 @@
public final class BugreportManager {
method @RequiresPermission(android.Manifest.permission.DUMP) public void cancelBugreport();
+ method @RequiresPermission(android.Manifest.permission.DUMP) public void requestBugreport(@NonNull android.os.BugreportParams, @Nullable CharSequence, @Nullable CharSequence);
method @RequiresPermission(android.Manifest.permission.DUMP) public void startBugreport(@NonNull android.os.ParcelFileDescriptor, @Nullable android.os.ParcelFileDescriptor, @NonNull android.os.BugreportParams, @NonNull java.util.concurrent.Executor, @NonNull android.os.BugreportManager.BugreportCallback);
}
@@ -2459,6 +2462,7 @@
public final class Settings {
field public static final String ACTION_ENTERPRISE_PRIVACY_SETTINGS = "android.settings.ENTERPRISE_PRIVACY_SETTINGS";
+ field public static final String ACTION_MANAGE_APP_OVERLAY_PERMISSION = "android.settings.MANAGE_APP_OVERLAY_PERMISSION";
field public static final String ACTION_REQUEST_ENABLE_CONTENT_CAPTURE = "android.settings.REQUEST_ENABLE_CONTENT_CAPTURE";
field public static final int RESET_MODE_PACKAGE_DEFAULTS = 1; // 0x1
}
diff --git a/api/test-lint-baseline.txt b/api/test-lint-baseline.txt
index ba85ae6..3aa8187 100644
--- a/api/test-lint-baseline.txt
+++ b/api/test-lint-baseline.txt
@@ -399,6 +399,8 @@
GetterSetterNames: android.location.GnssClock#setTimeUncertaintyNanos(double):
+GetterSetterNames: android.location.GnssMeasurement#setBasebandCn0DbHz(double):
+
GetterSetterNames: android.location.GnssMeasurement#setCarrierFrequencyHz(float):
GetterSetterNames: android.location.GnssMeasurement#setCodeType(String):
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 91f8a3c..aaab6b4 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -22,11 +22,14 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.LauncherApps;
+import android.content.pm.ShortcutInfo;
import android.graphics.Insets;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
+import android.os.Bundle;
import android.os.UserHandle;
import android.util.AttributeSet;
import android.util.Log;
@@ -209,6 +212,32 @@
}
/**
+ * Launch an activity represented by {@link ShortcutInfo} into this container.
+ * <p>The owner of this container must be allowed to access the shortcut information,
+ * as defined in {@link LauncherApps#hasShortcutHostPermission()} to use this method.
+ * <p>Activity resolved by the provided {@link ShortcutInfo} must have
+ * {@link android.R.attr#resizeableActivity} attribute set to {@code true} in order to be
+ * launched here. Also, if activity is not owned by the owner of this container, it must allow
+ * embedding and the caller must have permission to embed.
+ * <p>Note: This class must finish initializing and
+ * {@link StateCallback#onActivityViewReady(ActivityView)} callback must be triggered before
+ * this method can be called.
+ *
+ * @param shortcut the shortcut used to launch the activity.
+ * @param options for the activity.
+ * @param sourceBounds the rect containing the source bounds of the clicked icon to open
+ * this shortcut.
+ * @see StateCallback
+ * @see LauncherApps#startShortcut(ShortcutInfo, Rect, Bundle)
+ *
+ * @hide
+ */
+ public void startShortcutActivity(@NonNull ShortcutInfo shortcut,
+ @NonNull ActivityOptions options, @Nullable Rect sourceBounds) {
+ mTaskEmbedder.startShortcutActivity(shortcut, options, sourceBounds);
+ }
+
+ /**
* Launch a new activity into this container.
* <p>Activity resolved by the provided {@link Intent} must have
* {@link android.R.attr#resizeableActivity} attribute set to {@code true} in order to be
diff --git a/core/java/android/app/TaskEmbedder.java b/core/java/android/app/TaskEmbedder.java
index a8dc7bc..79d88fd 100644
--- a/core/java/android/app/TaskEmbedder.java
+++ b/core/java/android/app/TaskEmbedder.java
@@ -25,9 +25,12 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.LauncherApps;
+import android.content.pm.ShortcutInfo;
import android.graphics.Insets;
import android.graphics.Matrix;
import android.graphics.Point;
+import android.graphics.Rect;
import android.graphics.Region;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
@@ -346,6 +349,26 @@
}
/**
+ * Launch an activity represented by {@link ShortcutInfo} into this container.
+ * <p>The owner of this container must be allowed to access the shortcut information,
+ * as defined in {@link LauncherApps#hasShortcutHostPermission()} to use this method.
+ *
+ * @param shortcut the shortcut used to launch the activity.
+ * @param options options for the activity.
+ * @param sourceBounds the rect containing the source bounds of the clicked icon to open
+ * this shortcut.
+ *
+ * @see #startActivity(Intent)
+ */
+ public void startShortcutActivity(@NonNull ShortcutInfo shortcut,
+ @NonNull ActivityOptions options, @Nullable Rect sourceBounds) {
+ LauncherApps service =
+ (LauncherApps) mContext.getSystemService(Context.LAUNCHER_APPS_SERVICE);
+ options.setLaunchDisplayId(mVirtualDisplay.getDisplay().getDisplayId());
+ service.startShortcut(shortcut, sourceBounds, options.toBundle());
+ }
+
+ /**
* Check if container is ready to launch and create {@link ActivityOptions} to target the
* virtual display.
*/
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index ab404d2..fb5645a 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -160,48 +160,114 @@
public static final int REASON_MAIN_MASK = 0xFF00;
/** @hide */
public static final int REASON_MAIN_DEFAULT = 0x0100;
- /** @hide */
+ /**
+ * The app spent sufficient time in the old bucket without any substantial event so it reached
+ * the timeout threshold to have its bucket lowered.
+ *
+ * @hide
+ */
public static final int REASON_MAIN_TIMEOUT = 0x0200;
- /** @hide */
+ /**
+ * The app was used in some way. Look at the REASON_SUB_USAGE_ reason for more details.
+ * @hide
+ */
public static final int REASON_MAIN_USAGE = 0x0300;
- /** @hide */
+ /**
+ * Forced by a core UID.
+ * @hide
+ */
public static final int REASON_MAIN_FORCED = 0x0400;
- /** @hide */
+ /**
+ * Set by a privileged system app.
+ * @hide
+ */
public static final int REASON_MAIN_PREDICTED = 0x0500;
/** @hide */
public static final int REASON_SUB_MASK = 0x00FF;
- /** @hide */
+ /**
+ * The app was interacted with in some way by the system.
+ * @hide
+ */
public static final int REASON_SUB_USAGE_SYSTEM_INTERACTION = 0x0001;
- /** @hide */
+ /**
+ * A notification was viewed by the user. This does not mean the user interacted with the
+ * notification.
+ * @hide
+ */
public static final int REASON_SUB_USAGE_NOTIFICATION_SEEN = 0x0002;
- /** @hide */
+ /**
+ * The app was interacted with in some way by the user. This includes interacting with
+ * notification.
+ * @hide
+ */
public static final int REASON_SUB_USAGE_USER_INTERACTION = 0x0003;
- /** @hide */
+ /**
+ * An {@link android.app.Activity} moved to the foreground.
+ * @hide
+ */
public static final int REASON_SUB_USAGE_MOVE_TO_FOREGROUND = 0x0004;
- /** @hide */
+ /**
+ * An {@link android.app.Activity} moved to the background.
+ * @hide
+ */
public static final int REASON_SUB_USAGE_MOVE_TO_BACKGROUND = 0x0005;
- /** @hide */
+ /**
+ * There was a system update.
+ * @hide
+ */
public static final int REASON_SUB_USAGE_SYSTEM_UPDATE = 0x0006;
- /** @hide */
+ /**
+ * An app is in an elevated bucket because of an active timeout preventing it from being placed
+ * in a lower bucket.
+ * @hide
+ */
public static final int REASON_SUB_USAGE_ACTIVE_TIMEOUT = 0x0007;
- /** @hide */
+ /**
+ * This system package's sync adapter has been used for another package's content provider.
+ * @hide
+ */
public static final int REASON_SUB_USAGE_SYNC_ADAPTER = 0x0008;
- /** @hide */
+ /**
+ * A slice was pinned by an app.
+ * @hide
+ */
public static final int REASON_SUB_USAGE_SLICE_PINNED = 0x0009;
- /** @hide */
+ /** /**
+ * A slice was pinned by the default launcher or the default assistant.
+ * @hide
+ */
public static final int REASON_SUB_USAGE_SLICE_PINNED_PRIV = 0x000A;
- /** @hide */
+ /**
+ * A sync operation that is exempt from app standby was scheduled when the device wasn't Dozing.
+ * @hide
+ */
public static final int REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_NON_DOZE = 0x000B;
- /** @hide */
+ /**
+ * A sync operation that is exempt from app standby was scheduled while the device was Dozing.
+ * @hide
+ */
public static final int REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_DOZE = 0x000C;
- /** @hide */
+ /**
+ * A sync operation that is exempt from app standby started.
+ * @hide
+ */
public static final int REASON_SUB_USAGE_EXEMPTED_SYNC_START = 0x000D;
- /** @hide */
+ /**
+ * A sync operation that is not exempt from app standby was scheduled.
+ * @hide
+ */
public static final int REASON_SUB_USAGE_UNEXEMPTED_SYNC_SCHEDULED = 0x000E;
- /** @hide */
+ /**
+ * A foreground service started.
+ * @hide
+ */
public static final int REASON_SUB_USAGE_FOREGROUND_SERVICE_START = 0x000F;
- /** @hide */
+ /**
+ * The predicted bucket was restored after the app's temporary elevation to the ACTIVE bucket
+ * ended.
+ * @hide
+ */
public static final int REASON_SUB_PREDICTED_RESTORED = 0x0001;
diff --git a/core/java/android/content/pm/IPackageInstallerSession.aidl b/core/java/android/content/pm/IPackageInstallerSession.aidl
index 04e15c7..b740617 100644
--- a/core/java/android/content/pm/IPackageInstallerSession.aidl
+++ b/core/java/android/content/pm/IPackageInstallerSession.aidl
@@ -36,7 +36,7 @@
void close();
void commit(in IntentSender statusReceiver, boolean forTransferred);
- void transfer(in String packageName);
+ void transfer(in String packageName, in IntentSender statusReceiver);
void abandon();
boolean isMultiPackage();
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 0c52979..4ab6f3c 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -29,6 +29,8 @@
import android.annotation.UnsupportedAppUsage;
import android.app.ActivityManager;
import android.app.AppGlobals;
+import android.content.IIntentReceiver;
+import android.content.IIntentSender;
import android.content.Intent;
import android.content.IntentSender;
import android.content.pm.PackageManager.DeleteFlags;
@@ -36,9 +38,11 @@
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Build;
+import android.os.Bundle;
import android.os.FileBridge;
import android.os.Handler;
import android.os.HandlerExecutor;
+import android.os.IBinder;
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
@@ -67,6 +71,8 @@
import java.util.Iterator;
import java.util.List;
import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;
@@ -176,7 +182,7 @@
* {@link #STATUS_PENDING_USER_ACTION}, {@link #STATUS_SUCCESS},
* {@link #STATUS_FAILURE}, {@link #STATUS_FAILURE_ABORTED},
* {@link #STATUS_FAILURE_BLOCKED}, {@link #STATUS_FAILURE_CONFLICT},
- * {@link #STATUS_FAILURE_INCOMPATIBLE}, {@link #STATUS_FAILURE_INVALID}, or
+ * {@link #STATUS_FAILURE_INCOMPATIBLE}, {@link #STATUS_FAILURE_INVALID},
* {@link #STATUS_FAILURE_STORAGE}.
* <p>
* More information about a status may be available through additional
@@ -316,6 +322,34 @@
*/
public static final int STATUS_FAILURE_INCOMPATIBLE = 7;
+ /**
+ * The transfer failed because a target package can't be found. For example
+ * transferring a session to a non-existing package.
+ * <p>
+ * The result may also contain {@link #EXTRA_OTHER_PACKAGE_NAME} with the
+ * missing package.
+ *
+ * @see #EXTRA_STATUS_MESSAGE
+ * @see #EXTRA_OTHER_PACKAGE_NAME
+ */
+ public static final int STATUS_FAILURE_NAME_NOT_FOUND = 8;
+
+ /**
+ * The transfer failed because a session is in invalid state. For example
+ * transferring an already committed session.
+ *
+ * @see #EXTRA_STATUS_MESSAGE
+ */
+ public static final int STATUS_FAILURE_ILLEGAL_STATE = 9;
+
+ /**
+ * The transfer failed for security reasons. For example transferring
+ * to a package which does not have INSTALL_PACKAGES permission.
+ *
+ * @see #EXTRA_STATUS_MESSAGE
+ */
+ public static final int STATUS_FAILURE_SECURITY = 10;
+
private final IPackageInstaller mInstaller;
private final int mUserId;
private final String mInstallerPackageName;
@@ -1052,7 +1086,8 @@
}
/**
- * Attempt to commit a session that has been {@link #transfer(String) transferred}.
+ * Attempt to commit a session that has been {@link #transfer(String, IntentSender)
+ * transferred}.
*
* <p>If the device reboots before the session has been finalized, you may commit the
* session again.
@@ -1093,6 +1128,38 @@
*
* @param packageName The package of the new owner. Needs to hold the INSTALL_PACKAGES
* permission.
+ * @param statusReceiver Called when the state of the session changes. Intents sent to this
+ * receiver contain {@link #EXTRA_STATUS}. Refer to the individual
+ * transfer status codes on how to handle them.
+ *
+ * @throws PackageManager.NameNotFoundException if the new owner could not be found.
+ * @throws SecurityException if called after the session has been committed or abandoned.
+ * @throws SecurityException if the session does not update the original installer
+ * @throws SecurityException if streams opened through
+ * {@link #openWrite(String, long, long) are still open.
+ */
+ public void transfer(@NonNull String packageName, @NonNull IntentSender statusReceiver)
+ throws PackageManager.NameNotFoundException {
+ Preconditions.checkNotNull(statusReceiver);
+ Preconditions.checkNotNull(packageName);
+
+ try {
+ mSession.transfer(packageName, statusReceiver);
+ } catch (ParcelableException e) {
+ e.maybeRethrow(PackageManager.NameNotFoundException.class);
+ throw new RuntimeException(e);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Transfer the session to a new owner.
+ * This is a convenience blocking wrapper around {@link #transfer(String, IntentSender)}.
+ * Converts all statuses into exceptions.
+ *
+ * @param packageName The package of the new owner. Needs to hold the INSTALL_PACKAGES
+ * permission.
*
* @throws PackageManager.NameNotFoundException if the new owner could not be found.
* @throws SecurityException if called after the session has been committed or abandoned.
@@ -1104,13 +1171,43 @@
throws PackageManager.NameNotFoundException {
Preconditions.checkNotNull(packageName);
+ CompletableFuture<Intent> intentFuture = new CompletableFuture<Intent>();
try {
- mSession.transfer(packageName);
+ IIntentSender localSender = new IIntentSender.Stub() {
+ @Override
+ public void send(int code, Intent intent, String resolvedType,
+ IBinder whitelistToken,
+ IIntentReceiver finishedReceiver, String requiredPermission,
+ Bundle options) {
+ intentFuture.complete(intent);
+ }
+ };
+ transfer(packageName, new IntentSender(localSender));
} catch (ParcelableException e) {
e.maybeRethrow(PackageManager.NameNotFoundException.class);
throw new RuntimeException(e);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
+ }
+
+ try {
+ Intent intent = intentFuture.get();
+ final int status = intent.getIntExtra(EXTRA_STATUS, Integer.MIN_VALUE);
+ final String statusMessage = intent.getStringExtra(EXTRA_STATUS_MESSAGE);
+ switch (status) {
+ case STATUS_SUCCESS:
+ break;
+ case STATUS_FAILURE_NAME_NOT_FOUND:
+ throw new PackageManager.NameNotFoundException(statusMessage);
+ case STATUS_FAILURE_ILLEGAL_STATE:
+ throw new IllegalStateException(statusMessage);
+ case STATUS_FAILURE_SECURITY:
+ throw new SecurityException(statusMessage);
+ default:
+ throw new RuntimeException(statusMessage);
+ }
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ } catch (ExecutionException e) {
+ throw new RuntimeException(e);
}
}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 194068c..d95da91 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -1006,7 +1006,7 @@
*
* @hide
*/
- @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL)
+ @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
@Nullable
public Network getActiveNetworkForUid(int uid) {
return getActiveNetworkForUid(uid, false);
@@ -1135,7 +1135,7 @@
*
* {@hide}
*/
- @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL)
+ @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
@UnsupportedAppUsage
public NetworkInfo getActiveNetworkInfoForUid(int uid) {
return getActiveNetworkInfoForUid(uid, false);
@@ -1370,10 +1370,14 @@
* The system network validation may be using different strategies to detect captive portals,
* so this method does not necessarily return a URL used by the system. It only returns a URL
* that may be relevant for other components trying to detect captive portals.
+ *
* @hide
+ * @deprecated This API returns URL which is not guaranteed to be one of the URLs used by the
+ * system.
*/
+ @Deprecated
@SystemApi
- @RequiresPermission(android.Manifest.permission.LOCAL_MAC_ADDRESS)
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
public String getCaptivePortalServerUrl() {
try {
return mService.getCaptivePortalServerUrl();
@@ -2399,6 +2403,7 @@
* @return an array of 0 or more {@code String} of tethered dhcp ranges.
* {@hide}
*/
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
public String[] getTetheredDhcpRanges() {
try {
return mService.getTetheredDhcpRanges();
@@ -2978,7 +2983,7 @@
* HTTP proxy. A {@code null} value will clear the global HTTP proxy.
* @hide
*/
- @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL)
+ @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
public void setGlobalProxy(ProxyInfo p) {
try {
mService.setGlobalProxy(p);
@@ -3123,6 +3128,7 @@
* Get the mobile provisioning url.
* {@hide}
*/
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
public String getMobileProvisioningUrl() {
try {
return mService.getMobileProvisioningUrl();
@@ -3169,6 +3175,7 @@
/** {@hide} - returns the factory serial number */
@UnsupportedAppUsage
+ @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
public int registerNetworkFactory(Messenger messenger, String name) {
try {
return mService.registerNetworkFactory(messenger, name);
@@ -3179,6 +3186,7 @@
/** {@hide} */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
+ @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
public void unregisterNetworkFactory(Messenger messenger) {
try {
mService.unregisterNetworkFactory(messenger);
@@ -3196,6 +3204,7 @@
* Register a NetworkAgent with ConnectivityService.
* @return NetID corresponding to NetworkAgent.
*/
+ @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
public int registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp,
NetworkCapabilities nc, int score, NetworkMisc misc) {
return registerNetworkAgent(messenger, ni, lp, nc, score, misc,
@@ -3207,6 +3216,7 @@
* Register a NetworkAgent with ConnectivityService.
* @return NetID corresponding to NetworkAgent.
*/
+ @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
public int registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp,
NetworkCapabilities nc, int score, NetworkMisc misc, int factorySerialNumber) {
try {
@@ -4201,7 +4211,7 @@
*
* @hide
*/
- @RequiresPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL)
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
public void startCaptivePortalApp(Network network) {
try {
mService.startCaptivePortalApp(network);
@@ -4317,6 +4327,7 @@
* Resets all connectivity manager settings back to factory defaults.
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
public void factoryReset() {
try {
mService.factoryReset();
diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java
index c5cbad3..a3c2cd8 100644
--- a/core/java/android/os/BugreportManager.java
+++ b/core/java/android/os/BugreportManager.java
@@ -25,6 +25,7 @@
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
+import android.app.ActivityManager;
import android.content.Context;
import android.util.Log;
@@ -191,6 +192,32 @@
}
}
+ /**
+ * Requests a bugreport.
+ *
+ * <p>This requests the platform/system to take a bugreport and makes the final bugreport
+ * available to the user. The user may choose to share it with another app, but the bugreport
+ * is never given back directly to the app that requested it.
+ *
+ * @param params {@link BugreportParams} that specify what kind of a bugreport should
+ * be taken, please note that not all kinds of bugreport allow for a
+ * progress notification
+ * @param shareTitle title on the final share notification
+ * @param shareDescription description on the final share notification
+ */
+ @RequiresPermission(android.Manifest.permission.DUMP)
+ public void requestBugreport(@NonNull BugreportParams params, @Nullable CharSequence shareTitle,
+ @Nullable CharSequence shareDescription) {
+ try {
+ String title = shareTitle == null ? null : shareTitle.toString();
+ String description = shareDescription == null ? null : shareDescription.toString();
+ ActivityManager.getService().requestBugReportWithDescription(title, description,
+ params.getMode());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
private final class DumpstateListener extends IDumpstateListener.Stub {
private final Executor mExecutor;
private final BugreportCallback mCallback;
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 74340f0..dbe8dc3 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -2709,6 +2709,21 @@
}
/**
+ * Returns information for all users on this device. Requires
+ * {@link android.Manifest.permission#MANAGE_USERS} permission.
+ *
+ * @param excludeDying specify if the list should exclude users being
+ * removed.
+ * @return the list of users that were created.
+ * @hide
+ */
+ @UnsupportedAppUsage
+ public @NonNull List<UserInfo> getUsers(boolean excludeDying) {
+ return getUsers(/*excludePartial= */ true, excludeDying,
+ /* excludePreCreated= */ true);
+ }
+
+ /**
* Returns information for all users on this device, based on the filtering parameters.
*
* @hide
@@ -2724,6 +2739,24 @@
}
/**
+ * Returns the user handles for all users on this device, based on the filtering parameters.
+ *
+ * @param excludeDying specify if the list should exclude users being removed.
+ * @return the list of user handles.
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+ public @NonNull List<UserHandle> getUserHandles(boolean excludeDying) {
+ List<UserInfo> users = getUsers(excludeDying);
+ List<UserHandle> result = new ArrayList<>(users.size());
+ for (UserInfo user : users) {
+ result.add(user.getUserHandle());
+ }
+ return result;
+ }
+
+ /**
* Returns serial numbers of all users on this device.
*
* @param excludeDying specify if the list should exclude users being removed.
@@ -3263,21 +3296,6 @@
}
/**
- * Returns information for all users on this device. Requires
- * {@link android.Manifest.permission#MANAGE_USERS} permission.
- *
- * @param excludeDying specify if the list should exclude users being
- * removed.
- * @return the list of users that were created.
- * @hide
- */
- @UnsupportedAppUsage
- public @NonNull List<UserInfo> getUsers(boolean excludeDying) {
- return getUsers(/*excludePartial= */ true, excludeDying,
- /* excludePreCreated= */ true);
- }
-
- /**
* Removes a user and all associated data.
* Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
* @param userId the integer handle of the user.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index f19ef65..fa8896e 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -832,8 +832,7 @@
/**
* Activity Action: Show screen for controlling which apps can draw on top of other apps.
* <p>
- * In some cases, a matching Activity may not exist, so ensure you
- * safeguard against this.
+ * In some cases, a matching Activity may not exist, so ensure you safeguard against this.
* <p>
* Input: Optionally, in versions of Android prior to 11, the Intent's data URI can specify the
* application package name to directly invoke the management GUI specific to the package name.
@@ -846,6 +845,31 @@
"android.settings.action.MANAGE_OVERLAY_PERMISSION";
/**
+ * Activity Action: Show screen for controlling if the app specified in the data URI of the
+ * intent can draw on top of other apps.
+ * <p>
+ * Unlike {@link #ACTION_MANAGE_OVERLAY_PERMISSION}, which in Android 11 can't be used to show
+ * a GUI for a specific package, permission {@code android.permission.INTERNAL_SYSTEM_WINDOW} is
+ * needed to start an activity with this intent.
+ * <p>
+ * In some cases, a matching Activity may not exist, so ensure you
+ * safeguard against this.
+ * <p>
+ * Input: The Intent's data URI MUST specify the application package name whose ability of
+ * drawing on top of other apps you want to control.
+ * For example "package:com.my.app".
+ * <p>
+ * Output: Nothing.
+ *
+ * @hide
+ */
+ @TestApi
+ @SystemApi
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_MANAGE_APP_OVERLAY_PERMISSION =
+ "android.settings.MANAGE_APP_OVERLAY_PERMISSION";
+
+ /**
* Activity Action: Show screen for controlling which apps are allowed to write/modify
* system settings.
* <p>
diff --git a/core/java/android/util/StatsLog.java b/core/java/android/util/StatsLog.java
index f7077bb..64e15cf 100644
--- a/core/java/android/util/StatsLog.java
+++ b/core/java/android/util/StatsLog.java
@@ -224,12 +224,35 @@
/**
* Write an event to stats log using the raw format.
*
- * @param buffer The encoded buffer of data to write..
+ * @param buffer The encoded buffer of data to write.
* @param size The number of bytes from the buffer to write.
* @hide
*/
+ // TODO(b/144935988): Mark deprecated.
@SystemApi
- public static native void writeRaw(@NonNull byte[] buffer, int size);
+ public static void writeRaw(@NonNull byte[] buffer, int size) {
+ // TODO(b/144935988): make this no-op once clients have migrated to StatsEvent.
+ writeImpl(buffer, size, 0);
+ }
+
+ /**
+ * Write an event to stats log using the raw format.
+ *
+ * @param buffer The encoded buffer of data to write.
+ * @param size The number of bytes from the buffer to write.
+ * @param atomId The id of the atom to which the event belongs.
+ */
+ private static native void writeImpl(@NonNull byte[] buffer, int size, int atomId);
+
+ /**
+ * Write an event to stats log using the raw format encapsulated in StatsEvent.
+ *
+ * @param statsEvent The StatsEvent object containing the encoded buffer of data to write.
+ * @hide
+ */
+ public static void write(@NonNull final StatsEvent statsEvent) {
+ writeImpl(statsEvent.getBytes(), statsEvent.getNumBytes(), statsEvent.getAtomId());
+ }
private static void enforceDumpCallingPermission(Context context) {
context.enforceCallingPermission(android.Manifest.permission.DUMP, "Need DUMP permission.");
diff --git a/core/java/android/view/IPinnedStackListener.aidl b/core/java/android/view/IPinnedStackListener.aidl
index f4bee57..d01c933 100644
--- a/core/java/android/view/IPinnedStackListener.aidl
+++ b/core/java/android/view/IPinnedStackListener.aidl
@@ -67,20 +67,20 @@
void onActionsChanged(in ParceledListSlice actions);
/**
- * Called by the window manager to notify the listener to save the reentry fraction,
+ * Called by the window manager to notify the listener to save the reentry fraction and size,
* typically when an Activity leaves PiP (picture-in-picture) mode to fullscreen.
* {@param componentName} represents the application component of PiP window
* while {@param bounds} is the current PiP bounds used to calculate the
- * reentry snap fraction.
+ * reentry snap fraction and size.
*/
- void onSaveReentrySnapFraction(in ComponentName componentName, in Rect bounds);
+ void onSaveReentryBounds(in ComponentName componentName, in Rect bounds);
/**
- * Called by the window manager to notify the listener to reset saved reentry fraction,
+ * Called by the window manager to notify the listener to reset saved reentry fraction and size,
* typically when an Activity enters PiP (picture-in-picture) mode from fullscreen.
* {@param componentName} represents the application component of PiP window.
*/
- void onResetReentrySnapFraction(in ComponentName componentName);
+ void onResetReentryBounds(in ComponentName componentName);
/**
* Called when the window manager has detected change on DisplayInfo, or
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 1855a26..db6211d 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -162,7 +162,7 @@
int[] allowedConfigs);
private static native int[] nativeGetAllowedDisplayConfigs(IBinder displayToken);
private static native boolean nativeSetDesiredDisplayConfigSpecs(IBinder displayToken,
- int defaultModeId, float minRefreshRate, float maxRefreshRate);
+ SurfaceControl.DesiredDisplayConfigSpecs desiredDisplayConfigSpecs);
private static native int[] nativeGetDisplayColorModes(IBinder displayToken);
private static native SurfaceControl.DisplayPrimaries nativeGetDisplayNativePrimaries(
IBinder displayToken);
@@ -1492,16 +1492,47 @@
}
/**
+ * Contains information about desired display configuration.
+ *
+ * @hide
+ */
+ public static final class DesiredDisplayConfigSpecs {
+ /**
+ * @hide
+ */
+ public int mDefaultModeId;
+
+ /**
+ * @hide
+ */
+ public float mMinRefreshRate;
+
+ /**
+ * @hide
+ */
+ public float mMaxRefreshRate;
+
+ /**
+ * @hide
+ */
+ public DesiredDisplayConfigSpecs(
+ int defaultModeId, float minRefreshRate, float maxRefreshRate) {
+ mDefaultModeId = defaultModeId;
+ mMinRefreshRate = minRefreshRate;
+ mMaxRefreshRate = maxRefreshRate;
+ }
+ }
+
+ /**
* @hide
*/
public static boolean setDesiredDisplayConfigSpecs(IBinder displayToken,
- int defaultModeId, float minRefreshRate, float maxRefreshRate) {
+ SurfaceControl.DesiredDisplayConfigSpecs desiredDisplayConfigSpecs) {
if (displayToken == null) {
throw new IllegalArgumentException("displayToken must not be null");
}
- return nativeSetDesiredDisplayConfigSpecs(displayToken, defaultModeId, minRefreshRate,
- maxRefreshRate);
+ return nativeSetDesiredDisplayConfigSpecs(displayToken, desiredDisplayConfigSpecs);
}
/**
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 66bf982..f2f84cd 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -529,6 +529,20 @@
public static final String ACTION_ARGUMENT_ACCESSIBLE_CLICKABLE_SPAN =
"android.view.accessibility.action.ACTION_ARGUMENT_ACCESSIBLE_CLICKABLE_SPAN";
+ /**
+ * Argument to represent the duration in milliseconds to press and hold a node.
+ * <p>
+ * <strong>Type:</strong> int<br>
+ * <strong>Actions:</strong>
+ * <ul>
+ * <li>{@link AccessibilityAction#ACTION_PRESS_AND_HOLD}</li>
+ * </ul>
+ *
+ * @see AccessibilityAction#ACTION_PRESS_AND_HOLD
+ */
+ public static final String ACTION_ARGUMENT_PRESS_HOLD_DURATION_MILLIS_INT =
+ "android.view.accessibility.action.ARGUMENT_PRESS_HOLD_DURATION_MILLIS_INT";
+
// Focus types
/**
@@ -4035,6 +4049,8 @@
return "ACTION_SHOW_TOOLTIP";
case R.id.accessibilityActionHideTooltip:
return "ACTION_HIDE_TOOLTIP";
+ case R.id.accessibilityActionPressAndHold:
+ return "ACTION_PRESS_AND_HOLD";
default:
return "ACTION_UNKNOWN";
}
@@ -4626,6 +4642,31 @@
public static final AccessibilityAction ACTION_HIDE_TOOLTIP =
new AccessibilityAction(R.id.accessibilityActionHideTooltip);
+ /**
+ * Action that presses and holds a node.
+ * <p>
+ * This action is for nodes that have distinct behavior that depends on how long a press is
+ * held. Nodes having a single action for long press should use {@link #ACTION_LONG_CLICK}
+ * instead of this action, and nodes should not expose both actions.
+ * <p>
+ * Use {@link #ACTION_ARGUMENT_PRESS_HOLD_DURATION_MILLIS_INT} to specify how long the
+ * node is pressed. To ensure reasonable behavior, the first value of this argument should
+ * be 0 and the others should greater than 0 and less than 10,000. UIs requested to hold for
+ * times outside of this range should ignore the action.
+ * <p>
+ * The total time the element is held could be specified by an accessibility user up-front,
+ * or may depend on what happens on the UI as the user continues to request the hold.
+ * <p>
+ * <strong>Note:</strong> The time between dispatching the action and it arriving in the
+ * UI process is not guaranteed. It is possible on a busy system for the time to expire
+ * unexpectedly. For the case of holding down a key for a repeating action, a delayed
+ * arrival should be benign. Please do not use this sort of action in cases where such
+ * delays will lead to unexpected UI behavior.
+ * <p>
+ */
+ @NonNull public static final AccessibilityAction ACTION_PRESS_AND_HOLD =
+ new AccessibilityAction(R.id.accessibilityActionPressAndHold);
+
private final int mActionId;
private final CharSequence mLabel;
diff --git a/core/java/com/android/internal/policy/PipSnapAlgorithm.java b/core/java/com/android/internal/policy/PipSnapAlgorithm.java
index 1afc67b..e3623c5 100644
--- a/core/java/com/android/internal/policy/PipSnapAlgorithm.java
+++ b/core/java/com/android/internal/policy/PipSnapAlgorithm.java
@@ -360,6 +360,28 @@
}
/**
+ * @return the adjusted size so that it conforms to the given aspectRatio, ensuring that the
+ * minimum edge is at least minEdgeSize.
+ */
+ public Size getSizeForAspectRatio(Size size, float aspectRatio, float minEdgeSize) {
+ final int smallestSize = Math.min(size.getWidth(), size.getHeight());
+ final int minSize = (int) Math.max(minEdgeSize, smallestSize);
+
+ final int width;
+ final int height;
+ if (aspectRatio <= 1) {
+ // Portrait, width is the minimum size.
+ width = minSize;
+ height = Math.round(width / aspectRatio);
+ } else {
+ // Landscape, height is the minimum size
+ height = minSize;
+ width = Math.round(height * aspectRatio);
+ }
+ return new Size(width, height);
+ }
+
+ /**
* @return the closest point in {@param points} to the given {@param x} and {@param y}.
*/
private Point findClosestPoint(int x, int y, Point[] points) {
diff --git a/core/jni/android/graphics/Path.cpp b/core/jni/android/graphics/Path.cpp
index 1b27765..4814452 100644
--- a/core/jni/android/graphics/Path.cpp
+++ b/core/jni/android/graphics/Path.cpp
@@ -497,12 +497,12 @@
static jint getFillType(CRITICAL_JNI_PARAMS_COMMA jlong objHandle) {
SkPath* obj = reinterpret_cast<SkPath*>(objHandle);
- return obj->getFillType();
+ return static_cast<int>(obj->getFillType());
}
static void setFillType(CRITICAL_JNI_PARAMS_COMMA jlong pathHandle, jint ftHandle) {;
SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
- SkPath::FillType ft = static_cast<SkPath::FillType>(ftHandle);
+ SkPathFillType ft = static_cast<SkPathFillType>(ftHandle);
path->setFillType(ft);
}
};
diff --git a/core/jni/android_util_StatsLog.cpp b/core/jni/android_util_StatsLog.cpp
index e749d34..9225fc2 100644
--- a/core/jni/android_util_StatsLog.cpp
+++ b/core/jni/android_util_StatsLog.cpp
@@ -18,18 +18,17 @@
#define LOG_TAG "StatsLog_println"
#include <assert.h>
-#include <cutils/properties.h>
#include "jni.h"
#include <nativehelper/JNIHelp.h>
#include "utils/misc.h"
#include "core_jni_helpers.h"
-#include "stats_event_list.h"
+#include "stats_buffer_writer.h"
namespace android {
-static void android_util_StatsLog_writeRaw(JNIEnv* env, jobject clazz, jbyteArray buf, jint size)
-{
+static void android_util_StatsLog_write(JNIEnv* env, jobject clazz, jbyteArray buf, jint size,
+ jint atomId) {
if (buf == NULL) {
return;
}
@@ -42,13 +41,8 @@
if (bufferArray == NULL) {
return;
}
- const uint32_t statsEventTag = 1937006964;
- struct iovec vec[2];
- vec[0].iov_base = (void*) &statsEventTag;
- vec[0].iov_len = sizeof(statsEventTag);
- vec[1].iov_base = (void*) bufferArray;
- vec[1].iov_len = size;
- write_to_statsd(vec, 2);
+
+ write_buffer_to_statsd((void*) bufferArray, size, atomId);
env->ReleaseByteArrayElements(buf, bufferArray, 0);
}
@@ -58,7 +52,7 @@
*/
static const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
- { "writeRaw", "([BI)V", (void*) android_util_StatsLog_writeRaw },
+ { "writeImpl", "([BII)V", (void*) android_util_StatsLog_write },
};
int register_android_util_StatsLog(JNIEnv* env)
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index ba538a8..3531cf2 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -23,11 +23,10 @@
#include <inttypes.h>
#include <android_runtime/AndroidRuntime.h>
-#include <androidfw/DisplayEventDispatcher.h>
+#include <gui/DisplayEventDispatcher.h>
#include <utils/Log.h>
#include <utils/Looper.h>
#include <utils/threads.h>
-#include <gui/DisplayEventReceiver.h>
#include "android_os_MessageQueue.h"
#include <nativehelper/ScopedLocalRef.h>
@@ -59,7 +58,6 @@
private:
jobject mReceiverWeakGlobal;
sp<MessageQueue> mMessageQueue;
- DisplayEventReceiver mReceiver;
void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count) override;
void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override;
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index bd202c1..c6e678ab 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -138,6 +138,14 @@
jmethodID builder;
} gScreenshotGraphicBufferClassInfo;
+static struct {
+ jclass clazz;
+ jmethodID ctor;
+ jfieldID defaultModeId;
+ jfieldID minRefreshRate;
+ jfieldID maxRefreshRate;
+} gDesiredDisplayConfigSpecsClassInfo;
+
class JNamedColorSpace {
public:
// ColorSpace.Named.SRGB.ordinal() = 0;
@@ -810,13 +818,20 @@
return allowedConfigsArray;
}
-static jboolean nativeSetDesiredDisplayConfigSpecs(JNIEnv* env, jclass clazz,
- jobject tokenObj, jint displayModeId, jfloat minRefreshRate, jfloat maxRefreshRate) {
+static jboolean nativeSetDesiredDisplayConfigSpecs(JNIEnv* env, jclass clazz, jobject tokenObj,
+ jobject desiredDisplayConfigSpecs) {
sp<IBinder> token(ibinderForJavaObject(env, tokenObj));
if (token == nullptr) return JNI_FALSE;
+ jint defaultModeId = env->GetIntField(desiredDisplayConfigSpecs,
+ gDesiredDisplayConfigSpecsClassInfo.defaultModeId);
+ jfloat minRefreshRate = env->GetFloatField(desiredDisplayConfigSpecs,
+ gDesiredDisplayConfigSpecsClassInfo.minRefreshRate);
+ jfloat maxRefreshRate = env->GetFloatField(desiredDisplayConfigSpecs,
+ gDesiredDisplayConfigSpecsClassInfo.maxRefreshRate);
+
size_t result = SurfaceComposerClient::setDesiredDisplayConfigSpecs(
- token, displayModeId, minRefreshRate, maxRefreshRate);
+ token, defaultModeId, minRefreshRate, maxRefreshRate);
return result == NO_ERROR ? JNI_TRUE : JNI_FALSE;
}
@@ -1376,7 +1391,8 @@
(void*)nativeSetAllowedDisplayConfigs },
{"nativeGetAllowedDisplayConfigs", "(Landroid/os/IBinder;)[I",
(void*)nativeGetAllowedDisplayConfigs },
- {"nativeSetDesiredDisplayConfigSpecs", "(Landroid/os/IBinder;IFF)Z",
+ {"nativeSetDesiredDisplayConfigSpecs",
+ "(Landroid/os/IBinder;Landroid/view/SurfaceControl$DesiredDisplayConfigSpecs;)Z",
(void*)nativeSetDesiredDisplayConfigSpecs },
{"nativeGetDisplayColorModes", "(Landroid/os/IBinder;)[I",
(void*)nativeGetDisplayColorModes},
@@ -1547,6 +1563,19 @@
gDisplayPrimariesClassInfo.white = GetFieldIDOrDie(env, displayPrimariesClazz, "white",
"Landroid/view/SurfaceControl$CieXyz;");
+ jclass desiredDisplayConfigSpecsClazz =
+ FindClassOrDie(env, "android/view/SurfaceControl$DesiredDisplayConfigSpecs");
+ gDesiredDisplayConfigSpecsClassInfo.clazz =
+ MakeGlobalRefOrDie(env, desiredDisplayConfigSpecsClazz);
+ gDesiredDisplayConfigSpecsClassInfo.ctor =
+ GetMethodIDOrDie(env, gDesiredDisplayConfigSpecsClassInfo.clazz, "<init>", "(IFF)V");
+ gDesiredDisplayConfigSpecsClassInfo.defaultModeId =
+ GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "mDefaultModeId", "I");
+ gDesiredDisplayConfigSpecsClassInfo.minRefreshRate =
+ GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "mMinRefreshRate", "F");
+ gDesiredDisplayConfigSpecsClassInfo.maxRefreshRate =
+ GetFieldIDOrDie(env, desiredDisplayConfigSpecsClazz, "mMaxRefreshRate", "F");
+
return err;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index b83294c..9dc2319 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1614,6 +1614,14 @@
<permission android:name="android.permission.NETWORK_STACK"
android:protectionLevel="signature" />
+ <!-- @SystemApi @hide Allows an application to observe network policy changes. -->
+ <permission android:name="android.permission.OBSERVE_NETWORK_POLICY"
+ android:protectionLevel="signature" />
+
+ <!-- @SystemApi @hide Allows applications to register network factory or agent -->
+ <permission android:name="android.permission.NETWORK_FACTORY"
+ android:protectionLevel="signature" />
+
<!-- Allows Settings and SystemUI to call methods in Networking services
<p>Not for use by third-party or privileged applications.
@SystemApi
@@ -1744,7 +1752,11 @@
<permission android:name="android.permission.NFC_TRANSACTION_EVENT"
android:protectionLevel="normal" />
- <!-- @SystemApi Allows an internal user to use privileged ConnectivityManager APIs.
+ <!-- @deprecated This permission used to allow too broad access to sensitive methods and all its
+ uses have been replaced by a more appropriate permission. Most uses have been replaced with
+ a NETWORK_STACK or NETWORK_SETTINGS check. Please look up the documentation of the
+ individual functions to figure out what permission now protects the individual function.
+ @SystemApi Allows an internal user to use privileged ConnectivityManager APIs.
@hide -->
<permission android:name="android.permission.CONNECTIVITY_INTERNAL"
android:protectionLevel="signature|privileged" />
@@ -3536,9 +3548,10 @@
android:protectionLevel="signature|privileged" />
<!-- @SystemApi Allows an application to manage the holders of a role.
- @hide -->
+ @hide
+ STOPSHIP b/145526313: Remove wellbeing protection flag from MANAGE_ROLE_HOLDERS. -->
<permission android:name="android.permission.MANAGE_ROLE_HOLDERS"
- android:protectionLevel="signature|installer|telephony" />
+ android:protectionLevel="signature|installer|telephony|wellbeing" />
<!-- @SystemApi Allows an application to observe role holder changes.
@hide -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index d66e0ce..fc9fa85 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -508,7 +508,7 @@
-->
<string translatable="false" name="config_mobile_hotspot_provision_app_no_ui"></string>
<!-- Sent in response to a provisioning check. The caller must hold the
- permission android.permission.CONNECTIVITY_INTERNAL for Settings to
+ permission android.permission.TETHER_PRIVILEGED for Settings to
receive this response.
See config_mobile_hotspot_provision_response
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index b52f535..ddd9ba4 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -220,4 +220,7 @@
<!-- Accessibility action identifier for {@link android.accessibilityservice.AccessibilityService#GLOBAL_ACTION_TAKE_SCREENSHOT}. -->
<item type="id" name="accessibilitySystemActionTakeScreenshot" />
+
+ <!-- Accessibility action identifier for {@link android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_PRESS_AND_HOLD}. -->
+ <item type="id" name="accessibilityActionPressAndHold" />
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index cde95aa..57e0e1b 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3013,6 +3013,7 @@
</public-group>
<public-group type="id" first-id="0x0102004a">
+ <public name="accessibilityActionPressAndHold" />
</public-group>
<public-group type="string" first-id="0x01040025">
diff --git a/core/tests/ConnectivityManagerTest/AndroidManifest.xml b/core/tests/ConnectivityManagerTest/AndroidManifest.xml
index a391e1f..796d7e8 100644
--- a/core/tests/ConnectivityManagerTest/AndroidManifest.xml
+++ b/core/tests/ConnectivityManagerTest/AndroidManifest.xml
@@ -73,9 +73,9 @@
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
- <!-- This permission is added for API call setAirplaneMode() in ConnectivityManager -->
- <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
<uses-permission android:name="android.permission.TETHER_PRIVILEGED" />
+ <!-- This permission is added for API call setAirplaneMode() in ConnectivityManager -->
+ <uses-permission android:name="android.permission.NETWORK_SETTINGS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.DEVICE_POWER" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
diff --git a/core/tests/utiltests/AndroidManifest.xml b/core/tests/utiltests/AndroidManifest.xml
index 4ef4b1f..8e0f1d2 100644
--- a/core/tests/utiltests/AndroidManifest.xml
+++ b/core/tests/utiltests/AndroidManifest.xml
@@ -30,7 +30,6 @@
<uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
<uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" />
- <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.MANAGE_USERS" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
diff --git a/data/etc/Android.bp b/data/etc/Android.bp
index dd4f238c..c49d663 100644
--- a/data/etc/Android.bp
+++ b/data/etc/Android.bp
@@ -73,7 +73,7 @@
prebuilt_etc {
name: "privapp_whitelist_com.android.emergency",
- product_specific: true,
+ system_ext_specific: true,
sub_dir: "permissions",
src: "com.android.emergency.xml",
filename_from_src: true,
@@ -96,7 +96,7 @@
prebuilt_etc {
name: "privapp_whitelist_com.android.provision",
- product_specific: true,
+ system_ext_specific: true,
sub_dir: "permissions",
src: "com.android.provision.xml",
filename_from_src: true,
diff --git a/data/etc/CleanSpec.mk b/data/etc/CleanSpec.mk
index be10a2c..cffb1ba 100644
--- a/data/etc/CleanSpec.mk
+++ b/data/etc/CleanSpec.mk
@@ -45,6 +45,10 @@
#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/etc/permissions/com.android.carrierconfig.xml)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/etc/permissions/com.android.carrierconfig.xml)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/etc/permissions/com.android.emergency.xml)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/etc/permissions/com.android.emergency.xml)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/etc/permissions/com.android.provision.xml)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/etc/permissions/com.android.provision.xml)
# ******************************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
# ******************************************************************
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
index 4f52a88..8765719 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -67,7 +67,6 @@
"BackupData.cpp",
"BackupHelpers.cpp",
"CursorWindow.cpp",
- "DisplayEventDispatcher.cpp",
],
shared_libs: [
"libziparchive",
@@ -75,7 +74,6 @@
"libbinder",
"liblog",
"libcutils",
- "libgui",
"libutils",
"libz",
],
diff --git a/libs/androidfw/DisplayEventDispatcher.cpp b/libs/androidfw/DisplayEventDispatcher.cpp
deleted file mode 100644
index d8a3f426..0000000
--- a/libs/androidfw/DisplayEventDispatcher.cpp
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-#define LOG_TAG "DisplayEventDispatcher"
-
-#include <cinttypes>
-#include <cstdint>
-
-#include <androidfw/DisplayEventDispatcher.h>
-#include <gui/DisplayEventReceiver.h>
-#include <utils/Log.h>
-#include <utils/Looper.h>
-
-#include <utils/Timers.h>
-
-namespace android {
-
-// Number of events to read at a time from the DisplayEventDispatcher pipe.
-// The value should be large enough that we can quickly drain the pipe
-// using just a few large reads.
-static const size_t EVENT_BUFFER_SIZE = 100;
-
-DisplayEventDispatcher::DisplayEventDispatcher(const sp<Looper>& looper,
- ISurfaceComposer::VsyncSource vsyncSource,
- ISurfaceComposer::ConfigChanged configChanged) :
- mLooper(looper), mReceiver(vsyncSource, configChanged), mWaitingForVsync(false) {
- ALOGV("dispatcher %p ~ Initializing display event dispatcher.", this);
-}
-
-status_t DisplayEventDispatcher::initialize() {
- status_t result = mReceiver.initCheck();
- if (result) {
- ALOGW("Failed to initialize display event receiver, status=%d", result);
- return result;
- }
-
- int rc = mLooper->addFd(mReceiver.getFd(), 0, Looper::EVENT_INPUT,
- this, NULL);
- if (rc < 0) {
- return UNKNOWN_ERROR;
- }
- return OK;
-}
-
-void DisplayEventDispatcher::dispose() {
- ALOGV("dispatcher %p ~ Disposing display event dispatcher.", this);
-
- if (!mReceiver.initCheck()) {
- mLooper->removeFd(mReceiver.getFd());
- }
-}
-
-status_t DisplayEventDispatcher::scheduleVsync() {
- if (!mWaitingForVsync) {
- ALOGV("dispatcher %p ~ Scheduling vsync.", this);
-
- // Drain all pending events.
- nsecs_t vsyncTimestamp;
- PhysicalDisplayId vsyncDisplayId;
- uint32_t vsyncCount;
- if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) {
- ALOGE("dispatcher %p ~ last event processed while scheduling was for %" PRId64 "",
- this, ns2ms(static_cast<nsecs_t>(vsyncTimestamp)));
- }
-
- status_t status = mReceiver.requestNextVsync();
- if (status) {
- ALOGW("Failed to request next vsync, status=%d", status);
- return status;
- }
-
- mWaitingForVsync = true;
- }
- return OK;
-}
-
-int DisplayEventDispatcher::handleEvent(int, int events, void*) {
- if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
- ALOGE("Display event receiver pipe was closed or an error occurred. "
- "events=0x%x", events);
- return 0; // remove the callback
- }
-
- if (!(events & Looper::EVENT_INPUT)) {
- ALOGW("Received spurious callback for unhandled poll event. "
- "events=0x%x", events);
- return 1; // keep the callback
- }
-
- // Drain all pending events, keep the last vsync.
- nsecs_t vsyncTimestamp;
- PhysicalDisplayId vsyncDisplayId;
- uint32_t vsyncCount;
- if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) {
- ALOGV("dispatcher %p ~ Vsync pulse: timestamp=%" PRId64 ", displayId=%"
- ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", count=%d",
- this, ns2ms(vsyncTimestamp), vsyncDisplayId, vsyncCount);
- mWaitingForVsync = false;
- dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount);
- }
-
- return 1; // keep the callback
-}
-
-bool DisplayEventDispatcher::processPendingEvents(
- nsecs_t* outTimestamp, PhysicalDisplayId* outDisplayId, uint32_t* outCount) {
- bool gotVsync = false;
- DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
- ssize_t n;
- while ((n = mReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
- ALOGV("dispatcher %p ~ Read %d events.", this, int(n));
- for (ssize_t i = 0; i < n; i++) {
- const DisplayEventReceiver::Event& ev = buf[i];
- switch (ev.header.type) {
- case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
- // Later vsync events will just overwrite the info from earlier
- // ones. That's fine, we only care about the most recent.
- gotVsync = true;
- *outTimestamp = ev.header.timestamp;
- *outDisplayId = ev.header.displayId;
- *outCount = ev.vsync.count;
- break;
- case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
- dispatchHotplug(ev.header.timestamp, ev.header.displayId, ev.hotplug.connected);
- break;
- case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED:
- dispatchConfigChanged(ev.header.timestamp, ev.header.displayId, ev.config.configId);
- break;
- default:
- ALOGW("dispatcher %p ~ ignoring unknown event type %#x", this, ev.header.type);
- break;
- }
- }
- }
- if (n < 0) {
- ALOGW("Failed to get events from display event dispatcher, status=%d", status_t(n));
- }
- return gotVsync;
-}
-}
diff --git a/libs/androidfw/include/androidfw/DisplayEventDispatcher.h b/libs/androidfw/include/androidfw/DisplayEventDispatcher.h
deleted file mode 100644
index 8bc2520..0000000
--- a/libs/androidfw/include/androidfw/DisplayEventDispatcher.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <gui/DisplayEventReceiver.h>
-#include <utils/Log.h>
-#include <utils/Looper.h>
-
-namespace android {
-
-class DisplayEventDispatcher : public LooperCallback {
-public:
- explicit DisplayEventDispatcher(const sp<Looper>& looper,
- ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp,
- ISurfaceComposer::ConfigChanged configChanged = ISurfaceComposer::eConfigChangedSuppress);
-
- status_t initialize();
- void dispose();
- status_t scheduleVsync();
-
-protected:
- virtual ~DisplayEventDispatcher() = default;
-
-private:
- sp<Looper> mLooper;
- DisplayEventReceiver mReceiver;
- bool mWaitingForVsync;
-
- virtual void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count) = 0;
- virtual void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId,
- bool connected) = 0;
- virtual void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId,
- int32_t configId) = 0;
-
- virtual int handleEvent(int receiveFd, int events, void* data);
- bool processPendingEvents(nsecs_t* outTimestamp, PhysicalDisplayId* outDisplayId,
- uint32_t* outCount);
-};
-}
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index 217b0c4..cd908354 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -135,8 +135,7 @@
bool setFillPath = properties.getFillGradient() != nullptr ||
properties.getFillColor() != SK_ColorTRANSPARENT;
if (setFillPath) {
- SkPath::FillType ft = static_cast<SkPath::FillType>(properties.getFillType());
- outPath->setFillType(ft);
+ outPath->setFillType(static_cast<SkPathFillType>(properties.getFillType()));
}
return *outPath;
}
diff --git a/location/java/android/location/GnssMeasurement.java b/location/java/android/location/GnssMeasurement.java
index 9013a96..70abbb3 100644
--- a/location/java/android/location/GnssMeasurement.java
+++ b/location/java/android/location/GnssMeasurement.java
@@ -16,9 +16,11 @@
package android.location;
+import android.annotation.FloatRange;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.TestApi;
+import android.hardware.gnss.V1_0.IGnssMeasurementCallback.GnssMeasurementFlags;
import android.os.Parcel;
import android.os.Parcelable;
@@ -37,6 +39,7 @@
private long mReceivedSvTimeNanos;
private long mReceivedSvTimeUncertaintyNanos;
private double mCn0DbHz;
+ private double mBasebandCn0DbHz;
private double mPseudorangeRateMetersPerSecond;
private double mPseudorangeRateUncertaintyMetersPerSecond;
private int mAccumulatedDeltaRangeState;
@@ -51,16 +54,20 @@
private double mAutomaticGainControlLevelInDb;
@NonNull private String mCodeType;
- // The following enumerations must be in sync with the values declared in gps.h
+ // The following enumerations must be in sync with the values declared in GNSS HAL.
private static final int HAS_NO_FLAGS = 0;
- private static final int HAS_SNR = (1<<0);
- private static final int HAS_CARRIER_FREQUENCY = (1<<9);
- private static final int HAS_CARRIER_CYCLES = (1<<10);
- private static final int HAS_CARRIER_PHASE = (1<<11);
- private static final int HAS_CARRIER_PHASE_UNCERTAINTY = (1<<12);
- private static final int HAS_AUTOMATIC_GAIN_CONTROL = (1<<13);
+ private static final int HAS_SNR = GnssMeasurementFlags.HAS_SNR;
+ private static final int HAS_CARRIER_FREQUENCY = GnssMeasurementFlags.HAS_CARRIER_FREQUENCY;
+ private static final int HAS_CARRIER_CYCLES = GnssMeasurementFlags.HAS_CARRIER_CYCLES;
+ private static final int HAS_CARRIER_PHASE = GnssMeasurementFlags.HAS_CARRIER_PHASE;
+ private static final int HAS_CARRIER_PHASE_UNCERTAINTY =
+ GnssMeasurementFlags.HAS_CARRIER_PHASE_UNCERTAINTY;
+ private static final int HAS_AUTOMATIC_GAIN_CONTROL =
+ GnssMeasurementFlags.HAS_AUTOMATIC_GAIN_CONTROL;
+
private static final int HAS_CODE_TYPE = (1 << 14);
+ private static final int HAS_BASEBAND_CN0 = (1 << 15);
/**
* The status of the multipath indicator.
@@ -240,6 +247,7 @@
mReceivedSvTimeNanos = measurement.mReceivedSvTimeNanos;
mReceivedSvTimeUncertaintyNanos = measurement.mReceivedSvTimeUncertaintyNanos;
mCn0DbHz = measurement.mCn0DbHz;
+ mBasebandCn0DbHz = measurement.mBasebandCn0DbHz;
mPseudorangeRateMetersPerSecond = measurement.mPseudorangeRateMetersPerSecond;
mPseudorangeRateUncertaintyMetersPerSecond =
measurement.mPseudorangeRateUncertaintyMetersPerSecond;
@@ -788,6 +796,49 @@
}
/**
+ * Returns {@code true} if {@link #getBasebandCn0DbHz()} is available, {@code false} otherwise.
+ */
+ public boolean hasBasebandCn0DbHz() {
+ return isFlagSet(HAS_BASEBAND_CN0);
+ }
+
+ /**
+ * Gets the baseband carrier-to-noise density in dB-Hz.
+ *
+ * <p>Typical range: 0-50 dB-Hz.
+ *
+ * <p>The value contains the measured C/N0 for the signal at the baseband. This is typically
+ * a few dB weaker than the value estimated for C/N0 at the antenna port, which is reported
+ * in {@link #getCn0DbHz()}.
+ */
+ @FloatRange(from = 0, to = 50)
+ public double getBasebandCn0DbHz() {
+ return mBasebandCn0DbHz;
+ }
+
+ /**
+ * Sets the baseband carrier-to-noise density in dB-Hz.
+ *
+ * @hide
+ */
+ @TestApi
+ public void setBasebandCn0DbHz(double value) {
+ setFlag(HAS_BASEBAND_CN0);
+ mBasebandCn0DbHz = value;
+ }
+
+ /**
+ * Resets the baseband carrier-to-noise density in dB-Hz.
+ *
+ * @hide
+ */
+ @TestApi
+ public void resetBasebandCn0DbHz() {
+ resetFlag(HAS_BASEBAND_CN0);
+ mBasebandCn0DbHz = Double.NaN;
+ }
+
+ /**
* Gets the Pseudorange rate at the timestamp in m/s.
*
* <p>The error estimate for this value is
@@ -1400,6 +1451,7 @@
gnssMeasurement.mSnrInDb = parcel.readDouble();
gnssMeasurement.mAutomaticGainControlLevelInDb = parcel.readDouble();
gnssMeasurement.mCodeType = parcel.readString();
+ gnssMeasurement.mBasebandCn0DbHz = parcel.readDouble();
return gnssMeasurement;
}
@@ -1433,6 +1485,7 @@
parcel.writeDouble(mSnrInDb);
parcel.writeDouble(mAutomaticGainControlLevelInDb);
parcel.writeString(mCodeType);
+ parcel.writeDouble(mBasebandCn0DbHz);
}
@Override
@@ -1461,6 +1514,9 @@
builder.append(String.format(format, "Cn0DbHz", mCn0DbHz));
+ builder.append(String.format(format, "BasebandCn0DbHz",
+ hasBasebandCn0DbHz() ? mBasebandCn0DbHz : null));
+
builder.append(String.format(
formatWithUncertainty,
"PseudorangeRateMetersPerSecond",
@@ -1536,6 +1592,7 @@
resetSnrInDb();
resetAutomaticGainControlLevel();
resetCodeType();
+ resetBasebandCn0DbHz();
}
private void setFlag(int flag) {
diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl
index 81a7ee2..d803f04 100644
--- a/media/java/android/media/IMediaRouterService.aidl
+++ b/media/java/android/media/IMediaRouterService.aidl
@@ -40,7 +40,6 @@
void setSelectedRoute(IMediaRouterClient client, String routeId, boolean explicit);
void requestSetVolume(IMediaRouterClient client, String routeId, int volume);
void requestUpdateVolume(IMediaRouterClient client, String routeId, int direction);
- void setControlCategories(IMediaRouterClient client, in List<String> categories);
// Methods for media router 2
List<MediaRoute2Info> getSystemRoutes();
@@ -56,7 +55,7 @@
* @param route the route to be selected
*/
void requestSelectRoute2(IMediaRouter2Client client, in @nullable MediaRoute2Info route);
- void setControlCategories2(IMediaRouter2Client client, in List<String> categories);
+ void setControlCategories(IMediaRouter2Client client, in List<String> categories);
void registerManager(IMediaRouter2Manager manager, String packageName);
void unregisterManager(IMediaRouter2Manager manager);
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index 7b15d95..d72231f 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -49,8 +49,6 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
@@ -84,7 +82,6 @@
final ArrayList<RouteInfo> mRoutes = new ArrayList<RouteInfo>();
final ArrayList<RouteCategory> mCategories = new ArrayList<RouteCategory>();
- List<String> mControlCategories = Collections.emptyList();
final RouteCategory mSystemCategory;
@@ -361,18 +358,6 @@
return mDisplayService.getDisplays(DisplayManager.DISPLAY_CATEGORY_PRESENTATION);
}
- public void setControlCategories(Collection<String> controlCategories) {
- List<String> newControlCategories = new ArrayList<>(controlCategories);
- mControlCategories = newControlCategories;
- if (mClient != null) {
- try {
- mMediaRouterService.setControlCategories(mClient, newControlCategories);
- } catch (RemoteException ex) {
- Log.e(TAG, "Unable to set control categories.", ex);
- }
- }
- }
-
private void updatePresentationDisplays(int changedDisplayId) {
final int count = mRoutes.size();
for (int i = 0; i < count; i++) {
@@ -421,7 +406,6 @@
try {
Client client = new Client();
mMediaRouterService.registerClientAsUser(client, mPackageName, userId);
- mMediaRouterService.setControlCategories(client, mControlCategories);
mClient = client;
} catch (RemoteException ex) {
Log.e(TAG, "Unable to register media router client.", ex);
@@ -1318,20 +1302,6 @@
sStatic.rebindAsUser(userId);
}
- //TODO: remove this and Client1Record in MediaRouter2ServiceImpl.
- /**
- * Sets the control categories of the application.
- * Routes that support at least one of the given control categories only exists and are handled
- * by the media router.
- *
- * @hide
- */
- public void setControlCategories(@NonNull Collection<String> controlCategories) {
- Objects.requireNonNull(controlCategories, "control categories must not be null");
-
- sStatic.setControlCategories(controlCategories);
- }
-
static void updateRoute(final RouteInfo info) {
dispatchRouteChanged(info);
}
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index 35cb066..3e6f4c0 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -114,7 +114,7 @@
@GuardedBy("sLock")
private MediaRoute2Info mSelectingRoute;
@GuardedBy("sLock")
- private Client mClient;
+ private Client2 mClient;
final Handler mHandler;
volatile List<MediaRoute2Info> mFilteredRoutes = Collections.emptyList();
@@ -196,10 +196,10 @@
synchronized (sLock) {
if (mClient == null) {
- Client client = new Client();
+ Client2 client = new Client2();
try {
mMediaRouterService.registerClient2(client, mPackageName);
- mMediaRouterService.setControlCategories2(client, mControlCategories);
+ mMediaRouterService.setControlCategories(client, mControlCategories);
mClient = client;
} catch (RemoteException ex) {
Log.e(TAG, "Unable to register media router.", ex);
@@ -288,7 +288,7 @@
public void requestSelectRoute(@NonNull MediaRoute2Info route) {
Objects.requireNonNull(route, "route must not be null");
- Client client;
+ Client2 client;
synchronized (sLock) {
if (mSelectingRoute == route) {
Log.w(TAG, "The route selection request is already sent.");
@@ -318,7 +318,7 @@
Objects.requireNonNull(route, "route must not be null");
Objects.requireNonNull(request, "request must not be null");
- Client client;
+ Client2 client;
synchronized (sLock) {
client = mClient;
}
@@ -342,7 +342,7 @@
public void requestSetVolume(@NonNull MediaRoute2Info route, int volume) {
Objects.requireNonNull(route, "route must not be null");
- Client client;
+ Client2 client;
synchronized (sLock) {
client = mClient;
}
@@ -366,7 +366,7 @@
public void requestUpdateVolume(@NonNull MediaRoute2Info route, int delta) {
Objects.requireNonNull(route, "route must not be null");
- Client client;
+ Client2 client;
synchronized (sLock) {
client = mClient;
}
@@ -398,13 +398,13 @@
List<MediaRoute2Info> filteredRoutes = new ArrayList<>();
mControlCategories = newControlCategories;
- Client client;
+ Client2 client;
synchronized (sLock) {
client = mClient;
}
if (client != null) {
try {
- mMediaRouterService.setControlCategories2(client, mControlCategories);
+ mMediaRouterService.setControlCategories(client, mControlCategories);
} catch (RemoteException ex) {
Log.e(TAG, "Unable to set control categories.", ex);
}
@@ -600,7 +600,7 @@
}
}
- class Client extends IMediaRouter2Client.Stub {
+ class Client2 extends IMediaRouter2Client.Stub {
@Override
public void notifyRestoreRoute() throws RemoteException {}
diff --git a/media/jni/soundpool/Stream.cpp b/media/jni/soundpool/Stream.cpp
index e7d4d90..809e81b 100644
--- a/media/jni/soundpool/Stream.cpp
+++ b/media/jni/soundpool/Stream.cpp
@@ -179,6 +179,7 @@
{
std::lock_guard lock(mLock);
if (streamID == mStreamID) {
+ ALOGV("%s: track streamID: %d", __func__, streamID);
if (mAudioTrack != nullptr) {
if (mState == PLAYING && !mMuted && (mLeftVolume != 0.f || mRightVolume != 0.f)) {
setVolume_l(0.f, 0.f);
@@ -202,6 +203,7 @@
void Stream::stop_l()
{
if (mState != IDLE) {
+ ALOGV("%s: track streamID: %d", __func__, (int)mStreamID);
if (mAudioTrack != nullptr) {
mAudioTrack->stop();
}
@@ -227,6 +229,7 @@
LOG_ALWAYS_FATAL_IF(pairStream == nullptr, "No pair stream!");
sp<AudioTrack> releaseTracks[2];
{
+ ALOGV("%s: track streamID: %d", __func__, (int)mStreamID);
// TODO: Do we really want to force a simultaneous synchronization between
// the stream and its pair?
diff --git a/media/jni/soundpool/StreamManager.cpp b/media/jni/soundpool/StreamManager.cpp
index 64f81d5..79e4d8a 100644
--- a/media/jni/soundpool/StreamManager.cpp
+++ b/media/jni/soundpool/StreamManager.cpp
@@ -148,16 +148,18 @@
sanityCheckQueue_l();
// find an available stream, prefer one that has matching sound id.
if (mAvailableStreams.size() > 0) {
- newStream = *mAvailableStreams.begin();
for (auto stream : mAvailableStreams) {
if (stream->getSoundID() == soundID) {
newStream = stream;
+ ALOGV("%s: found soundID %d in available queue", __func__, soundID);
break;
}
}
- if (newStream != nullptr) {
- newStream->setStopTimeNs(systemTime());
+ if (newStream == nullptr) {
+ ALOGV("%s: found stream in available queue", __func__);
+ newStream = *mAvailableStreams.begin();
}
+ newStream->setStopTimeNs(systemTime());
fromAvailableQueue = true;
}
@@ -166,10 +168,12 @@
for (auto [unused , stream] : mRestartStreams) {
if (!stream->getPairStream()->hasSound()) {
if (stream->getSoundID() == soundID) {
+ ALOGV("%s: found soundID %d in restart queue", __func__, soundID);
newStream = stream;
fromAvailableQueue = false;
break;
} else if (newStream == nullptr) {
+ ALOGV("%s: found stream in restart queue", __func__);
newStream = stream;
}
}
@@ -183,6 +187,7 @@
if (newStream == nullptr
|| newStream->getPriority() > stream->getPriority()) {
newStream = stream;
+ ALOGV("%s: found stream in active queue", __func__);
}
}
}
@@ -195,6 +200,7 @@
if (newStream == nullptr) {
for (auto [unused, stream] : mRestartStreams) {
if (stream->getPairPriority() <= priority) {
+ ALOGV("%s: evict stream from restart queue", __func__);
newStream = stream;
break;
}
@@ -210,6 +216,8 @@
Stream *pairStream = newStream->getPairStream();
streamID = getNextIdForStream(pairStream);
+ ALOGV("%s: newStream:%p pairStream:%p, streamID:%d",
+ __func__, newStream, pairStream, streamID);
pairStream->setPlay(
streamID, sound, soundID, leftVolume, rightVolume, priority, loop, rate);
if (fromAvailableQueue && kPlayOnCallingThread) {
diff --git a/media/jni/soundpool/tests/build_and_run.sh b/media/jni/soundpool/tests/build_and_run.sh
index 741f2ef..72fd528 100755
--- a/media/jni/soundpool/tests/build_and_run.sh
+++ b/media/jni/soundpool/tests/build_and_run.sh
@@ -23,7 +23,10 @@
adb push $OUT/system/bin/soundpool_stress /system/bin
# test SoundPool playback of all the UI sound samples (loaded twice) looping 10s 1 thread.
-#adb shell /system/bin/soundpool_stress -l -1 $uidir/*.ogg $uidir/*.ogg
+adb shell /system/bin/soundpool_stress -l -1 $uidir/*.ogg $uidir/*.ogg
+
+# test SoundPool playback of all the UI sound samples (repeating 3 times) looping 10s 1 thread.
+adb shell /system/bin/soundpool_stress -l 1 -r 3 $uidir/*.ogg
# performance test SoundPool playback of all the UI sound samples (x2)
# 1 iterations, looping, 1 second playback, 4 threads.
diff --git a/media/jni/soundpool/tests/soundpool_stress.cpp b/media/jni/soundpool/tests/soundpool_stress.cpp
index 212662f..7d9b6a2 100644
--- a/media/jni/soundpool/tests/soundpool_stress.cpp
+++ b/media/jni/soundpool/tests/soundpool_stress.cpp
@@ -49,6 +49,7 @@
printf(" -i #iterations, default 1\n");
printf(" -l #loop looping mode, -1 forever\n");
printf(" -p #playback_seconds, default 10\n");
+ printf(" -r #repeat soundIDs (0 or more times), default 0\n");
printf(" -s #streams for concurrent sound playback, default 20\n");
printf(" -t #threads, default 1\n");
printf(" -z #snoozeSec after stopping, -1 forever, default 0\n");
@@ -112,7 +113,7 @@
}
void testStreams(SoundPool *soundPool, const std::vector<const char *> &filenames,
- int loop, int playSec)
+ int loop, int repeat, int playSec)
{
const int64_t startTimeNs = systemTime();
std::vector<int32_t> soundIDs;
@@ -153,23 +154,25 @@
// TODO: Use SoundPool::setCallback() for wait
for (int32_t soundID : soundIDs) {
- while (true) {
- const int32_t streamID =
+ for (int i = 0; i <= repeat; ++i) {
+ while (true) {
+ const int32_t streamID =
soundPool->play(soundID, silentVol, silentVol, priority, 0 /*loop*/, rate);
- if (streamID != 0) {
- const int32_t events = gCallbackManager.getNumberEvents(soundID);
- if (events != 1) {
- printf("WARNING: successful play for streamID:%d soundID:%d"
- " but callback events(%d) != 1\n", streamID, soundID, events);
- ++gWarnings;
+ if (streamID != 0) {
+ const int32_t events = gCallbackManager.getNumberEvents(soundID);
+ if (events != 1) {
+ printf("WARNING: successful play for streamID:%d soundID:%d"
+ " but callback events(%d) != 1\n", streamID, soundID, events);
+ ++gWarnings;
+ }
+ soundPool->stop(streamID);
+ break;
}
- soundPool->stop(streamID);
- break;
+ usleep(1000);
}
- usleep(1000);
+ printf("[%d]", soundID);
+ fflush(stdout);
}
- printf("[%d]", soundID);
- fflush(stdout);
}
const int64_t loadTimeNs = systemTime();
@@ -178,14 +181,17 @@
// check and play (overlap with above).
std::vector<int32_t> streamIDs;
for (int32_t soundID : soundIDs) {
- printf("\nplaying soundID=%d", soundID);
- const int32_t streamID = soundPool->play(soundID, maxVol, maxVol, priority, loop, rate);
- if (streamID == 0) {
- printf(" failed! ERROR");
- ++gErrors;
- } else {
- printf(" streamID=%d", streamID);
- streamIDs.emplace_back(streamID);
+ for (int i = 0; i <= repeat; ++i) {
+ printf("\nplaying soundID=%d", soundID);
+ const int32_t streamID =
+ soundPool->play(soundID, maxVol, maxVol, priority, loop, rate);
+ if (streamID == 0) {
+ printf(" failed! ERROR");
+ ++gErrors;
+ } else {
+ printf(" streamID=%d", streamID);
+ streamIDs.emplace_back(streamID);
+ }
}
}
const int64_t playTimeNs = systemTime();
@@ -217,9 +223,10 @@
int loop = 0; // disable looping
int maxStreams = 40; // change to have more concurrent playback streams
int playSec = 10;
+ int repeat = 0;
int snoozeSec = 0;
int threadCount = 1;
- for (int ch; (ch = getopt(argc, argv, "i:l:p:s:t:z:")) != -1; ) {
+ for (int ch; (ch = getopt(argc, argv, "i:l:p:r:s:t:z:")) != -1; ) {
switch (ch) {
case 'i':
iterations = atoi(optarg);
@@ -230,6 +237,9 @@
case 'p':
playSec = atoi(optarg);
break;
+ case 'r':
+ repeat = atoi(optarg);
+ break;
case 's':
maxStreams = atoi(optarg);
break;
@@ -280,7 +290,7 @@
printf("testing %zu threads\n", threads.size());
for (auto &thread : threads) {
thread = std::async(std::launch::async,
- [&]{ testStreams(soundPool.get(), filenames, loop, playSec);});
+ [&]{ testStreams(soundPool.get(), filenames, loop, repeat, playSec);});
}
// automatically joins.
}
diff --git a/packages/CarSystemUI/res/values/integers_car.xml b/packages/CarSystemUI/res/values/integers_car.xml
index e53446e..d245f67 100644
--- a/packages/CarSystemUI/res/values/integers_car.xml
+++ b/packages/CarSystemUI/res/values/integers_car.xml
@@ -32,4 +32,6 @@
<!-- Timeout values in milliseconds for displaying volume dialog-->
<integer name="car_volume_dialog_display_normal_timeout">3000</integer>
<integer name="car_volume_dialog_display_hovering_timeout">16000</integer>
+ <integer name="car_volume_dialog_display_expanded_normal_timeout">6000</integer>
+ <integer name="car_volume_dialog_display_expanded_hovering_timeout">32000</integer>
</resources>
diff --git a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
index 367959e..9a7c373 100644
--- a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
+++ b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
@@ -90,6 +90,8 @@
private final KeyguardManager mKeyguard;
private final int mNormalTimeout;
private final int mHoveringTimeout;
+ private final int mExpNormalTimeout;
+ private final int mExpHoveringTimeout;
private Window mWindow;
private CustomDialog mDialog;
@@ -176,6 +178,10 @@
R.integer.car_volume_dialog_display_normal_timeout);
mHoveringTimeout = mContext.getResources().getInteger(
R.integer.car_volume_dialog_display_hovering_timeout);
+ mExpNormalTimeout = mContext.getResources().getInteger(
+ R.integer.car_volume_dialog_display_expanded_normal_timeout);
+ mExpHoveringTimeout = mContext.getResources().getInteger(
+ R.integer.car_volume_dialog_display_expanded_hovering_timeout);
}
/** Sets a {@link CarServiceProvider} which connects to the audio service. */
@@ -313,7 +319,11 @@
}
private int computeTimeoutH() {
- return mHovering ? mHoveringTimeout : mNormalTimeout;
+ if (mExpanded) {
+ return mHovering ? mExpHoveringTimeout : mExpNormalTimeout;
+ } else {
+ return mHovering ? mHoveringTimeout : mNormalTimeout;
+ }
}
private void dismissH(int reason) {
@@ -532,6 +542,7 @@
public void onClick(final View v) {
mExpandIcon = v;
toggleDialogExpansion(true);
+ rescheduleTimeoutH();
}
}
diff --git a/packages/SettingsLib/SearchProvider/Android.bp b/packages/SettingsLib/SearchProvider/Android.bp
new file mode 100644
index 0000000..5254dde
--- /dev/null
+++ b/packages/SettingsLib/SearchProvider/Android.bp
@@ -0,0 +1,8 @@
+android_library {
+ name: "SettingsLibSearchProvider",
+
+ srcs: ["src/**/*.java"],
+
+ sdk_version: "system_current",
+ min_sdk_version: "21",
+}
diff --git a/packages/SettingsLib/SearchProvider/AndroidManifest.xml b/packages/SettingsLib/SearchProvider/AndroidManifest.xml
new file mode 100644
index 0000000..2c06673
--- /dev/null
+++ b/packages/SettingsLib/SearchProvider/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?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.settingslib.search">
+
+ <uses-sdk android:minSdkVersion="21" />
+
+</manifest>
diff --git a/packages/SettingsLib/SearchProvider/src/com/android/settingslib/searchprovider/SettingsXmlIndexProvider.java b/packages/SettingsLib/SearchProvider/src/com/android/settingslib/searchprovider/SettingsXmlIndexProvider.java
new file mode 100644
index 0000000..0b711ec
--- /dev/null
+++ b/packages/SettingsLib/SearchProvider/src/com/android/settingslib/searchprovider/SettingsXmlIndexProvider.java
@@ -0,0 +1,120 @@
+/*
+ * 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.
+ */
+
+package com.android.settingslib.searchprovider;
+
+import static android.provider.SearchIndexablesContract.INDEXABLES_XML_RES_COLUMNS;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.provider.SearchIndexableResource;
+import android.provider.SearchIndexablesContract.XmlResource;
+import android.provider.SearchIndexablesProvider;
+import android.text.TextUtils;
+
+import java.util.Collection;
+
+/**
+ * An abstract SearchIndexProvider using {@link SearchIndexableIntentResource} for indexing
+ */
+public abstract class SettingsXmlIndexProvider extends SearchIndexablesProvider {
+ private static final String TAG = "XmlIndexProvider";
+
+ @Override
+ public boolean onCreate() {
+ return true;
+ }
+
+ @Override
+ public Cursor queryXmlResources(String[] projection) {
+ final Context context = getContext();
+ final MatrixCursor cursor = new MatrixCursor(INDEXABLES_XML_RES_COLUMNS);
+ final Collection<SearchIndexableIntentResource> resources = getIntentResources();
+
+ for (SearchIndexableIntentResource indexableResource : resources) {
+ cursor.newRow()
+ .add(XmlResource.COLUMN_RANK, indexableResource.rank)
+ .add(XmlResource.COLUMN_XML_RESID, indexableResource.xmlResId)
+ .add(XmlResource.COLUMN_CLASS_NAME, indexableResource.className)
+ .add(XmlResource.COLUMN_INTENT_ACTION, indexableResource.intentAction)
+ .add(XmlResource.COLUMN_INTENT_TARGET_PACKAGE, context.getPackageName())
+ .add(XmlResource.COLUMN_INTENT_TARGET_CLASS,
+ indexableResource.intentTargetClass);
+ }
+ return cursor;
+ }
+
+ /**
+ * Returns all {@link android.provider.SearchIndexablesContract.RawData}.
+ *
+ * Those are the raw indexable data.
+ *
+ * @param projection list of {@link android.provider.SearchIndexablesContract.RawData} columns
+ * to put into the cursor. If {@code null} all supported columns should be
+ * included.
+ */
+ public Cursor queryRawData(String[] projection) {
+ return null;
+ }
+
+ /**
+ * Returns all {@link android.provider.SearchIndexablesContract.NonIndexableKey}.
+ *
+ * Those are the non indexable data keys.
+ *
+ * @param projection list of {@link android.provider.SearchIndexablesContract.NonIndexableKey}
+ * columns to put into the cursor. If {@code null} all supported columns
+ * should be included.
+ */
+ public Cursor queryNonIndexableKeys(String[] projection) {
+ return null;
+ }
+
+ /**
+ * Returns a Collection of {@link SearchIndexableIntentResource} that should be indexed for
+ * search.
+ */
+ protected abstract Collection<SearchIndexableIntentResource> getIntentResources();
+
+ /**
+ * Wrapper class of {@link SearchIndexableResource}. It is for setting the search indexable
+ * resource of corresponding XML and intent action with class.
+ */
+ public static final class SearchIndexableIntentResource extends SearchIndexableResource {
+ /**
+ * Constructor of {@link SearchIndexableIntentResource}.
+ *
+ * @param xmlResId preference xml of target {@link prefereceFragment}
+ * @param intentAction the intent to open target {@link Activity}
+ * @param className the target {@link Activity} class name
+ */
+ public SearchIndexableIntentResource(int xmlResId, String intentAction,
+ String className) {
+ super(
+ 0 /* rank */,
+ xmlResId,
+ className,
+ 0 /* icon resource id */);
+ if (TextUtils.isEmpty(intentAction)) {
+ this.intentAction = "android.intent.action.MAIN";
+ } else {
+ this.intentAction = intentAction;
+ }
+ this.intentTargetClass = className;
+ }
+ }
+}
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index e9c20db..0a671d9 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -206,6 +206,9 @@
<!-- shortcut manager -->
<uses-permission android:name="android.permission.RESET_SHORTCUT_MANAGER_THROTTLING" />
+ <!-- launcher apps -->
+ <uses-permission android:name="android.permission.ACCESS_SHORTCUTS" />
+
<uses-permission android:name="android.permission.MODIFY_THEME_OVERLAY" />
<!-- accessibility -->
diff --git a/packages/SystemUI/res/layout/qs_customize_panel_content.xml b/packages/SystemUI/res/layout/qs_customize_panel_content.xml
index 09f512f..7cce1ba 100644
--- a/packages/SystemUI/res/layout/qs_customize_panel_content.xml
+++ b/packages/SystemUI/res/layout/qs_customize_panel_content.xml
@@ -52,7 +52,7 @@
android:scrollIndicators="top"
android:scrollbars="vertical"
android:scrollbarStyle="outsideOverlay"
- android:importantForAccessibility="no" />
+ android:importantForAccessibility="auto" />
</com.android.keyguard.AlphaOptimizedLinearLayout>
<View
diff --git a/packages/SystemUI/res/layout/qs_detail_header.xml b/packages/SystemUI/res/layout/qs_detail_header.xml
index a1f0ee7..da80633 100644
--- a/packages/SystemUI/res/layout/qs_detail_header.xml
+++ b/packages/SystemUI/res/layout/qs_detail_header.xml
@@ -53,12 +53,12 @@
android:src="@drawable/ic_settings"
android:visibility="gone"/>
- <Switch
- android:id="@android:id/toggle"
+ <ViewStub
+ android:id="@+id/toggle_stub"
+ android:inflatedId="@+id/toggle"
+ android:layout="@layout/qs_detail_switch"
android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:clickable="false"
- android:textAppearance="@style/TextAppearance.QS.DetailHeader" />
+ android:layout_height="wrap_content"/>
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/qs_detail_switch.xml b/packages/SystemUI/res/layout/qs_detail_switch.xml
new file mode 100644
index 0000000..abb2497
--- /dev/null
+++ b/packages/SystemUI/res/layout/qs_detail_switch.xml
@@ -0,0 +1,23 @@
+<!--
+ ~ 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.
+ -->
+
+<Switch
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/toggle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:clickable="false"
+ android:textAppearance="@style/TextAppearance.QS.DetailHeader" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_media_panel_options.xml b/packages/SystemUI/res/layout/qs_media_panel_options.xml
new file mode 100644
index 0000000..0669357
--- /dev/null
+++ b/packages/SystemUI/res/layout/qs_media_panel_options.xml
@@ -0,0 +1,41 @@
+<?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
+ -->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/qs_media_controls_options"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal"
+ android:gravity="center"
+ android:layout_gravity="center"
+ android:padding="10dp"
+ >
+ <ImageButton
+ android:id="@+id/remove"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:src="@android:drawable/ic_menu_delete"
+ android:padding="8dp"
+ />
+ <ImageButton
+ android:id="@+id/cancel"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
+ android:src="@android:drawable/ic_menu_revert"
+ android:padding="8dp"
+ />
+</LinearLayout>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index f7b92b5..1a05ec1 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1179,4 +1179,5 @@
<dimen name="qs_media_height">150dp</dimen>
<dimen name="qs_media_width">350dp</dimen>
<dimen name="qs_media_padding">8dp</dimen>
+ <dimen name="qs_media_corner_radius">10dp</dimen>
</resources>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/PinnedStackListenerForwarder.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/PinnedStackListenerForwarder.java
index fe5a57a..8c0ffb8 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/PinnedStackListenerForwarder.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/PinnedStackListenerForwarder.java
@@ -83,16 +83,16 @@
}
@Override
- public void onSaveReentrySnapFraction(ComponentName componentName, Rect bounds) {
+ public void onSaveReentryBounds(ComponentName componentName, Rect bounds) {
for (PinnedStackListener listener : mListeners) {
- listener.onSaveReentrySnapFraction(componentName, bounds);
+ listener.onSaveReentryBounds(componentName, bounds);
}
}
@Override
- public void onResetReentrySnapFraction(ComponentName componentName) {
+ public void onResetReentryBounds(ComponentName componentName) {
for (PinnedStackListener listener : mListeners) {
- listener.onResetReentrySnapFraction(componentName);
+ listener.onResetReentryBounds(componentName);
}
}
@@ -140,9 +140,9 @@
public void onActionsChanged(ParceledListSlice actions) {}
- public void onSaveReentrySnapFraction(ComponentName componentName, Rect bounds) {}
+ public void onSaveReentryBounds(ComponentName componentName, Rect bounds) {}
- public void onResetReentrySnapFraction(ComponentName componentName) {}
+ public void onResetReentryBounds(ComponentName componentName) {}
public void onDisplayInfoChanged(DisplayInfo displayInfo) {}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 1d4b9ef..9bba2aa 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -151,7 +151,6 @@
private static final int MSG_DPM_STATE_CHANGED = 309;
private static final int MSG_USER_SWITCHING = 310;
private static final int MSG_KEYGUARD_RESET = 312;
- private static final int MSG_BOOT_COMPLETED = 313;
private static final int MSG_USER_SWITCH_COMPLETE = 314;
private static final int MSG_USER_INFO_CHANGED = 317;
private static final int MSG_REPORT_EMERGENCY_CALL_ACTION = 318;
@@ -234,7 +233,6 @@
private boolean mGoingToSleep;
private boolean mBouncer;
private boolean mAuthInterruptActive;
- private boolean mBootCompleted;
private boolean mNeedsSlowUnlockTransition;
private boolean mHasLockscreenWallpaper;
private boolean mAssistantVisible;
@@ -1075,8 +1073,6 @@
mHandler.sendMessage(mHandler.obtainMessage(MSG_PHONE_STATE_CHANGED, state));
} else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
mHandler.sendEmptyMessage(MSG_AIRPLANE_MODE_CHANGED);
- } else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
- dispatchBootCompleted();
} else if (TelephonyIntents.ACTION_SERVICE_STATE_CHANGED.equals(action)) {
ServiceState serviceState = ServiceState.newFromBundle(intent.getExtras());
int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
@@ -1550,9 +1546,6 @@
case MSG_KEYGUARD_BOUNCER_CHANGED:
handleKeyguardBouncerChanged(msg.arg1);
break;
- case MSG_BOOT_COMPLETED:
- handleBootCompleted();
- break;
case MSG_USER_INFO_CHANGED:
handleUserInfoChanged(msg.arg1);
break;
@@ -1648,11 +1641,6 @@
filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
broadcastDispatcher.registerReceiver(mBroadcastReceiver, filter, mHandler);
- final IntentFilter bootCompleteFilter = new IntentFilter();
- bootCompleteFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
- bootCompleteFilter.addAction(Intent.ACTION_BOOT_COMPLETED);
- broadcastDispatcher.registerReceiver(mBroadcastReceiver, bootCompleteFilter, mHandler);
-
final IntentFilter allUserFilter = new IntentFilter();
allUserFilter.addAction(Intent.ACTION_USER_INFO_CHANGED);
allUserFilter.addAction(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED);
@@ -2103,39 +2091,6 @@
}
/**
- * This is exposed since {@link Intent#ACTION_BOOT_COMPLETED} is not sticky. If
- * keyguard crashes sometime after boot, then it will never receive this
- * broadcast and hence not handle the event. This method is ultimately called by
- * PhoneWindowManager in this case.
- */
- public void dispatchBootCompleted() {
- mHandler.sendEmptyMessage(MSG_BOOT_COMPLETED);
- }
-
- /**
- * Handle {@link #MSG_BOOT_COMPLETED}
- */
- private void handleBootCompleted() {
- checkIsHandlerThread();
- if (mBootCompleted) return;
- mBootCompleted = true;
- for (int i = 0; i < mCallbacks.size(); i++) {
- KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
- if (cb != null) {
- cb.onBootCompleted();
- }
- }
- }
-
- /**
- * We need to store this state in the KeyguardUpdateMonitor since this class will not be
- * destroyed.
- */
- public boolean hasBootCompleted() {
- return mBootCompleted;
- }
-
- /**
* Handle {@link #MSG_DEVICE_PROVISIONED}
*/
private void handleDeviceProvisioned() {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index b4b83d6..04502f0 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -148,14 +148,6 @@
public void onUserUnlocked() { }
/**
- * Called when boot completed.
- *
- * Note, this callback will only be received if boot complete occurs after registering with
- * KeyguardUpdateMonitor.
- */
- public void onBootCompleted() { }
-
- /**
* Called when the emergency call button is pressed.
*/
public void onEmergencyCallAction() { }
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java
index 9793d72..8e49d58 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistHandleReminderExpBehavior.java
@@ -33,6 +33,7 @@
import androidx.slice.Clock;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
+import com.android.systemui.BootCompleteCache;
import com.android.systemui.assist.AssistHandleBehaviorController.BehaviorController;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.keyguard.WakefulnessLifecycle;
@@ -83,7 +84,6 @@
private static final String[] DEFAULT_HOME_CHANGE_ACTIONS = new String[] {
PackageManagerWrapper.ACTION_PREFERRED_ACTIVITY_CHANGED,
- Intent.ACTION_BOOT_COMPLETED,
Intent.ACTION_PACKAGE_ADDED,
Intent.ACTION_PACKAGE_CHANGED,
Intent.ACTION_PACKAGE_REMOVED
@@ -150,6 +150,15 @@
mDefaultHome = getCurrentDefaultHome();
}
};
+
+ private final BootCompleteCache.BootCompleteListener mBootCompleteListener =
+ new BootCompleteCache.BootCompleteListener() {
+ @Override
+ public void onBootComplete() {
+ mDefaultHome = getCurrentDefaultHome();
+ }
+ };
+
private final IntentFilter mDefaultHomeIntentFilter;
private final Runnable mResetConsecutiveTaskSwitches = this::resetConsecutiveTaskSwitches;
@@ -163,6 +172,7 @@
private final Lazy<WakefulnessLifecycle> mWakefulnessLifecycle;
private final Lazy<PackageManagerWrapper> mPackageManagerWrapper;
private final Lazy<BroadcastDispatcher> mBroadcastDispatcher;
+ private final Lazy<BootCompleteCache> mBootCompleteCache;
private boolean mOnLockscreen;
private boolean mIsDozing;
@@ -196,7 +206,8 @@
Lazy<SysUiState> sysUiFlagContainer,
Lazy<WakefulnessLifecycle> wakefulnessLifecycle,
Lazy<PackageManagerWrapper> packageManagerWrapper,
- Lazy<BroadcastDispatcher> broadcastDispatcher) {
+ Lazy<BroadcastDispatcher> broadcastDispatcher,
+ Lazy<BootCompleteCache> bootCompleteCache) {
mClock = clock;
mHandler = handler;
mDeviceConfigHelper = deviceConfigHelper;
@@ -211,6 +222,7 @@
mDefaultHomeIntentFilter.addAction(action);
}
mBroadcastDispatcher = broadcastDispatcher;
+ mBootCompleteCache = bootCompleteCache;
}
@Override
@@ -218,6 +230,7 @@
mContext = context;
mAssistHandleCallbacks = callbacks;
mConsecutiveTaskSwitches = 0;
+ mBootCompleteCache.get().addListener(mBootCompleteListener);
mDefaultHome = getCurrentDefaultHome();
mBroadcastDispatcher.get()
.registerReceiver(mDefaultHomeBroadcastReceiver, mDefaultHomeIntentFilter);
@@ -250,6 +263,7 @@
mAssistHandleCallbacks = null;
if (mContext != null) {
mBroadcastDispatcher.get().unregisterReceiver(mDefaultHomeBroadcastReceiver);
+ mBootCompleteCache.get().removeListener(mBootCompleteListener);
Settings.Secure.putLong(mContext.getContentResolver(), LEARNING_TIME_ELAPSED_KEY, 0);
Settings.Secure.putInt(mContext.getContentResolver(), LEARNING_EVENT_COUNT_KEY, 0);
Settings.Secure.putLong(mContext.getContentResolver(), LEARNED_HINT_LAST_SHOWN_KEY, 0);
diff --git a/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java b/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java
index 8cccffa..9de6854 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/PhoneStateMonitor.java
@@ -27,6 +27,7 @@
import androidx.annotation.Nullable;
+import com.android.systemui.BootCompleteCache;
import com.android.systemui.Dependency;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -62,7 +63,6 @@
private static final String[] DEFAULT_HOME_CHANGE_ACTIONS = new String[] {
PackageManagerWrapper.ACTION_PREFERRED_ACTIVITY_CHANGED,
- Intent.ACTION_BOOT_COMPLETED,
Intent.ACTION_PACKAGE_ADDED,
Intent.ACTION_PACKAGE_CHANGED,
Intent.ACTION_PACKAGE_REMOVED
@@ -77,13 +77,14 @@
@Inject
PhoneStateMonitor(Context context, BroadcastDispatcher broadcastDispatcher,
- Optional<Lazy<StatusBar>> statusBarOptionalLazy) {
+ Optional<Lazy<StatusBar>> statusBarOptionalLazy, BootCompleteCache bootCompleteCache) {
mContext = context;
mStatusBarOptionalLazy = statusBarOptionalLazy;
mStatusBarStateController = Dependency.get(StatusBarStateController.class);
ActivityManagerWrapper activityManagerWrapper = ActivityManagerWrapper.getInstance();
mDefaultHome = getCurrentDefaultHome();
+ bootCompleteCache.addListener(() -> mDefaultHome = getCurrentDefaultHome());
IntentFilter intentFilter = new IntentFilter();
for (String action : DEFAULT_HOME_CHANGE_ACTIONS) {
intentFilter.addAction(action);
diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
index 776189b..adb288a 100644
--- a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
+++ b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
@@ -56,7 +56,7 @@
* a given broadcast.
*
* Use only for IntentFilters with actions and optionally categories. It does not support,
- * permissions, schemes, data types or data authorities.
+ * permissions, schemes, data types, data authorities or priority different than 0.
* Cannot be used for getting sticky broadcasts.
*/
@Singleton
@@ -104,6 +104,7 @@
if (filter.countDataPaths() != 0) sb.append("Filter cannot contain DataPaths. ")
if (filter.countDataSchemes() != 0) sb.append("Filter cannot contain DataSchemes. ")
if (filter.countDataTypes() != 0) sb.append("Filter cannot contain DataTypes. ")
+ if (filter.priority != 0) sb.append("Filter cannot modify priority. ")
if (!TextUtils.isEmpty(sb)) throw IllegalArgumentException(sb.toString())
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
index c6b9090..044ea54 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
@@ -27,9 +27,13 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
+import android.content.pm.LauncherApps;
import android.content.pm.PackageManager;
+import android.content.pm.ShortcutInfo;
import android.content.res.Resources;
+import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.os.Bundle;
import android.os.Parcelable;
import android.os.UserHandle;
import android.provider.Settings;
@@ -57,6 +61,7 @@
private final String mGroupId;
private String mAppName;
private Drawable mUserBadgedAppIcon;
+ private ShortcutInfo mShortcutInfo;
private boolean mInflated;
private BubbleView mIconView;
@@ -94,6 +99,14 @@
mLastUpdated = e.getSbn().getPostTime();
mGroupId = groupId(e);
+ String shortcutId = e.getSbn().getNotification().getShortcutId();
+ if (BubbleExperimentConfig.useShortcutInfoToBubble(context)
+ && shortcutId != null) {
+ mShortcutInfo = BubbleExperimentConfig.getShortcutInfo(context,
+ e.getSbn().getPackageName(),
+ e.getSbn().getUser(), shortcutId);
+ }
+
PackageManager pm = context.getPackageManager();
ApplicationInfo info;
try {
@@ -137,6 +150,21 @@
return mUserBadgedAppIcon;
}
+ @Nullable
+ public ShortcutInfo getShortcutInfo() {
+ return mShortcutInfo;
+ }
+
+ /**
+ * Whether shortcut information should be used to populate the bubble.
+ * <p>
+ * To populate the activity use {@link LauncherApps#startShortcut(ShortcutInfo, Rect, Bundle)}.
+ * To populate the icon use {@link LauncherApps#getShortcutIconDrawable(ShortcutInfo, int)}.
+ */
+ public boolean usingShortcutInfo() {
+ return BubbleExperimentConfig.isShortcutIntent(getBubbleIntent());
+ }
+
boolean isInflated() {
return mInflated;
}
@@ -331,7 +359,7 @@
}
@Nullable
- PendingIntent getBubbleIntent(Context context) {
+ PendingIntent getBubbleIntent() {
Notification.BubbleMetadata data = mEntry.getBubbleMetadata();
if (data != null) {
return data.getIntent();
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index e9c19d2..ea51f4a 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -130,12 +130,17 @@
Log.d(TAG, "onActivityViewReady: calling startActivity, "
+ "bubble=" + getBubbleKey());
}
- Intent fillInIntent = new Intent();
- // Apply flags to make behaviour match documentLaunchMode=always.
- fillInIntent.addFlags(FLAG_ACTIVITY_NEW_DOCUMENT);
- fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
try {
- mActivityView.startActivity(mBubbleIntent, fillInIntent, options);
+ if (mBubble.usingShortcutInfo()) {
+ mActivityView.startShortcutActivity(mBubble.getShortcutInfo(),
+ options, null /* sourceBounds */);
+ } else {
+ Intent fillInIntent = new Intent();
+ // Apply flags to make behaviour match documentLaunchMode=always.
+ fillInIntent.addFlags(FLAG_ACTIVITY_NEW_DOCUMENT);
+ fillInIntent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK);
+ mActivityView.startActivity(mBubbleIntent, fillInIntent, options);
+ }
} catch (RuntimeException e) {
// If there's a runtime exception here then there's something
// wrong with the intent, we can't really recover / try to populate
@@ -415,7 +420,7 @@
+ getBubbleKey());
}
- mBubbleIntent = mBubble.getBubbleIntent(mContext);
+ mBubbleIntent = mBubble.getBubbleIntent();
if (mBubbleIntent != null) {
setContentVisibility(false);
mActivityView.setVisibility(VISIBLE);
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
index b478a72..6eeb5c3 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExperimentConfig.java
@@ -16,32 +16,58 @@
package com.android.systemui.bubbles;
+import static android.app.Notification.EXTRA_MESSAGES;
+import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_DYNAMIC;
+import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_MANIFEST;
+import static android.content.pm.LauncherApps.ShortcutQuery.FLAG_MATCH_PINNED;
+
+import static com.android.systemui.bubbles.BubbleController.canLaunchIntentInActivityView;
+
import android.app.Notification;
import android.app.PendingIntent;
+import android.app.Person;
import android.content.Context;
+import android.content.Intent;
+import android.content.pm.LauncherApps;
+import android.content.pm.ShortcutInfo;
import android.graphics.drawable.Icon;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.os.UserHandle;
import android.provider.Settings;
+import com.android.internal.util.ArrayUtils;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
/**
* Common class for experiments controlled via secure settings.
*/
public class BubbleExperimentConfig {
+ private static final String SHORTCUT_DUMMY_INTENT = "bubble_experiment_shortcut_intent";
+ private static PendingIntent sDummyShortcutIntent;
+
+ private static final int BUBBLE_HEIGHT = 10000;
+
private static final String ALLOW_ANY_NOTIF_TO_BUBBLE = "allow_any_notif_to_bubble";
private static final boolean ALLOW_ANY_NOTIF_TO_BUBBLE_DEFAULT = false;
private static final String ALLOW_MESSAGE_NOTIFS_TO_BUBBLE = "allow_message_notifs_to_bubble";
private static final boolean ALLOW_MESSAGE_NOTIFS_TO_BUBBLE_DEFAULT = false;
+ private static final String ALLOW_SHORTCUTS_TO_BUBBLE = "allow_shortcuts_to_bubble";
+ private static final boolean ALLOW_SHORTCUT_TO_BUBBLE_DEFAULT = false;
+
/**
* When true, if a notification has the information necessary to bubble (i.e. valid
* contentIntent and an icon or image), then a {@link android.app.Notification.BubbleMetadata}
* object will be created by the system and added to the notification.
- *
- * This does not produce a bubble, only adds the metadata. It should be used in conjunction
- * with {@see #allowNotifBubbleMenu} which shows an affordance to bubble notification content.
+ * <p>
+ * This does not produce a bubble, only adds the metadata based on the notification info.
*/
static boolean allowAnyNotifToBubble(Context context) {
return Settings.Secure.getInt(context.getContentResolver(),
@@ -60,16 +86,28 @@
}
/**
+ * When true, if the notification is able to bubble via {@link #allowAnyNotifToBubble(Context)}
+ * or {@link #allowMessageNotifsToBubble(Context)} or via normal BubbleMetadata, then a new
+ * BubbleMetadata object is constructed based on the shortcut info.
+ * <p>
+ * This does not produce a bubble, only adds the metadata based on shortcut info.
+ */
+ static boolean useShortcutInfoToBubble(Context context) {
+ return Settings.Secure.getInt(context.getContentResolver(),
+ ALLOW_SHORTCUTS_TO_BUBBLE,
+ ALLOW_SHORTCUT_TO_BUBBLE_DEFAULT ? 1 : 0) != 0;
+ }
+
+ /**
* If {@link #allowAnyNotifToBubble(Context)} is true, this method creates and adds
* {@link android.app.Notification.BubbleMetadata} to the notification entry as long as
* the notification has necessary info for BubbleMetadata.
*/
static void adjustForExperiments(Context context, NotificationEntry entry,
Bubble previousBubble) {
- if (entry.getBubbleMetadata() != null) {
- // Has metadata, nothing to do.
- return;
- }
+
+ Notification.BubbleMetadata metadata = null;
+ boolean addedMetadata = false;
Notification notification = entry.getSbn().getNotification();
boolean isMessage = Notification.MessagingStyle.class.equals(
@@ -77,22 +115,131 @@
boolean bubbleNotifForExperiment = (isMessage && allowMessageNotifsToBubble(context))
|| allowAnyNotifToBubble(context);
- final PendingIntent intent = notification.contentIntent;
- if (bubbleNotifForExperiment
- && BubbleController.canLaunchIntentInActivityView(context, entry, intent)) {
- final Icon smallIcon = entry.getSbn().getNotification().getSmallIcon();
- Notification.BubbleMetadata.Builder metadata =
- new Notification.BubbleMetadata.Builder()
- .setDesiredHeight(10000)
- .setIcon(smallIcon)
- .setIntent(intent);
- entry.setBubbleMetadata(metadata.build());
+ boolean useShortcutInfo = useShortcutInfoToBubble(context);
+ String shortcutId = entry.getSbn().getNotification().getShortcutId();
+
+ if (useShortcutInfo && shortcutId != null) {
+ // We don't actually get anything useful from ShortcutInfo so just check existence
+ ShortcutInfo info = getShortcutInfo(context, entry.getSbn().getPackageName(),
+ entry.getSbn().getUser(), shortcutId);
+ if (info != null) {
+ metadata = createForShortcut(context, entry);
+ }
+
+ // Replace existing metadata with shortcut, or we're bubbling for experiment
+ boolean shouldBubble = entry.getBubbleMetadata() != null || bubbleNotifForExperiment;
+
+ if (shouldBubble && metadata != null) {
+ entry.setBubbleMetadata(metadata);
+ addedMetadata = true;
+ }
}
- if (previousBubble != null) {
- // Update to a previously user-created bubble, set its flag now so the update goes
+ // Didn't get metadata from a shortcut & we're bubbling for experiment
+ if (entry.getBubbleMetadata() == null && bubbleNotifForExperiment) {
+ metadata = createFromNotif(context, entry);
+ if (metadata != null) {
+ entry.setBubbleMetadata(metadata);
+ addedMetadata = true;
+ }
+ }
+
+ if (previousBubble != null && addedMetadata) {
+ // Update to a previously bubble, set its flag now so the update goes
// to the bubble.
entry.setFlagBubble(true);
}
}
+
+ static Notification.BubbleMetadata createFromNotif(Context context, NotificationEntry entry) {
+ Notification notification = entry.getSbn().getNotification();
+ final PendingIntent intent = notification.contentIntent;
+ Icon icon = null;
+ // Use the icon of the person if available
+ List<Person> personList = getPeopleFromNotification(entry);
+ if (personList.size() > 0) {
+ icon = personList.get(0).getIcon();
+ }
+ if (icon == null) {
+ icon = notification.getLargeIcon() != null
+ ? notification.getLargeIcon()
+ : notification.getSmallIcon();
+ }
+ if (canLaunchIntentInActivityView(context, entry, intent)) {
+ return new Notification.BubbleMetadata.Builder()
+ .setDesiredHeight(BUBBLE_HEIGHT)
+ .setIcon(icon)
+ .setIntent(intent)
+ .build();
+ }
+ return null;
+ }
+
+ static Notification.BubbleMetadata createForShortcut(Context context, NotificationEntry entry) {
+ // ShortcutInfo does not return an icon, instead a Drawable, lets just use
+ // notification icon for BubbleMetadata.
+ Icon icon = entry.getSbn().getNotification().getSmallIcon();
+
+ // ShortcutInfo does not return the intent, lets make a fake but identifiable
+ // intent so we can still add bubbleMetadata
+ if (sDummyShortcutIntent == null) {
+ Intent i = new Intent(SHORTCUT_DUMMY_INTENT);
+ sDummyShortcutIntent = PendingIntent.getActivity(context, 0, i,
+ PendingIntent.FLAG_UPDATE_CURRENT);
+ }
+ return new Notification.BubbleMetadata.Builder()
+ .setDesiredHeight(BUBBLE_HEIGHT)
+ .setIcon(icon)
+ .setIntent(sDummyShortcutIntent)
+ .build();
+ }
+
+ static ShortcutInfo getShortcutInfo(Context context, String packageName, UserHandle user,
+ String shortcutId) {
+ LauncherApps launcherAppService =
+ (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
+ LauncherApps.ShortcutQuery query = new LauncherApps.ShortcutQuery();
+ if (packageName != null) {
+ query.setPackage(packageName);
+ }
+ if (shortcutId != null) {
+ query.setShortcutIds(Arrays.asList(shortcutId));
+ }
+ query.setQueryFlags(FLAG_MATCH_DYNAMIC | FLAG_MATCH_PINNED | FLAG_MATCH_MANIFEST);
+ List<ShortcutInfo> shortcuts = launcherAppService.getShortcuts(query, user);
+ return shortcuts != null && shortcuts.size() > 0
+ ? shortcuts.get(0)
+ : null;
+ }
+
+ static boolean isShortcutIntent(PendingIntent intent) {
+ return intent.equals(sDummyShortcutIntent);
+ }
+
+ static List<Person> getPeopleFromNotification(NotificationEntry entry) {
+ Bundle extras = entry.getSbn().getNotification().extras;
+ ArrayList<Person> personList = new ArrayList<>();
+ if (extras == null) {
+ return personList;
+ }
+
+ List<Person> p = extras.getParcelableArrayList(Notification.EXTRA_PEOPLE_LIST);
+
+ if (p != null) {
+ personList.addAll(p);
+ }
+
+ if (Notification.MessagingStyle.class.equals(
+ entry.getSbn().getNotification().getNotificationStyle())) {
+ final Parcelable[] messages = extras.getParcelableArray(EXTRA_MESSAGES);
+ if (!ArrayUtils.isEmpty(messages)) {
+ for (Notification.MessagingStyle.Message message :
+ Notification.MessagingStyle.Message
+ .getMessagesFromBundleArray(messages)) {
+ personList.add(message.getSenderPerson());
+ }
+ }
+ }
+ return personList;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java
index 35657d3..79807b3 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java
@@ -19,6 +19,7 @@
import android.annotation.Nullable;
import android.app.Notification;
import android.content.Context;
+import android.content.pm.LauncherApps;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
@@ -243,9 +244,16 @@
}
Drawable getBubbleDrawable(Context context) {
- Notification.BubbleMetadata metadata = getEntry().getBubbleMetadata();
- Icon ic = metadata.getIcon();
- return ic.loadDrawable(context);
+ if (mBubble.getShortcutInfo() != null && mBubble.usingShortcutInfo()) {
+ LauncherApps launcherApps =
+ (LauncherApps) getContext().getSystemService(Context.LAUNCHER_APPS_SERVICE);
+ int density = getContext().getResources().getConfiguration().densityDpi;
+ return launcherApps.getShortcutIconDrawable(mBubble.getShortcutInfo(), density);
+ } else {
+ Notification.BubbleMetadata metadata = getEntry().getBubbleMetadata();
+ Icon ic = metadata.getIcon();
+ return ic.loadDrawable(context);
+ }
}
BitmapInfo getBadgedBitmap() {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index f026e68..8d08b28 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -2082,7 +2082,6 @@
@Override
public void onBootCompleted() {
- mUpdateMonitor.dispatchBootCompleted();
synchronized (this) {
mBootCompleted = true;
if (mBootSendUserPresent) {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
index 686e7db..f10274a 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java
@@ -64,6 +64,7 @@
private IPinnedStackController mPinnedStackController;
private ComponentName mLastPipComponentName;
private float mReentrySnapFraction = INVALID_SNAP_FRACTION;
+ private Size mReentrySize = null;
private float mDefaultAspectRatio;
private float mMinAspectRatio;
@@ -162,7 +163,7 @@
public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds,
Rect animatingBounds, DisplayInfo displayInfo) {
getInsetBounds(insetBounds);
- final Rect defaultBounds = getDefaultBounds(INVALID_SNAP_FRACTION);
+ final Rect defaultBounds = getDefaultBounds(INVALID_SNAP_FRACTION, null);
normalBounds.set(defaultBounds);
if (animatingBounds.isEmpty()) {
animatingBounds.set(defaultBounds);
@@ -175,26 +176,28 @@
}
/**
- * Responds to IPinnedStackListener on saving reentry snap fraction
+ * Responds to IPinnedStackListener on saving reentry snap fraction and size
* for a given {@link ComponentName}.
*/
- public void onSaveReentrySnapFraction(ComponentName componentName, Rect bounds) {
+ public void onSaveReentryBounds(ComponentName componentName, Rect bounds) {
mReentrySnapFraction = getSnapFraction(bounds);
+ mReentrySize = new Size(bounds.width(), bounds.height());
mLastPipComponentName = componentName;
}
/**
- * Responds to IPinnedStackListener on resetting reentry snap fraction
+ * Responds to IPinnedStackListener on resetting reentry snap fraction and size
* for a given {@link ComponentName}.
*/
- public void onResetReentrySnapFraction(ComponentName componentName) {
+ public void onResetReentryBounds(ComponentName componentName) {
if (componentName.equals(mLastPipComponentName)) {
- onResetReentrySnapFractionUnchecked();
+ onResetReentryBoundsUnchecked();
}
}
- private void onResetReentrySnapFractionUnchecked() {
+ private void onResetReentryBoundsUnchecked() {
mReentrySnapFraction = INVALID_SNAP_FRACTION;
+ mReentrySize = null;
mLastPipComponentName = null;
}
@@ -233,7 +236,7 @@
public void onPrepareAnimation(Rect sourceRectHint, float aspectRatio, Rect bounds) {
final Rect destinationBounds;
if (bounds == null) {
- destinationBounds = getDefaultBounds(mReentrySnapFraction);
+ destinationBounds = getDefaultBounds(mReentrySnapFraction, mReentrySize);
} else {
destinationBounds = new Rect(bounds);
}
@@ -245,7 +248,7 @@
return;
}
mAspectRatio = aspectRatio;
- onResetReentrySnapFractionUnchecked();
+ onResetReentryBoundsUnchecked();
try {
mPinnedStackController.startAnimation(destinationBounds, sourceRectHint,
-1 /* animationDuration */);
@@ -269,13 +272,14 @@
*/
private void transformBoundsToAspectRatio(Rect stackBounds, float aspectRatio,
boolean useCurrentMinEdgeSize) {
- // Save the snap fraction, calculate the aspect ratio based on screen size
+
+ // Save the snap fraction and adjust the size based on the new aspect ratio.
final float snapFraction = mSnapAlgorithm.getSnapFraction(stackBounds,
getMovementBounds(stackBounds));
-
final int minEdgeSize = useCurrentMinEdgeSize ? mCurrentMinSize : mDefaultMinSize;
- final Size size = mSnapAlgorithm.getSizeForAspectRatio(aspectRatio, minEdgeSize,
- mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
+ final Size size = mSnapAlgorithm.getSizeForAspectRatio(
+ new Size(stackBounds.width(), stackBounds.height()), aspectRatio, minEdgeSize);
+
final int left = (int) (stackBounds.centerX() - size.getWidth() / 2f);
final int top = (int) (stackBounds.centerY() - size.getHeight() / 2f);
stackBounds.set(left, top, left + size.getWidth(), top + size.getHeight());
@@ -286,21 +290,20 @@
}
/**
- * @return the default bounds to show the PIP, if a {@param snapFraction} is provided, then it
- * will apply the default bounds to the provided snap fraction.
+ * @return the default bounds to show the PIP, if a {@param snapFraction} and {@param size} are
+ * provided, then it will apply the default bounds to the provided snap fraction and size.
*/
- private Rect getDefaultBounds(float snapFraction) {
- final Rect insetBounds = new Rect();
- getInsetBounds(insetBounds);
-
+ private Rect getDefaultBounds(float snapFraction, Size size) {
final Rect defaultBounds = new Rect();
- final Size size = mSnapAlgorithm.getSizeForAspectRatio(mDefaultAspectRatio,
- mDefaultMinSize, mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
- if (snapFraction != INVALID_SNAP_FRACTION) {
+ if (snapFraction != INVALID_SNAP_FRACTION && size != null) {
defaultBounds.set(0, 0, size.getWidth(), size.getHeight());
final Rect movementBounds = getMovementBounds(defaultBounds);
mSnapAlgorithm.applySnapFraction(defaultBounds, movementBounds, snapFraction);
} else {
+ final Rect insetBounds = new Rect();
+ getInsetBounds(insetBounds);
+ size = mSnapAlgorithm.getSizeForAspectRatio(mDefaultAspectRatio,
+ mDefaultMinSize, mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight);
Gravity.apply(mDefaultStackGravity, size.getWidth(), size.getHeight(), insetBounds,
0, Math.max(mIsImeShowing ? mImeHeight : 0,
mIsShelfShowing ? mShelfHeight : 0),
@@ -364,11 +367,19 @@
* @return the default snap fraction to apply instead of the default gravity when calculating
* the default stack bounds when first entering PiP.
*/
- private float getSnapFraction(Rect stackBounds) {
+ public float getSnapFraction(Rect stackBounds) {
return mSnapAlgorithm.getSnapFraction(stackBounds, getMovementBounds(stackBounds));
}
/**
+ * Applies the given snap fraction to the given stack bounds.
+ */
+ public void applySnapFraction(Rect stackBounds, float snapFraction) {
+ final Rect movementBounds = getMovementBounds(stackBounds);
+ mSnapAlgorithm.applySnapFraction(stackBounds, movementBounds, snapFraction);
+ }
+
+ /**
* @return the pixels for a given dp value.
*/
private int dpToPx(float dpValue, DisplayMetrics dm) {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index c33b8d9..a4707cf 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -65,6 +65,7 @@
private final DisplayInfo mTmpDisplayInfo = new DisplayInfo();
private final Rect mTmpInsetBounds = new Rect();
private final Rect mTmpNormalBounds = new Rect();
+ private final Rect mReentryBounds = new Rect();
private PipBoundsHandler mPipBoundsHandler;
private InputConsumerController mInputConsumerController;
@@ -164,13 +165,25 @@
}
@Override
- public void onSaveReentrySnapFraction(ComponentName componentName, Rect bounds) {
- mHandler.post(() -> mPipBoundsHandler.onSaveReentrySnapFraction(componentName, bounds));
+ public void onSaveReentryBounds(ComponentName componentName, Rect bounds) {
+ mHandler.post(() -> {
+ // On phones, the expansion animation that happens on pip tap before restoring
+ // to fullscreen makes it so that the bounds received here are the expanded
+ // bounds. We want to restore to the unexpanded bounds when re-entering pip,
+ // so we save the bounds before expansion (normal) instead of the current
+ // bounds.
+ mReentryBounds.set(mTouchHandler.getNormalBounds());
+ // Apply the snap fraction of the current bounds to the normal bounds.
+ float snapFraction = mPipBoundsHandler.getSnapFraction(bounds);
+ mPipBoundsHandler.applySnapFraction(mReentryBounds, snapFraction);
+ // Save reentry bounds (normal non-expand bounds with current position applied).
+ mPipBoundsHandler.onSaveReentryBounds(componentName, mReentryBounds);
+ });
}
@Override
- public void onResetReentrySnapFraction(ComponentName componentName) {
- mHandler.post(() -> mPipBoundsHandler.onResetReentrySnapFraction(componentName));
+ public void onResetReentryBounds(ComponentName componentName) {
+ mHandler.post(() -> mPipBoundsHandler.onResetReentryBounds(componentName));
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index f59b372..2e90a3e 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -592,6 +592,13 @@
}
/**
+ * @return the unexpanded bounds.
+ */
+ public Rect getNormalBounds() {
+ return mNormalBounds;
+ }
+
+ /**
* Gesture controlling normal movement of the PIP.
*/
private PipTouchGesture mDefaultMovementGesture = new PipTouchGesture() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
index 60d30da..019cb14 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetail.java
@@ -28,6 +28,7 @@
import android.util.SparseArray;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewStub;
import android.view.accessibility.AccessibilityEvent;
import android.widget.ImageView;
import android.widget.LinearLayout;
@@ -58,7 +59,8 @@
protected View mQsDetailHeader;
protected TextView mQsDetailHeaderTitle;
- protected Switch mQsDetailHeaderSwitch;
+ private ViewStub mQsDetailHeaderSwitchStub;
+ private Switch mQsDetailHeaderSwitch;
protected ImageView mQsDetailHeaderProgress;
protected QSTileHost mHost;
@@ -98,7 +100,7 @@
mQsDetailHeader = findViewById(R.id.qs_detail_header);
mQsDetailHeaderTitle = (TextView) mQsDetailHeader.findViewById(android.R.id.title);
- mQsDetailHeaderSwitch = (Switch) mQsDetailHeader.findViewById(android.R.id.toggle);
+ mQsDetailHeaderSwitchStub = mQsDetailHeader.findViewById(R.id.toggle_stub);
mQsDetailHeaderProgress = findViewById(R.id.qs_detail_header_progress);
updateDetailText();
@@ -252,9 +254,12 @@
mQsDetailHeaderTitle.setText(adapter.getTitle());
final Boolean toggleState = adapter.getToggleState();
if (toggleState == null) {
- mQsDetailHeaderSwitch.setVisibility(INVISIBLE);
+ if (mQsDetailHeaderSwitch != null) mQsDetailHeaderSwitch.setVisibility(INVISIBLE);
mQsDetailHeader.setClickable(false);
} else {
+ if (mQsDetailHeaderSwitch == null) {
+ mQsDetailHeaderSwitch = (Switch) mQsDetailHeaderSwitchStub.inflate();
+ }
mQsDetailHeaderSwitch.setVisibility(VISIBLE);
handleToggleStateChanged(toggleState, adapter.getToggleEnabled());
mQsDetailHeader.setClickable(true);
@@ -274,9 +279,9 @@
if (mAnimatingOpen) {
return;
}
- mQsDetailHeaderSwitch.setChecked(state);
+ if (mQsDetailHeaderSwitch != null) mQsDetailHeaderSwitch.setChecked(state);
mQsDetailHeader.setEnabled(toggleEnabled);
- mQsDetailHeaderSwitch.setEnabled(toggleEnabled);
+ if (mQsDetailHeaderSwitch != null) mQsDetailHeaderSwitch.setEnabled(toggleEnabled);
}
private void handleScanStateChanged(boolean state) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java b/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java
index 1a4c327..f7e4c79 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java
@@ -18,8 +18,11 @@
import android.app.Notification;
import android.app.PendingIntent;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.content.res.ColorStateList;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -35,6 +38,7 @@
import android.media.session.PlaybackState;
import android.text.TextUtils;
import android.util.Log;
+import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -54,6 +58,8 @@
import com.android.systemui.R;
import com.android.systemui.plugins.ActivityStarter;
+import java.util.List;
+
/**
* Single media player for carousel in QSPanel
*/
@@ -70,6 +76,83 @@
private int mHeight;
private int mForegroundColor;
private int mBackgroundColor;
+ private ComponentName mRecvComponent;
+ private QSPanel mParent;
+
+ private MediaController.Callback mSessionCallback = new MediaController.Callback() {
+ @Override
+ public void onSessionDestroyed() {
+ Log.d(TAG, "session destroyed");
+ mController.unregisterCallback(mSessionCallback);
+
+ // Hide all the old buttons
+ final int[] actionIds = {
+ R.id.action0,
+ R.id.action1,
+ R.id.action2,
+ R.id.action3,
+ R.id.action4
+ };
+ for (int i = 0; i < actionIds.length; i++) {
+ ImageButton thisBtn = mMediaNotifView.findViewById(actionIds[i]);
+ if (thisBtn != null) {
+ thisBtn.setVisibility(View.GONE);
+ }
+ }
+
+ // Add a restart button
+ ImageButton btn = mMediaNotifView.findViewById(actionIds[0]);
+ btn.setOnClickListener(v -> {
+ Log.d(TAG, "Attempting to restart session");
+ // Send a media button event to previously found receiver
+ if (mRecvComponent != null) {
+ Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
+ intent.setComponent(mRecvComponent);
+ int keyCode = KeyEvent.KEYCODE_MEDIA_PLAY;
+ intent.putExtra(
+ Intent.EXTRA_KEY_EVENT,
+ new KeyEvent(KeyEvent.ACTION_DOWN, keyCode));
+ mContext.sendBroadcast(intent);
+ } else {
+ Log.d(TAG, "No receiver to restart");
+ // If we don't have a receiver, try relaunching the activity instead
+ try {
+ mController.getSessionActivity().send();
+ } catch (PendingIntent.CanceledException e) {
+ Log.e(TAG, "Pending intent was canceled");
+ e.printStackTrace();
+ }
+ }
+ });
+ btn.setImageDrawable(mContext.getResources().getDrawable(R.drawable.lb_ic_replay));
+ btn.setImageTintList(ColorStateList.valueOf(mForegroundColor));
+ btn.setVisibility(View.VISIBLE);
+
+ // Add long-click option to remove the player
+ ViewGroup mMediaCarousel = (ViewGroup) mMediaNotifView.getParent();
+ mMediaNotifView.setOnLongClickListener(v -> {
+ // Replace player view with delete/cancel view
+ v.setVisibility(View.GONE);
+
+ View options = LayoutInflater.from(mContext).inflate(
+ R.layout.qs_media_panel_options, null, false);
+ ImageButton btnDelete = options.findViewById(R.id.remove);
+ btnDelete.setOnClickListener(b -> {
+ mMediaCarousel.removeView(options);
+ mParent.removeMediaPlayer(QSMediaPlayer.this);
+ });
+ ImageButton btnCancel = options.findViewById(R.id.cancel);
+ btnCancel.setOnClickListener(b -> {
+ mMediaCarousel.removeView(options);
+ v.setVisibility(View.VISIBLE);
+ });
+
+ int pos = mMediaCarousel.indexOfChild(v);
+ mMediaCarousel.addView(options, pos, v.getLayoutParams());
+ return true; // consumed click
+ });
+ }
+ };
/**
*
@@ -92,7 +175,8 @@
}
/**
- *
+ * Create or update the player view for the given media session
+ * @param parent the parent QSPanel
* @param token token for this media session
* @param icon app notification icon
* @param iconColor foreground color (for text, icons)
@@ -101,13 +185,30 @@
* @param notif reference to original notification
* @param device current playback device
*/
- public void setMediaSession(MediaSession.Token token, Icon icon, int iconColor, int bgColor,
- View actionsContainer, Notification notif, MediaDevice device) {
- Log.d(TAG, "got media session: " + token);
+ public void setMediaSession(QSPanel parent, MediaSession.Token token, Icon icon, int iconColor,
+ int bgColor, View actionsContainer, Notification notif, MediaDevice device) {
+ mParent = parent;
mToken = token;
mForegroundColor = iconColor;
mBackgroundColor = bgColor;
mController = new MediaController(mContext, token);
+
+ // Try to find a receiver for the media button that matches this app
+ PackageManager pm = mContext.getPackageManager();
+ Intent it = new Intent(Intent.ACTION_MEDIA_BUTTON);
+ List<ResolveInfo> info = pm.queryBroadcastReceiversAsUser(it, 0, mContext.getUser());
+ if (info != null) {
+ for (ResolveInfo inf : info) {
+ if (inf.activityInfo.packageName.equals(notif.contentIntent.getCreatorPackage())) {
+ Log.d(TAG, "Found receiver for package: " + inf);
+ mRecvComponent = inf.getComponentInfo().getComponentName();
+ }
+ }
+ }
+
+ // reset in case we had previously restarted the stream
+ mMediaNotifView.setOnLongClickListener(null);
+ mController.registerCallback(mSessionCallback);
MediaMetadata mMediaMetadata = mController.getMetadata();
if (mMediaMetadata == null) {
Log.e(TAG, "Media metadata was null");
@@ -235,7 +336,6 @@
for (; i < actionIds.length; i++) {
ImageButton thisBtn = mMediaNotifView.findViewById(actionIds[i]);
thisBtn.setVisibility(View.GONE);
- Log.d(TAG, "hid a button");
}
}
@@ -266,8 +366,9 @@
private void addAlbumArtBackground(MediaMetadata metadata, int bgColor, int width, int height) {
Bitmap albumArt = metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
+ float radius = mContext.getResources().getDimension(R.dimen.qs_media_corner_radius);
if (albumArt != null) {
-
+ Log.d(TAG, "updating album art");
Bitmap original = albumArt.copy(Bitmap.Config.ARGB_8888, true);
Bitmap scaled = scaleBitmap(original, width, height);
Canvas canvas = new Canvas(scaled);
@@ -281,12 +382,15 @@
RoundedBitmapDrawable roundedDrawable = RoundedBitmapDrawableFactory.create(
mContext.getResources(), scaled);
- roundedDrawable.setCornerRadius(20);
+ roundedDrawable.setCornerRadius(radius);
mMediaNotifView.setBackground(roundedDrawable);
} else {
Log.e(TAG, "No album art available");
- mMediaNotifView.setBackground(null);
+ GradientDrawable rect = new GradientDrawable();
+ rect.setCornerRadius(radius);
+ rect.setColor(bgColor);
+ mMediaNotifView.setBackground(rect);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 5e98f93..51e352b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -284,7 +284,7 @@
}
Log.d(TAG, "setting player session");
- player.setMediaSession(token, icon, iconColor, bgColor, actionsContainer,
+ player.setMediaSession(this, token, icon, iconColor, bgColor, actionsContainer,
notif.getNotification(), mDevice);
if (mMediaPlayers.size() > 0) {
@@ -303,6 +303,27 @@
return mMediaCarousel;
}
+ /**
+ * Remove the media player from the carousel
+ * @param player Player to remove
+ * @return true if removed, false if player was not found
+ */
+ protected boolean removeMediaPlayer(QSMediaPlayer player) {
+ // Remove from list
+ if (!mMediaPlayers.remove(player)) {
+ return false;
+ }
+
+ // Check if we need to collapse the carousel now
+ mMediaCarousel.removeView(player.getView());
+ if (mMediaPlayers.size() == 0) {
+ ((View) mMediaCarousel.getParent()).setVisibility(View.GONE);
+ mLocalMediaManager.stopScan();
+ mLocalMediaManager.unregisterCallback(mDeviceCallback);
+ }
+ return true;
+ }
+
protected void addDivider() {
mDivider = LayoutInflater.from(mContext).inflate(R.layout.qs_divider, this, false);
mDivider.setBackgroundColor(Utils.applyAlpha(mDivider.getAlpha(),
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java
index d7b8b83..5bb882e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java
@@ -16,19 +16,27 @@
package com.android.systemui.qs;
+import android.app.PendingIntent;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.ColorStateList;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.Icon;
import android.media.MediaMetadata;
import android.media.session.MediaController;
import android.media.session.MediaSession;
import android.media.session.PlaybackState;
import android.util.Log;
+import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -42,6 +50,8 @@
import com.android.systemui.R;
+import java.util.List;
+
/**
* QQS mini media player
*/
@@ -53,6 +63,54 @@
private LinearLayout mMediaNotifView;
private MediaSession.Token mToken;
private MediaController mController;
+ private int mBackgroundColor;
+ private int mForegroundColor;
+ private ComponentName mRecvComponent;
+
+ private MediaController.Callback mSessionCallback = new MediaController.Callback() {
+ @Override
+ public void onSessionDestroyed() {
+ Log.d(TAG, "session destroyed");
+ mController.unregisterCallback(mSessionCallback);
+
+ // Hide all the old buttons
+ final int[] actionIds = {R.id.action0, R.id.action1, R.id.action2};
+ for (int i = 0; i < actionIds.length; i++) {
+ ImageButton thisBtn = mMediaNotifView.findViewById(actionIds[i]);
+ if (thisBtn != null) {
+ thisBtn.setVisibility(View.GONE);
+ }
+ }
+
+ // Add a restart button
+ ImageButton btn = mMediaNotifView.findViewById(actionIds[0]);
+ btn.setOnClickListener(v -> {
+ Log.d(TAG, "Attempting to restart session");
+ // Send a media button event to previously found receiver
+ if (mRecvComponent != null) {
+ Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
+ intent.setComponent(mRecvComponent);
+ int keyCode = KeyEvent.KEYCODE_MEDIA_PLAY;
+ intent.putExtra(
+ Intent.EXTRA_KEY_EVENT,
+ new KeyEvent(KeyEvent.ACTION_DOWN, keyCode));
+ mContext.sendBroadcast(intent);
+ } else {
+ Log.d(TAG, "No receiver to restart");
+ // If we don't have a receiver, try relaunching the activity instead
+ try {
+ mController.getSessionActivity().send();
+ } catch (PendingIntent.CanceledException e) {
+ Log.e(TAG, "Pending intent was canceled");
+ e.printStackTrace();
+ }
+ }
+ });
+ btn.setImageDrawable(mContext.getResources().getDrawable(R.drawable.lb_ic_replay));
+ btn.setImageTintList(ColorStateList.valueOf(mForegroundColor));
+ btn.setVisibility(View.VISIBLE);
+ }
+ };
/**
*
@@ -83,34 +141,50 @@
View actionsContainer, int[] actionsToShow) {
Log.d(TAG, "Setting media session: " + token);
mToken = token;
+ mForegroundColor = iconColor;
+ mBackgroundColor = bgColor;
mController = new MediaController(mContext, token);
MediaMetadata mMediaMetadata = mController.getMetadata();
+ // Try to find a receiver for the media button that matches this app
+ PackageManager pm = mContext.getPackageManager();
+ Intent it = new Intent(Intent.ACTION_MEDIA_BUTTON);
+ List<ResolveInfo> info = pm.queryBroadcastReceiversAsUser(it, 0, mContext.getUser());
+ if (info != null) {
+ for (ResolveInfo inf : info) {
+ if (inf.activityInfo.packageName.equals(mController.getPackageName())) {
+ Log.d(TAG, "Found receiver for package: " + inf);
+ mRecvComponent = inf.getComponentInfo().getComponentName();
+ }
+ }
+ }
+ mController.registerCallback(mSessionCallback);
+
if (mMediaMetadata == null) {
Log.e(TAG, "Media metadata was null");
return;
}
// Album art
- addAlbumArtBackground(mMediaMetadata, bgColor);
+ addAlbumArtBackground(mMediaMetadata, mBackgroundColor);
// App icon
ImageView appIcon = mMediaNotifView.findViewById(R.id.icon);
Drawable iconDrawable = icon.loadDrawable(mContext);
- iconDrawable.setTint(iconColor);
+ iconDrawable.setTint(mForegroundColor);
appIcon.setImageDrawable(iconDrawable);
// Artist name
TextView appText = mMediaNotifView.findViewById(R.id.header_title);
String artistName = mMediaMetadata.getString(MediaMetadata.METADATA_KEY_ARTIST);
appText.setText(artistName);
- appText.setTextColor(iconColor);
+ appText.setTextColor(mForegroundColor);
// Song name
TextView titleText = mMediaNotifView.findViewById(R.id.header_text);
String songName = mMediaMetadata.getString(MediaMetadata.METADATA_KEY_TITLE);
titleText.setText(songName);
- titleText.setTextColor(iconColor);
+ titleText.setTextColor(mForegroundColor);
// Buttons we can display
final int[] actionIds = {R.id.action0, R.id.action1, R.id.action2};
@@ -178,6 +252,7 @@
private void addAlbumArtBackground(MediaMetadata metadata, int bgColor) {
Bitmap albumArt = metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
+ float radius = mContext.getResources().getDimension(R.dimen.qs_media_corner_radius);
if (albumArt != null) {
Rect bounds = new Rect();
mMediaNotifView.getBoundsOnScreen(bounds);
@@ -197,12 +272,15 @@
RoundedBitmapDrawable roundedDrawable = RoundedBitmapDrawableFactory.create(
mContext.getResources(), scaled);
- roundedDrawable.setCornerRadius(20);
+ roundedDrawable.setCornerRadius(radius);
mMediaNotifView.setBackground(roundedDrawable);
} else {
Log.e(TAG, "No album art available");
- mMediaNotifView.setBackground(null);
+ GradientDrawable rect = new GradientDrawable();
+ rect.setCornerRadius(radius);
+ rect.setColor(bgColor);
+ mMediaNotifView.setBackground(rect);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java
index 20e3cee..47cb45b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomizeTileView.java
@@ -49,4 +49,9 @@
protected boolean animationsEnabled() {
return false;
}
+
+ @Override
+ public boolean isLongClickable() {
+ return false;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index ff34be0..1de6355 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -32,6 +32,7 @@
import android.widget.Toolbar;
import android.widget.Toolbar.OnMenuItemClickListener;
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@@ -118,7 +119,13 @@
mTileQueryHelper.setListener(mTileAdapter);
mRecyclerView.setAdapter(mTileAdapter);
mTileAdapter.getItemTouchHelper().attachToRecyclerView(mRecyclerView);
- GridLayoutManager layout = new GridLayoutManager(getContext(), 3);
+ GridLayoutManager layout = new GridLayoutManager(getContext(), 3) {
+ @Override
+ public void onInitializeAccessibilityNodeInfoForItem(RecyclerView.Recycler recycler,
+ RecyclerView.State state, View host, AccessibilityNodeInfoCompat info) {
+ // Do not read row and column every time it changes.
+ }
+ };
layout.setSpanSizeLookup(mTileAdapter.getSizeLookup());
mRecyclerView.setLayoutManager(layout);
mRecyclerView.addItemDecoration(mTileAdapter.getItemDecoration());
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index bd3297b..3afc460 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -238,9 +238,21 @@
return true;
}
+ private void setSelectableForHeaders(View view) {
+ if (mAccessibilityManager.isTouchExplorationEnabled()) {
+ final boolean selectable = mAccessibilityAction == ACTION_NONE;
+ view.setFocusable(selectable);
+ view.setImportantForAccessibility(selectable
+ ? View.IMPORTANT_FOR_ACCESSIBILITY_YES
+ : View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
+ view.setFocusableInTouchMode(selectable);
+ }
+ }
+
@Override
public void onBindViewHolder(final Holder holder, int position) {
if (holder.getItemViewType() == TYPE_HEADER) {
+ setSelectableForHeaders(holder.itemView);
return;
}
if (holder.getItemViewType() == TYPE_DIVIDER) {
@@ -260,6 +272,8 @@
}
((TextView) holder.itemView.findViewById(android.R.id.title)).setText(titleText);
+ setSelectableForHeaders(holder.itemView);
+
return;
}
if (holder.getItemViewType() == TYPE_ACCESSIBLE_DROP) {
@@ -306,6 +320,7 @@
holder.mTileView.setImportantForAccessibility(selectable
? View.IMPORTANT_FOR_ACCESSIBILITY_YES
: View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
+ holder.mTileView.setFocusableInTouchMode(selectable);
if (selectable) {
holder.mTileView.setOnClickListener(new OnClickListener() {
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
index dc9a2ce..9fe9703 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UiModeNightTile.java
@@ -22,6 +22,7 @@
import android.provider.Settings;
import android.service.quicksettings.Tile;
import android.text.TextUtils;
+import android.widget.Switch;
import com.android.internal.logging.nano.MetricsProto;
import com.android.systemui.R;
@@ -112,6 +113,7 @@
state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
}
state.showRippleEffect = false;
+ state.expandedAccessibilityClassName = Switch.class.getName();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index 5a5f9e9..9dd7f48 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -174,7 +174,7 @@
if (ops.contains(OP_CAMERA) || ops.contains(OP_RECORD_AUDIO)) {
startAppDetailsSettingsActivity(pkg, uid, null, row);
} else {
- Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
+ Intent intent = new Intent(Settings.ACTION_MANAGE_APP_OVERLAY_PERMISSION);
intent.setData(Uri.fromParts("package", pkg, null));
mNotificationActivityStarter.startNotificationGutsIntent(intent, uid, row);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
index 2a4b315..352ba0f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationMediaTemplateViewWrapper.java
@@ -179,21 +179,22 @@
if (Utils.useQsMediaPlayer(mContext)) {
final int[] compactActions = mRow.getEntry().getSbn().getNotification().extras
.getIntArray(Notification.EXTRA_COMPACT_ACTIONS);
+ int tintColor = getNotificationHeader().getOriginalIconColor();
StatusBarWindowController ctrl = Dependency.get(StatusBarWindowController.class);
QuickQSPanel panel = ctrl.getStatusBarView().findViewById(
com.android.systemui.R.id.quick_qs_panel);
panel.getMediaPlayer().setMediaSession(token,
mRow.getEntry().getSbn().getNotification().getSmallIcon(),
- getNotificationHeader().getOriginalIconColor(),
- mRow.getCurrentBackgroundTint(),
+ tintColor,
+ mBackgroundColor,
mActions,
compactActions);
QSPanel bigPanel = ctrl.getStatusBarView().findViewById(
com.android.systemui.R.id.quick_settings_panel);
bigPanel.addMediaSession(token,
mRow.getEntry().getSbn().getNotification().getSmallIcon(),
- getNotificationHeader().getOriginalIconColor(),
- mRow.getCurrentBackgroundTint(),
+ tintColor,
+ mBackgroundColor,
mActions,
mRow.getEntry().getSbn());
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt b/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt
index ead14e5..2242c1a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/broadcast/BroadcastDispatcherTest.kt
@@ -178,6 +178,14 @@
broadcastDispatcher.registerReceiver(broadcastReceiver, testFilter)
}
+ @Test(expected = IllegalArgumentException::class)
+ fun testFilterMustNotSetPriority() {
+ val testFilter = IntentFilter(TEST_ACTION).apply {
+ priority = IntentFilter.SYSTEM_HIGH_PRIORITY
+ }
+ broadcastDispatcher.registerReceiver(broadcastReceiver, testFilter)
+ }
+
private class TestBroadcastDispatcher(
context: Context,
mainHandler: Handler,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
index ba28879..27e3a66 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterTest.java
@@ -64,6 +64,7 @@
@SmallTest
@RunWith(AndroidTestingRunner.class)
@RunWithLooper(setAsMainLooper = true)
+@Ignore
public class NotificationContentInflaterTest extends SysuiTestCase {
private NotificationContentInflater mNotificationInflater;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
index 4b3249d..43d39a2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
@@ -274,7 +274,7 @@
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
verify(mNotificationActivityStarter, times(1))
.startNotificationGutsIntent(captor.capture(), anyInt(), any());
- assertEquals(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, captor.getValue().getAction());
+ assertEquals(Settings.ACTION_MANAGE_APP_OVERLAY_PERMISSION, captor.getValue().getAction());
}
@Test
diff --git a/packages/VpnDialogs/AndroidManifest.xml b/packages/VpnDialogs/AndroidManifest.xml
index 469bdc6..e4de625 100644
--- a/packages/VpnDialogs/AndroidManifest.xml
+++ b/packages/VpnDialogs/AndroidManifest.xml
@@ -21,7 +21,6 @@
<uses-permission android:name="android.permission.CONTROL_VPN" />
<uses-permission android:name="android.permission.CONTROL_ALWAYS_ON_VPN" />
- <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
<uses-permission android:name="android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS"/>
<application android:label="VpnDialogs"
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index a3a6172..0ad275f 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1395,7 +1395,7 @@
@Override
public Network getActiveNetworkForUid(int uid, boolean ignoreBlocked) {
- enforceConnectivityInternalPermission();
+ NetworkStack.checkNetworkStackPermission(mContext);
return getActiveNetworkForUidInternal(uid, ignoreBlocked);
}
@@ -1437,7 +1437,7 @@
@Override
public NetworkInfo getActiveNetworkInfoForUid(int uid, boolean ignoreBlocked) {
- enforceConnectivityInternalPermission();
+ NetworkStack.checkNetworkStackPermission(mContext);
final NetworkState state = getUnfilteredActiveNetworkState(uid);
filterNetworkStateForUid(state, uid, ignoreBlocked);
return state.networkInfo;
@@ -1656,8 +1656,8 @@
@Override
public NetworkState[] getAllNetworkState() {
- // Require internal since we're handing out IMSI details
- enforceConnectivityInternalPermission();
+ // This contains IMSI details, so make sure the caller is privileged.
+ NetworkStack.checkNetworkStackPermission(mContext);
final ArrayList<NetworkState> result = Lists.newArrayList();
for (Network network : getAllNetworks()) {
@@ -1735,7 +1735,7 @@
}
enforceChangePermission();
if (mProtectedNetworks.contains(networkType)) {
- enforceConnectivityInternalPermission();
+ enforceConnectivityRestrictedNetworksPermission();
}
InetAddress addr;
@@ -2005,6 +2005,12 @@
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
}
+ private void enforceNetworkFactoryPermission() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.NETWORK_FACTORY,
+ "ConnectivityService");
+ }
+
private boolean checkSettingsPermission() {
return checkAnyPermissionOf(
android.Manifest.permission.NETWORK_SETTINGS,
@@ -2024,18 +2030,19 @@
"ConnectivityService");
}
- private void enforceConnectivityInternalPermission() {
- enforceAnyPermissionOf(
- android.Manifest.permission.CONNECTIVITY_INTERNAL,
- NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
- }
-
private void enforceControlAlwaysOnVpnPermission() {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.CONTROL_ALWAYS_ON_VPN,
"ConnectivityService");
}
+ private void enforceNetworkStackOrSettingsPermission() {
+ enforceAnyPermissionOf(
+ android.Manifest.permission.NETWORK_SETTINGS,
+ android.Manifest.permission.NETWORK_STACK,
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
+ }
+
private void enforceNetworkStackSettingsOrSetup() {
enforceAnyPermissionOf(
android.Manifest.permission.NETWORK_SETTINGS,
@@ -2063,7 +2070,11 @@
"ConnectivityService");
return;
} catch (SecurityException e) { /* fallback to ConnectivityInternalPermission */ }
- enforceConnectivityInternalPermission();
+ // TODO: Remove this fallback check after all apps have declared
+ // CONNECTIVITY_USE_RESTRICTED_NETWORKS.
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CONNECTIVITY_INTERNAL,
+ "ConnectivityService");
}
private void enforceKeepalivePermission() {
@@ -2072,7 +2083,7 @@
// Public because it's used by mLockdownTracker.
public void sendConnectedBroadcast(NetworkInfo info) {
- enforceConnectivityInternalPermission();
+ NetworkStack.checkNetworkStackPermission(mContext);
sendGeneralBroadcast(info, CONNECTIVITY_ACTION);
}
@@ -3589,7 +3600,7 @@
@Override
public void startCaptivePortalApp(Network network) {
- enforceConnectivityInternalPermission();
+ enforceNetworkStackOrSettingsPermission();
mHandler.post(() -> {
NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
if (nai == null) return;
@@ -4080,7 +4091,7 @@
@Override
public String[] getTetheredDhcpRanges() {
- enforceConnectivityInternalPermission();
+ enforceSettingsPermission();
return mTetheringManager.getTetheredDhcpRanges();
}
@@ -4304,7 +4315,7 @@
@Override
public void setGlobalProxy(final ProxyInfo proxyProperties) {
- enforceConnectivityInternalPermission();
+ NetworkStack.checkNetworkStackPermission(mContext);
mProxyTracker.setGlobalProxy(proxyProperties);
}
@@ -4843,7 +4854,7 @@
@Override
public String getMobileProvisioningUrl() {
- enforceConnectivityInternalPermission();
+ enforceSettingsPermission();
String url = getProvisioningUrlBaseFromFile();
if (TextUtils.isEmpty(url)) {
url = mContext.getResources().getString(R.string.mobile_provisioning_url);
@@ -4869,7 +4880,7 @@
@Override
public void setProvisioningNotificationVisible(boolean visible, int networkType,
String action) {
- enforceConnectivityInternalPermission();
+ enforceSettingsPermission();
if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
return;
}
@@ -5457,7 +5468,7 @@
@Override
public int registerNetworkFactory(Messenger messenger, String name) {
- enforceConnectivityInternalPermission();
+ enforceNetworkFactoryPermission();
NetworkFactoryInfo nfi = new NetworkFactoryInfo(name, messenger, new AsyncChannel(),
NetworkFactory.SerialNumber.nextSerialNumber());
mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_FACTORY, nfi));
@@ -5472,7 +5483,7 @@
@Override
public void unregisterNetworkFactory(Messenger messenger) {
- enforceConnectivityInternalPermission();
+ enforceNetworkFactoryPermission();
mHandler.sendMessage(mHandler.obtainMessage(EVENT_UNREGISTER_NETWORK_FACTORY, messenger));
}
@@ -5571,7 +5582,7 @@
public int registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,
LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
int currentScore, NetworkMisc networkMisc, int factorySerialNumber) {
- enforceConnectivityInternalPermission();
+ enforceNetworkFactoryPermission();
LinkProperties lp = new LinkProperties(linkProperties);
lp.ensureDirectlyConnectedRoutes();
@@ -6955,7 +6966,7 @@
@Override
public String getCaptivePortalServerUrl() {
- enforceConnectivityInternalPermission();
+ enforceNetworkStackOrSettingsPermission();
String settingUrl = mContext.getResources().getString(
R.string.config_networkCaptivePortalServerUrl);
@@ -7008,7 +7019,7 @@
@Override
public void factoryReset() {
- enforceConnectivityInternalPermission();
+ enforceSettingsPermission();
if (mUserManager.hasUserRestriction(UserManager.DISALLOW_NETWORK_RESET)) {
return;
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 5f562cf..f3089c1 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -294,9 +294,8 @@
AppOpsManager.WATCH_FOREGROUND_CHANGES,
new AppOpsManager.OnOpChangedInternalListener() {
public void onOpChanged(int op, String packageName) {
- // onOpChanged invoked on ui thread, move to our thread to reduce
- // risk of
- // blocking ui thread
+ // onOpChanged invoked on ui thread, move to our thread to reduce risk
+ // of blocking ui thread
mHandler.post(() -> {
synchronized (mLock) {
onAppOpChangedLocked();
@@ -307,8 +306,7 @@
mPackageManager.addOnPermissionsChangeListener(
uid -> {
// listener invoked on ui thread, move to our thread to reduce risk of
- // blocking
- // ui thread
+ // blocking ui thread
mHandler.post(() -> {
synchronized (mLock) {
onPermissionsChangedLocked();
@@ -318,8 +316,7 @@
mActivityManager.addOnUidImportanceListener(
(uid, importance) -> {
// listener invoked on ui thread, move to our thread to reduce risk of
- // blocking
- // ui thread
+ // blocking ui thread
mHandler.post(() -> {
synchronized (mLock) {
onUidImportanceChangedLocked(uid, importance);
@@ -331,8 +328,7 @@
localPowerManager.registerLowPowerModeObserver(ServiceType.LOCATION,
state -> {
// listener invoked on ui thread, move to our thread to reduce risk of
- // blocking
- // ui thread
+ // blocking ui thread
mHandler.post(() -> {
synchronized (mLock) {
onBatterySaverModeChangedLocked(state.locationMode);
@@ -341,14 +337,14 @@
});
mBatterySaverMode = mPowerManager.getLocationPowerSaveMode();
- mSettingsStore.addOnLocationEnabledChangedListener(() -> {
+ mSettingsStore.addOnLocationEnabledChangedListener((userId) -> {
synchronized (mLock) {
- onLocationModeChangedLocked(true);
+ onLocationModeChangedLocked(userId, true);
}
});
- mSettingsStore.addOnLocationProvidersAllowedChangedListener(() -> {
+ mSettingsStore.addOnLocationProvidersAllowedChangedListener((userId) -> {
synchronized (mLock) {
- onProviderAllowedChangedLocked();
+ onProviderAllowedChangedLocked(userId);
}
});
mSettingsStore.addOnBackgroundThrottleIntervalChangedListener(() -> {
@@ -471,7 +467,11 @@
}
@GuardedBy("mLock")
- private void onLocationModeChangedLocked(boolean broadcast) {
+ private void onLocationModeChangedLocked(int userId, boolean broadcast) {
+ if (!isCurrentProfileLocked(userId)) {
+ return;
+ }
+
if (D) {
Log.d(TAG, "location enabled is now " + isLocationEnabled());
}
@@ -490,7 +490,11 @@
}
@GuardedBy("mLock")
- private void onProviderAllowedChangedLocked() {
+ private void onProviderAllowedChangedLocked(int userId) {
+ if (!isCurrentProfileLocked(userId)) {
+ return;
+ }
+
for (LocationProvider p : mProviders) {
p.onAllowedChangedLocked();
}
@@ -803,8 +807,8 @@
onUserProfilesChangedLocked();
// if the user changes, per-user settings may also have changed
- onLocationModeChangedLocked(false);
- onProviderAllowedChangedLocked();
+ onLocationModeChangedLocked(userId, false);
+ onProviderAllowedChangedLocked(userId);
// always force useability to be rechecked, even if no per-user settings have changed
for (LocationProvider p : mProviders) {
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 9efaad8..e79a289 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -16,9 +16,8 @@
package com.android.server;
-import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
import static android.Manifest.permission.NETWORK_SETTINGS;
-import static android.Manifest.permission.NETWORK_STACK;
+import static android.Manifest.permission.OBSERVE_NETWORK_POLICY;
import static android.Manifest.permission.SHUTDOWN;
import static android.net.INetd.FIREWALL_BLACKLIST;
import static android.net.INetd.FIREWALL_CHAIN_DOZABLE;
@@ -54,6 +53,7 @@
import android.net.LinkAddress;
import android.net.Network;
import android.net.NetworkPolicyManager;
+import android.net.NetworkStack;
import android.net.NetworkStats;
import android.net.NetworkUtils;
import android.net.RouteInfo;
@@ -312,13 +312,13 @@
@Override
public void registerObserver(INetworkManagementEventObserver observer) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
mObservers.register(observer);
}
@Override
public void unregisterObserver(INetworkManagementEventObserver observer) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
mObservers.unregister(observer);
}
@@ -453,7 +453,7 @@
@Override
public void registerTetheringStatsProvider(ITetheringStatsProvider provider, String name) {
- mContext.enforceCallingOrSelfPermission(NETWORK_STACK, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
Preconditions.checkNotNull(provider);
synchronized(mTetheringStatsProviders) {
mTetheringStatsProviders.put(provider, name);
@@ -462,7 +462,7 @@
@Override
public void unregisterTetheringStatsProvider(ITetheringStatsProvider provider) {
- mContext.enforceCallingOrSelfPermission(NETWORK_STACK, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
synchronized(mTetheringStatsProviders) {
mTetheringStatsProviders.remove(provider);
}
@@ -470,7 +470,7 @@
@Override
public void tetherLimitReached(ITetheringStatsProvider provider) {
- mContext.enforceCallingOrSelfPermission(NETWORK_STACK, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
synchronized(mTetheringStatsProviders) {
if (!mTetheringStatsProviders.containsKey(provider)) {
return;
@@ -737,7 +737,7 @@
//
@Override
public String[] listInterfaces() {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
try {
return mNetdService.interfaceGetList();
} catch (RemoteException | ServiceSpecificException e) {
@@ -787,7 +787,7 @@
@Override
public InterfaceConfiguration getInterfaceConfig(String iface) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
final InterfaceConfigurationParcel result;
try {
result = mNetdService.interfaceGetCfg(iface);
@@ -805,7 +805,7 @@
@Override
public void setInterfaceConfig(String iface, InterfaceConfiguration cfg) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
LinkAddress linkAddr = cfg.getLinkAddress();
if (linkAddr == null || linkAddr.getAddress() == null) {
throw new IllegalStateException("Null LinkAddress given");
@@ -822,7 +822,7 @@
@Override
public void setInterfaceDown(String iface) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
final InterfaceConfiguration ifcg = getInterfaceConfig(iface);
ifcg.setInterfaceDown();
setInterfaceConfig(iface, ifcg);
@@ -830,7 +830,7 @@
@Override
public void setInterfaceUp(String iface) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
final InterfaceConfiguration ifcg = getInterfaceConfig(iface);
ifcg.setInterfaceUp();
setInterfaceConfig(iface, ifcg);
@@ -838,7 +838,7 @@
@Override
public void setInterfaceIpv6PrivacyExtensions(String iface, boolean enable) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
try {
mNetdService.interfaceSetIPv6PrivacyExtensions(iface, enable);
} catch (RemoteException | ServiceSpecificException e) {
@@ -850,7 +850,7 @@
IPv6 addresses on interface down, but we need to do full clean up here */
@Override
public void clearInterfaceAddresses(String iface) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
try {
mNetdService.interfaceClearAddrs(iface);
} catch (RemoteException | ServiceSpecificException e) {
@@ -860,7 +860,7 @@
@Override
public void enableIpv6(String iface) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
try {
mNetdService.interfaceSetEnableIPv6(iface, true);
} catch (RemoteException | ServiceSpecificException e) {
@@ -879,7 +879,7 @@
@Override
public void disableIpv6(String iface) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
try {
mNetdService.interfaceSetEnableIPv6(iface, false);
} catch (RemoteException | ServiceSpecificException e) {
@@ -898,7 +898,7 @@
}
private void modifyRoute(boolean add, int netId, RouteInfo route) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
final String ifName = route.getInterface();
final String dst = route.getDestination().toString();
@@ -963,7 +963,7 @@
@Override
public void setMtu(String iface, int mtu) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
try {
mNetdService.interfaceSetMtu(iface, mtu);
@@ -982,7 +982,7 @@
@Override
public boolean getIpForwardingEnabled() throws IllegalStateException{
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
try {
final boolean isEnabled = mNetdService.ipfwdEnabled();
@@ -994,7 +994,7 @@
@Override
public void setIpForwardingEnabled(boolean enable) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
try {
if (enable) {
mNetdService.ipfwdEnableForwarding("tethering");
@@ -1013,7 +1013,7 @@
@Override
public void startTetheringWithConfiguration(boolean usingLegacyDnsProxy, String[] dhcpRange) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
// an odd number of addrs will fail
try {
mNetdService.tetherStartWithConfiguration(usingLegacyDnsProxy, dhcpRange);
@@ -1024,7 +1024,7 @@
@Override
public void stopTethering() {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
try {
mNetdService.tetherStop();
} catch (RemoteException | ServiceSpecificException e) {
@@ -1034,7 +1034,7 @@
@Override
public boolean isTetheringStarted() {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
try {
final boolean isEnabled = mNetdService.tetherIsEnabled();
@@ -1046,7 +1046,7 @@
@Override
public void tetherInterface(String iface) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
try {
mNetdService.tetherInterfaceAdd(iface);
} catch (RemoteException | ServiceSpecificException e) {
@@ -1061,7 +1061,7 @@
@Override
public void untetherInterface(String iface) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
try {
mNetdService.tetherInterfaceRemove(iface);
} catch (RemoteException | ServiceSpecificException e) {
@@ -1073,7 +1073,7 @@
@Override
public String[] listTetheredInterfaces() {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
try {
return mNetdService.tetherInterfaceList();
} catch (RemoteException | ServiceSpecificException e) {
@@ -1083,7 +1083,7 @@
@Override
public void setDnsForwarders(Network network, String[] dns) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
int netId = (network != null) ? network.netId : ConnectivityManager.NETID_UNSET;
@@ -1096,7 +1096,7 @@
@Override
public String[] getDnsForwarders() {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
try {
return mNetdService.tetherDnsList();
} catch (RemoteException | ServiceSpecificException e) {
@@ -1127,19 +1127,19 @@
@Override
public void startInterfaceForwarding(String fromIface, String toIface) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
modifyInterfaceForward(true, fromIface, toIface);
}
@Override
public void stopInterfaceForwarding(String fromIface, String toIface) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
modifyInterfaceForward(false, fromIface, toIface);
}
@Override
public void enableNat(String internalInterface, String externalInterface) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
try {
mNetdService.tetherAddForward(internalInterface, externalInterface);
} catch (RemoteException | ServiceSpecificException e) {
@@ -1149,7 +1149,7 @@
@Override
public void disableNat(String internalInterface, String externalInterface) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
try {
mNetdService.tetherRemoveForward(internalInterface, externalInterface);
} catch (RemoteException | ServiceSpecificException e) {
@@ -1159,7 +1159,7 @@
@Override
public void addIdleTimer(String iface, int timeout, final int type) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
if (DBG) Slog.d(TAG, "Adding idletimer");
@@ -1189,7 +1189,7 @@
@Override
public void removeIdleTimer(String iface) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
if (DBG) Slog.d(TAG, "Removing idletimer");
@@ -1213,7 +1213,7 @@
@Override
public void setInterfaceQuota(String iface, long quotaBytes) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
synchronized (mQuotaLock) {
if (mActiveQuotas.containsKey(iface)) {
@@ -1244,7 +1244,7 @@
@Override
public void removeInterfaceQuota(String iface) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
synchronized (mQuotaLock) {
if (!mActiveQuotas.containsKey(iface)) {
@@ -1277,7 +1277,7 @@
@Override
public void setInterfaceAlert(String iface, long alertBytes) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
// quick sanity check
if (!mActiveQuotas.containsKey(iface)) {
@@ -1301,7 +1301,7 @@
@Override
public void removeInterfaceAlert(String iface) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
synchronized (mQuotaLock) {
if (!mActiveAlerts.containsKey(iface)) {
@@ -1321,7 +1321,7 @@
@Override
public void setGlobalAlert(long alertBytes) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
try {
mNetdService.bandwidthSetGlobalAlert(alertBytes);
@@ -1331,7 +1331,7 @@
}
private void setUidOnMeteredNetworkList(int uid, boolean blacklist, boolean enable) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
synchronized (mQuotaLock) {
boolean oldEnable;
@@ -1431,7 +1431,7 @@
@Override
public void setAllowOnlyVpnForUids(boolean add, UidRange[] uidRanges)
throws ServiceSpecificException {
- mContext.enforceCallingOrSelfPermission(NETWORK_STACK, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
try {
mNetdService.networkRejectNonSecureVpn(add, toStableParcels(uidRanges));
} catch (ServiceSpecificException e) {
@@ -1472,7 +1472,7 @@
@Override
public void setUidCleartextNetworkPolicy(int uid, int policy) {
if (Binder.getCallingUid() != uid) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
}
synchronized (mQuotaLock) {
@@ -1506,7 +1506,6 @@
@Override
public boolean isBandwidthControlEnabled() {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
return true;
}
@@ -1557,7 +1556,7 @@
@Override
public NetworkStats getNetworkStatsTethering(int how) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1);
synchronized (mTetheringStatsProviders) {
@@ -1575,7 +1574,7 @@
@Override
public void addVpnUidRanges(int netId, UidRange[] ranges) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
try {
mNetdService.networkAddUidRanges(netId, toStableParcels(ranges));
@@ -1586,7 +1585,7 @@
@Override
public void removeVpnUidRanges(int netId, UidRange[] ranges) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
try {
mNetdService.networkRemoveUidRanges(netId, toStableParcels(ranges));
} catch (RemoteException | ServiceSpecificException e) {
@@ -2020,7 +2019,7 @@
}
private void modifyInterfaceInNetwork(boolean add, int netId, String iface) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
try {
if (add) {
mNetdService.networkAddInterface(netId, iface);
@@ -2034,7 +2033,7 @@
@Override
public void addLegacyRouteForNetId(int netId, RouteInfo routeInfo, int uid) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
final LinkAddress la = routeInfo.getDestinationLinkAddress();
final String ifName = routeInfo.getInterface();
@@ -2055,7 +2054,7 @@
@Override
public void setDefaultNetId(int netId) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
try {
mNetdService.networkSetDefault(netId);
@@ -2066,7 +2065,7 @@
@Override
public void clearDefaultNetId() {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
try {
mNetdService.networkClearDefault();
@@ -2077,7 +2076,7 @@
@Override
public void setNetworkPermission(int netId, int permission) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
try {
mNetdService.networkSetPermissionForNetwork(netId, permission);
@@ -2088,7 +2087,7 @@
@Override
public void allowProtect(int uid) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
try {
mNetdService.networkSetProtectAllow(uid);
@@ -2099,7 +2098,7 @@
@Override
public void denyProtect(int uid) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
try {
mNetdService.networkSetProtectDeny(uid);
@@ -2145,7 +2144,7 @@
@Override
public boolean isNetworkRestricted(int uid) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ mContext.enforceCallingOrSelfPermission(OBSERVE_NETWORK_POLICY, TAG);
return isNetworkRestrictedInternal(uid);
}
diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java
index 3efef01..b9b7bf7 100644
--- a/services/core/java/com/android/server/NsdService.java
+++ b/services/core/java/com/android/server/NsdService.java
@@ -16,19 +16,18 @@
package com.android.server;
-import android.content.Context;
import android.content.ContentResolver;
+import android.content.Context;
import android.content.Intent;
-import android.content.pm.PackageManager;
import android.database.ContentObserver;
+import android.net.NetworkStack;
import android.net.Uri;
-import android.net.nsd.NsdServiceInfo;
import android.net.nsd.DnsSdTxtRecord;
import android.net.nsd.INsdManager;
import android.net.nsd.NsdManager;
-import android.os.Binder;
-import android.os.HandlerThread;
+import android.net.nsd.NsdServiceInfo;
import android.os.Handler;
+import android.os.HandlerThread;
import android.os.Message;
import android.os.Messenger;
import android.os.UserHandle;
@@ -38,6 +37,12 @@
import android.util.SparseArray;
import android.util.SparseIntArray;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.AsyncChannel;
+import com.android.internal.util.DumpUtils;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.net.InetAddress;
@@ -45,13 +50,6 @@
import java.util.HashMap;
import java.util.concurrent.CountDownLatch;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.AsyncChannel;
-import com.android.internal.util.DumpUtils;
-import com.android.internal.util.Protocol;
-import com.android.internal.util.State;
-import com.android.internal.util.StateMachine;
-
/**
* Network Service Discovery Service handles remote service discovery operation requests by
* implementing the INsdManager interface.
@@ -565,8 +563,7 @@
}
public void setEnabled(boolean isEnabled) {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL,
- "NsdService");
+ NetworkStack.checkNetworkStackPermission(mContext);
mNsdSettings.putEnabledStatus(isEnabled);
notifyEnabled(isEnabled);
}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 9d1eb6c..d4889ea 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -355,8 +355,7 @@
@GuardedBy("mLock")
private String mMoveTargetUuid;
- @Nullable
- private volatile String mMediaStoreAuthorityPackageName = null;
+ private volatile int mMediaStoreAuthorityAppId = -1;
private volatile int mCurrentUserId = UserHandle.USER_SYSTEM;
@@ -1725,7 +1724,7 @@
| PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
UserHandle.getUserId(UserHandle.USER_SYSTEM));
if (provider != null) {
- mMediaStoreAuthorityPackageName = provider.packageName;
+ mMediaStoreAuthorityAppId = UserHandle.getAppId(provider.applicationInfo.uid);
}
try {
@@ -3752,8 +3751,10 @@
return Zygote.MOUNT_EXTERNAL_NONE;
}
- if (mIsFuseEnabled && packageName.equals(mMediaStoreAuthorityPackageName)) {
- // Determine if caller requires pass_through mount
+ if (mIsFuseEnabled && mMediaStoreAuthorityAppId == UserHandle.getAppId(uid)) {
+ // Determine if caller requires pass_through mount; note that we do this for
+ // all processes that share a UID with MediaProvider; but this is fine, since
+ // those processes anyway share the same rights as MediaProvider.
return Zygote.MOUNT_EXTERNAL_PASS_THROUGH;
}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index dc61261..24cd21e 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -38,6 +38,7 @@
import android.os.Message;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.telephony.Annotation;
import android.telephony.Annotation.DataFailureCause;
import android.telephony.Annotation.RadioPowerState;
import android.telephony.Annotation.SrvccState;
@@ -1576,8 +1577,8 @@
&& (mDataConnectionState[phoneId] != state
|| mDataConnectionNetworkType[phoneId] != networkType)) {
String str = "onDataConnectionStateChanged("
- + TelephonyManager.dataStateToString(state)
- + ", " + TelephonyManager.getNetworkTypeName(networkType)
+ + dataStateToString(state)
+ + ", " + getNetworkTypeName(networkType)
+ ") subId=" + subId + ", phoneId=" + phoneId;
log(str);
mLocalLog.log(str);
@@ -2689,4 +2690,74 @@
}
}
}
+
+ /**
+ * Convert data state to string
+ *
+ * @return The data state in string format.
+ */
+ private String dataStateToString(@TelephonyManager.DataState int state) {
+ switch (state) {
+ case TelephonyManager.DATA_DISCONNECTED: return "DISCONNECTED";
+ case TelephonyManager.DATA_CONNECTING: return "CONNECTING";
+ case TelephonyManager.DATA_CONNECTED: return "CONNECTED";
+ case TelephonyManager.DATA_SUSPENDED: return "SUSPENDED";
+ }
+ return "UNKNOWN(" + state + ")";
+ }
+
+ /**
+ * Returns a string representation of the radio technology (network type)
+ * currently in use on the device.
+ * @param subId for which network type is returned
+ * @return the name of the radio technology
+ *
+ */
+ private String getNetworkTypeName(@Annotation.NetworkType int type) {
+ switch (type) {
+ case TelephonyManager.NETWORK_TYPE_GPRS:
+ return "GPRS";
+ case TelephonyManager.NETWORK_TYPE_EDGE:
+ return "EDGE";
+ case TelephonyManager.NETWORK_TYPE_UMTS:
+ return "UMTS";
+ case TelephonyManager.NETWORK_TYPE_HSDPA:
+ return "HSDPA";
+ case TelephonyManager.NETWORK_TYPE_HSUPA:
+ return "HSUPA";
+ case TelephonyManager.NETWORK_TYPE_HSPA:
+ return "HSPA";
+ case TelephonyManager.NETWORK_TYPE_CDMA:
+ return "CDMA";
+ case TelephonyManager.NETWORK_TYPE_EVDO_0:
+ return "CDMA - EvDo rev. 0";
+ case TelephonyManager.NETWORK_TYPE_EVDO_A:
+ return "CDMA - EvDo rev. A";
+ case TelephonyManager.NETWORK_TYPE_EVDO_B:
+ return "CDMA - EvDo rev. B";
+ case TelephonyManager.NETWORK_TYPE_1xRTT:
+ return "CDMA - 1xRTT";
+ case TelephonyManager.NETWORK_TYPE_LTE:
+ return "LTE";
+ case TelephonyManager.NETWORK_TYPE_EHRPD:
+ return "CDMA - eHRPD";
+ case TelephonyManager.NETWORK_TYPE_IDEN:
+ return "iDEN";
+ case TelephonyManager.NETWORK_TYPE_HSPAP:
+ return "HSPA+";
+ case TelephonyManager.NETWORK_TYPE_GSM:
+ return "GSM";
+ case TelephonyManager.NETWORK_TYPE_TD_SCDMA:
+ return "TD_SCDMA";
+ case TelephonyManager.NETWORK_TYPE_IWLAN:
+ return "IWLAN";
+ case TelephonyManager.NETWORK_TYPE_LTE_CA:
+ return "LTE_CA";
+ case TelephonyManager.NETWORK_TYPE_NR:
+ return "NR";
+ default:
+ return "UNKNOWN";
+ }
+ }
+
}
diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
index 79b56c6..33f6ed5 100644
--- a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
+++ b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
@@ -20,6 +20,7 @@
import android.net.ConnectivityMetricsEvent;
import android.net.IIpConnectivityMetrics;
import android.net.INetdEventCallback;
+import android.net.NetworkStack;
import android.net.metrics.ApfProgramEvent;
import android.net.metrics.IpConnectivityLog;
import android.os.Binder;
@@ -276,7 +277,7 @@
@Override
public int logEvent(ConnectivityMetricsEvent event) {
- enforceConnectivityInternalPermission();
+ NetworkStack.checkNetworkStackPermission(getContext());
return append(event);
}
@@ -299,10 +300,6 @@
}
}
- private void enforceConnectivityInternalPermission() {
- enforcePermission(android.Manifest.permission.CONNECTIVITY_INTERNAL);
- }
-
private void enforceDumpPermission() {
enforcePermission(android.Manifest.permission.DUMP);
}
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index 56f4959..f0b7150 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -17,7 +17,6 @@
package com.android.server.connectivity;
import static android.Manifest.permission.CHANGE_NETWORK_STATE;
-import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
import static android.Manifest.permission.INTERNET;
import static android.Manifest.permission.NETWORK_STACK;
@@ -25,6 +24,7 @@
import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
+import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
import static android.os.Process.INVALID_UID;
import static android.os.Process.SYSTEM_UID;
@@ -259,7 +259,8 @@
return true;
}
}
- return hasPermission(app, CONNECTIVITY_INTERNAL)
+
+ return hasPermission(app, PERMISSION_MAINLINE_NETWORK_STACK)
|| hasPermission(app, NETWORK_STACK)
|| hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS);
}
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index c466640..d20191d 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -431,7 +431,7 @@
recordTopInsetLocked(mLogicalDisplays.get(Display.DEFAULT_DISPLAY));
}
- mDisplayModeDirector.setListener(new AllowedDisplayModeObserver());
+ mDisplayModeDirector.setDisplayModeListener(new AllowedDisplayModeObserver());
mDisplayModeDirector.start(mSensorManager);
mHandler.sendEmptyMessage(MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS);
@@ -2488,7 +2488,7 @@
}
- class AllowedDisplayModeObserver implements DisplayModeDirector.Listener {
+ class AllowedDisplayModeObserver implements DisplayModeDirector.DisplayModeListener {
public void onAllowedDisplayModesChanged() {
onAllowedDisplayModesChangedInternal();
}
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index 6118df5..2df682f 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -95,7 +95,7 @@
private final BrightnessObserver mBrightnessObserver;
private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings;
- private Listener mListener;
+ private DisplayModeListener mDisplayModeListener;
public DisplayModeDirector(@NonNull Context context, @NonNull Handler handler) {
mContext = context;
@@ -311,11 +311,11 @@
}
/**
- * Sets the listener for changes to allowed display modes.
+ * Sets the modeListener for changes to allowed display modes.
*/
- public void setListener(@Nullable Listener listener) {
+ public void setDisplayModeListener(@Nullable DisplayModeListener displayModeListener) {
synchronized (mLock) {
- mListener = listener;
+ mDisplayModeListener = displayModeListener;
}
}
@@ -393,12 +393,12 @@
}
private void notifyAllowedModesChangedLocked() {
- if (mListener != null && !mHandler.hasMessages(MSG_ALLOWED_MODES_CHANGED)) {
+ if (mDisplayModeListener != null && !mHandler.hasMessages(MSG_ALLOWED_MODES_CHANGED)) {
// We need to post this to a handler to avoid calling out while holding the lock
// since we know there are things that both listen for changes as well as provide
// information. If we did call out while holding the lock, then there's no guaranteed
// lock order and we run the real of risk deadlock.
- Message msg = mHandler.obtainMessage(MSG_ALLOWED_MODES_CHANGED, mListener);
+ Message msg = mHandler.obtainMessage(MSG_ALLOWED_MODES_CHANGED, mDisplayModeListener);
msg.sendToTarget();
}
}
@@ -432,7 +432,7 @@
/**
* Listens for changes to display mode coordination.
*/
- public interface Listener {
+ public interface DisplayModeListener {
/**
* Called when the allowed display modes may have changed.
*/
@@ -448,8 +448,8 @@
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_ALLOWED_MODES_CHANGED:
- Listener listener = (Listener) msg.obj;
- listener.onAllowedDisplayModesChanged();
+ DisplayModeListener displayModeListener = (DisplayModeListener) msg.obj;
+ displayModeListener.onAllowedDisplayModesChanged();
break;
case MSG_BRIGHTNESS_THRESHOLDS_CHANGED:
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 1586473..c4ea81a 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -693,8 +693,9 @@
}
final IBinder token = getDisplayTokenLocked();
- SurfaceControl.setDesiredDisplayConfigSpecs(token, defaultModeId, minRefreshRate,
- maxRefreshRate);
+ SurfaceControl.setDesiredDisplayConfigSpecs(token,
+ new SurfaceControl.DesiredDisplayConfigSpecs(
+ defaultModeId, minRefreshRate, maxRefreshRate));
int activePhysIndex = SurfaceControl.getActiveConfig(token);
return updateActiveModeLocked(activePhysIndex);
}
diff --git a/services/core/java/com/android/server/location/LocationSettingsStore.java b/services/core/java/com/android/server/location/LocationSettingsStore.java
index dc5628e..eb2a37b 100644
--- a/services/core/java/com/android/server/location/LocationSettingsStore.java
+++ b/services/core/java/com/android/server/location/LocationSettingsStore.java
@@ -33,21 +33,51 @@
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
+import android.util.ArraySet;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.Preconditions;
+import com.android.server.SystemConfig;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.function.Supplier;
/**
* Provides accessors and listeners for all location related settings.
*/
public class LocationSettingsStore {
+ /**
+ * Listener for user-specific settings changes.
+ */
+ public interface UserSettingChangedListener {
+ /**
+ * Called when setting changes.
+ */
+ void onSettingChanged(int userId);
+ }
+
+ /**
+ * Listener for global settings changes.
+ */
+ public interface GlobalSettingChangedListener extends UserSettingChangedListener {
+ /**
+ * Called when setting changes.
+ */
+ void onSettingChanged();
+
+ @Override
+ default void onSettingChanged(int userId) {
+ onSettingChanged();
+ }
+ }
+
private static final String LOCATION_PACKAGE_BLACKLIST = "locationPackagePrefixBlacklist";
private static final String LOCATION_PACKAGE_WHITELIST = "locationPackagePrefixWhitelist";
@@ -63,9 +93,10 @@
private final LongGlobalSetting mBackgroundThrottleIntervalMs;
private final StringListCachedSecureSetting mLocationPackageBlacklist;
private final StringListCachedSecureSetting mLocationPackageWhitelist;
- private final StringListCachedGlobalSetting mBackgroundThrottlePackageWhitelist;
- private final StringListCachedGlobalSetting mIgnoreSettingsPackageWhitelist;
+ private final StringSetCachedGlobalSetting mBackgroundThrottlePackageWhitelist;
+ private final StringSetCachedGlobalSetting mIgnoreSettingsPackageWhitelist;
+ // TODO: get rid of handler
public LocationSettingsStore(Context context, Handler handler) {
mContext = context;
@@ -78,10 +109,12 @@
LOCATION_PACKAGE_BLACKLIST, handler);
mLocationPackageWhitelist = new StringListCachedSecureSetting(context,
LOCATION_PACKAGE_WHITELIST, handler);
- mBackgroundThrottlePackageWhitelist = new StringListCachedGlobalSetting(context,
- LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST, handler);
- mIgnoreSettingsPackageWhitelist = new StringListCachedGlobalSetting(context,
- LOCATION_IGNORE_SETTINGS_PACKAGE_WHITELIST, handler);
+ mBackgroundThrottlePackageWhitelist = new StringSetCachedGlobalSetting(context,
+ LOCATION_BACKGROUND_THROTTLE_PACKAGE_WHITELIST,
+ () -> SystemConfig.getInstance().getAllowUnthrottledLocation(), handler);
+ mIgnoreSettingsPackageWhitelist = new StringSetCachedGlobalSetting(context,
+ LOCATION_IGNORE_SETTINGS_PACKAGE_WHITELIST,
+ () -> SystemConfig.getInstance().getAllowIgnoreLocationSettings(), handler);
}
/**
@@ -94,14 +127,14 @@
/**
* Add a listener for changes to the location enabled setting.
*/
- public void addOnLocationEnabledChangedListener(Runnable listener) {
+ public void addOnLocationEnabledChangedListener(UserSettingChangedListener listener) {
mLocationMode.addListener(listener);
}
/**
* Remove a listener for changes to the location enabled setting.
*/
- public void removeOnLocationEnabledChangedListener(Runnable listener) {
+ public void removeOnLocationEnabledChangedListener(UserSettingChangedListener listener) {
mLocationMode.addListener(listener);
}
@@ -115,15 +148,16 @@
/**
* Add a listener for changes to the currently allowed location providers.
*/
- public void addOnLocationProvidersAllowedChangedListener(Runnable runnable) {
- mLocationProvidersAllowed.addListener(runnable);
+ public void addOnLocationProvidersAllowedChangedListener(UserSettingChangedListener listener) {
+ mLocationProvidersAllowed.addListener(listener);
}
/**
* Remove a listener for changes to the currently allowed location providers.
*/
- public void removeOnLocationProvidersAllowedChangedListener(Runnable runnable) {
- mLocationProvidersAllowed.removeListener(runnable);
+ public void removeOnLocationProvidersAllowedChangedListener(
+ UserSettingChangedListener listener) {
+ mLocationProvidersAllowed.removeListener(listener);
}
/**
@@ -136,14 +170,16 @@
/**
* Add a listener for changes to the background throttle interval.
*/
- public void addOnBackgroundThrottleIntervalChangedListener(Runnable listener) {
+ public void addOnBackgroundThrottleIntervalChangedListener(
+ GlobalSettingChangedListener listener) {
mBackgroundThrottleIntervalMs.addListener(listener);
}
/**
* Remove a listener for changes to the background throttle interval.
*/
- public void removeOnBackgroundThrottleIntervalChangedListener(Runnable listener) {
+ public void removeOnBackgroundThrottleIntervalChangedListener(
+ GlobalSettingChangedListener listener) {
mBackgroundThrottleIntervalMs.removeListener(listener);
}
@@ -175,42 +211,46 @@
/**
* Retrieve the background throttle package whitelist.
*/
- public List<String> getBackgroundThrottlePackageWhitelist() {
+ public Set<String> getBackgroundThrottlePackageWhitelist() {
return mBackgroundThrottlePackageWhitelist.getValue();
}
/**
* Add a listener for changes to the background throttle package whitelist.
*/
- public void addOnBackgroundThrottlePackageWhitelistChangedListener(Runnable listener) {
+ public void addOnBackgroundThrottlePackageWhitelistChangedListener(
+ GlobalSettingChangedListener listener) {
mBackgroundThrottlePackageWhitelist.addListener(listener);
}
/**
* Remove a listener for changes to the background throttle package whitelist.
*/
- public void removeOnBackgroundThrottlePackageWhitelistChangedListener(Runnable listener) {
+ public void removeOnBackgroundThrottlePackageWhitelistChangedListener(
+ GlobalSettingChangedListener listener) {
mBackgroundThrottlePackageWhitelist.removeListener(listener);
}
/**
* Retrieve the ignore settings package whitelist.
*/
- public List<String> getIgnoreSettingsPackageWhitelist() {
+ public Set<String> getIgnoreSettingsPackageWhitelist() {
return mIgnoreSettingsPackageWhitelist.getValue();
}
/**
* Add a listener for changes to the ignore settings package whitelist.
*/
- public void addOnIgnoreSettingsPackageWhitelistChangedListener(Runnable listener) {
+ public void addOnIgnoreSettingsPackageWhitelistChangedListener(
+ GlobalSettingChangedListener listener) {
mIgnoreSettingsPackageWhitelist.addListener(listener);
}
/**
* Remove a listener for changes to the ignore settings package whitelist.
*/
- public void removeOnIgnoreSettingsPackageWhitelistChangedListener(Runnable listener) {
+ public void removeOnIgnoreSettingsPackageWhitelistChangedListener(
+ GlobalSettingChangedListener listener) {
mIgnoreSettingsPackageWhitelist.removeListener(listener);
}
@@ -264,7 +304,7 @@
}
}
- List<String> backgroundThrottlePackageWhitelist =
+ Set<String> backgroundThrottlePackageWhitelist =
mBackgroundThrottlePackageWhitelist.getValue();
if (!backgroundThrottlePackageWhitelist.isEmpty()) {
ipw.println("Throttling Whitelisted Packages:");
@@ -275,7 +315,7 @@
ipw.decreaseIndent();
}
- List<String> ignoreSettingsPackageWhitelist = mIgnoreSettingsPackageWhitelist.getValue();
+ Set<String> ignoreSettingsPackageWhitelist = mIgnoreSettingsPackageWhitelist.getValue();
if (!ignoreSettingsPackageWhitelist.isEmpty()) {
ipw.println("Bypass Whitelisted Packages:");
ipw.increaseIndent();
@@ -288,7 +328,7 @@
private abstract static class ObservingSetting extends ContentObserver {
- private final CopyOnWriteArrayList<Runnable> mListeners;
+ private final CopyOnWriteArrayList<UserSettingChangedListener> mListeners;
private ObservingSetting(Context context, String settingName, Handler handler) {
super(handler);
@@ -298,11 +338,11 @@
getUriFor(settingName), false, this, UserHandle.USER_ALL);
}
- public void addListener(Runnable listener) {
+ public void addListener(UserSettingChangedListener listener) {
mListeners.add(listener);
}
- public void removeListener(Runnable listener) {
+ public void removeListener(UserSettingChangedListener listener) {
mListeners.remove(listener);
}
@@ -310,8 +350,8 @@
@Override
public void onChange(boolean selfChange, Uri uri, int userId) {
- for (Runnable listener : mListeners) {
- listener.run();
+ for (UserSettingChangedListener listener : mListeners) {
+ listener.onSettingChanged(userId);
}
}
}
@@ -354,6 +394,8 @@
}
public synchronized List<String> getValueForUser(int userId) {
+ Preconditions.checkArgument(userId != UserHandle.USER_NULL);
+
if (userId != mCachedUserId) {
String setting = Settings.Secure.getStringForUser(mContext.getContentResolver(),
mSettingName, userId);
@@ -409,29 +451,30 @@
}
}
- private static class StringListCachedGlobalSetting extends ObservingSetting {
+ private static class StringSetCachedGlobalSetting extends ObservingSetting {
private final Context mContext;
private final String mSettingName;
+ private final Supplier<ArraySet<String>> mBaseValuesSupplier;
private boolean mValid;
- private List<String> mCachedValue;
+ private ArraySet<String> mCachedValue;
- private StringListCachedGlobalSetting(Context context, String settingName,
- Handler handler) {
+ private StringSetCachedGlobalSetting(Context context, String settingName,
+ Supplier<ArraySet<String>> baseValuesSupplier, Handler handler) {
super(context, settingName, handler);
mContext = context;
mSettingName = settingName;
+ mBaseValuesSupplier = baseValuesSupplier;
}
- public synchronized List<String> getValue() {
+ public synchronized Set<String> getValue() {
if (!mValid) {
+ mCachedValue = new ArraySet<>(mBaseValuesSupplier.get());
String setting = Settings.Global.getString(mContext.getContentResolver(),
mSettingName);
- if (TextUtils.isEmpty(setting)) {
- mCachedValue = Collections.emptyList();
- } else {
- mCachedValue = Arrays.asList(setting.split(","));
+ if (!TextUtils.isEmpty(setting)) {
+ mCachedValue.addAll(Arrays.asList(setting.split(",")));
}
mValid = true;
}
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 2c478df..9fcee50 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -26,7 +26,6 @@
import android.content.pm.PackageManager;
import android.media.IMediaRouter2Client;
import android.media.IMediaRouter2Manager;
-import android.media.IMediaRouterClient;
import android.media.MediaRoute2Info;
import android.media.MediaRoute2ProviderInfo;
import android.media.MediaRouter2;
@@ -71,7 +70,7 @@
@GuardedBy("mLock")
private final SparseArray<UserRecord> mUserRecords = new SparseArray<>();
@GuardedBy("mLock")
- private final ArrayMap<IBinder, ClientRecord> mAllClientRecords = new ArrayMap<>();
+ private final ArrayMap<IBinder, Client2Record> mAllClientRecords = new ArrayMap<>();
@GuardedBy("mLock")
private final ArrayMap<IBinder, ManagerRecord> mAllManagerRecords = new ArrayMap<>();
@GuardedBy("mLock")
@@ -183,29 +182,14 @@
}
}
- //TODO: What would happen if a media app used MediaRouter and MediaRouter2 simultaneously?
- public void setControlCategories(@NonNull IMediaRouterClient client,
- @Nullable List<String> categories) {
- Objects.requireNonNull(client, "client must not be null");
- final long token = Binder.clearCallingIdentity();
- try {
- synchronized (mLock) {
- ClientRecord clientRecord = mAllClientRecords.get(client.asBinder());
- setControlCategoriesLocked(clientRecord, categories);
- }
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- public void setControlCategories2(@NonNull IMediaRouter2Client client,
+ public void setControlCategories(@NonNull IMediaRouter2Client client,
@Nullable List<String> categories) {
Objects.requireNonNull(client, "client must not be null");
final long token = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
- ClientRecord clientRecord = mAllClientRecords.get(client.asBinder());
+ Client2Record clientRecord = mAllClientRecords.get(client.asBinder());
setControlCategoriesLocked(clientRecord, categories);
}
} finally {
@@ -295,37 +279,6 @@
}
}
-
- public void registerClient(@NonNull IMediaRouterClient client, @NonNull String packageName) {
- Objects.requireNonNull(client, "client must not be null");
-
- final int uid = Binder.getCallingUid();
- final int pid = Binder.getCallingPid();
- final int userId = UserHandle.getUserId(uid);
-
- final long token = Binder.clearCallingIdentity();
- try {
- synchronized (mLock) {
- registerClient1Locked(client, packageName, userId);
- }
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- public void unregisterClient(@NonNull IMediaRouterClient client) {
- Objects.requireNonNull(client, "client must not be null");
-
- final long token = Binder.clearCallingIdentity();
- try {
- synchronized (mLock) {
- unregisterClient1Locked(client);
- }
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
//TODO: Review this is handling multi-user properly.
void switchUser() {
synchronized (mLock) {
@@ -389,7 +342,7 @@
}
private void unregisterClient2Locked(IMediaRouter2Client client, boolean died) {
- Client2Record clientRecord = (Client2Record) mAllClientRecords.remove(client.asBinder());
+ Client2Record clientRecord = mAllClientRecords.remove(client.asBinder());
if (clientRecord != null) {
UserRecord userRecord = clientRecord.mUserRecord;
userRecord.mClientRecords.remove(clientRecord);
@@ -399,7 +352,7 @@
}
}
- private void requestSelectRoute2Locked(ClientRecord clientRecord, boolean selectedByManager,
+ private void requestSelectRoute2Locked(Client2Record clientRecord, boolean selectedByManager,
MediaRoute2Info route) {
if (clientRecord != null) {
MediaRoute2Info oldRoute = clientRecord.mSelectedRoute;
@@ -435,7 +388,7 @@
}
}
- private void setControlCategoriesLocked(ClientRecord clientRecord, List<String> categories) {
+ private void setControlCategoriesLocked(Client2Record clientRecord, List<String> categories) {
if (clientRecord != null) {
clientRecord.mControlCategories = categories;
@@ -448,7 +401,7 @@
private void sendControlRequestLocked(IMediaRouter2Client client, MediaRoute2Info route,
Intent request) {
final IBinder binder = client.asBinder();
- ClientRecord clientRecord = mAllClientRecords.get(binder);
+ Client2Record clientRecord = mAllClientRecords.get(binder);
if (clientRecord != null) {
clientRecord.mUserRecord.mHandler.sendMessage(
@@ -460,7 +413,7 @@
private void requestSetVolumeLocked(IMediaRouter2Client client, MediaRoute2Info route,
int volume) {
final IBinder binder = client.asBinder();
- ClientRecord clientRecord = mAllClientRecords.get(binder);
+ Client2Record clientRecord = mAllClientRecords.get(binder);
if (clientRecord != null) {
clientRecord.mUserRecord.mHandler.sendMessage(
@@ -472,7 +425,7 @@
private void requestUpdateVolumeLocked(IMediaRouter2Client client, MediaRoute2Info route,
int delta) {
final IBinder binder = client.asBinder();
- ClientRecord clientRecord = mAllClientRecords.get(binder);
+ Client2Record clientRecord = mAllClientRecords.get(binder);
if (clientRecord != null) {
clientRecord.mUserRecord.mHandler.sendMessage(
@@ -511,7 +464,7 @@
obtainMessage(UserHandler::notifyRoutesToManager,
userRecord.mHandler, manager));
- for (ClientRecord clientRecord : userRecord.mClientRecords) {
+ for (Client2Record clientRecord : userRecord.mClientRecords) {
// TODO: Do not use updateClientUsage since it updates all managers.
// Instead, Notify only to the manager that is currently being registered.
@@ -538,7 +491,7 @@
String packageName, MediaRoute2Info route) {
ManagerRecord managerRecord = mAllManagerRecords.get(manager.asBinder());
if (managerRecord != null) {
- ClientRecord clientRecord =
+ Client2Record clientRecord =
managerRecord.mUserRecord.findClientRecordLocked(packageName);
if (clientRecord == null) {
Slog.w(TAG, "Ignoring route selection for unknown client.");
@@ -600,41 +553,10 @@
}
}
- private void registerClient1Locked(IMediaRouterClient client, String packageName,
- int userId) {
- final IBinder binder = client.asBinder();
- if (mAllClientRecords.get(binder) == null) {
- boolean newUser = false;
- UserRecord userRecord = mUserRecords.get(userId);
- if (userRecord == null) {
- userRecord = new UserRecord(userId);
- newUser = true;
- }
- ClientRecord clientRecord = new Client1Record(userRecord, client, packageName);
-
- if (newUser) {
- mUserRecords.put(userId, userRecord);
- initializeUserLocked(userRecord);
- }
-
- userRecord.mClientRecords.add(clientRecord);
- mAllClientRecords.put(binder, clientRecord);
- }
- }
-
- private void unregisterClient1Locked(IMediaRouterClient client) {
- ClientRecord clientRecord = mAllClientRecords.remove(client.asBinder());
- if (clientRecord != null) {
- UserRecord userRecord = clientRecord.mUserRecord;
- userRecord.mClientRecords.remove(clientRecord);
- disposeUserIfNeededLocked(userRecord);
- }
- }
-
final class UserRecord {
public final int mUserId;
//TODO: make records private for thread-safety
- final ArrayList<ClientRecord> mClientRecords = new ArrayList<>();
+ final ArrayList<Client2Record> mClientRecords = new ArrayList<>();
final ArrayList<ManagerRecord> mManagerRecords = new ArrayList<>();
final UserHandler mHandler;
@@ -643,8 +565,8 @@
mHandler = new UserHandler(MediaRouter2ServiceImpl.this, this);
}
- ClientRecord findClientRecordLocked(String packageName) {
- for (ClientRecord clientRecord : mClientRecords) {
+ Client2Record findClientRecordLocked(String packageName) {
+ for (Client2Record clientRecord : mClientRecords) {
if (TextUtils.equals(clientRecord.mPackageName, packageName)) {
return clientRecord;
}
@@ -653,44 +575,26 @@
}
}
- class ClientRecord {
+ final class Client2Record implements IBinder.DeathRecipient {
public final UserRecord mUserRecord;
public final String mPackageName;
public final List<Integer> mSelectRouteSequenceNumbers;
+ public final IMediaRouter2Client mClient;
+ public final int mUid;
+ public final int mPid;
+ public final boolean mTrusted;
public List<String> mControlCategories;
public boolean mIsManagerSelecting;
public MediaRoute2Info mSelectingRoute;
public MediaRoute2Info mSelectedRoute;
- ClientRecord(UserRecord userRecord, String packageName) {
+ Client2Record(UserRecord userRecord, IMediaRouter2Client client,
+ int uid, int pid, String packageName, boolean trusted) {
mUserRecord = userRecord;
mPackageName = packageName;
mSelectRouteSequenceNumbers = new ArrayList<>();
mControlCategories = Collections.emptyList();
- }
- }
-
- final class Client1Record extends ClientRecord {
- public final IMediaRouterClient mClient;
-
- Client1Record(UserRecord userRecord, IMediaRouterClient client,
- String packageName) {
- super(userRecord, packageName);
- mClient = client;
- }
- }
-
- final class Client2Record extends ClientRecord
- implements IBinder.DeathRecipient {
- public final IMediaRouter2Client mClient;
- public final int mUid;
- public final int mPid;
- public final boolean mTrusted;
-
- Client2Record(UserRecord userRecord, IMediaRouter2Client client,
- int uid, int pid, String packageName, boolean trusted) {
- super(userRecord, packageName);
mClient = client;
mUid = uid;
mPid = pid;
@@ -909,15 +813,10 @@
return;
}
- ClientRecord clientRecord;
+ Client2Record clientRecord;
synchronized (service.mLock) {
clientRecord = mUserRecord.findClientRecordLocked(clientPackageName);
}
- if (!(clientRecord instanceof Client2Record)) {
- Log.w(TAG, "Ignoring route selection for unknown client.");
- unselectRoute(clientPackageName, selectedRoute);
- return;
- }
//TODO: handle a case such that controlHints is null. (How should we notify MR2?)
@@ -931,7 +830,7 @@
clientRecord.mSelectingRoute = null;
clientRecord.mSelectedRoute = selectedRoute;
- notifyRouteSelectedToClient(((Client2Record) clientRecord).mClient,
+ notifyRouteSelectedToClient(clientRecord.mClient,
selectedRoute,
clientRecord.mIsManagerSelecting
? MediaRouter2.SELECT_REASON_SYSTEM_SELECTED :
@@ -950,14 +849,10 @@
return;
}
- ClientRecord clientRecord;
+ Client2Record clientRecord;
synchronized (service.mLock) {
clientRecord = mUserRecord.findClientRecordLocked(clientPackageName);
}
- if (!(clientRecord instanceof Client2Record)) {
- Log.w(TAG, "Ignoring fallback route selection for unknown client.");
- return;
- }
if (clientRecord.mSelectingRoute == null || !TextUtils.equals(
clientRecord.mSelectingRoute.getUniqueId(), selectingRoute.getUniqueId())) {
@@ -972,7 +867,7 @@
MediaRoute2Info fallbackRoute = null;
clientRecord.mSelectedRoute = fallbackRoute;
- notifyRouteSelectedToClient(((Client2Record) clientRecord).mClient,
+ notifyRouteSelectedToClient(clientRecord.mClient,
fallbackRoute,
MediaRouter2.SELECT_REASON_FALLBACK,
Bundle.EMPTY /* controlHints */);
@@ -1029,10 +924,8 @@
return clients;
}
synchronized (service.mLock) {
- for (ClientRecord clientRecord : mUserRecord.mClientRecords) {
- if (clientRecord instanceof Client2Record) {
- clients.add(((Client2Record) clientRecord).mClient);
- }
+ for (Client2Record clientRecord : mUserRecord.mClientRecords) {
+ clients.add(clientRecord.mClient);
}
}
return clients;
@@ -1157,7 +1050,7 @@
}
}
- private void updateClientUsage(ClientRecord clientRecord) {
+ private void updateClientUsage(Client2Record clientRecord) {
MediaRouter2ServiceImpl service = mServiceRef.get();
if (service == null) {
return;
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index 9336af4..9c99e8f 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -249,7 +249,6 @@
synchronized (mLock) {
registerClientLocked(client, uid, pid, packageName, resolvedUserId, trusted);
}
- mService2.registerClient(client, packageName);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -290,7 +289,6 @@
synchronized (mLock) {
unregisterClientLocked(client, false);
}
- mService2.unregisterClient(client);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -397,12 +395,6 @@
// Binder call
@Override
- public void setControlCategories(IMediaRouterClient client, List<String> controlCategories) {
- mService2.setControlCategories(client, controlCategories);
- }
-
- // Binder call
- @Override
public void requestUpdateVolume(IMediaRouterClient client, String routeId, int direction) {
if (client == null) {
throw new IllegalArgumentException("client must not be null");
@@ -501,8 +493,8 @@
// Binder call
@Override
- public void setControlCategories2(IMediaRouter2Client client, List<String> categories) {
- mService2.setControlCategories2(client, categories);
+ public void setControlCategories(IMediaRouter2Client client, List<String> categories) {
+ mService2.setControlCategories(client, categories);
}
// Binder call
@@ -601,7 +593,6 @@
synchronized (mLock) {
unregisterClientLocked(clientRecord.mClient, true);
}
- mService2.unregisterClient(clientRecord.mClient);
}
private void registerClientLocked(IMediaRouterClient client,
diff --git a/services/core/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java
index 77fbe41..4cb41da 100644
--- a/services/core/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java
@@ -16,7 +16,7 @@
package com.android.server.net;
-import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
+import static android.Manifest.permission.NETWORK_STACK;
import static android.provider.Settings.ACTION_VPN_SETTINGS;
import android.annotation.NonNull;
@@ -202,8 +202,7 @@
mVpn.setLockdown(true);
final IntentFilter resetFilter = new IntentFilter(ACTION_LOCKDOWN_RESET);
- mContext.registerReceiver(mResetReceiver, resetFilter, CONNECTIVITY_INTERNAL, mHandler);
-
+ mContext.registerReceiver(mResetReceiver, resetFilter, NETWORK_STACK, mHandler);
handleStateChangedLocked();
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 32d4b72..dfdc2c1 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -20,6 +20,9 @@
import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
import static android.Manifest.permission.MANAGE_NETWORK_POLICY;
import static android.Manifest.permission.MANAGE_SUBSCRIPTION_PLANS;
+import static android.Manifest.permission.NETWORK_SETTINGS;
+import static android.Manifest.permission.NETWORK_STACK;
+import static android.Manifest.permission.OBSERVE_NETWORK_POLICY;
import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
import static android.Manifest.permission.READ_PHONE_STATE;
import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
@@ -33,6 +36,7 @@
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED;
import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED;
@@ -153,6 +157,7 @@
import android.net.NetworkQuotaInfo;
import android.net.NetworkRequest;
import android.net.NetworkSpecifier;
+import android.net.NetworkStack;
import android.net.NetworkState;
import android.net.NetworkStats;
import android.net.NetworkTemplate;
@@ -825,7 +830,7 @@
// watch for network interfaces to be claimed
final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION);
- mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler);
+ mContext.registerReceiver(mConnReceiver, connFilter, NETWORK_STACK, mHandler);
// listen for package changes to update policy
final IntentFilter packageFilter = new IntentFilter();
@@ -1128,7 +1133,7 @@
@Override
public void limitReached(String limitName, String iface) {
// only someone like NMS should be calling us
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
if (!LIMIT_GLOBAL_ALERT.equals(limitName)) {
mHandler.obtainMessage(MSG_LIMIT_REACHED, iface).sendToTarget();
@@ -1483,7 +1488,7 @@
private BroadcastReceiver mConnReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- // on background handler thread, and verified CONNECTIVITY_INTERNAL
+ // on background handler thread, and verified NETWORK_STACK
// permission above.
updateNetworksInternal();
}
@@ -2721,17 +2726,35 @@
return changed;
}
+ private boolean checkAnyPermissionOf(String... permissions) {
+ for (String permission : permissions) {
+ if (mContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void enforceAnyPermissionOf(String... permissions) {
+ if (!checkAnyPermissionOf(permissions)) {
+ throw new SecurityException("Requires one of the following permissions: "
+ + String.join(", ", permissions) + ".");
+ }
+ }
+
@Override
public void registerListener(INetworkPolicyListener listener) {
- // TODO: create permission for observing network policy
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ // TODO: Remove CONNECTIVITY_INTERNAL and the *AnyPermissionOf methods above after all apps
+ // have declared OBSERVE_NETWORK_POLICY.
+ enforceAnyPermissionOf(CONNECTIVITY_INTERNAL, OBSERVE_NETWORK_POLICY);
mListeners.register(listener);
}
@Override
public void unregisterListener(INetworkPolicyListener listener) {
- // TODO: create permission for observing network policy
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ // TODO: Remove CONNECTIVITY_INTERNAL and the *AnyPermissionOf methods above after all apps
+ // have declared OBSERVE_NETWORK_POLICY.
+ enforceAnyPermissionOf(CONNECTIVITY_INTERNAL, OBSERVE_NETWORK_POLICY);
mListeners.unregister(listener);
}
@@ -4965,7 +4988,7 @@
@Override
public void factoryReset(String subscriber) {
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ mContext.enforceCallingOrSelfPermission(NETWORK_SETTINGS, TAG);
if (mUserManager.hasUserRestriction(UserManager.DISALLOW_NETWORK_RESET)) {
return;
@@ -4998,7 +5021,7 @@
public boolean isUidNetworkingBlocked(int uid, boolean isNetworkMetered) {
final long startTime = mStatLogger.getTime();
- mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+ mContext.enforceCallingOrSelfPermission(OBSERVE_NETWORK_POLICY, TAG);
final int uidRules;
final boolean isBackgroundRestricted;
synchronized (mUidRulesFirstLock) {
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index e473c96..16424f2 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -17,7 +17,6 @@
package com.android.server.net;
import static android.Manifest.permission.ACCESS_NETWORK_STATE;
-import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
import static android.content.Intent.ACTION_SHUTDOWN;
import static android.content.Intent.ACTION_UID_REMOVED;
@@ -91,6 +90,7 @@
import android.net.NetworkCapabilities;
import android.net.NetworkIdentity;
import android.net.NetworkInfo;
+import android.net.NetworkStack;
import android.net.NetworkState;
import android.net.NetworkStats;
import android.net.NetworkStats.NonMonotonicObserver;
@@ -1020,8 +1020,6 @@
private BroadcastReceiver mTetherReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- // on background handler thread, and verified CONNECTIVITY_INTERNAL
- // permission above.
performPoll(FLAG_PERSIST_NETWORK);
}
};
@@ -1095,7 +1093,7 @@
@Override
public void limitReached(String limitName, String iface) {
// only someone like NMS should be calling us
- mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+ NetworkStack.checkNetworkStackPermission(mContext);
if (LIMIT_GLOBAL_ALERT.equals(limitName)) {
// kick off background poll to collect network stats unless there is already
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index d63e704..4852947 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -133,6 +133,7 @@
private static final int MSG_COMMIT = 1;
private static final int MSG_ON_PACKAGE_INSTALLED = 2;
private static final int MSG_SEAL = 3;
+ private static final int MSG_TRANSFER = 4;
/** XML constants used for persisting a session */
static final String TAG_SESSION = "session";
@@ -332,6 +333,9 @@
private final Handler.Callback mHandlerCallback = new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
+ SomeArgs args;
+ String packageName;
+ IntentSender statusReceiver;
switch (msg.what) {
case MSG_SEAL:
handleSeal((IntentSender) msg.obj);
@@ -339,12 +343,20 @@
case MSG_COMMIT:
handleCommit();
break;
+ case MSG_TRANSFER:
+ args = (SomeArgs) msg.obj;
+ packageName = (String) args.arg1;
+ statusReceiver = (IntentSender) args.arg2;
+ args.recycle();
+
+ handleTransfer(statusReceiver, packageName);
+ break;
case MSG_ON_PACKAGE_INSTALLED:
- final SomeArgs args = (SomeArgs) msg.obj;
- final String packageName = (String) args.arg1;
+ args = (SomeArgs) msg.obj;
+ packageName = (String) args.arg1;
final String message = (String) args.arg2;
final Bundle extras = (Bundle) args.arg3;
- final IntentSender statusReceiver = (IntentSender) args.arg4;
+ statusReceiver = (IntentSender) args.arg4;
final int returnCode = args.argi1;
args.recycle();
@@ -378,7 +390,7 @@
* Checks if the permissions still need to be confirmed.
*
* <p>This is dependant on the identity of the installer, hence this cannot be cached if the
- * installer might still {@link #transfer(String) change}.
+ * installer might still {@link #transfer(String, IntentSender) change}.
*
* @return {@code true} iff we need to ask to confirm the permissions?
*/
@@ -1183,13 +1195,11 @@
}
}
- @Override
- public void transfer(String packageName) {
- Preconditions.checkNotNull(packageName);
-
+ private int assertCanBeTransferredAndReturnNewOwner(String packageName)
+ throws PackageManager.NameNotFoundException {
ApplicationInfo newOwnerAppInfo = mPm.getApplicationInfo(packageName, 0, userId);
if (newOwnerAppInfo == null) {
- throw new ParcelableException(new PackageManager.NameNotFoundException(packageName));
+ throw new PackageManager.NameNotFoundException(packageName);
}
if (PackageManager.PERMISSION_GRANTED != mPm.checkUidPermission(
@@ -1204,31 +1214,104 @@
throw new SecurityException("Can only transfer sessions that use public options");
}
- List<PackageInstallerSession> childSessions = getChildSessions();
+ return newOwnerAppInfo.uid;
+ }
+
+ @Override
+ public void transfer(String packageName, IntentSender statusReceiver) {
+ Preconditions.checkNotNull(statusReceiver);
+ Preconditions.checkNotNull(packageName);
+
+ try {
+ assertCanBeTransferredAndReturnNewOwner(packageName);
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new ParcelableException(e);
+ }
synchronized (mLock) {
assertCallerIsOwnerOrRootLocked();
assertPreparedAndNotSealedLocked("transfer");
+ }
- try {
- sealAndValidateLocked(childSessions);
- } catch (PackageManagerException e) {
- throw new IllegalArgumentException("Package is not valid", e);
+ final SomeArgs args = SomeArgs.obtain();
+ args.arg1 = packageName;
+ args.arg2 = statusReceiver;
+
+ mHandler.obtainMessage(MSG_TRANSFER, args).sendToTarget();
+ }
+
+ private void handleTransfer(IntentSender statusReceiver, String packageName) {
+ List<PackageInstallerSession> childSessions = getChildSessions();
+
+ try {
+ final int uid = assertCanBeTransferredAndReturnNewOwner(packageName);
+
+ synchronized (mLock) {
+ assertPreparedAndNotSealedLocked("transfer");
+
+ try {
+ sealAndValidateLocked(childSessions);
+ } catch (PackageManagerException e) {
+ throw new IllegalArgumentException("Package is not valid", e);
+ }
+
+ if (!mPackageName.equals(mInstallSource.installerPackageName)) {
+ throw new SecurityException(
+ "Can only transfer sessions that update the original installer");
+ }
+
+ mInstallerUid = uid;
+ mInstallSource = InstallSource.create(packageName, null, packageName, false);
}
-
- if (!mPackageName.equals(mInstallSource.installerPackageName)) {
- throw new SecurityException("Can only transfer sessions that update the original "
- + "installer");
- }
-
- mInstallerUid = newOwnerAppInfo.uid;
- mInstallSource = InstallSource.create(packageName, null, packageName, false);
+ } catch (PackageManager.NameNotFoundException e) {
+ onSessionTransferStatus(statusReceiver, packageName,
+ PackageInstaller.STATUS_FAILURE_NAME_NOT_FOUND, e.getMessage());
+ return;
+ } catch (IllegalStateException e) {
+ onSessionTransferStatus(statusReceiver, packageName,
+ PackageInstaller.STATUS_FAILURE_ILLEGAL_STATE, e.getMessage());
+ return;
+ } catch (SecurityException e) {
+ onSessionTransferStatus(statusReceiver, packageName,
+ PackageInstaller.STATUS_FAILURE_SECURITY, e.getMessage());
+ return;
+ } catch (Throwable e) {
+ onSessionTransferStatus(statusReceiver, packageName, PackageInstaller.STATUS_FAILURE,
+ e.getMessage());
+ return;
}
// Persist the fact that we've sealed ourselves to prevent
// mutations of any hard links we create. We do this without holding
// the session lock, since otherwise it's a lock inversion.
mCallback.onSessionSealedBlocking(this);
+
+ // Report success.
+ onSessionTransferStatus(statusReceiver, packageName, PackageInstaller.STATUS_SUCCESS, null);
+ }
+
+ private void onSessionTransferStatus(IntentSender statusReceiver, String otherPackageName,
+ int status, String statusMessage) {
+ final String packageName;
+ synchronized (mLock) {
+ packageName = mPackageName;
+ }
+
+ final Intent fillIn = new Intent();
+ fillIn.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, packageName);
+ fillIn.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);
+ fillIn.putExtra(PackageInstaller.EXTRA_OTHER_PACKAGE_NAME, otherPackageName);
+
+ fillIn.putExtra(PackageInstaller.EXTRA_STATUS, status);
+ if (!TextUtils.isEmpty(statusMessage)) {
+ fillIn.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE, statusMessage);
+ }
+
+ try {
+ statusReceiver.sendIntent(mContext, 0, fillIn, null, null);
+ } catch (IntentSender.SendIntentException ignored) {
+ }
+
}
private void handleCommit() {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 05f62b2..14cbe75 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -3107,36 +3107,11 @@
}
}
- // First try to use a pre-created user (if available).
- // TODO(b/142482943): Move this to its own function later.
- if (!preCreate
- && (parentId < 0 && isUserTypeEligibleForPreCreation(userTypeDetails))) {
- final UserData preCreatedUserData;
- synchronized (mUsersLock) {
- preCreatedUserData = getPreCreatedUserLU(userType);
- }
- if (preCreatedUserData != null) {
- final UserInfo preCreatedUser = preCreatedUserData.info;
- final int newFlags = preCreatedUser.flags | flags;
- if (!checkUserTypeConsistency(newFlags)) {
- Slog.wtf(LOG_TAG, "Cannot reuse pre-created user " + preCreatedUser.id
- + " of type " + userType + " because flags are inconsistent. "
- + "Flags (" + Integer.toHexString(flags) + "); preCreatedUserFlags ( "
- + Integer.toHexString(preCreatedUser.flags) + ").");
- } else {
- Log.i(LOG_TAG, "Reusing pre-created user " + preCreatedUser.id + " of type "
- + userType + " and bestowing on it flags "
- + UserInfo.flagsToString(flags));
- preCreatedUser.name = name;
- preCreatedUser.flags = newFlags;
- preCreatedUser.preCreated = false;
- preCreatedUser.creationTime = getCreationTime();
-
- dispatchUserAddedIntent(preCreatedUser);
- writeUserLP(preCreatedUserData);
- writeUserListLP();
- return preCreatedUser;
- }
+ // Try to use a pre-created user (if available).
+ if (!preCreate && parentId < 0 && isUserTypeEligibleForPreCreation(userTypeDetails)) {
+ final UserInfo preCreatedUser = convertPreCreatedUserIfPossible(userType, flags, name);
+ if (preCreatedUser != null) {
+ return preCreatedUser;
}
}
@@ -3320,6 +3295,44 @@
return userInfo;
}
+ /**
+ * Finds and converts a previously pre-created user into a regular user, if possible.
+ *
+ * @return the converted user, or {@code null} if no pre-created user could be converted.
+ */
+ private @Nullable UserInfo convertPreCreatedUserIfPossible(String userType,
+ @UserInfoFlag int flags, String name) {
+ final UserData preCreatedUserData;
+ synchronized (mUsersLock) {
+ preCreatedUserData = getPreCreatedUserLU(userType);
+ }
+ if (preCreatedUserData == null) {
+ return null;
+ }
+ final UserInfo preCreatedUser = preCreatedUserData.info;
+ final int newFlags = preCreatedUser.flags | flags;
+ if (!checkUserTypeConsistency(newFlags)) {
+ Slog.wtf(LOG_TAG, "Cannot reuse pre-created user " + preCreatedUser.id
+ + " of type " + userType + " because flags are inconsistent. "
+ + "Flags (" + Integer.toHexString(flags) + "); preCreatedUserFlags ( "
+ + Integer.toHexString(preCreatedUser.flags) + ").");
+ return null;
+ }
+ Log.i(LOG_TAG, "Reusing pre-created user " + preCreatedUser.id + " of type "
+ + userType + " and bestowing on it flags " + UserInfo.flagsToString(flags));
+ preCreatedUser.name = name;
+ preCreatedUser.flags = newFlags;
+ preCreatedUser.preCreated = false;
+ preCreatedUser.creationTime = getCreationTime();
+
+ dispatchUserAddedIntent(preCreatedUser);
+ synchronized (mPackagesLock) {
+ writeUserLP(preCreatedUserData);
+ writeUserListLP();
+ }
+ return preCreatedUser;
+ }
+
/** Checks that the flags do not contain mutually exclusive types/properties. */
static boolean checkUserTypeConsistency(@UserInfoFlag int flags) {
// Mask to check that flags don't refer to multiple user types.
diff --git a/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java
index 3c79b23..0b970bf 100644
--- a/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java
+++ b/services/core/java/com/android/server/timedetector/SimpleTimeDetectorStrategy.java
@@ -23,10 +23,13 @@
import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.PhoneTimeSuggestion;
import android.content.Intent;
+import android.util.LocalLog;
import android.util.Slog;
import android.util.TimestampedValue;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.util.IndentingPrintWriter;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -34,13 +37,14 @@
/**
* An implementation of TimeDetectorStrategy that passes only NITZ suggestions to
- * {@link AlarmManager}. The TimeDetectorService handles thread safety: all calls to
- * this class can be assumed to be single threaded (though the thread used may vary).
+ * {@link AlarmManager}.
+ *
+ * <p>Most public methods are marked synchronized to ensure thread safety around internal state.
*/
-// @NotThreadSafe
public final class SimpleTimeDetectorStrategy implements TimeDetectorStrategy {
- private final static String TAG = "timedetector.SimpleTimeDetectorStrategy";
+ private static final boolean DBG = false;
+ private static final String LOG_TAG = "SimpleTimeDetectorStrategy";
@IntDef({ ORIGIN_PHONE, ORIGIN_MANUAL })
@Retention(RetentionPolicy.SOURCE)
@@ -61,6 +65,9 @@
*/
private static final long SYSTEM_CLOCK_PARANOIA_THRESHOLD_MILLIS = 2 * 1000;
+ // A log for changes made to the system clock and why.
+ @NonNull private final LocalLog mTimeChangesLog = new LocalLog(30);
+
// @NonNull after initialize()
private Callback mCallback;
@@ -80,7 +87,7 @@
}
@Override
- public void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSuggestion) {
+ public synchronized void suggestPhoneTime(@NonNull PhoneTimeSuggestion timeSuggestion) {
// NITZ logic
// Empty suggestions are just ignored as we don't currently keep track of suggestion origin.
@@ -103,7 +110,7 @@
}
@Override
- public void suggestManualTime(ManualTimeSuggestion timeSuggestion) {
+ public synchronized void suggestManualTime(ManualTimeSuggestion timeSuggestion) {
final TimestampedValue<Long> newUtcTime = timeSuggestion.getUtcTime();
setSystemClockIfRequired(ORIGIN_MANUAL, newUtcTime, timeSuggestion);
}
@@ -116,7 +123,7 @@
newSuggestion.getUtcTime(), lastSuggestion.getUtcTime());
if (referenceTimeDifference < 0 || referenceTimeDifference > Integer.MAX_VALUE) {
// Out of order or bogus.
- Slog.w(TAG, "validateNewNitzTime: Bad NITZ signal received."
+ Slog.w(LOG_TAG, "Bad NITZ signal received."
+ " referenceTimeDifference=" + referenceTimeDifference
+ " lastSuggestion=" + lastSuggestion
+ " newSuggestion=" + newSuggestion);
@@ -126,6 +133,7 @@
return true;
}
+ @GuardedBy("this")
private void setSystemClockIfRequired(
@Origin int origin, TimestampedValue<Long> time, Object cause) {
// Historically, Android has sent a TelephonyIntents.ACTION_NETWORK_SET_TIME broadcast only
@@ -140,16 +148,20 @@
mLastAutoSystemClockTimeSendNetworkBroadcast = sendNetworkBroadcast;
if (!mCallback.isAutoTimeDetectionEnabled()) {
- Slog.d(TAG, "setSystemClockIfRequired: Auto time detection is not enabled."
- + " time=" + time
- + ", cause=" + cause);
+ if (DBG) {
+ Slog.d(LOG_TAG, "Auto time detection is not enabled."
+ + " time=" + time
+ + ", cause=" + cause);
+ }
return;
}
} else {
if (mCallback.isAutoTimeDetectionEnabled()) {
- Slog.d(TAG, "setSystemClockIfRequired: Auto time detection is enabled."
- + " time=" + time
- + ", cause=" + cause);
+ if (DBG) {
+ Slog.d(LOG_TAG, "Auto time detection is enabled."
+ + " time=" + time
+ + ", cause=" + cause);
+ }
return;
}
}
@@ -167,7 +179,7 @@
mLastAutoSystemClockTimeSet, elapsedRealtimeMillis);
long absSystemClockDifference = Math.abs(expectedTimeMillis - actualTimeMillis);
if (absSystemClockDifference > SYSTEM_CLOCK_PARANOIA_THRESHOLD_MILLIS) {
- Slog.w(TAG,
+ Slog.w(LOG_TAG,
"System clock has not tracked elapsed real time clock. A clock may"
+ " be inaccurate or something unexpectedly set the system"
+ " clock."
@@ -190,9 +202,10 @@
}
@Override
- public void handleAutoTimeDetectionToggle(boolean enabled) {
+ public synchronized void handleAutoTimeDetectionChanged() {
// If automatic time detection is enabled we update the system clock instantly if we can.
// Conversely, if automatic time detection is disabled we leave the clock as it is.
+ boolean enabled = mCallback.isAutoTimeDetectionEnabled();
if (enabled) {
if (mLastAutoSystemClockTime != null) {
// Only send the network broadcast if the last candidate would have caused one.
@@ -218,14 +231,27 @@
}
@Override
- public void dump(@NonNull PrintWriter pw, @Nullable String[] args) {
+ public synchronized void dump(@NonNull PrintWriter pw, @Nullable String[] args) {
pw.println("mLastPhoneSuggestion=" + mLastPhoneSuggestion);
pw.println("mLastAutoSystemClockTimeSet=" + mLastAutoSystemClockTimeSet);
pw.println("mLastAutoSystemClockTime=" + mLastAutoSystemClockTime);
pw.println("mLastAutoSystemClockTimeSendNetworkBroadcast="
+ mLastAutoSystemClockTimeSendNetworkBroadcast);
+
+ IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
+
+ ipw.println("TimeDetectorStrategyImpl logs:");
+ ipw.increaseIndent(); // level 1
+
+ ipw.println("Time change log:");
+ ipw.increaseIndent(); // level 2
+ mTimeChangesLog.dump(ipw);
+ ipw.decreaseIndent(); // level 2
+
+ ipw.decreaseIndent(); // level 1
}
+ @GuardedBy("this")
private void adjustAndSetDeviceSystemClock(
TimestampedValue<Long> newTime, boolean sendNetworkBroadcast,
long elapsedRealtimeMillis, long actualSystemClockMillis, Object cause) {
@@ -238,21 +264,27 @@
long absTimeDifference = Math.abs(newSystemClockMillis - actualSystemClockMillis);
long systemClockUpdateThreshold = mCallback.systemClockUpdateThresholdMillis();
if (absTimeDifference < systemClockUpdateThreshold) {
- Slog.d(TAG, "adjustAndSetDeviceSystemClock: Not setting system clock. New time and"
- + " system clock are close enough."
- + " elapsedRealtimeMillis=" + elapsedRealtimeMillis
- + " newTime=" + newTime
- + " cause=" + cause
- + " systemClockUpdateThreshold=" + systemClockUpdateThreshold
- + " absTimeDifference=" + absTimeDifference);
+ if (DBG) {
+ Slog.d(LOG_TAG, "Not setting system clock. New time and"
+ + " system clock are close enough."
+ + " elapsedRealtimeMillis=" + elapsedRealtimeMillis
+ + " newTime=" + newTime
+ + " cause=" + cause
+ + " systemClockUpdateThreshold=" + systemClockUpdateThreshold
+ + " absTimeDifference=" + absTimeDifference);
+ }
return;
}
- Slog.d(TAG, "Setting system clock using time=" + newTime
+ mCallback.setSystemClock(newSystemClockMillis);
+ String logMsg = "Set system clock using time=" + newTime
+ " cause=" + cause
+ " elapsedRealtimeMillis=" + elapsedRealtimeMillis
- + " newTimeMillis=" + newSystemClockMillis);
- mCallback.setSystemClock(newSystemClockMillis);
+ + " newSystemClockMillis=" + newSystemClockMillis;
+ if (DBG) {
+ Slog.d(LOG_TAG, logMsg);
+ }
+ mTimeChangesLog.log(logMsg);
// CLOCK_PARANOIA : Record the last time this class set the system clock.
mLastAutoSystemClockTimeSet = newTime;
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorService.java b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
index 7f5b403..34400ff 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorService.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
@@ -24,10 +24,9 @@
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
-import android.os.Binder;
+import android.os.Handler;
import android.provider.Settings;
-import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils;
import com.android.server.FgThread;
@@ -39,7 +38,7 @@
import java.util.Objects;
public final class TimeDetectorService extends ITimeDetectorService.Stub {
- private static final String TAG = "timedetector.TimeDetectorService";
+ private static final String TAG = "TimeDetectorService";
public static class Lifecycle extends SystemService {
@@ -57,29 +56,25 @@
}
}
+ @NonNull private final Handler mHandler;
@NonNull private final Context mContext;
@NonNull private final Callback mCallback;
-
- // The lock used when call the strategy to ensure thread safety.
- @NonNull private final Object mStrategyLock = new Object();
-
- @GuardedBy("mStrategyLock")
@NonNull private final TimeDetectorStrategy mTimeDetectorStrategy;
private static TimeDetectorService create(@NonNull Context context) {
- final TimeDetectorStrategy timeDetector = new SimpleTimeDetectorStrategy();
- final TimeDetectorStrategyCallbackImpl callback =
- new TimeDetectorStrategyCallbackImpl(context);
+ TimeDetectorStrategy timeDetector = new SimpleTimeDetectorStrategy();
+ TimeDetectorStrategyCallbackImpl callback = new TimeDetectorStrategyCallbackImpl(context);
timeDetector.initialize(callback);
+ Handler handler = FgThread.getHandler();
TimeDetectorService timeDetectorService =
- new TimeDetectorService(context, callback, timeDetector);
+ new TimeDetectorService(context, handler, callback, timeDetector);
// Wire up event listening.
ContentResolver contentResolver = context.getContentResolver();
contentResolver.registerContentObserver(
Settings.Global.getUriFor(Settings.Global.AUTO_TIME), true,
- new ContentObserver(FgThread.getHandler()) {
+ new ContentObserver(handler) {
public void onChange(boolean selfChange) {
timeDetectorService.handleAutoTimeDetectionToggle();
}
@@ -89,9 +84,10 @@
}
@VisibleForTesting
- public TimeDetectorService(@NonNull Context context, @NonNull Callback callback,
- @NonNull TimeDetectorStrategy timeDetectorStrategy) {
+ public TimeDetectorService(@NonNull Context context, @NonNull Handler handler,
+ @NonNull Callback callback, @NonNull TimeDetectorStrategy timeDetectorStrategy) {
mContext = Objects.requireNonNull(context);
+ mHandler = Objects.requireNonNull(handler);
mCallback = Objects.requireNonNull(callback);
mTimeDetectorStrategy = Objects.requireNonNull(timeDetectorStrategy);
}
@@ -101,14 +97,7 @@
enforceSuggestPhoneTimePermission();
Objects.requireNonNull(timeSignal);
- long idToken = Binder.clearCallingIdentity();
- try {
- synchronized (mStrategyLock) {
- mTimeDetectorStrategy.suggestPhoneTime(timeSignal);
- }
- } finally {
- Binder.restoreCallingIdentity(idToken);
- }
+ mHandler.post(() -> mTimeDetectorStrategy.suggestPhoneTime(timeSignal));
}
@Override
@@ -116,22 +105,12 @@
enforceSuggestManualTimePermission();
Objects.requireNonNull(timeSignal);
- long idToken = Binder.clearCallingIdentity();
- try {
- synchronized (mStrategyLock) {
- mTimeDetectorStrategy.suggestManualTime(timeSignal);
- }
- } finally {
- Binder.restoreCallingIdentity(idToken);
- }
+ mHandler.post(() -> mTimeDetectorStrategy.suggestManualTime(timeSignal));
}
@VisibleForTesting
public void handleAutoTimeDetectionToggle() {
- synchronized (mStrategyLock) {
- final boolean timeDetectionEnabled = mCallback.isAutoTimeDetectionEnabled();
- mTimeDetectorStrategy.handleAutoTimeDetectionToggle(timeDetectionEnabled);
- }
+ mHandler.post(mTimeDetectorStrategy::handleAutoTimeDetectionChanged);
}
@Override
@@ -139,9 +118,7 @@
@Nullable String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
- synchronized (mStrategyLock) {
- mTimeDetectorStrategy.dump(pw, args);
- }
+ mTimeDetectorStrategy.dump(pw, args);
}
private void enforceSuggestPhoneTimePermission() {
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
index b60cebf..32cee2d 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
@@ -27,12 +27,14 @@
/**
* The interface for classes that implement the time detection algorithm used by the
- * TimeDetectorService. The TimeDetectorService handles thread safety: all calls to implementations
- * of this interface can be assumed to be single threaded (though the thread used may vary).
+ * TimeDetectorService.
+ *
+ * <p>Most calls will be handled by a single thread but that is not true for all calls. For example
+ * {@link #dump(PrintWriter, String[])}) may be called on a different thread so implementations must
+ * handle thread safety.
*
* @hide
*/
-// @NotThreadSafe
public interface TimeDetectorStrategy {
/**
@@ -79,7 +81,7 @@
void suggestManualTime(@NonNull ManualTimeSuggestion timeSuggestion);
/** Handle the auto-time setting being toggled on or off. */
- void handleAutoTimeDetectionToggle(boolean enabled);
+ void handleAutoTimeDetectionChanged();
/** Dump debug information. */
void dump(@NonNull PrintWriter pw, @Nullable String[] args);
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index a593ef8..de51d4b 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -64,25 +64,24 @@
import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_TIMEOUT;
import static com.android.server.wm.EventLogTags.WM_ACTIVITY_LAUNCH_TIME;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.WaitResult;
import android.app.WindowConfiguration.WindowingMode;
import android.content.ComponentName;
-import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.dex.ArtManagerInternal;
import android.content.pm.dex.PackageOptimizationInfo;
import android.metrics.LogMaker;
-import android.os.Handler;
+import android.os.Binder;
import android.os.Looper;
-import android.os.Message;
import android.os.SystemClock;
import android.os.Trace;
+import android.util.ArrayMap;
import android.util.EventLog;
import android.util.Log;
import android.util.Slog;
-import android.util.SparseArray;
-import android.util.SparseIntArray;
import android.util.StatsLog;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
@@ -90,16 +89,23 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.os.BackgroundThread;
-import com.android.internal.os.SomeArgs;
+import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.LocalServices;
+import java.util.ArrayList;
+import java.util.LinkedList;
import java.util.concurrent.TimeUnit;
/**
* Listens to activity launches, transitions, visibility changes and window drawn callbacks to
* determine app launch times and draw delays. Source of truth for activity metrics and provides
* data for Tron, logcat, event logs and {@link android.app.WaitResult}.
- *
+ * <p>
+ * A typical sequence of a launch event could be:
+ * {@link #notifyActivityLaunching}, {@link #notifyActivityLaunched},
+ * {@link #notifyStartingWindowDrawn} (optional), {@link #notifyTransitionStarting}
+ * {@link #notifyWindowsDrawn}.
+ * <p>
* Tests:
* atest CtsWindowManagerDeviceTestCases:ActivityMetricsLoggerTests
*/
@@ -115,12 +121,14 @@
private static final int WINDOW_STATE_ASSISTANT = 3;
private static final int WINDOW_STATE_INVALID = -1;
- private static final long INVALID_START_TIME = -1;
+ /**
+ * The flag for {@link #notifyActivityLaunching} to skip associating a new launch with an active
+ * transition, in the case the launch is standalone (e.g. from recents).
+ */
+ private static final int IGNORE_CALLER = -1;
private static final int INVALID_DELAY = -1;
private static final int INVALID_TRANSITION_TYPE = -1;
- private static final int MSG_CHECK_VISIBILITY = 0;
-
// Preallocated strings we are sending to tron, so we don't have to allocate a new one every
// time we log.
private static final String[] TRON_WINDOW_STATE_VARZ_STRINGS = {
@@ -129,27 +137,12 @@
private int mWindowState = WINDOW_STATE_STANDARD;
private long mLastLogTimeSecs;
private final ActivityStackSupervisor mSupervisor;
- private final Context mContext;
private final MetricsLogger mMetricsLogger = new MetricsLogger();
- // set to INVALID_START_TIME in reset.
- // set to valid value in notifyActivityLaunching
- private long mCurrentTransitionStartTimeNs = INVALID_START_TIME;
- private long mLastTransitionStartTimeNs = INVALID_START_TIME;
-
- private int mCurrentTransitionDeviceUptime;
- private int mCurrentTransitionDelayMs;
-
- /** If the any app transitions have been logged as starting, after the latest reset. */
- private boolean mLoggedTransitionStarting;
-
- /** Map : @WindowingMode int => WindowingModeTransitionInfo */
- private final SparseArray<WindowingModeTransitionInfo> mWindowingModeTransitionInfo =
- new SparseArray<>();
- /** Map : @WindowingMode int => WindowingModeTransitionInfo */
- private final SparseArray<WindowingModeTransitionInfo> mLastWindowingModeTransitionInfo =
- new SparseArray<>();
- private final H mHandler;
+ /** All active transitions. */
+ private final ArrayList<TransitionInfo> mTransitionInfoList = new ArrayList<>();
+ /** Map : Last launched activity => {@link TransitionInfo} */
+ private final ArrayMap<ActivityRecord, TransitionInfo> mLastTransitionInfo = new ArrayMap<>();
private ArtManagerInternal mArtManagerInternal;
private final StringBuilder mStringBuilder = new StringBuilder();
@@ -161,54 +154,151 @@
private final LaunchObserverRegistryImpl mLaunchObserver;
@VisibleForTesting static final int LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE = 512;
- private final class H extends Handler {
+ /**
+ * The information created when an intent is incoming but we do not yet know whether it will be
+ * launched successfully.
+ */
+ static final class LaunchingState {
+ /** The timestamp of {@link #notifyActivityLaunching}. */
+ private long mCurrentTransitionStartTimeNs;
+ /** Non-null when a {@link TransitionInfo} is created for this state. */
+ private TransitionInfo mAssociatedTransitionInfo;
- public H(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_CHECK_VISIBILITY:
- final SomeArgs args = (SomeArgs) msg.obj;
- checkVisibility((Task) args.arg1, (ActivityRecord) args.arg2);
- break;
- }
+ @VisibleForTesting
+ boolean allDrawn() {
+ return mAssociatedTransitionInfo != null && mAssociatedTransitionInfo.allDrawn();
}
}
- private final class WindowingModeTransitionInfo {
+ /** The information created when an activity is confirmed to be launched. */
+ private static final class TransitionInfo {
+ /**
+ * The field to lookup and update an existing transition efficiently between
+ * {@link #notifyActivityLaunching} and {@link #notifyActivityLaunched}.
+ *
+ * @see LaunchingState#mAssociatedTransitionInfo
+ */
+ final LaunchingState mLaunchingState;
+ /**
+ * The timestamp of the first {@link #notifyActivityLaunching}. It can be used as a key for
+ * observer to identify which callbacks belong to a launch event.
+ */
+ final long mTransitionStartTimeNs;
+ /** The device uptime in seconds when this transition info is created. */
+ final int mCurrentTransitionDeviceUptime;
+ /** The type can be cold (new process), warm (new activity), or hot (bring to front). */
+ final int mTransitionType;
+ /** Whether the process was already running when the transition started. */
+ final boolean mProcessRunning;
+ /** The activities that should be drawn. */
+ final LinkedList<ActivityRecord> mPendingDrawActivities = new LinkedList<>();
/** The latest activity to have been launched. */
- private ActivityRecord launchedActivity;
- private int startResult;
- private boolean currentTransitionProcessRunning;
+ @NonNull ActivityRecord mLastLaunchedActivity;
+
+ /** The time from {@link #mTransitionStartTimeNs} to {@link #notifyTransitionStarting}. */
+ int mCurrentTransitionDelayMs;
+ /** The time from {@link #mTransitionStartTimeNs} to {@link #notifyStartingWindowDrawn}. */
+ int mStartingWindowDelayMs = INVALID_DELAY;
+ /** The time from {@link #mTransitionStartTimeNs} to {@link #notifyBindApplication}. */
+ int mBindApplicationDelayMs = INVALID_DELAY;
/** Elapsed time from when we launch an activity to when its windows are drawn. */
- private int windowsDrawnDelayMs;
- private int startingWindowDelayMs = INVALID_DELAY;
- private int bindApplicationDelayMs = INVALID_DELAY;
- private int reason = APP_TRANSITION_TIMEOUT;
- // TODO(b/132736359) The number may need to consider the visibility change.
- private int numUndrawnActivities = 1;
+ int mWindowsDrawnDelayMs;
+ /** The reason why the transition started (see ActivityManagerInternal.APP_TRANSITION_*). */
+ int mReason = APP_TRANSITION_TIMEOUT;
+ /** The flag ensures that {@link #mStartingWindowDelayMs} is only set once. */
+ boolean mLoggedStartingWindowDrawn;
+ /** If the any app transitions have been logged as starting. */
+ boolean mLoggedTransitionStarting;
+
/** Non-null if the application has reported drawn but its window hasn't. */
- private Runnable pendingFullyDrawn;
- private boolean loggedStartingWindowDrawn;
- private boolean launchTraceActive;
+ @Nullable Runnable mPendingFullyDrawn;
+ /** Non-null if the trace is active. */
+ @Nullable String mLaunchTraceName;
+
+ /** @return Non-null if there will be a window drawn event for the launch. */
+ @Nullable
+ static TransitionInfo create(@NonNull ActivityRecord r,
+ @NonNull LaunchingState launchingState, boolean processRunning, int startResult) {
+ int transitionType = INVALID_TRANSITION_TYPE;
+ if (processRunning) {
+ if (startResult == START_SUCCESS) {
+ transitionType = TYPE_TRANSITION_WARM_LAUNCH;
+ } else if (startResult == START_TASK_TO_FRONT) {
+ transitionType = TYPE_TRANSITION_HOT_LAUNCH;
+ }
+ } else if (startResult == START_SUCCESS || startResult == START_TASK_TO_FRONT) {
+ // Task may still exist when cold launching an activity and the start result will be
+ // set to START_TASK_TO_FRONT. Treat this as a COLD launch.
+ transitionType = TYPE_TRANSITION_COLD_LAUNCH;
+ }
+ if (transitionType == INVALID_TRANSITION_TYPE) {
+ // That means the startResult is neither START_SUCCESS nor START_TASK_TO_FRONT.
+ return null;
+ }
+ return new TransitionInfo(r, launchingState, transitionType, processRunning);
+ }
+
+ /** Use {@link TransitionInfo#create} instead to ensure the transition type is valid. */
+ private TransitionInfo(ActivityRecord r, LaunchingState launchingState, int transitionType,
+ boolean processRunning) {
+ mLaunchingState = launchingState;
+ mTransitionStartTimeNs = launchingState.mCurrentTransitionStartTimeNs;
+ mTransitionType = transitionType;
+ mProcessRunning = processRunning;
+ mCurrentTransitionDeviceUptime =
+ (int) TimeUnit.MILLISECONDS.toSeconds(SystemClock.uptimeMillis());
+ setLatestLaunchedActivity(r);
+ launchingState.mAssociatedTransitionInfo = this;
+ }
/**
* Remembers the latest launched activity to represent the final transition. This also
- * increments the number of activities that should be drawn, so a consecutive launching
- * sequence can be coalesced as one event.
+ * tracks the activities that should be drawn, so a consecutive launching sequence can be
+ * coalesced as one event.
*/
void setLatestLaunchedActivity(ActivityRecord r) {
- if (launchedActivity == r) {
+ if (mLastLaunchedActivity == r) {
return;
}
- launchedActivity = r;
+ mLastLaunchedActivity = r;
+ if (!r.noDisplay) {
+ if (DEBUG_METRICS) Slog.i(TAG, "Add pending draw " + r);
+ mPendingDrawActivities.add(r);
+ }
+ }
+
+ /** @return {@code true} if the activity matches a launched activity in this transition. */
+ boolean contains(ActivityRecord r) {
+ return r == mLastLaunchedActivity || mPendingDrawActivities.contains(r);
+ }
+
+ /** Called when the activity is drawn or won't be drawn. */
+ void removePendingDrawActivity(ActivityRecord r) {
+ if (DEBUG_METRICS) Slog.i(TAG, "Remove pending draw " + r);
+ mPendingDrawActivities.remove(r);
+ }
+
+ boolean allDrawn() {
+ return mPendingDrawActivities.isEmpty();
+ }
+
+ int calculateCurrentDelay() {
+ return calculateDelay(SystemClock.elapsedRealtimeNanos());
+ }
+
+ int calculateDelay(long timestampNs) {
+ // Shouldn't take more than 25 days to launch an app, so int is fine here.
+ return (int) TimeUnit.NANOSECONDS.toMillis(timestampNs - mTransitionStartTimeNs);
+ }
+
+ @Override
+ public String toString() {
+ return "TransitionInfo{" + Integer.toHexString(System.identityHashCode(this))
+ + " a=" + mLastLaunchedActivity + " ua=" + mPendingDrawActivities + "}";
}
}
- final class WindowingModeTransitionInfoSnapshot {
+ static final class TransitionInfoSnapshot {
final private ApplicationInfo applicationInfo;
final private WindowProcessController processRecord;
final String packageName;
@@ -231,17 +321,12 @@
final int windowsFullyDrawnDelayMs;
final int activityRecordIdHashCode;
- private WindowingModeTransitionInfoSnapshot(WindowingModeTransitionInfo info) {
- this(info, info.launchedActivity);
+ private TransitionInfoSnapshot(TransitionInfo info) {
+ this(info, info.mLastLaunchedActivity, INVALID_DELAY);
}
- private WindowingModeTransitionInfoSnapshot(WindowingModeTransitionInfo info,
- ActivityRecord launchedActivity) {
- this(info, launchedActivity, INVALID_DELAY);
- }
-
- private WindowingModeTransitionInfoSnapshot(WindowingModeTransitionInfo info,
- ActivityRecord launchedActivity, int windowsFullyDrawnDelayMs) {
+ private TransitionInfoSnapshot(TransitionInfo info, ActivityRecord launchedActivity,
+ int windowsFullyDrawnDelayMs) {
applicationInfo = launchedActivity.info.applicationInfo;
packageName = launchedActivity.packageName;
launchedActivityName = launchedActivity.info.name;
@@ -250,12 +335,12 @@
launchedActivityAppRecordRequiredAbi = launchedActivity.app == null
? null
: launchedActivity.app.getRequiredAbi();
- reason = info.reason;
- startingWindowDelayMs = info.startingWindowDelayMs;
- bindApplicationDelayMs = info.bindApplicationDelayMs;
- windowsDrawnDelayMs = info.windowsDrawnDelayMs;
- type = getTransitionType(info);
- processRecord = findProcessForActivity(launchedActivity);
+ reason = info.mReason;
+ startingWindowDelayMs = info.mStartingWindowDelayMs;
+ bindApplicationDelayMs = info.mBindApplicationDelayMs;
+ windowsDrawnDelayMs = info.mWindowsDrawnDelayMs;
+ type = info.mTransitionType;
+ processRecord = launchedActivity.app;
processName = launchedActivity.processName;
userId = launchedActivity.mUserId;
launchedActivityShortComponentName = launchedActivity.shortComponentName;
@@ -277,11 +362,9 @@
}
}
- ActivityMetricsLogger(ActivityStackSupervisor supervisor, Context context, Looper looper) {
+ ActivityMetricsLogger(ActivityStackSupervisor supervisor, Looper looper) {
mLastLogTimeSecs = SystemClock.elapsedRealtime() / 1000;
mSupervisor = supervisor;
- mContext = context;
- mHandler = new H(looper);
mLaunchObserver = new LaunchObserverRegistryImpl(looper);
}
@@ -291,7 +374,7 @@
// We log even if the window state hasn't changed, because the user might remain in
// home/fullscreen move forever and we would like to track this kind of behavior
// too.
- MetricsLogger.count(mContext, TRON_WINDOW_STATE_VARZ_STRINGS[mWindowState],
+ mMetricsLogger.count(TRON_WINDOW_STATE_VARZ_STRINGS[mWindowState],
(int) (now - mLastLogTimeSecs));
}
mLastLogTimeSecs = now;
@@ -332,145 +415,169 @@
}
}
+ /** @return Non-null {@link TransitionInfo} if the activity is found in an active transition. */
+ @Nullable
+ private TransitionInfo getActiveTransitionInfo(ActivityRecord r) {
+ for (int i = mTransitionInfoList.size() - 1; i >= 0; i--) {
+ final TransitionInfo info = mTransitionInfoList.get(i);
+ if (info.contains(r)) {
+ return info;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * This method should be only used by starting recents and starting from recents, or internal
+ * tests. Because it doesn't lookup caller and always creates a new launching state.
+ *
+ * @see #notifyActivityLaunching(Intent, ActivityRecord, int)
+ */
+ LaunchingState notifyActivityLaunching(Intent intent) {
+ return notifyActivityLaunching(intent, null /* caller */, IGNORE_CALLER);
+ }
+
+ /**
+ * If the caller is found in an active transition, it will be considered as consecutive launch
+ * and coalesced into the active transition.
+ *
+ * @see #notifyActivityLaunching(Intent, ActivityRecord, int)
+ */
+ LaunchingState notifyActivityLaunching(Intent intent, @Nullable ActivityRecord caller) {
+ return notifyActivityLaunching(intent, caller, Binder.getCallingUid());
+ }
+
/**
* Notifies the tracker at the earliest possible point when we are starting to launch an
- * activity.
+ * activity. The caller must ensure that {@link #notifyActivityLaunched} will be called later
+ * with the returned {@link LaunchingState}.
*/
- void notifyActivityLaunching(Intent intent) {
+ private LaunchingState notifyActivityLaunching(Intent intent, @Nullable ActivityRecord caller,
+ int callingUid) {
+ final long transitionStartTimeNs = SystemClock.elapsedRealtimeNanos();
+ TransitionInfo existingInfo = null;
+ if (callingUid != IGNORE_CALLER) {
+ // Associate the launching event to an active transition if the caller is found in its
+ // launched activities.
+ for (int i = mTransitionInfoList.size() - 1; i >= 0; i--) {
+ final TransitionInfo info = mTransitionInfoList.get(i);
+ if (caller != null && info.contains(caller)) {
+ existingInfo = info;
+ break;
+ }
+ if (existingInfo == null && callingUid == info.mLastLaunchedActivity.getUid()) {
+ // Fallback to check the most recent matched uid for the case that the caller is
+ // not an activity.
+ existingInfo = info;
+ }
+ }
+ }
if (DEBUG_METRICS) {
- Slog.i(TAG, String.format("notifyActivityLaunching: active:%b, intent:%s",
- isAnyTransitionActive(),
- intent));
+ Slog.i(TAG, "notifyActivityLaunching intent=" + intent
+ + " existingInfo=" + existingInfo);
}
- if (mCurrentTransitionStartTimeNs == INVALID_START_TIME) {
-
- mCurrentTransitionStartTimeNs = SystemClock.elapsedRealtimeNanos();
- mLastTransitionStartTimeNs = mCurrentTransitionStartTimeNs;
-
- launchObserverNotifyIntentStarted(intent, mCurrentTransitionStartTimeNs);
+ if (existingInfo == null) {
+ // Only notify the observer for a new launching event.
+ launchObserverNotifyIntentStarted(intent, transitionStartTimeNs);
+ final LaunchingState launchingState = new LaunchingState();
+ launchingState.mCurrentTransitionStartTimeNs = transitionStartTimeNs;
+ return launchingState;
}
+ existingInfo.mLaunchingState.mCurrentTransitionStartTimeNs = transitionStartTimeNs;
+ return existingInfo.mLaunchingState;
}
/**
* Notifies the tracker that the activity is actually launching.
*
- * @param resultCode one of the ActivityManager.START_* flags, indicating the result of the
- * launch
- * @param launchedActivity the activity that is being launched
+ * @param launchingState The launching state to track the new or active transition.
+ * @param resultCode One of the {@link android.app.ActivityManager}.START_* flags, indicating
+ * the result of the launch.
+ * @param launchedActivity The activity that is being launched
*/
- void notifyActivityLaunched(int resultCode, ActivityRecord launchedActivity) {
- final WindowProcessController processRecord = findProcessForActivity(launchedActivity);
- final boolean processRunning = processRecord != null;
+ void notifyActivityLaunched(@NonNull LaunchingState launchingState, int resultCode,
+ @Nullable ActivityRecord launchedActivity) {
+ if (launchedActivity == null) {
+ // The launch is aborted, e.g. intent not resolved, class not found.
+ abort(null /* info */, "nothing launched");
+ return;
+ }
+ final WindowProcessController processRecord = launchedActivity.app != null
+ ? launchedActivity.app
+ : mSupervisor.mService.getProcessController(
+ launchedActivity.processName, launchedActivity.info.applicationInfo.uid);
+ // Whether the process that will contains the activity is already running.
+ final boolean processRunning = processRecord != null;
// We consider this a "process switch" if the process of the activity that gets launched
// didn't have an activity that was in started state. In this case, we assume that lot
// of caches might be purged so the time until it produces the first frame is very
// interesting.
- final boolean processSwitch = processRecord == null
+ final boolean processSwitch = !processRunning
|| !processRecord.hasStartedActivity(launchedActivity);
- notifyActivityLaunched(resultCode, launchedActivity, processRunning, processSwitch);
- }
-
- /**
- * Notifies the tracker the the activity is actually launching.
- *
- * @param resultCode one of the ActivityManager.START_* flags, indicating the result of the
- * launch
- * @param launchedActivity the activity being launched
- * @param processRunning whether the process that will contains the activity is already running
- * @param processSwitch whether the process that will contain the activity didn't have any
- * activity that was stopped, i.e. the started activity is "switching"
- * processes
- */
- private void notifyActivityLaunched(int resultCode, ActivityRecord launchedActivity,
- boolean processRunning, boolean processSwitch) {
-
- if (DEBUG_METRICS) Slog.i(TAG, "notifyActivityLaunched"
- + " resultCode=" + resultCode
- + " launchedActivity=" + launchedActivity
- + " processRunning=" + processRunning
- + " processSwitch=" + processSwitch);
-
- // If we are already in an existing transition, only update the activity name, but not the
- // other attributes.
- final @WindowingMode int windowingMode = launchedActivity != null
- ? launchedActivity.getWindowingMode()
- : WINDOWING_MODE_UNDEFINED;
- final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(windowingMode);
- if (mCurrentTransitionStartTimeNs == INVALID_START_TIME) {
- // No transition is active ignore this launch.
- return;
+ final TransitionInfo info = launchingState.mAssociatedTransitionInfo;
+ if (DEBUG_METRICS) {
+ Slog.i(TAG, "notifyActivityLaunched" + " resultCode=" + resultCode
+ + " launchedActivity=" + launchedActivity + " processRunning=" + processRunning
+ + " processSwitch=" + processSwitch + " info=" + info);
}
- if (launchedActivity != null && launchedActivity.mDrawn) {
+ if (launchedActivity.mDrawn) {
// Launched activity is already visible. We cannot measure windows drawn delay.
abort(info, "launched activity already visible");
return;
}
- if (launchedActivity != null && info != null) {
+ if (info != null) {
// If we are already in an existing transition, only update the activity name, but not
// the other attributes.
+ if (DEBUG_METRICS) Slog.i(TAG, "notifyActivityLaunched update launched activity");
// Coalesce multiple (trampoline) activities from a single sequence together.
info.setLatestLaunchedActivity(launchedActivity);
return;
}
- final boolean otherWindowModesLaunching =
- mWindowingModeTransitionInfo.size() > 0 && info == null;
- if ((!isLoggableResultCode(resultCode) || launchedActivity == null || !processSwitch
- || windowingMode == WINDOWING_MODE_UNDEFINED) && !otherWindowModesLaunching) {
- // Failed to launch or it was not a process switch, so we don't care about the timing.
- abort(info, "failed to launch or not a process switch");
+ if (!processSwitch) {
+ abort(info, "not a process switch");
return;
- } else if (otherWindowModesLaunching) {
- // Don't log this windowing mode but continue with the other windowing modes.
+ }
+
+ final TransitionInfo newInfo = TransitionInfo.create(launchedActivity, launchingState,
+ processRunning, resultCode);
+ if (newInfo == null) {
+ abort(info, "unrecognized launch");
return;
}
if (DEBUG_METRICS) Slog.i(TAG, "notifyActivityLaunched successful");
-
- // A new launch sequence [with the windowingMode] has begun.
- // Start tracking it.
- final WindowingModeTransitionInfo newInfo = new WindowingModeTransitionInfo();
- newInfo.setLatestLaunchedActivity(launchedActivity);
- newInfo.currentTransitionProcessRunning = processRunning;
- newInfo.startResult = resultCode;
- mWindowingModeTransitionInfo.put(windowingMode, newInfo);
- mLastWindowingModeTransitionInfo.put(windowingMode, newInfo);
- mCurrentTransitionDeviceUptime = (int) (SystemClock.uptimeMillis() / 1000);
- startTraces(newInfo);
+ // A new launch sequence has begun. Start tracking it.
+ mTransitionInfoList.add(newInfo);
+ mLastTransitionInfo.put(launchedActivity, newInfo);
+ startLaunchTrace(newInfo);
launchObserverNotifyActivityLaunched(newInfo);
}
/**
- * @return True if we should start logging an event for an activity start that returned
- * {@code resultCode} and that we'll indeed get a windows drawn event.
- */
- private boolean isLoggableResultCode(int resultCode) {
- return resultCode == START_SUCCESS || resultCode == START_TASK_TO_FRONT;
- }
-
- /**
* Notifies the tracker that all windows of the app have been drawn.
*/
- WindowingModeTransitionInfoSnapshot notifyWindowsDrawn(@WindowingMode int windowingMode,
- long timestampNs) {
- if (DEBUG_METRICS) Slog.i(TAG, "notifyWindowsDrawn windowingMode=" + windowingMode);
+ @Nullable
+ TransitionInfoSnapshot notifyWindowsDrawn(@NonNull ActivityRecord r, long timestampNs) {
+ if (DEBUG_METRICS) Slog.i(TAG, "notifyWindowsDrawn " + r);
- final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(windowingMode);
- if (info == null || info.numUndrawnActivities == 0) {
+ final TransitionInfo info = getActiveTransitionInfo(r);
+ if (info == null || info.allDrawn()) {
+ if (DEBUG_METRICS) Slog.i(TAG, "notifyWindowsDrawn no activity to be drawn");
return null;
}
- info.windowsDrawnDelayMs = calculateDelay(timestampNs);
- info.numUndrawnActivities--;
- final WindowingModeTransitionInfoSnapshot infoSnapshot =
- new WindowingModeTransitionInfoSnapshot(info);
- if (allWindowsDrawn() && mLoggedTransitionStarting) {
- reset(false /* abort */, info, "notifyWindowsDrawn - all windows drawn", timestampNs);
+ // Always calculate the delay because the caller may need to know the individual drawn time.
+ info.mWindowsDrawnDelayMs = info.calculateDelay(timestampNs);
+ info.removePendingDrawActivity(r);
+ final TransitionInfoSnapshot infoSnapshot = new TransitionInfoSnapshot(info);
+ if (info.mLoggedTransitionStarting && info.allDrawn()) {
+ done(false /* abort */, info, "notifyWindowsDrawn - all windows drawn", timestampNs);
}
return infoSnapshot;
}
@@ -478,70 +585,76 @@
/**
* Notifies the tracker that the starting window was drawn.
*/
- void notifyStartingWindowDrawn(@WindowingMode int windowingMode, long timestampNs) {
- final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(windowingMode);
- if (info == null || info.loggedStartingWindowDrawn) {
+ void notifyStartingWindowDrawn(@NonNull ActivityRecord r) {
+ final TransitionInfo info = getActiveTransitionInfo(r);
+ if (info == null || info.mLoggedStartingWindowDrawn) {
return;
}
- info.loggedStartingWindowDrawn = true;
- info.startingWindowDelayMs = calculateDelay(timestampNs);
+ if (DEBUG_METRICS) Slog.i(TAG, "notifyStartingWindowDrawn " + r);
+ info.mLoggedStartingWindowDrawn = true;
+ info.mStartingWindowDelayMs = info.calculateDelay(SystemClock.elapsedRealtimeNanos());
}
/**
* Notifies the tracker that the app transition is starting.
*
- * @param windowingModeToReason A map from windowing mode to a reason integer, which must be on
- * of ActivityTaskManagerInternal.APP_TRANSITION_* reasons.
+ * @param activityToReason A map from activity to a reason integer, which must be on of
+ * ActivityTaskManagerInternal.APP_TRANSITION_* reasons.
*/
- void notifyTransitionStarting(SparseIntArray windowingModeToReason, long timestampNs) {
- if (!isAnyTransitionActive() || mLoggedTransitionStarting) {
- // Ignore calls to this made after a reset and prior to notifyActivityLaunching.
-
- // Ignore any subsequent notifyTransitionStarting until the next reset.
- return;
- }
+ void notifyTransitionStarting(ArrayMap<ActivityRecord, Integer> activityToReason) {
if (DEBUG_METRICS) Slog.i(TAG, "notifyTransitionStarting");
- mCurrentTransitionDelayMs = calculateDelay(timestampNs);
- mLoggedTransitionStarting = true;
- WindowingModeTransitionInfo foundInfo = null;
- for (int index = windowingModeToReason.size() - 1; index >= 0; index--) {
- final @WindowingMode int windowingMode = windowingModeToReason.keyAt(index);
- final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(
- windowingMode);
- if (info == null) {
+ final long timestampNs = SystemClock.elapsedRealtimeNanos();
+ for (int index = activityToReason.size() - 1; index >= 0; index--) {
+ final ActivityRecord r = activityToReason.keyAt(index);
+ final TransitionInfo info = getActiveTransitionInfo(r);
+ if (info == null || info.mLoggedTransitionStarting) {
+ // Ignore any subsequent notifyTransitionStarting.
continue;
}
- info.reason = windowingModeToReason.valueAt(index);
- foundInfo = info;
+ if (DEBUG_METRICS) {
+ Slog.i(TAG, "notifyTransitionStarting activity=" + r + " info=" + info);
+ }
+
+ info.mCurrentTransitionDelayMs = info.calculateDelay(timestampNs);
+ info.mReason = activityToReason.valueAt(index);
+ info.mLoggedTransitionStarting = true;
+ if (info.allDrawn()) {
+ done(false /* abort */, info, "notifyTransitionStarting - all windows drawn",
+ timestampNs);
+ }
}
- if (allWindowsDrawn()) {
- // abort metrics collection if we cannot find a matching transition.
- final boolean abortMetrics = foundInfo == null;
- reset(abortMetrics, foundInfo, "notifyTransitionStarting - all windows drawn",
- timestampNs /* timestampNs */);
- }
+ }
+
+ /** Makes sure that the reference to the removed activity is cleared. */
+ void notifyActivityRemoved(@NonNull ActivityRecord r) {
+ mLastTransitionInfo.remove(r);
}
/**
* Notifies the tracker that the visibility of an app is changing.
*
- * @param activityRecord the app that is changing its visibility
+ * @param r the app that is changing its visibility
*/
- void notifyVisibilityChanged(ActivityRecord activityRecord) {
- final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(
- activityRecord.getWindowingMode());
+ void notifyVisibilityChanged(@NonNull ActivityRecord r) {
+ final TransitionInfo info = getActiveTransitionInfo(r);
if (info == null) {
return;
}
- if (info.launchedActivity != activityRecord) {
+ if (DEBUG_METRICS) {
+ Slog.i(TAG, "notifyVisibilityChanged " + r + " visible=" + r.mVisibleRequested
+ + " state=" + r.getState() + " finishing=" + r.finishing);
+ }
+ if (!r.mVisibleRequested || r.finishing) {
+ info.removePendingDrawActivity(r);
+ }
+ if (info.mLastLaunchedActivity != r) {
return;
}
- final Task t = activityRecord.getTask();
- final SomeArgs args = SomeArgs.obtain();
- args.arg1 = t;
- args.arg2 = activityRecord;
- mHandler.obtainMessage(MSG_CHECK_VISIBILITY, args).sendToTarget();
+ // The activity and its task are passed separately because the activity may be removed from
+ // the task later.
+ r.mAtmService.mH.sendMessage(PooledLambda.obtainMessage(
+ ActivityMetricsLogger::checkVisibility, this, r.getTask(), r));
}
/** @return {@code true} if the given task has an activity will be drawn. */
@@ -552,8 +665,7 @@
private void checkVisibility(Task t, ActivityRecord r) {
synchronized (mSupervisor.mService.mGlobalLock) {
- final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.get(
- r.getWindowingMode());
+ final TransitionInfo info = getActiveTransitionInfo(r);
// If we have an active transition that's waiting on a certain activity that will be
// invisible now, we'll never get onWindowsDrawn, so abort the transition if necessary.
@@ -565,7 +677,7 @@
// The notified activity whose visibility changed is no longer the launched activity.
// We can still wait to get onWindowsDrawn.
- if (info.launchedActivity != r) {
+ if (info.mLastLaunchedActivity != r) {
return;
}
@@ -579,11 +691,7 @@
if (DEBUG_METRICS) Slog.i(TAG, "notifyVisibilityChanged to invisible activity=" + r);
logAppTransitionCancel(info);
- // Abort if this is the only one active transition.
- if (mWindowingModeTransitionInfo.size() == 1
- && mWindowingModeTransitionInfo.get(r.getWindowingMode()) != null) {
- abort(info, "notifyVisibilityChanged to invisible");
- }
+ abort(info, "notifyVisibilityChanged to invisible");
}
}
@@ -593,137 +701,86 @@
* @param appInfo The client into which we'll call bindApplication.
*/
void notifyBindApplication(ApplicationInfo appInfo) {
- for (int i = mWindowingModeTransitionInfo.size() - 1; i >= 0; i--) {
- final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.valueAt(i);
+ for (int i = mTransitionInfoList.size() - 1; i >= 0; i--) {
+ final TransitionInfo info = mTransitionInfoList.get(i);
// App isn't attached to record yet, so match with info.
- if (info.launchedActivity.info.applicationInfo == appInfo) {
- info.bindApplicationDelayMs = calculateCurrentDelay();
+ if (info.mLastLaunchedActivity.info.applicationInfo == appInfo) {
+ info.mBindApplicationDelayMs = info.calculateCurrentDelay();
}
}
}
- @VisibleForTesting
- boolean allWindowsDrawn() {
- for (int index = mWindowingModeTransitionInfo.size() - 1; index >= 0; index--) {
- if (mWindowingModeTransitionInfo.valueAt(index).numUndrawnActivities != 0) {
- return false;
- }
- }
- return true;
- }
-
- private boolean isAnyTransitionActive() {
- return mCurrentTransitionStartTimeNs != INVALID_START_TIME
- && mWindowingModeTransitionInfo.size() > 0;
- }
-
/** Aborts tracking of current launch metrics. */
- private void abort(WindowingModeTransitionInfo info, String cause) {
- reset(true /* abort */, info, cause, 0L /* timestampNs */);
+ private void abort(TransitionInfo info, String cause) {
+ done(true /* abort */, info, cause, 0L /* timestampNs */);
}
- private void reset(boolean abort, WindowingModeTransitionInfo info, String cause,
+ /** Called when the given transition (info) is no longer active. */
+ private void done(boolean abort, @Nullable TransitionInfo info, String cause,
long timestampNs) {
- final boolean isAnyTransitionActive = isAnyTransitionActive();
if (DEBUG_METRICS) {
- Slog.i(TAG, "reset abort=" + abort + " cause=" + cause + " timestamp=" + timestampNs
- + " active=" + isAnyTransitionActive);
+ Slog.i(TAG, "done abort=" + abort + " cause=" + cause + " timestamp=" + timestampNs
+ + " info=" + info);
}
- if (!abort && isAnyTransitionActive) {
- logAppTransitionMultiEvents();
- }
- stopLaunchTrace(info);
-
- // Ignore reset-after reset.
- if (isAnyTransitionActive) {
- // LaunchObserver callbacks.
- if (abort) {
- launchObserverNotifyActivityLaunchCancelled(info);
- } else {
- launchObserverNotifyActivityLaunchFinished(info, timestampNs);
- }
- } else {
+ if (info == null) {
launchObserverNotifyIntentFailed();
- }
-
- mCurrentTransitionStartTimeNs = INVALID_START_TIME;
- mCurrentTransitionDelayMs = INVALID_DELAY;
- mLoggedTransitionStarting = false;
- mWindowingModeTransitionInfo.clear();
- }
-
- private int calculateCurrentDelay() {
- // Shouldn't take more than 25 days to launch an app, so int is fine here.
- return (int) TimeUnit.NANOSECONDS
- .toMillis(SystemClock.elapsedRealtimeNanos() - mCurrentTransitionStartTimeNs);
- }
-
- private int calculateDelay(long timestampNs) {
- // Shouldn't take more than 25 days to launch an app, so int is fine here.
- return (int) TimeUnit.NANOSECONDS.toMillis(timestampNs -
- mCurrentTransitionStartTimeNs);
- }
-
- private void logAppTransitionCancel(WindowingModeTransitionInfo info) {
- final int type = getTransitionType(info);
- if (type == INVALID_TRANSITION_TYPE) {
return;
}
+
+ stopLaunchTrace(info);
+ if (abort) {
+ launchObserverNotifyActivityLaunchCancelled(info);
+ } else {
+ logAppTransitionFinished(info);
+ launchObserverNotifyActivityLaunchFinished(info, timestampNs);
+ }
+ info.mPendingDrawActivities.clear();
+ mTransitionInfoList.remove(info);
+ }
+
+ private void logAppTransitionCancel(TransitionInfo info) {
+ final int type = info.mTransitionType;
+ final ActivityRecord activity = info.mLastLaunchedActivity;
final LogMaker builder = new LogMaker(APP_TRANSITION_CANCELLED);
- builder.setPackageName(info.launchedActivity.packageName);
+ builder.setPackageName(activity.packageName);
builder.setType(type);
- builder.addTaggedData(FIELD_CLASS_NAME, info.launchedActivity.info.name);
+ builder.addTaggedData(FIELD_CLASS_NAME, activity.info.name);
mMetricsLogger.write(builder);
StatsLog.write(
StatsLog.APP_START_CANCELED,
- info.launchedActivity.info.applicationInfo.uid,
- info.launchedActivity.packageName,
+ activity.info.applicationInfo.uid,
+ activity.packageName,
convertAppStartTransitionType(type),
- info.launchedActivity.info.name);
+ activity.info.name);
if (DEBUG_METRICS) {
Slog.i(TAG, String.format("APP_START_CANCELED(%s, %s, %s, %s)",
- info.launchedActivity.info.applicationInfo.uid,
- info.launchedActivity.packageName,
+ activity.info.applicationInfo.uid,
+ activity.packageName,
convertAppStartTransitionType(type),
- info.launchedActivity.info.name));
+ activity.info.name));
}
}
- private void logAppTransitionMultiEvents() {
- if (DEBUG_METRICS) Slog.i(TAG, "logging transition events");
- for (int index = mWindowingModeTransitionInfo.size() - 1; index >= 0; index--) {
- final WindowingModeTransitionInfo info = mWindowingModeTransitionInfo.valueAt(index);
- final int type = getTransitionType(info);
- if (type == INVALID_TRANSITION_TYPE) {
- if (DEBUG_METRICS) {
- Slog.i(TAG, "invalid transition type"
- + " processRunning=" + info.currentTransitionProcessRunning
- + " startResult=" + info.startResult);
- }
- return;
- }
+ private void logAppTransitionFinished(@NonNull TransitionInfo info) {
+ if (DEBUG_METRICS) Slog.i(TAG, "logging finished transition " + info);
- // Take a snapshot of the transition info before sending it to the handler for logging.
- // This will avoid any races with other operations that modify the ActivityRecord.
- final WindowingModeTransitionInfoSnapshot infoSnapshot =
- new WindowingModeTransitionInfoSnapshot(info);
- final int currentTransitionDeviceUptime = mCurrentTransitionDeviceUptime;
- final int currentTransitionDelayMs = mCurrentTransitionDelayMs;
- BackgroundThread.getHandler().post(() -> logAppTransition(
- currentTransitionDeviceUptime, currentTransitionDelayMs, infoSnapshot));
- BackgroundThread.getHandler().post(() -> logAppDisplayed(infoSnapshot));
- if (info.pendingFullyDrawn != null) {
- info.pendingFullyDrawn.run();
- }
-
- info.launchedActivity.info.launchToken = null;
+ // Take a snapshot of the transition info before sending it to the handler for logging.
+ // This will avoid any races with other operations that modify the ActivityRecord.
+ final TransitionInfoSnapshot infoSnapshot = new TransitionInfoSnapshot(info);
+ BackgroundThread.getHandler().post(() -> logAppTransition(
+ info.mCurrentTransitionDeviceUptime, info.mCurrentTransitionDelayMs, infoSnapshot));
+ BackgroundThread.getHandler().post(() -> logAppDisplayed(infoSnapshot));
+ if (info.mPendingFullyDrawn != null) {
+ info.mPendingFullyDrawn.run();
}
+
+ info.mLastLaunchedActivity.info.launchToken = null;
}
// This gets called on a background thread without holding the activity manager lock.
private void logAppTransition(int currentTransitionDeviceUptime, int currentTransitionDelayMs,
- WindowingModeTransitionInfoSnapshot info) {
+ TransitionInfoSnapshot info) {
final LogMaker builder = new LogMaker(APP_TRANSITION);
builder.setPackageName(info.packageName);
builder.setType(info.type);
@@ -794,7 +851,7 @@
logAppStartMemoryStateCapture(info);
}
- private void logAppDisplayed(WindowingModeTransitionInfoSnapshot info) {
+ private void logAppDisplayed(TransitionInfoSnapshot info) {
if (info.type != TYPE_TRANSITION_WARM_LAUNCH && info.type != TYPE_TRANSITION_COLD_LAUNCH) {
return;
}
@@ -825,26 +882,25 @@
return StatsLog.APP_START_OCCURRED__TYPE__UNKNOWN;
}
- /** @return the last known window drawn delay of the given windowing mode. */
- int getLastDrawnDelayMs(@WindowingMode int windowingMode) {
- final WindowingModeTransitionInfo info = mLastWindowingModeTransitionInfo.get(
- windowingMode);
- return info != null ? info.windowsDrawnDelayMs : INVALID_DELAY;
+ /** @return the last known window drawn delay of the given activity. */
+ int getLastDrawnDelayMs(ActivityRecord r) {
+ final TransitionInfo info = mLastTransitionInfo.get(r);
+ return info != null ? info.mWindowsDrawnDelayMs : INVALID_DELAY;
}
- WindowingModeTransitionInfoSnapshot logAppTransitionReportedDrawn(ActivityRecord r,
+ /** @see android.app.Activity#reportFullyDrawn */
+ TransitionInfoSnapshot logAppTransitionReportedDrawn(ActivityRecord r,
boolean restoredFromBundle) {
- final WindowingModeTransitionInfo info = mLastWindowingModeTransitionInfo.get(
- r.getWindowingMode());
+ final TransitionInfo info = mLastTransitionInfo.get(r);
if (info == null) {
return null;
}
- if (info.numUndrawnActivities > 0 && info.pendingFullyDrawn == null) {
+ if (!info.allDrawn() && info.mPendingFullyDrawn == null) {
// There are still undrawn activities, postpone reporting fully drawn until all of its
// windows are drawn. So that is closer to an usable state.
- info.pendingFullyDrawn = () -> {
+ info.mPendingFullyDrawn = () -> {
logAppTransitionReportedDrawn(r, restoredFromBundle);
- info.pendingFullyDrawn = null;
+ info.mPendingFullyDrawn = null;
};
return null;
}
@@ -853,39 +909,39 @@
// actually used to trace this function, but instead the logical task that this function
// fullfils (handling reportFullyDrawn() callbacks).
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
- "ActivityManager:ReportingFullyDrawn " + info.launchedActivity.packageName);
+ "ActivityManager:ReportingFullyDrawn " + info.mLastLaunchedActivity.packageName);
final LogMaker builder = new LogMaker(APP_TRANSITION_REPORTED_DRAWN);
builder.setPackageName(r.packageName);
builder.addTaggedData(FIELD_CLASS_NAME, r.info.name);
final long currentTimestampNs = SystemClock.elapsedRealtimeNanos();
- final long startupTimeMs = info.pendingFullyDrawn != null
- ? info.windowsDrawnDelayMs
- : TimeUnit.NANOSECONDS.toMillis(currentTimestampNs - mLastTransitionStartTimeNs);
+ final long startupTimeMs = info.mPendingFullyDrawn != null
+ ? info.mWindowsDrawnDelayMs
+ : TimeUnit.NANOSECONDS.toMillis(currentTimestampNs - info.mTransitionStartTimeNs);
builder.addTaggedData(APP_TRANSITION_REPORTED_DRAWN_MS, startupTimeMs);
builder.setType(restoredFromBundle
? TYPE_TRANSITION_REPORTED_DRAWN_WITH_BUNDLE
: TYPE_TRANSITION_REPORTED_DRAWN_NO_BUNDLE);
builder.addTaggedData(APP_TRANSITION_PROCESS_RUNNING,
- info.currentTransitionProcessRunning ? 1 : 0);
+ info.mProcessRunning ? 1 : 0);
mMetricsLogger.write(builder);
StatsLog.write(
StatsLog.APP_START_FULLY_DRAWN,
- info.launchedActivity.info.applicationInfo.uid,
- info.launchedActivity.packageName,
+ info.mLastLaunchedActivity.info.applicationInfo.uid,
+ info.mLastLaunchedActivity.packageName,
restoredFromBundle
? StatsLog.APP_START_FULLY_DRAWN__TYPE__WITH_BUNDLE
: StatsLog.APP_START_FULLY_DRAWN__TYPE__WITHOUT_BUNDLE,
- info.launchedActivity.info.name,
- info.currentTransitionProcessRunning,
+ info.mLastLaunchedActivity.info.name,
+ info.mProcessRunning,
startupTimeMs);
// Ends the trace started at the beginning of this function. This is located here to allow
// the trace slice to have a noticable duration.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
- final WindowingModeTransitionInfoSnapshot infoSnapshot =
- new WindowingModeTransitionInfoSnapshot(info, r, (int) startupTimeMs);
+ final TransitionInfoSnapshot infoSnapshot =
+ new TransitionInfoSnapshot(info, r, (int) startupTimeMs);
BackgroundThread.getHandler().post(() -> logAppFullyDrawn(infoSnapshot));
// Notify reportFullyDrawn event.
@@ -894,7 +950,7 @@
return infoSnapshot;
}
- private void logAppFullyDrawn(WindowingModeTransitionInfoSnapshot info) {
+ private void logAppFullyDrawn(TransitionInfoSnapshot info) {
if (info.type != TYPE_TRANSITION_WARM_LAUNCH && info.type != TYPE_TRANSITION_COLD_LAUNCH) {
return;
}
@@ -970,23 +1026,7 @@
mMetricsLogger.write(builder);
}
- private int getTransitionType(WindowingModeTransitionInfo info) {
- if (info.currentTransitionProcessRunning) {
- if (info.startResult == START_SUCCESS) {
- return TYPE_TRANSITION_WARM_LAUNCH;
- } else if (info.startResult == START_TASK_TO_FRONT) {
- return TYPE_TRANSITION_HOT_LAUNCH;
- }
- } else if (info.startResult == START_SUCCESS
- || (info.startResult == START_TASK_TO_FRONT)) {
- // Task may still exist when cold launching an activity and the start
- // result will be set to START_TASK_TO_FRONT. Treat this as a COLD launch.
- return TYPE_TRANSITION_COLD_LAUNCH;
- }
- return INVALID_TRANSITION_TYPE;
- }
-
- private void logAppStartMemoryStateCapture(WindowingModeTransitionInfoSnapshot info) {
+ private void logAppStartMemoryStateCapture(TransitionInfoSnapshot info) {
if (info.processRecord == null) {
if (DEBUG_METRICS) Slog.i(TAG, "logAppStartMemoryStateCapture processRecord null");
return;
@@ -1012,13 +1052,6 @@
memoryStat.swapInBytes);
}
- private WindowProcessController findProcessForActivity(ActivityRecord launchedActivity) {
- return launchedActivity != null
- ? mSupervisor.mService.mProcessNames.get(
- launchedActivity.processName, launchedActivity.info.applicationInfo.uid)
- : null;
- }
-
private ArtManagerInternal getArtManagerInternal() {
if (mArtManagerInternal == null) {
// Note that this may be null.
@@ -1029,30 +1062,24 @@
return mArtManagerInternal;
}
- /**
- * Starts traces for app launch.
- *
- * @param info
- * */
- private void startTraces(WindowingModeTransitionInfo info) {
- if (!Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER) || info == null
- || info.launchTraceActive) {
+ /** Starts trace for an activity is actually launching. */
+ private void startLaunchTrace(@NonNull TransitionInfo info) {
+ if (DEBUG_METRICS) Slog.i(TAG, "startLaunchTrace " + info);
+ if (!Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
return;
}
- Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "launching: "
- + info.launchedActivity.packageName, 0);
- info.launchTraceActive = true;
+ info.mLaunchTraceName = "launching: " + info.mLastLaunchedActivity.packageName;
+ Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, info.mLaunchTraceName, 0);
}
- private void stopLaunchTrace(WindowingModeTransitionInfo info) {
- if (info == null) {
+ /** Stops trace for the launch is completed or cancelled. */
+ private void stopLaunchTrace(@NonNull TransitionInfo info) {
+ if (DEBUG_METRICS) Slog.i(TAG, "stopLaunchTrace " + info);
+ if (info.mLaunchTraceName == null) {
return;
}
- if (info.launchTraceActive) {
- Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, "launching: "
- + info.launchedActivity.packageName, 0);
- info.launchTraceActive = false;
- }
+ Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER, info.mLaunchTraceName, 0);
+ info.mLaunchTraceName = null;
}
public ActivityMetricsLaunchObserverRegistry getLaunchObserverRegistry() {
@@ -1088,16 +1115,16 @@
* Notify the {@link ActivityMetricsLaunchObserver} that the current launch sequence's activity
* has started.
*/
- private void launchObserverNotifyActivityLaunched(WindowingModeTransitionInfo info) {
+ private void launchObserverNotifyActivityLaunched(TransitionInfo info) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
"MetricsLogger:launchObserverNotifyActivityLaunched");
@ActivityMetricsLaunchObserver.Temperature int temperature =
- convertTransitionTypeToLaunchObserverTemperature(getTransitionType(info));
+ convertTransitionTypeToLaunchObserverTemperature(info.mTransitionType);
// Beginning a launch is timing sensitive and so should be observed as soon as possible.
- mLaunchObserver.onActivityLaunched(convertActivityRecordToProto(info.launchedActivity),
- temperature);
+ mLaunchObserver.onActivityLaunched(convertActivityRecordToProto(info.mLastLaunchedActivity),
+ temperature);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
@@ -1116,12 +1143,12 @@
* Notify the {@link ActivityMetricsLaunchObserver} that the current launch sequence is
* cancelled.
*/
- private void launchObserverNotifyActivityLaunchCancelled(WindowingModeTransitionInfo info) {
+ private void launchObserverNotifyActivityLaunchCancelled(TransitionInfo info) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
"MetricsLogger:launchObserverNotifyActivityLaunchCancelled");
final @ActivityMetricsLaunchObserver.ActivityRecordProto byte[] activityRecordProto =
- info != null ? convertActivityRecordToProto(info.launchedActivity) : null;
+ info != null ? convertActivityRecordToProto(info.mLastLaunchedActivity) : null;
mLaunchObserver.onActivityLaunchCancelled(activityRecordProto);
@@ -1132,14 +1159,12 @@
* Notify the {@link ActivityMetricsLaunchObserver} that the current launch sequence's activity
* has fully finished (successfully).
*/
- private void launchObserverNotifyActivityLaunchFinished(WindowingModeTransitionInfo info,
- long timestampNs) {
+ private void launchObserverNotifyActivityLaunchFinished(TransitionInfo info, long timestampNs) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
"MetricsLogger:launchObserverNotifyActivityLaunchFinished");
- mLaunchObserver
- .onActivityLaunchFinished(convertActivityRecordToProto(info.launchedActivity),
- timestampNs);
+ mLaunchObserver.onActivityLaunchFinished(
+ convertActivityRecordToProto(info.mLastLaunchedActivity), timestampNs);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 6af5025..963e090 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -312,7 +312,7 @@
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.protolog.common.ProtoLog;
import com.android.server.uri.UriPermissionOwner;
-import com.android.server.wm.ActivityMetricsLogger.WindowingModeTransitionInfoSnapshot;
+import com.android.server.wm.ActivityMetricsLogger.TransitionInfoSnapshot;
import com.android.server.wm.ActivityStack.ActivityState;
import com.android.server.wm.WindowManagerService.H;
import com.android.server.wm.utils.InsetUtils;
@@ -3010,6 +3010,7 @@
getDisplayContent().mChangingApps.remove(this);
getDisplayContent().mUnknownAppVisibilityController.appRemovedOrHidden(this);
mWmService.mTaskSnapshotController.onAppRemoved(this);
+ mStackSupervisor.getActivityMetricsLogger().notifyActivityRemoved(this);
waitingToShow = false;
if (getDisplayContent().mClosingApps.contains(this)) {
delayed = true;
@@ -3075,7 +3076,7 @@
}
// Reset the last saved PiP snap fraction on removal.
- mDisplayContent.mPinnedStackControllerLocked.resetReentrySnapFraction(mActivityComponent);
+ mDisplayContent.mPinnedStackControllerLocked.resetReentryBounds(mActivityComponent);
mRemovingFromDisplay = false;
}
@@ -4329,7 +4330,7 @@
ProtoLog.v(WM_DEBUG_ADD_REMOVE, "notifyAppStopped: %s", this);
mAppStopped = true;
// Reset the last saved PiP snap fraction on app stop.
- mDisplayContent.mPinnedStackControllerLocked.resetReentrySnapFraction(mActivityComponent);
+ mDisplayContent.mPinnedStackControllerLocked.resetReentryBounds(mActivityComponent);
destroySurfaces();
// Remove any starting window that was added for this app if they are still around.
removeStartingWindow();
@@ -4985,7 +4986,7 @@
}
void reportFullyDrawnLocked(boolean restoredFromBundle) {
- final WindowingModeTransitionInfoSnapshot info = mStackSupervisor
+ final TransitionInfoSnapshot info = mStackSupervisor
.getActivityMetricsLogger().logAppTransitionReportedDrawn(this, restoredFromBundle);
if (info != null) {
mStackSupervisor.reportActivityLaunchedLocked(false /* timeout */, this,
@@ -5017,8 +5018,8 @@
if (!drawn) {
return;
}
- final WindowingModeTransitionInfoSnapshot info = mStackSupervisor
- .getActivityMetricsLogger().notifyWindowsDrawn(getWindowingMode(), timestampNs);
+ final TransitionInfoSnapshot info = mStackSupervisor
+ .getActivityMetricsLogger().notifyWindowsDrawn(this, timestampNs);
final int windowsDrawnDelayMs = info != null ? info.windowsDrawnDelayMs : INVALID_DELAY;
final @LaunchState int launchState = info != null ? info.getLaunchState() : -1;
mStackSupervisor.reportActivityLaunchedLocked(false /* timeout */, this,
@@ -5219,7 +5220,8 @@
}
}
} else if (w.isDrawnLw()) {
- onStartingWindowDrawn(SystemClock.elapsedRealtimeNanos());
+ // The starting window for this container is drawn.
+ mStackSupervisor.getActivityMetricsLogger().notifyStartingWindowDrawn(this);
startingDisplayed = true;
}
}
@@ -5227,14 +5229,6 @@
return isInterestingAndDrawn;
}
- /** Called when the starting window for this container is drawn. */
- private void onStartingWindowDrawn(long timestampNs) {
- synchronized (mAtmService.mGlobalLock) {
- mAtmService.mStackSupervisor.getActivityMetricsLogger().notifyStartingWindowDrawn(
- getWindowingMode(), timestampNs);
- }
- }
-
/**
* Called when the key dispatching to a window associated with the app window container
* timed-out.
@@ -6572,7 +6566,7 @@
stackBounds = mTmpRect;
pinnedStack.getBounds(stackBounds);
}
- mDisplayContent.mPinnedStackControllerLocked.saveReentrySnapFraction(
+ mDisplayContent.mPinnedStackControllerLocked.saveReentryBounds(
mActivityComponent, stackBounds);
}
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 0376d2c..d98aa6f 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -142,6 +142,7 @@
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.am.ActivityManagerService;
import com.android.server.am.UserState;
+import com.android.server.wm.ActivityMetricsLogger.LaunchingState;
import java.io.FileDescriptor;
import java.io.IOException;
@@ -443,8 +444,7 @@
mInitialized = true;
setRunningTasks(new RunningTasks());
- mActivityMetricsLogger = new ActivityMetricsLogger(this, mService.mContext,
- mHandler.getLooper());
+ mActivityMetricsLogger = new ActivityMetricsLogger(this, mHandler.getLooper());
mKeyguardController = new KeyguardController(mService, this);
mPersisterQueue = new PersisterQueue();
@@ -576,8 +576,7 @@
}
void stopWaitingForActivityVisible(ActivityRecord r) {
- stopWaitingForActivityVisible(r,
- getActivityMetricsLogger().getLastDrawnDelayMs(r.getWindowingMode()));
+ stopWaitingForActivityVisible(r, getActivityMetricsLogger().getLastDrawnDelayMs(r));
}
void stopWaitingForActivityVisible(ActivityRecord r, long totalTime) {
@@ -2762,7 +2761,8 @@
mRootActivityContainer.sendPowerHintForLaunchStartIfNeeded(
true /* forceSend */, targetActivity);
- mActivityMetricsLogger.notifyActivityLaunching(task.intent);
+ final LaunchingState launchingState =
+ mActivityMetricsLogger.notifyActivityLaunching(task.intent);
try {
mService.moveTaskToFrontLocked(null /* appThread */, null /* callingPackage */,
task.mTaskId, 0, options, true /* fromRecents */);
@@ -2770,8 +2770,8 @@
// the override pending app transition will be applied immediately.
targetActivity.applyOptionsLocked();
} finally {
- mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT,
- targetActivity);
+ mActivityMetricsLogger.notifyActivityLaunched(launchingState,
+ START_TASK_TO_FRONT, targetActivity);
}
mService.getActivityStartController().postStartActivityProcessingForLastStarter(
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index a496396..8164bf4 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -121,6 +121,7 @@
import com.android.internal.app.IVoiceInteractor;
import com.android.server.am.PendingIntentRecord;
import com.android.server.pm.InstantAppResolver;
+import com.android.server.wm.ActivityMetricsLogger.LaunchingState;
import com.android.server.wm.ActivityStackSupervisor.PendingActivityLaunch;
import com.android.server.wm.LaunchParamsController.LaunchParams;
@@ -572,15 +573,16 @@
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, Task inTask) {
try {
- mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(r.intent);
+ final LaunchingState launchingState = mSupervisor.getActivityMetricsLogger()
+ .notifyActivityLaunching(r.intent, r.resultTo);
mLastStartReason = "startResolvedActivity";
mLastStartActivityTimeMs = System.currentTimeMillis();
mLastStartActivityRecord = r;
mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,
voiceInteractor, startFlags, doResume, options, inTask,
false /* restrictedBgActivity */);
- mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(mLastStartActivityResult,
- mLastStartActivityRecord);
+ mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(launchingState,
+ mLastStartActivityResult, mLastStartActivityRecord);
} finally {
onExecutionComplete();
}
@@ -598,8 +600,14 @@
throw new IllegalArgumentException("File descriptors passed in Intent");
}
- mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(mRequest.intent);
+ final LaunchingState launchingState;
+ synchronized (mService.mGlobalLock) {
+ final ActivityRecord caller = ActivityRecord.forTokenLocked(mRequest.resultTo);
+ launchingState = mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(
+ mRequest.intent, caller);
+ }
+ // Do not lock the resolving to avoid potential deadlock.
if (mRequest.activityInfo == null) {
mRequest.resolveActivity(mSupervisor);
}
@@ -643,7 +651,7 @@
// Notify ActivityMetricsLogger that the activity has launched.
// ActivityMetricsLogger will then wait for the windows to be drawn and populate
// WaitResult.
- mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(res,
+ mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(launchingState, res,
mLastStartActivityRecord);
return getExternalResult(mRequest.waitResult == null ? res
: waitForResult(res, mLastStartActivityRecord));
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index cce005b..25f6d6f 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -32,9 +32,7 @@
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
-import android.os.SystemClock;
import android.service.voice.IVoiceInteractionSession;
-import android.util.SparseIntArray;
import android.util.proto.ProtoOutputStream;
import com.android.internal.app.IVoiceInteractor;
@@ -154,17 +152,6 @@
IVoiceInteractor mInteractor);
/**
- * Callback for window manager to let activity manager know that we are finally starting the
- * app transition;
- *
- * @param reasons A map from windowing mode to a reason integer why the transition was started,
- * which must be one of the APP_TRANSITION_* values.
- * @param timestampNs The time at which the app transition started in
- * {@link SystemClock#elapsedRealtimeNs()} ()} timebase.
- */
- public abstract void notifyAppTransitionStarting(SparseIntArray reasons, long timestampNs);
-
- /**
* Callback for window manager to let activity manager know that the app transition was
* cancelled.
*/
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index df03940..d097368 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -220,7 +220,6 @@
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
-import android.util.SparseIntArray;
import android.util.StatsLog;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
@@ -1228,25 +1227,23 @@
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
final WaitResult res = new WaitResult();
- synchronized (mGlobalLock) {
- enforceNotIsolatedCaller("startActivityAndWait");
- userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
- userId, "startActivityAndWait");
- // TODO: Switch to user app stacks here.
- getActivityStartController().obtainStarter(intent, "startActivityAndWait")
- .setCaller(caller)
- .setCallingPackage(callingPackage)
- .setResolvedType(resolvedType)
- .setResultTo(resultTo)
- .setResultWho(resultWho)
- .setRequestCode(requestCode)
- .setStartFlags(startFlags)
- .setActivityOptions(bOptions)
- .setUserId(userId)
- .setProfilerInfo(profilerInfo)
- .setWaitResult(res)
- .execute();
- }
+ enforceNotIsolatedCaller("startActivityAndWait");
+ userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
+ userId, "startActivityAndWait");
+ // TODO: Switch to user app stacks here.
+ getActivityStartController().obtainStarter(intent, "startActivityAndWait")
+ .setCaller(caller)
+ .setCallingPackage(callingPackage)
+ .setResolvedType(resolvedType)
+ .setResultTo(resultTo)
+ .setResultWho(resultWho)
+ .setRequestCode(requestCode)
+ .setStartFlags(startFlags)
+ .setActivityOptions(bOptions)
+ .setUserId(userId)
+ .setProfilerInfo(profilerInfo)
+ .setWaitResult(res)
+ .execute();
return res;
}
@@ -1254,24 +1251,22 @@
public final int startActivityWithConfig(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, Configuration config, Bundle bOptions, int userId) {
- synchronized (mGlobalLock) {
- enforceNotIsolatedCaller("startActivityWithConfig");
- userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
- "startActivityWithConfig");
- // TODO: Switch to user app stacks here.
- return getActivityStartController().obtainStarter(intent, "startActivityWithConfig")
- .setCaller(caller)
- .setCallingPackage(callingPackage)
- .setResolvedType(resolvedType)
- .setResultTo(resultTo)
- .setResultWho(resultWho)
- .setRequestCode(requestCode)
- .setStartFlags(startFlags)
- .setGlobalConfiguration(config)
- .setActivityOptions(bOptions)
- .setUserId(userId)
- .execute();
- }
+ enforceNotIsolatedCaller("startActivityWithConfig");
+ userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId,
+ "startActivityWithConfig");
+ // TODO: Switch to user app stacks here.
+ return getActivityStartController().obtainStarter(intent, "startActivityWithConfig")
+ .setCaller(caller)
+ .setCallingPackage(callingPackage)
+ .setResolvedType(resolvedType)
+ .setResultTo(resultTo)
+ .setResultWho(resultWho)
+ .setRequestCode(requestCode)
+ .setStartFlags(startFlags)
+ .setGlobalConfiguration(config)
+ .setActivityOptions(bOptions)
+ .setUserId(userId)
+ .execute();
}
@@ -6099,15 +6094,6 @@
}
@Override
- public void notifyAppTransitionStarting(SparseIntArray reasons,
- long timestampNs) {
- synchronized (mGlobalLock) {
- mStackSupervisor.getActivityMetricsLogger().notifyTransitionStarting(
- reasons, timestampNs);
- }
- }
-
- @Override
public void notifySingleTaskDisplayDrawn(int displayId) {
mTaskChangeNotificationController.notifySingleTaskDisplayDrawn(displayId);
}
diff --git a/services/core/java/com/android/server/wm/AlertWindowNotification.java b/services/core/java/com/android/server/wm/AlertWindowNotification.java
index 9177d25..0de94d9 100644
--- a/services/core/java/com/android/server/wm/AlertWindowNotification.java
+++ b/services/core/java/com/android/server/wm/AlertWindowNotification.java
@@ -21,7 +21,7 @@
import static android.content.Context.NOTIFICATION_SERVICE;
import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
-import static android.provider.Settings.ACTION_MANAGE_OVERLAY_PERMISSION;
+import static android.provider.Settings.ACTION_MANAGE_APP_OVERLAY_PERMISSION;
import android.app.Notification;
import android.app.NotificationChannel;
@@ -29,13 +29,11 @@
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
-
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
-
import android.net.Uri;
import android.os.Bundle;
@@ -137,7 +135,7 @@
}
private PendingIntent getContentIntent(Context context, String packageName) {
- final Intent intent = new Intent(ACTION_MANAGE_OVERLAY_PERMISSION,
+ final Intent intent = new Intent(ACTION_MANAGE_APP_OVERLAY_PERMISSION,
Uri.fromParts("package", packageName, null));
intent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
// Calls into activity manager...
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index ff1b423..e9ad0d3 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -52,11 +52,10 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import android.os.SystemClock;
import android.os.Trace;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
-import android.util.SparseIntArray;
import android.view.Display;
import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationDefinition;
@@ -81,7 +80,7 @@
private final WallpaperController mWallpaperControllerLocked;
private RemoteAnimationDefinition mRemoteAnimationDefinition = null;
- private final SparseIntArray mTempTransitionReasons = new SparseIntArray();
+ private final ArrayMap<ActivityRecord, Integer> mTempTransitionReasons = new ArrayMap<>();
AppTransitionController(WindowManagerService service, DisplayContent displayContent) {
mService = service;
@@ -208,8 +207,8 @@
mDisplayContent.computeImeTarget(true /* updateImeTarget */);
- mService.mAtmInternal.notifyAppTransitionStarting(mTempTransitionReasons.clone(),
- SystemClock.elapsedRealtimeNanos());
+ mService.mAtmService.mStackSupervisor.getActivityMetricsLogger().notifyTransitionStarting(
+ mTempTransitionReasons);
if (transit == TRANSIT_SHOW_SINGLE_TASK_DISPLAY) {
mService.mAnimator.addAfterPrepareSurfacesRunnable(() -> {
@@ -442,7 +441,8 @@
}
}
- private boolean transitionGoodToGo(ArraySet<ActivityRecord> apps, SparseIntArray outReasons) {
+ private boolean transitionGoodToGo(ArraySet<ActivityRecord> apps,
+ ArrayMap<ActivityRecord, Integer> outReasons) {
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
"Checking %d opening apps (frozen=%b timeout=%b)...", apps.size(),
mService.mDisplayFrozen, mDisplayContent.mAppTransition.isTimeout());
@@ -478,11 +478,10 @@
if (!allDrawn && !activity.startingDisplayed && !activity.startingMoved) {
return false;
}
- final int windowingMode = activity.getWindowingMode();
if (allDrawn) {
- outReasons.put(windowingMode, APP_TRANSITION_WINDOWS_DRAWN);
+ outReasons.put(activity, APP_TRANSITION_WINDOWS_DRAWN);
} else {
- outReasons.put(windowingMode,
+ outReasons.put(activity,
activity.mStartingData instanceof SplashScreenStartingData
? APP_TRANSITION_SPLASH_SCREEN
: APP_TRANSITION_SNAPSHOT);
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index a5b1fda..0853f1f 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackController.java
@@ -236,10 +236,10 @@
/**
* Saves the current snap fraction for re-entry of the current activity into PiP.
*/
- void saveReentrySnapFraction(final ComponentName componentName, final Rect stackBounds) {
+ void saveReentryBounds(final ComponentName componentName, final Rect stackBounds) {
if (mPinnedStackListener == null) return;
try {
- mPinnedStackListener.onSaveReentrySnapFraction(componentName, stackBounds);
+ mPinnedStackListener.onSaveReentryBounds(componentName, stackBounds);
} catch (RemoteException e) {
Slog.e(TAG_WM, "Error delivering save reentry fraction event.", e);
}
@@ -248,10 +248,10 @@
/**
* Resets the last saved snap fraction so that the default bounds will be returned.
*/
- void resetReentrySnapFraction(ComponentName componentName) {
+ void resetReentryBounds(ComponentName componentName) {
if (mPinnedStackListener == null) return;
try {
- mPinnedStackListener.onResetReentrySnapFraction(componentName);
+ mPinnedStackListener.onResetReentryBounds(componentName);
} catch (RemoteException e) {
Slog.e(TAG_WM, "Error delivering reset reentry fraction event.", e);
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index f2e9505..f4c867c 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -45,6 +45,7 @@
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.internal.util.function.pooled.PooledPredicate;
import com.android.server.protolog.common.ProtoLog;
+import com.android.server.wm.ActivityMetricsLogger.LaunchingState;
import com.android.server.wm.RecentsAnimationController.RecentsAnimationCallbacks;
/**
@@ -196,7 +197,8 @@
true /* forceSend */, targetActivity);
}
- mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunching(mTargetIntent);
+ final LaunchingState launchingState =
+ mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunching(mTargetIntent);
if (mCaller != null) {
mCaller.setRunningRecentsAnimation(true);
@@ -255,8 +257,8 @@
// we fetch the visible tasks to be controlled by the animation
mService.mRootActivityContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
- mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunched(START_TASK_TO_FRONT,
- targetActivity);
+ mStackSupervisor.getActivityMetricsLogger().notifyActivityLaunched(launchingState,
+ START_TASK_TO_FRONT, targetActivity);
// Register for stack order changes
mDefaultDisplay.registerStackOrderChangedListener(this);
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 4c5ca38..39d08a2 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -16,7 +16,6 @@
package com.android.server.wm;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.RemoteAnimationTarget.MODE_CLOSING;
@@ -42,10 +41,10 @@
import android.os.IBinder.DeathRecipient;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseBooleanArray;
-import android.util.SparseIntArray;
import android.util.proto.ProtoOutputStream;
import android.view.IRecentsAnimationController;
import android.view.IRecentsAnimationRunner;
@@ -502,10 +501,13 @@
} catch (RemoteException e) {
Slog.e(TAG, "Failed to start recents animation", e);
}
- final SparseIntArray reasons = new SparseIntArray();
- reasons.put(WINDOWING_MODE_FULLSCREEN, APP_TRANSITION_RECENTS_ANIM);
- mService.mAtmInternal
- .notifyAppTransitionStarting(reasons, SystemClock.elapsedRealtimeNanos());
+
+ if (mTargetActivityRecord != null) {
+ final ArrayMap<ActivityRecord, Integer> reasons = new ArrayMap<>(1);
+ reasons.put(mTargetActivityRecord, APP_TRANSITION_RECENTS_ANIM);
+ mService.mAtmService.mStackSupervisor.getActivityMetricsLogger()
+ .notifyTransitionStarting(reasons);
+ }
}
private RemoteAnimationTarget[] createAppAnimations() {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 3b13ac8..4ec50f0 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2350,8 +2350,9 @@
win.setLastReportedMergedConfiguration(mergedConfiguration);
- // Update the last inset values here because the values are sent back to the client.
- // The last inset values represent the last client state.
+ // Update the last frames and inset values here because the values are sent back to the
+ // client. The last values represent the last client state.
+ win.updateLastFrames();
win.updateLastInsetValues();
win.getCompatFrame(outFrame);
@@ -6795,19 +6796,23 @@
"setShouldShowWithInsecureKeyguard()")) {
throw new SecurityException("Requires INTERNAL_SYSTEM_WINDOW permission");
}
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ final DisplayContent displayContent = getDisplayContentOrCreate(displayId, null);
+ if (displayContent == null) {
+ ProtoLog.w(WM_ERROR, "Attempted to set flag to a display that does not exist: "
+ + "%d", displayId);
+ return;
+ }
- synchronized (mGlobalLock) {
- final DisplayContent displayContent = getDisplayContentOrCreate(displayId, null);
- if (displayContent == null) {
- ProtoLog.w(WM_ERROR, "Attempted to set flag to a display that does not exist: %d",
- displayId);
- return;
+ mDisplayWindowSettings.setShouldShowWithInsecureKeyguardLocked(displayContent,
+ shouldShow);
+
+ displayContent.reconfigureDisplayLocked();
}
-
- mDisplayWindowSettings.setShouldShowWithInsecureKeyguardLocked(displayContent,
- shouldShow);
-
- displayContent.reconfigureDisplayLocked();
+ } finally {
+ Binder.restoreCallingIdentity(origId);
}
}
@@ -6836,22 +6841,26 @@
if (!checkCallingPermission(INTERNAL_SYSTEM_WINDOW, "setShouldShowSystemDecors()")) {
throw new SecurityException("Requires INTERNAL_SYSTEM_WINDOW permission");
}
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ final DisplayContent displayContent = getDisplayContentOrCreate(displayId, null);
+ if (displayContent == null) {
+ ProtoLog.w(WM_ERROR, "Attempted to set system decors flag to a display that "
+ + "does not exist: %d", displayId);
+ return;
+ }
+ if (displayContent.isUntrustedVirtualDisplay()) {
+ throw new SecurityException("Attempted to set system decors flag to an "
+ + "untrusted virtual display: " + displayId);
+ }
- synchronized (mGlobalLock) {
- final DisplayContent displayContent = getDisplayContentOrCreate(displayId, null);
- if (displayContent == null) {
- ProtoLog.w(WM_ERROR, "Attempted to set system decors flag to a display that does "
- + "not exist: %d", displayId);
- return;
+ mDisplayWindowSettings.setShouldShowSystemDecorsLocked(displayContent, shouldShow);
+
+ displayContent.reconfigureDisplayLocked();
}
- if (displayContent.isUntrustedVirtualDisplay()) {
- throw new SecurityException("Attempted to set system decors flag to an untrusted "
- + "virtual display: " + displayId);
- }
-
- mDisplayWindowSettings.setShouldShowSystemDecorsLocked(displayContent, shouldShow);
-
- displayContent.reconfigureDisplayLocked();
+ } finally {
+ Binder.restoreCallingIdentity(origId);
}
}
@@ -6882,23 +6891,26 @@
if (!checkCallingPermission(INTERNAL_SYSTEM_WINDOW, "setShouldShowIme()")) {
throw new SecurityException("Requires INTERNAL_SYSTEM_WINDOW permission");
}
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ final DisplayContent displayContent = getDisplayContentOrCreate(displayId, null);
+ if (displayContent == null) {
+ ProtoLog.w(WM_ERROR, "Attempted to set IME flag to a display that does not "
+ + "exist: %d", displayId);
+ return;
+ }
+ if (displayContent.isUntrustedVirtualDisplay()) {
+ throw new SecurityException("Attempted to set IME flag to an untrusted "
+ + "virtual display: " + displayId);
+ }
- synchronized (mGlobalLock) {
- final DisplayContent displayContent = getDisplayContentOrCreate(displayId, null);
- if (displayContent == null) {
- ProtoLog.w(WM_ERROR,
- "Attempted to set IME flag to a display that does not exist: %d",
- displayId);
- return;
+ mDisplayWindowSettings.setShouldShowImeLocked(displayContent, shouldShow);
+
+ displayContent.reconfigureDisplayLocked();
}
- if (displayContent.isUntrustedVirtualDisplay()) {
- throw new SecurityException("Attempted to set IME flag to an untrusted "
- + "virtual display: " + displayId);
- }
-
- mDisplayWindowSettings.setShouldShowImeLocked(displayContent, shouldShow);
-
- displayContent.reconfigureDisplayLocked();
+ } finally {
+ Binder.restoreCallingIdentity(origId);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 0441669..ce26e5f 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -983,7 +983,7 @@
- mWindowFrames.mVisibleFrame.bottom;
if (bottomOverlap > 0) {
final int distanceToTop = Math.max(mWindowFrames.mContainingFrame.top
- - mWindowFrames.mDisplayFrame.top, 0);
+ - mWindowFrames.mContentFrame.top, 0);
int offs = Math.min(bottomOverlap, distanceToTop);
mWindowFrames.mContainingFrame.top -= offs;
}
@@ -1308,8 +1308,7 @@
// We update mLastFrame always rather than in the conditional with the last inset
// variables, because mFrameSizeChanged only tracks the width and height changing.
- mWindowFrames.mLastFrame.set(mWindowFrames.mFrame);
- mWindowFrames.mLastRelFrame.set(mWindowFrames.mRelFrame);
+ updateLastFrames();
if (didFrameInsetsChange
|| winAnimator.mSurfaceResized
@@ -4817,6 +4816,12 @@
return mEmbeddedDisplayContents.remove(dc);
}
+ /** Updates the last frames and relative frames to the current ones. */
+ void updateLastFrames() {
+ mWindowFrames.mLastFrame.set(mWindowFrames.mFrame);
+ mWindowFrames.mLastRelFrame.set(mWindowFrames.mRelFrame);
+ }
+
/**
* Updates the last inset values to the current ones.
*/
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 471164d..fd8094c 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -124,6 +124,7 @@
"android.hardware.gnss@1.0",
"android.hardware.gnss@1.1",
"android.hardware.gnss@2.0",
+ "android.hardware.gnss@2.1",
"android.hardware.gnss.measurement_corrections@1.0",
"android.hardware.gnss.visibility_control@1.0",
"android.hardware.input.classifier@1.0",
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index a0f5628..6504e31 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -21,10 +21,12 @@
#include <android/hardware/gnss/1.0/IGnss.h>
#include <android/hardware/gnss/1.1/IGnss.h>
#include <android/hardware/gnss/2.0/IGnss.h>
+#include <android/hardware/gnss/2.1/IGnss.h>
#include <android/hardware/gnss/1.0/IGnssMeasurement.h>
#include <android/hardware/gnss/1.1/IGnssMeasurement.h>
#include <android/hardware/gnss/2.0/IGnssMeasurement.h>
+#include <android/hardware/gnss/2.1/IGnssMeasurement.h>
#include <android/hardware/gnss/measurement_corrections/1.0/IMeasurementCorrections.h>
#include <android/hardware/gnss/visibility_control/1.0/IGnssVisibilityControl.h>
#include <nativehelper/JNIHelp.h>
@@ -140,7 +142,6 @@
using android::hardware::gnss::V1_0::IGnssXtraCallback;
using android::hardware::gnss::V2_0::ElapsedRealtimeFlags;
-using android::hardware::gnss::V2_0::IGnssCallback;
using android::hardware::gnss::measurement_corrections::V1_0::MeasurementCorrections;
using android::hardware::gnss::measurement_corrections::V1_0::SingleSatCorrection;
@@ -153,7 +154,10 @@
using IGnss_V1_0 = android::hardware::gnss::V1_0::IGnss;
using IGnss_V1_1 = android::hardware::gnss::V1_1::IGnss;
using IGnss_V2_0 = android::hardware::gnss::V2_0::IGnss;
+using IGnss_V2_1 = android::hardware::gnss::V2_1::IGnss;
using IGnssCallback_V1_0 = android::hardware::gnss::V1_0::IGnssCallback;
+using IGnssCallback_V2_0 = android::hardware::gnss::V2_0::IGnssCallback;
+using IGnssCallback_V2_1 = android::hardware::gnss::V2_1::IGnssCallback;
using IGnssConfiguration_V1_0 = android::hardware::gnss::V1_0::IGnssConfiguration;
using IGnssConfiguration_V1_1 = android::hardware::gnss::V1_1::IGnssConfiguration;
using IGnssConfiguration_V2_0 = android::hardware::gnss::V2_0::IGnssConfiguration;
@@ -162,9 +166,11 @@
using IGnssMeasurement_V1_0 = android::hardware::gnss::V1_0::IGnssMeasurement;
using IGnssMeasurement_V1_1 = android::hardware::gnss::V1_1::IGnssMeasurement;
using IGnssMeasurement_V2_0 = android::hardware::gnss::V2_0::IGnssMeasurement;
+using IGnssMeasurement_V2_1 = android::hardware::gnss::V2_1::IGnssMeasurement;
using IGnssMeasurementCallback_V1_0 = android::hardware::gnss::V1_0::IGnssMeasurementCallback;
using IGnssMeasurementCallback_V1_1 = android::hardware::gnss::V1_1::IGnssMeasurementCallback;
using IGnssMeasurementCallback_V2_0 = android::hardware::gnss::V2_0::IGnssMeasurementCallback;
+using IGnssMeasurementCallback_V2_1 = android::hardware::gnss::V2_1::IGnssMeasurementCallback;
using IAGnssRil_V1_0 = android::hardware::gnss::V1_0::IAGnssRil;
using IAGnssRil_V2_0 = android::hardware::gnss::V2_0::IAGnssRil;
using IAGnss_V1_0 = android::hardware::gnss::V1_0::IAGnss;
@@ -201,6 +207,7 @@
sp<IGnss_V1_0> gnssHal = nullptr;
sp<IGnss_V1_1> gnssHal_V1_1 = nullptr;
sp<IGnss_V2_0> gnssHal_V2_0 = nullptr;
+sp<IGnss_V2_1> gnssHal_V2_1 = nullptr;
sp<IGnssXtra> gnssXtraIface = nullptr;
sp<IAGnssRil_V1_0> agnssRilIface = nullptr;
sp<IAGnssRil_V2_0> agnssRilIface_V2_0 = nullptr;
@@ -218,6 +225,7 @@
sp<IGnssMeasurement_V1_0> gnssMeasurementIface = nullptr;
sp<IGnssMeasurement_V1_1> gnssMeasurementIface_V1_1 = nullptr;
sp<IGnssMeasurement_V2_0> gnssMeasurementIface_V2_0 = nullptr;
+sp<IGnssMeasurement_V2_1> gnssMeasurementIface_V2_1 = nullptr;
sp<IGnssNavigationMessage> gnssNavigationMessageIface = nullptr;
sp<IMeasurementCorrections> gnssCorrectionsIface = nullptr;
sp<IGnssVisibilityControl> gnssVisibilityControlIface = nullptr;
@@ -582,9 +590,9 @@
/*
* GnssCallback class implements the callback methods for IGnss interface.
*/
-struct GnssCallback : public IGnssCallback {
+struct GnssCallback : public IGnssCallback_V2_1 {
Return<void> gnssLocationCb(const GnssLocation_V1_0& location) override;
- Return<void> gnssStatusCb(const IGnssCallback::GnssStatusValue status) override;
+ Return<void> gnssStatusCb(const IGnssCallback_V1_0::GnssStatusValue status) override;
Return<void> gnssSvStatusCb(const IGnssCallback_V1_0::GnssSvStatus& svStatus) override {
return gnssSvStatusCbImpl(svStatus);
}
@@ -595,7 +603,7 @@
Return<void> gnssRequestTimeCb() override;
Return<void> gnssRequestLocationCb(const bool independentFromGnss) override;
- Return<void> gnssSetSystemInfoCb(const IGnssCallback::GnssSystemInfo& info) override;
+ Return<void> gnssSetSystemInfoCb(const IGnssCallback_V1_0::GnssSystemInfo& info) override;
// New in 1.1
Return<void> gnssNameCb(const android::hardware::hidl_string& name) override;
@@ -605,10 +613,12 @@
override;
Return<void> gnssSetCapabilitiesCb_2_0(uint32_t capabilities) override;
Return<void> gnssLocationCb_2_0(const GnssLocation_V2_0& location) override;
- Return<void> gnssSvStatusCb_2_0(const hidl_vec<IGnssCallback::GnssSvInfo>& svInfoList) override {
+ Return<void> gnssSvStatusCb_2_0(const hidl_vec<IGnssCallback_V2_0::GnssSvInfo>& svInfoList) override {
return gnssSvStatusCbImpl(svInfoList);
}
-
+ Return<void> gnssSvStatusCb_2_1(const hidl_vec<IGnssCallback_V2_1::GnssSvInfo>& svInfoList) override {
+ return gnssSvStatusCbImpl(svInfoList);
+ }
Return<void> gnssSetCapabilitesCbImpl(uint32_t capabilities, bool hasSubHalCapabilityFlags);
// TODO: Reconsider allocation cost vs threadsafety on these statics
@@ -625,7 +635,11 @@
return svStatus.numSvs;
}
- uint32_t getGnssSvInfoListSize(const hidl_vec<IGnssCallback::GnssSvInfo>& svInfoList) {
+ uint32_t getGnssSvInfoListSize(const hidl_vec<IGnssCallback_V2_0::GnssSvInfo>& svInfoList) {
+ return svInfoList.size();
+ }
+
+ uint32_t getGnssSvInfoListSize(const hidl_vec<IGnssCallback_V2_1::GnssSvInfo>& svInfoList) {
return svInfoList.size();
}
@@ -635,17 +649,28 @@
}
const IGnssCallback_V1_0::GnssSvInfo& getGnssSvInfoOfIndex(
- const hidl_vec<IGnssCallback::GnssSvInfo>& svInfoList, size_t i) {
+ const hidl_vec<IGnssCallback_V2_0::GnssSvInfo>& svInfoList, size_t i) {
return svInfoList[i].v1_0;
}
+ const IGnssCallback_V1_0::GnssSvInfo& getGnssSvInfoOfIndex(
+ const hidl_vec<IGnssCallback_V2_1::GnssSvInfo>& svInfoList, size_t i) {
+ // TODO(b/144850155): fill baseband CN0 after it's available in Java object.
+ ALOGD("getGnssSvInfoOfIndex %d: baseband C/N0: %f", (int) i, svInfoList[i].basebandCN0DbHz);
+ return svInfoList[i].v2_0.v1_0;
+ }
+
uint32_t getConstellationType(const IGnssCallback_V1_0::GnssSvStatus& svStatus, size_t i) {
return static_cast<uint32_t>(svStatus.gnssSvList.data()[i].constellation);
}
- uint32_t getConstellationType(const hidl_vec<IGnssCallback::GnssSvInfo>& svInfoList, size_t i) {
+ uint32_t getConstellationType(const hidl_vec<IGnssCallback_V2_0::GnssSvInfo>& svInfoList, size_t i) {
return static_cast<uint32_t>(svInfoList[i].constellation);
}
+
+ uint32_t getConstellationType(const hidl_vec<IGnssCallback_V2_1::GnssSvInfo>& svInfoList, size_t i) {
+ return static_cast<uint32_t>(svInfoList[i].v2_0.constellation);
+ }
};
Return<void> GnssCallback::gnssNameCb(const android::hardware::hidl_string& name) {
@@ -686,7 +711,7 @@
return gnssLocationCbImpl<GnssLocation_V2_0>(location);
}
-Return<void> GnssCallback::gnssStatusCb(const IGnssCallback::GnssStatusValue status) {
+Return<void> GnssCallback::gnssStatusCb(const IGnssCallback_V2_0::GnssStatusValue status) {
JNIEnv* env = getJniEnv();
env->CallVoidMethod(mCallbacksObj, method_reportStatus, status);
checkAndClearExceptionFromCallback(env, __FUNCTION__);
@@ -808,7 +833,7 @@
return Void();
}
-Return<void> GnssCallback::gnssSetSystemInfoCb(const IGnssCallback::GnssSystemInfo& info) {
+Return<void> GnssCallback::gnssSetSystemInfoCb(const IGnssCallback_V2_0::GnssSystemInfo& info) {
ALOGD("%s: yearOfHw=%d\n", __func__, info.yearOfHw);
JNIEnv* env = getJniEnv();
@@ -997,7 +1022,9 @@
* GnssMeasurementCallback implements the callback methods required for the
* GnssMeasurement interface.
*/
-struct GnssMeasurementCallback : public IGnssMeasurementCallback_V2_0 {
+struct GnssMeasurementCallback : public IGnssMeasurementCallback_V2_1 {
+ Return<void> gnssMeasurementCb_2_1(const IGnssMeasurementCallback_V2_1::GnssData& data)
+ override;
Return<void> gnssMeasurementCb_2_0(const IGnssMeasurementCallback_V2_0::GnssData& data)
override;
Return<void> gnssMeasurementCb(const IGnssMeasurementCallback_V1_1::GnssData& data) override;
@@ -1021,6 +1048,12 @@
void setMeasurementData(JNIEnv* env, jobject clock, jobjectArray measurementArray);
};
+Return<void> GnssMeasurementCallback::gnssMeasurementCb_2_1(
+ const IGnssMeasurementCallback_V2_1::GnssData& data) {
+ translateAndSetGnssData(data);
+ return Void();
+}
+
Return<void> GnssMeasurementCallback::gnssMeasurementCb_2_0(
const IGnssMeasurementCallback_V2_0::GnssData& data) {
translateAndSetGnssData(data);
@@ -1142,6 +1175,17 @@
SET(ConstellationType, static_cast<int32_t>(measurement_V2_0->constellation));
}
+// Preallocate object as: JavaObject object(env, "android/location/GnssMeasurement");
+template<>
+void GnssMeasurementCallback::translateSingleGnssMeasurement
+ <IGnssMeasurementCallback_V2_1::GnssMeasurement>(
+ const IGnssMeasurementCallback_V2_1::GnssMeasurement* measurement_V2_1,
+ JavaObject& object) {
+ translateSingleGnssMeasurement(&(measurement_V2_1->v2_0), object);
+ // TODO(b/144850155): fill baseband CN0 after it's available in Java object
+ ALOGD("baseband CN0DbHz = %f\n", measurement_V2_1->basebandCN0DbHz);
+}
+
template<class T>
void GnssMeasurementCallback::translateGnssClock(JavaObject& object, const T& data) {
translateGnssClock(object, data.clock);
@@ -1523,6 +1567,17 @@
/* Initializes the GNSS service handle. */
static void android_location_GnssLocationProvider_set_gps_service_handle() {
+ ALOGD("Trying IGnss_V2_1::getService()");
+ gnssHal_V2_1 = IGnss_V2_1::getService();
+ if (gnssHal_V2_1 != nullptr) {
+ gnssHal = gnssHal_V2_1;
+ gnssHal_V2_0 = gnssHal_V2_1;
+ gnssHal_V1_1 = gnssHal_V2_1;
+ gnssHal = gnssHal_V2_1;
+ return;
+ }
+
+ ALOGD("gnssHal 2.1 was null, trying 2.0");
gnssHal_V2_0 = IGnss_V2_0::getService();
if (gnssHal_V2_0 != nullptr) {
gnssHal = gnssHal_V2_0;
@@ -1751,18 +1806,30 @@
}
// Allow all causal combinations between IGnss.hal and IGnssMeasurement.hal. That means,
+ // 2.1@IGnss can be paired with {1.0, 1,1, 2.0, 2.1}@IGnssMeasurement
// 2.0@IGnss can be paired with {1.0, 1,1, 2.0}@IGnssMeasurement
// 1.1@IGnss can be paired {1.0, 1.1}@IGnssMeasurement
// 1.0@IGnss is paired with 1.0@IGnssMeasurement
gnssMeasurementIface = nullptr;
- if (gnssHal_V2_0 != nullptr) {
+ if (gnssHal_V2_1 != nullptr) {
+ auto gnssMeasurement = gnssHal_V2_1->getExtensionGnssMeasurement_2_1();
+ if (!gnssMeasurement.isOk()) {
+ ALOGD("Unable to get a handle to GnssMeasurement_V2_1");
+ } else {
+ gnssMeasurementIface_V2_1 = gnssMeasurement;
+ gnssMeasurementIface_V2_0 = gnssMeasurementIface_V2_1;
+ gnssMeasurementIface_V1_1 = gnssMeasurementIface_V2_0;
+ gnssMeasurementIface = gnssMeasurementIface_V1_1;
+ }
+ }
+ if (gnssHal_V2_0 != nullptr && gnssMeasurementIface == nullptr) {
auto gnssMeasurement = gnssHal_V2_0->getExtensionGnssMeasurement_2_0();
if (!gnssMeasurement.isOk()) {
ALOGD("Unable to get a handle to GnssMeasurement_V2_0");
} else {
gnssMeasurementIface_V2_0 = gnssMeasurement;
gnssMeasurementIface_V1_1 = gnssMeasurementIface_V2_0;
- gnssMeasurementIface = gnssMeasurementIface_V2_0;
+ gnssMeasurementIface = gnssMeasurementIface_V1_1;
}
}
if (gnssHal_V1_1 != nullptr && gnssMeasurementIface == nullptr) {
@@ -1930,8 +1997,10 @@
Return<bool> result = false;
// Set top level IGnss.hal callback.
- sp<IGnssCallback> gnssCbIface = new GnssCallback();
- if (gnssHal_V2_0 != nullptr) {
+ sp<IGnssCallback_V2_1> gnssCbIface = new GnssCallback();
+ if (gnssHal_V2_1 != nullptr) {
+ result = gnssHal_V2_1->setCallback_2_1(gnssCbIface);
+ } else if (gnssHal_V2_0 != nullptr) {
result = gnssHal_V2_0->setCallback_2_0(gnssCbIface);
} else if (gnssHal_V1_1 != nullptr) {
result = gnssHal_V1_1->setCallback_1_1(gnssCbIface);
@@ -2564,7 +2633,9 @@
sp<GnssMeasurementCallback> cbIface = new GnssMeasurementCallback();
Return<IGnssMeasurement_V1_0::GnssMeasurementStatus> result =
IGnssMeasurement_V1_0::GnssMeasurementStatus::ERROR_GENERIC;
- if (gnssMeasurementIface_V2_0 != nullptr) {
+ if (gnssMeasurementIface_V2_1 != nullptr) {
+ result = gnssMeasurementIface_V2_1->setCallback_2_1(cbIface, enableFullTracking);
+ } else if (gnssMeasurementIface_V2_0 != nullptr) {
result = gnssMeasurementIface_V2_0->setCallback_2_0(cbIface, enableFullTracking);
} else if (gnssMeasurementIface_V1_1 != nullptr) {
result = gnssMeasurementIface_V1_1->setCallback_1_1(cbIface, enableFullTracking);
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index c1bbb30..fb42507 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -34,7 +34,7 @@
<uses-permission android:name="android.permission.REORDER_TASKS" />
<uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
<uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" />
- <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
+ <uses-permission android:name="android.permission.OBSERVE_NETWORK_POLICY" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.MANAGE_USERS" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
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 d071927..313afbb 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -703,6 +703,21 @@
assertEquals(canBeCreatedCount, created.get());
}
+ @MediumTest
+ public void testGetUserHandles_createNewUser_shouldFindNewUser() {
+ UserInfo user = createUser("Guest 1", UserManager.USER_TYPE_FULL_GUEST, /*flags*/ 0);
+
+ boolean found = false;
+ List<UserHandle> userHandles = mUserManager.getUserHandles(/* excludeDying= */ true);
+ for (UserHandle userHandle: userHandles) {
+ if (userHandle.getIdentifier() == user.id) {
+ found = true;
+ }
+ }
+
+ assertTrue(found);
+ }
+
private boolean isPackageInstalledForUser(String packageName, int userId) {
try {
return mPackageManager.getPackageInfoAsUser(packageName, 0, userId) != null;
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeZoneDetectorStrategyTest.java b/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeDetectorStrategyTest.java
similarity index 98%
rename from services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeZoneDetectorStrategyTest.java
rename to services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeDetectorStrategyTest.java
index 317fd4d..8a7edf7 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeZoneDetectorStrategyTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/SimpleTimeDetectorStrategyTest.java
@@ -40,7 +40,7 @@
import java.time.Duration;
@RunWith(AndroidJUnit4.class)
-public class SimpleTimeZoneDetectorStrategyTest {
+public class SimpleTimeDetectorStrategyTest {
private static final Scenario SCENARIO_1 = new Scenario.Builder()
.setInitialDeviceSystemClockUtc(1977, 1, 1, 12, 0, 0)
@@ -440,7 +440,7 @@
mSystemClockMillis = systemClockMillis;
}
- public void pokeTimeDetectionEnabled(boolean enabled) {
+ public void pokeAutoTimeDetectionEnabled(boolean enabled) {
mTimeDetectionEnabled = enabled;
}
@@ -457,6 +457,10 @@
mSystemClockMillis += incrementMillis;
}
+ public void simulateAutoTimeZoneDetectionToggle() {
+ mTimeDetectionEnabled = !mTimeDetectionEnabled;
+ }
+
public void verifySystemClockNotSet() {
assertFalse(mSystemClockWasSet);
}
@@ -493,7 +497,7 @@
private final FakeCallback mFakeCallback;
private final SimpleTimeDetectorStrategy mSimpleTimeDetectorStrategy;
- public Script() {
+ Script() {
mFakeCallback = new FakeCallback();
mSimpleTimeDetectorStrategy = new SimpleTimeDetectorStrategy();
mSimpleTimeDetectorStrategy.initialize(mFakeCallback);
@@ -501,7 +505,7 @@
}
Script pokeTimeDetectionEnabled(boolean enabled) {
- mFakeCallback.pokeTimeDetectionEnabled(enabled);
+ mFakeCallback.pokeAutoTimeDetectionEnabled(enabled);
return this;
}
@@ -535,9 +539,8 @@
}
Script simulateAutoTimeDetectionToggle() {
- boolean enabled = !mFakeCallback.isAutoTimeDetectionEnabled();
- mFakeCallback.pokeTimeDetectionEnabled(enabled);
- mSimpleTimeDetectorStrategy.handleAutoTimeDetectionToggle(enabled);
+ mFakeCallback.simulateAutoTimeZoneDetectionToggle();
+ mSimpleTimeDetectorStrategy.handleAutoTimeDetectionChanged();
return this;
}
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
index 4efe771..9951e85 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
@@ -17,13 +17,11 @@
package com.android.server.timedetector;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -32,12 +30,17 @@
import android.app.timedetector.PhoneTimeSuggestion;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
import android.util.TimestampedValue;
import androidx.test.runner.AndroidJUnit4;
import com.android.server.timedetector.TimeDetectorStrategy.Callback;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -52,54 +55,62 @@
private Callback mMockCallback;
private TimeDetectorService mTimeDetectorService;
+ private HandlerThread mHandlerThread;
+ private TestHandler mTestHandler;
+
@Before
public void setUp() {
mMockContext = mock(Context.class);
+
+ // Create a thread + handler for processing the work that the service posts.
+ mHandlerThread = new HandlerThread("TimeDetectorServiceTest");
+ mHandlerThread.start();
+ mTestHandler = new TestHandler(mHandlerThread.getLooper());
+
mMockCallback = mock(Callback.class);
mStubbedTimeDetectorStrategy = new StubbedTimeDetectorStrategy();
mTimeDetectorService = new TimeDetectorService(
- mMockContext, mMockCallback,
+ mMockContext, mTestHandler, mMockCallback,
mStubbedTimeDetectorStrategy);
}
- @Test(expected=SecurityException.class)
- public void testStubbedCall_withoutPermission() {
- doThrow(new SecurityException("Mock"))
- .when(mMockContext).enforceCallingPermission(anyString(), any());
- PhoneTimeSuggestion phoneTimeSuggestion = createPhoneTimeSuggestion();
-
- try {
- mTimeDetectorService.suggestPhoneTime(phoneTimeSuggestion);
- } finally {
- verify(mMockContext).enforceCallingPermission(
- eq(android.Manifest.permission.SET_TIME), anyString());
- }
+ @After
+ public void tearDown() throws Exception {
+ mHandlerThread.quit();
+ mHandlerThread.join();
}
@Test
- public void testSuggestPhoneTime() {
+ public void testSuggestPhoneTime() throws Exception {
doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
PhoneTimeSuggestion phoneTimeSuggestion = createPhoneTimeSuggestion();
mTimeDetectorService.suggestPhoneTime(phoneTimeSuggestion);
-
- verify(mMockContext)
- .enforceCallingPermission(eq(android.Manifest.permission.SET_TIME), anyString());
- mStubbedTimeDetectorStrategy.verifySuggestPhoneTimeCalled(phoneTimeSuggestion);
- }
-
- @Test
- public void testSuggestManualTime() {
- doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
-
- ManualTimeSuggestion manualTimeSuggestion = createManualTimeSuggestion();
- mTimeDetectorService.suggestManualTime(manualTimeSuggestion);
+ mTestHandler.assertTotalMessagesEnqueued(1);
verify(mMockContext).enforceCallingPermission(
eq(android.Manifest.permission.SET_TIME),
anyString());
+
+ mTestHandler.waitForEmptyQueue();
+ mStubbedTimeDetectorStrategy.verifySuggestPhoneTimeCalled(phoneTimeSuggestion);
+ }
+
+ @Test
+ public void testSuggestManualTime() throws Exception {
+ doNothing().when(mMockContext).enforceCallingPermission(anyString(), any());
+
+ ManualTimeSuggestion manualTimeSuggestion = createManualTimeSuggestion();
+ mTimeDetectorService.suggestManualTime(manualTimeSuggestion);
+ mTestHandler.assertTotalMessagesEnqueued(1);
+
+ verify(mMockContext).enforceCallingPermission(
+ eq(android.Manifest.permission.SET_TIME),
+ anyString());
+
+ mTestHandler.waitForEmptyQueue();
mStubbedTimeDetectorStrategy.verifySuggestManualTimeCalled(manualTimeSuggestion);
}
@@ -115,18 +126,16 @@
}
@Test
- public void testAutoTimeDetectionToggle() {
- when(mMockCallback.isAutoTimeDetectionEnabled()).thenReturn(true);
+ public void testAutoTimeDetectionToggle() throws Exception {
+ mTimeDetectorService.handleAutoTimeDetectionToggle();
+ mTestHandler.assertTotalMessagesEnqueued(1);
+ mTestHandler.waitForEmptyQueue();
+ mStubbedTimeDetectorStrategy.verifyHandleAutoTimeDetectionToggleCalled();
mTimeDetectorService.handleAutoTimeDetectionToggle();
-
- mStubbedTimeDetectorStrategy.verifyHandleAutoTimeDetectionToggleCalled(true);
-
- when(mMockCallback.isAutoTimeDetectionEnabled()).thenReturn(false);
-
- mTimeDetectorService.handleAutoTimeDetectionToggle();
-
- mStubbedTimeDetectorStrategy.verifyHandleAutoTimeDetectionToggleCalled(false);
+ mTestHandler.assertTotalMessagesEnqueued(2);
+ mTestHandler.waitForEmptyQueue();
+ mStubbedTimeDetectorStrategy.verifyHandleAutoTimeDetectionToggleCalled();
}
private static PhoneTimeSuggestion createPhoneTimeSuggestion() {
@@ -147,7 +156,7 @@
// Call tracking.
private PhoneTimeSuggestion mLastPhoneSuggestion;
private ManualTimeSuggestion mLastManualSuggestion;
- private Boolean mLastAutoTimeDetectionToggle;
+ private boolean mLastAutoTimeDetectionToggleCalled;
private boolean mDumpCalled;
@Override
@@ -167,9 +176,9 @@
}
@Override
- public void handleAutoTimeDetectionToggle(boolean enabled) {
+ public void handleAutoTimeDetectionChanged() {
resetCallTracking();
- mLastAutoTimeDetectionToggle = enabled;
+ mLastAutoTimeDetectionToggleCalled = true;
}
@Override
@@ -181,7 +190,7 @@
void resetCallTracking() {
mLastPhoneSuggestion = null;
mLastManualSuggestion = null;
- mLastAutoTimeDetectionToggle = null;
+ mLastAutoTimeDetectionToggleCalled = false;
mDumpCalled = false;
}
@@ -193,13 +202,45 @@
assertEquals(expectedSuggestion, mLastManualSuggestion);
}
- void verifyHandleAutoTimeDetectionToggleCalled(boolean expectedEnable) {
- assertNotNull(mLastAutoTimeDetectionToggle);
- assertEquals(expectedEnable, mLastAutoTimeDetectionToggle);
+ void verifyHandleAutoTimeDetectionToggleCalled() {
+ assertTrue(mLastAutoTimeDetectionToggleCalled);
}
void verifyDumpCalled() {
assertTrue(mDumpCalled);
}
}
+
+ /**
+ * A Handler that can track posts/sends and wait for work to be completed.
+ */
+ private static class TestHandler extends Handler {
+
+ private int mMessagesSent;
+
+ TestHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
+ mMessagesSent++;
+ return super.sendMessageAtTime(msg, uptimeMillis);
+ }
+
+ /** Asserts the number of messages posted or sent is as expected. */
+ void assertTotalMessagesEnqueued(int expected) {
+ assertEquals(expected, mMessagesSent);
+ }
+
+ /**
+ * Waits for all currently enqueued work due to be processed to be completed before
+ * returning.
+ */
+ void waitForEmptyQueue() throws InterruptedException {
+ while (!getLooper().getQueue().isIdle()) {
+ Thread.sleep(100);
+ }
+ }
+ }
}
diff --git a/services/tests/servicestests/test-apps/ConnTestApp/AndroidManifest.xml b/services/tests/servicestests/test-apps/ConnTestApp/AndroidManifest.xml
index 909e9bb..201cd05 100644
--- a/services/tests/servicestests/test-apps/ConnTestApp/AndroidManifest.xml
+++ b/services/tests/servicestests/test-apps/ConnTestApp/AndroidManifest.xml
@@ -18,8 +18,7 @@
package="com.android.servicestests.apps.conntestapp">
<uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
- <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
+ <uses-permission android:name="android.permission.OBSERVE_NETWORK_POLICY" />
<application>
<activity android:name=".ConnTestActivity"
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
index 734761f..12074dc3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -18,6 +18,7 @@
import static android.app.ActivityManager.START_SUCCESS;
import static android.app.ActivityManager.START_TASK_TO_FRONT;
+import static android.content.ComponentName.createRelative;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
@@ -34,7 +35,7 @@
import android.content.Intent;
import android.os.SystemClock;
import android.platform.test.annotations.Presubmit;
-import android.util.SparseIntArray;
+import android.util.ArrayMap;
import androidx.test.filters.SmallTest;
@@ -58,11 +59,13 @@
@Presubmit
public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase {
private ActivityMetricsLogger mActivityMetricsLogger;
+ private ActivityMetricsLogger.LaunchingState mLaunchingState;
private ActivityMetricsLaunchObserver mLaunchObserver;
private ActivityMetricsLaunchObserverRegistry mLaunchObserverRegistry;
private ActivityRecord mTrampolineActivity;
private ActivityRecord mTopActivity;
+ private boolean mLaunchTopByTrampoline;
@Before
public void setUpAMLO() {
@@ -76,9 +79,13 @@
// Sometimes we need an ActivityRecord for ActivityMetricsLogger to do anything useful.
// This seems to be the easiest way to create an ActivityRecord.
- mTrampolineActivity = new ActivityBuilder(mService).setCreateTask(true).build();
+ mTrampolineActivity = new ActivityBuilder(mService)
+ .setCreateTask(true)
+ .setComponent(createRelative(DEFAULT_COMPONENT_PACKAGE_NAME, "TrampolineActivity"))
+ .build();
mTopActivity = new ActivityBuilder(mService)
.setTask(mTrampolineActivity.getTask())
+ .setComponent(createRelative(DEFAULT_COMPONENT_PACKAGE_NAME, "TopActivity"))
.build();
}
@@ -114,42 +121,42 @@
return verify(mock, timeout(TimeUnit.SECONDS.toMillis(5)));
}
- private void onIntentStarted() {
- Intent intent = new Intent("action 1");
+ private void onIntentStarted(Intent intent) {
+ notifyActivityLaunching(intent);
- mActivityMetricsLogger.notifyActivityLaunching(intent);
-
- verifyAsync(mLaunchObserver).onIntentStarted(eq(intent), anyLong());
+ // If it is launching top activity from trampoline activity, the observer shouldn't receive
+ // onActivityLaunched because the activities should belong to the same transition.
+ if (!mLaunchTopByTrampoline) {
+ verifyAsync(mLaunchObserver).onIntentStarted(eq(intent), anyLong());
+ }
verifyNoMoreInteractions(mLaunchObserver);
}
@Test
public void testOnIntentFailed() {
- onIntentStarted();
+ onIntentStarted(new Intent("testOnIntentFailed"));
// Bringing an intent that's already running 'to front' is not considered
// as an ACTIVITY_LAUNCHED state transition.
- mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT,
- null /* launchedActivity */);
+ notifyActivityLaunched(START_TASK_TO_FRONT, null /* launchedActivity */);
verifyAsync(mLaunchObserver).onIntentFailed();
verifyNoMoreInteractions(mLaunchObserver);
}
- private void onActivityLaunched() {
- onIntentStarted();
+ private void onActivityLaunched(ActivityRecord activity) {
+ onIntentStarted(activity.intent);
+ notifyActivityLaunched(START_SUCCESS, activity);
- mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, mTopActivity);
-
- verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(mTopActivity), anyInt());
+ verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(activity), anyInt());
verifyNoMoreInteractions(mLaunchObserver);
}
@Test
public void testOnActivityLaunchFinished() {
- onActivityLaunched();
+ onActivityLaunched(mTopActivity);
- notifyTransitionStarting();
+ notifyTransitionStarting(mTopActivity);
notifyWindowsDrawn(mTopActivity);
verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mTopActivity), anyLong());
@@ -158,12 +165,12 @@
@Test
public void testOnActivityLaunchCancelled_hasDrawn() {
- onActivityLaunched();
+ onActivityLaunched(mTopActivity);
mTopActivity.mVisibleRequested = mTopActivity.mDrawn = true;
// Cannot time already-visible activities.
- mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, mTopActivity);
+ notifyActivityLaunched(START_TASK_TO_FRONT, mTopActivity);
verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(mTopActivity));
verifyNoMoreInteractions(mLaunchObserver);
@@ -182,8 +189,8 @@
.build();
mSupervisor.readyToResume();
- mActivityMetricsLogger.notifyActivityLaunching(noDrawnActivity.intent);
- mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, noDrawnActivity);
+ notifyActivityLaunching(noDrawnActivity.intent);
+ notifyActivityLaunched(START_SUCCESS, noDrawnActivity);
noDrawnActivity.destroyIfPossible("test");
mActivityMetricsLogger.notifyVisibilityChanged(noDrawnActivity);
@@ -193,12 +200,12 @@
@Test
public void testOnReportFullyDrawn() {
- onActivityLaunched();
+ onActivityLaunched(mTopActivity);
// The activity reports fully drawn before windows drawn, then the fully drawn event will
// be pending (see {@link WindowingModeTransitionInfo#pendingFullyDrawn}).
mActivityMetricsLogger.logAppTransitionReportedDrawn(mTopActivity, false);
- notifyTransitionStarting();
+ notifyTransitionStarting(mTopActivity);
// The pending fully drawn event should send when the actual windows drawn event occurs.
notifyWindowsDrawn(mTopActivity);
@@ -208,35 +215,56 @@
}
private void onActivityLaunchedTrampoline() {
- onIntentStarted();
-
- mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, mTrampolineActivity);
+ onIntentStarted(mTrampolineActivity.intent);
+ notifyActivityLaunched(START_SUCCESS, mTrampolineActivity);
verifyAsync(mLaunchObserver).onActivityLaunched(eqProto(mTrampolineActivity), anyInt());
// A second, distinct, activity launch is coalesced into the current app launch sequence.
- mActivityMetricsLogger.notifyActivityLaunched(START_SUCCESS, mTopActivity);
+ mLaunchTopByTrampoline = true;
+ onIntentStarted(mTopActivity.intent);
+ notifyActivityLaunched(START_SUCCESS, mTopActivity);
+ // The observer shouldn't receive onActivityLaunched for an existing transition.
verifyNoMoreInteractions(mLaunchObserver);
}
- private void notifyTransitionStarting() {
- mActivityMetricsLogger.notifyTransitionStarting(new SparseIntArray(),
- SystemClock.elapsedRealtimeNanos());
+ private void notifyActivityLaunching(Intent intent) {
+ final ActivityMetricsLogger.LaunchingState previousState = mLaunchingState;
+ mLaunchingState = mActivityMetricsLogger.notifyActivityLaunching(intent,
+ mLaunchTopByTrampoline ? mTrampolineActivity : null /* caller */);
+ if (mLaunchTopByTrampoline) {
+ // The transition of TrampolineActivity has not been completed, so when the next
+ // activity is starting from it, the same launching state should be returned.
+ assertWithMessage("Use existing launching state for a caller in active transition")
+ .that(previousState).isEqualTo(mLaunchingState);
+ }
+ }
+
+ private void notifyActivityLaunched(int resultCode, ActivityRecord activity) {
+ mActivityMetricsLogger.notifyActivityLaunched(mLaunchingState, resultCode, activity);
+ }
+
+ private void notifyTransitionStarting(ActivityRecord activity) {
+ final ArrayMap<ActivityRecord, Integer> reasons = new ArrayMap<>();
+ reasons.put(activity, ActivityTaskManagerInternal.APP_TRANSITION_SPLASH_SCREEN);
+ mActivityMetricsLogger.notifyTransitionStarting(reasons);
}
private void notifyWindowsDrawn(ActivityRecord r) {
- mActivityMetricsLogger.notifyWindowsDrawn(r.getWindowingMode(),
- SystemClock.elapsedRealtimeNanos());
+ mActivityMetricsLogger.notifyWindowsDrawn(r, SystemClock.elapsedRealtimeNanos());
}
@Test
public void testOnActivityLaunchFinishedTrampoline() {
onActivityLaunchedTrampoline();
- notifyTransitionStarting();
+ notifyTransitionStarting(mTopActivity);
notifyWindowsDrawn(mTrampolineActivity);
+ assertWithMessage("Trampoline activity is drawn but the top activity is not yet")
+ .that(mLaunchingState.allDrawn()).isFalse();
+
notifyWindowsDrawn(mTopActivity);
verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mTopActivity), anyLong());
@@ -244,13 +272,23 @@
}
@Test
+ public void testDoNotCountInvisibleActivityToBeDrawn() {
+ onActivityLaunchedTrampoline();
+ mTrampolineActivity.setVisibility(false);
+ notifyWindowsDrawn(mTopActivity);
+
+ assertWithMessage("Trampoline activity is invisble so there should be no undrawn windows")
+ .that(mLaunchingState.allDrawn()).isTrue();
+ }
+
+ @Test
public void testOnActivityLaunchCancelledTrampoline() {
onActivityLaunchedTrampoline();
mTopActivity.mDrawn = true;
// Cannot time already-visible activities.
- mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT, mTopActivity);
+ notifyActivityLaunched(START_TASK_TO_FRONT, mTopActivity);
verifyAsync(mLaunchObserver).onActivityLaunchCancelled(eqProto(mTopActivity));
verifyNoMoreInteractions(mLaunchObserver);
@@ -268,4 +306,32 @@
.that(activityRecordToProto(mTrampolineActivity).length)
.isAtMost(ActivityMetricsLogger.LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE);
}
+
+ @Test
+ public void testConcurrentLaunches() {
+ onActivityLaunched(mTopActivity);
+ final ActivityMetricsLogger.LaunchingState previousState = mLaunchingState;
+
+ final ActivityRecord otherActivity = new ActivityBuilder(mService)
+ .setComponent(createRelative(DEFAULT_COMPONENT_PACKAGE_NAME, "OtherActivity"))
+ .setCreateTask(true)
+ .build();
+ // Assume the calling uid is different from the uid of TopActivity, so a new launching
+ // state should be created here.
+ onActivityLaunched(otherActivity);
+
+ assertWithMessage("Different callers should get 2 indepedent launching states")
+ .that(previousState).isNotEqualTo(mLaunchingState);
+
+ notifyTransitionStarting(otherActivity);
+ notifyWindowsDrawn(otherActivity);
+
+ verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(otherActivity), anyLong());
+
+ // The first transition should still be valid.
+ notifyTransitionStarting(mTopActivity);
+ notifyWindowsDrawn(mTopActivity);
+
+ verifyAsync(mLaunchObserver).onActivityLaunchFinished(eqProto(mTopActivity), anyLong());
+ }
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 479b144..98d7661 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1042,6 +1042,9 @@
*
* When {@code false}, the old behavior is used, where the toggle in accessibility settings is
* used to set the IMS stack's RTT enabled state.
+ *
+ * @deprecated -- this flag no longer does anything. Remove once the new behavior is verified.
+ *
* @hide
*/
public static final String KEY_IGNORE_RTT_MODE_SETTING_BOOL =
@@ -3523,7 +3526,7 @@
sDefaults.putInt(KEY_IMS_DTMF_TONE_DELAY_INT, 0);
sDefaults.putInt(KEY_CDMA_DTMF_TONE_DELAY_INT, 100);
sDefaults.putBoolean(KEY_CALL_FORWARDING_MAP_NON_NUMBER_TO_VOICEMAIL_BOOL, false);
- sDefaults.putBoolean(KEY_IGNORE_RTT_MODE_SETTING_BOOL, false);
+ sDefaults.putBoolean(KEY_IGNORE_RTT_MODE_SETTING_BOOL, true);
sDefaults.putInt(KEY_CDMA_3WAYCALL_FLASH_DELAY_INT , 0);
sDefaults.putBoolean(KEY_SUPPORT_CONFERENCE_CALL_BOOL, true);
sDefaults.putBoolean(KEY_SUPPORT_IMS_CONFERENCE_CALL_BOOL, true);
diff --git a/tests/net/AndroidManifest.xml b/tests/net/AndroidManifest.xml
index dcacb6d..638b6d1 100644
--- a/tests/net/AndroidManifest.xml
+++ b/tests/net/AndroidManifest.xml
@@ -32,7 +32,7 @@
<uses-permission android:name="android.permission.GET_DETAILED_TASKS" />
<uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
<uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" />
- <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
+ <uses-permission android:name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.MANAGE_USERS" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
@@ -45,6 +45,8 @@
<uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.NETWORK_STACK" />
+ <uses-permission android:name="android.permission.OBSERVE_NETWORK_POLICY" />
+ <uses-permission android:name="android.permission.NETWORK_FACTORY" />
<application>
<uses-library android:name="android.test.runner" />
diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
index 2738daa..39f849c 100644
--- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -265,6 +265,8 @@
assertFalse(mPermissionMonitor.hasNetworkPermission(app));
app = systemPackageInfoWithPermissions(CONNECTIVITY_USE_RESTRICTED_NETWORKS);
assertFalse(mPermissionMonitor.hasNetworkPermission(app));
+ app = systemPackageInfoWithPermissions(CONNECTIVITY_INTERNAL);
+ assertFalse(mPermissionMonitor.hasNetworkPermission(app));
}
@Test
@@ -274,7 +276,7 @@
PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CHANGE_NETWORK_STATE));
assertTrue(hasRestrictedNetworkPermission(
PARTITION_SYSTEM, VERSION_P, MOCK_UID1, NETWORK_STACK));
- assertTrue(hasRestrictedNetworkPermission(
+ assertFalse(hasRestrictedNetworkPermission(
PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CONNECTIVITY_INTERNAL));
assertTrue(hasRestrictedNetworkPermission(
PARTITION_SYSTEM, VERSION_P, MOCK_UID1, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
@@ -283,7 +285,7 @@
assertFalse(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_Q, MOCK_UID1));
assertFalse(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_Q, MOCK_UID1, CHANGE_WIFI_STATE));
+ PARTITION_SYSTEM, VERSION_Q, MOCK_UID1, CONNECTIVITY_INTERNAL));
}
@Test
@@ -291,14 +293,14 @@
doReturn(VERSION_P).when(mPermissionMonitor).getDeviceFirstSdkInt();
assertTrue(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID));
assertTrue(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_P, SYSTEM_UID, CHANGE_WIFI_STATE));
+ PARTITION_SYSTEM, VERSION_P, SYSTEM_UID, CONNECTIVITY_INTERNAL));
assertTrue(hasRestrictedNetworkPermission(
PARTITION_SYSTEM, VERSION_P, SYSTEM_UID, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
doReturn(VERSION_Q).when(mPermissionMonitor).getDeviceFirstSdkInt();
assertFalse(hasRestrictedNetworkPermission(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID));
assertFalse(hasRestrictedNetworkPermission(
- PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID, CHANGE_WIFI_STATE));
+ PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID, CONNECTIVITY_INTERNAL));
assertTrue(hasRestrictedNetworkPermission(
PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID, CONNECTIVITY_USE_RESTRICTED_NETWORKS));
}
@@ -319,7 +321,7 @@
assertFalse(hasRestrictedNetworkPermission(PARTITION_VENDOR, VERSION_Q, MOCK_UID1));
assertFalse(hasRestrictedNetworkPermission(
- PARTITION_VENDOR, VERSION_Q, MOCK_UID1, CHANGE_WIFI_STATE));
+ PARTITION_VENDOR, VERSION_Q, MOCK_UID1, CONNECTIVITY_INTERNAL));
assertFalse(hasRestrictedNetworkPermission(
PARTITION_VENDOR, VERSION_Q, MOCK_UID1, CHANGE_NETWORK_STATE));
}
@@ -337,7 +339,7 @@
public void testHasUseBackgroundNetworksPermission() throws Exception {
assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(SYSTEM_UID));
assertBackgroundPermission(false, SYSTEM_PACKAGE1, SYSTEM_UID);
- assertBackgroundPermission(false, SYSTEM_PACKAGE1, SYSTEM_UID, CHANGE_WIFI_STATE);
+ assertBackgroundPermission(false, SYSTEM_PACKAGE1, SYSTEM_UID, CONNECTIVITY_INTERNAL);
assertBackgroundPermission(true, SYSTEM_PACKAGE1, SYSTEM_UID, CHANGE_NETWORK_STATE);
assertBackgroundPermission(true, SYSTEM_PACKAGE1, SYSTEM_UID, NETWORK_STACK);
@@ -348,8 +350,9 @@
assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID2));
assertBackgroundPermission(false, MOCK_PACKAGE2, MOCK_UID2);
- assertBackgroundPermission(true, MOCK_PACKAGE2, MOCK_UID2,
+ assertBackgroundPermission(false, MOCK_PACKAGE2, MOCK_UID2,
CONNECTIVITY_INTERNAL);
+ assertBackgroundPermission(true, MOCK_PACKAGE2, MOCK_UID2, NETWORK_STACK);
}
private class NetdMonitor {
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 83bba27..52f5eee 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -723,7 +723,9 @@
* had been reset.
* @hide
*/
- public static final String WIFI_NETWORK_SETTINGS_RESET_ACTION =
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_CARRIER_PROVISIONING)
+ public static final String ACTION_NETWORK_SETTINGS_RESET =
"android.net.wifi.action.NETWORK_SETTINGS_RESET";
/**