summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--PREUPLOAD.cfg1
-rw-r--r--api/test-current.txt8
-rw-r--r--cmds/statsd/src/logd/LogEvent.h3
-rw-r--r--cmds/statsd/src/shell/ShellSubscriber.cpp1
-rw-r--r--core/java/android/accessibilityservice/AccessibilityService.java7
-rw-r--r--core/java/android/app/Notification.java3
-rw-r--r--core/java/android/app/admin/DevicePolicyManagerInternal.java18
-rw-r--r--core/java/android/content/pm/CrossProfileApps.java3
-rw-r--r--core/java/android/content/pm/PackageManager.java8
-rw-r--r--core/java/android/content/pm/parsing/ParsingPackageUtils.java7
-rw-r--r--core/java/android/net/NetworkAgent.java4
-rw-r--r--core/java/android/os/PowerManagerInternal.java4
-rw-r--r--core/java/android/provider/Settings.java10
-rw-r--r--core/java/android/service/notification/StatusBarNotification.java10
-rw-r--r--core/java/android/util/FeatureFlagUtils.java3
-rw-r--r--core/java/android/view/SurfaceView.java2
-rw-r--r--core/java/android/view/accessibility/AccessibilityManager.java9
-rw-r--r--core/java/android/widget/Toast.java10
-rw-r--r--core/java/android/widget/ToastPresenter.java25
-rw-r--r--core/java/android/window/TaskOrganizerTaskEmbedder.java4
-rw-r--r--core/java/com/android/internal/app/AlertController.java1
-rw-r--r--core/java/com/android/internal/app/ChooserActivityLogger.java3
-rw-r--r--core/java/com/android/internal/statusbar/IStatusBar.aidl4
-rw-r--r--core/java/com/android/internal/widget/ConversationLayout.java6
-rw-r--r--core/res/res/layout/notification_template_material_conversation.xml99
-rw-r--r--core/res/res/values/symbols.xml1
-rw-r--r--core/xsd/vts/Android.bp2
-rw-r--r--media/java/android/media/AudioSystem.java475
-rw-r--r--media/java/android/media/tv/tuner/Tuner.java33
-rw-r--r--media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java4
-rw-r--r--media/jni/android_media_tv_Tuner.cpp30
-rw-r--r--media/jni/android_media_tv_Tuner.h2
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/CarComponentBinder.java3
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java2
-rw-r--r--packages/CarSystemUI/src/com/android/systemui/CarSystemUIRootComponent.java2
-rw-r--r--packages/SettingsLib/res/values/strings.xml8
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/WifiSavedConfigUtils.java12
-rw-r--r--packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java1
-rw-r--r--packages/Shell/src/com/android/shell/BugreportProgressService.java17
-rw-r--r--packages/SystemUI/AndroidManifest.xml3
-rw-r--r--packages/SystemUI/res/values/arrays_tv.xml2
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioActivityObserver.java44
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java (renamed from packages/SystemUI/src/com/android/systemui/statusbar/tv/AudioRecordingDisclosureBar.java)147
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/MicrophoneForegroundServicesObserver.java189
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/RecordAudioAppOpObserver.java80
-rw-r--r--packages/SystemUI/src/com/android/systemui/toast/ToastUI.java25
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java108
-rw-r--r--packages/Tethering/src/android/net/ip/IpServer.java29
-rw-r--r--packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java7
-rw-r--r--packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java166
-rw-r--r--packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java109
-rw-r--r--packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java32
-rw-r--r--packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/IPv6TetheringCoordinatorTest.java156
-rw-r--r--services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java23
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java8
-rw-r--r--services/core/java/com/android/server/PackageWatchdog.java39
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java2
-rw-r--r--services/core/java/com/android/server/biometrics/face/FaceService.java6
-rw-r--r--services/core/java/com/android/server/connectivity/Nat464Xlat.java77
-rw-r--r--services/core/java/com/android/server/content/ContentService.java149
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java28
-rw-r--r--services/core/java/com/android/server/notification/NotificationRecord.java5
-rw-r--r--services/core/java/com/android/server/notification/PreferencesHelper.java5
-rw-r--r--services/core/java/com/android/server/notification/toast/CustomToastRecord.java12
-rw-r--r--services/core/java/com/android/server/notification/toast/TextToastRecord.java13
-rw-r--r--services/core/java/com/android/server/notification/toast/ToastRecord.java8
-rw-r--r--services/core/java/com/android/server/pm/ApexManager.java22
-rw-r--r--services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java39
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java7
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java7
-rw-r--r--services/core/java/com/android/server/pm/Settings.java4
-rw-r--r--services/core/java/com/android/server/pm/StagingManager.java60
-rw-r--r--services/core/java/com/android/server/power/PowerManagerService.java33
-rw-r--r--services/core/java/com/android/server/security/FileIntegrityService.java13
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java2
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerService.java4
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java25
-rw-r--r--services/core/java/com/android/server/wm/Task.java14
-rw-r--r--services/core/java/com/android/server/wm/TaskOrganizerController.java136
-rw-r--r--services/core/java/com/android/server/wm/WindowContainer.java5
-rw-r--r--services/core/xsd/vts/Android.bp2
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java5
-rw-r--r--services/incremental/Android.bp1
-rw-r--r--services/incremental/IncrementalService.cpp82
-rw-r--r--services/incremental/IncrementalService.h13
-rw-r--r--services/incremental/IncrementalServiceValidation.h19
-rw-r--r--services/incremental/ServiceWrappers.h53
-rw-r--r--services/incremental/test/IncrementalServiceTest.cpp86
-rw-r--r--services/java/com/android/server/SystemServer.java6
-rw-r--r--services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java24
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java38
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelExtractorTest.java12
-rwxr-xr-xservices/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java2
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java9
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java26
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java9
-rw-r--r--services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java158
-rw-r--r--tests/ApkVerityTest/Android.bp2
-rw-r--r--tests/ApkVerityTest/block_device_writer/Android.bp2
-rw-r--r--tests/net/java/com/android/server/connectivity/Nat464XlatTest.java10
109 files changed, 2305 insertions, 1016 deletions
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 9abb308534df..2fd2e33bbc37 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -9,6 +9,7 @@ clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
core/jni/
libs/input/
services/core/jni/
+ services/incremental/
[Hook Scripts]
checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
diff --git a/api/test-current.txt b/api/test-current.txt
index 03f4dc5d2f87..629ce4e6470e 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1504,6 +1504,13 @@ package android.media {
ctor public AudioRecordingConfiguration(int, int, int, android.media.AudioFormat, android.media.AudioFormat, int, String);
}
+ public class AudioSystem {
+ method public static float getMasterBalance();
+ method public static final int getNumStreamTypes();
+ method public static int setMasterBalance(float);
+ field public static final int STREAM_DEFAULT = -1; // 0xffffffff
+ }
+
public static final class AudioTrack.MetricsConstants {
field public static final String ATTRIBUTES = "android.media.audiotrack.attributes";
field public static final String CHANNEL_MASK = "android.media.audiotrack.channelMask";
@@ -4707,7 +4714,6 @@ package android.util {
field public static final String FFLAG_OVERRIDE_PREFIX = "sys.fflag.override.";
field public static final String FFLAG_PREFIX = "sys.fflag.";
field public static final String HEARING_AID_SETTINGS = "settings_bluetooth_hearing_aid";
- field public static final String NOTIF_CONVO_BYPASS_SHORTCUT_REQ = "settings_notif_convo_bypass_shortcut_req";
field public static final String PERSIST_PREFIX = "persist.sys.fflag.override.";
field public static final String SCREENRECORD_LONG_PRESS = "settings_screenrecord_long_press";
field public static final String SEAMLESS_TRANSFER = "settings_seamless_transfer";
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index 850e2b010f8c..9e21c777e6ff 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -218,9 +218,6 @@ private:
* The below three variables are only valid during the execution of
* parseBuffer. There are no guarantees about the state of these variables
* before/after.
- *
- * TODO (b/150312423): These shouldn't be member variables. We should pass
- * them around as parameters.
*/
uint8_t* mBuf;
uint32_t mRemainingLen; // number of valid bytes left in the buffer being parsed
diff --git a/cmds/statsd/src/shell/ShellSubscriber.cpp b/cmds/statsd/src/shell/ShellSubscriber.cpp
index 1cee4d9babdc..bed836a1bd90 100644
--- a/cmds/statsd/src/shell/ShellSubscriber.cpp
+++ b/cmds/statsd/src/shell/ShellSubscriber.cpp
@@ -152,7 +152,6 @@ void ShellSubscriber::startPull(int64_t myToken) {
mPullerMgr->Pull(pullInfo.mPullerMatcher.atom_id(), uids, &data);
VLOG("pulled %zu atoms with id %d", data.size(), pullInfo.mPullerMatcher.atom_id());
- // TODO(b/150969574): Don't write to a pipe while holding a lock.
if (!writePulledAtomsLocked(data, pullInfo.mPullerMatcher)) {
mSubscriptionInfo->mClientAlive = false;
mSubscriptionShouldEnd.notify_one();
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index d4f511280553..67334f554df7 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -1819,6 +1819,13 @@ public abstract class AccessibilityService extends Service {
/**
* Returns a list of system actions available in the system right now.
+ * <p>
+ * System actions that correspond to the global action constants will have matching action IDs.
+ * For example, an with id {@link #GLOBAL_ACTION_BACK} will perform the back action.
+ * </p>
+ * <p>
+ * These actions should be called by {@link #performGlobalAction}.
+ * </p>
*
* @return A list of available system actions.
*/
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index f461a1708373..7a593498e967 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -7158,7 +7158,8 @@ public class Notification implements Parcelable
CharSequence conversationTitle = !TextUtils.isEmpty(super.mBigContentTitle)
? super.mBigContentTitle
: mConversationTitle;
- if (!TextUtils.isEmpty(conversationTitle) && !hasOnlyWhiteSpaceSenders()) {
+ if (mConversationType == CONVERSATION_TYPE_LEGACY
+ && !TextUtils.isEmpty(conversationTitle) && !hasOnlyWhiteSpaceSenders()) {
return conversationTitle;
}
return null;
diff --git a/core/java/android/app/admin/DevicePolicyManagerInternal.java b/core/java/android/app/admin/DevicePolicyManagerInternal.java
index 80fa87152d78..41f04f73aa87 100644
--- a/core/java/android/app/admin/DevicePolicyManagerInternal.java
+++ b/core/java/android/app/admin/DevicePolicyManagerInternal.java
@@ -176,19 +176,31 @@ public abstract class DevicePolicyManagerInternal {
* for cross-profile communication, via {@link
* DevicePolicyManager#setCrossProfilePackages(ComponentName, Set)}.</li>
* <li>The default package names that are allowed to request user consent for cross-profile
- * communication without being explicitly enabled by the admin , via {@link
- * DevicePolicyManager#setDefaultCrossProfilePackages(ComponentName, UserHandle, Set)}.</li>
+ * communication without being explicitly enabled by the admin, via
+ * {@link com.android.internal.R.array#cross_profile_apps} and
+ * {@link com.android.internal.R.array#vendor_cross_profile_apps}.</li>
* </ul>
*
* @return the combined set of whitelisted package names set via
* {@link DevicePolicyManager#setCrossProfilePackages(ComponentName, Set)} and
- * {@link DevicePolicyManager#setDefaultCrossProfilePackages(ComponentName, UserHandle, Set)}
+ * {@link com.android.internal.R.array#cross_profile_apps} and
+ * {@link com.android.internal.R.array#vendor_cross_profile_apps}
*
* @hide
*/
public abstract List<String> getAllCrossProfilePackages();
/**
+ * Returns the default package names set by the OEM that are allowed to request user consent for
+ * cross-profile communication without being explicitly enabled by the admin, via
+ * {@link com.android.internal.R.array#cross_profile_apps} and
+ * {@link com.android.internal.R.array#vendor_cross_profile_apps}.
+ *
+ * @hide
+ */
+ public abstract List<String> getDefaultCrossProfilePackages();
+
+ /**
* Sends the {@code intent} to the packages with cross profile capabilities.
*
* <p>This means the application must have the {@code crossProfile} property and the
diff --git a/core/java/android/content/pm/CrossProfileApps.java b/core/java/android/content/pm/CrossProfileApps.java
index 7578ede2648d..144a07eb4ea3 100644
--- a/core/java/android/content/pm/CrossProfileApps.java
+++ b/core/java/android/content/pm/CrossProfileApps.java
@@ -435,6 +435,9 @@ public class CrossProfileApps {
* <p>This differs from {@link #canConfigureInteractAcrossProfiles(String)} since it will
* not return {@code false} if the app is not whitelisted or not installed in the other profile.
*
+ * <p>Note that platform-signed apps that are automatically granted the permission and are not
+ * whitelisted by the OEM will not be included in this list.
+ *
* @hide
*/
public boolean canUserAttemptToConfigureInteractAcrossProfiles(String packageName) {
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index f48d78ac9cc3..9a2e07e9cfbd 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1542,6 +1542,14 @@ public abstract class PackageManager {
*/
public static final int INSTALL_FAILED_PROCESS_NOT_DEFINED = -122;
+ /**
+ * Installation parse return code: system is in a minimal boot state, and the parser only
+ * allows the package with {@code coreApp} manifest attribute to be a valid application.
+ *
+ * @hide
+ */
+ public static final int INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED = -123;
+
/** @hide */
@IntDef(flag = true, prefix = { "DELETE_" }, value = {
DELETE_KEEP_DATA,
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index 12328cf32fb3..c94d428f4475 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -22,6 +22,7 @@ import static android.content.pm.PackageManager.FEATURE_WATCH;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
+import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED;
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
import static android.os.Build.VERSION_CODES.DONUT;
import static android.os.Build.VERSION_CODES.O;
@@ -229,7 +230,8 @@ public class ParsingPackageUtils {
final PackageParser.PackageLite lite = ApkLiteParseUtils.parseClusterPackageLite(packageDir,
0);
if (mOnlyCoreApps && !lite.coreApp) {
- return input.error("Not a coreApp: " + packageDir);
+ return input.error(INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED,
+ "Not a coreApp: " + packageDir);
}
// Build the split dependency tree.
@@ -291,7 +293,8 @@ public class ParsingPackageUtils {
final PackageParser.PackageLite lite = ApkLiteParseUtils.parseMonolithicPackageLite(apkFile,
flags);
if (mOnlyCoreApps && !lite.coreApp) {
- return input.error("Not a coreApp: " + apkFile);
+ return input.error(INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED,
+ "Not a coreApp: " + apkFile);
}
final SplitAssetLoader assetLoader = new DefaultSplitAssetLoader(lite, flags);
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index c42dacc187a9..e9bcefef50c7 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -556,12 +556,12 @@ public abstract class NetworkAgent {
@NonNull
public Network register() {
if (VDBG) log("Registering NetworkAgent");
- final ConnectivityManager cm = (ConnectivityManager) mInitialConfiguration.context
- .getSystemService(Context.CONNECTIVITY_SERVICE);
synchronized (mRegisterLock) {
if (mNetwork != null) {
throw new IllegalStateException("Agent already registered");
}
+ final ConnectivityManager cm = (ConnectivityManager) mInitialConfiguration.context
+ .getSystemService(Context.CONNECTIVITY_SERVICE);
mNetwork = cm.registerNetworkAgent(new Messenger(mHandler),
new NetworkInfo(mInitialConfiguration.info),
mInitialConfiguration.properties, mInitialConfiguration.capabilities,
diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java
index 51f01cac8138..653a5594f495 100644
--- a/core/java/android/os/PowerManagerInternal.java
+++ b/core/java/android/os/PowerManagerInternal.java
@@ -102,9 +102,9 @@ public abstract class PowerManagerInternal {
*
* This method must only be called by the window manager.
*
- * @param brightness The overridden brightness, or -1 to disable the override.
+ * @param brightness The overridden brightness, or Float.NaN to disable the override.
*/
- public abstract void setScreenBrightnessOverrideFromWindowManager(int brightness);
+ public abstract void setScreenBrightnessOverrideFromWindowManager(float brightness);
/**
* Used by the window manager to override the user activity timeout based on the
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index e2d0c49d9d13..920302c75011 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -13757,6 +13757,16 @@ public final class Settings {
"show_notification_channel_warnings";
/**
+ * When enabled, requires all notifications in the conversation section to be backed
+ * by a long-lived sharing shortcut
+ *
+ * The value 1 - require a shortcut, 0 - do not require a shortcut
+ * @hide
+ */
+ public static final String REQUIRE_SHORTCUTS_FOR_CONVERSATIONS =
+ "require_shortcuts_for_conversations";
+
+ /**
* Whether cell is enabled/disabled
* @hide
*/
diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index 1beeb6554ee1..21b83c660446 100644
--- a/core/java/android/service/notification/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -17,8 +17,6 @@
package android.service.notification;
import static android.app.NotificationChannel.PLACEHOLDER_CONVERSATION_ID;
-import static android.util.FeatureFlagUtils.NOTIF_CONVO_BYPASS_SHORTCUT_REQ;
-import static android.util.FeatureFlagUtils.isEnabled;
import android.annotation.NonNull;
import android.app.Notification;
@@ -33,6 +31,7 @@ import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.UserHandle;
+import android.provider.Settings;
import android.text.TextUtils;
import com.android.internal.logging.InstanceId;
@@ -477,9 +476,10 @@ public class StatusBarNotification implements Parcelable {
*/
public String getShortcutId(Context context) {
String conversationId = getNotification().getShortcutId();
- if (isEnabled(context, NOTIF_CONVO_BYPASS_SHORTCUT_REQ)
- && getNotification().getNotificationStyle() == Notification.MessagingStyle.class
- && TextUtils.isEmpty(conversationId)) {
+ if (TextUtils.isEmpty(conversationId)
+ && (Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 0) == 0)
+ && getNotification().getNotificationStyle() == Notification.MessagingStyle.class) {
conversationId = getId() + getTag() + PLACEHOLDER_CONVERSATION_ID;
}
return conversationId;
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index faa5cf591408..cd20b357e2f1 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -42,8 +42,6 @@ public class FeatureFlagUtils {
public static final String DYNAMIC_SYSTEM = "settings_dynamic_system";
public static final String SETTINGS_WIFITRACKER2 = "settings_wifitracker2";
public static final String SETTINGS_FUSE_FLAG = "settings_fuse";
- public static final String NOTIF_CONVO_BYPASS_SHORTCUT_REQ =
- "settings_notif_convo_bypass_shortcut_req";
/** @hide */
public static final String SETTINGS_DO_NOT_RESTORE_PRESERVED =
"settings_do_not_restore_preserved";
@@ -66,7 +64,6 @@ public class FeatureFlagUtils {
DEFAULT_FLAGS.put(SETTINGS_WIFITRACKER2, "true");
DEFAULT_FLAGS.put("settings_controller_loading_enhancement", "false");
DEFAULT_FLAGS.put("settings_conditionals", "false");
- DEFAULT_FLAGS.put(NOTIF_CONVO_BYPASS_SHORTCUT_REQ, "true");
// This flags guards a feature introduced in R and will be removed in the next release
// (b/148367230).
DEFAULT_FLAGS.put(SETTINGS_DO_NOT_RESTORE_PRESERVED, "true");
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index b0981730c1eb..b677ccd9a618 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -1037,7 +1037,7 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
mTmpTransaction.setWindowCrop(mSurfaceControl, mSurfaceWidth,
mSurfaceHeight);
}
- } else if ((layoutSizeChanged || positionChanged) &&
+ } else if ((layoutSizeChanged || positionChanged || visibleChanged) &&
viewRoot.useBLAST()) {
viewRoot.setUseBLASTSyncTransaction();
}
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index dc87453bd867..6a109253a27c 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -1275,7 +1275,14 @@ public final class AccessibilityManager {
/**
* Register the provided {@link RemoteAction} with the given actionId
- *
+ * <p>
+ * To perform established system actions, an accessibility service uses the GLOBAL_ACTION
+ * constants in {@link android.accessibilityservice.AccessibilityService}. To provide a
+ * customized implementation for one of these actions, the id of the registered system action
+ * must match that of the corresponding GLOBAL_ACTION constant. For example, to register a
+ * Back action, {@code actionId} must be
+ * {@link android.accessibilityservice.AccessibilityService#GLOBAL_ACTION_BACK}
+ * </p>
* @param action The remote action to be registered with the given actionId as system action.
* @param actionId The id uniquely identify the system action.
* @hide
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index 08b32930971a..fb962103990c 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -43,7 +43,7 @@ import android.os.ServiceManager;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;
-import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.IAccessibilityManager;
import com.android.internal.annotations.GuardedBy;
@@ -610,10 +610,10 @@ public class Toast {
*/
TN(Context context, String packageName, Binder token, List<Callback> callbacks,
@Nullable Looper looper) {
- WindowManager windowManager = context.getSystemService(WindowManager.class);
- AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(context);
- mPresenter = new ToastPresenter(context, windowManager, accessibilityManager,
- getService(), packageName);
+ IAccessibilityManager accessibilityManager = IAccessibilityManager.Stub.asInterface(
+ ServiceManager.getService(Context.ACCESSIBILITY_SERVICE));
+ mPresenter = new ToastPresenter(context, accessibilityManager, getService(),
+ packageName);
mParams = mPresenter.getLayoutParams();
mPackageName = packageName;
mToken = token;
diff --git a/core/java/android/widget/ToastPresenter.java b/core/java/android/widget/ToastPresenter.java
index e9d4aa668891..2679c69be4f6 100644
--- a/core/java/android/widget/ToastPresenter.java
+++ b/core/java/android/widget/ToastPresenter.java
@@ -27,6 +27,7 @@ import android.content.res.Resources;
import android.graphics.PixelFormat;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
@@ -34,8 +35,10 @@ import android.view.View;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.IAccessibilityManager;
import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
/**
@@ -49,12 +52,14 @@ public class ToastPresenter {
private static final long SHORT_DURATION_TIMEOUT = 4000;
private static final long LONG_DURATION_TIMEOUT = 7000;
+ @VisibleForTesting
+ public static final int TEXT_TOAST_LAYOUT = R.layout.transient_notification;
+
/**
* Returns the default text toast view for message {@code text}.
*/
public static View getTextToastView(Context context, CharSequence text) {
- View view = LayoutInflater.from(context).inflate(
- R.layout.transient_notification, null);
+ View view = LayoutInflater.from(context).inflate(TEXT_TOAST_LAYOUT, null);
TextView textView = view.findViewById(com.android.internal.R.id.message);
textView.setText(text);
return view;
@@ -70,15 +75,23 @@ public class ToastPresenter {
@Nullable private View mView;
@Nullable private IBinder mToken;
- public ToastPresenter(Context context, WindowManager windowManager,
- AccessibilityManager accessibilityManager,
+ public ToastPresenter(Context context, IAccessibilityManager accessibilityManager,
INotificationManager notificationManager, String packageName) {
mContext = context;
mResources = context.getResources();
- mWindowManager = windowManager;
- mAccessibilityManager = accessibilityManager;
+ mWindowManager = context.getSystemService(WindowManager.class);
mNotificationManager = notificationManager;
mPackageName = packageName;
+
+ // We obtain AccessibilityManager manually via its constructor instead of using method
+ // AccessibilityManager.getInstance() for 2 reasons:
+ // 1. We want to be able to inject IAccessibilityManager in tests to verify behavior.
+ // 2. getInstance() caches the instance for the process even if we pass a different
+ // context to it. This is problematic for multi-user because callers can pass a context
+ // created via Context.createContextAsUser().
+ mAccessibilityManager = new AccessibilityManager(context, accessibilityManager,
+ UserHandle.getCallingUserId());
+
mParams = createLayoutParams();
}
diff --git a/core/java/android/window/TaskOrganizerTaskEmbedder.java b/core/java/android/window/TaskOrganizerTaskEmbedder.java
index 39a0101bbf59..2091c9398e95 100644
--- a/core/java/android/window/TaskOrganizerTaskEmbedder.java
+++ b/core/java/android/window/TaskOrganizerTaskEmbedder.java
@@ -254,9 +254,7 @@ public class TaskOrganizerTaskEmbedder extends TaskEmbedder {
mTaskToken = taskInfo.token;
mTaskLeash = mTaskToken.getLeash();
mTransaction.reparent(mTaskLeash, mSurfaceControl)
- .show(mTaskLeash)
- .show(mSurfaceControl)
- .apply();
+ .show(mSurfaceControl).apply();
if (mPendingNotifyBoundsChanged) {
// TODO: Either defer show or hide and synchronize show with the resize
notifyBoundsChanged();
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index 553721d75fd6..be43e82c3f88 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -286,6 +286,7 @@ public class AlertController {
if (mTitleView != null) {
mTitleView.setText(title);
}
+ mWindow.setTitle(title);
}
/**
diff --git a/core/java/com/android/internal/app/ChooserActivityLogger.java b/core/java/com/android/internal/app/ChooserActivityLogger.java
index dc482443040a..088973cde3e9 100644
--- a/core/java/com/android/internal/app/ChooserActivityLogger.java
+++ b/core/java/com/android/internal/app/ChooserActivityLogger.java
@@ -191,6 +191,9 @@ public interface ChooserActivityLogger {
* ChooserActivity.
*/
default int typeFromIntentString(String intent) {
+ if (intent == null) {
+ return FrameworkStatsLog.SHARESHEET_STARTED__INTENT_TYPE__INTENT_DEFAULT;
+ }
switch (intent) {
case Intent.ACTION_VIEW:
return FrameworkStatsLog.SHARESHEET_STARTED__INTENT_TYPE__INTENT_ACTION_VIEW;
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 5b79b184b6a4..38f5f3279c8e 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -204,8 +204,8 @@ oneway interface IStatusBar
/**
* Displays a text toast.
*/
- void showToast(String packageName, IBinder token, CharSequence text, IBinder windowToken,
- int duration, @nullable ITransientNotificationCallback callback);
+ void showToast(int uid, String packageName, IBinder token, CharSequence text,
+ IBinder windowToken, int duration, @nullable ITransientNotificationCallback callback);
/**
* Cancels toast with token {@code token} in {@code packageName}.
diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java
index 523c7493420b..5a979ac97c54 100644
--- a/core/java/com/android/internal/widget/ConversationLayout.java
+++ b/core/java/com/android/internal/widget/ConversationLayout.java
@@ -121,6 +121,7 @@ public class ConversationLayout extends FrameLayout
private CachingIconView mConversationIconBadgeBg;
private Icon mLargeIcon;
private View mExpandButtonContainer;
+ private View mExpandButtonInnerContainer;
private ViewGroup mExpandButtonAndContentContainer;
private NotificationExpandButton mExpandButton;
private MessagingLinearLayout mImageMessageContainer;
@@ -242,6 +243,7 @@ public class ConversationLayout extends FrameLayout
mConversationHeader = findViewById(R.id.conversation_header);
mContentContainer = findViewById(R.id.notification_action_list_margin_target);
mExpandButtonAndContentContainer = findViewById(R.id.expand_button_and_content_container);
+ mExpandButtonInnerContainer = findViewById(R.id.expand_button_inner_container);
mExpandButton = findViewById(R.id.expand_button);
mExpandButtonExpandedTopMargin = getResources().getDimensionPixelSize(
R.dimen.conversation_expand_button_top_margin_expanded);
@@ -1169,7 +1171,7 @@ public class ConversationLayout extends FrameLayout
layoutParams.topMargin = topMargin;
mExpandButton.setLayoutParams(layoutParams);
- mExpandButtonContainer.setContentDescription(mContext.getText(contentDescriptionId));
+ mExpandButtonInnerContainer.setContentDescription(mContext.getText(contentDescriptionId));
}
private void updateContentEndPaddings() {
@@ -1213,7 +1215,7 @@ public class ConversationLayout extends FrameLayout
mExpandable = expandable;
if (expandable) {
mExpandButtonContainer.setVisibility(VISIBLE);
- mExpandButtonContainer.setOnClickListener(onClickListener);
+ mExpandButtonInnerContainer.setOnClickListener(onClickListener);
} else {
// TODO: handle content paddings to end of layout
mExpandButtonContainer.setVisibility(GONE);
diff --git a/core/res/res/layout/notification_template_material_conversation.xml b/core/res/res/layout/notification_template_material_conversation.xml
index b9ca29276cf0..e986b1886abf 100644
--- a/core/res/res/layout/notification_template_material_conversation.xml
+++ b/core/res/res/layout/notification_template_material_conversation.xml
@@ -245,6 +245,7 @@
android:id="@+id/notification_messaging"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:minHeight="@dimen/notification_text_size"
android:spacing="@dimen/notification_messaging_spacing"
android:clipToPadding="false"
android:clipChildren="false"
@@ -263,53 +264,65 @@
<include layout="@layout/notification_material_action_list" />
</com.android.internal.widget.RemeasuringLinearLayout>
- <!--This is dynamically placed between here and at the end of the layout-->
- <LinearLayout
+ <!--This is dynamically placed between here and at the end of the layout. It starts here since
+ only FrameLayout layout params have gravity-->
+ <FrameLayout
android:id="@+id/expand_button_container"
android:layout_width="wrap_content"
- android:layout_height="@dimen/conversation_expand_button_size"
+ android:layout_height="match_parent"
android:layout_gravity="end|top"
- android:paddingStart="16dp"
- android:orientation="horizontal"
- android:paddingEnd="@dimen/notification_content_margin_end"
- android:clipToPadding="false"
android:clipChildren="false"
- >
- <!-- Images -->
- <com.android.internal.widget.MessagingLinearLayout
- android:id="@+id/conversation_image_message_container"
- android:forceHasOverlappingRendering="false"
- android:layout_width="40dp"
- android:layout_height="40dp"
- android:layout_marginEnd="11dp"
- android:spacing="0dp"
- android:layout_gravity="center"
+ android:clipToPadding="false">
+ <!--This layout makes sure that we can nicely center the expand content in the
+ collapsed layout while the parent makes sure that we're never laid out bigger
+ than the messaging content.-->
+ <LinearLayout
+ android:id="@+id/expand_button_inner_container"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/conversation_expand_button_size"
+ android:paddingStart="16dp"
+ android:orientation="horizontal"
+ android:layout_gravity="end|top"
+ android:paddingEnd="@dimen/notification_content_margin_end"
android:clipToPadding="false"
android:clipChildren="false"
- />
- <!-- Unread Count -->
- <TextView
- android:id="@+id/conversation_unread_count"
- android:layout_width="33sp"
- android:layout_height="wrap_content"
- android:layout_marginEnd="11dp"
- android:layout_gravity="center"
- android:gravity="center"
- android:padding="2dp"
- android:visibility="gone"
- android:textAppearance="@style/TextAppearance.DeviceDefault.Notification"
- android:textColor="#FFFFFF"
- android:textSize="12sp"
- android:background="@drawable/conversation_unread_bg"
- />
- <com.android.internal.widget.NotificationExpandButton
- android:id="@+id/expand_button"
- android:layout_width="@dimen/notification_header_expand_icon_size"
- android:layout_height="@dimen/notification_header_expand_icon_size"
- android:layout_gravity="center"
- android:drawable="@drawable/ic_expand_notification"
- android:clickable="false"
- android:importantForAccessibility="no"
- />
- </LinearLayout>
+ >
+ <!-- Images -->
+ <com.android.internal.widget.MessagingLinearLayout
+ android:id="@+id/conversation_image_message_container"
+ android:forceHasOverlappingRendering="false"
+ android:layout_width="40dp"
+ android:layout_height="40dp"
+ android:layout_marginEnd="11dp"
+ android:spacing="0dp"
+ android:layout_gravity="center"
+ android:clipToPadding="false"
+ android:clipChildren="false"
+ />
+ <!-- Unread Count -->
+ <TextView
+ android:id="@+id/conversation_unread_count"
+ android:layout_width="33sp"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="11dp"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:padding="2dp"
+ android:visibility="gone"
+ android:textAppearance="@style/TextAppearance.DeviceDefault.Notification"
+ android:textColor="#FFFFFF"
+ android:textSize="12sp"
+ android:background="@drawable/conversation_unread_bg"
+ />
+ <com.android.internal.widget.NotificationExpandButton
+ android:id="@+id/expand_button"
+ android:layout_width="@dimen/notification_header_expand_icon_size"
+ android:layout_height="@dimen/notification_header_expand_icon_size"
+ android:layout_gravity="center"
+ android:drawable="@drawable/ic_expand_notification"
+ android:clickable="false"
+ android:importantForAccessibility="no"
+ />
+ </LinearLayout>
+ </FrameLayout>
</com.android.internal.widget.ConversationLayout>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 11dda41d0b57..ef1e8b74b05f 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3866,6 +3866,7 @@
<java-symbol type="id" name="conversation_icon_badge_ring" />
<java-symbol type="id" name="conversation_icon_badge_bg" />
<java-symbol type="id" name="expand_button_container" />
+ <java-symbol type="id" name="expand_button_inner_container" />
<java-symbol type="id" name="messaging_group_content_container" />
<java-symbol type="id" name="expand_button_and_content_container" />
<java-symbol type="id" name="conversation_header" />
diff --git a/core/xsd/vts/Android.bp b/core/xsd/vts/Android.bp
index a2a2168c8377..ca655f18149c 100644
--- a/core/xsd/vts/Android.bp
+++ b/core/xsd/vts/Android.bp
@@ -36,7 +36,7 @@ cc_test {
],
test_suites: [
"general-tests",
- "vts-core"
+ "vts"
],
test_config: "vts_permission_validate_test.xml",
}
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 155eb1cfbd46..c11762bcdb40 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -44,46 +44,56 @@ import java.util.Set;
/**
* @hide
*/
+@TestApi
public class AudioSystem
{
private static final boolean DEBUG_VOLUME = false;
private static final String TAG = "AudioSystem";
+
+ // private constructor to prevent instantiating AudioSystem
+ private AudioSystem() {
+ throw new UnsupportedOperationException("Trying to instantiate AudioSystem");
+ }
+
/* These values must be kept in sync with system/audio.h */
/*
* If these are modified, please also update Settings.System.VOLUME_SETTINGS
* and attrs.xml and AudioManager.java.
*/
- /** Used to identify the default audio stream volume */
+ /** @hide Used to identify the default audio stream volume */
+ @TestApi
public static final int STREAM_DEFAULT = -1;
- /** Used to identify the volume of audio streams for phone calls */
+ /** @hide Used to identify the volume of audio streams for phone calls */
public static final int STREAM_VOICE_CALL = 0;
- /** Used to identify the volume of audio streams for system sounds */
+ /** @hide Used to identify the volume of audio streams for system sounds */
public static final int STREAM_SYSTEM = 1;
- /** Used to identify the volume of audio streams for the phone ring and message alerts */
+ /** @hide Used to identify the volume of audio streams for the phone ring and message alerts */
public static final int STREAM_RING = 2;
- /** Used to identify the volume of audio streams for music playback */
+ /** @hide Used to identify the volume of audio streams for music playback */
public static final int STREAM_MUSIC = 3;
- /** Used to identify the volume of audio streams for alarms */
+ /** @hide Used to identify the volume of audio streams for alarms */
public static final int STREAM_ALARM = 4;
- /** Used to identify the volume of audio streams for notifications */
+ /** @hide Used to identify the volume of audio streams for notifications */
public static final int STREAM_NOTIFICATION = 5;
- /** Used to identify the volume of audio streams for phone calls when connected on bluetooth */
+ /** @hide
+ * Used to identify the volume of audio streams for phone calls when connected on bluetooth */
public static final int STREAM_BLUETOOTH_SCO = 6;
- /** Used to identify the volume of audio streams for enforced system sounds in certain
+ /** @hide Used to identify the volume of audio streams for enforced system sounds in certain
* countries (e.g camera in Japan) */
@UnsupportedAppUsage
public static final int STREAM_SYSTEM_ENFORCED = 7;
- /** Used to identify the volume of audio streams for DTMF tones */
+ /** @hide Used to identify the volume of audio streams for DTMF tones */
public static final int STREAM_DTMF = 8;
- /** Used to identify the volume of audio streams exclusively transmitted through the
+ /** @hide Used to identify the volume of audio streams exclusively transmitted through the
* speaker (TTS) of the device */
public static final int STREAM_TTS = 9;
- /** Used to identify the volume of audio streams for accessibility prompts */
+ /** @hide Used to identify the volume of audio streams for accessibility prompts */
public static final int STREAM_ACCESSIBILITY = 10;
- /** Used to identify the volume of audio streams for virtual assistant */
+ /** @hide Used to identify the volume of audio streams for virtual assistant */
public static final int STREAM_ASSISTANT = 11;
/**
+ * @hide
* @deprecated Use {@link #numStreamTypes() instead}
*/
public static final int NUM_STREAMS = 5;
@@ -96,9 +106,16 @@ public class AudioSystem
// Expose only the getter method publicly so we can change it in the future
private static final int NUM_STREAM_TYPES = 12;
+
+ /**
+ * @hide
+ * @return total number of stream types
+ */
@UnsupportedAppUsage
+ @TestApi
public static final int getNumStreamTypes() { return NUM_STREAM_TYPES; }
+ /** @hide */
public static final String[] STREAM_NAMES = new String[] {
"STREAM_VOICE_CALL",
"STREAM_SYSTEM",
@@ -114,7 +131,8 @@ public class AudioSystem
"STREAM_ASSISTANT"
};
- /*
+ /**
+ * @hide
* Sets the microphone mute on or off.
*
* @param on set <var>true</var> to mute the microphone;
@@ -124,7 +142,8 @@ public class AudioSystem
@UnsupportedAppUsage
public static native int muteMicrophone(boolean on);
- /*
+ /**
+ * @hide
* Checks whether the microphone mute is on or off.
*
* @return true if microphone is muted, false if it's not
@@ -133,15 +152,24 @@ public class AudioSystem
public static native boolean isMicrophoneMuted();
/* modes for setPhoneState, must match AudioSystem.h audio_mode */
+ /** @hide */
public static final int MODE_INVALID = -2;
+ /** @hide */
public static final int MODE_CURRENT = -1;
+ /** @hide */
public static final int MODE_NORMAL = 0;
+ /** @hide */
public static final int MODE_RINGTONE = 1;
+ /** @hide */
public static final int MODE_IN_CALL = 2;
+ /** @hide */
public static final int MODE_IN_COMMUNICATION = 3;
+ /** @hide */
public static final int MODE_CALL_SCREENING = 4;
+ /** @hide */
public static final int NUM_MODES = 5;
+ /** @hide */
public static String modeToString(int mode) {
switch (mode) {
case MODE_CURRENT: return "MODE_CURRENT";
@@ -156,15 +184,23 @@ public class AudioSystem
}
/* Formats for A2DP codecs, must match system/audio-base.h audio_format_t */
+ /** @hide */
public static final int AUDIO_FORMAT_INVALID = 0xFFFFFFFF;
+ /** @hide */
public static final int AUDIO_FORMAT_DEFAULT = 0;
+ /** @hide */
public static final int AUDIO_FORMAT_AAC = 0x04000000;
+ /** @hide */
public static final int AUDIO_FORMAT_SBC = 0x1F000000;
+ /** @hide */
public static final int AUDIO_FORMAT_APTX = 0x20000000;
+ /** @hide */
public static final int AUDIO_FORMAT_APTX_HD = 0x21000000;
+ /** @hide */
public static final int AUDIO_FORMAT_LDAC = 0x23000000;
/**
+ * @hide
* Convert audio format enum values to Bluetooth codec values
*/
public static int audioFormatToBluetoothSourceCodec(int audioFormat) {
@@ -179,25 +215,27 @@ public class AudioSystem
}
/* Routing bits for the former setRouting/getRouting API */
- /** @deprecated */
+ /** @hide @deprecated */
@Deprecated public static final int ROUTE_EARPIECE = (1 << 0);
- /** @deprecated */
+ /** @hide @deprecated */
@Deprecated public static final int ROUTE_SPEAKER = (1 << 1);
- /** @deprecated use {@link #ROUTE_BLUETOOTH_SCO} */
+ /** @hide @deprecated use {@link #ROUTE_BLUETOOTH_SCO} */
@Deprecated public static final int ROUTE_BLUETOOTH = (1 << 2);
- /** @deprecated */
+ /** @hide @deprecated */
@Deprecated public static final int ROUTE_BLUETOOTH_SCO = (1 << 2);
- /** @deprecated */
+ /** @hide @deprecated */
@Deprecated public static final int ROUTE_HEADSET = (1 << 3);
- /** @deprecated */
+ /** @hide @deprecated */
@Deprecated public static final int ROUTE_BLUETOOTH_A2DP = (1 << 4);
- /** @deprecated */
+ /** @hide @deprecated */
@Deprecated public static final int ROUTE_ALL = 0xFFFFFFFF;
// Keep in sync with system/media/audio/include/system/audio.h
+ /** @hide */
public static final int AUDIO_SESSION_ALLOCATE = 0;
- /*
+ /**
+ * @hide
* Checks whether the specified stream type is active.
*
* return true if any track playing on this stream is active.
@@ -205,7 +243,8 @@ public class AudioSystem
@UnsupportedAppUsage
public static native boolean isStreamActive(int stream, int inPastMs);
- /*
+ /**
+ * @hide
* Checks whether the specified stream type is active on a remotely connected device. The notion
* of what constitutes a remote device is enforced by the audio policy manager of the platform.
*
@@ -213,7 +252,8 @@ public class AudioSystem
*/
public static native boolean isStreamActiveRemotely(int stream, int inPastMs);
- /*
+ /**
+ * @hide
* Checks whether the specified audio source is active.
*
* return true if any recorder using this source is currently recording
@@ -221,23 +261,27 @@ public class AudioSystem
@UnsupportedAppUsage
public static native boolean isSourceActive(int source);
- /*
+ /**
+ * @hide
* Returns a new unused audio session ID
*/
public static native int newAudioSessionId();
- /*
+ /**
+ * @hide
* Returns a new unused audio player ID
*/
public static native int newAudioPlayerId();
/**
+ * @hide
* Returns a new unused audio recorder ID
*/
public static native int newAudioRecorderId();
- /*
+ /**
+ * @hide
* Sets a group generic audio configuration parameters. The use of these parameters
* are platform dependent, see libaudio
*
@@ -247,7 +291,8 @@ public class AudioSystem
@UnsupportedAppUsage
public static native int setParameters(String keyValuePairs);
- /*
+ /**
+ * @hide
* Gets a group generic audio configuration parameters. The use of these parameters
* are platform dependent, see libaudio
*
@@ -259,16 +304,16 @@ public class AudioSystem
public static native String getParameters(String keys);
// These match the enum AudioError in frameworks/base/core/jni/android_media_AudioSystem.cpp
- /* Command sucessful or Media server restarted. see ErrorCallback */
+ /** @hide Command successful or Media server restarted. see ErrorCallback */
public static final int AUDIO_STATUS_OK = 0;
- /* Command failed or unspecified audio error. see ErrorCallback */
+ /** @hide Command failed or unspecified audio error. see ErrorCallback */
public static final int AUDIO_STATUS_ERROR = 1;
- /* Media server died. see ErrorCallback */
+ /** @hide Media server died. see ErrorCallback */
public static final int AUDIO_STATUS_SERVER_DIED = 100;
- private static ErrorCallback mErrorCallback;
+ private static ErrorCallback sErrorCallback;
- /*
+ /** @hide
* Handles the audio error callback.
*/
public interface ErrorCallback
@@ -283,7 +328,8 @@ public class AudioSystem
void onError(int error);
};
- /*
+ /**
+ * @hide
* Registers a callback to be invoked when an error occurs.
* @param cb the callback to run
*/
@@ -291,7 +337,7 @@ public class AudioSystem
public static void setErrorCallback(ErrorCallback cb)
{
synchronized (AudioSystem.class) {
- mErrorCallback = cb;
+ sErrorCallback = cb;
if (cb != null) {
cb.onError(checkAudioFlinger());
}
@@ -303,8 +349,8 @@ public class AudioSystem
{
ErrorCallback errorCallback = null;
synchronized (AudioSystem.class) {
- if (mErrorCallback != null) {
- errorCallback = mErrorCallback;
+ if (sErrorCallback != null) {
+ errorCallback = sErrorCallback;
}
}
if (errorCallback != null) {
@@ -313,6 +359,7 @@ public class AudioSystem
}
/**
+ * @hide
* Handles events from the audio policy manager about dynamic audio policies
* @see android.media.audiopolicy.AudioPolicy
*/
@@ -326,6 +373,7 @@ public class AudioSystem
private static DynamicPolicyCallback sDynPolicyCallback;
+ /** @hide */
public static void setDynamicPolicyCallback(DynamicPolicyCallback cb)
{
synchronized (AudioSystem.class) {
@@ -355,6 +403,7 @@ public class AudioSystem
}
/**
+ * @hide
* Handles events from the audio policy manager about recording events
* @see android.media.AudioManager.AudioRecordingCallback
*/
@@ -386,6 +435,7 @@ public class AudioSystem
private static AudioRecordingCallback sRecordingCallback;
+ /** @hide */
public static void setRecordingCallback(AudioRecordingCallback cb) {
synchronized (AudioSystem.class) {
sRecordingCallback = cb;
@@ -434,13 +484,21 @@ public class AudioSystem
* Error codes used by public APIs (AudioTrack, AudioRecord, AudioManager ...)
* Must be kept in sync with frameworks/base/core/jni/android_media_AudioErrors.h
*/
+ /** @hide */
public static final int SUCCESS = 0;
+ /** @hide */
public static final int ERROR = -1;
+ /** @hide */
public static final int BAD_VALUE = -2;
+ /** @hide */
public static final int INVALID_OPERATION = -3;
+ /** @hide */
public static final int PERMISSION_DENIED = -4;
+ /** @hide */
public static final int NO_INIT = -5;
+ /** @hide */
public static final int DEAD_OBJECT = -6;
+ /** @hide */
public static final int WOULD_BLOCK = -7;
/** @hide */
@@ -458,6 +516,7 @@ public class AudioSystem
public @interface AudioSystemError {}
/**
+ * @hide
* Convert an int error value to its String value for readability.
* Accepted error values are the java AudioSystem errors, matching android_media_AudioErrors.h,
* which map onto the native status_t type.
@@ -494,74 +553,113 @@ public class AudioSystem
//
// audio device definitions: must be kept in sync with values in system/core/audio.h
//
-
+ /** @hide */
public static final int DEVICE_NONE = 0x0;
// reserved bits
+ /** @hide */
public static final int DEVICE_BIT_IN = 0x80000000;
+ /** @hide */
public static final int DEVICE_BIT_DEFAULT = 0x40000000;
// output devices, be sure to update AudioManager.java also
+ /** @hide */
@UnsupportedAppUsage
public static final int DEVICE_OUT_EARPIECE = 0x1;
+ /** @hide */
@UnsupportedAppUsage
public static final int DEVICE_OUT_SPEAKER = 0x2;
+ /** @hide */
@UnsupportedAppUsage
public static final int DEVICE_OUT_WIRED_HEADSET = 0x4;
+ /** @hide */
@UnsupportedAppUsage
public static final int DEVICE_OUT_WIRED_HEADPHONE = 0x8;
+ /** @hide */
@UnsupportedAppUsage
public static final int DEVICE_OUT_BLUETOOTH_SCO = 0x10;
+ /** @hide */
@UnsupportedAppUsage
public static final int DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20;
+ /** @hide */
@UnsupportedAppUsage
public static final int DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 0x40;
+ /** @hide */
@UnsupportedAppUsage
public static final int DEVICE_OUT_BLUETOOTH_A2DP = 0x80;
+ /** @hide */
@UnsupportedAppUsage
public static final int DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100;
+ /** @hide */
@UnsupportedAppUsage
public static final int DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200;
+ /** @hide */
@UnsupportedAppUsage
public static final int DEVICE_OUT_AUX_DIGITAL = 0x400;
+ /** @hide */
public static final int DEVICE_OUT_HDMI = DEVICE_OUT_AUX_DIGITAL;
+ /** @hide */
@UnsupportedAppUsage
public static final int DEVICE_OUT_ANLG_DOCK_HEADSET = 0x800;
+ /** @hide */
@UnsupportedAppUsage
public static final int DEVICE_OUT_DGTL_DOCK_HEADSET = 0x1000;
+ /** @hide */
@UnsupportedAppUsage
public static final int DEVICE_OUT_USB_ACCESSORY = 0x2000;
+ /** @hide */
@UnsupportedAppUsage
public static final int DEVICE_OUT_USB_DEVICE = 0x4000;
+ /** @hide */
@UnsupportedAppUsage
public static final int DEVICE_OUT_REMOTE_SUBMIX = 0x8000;
+ /** @hide */
@UnsupportedAppUsage
public static final int DEVICE_OUT_TELEPHONY_TX = 0x10000;
+ /** @hide */
public static final int DEVICE_OUT_LINE = 0x20000;
+ /** @hide */
public static final int DEVICE_OUT_HDMI_ARC = 0x40000;
+ /** @hide */
public static final int DEVICE_OUT_SPDIF = 0x80000;
+ /** @hide */
@UnsupportedAppUsage
public static final int DEVICE_OUT_FM = 0x100000;
+ /** @hide */
public static final int DEVICE_OUT_AUX_LINE = 0x200000;
+ /** @hide */
public static final int DEVICE_OUT_SPEAKER_SAFE = 0x400000;
+ /** @hide */
public static final int DEVICE_OUT_IP = 0x800000;
+ /** @hide */
public static final int DEVICE_OUT_BUS = 0x1000000;
+ /** @hide */
public static final int DEVICE_OUT_PROXY = 0x2000000;
+ /** @hide */
public static final int DEVICE_OUT_USB_HEADSET = 0x4000000;
+ /** @hide */
public static final int DEVICE_OUT_HEARING_AID = 0x8000000;
+ /** @hide */
public static final int DEVICE_OUT_DEFAULT = DEVICE_BIT_DEFAULT;
// Deprecated in R because multiple device types are no longer accessed as a bit mask.
// Removing this will get lint warning about changing hidden apis.
+ /** @hide */
@UnsupportedAppUsage
public static final int DEVICE_OUT_ALL_USB = (DEVICE_OUT_USB_ACCESSORY |
DEVICE_OUT_USB_DEVICE |
DEVICE_OUT_USB_HEADSET);
+ /** @hide */
public static final Set<Integer> DEVICE_OUT_ALL_SET;
+ /** @hide */
public static final Set<Integer> DEVICE_OUT_ALL_A2DP_SET;
+ /** @hide */
public static final Set<Integer> DEVICE_OUT_ALL_SCO_SET;
+ /** @hide */
public static final Set<Integer> DEVICE_OUT_ALL_USB_SET;
+ /** @hide */
public static final Set<Integer> DEVICE_OUT_ALL_HDMI_SYSTEM_AUDIO_SET;
+ /** @hide */
public static final Set<Integer> DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER_SET;
static {
DEVICE_OUT_ALL_SET = new HashSet<>();
@@ -621,53 +719,85 @@ public class AudioSystem
}
// input devices
+ /** @hide */
@UnsupportedAppUsage
public static final int DEVICE_IN_COMMUNICATION = DEVICE_BIT_IN | 0x1;
+ /** @hide */
@UnsupportedAppUsage
public static final int DEVICE_IN_AMBIENT = DEVICE_BIT_IN | 0x2;
+ /** @hide */
@UnsupportedAppUsage
public static final int DEVICE_IN_BUILTIN_MIC = DEVICE_BIT_IN | 0x4;
+ /** @hide */
@UnsupportedAppUsage
public static final int DEVICE_IN_BLUETOOTH_SCO_HEADSET = DEVICE_BIT_IN | 0x8;
+ /** @hide */
@UnsupportedAppUsage
public static final int DEVICE_IN_WIRED_HEADSET = DEVICE_BIT_IN | 0x10;
+ /** @hide */
@UnsupportedAppUsage
public static final int DEVICE_IN_AUX_DIGITAL = DEVICE_BIT_IN | 0x20;
+ /** @hide */
public static final int DEVICE_IN_HDMI = DEVICE_IN_AUX_DIGITAL;
+ /** @hide */
@UnsupportedAppUsage
public static final int DEVICE_IN_VOICE_CALL = DEVICE_BIT_IN | 0x40;
+ /** @hide */
public static final int DEVICE_IN_TELEPHONY_RX = DEVICE_IN_VOICE_CALL;
+ /** @hide */
@UnsupportedAppUsage
public static final int DEVICE_IN_BACK_MIC = DEVICE_BIT_IN | 0x80;
+ /** @hide */
@UnsupportedAppUsage
public static final int DEVICE_IN_REMOTE_SUBMIX = DEVICE_BIT_IN | 0x100;
+ /** @hide */
@UnsupportedAppUsage
public static final int DEVICE_IN_ANLG_DOCK_HEADSET = DEVICE_BIT_IN | 0x200;
+ /** @hide */
@UnsupportedAppUsage
public static final int DEVICE_IN_DGTL_DOCK_HEADSET = DEVICE_BIT_IN | 0x400;
+ /** @hide */
@UnsupportedAppUsage
public static final int DEVICE_IN_USB_ACCESSORY = DEVICE_BIT_IN | 0x800;
+ /** @hide */
@UnsupportedAppUsage
public static final int DEVICE_IN_USB_DEVICE = DEVICE_BIT_IN | 0x1000;
+ /** @hide */
public static final int DEVICE_IN_FM_TUNER = DEVICE_BIT_IN | 0x2000;
+ /** @hide */
public static final int DEVICE_IN_TV_TUNER = DEVICE_BIT_IN | 0x4000;
+ /** @hide */
public static final int DEVICE_IN_LINE = DEVICE_BIT_IN | 0x8000;
+ /** @hide */
public static final int DEVICE_IN_SPDIF = DEVICE_BIT_IN | 0x10000;
+ /** @hide */
@UnsupportedAppUsage
public static final int DEVICE_IN_BLUETOOTH_A2DP = DEVICE_BIT_IN | 0x20000;
+ /** @hide */
public static final int DEVICE_IN_LOOPBACK = DEVICE_BIT_IN | 0x40000;
+ /** @hide */
public static final int DEVICE_IN_IP = DEVICE_BIT_IN | 0x80000;
+ /** @hide */
public static final int DEVICE_IN_BUS = DEVICE_BIT_IN | 0x100000;
+ /** @hide */
public static final int DEVICE_IN_PROXY = DEVICE_BIT_IN | 0x1000000;
+ /** @hide */
public static final int DEVICE_IN_USB_HEADSET = DEVICE_BIT_IN | 0x2000000;
+ /** @hide */
public static final int DEVICE_IN_BLUETOOTH_BLE = DEVICE_BIT_IN | 0x4000000;
+ /** @hide */
public static final int DEVICE_IN_HDMI_ARC = DEVICE_BIT_IN | 0x8000000;
+ /** @hide */
public static final int DEVICE_IN_ECHO_REFERENCE = DEVICE_BIT_IN | 0x10000000;
+ /** @hide */
@UnsupportedAppUsage
public static final int DEVICE_IN_DEFAULT = DEVICE_BIT_IN | DEVICE_BIT_DEFAULT;
+ /** @hide */
public static final Set<Integer> DEVICE_IN_ALL_SET;
+ /** @hide */
public static final Set<Integer> DEVICE_IN_ALL_SCO_SET;
+ /** @hide */
public static final Set<Integer> DEVICE_IN_ALL_USB_SET;
static {
DEVICE_IN_ALL_SET = new HashSet<>();
@@ -708,15 +838,19 @@ public class AudioSystem
DEVICE_IN_ALL_USB_SET.add(DEVICE_IN_USB_HEADSET);
}
+ /** @hide */
public static final String LEGACY_REMOTE_SUBMIX_ADDRESS = "0";
// device states, must match AudioSystem::device_connection_state
+ /** @hide */
@UnsupportedAppUsage
public static final int DEVICE_STATE_UNAVAILABLE = 0;
+ /** @hide */
@UnsupportedAppUsage
public static final int DEVICE_STATE_AVAILABLE = 1;
private static final int NUM_DEVICE_STATES = 1;
+ /** @hide */
public static String deviceStateToString(int state) {
switch (state) {
case DEVICE_STATE_UNAVAILABLE: return "DEVICE_STATE_UNAVAILABLE";
@@ -725,63 +859,65 @@ public class AudioSystem
}
}
- public static final String DEVICE_OUT_EARPIECE_NAME = "earpiece";
- public static final String DEVICE_OUT_SPEAKER_NAME = "speaker";
- public static final String DEVICE_OUT_WIRED_HEADSET_NAME = "headset";
- public static final String DEVICE_OUT_WIRED_HEADPHONE_NAME = "headphone";
- public static final String DEVICE_OUT_BLUETOOTH_SCO_NAME = "bt_sco";
- public static final String DEVICE_OUT_BLUETOOTH_SCO_HEADSET_NAME = "bt_sco_hs";
- public static final String DEVICE_OUT_BLUETOOTH_SCO_CARKIT_NAME = "bt_sco_carkit";
- public static final String DEVICE_OUT_BLUETOOTH_A2DP_NAME = "bt_a2dp";
+ /** @hide */ public static final String DEVICE_OUT_EARPIECE_NAME = "earpiece";
+ /** @hide */ public static final String DEVICE_OUT_SPEAKER_NAME = "speaker";
+ /** @hide */ public static final String DEVICE_OUT_WIRED_HEADSET_NAME = "headset";
+ /** @hide */ public static final String DEVICE_OUT_WIRED_HEADPHONE_NAME = "headphone";
+ /** @hide */ public static final String DEVICE_OUT_BLUETOOTH_SCO_NAME = "bt_sco";
+ /** @hide */ public static final String DEVICE_OUT_BLUETOOTH_SCO_HEADSET_NAME = "bt_sco_hs";
+ /** @hide */ public static final String DEVICE_OUT_BLUETOOTH_SCO_CARKIT_NAME = "bt_sco_carkit";
+ /** @hide */ public static final String DEVICE_OUT_BLUETOOTH_A2DP_NAME = "bt_a2dp";
+ /** @hide */
public static final String DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES_NAME = "bt_a2dp_hp";
- public static final String DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER_NAME = "bt_a2dp_spk";
- public static final String DEVICE_OUT_AUX_DIGITAL_NAME = "aux_digital";
- public static final String DEVICE_OUT_HDMI_NAME = "hdmi";
- public static final String DEVICE_OUT_ANLG_DOCK_HEADSET_NAME = "analog_dock";
- public static final String DEVICE_OUT_DGTL_DOCK_HEADSET_NAME = "digital_dock";
- public static final String DEVICE_OUT_USB_ACCESSORY_NAME = "usb_accessory";
- public static final String DEVICE_OUT_USB_DEVICE_NAME = "usb_device";
- public static final String DEVICE_OUT_REMOTE_SUBMIX_NAME = "remote_submix";
- public static final String DEVICE_OUT_TELEPHONY_TX_NAME = "telephony_tx";
- public static final String DEVICE_OUT_LINE_NAME = "line";
- public static final String DEVICE_OUT_HDMI_ARC_NAME = "hmdi_arc";
- public static final String DEVICE_OUT_SPDIF_NAME = "spdif";
- public static final String DEVICE_OUT_FM_NAME = "fm_transmitter";
- public static final String DEVICE_OUT_AUX_LINE_NAME = "aux_line";
- public static final String DEVICE_OUT_SPEAKER_SAFE_NAME = "speaker_safe";
- public static final String DEVICE_OUT_IP_NAME = "ip";
- public static final String DEVICE_OUT_BUS_NAME = "bus";
- public static final String DEVICE_OUT_PROXY_NAME = "proxy";
- public static final String DEVICE_OUT_USB_HEADSET_NAME = "usb_headset";
- public static final String DEVICE_OUT_HEARING_AID_NAME = "hearing_aid_out";
-
- public static final String DEVICE_IN_COMMUNICATION_NAME = "communication";
- public static final String DEVICE_IN_AMBIENT_NAME = "ambient";
- public static final String DEVICE_IN_BUILTIN_MIC_NAME = "mic";
- public static final String DEVICE_IN_BLUETOOTH_SCO_HEADSET_NAME = "bt_sco_hs";
- public static final String DEVICE_IN_WIRED_HEADSET_NAME = "headset";
- public static final String DEVICE_IN_AUX_DIGITAL_NAME = "aux_digital";
- public static final String DEVICE_IN_TELEPHONY_RX_NAME = "telephony_rx";
- public static final String DEVICE_IN_BACK_MIC_NAME = "back_mic";
- public static final String DEVICE_IN_REMOTE_SUBMIX_NAME = "remote_submix";
- public static final String DEVICE_IN_ANLG_DOCK_HEADSET_NAME = "analog_dock";
- public static final String DEVICE_IN_DGTL_DOCK_HEADSET_NAME = "digital_dock";
- public static final String DEVICE_IN_USB_ACCESSORY_NAME = "usb_accessory";
- public static final String DEVICE_IN_USB_DEVICE_NAME = "usb_device";
- public static final String DEVICE_IN_FM_TUNER_NAME = "fm_tuner";
- public static final String DEVICE_IN_TV_TUNER_NAME = "tv_tuner";
- public static final String DEVICE_IN_LINE_NAME = "line";
- public static final String DEVICE_IN_SPDIF_NAME = "spdif";
- public static final String DEVICE_IN_BLUETOOTH_A2DP_NAME = "bt_a2dp";
- public static final String DEVICE_IN_LOOPBACK_NAME = "loopback";
- public static final String DEVICE_IN_IP_NAME = "ip";
- public static final String DEVICE_IN_BUS_NAME = "bus";
- public static final String DEVICE_IN_PROXY_NAME = "proxy";
- public static final String DEVICE_IN_USB_HEADSET_NAME = "usb_headset";
- public static final String DEVICE_IN_BLUETOOTH_BLE_NAME = "bt_ble";
- public static final String DEVICE_IN_ECHO_REFERENCE_NAME = "echo_reference";
- public static final String DEVICE_IN_HDMI_ARC_NAME = "hdmi_arc";
+ /** @hide */ public static final String DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER_NAME = "bt_a2dp_spk";
+ /** @hide */ public static final String DEVICE_OUT_AUX_DIGITAL_NAME = "aux_digital";
+ /** @hide */ public static final String DEVICE_OUT_HDMI_NAME = "hdmi";
+ /** @hide */ public static final String DEVICE_OUT_ANLG_DOCK_HEADSET_NAME = "analog_dock";
+ /** @hide */ public static final String DEVICE_OUT_DGTL_DOCK_HEADSET_NAME = "digital_dock";
+ /** @hide */ public static final String DEVICE_OUT_USB_ACCESSORY_NAME = "usb_accessory";
+ /** @hide */ public static final String DEVICE_OUT_USB_DEVICE_NAME = "usb_device";
+ /** @hide */ public static final String DEVICE_OUT_REMOTE_SUBMIX_NAME = "remote_submix";
+ /** @hide */ public static final String DEVICE_OUT_TELEPHONY_TX_NAME = "telephony_tx";
+ /** @hide */ public static final String DEVICE_OUT_LINE_NAME = "line";
+ /** @hide */ public static final String DEVICE_OUT_HDMI_ARC_NAME = "hmdi_arc";
+ /** @hide */ public static final String DEVICE_OUT_SPDIF_NAME = "spdif";
+ /** @hide */ public static final String DEVICE_OUT_FM_NAME = "fm_transmitter";
+ /** @hide */ public static final String DEVICE_OUT_AUX_LINE_NAME = "aux_line";
+ /** @hide */ public static final String DEVICE_OUT_SPEAKER_SAFE_NAME = "speaker_safe";
+ /** @hide */ public static final String DEVICE_OUT_IP_NAME = "ip";
+ /** @hide */ public static final String DEVICE_OUT_BUS_NAME = "bus";
+ /** @hide */ public static final String DEVICE_OUT_PROXY_NAME = "proxy";
+ /** @hide */ public static final String DEVICE_OUT_USB_HEADSET_NAME = "usb_headset";
+ /** @hide */ public static final String DEVICE_OUT_HEARING_AID_NAME = "hearing_aid_out";
+
+ /** @hide */ public static final String DEVICE_IN_COMMUNICATION_NAME = "communication";
+ /** @hide */ public static final String DEVICE_IN_AMBIENT_NAME = "ambient";
+ /** @hide */ public static final String DEVICE_IN_BUILTIN_MIC_NAME = "mic";
+ /** @hide */ public static final String DEVICE_IN_BLUETOOTH_SCO_HEADSET_NAME = "bt_sco_hs";
+ /** @hide */ public static final String DEVICE_IN_WIRED_HEADSET_NAME = "headset";
+ /** @hide */ public static final String DEVICE_IN_AUX_DIGITAL_NAME = "aux_digital";
+ /** @hide */ public static final String DEVICE_IN_TELEPHONY_RX_NAME = "telephony_rx";
+ /** @hide */ public static final String DEVICE_IN_BACK_MIC_NAME = "back_mic";
+ /** @hide */ public static final String DEVICE_IN_REMOTE_SUBMIX_NAME = "remote_submix";
+ /** @hide */ public static final String DEVICE_IN_ANLG_DOCK_HEADSET_NAME = "analog_dock";
+ /** @hide */ public static final String DEVICE_IN_DGTL_DOCK_HEADSET_NAME = "digital_dock";
+ /** @hide */ public static final String DEVICE_IN_USB_ACCESSORY_NAME = "usb_accessory";
+ /** @hide */ public static final String DEVICE_IN_USB_DEVICE_NAME = "usb_device";
+ /** @hide */ public static final String DEVICE_IN_FM_TUNER_NAME = "fm_tuner";
+ /** @hide */ public static final String DEVICE_IN_TV_TUNER_NAME = "tv_tuner";
+ /** @hide */ public static final String DEVICE_IN_LINE_NAME = "line";
+ /** @hide */ public static final String DEVICE_IN_SPDIF_NAME = "spdif";
+ /** @hide */ public static final String DEVICE_IN_BLUETOOTH_A2DP_NAME = "bt_a2dp";
+ /** @hide */ public static final String DEVICE_IN_LOOPBACK_NAME = "loopback";
+ /** @hide */ public static final String DEVICE_IN_IP_NAME = "ip";
+ /** @hide */ public static final String DEVICE_IN_BUS_NAME = "bus";
+ /** @hide */ public static final String DEVICE_IN_PROXY_NAME = "proxy";
+ /** @hide */ public static final String DEVICE_IN_USB_HEADSET_NAME = "usb_headset";
+ /** @hide */ public static final String DEVICE_IN_BLUETOOTH_BLE_NAME = "bt_ble";
+ /** @hide */ public static final String DEVICE_IN_ECHO_REFERENCE_NAME = "echo_reference";
+ /** @hide */ public static final String DEVICE_IN_HDMI_ARC_NAME = "hdmi_arc";
+ /** @hide */
@UnsupportedAppUsage
public static String getOutputDeviceName(int device)
{
@@ -848,6 +984,7 @@ public class AudioSystem
}
}
+ /** @hide */
public static String getInputDeviceName(int device)
{
switch(device) {
@@ -910,6 +1047,7 @@ public class AudioSystem
}
/**
+ * @hide
* Returns a human readable name for a given device type
* @param device a native device type, NOT an AudioDeviceInfo type
* @return a string describing the device type
@@ -922,35 +1060,31 @@ public class AudioSystem
}
// phone state, match audio_mode???
- public static final int PHONE_STATE_OFFCALL = 0;
- public static final int PHONE_STATE_RINGING = 1;
- public static final int PHONE_STATE_INCALL = 2;
+ /** @hide */ public static final int PHONE_STATE_OFFCALL = 0;
+ /** @hide */ public static final int PHONE_STATE_RINGING = 1;
+ /** @hide */ public static final int PHONE_STATE_INCALL = 2;
// device categories config for setForceUse, must match audio_policy_forced_cfg_t
- @UnsupportedAppUsage
- public static final int FORCE_NONE = 0;
- public static final int FORCE_SPEAKER = 1;
- public static final int FORCE_HEADPHONES = 2;
- public static final int FORCE_BT_SCO = 3;
- public static final int FORCE_BT_A2DP = 4;
- public static final int FORCE_WIRED_ACCESSORY = 5;
- @UnsupportedAppUsage
- public static final int FORCE_BT_CAR_DOCK = 6;
- @UnsupportedAppUsage
- public static final int FORCE_BT_DESK_DOCK = 7;
- @UnsupportedAppUsage
- public static final int FORCE_ANALOG_DOCK = 8;
- @UnsupportedAppUsage
- public static final int FORCE_DIGITAL_DOCK = 9;
- public static final int FORCE_NO_BT_A2DP = 10;
- public static final int FORCE_SYSTEM_ENFORCED = 11;
- public static final int FORCE_HDMI_SYSTEM_AUDIO_ENFORCED = 12;
- public static final int FORCE_ENCODED_SURROUND_NEVER = 13;
- public static final int FORCE_ENCODED_SURROUND_ALWAYS = 14;
- public static final int FORCE_ENCODED_SURROUND_MANUAL = 15;
- public static final int NUM_FORCE_CONFIG = 16;
- public static final int FORCE_DEFAULT = FORCE_NONE;
+ /** @hide */ @UnsupportedAppUsage public static final int FORCE_NONE = 0;
+ /** @hide */ public static final int FORCE_SPEAKER = 1;
+ /** @hide */ public static final int FORCE_HEADPHONES = 2;
+ /** @hide */ public static final int FORCE_BT_SCO = 3;
+ /** @hide */ public static final int FORCE_BT_A2DP = 4;
+ /** @hide */ public static final int FORCE_WIRED_ACCESSORY = 5;
+ /** @hide */ @UnsupportedAppUsage public static final int FORCE_BT_CAR_DOCK = 6;
+ /** @hide */ @UnsupportedAppUsage public static final int FORCE_BT_DESK_DOCK = 7;
+ /** @hide */ @UnsupportedAppUsage public static final int FORCE_ANALOG_DOCK = 8;
+ /** @hide */ @UnsupportedAppUsage public static final int FORCE_DIGITAL_DOCK = 9;
+ /** @hide */ public static final int FORCE_NO_BT_A2DP = 10;
+ /** @hide */ public static final int FORCE_SYSTEM_ENFORCED = 11;
+ /** @hide */ public static final int FORCE_HDMI_SYSTEM_AUDIO_ENFORCED = 12;
+ /** @hide */ public static final int FORCE_ENCODED_SURROUND_NEVER = 13;
+ /** @hide */ public static final int FORCE_ENCODED_SURROUND_ALWAYS = 14;
+ /** @hide */ public static final int FORCE_ENCODED_SURROUND_MANUAL = 15;
+ /** @hide */ public static final int NUM_FORCE_CONFIG = 16;
+ /** @hide */ public static final int FORCE_DEFAULT = FORCE_NONE;
+ /** @hide */
public static String forceUseConfigToString(int config) {
switch (config) {
case FORCE_NONE: return "FORCE_NONE";
@@ -974,16 +1108,17 @@ public class AudioSystem
}
// usage for setForceUse, must match audio_policy_force_use_t
- public static final int FOR_COMMUNICATION = 0;
- public static final int FOR_MEDIA = 1;
- public static final int FOR_RECORD = 2;
- public static final int FOR_DOCK = 3;
- public static final int FOR_SYSTEM = 4;
- public static final int FOR_HDMI_SYSTEM_AUDIO = 5;
- public static final int FOR_ENCODED_SURROUND = 6;
- public static final int FOR_VIBRATE_RINGING = 7;
+ /** @hide */ public static final int FOR_COMMUNICATION = 0;
+ /** @hide */ public static final int FOR_MEDIA = 1;
+ /** @hide */ public static final int FOR_RECORD = 2;
+ /** @hide */ public static final int FOR_DOCK = 3;
+ /** @hide */ public static final int FOR_SYSTEM = 4;
+ /** @hide */ public static final int FOR_HDMI_SYSTEM_AUDIO = 5;
+ /** @hide */ public static final int FOR_ENCODED_SURROUND = 6;
+ /** @hide */ public static final int FOR_VIBRATE_RINGING = 7;
private static final int NUM_FORCE_USE = 8;
+ /** @hide */
public static String forceUseUsageToString(int usage) {
switch (usage) {
case FOR_COMMUNICATION: return "FOR_COMMUNICATION";
@@ -998,7 +1133,7 @@ public class AudioSystem
}
}
- /** Wrapper for native methods called from AudioService */
+ /** @hide Wrapper for native methods called from AudioService */
public static int setStreamVolumeIndexAS(int stream, int index, int device) {
if (DEBUG_VOLUME) {
Log.i(TAG, "setStreamVolumeIndex: " + STREAM_NAMES[stream]
@@ -1008,10 +1143,11 @@ public class AudioSystem
}
// usage for AudioRecord.startRecordingSync(), must match AudioSystem::sync_event_t
- public static final int SYNC_EVENT_NONE = 0;
- public static final int SYNC_EVENT_PRESENTATION_COMPLETE = 1;
+ /** @hide */ public static final int SYNC_EVENT_NONE = 0;
+ /** @hide */ public static final int SYNC_EVENT_PRESENTATION_COMPLETE = 1;
/**
+ * @hide
* @return command completion status, one of {@link #AUDIO_STATUS_OK},
* {@link #AUDIO_STATUS_ERROR} or {@link #AUDIO_STATUS_SERVER_DIED}
*/
@@ -1019,12 +1155,15 @@ public class AudioSystem
public static native int setDeviceConnectionState(int device, int state,
String device_address, String device_name,
int codecFormat);
+ /** @hide */
@UnsupportedAppUsage
public static native int getDeviceConnectionState(int device, String device_address);
+ /** @hide */
public static native int handleDeviceConfigChange(int device,
String device_address,
String device_name,
int codecFormat);
+ /** @hide */
@UnsupportedAppUsage
public static int setPhoneState(int state) {
Log.w(TAG, "Do not use this method! Use AudioManager.setMode() instead.");
@@ -1038,14 +1177,18 @@ public class AudioSystem
* @return command completion status.
*/
public static native int setPhoneState(int state, int uid);
+ /** @hide */
@UnsupportedAppUsage
public static native int setForceUse(int usage, int config);
+ /** @hide */
@UnsupportedAppUsage
public static native int getForceUse(int usage);
+ /** @hide */
@UnsupportedAppUsage
public static native int initStreamVolume(int stream, int indexMin, int indexMax);
@UnsupportedAppUsage
private static native int setStreamVolumeIndex(int stream, int index, int device);
+ /** @hide */
public static native int getStreamVolumeIndex(int stream, int device);
/**
* @hide
@@ -1082,16 +1225,22 @@ public class AudioSystem
*/
public static native int getMaxVolumeIndexForAttributes(@NonNull AudioAttributes attributes);
+ /** @hide */
public static native int setMasterVolume(float value);
+ /** @hide */
public static native float getMasterVolume();
+ /** @hide */
@UnsupportedAppUsage
public static native int setMasterMute(boolean mute);
+ /** @hide */
@UnsupportedAppUsage
public static native boolean getMasterMute();
+ /** @hide */
@UnsupportedAppUsage
public static native int getDevicesForStream(int stream);
/**
+ * @hide
* Do not use directly, see {@link AudioManager#getDevicesForAttributes(AudioAttributes)}
* Get the audio devices that would be used for the routing of the given audio attributes.
* @param attributes the {@link AudioAttributes} for which the routing is being queried
@@ -1136,31 +1285,43 @@ public class AudioSystem
/** @hide returns master balance value in range -1.f -> 1.f, where 0.f is dead center. */
@TestApi
public static native float getMasterBalance();
- /** @hide changes the audio balance of the device. */
+ /** @hide Changes the audio balance of the device. */
@TestApi
public static native int setMasterBalance(float balance);
// helpers for android.media.AudioManager.getProperty(), see description there for meaning
+ /** @hide */
@UnsupportedAppUsage(trackingBug = 134049522)
public static native int getPrimaryOutputSamplingRate();
+ /** @hide */
@UnsupportedAppUsage(trackingBug = 134049522)
public static native int getPrimaryOutputFrameCount();
+ /** @hide */
@UnsupportedAppUsage
public static native int getOutputLatency(int stream);
+ /** @hide */
public static native int setLowRamDevice(boolean isLowRamDevice, long totalMemory);
+ /** @hide */
@UnsupportedAppUsage
public static native int checkAudioFlinger();
+ /** @hide */
public static native int listAudioPorts(ArrayList<AudioPort> ports, int[] generation);
+ /** @hide */
public static native int createAudioPatch(AudioPatch[] patch,
AudioPortConfig[] sources, AudioPortConfig[] sinks);
+ /** @hide */
public static native int releaseAudioPatch(AudioPatch patch);
+ /** @hide */
public static native int listAudioPatches(ArrayList<AudioPatch> patches, int[] generation);
+ /** @hide */
public static native int setAudioPortConfig(AudioPortConfig config);
+ /** @hide */
public static native int startAudioSource(AudioPortConfig config,
AudioAttributes audioAttributes);
+ /** @hide */
public static native int stopAudioSource(int handle);
// declare this instance as having a dynamic policy callback handler
@@ -1169,36 +1330,42 @@ public class AudioSystem
private static native final void native_register_recording_callback();
// must be kept in sync with value in include/system/audio.h
- public static final int AUDIO_HW_SYNC_INVALID = 0;
+ /** @hide */ public static final int AUDIO_HW_SYNC_INVALID = 0;
+ /** @hide */
public static native int getAudioHwSyncForSession(int sessionId);
+ /** @hide */
public static native int registerPolicyMixes(ArrayList<AudioMix> mixes, boolean register);
- /** see AudioPolicy.setUidDeviceAffinities() */
+ /** @hide see AudioPolicy.setUidDeviceAffinities() */
public static native int setUidDeviceAffinities(int uid, @NonNull int[] types,
@NonNull String[] addresses);
- /** see AudioPolicy.removeUidDeviceAffinities() */
+ /** @hide see AudioPolicy.removeUidDeviceAffinities() */
public static native int removeUidDeviceAffinities(int uid);
- /** see AudioPolicy.setUserIdDeviceAffinities() */
+ /** @hide see AudioPolicy.setUserIdDeviceAffinities() */
public static native int setUserIdDeviceAffinities(int userId, @NonNull int[] types,
@NonNull String[] addresses);
- /** see AudioPolicy.removeUserIdDeviceAffinities() */
+ /** @hide see AudioPolicy.removeUserIdDeviceAffinities() */
public static native int removeUserIdDeviceAffinities(int userId);
+ /** @hide */
public static native int systemReady();
+ /** @hide */
public static native float getStreamVolumeDB(int stream, int index, int device);
/**
+ * @hide
* Communicate supported system usages to audio policy service.
*/
public static native int setSupportedSystemUsages(int[] systemUsages);
/**
+ * @hide
* @see AudioManager#setAllowedCapturePolicy()
*/
public static native int setAllowedCapturePolicy(int uid, int flags);
@@ -1212,45 +1379,57 @@ public class AudioSystem
private static native boolean native_is_offload_supported(int encoding, int sampleRate,
int channelMask, int channelIndexMask, int streamType);
+ /** @hide */
public static native int getMicrophones(ArrayList<MicrophoneInfo> microphonesInfo);
+ /** @hide */
public static native int getSurroundFormats(Map<Integer, Boolean> surroundFormats,
boolean reported);
/**
+ * @hide
* Returns a list of audio formats (codec) supported on the A2DP offload path.
*/
public static native int getHwOffloadEncodingFormatsSupportedForA2DP(
ArrayList<Integer> formatList);
+ /** @hide */
public static native int setSurroundFormatEnabled(int audioFormat, boolean enabled);
/**
+ * @hide
* Communicate UID of active assistant to audio policy service.
*/
public static native int setAssistantUid(int uid);
+
/**
+ * @hide
* Communicate UIDs of active accessibility services to audio policy service.
*/
public static native int setA11yServicesUids(int[] uids);
+
/**
+ * @hide
* Communicate UID of current InputMethodService to audio policy service.
*/
public static native int setCurrentImeUid(int uid);
/**
+ * @hide
* @see AudioManager#isHapticPlaybackSupported()
*/
public static native boolean isHapticPlaybackSupported();
/**
+ * @hide
* Send audio HAL server process pids to native audioserver process for use
* when generating audio HAL servers tombstones
*/
public static native int setAudioHalPids(int[] pids);
/**
+ * @hide
* @see AudioManager#isCallScreeningModeSupported()
*/
public static native boolean isCallScreeningModeSupported();
@@ -1258,6 +1437,7 @@ public class AudioSystem
// use case routing by product strategy
/**
+ * @hide
* Sets the preferred device to use for a given audio strategy in the audio policy engine
* @param strategy the id of the strategy to configure
* @param device the device type and address to route to when available
@@ -1270,6 +1450,7 @@ public class AudioSystem
device.getAddress());
}
/**
+ * @hide
* Set device routing per product strategy.
* @param strategy the id of the strategy to configure
* @param deviceType the native device type, NOT AudioDeviceInfo types
@@ -1280,6 +1461,7 @@ public class AudioSystem
int strategy, int deviceType, String deviceAddress);
/**
+ * @hide
* Remove preferred routing for the strategy
* @param strategy the id of the strategy to configure
* @return {@link #SUCCESS} if successfully removed
@@ -1287,6 +1469,7 @@ public class AudioSystem
public static native int removePreferredDeviceForStrategy(int strategy);
/**
+ * @hide
* Query previously set preferred device for a strategy
* @param strategy the id of the strategy to query for
* @param device an array of size 1 that will contain the preferred device, or null if
@@ -1300,6 +1483,7 @@ public class AudioSystem
// Items shared with audio service
/**
+ * @hide
* The delay before playing a sound. This small period exists so the user
* can press another key (non-volume keys, too) to have it NOT be audible.
* <p>
@@ -1308,6 +1492,7 @@ public class AudioSystem
public static final int PLAY_SOUND_DELAY = 300;
/**
+ * @hide
* Constant to identify a focus stack entry that is used to hold the focus while the phone
* is ringing or during a call. Used by com.android.internal.telephony.CallManager when
* entering and exiting calls.
@@ -1315,6 +1500,7 @@ public class AudioSystem
public final static String IN_VOICE_COMM_FOCUS_ID = "AudioFocus_For_Phone_Ring_And_Calls";
/**
+ * @hide
* @see AudioManager#setVibrateSetting(int, int)
*/
public static int getValueForVibrateSetting(int existingValue, int vibrateType,
@@ -1330,10 +1516,12 @@ public class AudioSystem
return existingValue;
}
+ /** @hide */
public static int getDefaultStreamVolume(int streamType) {
return DEFAULT_STREAM_VOLUME[streamType];
}
+ /** @hide */
public static int[] DEFAULT_STREAM_VOLUME = new int[] {
4, // STREAM_VOICE_CALL
7, // STREAM_SYSTEM
@@ -1349,20 +1537,22 @@ public class AudioSystem
5, // STREAM_ASSISTANT
};
+ /** @hide */
public static String streamToString(int stream) {
if (stream >= 0 && stream < STREAM_NAMES.length) return STREAM_NAMES[stream];
if (stream == AudioManager.USE_DEFAULT_STREAM_TYPE) return "USE_DEFAULT_STREAM_TYPE";
return "UNKNOWN_STREAM_" + stream;
}
- /** The platform has no specific capabilities */
+ /** @hide The platform has no specific capabilities */
public static final int PLATFORM_DEFAULT = 0;
- /** The platform is voice call capable (a phone) */
+ /** @hide The platform is voice call capable (a phone) */
public static final int PLATFORM_VOICE = 1;
- /** The platform is a television or a set-top box */
+ /** @hide The platform is a television or a set-top box */
public static final int PLATFORM_TELEVISION = 2;
/**
+ * @hide
* Return the platform type that this is running on. One of:
* <ul>
* <li>{@link #PLATFORM_VOICE}</li>
@@ -1392,6 +1582,7 @@ public class AudioSystem
}
/**
+ * @hide
* Return a set of audio device types from a bit mask audio device type, which may
* represent multiple audio device types.
* FIXME: Remove this when getting ride of bit mask usage of audio device types.
@@ -1409,6 +1600,7 @@ public class AudioSystem
}
/**
+ * @hide
* Return the intersection of two audio device types collections.
*/
public static Set<Integer> intersectionAudioDeviceTypes(
@@ -1419,12 +1611,14 @@ public class AudioSystem
}
/**
+ * @hide
* Return true if the audio device types collection only contains the given device type.
*/
public static boolean isSingleAudioDeviceType(@NonNull Set<Integer> types, int type) {
return types.size() == 1 && types.contains(type);
}
+ /** @hide */
public static final int DEFAULT_MUTE_STREAMS_AFFECTED =
(1 << STREAM_MUSIC) |
(1 << STREAM_RING) |
@@ -1434,6 +1628,7 @@ public class AudioSystem
(1 << STREAM_BLUETOOTH_SCO);
/**
+ * @hide
* Event posted by AudioTrack and AudioRecord JNI (JNIDeviceCallback) when routing changes.
* Keep in sync with core/jni/android_media_DeviceCallback.h.
*/
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index dbba4eb320ba..48aed349c39a 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -45,6 +45,7 @@ import android.media.tv.tuner.frontend.ScanCallback;
import android.media.tv.tunerresourcemanager.ResourceClientProfile;
import android.media.tv.tunerresourcemanager.TunerDemuxRequest;
import android.media.tv.tunerresourcemanager.TunerDescramblerRequest;
+import android.media.tv.tunerresourcemanager.TunerFrontendInfo;
import android.media.tv.tunerresourcemanager.TunerFrontendRequest;
import android.media.tv.tunerresourcemanager.TunerLnbRequest;
import android.media.tv.tunerresourcemanager.TunerResourceManager;
@@ -256,6 +257,36 @@ public class Tuner implements AutoCloseable {
mTunerResourceManager.registerClientProfile(
profile, new HandlerExecutor(mHandler), mResourceListener, clientId);
mClientId = clientId[0];
+
+ setFrontendInfoList();
+ setLnbIds();
+ }
+
+ private void setFrontendInfoList() {
+ List<Integer> ids = nativeGetFrontendIds();
+ if (ids == null) {
+ return;
+ }
+ TunerFrontendInfo[] infos = new TunerFrontendInfo[ids.size()];
+ for (int i = 0; i < ids.size(); i++) {
+ int id = ids.get(i);
+ FrontendInfo frontendInfo = nativeGetFrontendInfo(id);
+ if (frontendInfo == null) {
+ continue;
+ }
+ TunerFrontendInfo tunerFrontendInfo = new TunerFrontendInfo(
+ id, frontendInfo.getType(), frontendInfo.getExclusiveGroupId());
+ infos[i] = tunerFrontendInfo;
+ }
+ mTunerResourceManager.setFrontendInfoList(infos);
+ }
+
+ private void setLnbIds() {
+ int[] ids = nativeGetLnbIds();
+ if (ids == null) {
+ return;
+ }
+ mTunerResourceManager.setLnbInfoList(ids);
}
/**
@@ -358,7 +389,7 @@ public class Tuner implements AutoCloseable {
private native Filter nativeOpenFilter(int type, int subType, long bufferSize);
private native TimeFilter nativeOpenTimeFilter();
- private native List<Integer> nativeGetLnbIds();
+ private native int[] nativeGetLnbIds();
private native Lnb nativeOpenLnbByHandle(int handle);
private native Lnb nativeOpenLnbByName(String name);
diff --git a/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java b/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java
index 63a71e272e53..2c8899cfca78 100644
--- a/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java
+++ b/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java
@@ -390,7 +390,7 @@ public class TunerResourceManager {
* <li>If no Lnb system can be granted, the API would return false.
* <ul>
*
- * <p><strong>Note:</strong> {@link #setLnbInfos(int[])} must be called before this request.
+ * <p><strong>Note:</strong> {@link #setLnbInfoList(int[])} must be called before this request.
*
* @param request {@link TunerLnbRequest} information of the current request.
* @param lnbId a one-element array to return the granted Lnb id.
@@ -479,7 +479,7 @@ public class TunerResourceManager {
*
* <p>Client must call this whenever it releases an Lnb.
*
- * <p><strong>Note:</strong> {@link #setLnbInfos(int[])} must be called before this release.
+ * <p><strong>Note:</strong> {@link #setLnbInfoList(int[])} must be called before this release.
*
* @param lnbId the id of the released Tuner Lnb.
*/
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index 5820be6db8ea..ac7fe5d0403d 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -1079,29 +1079,26 @@ jobject JTuner::getFrontendInfo(int id) {
maxSymbolRate, acquireRange, exclusiveGroupId, statusCaps, jcaps);
}
-jobject JTuner::getLnbIds() {
+jintArray JTuner::getLnbIds() {
ALOGD("JTuner::getLnbIds()");
- mTuner->getLnbIds([&](Result, const hidl_vec<FrontendId>& lnbIds) {
- mLnbIds = lnbIds;
+ Result res;
+ hidl_vec<LnbId> lnbIds;
+ mTuner->getLnbIds([&](Result r, const hidl_vec<LnbId>& ids) {
+ lnbIds = ids;
+ res = r;
});
- if (mLnbIds.size() == 0) {
+ if (res != Result::SUCCESS || mLnbIds.size() == 0) {
ALOGW("Lnb isn't available");
return NULL;
}
+ mLnbIds = lnbIds;
JNIEnv *env = AndroidRuntime::getJNIEnv();
- jclass arrayListClazz = env->FindClass("java/util/ArrayList");
- jmethodID arrayListAdd = env->GetMethodID(arrayListClazz, "add", "(Ljava/lang/Object;)Z");
- jobject obj = env->NewObject(arrayListClazz, env->GetMethodID(arrayListClazz, "<init>", "()V"));
- jclass integerClazz = env->FindClass("java/lang/Integer");
- jmethodID intInit = env->GetMethodID(integerClazz, "<init>", "(I)V");
+ jintArray ids = env->NewIntArray(mLnbIds.size());
+ env->SetIntArrayRegion(ids, 0, mLnbIds.size(), reinterpret_cast<jint*>(&mLnbIds[0]));
- for (int i=0; i < mLnbIds.size(); i++) {
- jobject idObj = env->NewObject(integerClazz, intInit, mLnbIds[i]);
- env->CallBooleanMethod(obj, arrayListAdd, idObj);
- }
- return obj;
+ return ids;
}
jobject JTuner::openLnbById(int id) {
@@ -2405,7 +2402,7 @@ static jobject android_media_tv_Tuner_get_frontend_info(JNIEnv *env, jobject thi
return tuner->getFrontendInfo(id);
}
-static jobject android_media_tv_Tuner_get_lnb_ids(JNIEnv *env, jobject thiz) {
+static jintArray android_media_tv_Tuner_get_lnb_ids(JNIEnv *env, jobject thiz) {
sp<JTuner> tuner = getTuner(env, thiz);
return tuner->getLnbIds();
}
@@ -3415,8 +3412,7 @@ static const JNINativeMethod gTunerMethods[] = {
(void *)android_media_tv_Tuner_open_filter },
{ "nativeOpenTimeFilter", "()Landroid/media/tv/tuner/filter/TimeFilter;",
(void *)android_media_tv_Tuner_open_time_filter },
- { "nativeGetLnbIds", "()Ljava/util/List;",
- (void *)android_media_tv_Tuner_get_lnb_ids },
+ { "nativeGetLnbIds", "()[I", (void *)android_media_tv_Tuner_get_lnb_ids },
{ "nativeOpenLnbByHandle", "(I)Landroid/media/tv/tuner/Lnb;",
(void *)android_media_tv_Tuner_open_lnb_by_handle },
{ "nativeOpenLnbByName", "(Ljava/lang/String;)Landroid/media/tv/tuner/Lnb;",
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index 40fd644c62a0..73fc38dbdec8 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -179,7 +179,7 @@ struct JTuner : public RefBase {
int stopScan();
int setLnb(int id);
int setLna(bool enable);
- jobject getLnbIds();
+ jintArray getLnbIds();
jobject openLnbById(int id);
jobject openLnbByName(jstring name);
jobject openFilter(DemuxFilterType type, int bufferSize);
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarComponentBinder.java b/packages/CarSystemUI/src/com/android/systemui/CarComponentBinder.java
index f11eff851aa3..d84b2f958feb 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarComponentBinder.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarComponentBinder.java
@@ -28,7 +28,6 @@ import dagger.Module;
@Module(includes = {
DefaultActivityBinder.class,
DefaultBroadcastReceiverBinder.class,
- DefaultServiceBinder.class,
- CarSystemUIBinder.class})
+ DefaultServiceBinder.class})
public class CarComponentBinder {
}
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
index 5547fee0159c..c275536e4d92 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
@@ -65,7 +65,7 @@ import dagger.Module;
import dagger.Provides;
@Module(includes = {DividerModule.class})
-abstract class CarSystemUIModule {
+public abstract class CarSystemUIModule {
@Singleton
@Provides
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIRootComponent.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIRootComponent.java
index 7d544c9a9bd7..0e923f7164bb 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIRootComponent.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIRootComponent.java
@@ -40,6 +40,6 @@ import dagger.Component;
CarSystemUIModule.class,
CarSystemUIBinder.class
})
-interface CarSystemUIRootComponent extends SystemUIRootComponent {
+public interface CarSystemUIRootComponent extends SystemUIRootComponent {
}
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 9112602981e5..07f4a9a799ad 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -928,11 +928,15 @@
<!-- UI debug setting: show all ANRs summary [CHAR LIMIT=100] -->
<string name="show_all_anrs_summary">Display App Not Responding dialog for background apps</string>
- <!-- UI debug setting: show all ANRs? [CHAR LIMIT=25] -->
+ <!-- UI debug setting: show missing channel toasts? [CHAR LIMIT=25] -->
<string name="show_notification_channel_warnings">Show notification channel warnings</string>
- <!-- UI debug setting: show all ANRs summary [CHAR LIMIT=50] -->
+ <!-- UI debug setting: show missing channel toasts summary [CHAR LIMIT=50] -->
<string name="show_notification_channel_warnings_summary">Displays on-screen warning when an app posts a notification without a valid channel</string>
+ <!-- UI debug setting: enforce shortcut requirements for conversation space [CHAR LIMIT=25] -->
+ <string name="enforce_shortcuts_for_conversations">Enforce shortcuts for conversation notifications</string>
+ <!-- UI debug setting: enforce shortcut requirements for conversation space summary [CHAR LIMIT=50] -->
+ <string name="enforce_shortcuts_for_conversations_summary">Require notifications to be backed by a long-lived sharing shortcut in order to appear in the conversation section</string>
<!-- UI debug setting: force allow apps on external storage [CHAR LIMIT=50] -->
<string name="force_allow_on_external">Force allow apps on external</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiSavedConfigUtils.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiSavedConfigUtils.java
index 19e38081fcad..65c7786235bf 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiSavedConfigUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiSavedConfigUtils.java
@@ -65,5 +65,17 @@ public class WifiSavedConfigUtils {
}
return savedConfigs;
}
+
+ /**
+ * Returns the count of the saved configurations on the device, including both Wi-Fi networks
+ * and Passpoint profiles.
+ *
+ * @param context The application context
+ * @param wifiManager An instance of {@link WifiManager}
+ * @return count of saved Wi-Fi networks
+ */
+ public static int getAllConfigsCount(Context context, WifiManager wifiManager) {
+ return getAllConfigs(context, wifiManager).size();
+ }
}
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 86ba8bba31ee..01a2b6952f2a 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -418,6 +418,7 @@ public class SettingsBackupTest {
Settings.Global.RECOMMENDED_NETWORK_EVALUATOR_CACHE_EXPIRY_MS,
Settings.Global.READ_EXTERNAL_STORAGE_ENFORCED_DEFAULT,
Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT,
+ Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS,
Settings.Global.SAFE_BOOT_DISALLOWED,
Settings.Global.SELINUX_STATUS,
Settings.Global.SELINUX_UPDATE_CONTENT_URL,
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 68bd4071de05..c2015ed41b00 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -363,6 +363,7 @@ public class BugreportProgressService extends Service {
public void onError(@BugreportErrorCode int errorCode) {
synchronized (mLock) {
stopProgressLocked(mInfo.id);
+ mInfo.deleteEmptyFiles();
}
Log.e(TAG, "Bugreport API callback onError() errorCode = " + errorCode);
return;
@@ -1980,6 +1981,22 @@ public class BugreportProgressService extends Service {
}
/**
+ * Deletes empty files for a given bugreport.
+ */
+ private void deleteEmptyFiles() {
+ if (bugreportFile.length() == 0) {
+ Log.i(TAG, "Deleting empty bugreport file: " + bugreportFile);
+ bugreportFile.delete();
+ }
+ for (File file : screenshotFiles) {
+ if (file.length() == 0) {
+ Log.i(TAG, "Deleting empty screenshot file: " + file);
+ file.delete();
+ }
+ }
+ }
+
+ /**
* Rename all screenshots files so that they contain the new {@code name} instead of the
* {@code initialName} if user has changed it.
*/
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 791b83277571..c6f03271f931 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -255,6 +255,9 @@
<!-- Query all packages on device on R+ -->
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
+ <!-- Permission to register process observer -->
+ <uses-permission android:name="android.permission.SET_ACTIVITY_WATCHER"/>
+
<protected-broadcast android:name="com.android.settingslib.action.REGISTER_SLICE_RECEIVER" />
<protected-broadcast android:name="com.android.settingslib.action.UNREGISTER_SLICE_RECEIVER" />
<protected-broadcast android:name="com.android.settings.flashlight.action.FLASHLIGHT_CHANGED" />
diff --git a/packages/SystemUI/res/values/arrays_tv.xml b/packages/SystemUI/res/values/arrays_tv.xml
index 95716c834483..3343a84e7a9c 100644
--- a/packages/SystemUI/res/values/arrays_tv.xml
+++ b/packages/SystemUI/res/values/arrays_tv.xml
@@ -35,7 +35,5 @@
</string-array>
<string-array name="audio_recording_disclosure_exempt_apps" translatable="false">
- <item>com.google.android.katniss</item>
- <item>com.google.android.apps.mediashell</item>
</string-array>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
index ea1abf99a0f3..a0b49384d49f 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/ExpandedAnimationController.java
@@ -323,6 +323,9 @@ public class ExpandedAnimationController
/** Plays a dismiss animation on the dragged out bubble. */
public void dismissDraggedOutBubble(View bubble, Runnable after) {
+ if (bubble == null) {
+ return;
+ }
animationForChild(bubble)
.withStiffness(SpringForce.STIFFNESS_HIGH)
.scaleX(1.1f)
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
index dba43430b490..d219a9e65a3c 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java
@@ -319,7 +319,6 @@ public class PipAnimationController {
getSurfaceTransactionHelper()
.crop(tx, leash, getDestinationBounds())
.round(tx, leash, shouldApplyCornerRadius());
- tx.show(leash);
tx.apply();
}
};
@@ -360,7 +359,6 @@ public class PipAnimationController {
getSurfaceTransactionHelper()
.alpha(tx, leash, 1f)
.round(tx, leash, shouldApplyCornerRadius());
- tx.show(leash);
tx.apply();
}
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
index 8cff20ac31f7..d9872d7dcf17 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
@@ -319,23 +319,29 @@ public class PipTaskOrganizer extends TaskOrganizer {
* TODO(b/152809058): consolidate the display info handling logic in SysUI
*/
@SuppressWarnings("unchecked")
- public void mayUpdateCurrentAnimationOnRotationChange() {
+ public void onMovementBoundsChanged(boolean fromImeAdjustment, boolean fromShelfAdjustment) {
final PipAnimationController.PipTransitionAnimator animator =
mPipAnimationController.getCurrentAnimator();
- if (animator != null && animator.isRunning()
- && animator.getTransitionDirection() == TRANSITION_DIRECTION_TO_PIP) {
- final Rect currentDestinationBounds = animator.getDestinationBounds();
- if (mPipBoundsHandler.getDisplayBounds().contains(currentDestinationBounds)) {
- return;
- }
- final Rect newDestinationBounds = mPipBoundsHandler.getDestinationBounds(
- getAspectRatioOrDefault(mTaskInfo.pictureInPictureParams),
- null /* bounds */, getMinimalSize(mTaskInfo.topActivityInfo));
- if (animator.getAnimationType() == ANIM_TYPE_BOUNDS) {
- animator.updateEndValue(newDestinationBounds);
- }
- animator.setDestinationBounds(newDestinationBounds);
+ if (animator == null || !animator.isRunning()
+ || animator.getTransitionDirection() != TRANSITION_DIRECTION_TO_PIP) {
+ return;
+ }
+
+ final Rect currentDestinationBounds = animator.getDestinationBounds();
+ if (!fromImeAdjustment && !fromShelfAdjustment
+ && mPipBoundsHandler.getDisplayBounds().contains(currentDestinationBounds)) {
+ // no need to update the destination bounds, bail early
+ return;
+ }
+
+ final Rect newDestinationBounds = mPipBoundsHandler.getDestinationBounds(
+ getAspectRatioOrDefault(mTaskInfo.pictureInPictureParams),
+ null /* bounds */, getMinimalSize(mTaskInfo.topActivityInfo));
+ if (newDestinationBounds.equals(currentDestinationBounds)) return;
+ if (animator.getAnimationType() == ANIM_TYPE_BOUNDS) {
+ animator.updateEndValue(newDestinationBounds);
}
+ animator.setDestinationBounds(newDestinationBounds);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index 99d6df517224..918c45b52d61 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -362,7 +362,7 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio
mTouchHandler.onMovementBoundsChanged(mTmpInsetBounds, mTmpNormalBounds,
animatingBounds, fromImeAdjustment, fromShelfAdjustment,
mTmpDisplayInfo.rotation);
- mPipTaskOrganizer.mayUpdateCurrentAnimationOnRotationChange();
+ mPipTaskOrganizer.onMovementBoundsChanged(fromImeAdjustment, fromShelfAdjustment);
}
public void dump(PrintWriter pw) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 94afde786e78..24195156d8cf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -322,10 +322,10 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
default void suppressAmbientDisplay(boolean suppress) { }
/**
- * @see IStatusBar#showToast(String, IBinder, CharSequence, IBinder, int,
+ * @see IStatusBar#showToast(int, String, IBinder, CharSequence, IBinder, int,
* ITransientNotificationCallback)
*/
- default void showToast(String packageName, IBinder token, CharSequence text,
+ default void showToast(int uid, String packageName, IBinder token, CharSequence text,
IBinder windowToken, int duration,
@Nullable ITransientNotificationCallback callback) { }
@@ -798,7 +798,7 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
}
@Override
- public void showToast(String packageName, IBinder token, CharSequence text,
+ public void showToast(int uid, String packageName, IBinder token, CharSequence text,
IBinder windowToken, int duration, @Nullable ITransientNotificationCallback callback) {
synchronized (mLock) {
SomeArgs args = SomeArgs.obtain();
@@ -807,7 +807,8 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
args.arg3 = text;
args.arg4 = windowToken;
args.arg5 = callback;
- args.argi1 = duration;
+ args.argi1 = uid;
+ args.argi2 = duration;
mHandler.obtainMessage(MSG_SHOW_TOAST, args).sendToTarget();
}
}
@@ -1276,9 +1277,10 @@ public class CommandQueue extends IStatusBar.Stub implements CallbackController<
IBinder windowToken = (IBinder) args.arg4;
ITransientNotificationCallback callback =
(ITransientNotificationCallback) args.arg5;
- int duration = args.argi1;
+ int uid = args.argi1;
+ int duration = args.argi2;
for (Callbacks callbacks : mCallbacks) {
- callbacks.showToast(packageName, token, text, windowToken, duration,
+ callbacks.showToast(uid, packageName, token, text, windowToken, duration,
callback);
}
break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
index 88cca43fd1a9..5879c15c2493 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
@@ -83,9 +83,9 @@ class PeopleNotificationIdentifierImpl @Inject constructor(
private val Ranking.personTypeInfo
get() = when {
+ !isConversation -> TYPE_NON_PERSON
channel?.isImportantConversation == true -> TYPE_IMPORTANT_PERSON
- isConversation -> TYPE_PERSON
- else -> TYPE_NON_PERSON
+ else -> TYPE_PERSON
}
private fun extractPersonTypeInfo(sbn: StatusBarNotification) =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 4462c7218a76..3105155f28e8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -625,7 +625,9 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
// mOrientedHandle is initialized lazily
mOrientationHandle.setVisibility(View.GONE);
}
- mNavigationBarView.setVisibility(View.VISIBLE);
+ if (mNavigationBarView != null) {
+ mNavigationBarView.setVisibility(View.VISIBLE);
+ }
}
private int deltaRotation(int oldRotation, int newRotation) {
@@ -635,7 +637,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
}
private void updatedFixedRotation() {
- mFixedRotationEnabled = Settings.Global.getInt(getContext().getContentResolver(),
+ mFixedRotationEnabled = Settings.Global.getInt(mContentResolver,
FIXED_ROTATION_TRANSFORM_SETTING_NAME, 0) != 0;
if (!canShowSecondaryHandle()) {
resetSecondaryHandle();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index 07985ab5a43c..02ae1f8afcdf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -27,6 +27,7 @@ import android.os.UserHandle;
import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.SystemUI;
import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.tv.micdisclosure.AudioRecordingDisclosureBar;
import javax.inject.Inject;
import javax.inject.Singleton;
@@ -66,7 +67,8 @@ public class TvStatusBar extends SystemUI implements CommandQueue.Callbacks {
// If the system process isn't there we're doomed anyway.
}
- new AudioRecordingDisclosureBar(mContext).start();
+ // Creating AudioRecordingDisclosureBar and just letting it run
+ new AudioRecordingDisclosureBar(mContext);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioActivityObserver.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioActivityObserver.java
new file mode 100644
index 000000000000..87b3956060f3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioActivityObserver.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2020 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.systemui.statusbar.tv.micdisclosure;
+
+import android.content.Context;
+
+import java.util.Set;
+
+/**
+ * A base class for implementing observers for different kinds of activities related to audio
+ * recording. These observers are to be initialized by {@link AudioRecordingDisclosureBar} and to
+ * report back to it.
+ */
+abstract class AudioActivityObserver {
+
+ interface OnAudioActivityStateChangeListener {
+ void onAudioActivityStateChange(boolean active, String packageName);
+ }
+
+ final Context mContext;
+
+ final OnAudioActivityStateChangeListener mListener;
+
+ AudioActivityObserver(Context context, OnAudioActivityStateChangeListener listener) {
+ mContext = context;
+ mListener = listener;
+ }
+
+ abstract Set<String> getActivePackages();
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/AudioRecordingDisclosureBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java
index e70e30a5ab57..914868301d72 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/AudioRecordingDisclosureBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.tv;
+package com.android.systemui.statusbar.tv.micdisclosure;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
@@ -25,7 +25,6 @@ import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.annotation.IntDef;
import android.annotation.UiThread;
-import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
@@ -40,6 +39,7 @@ import android.view.WindowManager;
import android.widget.TextView;
import com.android.systemui.R;
+import com.android.systemui.statusbar.tv.TvStatusBar;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -54,9 +54,10 @@ import java.util.Set;
*
* @see TvStatusBar
*/
-class AudioRecordingDisclosureBar {
- private static final String TAG = "AudioRecordingDisclosureBar";
- private static final boolean DEBUG = false;
+public class AudioRecordingDisclosureBar implements
+ AudioActivityObserver.OnAudioActivityStateChangeListener {
+ private static final String TAG = "AudioRecordingDisclosure";
+ static final boolean DEBUG = false;
// This title is used to test the microphone disclosure indicator in
// CtsSystemUiHostTestCases:TvMicrophoneCaptureIndicatorTest
@@ -98,10 +99,12 @@ class AudioRecordingDisclosureBar {
private TextView mTextView;
@State private int mState = STATE_NOT_SHOWN;
+
/**
- * Set of the applications that currently are conducting audio recording.
+ * Array of the observers that monitor different aspects of the system, such as AppOps and
+ * microphone foreground services
*/
- private final Set<String> mActiveAudioRecordingPackages = new ArraySet<>();
+ private final AudioActivityObserver[] mAudioActivityObservers;
/**
* Set of applications that we've notified the user about since the indicator came up. Meaning
* that if an application is in this list then at some point since the indicator came up, it
@@ -119,29 +122,52 @@ class AudioRecordingDisclosureBar {
* one of the two aforementioned states.
*/
private final Queue<String> mPendingNotificationPackages = new LinkedList<>();
+ /**
+ * Set of applications for which we make an exception and do not show the indicator. This gets
+ * populated once - in {@link #AudioRecordingDisclosureBar(Context)}.
+ */
+ private final Set<String> mExemptPackages;
- AudioRecordingDisclosureBar(Context context) {
+ public AudioRecordingDisclosureBar(Context context) {
mContext = context;
- }
- void start() {
- // Register AppOpsManager callback
- final AppOpsManager appOpsManager = (AppOpsManager) mContext.getSystemService(
- Context.APP_OPS_SERVICE);
- appOpsManager.startWatchingActive(
- new String[]{AppOpsManager.OPSTR_RECORD_AUDIO},
- mContext.getMainExecutor(),
- new OnActiveRecordingListener());
+ mExemptPackages = new ArraySet<>(
+ Arrays.asList(mContext.getResources().getStringArray(
+ R.array.audio_recording_disclosure_exempt_apps)));
+
+ mAudioActivityObservers = new AudioActivityObserver[]{
+ new RecordAudioAppOpObserver(mContext, this),
+ new MicrophoneForegroundServicesObserver(mContext, this),
+ };
}
@UiThread
- private void onStartedRecording(String packageName) {
- if (!mActiveAudioRecordingPackages.add(packageName)) {
- // This app is already known to perform recording
+ @Override
+ public void onAudioActivityStateChange(boolean active, String packageName) {
+ if (DEBUG) {
+ Log.d(TAG,
+ "onAudioActivityStateChange, packageName=" + packageName + ", active="
+ + active);
+ }
+
+ if (mExemptPackages.contains(packageName)) {
+ if (DEBUG) Log.d(TAG, " - exempt package: ignoring");
return;
}
+
+ if (active) {
+ showIndicatorForPackageIfNeeded(packageName);
+ } else {
+ hideIndicatorIfNeeded();
+ }
+ }
+
+ @UiThread
+ private void showIndicatorForPackageIfNeeded(String packageName) {
+ if (DEBUG) Log.d(TAG, "showIndicatorForPackageIfNeeded, packageName=" + packageName);
if (!mSessionNotifiedPackages.add(packageName)) {
// We've already notified user about this app, no need to do it again.
+ if (DEBUG) Log.d(TAG, " - already notified");
return;
}
@@ -167,23 +193,33 @@ class AudioRecordingDisclosureBar {
}
@UiThread
- private void onDoneRecording(String packageName) {
- if (!mActiveAudioRecordingPackages.remove(packageName)) {
- // Was not marked as an active recorder, do nothing
- return;
- }
-
+ private void hideIndicatorIfNeeded() {
+ if (DEBUG) Log.d(TAG, "hideIndicatorIfNeeded");
// If not MINIMIZED, will check whether the indicator should be hidden when the indicator
- // comes to the STATE_MINIMIZED eventually. If is in the STATE_MINIMIZED, but there are
- // other active recorders - simply ignore.
- if (mState == STATE_MINIMIZED && mActiveAudioRecordingPackages.isEmpty()) {
- mSessionNotifiedPackages.clear();
- hide();
+ // comes to the STATE_MINIMIZED eventually.
+ if (mState != STATE_MINIMIZED) return;
+
+ // If is in the STATE_MINIMIZED, but there are other active recorders - simply ignore.
+ for (int index = mAudioActivityObservers.length - 1; index >= 0; index--) {
+ for (String activePackage : mAudioActivityObservers[index].getActivePackages()) {
+ if (mExemptPackages.contains(activePackage)) continue;
+ if (DEBUG) Log.d(TAG, " - there are still ongoing activities");
+ return;
+ }
}
+
+ // Clear the state and hide the indicator.
+ mSessionNotifiedPackages.clear();
+ hide();
}
@UiThread
private void show(String packageName) {
+ final String label = getApplicationLabel(packageName);
+ if (DEBUG) {
+ Log.d(TAG, "Showing indicator for " + packageName + " (" + label + ")...");
+ }
+
// Inflate the indicator view
mIndicatorView = LayoutInflater.from(mContext).inflate(
R.layout.tv_audio_recording_indicator,
@@ -196,7 +232,6 @@ class AudioRecordingDisclosureBar {
mBgRight = mIndicatorView.findViewById(R.id.bg_right);
// Set up the notification text
- final String label = getApplicationLabel(packageName);
mTextView.setText(mContext.getString(R.string.app_accessed_mic, label));
// Initially change the visibility to INVISIBLE, wait until and receives the size and
@@ -260,6 +295,9 @@ class AudioRecordingDisclosureBar {
@UiThread
private void expand(String packageName) {
final String label = getApplicationLabel(packageName);
+ if (DEBUG) {
+ Log.d(TAG, "Expanding for " + packageName + " (" + label + ")...");
+ }
mTextView.setText(mContext.getString(R.string.app_accessed_mic, label));
final AnimatorSet set = new AnimatorSet();
@@ -283,6 +321,7 @@ class AudioRecordingDisclosureBar {
@UiThread
private void minimize() {
+ if (DEBUG) Log.d(TAG, "Minimizing...");
final int targetOffset = mTextsContainers.getWidth();
final AnimatorSet set = new AnimatorSet();
set.playTogether(
@@ -305,6 +344,7 @@ class AudioRecordingDisclosureBar {
@UiThread
private void hide() {
+ if (DEBUG) Log.d(TAG, "Hiding...");
final int targetOffset =
mIndicatorView.getWidth() - (int) mIconTextsContainer.getTranslationX();
final AnimatorSet set = new AnimatorSet();
@@ -326,6 +366,7 @@ class AudioRecordingDisclosureBar {
@UiThread
private void onExpanded() {
+ if (DEBUG) Log.d(TAG, "Expanded");
mState = STATE_SHOWN;
mIndicatorView.postDelayed(this::minimize, MAXIMIZED_DURATION);
@@ -333,20 +374,21 @@ class AudioRecordingDisclosureBar {
@UiThread
private void onMinimized() {
+ if (DEBUG) Log.d(TAG, "Minimized");
mState = STATE_MINIMIZED;
if (!mPendingNotificationPackages.isEmpty()) {
// There is a new application that started recording, tell the user about it.
expand(mPendingNotificationPackages.poll());
- } else if (mActiveAudioRecordingPackages.isEmpty()) {
- // Nobody is recording anymore, clear state and remove the indicator.
- mSessionNotifiedPackages.clear();
- hide();
+ } else {
+ hideIndicatorIfNeeded();
}
}
@UiThread
private void onHidden() {
+ if (DEBUG) Log.d(TAG, "Hidden");
+
final WindowManager windowManager = (WindowManager) mContext.getSystemService(
Context.WINDOW_SERVICE);
windowManager.removeView(mIndicatorView);
@@ -392,35 +434,4 @@ class AudioRecordingDisclosureBar {
}
return pm.getApplicationLabel(appInfo).toString();
}
-
- private class OnActiveRecordingListener implements AppOpsManager.OnOpActiveChangedListener {
- private final Set<String> mExemptApps;
-
- private OnActiveRecordingListener() {
- mExemptApps = new ArraySet<>(Arrays.asList(mContext.getResources().getStringArray(
- R.array.audio_recording_disclosure_exempt_apps)));
- }
-
- @Override
- public void onOpActiveChanged(String op, int uid, String packageName, boolean active) {
- if (DEBUG) {
- Log.d(TAG,
- "OP_RECORD_AUDIO active change, active=" + active + ", app="
- + packageName);
- }
-
- if (mExemptApps.contains(packageName)) {
- if (DEBUG) {
- Log.d(TAG, "\t- exempt app");
- }
- return;
- }
-
- if (active) {
- onStartedRecording(packageName);
- } else {
- onDoneRecording(packageName);
- }
- }
- }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/MicrophoneForegroundServicesObserver.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/MicrophoneForegroundServicesObserver.java
new file mode 100644
index 000000000000..1ede88a26020
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/MicrophoneForegroundServicesObserver.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2020 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.systemui.statusbar.tv.micdisclosure;
+
+import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE;
+
+import static com.android.systemui.statusbar.tv.micdisclosure.AudioRecordingDisclosureBar.DEBUG;
+
+import android.annotation.UiThread;
+import android.app.ActivityManager;
+import android.app.IActivityManager;
+import android.app.IProcessObserver;
+import android.content.Context;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.SparseArray;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * The purpose of these class is to detect packages that are running foreground services of type
+ * 'microphone' and to report back to {@link AudioRecordingDisclosureBar}.
+ */
+class MicrophoneForegroundServicesObserver extends AudioActivityObserver {
+ private static final String TAG = "MicrophoneForegroundServicesObserver";
+ private static final boolean ENABLED = true;
+
+ private final IActivityManager mActivityManager;
+ /**
+ * A dictionary that maps PIDs to the package names. We only keep track of the PIDs that are
+ * "active" (those that are running FGS with FOREGROUND_SERVICE_TYPE_MICROPHONE flag).
+ */
+ private final SparseArray<String[]> mPidToPackages = new SparseArray<>();
+ /**
+ * A dictionary that maps "active" packages to the number of the "active" processes associated
+ * with those packages. We really only need this in case when one application is running in
+ * multiple processes, so that we don't lose track of the package when one of its "active"
+ * processes ceases, while others remain "active".
+ */
+ private final Map<String, Integer> mPackageToProcessCount = new ArrayMap<>();
+
+ MicrophoneForegroundServicesObserver(Context context,
+ OnAudioActivityStateChangeListener listener) {
+ super(context, listener);
+
+ mActivityManager = ActivityManager.getService();
+ try {
+ mActivityManager.registerProcessObserver(mProcessObserver);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Couldn't register process observer", e);
+ }
+ }
+
+ @Override
+ Set<String> getActivePackages() {
+ return ENABLED ? mPackageToProcessCount.keySet() : Collections.emptySet();
+ }
+
+ @UiThread
+ private void onProcessForegroundServicesChanged(int pid, boolean hasMicFgs) {
+ final String[] changedPackages;
+ if (hasMicFgs) {
+ if (mPidToPackages.contains(pid)) {
+ // We are already tracking this pid - ignore.
+ changedPackages = null;
+ } else {
+ changedPackages = getPackageNames(pid);
+ mPidToPackages.append(pid, changedPackages);
+ }
+ } else {
+ changedPackages = mPidToPackages.removeReturnOld(pid);
+ }
+
+ if (changedPackages == null) {
+ return;
+ }
+
+ for (int index = changedPackages.length - 1; index >= 0; index--) {
+ final String packageName = changedPackages[index];
+ int processCount = mPackageToProcessCount.getOrDefault(packageName, 0);
+ final boolean shouldNotify;
+ if (hasMicFgs) {
+ processCount++;
+ shouldNotify = processCount == 1;
+ } else {
+ processCount--;
+ shouldNotify = processCount == 0;
+ }
+ if (processCount > 0) {
+ mPackageToProcessCount.put(packageName, processCount);
+ } else {
+ mPackageToProcessCount.remove(packageName);
+ }
+ if (shouldNotify) notifyPackageStateChanged(packageName, hasMicFgs);
+ }
+ }
+
+ @UiThread
+ private void onProcessDied(int pid) {
+ final String[] packages = mPidToPackages.removeReturnOld(pid);
+ if (packages == null) {
+ // This PID was not active - ignore.
+ return;
+ }
+
+ for (int index = packages.length - 1; index >= 0; index--) {
+ final String packageName = packages[index];
+ int processCount = mPackageToProcessCount.getOrDefault(packageName, 0);
+ if (processCount <= 0) {
+ Log.e(TAG, "Bookkeeping error, process count for " + packageName + " is "
+ + processCount);
+ continue;
+ }
+ processCount--;
+ if (processCount > 0) {
+ mPackageToProcessCount.put(packageName, processCount);
+ } else {
+ mPackageToProcessCount.remove(packageName);
+ notifyPackageStateChanged(packageName, false);
+ }
+ }
+ }
+
+ @UiThread
+ private void notifyPackageStateChanged(String packageName, boolean active) {
+ if (active) {
+ if (DEBUG) Log.d(TAG, "New microphone fgs detected, package=" + packageName);
+ } else {
+ if (DEBUG) Log.d(TAG, "Microphone fgs is gone, package=" + packageName);
+ }
+
+ if (ENABLED) mListener.onAudioActivityStateChange(active, packageName);
+ }
+
+ @UiThread
+ private String[] getPackageNames(int pid) {
+ final List<ActivityManager.RunningAppProcessInfo> runningApps;
+ try {
+ runningApps = mActivityManager.getRunningAppProcesses();
+ } catch (RemoteException e) {
+ Log.d(TAG, "Couldn't get package name for pid=" + pid);
+ return null;
+ }
+ if (runningApps == null) {
+ Log.wtf(TAG, "No running apps reported");
+ }
+ for (ActivityManager.RunningAppProcessInfo app : runningApps) {
+ if (app.pid == pid) {
+ return app.pkgList;
+ }
+ }
+ return null;
+ }
+
+ private final IProcessObserver mProcessObserver = new IProcessObserver.Stub() {
+ @Override
+ public void onForegroundActivitiesChanged(int pid, int uid, boolean foregroundActivities) {}
+
+ @Override
+ public void onForegroundServicesChanged(int pid, int uid, int serviceTypes) {
+ mContext.getMainExecutor().execute(() -> onProcessForegroundServicesChanged(pid,
+ (serviceTypes & FOREGROUND_SERVICE_TYPE_MICROPHONE) != 0));
+ }
+
+ @Override
+ public void onProcessDied(int pid, int uid) {
+ mContext.getMainExecutor().execute(
+ () -> MicrophoneForegroundServicesObserver.this.onProcessDied(pid));
+ }
+ };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/RecordAudioAppOpObserver.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/RecordAudioAppOpObserver.java
new file mode 100644
index 000000000000..b5b1c2b3018a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/RecordAudioAppOpObserver.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2020 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.systemui.statusbar.tv.micdisclosure;
+
+import static com.android.systemui.statusbar.tv.micdisclosure.AudioRecordingDisclosureBar.DEBUG;
+
+import android.annotation.UiThread;
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.util.ArraySet;
+import android.util.Log;
+
+import java.util.Set;
+
+/**
+ * The purpose of these class is to detect packages that are conducting audio recording (according
+ * to {@link AppOpsManager}) and report this to {@link AudioRecordingDisclosureBar}.
+ */
+class RecordAudioAppOpObserver extends AudioActivityObserver implements
+ AppOpsManager.OnOpActiveChangedListener {
+ private static final String TAG = "RecordAudioAppOpObserver";
+
+ /**
+ * Set of the applications that currently are conducting audio recording according to {@link
+ * AppOpsManager}.
+ */
+ private final Set<String> mActiveAudioRecordingPackages = new ArraySet<>();
+
+ RecordAudioAppOpObserver(Context context, OnAudioActivityStateChangeListener listener) {
+ super(context, listener);
+
+ // Register AppOpsManager callback
+ final AppOpsManager appOpsManager = (AppOpsManager) mContext.getSystemService(
+ Context.APP_OPS_SERVICE);
+ appOpsManager.startWatchingActive(
+ new String[]{AppOpsManager.OPSTR_RECORD_AUDIO},
+ mContext.getMainExecutor(),
+ this);
+ }
+
+ @UiThread
+ @Override
+ Set<String> getActivePackages() {
+ return mActiveAudioRecordingPackages;
+ }
+
+ @UiThread
+ @Override
+ public void onOpActiveChanged(String op, int uid, String packageName, boolean active) {
+ if (DEBUG) {
+ Log.d(TAG,
+ "OP_RECORD_AUDIO active change, active=" + active + ", package="
+ + packageName);
+ }
+
+ if (active) {
+ if (mActiveAudioRecordingPackages.add(packageName)) {
+ mListener.onAudioActivityStateChange(true, packageName);
+ }
+ } else {
+ if (mActiveAudioRecordingPackages.remove(packageName)) {
+ mListener.onAudioActivityStateChange(false, packageName);
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java b/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java
index 9ccb9bf5b62b..9b465ae15478 100644
--- a/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java
+++ b/packages/SystemUI/src/com/android/systemui/toast/ToastUI.java
@@ -24,10 +24,10 @@ import android.content.Context;
import android.content.res.Resources;
import android.os.IBinder;
import android.os.ServiceManager;
+import android.os.UserHandle;
import android.util.Log;
import android.view.View;
-import android.view.WindowManager;
-import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.IAccessibilityManager;
import android.widget.ToastPresenter;
import com.android.internal.R;
@@ -48,9 +48,8 @@ public class ToastUI extends SystemUI implements CommandQueue.Callbacks {
private static final String TAG = "ToastUI";
private final CommandQueue mCommandQueue;
- private final WindowManager mWindowManager;
private final INotificationManager mNotificationManager;
- private final AccessibilityManager mAccessibilityManager;
+ private final IAccessibilityManager mAccessibilityManager;
private final int mGravity;
private final int mY;
@Nullable private ToastPresenter mPresenter;
@@ -59,18 +58,17 @@ public class ToastUI extends SystemUI implements CommandQueue.Callbacks {
@Inject
public ToastUI(Context context, CommandQueue commandQueue) {
this(context, commandQueue,
- (WindowManager) context.getSystemService(Context.WINDOW_SERVICE),
INotificationManager.Stub.asInterface(
ServiceManager.getService(Context.NOTIFICATION_SERVICE)),
- AccessibilityManager.getInstance(context));
+ IAccessibilityManager.Stub.asInterface(
+ ServiceManager.getService(Context.ACCESSIBILITY_SERVICE)));
}
@VisibleForTesting
- ToastUI(Context context, CommandQueue commandQueue, WindowManager windowManager,
- INotificationManager notificationManager, AccessibilityManager accessibilityManager) {
+ ToastUI(Context context, CommandQueue commandQueue, INotificationManager notificationManager,
+ @Nullable IAccessibilityManager accessibilityManager) {
super(context);
mCommandQueue = commandQueue;
- mWindowManager = windowManager;
mNotificationManager = notificationManager;
mAccessibilityManager = accessibilityManager;
Resources resources = mContext.getResources();
@@ -85,15 +83,16 @@ public class ToastUI extends SystemUI implements CommandQueue.Callbacks {
@Override
@MainThread
- public void showToast(String packageName, IBinder token, CharSequence text,
+ public void showToast(int uid, String packageName, IBinder token, CharSequence text,
IBinder windowToken, int duration, @Nullable ITransientNotificationCallback callback) {
if (mPresenter != null) {
hideCurrentToast();
}
- View view = ToastPresenter.getTextToastView(mContext, text);
+ Context context = mContext.createContextAsUser(UserHandle.getUserHandleForUid(uid), 0);
+ View view = ToastPresenter.getTextToastView(context, text);
mCallback = callback;
- mPresenter = new ToastPresenter(mContext, mWindowManager, mAccessibilityManager,
- mNotificationManager, packageName);
+ mPresenter = new ToastPresenter(context, mAccessibilityManager, mNotificationManager,
+ packageName);
mPresenter.show(view, token, windowToken, duration, mGravity, 0, mY, 0, 0, mCallback);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java
index 56a748497d4e..0d66340a3917 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java
@@ -51,6 +51,7 @@ public class PipAnimationControllerTest extends SysuiTestCase {
private PipAnimationController mPipAnimationController;
+ @Mock
private SurfaceControl mLeash;
@Mock
@@ -60,10 +61,6 @@ public class PipAnimationControllerTest extends SysuiTestCase {
public void setUp() throws Exception {
mPipAnimationController = new PipAnimationController(
mContext, new PipSurfaceTransactionHelper(mContext));
- mLeash = new SurfaceControl.Builder()
- .setContainerLayer()
- .setName("FakeLeash")
- .build();
MockitoAnnotations.initMocks(this);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java b/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java
index 65fbe79b5e9f..0a10ab2fbf02 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/toast/ToastUITest.java
@@ -16,29 +16,43 @@
package com.android.systemui.toast;
+import static android.view.accessibility.AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED;
+import static android.widget.ToastPresenter.TEXT_TOAST_LAYOUT;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.INotificationManager;
import android.app.ITransientNotificationCallback;
+import android.content.Context;
import android.os.Binder;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.testing.AndroidTestingRunner;
+import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
-import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.IAccessibilityManager;
import android.widget.FrameLayout;
import android.widget.TextView;
import android.widget.Toast;
+import android.widget.ToastPresenter;
import androidx.test.filters.SmallTest;
import com.android.internal.R;
+import com.android.internal.util.IntPair;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.statusbar.CommandQueue;
@@ -49,32 +63,53 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.mockito.stubbing.Answer;
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class ToastUITest extends SysuiTestCase {
+ private static final int ANDROID_UID = 1000;
+ private static final int SYSTEMUI_UID = 10140;
+
+ private static final int UID_1 = 10255;
private static final String PACKAGE_NAME_1 = "com.example1.test";
private static final Binder TOKEN_1 = new Binder();
private static final Binder WINDOW_TOKEN_1 = new Binder();
+
+ private static final int UID_2 = 10256;
private static final String PACKAGE_NAME_2 = "com.example2.test";
private static final Binder TOKEN_2 = new Binder();
private static final Binder WINDOW_TOKEN_2 = new Binder();
+
private static final String TEXT = "Hello World";
private static final int MESSAGE_RES_ID = R.id.message;
+ private Context mContextSpy;
+ private ToastUI mToastUI;
+ @Mock private LayoutInflater mLayoutInflater;
@Mock private CommandQueue mCommandQueue;
@Mock private WindowManager mWindowManager;
@Mock private INotificationManager mNotificationManager;
- @Mock private AccessibilityManager mAccessibilityManager;
+ @Mock private IAccessibilityManager mAccessibilityManager;
@Mock private ITransientNotificationCallback mCallback;
@Captor private ArgumentCaptor<View> mViewCaptor;
@Captor private ArgumentCaptor<ViewGroup.LayoutParams> mParamsCaptor;
- private ToastUI mToastUI;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mToastUI = new ToastUI(mContext, mCommandQueue, mWindowManager, mNotificationManager,
+
+ // This is because inflate will result in WindowManager (WM) calls, which will fail since we
+ // are mocking it, so we mock LayoutInflater with the view obtained before mocking WM.
+ View view = ToastPresenter.getTextToastView(mContext, TEXT);
+ when(mLayoutInflater.inflate(eq(TEXT_TOAST_LAYOUT), any())).thenReturn(view);
+ mContext.addMockSystemService(LayoutInflater.class, mLayoutInflater);
+
+ mContext.addMockSystemService(WindowManager.class, mWindowManager);
+ mContextSpy = spy(mContext);
+ doReturn(mContextSpy).when(mContextSpy).createContextAsUser(any(), anyInt());
+
+ mToastUI = new ToastUI(mContextSpy, mCommandQueue, mNotificationManager,
mAccessibilityManager);
}
@@ -87,7 +122,8 @@ public class ToastUITest extends SysuiTestCase {
@Test
public void testShowToast_addsCorrectViewToWindowManager() throws Exception {
- mToastUI.showToast(PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, null);
+ mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
+ null);
verify(mWindowManager).addView(mViewCaptor.capture(), any());
View view = mViewCaptor.getValue();
@@ -96,13 +132,14 @@ public class ToastUITest extends SysuiTestCase {
@Test
public void testShowToast_addsViewWithCorrectLayoutParamsToWindowManager() throws Exception {
- mToastUI.showToast(PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, null);
+ mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
+ null);
verify(mWindowManager).addView(any(), mParamsCaptor.capture());
ViewGroup.LayoutParams params = mParamsCaptor.getValue();
assertThat(params).isInstanceOf(WindowManager.LayoutParams.class);
WindowManager.LayoutParams windowParams = (WindowManager.LayoutParams) params;
- assertThat(windowParams.packageName).isEqualTo(mContext.getPackageName());
+ assertThat(windowParams.packageName).isEqualTo(mContextSpy.getPackageName());
assertThat(windowParams.getTitle()).isEqualTo("Toast");
assertThat(windowParams.token).isEqualTo(WINDOW_TOKEN_1);
assertThat(windowParams.privateFlags
@@ -111,7 +148,8 @@ public class ToastUITest extends SysuiTestCase {
@Test
public void testShowToast_forAndroidPackage_addsAllUserFlag() throws Exception {
- mToastUI.showToast("android", TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, null);
+ mToastUI.showToast(ANDROID_UID, "android", TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
+ null);
verify(mWindowManager).addView(any(), mParamsCaptor.capture());
ViewGroup.LayoutParams params = mParamsCaptor.getValue();
@@ -123,8 +161,8 @@ public class ToastUITest extends SysuiTestCase {
@Test
public void testShowToast_forSystemUiPackage_addsAllUserFlag() throws Exception {
- mToastUI.showToast("com.android.systemui", TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
- null);
+ mToastUI.showToast(SYSTEMUI_UID, "com.android.systemui", TOKEN_1, TEXT, WINDOW_TOKEN_1,
+ Toast.LENGTH_LONG, null);
verify(mWindowManager).addView(any(), mParamsCaptor.capture());
ViewGroup.LayoutParams params = mParamsCaptor.getValue();
@@ -136,7 +174,7 @@ public class ToastUITest extends SysuiTestCase {
@Test
public void testShowToast_callsCallback() throws Exception {
- mToastUI.showToast(PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
+ mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
mCallback);
verify(mCallback).onToastShown();
@@ -144,14 +182,24 @@ public class ToastUITest extends SysuiTestCase {
@Test
public void testShowToast_sendsAccessibilityEvent() throws Exception {
- when(mAccessibilityManager.isEnabled()).thenReturn(true);
-
- mToastUI.showToast(PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG, null);
+ // Enable accessibility
+ when(mAccessibilityManager.addClient(any(), anyInt())).thenReturn(
+ IntPair.of(STATE_FLAG_ACCESSIBILITY_ENABLED, AccessibilityEvent.TYPES_ALL_MASK));
+ // AccessibilityManager recycles the event that goes over the wire after making the binder
+ // call to the service. Since we are mocking the service, that call is local, so if we use
+ // ArgumentCaptor or ArgumentMatcher it will retain a reference to the recycled event, which
+ // will already have its state reset by the time we verify its contents. So, instead, we
+ // serialize it at call-time and later on deserialize it to verity its contents.
+ Parcel eventParcel = Parcel.obtain();
+ doAnswer(writeArgumentToParcel(0, eventParcel)).when(
+ mAccessibilityManager).sendAccessibilityEvent(any(), anyInt());
+
+ mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
+ null);
- ArgumentCaptor<AccessibilityEvent> eventCaptor = ArgumentCaptor.forClass(
- AccessibilityEvent.class);
- verify(mAccessibilityManager).sendAccessibilityEvent(eventCaptor.capture());
- AccessibilityEvent event = eventCaptor.getValue();
+ eventParcel.setDataPosition(0);
+ assertThat(eventParcel.dataSize()).isGreaterThan(0);
+ AccessibilityEvent event = AccessibilityEvent.CREATOR.createFromParcel(eventParcel);
assertThat(event.getEventType()).isEqualTo(
AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED);
assertThat(event.getClassName()).isEqualTo(Toast.class.getName());
@@ -160,7 +208,7 @@ public class ToastUITest extends SysuiTestCase {
@Test
public void testHideToast_removesView() throws Exception {
- mToastUI.showToast(PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
+ mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
mCallback);
View view = verifyWmAddViewAndAttachToParent();
@@ -171,7 +219,7 @@ public class ToastUITest extends SysuiTestCase {
@Test
public void testHideToast_finishesToken() throws Exception {
- mToastUI.showToast(PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
+ mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
mCallback);
mToastUI.hideToast(PACKAGE_NAME_1, TOKEN_1);
@@ -181,7 +229,7 @@ public class ToastUITest extends SysuiTestCase {
@Test
public void testHideToast_callsCallback() throws Exception {
- mToastUI.showToast(PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
+ mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
mCallback);
mToastUI.hideToast(PACKAGE_NAME_1, TOKEN_1);
@@ -191,7 +239,7 @@ public class ToastUITest extends SysuiTestCase {
@Test
public void testHideToast_whenNotCurrentToastToken_doesNotHideToast() throws Exception {
- mToastUI.showToast(PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
+ mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
mCallback);
mToastUI.hideToast(PACKAGE_NAME_1, TOKEN_2);
@@ -201,7 +249,7 @@ public class ToastUITest extends SysuiTestCase {
@Test
public void testHideToast_whenNotCurrentToastPackage_doesNotHideToast() throws Exception {
- mToastUI.showToast(PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
+ mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
mCallback);
mToastUI.hideToast(PACKAGE_NAME_2, TOKEN_1);
@@ -211,11 +259,12 @@ public class ToastUITest extends SysuiTestCase {
@Test
public void testShowToast_afterShowToast_hidesCurrentToast() throws Exception {
- mToastUI.showToast(PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
+ mToastUI.showToast(UID_1, PACKAGE_NAME_1, TOKEN_1, TEXT, WINDOW_TOKEN_1, Toast.LENGTH_LONG,
mCallback);
View view = verifyWmAddViewAndAttachToParent();
- mToastUI.showToast(PACKAGE_NAME_2, TOKEN_2, TEXT, WINDOW_TOKEN_2, Toast.LENGTH_LONG, null);
+ mToastUI.showToast(UID_2, PACKAGE_NAME_2, TOKEN_2, TEXT, WINDOW_TOKEN_2, Toast.LENGTH_LONG,
+ null);
verify(mWindowManager).removeViewImmediate(view);
verify(mNotificationManager).finishToken(PACKAGE_NAME_1, TOKEN_1);
@@ -227,8 +276,15 @@ public class ToastUITest extends SysuiTestCase {
verify(mWindowManager).addView(viewCaptor.capture(), any());
View view = viewCaptor.getValue();
// Simulate attaching to view hierarchy
- ViewGroup parent = new FrameLayout(mContext);
+ ViewGroup parent = new FrameLayout(mContextSpy);
parent.addView(view);
return view;
}
+
+ private Answer<Void> writeArgumentToParcel(int i, Parcel dest) {
+ return inv -> {
+ inv.<Parcelable>getArgument(i).writeToParcel(dest, 0);
+ return null;
+ };
+ }
}
diff --git a/packages/Tethering/src/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java
index c5478d2e1a14..5b6fe91b9c1a 100644
--- a/packages/Tethering/src/android/net/ip/IpServer.java
+++ b/packages/Tethering/src/android/net/ip/IpServer.java
@@ -33,6 +33,7 @@ import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.MacAddress;
import android.net.RouteInfo;
+import android.net.TetherOffloadRuleParcel;
import android.net.TetheredClient;
import android.net.TetheringManager;
import android.net.TetheringRequestParcel;
@@ -40,7 +41,7 @@ import android.net.dhcp.DhcpLeaseParcelable;
import android.net.dhcp.DhcpServerCallbacks;
import android.net.dhcp.DhcpServingParamsParcel;
import android.net.dhcp.DhcpServingParamsParcelExt;
-import android.net.dhcp.IDhcpLeaseCallbacks;
+import android.net.dhcp.IDhcpEventCallbacks;
import android.net.dhcp.IDhcpServer;
import android.net.ip.IpNeighborMonitor.NeighborEvent;
import android.net.ip.RouterAdvertisementDaemon.RaParams;
@@ -279,6 +280,19 @@ public class IpServer extends StateMachine {
return new Ipv6ForwardingRule(newUpstreamIfindex, downstreamIfindex, address, srcMac,
dstMac);
}
+
+ // Don't manipulate TetherOffloadRuleParcel directly because implementing onNewUpstream()
+ // would be error-prone due to generated stable AIDL classes not having a copy constructor.
+ public TetherOffloadRuleParcel toTetherOffloadRuleParcel() {
+ final TetherOffloadRuleParcel parcel = new TetherOffloadRuleParcel();
+ parcel.inputInterfaceIndex = upstreamIfindex;
+ parcel.outputInterfaceIndex = downstreamIfindex;
+ parcel.destination = address.getAddress();
+ parcel.prefixLength = 128;
+ parcel.srcL2Address = srcMac.toByteArray();
+ parcel.dstL2Address = dstMac.toByteArray();
+ return parcel;
+ }
}
private final LinkedHashMap<Inet6Address, Ipv6ForwardingRule> mIpv6ForwardingRules =
new LinkedHashMap<>();
@@ -448,7 +462,7 @@ public class IpServer extends StateMachine {
}
}
- private class DhcpLeaseCallback extends IDhcpLeaseCallbacks.Stub {
+ private class DhcpLeaseCallback extends IDhcpEventCallbacks.Stub {
@Override
public void onLeasesChanged(List<DhcpLeaseParcelable> leaseParcelables) {
final ArrayList<TetheredClient> leases = new ArrayList<>();
@@ -482,6 +496,11 @@ public class IpServer extends StateMachine {
}
@Override
+ public void onNewPrefixRequest(IpPrefix currentPrefix) {
+ //TODO: add specific implementation.
+ }
+
+ @Override
public int getInterfaceVersion() {
return this.VERSION;
}
@@ -815,9 +834,7 @@ public class IpServer extends StateMachine {
private void addIpv6ForwardingRule(Ipv6ForwardingRule rule) {
try {
- mNetd.tetherRuleAddDownstreamIpv6(mInterfaceParams.index, rule.upstreamIfindex,
- rule.address.getAddress(), mInterfaceParams.macAddr.toByteArray(),
- rule.dstMac.toByteArray());
+ mNetd.tetherOffloadRuleAdd(rule.toTetherOffloadRuleParcel());
mIpv6ForwardingRules.put(rule.address, rule);
} catch (RemoteException | ServiceSpecificException e) {
mLog.e("Could not add IPv6 downstream rule: ", e);
@@ -826,7 +843,7 @@ public class IpServer extends StateMachine {
private void removeIpv6ForwardingRule(Ipv6ForwardingRule rule, boolean removeFromMap) {
try {
- mNetd.tetherRuleRemoveDownstreamIpv6(rule.upstreamIfindex, rule.address.getAddress());
+ mNetd.tetherOffloadRuleRemove(rule.toTetherOffloadRuleParcel());
if (removeFromMap) {
mIpv6ForwardingRules.remove(rule.address);
}
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java b/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java
index bd60594f27bc..639cf65d7936 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java
@@ -20,6 +20,7 @@ import static android.net.TetheringConstants.EXTRA_ADD_TETHER_TYPE;
import static android.net.TetheringConstants.EXTRA_PROVISION_CALLBACK;
import static android.net.TetheringConstants.EXTRA_RUN_PROVISION;
import static android.net.TetheringManager.TETHERING_BLUETOOTH;
+import static android.net.TetheringManager.TETHERING_ETHERNET;
import static android.net.TetheringManager.TETHERING_INVALID;
import static android.net.TetheringManager.TETHERING_USB;
import static android.net.TetheringManager.TETHERING_WIFI;
@@ -537,6 +538,7 @@ public class EntitlementManager {
private static boolean isValidDownstreamType(int type) {
switch (type) {
case TETHERING_BLUETOOTH:
+ case TETHERING_ETHERNET:
case TETHERING_USB:
case TETHERING_WIFI:
return true;
@@ -650,6 +652,11 @@ public class EntitlementManager {
private void handleRequestLatestTetheringEntitlementValue(int downstream,
ResultReceiver receiver, boolean showEntitlementUi) {
+ if (!isValidDownstreamType(downstream)) {
+ receiver.send(TETHER_ERROR_ENTITLEMENT_UNKNOWN, null);
+ return;
+ }
+
final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
if (!isTetherProvisioningRequired(config)) {
receiver.send(TETHER_ERROR_NO_ERROR, null);
diff --git a/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java b/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
index 843a4f19c3b8..dbd68ef77cb7 100644
--- a/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
+++ b/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
@@ -18,6 +18,7 @@ package android.net;
import static android.Manifest.permission.MANAGE_TEST_NETWORKS;
import static android.Manifest.permission.NETWORK_SETTINGS;
+import static android.net.TetheringManager.TETHERING_ETHERNET;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -57,14 +58,17 @@ import org.junit.runner.RunWith;
import java.io.FileDescriptor;
import java.net.Inet4Address;
+import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.util.Collection;
import java.util.List;
import java.util.Random;
+import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
@RunWith(AndroidJUnit4.class)
@MediumTest
@@ -109,7 +113,7 @@ public class EthernetTetheringTest {
}
private void cleanUp() throws Exception {
- mTm.stopTethering(TetheringManager.TETHERING_ETHERNET);
+ mTm.stopTethering(TETHERING_ETHERNET);
if (mTetheringEventCallback != null) {
mTetheringEventCallback.awaitInterfaceUntethered();
mTetheringEventCallback.unregister();
@@ -150,10 +154,7 @@ public class EthernetTetheringTest {
Log.d(TAG, "Including test interfaces");
mEm.setIncludeTestInterfaces(true);
- Log.d(TAG, "Requesting tethered interface");
- mTetheredInterfaceRequester.requestInterface();
-
- final String iface = mTetheredInterfaceRequester.awaitRequestedInterface();
+ final String iface = mTetheredInterfaceRequester.getInterface();
assertEquals("TetheredInterfaceCallback for unexpected interface",
mTestIface.getInterfaceName(), iface);
@@ -165,14 +166,13 @@ public class EthernetTetheringTest {
// This test requires manipulating packets. Skip if there is a physical Ethernet connected.
assumeFalse(mEm.isAvailable());
- Log.d(TAG, "Requesting tethered interface");
- mTetheredInterfaceRequester.requestInterface();
+ CompletableFuture<String> futureIface = mTetheredInterfaceRequester.requestInterface();
mEm.setIncludeTestInterfaces(true);
mTestIface = createTestInterface();
- final String iface = mTetheredInterfaceRequester.awaitRequestedInterface();
+ final String iface = futureIface.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
assertEquals("TetheredInterfaceCallback for unexpected interface",
mTestIface.getInterfaceName(), iface);
@@ -180,12 +180,54 @@ public class EthernetTetheringTest {
}
@Test
+ public void testStaticIpv4() throws Exception {
+ assumeFalse(mEm.isAvailable());
+
+ mEm.setIncludeTestInterfaces(true);
+
+ mTestIface = createTestInterface();
+
+ final String iface = mTetheredInterfaceRequester.getInterface();
+ assertEquals("TetheredInterfaceCallback for unexpected interface",
+ mTestIface.getInterfaceName(), iface);
+
+ assertInvalidStaticIpv4Request(iface, null, null);
+ assertInvalidStaticIpv4Request(iface, "2001:db8::1/64", "2001:db8:2::/64");
+ assertInvalidStaticIpv4Request(iface, "192.0.2.2/28", "2001:db8:2::/28");
+ assertInvalidStaticIpv4Request(iface, "2001:db8:2::/28", "192.0.2.2/28");
+ assertInvalidStaticIpv4Request(iface, "192.0.2.2/28", null);
+ assertInvalidStaticIpv4Request(iface, null, "192.0.2.2/28");
+ assertInvalidStaticIpv4Request(iface, "192.0.2.3/27", "192.0.2.2/28");
+
+ final String localAddr = "192.0.2.3/28";
+ final String clientAddr = "192.0.2.2/28";
+ mTetheringEventCallback = enableEthernetTethering(iface,
+ requestWithStaticIpv4(localAddr, clientAddr));
+
+ mTetheringEventCallback.awaitInterfaceTethered();
+ assertInterfaceHasIpAddress(iface, clientAddr);
+
+ byte[] client1 = MacAddress.fromString("1:2:3:4:5:6").toByteArray();
+ byte[] client2 = MacAddress.fromString("a:b:c:d:e:f").toByteArray();
+
+ FileDescriptor fd = mTestIface.getFileDescriptor().getFileDescriptor();
+ mTapPacketReader = makePacketReader(fd, getMTU(mTestIface));
+ DhcpResults dhcpResults = runDhcp(fd, client1);
+ assertEquals(new LinkAddress(clientAddr), dhcpResults.ipAddress);
+
+ try {
+ runDhcp(fd, client2);
+ fail("Only one client should get an IP address");
+ } catch (TimeoutException expected) { }
+
+ }
+
+ @Test
public void testPhysicalEthernet() throws Exception {
assumeTrue(mEm.isAvailable());
// Get an interface to use.
- mTetheredInterfaceRequester.requestInterface();
- String iface = mTetheredInterfaceRequester.awaitRequestedInterface();
+ final String iface = mTetheredInterfaceRequester.getInterface();
// Enable Ethernet tethering and check that it starts.
mTetheringEventCallback = enableEthernetTethering(iface);
@@ -275,7 +317,8 @@ public class EthernetTetheringTest {
}
}
- private MyTetheringEventCallback enableEthernetTethering(String iface) throws Exception {
+ private MyTetheringEventCallback enableEthernetTethering(String iface,
+ TetheringRequest request) throws Exception {
MyTetheringEventCallback callback = new MyTetheringEventCallback(mTm, iface);
mTm.registerTetheringEventCallback(mHandler::post, callback);
@@ -286,34 +329,37 @@ public class EthernetTetheringTest {
}
};
Log.d(TAG, "Starting Ethernet tethering");
- mTm.startTethering(
- new TetheringRequest.Builder(TetheringManager.TETHERING_ETHERNET).build(),
- mHandler::post /* executor */, startTetheringCallback);
+ mTm.startTethering(request, mHandler::post /* executor */, startTetheringCallback);
callback.awaitInterfaceTethered();
return callback;
}
+ private MyTetheringEventCallback enableEthernetTethering(String iface) throws Exception {
+ return enableEthernetTethering(iface,
+ new TetheringRequest.Builder(TETHERING_ETHERNET).build());
+ }
+
private int getMTU(TestNetworkInterface iface) throws SocketException {
NetworkInterface nif = NetworkInterface.getByName(iface.getInterfaceName());
assertNotNull("Can't get NetworkInterface object for " + iface.getInterfaceName(), nif);
return nif.getMTU();
}
- private void checkVirtualEthernet(TestNetworkInterface iface, int mtu) throws Exception {
- FileDescriptor fd = iface.getFileDescriptor().getFileDescriptor();
- mTapPacketReader = new TapPacketReader(mHandler, fd, mtu);
- mHandler.post(() -> mTapPacketReader.start());
+ private TapPacketReader makePacketReader(FileDescriptor fd, int mtu) {
+ final TapPacketReader reader = new TapPacketReader(mHandler, fd, mtu);
+ mHandler.post(() -> reader.start());
HandlerUtilsKt.waitForIdle(mHandler, TIMEOUT_MS);
+ return reader;
+ }
+ private void checkVirtualEthernet(TestNetworkInterface iface, int mtu) throws Exception {
+ FileDescriptor fd = iface.getFileDescriptor().getFileDescriptor();
+ mTapPacketReader = makePacketReader(fd, mtu);
mTetheringEventCallback = enableEthernetTethering(iface.getInterfaceName());
checkTetheredClientCallbacks(fd);
}
- private void checkTetheredClientCallbacks(FileDescriptor fd) throws Exception {
- // Create a fake client.
- byte[] clientMacAddr = new byte[6];
- new Random().nextBytes(clientMacAddr);
-
+ private DhcpResults runDhcp(FileDescriptor fd, byte[] clientMacAddr) throws Exception {
// We have to retransmit DHCP requests because IpServer declares itself to be ready before
// its DhcpServer is actually started. TODO: fix this race and remove this loop.
DhcpPacket offerPacket = null;
@@ -323,13 +369,25 @@ public class EthernetTetheringTest {
offerPacket = getNextDhcpPacket();
if (offerPacket instanceof DhcpOfferPacket) break;
}
- assertTrue("No DHCPOFFER received on interface within timeout",
- offerPacket instanceof DhcpOfferPacket);
+ if (!(offerPacket instanceof DhcpOfferPacket)) {
+ throw new TimeoutException("No DHCPOFFER received on interface within timeout");
+ }
sendDhcpRequest(fd, offerPacket, clientMacAddr);
DhcpPacket ackPacket = getNextDhcpPacket();
- assertTrue("No DHCPACK received on interface within timeout",
- ackPacket instanceof DhcpAckPacket);
+ if (!(ackPacket instanceof DhcpAckPacket)) {
+ throw new TimeoutException("No DHCPACK received on interface within timeout");
+ }
+
+ return ackPacket.toDhcpResults();
+ }
+
+ private void checkTetheredClientCallbacks(FileDescriptor fd) throws Exception {
+ // Create a fake client.
+ byte[] clientMacAddr = new byte[6];
+ new Random().nextBytes(clientMacAddr);
+
+ DhcpResults dhcpResults = runDhcp(fd, clientMacAddr);
final Collection<TetheredClient> clients = mTetheringEventCallback.awaitClientConnected();
assertEquals(1, clients.size());
@@ -337,7 +395,7 @@ public class EthernetTetheringTest {
// Check the MAC address.
assertEquals(MacAddress.fromBytes(clientMacAddr), client.getMacAddress());
- assertEquals(TetheringManager.TETHERING_ETHERNET, client.getTetheringType());
+ assertEquals(TETHERING_ETHERNET, client.getTetheringType());
// Check the hostname.
assertEquals(1, client.getAddresses().size());
@@ -345,7 +403,6 @@ public class EthernetTetheringTest {
assertEquals(DHCP_HOSTNAME, info.getHostname());
// Check the address is the one that was handed out in the DHCP ACK.
- DhcpResults dhcpResults = offerPacket.toDhcpResults();
assertLinkAddressMatches(dhcpResults.ipAddress, info.getAddress());
// Check that the lifetime is correct +/- 10s.
@@ -373,8 +430,8 @@ public class EthernetTetheringTest {
private final Handler mHandler;
private final EthernetManager mEm;
- private volatile TetheredInterfaceRequest mRequest;
- private volatile String mIface;
+ private TetheredInterfaceRequest mRequest;
+ private final CompletableFuture<String> mFuture = new CompletableFuture<>();
TetheredInterfaceRequester(Handler handler, EthernetManager em) {
mHandler = handler;
@@ -384,25 +441,28 @@ public class EthernetTetheringTest {
@Override
public void onAvailable(String iface) {
Log.d(TAG, "Ethernet interface available: " + iface);
- mIface = iface;
- mInterfaceAvailableLatch.countDown();
+ mFuture.complete(iface);
}
+
@Override
- public void onUnavailable() {}
+ public void onUnavailable() {
+ mFuture.completeExceptionally(new IllegalStateException("onUnavailable received"));
+ }
- public void requestInterface() {
+ public CompletableFuture<String> requestInterface() {
assertNull("BUG: more than one tethered interface request", mRequest);
+ Log.d(TAG, "Requesting tethered interface");
mRequest = mEm.requestTetheredInterface(mHandler::post, this);
+ return mFuture;
}
- public String awaitRequestedInterface() throws InterruptedException {
- assertTrue("No tethered interface available after " + TIMEOUT_MS + "ms",
- mInterfaceAvailableLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
- return mIface;
+ public String getInterface() throws Exception {
+ return requestInterface().get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
}
public void release() {
if (mRequest != null) {
+ mFuture.obtrudeException(new IllegalStateException("Request already released"));
mRequest.release();
mRequest = null;
}
@@ -442,6 +502,34 @@ public class EthernetTetheringTest {
assertEquals("LinkAddress scope does not match", l1.getScope(), l2.getScope());
}
+ private TetheringRequest requestWithStaticIpv4(String local, String client) {
+ LinkAddress localAddr = local == null ? null : new LinkAddress(local);
+ LinkAddress clientAddr = client == null ? null : new LinkAddress(client);
+ return new TetheringRequest.Builder(TETHERING_ETHERNET)
+ .setStaticIpv4Addresses(localAddr, clientAddr).build();
+ }
+
+ private void assertInvalidStaticIpv4Request(String iface, String local, String client)
+ throws Exception {
+ try {
+ enableEthernetTethering(iface, requestWithStaticIpv4(local, client));
+ fail("Unexpectedly accepted invalid IPv4 configuration: " + local + ", " + client);
+ } catch (IllegalArgumentException | NullPointerException expected) { }
+ }
+
+ private void assertInterfaceHasIpAddress(String iface, String expected) throws Exception {
+ LinkAddress expectedAddr = new LinkAddress(expected);
+ NetworkInterface nif = NetworkInterface.getByName(iface);
+ for (InterfaceAddress ia : nif.getInterfaceAddresses()) {
+ final LinkAddress addr = new LinkAddress(ia.getAddress(), ia.getNetworkPrefixLength());
+ if (expectedAddr.equals(addr)) {
+ return;
+ }
+ }
+ fail("Expected " + iface + " to have IP address " + expected + ", found "
+ + nif.getInterfaceAddresses());
+ }
+
private TestNetworkInterface createTestInterface() throws Exception {
TestNetworkManager tnm = mContext.getSystemService(TestNetworkManager.class);
TestNetworkInterface iface = tnm.createTapInterface();
diff --git a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
index 3106e0e5e1c6..fdfdae837d51 100644
--- a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
+++ b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
@@ -43,7 +43,6 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doAnswer;
@@ -66,6 +65,7 @@ import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.MacAddress;
import android.net.RouteInfo;
+import android.net.TetherOffloadRuleParcel;
import android.net.dhcp.DhcpServingParamsParcel;
import android.net.dhcp.IDhcpServer;
import android.net.dhcp.IDhcpServerCallbacks;
@@ -85,6 +85,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatcher;
import org.mockito.Captor;
import org.mockito.InOrder;
import org.mockito.Mock;
@@ -92,6 +93,7 @@ import org.mockito.MockitoAnnotations;
import java.net.Inet4Address;
import java.net.InetAddress;
+import java.util.Arrays;
@RunWith(AndroidJUnit4.class)
@SmallTest
@@ -514,6 +516,65 @@ public class IpServerTest {
mLooper.dispatchAll();
}
+ /**
+ * Custom ArgumentMatcher for TetherOffloadRuleParcel. This is needed because generated stable
+ * AIDL classes don't have equals(), so we cannot just use eq(). A custom assert, such as:
+ *
+ * private void checkFooCalled(StableParcelable p, ...) {
+ * ArgumentCaptor<FooParam> captor = ArgumentCaptor.forClass(FooParam.class);
+ * verify(mMock).foo(captor.capture());
+ * Foo foo = captor.getValue();
+ * assertFooMatchesExpectations(foo);
+ * }
+ *
+ * almost works, but not quite. This is because if the code under test calls foo() twice, the
+ * first call to checkFooCalled() matches both the calls, putting both calls into the captor,
+ * and then fails with TooManyActualInvocations. It also makes it harder to use other mockito
+ * features such as never(), inOrder(), etc.
+ *
+ * This approach isn't great because if the match fails, the error message is unhelpful
+ * (actual: "android.net.TetherOffloadRuleParcel@8c827b0" or some such), but at least it does
+ * work.
+ *
+ * See ConnectivityServiceTest#assertRoutesAdded for an alternative approach which solves the
+ * TooManyActualInvocations problem described above by forcing the caller of the custom assert
+ * method to specify all expected invocations in one call. This is useful when the stable
+ * parcelable class being asserted on has a corresponding Java object (eg., RouteInfo and
+ * RouteInfoParcelable), and the caller can just pass in a list of them. It not useful here
+ * because there is no such object.
+ */
+ private static class TetherOffloadRuleParcelMatcher implements
+ ArgumentMatcher<TetherOffloadRuleParcel> {
+ public final int upstreamIfindex;
+ public final InetAddress dst;
+ public final MacAddress dstMac;
+
+ TetherOffloadRuleParcelMatcher(int upstreamIfindex, InetAddress dst, MacAddress dstMac) {
+ this.upstreamIfindex = upstreamIfindex;
+ this.dst = dst;
+ this.dstMac = dstMac;
+ }
+
+ public boolean matches(TetherOffloadRuleParcel parcel) {
+ return upstreamIfindex == parcel.inputInterfaceIndex
+ && (TEST_IFACE_PARAMS.index == parcel.outputInterfaceIndex)
+ && Arrays.equals(dst.getAddress(), parcel.destination)
+ && (128 == parcel.prefixLength)
+ && Arrays.equals(TEST_IFACE_PARAMS.macAddr.toByteArray(), parcel.srcL2Address)
+ && Arrays.equals(dstMac.toByteArray(), parcel.dstL2Address);
+ }
+
+ public String toString() {
+ return String.format("TetherOffloadRuleParcelMatcher(%d, %s, %s",
+ upstreamIfindex, dst.getHostAddress(), dstMac);
+ }
+ }
+
+ private TetherOffloadRuleParcel matches(
+ int upstreamIfindex, InetAddress dst, MacAddress dstMac) {
+ return argThat(new TetherOffloadRuleParcelMatcher(upstreamIfindex, dst, dstMac));
+ }
+
@Test
public void addRemoveipv6ForwardingRules() throws Exception {
initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */);
@@ -537,13 +598,11 @@ public class IpServerTest {
// Events on this interface are received and sent to netd.
recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA);
- verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX),
- eq(neighA.getAddress()), eq(myMac.toByteArray()), eq(macA.toByteArray()));
+ verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighA, macA));
reset(mNetd);
recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB);
- verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX),
- eq(neighB.getAddress()), eq(myMac.toByteArray()), eq(macB.toByteArray()));
+ verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighB, macB));
reset(mNetd);
// Link-local and multicast neighbors are ignored.
@@ -554,12 +613,12 @@ public class IpServerTest {
// A neighbor that is no longer valid causes the rule to be removed.
recvNewNeigh(myIfindex, neighA, NUD_FAILED, macA);
- verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX), eq(neighA.getAddress()));
+ verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighA, macA));
reset(mNetd);
// A neighbor that is deleted causes the rule to be removed.
recvDelNeigh(myIfindex, neighB, NUD_STALE, macB);
- verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX), eq(neighB.getAddress()));
+ verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macB));
reset(mNetd);
// Upstream changes result in deleting and re-adding the rules.
@@ -571,22 +630,16 @@ public class IpServerTest {
LinkProperties lp = new LinkProperties();
lp.setInterfaceName(UPSTREAM_IFACE2);
dispatchTetherConnectionChanged(UPSTREAM_IFACE2, lp);
- inOrder.verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX2),
- eq(neighA.getAddress()), eq(myMac.toByteArray()), eq(macA.toByteArray()));
- inOrder.verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX),
- eq(neighA.getAddress()));
- inOrder.verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX2),
- eq(neighB.getAddress()), eq(myMac.toByteArray()), eq(macB.toByteArray()));
- inOrder.verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX),
- eq(neighB.getAddress()));
+ inOrder.verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX2, neighA, macA));
+ inOrder.verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighA, macA));
+ inOrder.verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX2, neighB, macB));
+ inOrder.verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macB));
reset(mNetd);
// When the upstream is lost, rules are removed.
dispatchTetherConnectionChanged(null, null);
- verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX2),
- eq(neighA.getAddress()));
- verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX2),
- eq(neighB.getAddress()));
+ verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX2, neighA, macA));
+ verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX2, neighB, macB));
reset(mNetd);
// If the upstream is IPv4-only, no rules are added.
@@ -599,31 +652,27 @@ public class IpServerTest {
lp.setInterfaceName(UPSTREAM_IFACE);
dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp);
recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB);
- verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX),
- eq(neighB.getAddress()), eq(myMac.toByteArray()), eq(macB.toByteArray()));
- verify(mNetd, never()).tetherRuleAddDownstreamIpv6(anyInt(), anyInt(),
- eq(neighA.getAddress()), any(), any());
+ verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighB, macB));
+ verify(mNetd, never()).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighA, macA));
// If upstream IPv6 connectivity is lost, rules are removed.
reset(mNetd);
dispatchTetherConnectionChanged(UPSTREAM_IFACE, null);
- verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX), eq(neighB.getAddress()));
+ verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macB));
// When the interface goes down, rules are removed.
lp.setInterfaceName(UPSTREAM_IFACE);
dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp);
recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA);
recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB);
- verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX),
- eq(neighA.getAddress()), eq(myMac.toByteArray()), eq(macA.toByteArray()));
- verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX),
- eq(neighB.getAddress()), eq(myMac.toByteArray()), eq(macB.toByteArray()));
+ verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighA, macA));
+ verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighB, macB));
reset(mNetd);
mIpServer.stop();
mLooper.dispatchAll();
- verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX), eq(neighA.getAddress()));
- verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX), eq(neighB.getAddress()));
+ verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighA, macA));
+ verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macB));
reset(mNetd);
}
diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java
index 0a7850b68014..b3a30abca6f1 100644
--- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java
+++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java
@@ -17,8 +17,10 @@
package com.android.server.connectivity.tethering;
import static android.net.TetheringManager.TETHERING_BLUETOOTH;
+import static android.net.TetheringManager.TETHERING_ETHERNET;
import static android.net.TetheringManager.TETHERING_USB;
import static android.net.TetheringManager.TETHERING_WIFI;
+import static android.net.TetheringManager.TETHERING_WIFI_P2P;
import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKNOWN;
import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
import static android.net.TetheringManager.TETHER_ERROR_PROVISIONING_FAILED;
@@ -353,6 +355,20 @@ public final class EntitlementManagerTest {
callbackTimeoutHelper(mCallbacklatch);
assertEquals(0, mEnMgr.uiProvisionCount);
mEnMgr.reset();
+ // 8. Test get value for invalid downstream type.
+ mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
+ receiver = new ResultReceiver(null) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ assertEquals(TETHER_ERROR_ENTITLEMENT_UNKNOWN, resultCode);
+ mCallbacklatch.countDown();
+ }
+ };
+ mEnMgr.requestLatestTetheringEntitlementResult(TETHERING_WIFI_P2P, receiver, true);
+ mLooper.dispatchAll();
+ callbackTimeoutHelper(mCallbacklatch);
+ assertEquals(0, mEnMgr.uiProvisionCount);
+ mEnMgr.reset();
}
void callbackTimeoutHelper(final CountDownLatch latch) throws Exception {
@@ -471,6 +487,22 @@ public final class EntitlementManagerTest {
mLooper.dispatchAll();
assertEquals(0, mEnMgr.uiProvisionCount);
assertEquals(3, mEnMgr.silentProvisionCount);
+ assertFalse(mEnMgr.isCellularUpstreamPermitted());
+ mEnMgr.reset();
+ // 7. start ui provisioning, upstream is mobile, downstream is ethernet
+ mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
+ mEnMgr.startProvisioningIfNeeded(TETHERING_ETHERNET, true);
+ mLooper.dispatchAll();
+ assertEquals(1, mEnMgr.uiProvisionCount);
+ assertEquals(0, mEnMgr.silentProvisionCount);
+ assertTrue(mEnMgr.isCellularUpstreamPermitted());
+ mEnMgr.reset();
+ // 8. downstream is invalid
+ mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
+ mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI_P2P, true);
+ mLooper.dispatchAll();
+ assertEquals(0, mEnMgr.uiProvisionCount);
+ assertEquals(0, mEnMgr.silentProvisionCount);
mEnMgr.reset();
}
diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/IPv6TetheringCoordinatorTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/IPv6TetheringCoordinatorTest.java
new file mode 100644
index 000000000000..912124357ca8
--- /dev/null
+++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/IPv6TetheringCoordinatorTest.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2020 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.connectivity.tethering;
+
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.RouteInfo.RTN_UNICAST;
+import static android.net.ip.IpServer.STATE_LOCAL_ONLY;
+import static android.net.ip.IpServer.STATE_TETHERED;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import android.net.InetAddresses;
+import android.net.IpPrefix;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.RouteInfo;
+import android.net.ip.IpServer;
+import android.net.util.SharedLog;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class IPv6TetheringCoordinatorTest {
+ private static final String TEST_DNS_SERVER = "2001:4860:4860::8888";
+ private static final String TEST_INTERFACE = "test_rmnet0";
+ private static final String TEST_IPV6_ADDRESS = "2001:db8::1/64";
+ private static final String TEST_IPV4_ADDRESS = "192.168.100.1/24";
+
+ private IPv6TetheringCoordinator mIPv6TetheringCoordinator;
+ private ArrayList<IpServer> mNotifyList;
+
+ @Mock private SharedLog mSharedLog;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ when(mSharedLog.forSubComponent(anyString())).thenReturn(mSharedLog);
+ mNotifyList = new ArrayList<IpServer>();
+ mIPv6TetheringCoordinator = new IPv6TetheringCoordinator(mNotifyList, mSharedLog);
+ }
+
+ private UpstreamNetworkState createDualStackUpstream(final int transportType) {
+ final Network network = mock(Network.class);
+ final NetworkCapabilities netCap =
+ new NetworkCapabilities.Builder().addTransportType(transportType).build();
+ final InetAddress dns = InetAddresses.parseNumericAddress(TEST_DNS_SERVER);
+ final LinkProperties linkProp = new LinkProperties();
+ linkProp.setInterfaceName(TEST_INTERFACE);
+ linkProp.addLinkAddress(new LinkAddress(TEST_IPV6_ADDRESS));
+ linkProp.addLinkAddress(new LinkAddress(TEST_IPV4_ADDRESS));
+ linkProp.addRoute(new RouteInfo(new IpPrefix("::/0"), null, TEST_INTERFACE, RTN_UNICAST));
+ linkProp.addRoute(new RouteInfo(new IpPrefix("0.0.0.0/0"), null, TEST_INTERFACE,
+ RTN_UNICAST));
+ linkProp.addDnsServer(dns);
+ return new UpstreamNetworkState(linkProp, netCap, network);
+ }
+
+ private void assertOnlyOneV6AddressAndNoV4(LinkProperties lp) {
+ assertEquals(lp.getInterfaceName(), TEST_INTERFACE);
+ assertFalse(lp.hasIpv4Address());
+ final List<LinkAddress> addresses = lp.getLinkAddresses();
+ assertEquals(addresses.size(), 1);
+ final LinkAddress v6Address = addresses.get(0);
+ assertEquals(v6Address, new LinkAddress(TEST_IPV6_ADDRESS));
+ }
+
+ @Test
+ public void testUpdateIpv6Upstream() throws Exception {
+ // 1. Add first IpServer.
+ final IpServer firstServer = mock(IpServer.class);
+ mNotifyList.add(firstServer);
+ mIPv6TetheringCoordinator.addActiveDownstream(firstServer, STATE_TETHERED);
+ verify(firstServer).sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0, null);
+ verifyNoMoreInteractions(firstServer);
+
+ // 2. Add second IpServer and it would not have ipv6 tethering.
+ final IpServer secondServer = mock(IpServer.class);
+ mNotifyList.add(secondServer);
+ mIPv6TetheringCoordinator.addActiveDownstream(secondServer, STATE_LOCAL_ONLY);
+ verifyNoMoreInteractions(secondServer);
+ reset(firstServer, secondServer);
+
+ // 3. No upstream.
+ mIPv6TetheringCoordinator.updateUpstreamNetworkState(null);
+ verify(secondServer).sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0, null);
+ reset(firstServer, secondServer);
+
+ // 4. Update ipv6 mobile upstream.
+ final UpstreamNetworkState mobileUpstream = createDualStackUpstream(TRANSPORT_CELLULAR);
+ final ArgumentCaptor<LinkProperties> lp = ArgumentCaptor.forClass(LinkProperties.class);
+ mIPv6TetheringCoordinator.updateUpstreamNetworkState(mobileUpstream);
+ verify(firstServer).sendMessage(eq(IpServer.CMD_IPV6_TETHER_UPDATE), eq(0), eq(0),
+ lp.capture());
+ final LinkProperties v6OnlyLink = lp.getValue();
+ assertOnlyOneV6AddressAndNoV4(v6OnlyLink);
+ verifyNoMoreInteractions(firstServer);
+ verifyNoMoreInteractions(secondServer);
+ reset(firstServer, secondServer);
+
+ // 5. Remove first IpServer.
+ mNotifyList.remove(firstServer);
+ mIPv6TetheringCoordinator.removeActiveDownstream(firstServer);
+ verify(firstServer).sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0, null);
+ verify(secondServer).sendMessage(eq(IpServer.CMD_IPV6_TETHER_UPDATE), eq(0), eq(0),
+ lp.capture());
+ final LinkProperties localOnlyLink = lp.getValue();
+ assertNotNull(localOnlyLink);
+ assertNotEquals(localOnlyLink, v6OnlyLink);
+ reset(firstServer, secondServer);
+
+ // 6. Remove second IpServer.
+ mNotifyList.remove(secondServer);
+ mIPv6TetheringCoordinator.removeActiveDownstream(secondServer);
+ verifyNoMoreInteractions(firstServer);
+ verify(secondServer).sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0, null);
+ }
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 1b180e3357d7..2100c1a8be44 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -197,7 +197,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
private final MainHandler mMainHandler;
- private final SystemActionPerformer mSystemActionPerformer;
+ // Lazily initialized - access through getSystemActionPerfomer()
+ private SystemActionPerformer mSystemActionPerformer;
private MagnificationController mMagnificationController;
@@ -295,8 +296,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
mActivityTaskManagerService = LocalServices.getService(ActivityTaskManagerInternal.class);
mPackageManager = mContext.getPackageManager();
mSecurityPolicy = new AccessibilitySecurityPolicy(mContext, this);
- mSystemActionPerformer =
- new SystemActionPerformer(mContext, mWindowManagerService, null, this);
mA11yWindowManager = new AccessibilityWindowManager(mLock, mMainHandler,
mWindowManagerService, this, mSecurityPolicy, this);
mA11yDisplayListener = new AccessibilityDisplayListener(mContext, mMainHandler);
@@ -667,7 +666,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
mSecurityPolicy.enforceCallerIsRecentsOrHasPermission(
Manifest.permission.MANAGE_ACCESSIBILITY,
FUNCTION_REGISTER_SYSTEM_ACTION);
- mSystemActionPerformer.registerSystemAction(actionId, action);
+ getSystemActionPerformer().registerSystemAction(actionId, action);
}
/**
@@ -680,7 +679,15 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
mSecurityPolicy.enforceCallerIsRecentsOrHasPermission(
Manifest.permission.MANAGE_ACCESSIBILITY,
FUNCTION_UNREGISTER_SYSTEM_ACTION);
- mSystemActionPerformer.unregisterSystemAction(actionId);
+ getSystemActionPerformer().unregisterSystemAction(actionId);
+ }
+
+ private SystemActionPerformer getSystemActionPerformer() {
+ if (mSystemActionPerformer == null) {
+ mSystemActionPerformer =
+ new SystemActionPerformer(mContext, mWindowManagerService, null, this);
+ }
+ return mSystemActionPerformer;
}
@Override
@@ -792,7 +799,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
synchronized (mLock) {
mUiAutomationManager.registerUiTestAutomationServiceLocked(owner, serviceClient,
mContext, accessibilityServiceInfo, sIdCounter++, mMainHandler,
- mSecurityPolicy, this, mWindowManagerService, mSystemActionPerformer,
+ mSecurityPolicy, this, mWindowManagerService, getSystemActionPerformer(),
mA11yWindowManager, flags);
onUserStateChangedLocked(getCurrentUserStateLocked());
}
@@ -1503,7 +1510,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
if (service == null) {
service = new AccessibilityServiceConnection(userState, mContext, componentName,
installedService, sIdCounter++, mMainHandler, mLock, mSecurityPolicy,
- this, mWindowManagerService, mSystemActionPerformer,
+ this, mWindowManagerService, getSystemActionPerformer(),
mA11yWindowManager, mActivityTaskManagerService);
} else if (userState.mBoundServices.contains(service)) {
continue;
@@ -2741,7 +2748,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
userState, mContext,
COMPONENT_NAME, info, sIdCounter++, mMainHandler, mLock, mSecurityPolicy,
AccessibilityManagerService.this, mWindowManagerService,
- mSystemActionPerformer, mA11yWindowManager, mActivityTaskManagerService) {
+ getSystemActionPerformer(), mA11yWindowManager, mActivityTaskManagerService) {
@Override
public boolean supportsFlagForNotImportantViews(AccessibilityServiceInfo info) {
return true;
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 2eaa766ad32d..8a1de1f0763e 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -3153,7 +3153,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
- nai.clatd.setNat64Prefix(prefix);
+ nai.clatd.setNat64PrefixFromDns(prefix);
handleUpdateLinkProperties(nai, new LinkProperties(nai.linkProperties));
}
@@ -5865,9 +5865,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
@NonNull LinkProperties oldLp) {
int netId = networkAgent.network.netId;
- // The NetworkAgentInfo does not know whether clatd is running on its network or not, or
- // whether there is a NAT64 prefix. Before we do anything else, make sure its LinkProperties
- // are accurate.
+ // The NetworkAgent does not know whether clatd is running on its network or not, or whether
+ // a NAT64 prefix was discovered by the DNS resolver. Before we do anything else, make sure
+ // the LinkProperties for the network are accurate.
networkAgent.clatd.fixupLinkProperties(oldLp, newLp);
updateInterfaces(newLp, oldLp, netId, networkAgent.networkCapabilities,
diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java
index d9e7c3851906..e77458cc955a 100644
--- a/services/core/java/com/android/server/PackageWatchdog.java
+++ b/services/core/java/com/android/server/PackageWatchdog.java
@@ -315,28 +315,31 @@ public class PackageWatchdog {
// causing any elapsed time to be deducted from all existing packages before we add new
// packages. This maintains the invariant that the elapsed time for ALL (new and existing)
// packages is the same.
- syncState("observing new packages");
+ mLongTaskHandler.post(() -> {
+ syncState("observing new packages");
- synchronized (mLock) {
- ObserverInternal oldObserver = mAllObservers.get(observer.getName());
- if (oldObserver == null) {
- Slog.d(TAG, observer.getName() + " started monitoring health "
- + "of packages " + packageNames);
- mAllObservers.put(observer.getName(),
- new ObserverInternal(observer.getName(), packages));
- } else {
- Slog.d(TAG, observer.getName() + " added the following "
- + "packages to monitor " + packageNames);
- oldObserver.updatePackagesLocked(packages);
+ synchronized (mLock) {
+ ObserverInternal oldObserver = mAllObservers.get(observer.getName());
+ if (oldObserver == null) {
+ Slog.d(TAG, observer.getName() + " started monitoring health "
+ + "of packages " + packageNames);
+ mAllObservers.put(observer.getName(),
+ new ObserverInternal(observer.getName(), packages));
+ } else {
+ Slog.d(TAG, observer.getName() + " added the following "
+ + "packages to monitor " + packageNames);
+ oldObserver.updatePackagesLocked(packages);
+ }
}
- }
- // Register observer in case not already registered
- registerHealthObserver(observer);
+ // Register observer in case not already registered
+ registerHealthObserver(observer);
+
+ // Sync after we add the new packages to the observers. We may have received packges
+ // requiring an earlier schedule than we are currently scheduled for.
+ syncState("updated observers");
+ });
- // Sync after we add the new packages to the observers. We may have received packges
- // requiring an earlier schedule than we are currently scheduled for.
- syncState("updated observers");
}
/**
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 7523710dde9f..21760cdf02eb 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1440,7 +1440,7 @@ public final class ActiveServices {
active.mPackageName = r.packageName;
active.mUid = r.appInfo.uid;
active.mShownWhileScreenOn = mScreenOn;
- if (r.app != null) {
+ if (r.app != null && r.app.uidRecord != null) {
active.mAppOnTop = active.mShownWhileTop =
r.app.uidRecord.getCurProcState()
<= ActivityManager.PROCESS_STATE_TOP;
diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java
index 3ecf87c6860f..ad73b6491697 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -382,8 +382,10 @@ public class FaceService extends BiometricServiceBase {
checkPermission(MANAGE_BIOMETRIC);
updateActiveGroup(userId, opPackageName);
- mNotificationManager.cancelAsUser(NOTIFICATION_TAG, NOTIFICATION_ID,
- UserHandle.CURRENT);
+ mHandler.post(() -> {
+ mNotificationManager.cancelAsUser(NOTIFICATION_TAG, NOTIFICATION_ID,
+ UserHandle.CURRENT);
+ });
final boolean restricted = isRestricted();
final EnrollClientImpl client = new EnrollClientImpl(getContext(), mDaemonWrapper,
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index 82465f8a093e..741cb5b41ea3 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -81,7 +81,7 @@ public class Nat464Xlat extends BaseNetworkObserver {
RUNNING, // start() called, and the stacked iface is known to be up.
}
- private IpPrefix mNat64Prefix;
+ private IpPrefix mNat64PrefixFromDns;
private String mBaseIface;
private String mIface;
private Inet6Address mIPv6Address;
@@ -100,7 +100,7 @@ public class Nat464Xlat extends BaseNetworkObserver {
* currently connected and where the NetworkAgent has not disabled 464xlat. It is the signal to
* enable NAT64 prefix discovery.
*
- * @param network the NetworkAgentInfo corresponding to the network.
+ * @param nai the NetworkAgentInfo corresponding to the network.
* @return true if the network requires clat, false otherwise.
*/
@VisibleForTesting
@@ -180,7 +180,7 @@ public class Nat464Xlat extends BaseNetworkObserver {
String addrStr = null;
try {
- addrStr = mNetd.clatdStart(baseIface, mNat64Prefix.toString());
+ addrStr = mNetd.clatdStart(baseIface, getNat64Prefix().toString());
} catch (RemoteException | ServiceSpecificException e) {
Slog.e(TAG, "Error starting clatd on " + baseIface + ": " + e);
}
@@ -213,12 +213,10 @@ public class Nat464Xlat extends BaseNetworkObserver {
}
mIface = null;
mBaseIface = null;
- mState = State.IDLE;
if (requiresClat(mNetwork)) {
mState = State.DISCOVERING;
} else {
stopPrefixDiscovery();
- mState = State.IDLE;
}
}
@@ -285,6 +283,7 @@ public class Nat464Xlat extends BaseNetworkObserver {
private void stopPrefixDiscovery() {
try {
mDnsResolver.stopPrefix64Discovery(getNetId());
+ mState = State.IDLE;
} catch (RemoteException | ServiceSpecificException e) {
Slog.e(TAG, "Error stopping prefix discovery on netId " + getNetId() + ": " + e);
}
@@ -294,32 +293,52 @@ public class Nat464Xlat extends BaseNetworkObserver {
* Starts/stops NAT64 prefix discovery and clatd as necessary.
*/
public void update() {
- // TODO: turn this class into a proper StateMachine. // http://b/126113090
- if (requiresClat(mNetwork)) {
- if (!isPrefixDiscoveryStarted()) {
- startPrefixDiscovery();
- } else if (shouldStartClat(mNetwork)) {
- // NAT64 prefix detected. Start clatd.
- // TODO: support the NAT64 prefix changing after it's been discovered. There is no
- // need to support this at the moment because it cannot happen without changes to
- // the Dns64Configuration code in netd.
- start();
- } else {
- // NAT64 prefix removed. Stop clatd and go back into DISCOVERING state.
- stop();
- }
- } else {
- // Network no longer requires clat. Stop clat and prefix discovery.
- if (isStarted()) {
- stop();
- } else if (isPrefixDiscoveryStarted()) {
- leaveStartedState();
- }
+ // TODO: turn this class into a proper StateMachine. http://b/126113090
+ switch (mState) {
+ case IDLE:
+ if (requiresClat(mNetwork)) {
+ // Network is detected to be IPv6-only.
+ // TODO: consider going to STARTING directly if the NAT64 prefix is already
+ // known. This would however result in clatd running without prefix discovery
+ // running, which might be a surprising combination.
+ startPrefixDiscovery(); // Enters DISCOVERING state.
+ return;
+ }
+ break;
+
+ case DISCOVERING:
+ if (shouldStartClat(mNetwork)) {
+ // NAT64 prefix detected. Start clatd.
+ start(); // Enters STARTING state.
+ return;
+ }
+ if (!requiresClat(mNetwork)) {
+ // IPv4 address added. Go back to IDLE state.
+ stopPrefixDiscovery();
+ return;
+ }
+ break;
+
+ case STARTING:
+ case RUNNING:
+ // NAT64 prefix removed, or IPv4 address added.
+ // Stop clatd and go back into DISCOVERING or idle.
+ if (!shouldStartClat(mNetwork)) {
+ stop();
+ }
+ break;
+ // TODO: support the NAT64 prefix changing after it's been discovered. There is
+ // no need to support this at the moment because it cannot happen without
+ // changes to the Dns64Configuration code in netd.
}
}
- public void setNat64Prefix(IpPrefix nat64Prefix) {
- mNat64Prefix = nat64Prefix;
+ private IpPrefix getNat64Prefix() {
+ return mNat64PrefixFromDns;
+ }
+
+ public void setNat64PrefixFromDns(IpPrefix prefix) {
+ mNat64PrefixFromDns = prefix;
}
/**
@@ -328,7 +347,7 @@ public class Nat464Xlat extends BaseNetworkObserver {
* has no idea that 464xlat is running on top of it.
*/
public void fixupLinkProperties(@NonNull LinkProperties oldLp, @NonNull LinkProperties lp) {
- lp.setNat64Prefix(mNat64Prefix);
+ lp.setNat64Prefix(getNat64Prefix());
if (!isRunning()) {
return;
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 61b18eedfc6e..962f337a8b3f 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -80,6 +80,7 @@ import com.android.server.pm.permission.PermissionManagerServiceInternal;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
@@ -398,78 +399,93 @@ public final class ContentService extends IContentService.Stub {
*/
@Override
public void notifyChange(Uri[] uris, IContentObserver observer,
- boolean observerWantsSelfNotifications, int flags, int userHandle,
+ boolean observerWantsSelfNotifications, int flags, int userId,
int targetSdkVersion, String callingPackage) {
- final ObserverCollector collector = new ObserverCollector();
- for (Uri uri : uris) {
- notifyChange(uri, observer, observerWantsSelfNotifications, flags, userHandle,
- targetSdkVersion, callingPackage, collector);
- }
- final long token = clearCallingIdentity();
- try {
- collector.dispatch();
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- public void notifyChange(Uri uri, IContentObserver observer,
- boolean observerWantsSelfNotifications, int flags, int userHandle,
- int targetSdkVersion, String callingPackage, ObserverCollector collector) {
- if (DEBUG) Slog.d(TAG, "Notifying update of " + uri + " for user " + userHandle
- + " from observer " + observer + ", flags " + Integer.toHexString(flags));
-
- if (uri == null) {
- throw new NullPointerException("Uri must not be null");
+ if (DEBUG) {
+ Slog.d(TAG, "Notifying update of " + Arrays.toString(uris) + " for user " + userId
+ + ", observer " + observer + ", flags " + Integer.toHexString(flags));
}
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
- final int callingUserHandle = UserHandle.getCallingUserId();
+ final int callingUserId = UserHandle.getCallingUserId();
+
+ // Set of notification events that we need to dispatch
+ final ObserverCollector collector = new ObserverCollector();
- userHandle = handleIncomingUser(uri, callingPid, callingUid,
- Intent.FLAG_GRANT_WRITE_URI_PERMISSION, true, userHandle);
+ // Set of content provider authorities that we've validated the caller
+ // has access to, mapped to the package name hosting that provider
+ final ArrayMap<Pair<String, Integer>, String> validatedProviders = new ArrayMap<>();
- final String msg = LocalServices.getService(ActivityManagerInternal.class)
- .checkContentProviderAccess(uri.getAuthority(), userHandle);
- if (msg != null) {
- if (targetSdkVersion >= Build.VERSION_CODES.O) {
- throw new SecurityException(msg);
- } else {
- if (msg.startsWith("Failed to find provider")) {
- // Sigh, we need to quietly let apps targeting older API
- // levels notify on non-existent providers.
- } else {
- Log.w(TAG, "Ignoring notify for " + uri + " from " + callingUid + ": " + msg);
- return;
+ for (Uri uri : uris) {
+ // Validate that calling app has access to this provider
+ final int resolvedUserId = handleIncomingUser(uri, callingPid, callingUid,
+ Intent.FLAG_GRANT_WRITE_URI_PERMISSION, true, userId);
+ final Pair<String, Integer> provider = Pair.create(uri.getAuthority(), resolvedUserId);
+ if (!validatedProviders.containsKey(provider)) {
+ final String msg = LocalServices.getService(ActivityManagerInternal.class)
+ .checkContentProviderAccess(uri.getAuthority(), resolvedUserId);
+ if (msg != null) {
+ if (targetSdkVersion >= Build.VERSION_CODES.O) {
+ throw new SecurityException(msg);
+ } else {
+ if (msg.startsWith("Failed to find provider")) {
+ // Sigh, we need to quietly let apps targeting older API
+ // levels notify on non-existent providers.
+ } else {
+ Log.w(TAG, "Ignoring notify for " + uri + " from "
+ + callingUid + ": " + msg);
+ continue;
+ }
+ }
}
+
+ // Remember that we've validated this access
+ final String packageName = getProviderPackageName(uri, resolvedUserId);
+ validatedProviders.put(provider, packageName);
}
- }
- // This makes it so that future permission checks will be in the context of this
- // process rather than the caller's process. We will restore this before returning.
- long identityToken = clearCallingIdentity();
- try {
+ // No concerns raised above, so caller has access; let's collect the
+ // notifications that should be dispatched
synchronized (mRootNode) {
- mRootNode.collectObserversLocked(uri, 0, observer, observerWantsSelfNotifications,
- flags, userHandle, collector);
+ final int segmentCount = ObserverNode.countUriSegments(uri);
+ mRootNode.collectObserversLocked(uri, segmentCount, 0, observer,
+ observerWantsSelfNotifications, flags, resolvedUserId, collector);
}
- if ((flags&ContentResolver.NOTIFY_SYNC_TO_NETWORK) != 0) {
- SyncManager syncManager = getSyncManager();
- if (syncManager != null) {
- syncManager.scheduleLocalSync(null /* all accounts */, callingUserHandle,
- callingUid,
- uri.getAuthority(), getSyncExemptionForCaller(callingUid),
- callingUid, callingPid, callingPackage);
+ }
+
+ final long token = clearCallingIdentity();
+ try {
+ // Actually dispatch all the notifications we collected
+ collector.dispatch();
+
+ for (int i = 0; i < validatedProviders.size(); i++) {
+ final String authority = validatedProviders.keyAt(i).first;
+ final int resolvedUserId = validatedProviders.keyAt(i).second;
+ final String packageName = validatedProviders.valueAt(i);
+
+ // Kick off sync adapters for any authorities we touched
+ if ((flags & ContentResolver.NOTIFY_SYNC_TO_NETWORK) != 0) {
+ SyncManager syncManager = getSyncManager();
+ if (syncManager != null) {
+ syncManager.scheduleLocalSync(null /* all accounts */, callingUserId,
+ callingUid,
+ authority, getSyncExemptionForCaller(callingUid),
+ callingUid, callingPid, callingPackage);
+ }
}
- }
- synchronized (mCache) {
- final String providerPackageName = getProviderPackageName(uri, userHandle);
- invalidateCacheLocked(userHandle, providerPackageName, uri);
+ // Invalidate caches for any authorities we touched
+ synchronized (mCache) {
+ for (Uri uri : uris) {
+ if (Objects.equals(uri.getAuthority(), authority)) {
+ invalidateCacheLocked(resolvedUserId, packageName, uri);
+ }
+ }
+ }
}
} finally {
- restoreCallingIdentity(identityToken);
+ Binder.restoreCallingIdentity(token);
}
}
@@ -1533,7 +1549,7 @@ public final class ContentService extends IContentService.Stub {
}
}
- private String getUriSegment(Uri uri, int index) {
+ public static String getUriSegment(Uri uri, int index) {
if (uri != null) {
if (index == 0) {
return uri.getAuthority();
@@ -1545,7 +1561,7 @@ public final class ContentService extends IContentService.Stub {
}
}
- private int countUriSegments(Uri uri) {
+ public static int countUriSegments(Uri uri) {
if (uri == null) {
return 0;
}
@@ -1669,14 +1685,21 @@ public final class ContentService extends IContentService.Stub {
}
}
+ @VisibleForTesting
+ public void collectObserversLocked(Uri uri, int index,
+ IContentObserver observer, boolean observerWantsSelfNotifications, int flags,
+ int targetUserHandle, ObserverCollector collector) {
+ collectObserversLocked(uri, countUriSegments(uri), index, observer,
+ observerWantsSelfNotifications, flags, targetUserHandle, collector);
+ }
+
/**
* targetUserHandle is either a hard user handle or is USER_ALL
*/
- public void collectObserversLocked(Uri uri, int index, IContentObserver observer,
- boolean observerWantsSelfNotifications, int flags,
- int targetUserHandle, ObserverCollector collector) {
+ public void collectObserversLocked(Uri uri, int segmentCount, int index,
+ IContentObserver observer, boolean observerWantsSelfNotifications, int flags,
+ int targetUserHandle, ObserverCollector collector) {
String segment = null;
- int segmentCount = countUriSegments(uri);
if (index >= segmentCount) {
// This is the leaf node, notify all observers
if (DEBUG) Slog.d(TAG, "Collecting leaf observers @ #" + index + ", node " + mName);
@@ -1696,7 +1719,7 @@ public final class ContentService extends IContentService.Stub {
ObserverNode node = mChildren.get(i);
if (segment == null || node.mName.equals(segment)) {
// We found the child,
- node.collectObserversLocked(uri, index + 1, observer,
+ node.collectObserversLocked(uri, segmentCount, index + 1, observer,
observerWantsSelfNotifications, flags, targetUserHandle, collector);
if (segment != null) {
break;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index ed3b9f1fc265..f9fc82bf05b1 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -214,7 +214,6 @@ import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
-import android.util.FeatureFlagUtils;
import android.util.IntArray;
import android.util.Log;
import android.util.Pair;
@@ -2745,15 +2744,15 @@ public class NotificationManagerService extends SystemService {
return userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId;
}
- private ToastRecord getToastRecord(int pid, String packageName, IBinder token,
+ private ToastRecord getToastRecord(int uid, int pid, String packageName, IBinder token,
@Nullable CharSequence text, @Nullable ITransientNotification callback, int duration,
Binder windowToken, int displayId,
@Nullable ITransientNotificationCallback textCallback) {
if (callback == null) {
- return new TextToastRecord(this, mStatusBar, pid, packageName, token, text, duration,
- windowToken, displayId, textCallback);
+ return new TextToastRecord(this, mStatusBar, uid, pid, packageName, token, text,
+ duration, windowToken, displayId, textCallback);
} else {
- return new CustomToastRecord(this, pid, packageName, token, callback, duration,
+ return new CustomToastRecord(this, uid, pid, packageName, token, callback, duration,
windowToken, displayId);
}
}
@@ -2878,8 +2877,8 @@ public class NotificationManagerService extends SystemService {
Binder windowToken = new Binder();
mWindowManagerInternal.addWindowToken(windowToken, TYPE_TOAST, displayId);
- record = getToastRecord(callingPid, pkg, token, text, callback, duration,
- windowToken, displayId, textCallback);
+ record = getToastRecord(callingUid, callingPid, pkg, token, text, callback,
+ duration, windowToken, displayId, textCallback);
mToastQueue.add(record);
index = mToastQueue.size() - 1;
keepProcessAliveForToastIfNeededLocked(callingPid);
@@ -5617,18 +5616,16 @@ public class NotificationManagerService extends SystemService {
mUsageStats.registerEnqueuedByApp(pkg);
+ final StatusBarNotification n = new StatusBarNotification(
+ pkg, opPkg, id, tag, notificationUid, callingPid, notification,
+ user, null, System.currentTimeMillis());
+
// setup local book-keeping
String channelId = notification.getChannelId();
if (mIsTelevision && (new Notification.TvExtender(notification)).getChannelId() != null) {
channelId = (new Notification.TvExtender(notification)).getChannelId();
}
- String shortcutId = notification.getShortcutId();
- if (FeatureFlagUtils.isEnabled(getContext(),
- FeatureFlagUtils.NOTIF_CONVO_BYPASS_SHORTCUT_REQ)
- && shortcutId == null
- && notification.getNotificationStyle() == Notification.MessagingStyle.class) {
- shortcutId = id + tag + NotificationChannel.PLACEHOLDER_CONVERSATION_ID;
- }
+ String shortcutId = n.getShortcutId(getContext());
final NotificationChannel channel = mPreferencesHelper.getConversationNotificationChannel(
pkg, notificationUid, channelId, shortcutId,
true /* parent ok */, false /* includeDeleted */);
@@ -5656,9 +5653,6 @@ public class NotificationManagerService extends SystemService {
return;
}
- final StatusBarNotification n = new StatusBarNotification(
- pkg, opPkg, id, tag, notificationUid, callingPid, notification,
- user, null, System.currentTimeMillis());
final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
r.setIsAppImportanceLocked(mPreferencesHelper.getIsAppImportanceLocked(pkg, callingUid));
r.setPostSilently(postSilently);
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 54a0f9f46892..192df4139b37 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -1383,9 +1383,8 @@ public final class NotificationRecord {
|| !Notification.MessagingStyle.class.equals(notification.getNotificationStyle())) {
return false;
}
- if (mShortcutInfo == null
- && !FeatureFlagUtils.isEnabled(
- mContext, FeatureFlagUtils.NOTIF_CONVO_BYPASS_SHORTCUT_REQ)) {
+ if (mShortcutInfo == null && Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 0) == 1) {
return false;
}
if (mIsNotConversationOverride) {
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index dbb246e9fbe8..8154988a4917 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -47,7 +47,6 @@ import android.service.notification.RankingHelperProto;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
-import android.util.FeatureFlagUtils;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseBooleanArray;
@@ -181,8 +180,8 @@ public class PreferencesHelper implements RankingConfig {
updateBadgingEnabled();
updateBubblesEnabled();
syncChannelsBypassingDnd(mContext.getUserId());
- mAllowInvalidShortcuts = FeatureFlagUtils.isEnabled(mContext,
- FeatureFlagUtils.NOTIF_CONVO_BYPASS_SHORTCUT_REQ);
+ mAllowInvalidShortcuts = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 0) == 0;
}
public void readXml(XmlPullParser parser, boolean forRestore, int userId)
diff --git a/services/core/java/com/android/server/notification/toast/CustomToastRecord.java b/services/core/java/com/android/server/notification/toast/CustomToastRecord.java
index aca6f4853597..2b91a00f9da5 100644
--- a/services/core/java/com/android/server/notification/toast/CustomToastRecord.java
+++ b/services/core/java/com/android/server/notification/toast/CustomToastRecord.java
@@ -23,6 +23,7 @@ import android.app.ITransientNotification;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.Slog;
import com.android.server.notification.NotificationManagerService;
@@ -35,11 +36,10 @@ public class CustomToastRecord extends ToastRecord {
public final ITransientNotification callback;
- public CustomToastRecord(
- NotificationManagerService notificationManager, int pid, String packageName,
- IBinder token, ITransientNotification callback, int duration, Binder windowToken,
- int displayId) {
- super(notificationManager, pid, packageName, token, duration, windowToken, displayId);
+ public CustomToastRecord(NotificationManagerService notificationManager, int uid, int pid,
+ String packageName, IBinder token, ITransientNotification callback, int duration,
+ Binder windowToken, int displayId) {
+ super(notificationManager, uid, pid, packageName, token, duration, windowToken, displayId);
this.callback = checkNotNull(callback);
}
@@ -74,8 +74,8 @@ public class CustomToastRecord extends ToastRecord {
public String toString() {
return "CustomToastRecord{"
+ Integer.toHexString(System.identityHashCode(this))
+ + " " + pid + ":" + pkg + "/" + UserHandle.formatUid(uid)
+ " token=" + token
- + " packageName=" + pkg
+ " callback=" + callback
+ " duration=" + getDuration()
+ "}";
diff --git a/services/core/java/com/android/server/notification/toast/TextToastRecord.java b/services/core/java/com/android/server/notification/toast/TextToastRecord.java
index 3c231b445f62..544520edc7fc 100644
--- a/services/core/java/com/android/server/notification/toast/TextToastRecord.java
+++ b/services/core/java/com/android/server/notification/toast/TextToastRecord.java
@@ -23,6 +23,7 @@ import android.annotation.Nullable;
import android.app.ITransientNotificationCallback;
import android.os.Binder;
import android.os.IBinder;
+import android.os.UserHandle;
import android.util.Slog;
import com.android.server.notification.NotificationManagerService;
@@ -41,10 +42,10 @@ public class TextToastRecord extends ToastRecord {
private final ITransientNotificationCallback mCallback;
public TextToastRecord(NotificationManagerService notificationManager,
- @Nullable StatusBarManagerInternal statusBarManager, int pid, String packageName,
- IBinder token, CharSequence text, int duration, Binder windowToken, int displayId,
- @Nullable ITransientNotificationCallback callback) {
- super(notificationManager, pid, packageName, token, duration, windowToken, displayId);
+ @Nullable StatusBarManagerInternal statusBarManager, int uid, int pid,
+ String packageName, IBinder token, CharSequence text, int duration, Binder windowToken,
+ int displayId, @Nullable ITransientNotificationCallback callback) {
+ super(notificationManager, uid, pid, packageName, token, duration, windowToken, displayId);
mStatusBar = statusBarManager;
mCallback = callback;
this.text = checkNotNull(text);
@@ -59,7 +60,7 @@ public class TextToastRecord extends ToastRecord {
Slog.w(TAG, "StatusBar not available to show text toast for package " + pkg);
return false;
}
- mStatusBar.showToast(pkg, token, text, windowToken, getDuration(), mCallback);
+ mStatusBar.showToast(uid, pkg, token, text, windowToken, getDuration(), mCallback);
return true;
}
@@ -75,8 +76,8 @@ public class TextToastRecord extends ToastRecord {
public String toString() {
return "TextToastRecord{"
+ Integer.toHexString(System.identityHashCode(this))
+ + " " + pid + ":" + pkg + "/" + UserHandle.formatUid(uid)
+ " token=" + token
- + " packageName=" + pkg
+ " text=" + text
+ " duration=" + getDuration()
+ "}";
diff --git a/services/core/java/com/android/server/notification/toast/ToastRecord.java b/services/core/java/com/android/server/notification/toast/ToastRecord.java
index ef75a6f5dd7b..7915f7013227 100644
--- a/services/core/java/com/android/server/notification/toast/ToastRecord.java
+++ b/services/core/java/com/android/server/notification/toast/ToastRecord.java
@@ -28,6 +28,7 @@ import java.io.PrintWriter;
* Represents a toast, a transient notification.
*/
public abstract class ToastRecord {
+ public final int uid;
public final int pid;
public final String pkg;
public final IBinder token;
@@ -36,11 +37,10 @@ public abstract class ToastRecord {
protected final NotificationManagerService mNotificationManager;
private int mDuration;
- protected ToastRecord(
- NotificationManagerService notificationManager,
- int pid, String pkg, IBinder token, int duration,
- Binder windowToken, int displayId) {
+ protected ToastRecord(NotificationManagerService notificationManager, int uid, int pid,
+ String pkg, IBinder token, int duration, Binder windowToken, int displayId) {
this.mNotificationManager = notificationManager;
+ this.uid = uid;
this.pid = pid;
this.pkg = pkg;
this.token = token;
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index b9d656181b55..1e4dc7bfe778 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -30,7 +30,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
-import android.content.pm.PackageParser;
+import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.parsing.PackageInfoWithoutStateUtils;
import android.os.Binder;
import android.os.Environment;
@@ -137,7 +137,8 @@ public abstract class ApexManager {
/**
* Called by package manager service to scan apex package files when device boots up.
*
- * @param packageParser The package parser which supports caches.
+ * @param packageParser The package parser to support apex package parsing and caching parsed
+ * results.
* @param executorService An executor to support parallel package parsing.
*/
abstract void scanApexPackagesTraced(@NonNull PackageParser2 packageParser,
@@ -505,7 +506,13 @@ public abstract class ApexManager {
}
factoryPackagesSet.add(packageInfo.packageName);
}
- } else if (throwable instanceof PackageParser.PackageParserException) {
+ } else if (throwable instanceof PackageParserException) {
+ final PackageParserException e = (PackageParserException) throwable;
+ // Skip parsing non-coreApp apex file if system is in minimal boot state.
+ if (e.error == PackageManager.INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED) {
+ Slog.w(TAG, "Scan apex failed, not a coreApp:" + ai.modulePath);
+ continue;
+ }
throw new IllegalStateException("Unable to parse: " + ai.modulePath, throwable);
} else {
throw new IllegalStateException("Unexpected exception occurred while parsing "
@@ -522,7 +529,8 @@ public abstract class ApexManager {
"APEX packages have not been scanned");
boolean matchActive = (flags & MATCH_ACTIVE_PACKAGE) != 0;
boolean matchFactory = (flags & MATCH_FACTORY_PACKAGE) != 0;
- for (PackageInfo packageInfo: mAllPackagesCache) {
+ for (int i = 0, size = mAllPackagesCache.size(); i < size; i++) {
+ final PackageInfo packageInfo = mAllPackagesCache.get(i);
if (!packageInfo.packageName.equals(packageName)) {
continue;
}
@@ -581,7 +589,8 @@ public abstract class ApexManager {
if (!isApexSupported()) return false;
Preconditions.checkState(mAllPackagesCache != null,
"APEX packages have not been scanned");
- for (PackageInfo packageInfo : mAllPackagesCache) {
+ for (int i = 0, size = mAllPackagesCache.size(); i < size; i++) {
+ final PackageInfo packageInfo = mAllPackagesCache.get(i);
if (packageInfo.packageName.equals(packageName)) {
return true;
}
@@ -839,7 +848,8 @@ public abstract class ApexManager {
IndentingPrintWriter ipw) {
ipw.println();
ipw.increaseIndent();
- for (PackageInfo pi : packagesCache) {
+ for (int i = 0, size = packagesCache.size(); i < size; i++) {
+ final PackageInfo pi = packagesCache.get(i);
if (packageName != null && !packageName.equals(pi.packageName)) {
continue;
}
diff --git a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
index 40876754eae8..28c8642d3e60 100644
--- a/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
+++ b/services/core/java/com/android/server/pm/CrossProfileAppsServiceImpl.java
@@ -294,6 +294,12 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
.getAllCrossProfilePackages().contains(packageName));
}
+ private boolean isCrossProfilePackageWhitelistedByDefault(String packageName) {
+ return mInjector.withCleanCallingIdentity(() ->
+ mInjector.getDevicePolicyManagerInternal()
+ .getDefaultCrossProfilePackages().contains(packageName));
+ }
+
private List<UserHandle> getTargetUserProfilesUnchecked(
String packageName, @UserIdInt int userId) {
return mInjector.withCleanCallingIdentity(() -> {
@@ -528,6 +534,9 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
@Override
public boolean canConfigureInteractAcrossProfiles(String packageName) {
+ if (!canUserAttemptToConfigureInteractAcrossProfiles(packageName)) {
+ return false;
+ }
if (!hasOtherProfileWithPackageInstalled(packageName, mInjector.getCallingUserId())) {
return false;
}
@@ -546,7 +555,35 @@ public class CrossProfileAppsServiceImpl extends ICrossProfileApps.Stub {
return false;
}
return hasRequestedAppOpPermission(
- AppOpsManager.opToPermission(OP_INTERACT_ACROSS_PROFILES), packageName);
+ AppOpsManager.opToPermission(OP_INTERACT_ACROSS_PROFILES), packageName)
+ && !isPlatformSignedAppWithNonUserConfigurablePermission(packageName, profileIds);
+ }
+
+ private boolean isPlatformSignedAppWithNonUserConfigurablePermission(
+ String packageName, int[] profileIds) {
+ return !isCrossProfilePackageWhitelistedByDefault(packageName)
+ && isPlatformSignedAppWithAutomaticProfilesPermission(packageName, profileIds);
+ }
+
+ /**
+ * Only platform-signed apps can be granted INTERACT_ACROSS_PROFILES automatically without user
+ * consent.
+ *
+ * Returns true if the app is automatically granted the permission in at least one profile.
+ */
+ private boolean isPlatformSignedAppWithAutomaticProfilesPermission(
+ String packageName, int[] profileIds) {
+ for (int userId : profileIds) {
+ final int uid = mInjector.getPackageManagerInternal().getPackageUidInternal(
+ packageName, /* flags= */ 0, userId);
+ if (uid == -1) {
+ continue;
+ }
+ if (isPermissionGranted(Manifest.permission.INTERACT_ACROSS_PROFILES, uid)) {
+ return true;
+ }
+ }
+ return false;
}
private boolean hasOtherProfileWithPackageInstalled(String packageName, @UserIdInt int userId) {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 8ff7ea9d61dd..57908f3a4dac 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -82,6 +82,7 @@ import com.android.internal.util.ImageUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.IoThread;
import com.android.server.LocalServices;
+import com.android.server.pm.parsing.PackageParser2;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
import libcore.io.IoUtils;
@@ -105,6 +106,7 @@ import java.util.List;
import java.util.Objects;
import java.util.Random;
import java.util.function.IntPredicate;
+import java.util.function.Supplier;
/** The service responsible for installing packages. */
public class PackageInstallerService extends IPackageInstaller.Stub implements
@@ -194,7 +196,8 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
}
};
- public PackageInstallerService(Context context, PackageManagerService pm) {
+ public PackageInstallerService(Context context, PackageManagerService pm,
+ Supplier<PackageParser2> apexParserSupplier) {
mContext = context;
mPm = pm;
mPermissionManager = LocalServices.getService(PermissionManagerServiceInternal.class);
@@ -213,7 +216,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements
mSessionsDir.mkdirs();
mApexManager = ApexManager.getInstance();
- mStagingManager = new StagingManager(this, context);
+ mStagingManager = new StagingManager(this, context, apexParserSupplier);
}
boolean okToSendBroadcasts() {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index ab3b2be46988..bc3a0352484b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -417,6 +417,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Predicate;
+import java.util.function.Supplier;
/**
* Keep track of all those APKs everywhere.
@@ -3571,7 +3572,11 @@ public class PackageManagerService extends IPackageManager.Stub
}
}
- mInstallerService = new PackageInstallerService(mContext, this);
+ // Prepare a supplier of package parser for the staging manager to parse apex file
+ // during the staging installation.
+ final Supplier<PackageParser2> apexParserSupplier = () -> new PackageParser2(
+ mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir, mPackageParserCallback);
+ mInstallerService = new PackageInstallerService(mContext, this, apexParserSupplier);
final Pair<ComponentName, String> instantAppResolverComponent =
getInstantAppResolverLPr();
if (instantAppResolverComponent != null) {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index e8696f60b59a..f6e4e1f26bd5 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -4667,6 +4667,10 @@ public final class Settings {
pw.print(prefix); pw.print(" privateFlags="); printFlags(pw,
privateFlags, PRIVATE_FLAG_DUMP_SPEC); pw.println();
}
+ if (pkg.hasPreserveLegacyExternalStorage()) {
+ pw.print(prefix); pw.print(" hasPreserveLegacyExternalStorage=true");
+ pw.println();
+ }
pw.print(prefix); pw.print(" forceQueryable="); pw.print(ps.pkg.isForceQueryable());
if (ps.forceQueryableOverride) {
pw.print(" (override=true)");
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 60292b45c0ee..8f6bd026a9bd 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -35,11 +35,11 @@ import android.content.pm.PackageInstaller;
import android.content.pm.PackageInstaller.SessionInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
-import android.content.pm.PackageParser;
import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.PackageParser.SigningDetails;
import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion;
import android.content.pm.ParceledListSlice;
+import android.content.pm.parsing.PackageInfoWithoutStateUtils;
import android.content.rollback.IRollbackManager;
import android.content.rollback.RollbackInfo;
import android.content.rollback.RollbackManager;
@@ -68,8 +68,10 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.PackageHelper;
import com.android.internal.os.BackgroundThread;
import com.android.server.LocalServices;
+import com.android.server.pm.parsing.PackageParser2;
import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
+import com.android.server.pm.parsing.pkg.ParsedPackage;
import com.android.server.rollback.WatchdogRollbackLogger;
import java.io.File;
@@ -80,6 +82,7 @@ import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Predicate;
+import java.util.function.Supplier;
/**
* This class handles staged install sessions, i.e. install sessions that require packages to
@@ -94,6 +97,7 @@ public class StagingManager {
private final PowerManager mPowerManager;
private final Context mContext;
private final PreRebootVerificationHandler mPreRebootVerificationHandler;
+ private final Supplier<PackageParser2> mPackageParserSupplier;
@GuardedBy("mStagedSessions")
private final SparseArray<PackageInstallerSession> mStagedSessions = new SparseArray<>();
@@ -105,9 +109,11 @@ public class StagingManager {
private final List<String> mFailedPackageNames = new ArrayList<>();
private String mNativeFailureReason;
- StagingManager(PackageInstallerService pi, Context context) {
+ StagingManager(PackageInstallerService pi, Context context,
+ Supplier<PackageParser2> packageParserSupplier) {
mPi = pi;
mContext = context;
+ mPackageParserSupplier = packageParserSupplier;
mApexManager = ApexManager.getInstance();
mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
@@ -223,17 +229,21 @@ public class StagingManager {
final List<String> apexPackageNames = new ArrayList<>();
for (ApexInfo apexInfo : apexInfoList.apexInfos) {
final PackageInfo packageInfo;
- int flags = PackageManager.GET_META_DATA;
- PackageParser.Package pkg;
- try {
+ final int flags = PackageManager.GET_META_DATA;
+ try (PackageParser2 packageParser = mPackageParserSupplier.get()) {
File apexFile = new File(apexInfo.modulePath);
- PackageParser pp = new PackageParser();
- pkg = pp.parsePackage(apexFile, flags, false);
+ final ParsedPackage parsedPackage = packageParser.parsePackage(
+ apexFile, flags, false);
+ packageInfo = PackageInfoWithoutStateUtils.generate(parsedPackage, apexInfo, flags);
+ if (packageInfo == null) {
+ throw new PackageManagerException(
+ SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
+ "Unable to generate package info: " + apexInfo.modulePath);
+ }
} catch (PackageParserException e) {
throw new PackageManagerException(SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
"Failed to parse APEX package " + apexInfo.modulePath, e);
}
- packageInfo = PackageParser.generatePackageInfo(pkg, apexInfo, flags);
final PackageInfo activePackage = mApexManager.getPackageInfo(packageInfo.packageName,
ApexManager.MATCH_ACTIVE_PACKAGE);
if (activePackage == null) {
@@ -254,8 +264,9 @@ public class StagingManager {
private int retrieveRollbackIdForCommitSession(int sessionId) throws PackageManagerException {
RollbackManager rm = mContext.getSystemService(RollbackManager.class);
- List<RollbackInfo> rollbacks = rm.getRecentlyCommittedRollbacks();
- for (RollbackInfo rollback : rollbacks) {
+ final List<RollbackInfo> rollbacks = rm.getRecentlyCommittedRollbacks();
+ for (int i = 0, size = rollbacks.size(); i < size; i++) {
+ final RollbackInfo rollback = rollbacks.get(i);
if (rollback.getCommittedSessionId() == sessionId) {
return rollback.getRollbackId();
}
@@ -388,7 +399,8 @@ public class StagingManager {
}
}
}
- for (PackageInstallerSession childSession : childrenSessions) {
+ for (int i = 0, size = childrenSessions.size(); i < size; i++) {
+ final PackageInstallerSession childSession = childrenSessions.get(i);
if (sessionContainsApex(childSession)) {
apexSessions.add(childSession);
}
@@ -402,15 +414,15 @@ public class StagingManager {
IRollbackManager rm = IRollbackManager.Stub.asInterface(
ServiceManager.getService(Context.ROLLBACK_SERVICE));
- for (PackageInstallerSession apexSession : apexSessions) {
- String packageName = apexSession.getPackageName();
+ for (int i = 0, sessionsSize = apexSessions.size(); i < sessionsSize; i++) {
+ final String packageName = apexSessions.get(i).getPackageName();
// Perform any snapshots or restores for the APEX itself
snapshotAndRestoreApexUserData(packageName, allUsers, rm);
// Process the apks inside the APEX
- List<String> apksInApex = mApexManager.getApksInApex(packageName);
- for (String apk: apksInApex) {
- snapshotAndRestoreApkInApexUserData(apk, allUsers, rm);
+ final List<String> apksInApex = mApexManager.getApksInApex(packageName);
+ for (int j = 0, apksSize = apksInApex.size(); j < apksSize; j++) {
+ snapshotAndRestoreApkInApexUserData(apksInApex.get(j), allUsers, rm);
}
}
}
@@ -637,7 +649,8 @@ public class StagingManager {
0 /* UserHandle.SYSTEM */);
PackageInstallerSession apkSession = mPi.getSession(apkSessionId);
apkSession.open();
- for (String apkFilePath : apkFilePaths) {
+ for (int i = 0, size = apkFilePaths.size(); i < size; i++) {
+ final String apkFilePath = apkFilePaths.get(i);
File apkFile = new File(apkFilePath);
ParcelFileDescriptor pfd = ParcelFileDescriptor.open(apkFile,
ParcelFileDescriptor.MODE_READ_ONLY);
@@ -705,9 +718,9 @@ public class StagingManager {
"Unable to prepare multi-package session for staged session");
}
- for (PackageInstallerSession sessionToClone : childSessions) {
- PackageInstallerSession apkChildSession =
- createAndWriteApkSession(sessionToClone, preReboot);
+ for (int i = 0, size = childSessions.size(); i < size; i++) {
+ final PackageInstallerSession apkChildSession = createAndWriteApkSession(
+ childSessions.get(i), preReboot);
try {
apkParentSession.addChildSessionId(apkChildSession.sessionId);
} catch (IllegalStateException e) {
@@ -1206,10 +1219,9 @@ public class StagingManager {
// multi-package sessions, find all the child sessions that contain an APEX.
if (hasApex) {
try {
- final List<PackageInfo> apexPackages =
- submitSessionToApexService(session);
- for (PackageInfo apexPackage : apexPackages) {
- validateApexSignature(apexPackage);
+ final List<PackageInfo> apexPackages = submitSessionToApexService(session);
+ for (int i = 0, size = apexPackages.size(); i < size; i++) {
+ validateApexSignature(apexPackages.get(i));
}
} catch (PackageManagerException e) {
session.setStagedSessionFailed(e.error, e.getMessage());
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index b41bc5c2dc51..cd6c5bfaeb79 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -513,10 +513,7 @@ public final class PowerManagerService extends SystemService
// The screen brightness setting override from the window manager
// to allow the current foreground activity to override the brightness.
- // Use -1 to disable.
- private int mScreenBrightnessOverrideFromWindowManager = -1;
-
- private float mScreenBrightnessOverrideFromWindowManagerFloat =
+ private float mScreenBrightnessOverrideFromWindowManager =
PowerManager.BRIGHTNESS_INVALID_FLOAT;
// The window manager has determined the user to be inactive via other means.
@@ -2846,7 +2843,7 @@ public final class PowerManagerService extends SystemService
screenBrightnessOverride = mScreenBrightnessSettingDefault;
} else if (isValidBrightness(mScreenBrightnessOverrideFromWindowManager)) {
autoBrightness = false;
- screenBrightnessOverride = mScreenBrightnessOverrideFromWindowManagerFloat;
+ screenBrightnessOverride = mScreenBrightnessOverrideFromWindowManager;
} else {
autoBrightness = (mScreenBrightnessModeSetting ==
Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
@@ -2927,8 +2924,8 @@ public final class PowerManagerService extends SystemService
return !mIsVrModeEnabled && mScreenBrightnessBoostInProgress;
}
- private static boolean isValidBrightness(int value) {
- return value >= 0 && value <= 255;
+ private static boolean isValidBrightness(float value) {
+ return value >= PowerManager.BRIGHTNESS_MIN && value <= PowerManager.BRIGHTNESS_MAX;
}
@VisibleForTesting
@@ -3583,13 +3580,11 @@ public final class PowerManagerService extends SystemService
}
}
- // TODO(brightnessfloat): change to float
- private void setScreenBrightnessOverrideFromWindowManagerInternal(int brightness) {
+ private void setScreenBrightnessOverrideFromWindowManagerInternal(float brightness) {
synchronized (mLock) {
- if (mScreenBrightnessOverrideFromWindowManager != brightness) {
+ if (!BrightnessSynchronizer.floatEquals(mScreenBrightnessOverrideFromWindowManager,
+ brightness)) {
mScreenBrightnessOverrideFromWindowManager = brightness;
- mScreenBrightnessOverrideFromWindowManagerFloat =
- BrightnessSynchronizer.brightnessIntToFloat(mContext, brightness);
mDirty |= DIRTY_SETTINGS;
updatePowerStateLocked();
}
@@ -3890,8 +3885,8 @@ public final class PowerManagerService extends SystemService
+ isMaximumScreenOffTimeoutFromDeviceAdminEnforcedLocked() + ")");
pw.println(" mStayOnWhilePluggedInSetting=" + mStayOnWhilePluggedInSetting);
pw.println(" mScreenBrightnessModeSetting=" + mScreenBrightnessModeSetting);
- pw.println(" mScreenBrightnessOverrideFromWindowManagerFloat="
- + mScreenBrightnessOverrideFromWindowManagerFloat);
+ pw.println(" mScreenBrightnessOverrideFromWindowManager="
+ + mScreenBrightnessOverrideFromWindowManager);
pw.println(" mUserActivityTimeoutOverrideFromWindowManager="
+ mUserActivityTimeoutOverrideFromWindowManager);
pw.println(" mUserInactiveOverrideFromWindowManager="
@@ -4231,7 +4226,7 @@ public final class PowerManagerService extends SystemService
proto.write(
PowerServiceSettingsAndConfigurationDumpProto
.SCREEN_BRIGHTNESS_OVERRIDE_FROM_WINDOW_MANAGER,
- mScreenBrightnessOverrideFromWindowManagerFloat);
+ mScreenBrightnessOverrideFromWindowManager);
proto.write(
PowerServiceSettingsAndConfigurationDumpProto
.USER_ACTIVITY_TIMEOUT_OVERRIDE_FROM_WINDOW_MANAGER_MS,
@@ -5430,10 +5425,10 @@ public final class PowerManagerService extends SystemService
@VisibleForTesting
final class LocalService extends PowerManagerInternal {
@Override
- public void setScreenBrightnessOverrideFromWindowManager(int screenBrightness) {
- if (screenBrightness < PowerManager.BRIGHTNESS_DEFAULT
- || screenBrightness > PowerManager.BRIGHTNESS_ON) {
- screenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
+ public void setScreenBrightnessOverrideFromWindowManager(float screenBrightness) {
+ if (screenBrightness < PowerManager.BRIGHTNESS_MIN
+ || screenBrightness > PowerManager.BRIGHTNESS_MAX) {
+ screenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
}
setScreenBrightnessOverrideFromWindowManagerInternal(screenBrightness);
}
diff --git a/services/core/java/com/android/server/security/FileIntegrityService.java b/services/core/java/com/android/server/security/FileIntegrityService.java
index 841aca5a8d6f..225bd82e9a21 100644
--- a/services/core/java/com/android/server/security/FileIntegrityService.java
+++ b/services/core/java/com/android/server/security/FileIntegrityService.java
@@ -24,6 +24,7 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.os.Binder;
import android.os.Build;
+import android.os.Environment;
import android.os.IBinder;
import android.os.SystemProperties;
import android.os.UserHandle;
@@ -37,6 +38,7 @@ import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
+import java.nio.file.Path;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
@@ -131,12 +133,17 @@ public class FileIntegrityService extends SystemService {
// duplicate the same loading logic here.
// Load certificates trusted by the device manufacturer.
- loadCertificatesFromDirectory("/product/etc/security/fsverity");
+ // NB: Directories need to be synced with system/security/fsverity_init/fsverity_init.cpp.
+ final String relativeDir = "etc/security/fsverity";
+ loadCertificatesFromDirectory(Environment.getRootDirectory().toPath()
+ .resolve(relativeDir));
+ loadCertificatesFromDirectory(Environment.getProductDirectory().toPath()
+ .resolve(relativeDir));
}
- private void loadCertificatesFromDirectory(String path) {
+ private void loadCertificatesFromDirectory(Path path) {
try {
- File[] files = new File(path).listFiles();
+ File[] files = path.toFile().listFiles();
if (files == null) {
return;
}
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index d88dccb9afeb..26497d8b0290 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -131,7 +131,7 @@ public interface StatusBarManagerInternal {
* @see com.android.internal.statusbar.IStatusBar#showToast(String, IBinder, CharSequence,
* IBinder, int, ITransientNotificationCallback)
*/
- void showToast(String packageName, IBinder token, CharSequence text,
+ void showToast(int uid, String packageName, IBinder token, CharSequence text,
IBinder windowToken, int duration,
@Nullable ITransientNotificationCallback textCallback);
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 78ef68c09988..d7a0c9871b48 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -502,12 +502,12 @@ public class StatusBarManagerService extends IStatusBarService.Stub implements D
}
@Override
- public void showToast(String packageName, IBinder token, CharSequence text,
+ public void showToast(int uid, String packageName, IBinder token, CharSequence text,
IBinder windowToken, int duration,
@Nullable ITransientNotificationCallback callback) {
if (mBar != null) {
try {
- mBar.showToast(packageName, token, text, windowToken, duration, callback);
+ mBar.showToast(uid, packageName, token, text, windowToken, duration, callback);
} catch (RemoteException ex) { }
}
}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index e1ef76f128cd..80b8b5854966 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -178,7 +178,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
private Object mLastWindowFreezeSource = null;
private Session mHoldScreen = null;
- private float mScreenBrightness = -1;
+ private float mScreenBrightnessOverride = PowerManager.BRIGHTNESS_INVALID_FLOAT;
private long mUserActivityTimeout = -1;
private boolean mUpdateRotation = false;
// Following variables are for debugging screen wakelock only.
@@ -826,7 +826,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
}
mHoldScreen = null;
- mScreenBrightness = -1;
+ mScreenBrightnessOverride = PowerManager.BRIGHTNESS_INVALID_FLOAT;
mUserActivityTimeout = -1;
mObscureApplicationContentOnSecondaryDisplays = false;
mSustainedPerformanceModeCurrent = false;
@@ -936,12 +936,14 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
mWmService.setHoldScreenLocked(mHoldScreen);
if (!mWmService.mDisplayFrozen) {
- final int brightness = mScreenBrightness < 0 || mScreenBrightness > 1.0f
- ? -1 : toBrightnessOverride(mScreenBrightness);
-
+ final float brightnessOverride = mScreenBrightnessOverride < PowerManager.BRIGHTNESS_MIN
+ || mScreenBrightnessOverride > PowerManager.BRIGHTNESS_MAX
+ ? PowerManager.BRIGHTNESS_INVALID_FLOAT : mScreenBrightnessOverride;
+ int brightnessFloatAsIntBits = Float.floatToIntBits(brightnessOverride);
// Post these on a handler such that we don't call into power manager service while
// holding the window manager lock to avoid lock contention with power manager lock.
- mHandler.obtainMessage(SET_SCREEN_BRIGHTNESS_OVERRIDE, brightness, 0).sendToTarget();
+ mHandler.obtainMessage(SET_SCREEN_BRIGHTNESS_OVERRIDE, brightnessFloatAsIntBits,
+ 0).sendToTarget();
mHandler.obtainMessage(SET_USER_ACTIVITY_TIMEOUT, mUserActivityTimeout).sendToTarget();
}
@@ -1125,8 +1127,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
+ "has FLAG_KEEP_SCREEN_ON!!! called by%s",
w, Debug.getCallers(10));
}
- if (!syswin && w.mAttrs.screenBrightness >= 0 && mScreenBrightness < 0) {
- mScreenBrightness = w.mAttrs.screenBrightness;
+ if (!syswin && w.mAttrs.screenBrightness >= 0
+ && Float.isNaN(mScreenBrightnessOverride)) {
+ mScreenBrightnessOverride = w.mAttrs.screenBrightness;
}
final int type = attrs.type;
@@ -1190,10 +1193,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
return doRequest;
}
- private static int toBrightnessOverride(float value) {
- return (int)(value * PowerManager.BRIGHTNESS_ON);
- }
-
private final class MyHandler extends Handler {
public MyHandler(Looper looper) {
@@ -1205,7 +1204,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
switch (msg.what) {
case SET_SCREEN_BRIGHTNESS_OVERRIDE:
mWmService.mPowerManagerInternal.setScreenBrightnessOverrideFromWindowManager(
- msg.arg1);
+ Float.intBitsToFloat(msg.arg1));
break;
case SET_USER_ACTIVITY_TIMEOUT:
mWmService.mPowerManagerInternal.
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index c891c1166a06..cb897db9a2d0 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -2448,7 +2448,8 @@ class Task extends WindowContainer<WindowContainer> {
Rect updateOverrideConfigurationFromLaunchBounds() {
// If the task is controlled by another organized task, do not set override
// configurations and let its parent (organized task) to control it;
- final Rect bounds = isOrganized() && !isRootTask() ? null : getLaunchBounds();
+ final Task rootTask = getRootTask();
+ final Rect bounds = rootTask != this && rootTask.isOrganized() ? null : getLaunchBounds();
setBounds(bounds);
if (bounds != null && !bounds.isEmpty()) {
// TODO: Review if we actually want to do this - we are setting the launch bounds
@@ -4131,17 +4132,6 @@ class Task extends WindowContainer<WindowContainer> {
// Let the old organizer know it has lost control.
sendTaskVanished();
mTaskOrganizer = organizer;
-
- // If the task is not yet visible when it is added to the task organizer, then we should
- // hide it to allow the task organizer to show it when it is properly reparented. We skip
- // this for tasks created by the organizer because they can synchronously update the leash
- // before new children are added to the task.
- if (!mCreatedByOrganizer && organizer != null
- && (!getHasBeenVisible() || !hasVisibleChildren())) {
- getPendingTransaction().hide(getSurfaceControl());
- commitPendingTransaction();
- }
-
sendTaskAppeared();
onTaskOrganizerChanged();
return true;
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 75f2e1f0a8ba..2bbf8dbb274c 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -25,7 +25,6 @@ import static com.android.server.wm.WindowOrganizerController.CONTROLLABLE_CONFI
import static com.android.server.wm.WindowOrganizerController.CONTROLLABLE_WINDOW_CONFIGS;
import android.annotation.Nullable;
-import android.app.ActivityManager;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.WindowConfiguration;
import android.content.Intent;
@@ -39,7 +38,6 @@ import android.window.ITaskOrganizer;
import android.window.ITaskOrganizerController;
import android.window.WindowContainerToken;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import java.io.PrintWriter;
@@ -48,7 +46,6 @@ import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.WeakHashMap;
-import java.util.function.Consumer;
/**
* Stores the TaskOrganizers associated with a given windowing mode and
@@ -84,95 +81,17 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
}
}
}
- }
-
- /**
- * A wrapper class around ITaskOrganizer to ensure that the calls are made in the right
- * lifecycle order since we may be updating the visibility of task surface controls in a pending
- * transaction before they are presented to the task org.
- */
- private class TaskOrganizerCallbacks {
- final WindowManagerService mService;
- final ITaskOrganizer mTaskOrganizer;
- final Consumer<Runnable> mDeferTaskOrgCallbacksConsumer;
-
- TaskOrganizerCallbacks(WindowManagerService wm, ITaskOrganizer taskOrg,
- Consumer<Runnable> deferTaskOrgCallbacksConsumer) {
- mService = wm;
- mDeferTaskOrgCallbacksConsumer = deferTaskOrgCallbacksConsumer;
- mTaskOrganizer = taskOrg;
- }
-
- IBinder getBinder() {
- return mTaskOrganizer.asBinder();
- }
-
- void onTaskAppeared(Task task) {
- final RunningTaskInfo taskInfo = task.getTaskInfo();
- mDeferTaskOrgCallbacksConsumer.accept(() -> {
- try {
- mTaskOrganizer.onTaskAppeared(taskInfo);
- } catch (RemoteException e) {
- Slog.e(TAG, "Exception sending onTaskAppeared callback", e);
- }
- });
- }
-
-
- void onTaskVanished(Task task) {
- final RunningTaskInfo taskInfo = task.getTaskInfo();
- mDeferTaskOrgCallbacksConsumer.accept(() -> {
- try {
- mTaskOrganizer.onTaskVanished(taskInfo);
- } catch (RemoteException e) {
- Slog.e(TAG, "Exception sending onTaskVanished callback", e);
- }
- });
- }
-
- void onTaskInfoChanged(Task task, ActivityManager.RunningTaskInfo taskInfo) {
- mDeferTaskOrgCallbacksConsumer.accept(() -> {
- if (!task.isOrganized()) {
- // This is safe to ignore if the task is no longer organized
- return;
- }
- try {
- mTaskOrganizer.onTaskInfoChanged(taskInfo);
- } catch (RemoteException e) {
- Slog.e(TAG, "Exception sending onTaskInfoChanged callback", e);
- }
- });
- }
-
- void onBackPressedOnTaskRoot(Task task) {
- mDeferTaskOrgCallbacksConsumer.accept(() -> {
- if (!task.isOrganized()) {
- // This is safe to ignore if the task is no longer organized
- return;
- }
- try {
- mTaskOrganizer.onBackPressedOnTaskRoot(task.getTaskInfo());
- } catch (Exception e) {
- Slog.e(TAG, "Exception sending onBackPressedOnTaskRoot callback", e);
- }
- });
- }
- }
+ };
private class TaskOrganizerState {
- private final TaskOrganizerCallbacks mOrganizer;
+ private final ITaskOrganizer mOrganizer;
private final DeathRecipient mDeathRecipient;
private final ArrayList<Task> mOrganizedTasks = new ArrayList<>();
private final int mUid;
private boolean mInterceptBackPressedOnTaskRoot;
TaskOrganizerState(ITaskOrganizer organizer, int uid) {
- final Consumer<Runnable> deferTaskOrgCallbacksConsumer =
- mDeferTaskOrgCallbacksConsumer != null
- ? mDeferTaskOrgCallbacksConsumer
- : mService.mWindowManager.mAnimator::addAfterPrepareSurfacesRunnable;
- mOrganizer = new TaskOrganizerCallbacks(mService.mWindowManager, organizer,
- deferTaskOrgCallbacksConsumer);
+ mOrganizer = organizer;
mDeathRecipient = new DeathRecipient(organizer);
try {
organizer.asBinder().linkToDeath(mDeathRecipient, 0);
@@ -188,18 +107,26 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
void addTask(Task t) {
mOrganizedTasks.add(t);
- mOrganizer.onTaskAppeared(t);
+ try {
+ mOrganizer.onTaskAppeared(t.getTaskInfo());
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception sending taskAppeared callback" + e);
+ }
}
void removeTask(Task t) {
+ try {
+ mOrganizer.onTaskVanished(t.getTaskInfo());
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception sending taskVanished callback" + e);
+ }
mOrganizedTasks.remove(t);
- mOrganizer.onTaskVanished(t);
}
void dispose() {
releaseTasks();
for (int i = mTaskOrganizersForWindowingMode.size() - 1; i >= 0; --i) {
- mTaskOrganizersForWindowingMode.valueAt(i).remove(mOrganizer.getBinder());
+ mTaskOrganizersForWindowingMode.valueAt(i).remove(mOrganizer.asBinder());
}
}
@@ -212,7 +139,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
}
void unlinkDeath() {
- mOrganizer.getBinder().unlinkToDeath(mDeathRecipient, 0);
+ mOrganizer.asBinder().unlinkToDeath(mDeathRecipient, 0);
}
}
@@ -222,10 +149,9 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
private final WeakHashMap<Task, RunningTaskInfo> mLastSentTaskInfos = new WeakHashMap<>();
private final ArrayList<Task> mPendingTaskInfoChanges = new ArrayList<>();
- private final ActivityTaskManagerService mService;
+ final ActivityTaskManagerService mService;
- private RunningTaskInfo mTmpTaskInfo;
- private Consumer<Runnable> mDeferTaskOrgCallbacksConsumer;
+ RunningTaskInfo mTmpTaskInfo;
TaskOrganizerController(ActivityTaskManagerService atm) {
mService = atm;
@@ -237,15 +163,6 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
}
/**
- * Specifies the consumer to run to defer the task org callbacks. Can be overridden while
- * testing to allow the callbacks to be sent synchronously.
- */
- @VisibleForTesting
- public void setDeferTaskOrgCallbacksConsumer(Consumer<Runnable> consumer) {
- mDeferTaskOrgCallbacksConsumer = consumer;
- }
-
- /**
* Register a TaskOrganizer to manage tasks as they enter the given windowing mode.
* If there was already a TaskOrganizer for this windowing mode it will be evicted
* but will continue to organize it's existing tasks.
@@ -336,7 +253,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
if (state == null) {
return null;
}
- return state.mOrganizer.mTaskOrganizer;
+ return state.mOrganizer;
}
void onTaskAppeared(ITaskOrganizer organizer, Task task) {
@@ -441,10 +358,11 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
// change.
mTmpTaskInfo = null;
- if (task.isOrganized()) {
- final TaskOrganizerState state = mTaskOrganizerStates.get(
- task.mTaskOrganizer.asBinder());
- state.mOrganizer.onTaskInfoChanged(task, newInfo);
+ if (task.mTaskOrganizer != null) {
+ try {
+ task.mTaskOrganizer.onTaskInfoChanged(newInfo);
+ } catch (RemoteException e) {
+ }
}
}
@@ -603,7 +521,11 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
return false;
}
- state.mOrganizer.onBackPressedOnTaskRoot(task);
+ try {
+ state.mOrganizer.onBackPressedOnTaskRoot(task.getTaskInfo());
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception sending interceptBackPressedOnTaskRoot callback" + e);
+ }
return true;
}
@@ -620,7 +542,7 @@ class TaskOrganizerController extends ITaskOrganizerController.Stub {
final TaskOrganizerState state = mTaskOrganizerStates.get(taskOrgs.get(j));
final ArrayList<Task> tasks = state.mOrganizedTasks;
pw.print(innerPrefix + " ");
- pw.println(state.mOrganizer.mTaskOrganizer + " uid=" + state.mUid + ":");
+ pw.println(state.mOrganizer + " uid=" + state.mUid + ":");
for (int k = 0; k < tasks.size(); k++) {
pw.println(innerPrefix + " " + tasks.get(k));
}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 37a0417fcf75..569b8f61c4f4 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -2207,11 +2207,6 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer<
private Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
boolean isVoiceInteraction) {
- if (isOrganized()) {
- // Defer to the task organizer to run animations
- return null;
- }
-
final DisplayContent displayContent = getDisplayContent();
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
final int width = displayInfo.appWidth;
diff --git a/services/core/xsd/vts/Android.bp b/services/core/xsd/vts/Android.bp
index 636d11069731..a942108667a5 100644
--- a/services/core/xsd/vts/Android.bp
+++ b/services/core/xsd/vts/Android.bp
@@ -36,7 +36,7 @@ cc_test {
],
test_suites: [
"general-tests",
- "vts-core"
+ "vts"
],
test_config: "vts_defaultPermissions_validate_test.xml",
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index d1c47d9feed7..67e83bad154f 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -12459,6 +12459,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
return DevicePolicyManagerService.this.getAllCrossProfilePackages();
}
+ @Override
+ public List<String> getDefaultCrossProfilePackages() {
+ return DevicePolicyManagerService.this.getDefaultCrossProfilePackages();
+ }
+
/**
* Sends the {@code intent} to the packages with cross profile capabilities.
*
diff --git a/services/incremental/Android.bp b/services/incremental/Android.bp
index 02bb0bc3e49c..b13d33054e19 100644
--- a/services/incremental/Android.bp
+++ b/services/incremental/Android.bp
@@ -50,7 +50,6 @@ cc_defaults {
"libbinder",
"libcrypto",
"libcutils",
- "libdataloader",
"libincfs",
"liblog",
"libz",
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index 0da167303ccd..d36eae89c1ff 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -17,7 +17,6 @@
#define LOG_TAG "IncrementalService"
#include "IncrementalService.h"
-#include "IncrementalServiceValidation.h"
#include <android-base/file.h>
#include <android-base/logging.h>
@@ -582,25 +581,29 @@ int IncrementalService::setStorageParams(StorageId storageId, bool enableReadLog
return -EINVAL;
}
- ifs->dataLoaderFilesystemParams.readLogsEnabled = enableReadLogs;
if (enableReadLogs) {
- // We never unregister the callbacks, but given a restricted number of data loaders and even fewer asking for read log access, should be ok.
- registerAppOpsCallback(ifs->dataLoaderParams.packageName);
+ if (auto status =
+ mAppOpsManager->checkPermission(kDataUsageStats, kOpUsage,
+ ifs->dataLoaderParams.packageName.c_str());
+ !status.isOk()) {
+ LOG(ERROR) << "checkPermission failed: " << status.toString8();
+ return fromBinderStatus(status);
+ }
}
- return applyStorageParams(*ifs);
-}
+ if (auto status = applyStorageParams(*ifs, enableReadLogs); !status.isOk()) {
+ LOG(ERROR) << "applyStorageParams failed: " << status.toString8();
+ return fromBinderStatus(status);
+ }
-int IncrementalService::applyStorageParams(IncFsMount& ifs) {
- const bool enableReadLogs = ifs.dataLoaderFilesystemParams.readLogsEnabled;
if (enableReadLogs) {
- if (auto status = CheckPermissionForDataDelivery(kDataUsageStats, kOpUsage);
- !status.isOk()) {
- LOG(ERROR) << "CheckPermissionForDataDelivery failed: " << status.toString8();
- return fromBinderStatus(status);
- }
+ registerAppOpsCallback(ifs->dataLoaderParams.packageName);
}
+ return 0;
+}
+
+binder::Status IncrementalService::applyStorageParams(IncFsMount& ifs, bool enableReadLogs) {
using unique_fd = ::android::base::unique_fd;
::android::os::incremental::IncrementalFileSystemControlParcel control;
control.cmd.reset(unique_fd(dup(ifs.control.cmd())));
@@ -611,13 +614,7 @@ int IncrementalService::applyStorageParams(IncFsMount& ifs) {
}
std::lock_guard l(mMountOperationLock);
- const auto status = mVold->setIncFsMountOptions(control, enableReadLogs);
- if (!status.isOk()) {
- LOG(ERROR) << "Calling Vold::setIncFsMountOptions() failed: " << status.toString8();
- return fromBinderStatus(status);
- }
-
- return 0;
+ return mVold->setIncFsMountOptions(control, enableReadLogs);
}
void IncrementalService::deleteStorage(StorageId storageId) {
@@ -1280,39 +1277,54 @@ bool IncrementalService::configureNativeBinaries(StorageId storage, std::string_
}
void IncrementalService::registerAppOpsCallback(const std::string& packageName) {
- if (packageName.empty()) {
- return;
- }
-
+ sp<IAppOpsCallback> listener;
{
std::unique_lock lock{mCallbacksLock};
- if (!mCallbackRegistered.insert(packageName).second) {
+ auto& cb = mCallbackRegistered[packageName];
+ if (cb) {
return;
}
+ cb = new AppOpsListener(*this, packageName);
+ listener = cb;
}
- /* TODO(b/152633648): restore callback after it's not crashing Binder anymore.
- sp<AppOpsListener> listener = new AppOpsListener(*this, packageName);
mAppOpsManager->startWatchingMode(AppOpsManager::OP_GET_USAGE_STATS, String16(packageName.c_str()), listener);
- */
}
-void IncrementalService::onAppOppChanged(const std::string& packageName) {
+bool IncrementalService::unregisterAppOpsCallback(const std::string& packageName) {
+ sp<IAppOpsCallback> listener;
+ {
+ std::unique_lock lock{mCallbacksLock};
+ auto found = mCallbackRegistered.find(packageName);
+ if (found == mCallbackRegistered.end()) {
+ return false;
+ }
+ listener = found->second;
+ mCallbackRegistered.erase(found);
+ }
+
+ mAppOpsManager->stopWatchingMode(listener);
+ return true;
+}
+
+void IncrementalService::onAppOpChanged(const std::string& packageName) {
+ if (!unregisterAppOpsCallback(packageName)) {
+ return;
+ }
+
std::vector<IfsMountPtr> affected;
{
std::lock_guard l(mLock);
affected.reserve(mMounts.size());
for (auto&& [id, ifs] : mMounts) {
- if (ifs->dataLoaderFilesystemParams.readLogsEnabled && ifs->dataLoaderParams.packageName == packageName) {
+ if (ifs->mountId == id && ifs->dataLoaderParams.packageName == packageName) {
affected.push_back(ifs);
}
}
}
- /* TODO(b/152633648): restore callback after it's not crashing Kernel anymore.
for (auto&& ifs : affected) {
- applyStorageParams(*ifs);
+ applyStorageParams(*ifs, false);
}
- */
}
binder::Status IncrementalService::IncrementalDataLoaderListener::onStatusChanged(MountId mountId,
@@ -1378,8 +1390,8 @@ binder::Status IncrementalService::IncrementalDataLoaderListener::onStatusChange
return binder::Status::ok();
}
-void IncrementalService::AppOpsListener::opChanged(int32_t op, const String16&) {
- incrementalService.onAppOppChanged(packageName);
+void IncrementalService::AppOpsListener::opChanged(int32_t, const String16&) {
+ incrementalService.onAppOpChanged(packageName);
}
} // namespace android::incremental
diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h
index ff69633e185b..58002974e180 100644
--- a/services/incremental/IncrementalService.h
+++ b/services/incremental/IncrementalService.h
@@ -40,7 +40,6 @@
#include "ServiceWrappers.h"
#include "android/content/pm/BnDataLoaderStatusListener.h"
#include "incfs.h"
-#include "dataloader_ndk.h"
#include "path.h"
using namespace android::os::incremental;
@@ -182,7 +181,6 @@ private:
StorageMap storages;
BindMap bindPoints;
DataLoaderParamsParcel dataLoaderParams;
- DataLoaderFilesystemParams dataLoaderFilesystemParams;
std::atomic<int> nextStorageDirNo{0};
std::atomic<int> dataLoaderStatus = -1;
bool dataLoaderStartRequested = false;
@@ -193,9 +191,7 @@ private:
: root(std::move(root)),
control(std::move(control)),
mountId(mountId),
- incrementalService(incrementalService) {
- dataLoaderFilesystemParams.readLogsEnabled = false;
- }
+ incrementalService(incrementalService) {}
IncFsMount(IncFsMount&&) = delete;
IncFsMount& operator=(IncFsMount&&) = delete;
~IncFsMount();
@@ -234,10 +230,11 @@ private:
std::string normalizePathToStorage(const IfsMountPtr incfs, StorageId storage,
std::string_view path);
- int applyStorageParams(IncFsMount& ifs);
+ binder::Status applyStorageParams(IncFsMount& ifs, bool enableReadLogs);
void registerAppOpsCallback(const std::string& packageName);
- void onAppOppChanged(const std::string& packageName);
+ bool unregisterAppOpsCallback(const std::string& packageName);
+ void onAppOpChanged(const std::string& packageName);
// Member variables
std::unique_ptr<VoldServiceWrapper> const mVold;
@@ -252,7 +249,7 @@ private:
BindPathMap mBindsByPath;
std::mutex mCallbacksLock;
- std::set<std::string> mCallbackRegistered;
+ std::map<std::string, sp<AppOpsListener>> mCallbackRegistered;
std::atomic_bool mSystemReady = false;
StorageId mNextId = 0;
diff --git a/services/incremental/IncrementalServiceValidation.h b/services/incremental/IncrementalServiceValidation.h
index 24f9f7f94dfd..48894c6926c8 100644
--- a/services/incremental/IncrementalServiceValidation.h
+++ b/services/incremental/IncrementalServiceValidation.h
@@ -41,7 +41,8 @@ inline int fromBinderStatus(const binder::Status& status) {
: -EIO;
}
-inline binder::Status CheckPermissionForDataDelivery(const char* permission, const char* operation) {
+inline binder::Status CheckPermissionForDataDelivery(const char* permission, const char* operation,
+ const char* package) {
using android::base::StringPrintf;
int32_t pid;
@@ -52,23 +53,23 @@ inline binder::Status CheckPermissionForDataDelivery(const char* permission, con
StringPrintf("UID %d / PID %d lacks permission %s", uid, pid, permission));
}
+ String16 packageName{package};
+
// Caller must also have op granted.
PermissionController pc;
- // Package is a required parameter. Need to obtain one.
- Vector<String16> packages;
- pc.getPackagesForUid(uid, packages);
- if (packages.empty()) {
+ if (auto packageUid = pc.getPackageUid(packageName, 0); packageUid != uid) {
return Exception(binder::Status::EX_SECURITY,
- StringPrintf("UID %d / PID %d has no packages", uid, pid));
+ StringPrintf("UID %d / PID %d does not own package %s", uid, pid,
+ package));
}
- switch (auto result = pc.noteOp(String16(operation), uid, packages[0]); result) {
+ switch (auto result = pc.noteOp(String16(operation), uid, packageName); result) {
case PermissionController::MODE_ALLOWED:
case PermissionController::MODE_DEFAULT:
return binder::Status::ok();
default:
return Exception(binder::Status::EX_SECURITY,
- StringPrintf("UID %d / PID %d lacks app-op %s, error %d", uid, pid,
- operation, result));
+ StringPrintf("UID %d / PID %d / package %s lacks app-op %s, error %d",
+ uid, pid, package, operation, result));
}
}
diff --git a/services/incremental/ServiceWrappers.h b/services/incremental/ServiceWrappers.h
index 449b457045c6..84bf1ffaf45c 100644
--- a/services/incremental/ServiceWrappers.h
+++ b/services/incremental/ServiceWrappers.h
@@ -16,6 +16,8 @@
#pragma once
+#include "IncrementalServiceValidation.h"
+
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <android/content/pm/DataLoaderParamsParcel.h>
@@ -85,7 +87,10 @@ public:
class AppOpsManagerWrapper {
public:
virtual ~AppOpsManagerWrapper() = default;
+ virtual binder::Status checkPermission(const char* permission, const char* operation,
+ const char* package) const = 0;
virtual void startWatchingMode(int32_t op, const String16& packageName, const sp<IAppOpsCallback>& callback) = 0;
+ virtual void stopWatchingMode(const sp<IAppOpsCallback>& callback) = 0;
};
class ServiceManagerWrapper {
@@ -105,17 +110,19 @@ public:
~RealVoldService() = default;
binder::Status mountIncFs(const std::string& backingPath, const std::string& targetDir,
int32_t flags,
- IncrementalFileSystemControlParcel* _aidl_return) const override {
+ IncrementalFileSystemControlParcel* _aidl_return) const final {
return mInterface->mountIncFs(backingPath, targetDir, flags, _aidl_return);
}
- binder::Status unmountIncFs(const std::string& dir) const override {
+ binder::Status unmountIncFs(const std::string& dir) const final {
return mInterface->unmountIncFs(dir);
}
binder::Status bindMount(const std::string& sourceDir,
- const std::string& targetDir) const override {
+ const std::string& targetDir) const final {
return mInterface->bindMount(sourceDir, targetDir);
}
- binder::Status setIncFsMountOptions(const ::android::os::incremental::IncrementalFileSystemControlParcel& control, bool enableReadLogs) const override {
+ binder::Status setIncFsMountOptions(
+ const ::android::os::incremental::IncrementalFileSystemControlParcel& control,
+ bool enableReadLogs) const final {
return mInterface->setIncFsMountOptions(control, enableReadLogs);
}
@@ -131,13 +138,13 @@ public:
binder::Status initializeDataLoader(MountId mountId, const DataLoaderParamsParcel& params,
const FileSystemControlParcel& control,
const sp<IDataLoaderStatusListener>& listener,
- bool* _aidl_return) const override {
+ bool* _aidl_return) const final {
return mInterface->initializeDataLoader(mountId, params, control, listener, _aidl_return);
}
- binder::Status getDataLoader(MountId mountId, sp<IDataLoader>* _aidl_return) const override {
+ binder::Status getDataLoader(MountId mountId, sp<IDataLoader>* _aidl_return) const final {
return mInterface->getDataLoader(mountId, _aidl_return);
}
- binder::Status destroyDataLoader(MountId mountId) const override {
+ binder::Status destroyDataLoader(MountId mountId) const final {
return mInterface->destroyDataLoader(mountId);
}
@@ -148,9 +155,18 @@ private:
class RealAppOpsManager : public AppOpsManagerWrapper {
public:
~RealAppOpsManager() = default;
- void startWatchingMode(int32_t op, const String16& packageName, const sp<IAppOpsCallback>& callback) override {
+ binder::Status checkPermission(const char* permission, const char* operation,
+ const char* package) const final {
+ return android::incremental::CheckPermissionForDataDelivery(permission, operation, package);
+ }
+ void startWatchingMode(int32_t op, const String16& packageName,
+ const sp<IAppOpsCallback>& callback) final {
mAppOpsManager.startWatchingMode(op, packageName, callback);
}
+ void stopWatchingMode(const sp<IAppOpsCallback>& callback) final {
+ mAppOpsManager.stopWatchingMode(callback);
+ }
+
private:
android::AppOpsManager mAppOpsManager;
};
@@ -174,36 +190,35 @@ class RealIncFs : public IncFsWrapper {
public:
RealIncFs() = default;
~RealIncFs() = default;
- Control createControl(IncFsFd cmd, IncFsFd pendingReads, IncFsFd logs) const override {
+ Control createControl(IncFsFd cmd, IncFsFd pendingReads, IncFsFd logs) const final {
return incfs::createControl(cmd, pendingReads, logs);
}
ErrorCode makeFile(const Control& control, std::string_view path, int mode, FileId id,
- NewFileParams params) const override {
+ NewFileParams params) const final {
return incfs::makeFile(control, path, mode, id, params);
}
- ErrorCode makeDir(const Control& control, std::string_view path, int mode) const override {
+ ErrorCode makeDir(const Control& control, std::string_view path, int mode) const final {
return incfs::makeDir(control, path, mode);
}
- RawMetadata getMetadata(const Control& control, FileId fileid) const override {
+ RawMetadata getMetadata(const Control& control, FileId fileid) const final {
return incfs::getMetadata(control, fileid);
}
- RawMetadata getMetadata(const Control& control, std::string_view path) const override {
+ RawMetadata getMetadata(const Control& control, std::string_view path) const final {
return incfs::getMetadata(control, path);
}
- FileId getFileId(const Control& control, std::string_view path) const override {
+ FileId getFileId(const Control& control, std::string_view path) const final {
return incfs::getFileId(control, path);
}
- ErrorCode link(const Control& control, std::string_view from,
- std::string_view to) const override {
+ ErrorCode link(const Control& control, std::string_view from, std::string_view to) const final {
return incfs::link(control, from, to);
}
- ErrorCode unlink(const Control& control, std::string_view path) const override {
+ ErrorCode unlink(const Control& control, std::string_view path) const final {
return incfs::unlink(control, path);
}
- base::unique_fd openForSpecialOps(const Control& control, FileId id) const override {
+ base::unique_fd openForSpecialOps(const Control& control, FileId id) const final {
return base::unique_fd{incfs::openForSpecialOps(control, id).release()};
}
- ErrorCode writeBlocks(Span<const DataBlock> blocks) const override {
+ ErrorCode writeBlocks(Span<const DataBlock> blocks) const final {
return incfs::writeBlocks(blocks);
}
};
diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp
index 5553f688060a..0635ae169281 100644
--- a/services/incremental/test/IncrementalServiceTest.cpp
+++ b/services/incremental/test/IncrementalServiceTest.cpp
@@ -221,7 +221,28 @@ public:
};
class MockAppOpsManager : public AppOpsManagerWrapper {
+public:
+ MOCK_CONST_METHOD3(checkPermission, binder::Status(const char*, const char*, const char*));
MOCK_METHOD3(startWatchingMode, void(int32_t, const String16&, const sp<IAppOpsCallback>&));
+ MOCK_METHOD1(stopWatchingMode, void(const sp<IAppOpsCallback>&));
+
+ void checkPermissionSuccess() {
+ ON_CALL(*this, checkPermission(_, _, _)).WillByDefault(Return(android::incremental::Ok()));
+ }
+ void checkPermissionFails() {
+ ON_CALL(*this, checkPermission(_, _, _))
+ .WillByDefault(
+ Return(android::incremental::Exception(binder::Status::EX_SECURITY, {})));
+ }
+ void initializeStartWatchingMode() {
+ ON_CALL(*this, startWatchingMode(_, _, _))
+ .WillByDefault(Invoke(this, &MockAppOpsManager::storeCallback));
+ }
+ void storeCallback(int32_t, const String16&, const sp<IAppOpsCallback>& cb) {
+ mStoredCallback = cb;
+ }
+
+ sp<IAppOpsCallback> mStoredCallback;
};
class MockServiceManager : public ServiceManagerWrapper {
@@ -418,9 +439,15 @@ TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccess) {
mVold->setIncFsMountOptionsSuccess();
mDataLoaderManager->initializeDataLoaderSuccess();
mDataLoaderManager->getDataLoaderSuccess();
+ mAppOpsManager->checkPermissionSuccess();
EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_));
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
- EXPECT_CALL(*mVold, setIncFsMountOptions(_, _));
+ // We are calling setIncFsMountOptions(true).
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, true)).Times(1);
+ // After setIncFsMountOptions succeeded expecting to start watching.
+ EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(1);
+ // Not expecting callback removal.
+ EXPECT_CALL(*mAppOpsManager, stopWatchingMode(_)).Times(0);
TemporaryDir tempDir;
int storageId =
mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
@@ -429,6 +456,56 @@ TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccess) {
ASSERT_GE(mIncrementalService->setStorageParams(storageId, true), 0);
}
+TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccessAndPermissionChanged) {
+ mVold->mountIncFsSuccess();
+ mIncFs->makeFileSuccess();
+ mVold->bindMountSuccess();
+ mVold->setIncFsMountOptionsSuccess();
+ mDataLoaderManager->initializeDataLoaderSuccess();
+ mDataLoaderManager->getDataLoaderSuccess();
+ mAppOpsManager->checkPermissionSuccess();
+ mAppOpsManager->initializeStartWatchingMode();
+ EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_));
+ EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
+ // We are calling setIncFsMountOptions(true).
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, true)).Times(1);
+ // setIncFsMountOptions(false) is called on the callback.
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, false)).Times(1);
+ // After setIncFsMountOptions succeeded expecting to start watching.
+ EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(1);
+ // After callback is called, disable read logs and remove callback.
+ EXPECT_CALL(*mAppOpsManager, stopWatchingMode(_)).Times(1);
+ TemporaryDir tempDir;
+ int storageId =
+ mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
+ IncrementalService::CreateOptions::CreateNew);
+ ASSERT_GE(storageId, 0);
+ ASSERT_GE(mIncrementalService->setStorageParams(storageId, true), 0);
+ ASSERT_NE(nullptr, mAppOpsManager->mStoredCallback.get());
+ mAppOpsManager->mStoredCallback->opChanged(0, {});
+}
+
+TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsCheckPermissionFails) {
+ mVold->mountIncFsSuccess();
+ mIncFs->makeFileSuccess();
+ mVold->bindMountSuccess();
+ mDataLoaderManager->initializeDataLoaderSuccess();
+ mDataLoaderManager->getDataLoaderSuccess();
+ mAppOpsManager->checkPermissionFails();
+ EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_));
+ EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
+ // checkPermission fails, no calls to set opitions, start or stop WatchingMode.
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, true)).Times(0);
+ EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(0);
+ EXPECT_CALL(*mAppOpsManager, stopWatchingMode(_)).Times(0);
+ TemporaryDir tempDir;
+ int storageId =
+ mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
+ IncrementalService::CreateOptions::CreateNew);
+ ASSERT_GE(storageId, 0);
+ ASSERT_LT(mIncrementalService->setStorageParams(storageId, true), 0);
+}
+
TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsFails) {
mVold->mountIncFsSuccess();
mIncFs->makeFileSuccess();
@@ -436,9 +513,14 @@ TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsFails) {
mVold->setIncFsMountOptionsFails();
mDataLoaderManager->initializeDataLoaderSuccess();
mDataLoaderManager->getDataLoaderSuccess();
+ mAppOpsManager->checkPermissionSuccess();
EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_));
EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2);
- EXPECT_CALL(*mVold, setIncFsMountOptions(_, _));
+ // We are calling setIncFsMountOptions.
+ EXPECT_CALL(*mVold, setIncFsMountOptions(_, true)).Times(1);
+ // setIncFsMountOptions fails, no calls to start or stop WatchingMode.
+ EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(0);
+ EXPECT_CALL(*mAppOpsManager, stopWatchingMode(_)).Times(0);
TemporaryDir tempDir;
int storageId =
mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {},
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 2a914ecf4db6..e5ffbacb357b 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -519,10 +519,8 @@ public final class SystemServer {
// Initialize native services.
System.loadLibrary("android_servers");
- // Debug builds - allow heap profiling.
- if (Build.IS_DEBUGGABLE) {
- initZygoteChildHeapProfiling();
- }
+ // Allow heap / perf profiling.
+ initZygoteChildHeapProfiling();
// Debug builds - spawn a thread to monitor for fd leaks.
if (Build.IS_DEBUGGABLE) {
diff --git a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
index 138f9829c088..f8d197acf883 100644
--- a/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
+++ b/services/robotests/src/com/android/server/pm/CrossProfileAppsServiceImplRoboTest.java
@@ -199,6 +199,12 @@ public class CrossProfileAppsServiceImplRoboTest {
CROSS_PROFILE_APP_PACKAGE_NAME, PERSONAL_PROFILE_UID, PERSONAL_PROFILE_USER_ID);
ShadowApplicationPackageManager.setPackageUidAsUser(
CROSS_PROFILE_APP_PACKAGE_NAME, WORK_PROFILE_UID, WORK_PROFILE_USER_ID);
+ when(mPackageManagerInternal.getPackageUidInternal(
+ CROSS_PROFILE_APP_PACKAGE_NAME, /* flags= */ 0, PERSONAL_PROFILE_USER_ID))
+ .thenReturn(PERSONAL_PROFILE_UID);
+ when(mPackageManagerInternal.getPackageUidInternal(
+ CROSS_PROFILE_APP_PACKAGE_NAME, /* flags= */ 0, WORK_PROFILE_USER_ID))
+ .thenReturn(WORK_PROFILE_UID);
}
@Before
@@ -456,6 +462,19 @@ public class CrossProfileAppsServiceImplRoboTest {
}
@Test
+ public void canUserAttemptToConfigureInteractAcrossProfiles_platformSignedAppWithAutomaticPermission_returnsFalse() {
+ mockCrossProfileAppNotWhitelistedByOem();
+ shadowOf(mContext).grantPermissions(
+ Process.myPid(),
+ PERSONAL_PROFILE_UID,
+ Manifest.permission.INTERACT_ACROSS_PROFILES);
+
+ assertThat(mCrossProfileAppsServiceImpl
+ .canUserAttemptToConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME))
+ .isFalse();
+ }
+
+ @Test
public void canUserAttemptToConfigureInteractAcrossProfiles_returnsTrue() {
assertThat(mCrossProfileAppsServiceImpl
.canUserAttemptToConfigureInteractAcrossProfiles(CROSS_PROFILE_APP_PACKAGE_NAME))
@@ -528,6 +547,11 @@ public class CrossProfileAppsServiceImplRoboTest {
.thenReturn(new ArrayList<>());
}
+ private void mockCrossProfileAppNotWhitelistedByOem() {
+ when(mDevicePolicyManagerInternal.getDefaultCrossProfilePackages())
+ .thenReturn(new ArrayList<>());
+ }
+
private boolean receivedManifestCanInteractAcrossProfilesChangedBroadcast() {
final UserHandle userHandle = UserHandle.of(PERSONAL_PROFILE_USER_ID);
if (!mSentUserBroadcasts.containsKey(userHandle)) {
diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
index 5109de501157..b60e99363706 100644
--- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
@@ -17,7 +17,9 @@
package com.android.server.pm;
-import static org.hamcrest.Matchers.arrayContaining;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.Matchers.empty;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
@@ -48,7 +50,6 @@ import com.android.server.pm.parsing.pkg.AndroidPackage;
import com.android.server.pm.parsing.pkg.PackageImpl;
import com.android.server.pm.parsing.pkg.ParsedPackage;
-import org.hamcrest.Matcher;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -58,7 +59,7 @@ import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.security.cert.CertificateException;
-import java.util.Arrays;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -650,32 +651,32 @@ public class AppsFilterTest {
final int hasProviderAppId = Process.FIRST_APPLICATION_UID + 1;
final int queriesProviderAppId = Process.FIRST_APPLICATION_UID + 2;
PackageSetting system = simulateAddPackage(appsFilter, pkg("some.system.pkg"), systemAppId);
- PackageSetting seesNothing = simulateAddPackage(appsFilter, pkg("some.system.pkg"),
+ PackageSetting seesNothing = simulateAddPackage(appsFilter, pkg("com.some.package"),
seesNothingAppId);
PackageSetting hasProvider = simulateAddPackage(appsFilter,
- pkgWithProvider("com.some.package", "com.some.authority"), hasProviderAppId);
+ pkgWithProvider("com.some.other.package", "com.some.authority"), hasProviderAppId);
PackageSetting queriesProvider = simulateAddPackage(appsFilter,
- pkgQueriesProvider("com.some.other.package", "com.some.authority"),
+ pkgQueriesProvider("com.yet.some.other.package", "com.some.authority"),
queriesProviderAppId);
final int[] systemFilter =
appsFilter.getVisibilityWhitelist(system, new int[]{0}, mExisting).get(0);
- assertThat(Arrays.asList(systemFilter), arrayContaining(systemAppId));
+ assertThat(toList(systemFilter), empty());
final int[] seesNothingFilter =
appsFilter.getVisibilityWhitelist(seesNothing, new int[]{0}, mExisting).get(0);
- assertThat(Arrays.asList(seesNothingFilter),
- arrayContaining(systemAppId, seesNothingAppId));
+ assertThat(toList(seesNothingFilter),
+ contains(seesNothingAppId));
final int[] hasProviderFilter =
appsFilter.getVisibilityWhitelist(hasProvider, new int[]{0}, mExisting).get(0);
- assertThat(Arrays.asList(hasProviderFilter),
- arrayContaining(systemAppId, hasProviderAppId, queriesProviderAppId));
+ assertThat(toList(hasProviderFilter),
+ contains(hasProviderAppId, queriesProviderAppId));
int[] queriesProviderFilter =
appsFilter.getVisibilityWhitelist(queriesProvider, new int[]{0}, mExisting).get(0);
- assertThat(Arrays.asList(queriesProviderFilter),
- arrayContaining(systemAppId, queriesProviderAppId));
+ assertThat(toList(queriesProviderFilter),
+ contains(queriesProviderAppId));
// provider read
appsFilter.grantImplicitAccess(hasProviderAppId, queriesProviderAppId);
@@ -683,11 +684,16 @@ public class AppsFilterTest {
// ensure implicit access is included in the filter
queriesProviderFilter =
appsFilter.getVisibilityWhitelist(queriesProvider, new int[]{0}, mExisting).get(0);
- assertThat(Arrays.asList(queriesProviderFilter),
- arrayContaining(systemAppId, hasProviderAppId, queriesProviderAppId));
+ assertThat(toList(queriesProviderFilter),
+ contains(hasProviderAppId, queriesProviderAppId));
}
- private void assertThat(List<int[]> asList, Matcher<Integer[]> arrayContainingInAnyOrder) {
+ private List<Integer> toList(int[] array) {
+ ArrayList<Integer> ret = new ArrayList<>(array.length);
+ for (int i = 0; i < array.length; i++) {
+ ret.add(i, array[i]);
+ }
+ return ret;
}
private interface WithSettingBuilder {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelExtractorTest.java
index 47ad83147262..a23ade68b344 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelExtractorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelExtractorTest.java
@@ -18,7 +18,6 @@ package com.android.server.notification;
import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static android.app.NotificationManager.IMPORTANCE_LOW;
-import static android.util.FeatureFlagUtils.NOTIF_CONVO_BYPASS_SHORTCUT_REQ;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNull;
@@ -77,8 +76,8 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase {
@Test
public void testInvalidShortcutFlagEnabled_looksUpCorrectChannel() {
- Settings.Global.putString(
- mContext.getContentResolver(), NOTIF_CONVO_BYPASS_SHORTCUT_REQ, "true");
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 0);
NotificationChannelExtractor extractor = new NotificationChannelExtractor();
extractor.setConfig(mConfig);
@@ -97,7 +96,8 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase {
NotificationChannel updatedChannel =
new NotificationChannel("a", "", IMPORTANCE_HIGH);
when(mConfig.getConversationNotificationChannel(
- any(), anyInt(), eq("a"), eq(r.getSbn().getShortcutId(mContext)), eq(true), eq(false)))
+ any(), anyInt(), eq("a"), eq(r.getSbn().getShortcutId(mContext)),
+ eq(true), eq(false)))
.thenReturn(updatedChannel);
assertNull(extractor.process(r));
@@ -106,8 +106,8 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase {
@Test
public void testInvalidShortcutFlagDisabled_looksUpCorrectChannel() {
- Settings.Global.putString(
- mContext.getContentResolver(), NOTIF_CONVO_BYPASS_SHORTCUT_REQ, "false");
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 1);
NotificationChannelExtractor extractor = new NotificationChannelExtractor();
extractor.setConfig(mConfig);
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 f9596b53407f..15220e1ff54a 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -4791,7 +4791,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
// enqueue toast -> no toasts enqueued
((INotificationManager) mService.mService).enqueueTextToast(testPackage, new Binder(),
"Text", 2000, 0, null);
- verify(mStatusBar).showToast(any(), any(), any(), any(), anyInt(), any());
+ verify(mStatusBar).showToast(anyInt(), any(), any(), any(), any(), anyInt(), any());
}
@Test
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 00b9273c1eb1..3139bfaaf1f5 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
@@ -63,7 +63,6 @@ import android.os.UserHandle;
import android.provider.Settings;
import android.service.notification.Adjustment;
import android.service.notification.StatusBarNotification;
-import android.util.FeatureFlagUtils;
import android.widget.RemoteViews;
import androidx.test.filters.SmallTest;
@@ -124,8 +123,8 @@ public class NotificationRecordTest extends UiServiceTestCase {
when(mMockContext.getResources()).thenReturn(getContext().getResources());
when(mMockContext.getPackageManager()).thenReturn(mPm);
when(mMockContext.getContentResolver()).thenReturn(mContentResolver);
- Settings.Global.putString(mContentResolver,
- FeatureFlagUtils.NOTIF_CONVO_BYPASS_SHORTCUT_REQ, "false");
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 1);
ApplicationInfo appInfo = new ApplicationInfo();
appInfo.targetSdkVersion = Build.VERSION_CODES.O;
when(mMockContext.getApplicationInfo()).thenReturn(appInfo);
@@ -1138,8 +1137,8 @@ public class NotificationRecordTest extends UiServiceTestCase {
@Test
public void testIsConversation_bypassShortcutFlagEnabled() {
- Settings.Global.putString(mContentResolver,
- FeatureFlagUtils.NOTIF_CONVO_BYPASS_SHORTCUT_REQ, "true");
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 0);
StatusBarNotification sbn = getMessagingStyleNotification();
NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
record.setShortcutInfo(null);
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 af605112307f..ed5ec6ac785b 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -22,7 +22,6 @@ import static android.app.NotificationManager.IMPORTANCE_LOW;
import static android.app.NotificationManager.IMPORTANCE_MAX;
import static android.app.NotificationManager.IMPORTANCE_NONE;
import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
-import static android.util.FeatureFlagUtils.NOTIF_CONVO_BYPASS_SHORTCUT_REQ;
import static com.android.server.notification.PreferencesHelper.NOTIFICATION_CHANNEL_COUNT_LIMIT;
@@ -2922,9 +2921,10 @@ public class PreferencesHelperTest extends UiServiceTestCase {
}
@Test
- public void testPlaceholderConversationId_flagOn() throws Exception {
- Settings.Global.putString(
- mContext.getContentResolver(), NOTIF_CONVO_BYPASS_SHORTCUT_REQ, "true");
+ public void testPlaceholderConversationId_shortcutNotRequired() throws Exception {
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 0);
+
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger);
final String xml = "<ranking version=\"1\">\n"
@@ -2942,9 +2942,9 @@ public class PreferencesHelperTest extends UiServiceTestCase {
}
@Test
- public void testPlaceholderConversationId_flagOff() throws Exception {
- Settings.Global.putString(
- mContext.getContentResolver(), NOTIF_CONVO_BYPASS_SHORTCUT_REQ, "false");
+ public void testPlaceholderConversationId_shortcutRequired() throws Exception {
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 1);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger);
final String xml = "<ranking version=\"1\">\n"
@@ -2962,9 +2962,9 @@ public class PreferencesHelperTest extends UiServiceTestCase {
}
@Test
- public void testNormalConversationId_flagOff() throws Exception {
- Settings.Global.putString(
- mContext.getContentResolver(), NOTIF_CONVO_BYPASS_SHORTCUT_REQ, "false");
+ public void testNormalConversationId_shortcutRequired() throws Exception {
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 1);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger);
final String xml = "<ranking version=\"1\">\n"
@@ -2982,9 +2982,9 @@ public class PreferencesHelperTest extends UiServiceTestCase {
}
@Test
- public void testNoConversationId_flagOff() throws Exception {
- Settings.Global.putString(
- mContext.getContentResolver(), NOTIF_CONVO_BYPASS_SHORTCUT_REQ, "false");
+ public void testNoConversationId_shortcutRequired() throws Exception {
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 1);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger);
final String xml = "<ranking version=\"1\">\n"
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
index 62d311ae7b36..2ce9c2b9ced0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
@@ -69,8 +69,6 @@ import android.window.WindowContainerTransaction;
import androidx.test.filters.SmallTest;
-import org.junit.After;
-import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -119,13 +117,6 @@ public class TaskOrganizerTests extends WindowTestsBase {
return createTaskStackOnDisplay(mDisplayContent);
}
- @Before
- public void setUp() {
- // We defer callbacks since we need to adjust task surface visibility, but for these tests,
- // just run the callbacks synchronously
- mWm.mAtmService.mTaskOrganizerController.setDeferTaskOrgCallbacksConsumer((r) -> r.run());
- }
-
@Test
public void testAppearVanish() throws RemoteException {
final ActivityStack stack = createStack();
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
index 6c0f2b0cd278..edbdd4e94ac8 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
@@ -40,6 +40,9 @@ import android.hardware.soundtrigger.SoundTrigger.SoundModelEvent;
import android.hardware.soundtrigger.SoundTriggerModule;
import android.os.Binder;
import android.os.DeadObjectException;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
import android.os.PowerManager;
import android.os.PowerManager.ServiceType;
import android.os.RemoteException;
@@ -113,6 +116,13 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
private PowerSaveModeListener mPowerSaveModeListener;
+ // Handler to process call state changes will delay to allow time for the audio
+ // and sound trigger HALs to process the end of call notifications
+ // before we re enable pending recognition requests.
+ private final Handler mHandler;
+ private static final int MSG_CALL_STATE_CHANGED = 0;
+ private static final int CALL_INACTIVE_MSG_DELAY_MS = 1000;
+
SoundTriggerHelper(Context context) {
ArrayList <ModuleProperties> modules = new ArrayList<>();
int status = SoundTrigger.listModules(modules);
@@ -130,6 +140,31 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
// TODO: Figure out how to determine which module corresponds to the DSP hardware.
mModuleProperties = modules.get(0);
}
+
+ Looper looper = Looper.myLooper();
+ if (looper == null) {
+ looper = Looper.getMainLooper();
+ }
+ if (looper != null) {
+ mHandler = new Handler(looper) {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_CALL_STATE_CHANGED:
+ synchronized (mLock) {
+ onCallStateChangedLocked(
+ TelephonyManager.CALL_STATE_OFFHOOK == msg.arg1);
+ }
+ break;
+ default:
+ Slog.e(TAG, "unknown message in handler:" + msg.what);
+ break;
+ }
+ }
+ };
+ } else {
+ mHandler = null;
+ }
}
/**
@@ -227,6 +262,37 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
return status;
}
+ private int prepareForRecognition(ModelData modelData) {
+ if (mModule == null) {
+ mModule = SoundTrigger.attachModule(mModuleProperties.getId(), this, null);
+ if (mModule == null) {
+ Slog.w(TAG, "prepareForRecognition: cannot attach to sound trigger module");
+ return STATUS_ERROR;
+ }
+ }
+ // Load the model if it is not loaded.
+ if (!modelData.isModelLoaded()) {
+ // Before we try and load this model, we should first make sure that any other
+ // models that don't have an active recognition/dead callback are unloaded. Since
+ // there is a finite limit on the number of models that the hardware may be able to
+ // have loaded, we want to make sure there's room for our model.
+ stopAndUnloadDeadModelsLocked();
+ int[] handle = new int[] { 0 };
+ int status = mModule.loadSoundModel(modelData.getSoundModel(), handle);
+ if (status != SoundTrigger.STATUS_OK) {
+ Slog.w(TAG, "prepareForRecognition: loadSoundModel failed with status: " + status);
+ return status;
+ }
+ modelData.setHandle(handle[0]);
+ modelData.setLoaded();
+ if (DBG) {
+ Slog.d(TAG, "prepareForRecognition: Sound model loaded with handle:" + handle[0]);
+ }
+ }
+ return STATUS_OK;
+ }
+
+
/**
* Starts recognition for the given sound model. A single routine for both keyphrase and
* generic sound models.
@@ -248,12 +314,17 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
Slog.w(TAG, "Attempting startRecognition without the capability");
return STATUS_ERROR;
}
- if (mModule == null) {
- mModule = SoundTrigger.attachModule(mModuleProperties.getId(), this, null);
- if (mModule == null) {
- Slog.w(TAG, "startRecognition cannot attach to sound trigger module");
- return STATUS_ERROR;
+
+ IRecognitionStatusCallback oldCallback = modelData.getCallback();
+ if (oldCallback != null && oldCallback.asBinder() != callback.asBinder()) {
+ Slog.w(TAG, "Canceling previous recognition for model id: "
+ + modelData.getModelId());
+ try {
+ oldCallback.onError(STATUS_ERROR);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "RemoteException in onDetectionStopped", e);
}
+ modelData.clearCallback();
}
// If the existing SoundModel is different (for the same UUID for Generic and same
@@ -287,48 +358,25 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
}
}
- IRecognitionStatusCallback oldCallback = modelData.getCallback();
- if (oldCallback != null && oldCallback.asBinder() != callback.asBinder()) {
- Slog.w(TAG, "Canceling previous recognition for model id: " +
- modelData.getModelId());
- try {
- oldCallback.onError(STATUS_ERROR);
- } catch (RemoteException e) {
- Slog.w(TAG, "RemoteException in onDetectionStopped", e);
- }
- modelData.clearCallback();
- }
-
- // Load the model if it is not loaded.
- if (!modelData.isModelLoaded()) {
- // Before we try and load this model, we should first make sure that any other
- // models that don't have an active recognition/dead callback are unloaded. Since
- // there is a finite limit on the number of models that the hardware may be able to
- // have loaded, we want to make sure there's room for our model.
- stopAndUnloadDeadModelsLocked();
- int[] handle = new int[] { INVALID_VALUE };
- int status = mModule.loadSoundModel(soundModel, handle);
- if (status != SoundTrigger.STATUS_OK) {
- Slog.w(TAG, "loadSoundModel call failed with " + status);
- return status;
- }
- if (handle[0] == INVALID_VALUE) {
- Slog.w(TAG, "loadSoundModel call returned invalid sound model handle");
- return STATUS_ERROR;
- }
- modelData.setHandle(handle[0]);
- modelData.setLoaded();
- Slog.d(TAG, "Sound model loaded with handle:" + handle[0]);
- }
modelData.setCallback(callback);
modelData.setRequested(true);
modelData.setRecognitionConfig(recognitionConfig);
modelData.setSoundModel(soundModel);
- int status = startRecognitionLocked(modelData,
+ if (!isRecognitionAllowed()) {
+ initializeTelephonyAndPowerStateListeners();
+ return STATUS_OK;
+ }
+
+ int status = prepareForRecognition(modelData);
+ if (status != STATUS_OK) {
+ Slog.w(TAG, "startRecognition failed to prepare model for recognition");
+ return status;
+ }
+ status = startRecognitionLocked(modelData,
false /* Don't notify for synchronous calls */);
- // Initialize power save, call active state monitoring logic.
+ // Initialize power save, call active state monitoring logic.
if (status == STATUS_OK) {
initializeTelephonyAndPowerStateListeners();
}
@@ -398,7 +446,8 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
if (DBG) {
Slog.d(TAG, "stopRecognition for keyphraseId=" + keyphraseId + ", callback =" +
callback.asBinder());
- Slog.d(TAG, "current callback=" + (modelData == null ? "null" :
+ Slog.d(TAG, "current callback="
+ + ((modelData == null || modelData.getCallback() == null) ? "null" :
modelData.getCallback().asBinder()));
}
int status = stopRecognition(modelData, callback);
@@ -507,8 +556,8 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
synchronized (mLock) {
MetricsLogger.count(mContext, "sth_unload_keyphrase_sound_model", 1);
ModelData modelData = getKeyphraseModelDataLocked(keyphraseId);
- if (mModule == null || modelData == null || modelData.getHandle() == INVALID_VALUE ||
- !modelData.isKeyphraseModel()) {
+ if (mModule == null || modelData == null || !modelData.isModelLoaded()
+ || !modelData.isKeyphraseModel()) {
return STATUS_ERROR;
}
@@ -943,6 +992,10 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
return STATUS_OK;
}
if (start) {
+ int status = prepareForRecognition(model);
+ if (status != STATUS_OK) {
+ return status;
+ }
return startRecognitionLocked(model, notify);
} else {
return stopRecognitionLocked(model, notify);
@@ -992,8 +1045,15 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
@Override
public void onCallStateChanged(int state, String arg1) {
if (DBG) Slog.d(TAG, "onCallStateChanged: " + state);
- synchronized (mLock) {
- onCallStateChangedLocked(TelephonyManager.CALL_STATE_OFFHOOK == state);
+
+ if (mHandler != null) {
+ synchronized (mLock) {
+ mHandler.removeMessages(MSG_CALL_STATE_CHANGED);
+ Message msg = mHandler.obtainMessage(MSG_CALL_STATE_CHANGED, state, 0);
+ mHandler.sendMessageDelayed(
+ msg, (TelephonyManager.CALL_STATE_OFFHOOK == state) ? 0
+ : CALL_INACTIVE_MSG_DELAY_MS);
+ }
}
}
}
@@ -1216,9 +1276,8 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
// models.
private int startRecognitionLocked(ModelData modelData, boolean notify) {
IRecognitionStatusCallback callback = modelData.getCallback();
- int handle = modelData.getHandle();
RecognitionConfig config = modelData.getRecognitionConfig();
- if (callback == null || handle == INVALID_VALUE || config == null) {
+ if (callback == null || !modelData.isModelLoaded() || config == null) {
// Nothing to do here.
Slog.w(TAG, "startRecognition: Bad data passed in.");
MetricsLogger.count(mContext, "sth_start_recognition_error", 1);
@@ -1235,7 +1294,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
if (mModule == null) {
return STATUS_ERROR;
}
- int status = mModule.startRecognition(handle, config);
+ int status = mModule.startRecognition(modelData.getHandle(), config);
if (status != SoundTrigger.STATUS_OK) {
Slog.w(TAG, "startRecognition failed with " + status);
MetricsLogger.count(mContext, "sth_start_recognition_error", 1);
@@ -1376,7 +1435,7 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
// Model handle is an integer used by the HAL as an identifier for sound
// models.
- private int mModelHandle = INVALID_VALUE;
+ private int mModelHandle;
// The SoundModel instance, one of KeyphraseSoundModel or GenericSoundModel.
private SoundModel mSoundModel = null;
@@ -1436,7 +1495,6 @@ public class SoundTriggerHelper implements SoundTrigger.StatusListener {
synchronized void clearState() {
mModelState = MODEL_NOTLOADED;
- mModelHandle = INVALID_VALUE;
mRecognitionConfig = null;
mRequested = false;
mCallback = null;
diff --git a/tests/ApkVerityTest/Android.bp b/tests/ApkVerityTest/Android.bp
index 248206817740..02c75edafcd5 100644
--- a/tests/ApkVerityTest/Android.bp
+++ b/tests/ApkVerityTest/Android.bp
@@ -16,7 +16,7 @@ java_test_host {
name: "ApkVerityTest",
srcs: ["src/**/*.java"],
libs: ["tradefed", "compatibility-tradefed", "compatibility-host-util"],
- test_suites: ["general-tests", "vts-core"],
+ test_suites: ["general-tests", "vts"],
target_required: [
"block_device_writer_module",
],
diff --git a/tests/ApkVerityTest/block_device_writer/Android.bp b/tests/ApkVerityTest/block_device_writer/Android.bp
index 2760fe8df2d8..37fbc29470f6 100644
--- a/tests/ApkVerityTest/block_device_writer/Android.bp
+++ b/tests/ApkVerityTest/block_device_writer/Android.bp
@@ -48,6 +48,6 @@ cc_test {
},
auto_gen_config: false,
- test_suites: ["general-tests", "pts", "vts-core"],
+ test_suites: ["general-tests", "pts", "vts"],
gtest: false,
}
diff --git a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
index 9b248878fe96..d0ebb5283f49 100644
--- a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
+++ b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
@@ -181,7 +181,7 @@ public class Nat464XlatTest {
Nat464Xlat nat = makeNat464Xlat();
ArgumentCaptor<LinkProperties> c = ArgumentCaptor.forClass(LinkProperties.class);
- nat.setNat64Prefix(new IpPrefix(NAT64_PREFIX));
+ nat.setNat64PrefixFromDns(new IpPrefix(NAT64_PREFIX));
// Start clat.
nat.start();
@@ -222,7 +222,7 @@ public class Nat464XlatTest {
ArgumentCaptor<LinkProperties> c = ArgumentCaptor.forClass(LinkProperties.class);
InOrder inOrder = inOrder(mNetd, mConnectivity);
- nat.setNat64Prefix(new IpPrefix(NAT64_PREFIX));
+ nat.setNat64PrefixFromDns(new IpPrefix(NAT64_PREFIX));
nat.start();
@@ -309,7 +309,7 @@ public class Nat464XlatTest {
Nat464Xlat nat = makeNat464Xlat();
ArgumentCaptor<LinkProperties> c = ArgumentCaptor.forClass(LinkProperties.class);
- nat.setNat64Prefix(new IpPrefix(NAT64_PREFIX));
+ nat.setNat64PrefixFromDns(new IpPrefix(NAT64_PREFIX));
nat.start();
@@ -348,7 +348,7 @@ public class Nat464XlatTest {
public void testStopBeforeClatdStarts() throws Exception {
Nat464Xlat nat = makeNat464Xlat();
- nat.setNat64Prefix(new IpPrefix(NAT64_PREFIX));
+ nat.setNat64PrefixFromDns(new IpPrefix(NAT64_PREFIX));
nat.start();
@@ -380,7 +380,7 @@ public class Nat464XlatTest {
public void testStopAndClatdNeverStarts() throws Exception {
Nat464Xlat nat = makeNat464Xlat();
- nat.setNat64Prefix(new IpPrefix(NAT64_PREFIX));
+ nat.setNat64PrefixFromDns(new IpPrefix(NAT64_PREFIX));
nat.start();