summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/test-current.txt1
-rw-r--r--core/java/android/app/LocaleConfig.java4
-rw-r--r--core/java/android/app/NotificationChannel.java8
-rw-r--r--core/java/android/app/admin/ProvisioningIntentHelper.java38
-rw-r--r--core/java/android/content/pm/PackageParser.java18
-rw-r--r--core/java/android/content/pm/parsing/ApkLiteParseUtils.java7
-rw-r--r--core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java31
-rw-r--r--core/java/android/provider/DeviceConfig.java8
-rw-r--r--core/java/android/provider/Settings.java43
-rw-r--r--core/java/android/view/WindowManager.java8
-rw-r--r--core/java/android/window/WindowTokenClient.java28
-rw-r--r--core/java/com/android/internal/app/UnlaunchableAppActivity.java7
-rw-r--r--core/java/com/android/internal/notification/NotificationAccessConfirmationActivityContract.java7
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java5
-rw-r--r--core/java/com/android/internal/policy/DecorView.java2
-rw-r--r--core/jni/android_media_AudioSystem.cpp39
-rw-r--r--core/tests/coretests/src/com/android/internal/os/BatteryStatsHistoryIteratorTest.java21
-rw-r--r--data/etc/services.core.protolog.json6
-rw-r--r--keystore/java/android/security/keystore2/AndroidKeyStoreEdECPrivateKey.java46
-rw-r--r--keystore/java/android/security/keystore2/AndroidKeyStoreEdECPublicKey.java145
-rw-r--r--keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java6
-rw-r--r--keystore/tests/src/android/security/keystore2/AndroidKeyStoreEdECPublicKeyTest.java123
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java114
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt2
-rw-r--r--libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt4
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java8
-rw-r--r--media/java/android/media/tv/tuner/Tuner.java12
-rw-r--r--media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java37
-rw-r--r--media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl21
-rw-r--r--packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java8
-rw-r--r--packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v31/collapsing_toolbar_content_layout.xml2
-rw-r--r--packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/widget/CollapsingCoordinatorLayout.java3
-rw-r--r--packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java16
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java24
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java22
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java4
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java9
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java10
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java3
-rw-r--r--packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java5
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java11
-rw-r--r--packages/SystemUI/res/drawable/media_output_icon_volume.xml10
-rw-r--r--packages/SystemUI/res/layout/clipboard_overlay.xml2
-rw-r--r--packages/SystemUI/res/layout/screenshot.xml9
-rw-r--r--packages/SystemUI/res/layout/screenshot_static.xml15
-rw-r--r--packages/SystemUI/res/values-h800dp/dimens.xml2
-rw-r--r--packages/SystemUI/res/values/dimens.xml5
-rw-r--r--packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt197
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java29
-rw-r--r--packages/SystemUI/src/com/android/keyguard/LockIconView.java4
-rw-r--r--packages/SystemUI/src/com/android/keyguard/LockIconViewController.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/ScreenDecorations.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java46
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java105
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/SmartspaceMediaData.kt31
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java27
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java21
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java56
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt12
-rw-r--r--packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt193
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java23
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java31
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt172
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java6
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java71
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java45
-rw-r--r--services/autofill/java/com/android/server/autofill/Session.java5
-rw-r--r--services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java21
-rw-r--r--services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java56
-rw-r--r--services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java88
-rw-r--r--services/core/java/com/android/server/am/AppBatteryTracker.java106
-rw-r--r--services/core/java/com/android/server/am/DropboxRateLimiter.java11
-rw-r--r--services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java8
-rw-r--r--services/core/java/com/android/server/inputmethod/HandwritingModeController.java27
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java10
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java131
-rw-r--r--services/core/java/com/android/server/notification/NotificationRecord.java2
-rw-r--r--services/core/java/com/android/server/notification/PermissionHelper.java26
-rw-r--r--services/core/java/com/android/server/notification/PreferencesHelper.java291
-rw-r--r--services/core/java/com/android/server/notification/RankingConfig.java2
-rw-r--r--services/core/java/com/android/server/pm/Installer.java23
-rw-r--r--services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java3
-rw-r--r--services/core/java/com/android/server/policy/PermissionPolicyService.java10
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java15
-rw-r--r--services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java25
-rw-r--r--services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java268
-rw-r--r--services/core/java/com/android/server/utils/WatchedArrayList.java2
-rw-r--r--services/core/java/com/android/server/utils/WatchedArrayMap.java2
-rw-r--r--services/core/java/com/android/server/utils/WatchedArraySet.java2
-rw-r--r--services/core/java/com/android/server/utils/WatchedLongSparseArray.java2
-rw-r--r--services/core/java/com/android/server/utils/WatchedSparseArray.java2
-rw-r--r--services/core/java/com/android/server/utils/WatchedSparseBooleanArray.java2
-rw-r--r--services/core/java/com/android/server/utils/WatchedSparseIntArray.java2
-rw-r--r--services/core/java/com/android/server/utils/WatchedSparseSetArray.java2
-rw-r--r--services/core/java/com/android/server/wm/AccessibilityController.java37
-rw-r--r--services/core/java/com/android/server/wm/AppTransitionController.java7
-rw-r--r--services/core/java/com/android/server/wm/BLASTSyncEngine.java21
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java8
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerInternal.java38
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java43
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java46
-rw-r--r--services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/am/DropboxRateLimiterTest.java16
-rw-r--r--services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java4
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ImportanceExtractorTest.java4
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelLoggerFake.java7
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java430
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java877
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java3
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java42
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java737
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java3
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java41
-rw-r--r--telecomm/java/android/telecom/PhoneAccountHandle.java33
-rw-r--r--telephony/java/android/telephony/AnomalyReporter.java22
-rw-r--r--telephony/java/android/telephony/CarrierConfigManager.java19
-rw-r--r--tests/ApkVerityTest/Android.bp4
-rw-r--r--tests/ApkVerityTest/block_device_writer/Android.bp24
-rw-r--r--tests/ApkVerityTest/block_device_writer/src/com/android/blockdevicewriter/BlockDeviceWriter.java2
131 files changed, 2980 insertions, 2820 deletions
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 2c0b6e9ee89d..36e1c941cbc6 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -314,7 +314,6 @@ package android.app {
public final class NotificationChannel implements android.os.Parcelable {
method public int getOriginalImportance();
method public boolean isImportanceLockedByCriticalDeviceFunction();
- method public boolean isImportanceLockedByOEM();
method public void lockFields(int);
method public void setDeleted(boolean);
method public void setDeletedTimeMs(long);
diff --git a/core/java/android/app/LocaleConfig.java b/core/java/android/app/LocaleConfig.java
index 436eac37b4fb..7c83d5850f76 100644
--- a/core/java/android/app/LocaleConfig.java
+++ b/core/java/android/app/LocaleConfig.java
@@ -45,7 +45,9 @@ import java.util.Set;
* referenced in the manifest via {@code android:localeConfig} on
* {@code <application>}.
*
- * For more information, see TODO(b/214154050): add link to guide
+ * <p>For more information, see
+ * <a href="https://developer.android.com/about/versions/13/features/app-languages#use-localeconfig">
+ * the section on per-app language preferences</a>.
*
* @attr ref android.R.styleable#LocaleConfig_Locale_name
* @attr ref android.R.styleable#AndroidManifestApplication_localeConfig
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 91ab19b9e44a..6f0b03aeb6f3 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -867,14 +867,6 @@ public final class NotificationChannel implements Parcelable {
* @hide
*/
@TestApi
- public boolean isImportanceLockedByOEM() {
- return mImportanceLockedByOEM;
- }
-
- /**
- * @hide
- */
- @TestApi
public boolean isImportanceLockedByCriticalDeviceFunction() {
return mImportanceLockedDefaultApp;
}
diff --git a/core/java/android/app/admin/ProvisioningIntentHelper.java b/core/java/android/app/admin/ProvisioningIntentHelper.java
index fbad90c30d7e..1c38559a4083 100644
--- a/core/java/android/app/admin/ProvisioningIntentHelper.java
+++ b/core/java/android/app/admin/ProvisioningIntentHelper.java
@@ -17,8 +17,10 @@
package android.app.admin;
import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE_FROM_TRUSTED_SOURCE;
+import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE;
import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME;
import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME;
+import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_ROLE_HOLDER_EXTRAS_BUNDLE;
import static android.app.admin.DevicePolicyManager.EXTRA_PROVISIONING_TRIGGER;
import static android.app.admin.DevicePolicyManager.MIME_TYPE_PROVISIONING_NFC;
import static android.app.admin.DevicePolicyManager.PROVISIONING_TRIGGER_NFC;
@@ -36,12 +38,14 @@ import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.os.Bundle;
import android.os.Parcelable;
+import android.os.PersistableBundle;
import android.util.Log;
import java.io.IOException;
import java.io.StringReader;
import java.util.Enumeration;
import java.util.Properties;
+import java.util.Set;
/**
* Utility class that provides functionality to create provisioning intents from nfc intents.
@@ -124,12 +128,46 @@ final class ProvisioningIntentHelper {
ComponentName componentName = ComponentName.unflattenFromString(
properties.getProperty(propertyName));
bundle.putParcelable(propertyName, componentName);
+ } else if (EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE.equals(propertyName)
+ || EXTRA_PROVISIONING_ROLE_HOLDER_EXTRAS_BUNDLE.equals(propertyName)) {
+ try {
+ bundle.putParcelable(propertyName,
+ deserializeExtrasBundle(properties, propertyName));
+ } catch (IOException e) {
+ Log.e(TAG,
+ "Failed to parse " + propertyName + ".", e);
+ }
}
else {
bundle.putString(propertyName, properties.getProperty(propertyName));
}
}
+ /**
+ * Get a {@link PersistableBundle} from a {@code String} property in a {@link Properties}
+ * object.
+ * @param properties the source of the extra
+ * @param extraName key into the {@link Properties} object
+ * @return the {@link PersistableBundle} or {@code null} if there was no property with the
+ * given name
+ * @throws IOException if there was an error parsing the property
+ */
+ private static PersistableBundle deserializeExtrasBundle(
+ Properties properties, String extraName) throws IOException {
+ String serializedExtras = properties.getProperty(extraName);
+ if (serializedExtras == null) {
+ return null;
+ }
+ Properties bundleProperties = new Properties();
+ bundleProperties.load(new StringReader(serializedExtras));
+ PersistableBundle extrasBundle = new PersistableBundle(bundleProperties.size());
+ Set<String> propertyNames = bundleProperties.stringPropertyNames();
+ for (String propertyName : propertyNames) {
+ extrasBundle.putString(propertyName, bundleProperties.getProperty(propertyName));
+ }
+ return extrasBundle;
+ }
+
private static Intent createProvisioningIntentFromBundle(Bundle bundle) {
requireNonNull(bundle);
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 44dc28d2b0fa..52e64e80e6d4 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2618,6 +2618,15 @@ public class PackageParser {
return Build.VERSION_CODES.CUR_DEVELOPMENT;
}
+ // STOPSHIP: hack for the pre-release SDK
+ if (platformSdkCodenames.length == 0
+ && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
+ targetCode)) {
+ Slog.w(TAG, "Package requires development platform " + targetCode
+ + ", returning current version " + Build.VERSION.SDK_INT);
+ return Build.VERSION.SDK_INT;
+ }
+
// Otherwise, we're looking at an incompatible pre-release SDK.
if (platformSdkCodenames.length > 0) {
outError[0] = "Requires development platform " + targetCode
@@ -2689,6 +2698,15 @@ public class PackageParser {
return Build.VERSION_CODES.CUR_DEVELOPMENT;
}
+ // STOPSHIP: hack for the pre-release SDK
+ if (platformSdkCodenames.length == 0
+ && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
+ minCode)) {
+ Slog.w(TAG, "Package requires min development platform " + minCode
+ + ", returning current version " + Build.VERSION.SDK_INT);
+ return Build.VERSION.SDK_INT;
+ }
+
// Otherwise, we're looking at an incompatible pre-release SDK.
if (platformSdkCodenames.length > 0) {
outError[0] = "Requires development platform " + minCode
diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
index cb55e303e778..20a4fdf658c6 100644
--- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
@@ -567,9 +567,14 @@ public class ApkLiteParseUtils {
targetCode = minCode;
}
+ boolean allowUnknownCodenames = false;
+ if ((flags & FrameworkParsingPackageUtils.PARSE_APK_IN_APEX) != 0) {
+ allowUnknownCodenames = true;
+ }
+
ParseResult<Integer> targetResult = FrameworkParsingPackageUtils.computeTargetSdkVersion(
targetVer, targetCode, SDK_CODENAMES, input,
- /* allowUnknownCodenames= */ false);
+ allowUnknownCodenames);
if (targetResult.isError()) {
return input.error(targetResult);
}
diff --git a/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java b/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
index 6d74b819301d..8cc4cdb955ca 100644
--- a/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java
@@ -58,6 +58,7 @@ public class FrameworkParsingPackageUtils {
private static final int MAX_FILE_NAME_SIZE = 223;
public static final int PARSE_IGNORE_OVERLAY_REQUIRED_SYSTEM_PROPERTY = 1 << 7;
+ public static final int PARSE_APK_IN_APEX = 1 << 9;
/**
* Check if the given name is valid.
@@ -315,6 +316,15 @@ public class FrameworkParsingPackageUtils {
return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
}
+ // STOPSHIP: hack for the pre-release SDK
+ if (platformSdkCodenames.length == 0
+ && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
+ minCode)) {
+ Slog.w(TAG, "Parsed package requires min development platform " + minCode
+ + ", returning current version " + Build.VERSION.SDK_INT);
+ return input.success(Build.VERSION.SDK_INT);
+ }
+
// Otherwise, we're looking at an incompatible pre-release SDK.
if (platformSdkCodenames.length > 0) {
return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK,
@@ -367,16 +377,29 @@ public class FrameworkParsingPackageUtils {
return input.success(targetVers);
}
- if (allowUnknownCodenames && UnboundedSdkLevel.isAtMost(targetCode)) {
- return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
- }
-
// If it's a pre-release SDK and the codename matches this platform, it
// definitely targets this SDK.
if (matchTargetCode(platformSdkCodenames, targetCode)) {
return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
}
+ // STOPSHIP: hack for the pre-release SDK
+ if (platformSdkCodenames.length == 0
+ && Build.VERSION.KNOWN_CODENAMES.stream().max(String::compareTo).orElse("").equals(
+ targetCode)) {
+ Slog.w(TAG, "Parsed package requires development platform " + targetCode
+ + ", returning current version " + Build.VERSION.SDK_INT);
+ return input.success(Build.VERSION.SDK_INT);
+ }
+
+ try {
+ if (allowUnknownCodenames && UnboundedSdkLevel.isAtMost(targetCode)) {
+ return input.success(Build.VERSION_CODES.CUR_DEVELOPMENT);
+ }
+ } catch (IllegalArgumentException e) {
+ return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK, "Bad package SDK");
+ }
+
// Otherwise, we're looking at an incompatible pre-release SDK.
if (platformSdkCodenames.length > 0) {
return input.error(PackageManager.INSTALL_FAILED_OLDER_SDK,
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 37f44e98c165..9a2f7baa7265 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -738,6 +738,14 @@ public final class DeviceConfig {
*/
public static final String NAMESPACE_VENDOR_SYSTEM_NATIVE = "vendor_system_native";
+ /**
+ * Namespace for DevicePolicyManager related features.
+ *
+ * @hide
+ */
+ public static final String NAMESPACE_DEVICE_POLICY_MANAGER =
+ "device_policy_manager";
+
private static final Object sLock = new Object();
@GuardedBy("sLock")
private static ArrayMap<OnPropertiesChangedListener, Pair<String, Executor>> sListeners =
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index dac54cf6146e..d2a86eb31870 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9695,6 +9695,40 @@ public final class Settings {
"active_unlock_on_biometric_fail";
/**
+ * If active unlock triggers on biometric failures, include the following error codes
+ * as a biometric failure. See {@link android.hardware.biometrics.BiometricFaceConstants}.
+ * Error codes should be separated by a pipe. For example: "1|4|5". If active unlock
+ * should never trigger on any face errors, this should be set to an empty string.
+ * A null value will use the system default value (TIMEOUT).
+ * @hide
+ */
+ public static final String ACTIVE_UNLOCK_ON_FACE_ERRORS =
+ "active_unlock_on_face_errors";
+
+ /**
+ * If active unlock triggers on biometric failures, include the following acquired info
+ * as a "biometric failure". See {@link android.hardware.biometrics.BiometricFaceConstants}.
+ * Acquired codes should be separated by a pipe. For example: "1|4|5". If active unlock
+ * should never on trigger on any acquired info messages, this should be
+ * set to an empty string. A null value will use the system default value (none).
+ * @hide
+ */
+ public static final String ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO =
+ "active_unlock_on_face_acquire_info";
+
+ /**
+ * If active unlock triggers on biometric failures, then also request active unlock on
+ * unlock intent when each setting (BiometricType) is the only biometric type enrolled.
+ * Biometric types should be separated by a pipe. For example: "0|3" or "0". If this
+ * setting should be disabled, then this should be set to an empty string. A null value
+ * will use the system default value (0 / None).
+ * 0 = None, 1 = Any face, 2 = Any fingerprint, 3 = Under display fingerprint
+ * @hide
+ */
+ public static final String ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED =
+ "active_unlock_on_unlock_intent_when_biometric_enrolled";
+
+ /**
* Whether the assist gesture should be enabled.
*
* @hide
@@ -10121,15 +10155,6 @@ public final class Settings {
public static final String NOTIFICATION_DISMISS_RTL = "notification_dismiss_rtl";
/**
- * Whether the app-level notification setting is represented by a manifest permission.
- *
- * @hide
- */
- @Readable
- public static final String NOTIFICATION_PERMISSION_ENABLED =
- "notification_permission_enabled";
-
- /**
* Comma separated list of QS tiles that have been auto-added already.
* @hide
*/
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 5bc340b76f56..00052f6015d5 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -3108,10 +3108,14 @@ public interface WindowManager extends ViewManager {
/**
* The preferred refresh rate for the window.
- *
+ * <p>
* This must be one of the supported refresh rates obtained for the display(s) the window
* is on. The selected refresh rate will be applied to the display's default mode.
- *
+ * <p>
+ * This should be used in favor of {@link LayoutParams#preferredDisplayModeId} for
+ * applications that want to specify the refresh rate, but do not want to specify a
+ * preference for any other displayMode properties (e.g., resolution).
+ * <p>
* This value is ignored if {@link #preferredDisplayModeId} is set.
*
* @see Display#getSupportedRefreshRates()
diff --git a/core/java/android/window/WindowTokenClient.java b/core/java/android/window/WindowTokenClient.java
index 7db4243d3a83..0976f45c02b0 100644
--- a/core/java/android/window/WindowTokenClient.java
+++ b/core/java/android/window/WindowTokenClient.java
@@ -21,8 +21,10 @@ import static android.window.ConfigurationHelper.shouldUpdateResources;
import android.annotation.AnyThread;
import android.annotation.BinderThread;
+import android.annotation.MainThread;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityThread;
import android.app.IWindowToken;
import android.app.ResourcesManager;
import android.content.Context;
@@ -33,7 +35,6 @@ import android.os.Bundle;
import android.os.Debug;
import android.os.Handler;
import android.os.IBinder;
-import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
import android.view.IWindowManager;
@@ -42,6 +43,7 @@ import android.view.WindowManagerGlobal;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.function.pooled.PooledLambda;
import java.lang.ref.WeakReference;
@@ -76,7 +78,7 @@ public class WindowTokenClient extends IWindowToken.Stub {
private boolean mAttachToWindowContainer;
- private final Handler mHandler = new Handler(Looper.getMainLooper());
+ private final Handler mHandler = ActivityThread.currentActivityThread().getHandler();
/**
* Attaches {@code context} to this {@link WindowTokenClient}. Each {@link WindowTokenClient}
@@ -188,8 +190,8 @@ public class WindowTokenClient extends IWindowToken.Stub {
@BinderThread
@Override
public void onConfigurationChanged(Configuration newConfig, int newDisplayId) {
- mHandler.post(() -> onConfigurationChanged(newConfig, newDisplayId,
- true /* shouldReportConfigChange */));
+ mHandler.post(PooledLambda.obtainRunnable(this::onConfigurationChanged, newConfig,
+ newDisplayId, true /* shouldReportConfigChange */).recycleOnUse());
}
// TODO(b/192048581): rewrite this method based on WindowContext and WindowProviderService
@@ -279,12 +281,16 @@ public class WindowTokenClient extends IWindowToken.Stub {
@BinderThread
@Override
public void onWindowTokenRemoved() {
- mHandler.post(() -> {
- final Context context = mContextRef.get();
- if (context != null) {
- context.destroy();
- mContextRef.clear();
- }
- });
+ mHandler.post(PooledLambda.obtainRunnable(
+ WindowTokenClient::onWindowTokenRemovedInner, this).recycleOnUse());
+ }
+
+ @MainThread
+ private void onWindowTokenRemovedInner() {
+ final Context context = mContextRef.get();
+ if (context != null) {
+ context.destroy();
+ mContextRef.clear();
+ }
}
}
diff --git a/core/java/com/android/internal/app/UnlaunchableAppActivity.java b/core/java/com/android/internal/app/UnlaunchableAppActivity.java
index 957a6365739d..e56d92b48528 100644
--- a/core/java/com/android/internal/app/UnlaunchableAppActivity.java
+++ b/core/java/com/android/internal/app/UnlaunchableAppActivity.java
@@ -91,7 +91,12 @@ public class UnlaunchableAppActivity extends Activity
} else {
builder.setPositiveButton(R.string.ok, null);
}
- builder.show();
+ final AlertDialog dialog = builder.create();
+ dialog.create();
+ // Prevents screen overlay attack.
+ getWindow().setHideOverlayWindows(true);
+ dialog.getButton(DialogInterface.BUTTON_POSITIVE).setFilterTouchesWhenObscured(true);
+ dialog.show();
}
private String getDialogTitle() {
diff --git a/core/java/com/android/internal/notification/NotificationAccessConfirmationActivityContract.java b/core/java/com/android/internal/notification/NotificationAccessConfirmationActivityContract.java
index 3eb980465214..5adaf4fbd2cc 100644
--- a/core/java/com/android/internal/notification/NotificationAccessConfirmationActivityContract.java
+++ b/core/java/com/android/internal/notification/NotificationAccessConfirmationActivityContract.java
@@ -28,18 +28,15 @@ import com.android.internal.R;
public final class NotificationAccessConfirmationActivityContract {
public static final String EXTRA_USER_ID = "user_id";
public static final String EXTRA_COMPONENT_NAME = "component_name";
- public static final String EXTRA_PACKAGE_TITLE = "package_title";
/**
* Creates a launcher intent for NotificationAccessConfirmationActivity.
*/
- public static Intent launcherIntent(Context context, int userId, ComponentName component,
- String packageTitle) {
+ public static Intent launcherIntent(Context context, int userId, ComponentName component) {
return new Intent()
.setComponent(ComponentName.unflattenFromString(context.getString(
R.string.config_notificationAccessConfirmationActivity)))
.putExtra(EXTRA_USER_ID, userId)
- .putExtra(EXTRA_COMPONENT_NAME, component)
- .putExtra(EXTRA_PACKAGE_TITLE, packageTitle);
+ .putExtra(EXTRA_COMPONENT_NAME, component);
}
}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 3f87de2e0f8a..b03a8cbeb79c 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -167,7 +167,7 @@ public class BatteryStatsImpl extends BatteryStats {
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- static final int VERSION = 207;
+ static final int VERSION = 208;
// The maximum number of names wakelocks we will keep track of
// per uid; once the limit is reached, we batch the remaining wakelocks
@@ -3981,8 +3981,7 @@ public class BatteryStatsImpl extends BatteryStats {
if (idxObj != null) {
idx = idxObj;
if ((idx & TAG_FIRST_OCCURRENCE_FLAG) != 0) {
- idx &= ~TAG_FIRST_OCCURRENCE_FLAG;
- mHistoryTagPool.put(tag, idx);
+ mHistoryTagPool.put(tag, idx & ~TAG_FIRST_OCCURRENCE_FLAG);
}
return idx;
} else if (mNextHistoryTagIdx < HISTORY_TAG_INDEX_LIMIT) {
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 1db4bbba9ad5..ea5797d752d7 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -1262,7 +1262,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
}
}
- if (forceConsumingNavBar && !mDrawLegacyNavigationBarBackgroundHandled) {
+ if (forceConsumingNavBar && !hideNavigation && !mDrawLegacyNavigationBarBackgroundHandled) {
mBackgroundInsets = Insets.of(mLastLeftInset, 0, mLastRightInset, mLastBottomInset);
} else {
mBackgroundInsets = Insets.NONE;
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index b6fbe206a262..f24c66695052 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -1264,6 +1264,12 @@ static jint convertAudioProfileFromNative(JNIEnv *env, jobject *jAudioProfile,
size_t numPositionMasks = 0;
size_t numIndexMasks = 0;
+ int audioFormat = audioFormatFromNative(nAudioProfile->format);
+ if (audioFormat == ENCODING_INVALID) {
+ ALOGW("Unknown native audio format for JAVA API: %u", nAudioProfile->format);
+ return AUDIO_JAVA_BAD_VALUE;
+ }
+
// count up how many masks are positional and indexed
for (size_t index = 0; index < nAudioProfile->num_channel_masks; index++) {
const audio_channel_mask_t mask = nAudioProfile->channel_masks[index];
@@ -1306,10 +1312,9 @@ static jint convertAudioProfileFromNative(JNIEnv *env, jobject *jAudioProfile,
ALOGW("Unknown encapsulation type for JAVA API: %u", nAudioProfile->encapsulation_type);
}
- *jAudioProfile =
- env->NewObject(gAudioProfileClass, gAudioProfileCstor,
- audioFormatFromNative(nAudioProfile->format), jSamplingRates.get(),
- jChannelMasks.get(), jChannelIndexMasks.get(), encapsulationType);
+ *jAudioProfile = env->NewObject(gAudioProfileClass, gAudioProfileCstor, audioFormat,
+ jSamplingRates.get(), jChannelMasks.get(),
+ jChannelIndexMasks.get(), encapsulationType);
if (*jAudioProfile == nullptr) {
return AUDIO_JAVA_ERROR;
@@ -1368,6 +1373,10 @@ static jint convertAudioPortFromNative(JNIEnv *env, jobject *jAudioPort,
jobject jAudioProfile = nullptr;
jStatus = convertAudioProfileFromNative(env, &jAudioProfile, &nAudioPort->audio_profiles[i],
useInMask);
+ if (jStatus == AUDIO_JAVA_BAD_VALUE) {
+ // skipping Java layer unsupported audio formats
+ continue;
+ }
if (jStatus != NO_ERROR) {
jStatus = (jint)AUDIO_JAVA_ERROR;
goto exit;
@@ -2406,8 +2415,13 @@ static jint android_media_AudioSystem_getSurroundFormats(JNIEnv *env, jobject th
goto exit;
}
for (size_t i = 0; i < numSurroundFormats; i++) {
- jobject surroundFormat = env->NewObject(gIntegerClass, gIntegerCstor,
- audioFormatFromNative(surroundFormats[i]));
+ int audioFormat = audioFormatFromNative(surroundFormats[i]);
+ if (audioFormat == ENCODING_INVALID) {
+ // skipping Java layer unsupported audio formats
+ ALOGW("Unknown surround native audio format for JAVA API: %u", surroundFormats[i]);
+ continue;
+ }
+ jobject surroundFormat = env->NewObject(gIntegerClass, gIntegerCstor, audioFormat);
jobject enabled = env->NewObject(gBooleanClass, gBooleanCstor, surroundFormatsEnabled[i]);
env->CallObjectMethod(jSurroundFormats, gMapPut, surroundFormat, enabled);
env->DeleteLocalRef(surroundFormat);
@@ -2453,8 +2467,13 @@ static jint android_media_AudioSystem_getReportedSurroundFormats(JNIEnv *env, jo
goto exit;
}
for (size_t i = 0; i < numSurroundFormats; i++) {
- jobject surroundFormat = env->NewObject(gIntegerClass, gIntegerCstor,
- audioFormatFromNative(surroundFormats[i]));
+ int audioFormat = audioFormatFromNative(surroundFormats[i]);
+ if (audioFormat == ENCODING_INVALID) {
+ // skipping Java layer unsupported audio formats
+ ALOGW("Unknown surround native audio format for JAVA API: %u", surroundFormats[i]);
+ continue;
+ }
+ jobject surroundFormat = env->NewObject(gIntegerClass, gIntegerCstor, audioFormat);
env->CallObjectMethod(jSurroundFormats, gArrayListMethods.add, surroundFormat);
env->DeleteLocalRef(surroundFormat);
}
@@ -2919,6 +2938,10 @@ static jint android_media_AudioSystem_getDirectProfilesForAttributes(JNIEnv *env
for (const auto &audioProfile : audioProfiles) {
jobject jAudioProfile;
jStatus = convertAudioProfileFromNative(env, &jAudioProfile, &audioProfile, false);
+ if (jStatus == AUDIO_JAVA_BAD_VALUE) {
+ // skipping Java layer unsupported audio formats
+ continue;
+ }
if (jStatus != AUDIO_JAVA_SUCCESS) {
return jStatus;
}
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsHistoryIteratorTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsHistoryIteratorTest.java
index 2262c057d842..385879210d4a 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsHistoryIteratorTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsHistoryIteratorTest.java
@@ -35,6 +35,7 @@ import java.io.File;
@RunWith(AndroidJUnit4.class)
@SmallTest
+@SuppressWarnings("GuardedBy")
public class BatteryStatsHistoryIteratorTest {
private static final int APP_UID = Process.FIRST_APPLICATION_UID + 42;
@@ -124,7 +125,10 @@ public class BatteryStatsHistoryIteratorTest {
// More than 32k strings
final int eventCount = 0x7FFF + 100;
for (int i = 0; i < eventCount; i++) {
- mBatteryStats.noteAlarmStartLocked("a" + i, null, APP_UID, 3_000_000, 2_000_000);
+ // Names repeat in order to verify de-duping of identical history tags.
+ String name = "a" + (i % 10);
+ mBatteryStats.noteAlarmStartLocked(name, null, APP_UID, 3_000_000, 2_000_000);
+ mBatteryStats.noteAlarmFinishLocked(name, null, APP_UID, 3_500_000, 2_500_000);
}
final BatteryStatsHistoryIterator iterator =
@@ -149,10 +153,23 @@ public class BatteryStatsHistoryIteratorTest {
assertThat(item.time).isEqualTo(2_000_000);
for (int i = 0; i < eventCount; i++) {
+ String name = "a" + (i % 10);
assertThat(iterator.next(item)).isTrue();
+ // Skip a blank event inserted at the start of every buffer
+ if (item.eventCode == BatteryStats.HistoryItem.EVENT_NONE) {
+ assertThat(iterator.next(item)).isTrue();
+ }
assertThat(item.eventCode).isEqualTo(BatteryStats.HistoryItem.EVENT_ALARM
| BatteryStats.HistoryItem.EVENT_FLAG_START);
- assertThat(item.eventTag.string).isEqualTo("a" + i);
+ assertThat(item.eventTag.string).isEqualTo(name);
+
+ assertThat(iterator.next(item)).isTrue();
+ if (item.eventCode == BatteryStats.HistoryItem.EVENT_NONE) {
+ assertThat(iterator.next(item)).isTrue();
+ }
+ assertThat(item.eventCode).isEqualTo(BatteryStats.HistoryItem.EVENT_ALARM
+ | BatteryStats.HistoryItem.EVENT_FLAG_FINISH);
+ assertThat(item.eventTag.string).isEqualTo(name);
}
assertThat(iterator.next(item)).isFalse();
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 12d3d642a862..60da2e8cba27 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -2485,12 +2485,6 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "323235828": {
- "message": "Delaying app transition for recents animation to finish",
- "level": "VERBOSE",
- "group": "WM_DEBUG_APP_TRANSITIONS",
- "at": "com\/android\/server\/wm\/AppTransitionController.java"
- },
"327461496": {
"message": "Complete pause: %s",
"level": "VERBOSE",
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreEdECPrivateKey.java b/keystore/java/android/security/keystore2/AndroidKeyStoreEdECPrivateKey.java
new file mode 100644
index 000000000000..4855ad0f7293
--- /dev/null
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreEdECPrivateKey.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keystore2;
+
+import android.annotation.NonNull;
+import android.security.KeyStoreSecurityLevel;
+import android.system.keystore2.Authorization;
+import android.system.keystore2.KeyDescriptor;
+
+import java.security.PrivateKey;
+import java.security.interfaces.EdECKey;
+import java.security.spec.NamedParameterSpec;
+
+/**
+ * EdEC private key (instance of {@link PrivateKey} and {@link EdECKey}) backed by keystore.
+ *
+ * @hide
+ */
+public class AndroidKeyStoreEdECPrivateKey extends AndroidKeyStorePrivateKey implements EdECKey {
+ public AndroidKeyStoreEdECPrivateKey(
+ @NonNull KeyDescriptor descriptor, long keyId,
+ @NonNull Authorization[] authorizations,
+ @NonNull String algorithm,
+ @NonNull KeyStoreSecurityLevel securityLevel) {
+ super(descriptor, keyId, authorizations, algorithm, securityLevel);
+ }
+
+ @Override
+ public NamedParameterSpec getParams() {
+ return NamedParameterSpec.ED25519;
+ }
+}
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreEdECPublicKey.java b/keystore/java/android/security/keystore2/AndroidKeyStoreEdECPublicKey.java
new file mode 100644
index 000000000000..642e08813291
--- /dev/null
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreEdECPublicKey.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keystore2;
+
+import android.annotation.NonNull;
+import android.security.KeyStoreSecurityLevel;
+import android.system.keystore2.KeyDescriptor;
+import android.system.keystore2.KeyMetadata;
+
+import java.math.BigInteger;
+import java.security.interfaces.EdECPublicKey;
+import java.security.spec.EdECPoint;
+import java.security.spec.NamedParameterSpec;
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * {@link EdECPublicKey} backed by keystore.
+ *
+ * @hide
+ */
+public class AndroidKeyStoreEdECPublicKey extends AndroidKeyStorePublicKey
+ implements EdECPublicKey {
+ /**
+ * DER sequence, as defined in https://datatracker.ietf.org/doc/html/rfc8410#section-4 and
+ * https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.
+ * SEQUENCE (2 elem)
+ * SEQUENCE (1 elem)
+ * OBJECT IDENTIFIER 1.3.101.112 curveEd25519 (EdDSA 25519 signature algorithm)
+ * as defined in https://datatracker.ietf.org/doc/html/rfc8410#section-3
+ * BIT STRING (256 bit) as defined in
+ * https://datatracker.ietf.org/doc/html/rfc8032#section-5.1.2
+ */
+ private static final byte[] DER_KEY_PREFIX = new byte[] {
+ 0x30,
+ 0x2a,
+ 0x30,
+ 0x05,
+ 0x06,
+ 0x03,
+ 0x2b,
+ 0x65,
+ 0x70,
+ 0x03,
+ 0x21,
+ 0x00,
+ };
+ private static final int ED25519_KEY_SIZE_BYTES = 32;
+
+ private byte[] mEncodedKey;
+ private EdECPoint mPoint;
+
+ public AndroidKeyStoreEdECPublicKey(
+ @NonNull KeyDescriptor descriptor,
+ @NonNull KeyMetadata metadata,
+ @NonNull String algorithm,
+ @NonNull KeyStoreSecurityLevel iSecurityLevel,
+ @NonNull byte[] encodedKey) {
+ super(descriptor, metadata, encodedKey, algorithm, iSecurityLevel);
+ mEncodedKey = encodedKey;
+
+ int preambleLength = matchesPreamble(DER_KEY_PREFIX, encodedKey);
+ if (preambleLength == 0) {
+ throw new IllegalArgumentException("Key size is not correct size");
+ }
+
+ mPoint = pointFromKeyByteArray(
+ Arrays.copyOfRange(encodedKey, preambleLength, encodedKey.length));
+ }
+
+ @Override
+ AndroidKeyStorePrivateKey getPrivateKey() {
+ return new AndroidKeyStoreEdECPrivateKey(
+ getUserKeyDescriptor(),
+ getKeyIdDescriptor().nspace,
+ getAuthorizations(),
+ "EdDSA",
+ getSecurityLevel());
+ }
+
+ @Override
+ public NamedParameterSpec getParams() {
+ return NamedParameterSpec.ED25519;
+ }
+
+ @Override
+ public EdECPoint getPoint() {
+ return mPoint;
+ }
+
+ private static int matchesPreamble(byte[] preamble, byte[] encoded) {
+ if (encoded.length != (preamble.length + ED25519_KEY_SIZE_BYTES)) {
+ return 0;
+ }
+ if (Arrays.compare(preamble, Arrays.copyOf(encoded, preamble.length)) != 0) {
+ return 0;
+ }
+ return preamble.length;
+ }
+
+ private static EdECPoint pointFromKeyByteArray(byte[] coordinates) {
+ Objects.requireNonNull(coordinates);
+
+ // Oddity of the key is the most-significant bit of the last byte.
+ boolean isOdd = (0x80 & coordinates[coordinates.length - 1]) != 0;
+ // Zero out the oddity bit.
+ coordinates[coordinates.length - 1] &= (byte) 0x7f;
+ // Representation of Y is in little-endian, according to rfc8032 section-3.1.
+ reverse(coordinates);
+ // The integer representing Y starts from the first bit in the coordinates array.
+ BigInteger y = new BigInteger(1, coordinates);
+ return new EdECPoint(isOdd, y);
+ }
+
+ private static void reverse(byte[] coordinateArray) {
+ int start = 0;
+ int end = coordinateArray.length - 1;
+ while (start < end) {
+ byte tmp = coordinateArray[start];
+ coordinateArray[start] = coordinateArray[end];
+ coordinateArray[end] = tmp;
+ start++;
+ end--;
+ }
+ }
+
+ @Override
+ public byte[] getEncoded() {
+ return mEncodedKey.clone();
+ }
+}
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
index d31499e8b36d..0355628b8135 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
@@ -224,7 +224,6 @@ public class AndroidKeyStoreProvider extends Provider {
String jcaKeyAlgorithm = publicKey.getAlgorithm();
- KeyStoreSecurityLevel securityLevel = iSecurityLevel;
if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(jcaKeyAlgorithm)) {
return new AndroidKeyStoreECPublicKey(descriptor, metadata,
iSecurityLevel, (ECPublicKey) publicKey);
@@ -232,8 +231,9 @@ public class AndroidKeyStoreProvider extends Provider {
return new AndroidKeyStoreRSAPublicKey(descriptor, metadata,
iSecurityLevel, (RSAPublicKey) publicKey);
} else if (ED25519_OID.equalsIgnoreCase(jcaKeyAlgorithm)) {
- //TODO(b/214203951) missing classes in conscrypt
- throw new ProviderException("Curve " + ED25519_OID + " not supported yet");
+ final byte[] publicKeyEncoded = publicKey.getEncoded();
+ return new AndroidKeyStoreEdECPublicKey(descriptor, metadata, ED25519_OID,
+ iSecurityLevel, publicKeyEncoded);
} else if (X25519_ALIAS.equalsIgnoreCase(jcaKeyAlgorithm)) {
//TODO(b/214203951) missing classes in conscrypt
throw new ProviderException("Curve " + X25519_ALIAS + " not supported yet");
diff --git a/keystore/tests/src/android/security/keystore2/AndroidKeyStoreEdECPublicKeyTest.java b/keystore/tests/src/android/security/keystore2/AndroidKeyStoreEdECPublicKeyTest.java
new file mode 100644
index 000000000000..5bd5797859c9
--- /dev/null
+++ b/keystore/tests/src/android/security/keystore2/AndroidKeyStoreEdECPublicKeyTest.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keystore2;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+
+import android.security.KeyStoreSecurityLevel;
+import android.system.keystore2.Authorization;
+import android.system.keystore2.Domain;
+import android.system.keystore2.KeyDescriptor;
+import android.system.keystore2.KeyMetadata;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+import java.math.BigInteger;
+import java.util.Base64;
+
+@RunWith(AndroidJUnit4.class)
+public class AndroidKeyStoreEdECPublicKeyTest {
+ private static KeyDescriptor descriptor() {
+ final KeyDescriptor keyDescriptor = new KeyDescriptor();
+ keyDescriptor.alias = "key";
+ keyDescriptor.blob = null;
+ keyDescriptor.domain = Domain.APP;
+ keyDescriptor.nspace = -1;
+ return keyDescriptor;
+ }
+
+ private static KeyMetadata metadata(byte[] cert, byte[] certChain) {
+ KeyMetadata metadata = new KeyMetadata();
+ metadata.authorizations = new Authorization[0];
+ metadata.certificate = cert;
+ metadata.certificateChain = certChain;
+ metadata.key = descriptor();
+ metadata.modificationTimeMs = 0;
+ metadata.keySecurityLevel = 1;
+ return metadata;
+ }
+
+ @Mock
+ private KeyStoreSecurityLevel mKeystoreSecurityLevel;
+
+ private static class EdECTestVector {
+ public final byte[] encodedKeyBytes;
+ public final boolean isOdd;
+ public final BigInteger yValue;
+
+ EdECTestVector(String b64KeyBytes, boolean isOdd, String yValue) {
+ this.encodedKeyBytes = Base64.getDecoder().decode(b64KeyBytes);
+ this.isOdd = isOdd;
+ this.yValue = new BigInteger(yValue);
+ }
+ }
+
+ private static final EdECTestVector[] ED_EC_TEST_VECTORS = new EdECTestVector[]{
+ new EdECTestVector("MCowBQYDK2VwAyEADE+wvQqNHxaERPhAZ0rCFlgFbfWLs/YonPXdSTw0VSo=",
+ false,
+ "19147682157189290216699341180089409126316261024914226007941553249095116672780"
+ ),
+ new EdECTestVector("MCowBQYDK2VwAyEA/0E1IRNzGj85Ot/TPeXqifkqTkdk4voleH0hIq59D9w=",
+ true,
+ "41640152188550647350742178040529506688513911269563908889464821205156322689535"
+ ),
+ new EdECTestVector("MCowBQYDK2VwAyEAunOvGuenetl9GQSXGVo5L3RIr4OOIpFIv/Zre8qTc/8=",
+ true,
+ "57647939198144376128225770417635248407428273266444593100194116168980378907578"
+ ),
+ new EdECTestVector("MCowBQYDK2VwAyEA2hHqaZ5IolswN1Yd58Y4hzhmUMCCqc4PW5A/SFLmTX8=",
+ false,
+ "57581368614046789120409806291852629847774713088410311752049592044694364885466"
+ ),
+ };
+
+ @Test
+ public void testParsingOfValidKeys() {
+ for (EdECTestVector testVector : ED_EC_TEST_VECTORS) {
+ AndroidKeyStoreEdECPublicKey pkey = new AndroidKeyStoreEdECPublicKey(descriptor(),
+ metadata(null, null), "EdDSA", mKeystoreSecurityLevel,
+ testVector.encodedKeyBytes);
+
+ assertEquals(pkey.getPoint().isXOdd(), testVector.isOdd);
+ assertEquals(pkey.getPoint().getY(), testVector.yValue);
+ }
+ }
+
+ @Test
+ public void testFailedParsingOfKeysWithDifferentOid() {
+ final byte[] testVectorWithIncorrectOid = Base64.getDecoder().decode(
+ "MCowBQYDLGVwAyEADE+wvQqNHxaERPhAZ0rCFlgFbfWLs/YonPXdSTw0VSo=");
+ assertThrows("OID should be unrecognized", IllegalArgumentException.class,
+ () -> new AndroidKeyStoreEdECPublicKey(descriptor(), metadata(null, null), "EdDSA",
+ mKeystoreSecurityLevel, testVectorWithIncorrectOid));
+ }
+
+ @Test
+ public void testFailedParsingOfKeysWithWrongSize() {
+ final byte[] testVectorWithIncorrectKeySize = Base64.getDecoder().decode(
+ "MCwwBQYDK2VwAyMADE+wvQqNHxaERPhAZ0rCFlgFbfWLs/YonPXdSTw0VSrOzg==");
+ assertThrows("Key length should be invalid", IllegalArgumentException.class,
+ () -> new AndroidKeyStoreEdECPublicKey(descriptor(), metadata(null, null), "EdDSA",
+ mKeystoreSecurityLevel, testVectorWithIncorrectKeySize));
+ }
+}
+
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
index 64017e176fc3..d04c34916256 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java
@@ -40,6 +40,8 @@ public enum ShellProtoLogGroup implements IProtoLogGroup {
Consts.TAG_WM_SHELL),
WM_SHELL_PICTURE_IN_PICTURE(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG,
false, Consts.TAG_WM_SHELL),
+ WM_SHELL_SPLIT_SCREEN(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+ Consts.TAG_WM_SHELL),
TEST_GROUP(true, true, false, "WindowManagerShellProtoLogTest");
private final boolean mEnabled;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 91f9d2522397..d543aa742377 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -54,6 +54,9 @@ import static com.android.wm.shell.transition.Transitions.TRANSIT_SPLIT_SCREEN_P
import static com.android.wm.shell.transition.Transitions.isClosingType;
import static com.android.wm.shell.transition.Transitions.isOpeningType;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
import android.annotation.CallSuper;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -68,6 +71,7 @@ import android.content.res.Configuration;
import android.graphics.Rect;
import android.hardware.devicestate.DeviceStateManager;
import android.os.Bundle;
+import android.os.Debug;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
@@ -147,7 +151,9 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
private final int mDisplayId;
private SplitLayout mSplitLayout;
+ private ValueAnimator mDividerFadeInAnimator;
private boolean mDividerVisible;
+ private boolean mKeyguardShowing;
private final SyncTransactionQueue mSyncQueue;
private final ShellTaskOrganizer mTaskOrganizer;
private final Context mContext;
@@ -404,6 +410,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mSplitLayout.init();
// Set false to avoid record new bounds with old task still on top;
mShouldUpdateRecents = false;
+ mIsDividerRemoteAnimating = true;
final WindowContainerTransaction wct = new WindowContainerTransaction();
final WindowContainerTransaction evictWct = new WindowContainerTransaction();
prepareEvictChildTasks(SPLIT_POSITION_TOP_OR_LEFT, evictWct);
@@ -417,7 +424,6 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
RemoteAnimationTarget[] wallpapers,
RemoteAnimationTarget[] nonApps,
final IRemoteAnimationFinishedCallback finishedCallback) {
- mIsDividerRemoteAnimating = true;
RemoteAnimationTarget[] augmentedNonApps =
new RemoteAnimationTarget[nonApps.length + 1];
for (int i = 0; i < nonApps.length; ++i) {
@@ -494,8 +500,10 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
// Using legacy transitions, so we can't use blast sync since it conflicts.
mTaskOrganizer.applyTransaction(wct);
- mSyncQueue.runInSync(t ->
- updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */));
+ mSyncQueue.runInSync(t -> {
+ setDividerVisibility(true, t);
+ updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
+ });
}
private void onRemoteAnimationFinishedOrCancelled(WindowContainerTransaction evictWct) {
@@ -510,10 +518,6 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
? mSideStage : mMainStage, EXIT_REASON_UNKNOWN));
} else {
mSyncQueue.queue(evictWct);
- mSyncQueue.runInSync(t -> {
- setDividerVisibility(true, t);
- updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
- });
}
}
@@ -623,16 +627,12 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
void onKeyguardVisibilityChanged(boolean showing) {
+ mKeyguardShowing = showing;
if (!mMainStage.isActive()) {
return;
}
- if (ENABLE_SHELL_TRANSITIONS) {
- // Update divider visibility so it won't float on top of keyguard.
- setDividerVisibility(!showing, null /* transaction */);
- }
-
- if (!showing && mTopStageAfterFoldDismiss != STAGE_TYPE_UNDEFINED) {
+ if (!mKeyguardShowing && mTopStageAfterFoldDismiss != STAGE_TYPE_UNDEFINED) {
if (ENABLE_SHELL_TRANSITIONS) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
prepareExitSplitScreen(mTopStageAfterFoldDismiss, wct);
@@ -643,7 +643,10 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mTopStageAfterFoldDismiss == STAGE_TYPE_MAIN ? mMainStage : mSideStage,
EXIT_REASON_DEVICE_FOLDED);
}
+ return;
}
+
+ setDividerVisibility(!mKeyguardShowing, null);
}
void onFinishedWakingUp() {
@@ -727,6 +730,7 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
setResizingSplits(false /* resizing */);
t.setWindowCrop(mMainStage.mRootLeash, null)
.setWindowCrop(mSideStage.mRootLeash, null);
+ setDividerVisibility(false, t);
});
// Hide divider and reset its position.
@@ -1055,8 +1059,31 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
}
private void setDividerVisibility(boolean visible, @Nullable SurfaceControl.Transaction t) {
+ if (visible == mDividerVisible) {
+ return;
+ }
+
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
+ "%s: Request to %s divider bar from %s.", TAG,
+ (visible ? "show" : "hide"), Debug.getCaller());
+
+ // Defer showing divider bar after keyguard dismissed, so it won't interfere with keyguard
+ // dismissing animation.
+ if (visible && mKeyguardShowing) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
+ "%s: Defer showing divider bar due to keyguard showing.", TAG);
+ return;
+ }
+
mDividerVisible = visible;
sendSplitVisibilityChanged();
+
+ if (mIsDividerRemoteAnimating) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
+ "%s: Skip animating divider bar due to it's remote animating.", TAG);
+ return;
+ }
+
if (t != null) {
applyDividerVisibility(t);
} else {
@@ -1066,15 +1093,56 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
private void applyDividerVisibility(SurfaceControl.Transaction t) {
final SurfaceControl dividerLeash = mSplitLayout.getDividerLeash();
- if (mIsDividerRemoteAnimating || dividerLeash == null) return;
+ if (dividerLeash == null) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
+ "%s: Skip animating divider bar due to divider leash not ready.", TAG);
+ return;
+ }
+ if (mIsDividerRemoteAnimating) {
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
+ "%s: Skip animating divider bar due to it's remote animating.", TAG);
+ return;
+ }
+
+ if (mDividerFadeInAnimator != null && mDividerFadeInAnimator.isRunning()) {
+ mDividerFadeInAnimator.cancel();
+ }
if (mDividerVisible) {
- t.show(dividerLeash);
- t.setAlpha(dividerLeash, 1);
- t.setLayer(dividerLeash, Integer.MAX_VALUE);
- t.setPosition(dividerLeash,
- mSplitLayout.getRefDividerBounds().left,
- mSplitLayout.getRefDividerBounds().top);
+ final SurfaceControl.Transaction transaction = mTransactionPool.acquire();
+ mDividerFadeInAnimator = ValueAnimator.ofFloat(0f, 1f);
+ mDividerFadeInAnimator.addUpdateListener(animation -> {
+ if (dividerLeash == null) {
+ mDividerFadeInAnimator.cancel();
+ return;
+ }
+ transaction.setAlpha(dividerLeash, (float) animation.getAnimatedValue());
+ transaction.apply();
+ });
+ mDividerFadeInAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ if (dividerLeash == null) {
+ mDividerFadeInAnimator.cancel();
+ return;
+ }
+ transaction.show(dividerLeash);
+ transaction.setAlpha(dividerLeash, 0);
+ transaction.setLayer(dividerLeash, Integer.MAX_VALUE);
+ transaction.setPosition(dividerLeash,
+ mSplitLayout.getRefDividerBounds().left,
+ mSplitLayout.getRefDividerBounds().top);
+ transaction.apply();
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mTransactionPool.release(transaction);
+ mDividerFadeInAnimator = null;
+ }
+ });
+
+ mDividerFadeInAnimator.start();
} else {
t.hide(dividerLeash);
}
@@ -1096,10 +1164,8 @@ class StageCoordinator implements SplitLayout.SplitLayoutHandler,
mSplitLayout.init();
prepareEnterSplitScreen(wct);
mSyncQueue.queue(wct);
- mSyncQueue.runInSync(t -> {
- updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
- setDividerVisibility(true, t);
- });
+ mSyncQueue.runInSync(t ->
+ updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */));
}
if (mMainStageListener.mHasChildren && mSideStageListener.mHasChildren) {
mShouldUpdateRecents = true;
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt
index cf4ea467a29b..41cd31aabf05 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/AppPairsHelper.kt
@@ -37,7 +37,7 @@ class AppPairsHelper(
val displayBounds = WindowUtils.displayBounds
val secondaryAppBounds = Region.from(0,
dividerBounds.bounds.bottom - WindowUtils.dockedStackDividerInset,
- displayBounds.right, displayBounds.bottom - WindowUtils.navigationBarHeight)
+ displayBounds.right, displayBounds.bottom - WindowUtils.navigationBarFrameHeight)
return secondaryAppBounds
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt
index a510d699387e..e2da1a4565c0 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt
@@ -171,7 +171,7 @@ class ResizeLegacySplitScreen(
val bottomAppBounds = Region.from(0,
dividerBounds.bottom - WindowUtils.dockedStackDividerInset,
displayBounds.right,
- displayBounds.bottom - WindowUtils.navigationBarHeight)
+ displayBounds.bottom - WindowUtils.navigationBarFrameHeight)
visibleRegion(Components.SimpleActivity.COMPONENT.toFlickerComponent())
.coversExactly(topAppBounds)
visibleRegion(Components.ImeActivity.COMPONENT.toFlickerComponent())
@@ -192,7 +192,7 @@ class ResizeLegacySplitScreen(
val bottomAppBounds = Region.from(0,
dividerBounds.bottom - WindowUtils.dockedStackDividerInset,
displayBounds.right,
- displayBounds.bottom - WindowUtils.navigationBarHeight)
+ displayBounds.bottom - WindowUtils.navigationBarFrameHeight)
visibleRegion(Components.SimpleActivity.COMPONENT.toFlickerComponent())
.coversExactly(topAppBounds)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
index a55f737f2f25..ffaab652aa99 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
@@ -139,6 +139,7 @@ public class SplitTransitionTests extends ShellTestCase {
}
@Test
+ @UiThreadTest
public void testLaunchToSide() {
ActivityManager.RunningTaskInfo newTask = new TestRunningTaskInfoBuilder()
.setParentTaskId(mSideStage.mRootTaskInfo.taskId).build();
@@ -173,6 +174,7 @@ public class SplitTransitionTests extends ShellTestCase {
}
@Test
+ @UiThreadTest
public void testLaunchPair() {
TransitionInfo info = createEnterPairInfo();
@@ -195,6 +197,7 @@ public class SplitTransitionTests extends ShellTestCase {
}
@Test
+ @UiThreadTest
public void testMonitorInSplit() {
enterSplit();
@@ -251,6 +254,7 @@ public class SplitTransitionTests extends ShellTestCase {
}
@Test
+ @UiThreadTest
public void testEnterRecents() {
enterSplit();
@@ -288,6 +292,7 @@ public class SplitTransitionTests extends ShellTestCase {
}
@Test
+ @UiThreadTest
public void testDismissFromBeingOccluded() {
enterSplit();
@@ -325,6 +330,7 @@ public class SplitTransitionTests extends ShellTestCase {
}
@Test
+ @UiThreadTest
public void testDismissFromMultiWindowSupport() {
enterSplit();
@@ -346,6 +352,7 @@ public class SplitTransitionTests extends ShellTestCase {
}
@Test
+ @UiThreadTest
public void testDismissSnap() {
enterSplit();
@@ -370,6 +377,7 @@ public class SplitTransitionTests extends ShellTestCase {
}
@Test
+ @UiThreadTest
public void testDismissFromAppFinish() {
enterSplit();
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index ef0270b5414c..e5673a613b59 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -1728,7 +1728,9 @@ public class Tuner implements AutoCloseable {
}
int res = nativeSetMaxNumberOfFrontends(frontendType, maxNumber);
if (res == RESULT_SUCCESS) {
- // TODO: b/211778848 Update Tuner Resource Manager.
+ if (!mTunerResourceManager.setMaxNumberOfFrontends(frontendType, maxNumber)) {
+ res = RESULT_INVALID_ARGUMENT;
+ }
}
return res;
}
@@ -1749,7 +1751,13 @@ public class Tuner implements AutoCloseable {
TunerVersionChecker.TUNER_VERSION_2_0, "Set maximum Frontends")) {
return -1;
}
- return nativeGetMaxNumberOfFrontends(frontendType);
+ int maxNumFromHAL = nativeGetMaxNumberOfFrontends(frontendType);
+ int maxNumFromTRM = mTunerResourceManager.getMaxNumberOfFrontends(frontendType);
+ if (maxNumFromHAL != maxNumFromTRM) {
+ Log.w(TAG, "max num of usable frontend is out-of-sync b/w " + maxNumFromHAL
+ + " != " + maxNumFromTRM);
+ }
+ return maxNumFromHAL;
}
/** @hide */
diff --git a/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java b/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java
index 5ada89e9dea7..15175a783924 100644
--- a/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java
+++ b/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java
@@ -401,6 +401,43 @@ public class TunerResourceManager {
}
/**
+ * Sets the maximum usable frontends number of a given frontend type. It is used to enable or
+ * disable frontends when cable connection status is changed by user.
+ *
+ * @param frontendType the frontendType which the maximum usable number will be set for.
+ * @param maxNum the new maximum usable number.
+ *
+ * @return true if successful and false otherwise.
+ */
+ public boolean setMaxNumberOfFrontends(int frontendType, int maxNum) {
+ boolean result = false;
+ try {
+ result = mService.setMaxNumberOfFrontends(frontendType, maxNum);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ return result;
+ }
+
+ /**
+ * Get the maximum usable frontends number of a given frontend type.
+ *
+ * @param frontendType the frontendType which the maximum usable number will be queried for.
+ *
+ * @return the maximum usable number of the queried frontend type. Returns -1 when the
+ * frontendType is invalid
+ */
+ public int getMaxNumberOfFrontends(int frontendType) {
+ int result = -1;
+ try {
+ result = mService.getMaxNumberOfFrontends(frontendType);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ return result;
+ }
+
+ /**
* Requests from the client to share frontend with an existing client.
*
* <p><strong>Note:</strong> {@link #setFrontendInfoList(TunerFrontendInfo[])} must be called
diff --git a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl b/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl
index d16fc6ca1dc7..144b98c36655 100644
--- a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl
+++ b/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl
@@ -166,6 +166,27 @@ interface ITunerResourceManager {
boolean requestFrontend(in TunerFrontendRequest request, out int[] frontendHandle);
/*
+ * Sets the maximum usable frontends number of a given frontend type. It is used to enable or
+ * disable frontends when cable connection status is changed by user.
+ *
+ * @param frontendType the frontendType which the maximum usable number will be set for.
+ * @param maxNumber the new maximum usable number.
+ *
+ * @return true if successful and false otherwise.
+ */
+ boolean setMaxNumberOfFrontends(in int frontendType, in int maxNum);
+
+ /*
+ * Get the maximum usable frontends number of a given frontend type.
+ *
+ * @param frontendType the frontendType which the maximum usable number will be queried for.
+ *
+ * @return the maximum usable number of the queried frontend type. Returns -1 when the
+ * frontendType is invalid
+ */
+ int getMaxNumberOfFrontends(in int frontendType);
+
+ /*
* Requests to share frontend with an existing client.
*
* <p><strong>Note:</strong> {@link #setFrontendInfoList(TunerFrontendInfo[])} must be called
diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
index 05a143e7e38a..9e9ec04fbd93 100644
--- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
+++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/CompanionDeviceActivity.java
@@ -487,6 +487,14 @@ public class CompanionDeviceActivity extends FragmentActivity implements
if (deviceFilterPairs.isEmpty()) return;
mSelectedDevice = requireNonNull(deviceFilterPairs.get(0));
+ // No need to show user consent dialog if it is a singleDevice
+ // and isSkipPrompt(true) AssociationRequest.
+ // See AssociationRequestsProcessor#mayAssociateWithoutPrompt.
+ if (mRequest.isSkipPrompt()) {
+ mSingleDeviceSpinner.setVisibility(View.GONE);
+ onUserSelectedDevice(mSelectedDevice);
+ return;
+ }
final String deviceName = mSelectedDevice.getDisplayName();
final Spanned title = getHtmlFromResources(
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v31/collapsing_toolbar_content_layout.xml b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v31/collapsing_toolbar_content_layout.xml
index 25f0771b2170..72b569f22d6c 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v31/collapsing_toolbar_content_layout.xml
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/res/layout-v31/collapsing_toolbar_content_layout.xml
@@ -25,7 +25,7 @@
android:fitsSystemWindows="true"
android:outlineAmbientShadowColor="@android:color/transparent"
android:outlineSpotShadowColor="@android:color/transparent"
- android:background="?android:attr/colorPrimary"
+ android:background="@android:color/transparent"
android:theme="@style/Theme.CollapsingToolbar.Settings">
<com.google.android.material.appbar.CollapsingToolbarLayout
diff --git a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/widget/CollapsingCoordinatorLayout.java b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/widget/CollapsingCoordinatorLayout.java
index 72383fe59e7e..dbb4b5017e6b 100644
--- a/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/widget/CollapsingCoordinatorLayout.java
+++ b/packages/SettingsLib/CollapsingToolbarBaseActivity/src/com/android/settingslib/collapsingtoolbar/widget/CollapsingCoordinatorLayout.java
@@ -20,6 +20,7 @@ import android.app.ActionBar;
import android.app.Activity;
import android.content.Context;
import android.content.res.TypedArray;
+import android.os.Build;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
@@ -29,6 +30,7 @@ import android.widget.Toolbar;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
@@ -41,6 +43,7 @@ import com.google.android.material.appbar.CollapsingToolbarLayout;
* This widget is wrapping the collapsing toolbar and can be directly used by the
* {@link AppCompatActivity}.
*/
+@RequiresApi(Build.VERSION_CODES.S)
public class CollapsingCoordinatorLayout extends CoordinatorLayout {
private static final String TAG = "CollapsingCoordinatorLayout";
private static final float TOOLBAR_LINE_SPACING_MULTIPLIER = 1.1f;
diff --git a/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java b/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java
index ac306361386e..6766cdd0beb6 100644
--- a/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java
+++ b/packages/SettingsLib/FooterPreference/src/com/android/settingslib/widget/FooterPreference.java
@@ -40,6 +40,8 @@ public class FooterPreference extends Preference {
static final int ORDER_FOOTER = Integer.MAX_VALUE - 1;
@VisibleForTesting
View.OnClickListener mLearnMoreListener;
+ @VisibleForTesting
+ int mIconVisibility = View.VISIBLE;
private CharSequence mContentDescription;
private CharSequence mLearnMoreText;
private CharSequence mLearnMoreContentDescription;
@@ -84,6 +86,9 @@ public class FooterPreference extends Preference {
} else {
learnMore.setVisibility(View.GONE);
}
+
+ View icon = holder.itemView.findViewById(R.id.icon_frame);
+ icon.setVisibility(mIconVisibility);
}
@Override
@@ -165,6 +170,17 @@ public class FooterPreference extends Preference {
}
}
+ /**
+ * Set visibility of footer icon.
+ */
+ public void setIconVisibility(int iconVisibility) {
+ if (mIconVisibility == iconVisibility) {
+ return;
+ }
+ mIconVisibility = iconVisibility;
+ notifyChanged();
+ }
+
private void init() {
setLayoutResource(R.layout.preference_footer);
if (getIcon() == null) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
index fdb06072bbd1..6b9daa35f9ca 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
@@ -863,6 +863,30 @@ public class ApplicationsState {
}
}
+ /**
+ * Activate session to enable a class that implements Callbacks to receive the callback.
+ */
+ public void activateSession() {
+ synchronized (mEntriesMap) {
+ if (!mResumed) {
+ mResumed = true;
+ mSessionsChanged = true;
+ }
+ }
+ }
+
+ /**
+ * Deactivate session to disable a class that implements Callbacks to get the callback.
+ */
+ public void deactivateSession() {
+ synchronized (mEntriesMap) {
+ if (mResumed) {
+ mResumed = false;
+ mSessionsChanged = true;
+ }
+ }
+ }
+
public ArrayList<AppEntry> getAllApps() {
synchronized (mEntriesMap) {
return new ArrayList<>(mAppEntries);
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 4ee21229e364..6919cf237853 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -1376,7 +1376,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
/**
* Store the member devices that are in the same coordinated set.
*/
- public void setMemberDevice(CachedBluetoothDevice memberDevice) {
+ public void addMemberDevice(CachedBluetoothDevice memberDevice) {
mMemberDevices.add(memberDevice);
}
@@ -1393,24 +1393,24 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice>
* device and member devices.
*
* @param prevMainDevice the previous Main device, it will be added into the member device set.
- * @param newMainDevie the new Main device, it will be removed from the member device set.
+ * @param newMainDevice the new Main device, it will be removed from the member device set.
*/
public void switchMemberDeviceContent(CachedBluetoothDevice prevMainDevice,
- CachedBluetoothDevice newMainDevie) {
+ CachedBluetoothDevice newMainDevice) {
// Backup from main device
final BluetoothDevice tmpDevice = mDevice;
final short tmpRssi = mRssi;
final boolean tmpJustDiscovered = mJustDiscovered;
// Set main device from sub device
- mDevice = newMainDevie.mDevice;
- mRssi = newMainDevie.mRssi;
- mJustDiscovered = newMainDevie.mJustDiscovered;
- setMemberDevice(prevMainDevice);
- mMemberDevices.remove(newMainDevie);
+ mDevice = newMainDevice.mDevice;
+ mRssi = newMainDevice.mRssi;
+ mJustDiscovered = newMainDevice.mJustDiscovered;
+ addMemberDevice(prevMainDevice);
+ mMemberDevices.remove(newMainDevice);
// Set sub device from backup
- newMainDevie.mDevice = tmpDevice;
- newMainDevie.mRssi = tmpRssi;
- newMainDevie.mJustDiscovered = tmpJustDiscovered;
+ newMainDevice.mDevice = tmpDevice;
+ newMainDevice.mRssi = tmpRssi;
+ newMainDevice.mJustDiscovered = tmpJustDiscovered;
fetchActiveDevices();
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
index cc56a212aea1..89e10c4b5e11 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CsipDeviceManager.java
@@ -85,7 +85,7 @@ public class CsipDeviceManager {
// Once there is other devices with the same groupId, to add new device as member
// devices.
if (CsipDevice != null) {
- CsipDevice.setMemberDevice(newDevice);
+ CsipDevice.addMemberDevice(newDevice);
newDevice.setName(CsipDevice.getName());
return true;
}
@@ -148,7 +148,7 @@ public class CsipDeviceManager {
log("onGroupIdChanged: removed from UI device =" + cachedDevice
+ ", with groupId=" + groupId + " firstMatchedIndex=" + firstMatchedIndex);
- mainDevice.setMemberDevice(cachedDevice);
+ mainDevice.addMemberDevice(cachedDevice);
mCachedDevices.remove(i);
mBtManager.getEventManager().dispatchDeviceRemoved(cachedDevice);
break;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
index 298ee90d311d..bef1d9cbcde1 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManagerTest.java
@@ -40,7 +40,6 @@ import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import java.util.Collection;
-import java.util.HashMap;
import java.util.Map;
@RunWith(RobolectricTestRunner.class)
@@ -503,8 +502,8 @@ public class CachedBluetoothDeviceManagerTest {
CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
CachedBluetoothDevice cachedDevice3 = mCachedDeviceManager.addDevice(mDevice3);
- cachedDevice1.setMemberDevice(cachedDevice2);
- cachedDevice1.setMemberDevice(cachedDevice3);
+ cachedDevice1.addMemberDevice(cachedDevice2);
+ cachedDevice1.addMemberDevice(cachedDevice3);
assertThat(cachedDevice1.getMemberDevice()).contains(cachedDevice2);
assertThat(cachedDevice1.getMemberDevice()).contains(cachedDevice3);
@@ -524,7 +523,7 @@ public class CachedBluetoothDeviceManagerTest {
CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
cachedDevice1.setGroupId(1);
cachedDevice2.setGroupId(1);
- cachedDevice1.setMemberDevice(cachedDevice2);
+ cachedDevice1.addMemberDevice(cachedDevice2);
// Call onDeviceUnpaired for the one in mCachedDevices.
mCachedDeviceManager.onDeviceUnpaired(cachedDevice1);
@@ -541,7 +540,7 @@ public class CachedBluetoothDeviceManagerTest {
CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
cachedDevice1.setGroupId(1);
cachedDevice2.setGroupId(1);
- cachedDevice1.setMemberDevice(cachedDevice2);
+ cachedDevice1.addMemberDevice(cachedDevice2);
// Call onDeviceUnpaired for the one in mCachedDevices.
mCachedDeviceManager.onDeviceUnpaired(cachedDevice2);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java
index 61a28aab061f..9abb27e68398 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java
@@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat;
import android.content.Context;
import android.view.LayoutInflater;
+import android.view.View;
import android.widget.TextView;
import androidx.preference.PreferenceViewHolder;
@@ -61,7 +62,7 @@ public class FooterPreferenceTest {
mFooterPreference.onBindViewHolder(holder);
assertThat(((TextView) holder.findViewById(
- R.id.settingslib_learn_more)).getText().toString())
+ R.id.settingslib_learn_more)).getText().toString())
.isEqualTo("Custom learn more");
}
@@ -86,4 +87,11 @@ public class FooterPreferenceTest {
assertThat(mFooterPreference.mLearnMoreListener).isNotNull();
}
+
+ @Test
+ public void setIconVisibility_shouldReturnSameVisibilityType() {
+ mFooterPreference.setIconVisibility(View.GONE);
+
+ assertThat(mFooterPreference.mIconVisibility).isEqualTo(View.GONE);
+ }
}
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 3029781f3e99..5eaf553a2047 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -120,6 +120,9 @@ public class SecureSettings {
Settings.Secure.ACTIVE_UNLOCK_ON_WAKE,
Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT,
Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL,
+ Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ERRORS,
+ Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO,
+ Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED,
Settings.Secure.VR_DISPLAY_MODE,
Settings.Secure.NOTIFICATION_BADGING,
Settings.Secure.NOTIFICATION_DISMISS_RTL,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index a4da49713f87..9ee7b654046f 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -18,6 +18,7 @@ package android.provider.settings.validators;
import static android.provider.settings.validators.SettingsValidators.ACCESSIBILITY_SHORTCUT_TARGET_LIST_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.ANY_INTEGER_VALIDATOR;
+import static android.provider.settings.validators.SettingsValidators.ANY_STRING_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.BOOLEAN_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.COLON_SEPARATED_COMPONENT_LIST_VALIDATOR;
import static android.provider.settings.validators.SettingsValidators.COLON_SEPARATED_PACKAGE_LIST_VALIDATOR;
@@ -176,6 +177,10 @@ public class SecureSettingsValidators {
VALIDATORS.put(Secure.ACTIVE_UNLOCK_ON_WAKE, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL, BOOLEAN_VALIDATOR);
+ VALIDATORS.put(Secure.ACTIVE_UNLOCK_ON_FACE_ERRORS, ANY_STRING_VALIDATOR);
+ VALIDATORS.put(Secure.ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO, ANY_STRING_VALIDATOR);
+ VALIDATORS.put(Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED,
+ ANY_STRING_VALIDATOR);
VALIDATORS.put(Secure.ASSIST_GESTURE_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.ASSIST_GESTURE_SILENCE_ALERTS_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(Secure.ASSIST_GESTURE_WAKE_ENABLED, BOOLEAN_VALIDATOR);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index aadfcea150f7..a6edb0f0e2e3 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -5509,16 +5509,7 @@ public class SettingsProvider extends ContentProvider {
currentVersion = 209;
}
if (currentVersion == 209) {
- // Version 209: Enable enforcement of
- // android.Manifest.permission#POST_NOTIFICATIONS in order for applications
- // to post notifications.
- final SettingsState secureSettings = getSecureSettingsLocked(userId);
- secureSettings.insertSettingLocked(
- Secure.NOTIFICATION_PERMISSION_ENABLED,
- /* enabled= */ "1",
- /* tag= */ null,
- /* makeDefault= */ false,
- SettingsState.SYSTEM_PACKAGE_NAME);
+ // removed now that feature is enabled for everyone
currentVersion = 210;
}
diff --git a/packages/SystemUI/res/drawable/media_output_icon_volume.xml b/packages/SystemUI/res/drawable/media_output_icon_volume.xml
new file mode 100644
index 000000000000..fce4e0022c7a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/media_output_icon_volume.xml
@@ -0,0 +1,10 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@color/media_dialog_item_main_content"
+ android:pathData="M14,20.725V18.675Q16.25,18.025 17.625,16.175Q19,14.325 19,11.975Q19,9.625 17.625,7.775Q16.25,5.925 14,5.275V3.225Q17.1,3.925 19.05,6.362Q21,8.8 21,11.975Q21,15.15 19.05,17.587Q17.1,20.025 14,20.725ZM3,15V9H7L12,4V20L7,15ZM14,16V7.95Q15.125,8.475 15.812,9.575Q16.5,10.675 16.5,12Q16.5,13.325 15.812,14.4Q15.125,15.475 14,16ZM10,8.85 L7.85,11H5V13H7.85L10,15.15ZM7.5,12Z"/>
+</vector>
diff --git a/packages/SystemUI/res/layout/clipboard_overlay.xml b/packages/SystemUI/res/layout/clipboard_overlay.xml
index 10bb6cbb95aa..085a5810608f 100644
--- a/packages/SystemUI/res/layout/clipboard_overlay.xml
+++ b/packages/SystemUI/res/layout/clipboard_overlay.xml
@@ -67,7 +67,7 @@
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="@dimen/overlay_offset_x"
- android:layout_marginBottom="@dimen/overlay_offset_y"
+ android:layout_marginBottom="8dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="@id/actions_container_background"
android:elevation="7dp"
diff --git a/packages/SystemUI/res/layout/screenshot.xml b/packages/SystemUI/res/layout/screenshot.xml
index 890dbe592fc7..c29e11bff624 100644
--- a/packages/SystemUI/res/layout/screenshot.xml
+++ b/packages/SystemUI/res/layout/screenshot.xml
@@ -29,18 +29,11 @@
android:clickable="true"
android:importantForAccessibility="no"/>
<ImageView
- android:id="@+id/screenshot_actions_background"
- android:layout_height="@dimen/overlay_bg_protection_height"
- android:layout_width="match_parent"
- android:layout_gravity="bottom"
- android:alpha="0.0"
- android:src="@drawable/overlay_actions_background_protection"/>
- <ImageView
android:id="@+id/screenshot_flash"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
- android:elevation="@dimen/overlay_preview_elevation"
+ android:elevation="7dp"
android:src="@android:color/white"/>
<com.android.systemui.screenshot.ScreenshotSelectorView
android:id="@+id/screenshot_selector"
diff --git a/packages/SystemUI/res/layout/screenshot_static.xml b/packages/SystemUI/res/layout/screenshot_static.xml
index c60609b06d38..9c027495aa1e 100644
--- a/packages/SystemUI/res/layout/screenshot_static.xml
+++ b/packages/SystemUI/res/layout/screenshot_static.xml
@@ -24,7 +24,7 @@
android:visibility="gone"
android:layout_height="0dp"
android:layout_width="0dp"
- android:elevation="1dp"
+ android:elevation="4dp"
android:background="@drawable/action_chip_container_background"
android:layout_marginStart="@dimen/overlay_action_container_margin_horizontal"
app:layout_constraintBottom_toBottomOf="@+id/actions_container"
@@ -36,9 +36,10 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/overlay_action_container_margin_horizontal"
+ android:layout_marginBottom="4dp"
android:paddingEnd="@dimen/overlay_action_container_padding_right"
android:paddingVertical="@dimen/overlay_action_container_padding_vertical"
- android:elevation="1dp"
+ android:elevation="4dp"
android:scrollbars="none"
app:layout_constraintHorizontal_bias="0"
app:layout_constraintWidth_percent="1.0"
@@ -64,8 +65,8 @@
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="@dimen/overlay_offset_x"
- android:layout_marginBottom="@dimen/overlay_offset_y"
- android:elevation="@dimen/overlay_preview_elevation"
+ android:layout_marginBottom="12dp"
+ android:elevation="7dp"
android:alpha="0"
android:background="@drawable/overlay_border"
app:layout_constraintStart_toStartOf="parent"
@@ -93,7 +94,7 @@
android:layout_margin="@dimen/overlay_border_width"
android:layout_height="wrap_content"
android:layout_gravity="center"
- android:elevation="@dimen/overlay_preview_elevation"
+ android:elevation="7dp"
android:contentDescription="@string/screenshot_edit_description"
android:scaleType="fitEnd"
android:background="@drawable/overlay_preview_background"
@@ -108,7 +109,7 @@
android:id="@+id/screenshot_dismiss_button"
android:layout_width="@dimen/overlay_dismiss_button_tappable_size"
android:layout_height="@dimen/overlay_dismiss_button_tappable_size"
- android:elevation="@dimen/overlay_dismiss_button_elevation"
+ android:elevation="10dp"
android:visibility="gone"
app:layout_constraintStart_toEndOf="@id/screenshot_preview"
app:layout_constraintEnd_toEndOf="@id/screenshot_preview"
@@ -130,5 +131,5 @@
android:visibility="gone"
app:layout_constraintStart_toStartOf="@id/screenshot_preview"
app:layout_constraintTop_toTopOf="@id/screenshot_preview"
- android:elevation="@dimen/overlay_preview_elevation"/>
+ android:elevation="7dp"/>
</com.android.systemui.screenshot.DraggableConstraintLayout>
diff --git a/packages/SystemUI/res/values-h800dp/dimens.xml b/packages/SystemUI/res/values-h800dp/dimens.xml
index 1d6f279afc66..e6af6f46ae69 100644
--- a/packages/SystemUI/res/values-h800dp/dimens.xml
+++ b/packages/SystemUI/res/values-h800dp/dimens.xml
@@ -16,7 +16,7 @@
<resources>
<!-- Minimum margin between clock and top of screen or ambient indication -->
- <dimen name="keyguard_clock_top_margin">38dp</dimen>
+ <dimen name="keyguard_clock_top_margin">26dp</dimen>
<!-- Large clock maximum font size (dp is intentional, to prevent any further scaling) -->
<dimen name="large_clock_text_size">200dp</dimen>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index a014efb7d176..0bc3594ef183 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -282,15 +282,12 @@
<!-- Spacing between chip icon and chip text -->
<dimen name="overlay_action_chip_spacing">8dp</dimen>
<dimen name="overlay_action_chip_text_size">14sp</dimen>
- <dimen name="overlay_offset_y">8dp</dimen>
<dimen name="overlay_offset_x">16dp</dimen>
- <dimen name="overlay_preview_elevation">4dp</dimen>
<dimen name="overlay_action_container_margin_horizontal">8dp</dimen>
<dimen name="overlay_bg_protection_height">242dp</dimen>
<dimen name="overlay_action_container_corner_radius">18dp</dimen>
<dimen name="overlay_action_container_padding_vertical">4dp</dimen>
<dimen name="overlay_action_container_padding_right">8dp</dimen>
- <dimen name="overlay_dismiss_button_elevation">7dp</dimen>
<dimen name="overlay_dismiss_button_tappable_size">48dp</dimen>
<dimen name="overlay_dismiss_button_margin">8dp</dimen>
<dimen name="overlay_border_width">4dp</dimen>
@@ -1134,7 +1131,7 @@
<!-- Output switcher panel related dimensions -->
<dimen name="media_output_dialog_list_margin">12dp</dimen>
- <dimen name="media_output_dialog_list_max_height">364dp</dimen>
+ <dimen name="media_output_dialog_list_max_height">355dp</dimen>
<dimen name="media_output_dialog_header_album_icon_size">72dp</dimen>
<dimen name="media_output_dialog_header_back_icon_size">32dp</dimen>
<dimen name="media_output_dialog_header_icon_padding">16dp</dimen>
diff --git a/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt b/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt
index f195d2094d6a..38fa35453418 100644
--- a/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ActiveUnlockConfig.kt
@@ -16,14 +16,20 @@
package com.android.keyguard
+import android.annotation.IntDef
import android.content.ContentResolver
import android.database.ContentObserver
+import android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_TIMEOUT
import android.net.Uri
import android.os.Handler
import android.os.UserHandle
import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL
+import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO
+import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ERRORS
import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT
+import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED
import android.provider.Settings.Secure.ACTIVE_UNLOCK_ON_WAKE
+import android.util.Log
import com.android.keyguard.KeyguardUpdateMonitor.getCurrentUser
import com.android.systemui.Dumpable
import com.android.systemui.dagger.SysUISingleton
@@ -44,6 +50,20 @@ class ActiveUnlockConfig @Inject constructor(
dumpManager: DumpManager
) : Dumpable {
+ companion object {
+ const val TAG = "ActiveUnlockConfig"
+
+ const val BIOMETRIC_TYPE_NONE = 0
+ const val BIOMETRIC_TYPE_ANY_FACE = 1
+ const val BIOMETRIC_TYPE_ANY_FINGERPRINT = 2
+ const val BIOMETRIC_TYPE_UNDER_DISPLAY_FINGERPRINT = 3
+ }
+
+ @Retention(AnnotationRetention.SOURCE)
+ @IntDef(BIOMETRIC_TYPE_NONE, BIOMETRIC_TYPE_ANY_FACE, BIOMETRIC_TYPE_ANY_FINGERPRINT,
+ BIOMETRIC_TYPE_UNDER_DISPLAY_FINGERPRINT)
+ annotation class BiometricType
+
/**
* Indicates the origin for an active unlock request.
*/
@@ -51,35 +71,50 @@ class ActiveUnlockConfig @Inject constructor(
WAKE, UNLOCK_INTENT, BIOMETRIC_FAIL, ASSISTANT
}
+ var keyguardUpdateMonitor: KeyguardUpdateMonitor? = null
private var requestActiveUnlockOnWakeup = false
private var requestActiveUnlockOnUnlockIntent = false
private var requestActiveUnlockOnBioFail = false
+ private var faceErrorsToTriggerBiometricFailOn = mutableSetOf(FACE_ERROR_TIMEOUT)
+ private var faceAcquireInfoToTriggerBiometricFailOn = mutableSetOf<Int>()
+ private var onUnlockIntentWhenBiometricEnrolled = mutableSetOf<Int>(BIOMETRIC_TYPE_NONE)
+
private val settingsObserver = object : ContentObserver(handler) {
- private val wakeUri: Uri = secureSettings.getUriFor(ACTIVE_UNLOCK_ON_WAKE)
- private val unlockIntentUri: Uri = secureSettings.getUriFor(ACTIVE_UNLOCK_ON_UNLOCK_INTENT)
- private val bioFailUri: Uri = secureSettings.getUriFor(ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL)
+ private val wakeUri = secureSettings.getUriFor(ACTIVE_UNLOCK_ON_WAKE)
+ private val unlockIntentUri = secureSettings.getUriFor(ACTIVE_UNLOCK_ON_UNLOCK_INTENT)
+ private val bioFailUri = secureSettings.getUriFor(ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL)
+ private val faceErrorsUri = secureSettings.getUriFor(ACTIVE_UNLOCK_ON_FACE_ERRORS)
+ private val faceAcquireInfoUri =
+ secureSettings.getUriFor(ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO)
+ private val unlockIntentWhenBiometricEnrolledUri =
+ secureSettings.getUriFor(ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED)
fun register() {
- contentResolver.registerContentObserver(
- wakeUri,
- false,
- this,
- UserHandle.USER_ALL)
- contentResolver.registerContentObserver(
- unlockIntentUri,
- false,
- this,
- UserHandle.USER_ALL)
- contentResolver.registerContentObserver(
- bioFailUri,
- false,
- this,
- UserHandle.USER_ALL)
+ registerUri(
+ listOf(
+ wakeUri,
+ unlockIntentUri,
+ bioFailUri,
+ faceErrorsUri,
+ faceAcquireInfoUri,
+ unlockIntentWhenBiometricEnrolledUri
+ )
+ )
onChange(true, ArrayList(), 0, getCurrentUser())
}
+ private fun registerUri(uris: Collection<Uri>) {
+ for (uri in uris) {
+ contentResolver.registerContentObserver(
+ uri,
+ false,
+ this,
+ UserHandle.USER_ALL)
+ }
+ }
+
override fun onChange(
selfChange: Boolean,
uris: Collection<Uri>,
@@ -104,6 +139,55 @@ class ActiveUnlockConfig @Inject constructor(
requestActiveUnlockOnBioFail = secureSettings.getIntForUser(
ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL, 0, getCurrentUser()) == 1
}
+
+ if (selfChange || uris.contains(faceErrorsUri)) {
+ processStringArray(
+ secureSettings.getStringForUser(ACTIVE_UNLOCK_ON_FACE_ERRORS,
+ getCurrentUser()),
+ faceErrorsToTriggerBiometricFailOn,
+ setOf(FACE_ERROR_TIMEOUT))
+ }
+
+ if (selfChange || uris.contains(faceAcquireInfoUri)) {
+ processStringArray(
+ secureSettings.getStringForUser(ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO,
+ getCurrentUser()),
+ faceAcquireInfoToTriggerBiometricFailOn,
+ setOf<Int>())
+ }
+
+ if (selfChange || uris.contains(unlockIntentWhenBiometricEnrolledUri)) {
+ processStringArray(
+ secureSettings.getStringForUser(
+ ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED,
+ getCurrentUser()),
+ onUnlockIntentWhenBiometricEnrolled,
+ setOf(BIOMETRIC_TYPE_NONE))
+ }
+ }
+
+ /**
+ * Convert a pipe-separated set of integers into a set of ints.
+ * @param stringSetting expected input are integers delineated by a pipe. For example,
+ * it may look something like this: "1|5|3".
+ * @param out updates the "out" Set will the integers between the pipes.
+ * @param default If stringSetting is null, "out" will be populated with values in "default"
+ */
+ private fun processStringArray(
+ stringSetting: String?,
+ out: MutableSet<Int>,
+ default: Set<Int>
+ ) {
+ out.clear()
+ stringSetting?.let {
+ for (code: String in stringSetting.split("|")) {
+ try {
+ out.add(code.toInt())
+ } catch (e: NumberFormatException) {
+ Log.e(TAG, "Passed an invalid setting=$code")
+ }
+ }
+ } ?: out.addAll(default)
}
}
@@ -113,6 +197,30 @@ class ActiveUnlockConfig @Inject constructor(
}
/**
+ * If any active unlock triggers are enabled.
+ */
+ fun isActiveUnlockEnabled(): Boolean {
+ return requestActiveUnlockOnWakeup || requestActiveUnlockOnUnlockIntent ||
+ requestActiveUnlockOnBioFail
+ }
+
+ /**
+ * Whether the face error code from {@link BiometricFaceConstants} should trigger
+ * active unlock on biometric failure.
+ */
+ fun shouldRequestActiveUnlockOnFaceError(errorCode: Int): Boolean {
+ return faceErrorsToTriggerBiometricFailOn.contains(errorCode)
+ }
+
+ /**
+ * Whether the face acquireInfo from {@link BiometricFaceConstants} should trigger
+ * active unlock on biometric failure.
+ */
+ fun shouldRequestActiveUnlockOnFaceAcquireInfo(acquiredInfo: Int): Boolean {
+ return faceAcquireInfoToTriggerBiometricFailOn.contains(acquiredInfo)
+ }
+
+ /**
* Whether to trigger active unlock based on where the request is coming from and
* the current settings.
*/
@@ -121,7 +229,8 @@ class ActiveUnlockConfig @Inject constructor(
ACTIVE_UNLOCK_REQUEST_ORIGIN.WAKE -> requestActiveUnlockOnWakeup
ACTIVE_UNLOCK_REQUEST_ORIGIN.UNLOCK_INTENT ->
- requestActiveUnlockOnUnlockIntent || requestActiveUnlockOnWakeup
+ requestActiveUnlockOnUnlockIntent || requestActiveUnlockOnWakeup ||
+ (shouldRequestActiveUnlockOnUnlockIntentFromBiometricEnrollment())
ACTIVE_UNLOCK_REQUEST_ORIGIN.BIOMETRIC_FAIL ->
requestActiveUnlockOnBioFail || requestActiveUnlockOnUnlockIntent ||
@@ -131,17 +240,55 @@ class ActiveUnlockConfig @Inject constructor(
}
}
- /**
- * If any active unlock triggers are enabled.
- */
- fun isActiveUnlockEnabled(): Boolean {
- return requestActiveUnlockOnWakeup || requestActiveUnlockOnUnlockIntent ||
- requestActiveUnlockOnBioFail
+ private fun shouldRequestActiveUnlockOnUnlockIntentFromBiometricEnrollment(): Boolean {
+ if (!requestActiveUnlockOnBioFail) {
+ return false
+ }
+
+ keyguardUpdateMonitor?.let {
+ val anyFaceEnrolled = it.isFaceEnrolled
+ val anyFingerprintEnrolled =
+ it.getCachedIsUnlockWithFingerprintPossible(getCurrentUser())
+ val udfpsEnrolled = it.isUdfpsEnrolled
+
+ if (!anyFaceEnrolled && !anyFingerprintEnrolled) {
+ return onUnlockIntentWhenBiometricEnrolled.contains(BIOMETRIC_TYPE_NONE)
+ }
+
+ if (!anyFaceEnrolled && anyFingerprintEnrolled) {
+ return onUnlockIntentWhenBiometricEnrolled.contains(
+ BIOMETRIC_TYPE_ANY_FINGERPRINT) ||
+ (udfpsEnrolled && onUnlockIntentWhenBiometricEnrolled.contains(
+ BIOMETRIC_TYPE_UNDER_DISPLAY_FINGERPRINT))
+ }
+
+ if (!anyFingerprintEnrolled && anyFaceEnrolled) {
+ return onUnlockIntentWhenBiometricEnrolled.contains(BIOMETRIC_TYPE_ANY_FACE)
+ }
+ }
+
+ return false
}
override fun dump(pw: PrintWriter, args: Array<out String>) {
+ pw.println("Settings:")
pw.println(" requestActiveUnlockOnWakeup=$requestActiveUnlockOnWakeup")
pw.println(" requestActiveUnlockOnUnlockIntent=$requestActiveUnlockOnUnlockIntent")
pw.println(" requestActiveUnlockOnBioFail=$requestActiveUnlockOnBioFail")
+ pw.println(" requestActiveUnlockOnUnlockIntentWhenBiometricEnrolled=" +
+ "$onUnlockIntentWhenBiometricEnrolled")
+ pw.println(" requestActiveUnlockOnFaceError=$faceErrorsToTriggerBiometricFailOn")
+ pw.println(" requestActiveUnlockOnFaceAcquireInfo=" +
+ "$faceAcquireInfoToTriggerBiometricFailOn")
+
+ pw.println("Current state:")
+ keyguardUpdateMonitor?.let {
+ pw.println(" shouldRequestActiveUnlockOnUnlockIntentFromBiometricEnrollment=" +
+ "${shouldRequestActiveUnlockOnUnlockIntentFromBiometricEnrollment()}")
+ pw.println(" faceEnrolled=${it.isFaceEnrolled}")
+ pw.println(" fpEnrolled=${
+ it.getCachedIsUnlockWithFingerprintPossible(getCurrentUser())}")
+ pw.println(" udfpsEnrolled=${it.isUdfpsEnrolled}")
+ } ?: pw.println(" keyguardUpdateMonitor is uninitialized")
}
} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index bbe9a362b1fa..121ac299ec5b 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -56,7 +56,6 @@ import android.content.pm.ResolveInfo;
import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.hardware.SensorPrivacyManager;
-import android.hardware.biometrics.BiometricFaceConstants;
import android.hardware.biometrics.BiometricFingerprintConstants;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricSourceType;
@@ -1615,7 +1614,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
mKeyguardBypassController.setUserHasDeviceEntryIntent(false);
}
- if (errMsgId == BiometricFaceConstants.FACE_ERROR_TIMEOUT) {
+ if (mActiveUnlockConfig.shouldRequestActiveUnlockOnFaceError(errMsgId)) {
requestActiveUnlock(
ActiveUnlockConfig.ACTIVE_UNLOCK_REQUEST_ORIGIN.BIOMETRIC_FAIL,
"faceError-" + errMsgId);
@@ -1625,6 +1624,13 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
@Override
public void onAuthenticationAcquired(int acquireInfo) {
handleFaceAcquired(acquireInfo);
+
+ if (mActiveUnlockConfig.shouldRequestActiveUnlockOnFaceAcquireInfo(
+ acquireInfo)) {
+ requestActiveUnlock(
+ ActiveUnlockConfig.ACTIVE_UNLOCK_REQUEST_ORIGIN.BIOMETRIC_FAIL,
+ "faceAcquireInfo-" + acquireInfo);
+ }
}
};
@@ -1639,6 +1645,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
private boolean mFingerprintLockedOut;
private boolean mFingerprintLockedOutPermanent;
private boolean mFaceLockedOutPermanent;
+ private HashMap<Integer, Boolean> mIsUnlockWithFingerprintPossible = new HashMap<>();
private TelephonyManager mTelephonyManager;
/**
@@ -1889,6 +1896,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
dumpManager.registerDumpable(getClass().getName(), this);
mSensorPrivacyManager = context.getSystemService(SensorPrivacyManager.class);
mActiveUnlockConfig = activeUnlockConfiguration;
+ mActiveUnlockConfig.setKeyguardUpdateMonitor(this);
mHandler = new Handler(mainLooper) {
@Override
@@ -2329,7 +2337,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
if (shouldTriggerActiveUnlock()) {
- if (DEBUG) {
+ if (DEBUG_ACTIVE_UNLOCK) {
Log.d("ActiveUnlock", "initiate active unlock triggerReason=" + reason);
}
mTrustManager.reportUserMayRequestUnlock(KeyguardUpdateMonitor.getCurrentUser());
@@ -2359,7 +2367,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
if (allowRequest && shouldTriggerActiveUnlock()) {
- if (DEBUG) {
+ if (DEBUG_ACTIVE_UNLOCK) {
Log.d("ActiveUnlock", "reportUserRequestedUnlock"
+ " origin=" + requestOrigin.name()
+ " reason=" + reason
@@ -2777,8 +2785,17 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
}
private boolean isUnlockWithFingerprintPossible(int userId) {
- return mFpm != null && mFpm.isHardwareDetected() && !isFingerprintDisabled(userId)
- && mFpm.hasEnrolledTemplates(userId);
+ mIsUnlockWithFingerprintPossible.put(userId, mFpm != null && mFpm.isHardwareDetected()
+ && !isFingerprintDisabled(userId) && mFpm.hasEnrolledTemplates(userId));
+ return mIsUnlockWithFingerprintPossible.get(userId);
+ }
+
+ /**
+ * Cached value for whether fingerprint is enrolled and possible to use for authentication.
+ * Note: checking fingerprint enrollment directly with the AuthController requires an IPC.
+ */
+ public boolean getCachedIsUnlockWithFingerprintPossible(int userId) {
+ return mIsUnlockWithFingerprintPossible.get(userId);
}
private boolean isUnlockWithFacePossible(int userId) {
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconView.java b/packages/SystemUI/src/com/android/keyguard/LockIconView.java
index e1913657b7cc..fdde40296511 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconView.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconView.java
@@ -55,7 +55,7 @@ public class LockIconView extends FrameLayout implements Dumpable {
@NonNull private final RectF mSensorRect;
@NonNull private PointF mLockIconCenter = new PointF(0f, 0f);
- private int mRadius;
+ private float mRadius;
private int mLockIconPadding;
private ImageView mLockIcon;
@@ -126,7 +126,7 @@ public class LockIconView extends FrameLayout implements Dumpable {
* Set the location of the lock icon.
*/
@VisibleForTesting
- public void setCenterLocation(@NonNull PointF center, int radius, int drawablePadding) {
+ public void setCenterLocation(@NonNull PointF center, float radius, int drawablePadding) {
mLockIconCenter = center;
mRadius = radius;
mLockIconPadding = drawablePadding;
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 2b217f02e834..d79b1454514e 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -188,6 +188,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
protected void onViewAttached() {
updateIsUdfpsEnrolled();
updateConfiguration();
+ updateLockIconLocation();
updateKeyguardShowing();
mUserUnlockedWithBiometric = false;
@@ -340,20 +341,17 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
mHeightPixels = bounds.bottom;
mBottomPaddingPx = getResources().getDimensionPixelSize(R.dimen.lock_icon_margin_bottom);
- final int defaultPaddingPx =
- getResources().getDimensionPixelSize(R.dimen.lock_icon_padding);
- mScaledPaddingPx = (int) (defaultPaddingPx * mAuthController.getScaleFactor());
-
mUnlockedLabel = mView.getContext().getResources().getString(
R.string.accessibility_unlock_button);
mLockedLabel = mView.getContext()
.getResources().getString(R.string.accessibility_lock_icon);
-
- updateLockIconLocation();
}
private void updateLockIconLocation() {
if (mUdfpsSupported) {
+ final int defaultPaddingPx =
+ getResources().getDimensionPixelSize(R.dimen.lock_icon_padding);
+ mScaledPaddingPx = (int) (defaultPaddingPx * mAuthController.getScaleFactor());
mView.setCenterLocation(mAuthController.getUdfpsLocation(),
mAuthController.getUdfpsRadius(), mScaledPaddingPx);
} else {
@@ -362,8 +360,6 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
mHeightPixels - mBottomPaddingPx - sLockIconRadiusPx),
sLockIconRadiusPx, mScaledPaddingPx);
}
-
- mView.getHitRect(mSensorTouchLocation);
}
@Override
@@ -386,6 +382,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
pw.println(" mCanDismissLockScreen: " + mCanDismissLockScreen);
pw.println(" mStatusBarState: " + StatusBarState.toString(mStatusBarState));
pw.println(" mInterpolatedDarkAmount: " + mInterpolatedDarkAmount);
+ pw.println(" mSensorTouchLocation: " + mSensorTouchLocation);
if (mView != null) {
mView.dump(pw, args);
@@ -672,6 +669,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
}
private boolean inLockIconArea(MotionEvent event) {
+ mView.getHitRect(mSensorTouchLocation);
return mSensorTouchLocation.contains((int) event.getX(), (int) event.getY())
&& mView.getVisibility() == View.VISIBLE;
}
@@ -692,6 +690,7 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
mExecutor.execute(() -> {
updateIsUdfpsEnrolled();
updateConfiguration();
+ updateLockIconLocation();
});
}
@@ -705,6 +704,11 @@ public class LockIconViewController extends ViewController<LockIconView> impleme
public void onEnrollmentsChanged() {
updateUdfpsConfig();
}
+
+ @Override
+ public void onUdfpsLocationChanged() {
+ updateLockIconLocation();
+ }
};
private final View.OnClickListener mA11yClickListener = v -> onLongPress();
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index cbce854e4a71..dd312186afee 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -47,6 +47,7 @@ import android.hardware.graphics.common.AlphaInterpretation;
import android.hardware.graphics.common.DisplayDecorationSupport;
import android.os.Handler;
import android.os.SystemProperties;
+import android.os.Trace;
import android.os.UserHandle;
import android.provider.Settings.Secure;
import android.util.DisplayUtils;
@@ -1067,15 +1068,22 @@ public class ScreenDecorations extends CoreStartable implements Tunable , Dumpab
}
private void updateLayoutParams() {
- if (mOverlays == null) {
- return;
+ //ToDo: We should skip unnecessary call to update view layout.
+ Trace.beginSection("ScreenDecorations#updateLayoutParams");
+ if (mScreenDecorHwcWindow != null) {
+ mWindowManager.updateViewLayout(mScreenDecorHwcWindow, getHwcWindowLayoutParams());
}
- for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) {
- if (mOverlays[i] == null) {
- continue;
+
+ if (mOverlays != null) {
+ for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) {
+ if (mOverlays[i] == null) {
+ continue;
+ }
+ mWindowManager.updateViewLayout(
+ mOverlays[i].getRootView(), getWindowLayoutParams(i));
}
- mWindowManager.updateViewLayout(mOverlays[i].getRootView(), getWindowLayoutParams(i));
}
+ Trace.endSection();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 932489372872..75339aaa843d 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -79,6 +79,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
import javax.inject.Inject;
@@ -446,11 +447,11 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba
/**
* @return the radius of UDFPS on the screen in pixels
*/
- public int getUdfpsRadius() {
+ public float getUdfpsRadius() {
if (mUdfpsController == null || mUdfpsBounds == null) {
return -1;
}
- return mUdfpsBounds.height() / 2;
+ return mUdfpsBounds.height() / 2f;
}
/**
@@ -634,11 +635,17 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba
displayInfo.getNaturalHeight());
final FingerprintSensorPropertiesInternal udfpsProp = mUdfpsProps.get(0);
+ final Rect previousUdfpsBounds = mUdfpsBounds;
mUdfpsBounds = udfpsProp.getLocation().getRect();
mUdfpsBounds.scale(scaleFactor);
mUdfpsController.updateOverlayParams(udfpsProp.sensorId,
new UdfpsOverlayParams(mUdfpsBounds, displayInfo.getNaturalWidth(),
displayInfo.getNaturalHeight(), scaleFactor, displayInfo.rotation));
+ if (!Objects.equals(previousUdfpsBounds, mUdfpsBounds)) {
+ for (Callback cb : mCallbacks) {
+ cb.onUdfpsLocationChanged();
+ }
+ }
}
}
@@ -1054,5 +1061,10 @@ public class AuthController extends CoreStartable implements CommandQueue.Callba
* Called when the biometric prompt is no longer showing.
*/
default void onBiometricPromptDismissed() {}
+
+ /**
+ * The location in pixels can change due to resolution changes.
+ */
+ default void onUdfpsLocationChanged() {}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
index d9aa1bae3c69..86e501670440 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
@@ -335,15 +335,17 @@ class AuthRippleController @Inject constructor(
updateSensorLocation()
}
- override fun onEnrollmentsChanged() {
+ override fun onUdfpsLocationChanged() {
+ updateUdfpsDependentParams()
+ updateSensorLocation()
}
}
private fun updateUdfpsDependentParams() {
authController.udfpsProps?.let {
if (it.size > 0) {
- udfpsRadius = it[0].location.sensorRadius.toFloat()
udfpsController = udfpsControllerProvider.get()
+ udfpsRadius = authController.udfpsRadius
if (mView.isAttachedToWindow) {
udfpsController?.addCallback(udfpsControllerCallback)
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
index 9139699af26a..f28fedb9155b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
@@ -32,6 +32,7 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
+import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import androidx.asynclayoutinflater.view.AsyncLayoutInflater;
@@ -44,6 +45,8 @@ import com.airbnb.lottie.LottieProperty;
import com.airbnb.lottie.model.KeyPath;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
/**
* View corresponding with udfps_keyguard_view.xml
@@ -52,7 +55,6 @@ public class UdfpsKeyguardView extends UdfpsAnimationView {
private UdfpsDrawable mFingerprintDrawable; // placeholder
private LottieAnimationView mAodFp;
private LottieAnimationView mLockScreenFp;
- private int mStatusBarState;
// used when highlighting fp icon:
private int mTextColorPrimary;
@@ -70,7 +72,7 @@ public class UdfpsKeyguardView extends UdfpsAnimationView {
private float mBurnInOffsetY;
private float mBurnInProgress;
private float mInterpolatedDarkAmount;
- private boolean mAnimatingBetweenAodAndLockscreen; // As opposed to Unlocked => AOD
+ private int mAnimationType = ANIMATION_NONE;
private boolean mFullyInflated;
public UdfpsKeyguardView(Context context, @Nullable AttributeSet attrs) {
@@ -117,8 +119,10 @@ public class UdfpsKeyguardView extends UdfpsAnimationView {
return;
}
- final float darkAmountForAnimation = mAnimatingBetweenAodAndLockscreen
- ? mInterpolatedDarkAmount : 1f /* animating from unlocked to AOD */;
+ // if we're animating from screen off, we can immediately place the icon in the
+ // AoD-burn in location, else we need to translate the icon from LS => AoD.
+ final float darkAmountForAnimation = mAnimationType == ANIMATION_UNLOCKED_SCREEN_OFF
+ ? 1f : mInterpolatedDarkAmount;
mBurnInOffsetX = MathUtils.lerp(0f,
getBurnInOffset(mMaxBurnInOffsetX * 2, true /* xAxis */)
- mMaxBurnInOffsetX, darkAmountForAnimation);
@@ -127,12 +131,12 @@ public class UdfpsKeyguardView extends UdfpsAnimationView {
- mMaxBurnInOffsetY, darkAmountForAnimation);
mBurnInProgress = MathUtils.lerp(0f, getBurnInProgressOffset(), darkAmountForAnimation);
- if (mAnimatingBetweenAodAndLockscreen && !mPauseAuth) {
+ if (mAnimationType == ANIMATION_BETWEEN_AOD_AND_LOCKSCREEN && !mPauseAuth) {
mLockScreenFp.setTranslationX(mBurnInOffsetX);
mLockScreenFp.setTranslationY(mBurnInOffsetY);
mBgProtection.setAlpha(1f - mInterpolatedDarkAmount);
mLockScreenFp.setAlpha(1f - mInterpolatedDarkAmount);
- } else if (mInterpolatedDarkAmount == 0f) {
+ } else if (darkAmountForAnimation == 0f) {
mLockScreenFp.setTranslationX(0);
mLockScreenFp.setTranslationY(0);
mBgProtection.setAlpha(mAlpha / 255f);
@@ -148,9 +152,15 @@ public class UdfpsKeyguardView extends UdfpsAnimationView {
mAodFp.setProgress(mBurnInProgress);
mAodFp.setAlpha(mInterpolatedDarkAmount);
- // done animating between AoD & LS
- if (mInterpolatedDarkAmount == 1f || mInterpolatedDarkAmount == 0f) {
- mAnimatingBetweenAodAndLockscreen = false;
+ // done animating
+ final boolean doneAnimatingBetweenAodAndLS =
+ mAnimationType == ANIMATION_BETWEEN_AOD_AND_LOCKSCREEN
+ && (mInterpolatedDarkAmount == 0f || mInterpolatedDarkAmount == 1f);
+ final boolean doneAnimatingUnlockedScreenOff =
+ mAnimationType == ANIMATION_UNLOCKED_SCREEN_OFF
+ && (mInterpolatedDarkAmount == 1f);
+ if (doneAnimatingBetweenAodAndLS || doneAnimatingUnlockedScreenOff) {
+ mAnimationType = ANIMATION_NONE;
}
}
@@ -158,10 +168,6 @@ public class UdfpsKeyguardView extends UdfpsAnimationView {
mUdfpsRequested = request;
}
- void setStatusBarState(int statusBarState) {
- mStatusBarState = statusBarState;
- }
-
void updateColor() {
if (!mFullyInflated) {
return;
@@ -219,8 +225,16 @@ public class UdfpsKeyguardView extends UdfpsAnimationView {
return mAlpha;
}
- void onDozeAmountChanged(float linear, float eased, boolean animatingBetweenAodAndLockscreen) {
- mAnimatingBetweenAodAndLockscreen = animatingBetweenAodAndLockscreen;
+ static final int ANIMATION_NONE = 0;
+ static final int ANIMATION_BETWEEN_AOD_AND_LOCKSCREEN = 1;
+ static final int ANIMATION_UNLOCKED_SCREEN_OFF = 2;
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({ANIMATION_NONE, ANIMATION_BETWEEN_AOD_AND_LOCKSCREEN, ANIMATION_UNLOCKED_SCREEN_OFF})
+ private @interface AnimationType {}
+
+ void onDozeAmountChanged(float linear, float eased, @AnimationType int animationType) {
+ mAnimationType = animationType;
mInterpolatedDarkAmount = eased;
updateAlpha();
}
@@ -262,7 +276,7 @@ public class UdfpsKeyguardView extends UdfpsAnimationView {
pw.println(" mUnpausedAlpha=" + getUnpausedAlpha());
pw.println(" mUdfpsRequested=" + mUdfpsRequested);
pw.println(" mInterpolatedDarkAmount=" + mInterpolatedDarkAmount);
- pw.println(" mAnimatingBetweenAodAndLockscreen=" + mAnimatingBetweenAodAndLockscreen);
+ pw.println(" mAnimationType=" + mAnimationType);
}
private final AsyncLayoutInflater.OnInflateFinishedListener mLayoutInflaterFinishListener =
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
index 8b0f36fe1245..ec4cf2fd8bd4 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
@@ -121,7 +121,7 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
mView.onDozeAmountChanged(
animation.getAnimatedFraction(),
(float) animation.getAnimatedValue(),
- /* animatingBetweenAodAndLockScreen */ false);
+ UdfpsKeyguardView.ANIMATION_UNLOCKED_SCREEN_OFF);
}
});
}
@@ -394,7 +394,7 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
mUnlockedScreenOffDozeAnimator.start();
} else {
mView.onDozeAmountChanged(linear, eased,
- /* animatingBetweenAodAndLockScreen */ true);
+ UdfpsKeyguardView.ANIMATION_BETWEEN_AOD_AND_LOCKSCREEN);
}
mLastDozeAmount = linear;
@@ -404,7 +404,6 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
@Override
public void onStateChanged(int statusBarState) {
mStatusBarState = statusBarState;
- mView.setStatusBarState(statusBarState);
updateAlpha();
updatePauseAuth();
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 74044e2c2eb8..1cc5df5d04cf 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -39,7 +39,6 @@ import com.android.systemui.dock.DockManager;
import com.android.systemui.doze.DozeMachine.State;
import com.android.systemui.doze.dagger.DozeScope;
import com.android.systemui.statusbar.phone.DozeParameters;
-import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.DevicePostureController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.Assert;
@@ -94,7 +93,6 @@ public class DozeTriggers implements DozeMachine.Part {
private final AuthController mAuthController;
private final DelayableExecutor mMainExecutor;
private final KeyguardStateController mKeyguardStateController;
- private final BatteryController mBatteryController;
private final UiEventLogger mUiEventLogger;
private final DevicePostureController mDevicePostureController;
@@ -186,8 +184,7 @@ public class DozeTriggers implements DozeMachine.Part {
@Main DelayableExecutor mainExecutor,
UiEventLogger uiEventLogger,
KeyguardStateController keyguardStateController,
- DevicePostureController devicePostureController,
- BatteryController batteryController) {
+ DevicePostureController devicePostureController) {
mContext = context;
mDozeHost = dozeHost;
mConfig = config;
@@ -208,7 +205,6 @@ public class DozeTriggers implements DozeMachine.Part {
mMainExecutor = mainExecutor;
mUiEventLogger = uiEventLogger;
mKeyguardStateController = keyguardStateController;
- mBatteryController = batteryController;
}
private final DevicePostureController.Callback mDevicePostureCallback =
posture -> {
@@ -320,12 +316,7 @@ public class DozeTriggers implements DozeMachine.Part {
gentleWakeUp(pulseReason);
} else if (isPickup) {
if (shouldDropPickupEvent()) {
- mDozeLog.traceSensorEventDropped(
- pulseReason,
- "keyguardOccluded="
- + mKeyguardStateController.isOccluded()
- + " pluggedInWireless="
- + mBatteryController.isPluggedInWireless());
+ mDozeLog.traceSensorEventDropped(pulseReason, "keyguard occluded");
return;
}
gentleWakeUp(pulseReason);
@@ -356,7 +347,7 @@ public class DozeTriggers implements DozeMachine.Part {
}
private boolean shouldDropPickupEvent() {
- return mKeyguardStateController.isOccluded() || mBatteryController.isPluggedInWireless();
+ return mKeyguardStateController.isOccluded();
}
private void gentleWakeUp(int reason) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index 2fec49955c2d..8c2cb6ded678 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -97,7 +97,7 @@ import kotlin.Unit;
* A view controller used for Media Playback.
*/
public class MediaControlPanel {
- private static final String TAG = "MediaControlPanel";
+ protected static final String TAG = "MediaControlPanel";
private static final float DISABLED_ALPHA = 0.38f;
private static final String EXPORTED_SMARTSPACE_TRAMPOLINE_ACTIVITY_NAME = "com.google"
@@ -106,7 +106,7 @@ public class MediaControlPanel {
"com.google.android.apps.gsa.smartspace.extra.SMARTSPACE_INTENT";
private static final String KEY_SMARTSPACE_ARTIST_NAME = "artist_name";
private static final String KEY_SMARTSPACE_OPEN_IN_FOREGROUND = "KEY_OPEN_IN_FOREGROUND";
- private static final String KEY_SMARTSPACE_APP_NAME = "KEY_SMARTSPACE_APP_NAME";
+ protected static final String KEY_SMARTSPACE_APP_NAME = "KEY_SMARTSPACE_APP_NAME";
// Event types logged by smartspace
private static final int SMARTSPACE_CARD_CLICK_EVENT = 760;
@@ -149,6 +149,7 @@ public class MediaControlPanel {
private RecommendationViewHolder mRecommendationViewHolder;
private String mKey;
private MediaData mMediaData;
+ private SmartspaceMediaData mRecommendationData;
private MediaViewController mMediaViewController;
private MediaSession.Token mToken;
private MediaController mController;
@@ -448,6 +449,7 @@ public class MediaControlPanel {
bindOutputSwitcherChip(data);
bindGutsMenuForPlayer(data);
+ bindPlayerContentDescription(data);
bindScrubbingTime(data);
bindActionButtons(data);
@@ -541,12 +543,6 @@ public class MediaControlPanel {
}
private boolean bindSongMetadata(MediaData data) {
- // Accessibility label
- mMediaViewHolder.getPlayer().setContentDescription(
- mContext.getString(
- R.string.controls_media_playing_item_description,
- data.getSong(), data.getArtist(), data.getApp()));
-
TextView titleText = mMediaViewHolder.getTitleText();
TextView artistText = mMediaViewHolder.getArtistText();
return mMetadataAnimationHandler.setNext(
@@ -568,6 +564,48 @@ public class MediaControlPanel {
});
}
+ // We may want to look into unifying this with bindRecommendationContentDescription if/when we
+ // do a refactor of this class.
+ private void bindPlayerContentDescription(MediaData data) {
+ if (mMediaViewHolder == null) {
+ return;
+ }
+
+ CharSequence contentDescription;
+ if (mMediaViewController.isGutsVisible()) {
+ contentDescription = mMediaViewHolder.getGutsViewHolder().getGutsText().getText();
+ } else if (data != null) {
+ contentDescription = mContext.getString(
+ R.string.controls_media_playing_item_description,
+ data.getSong(),
+ data.getArtist(),
+ data.getApp());
+ } else {
+ contentDescription = null;
+ }
+ mMediaViewHolder.getPlayer().setContentDescription(contentDescription);
+ }
+
+ private void bindRecommendationContentDescription(SmartspaceMediaData data) {
+ if (mRecommendationViewHolder == null) {
+ return;
+ }
+
+ CharSequence contentDescription;
+ if (mMediaViewController.isGutsVisible()) {
+ contentDescription =
+ mRecommendationViewHolder.getGutsViewHolder().getGutsText().getText();
+ } else if (data != null) {
+ contentDescription = mContext.getString(
+ R.string.controls_media_smartspace_rec_description,
+ data.getAppName(mContext));
+ } else {
+ contentDescription = null;
+ }
+
+ mRecommendationViewHolder.getRecommendations().setContentDescription(contentDescription);
+ }
+
private void bindArtworkAndColors(MediaData data, boolean updateBackground) {
final int reqId = mArtworkNextBindRequestId++;
if (updateBackground) {
@@ -636,6 +674,10 @@ public class MediaControlPanel {
mIsArtworkBound = isArtworkBound;
}
+ // Scrim bounds are set manually so it scales as expected
+ albumView.getForeground().setBounds(0, 0,
+ Math.max(width, height), Math.max(width, height));
+
// Transition Colors to current color scheme
mColorSchemeTransition.updateColorScheme(colorScheme, mIsArtworkBound);
@@ -950,6 +992,7 @@ public class MediaControlPanel {
return;
}
+ mRecommendationData = data;
mSmartspaceId = SmallHash.hash(data.getTargetId());
mPackageName = data.getPackageName();
mInstanceId = data.getInstanceId();
@@ -965,6 +1008,12 @@ public class MediaControlPanel {
return;
}
+ CharSequence appName = data.getAppName(mContext);
+ if (appName == null) {
+ Log.w(TAG, "Fail to get media recommendation's app name");
+ return;
+ }
+
PackageManager packageManager = mContext.getPackageManager();
// Set up media source app's logo.
Drawable icon = packageManager.getApplicationIcon(applicationInfo);
@@ -972,28 +1021,11 @@ public class MediaControlPanel {
headerLogoImageView.setImageDrawable(icon);
fetchAndUpdateRecommendationColors(icon);
- // Set up media source app's label text.
- CharSequence appName = getAppName(data.getCardAction());
- if (TextUtils.isEmpty(appName)) {
- Intent launchIntent =
- packageManager.getLaunchIntentForPackage(data.getPackageName());
- if (launchIntent != null) {
- ActivityInfo launchActivity = launchIntent.resolveActivityInfo(packageManager, 0);
- appName = launchActivity.loadLabel(packageManager);
- } else {
- Log.w(TAG, "Package " + data.getPackageName()
- + " does not have a main launcher activity. Fallback to full app name");
- appName = packageManager.getApplicationLabel(applicationInfo);
- }
- }
-
// Set up media rec card's tap action if applicable.
TransitionLayout recommendationCard = mRecommendationViewHolder.getRecommendations();
setSmartspaceRecItemOnClickListener(recommendationCard, data.getCardAction(),
/* interactedSubcardRank */ -1);
- // Set up media rec card's accessibility label.
- recommendationCard.setContentDescription(
- mContext.getString(R.string.controls_media_smartspace_rec_description, appName));
+ bindRecommendationContentDescription(data);
List<ImageView> mediaCoverItems = mRecommendationViewHolder.getMediaCoverItems();
List<ViewGroup> mediaCoverContainers = mRecommendationViewHolder.getMediaCoverContainers();
@@ -1175,6 +1207,11 @@ public class MediaControlPanel {
mRecommendationViewHolder.marquee(false, mMediaViewController.GUTS_ANIMATION_DURATION);
}
mMediaViewController.closeGuts(immediate);
+ if (mMediaViewHolder != null) {
+ bindPlayerContentDescription(mMediaData);
+ } else if (mRecommendationViewHolder != null) {
+ bindRecommendationContentDescription(mRecommendationData);
+ }
}
private void closeGuts() {
@@ -1188,6 +1225,11 @@ public class MediaControlPanel {
mRecommendationViewHolder.marquee(true, mMediaViewController.GUTS_ANIMATION_DURATION);
}
mMediaViewController.openGuts();
+ if (mMediaViewHolder != null) {
+ bindPlayerContentDescription(mMediaData);
+ } else if (mRecommendationViewHolder != null) {
+ bindRecommendationContentDescription(mRecommendationData);
+ }
mLogger.logLongPressOpen(mUid, mPackageName, mInstanceId);
}
@@ -1302,17 +1344,6 @@ public class MediaControlPanel {
});
}
- /** Returns the upstream app name if available. */
- @Nullable
- private String getAppName(SmartspaceAction action) {
- if (action == null || action.getIntent() == null
- || action.getIntent().getExtras() == null) {
- return null;
- }
-
- return action.getIntent().getExtras().getString(KEY_SMARTSPACE_APP_NAME);
- }
-
/** Returns if the Smartspace action will open the activity in foreground. */
private boolean shouldSmartspaceRecItemOpenInForeground(SmartspaceAction action) {
if (action == null || action.getIntent() == null
diff --git a/packages/SystemUI/src/com/android/systemui/media/SmartspaceMediaData.kt b/packages/SystemUI/src/com/android/systemui/media/SmartspaceMediaData.kt
index 50a96f601443..c8f17d93bcc8 100644
--- a/packages/SystemUI/src/com/android/systemui/media/SmartspaceMediaData.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/SmartspaceMediaData.kt
@@ -17,8 +17,13 @@
package com.android.systemui.media
import android.app.smartspace.SmartspaceAction
+import android.content.Context
import android.content.Intent
+import android.content.pm.PackageManager
+import android.text.TextUtils
+import android.util.Log
import com.android.internal.logging.InstanceId
+import com.android.systemui.media.MediaControlPanel.KEY_SMARTSPACE_APP_NAME
/** State of a Smartspace media recommendations view. */
data class SmartspaceMediaData(
@@ -67,6 +72,32 @@ data class SmartspaceMediaData(
* Returns the list of [recommendations] that have valid data.
*/
fun getValidRecommendations() = recommendations.filter { it.icon != null }
+
+ /** Returns the upstream app name if available. */
+ fun getAppName(context: Context): CharSequence? {
+ val nameFromAction = cardAction?.intent?.extras?.getString(KEY_SMARTSPACE_APP_NAME)
+ if (!TextUtils.isEmpty(nameFromAction)) {
+ return nameFromAction
+ }
+
+ val packageManager = context.packageManager
+ packageManager.getLaunchIntentForPackage(packageName)?.let {
+ val launchActivity = it.resolveActivityInfo(packageManager, 0)
+ return launchActivity.loadLabel(packageManager)
+ }
+
+ Log.w(
+ TAG,
+ "Package $packageName does not have a main launcher activity. " +
+ "Fallback to full app name")
+ return try {
+ val applicationInfo = packageManager.getApplicationInfo(packageName, /* flags= */ 0)
+ packageManager.getApplicationLabel(applicationInfo)
+ } catch (e: PackageManager.NameNotFoundException) {
+ null
+ }
+ }
}
const val NUM_REQUIRED_RECOMMENDATIONS = 3
+private val TAG = SmartspaceMediaData::class.simpleName!!
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
index a397f32dcbbf..58a35ff7e350 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
@@ -143,6 +143,7 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
if (mController.isTransferring()) {
if (device.getState() == MediaDeviceState.STATE_CONNECTING
&& !mController.hasAdjustVolumeUserRestriction()) {
+ setUpDeviceIcon(device);
mProgressBar.getIndeterminateDrawable().setColorFilter(
new PorterDuffColorFilter(
mController.getColorItemContent(),
@@ -151,11 +152,13 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
false /* showSeekBar*/,
true /* showProgressBar */, false /* showStatus */);
} else {
+ setUpDeviceIcon(device);
setSingleLineLayout(getItemTitle(device), false /* bFocused */);
}
} else {
// Set different layout for each device
if (device.getState() == MediaDeviceState.STATE_CONNECTING_FAILED) {
+ setUpDeviceIcon(device);
mTitleText.setAlpha(DEVICE_CONNECTED_ALPHA);
mTitleIcon.setAlpha(DEVICE_CONNECTED_ALPHA);
mStatusIcon.setImageDrawable(
@@ -167,6 +170,7 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
mSubTitleText.setText(R.string.media_output_dialog_connect_failed);
mContainerLayout.setOnClickListener(v -> onItemClick(v, device));
} else if (device.getState() == MediaDeviceState.STATE_GROUPING) {
+ setUpDeviceIcon(device);
mProgressBar.getIndeterminateDrawable().setColorFilter(
new PorterDuffColorFilter(
mController.getColorItemContent(),
@@ -176,7 +180,12 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
true /* showProgressBar */, false /* showStatus */);
} else if (mController.getSelectedMediaDevice().size() > 1
&& isDeviceIncluded(mController.getSelectedMediaDevice(), device)) {
+ boolean isDeviceDeselectable = isDeviceIncluded(
+ mController.getDeselectableMediaDevice(), device);
mTitleText.setTextColor(mController.getColorItemContent());
+ mTitleIcon.setImageDrawable(
+ mContext.getDrawable(R.drawable.media_output_icon_volume));
+ mTitleIcon.setColorFilter(mController.getColorItemContent());
setSingleLineLayout(getItemTitle(device), true /* bFocused */,
true /* showSeekBar */,
false /* showProgressBar */, false /* showStatus */);
@@ -184,13 +193,20 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
mCheckBox.setOnCheckedChangeListener(null);
mCheckBox.setVisibility(View.VISIBLE);
mCheckBox.setChecked(true);
- mCheckBox.setOnCheckedChangeListener(
- (buttonView, isChecked) -> onGroupActionTriggered(false, device));
+ mCheckBox.setOnCheckedChangeListener(isDeviceDeselectable
+ ? (buttonView, isChecked) -> onGroupActionTriggered(false, device)
+ : null);
+ mCheckBox.setEnabled(isDeviceDeselectable);
+ mCheckBox.setAlpha(
+ isDeviceDeselectable ? DEVICE_CONNECTED_ALPHA
+ : DEVICE_DISCONNECTED_ALPHA
+ );
setCheckBoxColor(mCheckBox, mController.getColorItemContent());
initSeekbar(device, isCurrentSeekbarInvisible);
mEndTouchArea.setVisibility(View.VISIBLE);
mEndTouchArea.setOnClickListener(null);
- mEndTouchArea.setOnClickListener((v) -> mCheckBox.performClick());
+ mEndTouchArea.setOnClickListener(
+ isDeviceDeselectable ? (v) -> mCheckBox.performClick() : null);
mEndTouchArea.setImportantForAccessibility(
View.IMPORTANT_FOR_ACCESSIBILITY_YES);
setUpContentDescriptionForView(mEndTouchArea, true, device);
@@ -198,6 +214,9 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
mStatusIcon.setImageDrawable(
mContext.getDrawable(R.drawable.media_output_status_check));
mStatusIcon.setColorFilter(mController.getColorItemContent());
+ mTitleIcon.setImageDrawable(
+ mContext.getDrawable(R.drawable.media_output_icon_volume));
+ mTitleIcon.setColorFilter(mController.getColorItemContent());
mTitleText.setTextColor(mController.getColorItemContent());
setSingleLineLayout(getItemTitle(device), true /* bFocused */,
true /* showSeekBar */,
@@ -206,6 +225,7 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
setUpContentDescriptionForView(mContainerLayout, false, device);
mCurrentActivePosition = position;
} else if (isDeviceIncluded(mController.getSelectableMediaDevice(), device)) {
+ setUpDeviceIcon(device);
mCheckBox.setOnCheckedChangeListener(null);
mCheckBox.setVisibility(View.VISIBLE);
mCheckBox.setChecked(false);
@@ -218,6 +238,7 @@ public class MediaOutputAdapter extends MediaOutputBaseAdapter {
false /* showSeekBar */,
false /* showProgressBar */, false /* showStatus */);
} else {
+ setUpDeviceIcon(device);
setSingleLineLayout(getItemTitle(device), false /* bFocused */);
mContainerLayout.setOnClickListener(v -> onItemClick(v, device));
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
index 5c2cc0b6af35..b407e76f1b11 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
@@ -166,15 +166,6 @@ public abstract class MediaOutputBaseAdapter extends
void onBind(MediaDevice device, boolean topMargin, boolean bottomMargin, int position) {
mDeviceId = device.getId();
- ThreadUtils.postOnBackgroundThread(() -> {
- Icon icon = mController.getDeviceIconCompat(device).toIcon(mContext);
- ThreadUtils.postOnMainThread(() -> {
- if (!TextUtils.equals(mDeviceId, device.getId())) {
- return;
- }
- mTitleIcon.setImageIcon(icon);
- });
- });
}
abstract void onBind(int customizedItem, boolean topMargin, boolean bottomMargin);
@@ -414,5 +405,17 @@ public abstract class MediaOutputBaseAdapter extends
mSeekBar.setEnabled(false);
mSeekBar.setOnTouchListener((v, event) -> true);
}
+
+ protected void setUpDeviceIcon(MediaDevice device) {
+ ThreadUtils.postOnBackgroundThread(() -> {
+ Icon icon = mController.getDeviceIconCompat(device).toIcon(mContext);
+ ThreadUtils.postOnMainThread(() -> {
+ if (!TextUtils.equals(mDeviceId, device.getId())) {
+ return;
+ }
+ mTitleIcon.setImageIcon(icon);
+ });
+ });
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
index 6af6e36a75f7..ccfcaa692e22 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
@@ -149,7 +149,6 @@ public class ScreenshotView extends FrameLayout implements
private ImageView mActionsContainerBackground;
private HorizontalScrollView mActionsContainer;
private LinearLayout mActionsView;
- private ImageView mBackgroundProtection;
private FrameLayout mDismissButton;
private OverlayActionChip mShareChip;
private OverlayActionChip mEditChip;
@@ -345,8 +344,6 @@ public class ScreenshotView extends FrameLayout implements
R.id.actions_container_background));
mActionsContainer = requireNonNull(findViewById(R.id.actions_container));
mActionsView = requireNonNull(findViewById(R.id.screenshot_actions));
- mBackgroundProtection = requireNonNull(
- findViewById(R.id.screenshot_actions_background));
mDismissButton = requireNonNull(findViewById(R.id.screenshot_dismiss_button));
mScrollablePreview = requireNonNull(findViewById(R.id.screenshot_scrollable_preview));
mScreenshotFlash = requireNonNull(findViewById(R.id.screenshot_flash));
@@ -394,14 +391,6 @@ public class ScreenshotView extends FrameLayout implements
}
mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SWIPE_DISMISSED, 0,
mPackageName);
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- super.onAnimationStart(animation);
- mBackgroundProtection.animate()
- .alpha(0).setDuration(animation.getDuration()).start();
- }
- });
}
@Override
@@ -704,7 +693,6 @@ public class ScreenshotView extends FrameLayout implements
animator.addUpdateListener(animation -> {
float t = animation.getAnimatedFraction();
- mBackgroundProtection.setAlpha(t);
float containerAlpha = t < alphaFraction ? t / alphaFraction : 1;
mActionsContainer.setAlpha(containerAlpha);
mActionsContainerBackground.setAlpha(containerAlpha);
@@ -910,7 +898,6 @@ public class ScreenshotView extends FrameLayout implements
}
mDismissButton.setVisibility(View.GONE);
mActionsContainer.setVisibility(View.GONE);
- mBackgroundProtection.setVisibility(View.GONE);
// set these invisible, but not gone, so that the views are laid out correctly
mActionsContainerBackground.setVisibility(View.INVISIBLE);
mScreenshotPreviewBorder.setVisibility(View.INVISIBLE);
@@ -932,7 +919,6 @@ public class ScreenshotView extends FrameLayout implements
mDismissButton.setVisibility(View.VISIBLE);
}
mActionsContainer.setVisibility(View.VISIBLE);
- mBackgroundProtection.setVisibility(View.VISIBLE);
mActionsContainerBackground.setVisibility(View.VISIBLE);
mScreenshotPreviewBorder.setVisibility(View.VISIBLE);
mScreenshotPreview.setVisibility(View.VISIBLE);
@@ -969,7 +955,6 @@ public class ScreenshotView extends FrameLayout implements
mPendingSharedTransition = false;
mActionsContainerBackground.setVisibility(View.GONE);
mActionsContainer.setVisibility(View.GONE);
- mBackgroundProtection.setAlpha(0f);
mDismissButton.setVisibility(View.GONE);
mScrollingScrim.setVisibility(View.GONE);
mScrollablePreview.setVisibility(View.GONE);
@@ -1016,7 +1001,6 @@ public class ScreenshotView extends FrameLayout implements
mDismissButton.setAlpha(alpha);
mActionsContainerBackground.setAlpha(alpha);
mActionsContainer.setAlpha(alpha);
- mBackgroundProtection.setAlpha(alpha);
mScreenshotPreviewBorder.setAlpha(alpha);
});
alphaAnim.setDuration(600);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
index 6b79680fdb26..f0b221dd4726 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ChannelEditorDialogController.kt
@@ -160,8 +160,7 @@ class ChannelEditorDialogController @Inject constructor(
val channels = groupList
.flatMap { group ->
group.channels.asSequence().filterNot { channel ->
- channel.isImportanceLockedByOEM ||
- channel.importance == IMPORTANCE_NONE ||
+ channel.importance == IMPORTANCE_NONE ||
channel.isImportanceLockedByCriticalDeviceFunction
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 0ae365352df0..dff8c47e36e0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -376,44 +376,24 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
* calls.
*/
private static Boolean isSystemNotification(Context context, StatusBarNotification sbn) {
- // TODO (b/194833441): clean up before launch
- if (Settings.Secure.getIntForUser(context.getContentResolver(),
- Settings.Secure.NOTIFICATION_PERMISSION_ENABLED, 0, USER_SYSTEM) == 1) {
- INotificationManager iNm = INotificationManager.Stub.asInterface(
- ServiceManager.getService(Context.NOTIFICATION_SERVICE));
-
- boolean isSystem = false;
- try {
- isSystem = iNm.isPermissionFixed(sbn.getPackageName(), sbn.getUserId());
- } catch (RemoteException e) {
- Log.e(TAG, "cannot reach NMS");
- }
- RoleManager rm = context.getSystemService(RoleManager.class);
- List<String> fixedRoleHolders = new ArrayList<>();
- fixedRoleHolders.addAll(rm.getRoleHolders(RoleManager.ROLE_DIALER));
- fixedRoleHolders.addAll(rm.getRoleHolders(RoleManager.ROLE_EMERGENCY));
- if (fixedRoleHolders.contains(sbn.getPackageName())) {
- isSystem = true;
- }
-
- return isSystem;
- } else {
- PackageManager packageManager = CentralSurfaces.getPackageManagerForUser(
- context, sbn.getUser().getIdentifier());
- Boolean isSystemNotification = null;
-
- try {
- PackageInfo packageInfo = packageManager.getPackageInfo(
- sbn.getPackageName(), PackageManager.GET_SIGNATURES);
+ INotificationManager iNm = INotificationManager.Stub.asInterface(
+ ServiceManager.getService(Context.NOTIFICATION_SERVICE));
- isSystemNotification =
- com.android.settingslib.Utils.isSystemPackage(
- context.getResources(), packageManager, packageInfo);
- } catch (PackageManager.NameNotFoundException e) {
- Log.e(TAG, "cacheIsSystemNotification: Could not find package info");
- }
- return isSystemNotification;
+ boolean isSystem = false;
+ try {
+ isSystem = iNm.isPermissionFixed(sbn.getPackageName(), sbn.getUserId());
+ } catch (RemoteException e) {
+ Log.e(TAG, "cannot reach NMS");
}
+ RoleManager rm = context.getSystemService(RoleManager.class);
+ List<String> fixedRoleHolders = new ArrayList<>();
+ fixedRoleHolders.addAll(rm.getRoleHolders(RoleManager.ROLE_DIALER));
+ fixedRoleHolders.addAll(rm.getRoleHolders(RoleManager.ROLE_EMERGENCY));
+ if (fixedRoleHolders.contains(sbn.getPackageName())) {
+ isSystem = true;
+ }
+
+ return isSystem;
}
public NotificationContentView[] getLayouts() {
@@ -567,9 +547,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
mEntry.mIsSystemNotification = isSystemNotification(mContext, mEntry.getSbn());
}
- // TODO (b/194833441): remove when we've migrated to permission
- boolean isNonblockable = mEntry.getChannel().isImportanceLockedByOEM()
- || mEntry.getChannel().isImportanceLockedByCriticalDeviceFunction();
+ boolean isNonblockable = mEntry.getChannel().isImportanceLockedByCriticalDeviceFunction();
if (!isNonblockable && mEntry != null && mEntry.mIsSystemNotification != null) {
if (mEntry.mIsSystemNotification) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 83970dc15e61..629aa0317d24 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -220,7 +220,7 @@ public class KeyguardClockPositionAlgorithm {
}
}
- public float getMinStackScrollerPadding() {
+ public float getLockscreenMinStackScrollerPadding() {
if (mBypassEnabled) {
return mUnlockedStackScrollerPadding;
} else if (mIsSplitShade) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 7da32384b766..77b9efa3b16b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -326,6 +326,11 @@ public class NotificationPanelViewController extends PanelViewController {
private boolean mShouldUseSplitNotificationShade;
// The bottom padding reserved for elements of the keyguard measuring notifications
private float mKeyguardNotificationBottomPadding;
+ /**
+ * The top padding from where notification should start in lockscreen.
+ * Should be static also during animations and should match the Y of the first notification.
+ */
+ private float mKeyguardNotificationTopPadding;
// Current max allowed keyguard notifications determined by measuring the panel
private int mMaxAllowedKeyguardNotifications;
@@ -1514,7 +1519,10 @@ public class NotificationPanelViewController extends PanelViewController {
*/
@VisibleForTesting
float getSpaceForLockscreenNotifications() {
- float topPadding = mNotificationStackScrollLayoutController.getTopPadding();
+ float staticTopPadding = mClockPositionAlgorithm.getLockscreenMinStackScrollerPadding()
+ // getMinStackScrollerPadding is from the top of the screen,
+ // but we need it from the top of the NSSL.
+ - mNotificationStackScrollLayoutController.getTop();
// Space between bottom of notifications and top of lock icon or udfps background.
float lockIconPadding = mLockIconViewController.getTop();
@@ -1526,11 +1534,15 @@ public class NotificationPanelViewController extends PanelViewController {
float bottomPadding = Math.max(lockIconPadding,
Math.max(mIndicationBottomPadding, mAmbientIndicationBottomPadding));
+
mKeyguardNotificationBottomPadding = bottomPadding;
+ mKeyguardNotificationTopPadding = staticTopPadding;
+ // To debug the available space, enable debug lines in this class. If you change how the
+ // available space is calculated, please also update those lines.
float availableSpace =
mNotificationStackScrollLayoutController.getHeight()
- - topPadding
+ - staticTopPadding
- bottomPadding;
return availableSpace;
}
@@ -3198,6 +3210,8 @@ public class NotificationPanelViewController extends PanelViewController {
updateTrackingHeadsUp(null);
mExpandingFromHeadsUp = false;
setPanelScrimMinFraction(0.0f);
+ // Reset status bar alpha so alpha can be calculated upon updating view state.
+ setKeyguardStatusBarAlpha(-1f);
}
private void updateTrackingHeadsUp(@Nullable ExpandableNotificationRow pickedChild) {
@@ -4924,6 +4938,20 @@ public class NotificationPanelViewController extends PanelViewController {
drawDebugInfo(canvas, (int) mLockIconViewController.getTop(), Color.GRAY,
"mLockIconViewController.getTop()");
+ if (mKeyguardShowing) {
+ // Notifications have the space between those two lines.
+ drawDebugInfo(canvas,
+ mNotificationStackScrollLayoutController.getTop() +
+ (int) mKeyguardNotificationTopPadding,
+ Color.RED,
+ "NSSL.getTop() + mKeyguardNotificationTopPadding");
+
+ drawDebugInfo(canvas, mNotificationStackScrollLayoutController.getBottom() -
+ (int) mKeyguardNotificationBottomPadding,
+ Color.RED,
+ "NSSL.getBottom() - mKeyguardNotificationBottomPadding");
+ }
+
mDebugPaint.setColor(Color.CYAN);
canvas.drawLine(0, mClockPositionResult.stackScrollerPadding, mView.getWidth(),
mNotificationStackScrollLayoutController.getTopPadding(), mDebugPaint);
diff --git a/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt b/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt
index 3329eabc80ad..ad734914170b 100644
--- a/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/UserSwitcherActivity.kt
@@ -71,6 +71,11 @@ class UserSwitcherActivity @Inject constructor(
private var popupMenu: UserSwitcherPopupMenu? = null
private lateinit var addButton: View
private var addUserRecords = mutableListOf<UserRecord>()
+ private val userSwitchedCallback: UserTracker.Callback = object : UserTracker.Callback {
+ override fun onUserChanged(newUser: Int, userContext: Context) {
+ finish()
+ }
+ }
// When the add users options become available, insert another option to manage users
private val manageUserRecord = UserRecord(
null /* info */,
@@ -215,11 +220,7 @@ class UserSwitcherActivity @Inject constructor(
initBroadcastReceiver()
parent.post { buildUserViews() }
- userTracker.addCallback(object : UserTracker.Callback {
- override fun onUserChanged(newUser: Int, userContext: Context) {
- finish()
- }
- }, mainExecutor)
+ userTracker.addCallback(userSwitchedCallback, mainExecutor)
}
private fun showPopupMenu() {
@@ -340,6 +341,7 @@ class UserSwitcherActivity @Inject constructor(
super.onDestroy()
broadcastDispatcher.unregisterReceiver(broadcastReceiver)
+ userTracker.removeCallback(userSwitchedCallback)
}
private fun initBroadcastReceiver() {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt
index 747649006b45..39cc34bb7e26 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/ActiveUnlockConfigTest.kt
@@ -18,6 +18,7 @@ package com.android.keyguard
import android.content.ContentResolver
import android.database.ContentObserver
+import android.hardware.biometrics.BiometricFaceConstants
import android.net.Uri
import android.os.Handler
import android.os.UserHandle
@@ -44,18 +45,20 @@ class ActiveUnlockConfigTest : SysuiTestCase() {
private val fakeWakeUri = Uri.Builder().appendPath("wake").build()
private val fakeUnlockIntentUri = Uri.Builder().appendPath("unlock-intent").build()
private val fakeBioFailUri = Uri.Builder().appendPath("bio-fail").build()
+ private val fakeFaceErrorsUri = Uri.Builder().appendPath("face-errors").build()
+ private val fakeFaceAcquiredUri = Uri.Builder().appendPath("face-acquired").build()
+ private val fakeUnlockIntentBioEnroll = Uri.Builder().appendPath("unlock-intent-bio").build()
@Mock
private lateinit var secureSettings: SecureSettings
-
@Mock
private lateinit var contentResolver: ContentResolver
-
@Mock
private lateinit var handler: Handler
-
@Mock
private lateinit var dumpManager: DumpManager
+ @Mock
+ private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
@Captor
private lateinit var settingsObserverCaptor: ArgumentCaptor<ContentObserver>
@@ -72,6 +75,13 @@ class ActiveUnlockConfigTest : SysuiTestCase() {
.thenReturn(fakeUnlockIntentUri)
`when`(secureSettings.getUriFor(Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL))
.thenReturn(fakeBioFailUri)
+ `when`(secureSettings.getUriFor(Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ERRORS))
+ .thenReturn(fakeFaceErrorsUri)
+ `when`(secureSettings.getUriFor(Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO))
+ .thenReturn(fakeFaceAcquiredUri)
+ `when`(secureSettings.getUriFor(
+ Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED))
+ .thenReturn(fakeUnlockIntentBioEnroll)
activeUnlockConfig = ActiveUnlockConfig(
handler,
@@ -99,12 +109,7 @@ class ActiveUnlockConfigTest : SysuiTestCase() {
// WHEN unlock on wake is allowed
`when`(secureSettings.getIntForUser(Settings.Secure.ACTIVE_UNLOCK_ON_WAKE,
0, 0)).thenReturn(1)
- settingsObserverCaptor.value.onChange(
- false,
- listOf(fakeWakeUri),
- 0,
- 0
- )
+ updateSetting(fakeWakeUri)
// THEN active unlock triggers allowed on: wake, unlock-intent, and biometric failure
assertTrue(
@@ -134,12 +139,7 @@ class ActiveUnlockConfigTest : SysuiTestCase() {
// WHEN unlock on biometric failed is allowed
`when`(secureSettings.getIntForUser(Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT,
0, 0)).thenReturn(1)
- settingsObserverCaptor.value.onChange(
- false,
- listOf(fakeUnlockIntentUri),
- 0,
- 0
- )
+ updateSetting(fakeUnlockIntentUri)
// THEN active unlock triggers allowed on: biometric failure ONLY
assertFalse(activeUnlockConfig.shouldAllowActiveUnlockFromOrigin(
@@ -154,19 +154,19 @@ class ActiveUnlockConfigTest : SysuiTestCase() {
fun testOnBioFailSettingChanged() {
verifyRegisterSettingObserver()
- // GIVEN no active unlock settings enabled
+ // GIVEN no active unlock settings enabled and triggering unlock intent on biometric
+ // enrollment setting is disabled (empty string is disabled, null would use the default)
+ `when`(secureSettings.getStringForUser(
+ Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED,
+ 0)).thenReturn("")
+ updateSetting(fakeUnlockIntentBioEnroll)
assertFalse(activeUnlockConfig.shouldAllowActiveUnlockFromOrigin(
ActiveUnlockConfig.ACTIVE_UNLOCK_REQUEST_ORIGIN.BIOMETRIC_FAIL))
// WHEN unlock on biometric failed is allowed
`when`(secureSettings.getIntForUser(Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL,
0, 0)).thenReturn(1)
- settingsObserverCaptor.value.onChange(
- false,
- listOf(fakeBioFailUri),
- 0,
- 0
- )
+ updateSetting(fakeBioFailUri)
// THEN active unlock triggers allowed on: biometric failure ONLY
assertFalse(activeUnlockConfig.shouldAllowActiveUnlockFromOrigin(
@@ -177,21 +177,146 @@ class ActiveUnlockConfigTest : SysuiTestCase() {
ActiveUnlockConfig.ACTIVE_UNLOCK_REQUEST_ORIGIN.BIOMETRIC_FAIL))
}
- private fun verifyRegisterSettingObserver() {
- verify(contentResolver).registerContentObserver(
- eq(fakeWakeUri),
- eq(false),
- capture(settingsObserverCaptor),
- eq(UserHandle.USER_ALL))
+ @Test
+ fun testFaceErrorSettingsChanged() {
+ verifyRegisterSettingObserver()
- verify(contentResolver).registerContentObserver(
- eq(fakeUnlockIntentUri),
- eq(false),
- capture(settingsObserverCaptor),
- eq(UserHandle.USER_ALL))
+ // GIVEN unlock on biometric fail
+ `when`(secureSettings.getIntForUser(Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL,
+ 0, 0)).thenReturn(1)
+ updateSetting(fakeBioFailUri)
+
+ // WHEN face error timeout (3), allow trigger active unlock
+ `when`(secureSettings.getStringForUser(Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ERRORS,
+ 0)).thenReturn("3")
+ updateSetting(fakeFaceAcquiredUri)
+
+ // THEN active unlock triggers allowed on error TIMEOUT
+ assertTrue(activeUnlockConfig.shouldRequestActiveUnlockOnFaceError(
+ BiometricFaceConstants.FACE_ERROR_TIMEOUT))
+
+ assertFalse(activeUnlockConfig.shouldRequestActiveUnlockOnFaceError(
+ BiometricFaceConstants.FACE_ERROR_CANCELED))
+ }
+
+ @Test
+ fun testFaceAcquiredSettingsChanged() {
+ verifyRegisterSettingObserver()
+
+ // GIVEN unlock on biometric fail
+ `when`(secureSettings.getIntForUser(Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL,
+ 0, 0)).thenReturn(1)
+ updateSetting(fakeBioFailUri)
+
+ // WHEN face acquiredMsg DARK_GLASSESand MOUTH_COVERING are allowed to trigger
+ `when`(secureSettings.getStringForUser(Settings.Secure.ACTIVE_UNLOCK_ON_FACE_ACQUIRE_INFO,
+ 0)).thenReturn(
+ "${BiometricFaceConstants.FACE_ACQUIRED_MOUTH_COVERING_DETECTED}" +
+ "|${BiometricFaceConstants.FACE_ACQUIRED_DARK_GLASSES_DETECTED}")
+ updateSetting(fakeFaceAcquiredUri)
+
+ // THEN active unlock triggers allowed on acquired messages DARK_GLASSES & MOUTH_COVERING
+ assertTrue(activeUnlockConfig.shouldRequestActiveUnlockOnFaceAcquireInfo(
+ BiometricFaceConstants.FACE_ACQUIRED_MOUTH_COVERING_DETECTED))
+ assertTrue(activeUnlockConfig.shouldRequestActiveUnlockOnFaceAcquireInfo(
+ BiometricFaceConstants.FACE_ACQUIRED_DARK_GLASSES_DETECTED))
+
+ assertFalse(activeUnlockConfig.shouldRequestActiveUnlockOnFaceAcquireInfo(
+ BiometricFaceConstants.FACE_ACQUIRED_GOOD))
+ assertFalse(activeUnlockConfig.shouldRequestActiveUnlockOnFaceAcquireInfo(
+ BiometricFaceConstants.FACE_ACQUIRED_NOT_DETECTED))
+ }
+
+ @Test
+ fun testTriggerOnUnlockIntentWhenBiometricEnrolledNone() {
+ verifyRegisterSettingObserver()
+
+ // GIVEN unlock on biometric fail
+ `when`(secureSettings.getIntForUser(Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL,
+ 0, 0)).thenReturn(1)
+ updateSetting(fakeBioFailUri)
+
+ // GIVEN fingerprint and face are NOT enrolled
+ activeUnlockConfig.keyguardUpdateMonitor = keyguardUpdateMonitor
+ `when`(keyguardUpdateMonitor.isFaceEnrolled()).thenReturn(false)
+ `when`(keyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(0)).thenReturn(false)
+
+ // WHEN unlock intent is allowed when NO biometrics are enrolled (0)
+ `when`(secureSettings.getStringForUser(
+ Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED,
+ 0)).thenReturn("${ActiveUnlockConfig.BIOMETRIC_TYPE_NONE}")
+ updateSetting(fakeUnlockIntentBioEnroll)
+
+ // THEN active unlock triggers allowed on unlock intent
+ assertTrue(activeUnlockConfig.shouldAllowActiveUnlockFromOrigin(
+ ActiveUnlockConfig.ACTIVE_UNLOCK_REQUEST_ORIGIN.UNLOCK_INTENT))
+ }
+
+ @Test
+ fun testTriggerOnUnlockIntentWhenBiometricEnrolledFingerprintOrFaceOnly() {
+ verifyRegisterSettingObserver()
+
+ // GIVEN unlock on biometric fail
+ `when`(secureSettings.getIntForUser(Settings.Secure.ACTIVE_UNLOCK_ON_BIOMETRIC_FAIL,
+ 0, 0)).thenReturn(1)
+ updateSetting(fakeBioFailUri)
+
+ // GIVEN fingerprint and face are both enrolled
+ activeUnlockConfig.keyguardUpdateMonitor = keyguardUpdateMonitor
+ `when`(keyguardUpdateMonitor.isFaceEnrolled()).thenReturn(true)
+ `when`(keyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(0)).thenReturn(true)
+
+ // WHEN unlock intent is allowed when ONLY fingerprint is enrolled or NO biometircs
+ // are enrolled
+ `when`(secureSettings.getStringForUser(
+ Settings.Secure.ACTIVE_UNLOCK_ON_UNLOCK_INTENT_WHEN_BIOMETRIC_ENROLLED,
+ 0)).thenReturn(
+ "${ActiveUnlockConfig.BIOMETRIC_TYPE_ANY_FACE}" +
+ "|${ActiveUnlockConfig.BIOMETRIC_TYPE_ANY_FINGERPRINT}")
+ updateSetting(fakeUnlockIntentBioEnroll)
+
+ // THEN active unlock triggers NOT allowed on unlock intent
+ assertFalse(activeUnlockConfig.shouldAllowActiveUnlockFromOrigin(
+ ActiveUnlockConfig.ACTIVE_UNLOCK_REQUEST_ORIGIN.UNLOCK_INTENT))
+
+ // WHEN fingerprint ONLY enrolled
+ `when`(keyguardUpdateMonitor.isFaceEnrolled()).thenReturn(false)
+ `when`(keyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(0)).thenReturn(true)
+
+ // THEN active unlock triggers allowed on unlock intent
+ assertTrue(activeUnlockConfig.shouldAllowActiveUnlockFromOrigin(
+ ActiveUnlockConfig.ACTIVE_UNLOCK_REQUEST_ORIGIN.UNLOCK_INTENT))
+
+ // WHEN face ONLY enrolled
+ `when`(keyguardUpdateMonitor.isFaceEnrolled()).thenReturn(true)
+ `when`(keyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(0)).thenReturn(false)
+
+ // THEN active unlock triggers allowed on unlock intent
+ assertTrue(activeUnlockConfig.shouldAllowActiveUnlockFromOrigin(
+ ActiveUnlockConfig.ACTIVE_UNLOCK_REQUEST_ORIGIN.UNLOCK_INTENT))
+ }
+
+ private fun updateSetting(uri: Uri) {
+ settingsObserverCaptor.value.onChange(
+ false,
+ listOf(uri),
+ 0,
+ 0 /* flags */
+ )
+ }
+
+ private fun verifyRegisterSettingObserver() {
+ verifyRegisterSettingObserver(fakeWakeUri)
+ verifyRegisterSettingObserver(fakeUnlockIntentUri)
+ verifyRegisterSettingObserver(fakeBioFailUri)
+ verifyRegisterSettingObserver(fakeFaceErrorsUri)
+ verifyRegisterSettingObserver(fakeFaceAcquiredUri)
+ verifyRegisterSettingObserver(fakeUnlockIntentBioEnroll)
+ }
+ private fun verifyRegisterSettingObserver(uri: Uri) {
verify(contentResolver).registerContentObserver(
- eq(fakeBioFailUri),
+ eq(uri),
eq(false),
capture(settingsObserverCaptor),
eq(UserHandle.USER_ALL))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
index b87a7e78f73a..0fdd9054e4bc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
@@ -168,7 +168,8 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase {
mController.onViewAttached();
verify(mView, atLeast(1)).setPauseAuth(true);
- verify(mView).onDozeAmountChanged(dozeAmount, dozeAmount, true);
+ verify(mView).onDozeAmountChanged(dozeAmount, dozeAmount,
+ UdfpsKeyguardView.ANIMATION_BETWEEN_AOD_AND_LOCKSCREEN);
}
@Test
@@ -195,7 +196,8 @@ public class UdfpsKeyguardViewControllerTest extends SysuiTestCase {
final float eased = .65f;
mStatusBarStateListener.onDozeAmountChanged(linear, eased);
- verify(mView).onDozeAmountChanged(linear, eased, true);
+ verify(mView).onDozeAmountChanged(linear, eased,
+ UdfpsKeyguardView.ANIMATION_BETWEEN_AOD_AND_LOCKSCREEN);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
index ae387e86de9d..4eeb4acf18b8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -45,7 +45,6 @@ import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.dock.DockManager;
import com.android.systemui.doze.DozeTriggers.DozingUpdateUiEvent;
import com.android.systemui.statusbar.phone.DozeParameters;
-import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.DevicePostureController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.FakeExecutor;
@@ -91,8 +90,6 @@ public class DozeTriggersTest extends SysuiTestCase {
private KeyguardStateController mKeyguardStateController;
@Mock
private DevicePostureController mDevicePostureController;
- @Mock
- private BatteryController mBatteryController;
private DozeTriggers mTriggers;
private FakeSensorManager mSensors;
@@ -125,7 +122,7 @@ public class DozeTriggersTest extends SysuiTestCase {
asyncSensorManager, wakeLock, mDockManager, mProximitySensor,
mProximityCheck, mock(DozeLog.class), mBroadcastDispatcher, new FakeSettings(),
mAuthController, mExecutor, mUiEventLogger, mKeyguardStateController,
- mDevicePostureController, mBatteryController);
+ mDevicePostureController);
mTriggers.setDozeMachine(mMachine);
waitForSensorManager();
}
@@ -233,9 +230,7 @@ public class DozeTriggersTest extends SysuiTestCase {
when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE);
// WHEN the pick up gesture is triggered and keyguard isn't occluded
- // and device isn't on a wireless charger
when(mKeyguardStateController.isOccluded()).thenReturn(false);
- when(mBatteryController.isPluggedInWireless()).thenReturn(false);
mTriggers.onSensor(DozeLog.REASON_SENSOR_PICKUP, 100, 100, null);
// THEN wakeup
@@ -249,22 +244,6 @@ public class DozeTriggersTest extends SysuiTestCase {
// WHEN the pick up gesture is triggered and keyguard IS occluded
when(mKeyguardStateController.isOccluded()).thenReturn(true);
- when(mBatteryController.isPluggedInWireless()).thenReturn(false);
- mTriggers.onSensor(DozeLog.REASON_SENSOR_PICKUP, 100, 100, null);
-
- // THEN never wakeup
- verify(mMachine, never()).wakeUp();
- }
-
- @Test
- public void testPickupGestureWirelessCharger() {
- // GIVEN device is in doze (screen blank, but running doze sensors)
- when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE);
-
- // WHEN the pick up gesture is triggered
- // and device IS on a wireless charger
- when(mKeyguardStateController.isOccluded()).thenReturn(false);
- when(mBatteryController.isPluggedInWireless()).thenReturn(true);
mTriggers.onSensor(DozeLog.REASON_SENSOR_PICKUP, 100, 100, null);
// THEN never wakeup
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java
index 5ff316e2efec..c532ed5ab651 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/LockIconViewControllerTest.java
@@ -34,8 +34,6 @@ import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.drawable.AnimatedStateListDrawable;
import android.hardware.biometrics.BiometricSourceType;
-import android.hardware.biometrics.SensorLocationInternal;
-import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.Pair;
@@ -77,9 +75,6 @@ import org.mockito.MockitoAnnotations;
import org.mockito.MockitoSession;
import org.mockito.quality.Strictness;
-import java.util.ArrayList;
-import java.util.List;
-
@SmallTest
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@@ -182,7 +177,7 @@ public class LockIconViewControllerTest extends SysuiTestCase {
@Test
public void testUpdateFingerprintLocationOnInit() {
// GIVEN fp sensor location is available pre-attached
- Pair<Integer, PointF> udfps = setupUdfps(); // first = radius, second = udfps location
+ Pair<Float, PointF> udfps = setupUdfps(); // first = radius, second = udfps location
// WHEN lock icon view controller is initialized and attached
mLockIconViewController.init();
@@ -197,7 +192,7 @@ public class LockIconViewControllerTest extends SysuiTestCase {
@Test
public void testUpdatePaddingBasedOnResolutionScale() {
// GIVEN fp sensor location is available pre-attached & scaled resolution factor is 5
- Pair<Integer, PointF> udfps = setupUdfps(); // first = radius, second = udfps location
+ Pair<Float, PointF> udfps = setupUdfps(); // first = radius, second = udfps location
when(mAuthController.getScaleFactor()).thenReturn(5f);
// WHEN lock icon view controller is initialized and attached
@@ -215,20 +210,19 @@ public class LockIconViewControllerTest extends SysuiTestCase {
// GIVEN fp sensor location is not available pre-init
when(mKeyguardUpdateMonitor.isUdfpsSupported()).thenReturn(false);
when(mAuthController.getFingerprintSensorLocation()).thenReturn(null);
- when(mAuthController.getUdfpsProps()).thenReturn(null);
mLockIconViewController.init();
captureAttachListener();
mAttachListener.onViewAttachedToWindow(mLockIconView);
- // GIVEN fp sensor location is available post-atttached
+ // GIVEN fp sensor location is available post-attached
captureAuthControllerCallback();
- Pair<Integer, PointF> udfps = setupUdfps();
+ Pair<Float, PointF> udfps = setupUdfps();
// WHEN all authenticators are registered
mAuthControllerCallback.onAllAuthenticatorsRegistered();
mDelayableExecutor.runAllReady();
- // THEN lock icon view location is updated with the same coordinates as fpProps
+ // THEN lock icon view location is updated with the same coordinates as auth controller vals
verify(mLockIconView).setCenterLocation(eq(udfps.second), eq(udfps.first),
eq(PADDING));
}
@@ -402,21 +396,10 @@ public class LockIconViewControllerTest extends SysuiTestCase {
verify(mLockIconView).setTranslationX(0);
}
- private Pair<Integer, PointF> setupUdfps() {
+ private Pair<Float, PointF> setupUdfps() {
when(mKeyguardUpdateMonitor.isUdfpsSupported()).thenReturn(true);
final PointF udfpsLocation = new PointF(50, 75);
- final int radius = 33;
- final FingerprintSensorPropertiesInternal fpProps =
- new FingerprintSensorPropertiesInternal(
- /* sensorId */ 0,
- /* strength */ 0,
- /* max enrollments per user */ 5,
- /* component info */ new ArrayList<>(),
- /* sensorType */ 3,
- /* halControlsIllumination */ true,
- /* resetLockoutRequiresHwToken */ false,
- List.of(new SensorLocationInternal("" /* displayId */,
- (int) udfpsLocation.x, (int) udfpsLocation.y, radius)));
+ final float radius = 33f;
when(mAuthController.getUdfpsLocation()).thenReturn(udfpsLocation);
when(mAuthController.getUdfpsRadius()).thenReturn(radius);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
index f9fb8657d0f6..18aae0edd846 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
@@ -21,7 +21,6 @@ import android.animation.AnimatorSet
import android.app.PendingIntent
import android.app.smartspace.SmartspaceAction
import android.content.Context
-import org.mockito.Mockito.`when` as whenever
import android.content.Intent
import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
@@ -59,6 +58,7 @@ import com.android.systemui.ActivityIntentHelper
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastSender
+import com.android.systemui.media.MediaControlPanel.KEY_SMARTSPACE_APP_NAME
import com.android.systemui.media.dialog.MediaOutputDialogFactory
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.plugins.FalsingManager
@@ -67,8 +67,8 @@ import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.animation.TransitionLayout
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.KotlinArgumentCaptor
-import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.argumentCaptor
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.nullable
import com.android.systemui.util.mockito.withArgCaptor
@@ -92,6 +92,7 @@ import org.mockito.Mockito.reset
import org.mockito.Mockito.times
import org.mockito.Mockito.verify
import org.mockito.junit.MockitoJUnit
+import org.mockito.Mockito.`when` as whenever
private const val KEY = "TEST_KEY"
private const val PACKAGE = "PKG"
@@ -102,6 +103,7 @@ private const val SESSION_KEY = "SESSION_KEY"
private const val SESSION_ARTIST = "SESSION_ARTIST"
private const val SESSION_TITLE = "SESSION_TITLE"
private const val DISABLED_DEVICE_NAME = "DISABLED_DEVICE_NAME"
+private const val REC_APP_NAME = "REC APP NAME"
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -262,6 +264,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
// Set valid recommendation data
val extras = Bundle()
+ extras.putString(KEY_SMARTSPACE_APP_NAME, REC_APP_NAME)
val intent = Intent().apply {
putExtras(extras)
setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
@@ -339,6 +342,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
whenever(viewHolder.player).thenReturn(view)
whenever(viewHolder.appIcon).thenReturn(appIcon)
whenever(viewHolder.albumView).thenReturn(albumView)
+ whenever(albumView.foreground).thenReturn(mock(Drawable::class.java))
whenever(viewHolder.titleText).thenReturn(titleText)
whenever(viewHolder.artistText).thenReturn(artistText)
whenever(seamlessBackground.getDrawable(0)).thenReturn(mock(GradientDrawable::class.java))
@@ -1121,6 +1125,91 @@ public class MediaControlPanelTest : SysuiTestCase() {
verify(mediaCarouselController).removePlayer(eq(mediaKey), eq(false), eq(false))
}
+ @Test
+ fun player_gutsOpen_contentDescriptionIsForGuts() {
+ whenever(mediaViewController.isGutsVisible).thenReturn(true)
+ player.attachPlayer(viewHolder)
+
+ val gutsTextString = "gutsText"
+ whenever(gutsText.text).thenReturn(gutsTextString)
+ player.bindPlayer(mediaData, KEY)
+
+ val descriptionCaptor = ArgumentCaptor.forClass(CharSequence::class.java)
+ verify(viewHolder.player).contentDescription = descriptionCaptor.capture()
+ val description = descriptionCaptor.value.toString()
+
+ assertThat(description).isEqualTo(gutsTextString)
+ }
+
+ @Test
+ fun player_gutsClosed_contentDescriptionIsForPlayer() {
+ whenever(mediaViewController.isGutsVisible).thenReturn(false)
+ player.attachPlayer(viewHolder)
+
+ val app = "appName"
+ player.bindPlayer(mediaData.copy(app = app), KEY)
+
+ val descriptionCaptor = ArgumentCaptor.forClass(CharSequence::class.java)
+ verify(viewHolder.player).contentDescription = descriptionCaptor.capture()
+ val description = descriptionCaptor.value.toString()
+
+ assertThat(description).contains(mediaData.song!!)
+ assertThat(description).contains(mediaData.artist!!)
+ assertThat(description).contains(app)
+ }
+
+ @Test
+ fun player_gutsChangesFromOpenToClosed_contentDescriptionUpdated() {
+ // Start out open
+ whenever(mediaViewController.isGutsVisible).thenReturn(true)
+ whenever(gutsText.text).thenReturn("gutsText")
+ player.attachPlayer(viewHolder)
+ val app = "appName"
+ player.bindPlayer(mediaData.copy(app = app), KEY)
+
+ // Update to closed by long pressing
+ val captor = ArgumentCaptor.forClass(View.OnLongClickListener::class.java)
+ verify(viewHolder.player).onLongClickListener = captor.capture()
+ reset(viewHolder.player)
+
+ whenever(mediaViewController.isGutsVisible).thenReturn(false)
+ captor.value.onLongClick(viewHolder.player)
+
+ // Then content description is now the player content description
+ val descriptionCaptor = ArgumentCaptor.forClass(CharSequence::class.java)
+ verify(viewHolder.player).contentDescription = descriptionCaptor.capture()
+ val description = descriptionCaptor.value.toString()
+
+ assertThat(description).contains(mediaData.song!!)
+ assertThat(description).contains(mediaData.artist!!)
+ assertThat(description).contains(app)
+ }
+
+ @Test
+ fun player_gutsChangesFromClosedToOpen_contentDescriptionUpdated() {
+ // Start out closed
+ whenever(mediaViewController.isGutsVisible).thenReturn(false)
+ val gutsTextString = "gutsText"
+ whenever(gutsText.text).thenReturn(gutsTextString)
+ player.attachPlayer(viewHolder)
+ player.bindPlayer(mediaData.copy(app = "appName"), KEY)
+
+ // Update to open by long pressing
+ val captor = ArgumentCaptor.forClass(View.OnLongClickListener::class.java)
+ verify(viewHolder.player).onLongClickListener = captor.capture()
+ reset(viewHolder.player)
+
+ whenever(mediaViewController.isGutsVisible).thenReturn(true)
+ captor.value.onLongClick(viewHolder.player)
+
+ // Then content description is now the guts content description
+ val descriptionCaptor = ArgumentCaptor.forClass(CharSequence::class.java)
+ verify(viewHolder.player).contentDescription = descriptionCaptor.capture()
+ val description = descriptionCaptor.value.toString()
+
+ assertThat(description).isEqualTo(gutsTextString)
+ }
+
/* ***** END guts tests for the player ***** */
/* ***** Guts tests for the recommendations ***** */
@@ -1189,6 +1278,85 @@ public class MediaControlPanelTest : SysuiTestCase() {
verify(mediaDataManager).dismissSmartspaceRecommendation(eq(mediaKey), anyLong())
}
+ @Test
+ fun recommendation_gutsOpen_contentDescriptionIsForGuts() {
+ whenever(mediaViewController.isGutsVisible).thenReturn(true)
+ player.attachRecommendation(recommendationViewHolder)
+
+ val gutsTextString = "gutsText"
+ whenever(gutsText.text).thenReturn(gutsTextString)
+ player.bindRecommendation(smartspaceData)
+
+ val descriptionCaptor = ArgumentCaptor.forClass(CharSequence::class.java)
+ verify(viewHolder.player).contentDescription = descriptionCaptor.capture()
+ val description = descriptionCaptor.value.toString()
+
+ assertThat(description).isEqualTo(gutsTextString)
+ }
+
+ @Test
+ fun recommendation_gutsClosed_contentDescriptionIsForPlayer() {
+ whenever(mediaViewController.isGutsVisible).thenReturn(false)
+ player.attachRecommendation(recommendationViewHolder)
+
+ player.bindRecommendation(smartspaceData)
+
+ val descriptionCaptor = ArgumentCaptor.forClass(CharSequence::class.java)
+ verify(viewHolder.player).contentDescription = descriptionCaptor.capture()
+ val description = descriptionCaptor.value.toString()
+
+ assertThat(description).contains(REC_APP_NAME)
+ }
+
+ @Test
+ fun recommendation_gutsChangesFromOpenToClosed_contentDescriptionUpdated() {
+ // Start out open
+ whenever(mediaViewController.isGutsVisible).thenReturn(true)
+ whenever(gutsText.text).thenReturn("gutsText")
+ player.attachRecommendation(recommendationViewHolder)
+ player.bindRecommendation(smartspaceData)
+
+ // Update to closed by long pressing
+ val captor = ArgumentCaptor.forClass(View.OnLongClickListener::class.java)
+ verify(viewHolder.player).onLongClickListener = captor.capture()
+ reset(viewHolder.player)
+
+ whenever(mediaViewController.isGutsVisible).thenReturn(false)
+ captor.value.onLongClick(viewHolder.player)
+
+ // Then content description is now the player content description
+ val descriptionCaptor = ArgumentCaptor.forClass(CharSequence::class.java)
+ verify(viewHolder.player).contentDescription = descriptionCaptor.capture()
+ val description = descriptionCaptor.value.toString()
+
+ assertThat(description).contains(REC_APP_NAME)
+ }
+
+ @Test
+ fun recommendation_gutsChangesFromClosedToOpen_contentDescriptionUpdated() {
+ // Start out closed
+ whenever(mediaViewController.isGutsVisible).thenReturn(false)
+ val gutsTextString = "gutsText"
+ whenever(gutsText.text).thenReturn(gutsTextString)
+ player.attachRecommendation(recommendationViewHolder)
+ player.bindRecommendation(smartspaceData)
+
+ // Update to open by long pressing
+ val captor = ArgumentCaptor.forClass(View.OnLongClickListener::class.java)
+ verify(viewHolder.player).onLongClickListener = captor.capture()
+ reset(viewHolder.player)
+
+ whenever(mediaViewController.isGutsVisible).thenReturn(true)
+ captor.value.onLongClick(viewHolder.player)
+
+ // Then content description is now the guts content description
+ val descriptionCaptor = ArgumentCaptor.forClass(CharSequence::class.java)
+ verify(viewHolder.player).contentDescription = descriptionCaptor.capture()
+ val description = descriptionCaptor.value.toString()
+
+ assertThat(description).isEqualTo(gutsTextString)
+ }
+
/* ***** END guts tests for the recommendations ***** */
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
index 4ea932157457..0f2e9bccc215 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
@@ -318,15 +318,6 @@ public class ExpandableNotificationRowTest extends SysuiTestCase {
}
@Test
- public void testGetIsNonblockable_oemLocked() throws Exception {
- ExpandableNotificationRow row =
- mNotificationTestHelper.createRow(mNotificationTestHelper.createNotification());
- row.getEntry().getChannel().setImportanceLockedByOEM(true);
-
- assertTrue(row.getIsNonblockable());
- }
-
- @Test
public void testGetIsNonblockable_criticalDeviceFunction() throws Exception {
ExpandableNotificationRow row =
mNotificationTestHelper.createRow(mNotificationTestHelper.createNotification());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
index 6d3a5fecc826..ec20271ea43b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
@@ -336,7 +336,7 @@ public class KeyguardClockPositionAlgorithmTest extends SysuiTestCase {
// WHEN the position algorithm is run
positionClock();
// THEN the padding DOESN'T adjust for keyguard status height.
- assertThat(mClockPositionAlgorithm.getMinStackScrollerPadding())
+ assertThat(mClockPositionAlgorithm.getLockscreenMinStackScrollerPadding())
.isEqualTo(mKeyguardStatusBarHeaderHeight);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
index 94e6b9a12a93..11f96cec6369 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewControllerTest.java
@@ -610,13 +610,13 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
when(mLockIconViewController.getTop()).thenReturn(80f);
when(mResources.getDimensionPixelSize(R.dimen.shelf_and_lock_icon_overlap)).thenReturn(5);
- // Available space (100 - 10 - 15 = 75)
+ // Available space (100 - 0 - 15 = 85)
when(mNotificationStackScrollLayoutController.getHeight()).thenReturn(100);
- when(mNotificationStackScrollLayoutController.getTopPadding()).thenReturn(10);
+ when(mNotificationStackScrollLayoutController.getTop()).thenReturn(0);
mNotificationPanelViewController.updateResources();
assertThat(mNotificationPanelViewController.getSpaceForLockscreenNotifications())
- .isEqualTo(75);
+ .isEqualTo(85);
}
@Test
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index 649328d1eef3..9b29bae1fc46 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -242,6 +242,9 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
int getCurrentUserIdLocked();
+ Pair<float[], MagnificationSpec> getWindowTransformationMatrixAndMagnificationSpec(
+ int windowId);
+
boolean isAccessibilityButtonShown();
/**
@@ -551,8 +554,6 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
final int resolvedWindowId;
RemoteAccessibilityConnection connection;
Region partialInteractiveRegion = Region.obtain();
- final MagnificationSpec spec;
- final float[] transformMatrix;
synchronized (mLock) {
mUsesAccessibilityCache = true;
if (!hasRightsToCurrentUserLocked()) {
@@ -576,11 +577,11 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
partialInteractiveRegion.recycle();
partialInteractiveRegion = null;
}
- final Pair<float[], MagnificationSpec> transformMatrixAndSpec =
- getTransformMatrixAndSpecLocked(resolvedWindowId);
- transformMatrix = transformMatrixAndSpec.first;
- spec = transformMatrixAndSpec.second;
}
+ final Pair<float[], MagnificationSpec> transformMatrixAndSpec =
+ getWindowTransformationMatrixAndMagnificationSpec(resolvedWindowId);
+ final float[] transformMatrix = transformMatrixAndSpec.first;
+ final MagnificationSpec spec = transformMatrixAndSpec.second;
if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
return null;
}
@@ -628,8 +629,6 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
final int resolvedWindowId;
RemoteAccessibilityConnection connection;
Region partialInteractiveRegion = Region.obtain();
- final MagnificationSpec spec;
- final float [] transformMatrix;
synchronized (mLock) {
mUsesAccessibilityCache = true;
if (!hasRightsToCurrentUserLocked()) {
@@ -653,11 +652,11 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
partialInteractiveRegion.recycle();
partialInteractiveRegion = null;
}
- final Pair<float[], MagnificationSpec> transformMatrixAndSpec =
- getTransformMatrixAndSpecLocked(resolvedWindowId);
- transformMatrix = transformMatrixAndSpec.first;
- spec = transformMatrixAndSpec.second;
}
+ final Pair<float[], MagnificationSpec> transformMatrixAndSpec =
+ getWindowTransformationMatrixAndMagnificationSpec(resolvedWindowId);
+ final float[] transformMatrix = transformMatrixAndSpec.first;
+ final MagnificationSpec spec = transformMatrixAndSpec.second;
if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
return null;
}
@@ -706,8 +705,6 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
final int resolvedWindowId;
RemoteAccessibilityConnection connection;
Region partialInteractiveRegion = Region.obtain();
- final MagnificationSpec spec;
- final float[] transformMatrix;
synchronized (mLock) {
mUsesAccessibilityCache = true;
if (!hasRightsToCurrentUserLocked()) {
@@ -731,11 +728,11 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
partialInteractiveRegion.recycle();
partialInteractiveRegion = null;
}
- final Pair<float[], MagnificationSpec> transformMatrixAndSpec =
- getTransformMatrixAndSpecLocked(resolvedWindowId);
- transformMatrix = transformMatrixAndSpec.first;
- spec = transformMatrixAndSpec.second;
}
+ final Pair<float[], MagnificationSpec> transformMatrixAndSpec =
+ getWindowTransformationMatrixAndMagnificationSpec(resolvedWindowId);
+ final float[] transformMatrix = transformMatrixAndSpec.first;
+ final MagnificationSpec spec = transformMatrixAndSpec.second;
if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
return null;
}
@@ -786,8 +783,6 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
final int resolvedWindowId;
RemoteAccessibilityConnection connection;
Region partialInteractiveRegion = Region.obtain();
- final MagnificationSpec spec;
- final float[] transformMatrix;
synchronized (mLock) {
if (!hasRightsToCurrentUserLocked()) {
return null;
@@ -811,11 +806,11 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
partialInteractiveRegion.recycle();
partialInteractiveRegion = null;
}
- final Pair<float[], MagnificationSpec> transformMatrixAndSpec =
- getTransformMatrixAndSpecLocked(resolvedWindowId);
- transformMatrix = transformMatrixAndSpec.first;
- spec = transformMatrixAndSpec.second;
}
+ final Pair<float[], MagnificationSpec> transformMatrixAndSpec =
+ getWindowTransformationMatrixAndMagnificationSpec(resolvedWindowId);
+ final float[] transformMatrix = transformMatrixAndSpec.first;
+ final MagnificationSpec spec = transformMatrixAndSpec.second;
if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
return null;
}
@@ -865,8 +860,6 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
final int resolvedWindowId;
RemoteAccessibilityConnection connection;
Region partialInteractiveRegion = Region.obtain();
- final MagnificationSpec spec;
- final float[] transformMatrix;
synchronized (mLock) {
if (!hasRightsToCurrentUserLocked()) {
return null;
@@ -889,12 +882,11 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
partialInteractiveRegion.recycle();
partialInteractiveRegion = null;
}
-
- final Pair<float[], MagnificationSpec> transformMatrixAndSpec =
- getTransformMatrixAndSpecLocked(resolvedWindowId);
- transformMatrix = transformMatrixAndSpec.first;
- spec = transformMatrixAndSpec.second;
}
+ final Pair<float[], MagnificationSpec> transformMatrixAndSpec =
+ getWindowTransformationMatrixAndMagnificationSpec(resolvedWindowId);
+ final float[] transformMatrix = transformMatrixAndSpec.first;
+ final MagnificationSpec spec = transformMatrixAndSpec.second;
if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
return null;
}
@@ -1672,21 +1664,10 @@ abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServ
mInvocationHandler.startInputLocked(connection, editorInfo, restarting);
}
-
-
@Nullable
- Pair<float[], MagnificationSpec> getTransformMatrixAndSpecLocked(int resolvedWindowId) {
- final WindowInfo windowInfo =
- mA11yWindowManager.findWindowInfoByIdLocked(resolvedWindowId);
- if (windowInfo == null) {
- Slog.w(LOG_TAG, "getTransformMatrixAndSpec, windowInfo is null window id = "
- + resolvedWindowId);
- return new Pair<>(null, null);
- }
-
- final MagnificationSpec spec = new MagnificationSpec();
- spec.setTo(windowInfo.mMagnificationSpec);
- return new Pair<>(windowInfo.mTransformMatrix, spec);
+ private Pair<float[], MagnificationSpec> getWindowTransformationMatrixAndMagnificationSpec(
+ int resolvedWindowId) {
+ return mSystemSupport.getWindowTransformationMatrixAndMagnificationSpec(resolvedWindowId);
}
/**
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 4806514a0e13..99c849527034 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -68,6 +68,7 @@ import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.database.ContentObserver;
+import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
@@ -99,6 +100,7 @@ import android.text.TextUtils;
import android.text.TextUtils.SimpleStringSplitter;
import android.util.ArraySet;
import android.util.IntArray;
+import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
@@ -458,6 +460,41 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
@Override
+ public Pair<float[], MagnificationSpec> getWindowTransformationMatrixAndMagnificationSpec(
+ int windowId) {
+ WindowInfo windowInfo;
+ synchronized (mLock) {
+ windowInfo = mA11yWindowManager.findWindowInfoByIdLocked(windowId);
+ }
+ if (windowInfo != null) {
+ final MagnificationSpec spec = new MagnificationSpec();
+ spec.setTo(windowInfo.mMagnificationSpec);
+ return new Pair<>(windowInfo.mTransformMatrix, spec);
+ } else {
+ // If the framework doesn't track windows, we fall back to get the pair of
+ // transformation matrix and MagnificationSpe from the WindowManagerService's
+ // WindowState.
+ IBinder token;
+ synchronized (mLock) {
+ token = mA11yWindowManager.getWindowTokenForUserAndWindowIdLocked(mCurrentUserId,
+ windowId);
+ }
+ Pair<Matrix, MagnificationSpec> pair =
+ mWindowManagerService.getWindowTransformationMatrixAndMagnificationSpec(token);
+ final float[] outTransformationMatrix = new float[9];
+ final Matrix tmpMatrix = pair.first;
+ final MagnificationSpec spec = pair.second;
+ if (!spec.isNop()) {
+ tmpMatrix.postScale(spec.scale, spec.scale);
+ tmpMatrix.postTranslate(spec.offsetX, spec.offsetY);
+ }
+ tmpMatrix.getValues(outTransformationMatrix);
+
+ return new Pair<>(outTransformationMatrix, pair.second);
+ }
+ }
+
+ @Override
public void onServiceInfoChangedLocked(AccessibilityUserState userState) {
mSecurityPolicy.onBoundServicesChangedLocked(userState.mUserId,
userState.mBoundServices);
@@ -3750,12 +3787,12 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
boundsInScreenBeforeMagnification.centerY());
// Invert magnification if needed.
- final WindowInfo windowInfo = mA11yWindowManager.findWindowInfoByIdLocked(
- focus.getWindowId());
+ final Pair<float[], MagnificationSpec> pair =
+ getWindowTransformationMatrixAndMagnificationSpec(focus.getWindowId());
MagnificationSpec spec = null;
- if (windowInfo != null) {
+ if (pair != null && pair.second != null) {
spec = new MagnificationSpec();
- spec.setTo(windowInfo.mMagnificationSpec);
+ spec.setTo(pair.second);
}
if (spec != null && !spec.isNop()) {
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 8e32a7a8e255..6d3620fa2ee6 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -3225,10 +3225,15 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
currentView.setState(ViewState.STATE_FILL_DIALOG_SHOWN);
mService.logDatasetShown(id, mClientState, UI_TYPE_DIALOG);
}
+ // Just show fill dialog once, so disabled after shown.
+ // Note: Cannot disable before requestShowFillDialog() because the method
+ // need to check whether fill dialog enabled.
+ setFillDialogDisabled();
return;
} else {
setFillDialogDisabled();
}
+
}
if (response.supportsInlineSuggestions()) {
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 62bb9f155c34..2a22cac75ae0 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -62,7 +62,6 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
-import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.content.pm.UserInfo;
@@ -81,7 +80,6 @@ import android.os.ServiceManager;
import android.os.ShellCallback;
import android.os.UserHandle;
import android.os.UserManager;
-import android.text.BidiFormatter;
import android.util.ArraySet;
import android.util.ExceptionUtils;
import android.util.Log;
@@ -538,20 +536,12 @@ public class CompanionDeviceManagerService extends SystemService {
String callingPackage = component.getPackageName();
checkCanCallNotificationApi(callingPackage);
// TODO: check userId.
- String packageTitle = BidiFormatter.getInstance().unicodeWrap(
- getPackageInfo(getContext(), userId, callingPackage)
- .applicationInfo
- .loadSafeLabel(getContext().getPackageManager(),
- PackageItemInfo.DEFAULT_MAX_LABEL_SIZE_PX,
- PackageItemInfo.SAFE_LABEL_FLAG_TRIM
- | PackageItemInfo.SAFE_LABEL_FLAG_FIRST_LINE)
- .toString());
final long identity = Binder.clearCallingIdentity();
try {
return PendingIntent.getActivityAsUser(getContext(),
0 /* request code */,
NotificationAccessConfirmationActivityContract.launcherIntent(
- getContext(), userId, component, packageTitle),
+ getContext(), userId, component),
PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT
| PendingIntent.FLAG_CANCEL_CURRENT,
null /* options */,
@@ -732,9 +722,12 @@ public class CompanionDeviceManagerService extends SystemService {
String[] args, ShellCallback callback, ResultReceiver resultReceiver)
throws RemoteException {
enforceCallerCanManageCompanionDevice(getContext(), "onShellCommand");
- new CompanionDeviceShellCommand(
- CompanionDeviceManagerService.this, mAssociationStore)
- .exec(this, in, out, err, args, callback, resultReceiver);
+
+ final CompanionDeviceShellCommand cmd = new CompanionDeviceShellCommand(
+ CompanionDeviceManagerService.this,
+ mAssociationStore,
+ mDevicePresenceMonitor);
+ cmd.exec(this, in, out, err, args, callback, resultReceiver);
}
@Override
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
index fd130852a43a..6a19a42723c5 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
@@ -21,6 +21,8 @@ import android.os.ShellCommand;
import android.util.Log;
import android.util.Slog;
+import com.android.server.companion.presence.CompanionDevicePresenceMonitor;
+
import java.io.PrintWriter;
import java.util.List;
@@ -29,20 +31,24 @@ class CompanionDeviceShellCommand extends ShellCommand {
private final CompanionDeviceManagerService mService;
private final AssociationStore mAssociationStore;
+ private final CompanionDevicePresenceMonitor mDevicePresenceMonitor;
CompanionDeviceShellCommand(CompanionDeviceManagerService service,
- AssociationStore associationStore) {
+ AssociationStore associationStore,
+ CompanionDevicePresenceMonitor devicePresenceMonitor) {
mService = service;
mAssociationStore = associationStore;
+ mDevicePresenceMonitor = devicePresenceMonitor;
}
@Override
public int onCommand(String cmd) {
final PrintWriter out = getOutPrintWriter();
+ final int associationId;
try {
switch (cmd) {
case "list": {
- final int userId = getNextArgInt();
+ final int userId = getNextIntArgRequired();
final List<AssociationInfo> associationsForUser =
mAssociationStore.getAssociationsForUser(userId);
for (AssociationInfo association : associationsForUser) {
@@ -55,7 +61,7 @@ class CompanionDeviceShellCommand extends ShellCommand {
break;
case "associate": {
- int userId = getNextArgInt();
+ int userId = getNextIntArgRequired();
String packageName = getNextArgRequired();
String address = getNextArgRequired();
mService.legacyCreateAssociation(userId, address, packageName, null);
@@ -63,7 +69,7 @@ class CompanionDeviceShellCommand extends ShellCommand {
break;
case "disassociate": {
- final int userId = getNextArgInt();
+ final int userId = getNextIntArgRequired();
final String packageName = getNextArgRequired();
final String address = getNextArgRequired();
final AssociationInfo association =
@@ -80,6 +86,16 @@ class CompanionDeviceShellCommand extends ShellCommand {
}
break;
+ case "simulate-device-appeared":
+ associationId = getNextIntArgRequired();
+ mDevicePresenceMonitor.simulateDeviceAppeared(associationId);
+ break;
+
+ case "simulate-device-disappeared":
+ associationId = getNextIntArgRequired();
+ mDevicePresenceMonitor.simulateDeviceDisappeared(associationId);
+ break;
+
default:
return handleDefaultCommands(cmd);
}
@@ -91,10 +107,6 @@ class CompanionDeviceShellCommand extends ShellCommand {
}
}
- private int getNextArgInt() {
- return Integer.parseInt(getNextArgRequired());
- }
-
@Override
public void onHelp() {
PrintWriter pw = getOutPrintWriter();
@@ -108,7 +120,31 @@ class CompanionDeviceShellCommand extends ShellCommand {
pw.println(" disassociate USER_ID PACKAGE MAC_ADDRESS");
pw.println(" Remove an existing Association.");
pw.println(" clear-association-memory-cache");
- pw.println(" Clear the in-memory association cache and reload all association "
- + "information from persistent storage. USE FOR DEBUGGING PURPOSES ONLY.");
+ pw.println(" Clear the in-memory association cache and reload all association ");
+ pw.println(" information from persistent storage. USE FOR DEBUGGING PURPOSES ONLY.");
+ pw.println(" USE FOR DEBUGGING AND/OR TESTING PURPOSES ONLY.");
+
+ pw.println(" simulate-device-appeared ASSOCIATION_ID");
+ pw.println(" Make CDM act as if the given companion device has appeared.");
+ pw.println(" I.e. bind the associated companion application's");
+ pw.println(" CompanionDeviceService(s) and trigger onDeviceAppeared() callback.");
+ pw.println(" The CDM will consider the devices as present for 60 seconds and then");
+ pw.println(" will act as if device disappeared, unless 'simulate-device-disappeared'");
+ pw.println(" or 'simulate-device-appeared' is called again before 60 seconds run out"
+ + ".");
+ pw.println(" USE FOR DEBUGGING AND/OR TESTING PURPOSES ONLY.");
+
+ pw.println(" simulate-device-disappeared ASSOCIATION_ID");
+ pw.println(" Make CDM act as if the given companion device has disappeared.");
+ pw.println(" I.e. unbind the associated companion application's");
+ pw.println(" CompanionDeviceService(s) and trigger onDeviceDisappeared() callback.");
+ pw.println(" NOTE: This will only have effect if 'simulate-device-appeared' was");
+ pw.println(" invoked for the same device (same ASSOCIATION_ID) no longer than");
+ pw.println(" 60 seconds ago.");
+ pw.println(" USE FOR DEBUGGING AND/OR TESTING PURPOSES ONLY.");
+ }
+
+ private int getNextIntArgRequired() {
+ return Integer.parseInt(getNextArgRequired());
}
}
diff --git a/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java b/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java
index 24be1b6fd701..37e83697c787 100644
--- a/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java
+++ b/services/companion/java/com/android/server/companion/presence/CompanionDevicePresenceMonitor.java
@@ -16,11 +16,19 @@
package com.android.server.companion.presence;
+import static android.os.Process.ROOT_UID;
+import static android.os.Process.SHELL_UID;
+
import android.annotation.NonNull;
import android.annotation.SuppressLint;
+import android.annotation.TestApi;
import android.bluetooth.BluetoothAdapter;
import android.companion.AssociationInfo;
import android.content.Context;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
import android.util.Log;
import com.android.server.companion.AssociationStore;
@@ -72,6 +80,11 @@ public class CompanionDevicePresenceMonitor implements AssociationStore.OnChange
private final @NonNull Set<Integer> mNearbyBleDevices = new HashSet<>();
private final @NonNull Set<Integer> mReportedSelfManagedDevices = new HashSet<>();
+ // Tracking "simulated" presence. Used for debugging and testing only.
+ private final @NonNull Set<Integer> mSimulated = new HashSet<>();
+ private final SimulatedDevicePresenceSchedulerHelper mSchedulerHelper =
+ new SimulatedDevicePresenceSchedulerHelper();
+
public CompanionDevicePresenceMonitor(@NonNull AssociationStore associationStore,
@NonNull Callback callback) {
mAssociationStore = associationStore;
@@ -106,7 +119,8 @@ public class CompanionDevicePresenceMonitor implements AssociationStore.OnChange
public boolean isDevicePresent(int associationId) {
return mReportedSelfManagedDevices.contains(associationId)
|| mConnectedBtDevices.contains(associationId)
- || mNearbyBleDevices.contains(associationId);
+ || mNearbyBleDevices.contains(associationId)
+ || mSimulated.contains(associationId);
}
/**
@@ -155,6 +169,45 @@ public class CompanionDevicePresenceMonitor implements AssociationStore.OnChange
onDeviceGone(mNearbyBleDevices, associationId, /* sourceLoggingTag */ "ble");
}
+ /** FOR DEBUGGING AND/OR TESTING PURPOSES ONLY. */
+ @TestApi
+ public void simulateDeviceAppeared(int associationId) {
+ // IMPORTANT: this API should only be invoked via the
+ // 'companiondevice simulate-device-appeared' Shell command, so the only uid-s allowed to
+ // make this call are SHELL and ROOT.
+ // No other caller (including SYSTEM!) should be allowed.
+ enforceCallerShellOrRoot();
+ // Make sure the association exists.
+ enforceAssociationExists(associationId);
+
+ onDevicePresent(mSimulated, associationId, /* sourceLoggingTag */ "simulated");
+
+ mSchedulerHelper.scheduleOnDeviceGoneCallForSimulatedDevicePresence(associationId);
+ }
+
+ /** FOR DEBUGGING AND/OR TESTING PURPOSES ONLY. */
+ @TestApi
+ public void simulateDeviceDisappeared(int associationId) {
+ // IMPORTANT: this API should only be invoked via the
+ // 'companiondevice simulate-device-appeared' Shell command, so the only uid-s allowed to
+ // make this call are SHELL and ROOT.
+ // No other caller (including SYSTEM!) should be allowed.
+ enforceCallerShellOrRoot();
+ // Make sure the association exists.
+ enforceAssociationExists(associationId);
+
+ mSchedulerHelper.unscheduleOnDeviceGoneCallForSimulatedDevicePresence(associationId);
+
+ onDeviceGone(mSimulated, associationId, /* sourceLoggingTag */ "simulated");
+ }
+
+ private void enforceAssociationExists(int associationId) {
+ if (mAssociationStore.getAssociationById(associationId) == null) {
+ throw new IllegalArgumentException(
+ "Association with id " + associationId + " does not exist.");
+ }
+ }
+
private void onDevicePresent(@NonNull Set<Integer> presentDevicesForSource,
int newDeviceAssociationId, @NonNull String sourceLoggingTag) {
if (DEBUG) {
@@ -212,6 +265,7 @@ public class CompanionDevicePresenceMonitor implements AssociationStore.OnChange
mConnectedBtDevices.remove(associationId);
mNearbyBleDevices.remove(associationId);
mReportedSelfManagedDevices.remove(associationId);
+ mSimulated.remove(associationId);
}
/**
@@ -232,4 +286,36 @@ public class CompanionDevicePresenceMonitor implements AssociationStore.OnChange
// CompanionDeviceManagerService will know that the association is removed, and will do
// what's needed.
}
+
+ private static void enforceCallerShellOrRoot() {
+ final int callingUid = Binder.getCallingUid();
+ if (callingUid == SHELL_UID || callingUid == ROOT_UID) return;
+
+ throw new SecurityException("Caller is neither Shell nor Root");
+ }
+
+ private class SimulatedDevicePresenceSchedulerHelper extends Handler {
+ SimulatedDevicePresenceSchedulerHelper() {
+ super(Looper.getMainLooper());
+ }
+
+ void scheduleOnDeviceGoneCallForSimulatedDevicePresence(int associationId) {
+ // First, unschedule if it was scheduled previously.
+ if (hasMessages(/* what */ associationId)) {
+ removeMessages(/* what */ associationId);
+ }
+
+ sendEmptyMessageDelayed(/* what */ associationId, 60 * 1000 /* 60 seconds */);
+ }
+
+ void unscheduleOnDeviceGoneCallForSimulatedDevicePresence(int associationId) {
+ removeMessages(/* what */ associationId);
+ }
+
+ @Override
+ public void handleMessage(@NonNull Message msg) {
+ final int associationId = msg.what;
+ onDeviceGone(mSimulated, associationId, /* sourceLoggingTag */ "simulated");
+ }
+ }
}
diff --git a/services/core/java/com/android/server/am/AppBatteryTracker.java b/services/core/java/com/android/server/am/AppBatteryTracker.java
index 5a234f5010dd..c09bb2d4dc28 100644
--- a/services/core/java/com/android/server/am/AppBatteryTracker.java
+++ b/services/core/java/com/android/server/am/AppBatteryTracker.java
@@ -67,6 +67,7 @@ import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
+import android.util.SparseLongArray;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
@@ -360,6 +361,7 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
mUidBatteryUsageInWindow.removeAt(i);
}
}
+ mInjector.getPolicy().onUserRemovedLocked(userId);
}
}
@@ -368,6 +370,7 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
synchronized (mLock) {
mUidBatteryUsage.delete(uid);
mUidBatteryUsageInWindow.delete(uid);
+ mInjector.getPolicy().onUidRemovedLocked(uid);
}
}
@@ -1208,6 +1211,14 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_window";
/**
+ * The grace period after an interaction event with the app, if the background current
+ * drain goes beyond the threshold within that period, the system won't apply the
+ * restrictions.
+ */
+ static final String KEY_BG_CURRENT_DRAIN_INTERACTION_GRACE_PERIOD =
+ DEVICE_CONFIG_SUBNAMESPACE_PREFIX + "current_drain_interaction_grace_period";
+
+ /**
* Similar to {@link #KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_RESTRICTED_BUCKET}, but a higher
* value for the legitimate cases with higher background current drain.
*/
@@ -1310,6 +1321,11 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
final long mDefaultBgCurrentDrainWindowMs;
/**
+ * Default value to {@link #mBgCurrentDrainInteractionGracePeriodMs}.
+ */
+ final long mDefaultBgCurrentDrainInteractionGracePeriodMs;
+
+ /**
* Default value to the {@link #INDEX_HIGH_CURRENT_DRAIN_THRESHOLD} of
* the {@link #mBgCurrentDrainRestrictedBucketThreshold}.
*/
@@ -1394,6 +1410,11 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
volatile long mBgCurrentDrainWindowMs;
/**
+ * @see #KEY_BG_CURRENT_DRAIN_INTERACTION_GRACE_PERIOD.
+ */
+ volatile long mBgCurrentDrainInteractionGracePeriodMs;
+
+ /**
* @see #KEY_BG_CURRENT_DRAIN_MEDIA_PLAYBACK_MIN_DURATION.
*/
volatile long mBgCurrentDrainMediaPlaybackMinDuration;
@@ -1455,6 +1476,12 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
private final SparseArray<Pair<long[], ImmutableBatteryUsage[]>> mHighBgBatteryPackages =
new SparseArray<>();
+ /**
+ * The timestamp of the last interaction, key is the UID.
+ */
+ @GuardedBy("mLock")
+ private final SparseLongArray mLastInteractionTime = new SparseLongArray();
+
@NonNull
private final Object mLock;
@@ -1478,6 +1505,7 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
isLowRamDeviceStatic() ? val[1] : val[0];
mDefaultBgCurrentDrainWindowMs = resources.getInteger(
R.integer.config_bg_current_drain_window) * 1_000;
+ mDefaultBgCurrentDrainInteractionGracePeriodMs = mDefaultBgCurrentDrainWindowMs;
val = getFloatArray(resources.obtainTypedArray(
R.array.config_bg_current_drain_high_threshold_to_restricted_bucket));
mDefaultBgCurrentDrainRestrictedBucketHighThreshold =
@@ -1511,6 +1539,8 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
mBgCurrentDrainBgRestrictedThreshold[1] =
mDefaultBgCurrentDrainBgRestrictedHighThreshold;
mBgCurrentDrainWindowMs = mDefaultBgCurrentDrainWindowMs;
+ mBgCurrentDrainInteractionGracePeriodMs =
+ mDefaultBgCurrentDrainInteractionGracePeriodMs;
mBgCurrentDrainMediaPlaybackMinDuration =
mDefaultBgCurrentDrainMediaPlaybackMinDuration;
mBgCurrentDrainLocationMinDuration = mDefaultBgCurrentDrainLocationMinDuration;
@@ -1542,6 +1572,9 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
case KEY_BG_CURRENT_DRAIN_WINDOW:
updateCurrentDrainWindow();
break;
+ case KEY_BG_CURRENT_DRAIN_INTERACTION_GRACE_PERIOD:
+ updateCurrentDrainInteractionGracePeriod();
+ break;
case KEY_BG_CURRENT_DRAIN_MEDIA_PLAYBACK_MIN_DURATION:
updateCurrentDrainMediaPlaybackMinDuration();
break;
@@ -1626,6 +1659,13 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
mDefaultBgCurrentDrainWindowMs);
}
+ private void updateCurrentDrainInteractionGracePeriod() {
+ mBgCurrentDrainInteractionGracePeriodMs = DeviceConfig.getLong(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_BG_CURRENT_DRAIN_INTERACTION_GRACE_PERIOD,
+ mDefaultBgCurrentDrainInteractionGracePeriodMs);
+ }
+
private void updateCurrentDrainMediaPlaybackMinDuration() {
mBgCurrentDrainMediaPlaybackMinDuration = DeviceConfig.getLong(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
@@ -1668,6 +1708,7 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
super.onSystemReady();
updateCurrentDrainThreshold();
updateCurrentDrainWindow();
+ updateCurrentDrainInteractionGracePeriod();
updateCurrentDrainMediaPlaybackMinDuration();
updateCurrentDrainLocationMinDuration();
updateCurrentDrainEventDurationBasedThresholdEnabled();
@@ -1685,8 +1726,10 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
synchronized (mLock) {
final Pair<long[], ImmutableBatteryUsage[]> pair = mHighBgBatteryPackages.get(uid);
if (pair != null) {
+ final long lastInteractionTime = mLastInteractionTime.get(uid, 0L);
final long[] ts = pair.first;
- final int restrictedLevel = ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET] > 0
+ final int restrictedLevel = ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET]
+ > (lastInteractionTime + mBgCurrentDrainInteractionGracePeriodMs)
&& mTracker.mAppRestrictionController.isAutoRestrictAbusiveAppEnabled()
? RESTRICTION_LEVEL_RESTRICTED_BUCKET
: RESTRICTION_LEVEL_ADAPTIVE_BUCKET;
@@ -1777,6 +1820,7 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
// We're already in the background restricted level, nothing more we could do.
return;
}
+ final long lastInteractionTime = mLastInteractionTime.get(uid, 0L);
final long now = SystemClock.elapsedRealtime();
final int thresholdIndex = getCurrentDrainThresholdIndex(uid, now,
mBgCurrentDrainWindowMs);
@@ -1788,13 +1832,17 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
long[] ts = null;
ImmutableBatteryUsage[] usages = null;
if (rbPercentage >= rbThreshold) {
- // New findings to us, track it and let the controller know.
- ts = new long[TIME_STAMP_INDEX_LAST];
- ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET] = now;
- usages = new ImmutableBatteryUsage[TIME_STAMP_INDEX_LAST];
- usages[TIME_STAMP_INDEX_RESTRICTED_BUCKET] = usage;
- mHighBgBatteryPackages.put(uid, Pair.create(ts, usages));
- notifyController = excessive = true;
+ if (now > lastInteractionTime + mBgCurrentDrainInteractionGracePeriodMs) {
+ // New findings to us, track it and let the controller know.
+ ts = new long[TIME_STAMP_INDEX_LAST];
+ ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET] = now;
+ usages = new ImmutableBatteryUsage[TIME_STAMP_INDEX_LAST];
+ usages[TIME_STAMP_INDEX_RESTRICTED_BUCKET] = usage;
+ mHighBgBatteryPackages.put(uid, Pair.create(ts, usages));
+ // It's beeen long enough since last interaction with this app.
+ notifyController = true;
+ }
+ excessive = true;
}
if (decoupleThresholds && brPercentage >= brThreshold) {
if (ts == null) {
@@ -1812,11 +1860,15 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
final long[] ts = pair.first;
final long lastRestrictBucketTs = ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET];
if (rbPercentage >= rbThreshold) {
- if (lastRestrictBucketTs == 0) {
- ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET] = now;
- pair.second[TIME_STAMP_INDEX_RESTRICTED_BUCKET] = usage;
+ if (now > lastInteractionTime + mBgCurrentDrainInteractionGracePeriodMs) {
+ if (lastRestrictBucketTs == 0) {
+ ts[TIME_STAMP_INDEX_RESTRICTED_BUCKET] = now;
+ pair.second[TIME_STAMP_INDEX_RESTRICTED_BUCKET] = usage;
+ }
+ // It's been long enough since last interaction with this app.
+ notifyController = true;
}
- notifyController = excessive = true;
+ excessive = true;
} else {
// It's actually back to normal, but we don't untrack it until
// explicit user interactions, because the restriction could be the cause
@@ -1833,7 +1885,7 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
&& (now > lastRestrictBucketTs + mBgCurrentDrainWindowMs));
if (notifyController) {
ts[TIME_STAMP_INDEX_BG_RESTRICTED] = now;
- pair.second[TIME_STAMP_INDEX_RESTRICTED_BUCKET] = usage;
+ pair.second[TIME_STAMP_INDEX_BG_RESTRICTED] = usage;
}
excessive = true;
} else {
@@ -1841,7 +1893,7 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
// user consent to unrestrict it; or if it's in restricted bucket level,
// resetting this won't lift it from that level.
ts[TIME_STAMP_INDEX_BG_RESTRICTED] = 0;
- pair.second[TIME_STAMP_INDEX_RESTRICTED_BUCKET] = null;
+ pair.second[TIME_STAMP_INDEX_BG_RESTRICTED] = null;
// Now need to notify the controller.
}
}
@@ -1902,6 +1954,7 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
void onUserInteractionStarted(String packageName, int uid) {
boolean changed = false;
synchronized (mLock) {
+ mLastInteractionTime.put(uid, SystemClock.elapsedRealtime());
final int curLevel = mTracker.mAppRestrictionController.getRestrictionLevel(
uid, packageName);
if (curLevel == RESTRICTION_LEVEL_BACKGROUND_RESTRICTED) {
@@ -1940,9 +1993,30 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
@VisibleForTesting
void reset() {
mHighBgBatteryPackages.clear();
+ mLastInteractionTime.clear();
mTracker.reset();
}
+ @GuardedBy("mLock")
+ void onUserRemovedLocked(final @UserIdInt int userId) {
+ for (int i = mHighBgBatteryPackages.size() - 1; i >= 0; i--) {
+ if (UserHandle.getUserId(mHighBgBatteryPackages.keyAt(i)) == userId) {
+ mHighBgBatteryPackages.removeAt(i);
+ }
+ }
+ for (int i = mLastInteractionTime.size() - 1; i >= 0; i--) {
+ if (UserHandle.getUserId(mLastInteractionTime.keyAt(i)) == userId) {
+ mLastInteractionTime.removeAt(i);
+ }
+ }
+ }
+
+ @GuardedBy("mLock")
+ void onUidRemovedLocked(final int uid) {
+ mHighBgBatteryPackages.remove(uid);
+ mLastInteractionTime.delete(uid);
+ }
+
@Override
void dump(PrintWriter pw, String prefix) {
pw.print(prefix);
@@ -1976,6 +2050,10 @@ final class AppBatteryTracker extends BaseAppStateTracker<AppBatteryPolicy>
pw.print('=');
pw.println(mBgCurrentDrainWindowMs);
pw.print(prefix);
+ pw.print(KEY_BG_CURRENT_DRAIN_INTERACTION_GRACE_PERIOD);
+ pw.print('=');
+ pw.println(mBgCurrentDrainInteractionGracePeriodMs);
+ pw.print(prefix);
pw.print(KEY_BG_CURRENT_DRAIN_MEDIA_PLAYBACK_MIN_DURATION);
pw.print('=');
pw.println(mBgCurrentDrainMediaPlaybackMinDuration);
diff --git a/services/core/java/com/android/server/am/DropboxRateLimiter.java b/services/core/java/com/android/server/am/DropboxRateLimiter.java
index 18fb6a480f29..08a6719a016a 100644
--- a/services/core/java/com/android/server/am/DropboxRateLimiter.java
+++ b/services/core/java/com/android/server/am/DropboxRateLimiter.java
@@ -24,9 +24,14 @@ import com.android.internal.annotations.GuardedBy;
/** Rate limiter for adding errors into dropbox. */
public class DropboxRateLimiter {
- private static final long RATE_LIMIT_BUFFER_EXPIRY = 15 * DateUtils.SECOND_IN_MILLIS;
- private static final long RATE_LIMIT_BUFFER_DURATION = 10 * DateUtils.SECOND_IN_MILLIS;
- private static final int RATE_LIMIT_ALLOWED_ENTRIES = 5;
+ // After RATE_LIMIT_ALLOWED_ENTRIES have been collected (for a single breakdown of
+ // process/eventType) further entries will be rejected until RATE_LIMIT_BUFFER_DURATION has
+ // elapsed, after which the current count for this breakdown will be reset.
+ private static final long RATE_LIMIT_BUFFER_DURATION = 10 * DateUtils.MINUTE_IN_MILLIS;
+ // The time duration after which the rate limit buffer will be cleared.
+ private static final long RATE_LIMIT_BUFFER_EXPIRY = 3 * RATE_LIMIT_BUFFER_DURATION;
+ // The number of entries to keep per breakdown of process/eventType.
+ private static final int RATE_LIMIT_ALLOWED_ENTRIES = 6;
@GuardedBy("mErrorClusterRecords")
private final ArrayMap<String, ErrorRecord> mErrorClusterRecords = new ArrayMap<>();
diff --git a/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java b/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java
index db17c1056e39..8180e66166d9 100644
--- a/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java
+++ b/services/core/java/com/android/server/inputmethod/HandwritingEventReceiverSurface.java
@@ -64,7 +64,9 @@ final class HandwritingEventReceiverSurface {
| InputConfig.INTERCEPTS_STYLUS
| InputConfig.TRUSTED_OVERLAY;
- // The touchable region of this input surface is not initially configured.
+ // Configure the surface to receive stylus events across the entire display.
+ mWindowHandle.replaceTouchableRegionWithCrop(null /* use this surface's bounds */);
+
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
t.setInputWindowInfo(mInputSurface, mWindowHandle);
t.setLayer(mInputSurface, HANDWRITING_SURFACE_LAYER);
@@ -81,10 +83,6 @@ final class HandwritingEventReceiverSurface {
mWindowHandle.ownerUid = imeUid;
mWindowHandle.inputConfig &= ~InputConfig.SPY;
- // Update the touchable region so that the IME can intercept stylus events
- // across the entire display.
- mWindowHandle.replaceTouchableRegionWithCrop(null /* use this surface's bounds */);
-
new SurfaceControl.Transaction()
.setInputWindowInfo(mInputSurface, mWindowHandle)
.apply();
diff --git a/services/core/java/com/android/server/inputmethod/HandwritingModeController.java b/services/core/java/com/android/server/inputmethod/HandwritingModeController.java
index a70677222506..f89b6aedf1f5 100644
--- a/services/core/java/com/android/server/inputmethod/HandwritingModeController.java
+++ b/services/core/java/com/android/server/inputmethod/HandwritingModeController.java
@@ -91,7 +91,7 @@ final class HandwritingModeController {
* InputEventReceiver that batches events according to the current thread's Choreographer.
*/
@UiThread
- void initializeHandwritingSpy(int displayId, IBinder focusedWindowToken) {
+ void initializeHandwritingSpy(int displayId) {
// When resetting, reuse resources if we are reinitializing on the same display.
reset(displayId == mCurrentDisplayId);
mCurrentDisplayId = displayId;
@@ -115,12 +115,6 @@ final class HandwritingModeController {
mHandwritingSurface = new HandwritingEventReceiverSurface(
name, displayId, surface, channel);
- // Configure the handwriting window to receive events over the focused window's bounds.
- mWindowManagerInternal.replaceInputSurfaceTouchableRegionWithWindowCrop(
- mHandwritingSurface.getSurface(),
- mHandwritingSurface.getInputWindowHandle(),
- focusedWindowToken);
-
// Use a dup of the input channel so that event processing can be paused by disposing the
// event receiver without causing a fd hangup.
mHandwritingEventReceiver = new BatchedInputEventReceiver.SimpleBatchedInputEventReceiver(
@@ -149,7 +143,8 @@ final class HandwritingModeController {
*/
@UiThread
@Nullable
- HandwritingSession startHandwritingSession(int requestId, int imePid, int imeUid) {
+ HandwritingSession startHandwritingSession(
+ int requestId, int imePid, int imeUid, IBinder focusedWindowToken) {
if (mHandwritingSurface == null) {
Slog.e(TAG, "Cannot start handwriting session: Handwriting was not initialized.");
return null;
@@ -158,12 +153,20 @@ final class HandwritingModeController {
Slog.e(TAG, "Cannot start handwriting session: Invalid request id: " + requestId);
return null;
}
- if (!mRecordingGesture) {
+ if (!mRecordingGesture || mHandwritingBuffer.isEmpty()) {
Slog.e(TAG, "Cannot start handwriting session: No stylus gesture is being recorded.");
return null;
}
Objects.requireNonNull(mHandwritingEventReceiver,
"Handwriting session was already transferred to IME.");
+ final MotionEvent downEvent = mHandwritingBuffer.get(0);
+ assert (downEvent.getActionMasked() == MotionEvent.ACTION_DOWN);
+ if (!mWindowManagerInternal.isPointInsideWindow(
+ focusedWindowToken, mCurrentDisplayId, downEvent.getRawX(), downEvent.getRawY())) {
+ Slog.e(TAG, "Cannot start handwriting session: "
+ + "Stylus gesture did not start inside the focused window.");
+ return null;
+ }
if (DEBUG) Slog.d(TAG, "Starting handwriting session in display: " + mCurrentDisplayId);
mInputManagerInternal.pilferPointers(mHandwritingSurface.getInputChannel().getToken());
@@ -226,13 +229,17 @@ final class HandwritingModeController {
}
if (!(ev instanceof MotionEvent)) {
- Slog.e("Stylus", "Received non-motion event in stylus monitor.");
+ Slog.wtf(TAG, "Received non-motion event in stylus monitor.");
return false;
}
final MotionEvent event = (MotionEvent) ev;
if (!isStylusEvent(event)) {
return false;
}
+ if (event.getDisplayId() != mCurrentDisplayId) {
+ Slog.wtf(TAG, "Received stylus event associated with the incorrect display.");
+ return false;
+ }
onStylusEvent(event);
return true;
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index c759c645a318..ea2b1571c0ae 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -5118,9 +5118,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
case MSG_RESET_HANDWRITING: {
synchronized (ImfLock.class) {
if (mBindingController.supportsStylusHandwriting()
- && getCurMethodLocked() != null && mCurFocusedWindow != null) {
- mHwController.initializeHandwritingSpy(
- mCurTokenDisplayId, mCurFocusedWindow);
+ && getCurMethodLocked() != null) {
+ mHwController.initializeHandwritingSpy(mCurTokenDisplayId);
} else {
mHwController.reset();
}
@@ -5130,14 +5129,15 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
case MSG_START_HANDWRITING:
synchronized (ImfLock.class) {
IInputMethodInvoker curMethod = getCurMethodLocked();
- if (curMethod == null) {
+ if (curMethod == null || mCurFocusedWindow == null) {
return true;
}
final HandwritingModeController.HandwritingSession session =
mHwController.startHandwritingSession(
msg.arg1 /*requestId*/,
msg.arg2 /*pid*/,
- mBindingController.getCurMethodUid());
+ mBindingController.getCurMethodUid(),
+ mCurFocusedWindow);
if (session == null) {
Slog.e(TAG,
"Failed to start handwriting session for requestId: " + msg.arg1);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 83c576e9259d..9042326c5760 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -58,6 +58,7 @@ import static android.content.Context.BIND_AUTO_CREATE;
import static android.content.Context.BIND_FOREGROUND_SERVICE;
import static android.content.Context.BIND_NOT_PERCEPTIBLE;
import static android.content.pm.PackageManager.FEATURE_LEANBACK;
+import static android.content.pm.PackageManager.FEATURE_TELECOM;
import static android.content.pm.PackageManager.FEATURE_TELEVISION;
import static android.content.pm.PackageManager.MATCH_ALL;
import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AWARE;
@@ -655,10 +656,10 @@ public class NotificationManagerService extends SystemService {
private int mWarnRemoteViewsSizeBytes;
private int mStripRemoteViewsSizeBytes;
- final boolean mEnableAppSettingMigration;
private boolean mForceUserSetOnUpgrade;
private MetricsLogger mMetricsLogger;
+ private NotificationChannelLogger mNotificationChannelLogger;
private TriPredicate<String, Integer, String> mAllowedManagedServicePackages;
private final SavePolicyFileRunnable mSavePolicyFile = new SavePolicyFileRunnable();
@@ -1998,12 +1999,6 @@ public class NotificationManagerService extends SystemService {
mNotificationRecordLogger = notificationRecordLogger;
mNotificationInstanceIdSequence = notificationInstanceIdSequence;
Notification.processAllowlistToken = ALLOWLIST_TOKEN;
- // TODO (b/194833441): remove when OS is ready for migration. This flag is checked once
- // rather than having a settings observer because some of the behaviors (e.g. readXml) only
- // happen on reboot
- mEnableAppSettingMigration = Settings.Secure.getIntForUser(
- getContext().getContentResolver(),
- Settings.Secure.NOTIFICATION_PERMISSION_ENABLED, 0, USER_SYSTEM) == 1;
}
// TODO - replace these methods with new fields in the VisibleForTesting constructor
@@ -2161,6 +2156,11 @@ public class NotificationManagerService extends SystemService {
mAccessibilityManager = am;
}
+ @VisibleForTesting
+ void setTelecomManager(TelecomManager tm) {
+ mTelecomManager = tm;
+ }
+
// TODO: All tests should use this init instead of the one-off setters above.
@VisibleForTesting
void init(WorkerHandler handler, RankingHandler rankingHandler,
@@ -2178,7 +2178,7 @@ public class NotificationManagerService extends SystemService {
TelephonyManager telephonyManager, ActivityManagerInternal ami,
MultiRateLimiter toastRateLimiter, PermissionHelper permissionHelper,
UsageStatsManagerInternal usageStatsManagerInternal,
- TelecomManager telecomManager) {
+ TelecomManager telecomManager, NotificationChannelLogger channelLogger) {
mHandler = handler;
Resources resources = getContext().getResources();
mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
@@ -2275,12 +2275,13 @@ public class NotificationManagerService extends SystemService {
}
});
mPermissionHelper = permissionHelper;
+ mNotificationChannelLogger = channelLogger;
mPreferencesHelper = new PreferencesHelper(getContext(),
mPackageManagerClient,
mRankingHandler,
mZenModeHelper,
mPermissionHelper,
- new NotificationChannelLoggerImpl(),
+ mNotificationChannelLogger,
mAppOps,
new SysUiStatsEvent.BuilderFactory());
mRankingHelper = new RankingHelper(getContext(),
@@ -2362,9 +2363,6 @@ public class NotificationManagerService extends SystemService {
mNotificationEffectsEnabledForAutomotive =
resources.getBoolean(R.bool.config_enableServerNotificationEffectsForAutomotive);
- mPreferencesHelper.lockChannelsForOEM(getContext().getResources().getStringArray(
- com.android.internal.R.array.config_nonBlockableNotificationPackages));
-
mZenModeHelper.setPriorityOnlyDndExemptPackages(getContext().getResources().getStringArray(
com.android.internal.R.array.config_priorityOnlyDndExemptPackages));
@@ -2504,10 +2502,11 @@ public class NotificationManagerService extends SystemService {
LocalServices.getService(ActivityManagerInternal.class),
createToastRateLimiter(), new PermissionHelper(LocalServices.getService(
PermissionManagerServiceInternal.class), AppGlobals.getPackageManager(),
- AppGlobals.getPermissionManager(), mEnableAppSettingMigration,
+ AppGlobals.getPermissionManager(),
mForceUserSetOnUpgrade),
LocalServices.getService(UsageStatsManagerInternal.class),
- getContext().getSystemService(TelecomManager.class));
+ getContext().getSystemService(TelecomManager.class),
+ new NotificationChannelLoggerImpl());
publishBinderService(Context.NOTIFICATION_SERVICE, mService, /* allowIsolated= */ false,
DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL);
@@ -2799,7 +2798,7 @@ public class NotificationManagerService extends SystemService {
}
}
- private void updateNotificationChannelInt(String pkg, int uid, NotificationChannel channel,
+ void updateNotificationChannelInt(String pkg, int uid, NotificationChannel channel,
boolean fromListener) {
if (channel.getImportance() == NotificationManager.IMPORTANCE_NONE) {
// cancel
@@ -2821,11 +2820,9 @@ public class NotificationManagerService extends SystemService {
mPreferencesHelper.getNotificationChannel(pkg, uid, channel.getId(), true);
mPreferencesHelper.updateNotificationChannel(pkg, uid, channel, true);
- if (mEnableAppSettingMigration) {
- if (mPreferencesHelper.onlyHasDefaultChannel(pkg, uid)) {
- mPermissionHelper.setNotificationPermission(pkg, UserHandle.getUserId(uid),
- channel.getImportance() != IMPORTANCE_NONE, true);
- }
+ if (mPreferencesHelper.onlyHasDefaultChannel(pkg, uid)) {
+ mPermissionHelper.setNotificationPermission(pkg, UserHandle.getUserId(uid),
+ channel.getImportance() != IMPORTANCE_NONE, true);
}
maybeNotifyChannelOwner(pkg, uid, preUpdate, channel);
@@ -3474,36 +3471,19 @@ public class NotificationManagerService extends SystemService {
@Override
public void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) {
enforceSystemOrSystemUI("setNotificationsEnabledForPackage");
- if (mEnableAppSettingMigration) {
- boolean wasEnabled = mPermissionHelper.hasPermission(uid);
- if (wasEnabled == enabled) {
- return;
- }
- mPermissionHelper.setNotificationPermission(
- pkg, UserHandle.getUserId(uid), enabled, true);
- sendAppBlockStateChangedBroadcast(pkg, uid, !enabled);
- } else {
- synchronized (mNotificationLock) {
- boolean wasEnabled = mPreferencesHelper.getImportance(pkg, uid)
- != NotificationManager.IMPORTANCE_NONE;
-
- if (wasEnabled == enabled) {
- return;
- }
- }
-
- mPreferencesHelper.setEnabled(pkg, uid, enabled);
- // TODO (b/194833441): this is being ignored by app ops now that the permission
- // exists, so send the broadcast manually
- mAppOps.setMode(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg,
- enabled ? MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
-
- sendAppBlockStateChangedBroadcast(pkg, uid, !enabled);
+ boolean wasEnabled = mPermissionHelper.hasPermission(uid);
+ if (wasEnabled == enabled) {
+ return;
}
+ mPermissionHelper.setNotificationPermission(
+ pkg, UserHandle.getUserId(uid), enabled, true);
+ sendAppBlockStateChangedBroadcast(pkg, uid, !enabled);
+
mMetricsLogger.write(new LogMaker(MetricsEvent.ACTION_BAN_APP_NOTES)
.setType(MetricsEvent.TYPE_ACTION)
.setPackageName(pkg)
.setSubtype(enabled ? 1 : 0));
+ mNotificationChannelLogger.logAppNotificationsAllowed(uid, pkg, enabled);
// Now, cancel any outstanding notifications that are part of a just-disabled app
if (!enabled) {
cancelAllNotificationsInt(MY_UID, MY_PID, pkg, null, 0, 0, true,
@@ -3529,8 +3509,6 @@ public class NotificationManagerService extends SystemService {
public void setNotificationsEnabledWithImportanceLockForPackage(
String pkg, int uid, boolean enabled) {
setNotificationsEnabledForPackage(pkg, uid, enabled);
-
- mPreferencesHelper.setAppImportanceLocked(pkg, uid);
}
/**
@@ -3646,14 +3624,10 @@ public class NotificationManagerService extends SystemService {
@Override
public int getPackageImportance(String pkg) {
checkCallerIsSystemOrSameApp(pkg);
- if (mEnableAppSettingMigration) {
- if (mPermissionHelper.hasPermission(Binder.getCallingUid())) {
- return IMPORTANCE_DEFAULT;
- } else {
- return IMPORTANCE_NONE;
- }
+ if (mPermissionHelper.hasPermission(Binder.getCallingUid())) {
+ return IMPORTANCE_DEFAULT;
} else {
- return mPreferencesHelper.getImportance(pkg, Binder.getCallingUid());
+ return IMPORTANCE_NONE;
}
}
@@ -5885,8 +5859,7 @@ public class NotificationManagerService extends SystemService {
NotificationRecord createAutoGroupSummary(int userId, String pkg, String triggeringKey,
boolean needsOngoingFlag) {
NotificationRecord summaryRecord = null;
- boolean isPermissionFixed = mPermissionHelper.isMigrationEnabled()
- ? mPermissionHelper.isPermissionFixed(pkg, userId) : false;
+ boolean isPermissionFixed = mPermissionHelper.isPermissionFixed(pkg, userId);
synchronized (mNotificationLock) {
NotificationRecord notificationRecord = mNotificationsByKey.get(triggeringKey);
if (notificationRecord == null) {
@@ -5895,10 +5868,6 @@ public class NotificationManagerService extends SystemService {
return null;
}
NotificationChannel channel = notificationRecord.getChannel();
- boolean isImportanceFixed = mPermissionHelper.isMigrationEnabled()
- ? isPermissionFixed
- : (channel.isImportanceLockedByOEM()
- || channel.isImportanceLockedByCriticalDeviceFunction());
final StatusBarNotification adjustedSbn = notificationRecord.getSbn();
userId = adjustedSbn.getUser().getIdentifier();
int uid = adjustedSbn.getUid();
@@ -5944,7 +5913,7 @@ public class NotificationManagerService extends SystemService {
System.currentTimeMillis());
summaryRecord = new NotificationRecord(getContext(), summarySbn,
notificationRecord.getChannel());
- summaryRecord.setImportanceFixed(isImportanceFixed);
+ summaryRecord.setImportanceFixed(isPermissionFixed);
summaryRecord.setIsAppImportanceLocked(
notificationRecord.getIsAppImportanceLocked());
summaries.put(pkg, summarySbn.getKey());
@@ -5992,10 +5961,6 @@ public class NotificationManagerService extends SystemService {
@VisibleForTesting
protected ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>>
getAllUsersNotificationPermissions() {
- // don't bother if migration is not enabled
- if (!mEnableAppSettingMigration) {
- return null;
- }
ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> allPermissions = new ArrayMap<>();
final List<UserInfo> allUsers = mUm.getUsers();
// for each of these, get the package notification permissions that are associated
@@ -6509,13 +6474,8 @@ public class NotificationManagerService extends SystemService {
+ ", notificationUid=" + notificationUid
+ ", notification=" + notification;
Slog.e(TAG, noChannelStr);
- boolean appNotificationsOff;
- if (mEnableAppSettingMigration) {
- appNotificationsOff = !mPermissionHelper.hasPermission(notificationUid);
- } else {
- appNotificationsOff = mPreferencesHelper.getImportance(pkg, notificationUid)
- == NotificationManager.IMPORTANCE_NONE;
- }
+ boolean appNotificationsOff = !mPermissionHelper.hasPermission(notificationUid);
+
if (!appNotificationsOff) {
doChannelWarningToast(notificationUid,
@@ -6527,14 +6487,11 @@ public class NotificationManagerService extends SystemService {
}
final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
- r.setIsAppImportanceLocked(mPreferencesHelper.getIsAppImportanceLocked(pkg, callingUid));
+ r.setIsAppImportanceLocked(mPermissionHelper.isPermissionUserSet(pkg, userId));
r.setPostSilently(postSilently);
r.setFlagBubbleRemoved(false);
r.setPkgAllowedAsConvo(mMsgPkgsAllowedAsConvos.contains(pkg));
- boolean isImportanceFixed = mPermissionHelper.isMigrationEnabled()
- ? mPermissionHelper.isPermissionFixed(pkg, userId)
- : (channel.isImportanceLockedByOEM()
- || channel.isImportanceLockedByCriticalDeviceFunction());
+ boolean isImportanceFixed = mPermissionHelper.isPermissionFixed(pkg, userId);
r.setImportanceFixed(isImportanceFixed);
if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
@@ -6978,19 +6935,20 @@ public class NotificationManagerService extends SystemService {
private boolean isCallNotification(String pkg, int uid) {
final long identity = Binder.clearCallingIdentity();
try {
- return mTelecomManager.isInManagedCall() || mTelecomManager.isInSelfManagedCall(
- pkg, UserHandle.getUserHandleForUid(uid));
+ if (mPackageManagerClient.hasSystemFeature(FEATURE_TELECOM)
+ && mTelecomManager != null) {
+ return mTelecomManager.isInManagedCall()
+ || mTelecomManager.isInSelfManagedCall(
+ pkg, UserHandle.getUserHandleForUid(uid));
+ }
+ return false;
} finally {
Binder.restoreCallingIdentity(identity);
}
}
private boolean areNotificationsEnabledForPackageInt(String pkg, int uid) {
- if (mEnableAppSettingMigration) {
- return mPermissionHelper.hasPermission(uid);
- } else {
- return mPreferencesHelper.getImportance(pkg, uid) != IMPORTANCE_NONE;
- }
+ return mPermissionHelper.hasPermission(uid);
}
protected int getNotificationCount(String pkg, int userId, int excludedId,
@@ -7405,6 +7363,7 @@ public class NotificationManagerService extends SystemService {
@Override
public void run() {
boolean appBanned = !areNotificationsEnabledForPackageInt(pkg, uid);
+ boolean isCallNotification = isCallNotification(pkg, uid);
synchronized (mNotificationLock) {
try {
NotificationRecord r = null;
@@ -7423,8 +7382,10 @@ public class NotificationManagerService extends SystemService {
final StatusBarNotification n = r.getSbn();
final Notification notification = n.getNotification();
+ boolean isCallNotificationAndCorrectStyle = isCallNotification
+ && notification.isStyle(Notification.CallStyle.class);
- if (!notification.isMediaNotification()
+ if (!(notification.isMediaNotification() || isCallNotificationAndCorrectStyle)
&& (appBanned || isRecordBlockedLocked(r))) {
mUsageStats.registerBlocked(r);
if (DBG) {
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index f979343248f1..cbaf485c077f 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -1089,7 +1089,7 @@ public final class NotificationRecord {
}
/**
- * @see PreferencesHelper#getIsAppImportanceLocked(String, int)
+ * @see PermissionHelper#isPermissionUserSet(String, int)
*/
public boolean getIsAppImportanceLocked() {
return mIsAppImportanceLocked;
diff --git a/services/core/java/com/android/server/notification/PermissionHelper.java b/services/core/java/com/android/server/notification/PermissionHelper.java
index b4230c11bcab..b2fee1e8b545 100644
--- a/services/core/java/com/android/server/notification/PermissionHelper.java
+++ b/services/core/java/com/android/server/notification/PermissionHelper.java
@@ -55,30 +55,21 @@ public final class PermissionHelper {
private final PermissionManagerServiceInternal mPmi;
private final IPackageManager mPackageManager;
private final IPermissionManager mPermManager;
- // TODO (b/194833441): Remove when the migration is enabled
- private final boolean mMigrationEnabled;
private final boolean mForceUserSetOnUpgrade;
public PermissionHelper(PermissionManagerServiceInternal pmi, IPackageManager packageManager,
- IPermissionManager permManager, boolean migrationEnabled,
- boolean forceUserSetOnUpgrade) {
+ IPermissionManager permManager, boolean forceUserSetOnUpgrade) {
mPmi = pmi;
mPackageManager = packageManager;
mPermManager = permManager;
- mMigrationEnabled = migrationEnabled;
mForceUserSetOnUpgrade = forceUserSetOnUpgrade;
}
- public boolean isMigrationEnabled() {
- return mMigrationEnabled;
- }
-
/**
* Returns whether the given uid holds the notification permission. Must not be called
* with a lock held.
*/
public boolean hasPermission(int uid) {
- assertFlag();
final long callingId = Binder.clearCallingIdentity();
try {
return mPmi.checkPostNotificationsPermissionGrantedOrLegacyAccess(uid)
@@ -93,7 +84,6 @@ public final class PermissionHelper {
* Must not be called with a lock held. Format: uid, packageName
*/
Set<Pair<Integer, String>> getAppsRequestingPermission(int userId) {
- assertFlag();
Set<Pair<Integer, String>> requested = new HashSet<>();
List<PackageInfo> pkgs = getInstalledPackages(userId);
for (PackageInfo pi : pkgs) {
@@ -131,7 +121,6 @@ public final class PermissionHelper {
* with a lock held. Format: uid, packageName.
*/
Set<Pair<Integer, String>> getAppsGrantedPermission(int userId) {
- assertFlag();
Set<Pair<Integer, String>> granted = new HashSet<>();
ParceledListSlice<PackageInfo> parceledList = null;
try {
@@ -153,7 +142,6 @@ public final class PermissionHelper {
public @NonNull
ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>>
getNotificationPermissionValues(int userId) {
- assertFlag();
ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> notifPermissions = new ArrayMap<>();
Set<Pair<Integer, String>> allRequestingUids = getAppsRequestingPermission(userId);
Set<Pair<Integer, String>> allApprovedUids = getAppsGrantedPermission(userId);
@@ -180,7 +168,6 @@ public final class PermissionHelper {
*/
public void setNotificationPermission(String packageName, @UserIdInt int userId, boolean grant,
boolean userSet, boolean reviewRequired) {
- assertFlag();
final long callingId = Binder.clearCallingIdentity();
try {
// Do not change the permission if the package doesn't request it, do not change fixed
@@ -221,7 +208,6 @@ public final class PermissionHelper {
* restoring a pre-T backup on a T+ device
*/
public void setNotificationPermission(PackagePermission pkgPerm) {
- assertFlag();
if (pkgPerm == null || pkgPerm.packageName == null) {
return;
}
@@ -233,7 +219,6 @@ public final class PermissionHelper {
}
public boolean isPermissionFixed(String packageName, @UserIdInt int userId) {
- assertFlag();
final long callingId = Binder.clearCallingIdentity();
try {
try {
@@ -251,7 +236,6 @@ public final class PermissionHelper {
}
boolean isPermissionUserSet(String packageName, @UserIdInt int userId) {
- assertFlag();
final long callingId = Binder.clearCallingIdentity();
try {
try {
@@ -269,7 +253,6 @@ public final class PermissionHelper {
}
boolean isPermissionGrantedByDefaultOrRole(String packageName, @UserIdInt int userId) {
- assertFlag();
final long callingId = Binder.clearCallingIdentity();
try {
try {
@@ -288,7 +271,6 @@ public final class PermissionHelper {
private boolean packageRequestsNotificationPermission(String packageName,
@UserIdInt int userId) {
- assertFlag();
try {
String[] permissions = mPackageManager.getPackageInfo(packageName, GET_PERMISSIONS,
userId).requestedPermissions;
@@ -299,12 +281,6 @@ public final class PermissionHelper {
return false;
}
- private void assertFlag() {
- if (!mMigrationEnabled) {
- throw new IllegalStateException("Method called without checking flag value");
- }
- }
-
public static class PackagePermission {
public final String packageName;
public final @UserIdInt int userId;
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index ef3c770f125b..4e3fbaa18870 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -209,11 +209,7 @@ public class PreferencesHelper implements RankingConfig {
mAppOps = appOpsManager;
mStatsEventBuilderFactory = statsEventBuilderFactory;
- if (mPermissionHelper.isMigrationEnabled()) {
- XML_VERSION = 4;
- } else {
- XML_VERSION = 2;
- }
+ XML_VERSION = 4;
updateBadgingEnabled();
updateBubblesEnabled();
@@ -230,8 +226,7 @@ public class PreferencesHelper implements RankingConfig {
final int xmlVersion = parser.getAttributeInt(null, ATT_VERSION, -1);
boolean upgradeForBubbles = xmlVersion == XML_VERSION_BUBBLES_UPGRADE;
- boolean migrateToPermission = (xmlVersion < XML_VERSION_NOTIF_PERMISSION)
- && mPermissionHelper.isMigrationEnabled();
+ boolean migrateToPermission = (xmlVersion < XML_VERSION_NOTIF_PERMISSION);
if (xmlVersion < XML_VERSION_REVIEW_PERMISSIONS_NOTIFICATION) {
// make a note that we should show the notification at some point.
// it shouldn't be possible for the user to already have seen it, as the XML version
@@ -393,8 +388,6 @@ public class PreferencesHelper implements RankingConfig {
hasUserConfiguredSettings(r));
pkgPerms.add(pkgPerm);
}
- } else if (!mPermissionHelper.isMigrationEnabled()) {
- r.importance = appImportance;
}
} catch (Exception e) {
Slog.w(TAG, "Failed to restore pkg", e);
@@ -417,16 +410,8 @@ public class PreferencesHelper implements RankingConfig {
} else {
channel.populateFromXml(parser);
}
- if (!mPermissionHelper.isMigrationEnabled()) {
- channel.setImportanceLockedByCriticalDeviceFunction(
- r.defaultAppLockedImportance);
- channel.setImportanceLockedByOEM(r.oemLockedImportance);
- if (!channel.isImportanceLockedByOEM()) {
- if (r.oemLockedChannels.contains(channel.getId())) {
- channel.setImportanceLockedByOEM(true);
- }
- }
- }
+ channel.setImportanceLockedByCriticalDeviceFunction(
+ r.defaultAppLockedImportance);
if (isShortcutOk(channel) && isDeletionOk(channel)) {
r.channels.put(id, channel);
@@ -604,7 +589,7 @@ public class PreferencesHelper implements RankingConfig {
out.endTag(null, TAG_STATUS_ICONS);
}
ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> notifPermissions = new ArrayMap<>();
- if (mPermissionHelper.isMigrationEnabled() && forBackup) {
+ if (forBackup) {
notifPermissions = mPermissionHelper.getNotificationPermissionValues(userId);
}
@@ -736,28 +721,6 @@ public class PreferencesHelper implements RankingConfig {
}
}
- /**
- * Gets importance.
- */
- @Override
- public int getImportance(String packageName, int uid) {
- synchronized (mPackagePreferences) {
- return getOrCreatePackagePreferencesLocked(packageName, uid).importance;
- }
- }
-
- /**
- * Returns whether the importance of the corresponding notification is user-locked and shouldn't
- * be adjusted by an assistant (via means of a blocking helper, for example). For the channel
- * locking field, see {@link NotificationChannel#USER_LOCKED_IMPORTANCE}.
- */
- public boolean getIsAppImportanceLocked(String packageName, int uid) {
- synchronized (mPackagePreferences) {
- int userLockedFields = getOrCreatePackagePreferencesLocked(packageName, uid).lockedAppFields;
- return (userLockedFields & LockableAppFields.USER_LOCKED_IMPORTANCE) != 0;
- }
- }
-
@Override
public boolean canShowBadge(String packageName, int uid) {
synchronized (mPackagePreferences) {
@@ -1043,16 +1006,10 @@ public class PreferencesHelper implements RankingConfig {
: NotificationChannel.DEFAULT_ALLOW_BUBBLE);
}
clearLockedFieldsLocked(channel);
- if (!mPermissionHelper.isMigrationEnabled()) {
- channel.setImportanceLockedByOEM(r.oemLockedImportance);
- if (!channel.isImportanceLockedByOEM()) {
- if (r.oemLockedChannels.contains(channel.getId())) {
- channel.setImportanceLockedByOEM(true);
- }
- }
- channel.setImportanceLockedByCriticalDeviceFunction(
- r.defaultAppLockedImportance);
- }
+
+ channel.setImportanceLockedByCriticalDeviceFunction(
+ r.defaultAppLockedImportance);
+
if (channel.getLockscreenVisibility() == Notification.VISIBILITY_PUBLIC) {
channel.setLockscreenVisibility(
NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE);
@@ -1133,33 +1090,15 @@ public class PreferencesHelper implements RankingConfig {
updatedChannel.unlockFields(updatedChannel.getUserLockedFields());
}
- if (mPermissionHelper.isMigrationEnabled()) {
- if (mPermissionHelper.isPermissionFixed(r.pkg, UserHandle.getUserId(r.uid))
- && !(channel.isBlockable() || channel.getImportance() == IMPORTANCE_NONE)) {
- updatedChannel.setImportance(channel.getImportance());
- }
- } else {
- // no importance updates are allowed if OEM blocked it
- updatedChannel.setImportanceLockedByOEM(channel.isImportanceLockedByOEM());
- if (updatedChannel.isImportanceLockedByOEM()) {
- updatedChannel.setImportance(channel.getImportance());
- }
- updatedChannel.setImportanceLockedByCriticalDeviceFunction(
- r.defaultAppLockedImportance);
- if (updatedChannel.isImportanceLockedByCriticalDeviceFunction()
- && updatedChannel.getImportance() == IMPORTANCE_NONE) {
- updatedChannel.setImportance(channel.getImportance());
- }
+ if ((mPermissionHelper.isPermissionFixed(r.pkg, UserHandle.getUserId(r.uid))
+ || channel.isImportanceLockedByCriticalDeviceFunction())
+ && !(channel.isBlockable() || channel.getImportance() == IMPORTANCE_NONE)) {
+ updatedChannel.setImportance(channel.getImportance());
}
r.channels.put(updatedChannel.getId(), updatedChannel);
if (onlyHasDefaultChannel(pkg, uid)) {
- if (!mPermissionHelper.isMigrationEnabled()) {
- // copy settings to app level so they are inherited by new channels
- // when the app migrates
- r.importance = updatedChannel.getImportance();
- }
r.priority = updatedChannel.canBypassDnd()
? Notification.PRIORITY_MAX : Notification.PRIORITY_DEFAULT;
r.visibility = updatedChannel.getLockscreenVisibility();
@@ -1328,61 +1267,8 @@ public class PreferencesHelper implements RankingConfig {
mHideSilentStatusBarIcons = hide;
}
- public void lockChannelsForOEM(String[] appOrChannelList) {
- if (mPermissionHelper.isMigrationEnabled()) {
- return;
- }
- if (appOrChannelList == null) {
- return;
- }
- for (String appOrChannel : appOrChannelList) {
- if (!TextUtils.isEmpty(appOrChannel)) {
- String[] appSplit = appOrChannel.split(NON_BLOCKABLE_CHANNEL_DELIM);
- if (appSplit != null && appSplit.length > 0) {
- String appName = appSplit[0];
- String channelId = appSplit.length == 2 ? appSplit[1] : null;
-
- synchronized (mPackagePreferences) {
- boolean foundApp = false;
- for (PackagePreferences r : mPackagePreferences.values()) {
- if (r.pkg.equals(appName)) {
- foundApp = true;
- if (channelId == null) {
- // lock all channels for the app
- r.oemLockedImportance = true;
- for (NotificationChannel channel : r.channels.values()) {
- channel.setImportanceLockedByOEM(true);
- }
- } else {
- NotificationChannel channel = r.channels.get(channelId);
- if (channel != null) {
- channel.setImportanceLockedByOEM(true);
- }
- // Also store the locked channels on the record, so they aren't
- // temporarily lost when data is cleared on the package
- r.oemLockedChannels.add(channelId);
- }
- }
- }
- if (!foundApp) {
- List<String> channels =
- mOemLockedApps.getOrDefault(appName, new ArrayList<>());
- if (channelId != null) {
- channels.add(channelId);
- }
- mOemLockedApps.put(appName, channels);
- }
- }
- }
- }
- }
- }
-
public void updateDefaultApps(int userId, ArraySet<String> toRemove,
ArraySet<Pair<String, Integer>> toAdd) {
- if (mPermissionHelper.isMigrationEnabled()) {
- return;
- }
synchronized (mPackagePreferences) {
for (PackagePreferences p : mPackagePreferences.values()) {
if (userId == UserHandle.getUserId(p.uid)) {
@@ -1802,20 +1688,8 @@ public class PreferencesHelper implements RankingConfig {
}
for (int i = candidatePkgs.size() - 1; i >= 0; i--) {
Pair<String, Integer> app = candidatePkgs.valueAt(i);
- if (mPermissionHelper.isMigrationEnabled()) {
- if (!mPermissionHelper.hasPermission(app.second)) {
- candidatePkgs.removeAt(i);
- }
- } else {
- synchronized (mPackagePreferences) {
- PackagePreferences r = getPackagePreferencesLocked(app.first, app.second);
- if (r == null) {
- continue;
- }
- if (r.importance == IMPORTANCE_NONE) {
- candidatePkgs.removeAt(i);
- }
- }
+ if (!mPermissionHelper.hasPermission(app.second)) {
+ candidatePkgs.removeAt(i);
}
}
boolean haveBypassingApps = candidatePkgs.size() > 0;
@@ -1861,27 +1735,6 @@ public class PreferencesHelper implements RankingConfig {
}
/**
- * Sets importance.
- */
- @Override
- public void setImportance(String pkgName, int uid, int importance) {
- synchronized (mPackagePreferences) {
- getOrCreatePackagePreferencesLocked(pkgName, uid).importance = importance;
- }
- updateConfig();
- }
-
- public void setEnabled(String packageName, int uid, boolean enabled) {
- boolean wasEnabled = getImportance(packageName, uid) != IMPORTANCE_NONE;
- if (wasEnabled == enabled) {
- return;
- }
- setImportance(packageName, uid,
- enabled ? DEFAULT_IMPORTANCE : IMPORTANCE_NONE);
- mNotificationChannelLogger.logAppNotificationsAllowed(uid, packageName, enabled);
- }
-
- /**
* Sets whether any notifications from the app, represented by the given {@code pkgName} and
* {@code uid}, have their importance locked by the user. Locked notifications don't get
* considered for sentiment adjustments (and thus never show a blocking helper).
@@ -2055,23 +1908,15 @@ public class PreferencesHelper implements RankingConfig {
pw.print(" (");
pw.print(r.uid == UNKNOWN_UID ? "UNKNOWN_UID" : Integer.toString(r.uid));
pw.print(')');
- if (!mPermissionHelper.isMigrationEnabled()) {
- if (r.importance != DEFAULT_IMPORTANCE) {
- pw.print(" importance=");
- pw.print(NotificationListenerService.Ranking.importanceToString(
- r.importance));
- }
- } else {
- Pair<Integer, String> key = new Pair<>(r.uid, r.pkg);
- if (packagePermissions != null && pkgsWithPermissionsToHandle.contains(key)) {
- pw.print(" importance=");
- pw.print(NotificationListenerService.Ranking.importanceToString(
- packagePermissions.get(key).first
- ? IMPORTANCE_DEFAULT : IMPORTANCE_NONE));
- pw.print(" userSet=");
- pw.print(packagePermissions.get(key).second);
- pkgsWithPermissionsToHandle.remove(key);
- }
+ Pair<Integer, String> key = new Pair<>(r.uid, r.pkg);
+ if (packagePermissions != null && pkgsWithPermissionsToHandle.contains(key)) {
+ pw.print(" importance=");
+ pw.print(NotificationListenerService.Ranking.importanceToString(
+ packagePermissions.get(key).first
+ ? IMPORTANCE_DEFAULT : IMPORTANCE_NONE));
+ pw.print(" userSet=");
+ pw.print(packagePermissions.get(key).second);
+ pkgsWithPermissionsToHandle.remove(key);
}
if (r.priority != DEFAULT_PRIORITY) {
pw.print(" priority=");
@@ -2111,7 +1956,7 @@ public class PreferencesHelper implements RankingConfig {
}
}
// Handle any remaining packages with permissions
- if (mPermissionHelper.isMigrationEnabled() && pkgsWithPermissionsToHandle != null) {
+ if (pkgsWithPermissionsToHandle != null) {
for (Pair<Integer, String> p : pkgsWithPermissionsToHandle) {
// p.first is the uid of this package; p.second is the package name
if (filter.matches(p.second)) {
@@ -2151,16 +1996,12 @@ public class PreferencesHelper implements RankingConfig {
proto.write(RankingHelperProto.RecordProto.PACKAGE, r.pkg);
proto.write(RankingHelperProto.RecordProto.UID, r.uid);
- if (mPermissionHelper.isMigrationEnabled()) {
- Pair<Integer, String> key = new Pair<>(r.uid, r.pkg);
- if (packagePermissions != null && pkgsWithPermissionsToHandle.contains(key)) {
- proto.write(RankingHelperProto.RecordProto.IMPORTANCE,
- packagePermissions.get(key).first
- ? IMPORTANCE_DEFAULT : IMPORTANCE_NONE);
- pkgsWithPermissionsToHandle.remove(key);
- }
- } else {
- proto.write(RankingHelperProto.RecordProto.IMPORTANCE, r.importance);
+ Pair<Integer, String> key = new Pair<>(r.uid, r.pkg);
+ if (packagePermissions != null && pkgsWithPermissionsToHandle.contains(key)) {
+ proto.write(RankingHelperProto.RecordProto.IMPORTANCE,
+ packagePermissions.get(key).first
+ ? IMPORTANCE_DEFAULT : IMPORTANCE_NONE);
+ pkgsWithPermissionsToHandle.remove(key);
}
proto.write(RankingHelperProto.RecordProto.PRIORITY, r.priority);
proto.write(RankingHelperProto.RecordProto.VISIBILITY, r.visibility);
@@ -2177,7 +2018,7 @@ public class PreferencesHelper implements RankingConfig {
}
}
- if (mPermissionHelper.isMigrationEnabled() && pkgsWithPermissionsToHandle != null) {
+ if (pkgsWithPermissionsToHandle != null) {
for (Pair<Integer, String> p : pkgsWithPermissionsToHandle) {
if (filter.matches(p.second)) {
fToken = proto.start(fieldId);
@@ -2217,25 +2058,22 @@ public class PreferencesHelper implements RankingConfig {
// collect whether this package's importance info was user-set for later, if needed
// before the migration is enabled, this will simply default to false in all cases.
boolean importanceIsUserSet = false;
- if (mPermissionHelper.isMigrationEnabled()) {
- // Even if this package's data is not present, we need to write something;
- // so default to IMPORTANCE_NONE, since if PM doesn't know about the package
- // for some reason, notifications are not allowed.
- int importance = IMPORTANCE_NONE;
- Pair<Integer, String> key = new Pair<>(r.uid, r.pkg);
- if (pkgPermissions != null && pkgsWithPermissionsToHandle.contains(key)) {
- Pair<Boolean, Boolean> permissionPair = pkgPermissions.get(key);
- importance = permissionPair.first
- ? IMPORTANCE_DEFAULT : IMPORTANCE_NONE;
- // cache the second value for writing later
- importanceIsUserSet = permissionPair.second;
-
- pkgsWithPermissionsToHandle.remove(key);
- }
- event.writeInt(importance);
- } else {
- event.writeInt(r.importance);
- }
+ // Even if this package's data is not present, we need to write something;
+ // so default to IMPORTANCE_NONE, since if PM doesn't know about the package
+ // for some reason, notifications are not allowed.
+ int importance = IMPORTANCE_NONE;
+ Pair<Integer, String> key = new Pair<>(r.uid, r.pkg);
+ if (pkgPermissions != null && pkgsWithPermissionsToHandle.contains(key)) {
+ Pair<Boolean, Boolean> permissionPair = pkgPermissions.get(key);
+ importance = permissionPair.first
+ ? IMPORTANCE_DEFAULT : IMPORTANCE_NONE;
+ // cache the second value for writing later
+ importanceIsUserSet = permissionPair.second;
+
+ pkgsWithPermissionsToHandle.remove(key);
+ }
+ event.writeInt(importance);
+
event.writeInt(r.visibility);
event.writeInt(r.lockedAppFields);
event.writeBoolean(importanceIsUserSet); // optional bool user_set_importance = 5;
@@ -2244,7 +2082,7 @@ public class PreferencesHelper implements RankingConfig {
}
// handle remaining packages with PackageManager permissions but not local settings
- if (mPermissionHelper.isMigrationEnabled() && pkgPermissions != null) {
+ if (pkgPermissions != null) {
for (Pair<Integer, String> p : pkgsWithPermissionsToHandle) {
if (pulledEvents > NOTIFICATION_PREFERENCES_PULL_LIMIT) {
break;
@@ -2357,22 +2195,14 @@ public class PreferencesHelper implements RankingConfig {
try {
PackagePreferences.put("userId", UserHandle.getUserId(r.uid));
PackagePreferences.put("packageName", r.pkg);
- if (mPermissionHelper.isMigrationEnabled()) {
- Pair<Integer, String> key = new Pair<>(r.uid, r.pkg);
- if (pkgPermissions != null
- && pkgsWithPermissionsToHandle.contains(key)) {
- PackagePreferences.put("importance",
- NotificationListenerService.Ranking.importanceToString(
- pkgPermissions.get(key).first
- ? IMPORTANCE_DEFAULT : IMPORTANCE_NONE));
- pkgsWithPermissionsToHandle.remove(key);
- }
- } else {
- if (r.importance != DEFAULT_IMPORTANCE) {
- PackagePreferences.put("importance",
- NotificationListenerService.Ranking.importanceToString(
- r.importance));
- }
+ Pair<Integer, String> key = new Pair<>(r.uid, r.pkg);
+ if (pkgPermissions != null
+ && pkgsWithPermissionsToHandle.contains(key)) {
+ PackagePreferences.put("importance",
+ NotificationListenerService.Ranking.importanceToString(
+ pkgPermissions.get(key).first
+ ? IMPORTANCE_DEFAULT : IMPORTANCE_NONE));
+ pkgsWithPermissionsToHandle.remove(key);
}
if (r.priority != DEFAULT_PRIORITY) {
PackagePreferences.put("priority",
@@ -2404,7 +2234,7 @@ public class PreferencesHelper implements RankingConfig {
}
// handle packages for which there are permissions but no local settings
- if (mPermissionHelper.isMigrationEnabled() && pkgsWithPermissionsToHandle != null) {
+ if (pkgsWithPermissionsToHandle != null) {
for (Pair<Integer, String> p : pkgsWithPermissionsToHandle) {
if (filter == null || filter.matches(p.second)) {
JSONObject PackagePreferences = new JSONObject();
@@ -2443,8 +2273,7 @@ public class PreferencesHelper implements RankingConfig {
public JSONArray dumpBansJson(NotificationManagerService.DumpFilter filter,
ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> pkgPermissions) {
JSONArray bans = new JSONArray();
- Map<Integer, String> packageBans = mPermissionHelper.isMigrationEnabled()
- ? getPermissionBasedPackageBans(pkgPermissions) : getPackageBans();
+ Map<Integer, String> packageBans = getPermissionBasedPackageBans(pkgPermissions);
for (Map.Entry<Integer, String> ban : packageBans.entrySet()) {
final int userId = UserHandle.getUserId(ban.getKey());
final String packageName = ban.getValue();
@@ -2597,7 +2426,7 @@ public class PreferencesHelper implements RankingConfig {
synchronized (mPackagePreferences) {
mPackagePreferences.put(packagePreferencesKey(r.pkg, r.uid), r);
}
- if (mPermissionHelper.isMigrationEnabled() && r.migrateToPm) {
+ if (r.migrateToPm) {
try {
PackagePermission p = new PackagePermission(
r.pkg, UserHandle.getUserId(r.uid),
diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java
index 398259333e16..3e9d90c440b6 100644
--- a/services/core/java/com/android/server/notification/RankingConfig.java
+++ b/services/core/java/com/android/server/notification/RankingConfig.java
@@ -24,8 +24,6 @@ import java.util.Collection;
public interface RankingConfig {
- void setImportance(String packageName, int uid, int importance);
- int getImportance(String packageName, int uid);
void setShowBadge(String packageName, int uid, boolean showBadge);
boolean canShowBadge(String packageName, int uid);
boolean badgingEnabled(UserHandle userHandle);
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 320b06f6dc3e..32f0f109821d 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -119,7 +119,7 @@ public class Installer extends SystemService {
IInstalld.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES;
private final boolean mIsolated;
-
+ private volatile boolean mDeferSetFirstBoot;
private volatile IInstalld mInstalld;
private volatile Object mWarnIfHeld;
@@ -171,6 +171,7 @@ public class Installer extends SystemService {
mInstalld = IInstalld.Stub.asInterface(binder);
try {
invalidateMounts();
+ executeDeferredActions();
} catch (InstallerException ignored) {
}
} else {
@@ -180,6 +181,15 @@ public class Installer extends SystemService {
}
/**
+ * Perform any deferred actions on mInstalld while the connection could not be made.
+ */
+ private void executeDeferredActions() throws InstallerException {
+ if (mDeferSetFirstBoot) {
+ setFirstBoot();
+ }
+ }
+
+ /**
* Do several pre-flight checks before making a remote call.
*
* @return if the remote call should continue.
@@ -291,8 +301,15 @@ public class Installer extends SystemService {
return;
}
try {
- mInstalld.setFirstBoot();
- } catch (RemoteException e) {
+ // mInstalld might be null if the connection could not be established.
+ if (mInstalld != null) {
+ mInstalld.setFirstBoot();
+ } else {
+ // if it is null while trying to set the first boot, set a flag to try and set the
+ // first boot when the connection is eventually established
+ mDeferSetFirstBoot = true;
+ }
+ } catch (Exception e) {
throw InstallerException.from(e);
}
}
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
index e1ff9ead6740..6ee9c66e328a 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
@@ -392,6 +392,9 @@ public class ParsingPackageUtils {
if ((flags & PARSE_FRAMEWORK_RES_SPLITS) != 0) {
liteParseFlags = flags;
}
+ if ((flags & PARSE_APK_IN_APEX) != 0) {
+ liteParseFlags |= PARSE_APK_IN_APEX;
+ }
final ParseResult<PackageLite> liteResult =
ApkLiteParseUtils.parseClusterPackageLite(input, packageDir, frameworkSplits,
liteParseFlags);
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 7ba1cadc5c8b..977f79f6175d 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -1453,16 +1453,6 @@ public final class PermissionPolicyService extends SystemService {
}
}
- try {
- if (Settings.Secure.getIntForUser(mContext.getContentResolver(),
- Settings.Secure.NOTIFICATION_PERMISSION_ENABLED, UserHandle.USER_SYSTEM)
- == 0) {
- return false;
- }
- } catch (Settings.SettingNotFoundException e) {
- return false;
- }
-
if (!pkg.getRequestedPermissions().contains(POST_NOTIFICATIONS)
|| CompatChanges.isChangeEnabled(NOTIFICATION_PERM_CHANGE_ID, pkgName, user)
|| mKeyguardManager.isKeyguardLocked()) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index b14214189833..d8e7fbe8b296 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -27,7 +27,6 @@ import static android.content.pm.PackageManager.FEATURE_LEANBACK;
import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
import static android.content.pm.PackageManager.FEATURE_WATCH;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.os.BatteryManager.BATTERY_PLUGGED_WIRELESS;
import static android.os.Build.VERSION_CODES.M;
import static android.os.Build.VERSION_CODES.O;
import static android.provider.Settings.Secure.VOLUME_HUSH_OFF;
@@ -130,7 +129,6 @@ import android.media.AudioManagerInternal;
import android.media.AudioSystem;
import android.media.IAudioService;
import android.media.session.MediaSessionLegacyHelper;
-import android.os.BatteryManagerInternal;
import android.os.Binder;
import android.os.Bundle;
import android.os.DeviceIdleManager;
@@ -396,7 +394,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
PowerManagerInternal mPowerManagerInternal;
IStatusBarService mStatusBarService;
StatusBarManagerInternal mStatusBarManagerInternal;
- BatteryManagerInternal mBatteryManagerInternal;
AudioManagerInternal mAudioManagerInternal;
DisplayManager mDisplayManager;
DisplayManagerInternal mDisplayManagerInternal;
@@ -791,8 +788,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
@Override
public void onWakeUp() {
synchronized (mLock) {
- if (shouldEnableWakeGestureLp()
- && getBatteryManagerInternal().getPlugType() != BATTERY_PLUGGED_WIRELESS) {
+ if (shouldEnableWakeGestureLp()) {
performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, false,
"Wake Up");
wakeUp(SystemClock.uptimeMillis(), mAllowTheaterModeWakeFromWakeGesture,
@@ -849,15 +845,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
- BatteryManagerInternal getBatteryManagerInternal() {
- synchronized (mServiceAcquireLock) {
- if (mBatteryManagerInternal == null) {
- mBatteryManagerInternal =
- LocalServices.getService(BatteryManagerInternal.class);
- }
- return mBatteryManagerInternal;
- }
- }
// returns true if the key was handled and should not be passed to the user
private boolean backKeyPress() {
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java b/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java
index ee30fa2ac928..fb9a4d41ee90 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java
@@ -15,6 +15,8 @@
*/
package com.android.server.tv.tunerresourcemanager;
+import android.media.tv.tunerresourcemanager.TunerResourceManager;
+
import java.util.HashSet;
import java.util.Set;
@@ -63,6 +65,11 @@ public final class ClientProfile {
private int mNiceValue;
/**
+ * The handle of the primary frontend resource
+ */
+ private int mPrimaryUsingFrontendHandle = TunerResourceManager.INVALID_RESOURCE_HANDLE;
+
+ /**
* List of the frontend handles that are used by the current client.
*/
private Set<Integer> mUsingFrontendHandles = new HashSet<>();
@@ -175,6 +182,22 @@ public final class ClientProfile {
}
/**
+ * Set the primary frontend used by the client
+ *
+ * @param frontendHandle being used.
+ */
+ public void setPrimaryFrontend(int frontendHandle) {
+ mPrimaryUsingFrontendHandle = frontendHandle;
+ }
+
+ /**
+ * Get the primary frontend used by the client
+ */
+ public int getPrimaryFrontend() {
+ return mPrimaryUsingFrontendHandle;
+ }
+
+ /**
* Update the set of client that share frontend with the current client.
*
* @param clientId the client to share the fe with the current client.
@@ -206,6 +229,7 @@ public final class ClientProfile {
public void releaseFrontend() {
mUsingFrontendHandles.clear();
mShareFeClientIds.clear();
+ mPrimaryUsingFrontendHandle = TunerResourceManager.INVALID_RESOURCE_HANDLE;
}
/**
@@ -276,6 +300,7 @@ public final class ClientProfile {
public void reclaimAllResources() {
mUsingFrontendHandles.clear();
mShareFeClientIds.clear();
+ mPrimaryUsingFrontendHandle = TunerResourceManager.INVALID_RESOURCE_HANDLE;
mUsingLnbHandles.clear();
mUsingCasSystemId = INVALID_RESOURCE_ID;
mUsingCiCamId = INVALID_RESOURCE_ID;
diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
index af705d597af2..6162d716b85e 100644
--- a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
+++ b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java
@@ -42,6 +42,7 @@ import android.os.SystemClock;
import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.Slog;
+import android.util.SparseIntArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -72,14 +73,28 @@ public class TunerResourceManagerService extends SystemService implements IBinde
private static final long INVALID_THREAD_ID = -1;
private static final long TRMS_LOCK_TIMEOUT = 500;
+ private static final int INVALID_FE_COUNT = -1;
+
// Map of the registered client profiles
private Map<Integer, ClientProfile> mClientProfiles = new HashMap<>();
private int mNextUnusedClientId = 0;
// Map of the current available frontend resources
private Map<Integer, FrontendResource> mFrontendResources = new HashMap<>();
- // Backup Map of the current available frontend resources
+ // SparseIntArray of the max usable number for each frontend resource type
+ private SparseIntArray mFrontendMaxUsableNums = new SparseIntArray();
+ // SparseIntArray of the currently used number for each frontend resource type
+ private SparseIntArray mFrontendUsedNums = new SparseIntArray();
+ // SparseIntArray of the existing number for each frontend resource type
+ private SparseIntArray mFrontendExistingNums = new SparseIntArray();
+
+ // Backups for the frontend resource maps for enabling testing with custom resource maps
+ // such as TunerTest.testHasUnusedFrontend1()
private Map<Integer, FrontendResource> mFrontendResourcesBackup = new HashMap<>();
+ private SparseIntArray mFrontendMaxUsableNumsBackup = new SparseIntArray();
+ private SparseIntArray mFrontendUsedNumsBackup = new SparseIntArray();
+ private SparseIntArray mFrontendExistingNumsBackup = new SparseIntArray();
+
// Map of the current available lnb resources
private Map<Integer, LnbResource> mLnbResources = new HashMap<>();
// Map of the current available Cas resources
@@ -268,6 +283,29 @@ public class TunerResourceManagerService extends SystemService implements IBinde
}
@Override
+ public boolean setMaxNumberOfFrontends(int frontendType, int maxUsableNum) {
+ enforceTunerAccessPermission("requestFrontend");
+ enforceTrmAccessPermission("requestFrontend");
+ if (maxUsableNum < 0) {
+ Slog.w(TAG, "setMaxNumberOfFrontends failed with maxUsableNum:" + maxUsableNum
+ + " frontendType:" + frontendType);
+ return false;
+ }
+ synchronized (mLock) {
+ return setMaxNumberOfFrontendsInternal(frontendType, maxUsableNum);
+ }
+ }
+
+ @Override
+ public int getMaxNumberOfFrontends(int frontendType) {
+ enforceTunerAccessPermission("requestFrontend");
+ enforceTrmAccessPermission("requestFrontend");
+ synchronized (mLock) {
+ return getMaxNumberOfFrontendsInternal(frontendType);
+ }
+ }
+
+ @Override
public void shareFrontend(int selfClientId, int targetClientId) throws RemoteException {
enforceTunerAccessPermission("shareFrontend");
enforceTrmAccessPermission("shareFrontend");
@@ -572,71 +610,19 @@ public class TunerResourceManagerService extends SystemService implements IBinde
}
synchronized (mLock) {
- if (mClientProfiles != null) {
- pw.println("ClientProfiles:");
- pw.increaseIndent();
- for (Map.Entry<Integer, ClientProfile> entry : mClientProfiles.entrySet()) {
- pw.println(entry.getKey() + " : " + entry.getValue());
- }
- pw.decreaseIndent();
- }
-
- if (mFrontendResources != null) {
- pw.println("FrontendResources:");
- pw.increaseIndent();
- for (Map.Entry<Integer, FrontendResource> entry
- : mFrontendResources.entrySet()) {
- pw.println(entry.getKey() + " : " + entry.getValue());
- }
- pw.decreaseIndent();
- }
-
- if (mFrontendResourcesBackup != null) {
- pw.println("FrontendResourcesBackUp:");
- pw.increaseIndent();
- for (Map.Entry<Integer, FrontendResource> entry
- : mFrontendResourcesBackup.entrySet()) {
- pw.println(entry.getKey() + " : " + entry.getValue());
- }
- pw.decreaseIndent();
- }
-
- if (mLnbResources != null) {
- pw.println("LnbResources:");
- pw.increaseIndent();
- for (Map.Entry<Integer, LnbResource> entry : mLnbResources.entrySet()) {
- pw.println(entry.getKey() + " : " + entry.getValue());
- }
- pw.decreaseIndent();
- }
-
- if (mCasResources != null) {
- pw.println("CasResources:");
- pw.increaseIndent();
- for (Map.Entry<Integer, CasResource> entry : mCasResources.entrySet()) {
- pw.println(entry.getKey() + " : " + entry.getValue());
- }
- pw.decreaseIndent();
- }
-
- if (mCiCamResources != null) {
- pw.println("CiCamResources:");
- pw.increaseIndent();
- for (Map.Entry<Integer, CiCamResource> entry : mCiCamResources.entrySet()) {
- pw.println(entry.getKey() + " : " + entry.getValue());
- }
- pw.decreaseIndent();
- }
-
- if (mListeners != null) {
- pw.println("Listners:");
- pw.increaseIndent();
- for (Map.Entry<Integer, ResourcesReclaimListenerRecord> entry
- : mListeners.entrySet()) {
- pw.println(entry.getKey() + " : " + entry.getValue());
- }
- pw.decreaseIndent();
- }
+ dumpMap(mClientProfiles, "ClientProfiles:", "\n", pw);
+ dumpMap(mFrontendResources, "FrontendResources:", "\n", pw);
+ dumpSIA(mFrontendExistingNums, "FrontendExistingNums:", ", ", pw);
+ dumpSIA(mFrontendUsedNums, "FrontendUsedNums:", ", ", pw);
+ dumpSIA(mFrontendMaxUsableNums, "FrontendMaxUsableNums:", ", ", pw);
+ dumpMap(mFrontendResourcesBackup, "FrontendResourcesBackUp:", "\n", pw);
+ dumpSIA(mFrontendExistingNumsBackup, "FrontendExistingNumsBackup:", ", ", pw);
+ dumpSIA(mFrontendUsedNumsBackup, "FrontendUsedNumsBackup:", ", ", pw);
+ dumpSIA(mFrontendMaxUsableNumsBackup, "FrontendUsedNumsBackup:", ", ", pw);
+ dumpMap(mLnbResources, "LnbResource:", "\n", pw);
+ dumpMap(mCasResources, "CasResource:", "\n", pw);
+ dumpMap(mCiCamResources, "CiCamResource:", "\n", pw);
+ dumpMap(mListeners, "Listners:", "\n", pw);
}
}
@@ -786,10 +772,10 @@ public class TunerResourceManagerService extends SystemService implements IBinde
protected void storeResourceMapInternal(int resourceType) {
switch (resourceType) {
case TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND:
- if (mFrontendResources != null && mFrontendResources.size() > 0) {
- mFrontendResourcesBackup.putAll(mFrontendResources);
- mFrontendResources.clear();
- }
+ replaceFeResourceMap(mFrontendResources, mFrontendResourcesBackup);
+ replaceFeCounts(mFrontendExistingNums, mFrontendExistingNumsBackup);
+ replaceFeCounts(mFrontendUsedNums, mFrontendUsedNumsBackup);
+ replaceFeCounts(mFrontendMaxUsableNums, mFrontendMaxUsableNumsBackup);
break;
// TODO: implement for other resource type when needed
default:
@@ -800,9 +786,10 @@ public class TunerResourceManagerService extends SystemService implements IBinde
protected void clearResourceMapInternal(int resourceType) {
switch (resourceType) {
case TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND:
- if (mFrontendResources != null) {
- mFrontendResources.clear();
- }
+ replaceFeResourceMap(null, mFrontendResources);
+ replaceFeCounts(null, mFrontendExistingNums);
+ replaceFeCounts(null, mFrontendUsedNums);
+ replaceFeCounts(null, mFrontendMaxUsableNums);
break;
// TODO: implement for other resource type when needed
default:
@@ -813,12 +800,10 @@ public class TunerResourceManagerService extends SystemService implements IBinde
protected void restoreResourceMapInternal(int resourceType) {
switch (resourceType) {
case TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND:
- if (mFrontendResourcesBackup != null
- && mFrontendResourcesBackup.size() > 0) {
- mFrontendResources.clear();
- mFrontendResources.putAll(mFrontendResourcesBackup);
- mFrontendResourcesBackup.clear();
- }
+ replaceFeResourceMap(mFrontendResourcesBackup, mFrontendResources);
+ replaceFeCounts(mFrontendExistingNumsBackup, mFrontendExistingNums);
+ replaceFeCounts(mFrontendUsedNumsBackup, mFrontendUsedNums);
+ replaceFeCounts(mFrontendMaxUsableNumsBackup, mFrontendMaxUsableNums);
break;
// TODO: implement for other resource type when needed
default:
@@ -954,6 +939,11 @@ public class TunerResourceManagerService extends SystemService implements IBinde
for (FrontendResource fr : getFrontendResources().values()) {
if (fr.getType() == request.frontendType) {
if (!fr.isInUse()) {
+ // Unused resource cannot be acquired if the max is already reached, but
+ // TRM still has to look for the reclaim candidate
+ if (isFrontendMaxNumUseReached(request.frontendType)) {
+ continue;
+ }
// Grant unused frontend with no exclusive group members first.
if (fr.getExclusiveGroupMemberFeHandles().isEmpty()) {
grantingFrontendHandle = fr.getHandle();
@@ -1021,6 +1011,9 @@ public class TunerResourceManagerService extends SystemService implements IBinde
for (int inUseHandle : newOwnerProfile.getInUseFrontendHandles()) {
getFrontendResource(inUseHandle).setOwner(newOwnerId);
}
+ // change the primary frontend
+ newOwnerProfile.setPrimaryFrontend(currentOwnerProfile.getPrimaryFrontend());
+ currentOwnerProfile.setPrimaryFrontend(TunerResourceManager.INVALID_RESOURCE_HANDLE);
// double check there is no other resources tied to the previous owner
for (int inUseHandle : currentOwnerProfile.getInUseFrontendHandles()) {
int ownerId = getFrontendResource(inUseHandle).getOwnerClientId();
@@ -1657,11 +1650,13 @@ public class TunerResourceManagerService extends SystemService implements IBinde
FrontendResource grantingFrontend = getFrontendResource(grantingHandle);
ClientProfile ownerProfile = getClientProfile(ownerClientId);
grantingFrontend.setOwner(ownerClientId);
+ increFrontendNum(mFrontendUsedNums, grantingFrontend.getType());
ownerProfile.useFrontend(grantingHandle);
for (int exclusiveGroupMember : grantingFrontend.getExclusiveGroupMemberFeHandles()) {
getFrontendResource(exclusiveGroupMember).setOwner(ownerClientId);
ownerProfile.useFrontend(exclusiveGroupMember);
}
+ ownerProfile.setPrimaryFrontend(grantingHandle);
}
private void updateLnbClientMappingOnNewGrant(int grantingHandle, int ownerClientId) {
@@ -1755,6 +1750,109 @@ public class TunerResourceManagerService extends SystemService implements IBinde
return mFrontendResources;
}
+ private boolean setMaxNumberOfFrontendsInternal(int frontendType, int maxUsableNum) {
+ int usedNum = mFrontendUsedNums.get(frontendType, INVALID_FE_COUNT);
+ if (usedNum == INVALID_FE_COUNT || usedNum <= maxUsableNum) {
+ mFrontendMaxUsableNums.put(frontendType, maxUsableNum);
+ return true;
+ } else {
+ Slog.e(TAG, "max number of frontend for frontendType: " + frontendType
+ + " cannot be set to a value lower than the current usage count."
+ + " (requested max num = " + maxUsableNum + ", current usage = " + usedNum);
+ return false;
+ }
+ }
+
+ private int getMaxNumberOfFrontendsInternal(int frontendType) {
+ int existingNum = mFrontendExistingNums.get(frontendType, INVALID_FE_COUNT);
+ if (existingNum == INVALID_FE_COUNT) {
+ Log.e(TAG, "existingNum is -1 for " + frontendType);
+ return -1;
+ }
+ int maxUsableNum = mFrontendMaxUsableNums.get(frontendType, INVALID_FE_COUNT);
+ if (maxUsableNum == INVALID_FE_COUNT) {
+ return existingNum;
+ } else {
+ return maxUsableNum;
+ }
+ }
+
+ private boolean isFrontendMaxNumUseReached(int frontendType) {
+ int maxUsableNum = mFrontendMaxUsableNums.get(frontendType, INVALID_FE_COUNT);
+ if (maxUsableNum == INVALID_FE_COUNT) {
+ return false;
+ }
+ int useNum = mFrontendUsedNums.get(frontendType, INVALID_FE_COUNT);
+ if (useNum == INVALID_FE_COUNT) {
+ useNum = 0;
+ }
+ return useNum >= maxUsableNum;
+ }
+
+ private void increFrontendNum(SparseIntArray targetNums, int frontendType) {
+ int num = targetNums.get(frontendType, INVALID_FE_COUNT);
+ if (num == INVALID_FE_COUNT) {
+ targetNums.put(frontendType, 1);
+ } else {
+ targetNums.put(frontendType, num + 1);
+ }
+ }
+
+ private void decreFrontendNum(SparseIntArray targetNums, int frontendType) {
+ int num = targetNums.get(frontendType, INVALID_FE_COUNT);
+ if (num != INVALID_FE_COUNT) {
+ targetNums.put(frontendType, num - 1);
+ }
+ }
+
+ private void replaceFeResourceMap(Map<Integer, FrontendResource> srcMap, Map<Integer,
+ FrontendResource> dstMap) {
+ if (dstMap != null) {
+ dstMap.clear();
+ if (srcMap != null && srcMap.size() > 0) {
+ dstMap.putAll(srcMap);
+ }
+ }
+ }
+
+ private void replaceFeCounts(SparseIntArray srcCounts, SparseIntArray dstCounts) {
+ if (dstCounts != null) {
+ dstCounts.clear();
+ if (srcCounts != null) {
+ for (int i = 0; i < srcCounts.size(); i++) {
+ dstCounts.put(srcCounts.keyAt(i), srcCounts.valueAt(i));
+ }
+ }
+ }
+ }
+ private void dumpMap(Map<?, ?> targetMap, String headline, String delimiter,
+ IndentingPrintWriter pw) {
+ if (targetMap != null) {
+ pw.println(headline);
+ pw.increaseIndent();
+ for (Map.Entry<?, ?> entry : targetMap.entrySet()) {
+ pw.print(entry.getKey() + " : " + entry.getValue());
+ pw.print(delimiter);
+ }
+ pw.println();
+ pw.decreaseIndent();
+ }
+ }
+
+ private void dumpSIA(SparseIntArray array, String headline, String delimiter,
+ IndentingPrintWriter pw) {
+ if (array != null) {
+ pw.println(headline);
+ pw.increaseIndent();
+ for (int i = 0; i < array.size(); i++) {
+ pw.print(array.keyAt(i) + " : " + array.valueAt(i));
+ pw.print(delimiter);
+ }
+ pw.println();
+ pw.decreaseIndent();
+ }
+ }
+
private void addFrontendResource(FrontendResource newFe) {
// Update the exclusive group member list in all the existing Frontend resource
for (FrontendResource fe : getFrontendResources().values()) {
@@ -1771,6 +1869,8 @@ public class TunerResourceManagerService extends SystemService implements IBinde
}
// Update resource list and available id list
mFrontendResources.put(newFe.getHandle(), newFe);
+ increFrontendNum(mFrontendExistingNums, newFe.getType());
+
}
private void removeFrontendResource(int removingHandle) {
@@ -1789,6 +1889,7 @@ public class TunerResourceManagerService extends SystemService implements IBinde
getFrontendResource(excGroupmemberFeHandle)
.removeExclusiveGroupMemberFeId(fe.getHandle());
}
+ decreFrontendNum(mFrontendExistingNums, fe.getType());
mFrontendResources.remove(removingHandle);
}
@@ -1918,6 +2019,15 @@ public class TunerResourceManagerService extends SystemService implements IBinde
}
}
+
+ int primaryFeId = profile.getPrimaryFrontend();
+ if (primaryFeId != TunerResourceManager.INVALID_RESOURCE_HANDLE) {
+ FrontendResource primaryFe = getFrontendResource(primaryFeId);
+ if (primaryFe != null) {
+ decreFrontendNum(mFrontendUsedNums, primaryFe.getType());
+ }
+ }
+
profile.releaseFrontend();
}
diff --git a/services/core/java/com/android/server/utils/WatchedArrayList.java b/services/core/java/com/android/server/utils/WatchedArrayList.java
index 6059f9675e34..07474a63cb2a 100644
--- a/services/core/java/com/android/server/utils/WatchedArrayList.java
+++ b/services/core/java/com/android/server/utils/WatchedArrayList.java
@@ -416,7 +416,7 @@ public class WatchedArrayList<E> extends WatchableImpl
dst.mStorage.ensureCapacity(end);
for (int i = 0; i < end; i++) {
final E val = Snapshots.maybeSnapshot(src.get(i));
- dst.add(i, val);
+ dst.mStorage.add(val);
}
dst.seal();
}
diff --git a/services/core/java/com/android/server/utils/WatchedArrayMap.java b/services/core/java/com/android/server/utils/WatchedArrayMap.java
index 7c1cde8502bd..63441aac8e1f 100644
--- a/services/core/java/com/android/server/utils/WatchedArrayMap.java
+++ b/services/core/java/com/android/server/utils/WatchedArrayMap.java
@@ -465,7 +465,7 @@ public class WatchedArrayMap<K, V> extends WatchableImpl
for (int i = 0; i < end; i++) {
final V val = Snapshots.maybeSnapshot(src.valueAt(i));
final K key = src.keyAt(i);
- dst.put(key, val);
+ dst.mStorage.put(key, val);
}
dst.seal();
}
diff --git a/services/core/java/com/android/server/utils/WatchedArraySet.java b/services/core/java/com/android/server/utils/WatchedArraySet.java
index ec80261a2196..a2eaed72dd65 100644
--- a/services/core/java/com/android/server/utils/WatchedArraySet.java
+++ b/services/core/java/com/android/server/utils/WatchedArraySet.java
@@ -427,7 +427,7 @@ public class WatchedArraySet<E> extends WatchableImpl
dst.mStorage.ensureCapacity(end);
for (int i = 0; i < end; i++) {
final E val = Snapshots.maybeSnapshot(src.valueAt(i));
- dst.append(val);
+ dst.mStorage.append(val);
}
dst.seal();
}
diff --git a/services/core/java/com/android/server/utils/WatchedLongSparseArray.java b/services/core/java/com/android/server/utils/WatchedLongSparseArray.java
index bf23de12ffef..9da9e75f98fb 100644
--- a/services/core/java/com/android/server/utils/WatchedLongSparseArray.java
+++ b/services/core/java/com/android/server/utils/WatchedLongSparseArray.java
@@ -410,7 +410,7 @@ public class WatchedLongSparseArray<E> extends WatchableImpl
for (int i = 0; i < end; i++) {
final E val = Snapshots.maybeSnapshot(src.valueAt(i));
final long key = src.keyAt(i);
- dst.put(key, val);
+ dst.mStorage.put(key, val);
}
dst.seal();
}
diff --git a/services/core/java/com/android/server/utils/WatchedSparseArray.java b/services/core/java/com/android/server/utils/WatchedSparseArray.java
index 9b99b9176d19..6ce38b71d9cd 100644
--- a/services/core/java/com/android/server/utils/WatchedSparseArray.java
+++ b/services/core/java/com/android/server/utils/WatchedSparseArray.java
@@ -490,7 +490,7 @@ public class WatchedSparseArray<E> extends WatchableImpl
for (int i = 0; i < end; i++) {
final E val = Snapshots.maybeSnapshot(src.valueAt(i));
final int key = src.keyAt(i);
- dst.put(key, val);
+ dst.mStorage.put(key, val);
}
dst.seal();
}
diff --git a/services/core/java/com/android/server/utils/WatchedSparseBooleanArray.java b/services/core/java/com/android/server/utils/WatchedSparseBooleanArray.java
index 772a8d07cffb..50e2272afb72 100644
--- a/services/core/java/com/android/server/utils/WatchedSparseBooleanArray.java
+++ b/services/core/java/com/android/server/utils/WatchedSparseBooleanArray.java
@@ -310,7 +310,7 @@ public class WatchedSparseBooleanArray extends WatchableImpl
}
final int end = src.size();
for (int i = 0; i < end; i++) {
- dst.put(src.keyAt(i), src.valueAt(i));
+ dst.mStorage.put(src.keyAt(i), src.valueAt(i));
}
dst.seal();
}
diff --git a/services/core/java/com/android/server/utils/WatchedSparseIntArray.java b/services/core/java/com/android/server/utils/WatchedSparseIntArray.java
index 72705bf24199..53d168245180 100644
--- a/services/core/java/com/android/server/utils/WatchedSparseIntArray.java
+++ b/services/core/java/com/android/server/utils/WatchedSparseIntArray.java
@@ -315,7 +315,7 @@ public class WatchedSparseIntArray extends WatchableImpl
}
final int end = src.size();
for (int i = 0; i < end; i++) {
- dst.put(src.keyAt(i), src.valueAt(i));
+ dst.mStorage.put(src.keyAt(i), src.valueAt(i));
}
dst.seal();
}
diff --git a/services/core/java/com/android/server/utils/WatchedSparseSetArray.java b/services/core/java/com/android/server/utils/WatchedSparseSetArray.java
index 05db12e49a13..77750ed92273 100644
--- a/services/core/java/com/android/server/utils/WatchedSparseSetArray.java
+++ b/services/core/java/com/android/server/utils/WatchedSparseSetArray.java
@@ -169,7 +169,7 @@ public class WatchedSparseSetArray<T> extends WatchableImpl implements Snappable
final ArraySet set = src.get(i);
final int setSize = set.size();
for (int j = 0; j < setSize; j++) {
- dst.add(src.keyAt(i), set.valueAt(j));
+ dst.mStorage.add(src.keyAt(i), set.valueAt(j));
}
}
dst.seal();
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 63619e543a6d..f1dbad61a76d 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -446,6 +446,43 @@ final class AccessibilityController {
// Not relevant for the window observer.
}
+ public Pair<Matrix, MagnificationSpec> getWindowTransformationMatrixAndMagnificationSpec(
+ IBinder token) {
+ synchronized (mService.mGlobalLock) {
+ final Matrix transformationMatrix = new Matrix();
+ final MagnificationSpec magnificationSpec = new MagnificationSpec();
+
+ final WindowState windowState = mService.mWindowMap.get(token);
+ if (windowState != null) {
+ windowState.getTransformationMatrix(new float[9], transformationMatrix);
+
+ if (hasCallbacks()) {
+ final MagnificationSpec otherMagnificationSpec =
+ getMagnificationSpecForWindow(windowState);
+ if (otherMagnificationSpec != null && !otherMagnificationSpec.isNop()) {
+ magnificationSpec.setTo(otherMagnificationSpec);
+ }
+ }
+ }
+
+ return new Pair<>(transformationMatrix, magnificationSpec);
+ }
+ }
+
+ MagnificationSpec getMagnificationSpecForWindow(WindowState windowState) {
+ if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
+ mAccessibilityTracing.logTrace(TAG + ".getMagnificationSpecForWindow",
+ FLAGS_MAGNIFICATION_CALLBACK,
+ "windowState={" + windowState + "}");
+ }
+ final int displayId = windowState.getDisplayId();
+ final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
+ if (displayMagnifier != null) {
+ return displayMagnifier.getMagnificationSpecForWindow(windowState);
+ }
+ return null;
+ }
+
boolean hasCallbacks() {
if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK
| FLAGS_WINDOWS_FOR_ACCESSIBILITY_CALLBACK)) {
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index cb6559715c55..701fc9441acb 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -68,7 +68,6 @@ import static com.android.server.wm.AppTransition.isNormalTransit;
import static com.android.server.wm.NonAppWindowAnimationAdapter.shouldAttachNavBarToApp;
import static com.android.server.wm.NonAppWindowAnimationAdapter.shouldStartNonAppWindowAnimationsForKeyguardExit;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
-import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
import static com.android.server.wm.WallpaperAnimationAdapter.shouldStartWallpaperAnimation;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
@@ -1143,17 +1142,13 @@ public class AppTransitionController {
if (activity == null) {
continue;
}
- if (activity.isAnimating(PARENTS, ANIMATION_TYPE_RECENTS)) {
- ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
- "Delaying app transition for recents animation to finish");
- return false;
- }
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
"Check opening app=%s: allDrawn=%b startingDisplayed=%b "
+ "startingMoved=%b isRelaunching()=%b startingWindow=%s",
activity, activity.allDrawn, activity.startingDisplayed,
activity.startingMoved, activity.isRelaunching(),
activity.mStartingWindow);
+
final boolean allDrawn = activity.allDrawn && !activity.isRelaunching();
if (!allDrawn && !activity.startingDisplayed && !activity.startingMoved) {
return false;
diff --git a/services/core/java/com/android/server/wm/BLASTSyncEngine.java b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
index ee7d9a9b3f2d..46ce43335f01 100644
--- a/services/core/java/com/android/server/wm/BLASTSyncEngine.java
+++ b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
@@ -153,10 +153,10 @@ class BLASTSyncEngine {
for (WindowContainer wc : mRootMembers) {
wc.waitForSyncTransactionCommit(wcAwaitingCommit);
}
- final Runnable callback = new Runnable() {
+ class CommitCallback implements Runnable {
// Can run a second time if the action completes after the timeout.
boolean ran = false;
- public void run() {
+ public void onCommitted() {
synchronized (mWm.mGlobalLock) {
if (ran) {
return;
@@ -171,8 +171,23 @@ class BLASTSyncEngine {
wcAwaitingCommit.clear();
}
}
+
+ // Called in timeout
+ @Override
+ public void run() {
+ // Sometimes we get a trace, sometimes we get a bugreport without
+ // a trace. Since these kind of ANRs can trigger such an issue,
+ // try and ensure we will have some visibility in both cases.
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "onTransactionCommitTimeout");
+ Slog.e(TAG, "WM sent Transaction to organized, but never received" +
+ " commit callback. Application ANR likely to follow.");
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+ onCommitted();
+
+ }
};
- merged.addTransactionCommittedListener((r) -> { r.run(); }, callback::run);
+ CommitCallback callback = new CommitCallback();
+ merged.addTransactionCommittedListener((r) -> { r.run(); }, callback::onCommitted);
mWm.mH.postDelayed(callback, BLAST_TIMEOUT_DURATION);
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "onTransactionReady");
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index a480c37fbcf3..2f00bc821678 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -1584,14 +1584,6 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
return true;
}
- void forAllWindowContainers(Consumer<WindowContainer> callback) {
- callback.accept(this);
- final int count = mChildren.size();
- for (int i = 0; i < count; i++) {
- mChildren.get(i).forAllWindowContainers(callback);
- }
- }
-
/**
* For all windows at or below this container call the callback.
* @param callback Calls the {@link ToBooleanFunction#apply} method for each window found and
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index f8bc26a7d91d..c0d7d1362ac3 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -23,17 +23,18 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ClipData;
import android.content.Context;
+import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.Region;
import android.hardware.display.DisplayManagerInternal;
import android.os.Bundle;
import android.os.IBinder;
+import android.util.Pair;
import android.view.Display;
import android.view.IInputFilter;
import android.view.IRemoteAnimationFinishedCallback;
import android.view.IWindow;
import android.view.InputChannel;
-import android.view.InputWindowHandle;
import android.view.MagnificationSpec;
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
@@ -459,6 +460,17 @@ public abstract class WindowManagerInternal {
public abstract void getWindowFrame(IBinder token, Rect outBounds);
/**
+ * Get the transformation matrix and MagnificationSpec given its token.
+ *
+ * @param token The token.
+ * @return The pair of the transformation matrix and magnification spec.
+ */
+ // TODO (b/231663133): Long term solution for tracking window when the
+ // FLAG_RETRIEVE_INTERACTIVE_WINDOWS is unset.
+ public abstract Pair<Matrix, MagnificationSpec>
+ getWindowTransformationMatrixAndMagnificationSpec(IBinder token);
+
+ /**
* Opens the global actions dialog.
*/
public abstract void showGlobalActions();
@@ -849,24 +861,12 @@ public abstract class WindowManagerInternal {
public abstract SurfaceControl getHandwritingSurfaceForDisplay(int displayId);
/**
- * Replaces the touchable region of the provided input surface with the crop of the window with
- * the provided token. This method will associate the inputSurface with a copy of
- * the given inputWindowHandle, where the copy is configured using
- * {@link InputWindowHandle#replaceTouchableRegionWithCrop(SurfaceControl)} with the surface
- * of the provided windowToken.
- *
- * This is a no-op if windowToken is not valid or the window is not found.
- *
- * This does not change any other properties of the inputSurface.
- *
- * This method exists to avoid leaking the window's SurfaceControl outside WindowManagerService.
+ * Returns {@code true} if the given point is within the window bounds of the given window.
*
- * @param inputSurface The surface for which the touchable region should be set.
- * @param inputWindowHandle The {@link InputWindowHandle} for the input surface.
- * @param windowToken The window whose bounds should be used as the touchable region for the
- * inputSurface.
+ * @param windowToken the window whose bounds should be used for the hit test.
+ * @param displayX the x coordinate of the test point in the display's coordinate space.
+ * @param displayY the y coordinate of the test point in the display's coordinate space.
*/
- public abstract void replaceInputSurfaceTouchableRegionWithWindowCrop(
- @NonNull SurfaceControl inputSurface, @NonNull InputWindowHandle inputWindowHandle,
- @NonNull IBinder windowToken);
+ public abstract boolean isPointInsideWindow(
+ @NonNull IBinder windowToken, int displayId, float displayX, float displayY);
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index a9f56d3d51e1..8f1f7ece897b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -118,7 +118,6 @@ import static com.android.server.wm.DisplayContent.IME_TARGET_CONTROL;
import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING;
import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_OR_RECENT_TASKS;
import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_ALL;
-import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
@@ -173,6 +172,7 @@ import android.content.res.Resources;
import android.content.res.TypedArray;
import android.database.ContentObserver;
import android.graphics.Bitmap;
+import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
@@ -224,6 +224,7 @@ import android.util.ArraySet;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.MergedConfiguration;
+import android.util.Pair;
import android.util.Slog;
import android.util.SparseBooleanArray;
import android.util.TimeUtils;
@@ -3051,22 +3052,13 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
-
void cleanupRecentsAnimation(@RecentsAnimationController.ReorderMode int reorderMode) {
if (mRecentsAnimationController != null) {
final RecentsAnimationController controller = mRecentsAnimationController;
mRecentsAnimationController = null;
controller.cleanupAnimation(reorderMode);
- // TODO(multi-display): currently only default display support recents animation.
- // Cancel any existing app transition animation running in the legacy transition
- // framework.
- final DisplayContent dc = getDefaultDisplayContentLocked();
- dc.mAppTransition.freeze();
- dc.forAllWindowContainers((wc) -> {
- if (wc.isAnimating(TRANSITION, ANIMATION_TYPE_APP_TRANSITION)) {
- wc.cancelAnimation();
- }
- });
+ // TODO(mult-display): currently only default display support recents animation.
+ getDefaultDisplayContentLocked().mAppTransition.updateBooster();
}
}
@@ -7769,6 +7761,13 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
+ public Pair<Matrix, MagnificationSpec> getWindowTransformationMatrixAndMagnificationSpec(
+ IBinder token) {
+ return mAccessibilityController
+ .getWindowTransformationMatrixAndMagnificationSpec(token);
+ }
+
+ @Override
public void waitForAllWindowsDrawn(Runnable callback, long timeout, int displayId) {
final WindowContainer container = displayId == INVALID_DISPLAY
? mRoot : mRoot.getDisplayContent(displayId);
@@ -8241,23 +8240,15 @@ public class WindowManagerService extends IWindowManager.Stub
}
@Override
- public void replaceInputSurfaceTouchableRegionWithWindowCrop(
- @NonNull SurfaceControl inputSurface,
- @NonNull InputWindowHandle inputWindowHandle,
- @NonNull IBinder windowToken) {
+ public boolean isPointInsideWindow(@NonNull IBinder windowToken, int displayId,
+ float displayX, float displayY) {
synchronized (mGlobalLock) {
final WindowState w = mWindowMap.get(windowToken);
- if (w == null) {
- return;
+ if (w == null || w.getDisplayId() != displayId) {
+ return false;
}
- // Make a copy of the InputWindowHandle to avoid leaking the window's
- // SurfaceControl.
- final InputWindowHandle localHandle = new InputWindowHandle(inputWindowHandle);
- localHandle.replaceTouchableRegionWithCrop(w.getSurfaceControl());
- final SurfaceControl.Transaction t = mTransactionFactory.get();
- t.setInputWindowInfo(inputSurface, localHandle);
- t.apply();
- t.close();
+
+ return w.getBounds().contains((int) displayX, (int) displayY);
}
}
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
index ac542935fa0a..009dae51e94b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BackgroundRestrictionTest.java
@@ -582,6 +582,7 @@ public final class BackgroundRestrictionTest {
DeviceConfigSession<Boolean> bgCurrentDrainMonitor = null;
DeviceConfigSession<Long> bgCurrentDrainWindow = null;
+ DeviceConfigSession<Long> bgCurrentDrainInteractionGracePeriod = null;
DeviceConfigSession<Float> bgCurrentDrainRestrictedBucketThreshold = null;
DeviceConfigSession<Float> bgCurrentDrainBgRestrictedThreshold = null;
DeviceConfigSession<Boolean> bgPromptFgsWithNotiToBgRestricted = null;
@@ -617,6 +618,14 @@ public final class BackgroundRestrictionTest {
R.integer.config_bg_current_drain_window));
bgCurrentDrainWindow.set(windowMs);
+ bgCurrentDrainInteractionGracePeriod = new DeviceConfigSession<>(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_INTERACTION_GRACE_PERIOD,
+ DeviceConfig::getLong,
+ (long) mContext.getResources().getInteger(
+ R.integer.config_bg_current_drain_window));
+ bgCurrentDrainInteractionGracePeriod.set(windowMs);
+
bgCurrentDrainRestrictedBucketThreshold = new DeviceConfigSession<>(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_RESTRICTED_BUCKET,
@@ -768,6 +777,32 @@ public final class BackgroundRestrictionTest {
clearInvocations(mInjector.getAppStandbyInternal());
+ // It won't be restricted since user just interacted with it.
+ runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
+ zeros, new double[]{0, restrictBucketThresholdMah - 1},
+ zeros, new double[]{restrictBucketThresholdMah + 1, 0},
+ () -> {
+ doReturn(mCurrentTimeMillis).when(stats).getStatsStartTimestamp();
+ doReturn(mCurrentTimeMillis + windowMs)
+ .when(stats).getStatsEndTimestamp();
+ mCurrentTimeMillis += windowMs + 1;
+ try {
+ listener.verify(timeout, testUid, testPkgName,
+ RESTRICTION_LEVEL_RESTRICTED_BUCKET);
+ fail("There shouldn't be any level change events");
+ } catch (Exception e) {
+ // Expected.
+ }
+ verify(mInjector.getAppStandbyInternal(), never()).restrictApp(
+ eq(testPkgName),
+ eq(testUser),
+ anyInt(), anyInt());
+ });
+
+ // Sleep a while.
+ Thread.sleep(windowMs);
+ clearInvocations(mInjector.getAppStandbyInternal());
+ // Now it should have been restricted.
runTestBgCurrentDrainMonitorOnce(listener, stats, uids,
zeros, new double[]{0, restrictBucketThresholdMah - 1},
zeros, new double[]{restrictBucketThresholdMah + 1, 0},
@@ -1061,6 +1096,7 @@ public final class BackgroundRestrictionTest {
} finally {
closeIfNotNull(bgCurrentDrainMonitor);
closeIfNotNull(bgCurrentDrainWindow);
+ closeIfNotNull(bgCurrentDrainInteractionGracePeriod);
closeIfNotNull(bgCurrentDrainRestrictedBucketThreshold);
closeIfNotNull(bgCurrentDrainBgRestrictedThreshold);
closeIfNotNull(bgPromptFgsWithNotiToBgRestricted);
@@ -1610,6 +1646,7 @@ public final class BackgroundRestrictionTest {
DeviceConfigSession<Boolean> bgCurrentDrainMonitor = null;
DeviceConfigSession<Long> bgCurrentDrainWindow = null;
+ DeviceConfigSession<Long> bgCurrentDrainInteractionGracePeriod = null;
DeviceConfigSession<Float> bgCurrentDrainRestrictedBucketThreshold = null;
DeviceConfigSession<Float> bgCurrentDrainBgRestrictedThreshold = null;
DeviceConfigSession<Float> bgCurrentDrainRestrictedBucketHighThreshold = null;
@@ -1655,6 +1692,14 @@ public final class BackgroundRestrictionTest {
R.integer.config_bg_current_drain_window));
bgCurrentDrainWindow.set(windowMs);
+ bgCurrentDrainInteractionGracePeriod = new DeviceConfigSession<>(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_INTERACTION_GRACE_PERIOD,
+ DeviceConfig::getLong,
+ (long) mContext.getResources().getInteger(
+ R.integer.config_bg_current_drain_window));
+ bgCurrentDrainInteractionGracePeriod.set(windowMs);
+
bgCurrentDrainRestrictedBucketThreshold = new DeviceConfigSession<>(
DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
AppBatteryPolicy.KEY_BG_CURRENT_DRAIN_THRESHOLD_TO_RESTRICTED_BUCKET,
@@ -2176,6 +2221,7 @@ public final class BackgroundRestrictionTest {
} finally {
closeIfNotNull(bgCurrentDrainMonitor);
closeIfNotNull(bgCurrentDrainWindow);
+ closeIfNotNull(bgCurrentDrainInteractionGracePeriod);
closeIfNotNull(bgCurrentDrainRestrictedBucketThreshold);
closeIfNotNull(bgCurrentDrainBgRestrictedThreshold);
closeIfNotNull(bgCurrentDrainRestrictedBucketHighThreshold);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
index 08df4381ad62..19df5a2ddd8b 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AbstractAccessibilityServiceConnectionTest.java
@@ -89,8 +89,10 @@ import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteCallback;
import android.os.RemoteException;
+import android.util.Pair;
import android.view.Display;
import android.view.KeyEvent;
+import android.view.MagnificationSpec;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityWindowInfo;
import android.view.accessibility.IAccessibilityInteractionConnection;
@@ -145,6 +147,8 @@ public class AbstractAccessibilityServiceConnectionTest {
private static final int USER_ID = 1;
private static final int USER_ID2 = 2;
private static final int INTERACTION_ID = 199;
+ private static final Pair<float[], MagnificationSpec> FAKE_MATRIX_AND_MAG_SPEC =
+ new Pair<>(new float[9], new MagnificationSpec());
private static final int PID = Process.myPid();
private static final long TID = Process.myTid();
private static final int UID = Process.myUid();
@@ -188,6 +192,8 @@ public class AbstractAccessibilityServiceConnectionTest {
.thenReturn(mMockFingerprintGestureDispatcher);
when(mMockSystemSupport.getMagnificationProcessor())
.thenReturn(mMockMagnificationProcessor);
+ when(mMockSystemSupport.getWindowTransformationMatrixAndMagnificationSpec(anyInt()))
+ .thenReturn(FAKE_MATRIX_AND_MAG_SPEC);
PowerManager powerManager =
new PowerManager(mMockContext, mMockIPowerManager, mMockIThermalService, mHandler);
diff --git a/services/tests/servicestests/src/com/android/server/am/DropboxRateLimiterTest.java b/services/tests/servicestests/src/com/android/server/am/DropboxRateLimiterTest.java
index d1390c68e130..e68a8a0f3af8 100644
--- a/services/tests/servicestests/src/com/android/server/am/DropboxRateLimiterTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/DropboxRateLimiterTest.java
@@ -49,10 +49,11 @@ public class DropboxRateLimiterTest {
assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
+ assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
// Different processes and tags should not get rate limited either.
assertFalse(mRateLimiter.shouldRateLimit("tag", "process2").shouldRateLimit());
assertFalse(mRateLimiter.shouldRateLimit("tag2", "process").shouldRateLimit());
- // The 6th entry of the same process should be rate limited.
+ // The 7th entry of the same process should be rate limited.
assertTrue(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
}
@@ -64,12 +65,13 @@ public class DropboxRateLimiterTest {
assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
- // The 6th entry of the same process should be rate limited.
+ assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
+ // The 7th entry of the same process should be rate limited.
assertTrue(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
- // After 11 seconds there should be nothing left in the buffer and the same type of entry
+ // After 11 minutes there should be nothing left in the buffer and the same type of entry
// should not get rate limited anymore.
- mClock.setOffsetMillis(11000);
+ mClock.setOffsetMillis(11 * 60 * 1000);
assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
}
@@ -86,13 +88,15 @@ public class DropboxRateLimiterTest {
mRateLimiter.shouldRateLimit("tag", "p").droppedCountSinceRateLimitActivated());
assertEquals(0,
mRateLimiter.shouldRateLimit("tag", "p").droppedCountSinceRateLimitActivated());
+ assertEquals(0,
+ mRateLimiter.shouldRateLimit("tag", "p").droppedCountSinceRateLimitActivated());
assertEquals(1,
mRateLimiter.shouldRateLimit("tag", "p").droppedCountSinceRateLimitActivated());
assertEquals(2,
mRateLimiter.shouldRateLimit("tag", "p").droppedCountSinceRateLimitActivated());
- // After 11 seconds the rate limiting buffer will be cleared and rate limiting will stop.
- mClock.setOffsetMillis(11000);
+ // After 11 minutes the rate limiting buffer will be cleared and rate limiting will stop.
+ mClock.setOffsetMillis(11 * 60 * 1000);
// The first call after rate limiting stops will still return the number of dropped events.
assertEquals(2,
diff --git a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
index 20486b3e396d..8167b44ee59d 100644
--- a/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/systemconfig/SystemConfigTest.java
@@ -454,14 +454,14 @@ public class SystemConfigTest {
+ " <library \n"
+ " name=\"foo\"\n"
+ " file=\"" + mFooJar + "\"\n"
- + " on-bootclasspath-before=\"Q\"\n"
+ + " on-bootclasspath-before=\"A\"\n"
+ " on-bootclasspath-since=\"W\"\n"
+ " />\n\n"
+ " </permissions>";
parseSharedLibraries(contents);
assertFooIsOnlySharedLibrary();
SystemConfig.SharedLibraryEntry entry = mSysConfig.getSharedLibraries().get("foo");
- assertThat(entry.onBootclasspathBefore).isEqualTo("Q");
+ assertThat(entry.onBootclasspathBefore).isEqualTo("A");
assertThat(entry.onBootclasspathSince).isEqualTo("W");
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ImportanceExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ImportanceExtractorTest.java
index e9515fa7fd9d..ffc0dcdca5fc 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ImportanceExtractorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ImportanceExtractorTest.java
@@ -82,8 +82,6 @@ public class ImportanceExtractorTest extends UiServiceTestCase {
ImportanceExtractor extractor = new ImportanceExtractor();
extractor.setConfig(mConfig);
- when(mConfig.getImportance(anyString(), anyInt())).thenReturn(
- NotificationManager.IMPORTANCE_MIN);
NotificationChannel channel =
new NotificationChannel("a", "a", NotificationManager.IMPORTANCE_UNSPECIFIED);
@@ -101,8 +99,6 @@ public class ImportanceExtractorTest extends UiServiceTestCase {
ImportanceExtractor extractor = new ImportanceExtractor();
extractor.setConfig(mConfig);
- when(mConfig.getImportance(anyString(), anyInt())).thenReturn(
- NotificationManager.IMPORTANCE_MIN);
NotificationChannel channel =
new NotificationChannel("a", "a", NotificationManager.IMPORTANCE_HIGH);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelLoggerFake.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelLoggerFake.java
index f609306e44b0..6f7bacedc467 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelLoggerFake.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelLoggerFake.java
@@ -28,6 +28,13 @@ public class NotificationChannelLoggerFake implements NotificationChannelLogger
CallRecord(NotificationChannelEvent event) {
this.event = event;
}
+
+ @Override
+ public String toString() {
+ return "CallRecord{" +
+ "event=" + event +
+ '}';
+ }
}
private List<CallRecord> mCalls = new ArrayList<>();
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index c0cd7a755e25..267a50675231 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -52,6 +52,7 @@ import static android.app.PendingIntent.FLAG_IMMUTABLE;
import static android.app.PendingIntent.FLAG_MUTABLE;
import static android.app.PendingIntent.FLAG_ONE_SHOT;
import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
+import static android.content.pm.PackageManager.FEATURE_TELECOM;
import static android.content.pm.PackageManager.FEATURE_WATCH;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -187,6 +188,7 @@ import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
+import android.util.Pair;
import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;
import android.util.Xml;
@@ -220,6 +222,7 @@ import com.android.server.wm.WindowManagerInternal;
import com.google.common.collect.ImmutableList;
import org.junit.After;
+import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -272,6 +275,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
private WindowManagerInternal mWindowManagerInternal;
@Mock
private PermissionHelper mPermissionHelper;
+ private NotificationChannelLoggerFake mLogger = new NotificationChannelLoggerFake();
private TestableContext mContext = spy(getContext());
private final String PKG = mContext.getPackageName();
private TestableLooper mTestableLooper;
@@ -384,9 +388,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
"android.permission.WRITE_DEVICE_CONFIG",
"android.permission.READ_DEVICE_CONFIG",
"android.permission.READ_CONTACTS");
- Settings.Secure.putIntForUser(
- getContext().getContentResolver(),
- Settings.Secure.NOTIFICATION_PERMISSION_ENABLED, 0, USER_SYSTEM);
MockitoAnnotations.initMocks(this);
@@ -448,6 +449,8 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mContext.addMockSystemService(AppOpsManager.class, mock(AppOpsManager.class));
when(mUm.getProfileIds(0, false)).thenReturn(new int[]{0});
+ when(mPackageManagerClient.hasSystemFeature(FEATURE_TELECOM)).thenReturn(true);
+
ActivityManager.AppTask task = mock(ActivityManager.AppTask.class);
List<ActivityManager.AppTask> taskList = new ArrayList<>();
ActivityManager.RecentTaskInfo taskInfo = new ActivityManager.RecentTaskInfo();
@@ -506,7 +509,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
mAppOpsManager, mAppOpsService, mUm, mHistoryManager, mStatsManager,
mock(TelephonyManager.class),
mAmi, mToastRateLimiter, mPermissionHelper, mock(UsageStatsManagerInternal.class),
- mTelecomManager);
+ mTelecomManager, mLogger);
// Return first true for RoleObserver main-thread check
when(mMainLooper.isCurrentThread()).thenReturn(true).thenReturn(false);
mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY, mMainLooper);
@@ -582,6 +585,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
assertNotNull(mBinderService.getNotificationChannel(
PKG, mContext.getUserId(), PKG, TEST_CHANNEL_ID));
clearInvocations(mRankingHandler);
+ when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
}
@After
@@ -1234,8 +1238,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
public void testEnqueuedBlockedNotifications_blockedApp() throws Exception {
when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
-
- mBinderService.setNotificationsEnabledForPackage(PKG, mUid, false);
+ when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
mBinderService.enqueueNotificationWithTag(PKG, PKG,
@@ -1248,8 +1251,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
public void testEnqueuedBlockedNotifications_blockedAppForegroundService() throws Exception {
when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
-
- mBinderService.setNotificationsEnabledForPackage(PKG, mUid, false);
+ when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
final StatusBarNotification sbn = generateNotificationRecord(null).getSbn();
sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE;
@@ -1342,6 +1344,30 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ public void testSetNotificationsEnabledForPackage_noChange() throws Exception {
+ when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
+ mBinderService.setNotificationsEnabledForPackage(mContext.getPackageName(), mUid, true);
+
+ verify(mPermissionHelper, never()).setNotificationPermission(
+ anyString(), anyInt(), anyBoolean(), anyBoolean());
+ }
+
+ @Test
+ public void testSetNotificationsEnabledForPackage() throws Exception {
+ when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
+ mBinderService.setNotificationsEnabledForPackage(mContext.getPackageName(), mUid, false);
+
+ verify(mPermissionHelper).setNotificationPermission(
+ mContext.getPackageName(), UserHandle.getUserId(mUid), false, true);
+
+ verify(mAppOpsManager, never()).setMode(anyInt(), anyInt(), anyString(), anyInt());
+ List<NotificationChannelLoggerFake.CallRecord> calls = mLogger.getCalls();
+ Assert.assertEquals(
+ NotificationChannelLogger.NotificationChannelEvent.APP_NOTIFICATIONS_BLOCKED,
+ calls.get(calls.size() -1).event);
+ }
+
+ @Test
public void testBlockedNotifications_blockedByAssistant() throws Exception {
when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
@@ -1368,7 +1394,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
public void testBlockedNotifications_blockedByUser() throws Exception {
- mService.setPreferencesHelper(mPreferencesHelper);
when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
@@ -1377,7 +1402,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
NotificationRecord r = generateNotificationRecord(channel);
mService.addEnqueuedNotification(r);
- when(mPreferencesHelper.getImportance(anyString(), anyInt())).thenReturn(IMPORTANCE_NONE);
+ when(mPermissionHelper.hasPermission(anyInt())).thenReturn(false);
NotificationManagerService.PostNotificationRunnable runnable =
mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
@@ -1390,8 +1415,32 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ public void testEnqueueNotificationInternal_noChannel() throws Exception {
+ when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
+ NotificationRecord nr = generateNotificationRecord(
+ new NotificationChannel("did not create", "", IMPORTANCE_DEFAULT));
+
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
+ nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
+ waitForIdle();
+
+ verify(mPermissionHelper).hasPermission(mUid);
+ verify(mPermissionHelper, never()).hasPermission(Process.SYSTEM_UID);
+
+ reset(mPermissionHelper);
+ when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
+
+ mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
+ nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
+ waitForIdle();
+
+ verify(mPermissionHelper).hasPermission(mUid);
+ assertThat(mService.mChannelToastsSent).contains(mUid);
+ }
+
+ @Test
public void testEnqueueNotification_appBlocked() throws Exception {
- mBinderService.setNotificationsEnabledForPackage(PKG, mUid, false);
+ when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
mBinderService.enqueueNotificationWithTag(PKG, PKG,
"testEnqueueNotification_appBlocked", 0,
@@ -2686,6 +2735,49 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ public void testDefaultChannelUpdatesApp_postMigrationToPermissions() throws Exception {
+ final NotificationChannel defaultChannel = mBinderService.getNotificationChannel(
+ PKG_N_MR1, ActivityManager.getCurrentUser(), PKG_N_MR1,
+ NotificationChannel.DEFAULT_CHANNEL_ID);
+ defaultChannel.setImportance(IMPORTANCE_NONE);
+
+ mBinderService.updateNotificationChannelForPackage(PKG_N_MR1, mUid, defaultChannel);
+
+ verify(mPermissionHelper).setNotificationPermission(
+ PKG_N_MR1, ActivityManager.getCurrentUser(), false, true);
+ }
+
+ @Test
+ public void testPostNotification_appPermissionFixed() throws Exception {
+ when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
+ when(mPermissionHelper.isPermissionFixed(PKG, 0)).thenReturn(true);
+
+ NotificationRecord temp = generateNotificationRecord(mTestNotificationChannel);
+ mBinderService.enqueueNotificationWithTag(PKG, PKG,
+ "testPostNotification_appPermissionFixed", 0,
+ temp.getNotification(), 0);
+ waitForIdle();
+ assertThat(mService.getNotificationRecordCount()).isEqualTo(1);
+ StatusBarNotification[] notifs =
+ mBinderService.getActiveNotifications(PKG);
+ assertThat(mService.getNotificationRecord(notifs[0].getKey()).isImportanceFixed()).isTrue();
+ }
+
+ @Test
+ public void testSummaryNotification_appPermissionFixed() {
+ NotificationRecord temp = generateNotificationRecord(mTestNotificationChannel);
+ mService.addNotification(temp);
+
+ when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
+ when(mPermissionHelper.isPermissionFixed(PKG, temp.getUserId())).thenReturn(true);
+
+ NotificationRecord r = mService.createAutoGroupSummary(
+ temp.getUserId(), temp.getSbn().getPackageName(), temp.getKey(), false);
+
+ assertThat(r.isImportanceFixed()).isTrue();
+ }
+
+ @Test
public void testTvExtenderChannelOverride_onTv() throws Exception {
mService.setIsTelevision(true);
mService.setPreferencesHelper(mPreferencesHelper);
@@ -2718,13 +2810,12 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
public void testUpdateAppNotifyCreatorBlock() throws Exception {
- mService.setPreferencesHelper(mPreferencesHelper);
- when(mPreferencesHelper.getImportance(PKG, mUid)).thenReturn(IMPORTANCE_DEFAULT);
+ when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
- // should trigger a broadcast
mBinderService.setNotificationsEnabledForPackage(PKG, mUid, false);
Thread.sleep(500);
waitForIdle();
+
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null));
@@ -2736,7 +2827,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
public void testUpdateAppNotifyCreatorBlock_notIfMatchesExistingSetting() throws Exception {
- mService.setPreferencesHelper(mPreferencesHelper);
+ when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
mBinderService.setNotificationsEnabledForPackage(PKG, 0, false);
verify(mContext, never()).sendBroadcastAsUser(any(), any(), eq(null));
@@ -2744,15 +2835,12 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
public void testUpdateAppNotifyCreatorUnblock() throws Exception {
- mService.setPreferencesHelper(mPreferencesHelper);
-
- // should not trigger a broadcast
- when(mAppOpsManager.checkOpNoThrow(anyInt(), eq(mUid), eq(PKG))).thenReturn(MODE_ALLOWED);
+ when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
- // should trigger a broadcast
- mBinderService.setNotificationsEnabledForPackage(PKG, 0, true);
+ mBinderService.setNotificationsEnabledForPackage(PKG, mUid, true);
Thread.sleep(500);
waitForIdle();
+
ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null));
@@ -4344,7 +4432,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
assertEquals(IMPORTANCE_LOW,
mService.getNotificationRecord(sbn.getKey()).getImportance());
- assertEquals(IMPORTANCE_UNSPECIFIED, mBinderService.getPackageImportance(
+ assertEquals(IMPORTANCE_DEFAULT, mBinderService.getPackageImportance(
sbn.getPackageName()));
nb = new Notification.Builder(mContext)
@@ -4860,6 +4948,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
@Test
public void testBackup() throws Exception {
+ mService.setPreferencesHelper(mPreferencesHelper);
int systemChecks = mService.countSystemChecks;
when(mListeners.queryPackageForServices(anyString(), anyInt(), anyInt()))
.thenReturn(new ArraySet<>());
@@ -5963,8 +6052,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
.thenReturn(false);
// notifications from this package are blocked by the user
- mService.setPreferencesHelper(mPreferencesHelper);
- when(mPreferencesHelper.getImportance(testPackage, mUid)).thenReturn(IMPORTANCE_NONE);
+ when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
setAppInForegroundForToasts(mUid, true);
@@ -6260,8 +6348,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
.thenReturn(false);
// notifications from this package are blocked by the user
- mService.setPreferencesHelper(mPreferencesHelper);
- when(mPreferencesHelper.getImportance(testPackage, mUid)).thenReturn(IMPORTANCE_NONE);
+ when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
setAppInForegroundForToasts(mUid, false);
@@ -6347,8 +6434,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
.thenReturn(true);
// notifications from this package are NOT blocked by the user
- mService.setPreferencesHelper(mPreferencesHelper);
- when(mPreferencesHelper.getImportance(testPackage, mUid)).thenReturn(IMPORTANCE_LOW);
+ when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
// enqueue toast -> no toasts enqueued
((INotificationManager) mService.mService).enqueueToast(testPackage, new Binder(),
@@ -6369,8 +6455,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
.thenReturn(false);
// notifications from this package are blocked by the user
- mService.setPreferencesHelper(mPreferencesHelper);
- when(mPreferencesHelper.getImportance(testPackage, mUid)).thenReturn(IMPORTANCE_NONE);
+ when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
setAppInForegroundForToasts(mUid, false);
@@ -6393,8 +6478,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
.thenReturn(true);
// notifications from this package ARE blocked by the user
- mService.setPreferencesHelper(mPreferencesHelper);
- when(mPreferencesHelper.getImportance(testPackage, mUid)).thenReturn(IMPORTANCE_NONE);
+ when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
setAppInForegroundForToasts(mUid, false);
@@ -7303,6 +7387,14 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ public void testAreNotificationsEnabledForPackage() throws Exception {
+ mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(),
+ mUid);
+
+ verify(mPermissionHelper).hasPermission(mUid);
+ }
+
+ @Test
public void testAreNotificationsEnabledForPackage_crossUser() throws Exception {
try {
mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(),
@@ -7311,21 +7403,31 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
} catch (SecurityException e) {
// pass
}
+ verify(mPermissionHelper, never()).hasPermission(anyInt());
// cross user, with permission, no problem
enableInteractAcrossUsers();
mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(),
mUid + UserHandle.PER_USER_RANGE);
- verify(mPermissionHelper, never()).hasPermission(anyInt());
+ verify(mPermissionHelper).hasPermission(mUid + UserHandle.PER_USER_RANGE);
}
@Test
- public void testAreNotificationsEnabledForPackage_viaInternalService() throws Exception {
- assertEquals(mInternalService.areNotificationsEnabledForPackage(
- mContext.getPackageName(), mUid),
- mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(), mUid));
- verify(mPermissionHelper, never()).hasPermission(anyInt());
+ public void testAreNotificationsEnabledForPackage_viaInternalService() {
+ mInternalService.areNotificationsEnabledForPackage(mContext.getPackageName(), mUid);
+ verify(mPermissionHelper).hasPermission(mUid);
+ }
+
+ @Test
+ public void testGetPackageImportance() throws Exception {
+ when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
+ assertThat(mBinderService.getPackageImportance(mContext.getPackageName()))
+ .isEqualTo(IMPORTANCE_DEFAULT);
+
+ when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
+ assertThat(mBinderService.getPackageImportance(mContext.getPackageName()))
+ .isEqualTo(IMPORTANCE_NONE);
}
@Test
@@ -8975,48 +9077,13 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
- public void testMigrationDisabledByDefault() {
- assertThat(mService.mEnableAppSettingMigration).isFalse();
- }
-
- @Test
- public void testPostNotification_channelLockedFixed() throws Exception {
- mTestNotificationChannel.setImportanceLockedByOEM(true);
-
- NotificationRecord temp = generateNotificationRecord(mTestNotificationChannel);
- mBinderService.enqueueNotificationWithTag(PKG, PKG,
- "testPostNotification_appPermissionFixed", 0,
- temp.getNotification(), 0);
- waitForIdle();
- assertThat(mService.getNotificationRecordCount()).isEqualTo(1);
- StatusBarNotification[] notifs =
- mBinderService.getActiveNotifications(PKG);
- assertThat(mService.getNotificationRecord(notifs[0].getKey()).isImportanceFixed()).isTrue();
-
- mBinderService.cancelAllNotifications(PKG, 0);
- waitForIdle();
-
- mTestNotificationChannel.setImportanceLockedByOEM(false);
- mTestNotificationChannel.setImportanceLockedByCriticalDeviceFunction(true);
-
- temp = generateNotificationRecord(mTestNotificationChannel);
- mBinderService.enqueueNotificationWithTag(PKG, PKG,
- "testPostNotification_appPermissionFixed", 0,
- temp.getNotification(), 0);
- waitForIdle();
- assertThat(mService.getNotificationRecordCount()).isEqualTo(1);
- notifs = mBinderService.getActiveNotifications(PKG);
- assertThat(mService.getNotificationRecord(notifs[0].getKey()).isImportanceFixed()).isTrue();
- }
-
- @Test
public void testGetNotificationChannelsBypassingDnd_blocked() throws RemoteException {
mService.setPreferencesHelper(mPreferencesHelper);
- when(mPreferencesHelper.getImportance(PKG, mUid)).thenReturn(IMPORTANCE_NONE);
+
+ when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
assertThat(mBinderService.getNotificationChannelsBypassingDnd(PKG, mUid).getList())
.isEmpty();
- verify(mPermissionHelper, never()).hasPermission(anyInt());
verify(mPreferencesHelper, never()).getNotificationChannelsBypassingDnd(PKG, mUid);
}
@@ -9110,8 +9177,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
- mBinderService.setNotificationsEnabledForPackage(
- r.getSbn().getPackageName(), r.getUid(), false);
+ when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
// normal blocked notifications - blocked
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
@@ -9149,6 +9215,67 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
}
@Test
+ public void testMediaNotificationsBypassBlock_atPost() throws Exception {
+ when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
+ when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
+
+ Notification.Builder nb = new Notification.Builder(
+ mContext, mTestNotificationChannel.getId())
+ .setContentTitle("foo")
+ .setSmallIcon(android.R.drawable.sym_def_app_icon)
+ .addAction(new Notification.Action.Builder(null, "test", null).build());
+ StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0,
+ nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
+ NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+ when(mPermissionHelper.hasPermission(anyInt())).thenReturn(false);
+
+ mService.addEnqueuedNotification(r);
+ NotificationManagerService.PostNotificationRunnable runnable =
+ mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
+ r.getUid(), SystemClock.elapsedRealtime());
+ runnable.run();
+ waitForIdle();
+
+ verify(mUsageStats).registerBlocked(any());
+ verify(mUsageStats, never()).registerPostedByApp(any());
+
+ // just using the style - blocked
+ mService.clearNotifications();
+ reset(mUsageStats);
+ nb.setStyle(new Notification.MediaStyle());
+ sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0,
+ nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
+ r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+ mService.addEnqueuedNotification(r);
+ runnable = mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
+ r.getUid(), SystemClock.elapsedRealtime());
+ runnable.run();
+ waitForIdle();
+
+ verify(mUsageStats).registerBlocked(any());
+ verify(mUsageStats, never()).registerPostedByApp(any());
+
+ // style + media session - bypasses block
+ mService.clearNotifications();
+ reset(mUsageStats);
+ nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class)));
+ sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0,
+ nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
+ r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+ mService.addEnqueuedNotification(r);
+ runnable = mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
+ r.getUid(), SystemClock.elapsedRealtime());
+ runnable.run();
+ waitForIdle();
+
+ verify(mUsageStats, never()).registerBlocked(any());
+ verify(mUsageStats).registerPostedByApp(any());
+ }
+
+ @Test
public void testCallNotificationsBypassBlock() throws Exception {
when(mAmi.getPendingIntentFlags(any(IIntentSender.class)))
.thenReturn(FLAG_MUTABLE | FLAG_ONE_SHOT);
@@ -9163,8 +9290,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
- mBinderService.setNotificationsEnabledForPackage(
- r.getSbn().getPackageName(), r.getUid(), false);
+ when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
// normal blocked notifications - blocked
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
@@ -9194,12 +9320,152 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
r.getSbn().getPackageName(), r.getUser())).thenReturn(true);
assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
r.getSbn().getId(), r.getSbn().getTag(), r, false)).isTrue();
+
+ // set telecom manager to null - blocked
+ mService.setTelecomManager(null);
+ assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
+ r.getSbn().getId(), r.getSbn().getTag(), r, false))
+ .isFalse();
+
+ // set telecom feature to false - blocked
+ when(mPackageManagerClient.hasSystemFeature(FEATURE_TELECOM)).thenReturn(false);
+ assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
+ r.getSbn().getId(), r.getSbn().getTag(), r, false))
+ .isFalse();
+ }
+
+ @Test
+ public void testCallNotificationsBypassBlock_atPost() throws Exception {
+ when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
+ when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
+
+ Notification.Builder nb =
+ new Notification.Builder(mContext, mTestNotificationChannel.getId())
+ .setContentTitle("foo")
+ .setSmallIcon(android.R.drawable.sym_def_app_icon)
+ .addAction(new Notification.Action.Builder(null, "test", null).build());
+ StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0,
+ nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
+ NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+ mBinderService.setNotificationsEnabledForPackage(
+ r.getSbn().getPackageName(), r.getUid(), false);
+
+ // normal blocked notifications - blocked
+ mService.addEnqueuedNotification(r);
+ NotificationManagerService.PostNotificationRunnable runnable =
+ mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
+ r.getUid(), SystemClock.elapsedRealtime());
+ runnable.run();
+ waitForIdle();
+
+ verify(mUsageStats).registerBlocked(any());
+ verify(mUsageStats, never()).registerPostedByApp(any());
+
+ // just using the style - blocked
+ mService.clearNotifications();
+ reset(mUsageStats);
+ Person person = new Person.Builder().setName("caller").build();
+ nb.setStyle(Notification.CallStyle.forOngoingCall(person, mock(PendingIntent.class)));
+ nb.setFullScreenIntent(mock(PendingIntent.class), true);
+ sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0, nb.build(),
+ UserHandle.getUserHandleForUid(mUid), null, 0);
+ r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+ mService.addEnqueuedNotification(r);
+ runnable = mService.new PostNotificationRunnable(
+ r.getKey(), r.getSbn().getPackageName(), r.getUid(), SystemClock.elapsedRealtime());
+ runnable.run();
+ waitForIdle();
+
+ verify(mUsageStats).registerBlocked(any());
+ verify(mUsageStats, never()).registerPostedByApp(any());
+
+ // style + managed call - bypasses block
+ mService.clearNotifications();
+ reset(mUsageStats);
+ when(mTelecomManager.isInManagedCall()).thenReturn(true);
+
+ mService.addEnqueuedNotification(r);
+ runnable.run();
+ waitForIdle();
+
+ verify(mUsageStats, never()).registerBlocked(any());
+ verify(mUsageStats).registerPostedByApp(any());
+
+ // style + self managed call - bypasses block
+ mService.clearNotifications();
+ reset(mUsageStats);
+ when(mTelecomManager.isInSelfManagedCall(r.getSbn().getPackageName(), r.getUser()))
+ .thenReturn(true);
+
+ mService.addEnqueuedNotification(r);
+ runnable.run();
+ waitForIdle();
+
+ verify(mUsageStats, never()).registerBlocked(any());
+ verify(mUsageStats).registerPostedByApp(any());
+
+ // set telecom manager to null - notifications should be blocked
+ // but post notifications runnable should not crash
+ mService.clearNotifications();
+ reset(mUsageStats);
+ mService.setTelecomManager(null);
+
+ mService.addEnqueuedNotification(r);
+ runnable.run();
+ waitForIdle();
+
+ verify(mUsageStats).registerBlocked(any());
+ verify(mUsageStats, never()).registerPostedByApp(any());
+
+ // set FEATURE_TELECOM to false - notifications should be blocked
+ // but post notifications runnable should not crash
+ mService.setTelecomManager(mTelecomManager);
+ when(mPackageManagerClient.hasSystemFeature(FEATURE_TELECOM)).thenReturn(false);
+ reset(mUsageStats);
+ mService.setTelecomManager(null);
+
+ mService.addEnqueuedNotification(r);
+ runnable.run();
+ waitForIdle();
+
+ verify(mUsageStats).registerBlocked(any());
+ verify(mUsageStats, never()).registerPostedByApp(any());
}
@Test
- public void testGetAllUsersNotificationPermissions_migrationNotEnabled() {
- // make sure we don't bother if the migration is not enabled
- assertThat(mService.getAllUsersNotificationPermissions()).isNull();
+ public void testGetAllUsersNotificationPermissions() {
+ // In this case, there are multiple users each with notification permissions (and also,
+ // for good measure, some without).
+ // make sure the collection returned contains info for all of them
+ final List<UserInfo> userInfos = new ArrayList<>();
+ userInfos.add(new UserInfo(0, "user0", 0));
+ userInfos.add(new UserInfo(1, "user1", 0));
+ userInfos.add(new UserInfo(2, "user2", 0));
+ when(mUm.getUsers()).thenReturn(userInfos);
+
+ // construct the permissions for each of them
+ ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> permissions0 = new ArrayMap<>(),
+ permissions1 = new ArrayMap<>();
+ permissions0.put(new Pair<>(10, "package1"), new Pair<>(true, false));
+ permissions0.put(new Pair<>(20, "package2"), new Pair<>(false, true));
+ permissions1.put(new Pair<>(11, "package1"), new Pair<>(false, false));
+ permissions1.put(new Pair<>(21, "package2"), new Pair<>(true, true));
+ when(mPermissionHelper.getNotificationPermissionValues(0)).thenReturn(permissions0);
+ when(mPermissionHelper.getNotificationPermissionValues(1)).thenReturn(permissions1);
+ when(mPermissionHelper.getNotificationPermissionValues(2)).thenReturn(new ArrayMap<>());
+
+ ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> combinedPermissions =
+ mService.getAllUsersNotificationPermissions();
+ assertTrue(combinedPermissions.get(new Pair<>(10, "package1")).first);
+ assertFalse(combinedPermissions.get(new Pair<>(10, "package1")).second);
+ assertFalse(combinedPermissions.get(new Pair<>(20, "package2")).first);
+ assertTrue(combinedPermissions.get(new Pair<>(20, "package2")).second);
+ assertFalse(combinedPermissions.get(new Pair<>(11, "package1")).first);
+ assertFalse(combinedPermissions.get(new Pair<>(11, "package1")).second);
+ assertTrue(combinedPermissions.get(new Pair<>(21, "package2")).first);
+ assertTrue(combinedPermissions.get(new Pair<>(21, "package2")).second);
}
@Test
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java
deleted file mode 100755
index b751c7fc73ea..000000000000
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationPermissionMigrationTest.java
+++ /dev/null
@@ -1,877 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.notification;
-
-import static android.app.AppOpsManager.MODE_ALLOWED;
-import static android.app.AppOpsManager.MODE_IGNORED;
-import static android.app.NotificationManager.EXTRA_BLOCKED_STATE;
-import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
-import static android.app.NotificationManager.IMPORTANCE_NONE;
-import static android.app.PendingIntent.FLAG_MUTABLE;
-import static android.app.PendingIntent.FLAG_ONE_SHOT;
-import static android.content.pm.PackageManager.FEATURE_WATCH;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.os.UserHandle.USER_SYSTEM;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertNotNull;
-import static junit.framework.Assert.assertTrue;
-import static junit.framework.Assert.fail;
-
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.anyLong;
-import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.clearInvocations;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.app.ActivityManager;
-import android.app.ActivityManagerInternal;
-import android.app.AlarmManager;
-import android.app.AppOpsManager;
-import android.app.IActivityManager;
-import android.app.INotificationManager;
-import android.app.IUriGrantsManager;
-import android.app.Notification;
-import android.app.NotificationChannel;
-import android.app.NotificationManager;
-import android.app.StatsManager;
-import android.app.admin.DevicePolicyManagerInternal;
-import android.app.usage.UsageStatsManagerInternal;
-import android.companion.ICompanionDeviceManager;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.IIntentSender;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.IPackageManager;
-import android.content.pm.LauncherApps;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal;
-import android.content.pm.ParceledListSlice;
-import android.content.pm.ShortcutInfo;
-import android.content.pm.ShortcutServiceInternal;
-import android.content.pm.UserInfo;
-import android.content.res.Resources;
-import android.media.AudioManager;
-import android.media.session.MediaSession;
-import android.os.Binder;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.provider.Settings;
-import android.service.notification.NotificationListenerFilter;
-import android.service.notification.StatusBarNotification;
-import android.telecom.TelecomManager;
-import android.telephony.TelephonyManager;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.testing.AndroidTestingRunner;
-import android.testing.TestableContext;
-import android.testing.TestableLooper;
-import android.testing.TestableLooper.RunWithLooper;
-import android.testing.TestablePermissions;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.AtomicFile;
-import android.util.Pair;
-
-import androidx.test.InstrumentationRegistry;
-
-import com.android.internal.app.IAppOpsService;
-import com.android.internal.logging.InstanceIdSequence;
-import com.android.internal.logging.InstanceIdSequenceFake;
-import com.android.server.DeviceIdleInternal;
-import com.android.server.LocalServices;
-import com.android.server.SystemService;
-import com.android.server.UiServiceTestCase;
-import com.android.server.lights.LightsManager;
-import com.android.server.lights.LogicalLight;
-import com.android.server.notification.NotificationManagerService.NotificationAssistants;
-import com.android.server.notification.NotificationManagerService.NotificationListeners;
-import com.android.server.statusbar.StatusBarManagerInternal;
-import com.android.server.uri.UriGrantsManagerInternal;
-import com.android.server.utils.quota.MultiRateLimiter;
-import com.android.server.wm.ActivityTaskManagerInternal;
-import com.android.server.wm.WindowManagerInternal;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.mockito.stubbing.Answer;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-
-
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-@RunWithLooper
-/**
- * Tests that NMS reads/writes the app notification state from Package/PermissionManager when
- * migration is enabled. Because the migration field is read onStart
- * TODO (b/194833441): migrate these tests to NotificationManagerServiceTest when the migration is
- * permanently enabled.
- */
-public class NotificationPermissionMigrationTest extends UiServiceTestCase {
- private static final String TEST_CHANNEL_ID = "NotificationManagerServiceTestChannelId";
- private static final int UID_HEADLESS = 1000000;
-
- private final int mUid = Binder.getCallingUid();
- private TestableNotificationManagerService mService;
- private INotificationManager mBinderService;
- private NotificationManagerInternal mInternalService;
- private ShortcutHelper mShortcutHelper;
- @Mock
- private IPackageManager mPackageManager;
- @Mock
- private PackageManager mPackageManagerClient;
- @Mock
- private PackageManagerInternal mPackageManagerInternal;
- @Mock
- private WindowManagerInternal mWindowManagerInternal;
- @Mock
- private PermissionHelper mPermissionHelper;
- private TestableContext mContext = spy(getContext());
- private final String PKG = mContext.getPackageName();
- private TestableLooper mTestableLooper;
- @Mock
- private RankingHelper mRankingHelper;
- @Mock private PreferencesHelper mPreferencesHelper;
- AtomicFile mPolicyFile;
- File mFile;
- @Mock
- private NotificationUsageStats mUsageStats;
- @Mock
- private UsageStatsManagerInternal mAppUsageStats;
- @Mock
- private AudioManager mAudioManager;
- @Mock
- private LauncherApps mLauncherApps;
- @Mock
- private ShortcutServiceInternal mShortcutServiceInternal;
- @Mock
- private UserManager mUserManager;
- @Mock
- ActivityManager mActivityManager;
- @Mock
- Resources mResources;
- @Mock
- RankingHandler mRankingHandler;
- @Mock
- ActivityManagerInternal mAmi;
- @Mock
- private Looper mMainLooper;
-
- @Mock
- IIntentSender pi1;
-
- private static final int MAX_POST_DELAY = 1000;
-
- private NotificationChannel mTestNotificationChannel = new NotificationChannel(
- TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT);
-
- private static final String VALID_CONVO_SHORTCUT_ID = "shortcut";
-
- @Mock
- private NotificationListeners mListeners;
- @Mock
- private NotificationListenerFilter mNlf;
- @Mock private NotificationAssistants mAssistants;
- @Mock private ConditionProviders mConditionProviders;
- private ManagedServices.ManagedServiceInfo mListener;
- @Mock private ICompanionDeviceManager mCompanionMgr;
- @Mock SnoozeHelper mSnoozeHelper;
- @Mock GroupHelper mGroupHelper;
- @Mock
- IBinder mPermOwner;
- @Mock
- IActivityManager mAm;
- @Mock
- ActivityTaskManagerInternal mAtm;
- @Mock
- IUriGrantsManager mUgm;
- @Mock
- UriGrantsManagerInternal mUgmInternal;
- @Mock
- AppOpsManager mAppOpsManager;
- @Mock
- private TestableNotificationManagerService.NotificationAssistantAccessGrantedCallback
- mNotificationAssistantAccessGrantedCallback;
- @Mock
- UserManager mUm;
- @Mock
- NotificationHistoryManager mHistoryManager;
- @Mock
- StatsManager mStatsManager;
- @Mock
- AlarmManager mAlarmManager;
- @Mock
- MultiRateLimiter mToastRateLimiter;
- BroadcastReceiver mPackageIntentReceiver;
- NotificationRecordLoggerFake mNotificationRecordLogger = new NotificationRecordLoggerFake();
- private InstanceIdSequence mNotificationInstanceIdSequence = new InstanceIdSequenceFake(
- 1 << 30);
- @Mock
- StatusBarManagerInternal mStatusBar;
-
- private NotificationManagerService.WorkerHandler mWorkerHandler;
-
- @Before
- public void setUp() throws Exception {
- // These should be the only difference in setup from NMSTest
- Settings.Secure.putIntForUser(
- getContext().getContentResolver(),
- Settings.Secure.NOTIFICATION_PERMISSION_ENABLED, 1, USER_SYSTEM);
- Settings.Global.putInt(getContext().getContentResolver(),
- Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, 1);
-
- // Shell permissions will override permissions of our app, so add all necessary permissions
- // for this test here:
- InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
- "android.permission.WRITE_DEVICE_CONFIG",
- "android.permission.READ_DEVICE_CONFIG",
- "android.permission.READ_CONTACTS");
-
- MockitoAnnotations.initMocks(this);
-
- when(mPermissionHelper.isMigrationEnabled()).thenReturn(true);
-
- DeviceIdleInternal deviceIdleInternal = mock(DeviceIdleInternal.class);
- when(deviceIdleInternal.getNotificationAllowlistDuration()).thenReturn(3000L);
-
- LocalServices.removeServiceForTest(UriGrantsManagerInternal.class);
- LocalServices.addService(UriGrantsManagerInternal.class, mUgmInternal);
- LocalServices.removeServiceForTest(WindowManagerInternal.class);
- LocalServices.addService(WindowManagerInternal.class, mWindowManagerInternal);
- LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
- LocalServices.addService(StatusBarManagerInternal.class, mStatusBar);
- LocalServices.removeServiceForTest(DeviceIdleInternal.class);
- LocalServices.addService(DeviceIdleInternal.class, deviceIdleInternal);
- LocalServices.removeServiceForTest(ActivityManagerInternal.class);
- LocalServices.addService(ActivityManagerInternal.class, mAmi);
- LocalServices.removeServiceForTest(PackageManagerInternal.class);
- LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal);
- mContext.addMockSystemService(Context.ALARM_SERVICE, mAlarmManager);
- when(mUm.getProfileIds(0, false)).thenReturn(new int[]{0});
-
- doNothing().when(mContext).sendBroadcastAsUser(any(), any(), any());
-
- mService = new TestableNotificationManagerService(mContext, mNotificationRecordLogger,
- mNotificationInstanceIdSequence);
-
- // Use this testable looper.
- mTestableLooper = TestableLooper.get(this);
- // MockPackageManager - default returns ApplicationInfo with matching calling UID
- mContext.setMockPackageManager(mPackageManagerClient);
-
- when(mPackageManager.getApplicationInfo(anyString(), anyLong(), anyInt()))
- .thenAnswer((Answer<ApplicationInfo>) invocation -> {
- Object[] args = invocation.getArguments();
- return getApplicationInfo((String) args[0], mUid);
- });
- when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
- .thenAnswer((Answer<ApplicationInfo>) invocation -> {
- Object[] args = invocation.getArguments();
- return getApplicationInfo((String) args[0], mUid);
- });
- when(mPackageManagerClient.getPackageUidAsUser(any(), anyInt())).thenReturn(mUid);
- when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenAnswer(
- (Answer<Boolean>) invocation -> {
- Object[] args = invocation.getArguments();
- return (int) args[1] == mUid;
- });
- final LightsManager mockLightsManager = mock(LightsManager.class);
- when(mockLightsManager.getLight(anyInt())).thenReturn(mock(LogicalLight.class));
- when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
- when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(false);
- when(mUgmInternal.newUriPermissionOwner(anyString())).thenReturn(mPermOwner);
- when(mPackageManager.getPackagesForUid(mUid)).thenReturn(new String[]{PKG});
- when(mPackageManagerClient.getPackagesForUid(anyInt())).thenReturn(new String[]{PKG});
- mContext.addMockSystemService(AppOpsManager.class, mock(AppOpsManager.class));
-
- // write to a test file; the system file isn't readable from tests
- mFile = new File(mContext.getCacheDir(), "test.xml");
- mFile.createNewFile();
- final String preupgradeXml = "<notification-policy></notification-policy>";
- mPolicyFile = new AtomicFile(mFile);
- FileOutputStream fos = mPolicyFile.startWrite();
- fos.write(preupgradeXml.getBytes());
- mPolicyFile.finishWrite(fos);
-
- // Setup managed services
- when(mNlf.isTypeAllowed(anyInt())).thenReturn(true);
- when(mNlf.isPackageAllowed(any())).thenReturn(true);
- when(mNlf.isPackageAllowed(null)).thenReturn(true);
- when(mListeners.getNotificationListenerFilter(any())).thenReturn(mNlf);
- mListener = mListeners.new ManagedServiceInfo(
- null, new ComponentName(PKG, "test_class"),
- UserHandle.getUserId(mUid), true, null, 0, 123);
- ComponentName defaultComponent = ComponentName.unflattenFromString("config/device");
- ArraySet<ComponentName> components = new ArraySet<>();
- components.add(defaultComponent);
- when(mListeners.getDefaultComponents()).thenReturn(components);
- when(mConditionProviders.getDefaultPackages())
- .thenReturn(new ArraySet<>(Arrays.asList("config")));
- when(mAssistants.getDefaultComponents()).thenReturn(components);
- when(mAssistants.queryPackageForServices(
- anyString(), anyInt(), anyInt())).thenReturn(components);
- when(mListeners.checkServiceTokenLocked(null)).thenReturn(mListener);
- ManagedServices.Config listenerConfig = new ManagedServices.Config();
- listenerConfig.xmlTag = NotificationListeners.TAG_ENABLED_NOTIFICATION_LISTENERS;
- when(mListeners.getConfig()).thenReturn(listenerConfig);
- ManagedServices.Config assistantConfig = new ManagedServices.Config();
- assistantConfig.xmlTag = NotificationAssistants.TAG_ENABLED_NOTIFICATION_ASSISTANTS;
- when(mAssistants.getConfig()).thenReturn(assistantConfig);
- ManagedServices.Config dndConfig = new ManagedServices.Config();
- dndConfig.xmlTag = ConditionProviders.TAG_ENABLED_DND_APPS;
- when(mConditionProviders.getConfig()).thenReturn(dndConfig);
-
- when(mAssistants.isAdjustmentAllowed(anyString())).thenReturn(true);
-
- // apps allowed as convos
- mService.setStringArrayResourceValue(PKG_O);
-
- mWorkerHandler = spy(mService.new WorkerHandler(mTestableLooper.getLooper()));
- mService.init(mWorkerHandler, mRankingHandler, mPackageManager, mPackageManagerClient,
- mockLightsManager, mListeners, mAssistants, mConditionProviders, mCompanionMgr,
- mSnoozeHelper, mUsageStats, mPolicyFile, mActivityManager, mGroupHelper, mAm, mAtm,
- mAppUsageStats, mock(DevicePolicyManagerInternal.class), mUgm, mUgmInternal,
- mAppOpsManager, mock(IAppOpsService.class), mUm, mHistoryManager, mStatsManager,
- mock(TelephonyManager.class), mAmi, mToastRateLimiter, mPermissionHelper,
- mock(UsageStatsManagerInternal.class), mock(TelecomManager.class));
- // Return first true for RoleObserver main-thread check
- when(mMainLooper.isCurrentThread()).thenReturn(true).thenReturn(false);
- mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY, mMainLooper);
-
- mService.setAudioManager(mAudioManager);
-
- mShortcutHelper = mService.getShortcutHelper();
- mShortcutHelper.setLauncherApps(mLauncherApps);
- mShortcutHelper.setShortcutServiceInternal(mShortcutServiceInternal);
- mShortcutHelper.setUserManager(mUserManager);
-
- // Capture PackageIntentReceiver
- ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
- ArgumentCaptor.forClass(BroadcastReceiver.class);
- ArgumentCaptor<IntentFilter> intentFilterCaptor =
- ArgumentCaptor.forClass(IntentFilter.class);
-
- verify(mContext, atLeastOnce()).registerReceiverAsUser(broadcastReceiverCaptor.capture(),
- any(), intentFilterCaptor.capture(), any(), any());
- verify(mContext, atLeastOnce()).registerReceiver(broadcastReceiverCaptor.capture(),
- intentFilterCaptor.capture());
- List<BroadcastReceiver> broadcastReceivers = broadcastReceiverCaptor.getAllValues();
- List<IntentFilter> intentFilters = intentFilterCaptor.getAllValues();
-
- for (int i = 0; i < intentFilters.size(); i++) {
- final IntentFilter filter = intentFilters.get(i);
- if (filter.hasAction(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED)
- && filter.hasAction(Intent.ACTION_PACKAGES_UNSUSPENDED)
- && filter.hasAction(Intent.ACTION_PACKAGES_SUSPENDED)) {
- mPackageIntentReceiver = broadcastReceivers.get(i);
- }
- }
- assertNotNull("package intent receiver should exist", mPackageIntentReceiver);
-
- // Pretend the shortcut exists
- List<ShortcutInfo> shortcutInfos = new ArrayList<>();
- ShortcutInfo info = mock(ShortcutInfo.class);
- when(info.getPackage()).thenReturn(PKG);
- when(info.getId()).thenReturn(VALID_CONVO_SHORTCUT_ID);
- when(info.getUserId()).thenReturn(USER_SYSTEM);
- when(info.isLongLived()).thenReturn(true);
- when(info.isEnabled()).thenReturn(true);
- shortcutInfos.add(info);
- when(mLauncherApps.getShortcuts(any(), any())).thenReturn(shortcutInfos);
- when(mShortcutServiceInternal.isSharingShortcut(anyInt(), anyString(), anyString(),
- anyString(), anyInt(), any())).thenReturn(true);
- when(mUserManager.isUserUnlocked(any(UserHandle.class))).thenReturn(true);
-
- // Set the testable bubble extractor
- RankingHelper rankingHelper = mService.getRankingHelper();
- BubbleExtractor extractor = rankingHelper.findExtractor(BubbleExtractor.class);
- extractor.setActivityManager(mActivityManager);
-
- // Tests call directly into the Binder.
- mBinderService = mService.getBinderService();
- mInternalService = mService.getInternalService();
-
- mBinderService.createNotificationChannels(
- PKG, new ParceledListSlice(Arrays.asList(mTestNotificationChannel)));
- mBinderService.createNotificationChannels(
- PKG_P, new ParceledListSlice(Arrays.asList(mTestNotificationChannel)));
- mBinderService.createNotificationChannels(
- PKG_O, new ParceledListSlice(Arrays.asList(mTestNotificationChannel)));
- assertNotNull(mBinderService.getNotificationChannel(
- PKG, mContext.getUserId(), PKG, TEST_CHANNEL_ID));
- clearInvocations(mRankingHandler);
- }
-
- @After
- public void tearDown() throws Exception {
- if (mFile != null) mFile.delete();
-
- try {
- mService.onDestroy();
- } catch (IllegalStateException | IllegalArgumentException e) {
- // can throw if a broadcast receiver was never registered
- }
-
- InstrumentationRegistry.getInstrumentation()
- .getUiAutomation().dropShellPermissionIdentity();
- // Remove scheduled messages that would be processed when the test is already done, and
- // could cause issues, for example, messages that remove/cancel shown toasts (this causes
- // problematic interactions with mocks when they're no longer working as expected).
- mWorkerHandler.removeCallbacksAndMessages(null);
- }
-
- private ApplicationInfo getApplicationInfo(String pkg, int uid) {
- final ApplicationInfo applicationInfo = new ApplicationInfo();
- applicationInfo.uid = uid;
- switch (pkg) {
- case PKG_N_MR1:
- applicationInfo.targetSdkVersion = Build.VERSION_CODES.N_MR1;
- break;
- case PKG_O:
- applicationInfo.targetSdkVersion = Build.VERSION_CODES.O;
- break;
- case PKG_P:
- applicationInfo.targetSdkVersion = Build.VERSION_CODES.P;
- break;
- default:
- applicationInfo.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT;
- break;
- }
- return applicationInfo;
- }
-
- public void waitForIdle() {
- mTestableLooper.processAllMessages();
- }
-
- private NotificationRecord generateNotificationRecord(NotificationChannel channel) {
- return generateNotificationRecord(channel, null);
- }
-
- private NotificationRecord generateNotificationRecord(NotificationChannel channel,
- Notification.TvExtender extender) {
- if (channel == null) {
- channel = mTestNotificationChannel;
- }
- Notification.Builder nb = new Notification.Builder(mContext, channel.getId())
- .setContentTitle("foo")
- .setSmallIcon(android.R.drawable.sym_def_app_icon)
- .addAction(new Notification.Action.Builder(null, "test", null).build());
- if (extender != null) {
- nb.extend(extender);
- }
- StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0,
- nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
- return new NotificationRecord(mContext, sbn, channel);
- }
-
- private void enableInteractAcrossUsers() {
- TestablePermissions perms = mContext.getTestablePermissions();
- perms.setPermission(android.Manifest.permission.INTERACT_ACROSS_USERS, PERMISSION_GRANTED);
- }
-
- @Test
- public void testAreNotificationsEnabledForPackage() throws Exception {
- mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(),
- mUid);
-
- verify(mPermissionHelper).hasPermission(mUid);
- }
-
- @Test
- public void testAreNotificationsEnabledForPackage_crossUser() throws Exception {
- try {
- mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(),
- mUid + UserHandle.PER_USER_RANGE);
- fail("Cannot call cross user without permission");
- } catch (SecurityException e) {
- // pass
- }
- verify(mPermissionHelper, never()).hasPermission(anyInt());
-
- // cross user, with permission, no problem
- enableInteractAcrossUsers();
- mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(),
- mUid + UserHandle.PER_USER_RANGE);
-
- verify(mPermissionHelper).hasPermission(mUid + UserHandle.PER_USER_RANGE);
- }
-
- @Test
- public void testAreNotificationsEnabledForPackage_viaInternalService() {
- mInternalService.areNotificationsEnabledForPackage(mContext.getPackageName(), mUid);
- verify(mPermissionHelper).hasPermission(mUid);
- }
-
- @Test
- public void testGetPackageImportance() throws Exception {
- when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
- assertThat(mBinderService.getPackageImportance(mContext.getPackageName()))
- .isEqualTo(IMPORTANCE_DEFAULT);
-
- when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
- assertThat(mBinderService.getPackageImportance(mContext.getPackageName()))
- .isEqualTo(IMPORTANCE_NONE);
- }
-
- @Test
- public void testEnqueueNotificationInternal_noChannel() throws Exception {
- when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
- NotificationRecord nr = generateNotificationRecord(
- new NotificationChannel("did not create", "", IMPORTANCE_DEFAULT));
-
- mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
- nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
- waitForIdle();
-
- verify(mPermissionHelper).hasPermission(mUid);
- verify(mPermissionHelper, never()).hasPermission(Process.SYSTEM_UID);
-
- reset(mPermissionHelper);
- when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
-
- mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(),
- nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId());
- waitForIdle();
-
- verify(mPermissionHelper).hasPermission(mUid);
- assertThat(mService.mChannelToastsSent).contains(mUid);
- }
-
- @Test
- public void testSetNotificationsEnabledForPackage_noChange() throws Exception {
- when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
- mBinderService.setNotificationsEnabledForPackage(mContext.getPackageName(), mUid, true);
-
- verify(mPermissionHelper, never()).setNotificationPermission(
- anyString(), anyInt(), anyBoolean(), anyBoolean());
- }
-
- @Test
- public void testSetNotificationsEnabledForPackage() throws Exception {
- when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
- mBinderService.setNotificationsEnabledForPackage(mContext.getPackageName(), mUid, false);
-
- verify(mPermissionHelper).setNotificationPermission(
- mContext.getPackageName(), UserHandle.getUserId(mUid), false, true);
-
- verify(mAppOpsManager, never()).setMode(anyInt(), anyInt(), anyString(), anyInt());
- }
-
- @Test
- public void testUpdateAppNotifyCreatorBlock() throws Exception {
- when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
-
- mBinderService.setNotificationsEnabledForPackage(PKG, mUid, false);
- Thread.sleep(500);
- waitForIdle();
-
- ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
- verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null));
-
- assertEquals(NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED,
- captor.getValue().getAction());
- assertEquals(PKG, captor.getValue().getPackage());
- assertTrue(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, true));
- }
-
- @Test
- public void testUpdateAppNotifyCreatorUnblock() throws Exception {
- when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
-
- mBinderService.setNotificationsEnabledForPackage(PKG, mUid, true);
- Thread.sleep(500);
- waitForIdle();
-
- ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
- verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null));
-
- assertEquals(NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED,
- captor.getValue().getAction());
- assertEquals(PKG, captor.getValue().getPackage());
- assertFalse(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, true));
- }
-
- @Test
- public void testGetNotificationChannelsBypassingDnd_blocked() throws RemoteException {
- mService.setPreferencesHelper(mPreferencesHelper);
-
- when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
-
- assertThat(mBinderService.getNotificationChannelsBypassingDnd(PKG, mUid).getList())
- .isEmpty();
- verify(mPreferencesHelper, never()).getImportance(anyString(), anyInt());
- verify(mPreferencesHelper, never()).getNotificationChannelsBypassingDnd(PKG, mUid);
- }
-
- @Test
- public void testBlockedNotifications_blockedByUser() throws Exception {
- when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
- when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
-
- NotificationChannel channel = new NotificationChannel("id", "name",
- NotificationManager.IMPORTANCE_HIGH);
- NotificationRecord r = generateNotificationRecord(channel);
- mService.addEnqueuedNotification(r);
-
- when(mPermissionHelper.hasPermission(anyInt())).thenReturn(false);
-
- NotificationManagerService.PostNotificationRunnable runnable =
- mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
- r.getUid(), SystemClock.elapsedRealtime());
- runnable.run();
- waitForIdle();
-
- verify(mUsageStats).registerBlocked(any());
- verify(mUsageStats, never()).registerPostedByApp(any());
- }
-
- @Test
- public void testEnqueueNotification_appBlocked() throws Exception {
- when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
-
- mBinderService.enqueueNotificationWithTag(PKG, PKG,
- "testEnqueueNotification_appBlocked", 0,
- generateNotificationRecord(null).getNotification(), 0);
- waitForIdle();
- verify(mWorkerHandler, never()).post(
- any(NotificationManagerService.EnqueueNotificationRunnable.class));
- }
-
- @Test
- public void testDefaultChannelDoesNotUpdateApp_postMigrationToPermissions() throws Exception {
- final NotificationChannel defaultChannel = mBinderService.getNotificationChannel(
- PKG_N_MR1, ActivityManager.getCurrentUser(), PKG_N_MR1,
- NotificationChannel.DEFAULT_CHANNEL_ID);
- defaultChannel.setImportance(IMPORTANCE_NONE);
-
- mBinderService.updateNotificationChannelForPackage(PKG_N_MR1, mUid, defaultChannel);
-
- verify(mPermissionHelper).setNotificationPermission(
- PKG_N_MR1, ActivityManager.getCurrentUser(), false, true);
- }
-
- @Test
- public void testPostNotification_appPermissionFixed() throws Exception {
- when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
- when(mPermissionHelper.isPermissionFixed(PKG, 0)).thenReturn(true);
-
- NotificationRecord temp = generateNotificationRecord(mTestNotificationChannel);
- mBinderService.enqueueNotificationWithTag(PKG, PKG,
- "testPostNotification_appPermissionFixed", 0,
- temp.getNotification(), 0);
- waitForIdle();
- assertThat(mService.getNotificationRecordCount()).isEqualTo(1);
- StatusBarNotification[] notifs =
- mBinderService.getActiveNotifications(PKG);
- assertThat(mService.getNotificationRecord(notifs[0].getKey()).isImportanceFixed()).isTrue();
- }
-
- @Test
- public void testSummaryNotification_appPermissionFixed() {
- NotificationRecord temp = generateNotificationRecord(mTestNotificationChannel);
- mService.addNotification(temp);
-
- when(mPermissionHelper.hasPermission(mUid)).thenReturn(true);
- when(mPermissionHelper.isPermissionFixed(PKG, temp.getUserId())).thenReturn(true);
-
- NotificationRecord r = mService.createAutoGroupSummary(
- temp.getUserId(), temp.getSbn().getPackageName(), temp.getKey(), false);
-
- assertThat(r.isImportanceFixed()).isTrue();
- }
-
- @Test
- public void testMediaNotificationsBypassBlock() throws Exception {
- when(mAmi.getPendingIntentFlags(any(IIntentSender.class)))
- .thenReturn(FLAG_MUTABLE | FLAG_ONE_SHOT);
- when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
-
- Notification.Builder nb = new Notification.Builder(
- mContext, mTestNotificationChannel.getId())
- .setContentTitle("foo")
- .setSmallIcon(android.R.drawable.sym_def_app_icon)
- .addAction(new Notification.Action.Builder(null, "test", null).build());
- StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0,
- nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
- NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
-
- when(mPermissionHelper.hasPermission(mUid)).thenReturn(false);
-
- // normal blocked notifications - blocked
- assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
- r.getSbn().getId(), r.getSbn().getTag(), r, false)).isFalse();
-
- // just using the style - blocked
- nb.setStyle(new Notification.MediaStyle());
- sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0,
- nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
- r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
-
- assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
- r.getSbn().getId(), r.getSbn().getTag(), r, false)).isFalse();
-
- // using the style, but incorrect type in session - blocked
- nb.setStyle(new Notification.MediaStyle());
- Bundle extras = new Bundle();
- extras.putParcelable(Notification.EXTRA_MEDIA_SESSION, new Intent());
- nb.addExtras(extras);
- sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0,
- nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
- r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
-
- assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
- r.getSbn().getId(), r.getSbn().getTag(), r, false)).isFalse();
-
- // style + media session - bypasses block
- nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class)));
- sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0,
- nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
- r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
-
- assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(),
- r.getSbn().getId(), r.getSbn().getTag(), r, false)).isTrue();
- }
-
- @Test
- public void testMediaNotificationsBypassBlock_atPost() throws Exception {
- when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
- when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true);
-
- Notification.Builder nb = new Notification.Builder(
- mContext, mTestNotificationChannel.getId())
- .setContentTitle("foo")
- .setSmallIcon(android.R.drawable.sym_def_app_icon)
- .addAction(new Notification.Action.Builder(null, "test", null).build());
- StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0,
- nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
- NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
-
- when(mPermissionHelper.hasPermission(anyInt())).thenReturn(false);
-
- mService.addEnqueuedNotification(r);
- NotificationManagerService.PostNotificationRunnable runnable =
- mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
- r.getUid(), SystemClock.elapsedRealtime());
- runnable.run();
- waitForIdle();
-
- verify(mUsageStats).registerBlocked(any());
- verify(mUsageStats, never()).registerPostedByApp(any());
-
- // just using the style - blocked
- mService.clearNotifications();
- reset(mUsageStats);
- nb.setStyle(new Notification.MediaStyle());
- sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0,
- nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
- r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
-
- mService.addEnqueuedNotification(r);
- runnable = mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
- r.getUid(), SystemClock.elapsedRealtime());
- runnable.run();
- waitForIdle();
-
- verify(mUsageStats).registerBlocked(any());
- verify(mUsageStats, never()).registerPostedByApp(any());
-
- // style + media session - bypasses block
- mService.clearNotifications();
- reset(mUsageStats);
- nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class)));
- sbn = new StatusBarNotification(PKG, PKG, 8, "tag", mUid, 0,
- nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0);
- r = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
-
- mService.addEnqueuedNotification(r);
- runnable = mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(),
- r.getUid(), SystemClock.elapsedRealtime());
- runnable.run();
- waitForIdle();
-
- verify(mUsageStats, never()).registerBlocked(any());
- verify(mUsageStats).registerPostedByApp(any());
- }
-
- @Test
- public void testGetAllUsersNotificationPermissions() {
- // In this case, there are multiple users each with notification permissions (and also,
- // for good measure, some without).
- // make sure the collection returned contains info for all of them
- final List<UserInfo> userInfos = new ArrayList<>();
- userInfos.add(new UserInfo(0, "user0", 0));
- userInfos.add(new UserInfo(1, "user1", 0));
- userInfos.add(new UserInfo(2, "user2", 0));
- when(mUm.getUsers()).thenReturn(userInfos);
-
- // construct the permissions for each of them
- ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> permissions0 = new ArrayMap<>(),
- permissions1 = new ArrayMap<>();
- permissions0.put(new Pair<>(10, "package1"), new Pair<>(true, false));
- permissions0.put(new Pair<>(20, "package2"), new Pair<>(false, true));
- permissions1.put(new Pair<>(11, "package1"), new Pair<>(false, false));
- permissions1.put(new Pair<>(21, "package2"), new Pair<>(true, true));
- when(mPermissionHelper.getNotificationPermissionValues(0)).thenReturn(permissions0);
- when(mPermissionHelper.getNotificationPermissionValues(1)).thenReturn(permissions1);
- when(mPermissionHelper.getNotificationPermissionValues(2)).thenReturn(new ArrayMap<>());
-
- ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> combinedPermissions =
- mService.getAllUsersNotificationPermissions();
- assertTrue(combinedPermissions.get(new Pair<>(10, "package1")).first);
- assertFalse(combinedPermissions.get(new Pair<>(10, "package1")).second);
- assertFalse(combinedPermissions.get(new Pair<>(20, "package2")).first);
- assertTrue(combinedPermissions.get(new Pair<>(20, "package2")).second);
- assertFalse(combinedPermissions.get(new Pair<>(11, "package1")).first);
- assertFalse(combinedPermissions.get(new Pair<>(11, "package1")).second);
- assertTrue(combinedPermissions.get(new Pair<>(21, "package2")).first);
- assertTrue(combinedPermissions.get(new Pair<>(21, "package2")).second);
- }
-}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
index d89141cc1000..5468220d9564 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
@@ -1065,9 +1065,8 @@ public class NotificationRecordTest extends UiServiceTestCase {
}
@Test
- public void testApplyImportanceAdjustmentsForNonOemDefaultAppLockedChannels() {
+ public void testApplyImportanceAdjustments() {
NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_DEFAULT);
- channel.setImportanceLockedByOEM(false);
StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java
index 46b47f4dcfdd..3a352cbe1900 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PermissionHelperTest.java
@@ -88,51 +88,13 @@ public class PermissionHelperTest extends UiServiceTestCase {
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mPermissionHelper = new PermissionHelper(mPmi, mPackageManager, mPermManager, true, false);
+ mPermissionHelper = new PermissionHelper(mPmi, mPackageManager, mPermManager, false);
PackageInfo testPkgInfo = new PackageInfo();
testPkgInfo.requestedPermissions = new String[]{ Manifest.permission.POST_NOTIFICATIONS };
when(mPackageManager.getPackageInfo(anyString(), anyLong(), anyInt()))
.thenReturn(testPkgInfo);
}
- // TODO (b/194833441): Remove when the migration is enabled
- @Test
- public void testMethodsThrowIfMigrationDisabled() throws IllegalAccessException,
- InvocationTargetException {
- PermissionHelper permHelper =
- new PermissionHelper(mPmi, mPackageManager, mPermManager, false, false);
-
- Method[] allMethods = PermissionHelper.class.getDeclaredMethods();
- for (Method method : allMethods) {
- if (Modifier.isPublic(method.getModifiers()) &&
- !Objects.equals("isMigrationEnabled", method.getName())) {
- Parameter[] params = method.getParameters();
- List<Object> args = Lists.newArrayListWithCapacity(params.length);
- for (int i = 0; i < params.length; i++) {
- Type type = params[i].getParameterizedType();
- if (type.getTypeName().equals("java.lang.String")) {
- args.add("");
- } else if (type.getTypeName().equals("boolean")){
- args.add(false);
- } else if (type.getTypeName().equals("int")) {
- args.add(1);
- } else if (type.getTypeName().equals(
- "com.android.server.notification.PermissionHelper$PackagePermission")) {
- args.add(null);
- }
- }
- try {
- method.invoke(permHelper, args.toArray());
- fail("Method should have thrown because migration flag is disabled");
- } catch (InvocationTargetException e) {
- if (!(e.getTargetException() instanceof IllegalStateException)) {
- throw e;
- }
- }
- }
- }
- }
-
@Test
public void testHasPermission() throws Exception {
when(mPmi.checkPostNotificationsPermissionGrantedOrLegacyAccess(anyInt()))
@@ -304,7 +266,7 @@ public class PermissionHelperTest extends UiServiceTestCase {
@Test
public void testSetNotificationPermission_pkgPerm_grantedByDefaultPermSet_allUserSet()
throws Exception {
- mPermissionHelper = new PermissionHelper(mPmi, mPackageManager, mPermManager, true, true);
+ mPermissionHelper = new PermissionHelper(mPmi, mPackageManager, mPermManager, true);
when(mPmi.checkPermission(anyString(), anyString(), anyInt()))
.thenReturn(PERMISSION_DENIED);
when(mPermManager.getPermissionFlags(anyString(),
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 6d0895935877..a5cec7e01e9a 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -278,6 +278,14 @@ public class PreferencesHelperTest extends UiServiceTestCase {
when(mAppOpsManager.noteOpNoThrow(anyInt(), anyInt(),
anyString(), eq(null), anyString())).thenReturn(MODE_DEFAULT);
+ ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
+ appPermissions.put(new Pair(UID_P, PKG_P), new Pair(true, false));
+ appPermissions.put(new Pair(UID_O, PKG_O), new Pair(true, false));
+ appPermissions.put(new Pair(UID_N_MR1, PKG_N_MR1), new Pair(true, false));
+
+ when(mPermissionHelper.getNotificationPermissionValues(USER_SYSTEM))
+ .thenReturn(appPermissions);
+
mStatsEventBuilderFactory = new WrappedSysUiStatsEvent.WrappedBuilderFactory();
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
@@ -408,6 +416,13 @@ public class PreferencesHelperTest extends UiServiceTestCase {
NotificationChannel channel10 = new NotificationChannel("id10", "name10", IMPORTANCE_HIGH);
assertTrue(mHelper.createNotificationChannel(package10, uid10, channel10, true, false));
+ ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
+ appPermissions.put(new Pair(uid0, package0), new Pair(false, false));
+ appPermissions.put(new Pair(uid10, package10), new Pair(true, false));
+
+ when(mPermissionHelper.getNotificationPermissionValues(10))
+ .thenReturn(appPermissions);
+
ByteArrayOutputStream baos = writeXmlAndPurge(package10, uid10, true, 10);
// Reset state.
@@ -433,6 +448,12 @@ public class PreferencesHelperTest extends UiServiceTestCase {
NotificationChannel channel0 = new NotificationChannel("id0", "name0", IMPORTANCE_HIGH);
assertTrue(mHelper.createNotificationChannel(package0, uid0, channel0, true, false));
+ ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
+ appPermissions.put(new Pair(uid0, package0), new Pair(true, false));
+
+ when(mPermissionHelper.getNotificationPermissionValues(USER_SYSTEM))
+ .thenReturn(appPermissions);
+
ByteArrayOutputStream baos = writeXmlAndPurge(package0, uid0, true, 0);
// Reset state.
@@ -478,7 +499,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, false, false));
mHelper.setShowBadge(PKG_N_MR1, UID_N_MR1, true);
- mHelper.setAppImportanceLocked(PKG_N_MR1, UID_N_MR1);
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, false,
UserHandle.USER_ALL, channel1.getId(), channel2.getId(),
@@ -489,7 +509,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
loadStreamXml(baos, false, UserHandle.USER_ALL);
assertTrue(mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
- assertTrue(mHelper.getIsAppImportanceLocked(PKG_N_MR1, UID_N_MR1));
assertEquals(channel1,
mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1.getId(), false));
compareChannels(channel2,
@@ -550,8 +569,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
mHelper.setInvalidMsgAppDemoted(PKG_P, UID_P, true);
mHelper.setValidBubbleSent(PKG_P, UID_P);
- mHelper.setImportance(PKG_O, UID_O, IMPORTANCE_NONE);
-
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true,
USER_SYSTEM, channel1.getId(), channel2.getId(), channel3.getId(),
NotificationChannel.DEFAULT_CHANNEL_ID);
@@ -562,7 +579,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
loadStreamXml(baos, true, USER_SYSTEM);
- assertEquals(IMPORTANCE_NONE, mHelper.getImportance(PKG_O, UID_O));
assertTrue(mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
assertTrue(mHelper.hasSentInvalidMsg(PKG_P, UID_P));
assertFalse(mHelper.hasSentInvalidMsg(PKG_N_MR1, UID_N_MR1));
@@ -601,7 +617,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testReadXml_oldXml_migrates() throws Exception {
- when(mPermissionHelper.isMigrationEnabled()).thenReturn(true);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
mPermissionHelper, mLogger, mAppOpsManager, mStatsEventBuilderFactory);
@@ -672,7 +687,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testReadXml_oldXml_backup_migratesWhenPkgInstalled() throws Exception {
- when(mPermissionHelper.isMigrationEnabled()).thenReturn(true);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
mPermissionHelper, mLogger, mAppOpsManager, mStatsEventBuilderFactory);
@@ -751,7 +765,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testReadXml_newXml_noMigration_showPermissionNotification() throws Exception {
- when(mPermissionHelper.isMigrationEnabled()).thenReturn(true);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
mPermissionHelper, mLogger, mAppOpsManager, mStatsEventBuilderFactory);
@@ -809,7 +822,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testReadXml_newXml_noMigration_noPermissionNotification() throws Exception {
- when(mPermissionHelper.isMigrationEnabled()).thenReturn(true);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
mPermissionHelper, mLogger, mAppOpsManager, mStatsEventBuilderFactory);
@@ -866,7 +878,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testReadXml_oldXml_migration_NoUid() throws Exception {
- when(mPermissionHelper.isMigrationEnabled()).thenReturn(true);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
mPermissionHelper, mLogger, mAppOpsManager, mStatsEventBuilderFactory);
@@ -900,7 +911,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testReadXml_newXml_noMigration_NoUid() throws Exception {
- when(mPermissionHelper.isMigrationEnabled()).thenReturn(true);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
mPermissionHelper, mLogger, mAppOpsManager, mStatsEventBuilderFactory);
@@ -933,7 +943,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testChannelXmlForNonBackup_postMigration() throws Exception {
- when(mPermissionHelper.isMigrationEnabled()).thenReturn(true);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
mPermissionHelper, mLogger, mAppOpsManager, mStatsEventBuilderFactory);
@@ -1014,7 +1023,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testChannelXmlForBackup_postMigration() throws Exception {
- when(mPermissionHelper.isMigrationEnabled()).thenReturn(true);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
mPermissionHelper, mLogger, mAppOpsManager, mStatsEventBuilderFactory);
@@ -1101,7 +1109,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testChannelXmlForBackup_postMigration_noExternal() throws Exception {
- when(mPermissionHelper.isMigrationEnabled()).thenReturn(true);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
mPermissionHelper, mLogger, mAppOpsManager, mStatsEventBuilderFactory);
@@ -1181,7 +1188,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testChannelXmlForBackup_postMigration_noLocalSettings() throws Exception {
- when(mPermissionHelper.isMigrationEnabled()).thenReturn(true);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
mPermissionHelper, mLogger, mAppOpsManager, mStatsEventBuilderFactory);
@@ -1303,6 +1309,12 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testBackupRestoreXml_withNullSoundUri() throws Exception {
+ ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
+ appPermissions.put(new Pair(UID_N_MR1, PKG_N_MR1), new Pair(true, false));
+
+ when(mPermissionHelper.getNotificationPermissionValues(USER_SYSTEM))
+ .thenReturn(appPermissions);
+
NotificationChannel channel =
new NotificationChannel("id", "name", IMPORTANCE_LOW);
channel.setSound(null, mAudioAttributes);
@@ -1472,14 +1484,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
}
@Test
- public void testCreateChannel_blocked() throws Exception {
- mHelper.setImportance(PKG_N_MR1, UID_N_MR1, IMPORTANCE_NONE);
-
- assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1,
- new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true, false));
- }
-
- @Test
public void testCreateChannel_badImportance() throws Exception {
try {
mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1,
@@ -1543,12 +1547,10 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testUpdate_preUpgrade_updatesAppFields() throws Exception {
- mHelper.setImportance(PKG_N_MR1, UID_N_MR1, IMPORTANCE_UNSPECIFIED);
assertTrue(mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG_N_MR1, UID_N_MR1));
assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE,
mHelper.getPackageVisibility(PKG_N_MR1, UID_N_MR1));
- assertFalse(mHelper.getIsAppImportanceLocked(PKG_N_MR1, UID_N_MR1));
NotificationChannel defaultChannel = mHelper.getNotificationChannel(
PKG_N_MR1, UID_N_MR1, NotificationChannel.DEFAULT_CHANNEL_ID, false);
@@ -1566,8 +1568,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
assertEquals(Notification.PRIORITY_MAX, mHelper.getPackagePriority(PKG_N_MR1, UID_N_MR1));
assertEquals(Notification.VISIBILITY_SECRET, mHelper.getPackageVisibility(PKG_N_MR1,
UID_N_MR1));
- assertEquals(IMPORTANCE_NONE, mHelper.getImportance(PKG_N_MR1, UID_N_MR1));
- assertTrue(mHelper.getIsAppImportanceLocked(PKG_N_MR1, UID_N_MR1));
}
@Test
@@ -1592,9 +1592,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG_O, UID_O));
assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE,
mHelper.getPackageVisibility(PKG_O, UID_O));
- assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, mHelper.getImportance(PKG_O,
- UID_O));
- assertFalse(mHelper.getIsAppImportanceLocked(PKG_O, UID_O));
}
@Test
@@ -1629,8 +1626,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG_N_MR1, UID_N_MR1));
assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE,
mHelper.getPackageVisibility(PKG_N_MR1, UID_N_MR1));
- assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, mHelper.getImportance(PKG_N_MR1,
- UID_N_MR1));
}
@Test
@@ -2015,8 +2010,9 @@ public class PreferencesHelperTest extends UiServiceTestCase {
}
@Test
- public void testCreateAndDeleteCanChannelsBypassDnd_localSettings() throws Exception {
+ public void testCreateAndDeleteCanChannelsBypassDnd_localSettings() {
int uid = UserManager.isHeadlessSystemUserMode() ? UID_HEADLESS : UID_N_MR1;
+ when(mPermissionHelper.hasPermission(uid)).thenReturn(true);
// create notification channel that can't bypass dnd
// expected result: areChannelsBypassingDnd = false
@@ -2029,7 +2025,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
// create notification channel that can bypass dnd
// expected result: areChannelsBypassingDnd = true
- assertTrue(mHelper.getImportance(PKG_N_MR1, uid) != IMPORTANCE_NONE);
NotificationChannel channel2 = new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
channel2.setBypassDnd(true);
mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true);
@@ -2052,8 +2047,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testCreateAndUpdateChannelsBypassingDnd_permissionHelper() {
int uid = UserManager.isHeadlessSystemUserMode() ? UID_HEADLESS : UID_N_MR1;
-
- when(mPermissionHelper.isMigrationEnabled()).thenReturn(true);
when(mPermissionHelper.hasPermission(uid)).thenReturn(true);
// create notification channel that can't bypass dnd
@@ -2076,10 +2069,8 @@ public class PreferencesHelperTest extends UiServiceTestCase {
}
@Test
- public void testCreateAndDeleteCanChannelsBypassDnd_permissionHelper() throws Exception {
+ public void testCreateAndDeleteCanChannelsBypassDnd_permissionHelper() {
int uid = UserManager.isHeadlessSystemUserMode() ? UID_HEADLESS : UID_N_MR1;
-
- when(mPermissionHelper.isMigrationEnabled()).thenReturn(true);
when(mPermissionHelper.hasPermission(uid)).thenReturn(true);
// create notification channel that can't bypass dnd
@@ -2113,8 +2104,9 @@ public class PreferencesHelperTest extends UiServiceTestCase {
}
@Test
- public void testBlockedGroupDoesNotBypassDnd() throws Exception {
+ public void testBlockedGroupDoesNotBypassDnd() {
int uid = UserManager.isHeadlessSystemUserMode() ? UID_HEADLESS : UID_N_MR1;
+ when(mPermissionHelper.hasPermission(uid)).thenReturn(true);
// start in a 'allowed to bypass dnd state'
mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0,
@@ -2140,8 +2132,9 @@ public class PreferencesHelperTest extends UiServiceTestCase {
}
@Test
- public void testBlockedAppsDoNotBypassDnd_localSettings() throws Exception {
+ public void testBlockedAppsDoNotBypassDnd_localSettings() {
int uid = UserManager.isHeadlessSystemUserMode() ? UID_HEADLESS : UID_N_MR1;
+ when(mPermissionHelper.hasPermission(uid)).thenReturn(false);
// start in a 'allowed to bypass dnd state'
mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0,
@@ -2151,7 +2144,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
mPermissionHelper, mLogger,
mAppOpsManager, mStatsEventBuilderFactory);
- mHelper.setImportance(PKG_N_MR1, uid, IMPORTANCE_NONE);
// create notification channel that can bypass dnd, but app is blocked
// expected result: areChannelsBypassingDnd = false
NotificationChannel channel2 = new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
@@ -2163,10 +2155,10 @@ public class PreferencesHelperTest extends UiServiceTestCase {
}
@Test
- public void testBlockedAppsDoNotBypassDnd_permissionHelper() throws Exception {
+ public void testBlockedAppsDoNotBypassDnd_permissionHelper() {
int uid = UserManager.isHeadlessSystemUserMode() ? UID_HEADLESS : UID_N_MR1;
- when(mPermissionHelper.isMigrationEnabled()).thenReturn(true);
when(mPermissionHelper.hasPermission(uid)).thenReturn(false);
+
// start in a 'allowed to bypass dnd state'
mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0,
NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND, 0);
@@ -2186,8 +2178,9 @@ public class PreferencesHelperTest extends UiServiceTestCase {
}
@Test
- public void testUpdateCanChannelsBypassDnd() throws Exception {
+ public void testUpdateCanChannelsBypassDnd() {
int uid = UserManager.isHeadlessSystemUserMode() ? UID_HEADLESS : UID_N_MR1;
+ when(mPermissionHelper.hasPermission(uid)).thenReturn(true);
// create notification channel that can't bypass dnd
// expected result: areChannelsBypassingDnd = false
@@ -2405,8 +2398,8 @@ public class PreferencesHelperTest extends UiServiceTestCase {
when(mPm.getApplicationInfoAsUser(eq(PKG_N_MR1), anyInt(), anyInt())).thenReturn(legacy);
// create records with the default channel for all user 0 and user 1 uids
- mHelper.getImportance(PKG_N_MR1, user0Uids[i]);
- mHelper.getImportance(PKG_N_MR1, user1Uids[i]);
+ mHelper.canShowBadge(PKG_N_MR1, user0Uids[i]);
+ mHelper.canShowBadge(PKG_N_MR1, user1Uids[i]);
}
mHelper.onUserRemoved(1);
@@ -2445,17 +2438,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
}
@Test
- public void testOnPackageChanged_packageRemoval_importance() throws Exception {
- mHelper.setImportance(PKG_N_MR1, UID_N_MR1, NotificationManager.IMPORTANCE_HIGH);
-
- mHelper.onPackagesChanged(true, USER_SYSTEM, new String[]{PKG_N_MR1}, new int[]{
- UID_N_MR1});
-
- assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, mHelper.getImportance(PKG_N_MR1,
- UID_N_MR1));
- }
-
- @Test
public void testOnPackageChanged_packageRemoval_groups() throws Exception {
NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
@@ -2496,17 +2478,14 @@ public class PreferencesHelperTest extends UiServiceTestCase {
mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false);
mHelper.createNotificationChannelGroup(
PKG_O, UID_O, new NotificationChannelGroup("1", "bye"), true);
- mHelper.lockChannelsForOEM(pkg.toArray(new String[]{}));
mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, pkgPair);
mHelper.setNotificationDelegate(PKG_O, UID_O, "", 1);
- mHelper.setImportance(PKG_O, UID_O, IMPORTANCE_NONE);
mHelper.setBubblesAllowed(PKG_O, UID_O, DEFAULT_BUBBLE_PREFERENCE);
mHelper.setShowBadge(PKG_O, UID_O, false);
mHelper.setAppImportanceLocked(PKG_O, UID_O);
mHelper.clearData(PKG_O, UID_O);
- assertEquals(IMPORTANCE_UNSPECIFIED, mHelper.getImportance(PKG_O, UID_O));
assertEquals(mHelper.getBubblePreference(PKG_O, UID_O), DEFAULT_BUBBLE_PREFERENCE);
assertTrue(mHelper.canShowBadge(PKG_O, UID_O));
assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
@@ -2518,13 +2497,10 @@ public class PreferencesHelperTest extends UiServiceTestCase {
mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false);
assertTrue(channel.isImportanceLockedByCriticalDeviceFunction());
- assertTrue(channel.isImportanceLockedByOEM());
}
@Test
public void testRecordDefaults() throws Exception {
- assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, mHelper.getImportance(PKG_N_MR1,
- UID_N_MR1));
assertEquals(true, mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
assertEquals(1, mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, false).getList().size());
}
@@ -2760,69 +2736,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
}
@Test
- public void testDumpJson_prePermissionMigration() throws Exception {
- when(mPermissionHelper.isMigrationEnabled()).thenReturn(false);
- // before the migration is active, we want to verify that:
- // - all notification importance info should come from package preferences
- // - if there are permissions granted or denied from packages PreferencesHelper doesn't
- // know about, those are ignored if migration is not enabled
-
- // package permissions map to be passed in
- ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
- appPermissions.put(new Pair(1, "first"), new Pair(true, false)); // not in local prefs
- appPermissions.put(new Pair(3, "third"), new Pair(false, false)); // not in local prefs
- appPermissions.put(new Pair(UID_P, PKG_P), new Pair(true, false)); // in local prefs
- appPermissions.put(new Pair(UID_O, PKG_O), new Pair(false, false)); // in local prefs
-
- NotificationChannel channel1 =
- new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
- NotificationChannel channel3 = new NotificationChannel("id3", "name3", IMPORTANCE_HIGH);
-
- mHelper.createNotificationChannel(PKG_P, UID_P, channel1, true, false);
- mHelper.setImportance(PKG_P, UID_P, IMPORTANCE_LOW);
- mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, false, false);
- mHelper.setImportance(PKG_N_MR1, UID_N_MR1, IMPORTANCE_NONE);
- mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false);
- mHelper.setImportance(PKG_O, UID_O, IMPORTANCE_HIGH);
-
- // in the json array, all of the individual package preferences are simply elements in the
- // values array. this set is to collect expected outputs for each of our packages.
- // the key/value pairs are: (userId, package name) -> expected importance
- ArrayMap<Pair<Integer, String>, String> expected = new ArrayMap<>();
- expected.put(new Pair(UserHandle.getUserId(UID_P), PKG_P), "LOW");
- expected.put(new Pair(UserHandle.getUserId(UID_O), PKG_O), "HIGH");
- expected.put(new Pair(UserHandle.getUserId(UID_N_MR1), PKG_N_MR1), "NONE");
-
- JSONArray actual = (JSONArray) mHelper.dumpJson(
- new NotificationManagerService.DumpFilter(), appPermissions)
- .get("PackagePreferencess");
- assertThat(actual.length()).isEqualTo(expected.size());
- for (int i = 0; i < actual.length(); i++) {
- JSONObject pkgInfo = actual.getJSONObject(i);
- Pair<Integer, String> pkgKey =
- new Pair(pkgInfo.getInt("userId"), pkgInfo.getString("packageName"));
- assertTrue(expected.containsKey(pkgKey));
- assertThat(pkgInfo.getString("importance")).isEqualTo(expected.get(pkgKey));
- }
-
- // also make sure that (more likely to actually happen) if we don't provide an array of
- // app preferences (and do null instead), the same thing happens, so do the same checks
- JSONArray actualWithNullInput = (JSONArray) mHelper.dumpJson(
- new NotificationManagerService.DumpFilter(), null)
- .get("PackagePreferencess");
- assertThat(actualWithNullInput.length()).isEqualTo(expected.size());
- for (int i = 0; i < actualWithNullInput.length(); i++) {
- JSONObject pkgInfo = actualWithNullInput.getJSONObject(i);
- Pair<Integer, String> pkgKey =
- new Pair(pkgInfo.getInt("userId"), pkgInfo.getString("packageName"));
- assertTrue(expected.containsKey(pkgKey));
- assertThat(pkgInfo.getString("importance")).isEqualTo(expected.get(pkgKey));
- }
- }
-
- @Test
public void testDumpJson_postPermissionMigration() throws Exception {
- when(mPermissionHelper.isMigrationEnabled()).thenReturn(true);
// when getting a json dump, we want to verify that:
// - all notification importance info should come from the permission, even if the data
// isn't there yet but is present in package preferences
@@ -2844,11 +2758,8 @@ public class PreferencesHelperTest extends UiServiceTestCase {
mHelper.createNotificationChannel(PKG_P, UID_P, channel1, true, false);
mHelper.createNotificationChannel(PKG_P, UID_P, channel2, false, false);
- mHelper.setImportance(PKG_P, UID_P, IMPORTANCE_LOW);
mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, false, false);
- mHelper.setImportance(PKG_P, UID_P, IMPORTANCE_NONE);
mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false);
- mHelper.setImportance(PKG_O, UID_O, IMPORTANCE_HIGH);
// in the json array, all of the individual package preferences are simply elements in the
// values array. this set is to collect expected outputs for each of our packages.
@@ -2887,11 +2798,10 @@ public class PreferencesHelperTest extends UiServiceTestCase {
public void testDumpJson_givenNullInput_postMigration() throws Exception {
// simple test just to make sure nothing dies if we pass in null input even post migration
// for some reason, even though in practice this should not be how one calls this method
- when(mPermissionHelper.isMigrationEnabled()).thenReturn(true);
- // some packages exist, with some importance info that won't be looked at
- mHelper.setImportance(PKG_O, UID_O, IMPORTANCE_HIGH);
- mHelper.setImportance(PKG_P, UID_P, IMPORTANCE_NONE);
+ // some packages exist
+ mHelper.canShowBadge(PKG_O, UID_O);
+ mHelper.canShowBadge(PKG_P, UID_P);
JSONArray actual = (JSONArray) mHelper.dumpJson(
new NotificationManagerService.DumpFilter(), null)
@@ -2908,44 +2818,16 @@ public class PreferencesHelperTest extends UiServiceTestCase {
}
@Test
- public void testDumpBansJson_prePermissionMigration() throws Exception {
- // confirm that the package bans that are in json are only from package preferences, and
- // not from the passed-in permissions map
- when(mPermissionHelper.isMigrationEnabled()).thenReturn(false);
-
- ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
- appPermissions.put(new Pair(1, "first"), new Pair(true, false)); // not in local prefs
- appPermissions.put(new Pair(3, "third"), new Pair(false, false)); // not in local prefs
- appPermissions.put(new Pair(UID_O, PKG_O), new Pair(false, false)); // in local prefs
-
- // package preferences: only PKG_P is banned
- mHelper.setImportance(PKG_O, UID_O, IMPORTANCE_HIGH);
- mHelper.setImportance(PKG_P, UID_P, IMPORTANCE_NONE);
-
- // make sure that's the only thing in the package ban output
- JSONArray actual = mHelper.dumpBansJson(
- new NotificationManagerService.DumpFilter(), appPermissions);
- assertThat(actual.length()).isEqualTo(1);
-
- JSONObject ban = actual.getJSONObject(0);
- assertThat(ban.getInt("userId")).isEqualTo(UserHandle.getUserId(UID_P));
- assertThat(ban.getString("packageName")).isEqualTo(PKG_P);
- }
-
- @Test
public void testDumpBansJson_postPermissionMigration() throws Exception {
// confirm that the package bans that are in the output include all packages that
// have their permission set to false, and not based on PackagePreferences importance
- when(mPermissionHelper.isMigrationEnabled()).thenReturn(true);
ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
appPermissions.put(new Pair(1, "first"), new Pair(true, false)); // not in local prefs
appPermissions.put(new Pair(3, "third"), new Pair(false, false)); // not in local prefs
appPermissions.put(new Pair(UID_O, PKG_O), new Pair(false, false)); // in local prefs
- // package preferences: PKG_O not banned based on local importance, and PKG_P is
- mHelper.setImportance(PKG_O, UID_O, IMPORTANCE_HIGH);
- mHelper.setImportance(PKG_P, UID_P, IMPORTANCE_NONE);
+ mHelper.canShowBadge(PKG_O, UID_O);
// expected output
ArraySet<Pair<Integer, String>> expected = new ArraySet<>();
@@ -2967,10 +2849,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testDumpBansJson_givenNullInput() throws Exception {
// no one should do this, but...
- when(mPermissionHelper.isMigrationEnabled()).thenReturn(true);
-
- mHelper.setImportance(PKG_O, UID_O, IMPORTANCE_HIGH);
- mHelper.setImportance(PKG_P, UID_P, IMPORTANCE_NONE);
JSONArray actual = mHelper.dumpBansJson(
new NotificationManagerService.DumpFilter(), null);
@@ -2978,59 +2856,8 @@ public class PreferencesHelperTest extends UiServiceTestCase {
}
@Test
- public void testDumpString_prePermissionMigration() {
- // confirm that the string resulting from dumpImpl contains only info from package prefs
- when(mPermissionHelper.isMigrationEnabled()).thenReturn(false);
-
- ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
- appPermissions.put(new Pair(1, "first"), new Pair(true, false)); // not in local prefs
- appPermissions.put(new Pair(3, "third"), new Pair(false, true)); // not in local prefs
- appPermissions.put(new Pair(UID_O, PKG_O), new Pair(false, false)); // in local prefs
-
- // local package preferences: PKG_O is not banned even though the permissions would
- // indicate so
- mHelper.setImportance(PKG_O, UID_O, IMPORTANCE_HIGH);
- mHelper.setImportance(PKG_P, UID_P, IMPORTANCE_NONE);
-
- // get dump output as a string so we can inspect the contents later
- StringWriter sw = new StringWriter();
- PrintWriter pw = new PrintWriter(sw);
- mHelper.dump(pw, "", new NotificationManagerService.DumpFilter(), appPermissions);
- pw.flush();
- String actual = sw.toString();
-
- // expected (substring) output for each preference
- ArrayList<String> expected = new ArrayList<>();
- expected.add(PKG_O + " (" + UID_O + ") importance=HIGH");
- expected.add(PKG_P + " (" + UID_P + ") importance=NONE");
-
- // make sure the things in app permissions do NOT show up
- ArrayList<String> notExpected = new ArrayList<>();
- notExpected.add("first (1) importance=DEFAULT");
- notExpected.add("third (3) importance=NONE");
- notExpected.add("userSet="); // no user-set information pre migration
-
- for (String exp : expected) {
- assertTrue(actual.contains(exp));
- }
-
- for (String notExp : notExpected) {
- assertFalse(actual.contains(notExp));
- }
-
- // also make sure it works the same if we pass in a null input
- StringWriter sw2 = new StringWriter();
- PrintWriter pw2 = new PrintWriter(sw2);
- mHelper.dump(pw2, "", new NotificationManagerService.DumpFilter(), null);
- pw.flush();
- String actualWithNullInput = sw2.toString();
- assertThat(actualWithNullInput).isEqualTo(actual);
- }
-
- @Test
public void testDumpString_postPermissionMigration() {
// confirm that the string resulting from dumpImpl contains only importances from permission
- when(mPermissionHelper.isMigrationEnabled()).thenReturn(true);
ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
appPermissions.put(new Pair(1, "first"), new Pair(true, false)); // not in local prefs
@@ -3038,8 +2865,8 @@ public class PreferencesHelperTest extends UiServiceTestCase {
appPermissions.put(new Pair(UID_O, PKG_O), new Pair(false, false)); // in local prefs
// local package preferences
- mHelper.setImportance(PKG_O, UID_O, IMPORTANCE_HIGH);
- mHelper.setImportance(PKG_P, UID_P, IMPORTANCE_NONE);
+ mHelper.canShowBadge(PKG_O, UID_O);
+ mHelper.canShowBadge(PKG_P, UID_P);
// get dump output as a string so we can inspect the contents later
StringWriter sw = new StringWriter();
@@ -3072,11 +2899,10 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testDumpString_givenNullInput() {
// test that this doesn't choke on null input
- when(mPermissionHelper.isMigrationEnabled()).thenReturn(true);
// local package preferences
- mHelper.setImportance(PKG_O, UID_O, IMPORTANCE_HIGH);
- mHelper.setImportance(PKG_P, UID_P, IMPORTANCE_NONE);
+ mHelper.canShowBadge(PKG_O, UID_O);
+ mHelper.canShowBadge(PKG_P, UID_P);
// get dump output
StringWriter sw = new StringWriter();
@@ -3090,48 +2916,8 @@ public class PreferencesHelperTest extends UiServiceTestCase {
}
@Test
- public void testDumpProto_prePermissionMigration() throws Exception {
- // test that dumping to proto gets the importances from the right place
- when(mPermissionHelper.isMigrationEnabled()).thenReturn(false);
-
- ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
- appPermissions.put(new Pair(1, "first"), new Pair(true, false)); // not in local prefs
- appPermissions.put(new Pair(3, "third"), new Pair(false, false)); // not in local prefs
- appPermissions.put(new Pair(UID_O, PKG_O), new Pair(false, false)); // in local prefs
-
- // local package preferences
- mHelper.setImportance(PKG_O, UID_O, IMPORTANCE_HIGH);
- mHelper.setImportance(PKG_P, UID_P, IMPORTANCE_NONE);
-
- // expected output: only the local preferences
- // map format: (uid, package name) -> importance (int)
- ArrayMap<Pair<Integer, String>, Integer> expected = new ArrayMap<>();
- expected.put(new Pair(UID_O, PKG_O), IMPORTANCE_HIGH);
- expected.put(new Pair(UID_P, PKG_P), IMPORTANCE_NONE);
-
- // get the proto output and inspect its contents
- ProtoOutputStream proto = new ProtoOutputStream();
- mHelper.dump(proto, new NotificationManagerService.DumpFilter(), appPermissions);
-
- RankingHelperProto actual = RankingHelperProto.parseFrom(proto.getBytes());
- assertThat(actual.records.length).isEqualTo(expected.size());
- for (int i = 0; i < actual.records.length; i++) {
- RankingHelperProto.RecordProto record = actual.records[i];
- Pair<Integer, String> pkgKey = new Pair(record.uid, record.package_);
- assertTrue(expected.containsKey(pkgKey));
- assertThat(record.importance).isEqualTo(expected.get(pkgKey));
- }
-
- // also check that it's the same as passing in null input
- ProtoOutputStream proto2 = new ProtoOutputStream();
- mHelper.dump(proto2, new NotificationManagerService.DumpFilter(), null);
- assertThat(proto.getBytes()).isEqualTo(proto2.getBytes());
- }
-
- @Test
public void testDumpProto_postPermissionMigration() throws Exception {
// test that dumping to proto gets the importances from the right place
- when(mPermissionHelper.isMigrationEnabled()).thenReturn(true);
// permissions -- these should take precedence
ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
@@ -3140,8 +2926,8 @@ public class PreferencesHelperTest extends UiServiceTestCase {
appPermissions.put(new Pair(UID_O, PKG_O), new Pair(false, false)); // in local prefs
// local package preferences
- mHelper.setImportance(PKG_O, UID_O, IMPORTANCE_HIGH);
- mHelper.setImportance(PKG_P, UID_P, IMPORTANCE_LOW);
+ mHelper.canShowBadge(PKG_O, UID_O);
+ mHelper.canShowBadge(PKG_P, UID_P);
// expected output: all the packages, but only the ones provided via appPermissions
// should have importance set (aka not PKG_P)
@@ -3429,14 +3215,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
}
@Test
- public void testAppBlockedLogging() {
- mHelper.setEnabled(PKG_N_MR1, 1020, false);
- assertEquals(1, mLogger.getCalls().size());
- assertEquals(
- NotificationChannelLogger.NotificationChannelEvent.APP_NOTIFICATIONS_BLOCKED,
- mLogger.get(0).event);
- }
- @Test
public void testXml_statusBarIcons_default() throws Exception {
String preQXml = "<ranking version=\"1\">\n"
+ "<package name=\"" + PKG_N_MR1 + "\" show_badge=\"true\">\n"
@@ -3517,7 +3295,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testIsDelegateAllowed_noDelegate() {
- mHelper.setImportance(PKG_O, UID_O, IMPORTANCE_UNSPECIFIED);
+ mHelper.canShowBadge(PKG_O, UID_O);
assertFalse(mHelper.isDelegateAllowed(PKG_O, UID_O, "whatever", 0));
}
@@ -3555,7 +3333,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testDelegateXml_noDelegate() throws Exception {
- mHelper.setImportance(PKG_O, UID_O, IMPORTANCE_UNSPECIFIED);
+ mHelper.canShowBadge(PKG_O, UID_O);
ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
@@ -3744,337 +3522,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
}
@Test
- public void testLockChannelsForOEM_emptyList() {
- mHelper.lockChannelsForOEM(null);
- mHelper.lockChannelsForOEM(new String[0]);
- // no exception
- }
-
- @Test
- public void testLockChannelsForOEM_appWide() {
- NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
- NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
- NotificationChannel c = new NotificationChannel("c", "c", IMPORTANCE_DEFAULT);
- // different uids, same package
- mHelper.createNotificationChannel(PKG_O, 3, a, true, false);
- mHelper.createNotificationChannel(PKG_O, 3, b, false, false);
- mHelper.createNotificationChannel(PKG_O, 30, c, true, true);
-
- mHelper.lockChannelsForOEM(new String[] {PKG_O});
-
- assertTrue(mHelper.getNotificationChannel(PKG_O, 3, a.getId(), false)
- .isImportanceLockedByOEM());
- assertTrue(mHelper.getNotificationChannel(PKG_O, 3, b.getId(), false)
- .isImportanceLockedByOEM());
- assertTrue(mHelper.getNotificationChannel(PKG_O, 30, c.getId(), false)
- .isImportanceLockedByOEM());
- }
-
- @Test
- public void testLockChannelsForOEM_onlyGivenPkg() {
- NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
- NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
- mHelper.createNotificationChannel(PKG_O, 3, a, true, false);
- mHelper.createNotificationChannel(PKG_N_MR1, 30, b, false, false);
-
- mHelper.lockChannelsForOEM(new String[] {PKG_O});
-
- assertTrue(mHelper.getNotificationChannel(PKG_O, 3, a.getId(), false)
- .isImportanceLockedByOEM());
- assertFalse(mHelper.getNotificationChannel(PKG_N_MR1, 30, b.getId(), false)
- .isImportanceLockedByOEM());
- }
-
- @Test
- public void testLockChannelsForOEM_channelSpecific() {
- NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
- NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
- NotificationChannel c = new NotificationChannel("c", "c", IMPORTANCE_DEFAULT);
- // different uids, same package
- mHelper.createNotificationChannel(PKG_O, 3, a, true, false);
- mHelper.createNotificationChannel(PKG_O, 3, b, false, false);
- mHelper.createNotificationChannel(PKG_O, 30, c, true, true);
-
- mHelper.lockChannelsForOEM(new String[] {PKG_O + ":b", PKG_O + ":c"});
-
- assertFalse(mHelper.getNotificationChannel(PKG_O, 3, a.getId(), false)
- .isImportanceLockedByOEM());
- assertTrue(mHelper.getNotificationChannel(PKG_O, 3, b.getId(), false)
- .isImportanceLockedByOEM());
- assertTrue(mHelper.getNotificationChannel(PKG_O, 30, c.getId(), false)
- .isImportanceLockedByOEM());
- }
-
- @Test
- public void testLockChannelsForOEM_onlyGivenPkg_appDoesNotExistYet() {
- mHelper.lockChannelsForOEM(new String[] {PKG_O});
-
- NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
- NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
- mHelper.createNotificationChannel(PKG_O, 3, a, true, false);
- mHelper.createNotificationChannel(PKG_N_MR1, 30, b, false, false);
-
- assertTrue(mHelper.getNotificationChannel(PKG_O, 3, a.getId(), false)
- .isImportanceLockedByOEM());
- assertFalse(mHelper.getNotificationChannel(PKG_N_MR1, 30, b.getId(), false)
- .isImportanceLockedByOEM());
- }
-
- @Test
- public void testLockChannelsForOEM_channelSpecific_appDoesNotExistYet() {
- mHelper.lockChannelsForOEM(new String[] {PKG_O + ":b", PKG_O + ":c"});
-
- NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
- NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
- NotificationChannel c = new NotificationChannel("c", "c", IMPORTANCE_DEFAULT);
- // different uids, same package
- mHelper.createNotificationChannel(PKG_O, 3, a, true, false);
- mHelper.createNotificationChannel(PKG_O, 3, b, false, false);
- mHelper.createNotificationChannel(PKG_O, 30, c, true, true);
-
- assertFalse(mHelper.getNotificationChannel(PKG_O, 3, a.getId(), false)
- .isImportanceLockedByOEM());
- assertTrue(mHelper.getNotificationChannel(PKG_O, 3, b.getId(), false)
- .isImportanceLockedByOEM());
- assertTrue(mHelper.getNotificationChannel(PKG_O, 30, c.getId(), false)
- .isImportanceLockedByOEM());
- }
-
- @Test
- public void testLockChannelsForOEM_onlyGivenPkg_appDoesNotExistYet_restoreData()
- throws Exception {
- mHelper.lockChannelsForOEM(new String[] {PKG_O});
-
- final String xml = "<ranking version=\"1\">\n"
- + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n"
- + "<channel id=\"a\" name=\"a\" importance=\"3\"/>"
- + "<channel id=\"b\" name=\"b\" importance=\"3\"/>"
- + "</package>"
- + "<package name=\"" + PKG_N_MR1 + "\" uid=\"" + UID_N_MR1 + "\" >\n"
- + "<channel id=\"a\" name=\"a\" importance=\"3\"/>"
- + "<channel id=\"b\" name=\"b\" importance=\"3\"/>"
- + "</package>"
- + "</ranking>";
- TypedXmlPullParser parser = Xml.newFastPullParser();
- parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
- null);
- parser.nextTag();
- mHelper.readXml(parser, false, UserHandle.USER_ALL);
-
- assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, "a", false)
- .isImportanceLockedByOEM());
- assertFalse(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "b", false)
- .isImportanceLockedByOEM());
- }
-
- @Test
- public void testLockChannelsForOEM_onlyGivenPkg_appDoesNotExistYet_restoreData_postMigration()
- throws Exception {
- when(mPermissionHelper.isMigrationEnabled()).thenReturn(true);
- mHelper.lockChannelsForOEM(new String[] {PKG_O});
-
- final String xml = "<ranking version=\"1\">\n"
- + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n"
- + "<channel id=\"a\" name=\"a\" importance=\"3\"/>"
- + "<channel id=\"b\" name=\"b\" importance=\"3\"/>"
- + "</package>"
- + "</ranking>";
- TypedXmlPullParser parser = Xml.newFastPullParser();
- parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
- null);
- parser.nextTag();
- mHelper.readXml(parser, false, UserHandle.USER_ALL);
-
- assertFalse(mHelper.getNotificationChannel(PKG_O, UID_O, "a", false)
- .isImportanceLockedByOEM());
- }
-
- @Test
- public void testLockChannelsForOEM_channelSpecific_appDoesNotExistYet_restoreData()
- throws Exception {
- mHelper.lockChannelsForOEM(new String[] {PKG_O + ":b", PKG_O + ":c"});
-
- final String xml = "<ranking version=\"1\">\n"
- + "<package name=\"" + PKG_O + "\" uid=\"" + 3 + "\" >\n"
- + "<channel id=\"a\" name=\"a\" importance=\"3\"/>"
- + "<channel id=\"b\" name=\"b\" importance=\"3\"/>"
- + "</package>"
- + "<package name=\"" + PKG_O + "\" uid=\"" + 30 + "\" >\n"
- + "<channel id=\"c\" name=\"c\" importance=\"3\"/>"
- + "</package>"
- + "</ranking>";
- TypedXmlPullParser parser = Xml.newFastPullParser();
- parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
- null);
- parser.nextTag();
- mHelper.readXml(parser, false, UserHandle.USER_ALL);
-
- assertFalse(mHelper.getNotificationChannel(PKG_O, 3, "a", false)
- .isImportanceLockedByOEM());
- assertTrue(mHelper.getNotificationChannel(PKG_O, 3, "b", false)
- .isImportanceLockedByOEM());
- assertTrue(mHelper.getNotificationChannel(PKG_O, 30, "c", false)
- .isImportanceLockedByOEM());
- }
-
- @Test
- public void testLockChannelsForOEM_channelSpecific_appDoesNotExistYet_restoreData_postMigration()
- throws Exception {
- when(mPermissionHelper.isMigrationEnabled()).thenReturn(true);
- mHelper.lockChannelsForOEM(new String[] {PKG_O + ":b", PKG_O + ":c"});
-
- final String xml = "<ranking version=\"1\">\n"
- + "<package name=\"" + PKG_O + "\" uid=\"" + 3 + "\" >\n"
- + "<channel id=\"a\" name=\"a\" importance=\"3\"/>"
- + "<channel id=\"b\" name=\"b\" importance=\"3\"/>"
- + "</package>"
- + "<package name=\"" + PKG_O + "\" uid=\"" + 30 + "\" >\n"
- + "<channel id=\"c\" name=\"c\" importance=\"3\"/>"
- + "</package>"
- + "</ranking>";
- TypedXmlPullParser parser = Xml.newFastPullParser();
- parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())),
- null);
- parser.nextTag();
- mHelper.readXml(parser, false, UserHandle.USER_ALL);
-
- assertFalse(mHelper.getNotificationChannel(PKG_O, 3, "a", false)
- .isImportanceLockedByOEM());
- assertFalse(mHelper.getNotificationChannel(PKG_O, 3, "b", false)
- .isImportanceLockedByOEM());
- assertFalse(mHelper.getNotificationChannel(PKG_O, 30, "c", false)
- .isImportanceLockedByOEM());
- }
-
- @Test
- public void testLockChannelsForOEM_channelSpecific_clearData() {
- NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
- mHelper.getImportance(PKG_O, UID_O);
- mHelper.lockChannelsForOEM(new String[] {PKG_O + ":" + a.getId()});
- mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
- assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
- .isImportanceLockedByOEM());
-
- mHelper.clearData(PKG_O, UID_O);
-
- // it's back!
- mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
- // and still locked
- assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
- .isImportanceLockedByOEM());
- }
-
- @Test
- public void testLockChannelsForOEM_channelDoesNotExistYet_appWide() {
- NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
- NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
- mHelper.createNotificationChannel(PKG_O, 3, a, true, false);
-
- mHelper.lockChannelsForOEM(new String[] {PKG_O});
-
- assertTrue(mHelper.getNotificationChannel(PKG_O, 3, a.getId(), false)
- .isImportanceLockedByOEM());
-
- mHelper.createNotificationChannel(PKG_O, 3, b, true, false);
- assertTrue(mHelper.getNotificationChannel(PKG_O, 3, b.getId(), false)
- .isImportanceLockedByOEM());
- }
-
- @Test
- public void testLockChannelsForOEM_channelDoesNotExistYet_channelSpecific() {
- NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
- NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
- mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
-
- mHelper.lockChannelsForOEM(new String[] {PKG_O + ":a", PKG_O + ":b"});
-
- assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
- .isImportanceLockedByOEM());
-
- mHelper.createNotificationChannel(PKG_O, UID_O, b, true, false);
- assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, b.getId(), false)
- .isImportanceLockedByOEM());
- }
-
- @Test
- public void testLockChannelsForOEM_channelSpecific_clearData_postMigration() {
- when(mPermissionHelper.isMigrationEnabled()).thenReturn(true);
- NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
- mHelper.getImportance(PKG_O, UID_O);
- mHelper.lockChannelsForOEM(new String[] {PKG_O + ":" + a.getId()});
- mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
- assertFalse(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
- .isImportanceLockedByOEM());
-
- mHelper.clearData(PKG_O, UID_O);
-
- // it's back!
- mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
- // and never locked
- assertFalse(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
- .isImportanceLockedByOEM());
- }
-
- @Test
- public void testLockChannelsForOEM_channelDoesNotExistYet_appWide_postMigration() {
- when(mPermissionHelper.isMigrationEnabled()).thenReturn(true);
- NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
- NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
- mHelper.createNotificationChannel(PKG_O, 3, a, true, false);
-
- mHelper.lockChannelsForOEM(new String[] {PKG_O});
-
- assertFalse(mHelper.getNotificationChannel(PKG_O, 3, a.getId(), false)
- .isImportanceLockedByOEM());
-
- mHelper.createNotificationChannel(PKG_O, 3, b, true, false);
- assertFalse(mHelper.getNotificationChannel(PKG_O, 3, b.getId(), false)
- .isImportanceLockedByOEM());
- }
-
- @Test
- public void testLockChannelsForOEM_channelDoesNotExistYet_channelSpecific_postMigration() {
- when(mPermissionHelper.isMigrationEnabled()).thenReturn(true);
- NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
- NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
- mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
-
- mHelper.lockChannelsForOEM(new String[] {PKG_O + ":a", PKG_O + ":b"});
-
- assertFalse(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
- .isImportanceLockedByOEM());
-
- mHelper.createNotificationChannel(PKG_O, UID_O, b, true, false);
- assertFalse(mHelper.getNotificationChannel(PKG_O, UID_O, b.getId(), false)
- .isImportanceLockedByOEM());
- }
-
- @Test
- public void testUpdateNotificationChannel_oemLockedImportance() {
- NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
- mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
-
- mHelper.lockChannelsForOEM(new String[] {PKG_O});
-
- NotificationChannel update = new NotificationChannel("a", "a", IMPORTANCE_NONE);
- update.setAllowBubbles(false);
-
- mHelper.updateNotificationChannel(PKG_O, UID_O, update, true);
-
- assertEquals(IMPORTANCE_HIGH,
- mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance());
- assertEquals(false,
- mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).canBubble());
-
- mHelper.updateNotificationChannel(PKG_O, UID_O, update, true);
-
- assertEquals(IMPORTANCE_HIGH,
- mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance());
- }
-
- @Test
public void testUpdateNotificationChannel_fixedPermission() {
- when(mPermissionHelper.isMigrationEnabled()).thenReturn(true);
when(mPermissionHelper.isPermissionFixed(PKG_O, 0)).thenReturn(true);
NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
@@ -4093,7 +3541,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testUpdateNotificationChannel_fixedPermission_butUserPreviouslyBlockedIt() {
- when(mPermissionHelper.isMigrationEnabled()).thenReturn(true);
when(mPermissionHelper.isPermissionFixed(PKG_O, 0)).thenReturn(true);
NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_NONE);
@@ -4112,7 +3559,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testUpdateNotificationChannel_fixedPermission_butAppAllowsIt() {
- when(mPermissionHelper.isMigrationEnabled()).thenReturn(true);
when(mPermissionHelper.isPermissionFixed(PKG_O, 0)).thenReturn(true);
NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
@@ -4132,7 +3578,6 @@ public class PreferencesHelperTest extends UiServiceTestCase {
@Test
public void testUpdateNotificationChannel_notFixedPermission() {
- when(mPermissionHelper.isMigrationEnabled()).thenReturn(true);
when(mPermissionHelper.isPermissionFixed(PKG_O, 0)).thenReturn(false);
NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
@@ -5312,56 +4757,7 @@ public class PreferencesHelperTest extends UiServiceTestCase {
}
@Test
- public void testPullPackagePreferencesStats_prePermissionMigration() {
- when(mPermissionHelper.isMigrationEnabled()).thenReturn(false);
-
- // build a collection of app permissions that should be passed in but ignored
- ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
- appPermissions.put(new Pair(1, "first"), new Pair(true, false)); // not in local prefs
- appPermissions.put(new Pair(3, "third"), new Pair(false, false)); // not in local prefs
- appPermissions.put(new Pair(UID_O, PKG_O), new Pair(false, false)); // in local prefs
-
- // package preferences: PKG_O not banned based on local importance, and PKG_P is
- mHelper.setImportance(PKG_O, UID_O, IMPORTANCE_HIGH);
- mHelper.setImportance(PKG_P, UID_P, IMPORTANCE_NONE);
-
- // expected output. format: uid -> importance, as only uid (and not package name)
- // is in PackageNotificationPreferences
- ArrayMap<Integer, Integer> expected = new ArrayMap<>();
- expected.put(UID_O, IMPORTANCE_HIGH);
- expected.put(UID_P, IMPORTANCE_NONE);
-
- // unexpected output. these UIDs should not show up in the output at all
- ArraySet<Integer> unexpected = new ArraySet<>();
- unexpected.add(1);
- unexpected.add(3);
-
- ArrayList<StatsEvent> events = new ArrayList<>();
- mHelper.pullPackagePreferencesStats(events, appPermissions);
-
- for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) {
- if (builder.getAtomId() == PACKAGE_NOTIFICATION_PREFERENCES) {
- int uid = builder.getInt(PackageNotificationPreferences.UID_FIELD_NUMBER);
-
- // this shouldn't be any of the forbidden uids
- assertFalse(unexpected.contains(uid));
-
- // if it's one of the expected ids, then make sure the importance matches
- assertTrue(expected.containsKey(uid));
- assertThat(expected.get(uid)).isEqualTo(
- builder.getInt(PackageNotificationPreferences.IMPORTANCE_FIELD_NUMBER));
-
- // pre-migration, the userSet field will always default to false
- boolean userSet = builder.getBoolean(
- PackageNotificationPreferences.USER_SET_IMPORTANCE_FIELD_NUMBER);
- assertFalse(userSet);
- }
- }
- }
-
- @Test
public void testPullPackagePreferencesStats_postPermissionMigration() {
- when(mPermissionHelper.isMigrationEnabled()).thenReturn(true);
// build a collection of app permissions that should be passed in but ignored
ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>();
@@ -5369,9 +4765,9 @@ public class PreferencesHelperTest extends UiServiceTestCase {
appPermissions.put(new Pair(3, "third"), new Pair(false, true)); // not in local prefs
appPermissions.put(new Pair(UID_O, PKG_O), new Pair(false, true)); // in local prefs
- // package preferences: PKG_O not banned based on local importance, and PKG_P is
- mHelper.setImportance(PKG_O, UID_O, IMPORTANCE_HIGH);
- mHelper.setImportance(PKG_P, UID_P, IMPORTANCE_NONE);
+ // local preferences
+ mHelper.canShowBadge(PKG_O, UID_O);
+ mHelper.canShowBadge(PKG_P, UID_P);
// expected output. format: uid -> importance, as only uid (and not package name)
// is in PackageNotificationPreferences
@@ -5433,27 +4829,4 @@ public class PreferencesHelperTest extends UiServiceTestCase {
assertTrue((channelB.getUserLockedFields() & USER_LOCKED_IMPORTANCE) == 0);
assertTrue((channelC.getUserLockedFields() & USER_LOCKED_IMPORTANCE) == 0);
}
-
- @Test
- public void testDefaultChannelUpdatesApp_preMigrationToPermissions() throws Exception {
- final NotificationChannel defaultChannel = mHelper.getNotificationChannel(PKG_N_MR1,
- UID_N_MR1,
- NotificationChannel.DEFAULT_CHANNEL_ID, false);
- defaultChannel.setImportance(IMPORTANCE_NONE);
- mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, defaultChannel, true);
-
- assertEquals(IMPORTANCE_NONE, mHelper.getImportance(PKG_N_MR1, UID_N_MR1));
- }
-
- @Test
- public void testDefaultChannelDoesNotUpdateApp_postMigrationToPermissions() throws Exception {
- when(mPermissionHelper.isMigrationEnabled()).thenReturn(true);
- final NotificationChannel defaultChannel = mHelper.getNotificationChannel(PKG_N_MR1,
- UID_N_MR1,
- NotificationChannel.DEFAULT_CHANNEL_ID, false);
- defaultChannel.setImportance(IMPORTANCE_NONE);
- mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, defaultChannel, true);
-
- assertEquals(IMPORTANCE_UNSPECIFIED, mHelper.getImportance(PKG_N_MR1, UID_N_MR1));
- }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
index 0bfd2020622f..98c156e6f3b5 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
@@ -168,7 +168,8 @@ public class RoleObserverTest extends UiServiceTestCase {
mock(StatsManager.class), mock(TelephonyManager.class),
mock(ActivityManagerInternal.class),
mock(MultiRateLimiter.class), mock(PermissionHelper.class),
- mock(UsageStatsManagerInternal.class), mock (TelecomManager.class));
+ mock(UsageStatsManagerInternal.class), mock (TelecomManager.class),
+ mock(NotificationChannelLogger.class));
} catch (SecurityException e) {
if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
throw e;
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
index 35921585d56f..eb6395b46120 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
@@ -39,10 +39,8 @@ import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentat
import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
-import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static org.junit.Assert.assertEquals;
@@ -50,9 +48,7 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.never;
import android.graphics.Rect;
import android.os.Binder;
@@ -380,7 +376,7 @@ public class AppTransitionTests extends WindowTestsBase {
doReturn(false).when(dc).onDescendantOrientationChanged(any());
final WindowState exitingAppWindow = createWindow(null /* parent */, TYPE_BASE_APPLICATION,
dc, "exiting app");
- final ActivityRecord exitingActivity = exitingAppWindow.mActivityRecord;
+ final ActivityRecord exitingActivity= exitingAppWindow.mActivityRecord;
// Wait until everything in animation handler get executed to prevent the exiting window
// from being removed during WindowSurfacePlacer Traversal.
waitUntilHandlersIdle();
@@ -409,41 +405,6 @@ public class AppTransitionTests extends WindowTestsBase {
}
@Test
- public void testDelayWhileRecents() {
- final DisplayContent dc = createNewDisplay(Display.STATE_ON);
- doReturn(false).when(dc).onDescendantOrientationChanged(any());
- final Task task = createTask(dc);
-
- // Simulate activity1 launches activity2.
- final ActivityRecord activity1 = createActivityRecord(task);
- activity1.setVisible(true);
- activity1.mVisibleRequested = false;
- activity1.allDrawn = true;
- final ActivityRecord activity2 = createActivityRecord(task);
- activity2.setVisible(false);
- activity2.mVisibleRequested = true;
- activity2.allDrawn = true;
-
- dc.mClosingApps.add(activity1);
- dc.mOpeningApps.add(activity2);
- dc.prepareAppTransition(TRANSIT_OPEN);
- assertTrue(dc.mAppTransition.containsTransitRequest(TRANSIT_OPEN));
-
- // Wait until everything in animation handler get executed to prevent the exiting window
- // from being removed during WindowSurfacePlacer Traversal.
- waitUntilHandlersIdle();
-
- // Start recents
- doReturn(true).when(task)
- .isSelfAnimating(anyInt(), eq(ANIMATION_TYPE_RECENTS));
-
- dc.mAppTransitionController.handleAppTransitionReady();
-
- verify(activity1, never()).commitVisibility(anyBoolean(), anyBoolean(), anyBoolean());
- verify(activity2, never()).commitVisibility(anyBoolean(), anyBoolean(), anyBoolean());
- }
-
- @Test
public void testGetAnimationStyleResId() {
// Verify getAnimationStyleResId will return as LayoutParams.windowAnimations when without
// specifying window type.
diff --git a/telecomm/java/android/telecom/PhoneAccountHandle.java b/telecomm/java/android/telecom/PhoneAccountHandle.java
index e3485deb9080..ec94f8a1829f 100644
--- a/telecomm/java/android/telecom/PhoneAccountHandle.java
+++ b/telecomm/java/android/telecom/PhoneAccountHandle.java
@@ -46,6 +46,14 @@ import java.util.Objects;
* See {@link PhoneAccount}, {@link TelecomManager}.
*/
public final class PhoneAccountHandle implements Parcelable {
+ /**
+ * Expected component name of Telephony phone accounts; ONLY used to determine if we should log
+ * the phone account handle ID.
+ */
+ private static final ComponentName TELEPHONY_COMPONENT_NAME =
+ new ComponentName("com.android.phone",
+ "com.android.services.telephony.TelephonyConnectionService");
+
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 127403196)
private final ComponentName mComponentName;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
@@ -136,14 +144,23 @@ public final class PhoneAccountHandle implements Parcelable {
@Override
public String toString() {
- // Note: Log.pii called for mId as it can contain personally identifying phone account
- // information such as SIP account IDs.
- return new StringBuilder().append(mComponentName)
- .append(", ")
- .append(Log.pii(mId))
- .append(", ")
- .append(mUserHandle)
- .toString();
+ StringBuilder sb = new StringBuilder()
+ .append(mComponentName)
+ .append(", ");
+
+ if (TELEPHONY_COMPONENT_NAME.equals(mComponentName)) {
+ // Telephony phone account handles are now keyed by subscription id which is not
+ // sensitive.
+ sb.append(mId);
+ } else {
+ // Note: Log.pii called for mId as it can contain personally identifying phone account
+ // information such as SIP account IDs.
+ sb.append(Log.pii(mId));
+ }
+ sb.append(", ");
+ sb.append(mUserHandle);
+
+ return sb.toString();
}
@Override
diff --git a/telephony/java/android/telephony/AnomalyReporter.java b/telephony/java/android/telephony/AnomalyReporter.java
index f47cf3384791..e7d95e4f53b3 100644
--- a/telephony/java/android/telephony/AnomalyReporter.java
+++ b/telephony/java/android/telephony/AnomalyReporter.java
@@ -16,6 +16,8 @@
package android.telephony;
+import static android.telephony.TelephonyManager.UNKNOWN_CARRIER_ID;
+
import static com.android.internal.telephony.TelephonyStatsLog.TELEPHONY_ANOMALY_DETECTED;
import android.annotation.NonNull;
@@ -73,6 +75,7 @@ public final class AnomalyReporter {
*
* This method sends the {@link TelephonyManager#ACTION_ANOMALY_REPORTED} broadcast, which is
* system protected. Invoking this method unless you are the system will result in an error.
+ * Carrier Id will be set as UNKNOWN_CARRIER_ID.
*
* @param eventId a fixed event ID that will be sent for each instance of the same event. This
* ID should be generated randomly.
@@ -81,6 +84,23 @@ public final class AnomalyReporter {
* static and must not contain any sensitive information (especially PII).
*/
public static void reportAnomaly(@NonNull UUID eventId, String description) {
+ reportAnomaly(eventId, description, UNKNOWN_CARRIER_ID);
+ }
+
+ /**
+ * If enabled, build and send an intent to a Debug Service for logging.
+ *
+ * This method sends the {@link TelephonyManager#ACTION_ANOMALY_REPORTED} broadcast, which is
+ * system protected. Invoking this method unless you are the system will result in an error.
+ *
+ * @param eventId a fixed event ID that will be sent for each instance of the same event. This
+ * ID should be generated randomly.
+ * @param description an optional description, that if included will be used as the subject for
+ * identification and discussion of this event. This description should ideally be
+ * static and must not contain any sensitive information (especially PII).
+ * @param carrierId the carrier of the id associated with this event.
+ */
+ public static void reportAnomaly(@NonNull UUID eventId, String description, int carrierId) {
if (sContext == null) {
Rlog.w(TAG, "AnomalyReporter not yet initialized, dropping event=" + eventId);
return;
@@ -88,7 +108,7 @@ public final class AnomalyReporter {
TelephonyStatsLog.write(
TELEPHONY_ANOMALY_DETECTED,
- 0, // TODO: carrier id needs to be populated
+ carrierId,
eventId.getLeastSignificantBits(),
eventId.getMostSignificantBits());
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index e21301eb32af..70fe6b10ef20 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -4980,6 +4980,25 @@ public class CarrierConfigManager {
KEY_PREFIX + "use_sip_uri_for_presence_subscribe_bool";
/**
+ * Flag indicating whether or not to use TEL URI when setting the entity uri field and
+ * contact element of each tuple.
+ *
+ * When {@code true}, the device sets the entity uri field and contact element to be
+ * TEL URI. This is done by first searching for the first TEL URI provided in
+ * p-associated-uri header. If there are no TEL URIs in the p-associated-uri header, we will
+ * convert the first SIP URI provided in the header to a TEL URI. If there are no URIs in
+ * the p-associated-uri header, we will then fall back to using the SIM card to generate the
+ * TEL URI.
+ * If {@code false}, the first URI provided in the p-associated-uri header is used,
+ * independent of the URI scheme. If there are no URIs available from p-associated-uri
+ * header, we will try to generate a SIP URI or TEL URI from the information provided by the
+ * SIM card, depending on the information available.
+ * @hide
+ */
+ public static final String KEY_USE_TEL_URI_FOR_PIDF_XML_BOOL =
+ KEY_PREFIX + "use_tel_uri_for_pidf_xml";
+
+ /**
* An integer key associated with the period of time in seconds the non-rcs capability
* information of each contact is cached on the device.
* <p>
diff --git a/tests/ApkVerityTest/Android.bp b/tests/ApkVerityTest/Android.bp
index d4fa1dda8bdf..62e16a5b83de 100644
--- a/tests/ApkVerityTest/Android.bp
+++ b/tests/ApkVerityTest/Android.bp
@@ -37,8 +37,8 @@ java_test_host {
"general-tests",
"vts",
],
- data_device_bins: [
- "block_device_writer",
+ target_required: [
+ "block_device_writer_module",
],
data: [
":ApkVerityTestCertDer",
diff --git a/tests/ApkVerityTest/block_device_writer/Android.bp b/tests/ApkVerityTest/block_device_writer/Android.bp
index e5d009dc10fd..fdfa41fd4ca9 100644
--- a/tests/ApkVerityTest/block_device_writer/Android.bp
+++ b/tests/ApkVerityTest/block_device_writer/Android.bp
@@ -24,7 +24,12 @@ package {
}
cc_test {
- name: "block_device_writer",
+ // Depending on how the test runs, the executable may be uploaded to different location.
+ // Before the bug in the file pusher is fixed, workaround by making the name unique.
+ // See b/124718249#comment12.
+ name: "block_device_writer_module",
+ stem: "block_device_writer",
+
srcs: ["block_device_writer.cpp"],
cflags: [
"-D_FILE_OFFSET_BITS=64",
@@ -37,7 +42,22 @@ cc_test {
"libbase",
"libutils",
],
- compile_multilib: "first",
+ // For some reasons, cuttlefish (x86) uses x86_64 test suites for testing. Unfortunately, when
+ // the uploader does not pick up the executable from correct output location. The following
+ // workaround allows the test to:
+ // * upload the 32-bit exectuable for both 32 and 64 bits devices to use
+ // * refer to the same executable name in Java
+ // * no need to force the Java test to be archiecture specific.
+ //
+ // See b/145573317 for details.
+ multilib: {
+ lib32: {
+ suffix: "",
+ },
+ lib64: {
+ suffix: "64", // not really used
+ },
+ },
auto_gen_config: false,
test_suites: [
diff --git a/tests/ApkVerityTest/block_device_writer/src/com/android/blockdevicewriter/BlockDeviceWriter.java b/tests/ApkVerityTest/block_device_writer/src/com/android/blockdevicewriter/BlockDeviceWriter.java
index 730daf32f20d..5c2c15b22bb0 100644
--- a/tests/ApkVerityTest/block_device_writer/src/com/android/blockdevicewriter/BlockDeviceWriter.java
+++ b/tests/ApkVerityTest/block_device_writer/src/com/android/blockdevicewriter/BlockDeviceWriter.java
@@ -32,7 +32,7 @@ import java.util.ArrayList;
* <p>To use this class, please push block_device_writer binary to /data/local/tmp.
* 1. In Android.bp, add:
* <pre>
- * data_device_bins: ["block_device_writer"],
+ * target_required: ["block_device_writer_module"],
* </pre>
* 2. In AndroidText.xml, add:
* <pre>