summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java109
-rw-r--r--api/current.txt1
-rw-r--r--api/system-current.txt1
-rw-r--r--api/test-current.txt5
-rw-r--r--cmds/idmap2/libidmap2/Idmap.cpp6
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java31
-rw-r--r--core/java/android/content/pm/PackageParser.java58
-rw-r--r--core/java/android/content/res/AssetManager.java18
-rw-r--r--core/java/android/util/FeatureFlagUtils.java5
-rw-r--r--core/java/android/view/LayoutInflater.java10
-rw-r--r--core/java/android/view/RenderNodeAnimator.java13
-rw-r--r--core/java/com/android/internal/app/IAppOpsService.aidl8
-rw-r--r--core/java/com/android/internal/os/Zygote.java22
-rw-r--r--core/java/com/android/internal/os/ZygoteInit.java10
-rw-r--r--core/jni/android_util_AssetManager.cpp10
-rw-r--r--core/jni/com_android_internal_os_Zygote.cpp128
-rw-r--r--core/jni/fd_utils.cpp6
-rw-r--r--core/tests/featureflagtests/Android.bp19
-rw-r--r--core/tests/featureflagtests/Android.mk20
-rw-r--r--core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.mk1
-rw-r--r--core/tests/overlaytests/device/test-apps/AppOverlayOne/AndroidManifest.xml2
-rw-r--r--core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.mk1
-rw-r--r--core/tests/overlaytests/device/test-apps/AppOverlayTwo/AndroidManifest.xml2
-rw-r--r--core/tests/overlaytests/host/Android.mk2
-rw-r--r--core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java8
-rw-r--r--core/tests/overlaytests/host/test-apps/SignatureOverlay/Android.mk2
-rw-r--r--core/tests/overlaytests/host/test-apps/SignatureOverlay/AndroidManifest.xml1
-rw-r--r--core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk2
-rw-r--r--core/tests/overlaytests/host/test-apps/UpdateOverlay/app/v2/AndroidManifest.xml3
-rw-r--r--data/fonts/fonts.xml30
-rw-r--r--libs/androidfw/AssetManager.cpp1
-rw-r--r--libs/androidfw/include/androidfw/AssetManager.h1
-rw-r--r--media/java/android/media/AudioAttributes.java7
-rw-r--r--media/java/android/media/AudioPlaybackConfiguration.java2
-rw-r--r--media/java/android/media/PlayerBase.java44
-rw-r--r--native/android/libandroid.map.txt25
-rw-r--r--native/android/system_fonts.cpp89
-rw-r--r--packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java18
-rw-r--r--packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java22
-rw-r--r--packages/SettingsLib/HelpUtils/res/drawable/ic_help_actionbar.xml1
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java22
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java3
-rw-r--r--packages/SystemUI/res/drawable-nodpi/icon.xml2
-rw-r--r--packages/SystemUI/res/drawable-nodpi/icon_bg.xml2
-rw-r--r--packages/SystemUI/res/drawable-nodpi/p.xml33
-rw-r--r--packages/SystemUI/res/drawable-nodpi/q.xml40
-rw-r--r--packages/SystemUI/res/drawable/bubble_flyout.xml29
-rw-r--r--packages/SystemUI/res/drawable/ic_notification_gentle.xml40
-rw-r--r--packages/SystemUI/res/drawable/ic_notification_interruptive.xml41
-rw-r--r--packages/SystemUI/res/layout/bubble_flyout.xml33
-rw-r--r--packages/SystemUI/res/layout/bubble_view.xml8
-rw-r--r--packages/SystemUI/res/layout/notification_info.xml412
-rw-r--r--packages/SystemUI/res/values-night/colors.xml4
-rw-r--r--packages/SystemUI/res/values/colors.xml7
-rw-r--r--packages/SystemUI/res/values/config.xml4
-rw-r--r--packages/SystemUI/res/values/dimens.xml20
-rw-r--r--packages/SystemUI/res/values/strings.xml18
-rw-r--r--packages/SystemUI/res/values/styles.xml9
-rw-r--r--packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/MultiListLayout.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java96
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java18
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java47
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java43
-rw-r--r--packages/SystemUI/src/com/android/systemui/globalactions/ListGridLayout.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java68
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManager.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java344
-rw-r--r--packages/SystemUI/tests/Android.mk4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleStackViewTest.java74
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java121
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManagerTest.java18
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java441
-rw-r--r--services/core/java/com/android/server/ServiceWatcher.java6
-rw-r--r--services/core/java/com/android/server/StorageManagerService.java25
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerDebugConfig.java1
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java5
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerShellCommand.java7
-rw-r--r--services/core/java/com/android/server/am/AppCompactor.java273
-rw-r--r--services/core/java/com/android/server/attention/AttentionManagerService.java4
-rw-r--r--services/core/java/com/android/server/broadcastradio/hal2/AnnouncementAggregator.java6
-rw-r--r--services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java31
-rw-r--r--services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java153
-rw-r--r--services/core/java/com/android/server/broadcastradio/hal2/TunerCallback.java76
-rw-r--r--services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java15
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java9
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java93
-rw-r--r--services/core/java/com/android/server/pm/PackageSetting.java4
-rw-r--r--services/core/java/com/android/server/pm/SettingBase.java3
-rw-r--r--services/core/java/com/android/server/pm/Settings.java6
-rw-r--r--services/core/java/com/android/server/wm/InputManagerCallback.java6
-rw-r--r--services/core/java/com/android/server/wm/InputMonitor.java18
-rw-r--r--services/core/java/com/android/server/wm/RecentsAnimation.java81
-rw-r--r--services/core/java/com/android/server/wm/TaskTapPointerEventListener.java71
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java52
-rw-r--r--services/net/Android.bp1
-rw-r--r--services/net/java/android/net/IIpMemoryStore.aidl8
-rw-r--r--services/net/java/android/net/IpMemoryStoreClient.java59
-rw-r--r--services/net/java/android/net/ipmemorystore/IOnNetworkAttributesRetrievedListener.aidl (renamed from services/net/java/android/net/ipmemorystore/IOnNetworkAttributesRetrieved.aidl)2
-rw-r--r--services/net/java/android/net/ipmemorystore/IOnSameL3NetworkResponseListener.aidl (renamed from services/net/java/android/net/ipmemorystore/IOnSameNetworkResponseListener.aidl)4
-rw-r--r--services/net/java/android/net/ipmemorystore/OnBlobRetrievedListener.java42
-rw-r--r--services/net/java/android/net/ipmemorystore/OnL2KeyResponseListener.java42
-rw-r--r--services/net/java/android/net/ipmemorystore/OnNetworkAttributesRetrievedListener.java46
-rw-r--r--services/net/java/android/net/ipmemorystore/OnSameL3NetworkResponseListener.java44
-rw-r--r--services/net/java/android/net/ipmemorystore/OnStatusListener.java41
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/AppCompactorTest.java233
-rw-r--r--telephony/java/android/telephony/DataSpecificRegistrationInfo.java32
-rw-r--r--telephony/java/android/telephony/NetworkRegistrationInfo.java7
-rw-r--r--telephony/java/android/telephony/PhoneNumberUtils.java11
-rw-r--r--telephony/java/android/telephony/ServiceState.java151
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java22
-rw-r--r--telephony/java/android/telephony/euicc/EuiccManager.java26
-rw-r--r--telephony/java/com/android/internal/telephony/ITelephony.aidl4
-rw-r--r--tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java2
120 files changed, 2957 insertions, 1631 deletions
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
index 2fdba0af2c1b..c121bd9caa57 100644
--- a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
+++ b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
@@ -27,6 +27,7 @@ import android.content.pm.UserInfo;
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
+import android.util.Log;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.LargeTest;
@@ -130,6 +131,47 @@ public class UserLifecycleTests {
}
}
+ /** Tests switching to an already-created, but no-longer-running, user. */
+ @Test
+ public void switchUser_stopped() throws Exception {
+ while (mRunner.keepRunning()) {
+ mRunner.pauseTiming();
+ final int startUser = mAm.getCurrentUser();
+ final int testUser = initializeNewUserAndSwitchBack(/* stopNewUser */ true);
+ final CountDownLatch latch = new CountDownLatch(1);
+ registerBroadcastReceiver(Intent.ACTION_USER_UNLOCKED, latch, testUser);
+ mRunner.resumeTiming();
+
+ mAm.switchUser(testUser);
+ boolean success = latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
+
+ mRunner.pauseTiming();
+ attestTrue("Failed to achieve 2nd ACTION_USER_UNLOCKED for user " + testUser, success);
+ switchUser(startUser);
+ removeUser(testUser);
+ mRunner.resumeTiming();
+ }
+ }
+
+ /** Tests switching to an already-created already-running non-owner user. */
+ @Test
+ public void switchUser_running() throws Exception {
+ while (mRunner.keepRunning()) {
+ mRunner.pauseTiming();
+ final int startUser = mAm.getCurrentUser();
+ final int testUser = initializeNewUserAndSwitchBack(/* stopNewUser */ false);
+ mRunner.resumeTiming();
+
+ switchUser(testUser);
+
+ mRunner.pauseTiming();
+ attestTrue("Failed to switch to user " + testUser, mAm.isUserRunning(testUser));
+ switchUser(startUser);
+ removeUser(testUser);
+ mRunner.resumeTiming();
+ }
+ }
+
@Test
public void stopUser() throws Exception {
while (mRunner.keepRunning()) {
@@ -188,6 +230,34 @@ public class UserLifecycleTests {
}
}
+ /** Tests starting an already-created, but no-longer-running, profile. */
+ @Test
+ public void managedProfileUnlock_stopped() throws Exception {
+ while (mRunner.keepRunning()) {
+ mRunner.pauseTiming();
+ final UserInfo userInfo = mUm.createProfileForUser("TestUser",
+ UserInfo.FLAG_MANAGED_PROFILE, mAm.getCurrentUser());
+ // Start the profile initially, then stop it. Similar to setQuietModeEnabled.
+ final CountDownLatch latch1 = new CountDownLatch(1);
+ registerBroadcastReceiver(Intent.ACTION_USER_UNLOCKED, latch1, userInfo.id);
+ mIam.startUserInBackground(userInfo.id);
+ latch1.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
+ stopUser(userInfo.id, true);
+
+ // Now we restart the profile.
+ final CountDownLatch latch2 = new CountDownLatch(1);
+ registerBroadcastReceiver(Intent.ACTION_USER_UNLOCKED, latch2, userInfo.id);
+ mRunner.resumeTiming();
+
+ mIam.startUserInBackground(userInfo.id);
+ latch2.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
+
+ mRunner.pauseTiming();
+ removeUser(userInfo.id);
+ mRunner.resumeTiming();
+ }
+ }
+
@Test
public void ephemeralUserStopped() throws Exception {
while (mRunner.keepRunning()) {
@@ -262,6 +332,35 @@ public class UserLifecycleTests {
latch.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS);
}
+ /**
+ * Creates a user and waits for its ACTION_USER_UNLOCKED.
+ * Then switches to back to the original user and waits for its switchUser() to finish.
+ *
+ * @param stopNewUser whether to stop the new user after switching to otherUser.
+ * @return userId of the newly created user.
+ */
+ private int initializeNewUserAndSwitchBack(boolean stopNewUser) throws Exception {
+ final int origUser = mAm.getCurrentUser();
+ // First, create and switch to testUser, waiting for its ACTION_USER_UNLOCKED
+ final int testUser = mUm.createUser("TestUser", 0).id;
+ final CountDownLatch latch1 = new CountDownLatch(1);
+ registerBroadcastReceiver(Intent.ACTION_USER_UNLOCKED, latch1, testUser);
+ mAm.switchUser(testUser);
+ attestTrue("Failed to achieve initial ACTION_USER_UNLOCKED for user " + testUser,
+ latch1.await(TIMEOUT_IN_SECOND, TimeUnit.SECONDS));
+
+ // Second, switch back to origUser, waiting merely for switchUser() to finish
+ switchUser(origUser);
+ attestTrue("Didn't switch back to user, " + origUser, origUser == mAm.getCurrentUser());
+
+ if (stopNewUser) {
+ stopUser(testUser, true);
+ attestFalse("Failed to stop user " + testUser, mAm.isUserRunning(testUser));
+ }
+
+ return testUser;
+ }
+
private void registerUserSwitchObserver(final CountDownLatch switchLatch,
final CountDownLatch bootCompleteLatch, final int userId) throws Exception {
ActivityManager.getService().registerUserSwitchObserver(
@@ -313,4 +412,14 @@ public class UserLifecycleTests {
mUsersToRemove.add(userId);
}
}
+
+ private void attestTrue(String message, boolean attestion) {
+ if (!attestion) {
+ Log.w(TAG, message);
+ }
+ }
+
+ private void attestFalse(String message, boolean attestion) {
+ attestTrue(message, !attestion);
+ }
}
diff --git a/api/current.txt b/api/current.txt
index d4a155499aa5..cb53ba11a4cd 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -45108,6 +45108,7 @@ package android.telephony {
method public boolean canChangeDtmfToneLength();
method @Nullable public android.telephony.TelephonyManager createForPhoneAccountHandle(android.telecom.PhoneAccountHandle);
method public android.telephony.TelephonyManager createForSubscriptionId(int);
+ method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean doesSwitchMultiSimConfigTriggerReboot();
method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public java.util.List<android.telephony.CellInfo> getAllCellInfo();
method public int getCallState();
method public int getCardIdForDefaultEuicc();
diff --git a/api/system-current.txt b/api/system-current.txt
index d1018be2532d..3f74596999cb 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -8063,7 +8063,6 @@ package android.telephony {
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isOffhook();
method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isPotentialEmergencyNumber(@NonNull String);
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRadioOn();
- method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isRebootRequiredForModemConfigChange();
method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRinging();
method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isVideoCallingEnabled();
method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isVisualVoicemailEnabled(android.telecom.PhoneAccountHandle);
diff --git a/api/test-current.txt b/api/test-current.txt
index 1e24ff953b2a..67a26f39ebbc 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -716,6 +716,11 @@ package android.content.pm {
package android.content.res {
+ public final class AssetManager implements java.lang.AutoCloseable {
+ method @NonNull public String[] getApkPaths();
+ method @Nullable public java.util.Map<java.lang.String,java.lang.String> getOverlayableMap(String);
+ }
+
public final class Configuration implements java.lang.Comparable<android.content.res.Configuration> android.os.Parcelable {
field public int assetsSeq;
field public final android.app.WindowConfiguration windowConfiguration;
diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp
index 6d5fe7b3446a..49470b4f4e95 100644
--- a/cmds/idmap2/libidmap2/Idmap.cpp
+++ b/cmds/idmap2/libidmap2/Idmap.cpp
@@ -269,12 +269,10 @@ Result<std::unique_ptr<const Idmap>> Idmap::FromBinaryStream(std::istream& strea
std::string ConcatPolicies(const std::vector<std::string>& policies) {
std::string message;
for (const std::string& policy : policies) {
- if (message.empty()) {
- message.append(policy);
- } else {
- message.append(policy);
+ if (!message.empty()) {
message.append("|");
}
+ message.append(policy);
}
return message;
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 5328dda03893..deb181f4fd0a 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -687,6 +687,13 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
*/
public static final int PRIVATE_FLAG_ALLOW_EXTERNAL_STORAGE_SANDBOX = 1 << 29;
+ /**
+ * Value for {@link #privateFlags}: whether this app is pre-installed on the
+ * ODM partition of the system image.
+ * @hide
+ */
+ public static final int PRIVATE_FLAG_ODM = 1 << 30;
+
/** @hide */
@IntDef(flag = true, prefix = { "PRIVATE_FLAG_" }, value = {
PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE,
@@ -717,6 +724,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE,
PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE,
PRIVATE_FLAG_ALLOW_EXTERNAL_STORAGE_SANDBOX,
+ PRIVATE_FLAG_ODM,
})
@Retention(RetentionPolicy.SOURCE)
public @interface ApplicationInfoPrivateFlags {}
@@ -1093,6 +1101,18 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
public String appComponentFactory;
/**
+ * Resource id of {@link com.android.internal.R.styleable.AndroidManifestProvider_icon}
+ * @hide
+ */
+ public int iconRes;
+
+ /**
+ * Resource id of {@link com.android.internal.R.styleable.AndroidManifestProvider_roundIcon}
+ * @hide
+ */
+ public int roundIconRes;
+
+ /**
* The category of this app. Categories are used to cluster multiple apps
* together into meaningful groups, such as when summarizing battery,
* network, or disk usage. Apps should only define this value when they fit
@@ -1571,6 +1591,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
classLoaderName = orig.classLoaderName;
splitClassLoaderNames = orig.splitClassLoaderNames;
appComponentFactory = orig.appComponentFactory;
+ iconRes = orig.iconRes;
+ roundIconRes = orig.roundIconRes;
compileSdkVersion = orig.compileSdkVersion;
compileSdkVersionCodename = orig.compileSdkVersionCodename;
mHiddenApiPolicy = orig.mHiddenApiPolicy;
@@ -1650,6 +1672,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
dest.writeInt(compileSdkVersion);
dest.writeString(compileSdkVersionCodename);
dest.writeString(appComponentFactory);
+ dest.writeInt(iconRes);
+ dest.writeInt(roundIconRes);
dest.writeInt(mHiddenApiPolicy);
dest.writeInt(hiddenUntilInstalled ? 1 : 0);
dest.writeString(zygotePreloadName);
@@ -1724,6 +1748,8 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
compileSdkVersion = source.readInt();
compileSdkVersionCodename = source.readString();
appComponentFactory = source.readString();
+ iconRes = source.readInt();
+ roundIconRes = source.readInt();
mHiddenApiPolicy = source.readInt();
hiddenUntilInstalled = source.readInt() != 0;
zygotePreloadName = source.readString();
@@ -1970,6 +1996,11 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
}
/** @hide */
+ public boolean isOdm() {
+ return (privateFlags & ApplicationInfo.PRIVATE_FLAG_ODM) != 0;
+ }
+
+ /** @hide */
public boolean isPartiallyDirectBootAware() {
return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE) != 0;
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 93bc6d7eb583..8981000714dd 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -49,6 +49,8 @@ import android.annotation.StringRes;
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
import android.app.ActivityTaskManager;
+import android.app.ActivityThread;
+import android.app.ResourcesManager;
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
@@ -69,6 +71,7 @@ import android.os.FileUtils;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.PatternMatcher;
+import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.Trace;
@@ -92,6 +95,7 @@ import android.util.Slog;
import android.util.SparseArray;
import android.util.TypedValue;
import android.util.apk.ApkSignatureVerifier;
+import android.view.Display;
import android.view.Gravity;
import com.android.internal.R;
@@ -320,6 +324,8 @@ public class PackageParser {
private int mParseError = PackageManager.INSTALL_SUCCEEDED;
private static boolean sCompatibilityModeEnabled = true;
+ private static boolean sUseRoundIcon = false;
+
private static final int PARSE_DEFAULT_INSTALL_LOCATION =
PackageInfo.INSTALL_LOCATION_UNSPECIFIED;
private static final int PARSE_DEFAULT_TARGET_SANDBOX = 1;
@@ -3437,6 +3443,11 @@ public class PackageParser {
TypedArray sa = res.obtainAttributes(parser,
com.android.internal.R.styleable.AndroidManifestApplication);
+ ai.iconRes = sa.getResourceId(
+ com.android.internal.R.styleable.AndroidManifestApplication_icon, 0);
+ ai.roundIconRes = sa.getResourceId(
+ com.android.internal.R.styleable.AndroidManifestApplication_roundIcon, 0);
+
if (!parsePackageItemInfo(owner, ai, outError,
"<application>", sa, false /*nameRequired*/,
com.android.internal.R.styleable.AndroidManifestApplication_name,
@@ -4240,9 +4251,7 @@ public class PackageParser {
}
}
- final boolean useRoundIcon =
- Resources.getSystem().getBoolean(com.android.internal.R.bool.config_useRoundIcon);
- int roundIconVal = useRoundIcon ? sa.getResourceId(roundIconRes, 0) : 0;
+ int roundIconVal = sUseRoundIcon ? sa.getResourceId(roundIconRes, 0) : 0;
if (roundIconVal != 0) {
outInfo.icon = roundIconVal;
outInfo.nonLocalizedLabel = null;
@@ -5750,9 +5759,7 @@ public class PackageParser {
outInfo.nonLocalizedLabel = v.coerceToString();
}
- final boolean useRoundIcon =
- Resources.getSystem().getBoolean(com.android.internal.R.bool.config_useRoundIcon);
- int roundIconVal = useRoundIcon ? sa.getResourceId(
+ int roundIconVal = sUseRoundIcon ? sa.getResourceId(
com.android.internal.R.styleable.AndroidManifestIntentFilter_roundIcon, 0) : 0;
if (roundIconVal != 0) {
outInfo.icon = roundIconVal;
@@ -6920,6 +6927,11 @@ public class PackageParser {
}
/** @hide */
+ public boolean isOdm() {
+ return applicationInfo.isOdm();
+ }
+
+ /** @hide */
public boolean isPrivileged() {
return applicationInfo.isPrivilegedApp();
}
@@ -7739,6 +7751,7 @@ public class PackageParser {
}
ai.seInfoUser = SELinuxUtil.assignSeinfoUser(state);
ai.resourceDirs = state.overlayPaths;
+ ai.icon = (sUseRoundIcon && ai.roundIconRes != 0) ? ai.roundIconRes : ai.iconRes;
}
@UnsupportedAppUsage
@@ -8344,6 +8357,39 @@ public class PackageParser {
sCompatibilityModeEnabled = compatibilityModeEnabled;
}
+ /**
+ * @hide
+ */
+ public static void readConfigUseRoundIcon(Resources r) {
+ if (r != null) {
+ sUseRoundIcon = r.getBoolean(com.android.internal.R.bool.config_useRoundIcon);
+ return;
+ }
+
+ ApplicationInfo androidAppInfo;
+ try {
+ androidAppInfo = ActivityThread.getPackageManager().getApplicationInfo(
+ "android", 0 /* flags */,
+ UserHandle.myUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ Resources systemResources = Resources.getSystem();
+
+ // Create in-flight as this overlayable resource is only used when config changes
+ Resources overlayableRes = ResourcesManager.getInstance().getResources(null,
+ null,
+ null,
+ androidAppInfo.resourceDirs,
+ androidAppInfo.sharedLibraryFiles,
+ Display.DEFAULT_DISPLAY,
+ null,
+ systemResources.getCompatibilityInfo(),
+ systemResources.getClassLoader());
+
+ sUseRoundIcon = overlayableRes.getBoolean(com.android.internal.R.bool.config_useRoundIcon);
+ }
+
public static class PackageParserException extends Exception {
public final int error;
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 514015fe0c86..e5ef67b7d4bd 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -23,6 +23,7 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringRes;
import android.annotation.StyleRes;
+import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration.NativeConfig;
@@ -357,6 +358,22 @@ public final class AssetManager implements AutoCloseable {
return sEmptyApkAssets;
}
+ /** @hide */
+ @TestApi
+ public @NonNull String[] getApkPaths() {
+ synchronized (this) {
+ if (mOpen) {
+ String[] paths = new String[mApkAssets.length];
+ final int count = mApkAssets.length;
+ for (int i = 0; i < count; i++) {
+ paths[i] = mApkAssets[i].getAssetPath();
+ }
+ return paths;
+ }
+ }
+ return new String[0];
+ }
+
/**
* Returns a cookie for use with the other APIs of AssetManager.
* @return 0 if the path was not found, otherwise a positive integer cookie representing
@@ -1356,6 +1373,7 @@ public final class AssetManager implements AutoCloseable {
/**
* @hide
*/
+ @TestApi
@GuardedBy("this")
public @Nullable Map<String, String> getOverlayableMap(String packageName) {
synchronized (this) {
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 5d33b49e181b..336c2e51c4a3 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -38,7 +38,8 @@ public class FeatureFlagUtils {
public static final String HEARING_AID_SETTINGS = "settings_bluetooth_hearing_aid";
public static final String SAFETY_HUB = "settings_safety_hub";
public static final String SCREENRECORD_LONG_PRESS = "settings_screenrecord_long_press";
- public static final String GLOBAL_ACTIONS_GRID_ENABLED = "settings_global_actions_grid_enabled";
+ public static final String FORCE_GLOBAL_ACTIONS_GRID_ENABLED =
+ "settings_global_actions_force_grid_enabled";
public static final String GLOBAL_ACTIONS_PANEL_ENABLED =
"settings_global_actions_panel_enabled";
public static final String DYNAMIC_SYSTEM = "settings_dynamic_system";
@@ -58,7 +59,7 @@ public class FeatureFlagUtils {
DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "false");
DEFAULT_FLAGS.put(SAFETY_HUB, "true");
DEFAULT_FLAGS.put(SCREENRECORD_LONG_PRESS, "false");
- DEFAULT_FLAGS.put(GLOBAL_ACTIONS_GRID_ENABLED, "true");
+ DEFAULT_FLAGS.put(FORCE_GLOBAL_ACTIONS_GRID_ENABLED, "false");
DEFAULT_FLAGS.put(GLOBAL_ACTIONS_PANEL_ENABLED, "true");
DEFAULT_FLAGS.put("settings_wifi_details_saved_screen", "true");
DEFAULT_FLAGS.put("settings_wifi_details_datausage_header", "false");
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index 35cf129d81b8..f9b629c85fb0 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -566,7 +566,7 @@ public abstract class LayoutInflater {
String layout = res.getResourceEntryName(resource);
try {
- Class clazz = mPrecompiledClassLoader.loadClass("" + pkg + ".CompiledView");
+ Class clazz = Class.forName("" + pkg + ".CompiledView", false, mPrecompiledClassLoader);
Method inflater = clazz.getMethod(layout, Context.class, int.class);
View view = (View) inflater.invoke(null, mContext, resource);
@@ -827,8 +827,8 @@ public abstract class LayoutInflater {
if (constructor == null) {
// Class not found in the cache, see if it's real, and try to add it
- clazz = mContext.getClassLoader().loadClass(
- prefix != null ? (prefix + name) : name).asSubclass(View.class);
+ clazz = Class.forName(prefix != null ? (prefix + name) : name, false,
+ mContext.getClassLoader()).asSubclass(View.class);
if (mFilter != null && clazz != null) {
boolean allowed = mFilter.onLoadClass(clazz);
@@ -846,8 +846,8 @@ public abstract class LayoutInflater {
Boolean allowedState = mFilterMap.get(name);
if (allowedState == null) {
// New class -- remember whether it is allowed
- clazz = mContext.getClassLoader().loadClass(
- prefix != null ? (prefix + name) : name).asSubclass(View.class);
+ clazz = Class.forName(prefix != null ? (prefix + name) : name, false,
+ mContext.getClassLoader()).asSubclass(View.class);
boolean allowed = clazz != null && mFilter.onLoadClass(clazz);
mFilterMap.put(name, allowed);
diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java
index 7ab9534941c7..04ac92292740 100644
--- a/core/java/android/view/RenderNodeAnimator.java
+++ b/core/java/android/view/RenderNodeAnimator.java
@@ -26,6 +26,7 @@ import android.graphics.RecordingCanvas;
import android.graphics.RenderNode;
import android.os.Build;
import android.os.Handler;
+import android.os.Looper;
import android.util.SparseIntArray;
import com.android.internal.util.VirtualRefBasePtr;
@@ -191,6 +192,9 @@ public class RenderNodeAnimator extends Animator {
}
mState = STATE_DELAYED;
+ if (mHandler == null) {
+ mHandler = new Handler(true);
+ }
applyInterpolator();
if (mNativePtr == null) {
@@ -224,9 +228,6 @@ public class RenderNodeAnimator extends Animator {
private void moveToRunningState() {
mState = STATE_RUNNING;
if (mNativePtr != null) {
- if (mHandler == null) {
- mHandler = new Handler();
- }
nStart(mNativePtr.get());
}
notifyStartListeners();
@@ -503,7 +504,11 @@ public class RenderNodeAnimator extends Animator {
// Called by native
@UnsupportedAppUsage
private static void callOnFinished(RenderNodeAnimator animator) {
- animator.mHandler.post(animator::onFinished);
+ if (animator.mHandler != null) {
+ animator.mHandler.post(animator::onFinished);
+ } else {
+ new Handler(Looper.getMainLooper(), null, true).post(animator::onFinished);
+ }
}
@Override
diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl
index 1c901823566a..72dbbf3b8b87 100644
--- a/core/java/com/android/internal/app/IAppOpsService.aidl
+++ b/core/java/com/android/internal/app/IAppOpsService.aidl
@@ -26,8 +26,9 @@ import com.android.internal.app.IAppOpsActiveCallback;
import com.android.internal.app.IAppOpsNotedCallback;
interface IAppOpsService {
- // These first methods are also called by native code, so must
+ // These methods are also called by native code, so must
// be kept in sync with frameworks/native/libs/binder/include/binder/IAppOpsService.h
+ // and not be reordered
int checkOperation(int code, int uid, String packageName);
int noteOperation(int code, int uid, String packageName);
int startOperation(IBinder token, int code, int uid, String packageName,
@@ -38,6 +39,10 @@ interface IAppOpsService {
void stopWatchingMode(IAppOpsCallback callback);
IBinder getToken(IBinder clientToken);
int permissionToOpCode(String permission);
+ int checkAudioOperation(int code, int usage, int uid, String packageName);
+ // End of methods also called by native code.
+ // Any new method exposed to native must be added after the last one, do not reorder
+
int noteProxyOperation(int code, int proxyUid, String proxyPackageName,
int callingUid, String callingPackageName);
@@ -62,7 +67,6 @@ interface IAppOpsService {
void setMode(int code, int uid, String packageName, int mode);
@UnsupportedAppUsage
void resetAllModes(int reqUserId, String reqPackageName);
- int checkAudioOperation(int code, int usage, int uid, String packageName);
void setAudioRestriction(int code, int usage, int uid, int mode, in String[] exceptionPackages);
void setUserRestrictions(in Bundle restrictions, IBinder token, int userHandle);
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 8ca0bd1df1eb..afdeb1b602d7 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -197,9 +197,6 @@ public final class Zygote {
private Zygote() {}
- /** Called for some security initialization before any fork. */
- static native void nativeSecurityInit();
-
/**
* Forks a new VM instance. The current VM must have been started
* with the -Xzygote flag. <b>NOTE: new instance keeps all
@@ -384,22 +381,19 @@ public final class Zygote {
native protected static void nativeInstallSeccompUidGidFilter(int uidGidMin, int uidGidMax);
/**
- * Zygote unmount storage space on initializing.
- * This method is called once.
- */
- protected static native void nativeUnmountStorageOnInit();
-
- /**
- * Get socket file descriptors (opened by init) from the environment and
- * store them for access from native code later.
+ * Initialize the native state of the Zygote. This inclues
+ * - Fetching socket FDs from the environment
+ * - Initializing security properties
+ * - Unmounting storage as appropriate
+ * - Loading necessary performance profile information
*
* @param isPrimary True if this is the zygote process, false if it is zygote_secondary
*/
- public static void getSocketFDs(boolean isPrimary) {
- nativeGetSocketFDs(isPrimary);
+ static void initNativeState(boolean isPrimary) {
+ nativeInitNativeState(isPrimary);
}
- protected static native void nativeGetSocketFDs(boolean isPrimary);
+ protected static native void nativeInitNativeState(boolean isPrimary);
/**
* Returns the raw string value of a system property.
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 7cca7b77b45d..bb7b09ab4df3 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -20,10 +20,10 @@ import static android.system.OsConstants.S_IRWXG;
import static android.system.OsConstants.S_IRWXO;
import android.annotation.UnsupportedAppUsage;
-import android.content.res.Resources;
-import android.content.res.TypedArray;
import android.app.ApplicationLoaders;
import android.content.pm.SharedLibraryInfo;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.os.Build;
import android.os.Environment;
import android.os.IInstalld;
@@ -863,8 +863,6 @@ public class ZygoteInit {
throw new RuntimeException("No ABI list supplied.");
}
- Zygote.getSocketFDs(isPrimaryZygote);
-
// In some configurations, we avoid preloading resources and classes eagerly.
// In such cases, we will preload things prior to our first fork.
if (!enableLazyPreload) {
@@ -889,10 +887,8 @@ public class ZygoteInit {
// Zygote.
Trace.setTracingEnabled(false, 0);
- Zygote.nativeSecurityInit();
- // Zygote process unmounts root storage spaces.
- Zygote.nativeUnmountStorageOnInit();
+ Zygote.initNativeState(isPrimaryZygote);
ZygoteHooks.stopZygoteNoThreadCreation();
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index bf56ef438a1d..d3f9196ce763 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -163,7 +163,7 @@ static void NativeVerifySystemIdmaps(JNIEnv* /*env*/, jclass /*clazz*/) {
}
// Generic idmap parameters
- const char* argv[8];
+ const char* argv[9];
int argc = 0;
struct stat st;
@@ -199,6 +199,10 @@ static void NativeVerifySystemIdmaps(JNIEnv* /*env*/, jclass /*clazz*/) {
argv[argc++] = AssetManager::PRODUCT_SERVICES_OVERLAY_DIR;
}
+ if (stat(AssetManager::ODM_OVERLAY_DIR, &st) == 0) {
+ argv[argc++] = AssetManager::ODM_OVERLAY_DIR;
+ }
+
// Finally, invoke idmap (if any overlay directory exists)
if (argc > 5) {
execv(AssetManager::IDMAP_BIN, (char* const*)argv);
@@ -233,6 +237,10 @@ static jobjectArray NativeCreateIdmapsForStaticOverlaysTargetingAndroid(JNIEnv*
input_dirs.push_back(AssetManager::PRODUCT_SERVICES_OVERLAY_DIR);
}
+ if (stat(AssetManager::ODM_OVERLAY_DIR, &st) == 0) {
+ input_dirs.push_back(AssetManager::ODM_OVERLAY_DIR);
+ }
+
if (input_dirs.empty()) {
LOG(WARNING) << "no directories for idmap2 to scan";
return env->NewObjectArray(0, g_stringClass, nullptr);
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 8dd7e8ea3b90..430b9c505223 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -126,7 +126,7 @@ static constexpr const char* kZygoteInitClassName = "com/android/internal/os/Zyg
static jclass gZygoteInitClass;
static jmethodID gCreateSystemServerClassLoader;
-static bool g_is_security_enforced = true;
+static bool gIsSecurityEnforced = true;
/**
* The maximum number of characters (not including a null terminator) that a
@@ -510,7 +510,7 @@ static void PreApplicationInit() {
}
static void SetUpSeccompFilter(uid_t uid, bool is_child_zygote) {
- if (!g_is_security_enforced) {
+ if (!gIsSecurityEnforced) {
ALOGI("seccomp disabled by setenforce 0");
return;
}
@@ -1626,18 +1626,48 @@ std::vector<int> MakeUsapPipeReadFDVector() {
return fd_vec;
}
-} // anonymous namespace
+static void UnmountStorageOnInit(JNIEnv* env) {
+ // Zygote process unmount root storage space initially before every child processes are forked.
+ // Every forked child processes (include SystemServer) only mount their own root storage space
+ // and no need unmount storage operation in MountEmulatedStorage method.
+ // Zygote process does not utilize root storage spaces and unshares its mount namespace below.
-namespace android {
+ // See storage config details at http://source.android.com/tech/storage/
+ // Create private mount namespace shared by all children
+ if (unshare(CLONE_NEWNS) == -1) {
+ RuntimeAbort(env, __LINE__, "Failed to unshare()");
+ return;
+ }
-static void com_android_internal_os_Zygote_nativeSecurityInit(JNIEnv*, jclass) {
- // security_getenforce is not allowed on app process. Initialize and cache
- // the value before zygote forks.
- g_is_security_enforced = security_getenforce();
+ // Mark rootfs as being a slave so that changes from default
+ // namespace only flow into our children.
+ if (mount("rootfs", "/", nullptr, (MS_SLAVE | MS_REC), nullptr) == -1) {
+ RuntimeAbort(env, __LINE__, "Failed to mount() rootfs as MS_SLAVE");
+ return;
+ }
- selinux_android_seapp_context_init();
+ // Create a staging tmpfs that is shared by our children; they will
+ // bind mount storage into their respective private namespaces, which
+ // are isolated from each other.
+ const char* target_base = getenv("EMULATED_STORAGE_TARGET");
+ if (target_base != nullptr) {
+#define STRINGIFY_UID(x) __STRING(x)
+ if (mount("tmpfs", target_base, "tmpfs", MS_NOSUID | MS_NODEV,
+ "uid=0,gid=" STRINGIFY_UID(AID_SDCARD_R) ",mode=0751") == -1) {
+ ALOGE("Failed to mount tmpfs to %s", target_base);
+ RuntimeAbort(env, __LINE__, "Failed to mount tmpfs");
+ return;
+ }
+#undef STRINGIFY_UID
+ }
+
+ UnmountTree("/storage");
}
+} // anonymous namespace
+
+namespace android {
+
static void com_android_internal_os_Zygote_nativePreApplicationInit(JNIEnv*, jclass) {
PreApplicationInit();
}
@@ -1791,47 +1821,9 @@ static void com_android_internal_os_Zygote_nativeAllowFileAcrossFork(
FileDescriptorWhitelist::Get()->Allow(path_cstr);
}
-static void com_android_internal_os_Zygote_nativeUnmountStorageOnInit(JNIEnv* env, jclass) {
- // Zygote process unmount root storage space initially before every child processes are forked.
- // Every forked child processes (include SystemServer) only mount their own root storage space
- // and no need unmount storage operation in MountEmulatedStorage method.
- // Zygote process does not utilize root storage spaces and unshares its mount namespace below.
-
- // See storage config details at http://source.android.com/tech/storage/
- // Create private mount namespace shared by all children
- if (unshare(CLONE_NEWNS) == -1) {
- RuntimeAbort(env, __LINE__, "Failed to unshare()");
- return;
- }
-
- // Mark rootfs as being a slave so that changes from default
- // namespace only flow into our children.
- if (mount("rootfs", "/", nullptr, (MS_SLAVE | MS_REC), nullptr) == -1) {
- RuntimeAbort(env, __LINE__, "Failed to mount() rootfs as MS_SLAVE");
- return;
- }
-
- // Create a staging tmpfs that is shared by our children; they will
- // bind mount storage into their respective private namespaces, which
- // are isolated from each other.
- const char* target_base = getenv("EMULATED_STORAGE_TARGET");
- if (target_base != nullptr) {
-#define STRINGIFY_UID(x) __STRING(x)
- if (mount("tmpfs", target_base, "tmpfs", MS_NOSUID | MS_NODEV,
- "uid=0,gid=" STRINGIFY_UID(AID_SDCARD_R) ",mode=0751") == -1) {
- ALOGE("Failed to mount tmpfs to %s", target_base);
- RuntimeAbort(env, __LINE__, "Failed to mount tmpfs");
- return;
- }
-#undef STRINGIFY_UID
- }
-
- UnmountTree("/storage");
-}
-
static void com_android_internal_os_Zygote_nativeInstallSeccompUidGidFilter(
JNIEnv* env, jclass, jint uidGidMin, jint uidGidMax) {
- if (!g_is_security_enforced) {
+ if (!gIsSecurityEnforced) {
ALOGI("seccomp disabled by setenforce 0");
return;
}
@@ -1883,8 +1875,12 @@ static void com_android_internal_os_Zygote_nativeSpecializeAppProcess(
* @param is_primary If this process is the primary or secondary Zygote; used to compute the name
* of the environment variable storing the file descriptors.
*/
-static void com_android_internal_os_Zygote_nativeGetSocketFDs(JNIEnv* env, jclass,
- jboolean is_primary) {
+static void com_android_internal_os_Zygote_nativeInitNativeState(JNIEnv* env, jclass,
+ jboolean is_primary) {
+ /*
+ * Obtain file descriptors created by init from the environment.
+ */
+
std::string android_socket_prefix(ANDROID_SOCKET_PREFIX);
std::string env_var_name = android_socket_prefix + (is_primary ? "zygote" : "zygote_secondary");
char* env_var_val = getenv(env_var_name.c_str());
@@ -1905,6 +1901,30 @@ static void com_android_internal_os_Zygote_nativeGetSocketFDs(JNIEnv* env, jclas
} else {
ALOGE("Unable to fetch USAP pool socket file descriptor");
}
+
+ /*
+ * Security Initialization
+ */
+
+ // security_getenforce is not allowed on app process. Initialize and cache
+ // the value before zygote forks.
+ gIsSecurityEnforced = security_getenforce();
+
+ selinux_android_seapp_context_init();
+
+ /*
+ * Storage Initialization
+ */
+
+ UnmountStorageOnInit(env);
+
+ /*
+ * Performance Initialization
+ */
+
+ if (!SetTaskProfiles(0, {})) {
+ ZygoteFailure(env, "zygote", nullptr, "Zygote SetTaskProfiles failed");
+ }
}
/**
@@ -2001,8 +2021,6 @@ static jboolean com_android_internal_os_Zygote_nativeDisableExecuteOnly(JNIEnv*
}
static const JNINativeMethod gMethods[] = {
- { "nativeSecurityInit", "()V",
- (void *) com_android_internal_os_Zygote_nativeSecurityInit },
{ "nativeForkAndSpecialize",
"(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)I",
(void *) com_android_internal_os_Zygote_nativeForkAndSpecialize },
@@ -2010,8 +2028,6 @@ static const JNINativeMethod gMethods[] = {
(void *) com_android_internal_os_Zygote_nativeForkSystemServer },
{ "nativeAllowFileAcrossFork", "(Ljava/lang/String;)V",
(void *) com_android_internal_os_Zygote_nativeAllowFileAcrossFork },
- { "nativeUnmountStorageOnInit", "()V",
- (void *) com_android_internal_os_Zygote_nativeUnmountStorageOnInit },
{ "nativePreApplicationInit", "()V",
(void *) com_android_internal_os_Zygote_nativePreApplicationInit },
{ "nativeInstallSeccompUidGidFilter", "(II)V",
@@ -2021,8 +2037,8 @@ static const JNINativeMethod gMethods[] = {
{ "nativeSpecializeAppProcess",
"(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)V",
(void *) com_android_internal_os_Zygote_nativeSpecializeAppProcess },
- { "nativeGetSocketFDs", "(Z)V",
- (void *) com_android_internal_os_Zygote_nativeGetSocketFDs },
+ { "nativeInitNativeState", "(Z)V",
+ (void *) com_android_internal_os_Zygote_nativeInitNativeState },
{ "nativeGetUsapPipeFDs", "()[I",
(void *) com_android_internal_os_Zygote_nativeGetUsapPipeFDs },
{ "nativeRemoveUsapTableEntry", "(I)Z",
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index d8d46560876d..099635246f05 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -102,6 +102,8 @@ bool FileDescriptorWhitelist::IsAllowed(const std::string& path) const {
static const char* kProductOverlayDir = "/product/overlay";
static const char* kSystemProductServicesOverlayDir = "/system/product_services/overlay/";
static const char* kProductServicesOverlayDir = "/product_services/overlay";
+ static const char* kSystemOdmOverlayDir = "/system/odm/overlay";
+ static const char* kOdmOverlayDir = "/odm/overlay";
static const char* kApkSuffix = ".apk";
if ((android::base::StartsWith(path, kOverlayDir)
@@ -110,7 +112,9 @@ bool FileDescriptorWhitelist::IsAllowed(const std::string& path) const {
|| android::base::StartsWith(path, kSystemProductOverlayDir)
|| android::base::StartsWith(path, kProductOverlayDir)
|| android::base::StartsWith(path, kSystemProductServicesOverlayDir)
- || android::base::StartsWith(path, kProductServicesOverlayDir))
+ || android::base::StartsWith(path, kProductServicesOverlayDir)
+ || android::base::StartsWith(path, kSystemOdmOverlayDir)
+ || android::base::StartsWith(path, kOdmOverlayDir))
&& android::base::EndsWith(path, kApkSuffix)
&& path.find("/../") == std::string::npos) {
return true;
diff --git a/core/tests/featureflagtests/Android.bp b/core/tests/featureflagtests/Android.bp
new file mode 100644
index 000000000000..8730b7012c4a
--- /dev/null
+++ b/core/tests/featureflagtests/Android.bp
@@ -0,0 +1,19 @@
+android_test {
+ name: "FrameworksCoreFeatureFlagTests",
+ // We only want this apk build for tests.
+ // Include all test java files.
+ srcs: ["src/**/*.java"],
+ dxflags: ["--core-library"],
+ static_libs: [
+ "android-common",
+ "frameworks-core-util-lib",
+ "androidx.test.rules",
+ ],
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ ],
+ platform_apis: true,
+ certificate: "platform",
+ test_suites: ["device-tests"],
+}
diff --git a/core/tests/featureflagtests/Android.mk b/core/tests/featureflagtests/Android.mk
deleted file mode 100644
index ce7cb181b53a..000000000000
--- a/core/tests/featureflagtests/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# We only want this apk build for tests.
-LOCAL_MODULE_TAGS := tests
-
-# Include all test java files.
-LOCAL_SRC_FILES := \
- $(call all-java-files-under, src)
-
-LOCAL_DX_FLAGS := --core-library
-LOCAL_STATIC_JAVA_LIBRARIES := android-common frameworks-core-util-lib androidx.test.rules
-LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
-LOCAL_PACKAGE_NAME := FrameworksCoreFeatureFlagTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_CERTIFICATE := platform
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.mk b/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.mk
index 97a3d0078e26..fa15241b9cc5 100644
--- a/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.mk
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.mk
@@ -19,7 +19,6 @@ LOCAL_MODULE_TAGS := tests
LOCAL_PACKAGE_NAME := OverlayDeviceTests_AppOverlayOne
LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := device-tests
-LOCAL_CERTIFICATE := platform
LOCAL_USE_AAPT2 := true
LOCAL_AAPT_FLAGS := --no-resource-removal
include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/AndroidManifest.xml b/core/tests/overlaytests/device/test-apps/AppOverlayOne/AndroidManifest.xml
index 8ac6953b44e5..7d2840886683 100644
--- a/core/tests/overlaytests/device/test-apps/AppOverlayOne/AndroidManifest.xml
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayOne/AndroidManifest.xml
@@ -19,5 +19,5 @@
android:versionCode="1"
android:versionName="1.0">
<application android:hasCode="false" />
- <overlay android:targetPackage="com.android.overlaytest" android:priority="1" />
+ <overlay android:targetPackage="com.android.overlaytest" />
</manifest>
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.mk b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.mk
index a3470255997d..ada9b3cb625d 100644
--- a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.mk
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.mk
@@ -19,7 +19,6 @@ LOCAL_MODULE_TAGS := tests
LOCAL_PACKAGE_NAME := OverlayDeviceTests_AppOverlayTwo
LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := device-tests
-LOCAL_CERTIFICATE := platform
LOCAL_USE_AAPT2 := true
LOCAL_AAPT_FLAGS := --no-resource-removal
include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/AndroidManifest.xml b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/AndroidManifest.xml
index f3c39ccbb301..6e75a350204d 100644
--- a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/AndroidManifest.xml
+++ b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/AndroidManifest.xml
@@ -19,5 +19,5 @@
android:versionCode="1"
android:versionName="1.0">
<application android:hasCode="false" />
- <overlay android:targetPackage="com.android.overlaytest" android:priority="2" />
+ <overlay android:targetPackage="com.android.overlaytest" />
</manifest>
diff --git a/core/tests/overlaytests/host/Android.mk b/core/tests/overlaytests/host/Android.mk
index b48a46bbda9a..e7348d52adfe 100644
--- a/core/tests/overlaytests/host/Android.mk
+++ b/core/tests/overlaytests/host/Android.mk
@@ -21,7 +21,7 @@ LOCAL_MODULE := OverlayHostTests
LOCAL_JAVA_LIBRARIES := tradefed
LOCAL_COMPATIBILITY_SUITE := general-tests
LOCAL_TARGET_REQUIRED_MODULES := \
- OverlayHostTests_BadSignatureOverlay \
+ OverlayHostTests_NonPlatformSignatureOverlay \
OverlayHostTests_PlatformSignatureStaticOverlay \
OverlayHostTests_PlatformSignatureOverlay \
OverlayHostTests_UpdateOverlay \
diff --git a/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java b/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java
index c133469bbf80..99b6421d2bc7 100644
--- a/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java
+++ b/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java
@@ -67,10 +67,10 @@ public class InstallOverlayTests extends BaseHostJUnit4Test {
}
@Test
- public void failToInstallNonPlatformSignedOverlay() throws Exception {
+ public void failToInstallNonPlatformSignedOverlayTargetPreQ() throws Exception {
try {
- installPackage("OverlayHostTests_BadSignatureOverlay.apk");
- fail("installed a non-platform signed overlay");
+ installPackage("OverlayHostTests_NonPlatformSignatureOverlay.apk");
+ fail("installed a non-platform signed overlay with targetSdkVersion < Q");
} catch (Exception e) {
// Expected.
}
@@ -165,7 +165,7 @@ public class InstallOverlayTests extends BaseHostJUnit4Test {
private void delay() {
try {
- Thread.sleep(100);
+ Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
diff --git a/core/tests/overlaytests/host/test-apps/SignatureOverlay/Android.mk b/core/tests/overlaytests/host/test-apps/SignatureOverlay/Android.mk
index 3d2410dd77a5..cc7704b0ce98 100644
--- a/core/tests/overlaytests/host/test-apps/SignatureOverlay/Android.mk
+++ b/core/tests/overlaytests/host/test-apps/SignatureOverlay/Android.mk
@@ -18,7 +18,7 @@ my_package_prefix := com.android.server.om.hosttest.signature_overlay
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
-LOCAL_PACKAGE_NAME := OverlayHostTests_BadSignatureOverlay
+LOCAL_PACKAGE_NAME := OverlayHostTests_NonPlatformSignatureOverlay
LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := general-tests
LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_bad
diff --git a/core/tests/overlaytests/host/test-apps/SignatureOverlay/AndroidManifest.xml b/core/tests/overlaytests/host/test-apps/SignatureOverlay/AndroidManifest.xml
index 26b3875caab6..67592f834bb2 100644
--- a/core/tests/overlaytests/host/test-apps/SignatureOverlay/AndroidManifest.xml
+++ b/core/tests/overlaytests/host/test-apps/SignatureOverlay/AndroidManifest.xml
@@ -16,6 +16,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.server.om.hosttest.signature_overlay">
+ <uses-sdk android:targetSdkVersion="28" />
<application android:hasCode="false" />
<overlay android:targetPackage="android" />
</manifest>
diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk b/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk
index c7b2dd1ac8f9..f8607f44bda6 100644
--- a/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk
+++ b/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk
@@ -58,7 +58,6 @@ LOCAL_MODULE_TAGS := tests
LOCAL_PACKAGE_NAME := OverlayHostTests_AppOverlayV1
LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := general-tests
-LOCAL_CERTIFICATE := platform
LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v1
LOCAL_AAPT_FLAGS += --version-code 1 --version-name v1
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/app/v1/res
@@ -70,7 +69,6 @@ LOCAL_MODULE_TAGS := tests
LOCAL_PACKAGE_NAME := OverlayHostTests_AppOverlayV2
LOCAL_SDK_VERSION := current
LOCAL_COMPATIBILITY_SUITE := general-tests
-LOCAL_CERTIFICATE := platform
LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v2
LOCAL_AAPT_FLAGS += --version-code 2 --version-name v2
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/app/v2/res
diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/v2/AndroidManifest.xml b/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/v2/AndroidManifest.xml
index f1a39817af86..b6ff0c3c6725 100644
--- a/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/v2/AndroidManifest.xml
+++ b/core/tests/overlaytests/host/test-apps/UpdateOverlay/app/v2/AndroidManifest.xml
@@ -17,6 +17,5 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.server.om.hosttest.app_overlay">
<application android:hasCode="false" />
- <overlay android:targetPackage="com.android.server.om.hosttest.update_overlay_test"
- android:category="android.theme" />
+ <overlay android:targetPackage="com.android.server.om.hosttest.update_overlay_test" />
</manifest>
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index 626bbf0001dd..072beae8baf7 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -100,36 +100,6 @@
<font weight="400" style="normal">CarroisGothicSC-Regular.ttf</font>
</family>
- <family name="arbutus-slab">
- <font weight="400" style="normal">ArbutusSlab-Regular.ttf</font>
- </family>
-
- <family name="arvo">
- <font weight="400" style="normal">Arvo-Regular.ttf</font>
- <font weight="400" style="italic">Arvo-Italic.ttf</font>
- <font weight="700" style="normal">Arvo-Bold.ttf</font>
- <font weight="700" style="italic">Arvo-BoldItalic.ttf</font>
- </family>
- <alias name="arvo-bold" to="arvo" weight="700" />
-
- <family name="lato">
- <font weight="400" style="normal">Lato-Regular.ttf</font>
- <font weight="400" style="italic">Lato-Italic.ttf</font>
- <font weight="700" style="normal">Lato-Bold.ttf</font>
- <font weight="700" style="italic">Lato-BoldItalic.ttf</font>
- </family>
- <alias name="lato-bold" to="lato" weight="700" />
-
- <family name="rubik">
- <font weight="400" style="normal">Rubik-Regular.ttf</font>
- <font weight="400" style="italic">Rubik-Italic.ttf</font>
- <font weight="500" style="normal">Rubik-Medium.ttf</font>
- <font weight="500" style="italic">Rubik-MediumItalic.ttf</font>
- <font weight="700" style="normal">Rubik-Bold.ttf</font>
- <font weight="700" style="italic">Rubik-BoldItalic.ttf</font>
- </family>
- <alias name="rubik-medium" to="rubik" weight="500" />
-
<family name="source-sans-pro">
<font weight="400" style="normal">SourceSansPro-Regular.ttf</font>
<font weight="400" style="italic">SourceSansPro-Italic.ttf</font>
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index 365be10f597f..21609d30e92c 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -75,6 +75,7 @@ const char* AssetManager::IDMAP_BIN = "/system/bin/idmap";
const char* AssetManager::VENDOR_OVERLAY_DIR = "/vendor/overlay";
const char* AssetManager::PRODUCT_OVERLAY_DIR = "/product/overlay";
const char* AssetManager::PRODUCT_SERVICES_OVERLAY_DIR = "/product_services/overlay";
+const char* AssetManager::ODM_OVERLAY_DIR = "/odm/overlay";
const char* AssetManager::OVERLAY_THEME_DIR_PROPERTY = "ro.boot.vendor.overlay.theme";
const char* AssetManager::TARGET_PACKAGE_NAME = "android";
const char* AssetManager::TARGET_APK_PATH = "/system/framework/framework-res.apk";
diff --git a/libs/androidfw/include/androidfw/AssetManager.h b/libs/androidfw/include/androidfw/AssetManager.h
index e22e2d239a55..a015eabc200c 100644
--- a/libs/androidfw/include/androidfw/AssetManager.h
+++ b/libs/androidfw/include/androidfw/AssetManager.h
@@ -62,6 +62,7 @@ public:
static const char* VENDOR_OVERLAY_DIR;
static const char* PRODUCT_OVERLAY_DIR;
static const char* PRODUCT_SERVICES_OVERLAY_DIR;
+ static const char* ODM_OVERLAY_DIR;
/*
* If OVERLAY_THEME_DIR_PROPERTY is set, search for runtime resource overlay
* APKs in VENDOR_OVERLAY_DIR/<value of OVERLAY_THEME_DIR_PROPERTY> in
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index a3eee0a67d56..55f1911119f4 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -388,9 +388,10 @@ public final class AudioAttributes implements Parcelable {
*/
public static final int FLAG_NO_SYSTEM_CAPTURE = 0x1 << 12;
- private final static int FLAG_ALL = FLAG_AUDIBILITY_ENFORCED | FLAG_SECURE | FLAG_SCO |
- FLAG_BEACON | FLAG_HW_AV_SYNC | FLAG_HW_HOTWORD | FLAG_BYPASS_INTERRUPTION_POLICY |
- FLAG_BYPASS_MUTE | FLAG_LOW_LATENCY | FLAG_DEEP_BUFFER | FLAG_MUTE_HAPTIC;
+ private static final int FLAG_ALL = FLAG_AUDIBILITY_ENFORCED | FLAG_SECURE | FLAG_SCO
+ | FLAG_BEACON | FLAG_HW_AV_SYNC | FLAG_HW_HOTWORD | FLAG_BYPASS_INTERRUPTION_POLICY
+ | FLAG_BYPASS_MUTE | FLAG_LOW_LATENCY | FLAG_DEEP_BUFFER | FLAG_NO_MEDIA_PROJECTION
+ | FLAG_MUTE_HAPTIC | FLAG_NO_SYSTEM_CAPTURE;
private final static int FLAG_ALL_PUBLIC = FLAG_AUDIBILITY_ENFORCED |
FLAG_HW_AV_SYNC | FLAG_LOW_LATENCY;
diff --git a/media/java/android/media/AudioPlaybackConfiguration.java b/media/java/android/media/AudioPlaybackConfiguration.java
index 5d12c3cd251d..b2ebfa934178 100644
--- a/media/java/android/media/AudioPlaybackConfiguration.java
+++ b/media/java/android/media/AudioPlaybackConfiguration.java
@@ -43,8 +43,6 @@ public final class AudioPlaybackConfiguration implements Parcelable {
/** @hide */
public static final int PLAYER_PIID_INVALID = -1;
/** @hide */
- public static final int PLAYER_PIID_UNASSIGNED = 0;
- /** @hide */
public static final int PLAYER_UPID_INVALID = -1;
// information about the implementation
diff --git a/media/java/android/media/PlayerBase.java b/media/java/android/media/PlayerBase.java
index 50caf733da9d..ee8f1b3eec77 100644
--- a/media/java/android/media/PlayerBase.java
+++ b/media/java/android/media/PlayerBase.java
@@ -50,6 +50,10 @@ public abstract class PlayerBase {
private static final boolean DEBUG = DEBUG_APP_OPS || false;
private static IAudioService sService; //lazy initialization, use getService()
+ /** if true, only use OP_PLAY_AUDIO monitoring for logging, and rely on muting to happen
+ * in AudioFlinger */
+ private static final boolean USE_AUDIOFLINGER_MUTING_FOR_OP = true;
+
// parameters of the player that affect AppOps
protected AudioAttributes mAttributes;
@@ -67,13 +71,13 @@ public abstract class PlayerBase {
// for AppOps
private @Nullable IAppOpsService mAppOps;
- private IAppOpsCallback mAppOpsCallback;
+ private @Nullable IAppOpsCallback mAppOpsCallback;
@GuardedBy("mLock")
private boolean mHasAppOpsPlayAudio = true;
private final int mImplType;
// uniquely identifies the Player Interface throughout the system (P I Id)
- private int mPlayerIId = AudioPlaybackConfiguration.PLAYER_PIID_UNASSIGNED;
+ private int mPlayerIId = AudioPlaybackConfiguration.PLAYER_PIID_INVALID;
@GuardedBy("mLock")
private int mState;
@@ -104,27 +108,27 @@ public abstract class PlayerBase {
* Call from derived class when instantiation / initialization is successful
*/
protected void baseRegisterPlayer() {
- int newPiid = AudioPlaybackConfiguration.PLAYER_PIID_INVALID;
- IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE);
- mAppOps = IAppOpsService.Stub.asInterface(b);
- // initialize mHasAppOpsPlayAudio
- updateAppOpsPlayAudio();
- // register a callback to monitor whether the OP_PLAY_AUDIO is still allowed
- mAppOpsCallback = new IAppOpsCallbackWrapper(this);
- try {
- mAppOps.startWatchingMode(AppOpsManager.OP_PLAY_AUDIO,
- ActivityThread.currentPackageName(), mAppOpsCallback);
- } catch (RemoteException e) {
- Log.e(TAG, "Error registering appOps callback", e);
- mHasAppOpsPlayAudio = false;
+ if (!USE_AUDIOFLINGER_MUTING_FOR_OP) {
+ IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE);
+ mAppOps = IAppOpsService.Stub.asInterface(b);
+ // initialize mHasAppOpsPlayAudio
+ updateAppOpsPlayAudio();
+ // register a callback to monitor whether the OP_PLAY_AUDIO is still allowed
+ mAppOpsCallback = new IAppOpsCallbackWrapper(this);
+ try {
+ mAppOps.startWatchingMode(AppOpsManager.OP_PLAY_AUDIO,
+ ActivityThread.currentPackageName(), mAppOpsCallback);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error registering appOps callback", e);
+ mHasAppOpsPlayAudio = false;
+ }
}
try {
- newPiid = getService().trackPlayer(
+ mPlayerIId = getService().trackPlayer(
new PlayerIdCard(mImplType, mAttributes, new IPlayerWrapper(this)));
} catch (RemoteException e) {
Log.e(TAG, "Error talking to audio service, player will not be tracked", e);
}
- mPlayerIId = newPiid;
}
/**
@@ -284,6 +288,9 @@ public abstract class PlayerBase {
* Must be called synchronized on mLock.
*/
void updateAppOpsPlayAudio_sync(boolean attributesChanged) {
+ if (USE_AUDIOFLINGER_MUTING_FOR_OP) {
+ return;
+ }
boolean oldHasAppOpsPlayAudio = mHasAppOpsPlayAudio;
try {
int mode = AppOpsManager.MODE_IGNORED;
@@ -333,6 +340,9 @@ public abstract class PlayerBase {
* @return
*/
boolean isRestricted_sync() {
+ if (USE_AUDIOFLINGER_MUTING_FOR_OP) {
+ return false;
+ }
// check app ops
if (mHasAppOpsPlayAudio) {
return false;
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index 1f2480ba0b47..177f2b8ee491 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -248,16 +248,21 @@ LIBANDROID {
ASystemFontIterator_open; # introduced=29
ASystemFontIterator_close; # introduced=29
ASystemFontIterator_next; # introduced=29
- ASystemFont_close; # introduced=29
- ASystemFont_getFontFilePath; # introduced=29
- ASystemFont_getWeight; # introduced=29
- ASystemFont_isItalic; # introduced=29
- ASystemFont_getLocale; # introduced=29
- ASystemFont_getCollectionIndex; # introduced=29
- ASystemFont_getAxisCount; # introduced=29
- ASystemFont_getAxisTag; # introduced=29
- ASystemFont_getAxisValue; # introduced=29
- ASystemFont_matchFamilyStyleCharacter; # introduced=29
+ AFont_close; # introduced=29
+ AFont_getFontFilePath; # introduced=29
+ AFont_getWeight; # introduced=29
+ AFont_isItalic; # introduced=29
+ AFont_getLocale; # introduced=29
+ AFont_getCollectionIndex; # introduced=29
+ AFont_getAxisCount; # introduced=29
+ AFont_getAxisTag; # introduced=29
+ AFont_getAxisValue; # introduced=29
+ AFontMatcher_create; # introduced=29
+ AFontMatcher_destroy; # introduced=29
+ AFontMatcher_setStyle; # introduced=29
+ AFontMatcher_setLocales; # introduced=29
+ AFontMatcher_setFamilyVariant; # introduced=29
+ AFontMatcher_match; # introduced=29
ATrace_beginSection; # introduced=23
ATrace_endSection; # introduced=23
ATrace_isEnabled; # introduced=23
diff --git a/native/android/system_fonts.cpp b/native/android/system_fonts.cpp
index 4d3d1d66ffda..302cbd11da4b 100644
--- a/native/android/system_fonts.cpp
+++ b/native/android/system_fonts.cpp
@@ -16,6 +16,8 @@
#include <jni.h>
+#include <android/font.h>
+#include <android/font_matcher.h>
#include <android/system_fonts.h>
#include <memory>
@@ -53,7 +55,7 @@ struct ASystemFontIterator {
XmlDocUniquePtr mCustomizationXmlDoc;
};
-struct ASystemFont {
+struct AFont {
std::string mFilePath;
std::unique_ptr<std::string> mLocale;
uint16_t mWeight;
@@ -62,6 +64,19 @@ struct ASystemFont {
std::vector<std::pair<uint32_t, float>> mAxes;
};
+struct AFontMatcher {
+ minikin::FontStyle mFontStyle;
+ uint32_t mLocaleListId = 0; // 0 is reserved for empty locale ID.
+ bool mFamilyVariant = AFAMILY_VARIANT_DEFAULT;
+};
+
+static_assert(static_cast<uint32_t>(AFAMILY_VARIANT_DEFAULT) ==
+ static_cast<uint32_t>(minikin::FamilyVariant::DEFAULT));
+static_assert(static_cast<uint32_t>(AFAMILY_VARIANT_COMPACT) ==
+ static_cast<uint32_t>(minikin::FamilyVariant::COMPACT));
+static_assert(static_cast<uint32_t>(AFAMILY_VARIANT_ELEGANT) ==
+ static_cast<uint32_t>(minikin::FamilyVariant::ELEGANT));
+
namespace {
std::string xmlTrim(const std::string& in) {
@@ -101,7 +116,7 @@ xmlNode* nextSibling(xmlNode* node, const xmlChar* tag) {
return nullptr;
}
-void copyFont(const XmlDocUniquePtr& xmlDoc, xmlNode* fontNode, ASystemFont* out,
+void copyFont(const XmlDocUniquePtr& xmlDoc, xmlNode* fontNode, AFont* out,
const std::string& pathPrefix) {
const xmlChar* LOCALE_ATTR_NAME = BAD_CAST("lang");
XmlCharUniquePtr filePathStr(
@@ -197,24 +212,48 @@ void ASystemFontIterator_close(ASystemFontIterator* ite) {
delete ite;
}
-ASystemFont* ASystemFont_matchFamilyStyleCharacter(
- const char* _Nonnull familyName,
+AFontMatcher* _Nonnull AFontMatcher_create() {
+ return new AFontMatcher();
+}
+
+void AFontMatcher_destroy(AFontMatcher* matcher) {
+ delete matcher;
+}
+
+void AFontMatcher_setStyle(
+ AFontMatcher* _Nonnull matcher,
uint16_t weight,
- bool italic,
- const char* _Nonnull languageTags,
+ bool italic) {
+ matcher->mFontStyle = minikin::FontStyle(
+ weight, static_cast<minikin::FontStyle::Slant>(italic));
+}
+
+void AFontMatcher_setLocales(
+ AFontMatcher* _Nonnull matcher,
+ const char* _Nonnull languageTags) {
+ matcher->mLocaleListId = minikin::registerLocaleList(languageTags);
+}
+
+void AFontMatcher_setFamilyVariant(AFontMatcher* _Nonnull matcher, uint32_t familyVariant) {
+ matcher->mFamilyVariant = familyVariant;
+}
+
+AFont* _Nonnull AFontMatcher_match(
+ const AFontMatcher* _Nonnull matcher,
+ const char* _Nonnull familyName,
const uint16_t* _Nonnull text,
- uint32_t textLength,
+ const uint32_t textLength,
uint32_t* _Nullable runLength) {
std::shared_ptr<minikin::FontCollection> fc =
minikin::SystemFonts::findFontCollection(familyName);
- std::vector<minikin::FontCollection::Run> runs =
- fc->itemize(minikin::U16StringPiece(text, textLength),
- minikin::FontStyle(weight, static_cast<minikin::FontStyle::Slant>(italic)),
- minikin::registerLocaleList(languageTags),
- minikin::FamilyVariant::DEFAULT);
+ std::vector<minikin::FontCollection::Run> runs = fc->itemize(
+ minikin::U16StringPiece(text, textLength),
+ matcher->mFontStyle,
+ matcher->mLocaleListId,
+ static_cast<minikin::FamilyVariant>(matcher->mFamilyVariant));
const minikin::Font* font = runs[0].fakedFont.font;
- std::unique_ptr<ASystemFont> result = std::make_unique<ASystemFont>();
+ std::unique_ptr<AFont> result = std::make_unique<AFont>();
const android::MinikinFontSkia* minikinFontSkia =
reinterpret_cast<android::MinikinFontSkia*>(font->typeface().get());
result->mFilePath = minikinFontSkia->getFilePath();
@@ -253,7 +292,7 @@ xmlNode* findNextFontNode(const XmlDocUniquePtr& xmlDoc, xmlNode* fontNode) {
}
}
-ASystemFont* ASystemFontIterator_next(ASystemFontIterator* ite) {
+AFont* ASystemFontIterator_next(ASystemFontIterator* ite) {
LOG_ALWAYS_FATAL_IF(ite == nullptr, "nullptr has passed as iterator argument");
if (ite->mXmlDoc) {
ite->mFontNode = findNextFontNode(ite->mXmlDoc, ite->mFontNode);
@@ -262,7 +301,7 @@ ASystemFont* ASystemFontIterator_next(ASystemFontIterator* ite) {
ite->mXmlDoc.reset();
ite->mFontNode = nullptr;
} else {
- std::unique_ptr<ASystemFont> font = std::make_unique<ASystemFont>();
+ std::unique_ptr<AFont> font = std::make_unique<AFont>();
copyFont(ite->mXmlDoc, ite->mFontNode, font.get(), "/system/fonts/");
if (!isFontFileAvailable(font->mFilePath)) {
return ASystemFontIterator_next(ite);
@@ -279,7 +318,7 @@ ASystemFont* ASystemFontIterator_next(ASystemFontIterator* ite) {
ite->mFontNode = nullptr;
return nullptr;
} else {
- std::unique_ptr<ASystemFont> font = std::make_unique<ASystemFont>();
+ std::unique_ptr<AFont> font = std::make_unique<AFont>();
copyFont(ite->mCustomizationXmlDoc, ite->mFontNode, font.get(), "/product/fonts/");
if (!isFontFileAvailable(font->mFilePath)) {
return ASystemFontIterator_next(ite);
@@ -290,48 +329,48 @@ ASystemFont* ASystemFontIterator_next(ASystemFontIterator* ite) {
return nullptr;
}
-void ASystemFont_close(ASystemFont* font) {
+void AFont_close(AFont* font) {
delete font;
}
-const char* ASystemFont_getFontFilePath(const ASystemFont* font) {
+const char* AFont_getFontFilePath(const AFont* font) {
LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed as font argument");
return font->mFilePath.c_str();
}
-uint16_t ASystemFont_getWeight(const ASystemFont* font) {
+uint16_t AFont_getWeight(const AFont* font) {
LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed as font argument");
return font->mWeight;
}
-bool ASystemFont_isItalic(const ASystemFont* font) {
+bool AFont_isItalic(const AFont* font) {
LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed as font argument");
return font->mItalic;
}
-const char* ASystemFont_getLocale(const ASystemFont* font) {
+const char* AFont_getLocale(const AFont* font) {
LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed to font argument");
return font->mLocale ? nullptr : font->mLocale->c_str();
}
-size_t ASystemFont_getCollectionIndex(const ASystemFont* font) {
+size_t AFont_getCollectionIndex(const AFont* font) {
LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed to font argument");
return font->mCollectionIndex;
}
-size_t ASystemFont_getAxisCount(const ASystemFont* font) {
+size_t AFont_getAxisCount(const AFont* font) {
LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed to font argument");
return font->mAxes.size();
}
-uint32_t ASystemFont_getAxisTag(const ASystemFont* font, uint32_t axisIndex) {
+uint32_t AFont_getAxisTag(const AFont* font, uint32_t axisIndex) {
LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed to font argument");
LOG_ALWAYS_FATAL_IF(axisIndex >= font->mAxes.size(),
"given axis index is out of bounds. (< %zd", font->mAxes.size());
return font->mAxes[axisIndex].first;
}
-float ASystemFont_getAxisValue(const ASystemFont* font, uint32_t axisIndex) {
+float AFont_getAxisValue(const AFont* font, uint32_t axisIndex) {
LOG_ALWAYS_FATAL_IF(font == nullptr, "nullptr has passed to font argument");
LOG_ALWAYS_FATAL_IF(axisIndex >= font->mAxes.size(),
"given axis index is out of bounds. (< %zd", font->mAxes.size());
diff --git a/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java
index 5650f2125737..bee4bbd9f42d 100644
--- a/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java
@@ -33,8 +33,8 @@ import android.net.IIpMemoryStore;
import android.net.ipmemorystore.Blob;
import android.net.ipmemorystore.IOnBlobRetrievedListener;
import android.net.ipmemorystore.IOnL2KeyResponseListener;
-import android.net.ipmemorystore.IOnNetworkAttributesRetrieved;
-import android.net.ipmemorystore.IOnSameNetworkResponseListener;
+import android.net.ipmemorystore.IOnNetworkAttributesRetrievedListener;
+import android.net.ipmemorystore.IOnSameL3NetworkResponseListener;
import android.net.ipmemorystore.IOnStatusListener;
import android.net.ipmemorystore.NetworkAttributes;
import android.net.ipmemorystore.NetworkAttributesParcelable;
@@ -297,16 +297,16 @@ public class IpMemoryStoreService extends IIpMemoryStore.Stub {
*/
@Override
public void isSameNetwork(@Nullable final String l2Key1, @Nullable final String l2Key2,
- @Nullable final IOnSameNetworkResponseListener listener) {
+ @Nullable final IOnSameL3NetworkResponseListener listener) {
if (null == listener) return;
mExecutor.execute(() -> {
try {
if (null == l2Key1 || null == l2Key2) {
- listener.onSameNetworkResponse(makeStatus(ERROR_ILLEGAL_ARGUMENT), null);
+ listener.onSameL3NetworkResponse(makeStatus(ERROR_ILLEGAL_ARGUMENT), null);
return;
}
if (null == mDb) {
- listener.onSameNetworkResponse(makeStatus(ERROR_ILLEGAL_ARGUMENT), null);
+ listener.onSameL3NetworkResponse(makeStatus(ERROR_ILLEGAL_ARGUMENT), null);
return;
}
try {
@@ -315,16 +315,16 @@ public class IpMemoryStoreService extends IIpMemoryStore.Stub {
final NetworkAttributes attr2 =
IpMemoryStoreDatabase.retrieveNetworkAttributes(mDb, l2Key2);
if (null == attr1 || null == attr2) {
- listener.onSameNetworkResponse(makeStatus(SUCCESS),
+ listener.onSameL3NetworkResponse(makeStatus(SUCCESS),
new SameL3NetworkResponse(l2Key1, l2Key2,
-1f /* never connected */).toParcelable());
return;
}
final float confidence = attr1.getNetworkGroupSamenessConfidence(attr2);
- listener.onSameNetworkResponse(makeStatus(SUCCESS),
+ listener.onSameL3NetworkResponse(makeStatus(SUCCESS),
new SameL3NetworkResponse(l2Key1, l2Key2, confidence).toParcelable());
} catch (Exception e) {
- listener.onSameNetworkResponse(makeStatus(ERROR_GENERIC), null);
+ listener.onSameL3NetworkResponse(makeStatus(ERROR_GENERIC), null);
}
} catch (final RemoteException e) {
// Client at the other end died
@@ -343,7 +343,7 @@ public class IpMemoryStoreService extends IIpMemoryStore.Stub {
*/
@Override
public void retrieveNetworkAttributes(@Nullable final String l2Key,
- @Nullable final IOnNetworkAttributesRetrieved listener) {
+ @Nullable final IOnNetworkAttributesRetrievedListener listener) {
if (null == listener) return;
mExecutor.execute(() -> {
try {
diff --git a/packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java b/packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java
index 94cc58919459..a00eff7992d4 100644
--- a/packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java
+++ b/packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java
@@ -31,8 +31,8 @@ import android.content.Context;
import android.net.ipmemorystore.Blob;
import android.net.ipmemorystore.IOnBlobRetrievedListener;
import android.net.ipmemorystore.IOnL2KeyResponseListener;
-import android.net.ipmemorystore.IOnNetworkAttributesRetrieved;
-import android.net.ipmemorystore.IOnSameNetworkResponseListener;
+import android.net.ipmemorystore.IOnNetworkAttributesRetrievedListener;
+import android.net.ipmemorystore.IOnSameL3NetworkResponseListener;
import android.net.ipmemorystore.IOnStatusListener;
import android.net.ipmemorystore.NetworkAttributes;
import android.net.ipmemorystore.NetworkAttributesParcelable;
@@ -163,9 +163,9 @@ public class IpMemoryStoreServiceTest {
private interface OnNetworkAttributesRetrievedListener {
void onNetworkAttributesRetrieved(Status status, String l2Key, NetworkAttributes attr);
}
- private IOnNetworkAttributesRetrieved onNetworkAttributesRetrieved(
+ private IOnNetworkAttributesRetrievedListener onNetworkAttributesRetrieved(
final OnNetworkAttributesRetrievedListener functor) {
- return new IOnNetworkAttributesRetrieved() {
+ return new IOnNetworkAttributesRetrievedListener() {
@Override
public void onNetworkAttributesRetrieved(final StatusParcelable status,
final String l2Key, final NetworkAttributesParcelable attributes)
@@ -182,17 +182,17 @@ public class IpMemoryStoreServiceTest {
}
/** Helper method to make an IOnSameNetworkResponseListener */
- private interface OnSameNetworkResponseListener {
- void onSameNetworkResponse(Status status, SameL3NetworkResponse answer);
+ private interface OnSameL3NetworkResponseListener {
+ void onSameL3NetworkResponse(Status status, SameL3NetworkResponse answer);
}
- private IOnSameNetworkResponseListener onSameResponse(
- final OnSameNetworkResponseListener functor) {
- return new IOnSameNetworkResponseListener() {
+ private IOnSameL3NetworkResponseListener onSameResponse(
+ final OnSameL3NetworkResponseListener functor) {
+ return new IOnSameL3NetworkResponseListener() {
@Override
- public void onSameNetworkResponse(final StatusParcelable status,
+ public void onSameL3NetworkResponse(final StatusParcelable status,
final SameL3NetworkResponseParcelable sameL3Network)
throws RemoteException {
- functor.onSameNetworkResponse(new Status(status),
+ functor.onSameL3NetworkResponse(new Status(status),
null == sameL3Network ? null : new SameL3NetworkResponse(sameL3Network));
}
diff --git a/packages/SettingsLib/HelpUtils/res/drawable/ic_help_actionbar.xml b/packages/SettingsLib/HelpUtils/res/drawable/ic_help_actionbar.xml
index 9089a930c254..1a4b1c3ebe50 100644
--- a/packages/SettingsLib/HelpUtils/res/drawable/ic_help_actionbar.xml
+++ b/packages/SettingsLib/HelpUtils/res/drawable/ic_help_actionbar.xml
@@ -20,6 +20,7 @@
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
+ android:autoMirrored="true"
android:tint="?android:attr/colorControlNormal">
<path
android:fillColor="#FFFFFFFF"
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java
index 9feacac60365..eeb6cb015ae6 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java
@@ -75,20 +75,32 @@ public class PowerWhitelistBackend {
return true;
}
+ if (isDefaultActiveApp(pkg)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Check if it is default active app in multiple area(i.e. SMS, Dialer, Device admin..)
+ */
+ public boolean isDefaultActiveApp(String pkg) {
// Additionally, check if pkg is default dialer/sms. They are considered essential apps and
// should be automatically whitelisted (otherwise user may be able to set restriction on
// them, leading to bad device behavior.)
- if (!mAppContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
- return false;
- }
+
+ final boolean hasTelephony = mAppContext.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_TELEPHONY);
final ComponentName defaultSms = SmsApplication.getDefaultSmsApplication(mAppContext,
true /* updateIfNeeded */);
- if (defaultSms != null && TextUtils.equals(pkg, defaultSms.getPackageName())) {
+ if (hasTelephony && defaultSms != null && TextUtils.equals(pkg,
+ defaultSms.getPackageName())) {
return true;
}
final String defaultDialer = DefaultDialerManager.getDefaultDialerApplication(mAppContext);
- if (TextUtils.equals(pkg, defaultDialer)) {
+ if (hasTelephony && TextUtils.equals(pkg, defaultDialer)) {
return true;
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java
index bbf807d29402..44ee423785c2 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java
@@ -118,6 +118,7 @@ public class PowerWhitelistBackendTest {
ShadowSmsApplication.setDefaultSmsApplication(new ComponentName(testSms, "receiver"));
assertThat(mPowerWhitelistBackend.isWhitelisted(testSms)).isTrue();
+ assertThat(mPowerWhitelistBackend.isDefaultActiveApp(testSms)).isTrue();
}
@Test
@@ -126,6 +127,7 @@ public class PowerWhitelistBackendTest {
ShadowDefaultDialerManager.setDefaultDialerApplication(testDialer);
assertThat(mPowerWhitelistBackend.isWhitelisted(testDialer)).isTrue();
+ assertThat(mPowerWhitelistBackend.isDefaultActiveApp(testDialer)).isTrue();
}
@Test
@@ -133,6 +135,7 @@ public class PowerWhitelistBackendTest {
doReturn(true).when(mDevicePolicyManager).packageHasActiveAdmins(PACKAGE_ONE);
assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isTrue();
+ assertThat(mPowerWhitelistBackend.isDefaultActiveApp(PACKAGE_ONE)).isTrue();
}
@Test
diff --git a/packages/SystemUI/res/drawable-nodpi/icon.xml b/packages/SystemUI/res/drawable-nodpi/icon.xml
index 48094c48aa68..7a68c032d8be 100644
--- a/packages/SystemUI/res/drawable-nodpi/icon.xml
+++ b/packages/SystemUI/res/drawable-nodpi/icon.xml
@@ -15,5 +15,5 @@ Copyright (C) 2018 The Android Open Source Project
-->
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/icon_bg"/>
- <foreground android:drawable="@drawable/p"/>
+ <foreground android:drawable="@drawable/q"/>
</adaptive-icon>
diff --git a/packages/SystemUI/res/drawable-nodpi/icon_bg.xml b/packages/SystemUI/res/drawable-nodpi/icon_bg.xml
index 31ecf7edfb11..2a54dfad8191 100644
--- a/packages/SystemUI/res/drawable-nodpi/icon_bg.xml
+++ b/packages/SystemUI/res/drawable-nodpi/icon_bg.xml
@@ -14,5 +14,5 @@ Copyright (C) 2018 The Android Open Source Project
limitations under the License.
-->
<color xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="#C5E1A5" />
+ android:color="#77C360" />
diff --git a/packages/SystemUI/res/drawable-nodpi/p.xml b/packages/SystemUI/res/drawable-nodpi/p.xml
deleted file mode 100644
index 596b7824cdb7..000000000000
--- a/packages/SystemUI/res/drawable-nodpi/p.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<!--
-Copyright (C) 2018 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="108dp"
- android:height="108dp"
- android:viewportWidth="108"
- android:viewportHeight="108">
- <path
- android:pathData="M49,65L54,65C60.075,65 65,60.075 65,54C65,47.925 60.075,43 54,43C47.925,43 43,47.925 43,54L43,108"
- android:strokeWidth="16"
- android:fillColor="#00000000"
- android:strokeColor="#7CB342"
- android:fillType="evenOdd"/>
- <path
- android:pathData="M51,65L54,65C60.075,65 65,60.075 65,54C65,47.925 60.075,43 54,43C47.925,43 43,47.925 43,54L43,108"
- android:strokeWidth="8"
- android:fillColor="#00000000"
- android:strokeColor="#FFFFFF"
- android:fillType="evenOdd"/>
-</vector>
diff --git a/packages/SystemUI/res/drawable-nodpi/q.xml b/packages/SystemUI/res/drawable-nodpi/q.xml
new file mode 100644
index 000000000000..0f42d2e20040
--- /dev/null
+++ b/packages/SystemUI/res/drawable-nodpi/q.xml
@@ -0,0 +1,40 @@
+<!--
+Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportWidth="108.0"
+ android:viewportHeight="108.0">
+ <group
+ android:name="scale"
+ android:pivotX="54" android:pivotY="54"
+ android:scaleX="0.9"
+ android:scaleY="0.9">
+ <group
+ android:name="nudge"
+ android:translateX="24"
+ android:translateY="23.5">
+ <path
+ android:name="tail"
+ android:fillColor="#FFFFFF"
+ android:pathData="M21.749674,34.122784l-9.431964,9.529709l-6.31771,-6.2529106l15.736504,-15.899582l64.765724,65.16436l-6.3046494,6.266083z"/>
+ <path
+ android:name="counter"
+ android:fillColor="#FFFFFF"
+ android:pathData="M30,9.32352941 C41.6954418,9.32352941 51.1764706,18.8045582 51.1764706,30.5 C51.1764706,42.1954418 41.6954418,51.6764706 30,51.6764706 C18.3045582,51.6764706 8.82352941,42.1954418 8.82352941,30.5 C8.82352941,18.8045582 18.3045582,9.32352941 30,9.32352941 L30,9.32352941 Z M30,0.5 C13.4314575,0.5 -5.53805368e-15,13.9314575 -7.10542736e-15,30.5 C-1.02401747e-14,47.0685425 13.4314575,60.5 30,60.5 C46.5685425,60.5 60,47.0685425 60,30.5 C59.9805514,13.9395201 46.5604799,0.519448617 30,0.5 Z"/>
+ </group>
+ </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/bubble_flyout.xml b/packages/SystemUI/res/drawable/bubble_flyout.xml
new file mode 100644
index 000000000000..5406aaa65372
--- /dev/null
+++ b/packages/SystemUI/res/drawable/bubble_flyout.xml
@@ -0,0 +1,29 @@
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
+ <!-- TODO: Add the triangle pointing to the bubble stack. -->
+ <item>
+ <shape android:shape="rectangle">
+ <solid android:color="?android:attr/colorBackgroundFloating" />
+ <corners
+ android:bottomLeftRadius="?android:attr/dialogCornerRadius"
+ android:topLeftRadius="?android:attr/dialogCornerRadius"
+ android:bottomRightRadius="?android:attr/dialogCornerRadius"
+ android:topRightRadius="?android:attr/dialogCornerRadius"
+ />
+ </shape>
+ </item>
+</layer-list> \ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_notification_gentle.xml b/packages/SystemUI/res/drawable/ic_notification_gentle.xml
new file mode 100644
index 000000000000..7074130a63ce
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_notification_gentle.xml
@@ -0,0 +1,40 @@
+<!--
+Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:id="@+id/back">
+ <shape android:shape="oval">
+ <solid
+ android:color="@color/GM2_green_500" />
+ <size
+ android:height="36dp"
+ android:width="36dp"/>
+ </shape>
+ </item>
+ <item
+ android:id="@+id/fore"
+ android:gravity="center">
+ <vector
+ android:width="32dp"
+ android:height="32dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M15,14.5c-1.38,0 -2.5,-1.12 -2.5,-2.5c0,-0.28 -0.22,-0.5 -0.5,-0.5s-0.5,0.22 -0.5,0.5c0,1.38 -1.12,2.5 -2.5,2.5S6.5,13.38 6.5,12c0,-0.28 -0.22,-0.5 -0.5,-0.5c-0.24,0 -0.46,0.18 -0.49,0.42C5.41,12.55 4.89,13 4.27,13H2v-2h1.71C4.1,10.11 5,9.5 6,9.5c1.38,0 2.5,1.12 2.5,2.5c0,0.28 0.22,0.5 0.5,0.5s0.5,-0.22 0.5,-0.5c0,-1.38 1.12,-2.5 2.5,-2.5s2.5,1.12 2.5,2.5c0,0.28 0.22,0.5 0.5,0.5s0.5,-0.22 0.5,-0.5c0,-1.38 1.12,-2.5 2.5,-2.5c1.02,0 1.91,0.6 2.29,1.5H22v2h-2.27c-0.62,0 -1.14,-0.45 -1.23,-1.08c-0.04,-0.24 -0.25,-0.42 -0.49,-0.42c-0.28,0 -0.5,0.22 -0.5,0.5C17.5,13.38 16.38,14.5 15,14.5z"/>
+ </vector>
+ </item>
+</layer-list>
diff --git a/packages/SystemUI/res/drawable/ic_notification_interruptive.xml b/packages/SystemUI/res/drawable/ic_notification_interruptive.xml
new file mode 100644
index 000000000000..0a8b3b8fa775
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_notification_interruptive.xml
@@ -0,0 +1,41 @@
+<!--
+Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:id="@+id/back">
+ <shape android:shape="oval">
+ <solid
+ android:color="@color/GM2_yellow_500" />
+ <size
+ android:height="36dp"
+ android:width="36dp"/>
+ </shape>
+ </item>
+ <item
+ android:id="@+id/fore"
+ android:gravity="center">
+ <vector
+ android:width="32dp"
+ android:height="32dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M8.98,16.65c-0.47,0 -0.91,-0.27 -1.12,-0.69l-1.93,-4.61L5.46,12.3c-0.21,0.43 -0.64,0.69 -1.12,0.69H2v-2h1.88l1,-2C5.1,8.56 5.52,8.3 6,8.3s0.9,0.26 1.12,0.69l1.73,4.14l2,-7c0.2,-0.46 0.65,-0.76 1.15,-0.76s0.95,0.3 1.15,0.76l0.04,0.12l1.96,6.88l1.7,-4.08c0.49,-0.98 1.84,-0.91 2.26,-0.06l1,2H22v2h-2.35c-0.47,0 -0.91,-0.27 -1.12,-0.7l-0.47,-0.95l-1.9,4.55c-0.25,0.5 -0.69,0.77 -1.18,0.75c-0.48,-0.01 -0.92,-0.31 -1.11,-0.76l-0.04,-0.12L12,9.37l-1.87,6.52c-0.19,0.45 -0.63,0.74 -1.11,0.76C9.01,16.65 9,16.65 8.98,16.65zM20.32,11.4L20.32,11.4C20.32,11.4 20.32,11.4 20.32,11.4z" />
+ </vector>
+ </item>
+</layer-list>
diff --git a/packages/SystemUI/res/layout/bubble_flyout.xml b/packages/SystemUI/res/layout/bubble_flyout.xml
new file mode 100644
index 000000000000..74c6c123479c
--- /dev/null
+++ b/packages/SystemUI/res/layout/bubble_flyout.xml
@@ -0,0 +1,33 @@
+<!--
+ ~ Copyright (C) 2019 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<FrameLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/bubble_flyout"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:background="@drawable/bubble_flyout"
+ android:padding="@dimen/bubble_flyout_padding"
+ android:translationZ="@dimen/bubble_flyout_elevation">
+
+ <TextView
+ android:id="@+id/bubble_flyout_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:maxLines="2"
+ android:maxWidth="@dimen/bubble_flyout_maxwidth"
+ android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Title" />
+
+</FrameLayout> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/bubble_view.xml b/packages/SystemUI/res/layout/bubble_view.xml
index 13186fc6437c..a8eb2914b0b2 100644
--- a/packages/SystemUI/res/layout/bubble_view.xml
+++ b/packages/SystemUI/res/layout/bubble_view.xml
@@ -27,12 +27,4 @@
android:padding="@dimen/bubble_view_padding"
android:clipToPadding="false"/>
- <TextView
- android:id="@+id/message_view"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:minWidth="@dimen/bubble_message_min_width"
- android:maxWidth="@dimen/bubble_message_max_width"
- android:padding="@dimen/bubble_message_padding"/>
-
</com.android.systemui.bubbles.BubbleView>
diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml
index 0d44931463bd..f7c6c435d258 100644
--- a/packages/SystemUI/res/layout/notification_info.xml
+++ b/packages/SystemUI/res/layout/notification_info.xml
@@ -24,6 +24,7 @@
android:clipChildren="false"
android:clipToPadding="false"
android:orientation="vertical"
+ android:paddingStart="@*android:dimen/notification_content_margin_start"
android:background="@color/notification_guts_bg_color">
<!-- Package Info -->
@@ -31,7 +32,6 @@
android:id="@+id/header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginStart="@*android:dimen/notification_content_margin_start"
android:clipChildren="false"
android:clipToPadding="false">
<ImageView
@@ -44,7 +44,7 @@
android:id="@+id/pkgname"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Info"
+ style="@style/TextAppearance.NotificationInfo.Primary"
android:layout_marginStart="3dp"
android:layout_marginEnd="2dp"
android:singleLine="true"
@@ -54,7 +54,7 @@
android:id="@+id/pkg_divider"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Info"
+ style="@style/TextAppearance.NotificationInfo.Primary"
android:layout_marginStart="2dp"
android:layout_marginEnd="2dp"
android:text="@*android:string/notification_header_divider_symbol"
@@ -64,7 +64,7 @@
android:id="@+id/delegate_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Info"
+ style="@style/TextAppearance.NotificationInfo.Primary"
android:layout_marginStart="2dp"
android:layout_marginEnd="2dp"
android:ellipsize="end"
@@ -77,286 +77,284 @@
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_alignParentEnd="true"
- android:paddingHorizontal="16dp"
+
android:orientation="horizontal">
<!-- Optional link to app. Only appears if the channel is not disabled and the app
asked for it -->
<ImageButton
android:id="@+id/app_settings"
- android:layout_width="40dp"
- android:layout_height="56dp"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
android:layout_centerVertical="true"
- android:paddingRight="16dp"
android:visibility="gone"
android:background="@drawable/ripple_drawable"
android:contentDescription="@string/notification_app_settings"
- android:src="@drawable/ic_settings"
- android:tint="?android:attr/colorAccent" />
+ android:src="@drawable/ic_info"
+ android:tint="@color/notification_guts_link_icon_tint" />
<!-- 24 dp icon with 16 dp padding all around to mirror notification content margins -->
<ImageButton
android:id="@+id/info"
- android:layout_width="24dp"
- android:layout_height="56dp"
+ android:layout_width="48dp"
+ android:layout_height="48dp"
android:layout_centerVertical="true"
android:background="@drawable/ripple_drawable"
android:contentDescription="@string/notification_more_settings"
- android:src="@drawable/ic_info"
- android:tint="?android:attr/colorAccent" />
+ android:src="@drawable/ic_settings"
+ android:tint="@color/notification_guts_link_icon_tint" />
</LinearLayout>
</RelativeLayout>
+ <!-- Channel Info Block -->
<LinearLayout
- android:id="@+id/prompt"
+ android:id="@+id/channel_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/notification_guts_button_spacing"
- android:clipChildren="false"
- android:clipToPadding="false"
+ android:paddingEnd="@*android:dimen/notification_content_margin_end"
android:orientation="vertical">
-
- <!-- Channel Info Block -->
- <LinearLayout
+ <RelativeLayout
+ android:id="@+id/names"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginStart="@*android:dimen/notification_content_margin_start"
- android:layout_marginEnd="@*android:dimen/notification_content_margin_start"
- android:orientation="vertical">
- <RelativeLayout
- android:id="@+id/names"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
- <TextView
- android:id="@+id/group_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Title"
- android:layout_marginStart="2dp"
- android:layout_marginEnd="2dp"
- android:ellipsize="end"
- android:maxLines="1"
- android:layout_centerVertical="true" />
- <TextView
- android:id="@+id/pkg_group_divider"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Notification.Title"
- android:layout_marginStart="2dp"
- android:layout_marginEnd="2dp"
- android:text="@*android:string/notification_header_divider_symbol"
- android:layout_centerVertical="true"
- android:layout_toEndOf="@id/group_name" />
- <!-- Channel Name -->
- <TextView
- android:id="@+id/channel_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- style="@*android:style/TextAppearance.DeviceDefault.Notification.Title"
- android:layout_toEndOf="@id/pkg_group_divider"/>
- </RelativeLayout>
- <!-- Question prompt -->
+ android:layout_height="wrap_content">
<TextView
- android:id="@+id/block_prompt"
+ android:id="@+id/group_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- style="@*android:style/TextAppearance.DeviceDefault.Notification" />
- </LinearLayout>
+ style="@style/TextAppearance.NotificationInfo.Primary"
+ android:layout_marginStart="2dp"
+ android:layout_marginEnd="2dp"
+ android:ellipsize="end"
+ android:maxLines="1"
+ android:layout_centerVertical="true" />
+ <TextView
+ android:id="@+id/pkg_group_divider"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ style="@style/TextAppearance.NotificationInfo.Primary"
+ android:layout_marginStart="2dp"
+ android:layout_marginEnd="2dp"
+ android:text="@*android:string/notification_header_divider_symbol"
+ android:layout_centerVertical="true"
+ android:layout_toEndOf="@id/group_name" />
+ <!-- Channel Name -->
+ <TextView
+ android:id="@+id/channel_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ style="@style/TextAppearance.NotificationInfo.Primary"
+ android:layout_toEndOf="@id/pkg_group_divider"/>
+ </RelativeLayout>
+ </LinearLayout>
- <!-- Settings and Done buttons -->
+ <LinearLayout
+ android:id="@+id/blocking_helper"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/notification_guts_button_spacing"
+ android:paddingEnd="@*android:dimen/notification_content_margin_end"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:orientation="vertical">
+ <!-- blocking helper text. no need for non-configurable check b/c controls won't be
+ activated in that case -->
+ <TextView
+ android:id="@+id/blocking_helper_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="2dp"
+ android:text="@string/inline_blocking_helper"
+ style="@*android:style/TextAppearance.DeviceDefault.Notification" />
<RelativeLayout
- android:id="@+id/block_or_minimize"
+ android:id="@+id/block_buttons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/notification_guts_button_spacing"
- android:layout_marginStart="@dimen/notification_guts_button_side_margin"
- android:layout_marginEnd="@dimen/notification_guts_button_side_margin"
- android:clipChildren="false"
- android:clipToPadding="false">
+ android:layout_marginTop="@dimen/notification_guts_button_spacing">
<TextView
- android:id="@+id/done"
- android:text="@string/inline_ok_button"
+ android:id="@+id/blocking_helper_turn_off_notifications"
+ android:text="@string/inline_turn_off_notifications"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
- android:maxWidth="100dp"
+ android:layout_alignParentStart="true"
+ android:width="110dp"
+ android:paddingEnd="15dp"
+ android:breakStrategy="simple"
style="@style/TextAppearance.NotificationInfo.Button"/>
-
- <LinearLayout
- android:id="@+id/block_buttons"
+ <TextView
+ android:id="@+id/deliver_silently"
+ android:text="@string/inline_deliver_silently_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing"
+ android:paddingEnd="15dp"
+ android:width="110dp"
+ android:breakStrategy="simple"
+ android:layout_toStartOf="@+id/keep_showing"
+ style="@style/TextAppearance.NotificationInfo.Button"/>
+ <TextView
+ android:id="@+id/keep_showing"
+ android:text="@string/inline_keep_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
+ android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing"
+ android:width="110dp"
+ android:breakStrategy="simple"
android:layout_alignParentEnd="true"
- android:maxWidth="200dp"
- android:orientation="horizontal">
- <TextView
- android:id="@+id/deliver_silently"
- android:text="@string/inline_silent_button_silent"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing"
- android:paddingRight="24dp"
- android:maxWidth="125dp"
- style="@style/TextAppearance.NotificationInfo.Button"/>
- <TextView
- android:id="@+id/block"
- android:text="@string/inline_block_button"
- android:minWidth="48dp"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:maxWidth="75dp"
- android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing"
- style="@style/TextAppearance.NotificationInfo.Button"/>
- <TextView
- android:id="@+id/minimize"
- android:text="@string/inline_minimize_button"
- android:minWidth="48dp"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:maxWidth="75dp"
- android:layout_marginStart="@dimen/notification_guts_button_horizontal_spacing"
- style="@style/TextAppearance.NotificationInfo.Button"/>
- </LinearLayout>
+ style="@style/TextAppearance.NotificationInfo.Button"/>
</RelativeLayout>
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/inline_controls"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/notification_guts_button_spacing"
+ android:paddingEnd="@*android:dimen/notification_content_margin_end"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:orientation="vertical">
+
+ <!-- Non configurable app/channel text. appears instead of @+id/interruptiveness_settings-->
+ <TextView
+ android:id="@+id/non_configurable_text"
+ android:text="@string/notification_unblockable_desc"
+ android:visibility="gone"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="@dimen/notification_guts_option_vertical_padding"
+ style="@*android:style/TextAppearance.DeviceDefault.Notification" />
+
+ <!-- Non configurable multichannel text. appears instead of @+id/interruptiveness_settings-->
+ <TextView
+ android:id="@+id/non_configurable_multichannel_text"
+ android:text="@string/notification_multichannel_desc"
+ android:visibility="gone"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="@dimen/notification_guts_option_vertical_padding"
+ style="@*android:style/TextAppearance.DeviceDefault.Notification" />
+
<LinearLayout
android:id="@+id/interruptiveness_settings"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical"
- android:visibility="gone">
+ android:orientation="vertical">
+ <!-- Interruptive row -->
<LinearLayout
+ android:id="@+id/alert_row"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="2dp"
- android:layout_marginStart="@dimen/notification_guts_button_side_margin"
- android:layout_marginEnd="@dimen/notification_guts_button_side_margin"
- android:gravity="center"
+ android:paddingTop="@dimen/notification_guts_option_vertical_padding"
+ android:paddingBottom="@dimen/notification_guts_option_vertical_padding"
+ android:paddingStart="@dimen/notification_guts_option_horizontal_padding"
android:orientation="horizontal">
+
+ <ImageView
+ android:id="@+id/int_alert"
+ android:src="@drawable/ic_notification_interruptive"
+ android:background="@android:color/transparent"
+ android:layout_gravity="center"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/inline_silent_button_alert"/>
+
<LinearLayout
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:gravity="center_horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="@dimen/notification_guts_option_horizontal_padding"
+ android:paddingEnd="@dimen/notification_guts_option_horizontal_padding"
android:orientation="vertical">
- <FrameLayout
- android:id="@+id/int_block_wrapper"
- android:padding="4dp"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:gravity="center">
- <ImageButton
- android:id="@+id/int_block"
- android:background="@drawable/circle_white_40dp"
- android:src="@drawable/ic_notification_block"
- android:layout_gravity="center"
- android:layout_width="40dp"
- android:layout_height="40dp"
- android:clickable="false"
- android:contentDescription="@string/inline_block_button"
- android:tint="@color/GM2_grey_400"
- style="@style/TextAppearance.NotificationInfo.Button"/>
- </FrameLayout>
<TextView
- android:id="@+id/int_block_label"
- android:text="@string/inline_block_button"
- android:layout_gravity="center_horizontal"
- android:gravity="center"
+ android:id="@+id/int_alert_label"
+ android:text="@string/inline_silent_button_alert"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
- style="@style/TextAppearance.NotificationInfo.ButtonLabel"/>
+ style="@style/TextAppearance.NotificationInfo.Primary"/>
+ <TextView
+ android:id="@+id/int_alert_summary"
+ android:text="@string/hint_text_alert"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:ellipsize="end"
+ style="@style/TextAppearance.NotificationInfo.Secondary"/>
</LinearLayout>
+ </LinearLayout>
+
+ <!-- Gentle row -->
+ <LinearLayout
+ android:id="@+id/silent_row"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="@dimen/notification_guts_option_vertical_padding"
+ android:paddingBottom="@dimen/notification_guts_option_vertical_padding"
+ android:paddingStart="@dimen/notification_guts_option_horizontal_padding"
+ android:layout_marginTop="@dimen/notification_guts_option_vertical_margin"
+ android:orientation="horizontal">
+ <ImageView
+ android:id="@+id/int_silent"
+ android:src="@drawable/ic_notification_gentle"
+ android:layout_gravity="center"
+ android:layout_width="36dp"
+ android:layout_height="36dp"
+ android:background="@android:color/transparent"
+ android:contentDescription="@string/inline_silent_button_silent"/>
<LinearLayout
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:gravity="center_horizontal"
- android:orientation="vertical">
- <FrameLayout
- android:id="@+id/int_silent_wrapper"
- android:padding="4dp"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:gravity="center">
- <ImageButton
- android:id="@+id/int_silent"
- android:background="@drawable/circle_white_40dp"
- android:src="@drawable/ic_notifications_silence"
- android:layout_gravity="center"
- android:layout_width="40dp"
- android:layout_height="40dp"
- android:clickable="false"
- android:contentDescription="@string/inline_silent_button_silent"
- android:tint="@color/GM2_grey_400"
- style="@style/TextAppearance.NotificationInfo.Button"/>
- </FrameLayout>
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:paddingStart="@dimen/notification_guts_option_horizontal_padding"
+ android:paddingEnd="@dimen/notification_guts_option_horizontal_padding">
<TextView
android:id="@+id/int_silent_label"
android:text="@string/inline_silent_button_silent"
- android:layout_gravity="center_horizontal"
- android:gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
- style="@style/TextAppearance.NotificationInfo.ButtonLabel"/>
- </LinearLayout>
- <LinearLayout
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:gravity="center_horizontal"
- android:orientation="vertical">
- <FrameLayout
- android:id="@+id/int_alert_wrapper"
- android:padding="4dp"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:gravity="center">
- <ImageButton
- android:id="@+id/int_alert"
- android:background="@drawable/circle_white_40dp"
- android:src="@drawable/ic_notifications_alert"
- android:layout_gravity="center"
- android:layout_width="40dp"
- android:layout_height="40dp"
- android:contentDescription="@string/inline_silent_button_alert"
- android:clickable="false"
- android:tint="@color/GM2_grey_400"
- style="@style/TextAppearance.NotificationInfo.Button"/>
- </FrameLayout>
+ style="@style/TextAppearance.NotificationInfo.Primary"/>
<TextView
- android:id="@+id/int_alert_label"
- android:text="@string/inline_silent_button_alert"
- android:layout_gravity="center_horizontal"
- android:gravity="center"
+ android:id="@+id/int_silent_summary"
+ android:text="@string/hint_text_silent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
- android:maxLines="1"
- style="@style/TextAppearance.NotificationInfo.ButtonLabel"/>
+ style="@style/TextAppearance.NotificationInfo.Secondary"/>
</LinearLayout>
</LinearLayout>
+ </LinearLayout>
+
+ <RelativeLayout
+ android:id="@+id/bottom_buttons"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="@dimen/notification_guts_button_spacing"
+ android:paddingBottom="@dimen/notification_guts_button_spacing">
<TextView
- android:id="@+id/hint_text"
- android:layout_marginStart="@*android:dimen/notification_content_margin_start"
- android:layout_marginEnd="@*android:dimen/notification_content_margin_start"
+ android:id="@+id/turn_off_notifications"
+ android:text="@string/inline_turn_off_notifications"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- style="@style/TextAppearance.NotificationInfo.HintText" />
+ android:layout_centerVertical="true"
+ android:layout_alignParentStart="true"
+ android:maxWidth="200dp"
+ style="@style/TextAppearance.NotificationInfo.Button"/>
<TextView
- android:id="@+id/done_button"
+ android:id="@+id/done"
+ android:text="@string/inline_ok_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="right"
- android:paddingRight="24dp"
- android:text="@string/inline_done_button"
- style="@style/TextAppearance.NotificationInfo.Button" />
- </LinearLayout>
+ android:layout_centerVertical="true"
+ android:maxWidth="125dp"
+ android:layout_alignParentEnd="true"
+ style="@style/TextAppearance.NotificationInfo.Button"/>
+ </RelativeLayout>
+
</LinearLayout>
<com.android.systemui.statusbar.notification.row.NotificationUndoLayout
diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml
index d74d25846e3c..8a0aaea77d52 100644
--- a/packages/SystemUI/res/values-night/colors.xml
+++ b/packages/SystemUI/res/values-night/colors.xml
@@ -42,6 +42,10 @@
<!-- The color of the text inside a notification -->
<color name="notification_primary_text_color">@*android:color/notification_primary_text_color_dark</color>
+ <color name="notification_guts_selection_bg">#202124</color>
+ <color name="notification_guts_selection_border">#669DF6</color>
+ <color name="notification_guts_link_icon_tint">@color/GM2_grey_200</color>
+
<!-- The color of the background in the top part of QSCustomizer -->
<color name="qs_customize_background">@color/GM2_grey_900</color>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 290d75b4de9c..b2a507549cce 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -88,6 +88,10 @@
<!-- The "inside" of a notification, reached via longpress -->
<color name="notification_guts_bg_color">@color/GM2_grey_50</color>
+ <color name="notification_guts_selection_bg">#FFFFFF</color>
+ <color name="notification_guts_selection_border">#4285F4</color>
+ <color name="notification_guts_link_icon_tint">@color/GM2_grey_900</color>
+
<color name="assist_orb_color">#ffffff</color>
<color name="keyguard_user_switcher_background_gradient_color">#77000000</color>
@@ -163,4 +167,7 @@
<color name="GM2_red_300">#F28B82</color>
<color name="GM2_red_500">#B71C1C</color>
+
+ <color name="GM2_yellow_500">#FFFBBC04</color>
+ <color name="GM2_green_500">#FF34A853</color>
</resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index f8295ebff027..b0afe75ebc68 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -109,12 +109,12 @@
<!-- The default tiles to display in QuickSettings -->
<string name="quick_settings_tiles_default" translatable="false">
- wifi,bt,dnd,flashlight,rotation,battery,cell,airplane,cast,sensorprivacy
+ wifi,bt,dnd,flashlight,rotation,battery,cell,airplane,cast
</string>
<!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" -->
<string name="quick_settings_tiles_stock" translatable="false">
- wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location,hotspot,inversion,saver,work,cast,night,sensorprivacy
+ wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location,hotspot,inversion,saver,work,cast,night
</string>
<!-- The tiles to display in QuickSettings -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 1c97f489846c..a02469ee9fb9 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -179,7 +179,7 @@
<dimen name="notification_menu_icon_padding">20dp</dimen>
<!-- The vertical space around the buttons in the inline settings -->
- <dimen name="notification_guts_button_spacing">6dp</dimen>
+ <dimen name="notification_guts_button_spacing">12dp</dimen>
<!-- Extra horizontal space for properly aligning guts buttons with the notification content -->
<dimen name="notification_guts_button_side_margin">8dp</dimen>
@@ -196,6 +196,18 @@
<!-- The height of the header in inline settings -->
<dimen name="notification_guts_header_height">24dp</dimen>
+ <!-- The text size of the header in inline settings -->
+ <dimen name="notification_guts_header_text_size">16sp</dimen>
+
+ <!-- The horizontal space between items in the alert selections in the inline settings -->
+ <dimen name="notification_guts_option_horizontal_padding">15dp</dimen>
+
+ <!-- The vertical space between items in the alert selections in the inline settings -->
+ <dimen name="notification_guts_option_vertical_padding">15dp</dimen>
+
+ <!-- The vertical space between the alert selections in the inline settings -->
+ <dimen name="notification_guts_option_vertical_margin">6dp</dimen>
+
<!-- The minimum height for the snackbar shown after the snooze option has been chosen. -->
<dimen name="snooze_snackbar_min_height">56dp</dimen>
@@ -1035,6 +1047,12 @@
<!-- How much each bubble is elevated. -->
<dimen name="bubble_elevation">1dp</dimen>
+ <!-- How much the bubble flyout text container is elevated. -->
+ <dimen name="bubble_flyout_elevation">4dp</dimen>
+ <!-- How much padding is around the flyout text. -->
+ <dimen name="bubble_flyout_padding">16dp</dimen>
+ <!-- The maximum width of a bubble flyout. -->
+ <dimen name="bubble_flyout_maxwidth">200dp</dimen>
<!-- Padding around a collapsed bubble -->
<dimen name="bubble_view_padding">0dp</dimen>
<!-- Padding between bubbles when displayed in expanded state -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 0411d015fd63..f47d4b5aac6d 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -670,6 +670,9 @@
<item quantity="other"><xliff:g id="number" example="3">%s</xliff:g> more notifications inside.</item>
</plurals>
+ <!-- Format to use to summarize a message from a contact in a single line of text. For example: "Julia: How's it going?". [CHAR LIMIT=NONE] -->
+ <string name="notification_summary_message_format"><xliff:g id="contact_name" example="Julia">%1$s</xliff:g>: <xliff:g id="message_content" example="How is it going?">%2$s</xliff:g></string>
+
<!-- Content description of button in notification inspector for system settings relating to
notifications from this application [CHAR LIMIT=NONE] -->
<string name="status_bar_notification_inspect_item_title">Notification settings</string>
@@ -1599,7 +1602,7 @@
<string name="inline_done_button">Done</string>
<!-- Notification Inline controls: button to dismiss the blocking helper [CHAR_LIMIT=20] -->
- <string name="inline_ok_button">OK</string>
+ <string name="inline_ok_button">Apply</string>
<!-- Notification Inline controls: continue receiving notifications prompt, channel level -->
<string name="inline_keep_showing">Keep showing these notifications?</string>
@@ -1620,17 +1623,20 @@
<string name="inline_minimize_button">Minimize</string>
<!-- Notification inline controls: button to show notifications silently, without alerting the user [CHAR_LIMIT=35] -->
- <string name="inline_silent_button_silent">Show silently</string>
+ <string name="inline_silent_button_silent">Gentle</string>
<!-- Notification inline controls: button to continue showing notifications silently [CHAR_LIMIT=35] -->
<string name="inline_silent_button_stay_silent">Stay silent</string>
<!-- Notification inline controls: button to make notifications alert the user [CHAR_LIMIT=35] -->
- <string name="inline_silent_button_alert">Alert</string>
+ <string name="inline_silent_button_alert">Interruptive</string>
<!-- Notification inline controls: button to continue alerting the user when notifications arrive [CHAR_LIMIT=35] -->
<string name="inline_silent_button_keep_alerting">Keep alerting</string>
+ <!-- Notification inline controls: button to show block screen [CHAR_LIMIT=35] -->
+ <string name="inline_turn_off_notifications">Turn off notifications</string>
+
<!-- Notification Inline controls: continue receiving notifications prompt, app level -->
<string name="inline_keep_showing_app">Keep showing notifications from this app?</string>
@@ -1641,11 +1647,14 @@
<string name="hint_text_silent">Silent notifications appear in the shade, but do not appear on the lock screen, present a banner, or play a sound.</string>
<!-- Hint text for alert button in the interruptiveness settings [CHAR_LIMIT=NONE]-->
- <string name="hint_text_alert">Alerted notifications appear in the shade, on the lock screen, present a banner, and play a sound.</string>
+ <string name="hint_text_alert">These notifications will make a sound and show in the notification drawer, status bar, and lock screen</string>
<!-- Notification: Control panel: Label that displays when the app's notifications cannot be blocked. -->
<string name="notification_unblockable_desc">These notifications can\'t be turned off</string>
+ <!-- Notification: Control panel: label that displays when viewing settings for a group of notifications posted to multiple channels. -->
+ <string name="notification_multichannel_desc">This group of notifications cannot be configured here</string>
+
<!-- Notification: Control panel: Label for the app that posted this notification, if it's not the package that the notification was posted for -->
<string name="notification_delegate_header">via <xliff:g id="app_name" example="YouTube">%1$s</xliff:g></string>
@@ -2401,5 +2410,4 @@
<string name="bubble_accessibility_action_move_bottom_left">Move bottom left</string>
<!-- Action in accessibility menu to move the stack of bubbles to the bottom right of the screen. [CHAR LIMIT=30]-->
<string name="bubble_accessibility_action_move_bottom_right">Move bottom right</string>
-
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 7c123eff2044..2ff481f7c8fd 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -435,6 +435,7 @@
</style>
<style name="TextAppearance.NotificationInfo.Primary">
+ <item name="android:fontFamily">@*android:string/config_bodyFontFamilyMedium</item>
<item name="android:textSize">16sp</item>
<item name="android:alpha">0.87</item>
</style>
@@ -471,16 +472,12 @@
</style>
<style name="TextAppearance.NotificationInfo.Button">
- <item name="android:fontFamily">@*android:string/config_bodyFontFamilyMedium</item>
- <item name="android:textSize">14sp</item>
+ <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
+ <item name="android:textSize">16sp</item>
<item name="android:textColor">?android:attr/colorAccent</item>
<item name="android:background">@drawable/btn_borderless_rect</item>
<item name="android:gravity">center</item>
<item name="android:focusable">true</item>
- <item name="android:paddingTop">@dimen/notification_guts_button_vertical_padding</item>
- <item name="android:paddingBottom">@dimen/notification_guts_button_vertical_padding</item>
- <item name="android:paddingLeft">@dimen/notification_guts_button_horizontal_padding</item>
- <item name="android:paddingRight">@dimen/notification_guts_button_horizontal_padding</item>
</style>
<style name="TextAppearance.HeadsUpStatusBarText"
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index 7e935e3a26a5..1076e73d1072 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -24,6 +24,8 @@ import android.content.Context;
import android.content.res.Resources;
import android.view.WindowManagerPolicyConstants;
+import com.android.internal.policy.ScreenDecorationsUtils;
+
/**
* Various shared constants between Launcher and SysUI as part of quickstep
*/
@@ -130,5 +132,19 @@ public class QuickStepContract {
com.android.internal.R.dimen.config_backGestureInset);
}
+ /**
+ * Corner radius that should be used on windows in order to cover the display.
+ * These values are expressed in pixels because they should not respect display or font
+ * scaling, this means that we don't have to reload them on config changes.
+ */
+ public static float getWindowCornerRadius(Resources resources) {
+ return ScreenDecorationsUtils.getWindowCornerRadius(resources);
+ }
+ /**
+ * If live rounded corners are supported on windows.
+ */
+ public static boolean supportsRoundedCornersOnWindows(Resources resources) {
+ return ScreenDecorationsUtils.supportsRoundedCornersOnWindows(resources);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
index 72ab02c21192..822538b0ac0a 100644
--- a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
@@ -561,4 +561,29 @@ public class HardwareUiLayout extends MultiListLayout implements Tunable {
inoutInfo.contentInsets.set(mList.getLeft(), mList.getTop(),
0, getBottom() - mList.getBottom());
};
+
+ private float getAnimationDistance() {
+ return getContext().getResources().getDimension(
+ com.android.systemui.R.dimen.global_actions_panel_width) / 2;
+ }
+
+ @Override
+ public float getAnimationOffsetX() {
+ if (RotationUtils.getRotation(mContext) == ROTATION_NONE) {
+ return getAnimationDistance();
+ }
+ return 0;
+ }
+
+ @Override
+ public float getAnimationOffsetY() {
+ switch (RotationUtils.getRotation(getContext())) {
+ case RotationUtils.ROTATION_LANDSCAPE:
+ return -getAnimationDistance();
+ case RotationUtils.ROTATION_SEASCAPE:
+ return getAnimationDistance();
+ default: // Portrait
+ return 0;
+ }
+ }
} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/MultiListLayout.java b/packages/SystemUI/src/com/android/systemui/MultiListLayout.java
index d063a0f4086e..a30b681ed7cc 100644
--- a/packages/SystemUI/src/com/android/systemui/MultiListLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/MultiListLayout.java
@@ -148,6 +148,16 @@ public abstract class MultiListLayout extends LinearLayout {
}
/**
+ * Get the X offset in pixels for use when animating the view onto or off of the screen.
+ */
+ public abstract float getAnimationOffsetX();
+
+ /**
+ * Get the Y offset in pixels for use when animating the view onto or off of the screen.
+ */
+ public abstract float getAnimationOffsetY();
+
+ /**
* Adapter class for converting items into child views for MultiListLayout and handling
* callbacks for input events.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index be55829869eb..de4605b55272 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -42,7 +42,9 @@ import android.view.ViewTreeObserver;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.FrameLayout;
+import android.widget.TextView;
import androidx.annotation.MainThread;
import androidx.annotation.Nullable;
@@ -70,6 +72,13 @@ public class BubbleStackView extends FrameLayout {
private static final String TAG = "BubbleStackView";
private static final boolean DEBUG = false;
+ /** Duration of the flyout alpha animations. */
+ private static final int FLYOUT_ALPHA_ANIMATION_DURATION = 100;
+
+ /** How long to wait, in milliseconds, before hiding the flyout. */
+ @VisibleForTesting
+ static final int FLYOUT_HIDE_AFTER = 5000;
+
/**
* Interface to synchronize {@link View} state and the screen.
*
@@ -119,6 +128,14 @@ public class BubbleStackView extends FrameLayout {
private FrameLayout mExpandedViewContainer;
+ private View mFlyout;
+ private TextView mFlyoutText;
+ /** Spring animation for the flyout. */
+ private SpringAnimation mFlyoutSpring;
+ /** Runnable that fades out the flyout and then sets it to GONE. */
+ private Runnable mHideFlyout =
+ () -> mFlyout.animate().alpha(0f).withEndAction(() -> mFlyout.setVisibility(GONE));
+
private int mBubbleSize;
private int mBubblePadding;
private int mExpandedAnimateXDistance;
@@ -131,6 +148,9 @@ public class BubbleStackView extends FrameLayout {
private boolean mIsExpanded;
private boolean mImeVisible;
+ /** Whether the stack is currently being dragged. */
+ private boolean mIsDragging = false;
+
private BubbleTouchHandler mTouchHandler;
private BubbleController.BubbleExpandListener mExpandListener;
private BubbleExpandedView.OnBubbleBlockedListener mBlockedListener;
@@ -221,6 +241,17 @@ public class BubbleStackView extends FrameLayout {
mExpandedViewContainer.setClipChildren(false);
addView(mExpandedViewContainer);
+ mFlyout = mInflater.inflate(R.layout.bubble_flyout, this, false);
+ mFlyout.setVisibility(GONE);
+ mFlyout.animate()
+ .setDuration(FLYOUT_ALPHA_ANIMATION_DURATION)
+ .setInterpolator(new AccelerateDecelerateInterpolator());
+ addView(mFlyout);
+
+ mFlyoutText = mFlyout.findViewById(R.id.bubble_flyout_text);
+
+ mFlyoutSpring = new SpringAnimation(mFlyout, DynamicAnimation.TRANSLATION_X);
+
mExpandedViewXAnim =
new SpringAnimation(mExpandedViewContainer, DynamicAnimation.TRANSLATION_X);
mExpandedViewXAnim.setSpring(
@@ -448,6 +479,8 @@ public class BubbleStackView extends FrameLayout {
requestUpdate();
logBubbleEvent(b, StatsLog.BUBBLE_UICHANGED__ACTION__POSTED);
+
+ animateInFlyoutForBubble(b);
}
/**
@@ -549,6 +582,7 @@ public class BubbleStackView extends FrameLayout {
mBubbleContainer.moveViewTo(b.iconView, 0);
}
requestUpdate();
+ animateInFlyoutForBubble(b /* bubble */);
}
if (mIsExpanded && entry.equals(mExpandedBubble.entry)) {
entry.setShowInShadeWhenBubble(false);
@@ -577,11 +611,18 @@ public class BubbleStackView extends FrameLayout {
}
// Outside parts of view we care about.
return null;
+ } else if (isIntersecting(mFlyout, x, y)) {
+ return mFlyout;
}
- // If we're collapsed, the stack is always the target.
+
+ // If it wasn't an individual bubble in the expanded state, or the flyout, it's the stack.
return this;
}
+ public View getFlyoutView() {
+ return mFlyout;
+ }
+
/**
* Collapses the stack of bubbles.
* <p>
@@ -622,6 +663,8 @@ public class BubbleStackView extends FrameLayout {
*/
private void animateExpansion(boolean shouldExpand) {
if (mIsExpanded != shouldExpand) {
+ hideFlyoutImmediate();
+
mIsExpanded = shouldExpand;
updateExpandedBubble();
applyCurrentState();
@@ -735,6 +778,9 @@ public class BubbleStackView extends FrameLayout {
mStackAnimationController.cancelStackPositionAnimations();
mBubbleContainer.setController(mStackAnimationController);
+ hideFlyoutImmediate();
+
+ mIsDragging = true;
}
void onDragged(float x, float y) {
@@ -747,6 +793,7 @@ public class BubbleStackView extends FrameLayout {
void onDragFinish(float x, float y, float velX, float velY) {
// TODO: Add fling to bottom to dismiss.
+ mIsDragging = false;
if (mIsExpanded || mIsExpansionAnimating) {
return;
@@ -797,6 +844,47 @@ public class BubbleStackView extends FrameLayout {
}
}
+ /**
+ * Animates in the flyout for the given bubble, if available, and then hides it after some time.
+ */
+ @VisibleForTesting
+ void animateInFlyoutForBubble(Bubble bubble) {
+ final CharSequence updateMessage = bubble.entry.getUpdateMessage(getContext());
+
+ // Show the message if one exists, and we're not expanded or animating expansion.
+ if (updateMessage != null && !isExpanded() && !mIsExpansionAnimating && !mIsDragging) {
+ final PointF stackPos = mStackAnimationController.getStackPosition();
+
+ mFlyoutText.setText(updateMessage);
+ mFlyout.measure(WRAP_CONTENT, WRAP_CONTENT);
+ mFlyout.post(() -> {
+ final boolean onLeft = mStackAnimationController.isStackOnLeftSide();
+ final float destinationX = onLeft
+ ? stackPos.x + mBubbleSize + mBubblePadding
+ : stackPos.x - mFlyout.getMeasuredWidth();
+
+ // Translate towards the stack slightly, then spring out from the stack.
+ mFlyout.setTranslationX(destinationX + (onLeft ? -mBubblePadding : mBubblePadding));
+ mFlyout.setTranslationY(stackPos.y);
+ mFlyout.setAlpha(0f);
+
+ mFlyout.setVisibility(VISIBLE);
+
+ mFlyout.animate().alpha(1f);
+ mFlyoutSpring.animateToFinalPosition(destinationX);
+
+ mFlyout.removeCallbacks(mHideFlyout);
+ mFlyout.postDelayed(mHideFlyout, FLYOUT_HIDE_AFTER);
+ });
+ }
+ }
+
+ /** Hide the flyout immediately and cancel any pending hide runnables. */
+ private void hideFlyoutImmediate() {
+ mFlyout.removeCallbacks(mHideFlyout);
+ mHideFlyout.run();
+ }
+
@Override
public void getBoundsOnScreen(Rect outRect) {
if (!mIsExpanded) {
@@ -806,6 +894,12 @@ public class BubbleStackView extends FrameLayout {
} else {
mBubbleContainer.getBoundsOnScreen(outRect);
}
+
+ if (mFlyout.getVisibility() == View.VISIBLE) {
+ final Rect flyoutBounds = new Rect();
+ mFlyout.getBoundsOnScreen(flyoutBounds);
+ outRect.union(flyoutBounds);
+ }
}
private int getStatusBarHeight() {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
index a7170d0256e3..baeedaacdd95 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleTouchHandler.java
@@ -86,6 +86,7 @@ class BubbleTouchHandler implements View.OnTouchListener {
}
final boolean isStack = mStack.equals(mTouchedView);
+ final boolean isFlyout = mStack.getFlyoutView().equals(mTouchedView);
final float rawX = event.getRawX();
final float rawY = event.getRawY();
@@ -96,14 +97,18 @@ class BubbleTouchHandler implements View.OnTouchListener {
case MotionEvent.ACTION_DOWN:
trackMovement(event);
- mDismissViewController.createDismissTarget();
- mHandler.postDelayed(mShowDismissAffordance, SHOW_TARGET_DELAY);
-
mTouchDown.set(rawX, rawY);
+ if (!isFlyout) {
+ mDismissViewController.createDismissTarget();
+ mHandler.postDelayed(mShowDismissAffordance, SHOW_TARGET_DELAY);
+ }
+
if (isStack) {
mViewPositionOnTouchDown.set(mStack.getStackPosition());
mStack.onDragStart();
+ } else if (isFlyout) {
+ // TODO(b/129768381): Make the flyout dismissable with a gesture.
} else {
mViewPositionOnTouchDown.set(
mTouchedView.getTranslationX(), mTouchedView.getTranslationY());
@@ -123,6 +128,8 @@ class BubbleTouchHandler implements View.OnTouchListener {
if (mMovedEnough) {
if (isStack) {
mStack.onDragged(viewX, viewY);
+ } else if (isFlyout) {
+ // TODO(b/129768381): Make the flyout dismissable with a gesture.
} else {
mStack.onBubbleDragged(mTouchedView, viewX, viewY);
}
@@ -141,6 +148,11 @@ class BubbleTouchHandler implements View.OnTouchListener {
trackMovement(event);
if (mInDismissTarget && isStack) {
mController.dismissStack(BubbleController.DISMISS_USER_GESTURE);
+ } else if (isFlyout) {
+ // TODO(b/129768381): Expand if tapped, dismiss if swiped away.
+ if (!mStack.isExpanded() && !mMovedEnough) {
+ mStack.expandStack();
+ }
} else if (mMovedEnough) {
mVelocityTracker.computeCurrentVelocity(/* maxVelocity */ 1000);
final float velX = mVelocityTracker.getXVelocity();
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java
index 3b9164d60c5c..84b86bf9b69f 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java
@@ -27,7 +27,6 @@ import android.graphics.drawable.Icon;
import android.graphics.drawable.InsetDrawable;
import android.util.AttributeSet;
import android.widget.FrameLayout;
-import android.widget.TextView;
import com.android.internal.graphics.ColorUtils;
import com.android.systemui.Interpolators;
@@ -49,7 +48,6 @@ public class BubbleView extends FrameLayout {
private Context mContext;
private BadgedImageView mBadgedImageView;
- private TextView mMessageView;
private int mPadding;
private int mIconInset;
@@ -78,10 +76,7 @@ public class BubbleView extends FrameLayout {
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mBadgedImageView = (BadgedImageView) findViewById(R.id.bubble_image);
- mMessageView = (TextView) findViewById(R.id.message_view);
- mMessageView.setVisibility(GONE);
- mMessageView.setPivotX(0);
+ mBadgedImageView = findViewById(R.id.bubble_image);
}
@Override
@@ -89,33 +84,6 @@ public class BubbleView extends FrameLayout {
super.onAttachedToWindow();
}
- @Override
- protected void onMeasure(int widthSpec, int heightSpec) {
- measureChild(mBadgedImageView, widthSpec, heightSpec);
- measureChild(mMessageView, widthSpec, heightSpec);
- boolean messageGone = mMessageView.getVisibility() == GONE;
- int imageHeight = mBadgedImageView.getMeasuredHeight();
- int imageWidth = mBadgedImageView.getMeasuredWidth();
- int messageHeight = messageGone ? 0 : mMessageView.getMeasuredHeight();
- int messageWidth = messageGone ? 0 : mMessageView.getMeasuredWidth();
- setMeasuredDimension(
- getPaddingStart() + imageWidth + mPadding + messageWidth + getPaddingEnd(),
- getPaddingTop() + Math.max(imageHeight, messageHeight) + getPaddingBottom());
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- left = getPaddingStart();
- top = getPaddingTop();
- int imageWidth = mBadgedImageView.getMeasuredWidth();
- int imageHeight = mBadgedImageView.getMeasuredHeight();
- int messageWidth = mMessageView.getMeasuredWidth();
- int messageHeight = mMessageView.getMeasuredHeight();
- mBadgedImageView.layout(left, top, left + imageWidth, top + imageHeight);
- mMessageView.layout(left + imageWidth + mPadding, top,
- left + imageWidth + mPadding + messageWidth, top + messageHeight);
- }
-
/**
* Populates this view with a notification.
* <p>
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
index c39503129454..78c4fc17c655 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java
@@ -157,6 +157,15 @@ public class StackAnimationController extends
return mStackPosition;
}
+ /** Whether the stack is on the left side of the screen. */
+ public boolean isStackOnLeftSide() {
+ if (mLayout != null) {
+ return mStackPosition.x - mIndividualBubbleSize / 2 < mLayout.getWidth() / 2;
+ } else {
+ return false;
+ }
+ }
+
/**
* Flings the stack starting with the given velocities, springing it to the nearest edge
* afterward.
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index dcacd0fbc644..e22b24e2ed46 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -1127,10 +1127,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
}
protected int getActionLayoutId(Context context) {
- if (isGridEnabled(context)) {
- return com.android.systemui.R.layout.global_actions_grid_item;
- }
- return com.android.systemui.R.layout.global_actions_item;
+ return com.android.systemui.R.layout.global_actions_grid_item;
}
public View create(
@@ -1540,26 +1537,28 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
initializeLayout();
}
- private boolean initializePanel() {
+ private boolean shouldUsePanel() {
if (!isPanelEnabled(mContext) || mPanelController == null) {
return false;
}
- View panelView = mPanelController.getPanelContent();
- if (panelView == null) {
+ if (mPanelController.getPanelContent() == null) {
return false;
}
+ return true;
+ }
+
+ private void initializePanel() {
FrameLayout panelContainer = new FrameLayout(mContext);
FrameLayout.LayoutParams panelParams =
new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT);
- panelContainer.addView(panelView, panelParams);
+ panelContainer.addView(mPanelController.getPanelContent(), panelParams);
addContentView(
panelContainer,
new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
- return true;
}
private void initializeLayout() {
@@ -1578,8 +1577,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
mGlobalActionsLayout.setRotationListener(this::onRotate);
mGlobalActionsLayout.setAdapter(mAdapter);
- boolean panelEnabled = initializePanel();
- if (!panelEnabled) {
+ if (!shouldUsePanel()) {
if (mBackgroundDrawable == null) {
mBackgroundDrawable = new GradientDrawable(mContext);
}
@@ -1589,12 +1587,12 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
com.android.systemui.R.drawable.global_action_panel_scrim);
mScrimAlpha = 1f;
}
- mGlobalActionsLayout.setSnapToEdge(panelEnabled);
+ mGlobalActionsLayout.setSnapToEdge(true);
getWindow().setBackgroundDrawable(mBackgroundDrawable);
}
private int getGlobalActionsLayoutId(Context context) {
- if (isGridEnabled(context)) {
+ if (isForceGridEnabled(context) || shouldUsePanel()) {
if (RotationUtils.getRotation(context) == RotationUtils.ROTATION_SEASCAPE) {
return com.android.systemui.R.layout.global_actions_grid_seascape;
}
@@ -1653,11 +1651,13 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
super.show();
mShowing = true;
mBackgroundDrawable.setAlpha(0);
- mGlobalActionsLayout.setTranslationX(getAnimTranslation());
+ mGlobalActionsLayout.setTranslationX(mGlobalActionsLayout.getAnimationOffsetX());
+ mGlobalActionsLayout.setTranslationY(mGlobalActionsLayout.getAnimationOffsetY());
mGlobalActionsLayout.setAlpha(0);
mGlobalActionsLayout.animate()
.alpha(1)
.translationX(0)
+ .translationY(0)
.setDuration(300)
.setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.setUpdateListener(animation -> {
@@ -1675,10 +1675,12 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
}
mShowing = false;
mGlobalActionsLayout.setTranslationX(0);
+ mGlobalActionsLayout.setTranslationY(0);
mGlobalActionsLayout.setAlpha(1);
mGlobalActionsLayout.animate()
.alpha(0)
- .translationX(getAnimTranslation())
+ .translationX(mGlobalActionsLayout.getAnimationOffsetX())
+ .translationY(mGlobalActionsLayout.getAnimationOffsetY())
.setDuration(300)
.withEndAction(super::dismiss)
.setInterpolator(new LogAccelerateInterpolator())
@@ -1701,11 +1703,6 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
}
}
- private float getAnimTranslation() {
- return getContext().getResources().getDimension(
- com.android.systemui.R.dimen.global_actions_panel_width) / 2;
- }
-
@Override
public void onColorsChanged(ColorExtractor extractor, int which) {
if (mKeyguardShowing) {
@@ -1731,17 +1728,19 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener,
}
public void onRotate(int from, int to) {
- if (mShowing && isGridEnabled(mContext)) {
+ if (mShowing && (shouldUsePanel() || isForceGridEnabled(mContext))) {
refreshDialog();
}
}
}
/**
- * Determines whether or not the Global Actions menu should use the newer grid-style layout.
+ * Determines whether or not the Global Actions menu should be forced to
+ * use the newer grid-style layout.
*/
- private static boolean isGridEnabled(Context context) {
- return FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.GLOBAL_ACTIONS_GRID_ENABLED);
+ private static boolean isForceGridEnabled(Context context) {
+ return FeatureFlagUtils.isEnabled(context,
+ FeatureFlagUtils.FORCE_GLOBAL_ACTIONS_GRID_ENABLED);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java
index 9a0759c70b5b..f8825690056e 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java
@@ -16,6 +16,10 @@
package com.android.systemui.globalactions;
+import static com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE;
+import static com.android.systemui.util.leak.RotationUtils.ROTATION_NONE;
+import static com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE;
+
import android.content.Context;
import android.text.TextUtils;
import android.util.AttributeSet;
@@ -85,8 +89,8 @@ public class GlobalActionsGridLayout extends MultiListLayout {
int rotation = RotationUtils.getRotation(mContext);
boolean reverse = false; // should we add items to parents in the reverse order?
- if (rotation == RotationUtils.ROTATION_NONE
- || rotation == RotationUtils.ROTATION_SEASCAPE) {
+ if (rotation == ROTATION_NONE
+ || rotation == ROTATION_SEASCAPE) {
reverse = !reverse; // if we're in portrait or seascape, reverse items
}
if (TextUtils.getLayoutDirectionFromLocale(Locale.getDefault())
@@ -125,9 +129,9 @@ public class GlobalActionsGridLayout extends MultiListLayout {
private void updateSnapPosition() {
if (mSnapToEdge) {
setPadding(0, 0, 0, 0);
- if (mRotation == RotationUtils.ROTATION_LANDSCAPE) {
+ if (mRotation == ROTATION_LANDSCAPE) {
setGravity(Gravity.RIGHT);
- } else if (mRotation == RotationUtils.ROTATION_SEASCAPE) {
+ } else if (mRotation == ROTATION_SEASCAPE) {
setGravity(Gravity.LEFT);
} else {
setGravity(Gravity.BOTTOM);
@@ -157,9 +161,9 @@ public class GlobalActionsGridLayout extends MultiListLayout {
return getSeparatedView();
} else {
switch (rotation) {
- case RotationUtils.ROTATION_LANDSCAPE:
+ case ROTATION_LANDSCAPE:
return getListView().getParentView(index, false, true);
- case RotationUtils.ROTATION_SEASCAPE:
+ case ROTATION_SEASCAPE:
return getListView().getParentView(index, true, true);
default:
return getListView().getParentView(index, false, false);
@@ -174,4 +178,31 @@ public class GlobalActionsGridLayout extends MultiListLayout {
public void setDivisionView(View v) {
// do nothing
}
+
+ private float getAnimationDistance() {
+ int rows = getListView().getRowCount();
+ float gridItemSize = getContext().getResources().getDimension(
+ com.android.systemui.R.dimen.global_actions_grid_item_height);
+ return rows * gridItemSize / 2;
+ }
+
+ @Override
+ public float getAnimationOffsetX() {
+ switch (RotationUtils.getRotation(getContext())) {
+ case ROTATION_LANDSCAPE:
+ return getAnimationDistance();
+ case ROTATION_SEASCAPE:
+ return -getAnimationDistance();
+ default: // Portrait
+ return 0;
+ }
+ }
+
+ @Override
+ public float getAnimationOffsetY() {
+ if (RotationUtils.getRotation(mContext) == ROTATION_NONE) {
+ return getAnimationDistance();
+ }
+ return 0;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/ListGridLayout.java b/packages/SystemUI/src/com/android/systemui/globalactions/ListGridLayout.java
index 048f80196781..9c71ffc0e73b 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/ListGridLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/ListGridLayout.java
@@ -109,7 +109,10 @@ public class ListGridLayout extends LinearLayout {
}
}
- private int getRowCount() {
+ /**
+ * Get the number of rows which will be used to render children.
+ */
+ public int getRowCount() {
// special case for 3 to use a single row
if (mExpectedCount == 3) {
return 1;
@@ -117,7 +120,10 @@ public class ListGridLayout extends LinearLayout {
return (int) Math.round(Math.sqrt(mExpectedCount));
}
- private int getColumnCount() {
+ /**
+ * Get the number of columns which will be used to render children.
+ */
+ public int getColumnCount() {
// special case for 3 to use a single row
if (mExpectedCount == 3) {
return 3;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index 3140e6db2442..3ec6cb78ecc1 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -795,7 +795,10 @@ public class PipTouchHandler {
? mExpandedMovementBounds
: mNormalMovementBounds;
try {
- mPinnedStackController.setMinEdgeSize(isMenuExpanded ? mExpandedShortestEdgeSize : 0);
+ if (mPinnedStackController != null) {
+ mPinnedStackController.setMinEdgeSize(
+ isMenuExpanded ? mExpandedShortestEdgeSize : 0);
+ }
} catch (RemoteException e) {
Log.e(TAG, "Could not set minimized state", e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index 4f4dcbc9ce92..f69356ea14a0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -41,6 +41,7 @@ import android.os.SystemClock;
import android.service.notification.NotificationListenerService;
import android.service.notification.SnoozeCriterion;
import android.service.notification.StatusBarNotification;
+import android.text.TextUtils;
import android.util.ArraySet;
import android.view.View;
import android.widget.ImageView;
@@ -51,6 +52,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.ContrastColorUtil;
+import com.android.systemui.R;
import com.android.systemui.statusbar.InflationTask;
import com.android.systemui.statusbar.StatusBarIconView;
import com.android.systemui.statusbar.notification.InflationException;
@@ -393,6 +395,72 @@ public final class NotificationEntry {
}
/**
+ * Returns our best guess for the most relevant text summary of the latest update to this
+ * notification, based on its type. Returns null if there should not be an update message.
+ */
+ public CharSequence getUpdateMessage(Context context) {
+ final Notification underlyingNotif = notification.getNotification();
+ final Class<? extends Notification.Style> style = underlyingNotif.getNotificationStyle();
+
+ try {
+ if (Notification.BigTextStyle.class.equals(style)) {
+ // Return the big text, it is big so probably important. If it's not there use the
+ // normal text.
+ CharSequence bigText =
+ underlyingNotif.extras.getCharSequence(Notification.EXTRA_BIG_TEXT);
+ return !TextUtils.isEmpty(bigText)
+ ? bigText
+ : underlyingNotif.extras.getCharSequence(Notification.EXTRA_TEXT);
+ } else if (Notification.MessagingStyle.class.equals(style)) {
+ final List<Notification.MessagingStyle.Message> messages =
+ Notification.MessagingStyle.Message.getMessagesFromBundleArray(
+ (Parcelable[]) underlyingNotif.extras.get(
+ Notification.EXTRA_MESSAGES));
+
+ final Notification.MessagingStyle.Message latestMessage =
+ Notification.MessagingStyle.findLatestIncomingMessage(messages);
+
+ if (latestMessage != null) {
+ final CharSequence personName = latestMessage.getSenderPerson() != null
+ ? latestMessage.getSenderPerson().getName()
+ : null;
+
+ // Prepend the sender name if available since group chats also use messaging
+ // style.
+ if (!TextUtils.isEmpty(personName)) {
+ return context.getResources().getString(
+ R.string.notification_summary_message_format,
+ personName,
+ latestMessage.getText());
+ } else {
+ return latestMessage.getText();
+ }
+ }
+ } else if (Notification.InboxStyle.class.equals(style)) {
+ CharSequence[] lines =
+ underlyingNotif.extras.getCharSequenceArray(Notification.EXTRA_TEXT_LINES);
+
+ // Return the last line since it should be the most recent.
+ if (lines != null && lines.length > 0) {
+ return lines[lines.length - 1];
+ }
+ } else if (Notification.MediaStyle.class.equals(style)) {
+ // Return nothing, media updates aren't typically useful as a text update.
+ return null;
+ } else {
+ // Default to text extra.
+ return underlyingNotif.extras.getCharSequence(Notification.EXTRA_TEXT);
+ }
+ } catch (ClassCastException | NullPointerException | ArrayIndexOutOfBoundsException e) {
+ // No use crashing, we'll just return null and the caller will assume there's no update
+ // message.
+ e.printStackTrace();
+ }
+
+ return null;
+ }
+
+ /**
* Abort all existing inflation tasks
*/
public void abortTask() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManager.java
index 580e7024347c..2c15e87ee1e6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManager.java
@@ -85,11 +85,13 @@ public class NotificationBlockingHelperManager {
// - User sentiment is negative (DEBUG flag can bypass)
// - The notification shade is fully expanded (guarantees we're not touching a HUN).
// - The row is blockable (i.e. not non-blockable)
- // - The dismissed row is a valid group (>1 or 0 children) or the only child in the group
+ // - The dismissed row is a valid group (>1 or 0 children from the same channel)
+ // or the only child in the group
if ((row.getEntry().userSentiment == USER_SENTIMENT_NEGATIVE || DEBUG)
&& mIsShadeExpanded
&& !row.getIsNonblockable()
- && (!row.isChildInGroup() || row.isOnlyChildInGroup())) {
+ && ((!row.isChildInGroup() || row.isOnlyChildInGroup())
+ && row.getNumUniqueChannels() <= 1)) {
// Dismiss any current blocking helper before continuing forward (only one can be shown
// at a given time).
dismissCurrentBlockingHelper();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index 54bdaa23ea1d..69e61201a4d0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -309,7 +309,6 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx
mDeviceProvisionedController.isDeviceProvisioned(),
row.getIsNonblockable(),
isForBlockingHelper,
- row.getEntry().userSentiment == USER_SENTIMENT_NEGATIVE,
row.getEntry().importance,
row.getEntry().isHighPriority());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
index 2e4325b2f41f..622b869c9e4c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
@@ -39,6 +39,7 @@ import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
import android.metrics.LogMaker;
import android.os.Handler;
import android.os.RemoteException;
@@ -82,9 +83,13 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
public static final int ACTION_NONE = 0;
static final int ACTION_UNDO = 1;
+ // standard controls
static final int ACTION_TOGGLE_SILENT = 2;
+ // unused
static final int ACTION_BLOCK = 3;
+ // blocking helper
static final int ACTION_DELIVER_SILENTLY = 4;
+ // standard controls
private static final int ACTION_ALERT = 5;
private INotificationManager mINotificationManager;
@@ -99,7 +104,6 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
private NotificationChannel mSingleNotificationChannel;
private int mStartingChannelImportance;
private boolean mWasShownHighPriority;
- private int mNotificationBlockState = ACTION_NONE;
/**
* The last importance level chosen by the user. Null if the user has not chosen an importance
* level; non-null once the user takes an action which indicates an explicit preference.
@@ -109,13 +113,13 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
private boolean mIsNonblockable;
private StatusBarNotification mSbn;
private AnimatorSet mExpandAnimation;
- private boolean mIsForeground;
private boolean mIsDeviceProvisioned;
private CheckSaveListener mCheckSaveListener;
private OnSettingsClickListener mOnSettingsClickListener;
private OnAppSettingsClickListener mAppSettingsClickListener;
private NotificationGuts mGutsContainer;
+ private GradientDrawable mSelectedBackground;
/** Whether this view is being shown as part of the blocking helper. */
private boolean mIsForBlockingHelper;
@@ -125,40 +129,39 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
*/
private String mExitReason = NotificationCounters.BLOCKING_HELPER_DISMISSED;
- private OnClickListener mOnKeepShowing = v -> {
- mExitReason = NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING;
- if (mIsForBlockingHelper) {
- closeControls(v);
- mMetricsLogger.write(getLogMaker().setCategory(
- MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
- .setType(MetricsEvent.TYPE_ACTION)
- .setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_STAY_SILENT));
- }
- };
-
+ // used by standard ui
private OnClickListener mOnAlert = v -> {
mExitReason = NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING;
mChosenImportance = IMPORTANCE_DEFAULT;
- updateButtonsAndHelpText(ACTION_ALERT);
+ updateButtons(ACTION_ALERT);
+ };
+
+ // used by standard ui
+ private OnClickListener mOnSilent = v -> {
+ mExitReason = NotificationCounters.BLOCKING_HELPER_DELIVER_SILENTLY;
+ mChosenImportance = IMPORTANCE_LOW;
+ updateButtons(ACTION_TOGGLE_SILENT);
};
+ // used by standard ui
private OnClickListener mOnDismissSettings = v -> {
closeControls(v);
};
+ // used by blocking helper
+ private OnClickListener mOnKeepShowing = v -> {
+ mExitReason = NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING;
+ closeControls(v);
+ mMetricsLogger.write(getLogMaker().setCategory(
+ MetricsEvent.NOTIFICATION_BLOCKING_HELPER)
+ .setType(MetricsEvent.TYPE_ACTION)
+ .setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_STAY_SILENT));
+ };
+
+ // used by blocking helper
private OnClickListener mOnDeliverSilently = v -> {
handleSaveImportance(
ACTION_DELIVER_SILENTLY, MetricsEvent.BLOCKING_HELPER_CLICK_STAY_SILENT);
- if (!mIsForBlockingHelper) {
- updateButtonsAndHelpText(ACTION_DELIVER_SILENTLY);
- }
- };
-
- private OnClickListener mOnStopOrMinimizeNotifications = v -> {
- handleSaveImportance(ACTION_BLOCK, MetricsEvent.BLOCKING_HELPER_CLICK_BLOCKED);
- if (!mIsForBlockingHelper) {
- updateButtonsAndHelpText(ACTION_BLOCK);
- }
};
private void handleSaveImportance(int action, int metricsSubtype) {
@@ -189,6 +192,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
.setType(MetricsEvent.TYPE_DISMISS)
.setSubtype(MetricsEvent.BLOCKING_HELPER_CLICK_UNDO));
} else {
+ // TODO: this can't happen?
mMetricsLogger.write(importanceChangeLogMaker().setType(MetricsEvent.TYPE_DISMISS));
}
saveImportanceAndExitReason(ACTION_UNDO);
@@ -233,7 +237,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
bindNotification(pm, iNotificationManager, pkg, notificationChannel,
numUniqueChannelsInRow, sbn, checkSaveListener, onSettingsClick,
onAppSettingsClick, isDeviceProvisioned, isNonblockable,
- false /* isBlockingHelper */, false /* isUserSentimentNegative */,
+ false /* isBlockingHelper */,
importance, wasShownHighPriority);
}
@@ -250,7 +254,6 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
boolean isDeviceProvisioned,
boolean isNonblockable,
boolean isForBlockingHelper,
- boolean isUserSentimentNegative,
int importance,
boolean wasShownHighPriority)
throws RemoteException {
@@ -268,13 +271,20 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
mStartingChannelImportance = mSingleNotificationChannel.getImportance();
mWasShownHighPriority = wasShownHighPriority;
mIsNonblockable = isNonblockable;
- mIsForeground =
- (mSbn.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE) != 0;
mIsForBlockingHelper = isForBlockingHelper;
mAppUid = mSbn.getUid();
mDelegatePkg = mSbn.getOpPkg();
mIsDeviceProvisioned = isDeviceProvisioned;
+ mSelectedBackground = new GradientDrawable();
+ mSelectedBackground.setShape(GradientDrawable.RECTANGLE);
+ mSelectedBackground.setColor(mContext.getColor(R.color.notification_guts_selection_bg));
+ final float cornerRadii = getResources().getDisplayMetrics().density * 8;
+ mSelectedBackground.setCornerRadii(new float[]{cornerRadii, cornerRadii, cornerRadii,
+ cornerRadii, cornerRadii, cornerRadii, cornerRadii, cornerRadii});
+ mSelectedBackground.setStroke((int) (getResources().getDisplayMetrics().density * 2),
+ mContext.getColor(R.color.notification_guts_selection_border));
+
int numTotalChannels = mINotificationManager.getNumNotificationChannelsForPackage(
pkg, mAppUid, false /* includeDeleted */);
if (mNumUniqueChannelsInRow == 0) {
@@ -288,13 +298,74 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
}
bindHeader();
- bindPrompt();
- bindButtons();
+ bindChannelDetails();
+
+ if (mIsForBlockingHelper) {
+ bindBlockingHelper();
+ } else {
+ bindInlineControls();
+ }
mMetricsLogger.write(notificationControlsLogMaker());
}
- private void bindHeader() throws RemoteException {
+ private void bindBlockingHelper() {
+ findViewById(R.id.inline_controls).setVisibility(GONE);
+ findViewById(R.id.blocking_helper).setVisibility(VISIBLE);
+
+ findViewById(R.id.undo).setOnClickListener(mOnUndo);
+
+ View turnOffButton = findViewById(R.id.blocking_helper_turn_off_notifications);
+ turnOffButton.setOnClickListener(getSettingsOnClickListener());
+ turnOffButton.setVisibility(turnOffButton.hasOnClickListeners() ? VISIBLE : GONE);
+
+ TextView keepShowing = findViewById(R.id.keep_showing);
+ keepShowing.setOnClickListener(mOnKeepShowing);
+
+ View deliverSilently = findViewById(R.id.deliver_silently);
+ deliverSilently.setOnClickListener(mOnDeliverSilently);
+ }
+
+ private void bindInlineControls() {
+ findViewById(R.id.inline_controls).setVisibility(VISIBLE);
+ findViewById(R.id.blocking_helper).setVisibility(GONE);
+
+ if (mIsNonblockable) {
+ findViewById(R.id.non_configurable_text).setVisibility(VISIBLE);
+ findViewById(R.id.non_configurable_multichannel_text).setVisibility(GONE);
+ findViewById(R.id.interruptiveness_settings).setVisibility(GONE);
+ } else if (mNumUniqueChannelsInRow > 1) {
+ findViewById(R.id.non_configurable_text).setVisibility(GONE);
+ findViewById(R.id.interruptiveness_settings).setVisibility(GONE);
+ findViewById(R.id.non_configurable_multichannel_text).setVisibility(VISIBLE);
+ } else {
+ findViewById(R.id.non_configurable_text).setVisibility(GONE);
+ findViewById(R.id.non_configurable_multichannel_text).setVisibility(GONE);
+ findViewById(R.id.interruptiveness_settings).setVisibility(VISIBLE);
+ }
+
+ View turnOffButton = findViewById(R.id.turn_off_notifications);
+ turnOffButton.setOnClickListener(getSettingsOnClickListener());
+ turnOffButton.setVisibility(turnOffButton.hasOnClickListeners() && !mIsNonblockable
+ ? VISIBLE : GONE);
+
+ View done = findViewById(R.id.done);
+ done.setOnClickListener(mOnDismissSettings);
+
+
+ View silent = findViewById(R.id.silent_row);
+ View alert = findViewById(R.id.alert_row);
+ silent.setOnClickListener(mOnSilent);
+ alert.setOnClickListener(mOnAlert);
+
+ if (mWasShownHighPriority) {
+ updateButtons(ACTION_ALERT);
+ } else {
+ updateButtons(ACTION_TOGGLE_SILENT);
+ }
+ }
+
+ private void bindHeader() {
// Package name
Drawable pkgicon = null;
ApplicationInfo info;
@@ -319,31 +390,44 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
// Delegate
bindDelegate();
- // Settings button.
+ // Set up app settings link (i.e. Customize)
+ View settingsLinkView = findViewById(R.id.app_settings);
+ Intent settingsIntent = getAppSettingsIntent(mPm, mPackageName,
+ mSingleNotificationChannel,
+ mSbn.getId(), mSbn.getTag());
+ if (settingsIntent != null
+ && !TextUtils.isEmpty(mSbn.getNotification().getSettingsText())) {
+ settingsLinkView.setVisibility(VISIBLE);
+ settingsLinkView.setOnClickListener((View view) -> {
+ mAppSettingsClickListener.onClick(view, settingsIntent);
+ });
+ } else {
+ settingsLinkView.setVisibility(View.GONE);
+ }
+
+ // System Settings button.
final View settingsButton = findViewById(R.id.info);
+ settingsButton.setOnClickListener(getSettingsOnClickListener());
+ settingsButton.setVisibility(settingsButton.hasOnClickListeners() ? VISIBLE : GONE);
+ }
+
+ private OnClickListener getSettingsOnClickListener() {
if (mAppUid >= 0 && mOnSettingsClickListener != null && mIsDeviceProvisioned) {
- settingsButton.setVisibility(View.VISIBLE);
final int appUidF = mAppUid;
- settingsButton.setOnClickListener(
- (View view) -> {
- logBlockingHelperCounter(
- NotificationCounters.BLOCKING_HELPER_NOTIF_SETTINGS);
- mOnSettingsClickListener.onClick(view,
- mNumUniqueChannelsInRow > 1 ? null : mSingleNotificationChannel,
- appUidF);
- });
- } else {
- settingsButton.setVisibility(View.GONE);
+ return ((View view) -> {
+ logBlockingHelperCounter(
+ NotificationCounters.BLOCKING_HELPER_NOTIF_SETTINGS);
+ mOnSettingsClickListener.onClick(view,
+ mNumUniqueChannelsInRow > 1 ? null : mSingleNotificationChannel,
+ appUidF);
+ });
}
+ return null;
}
- private void bindPrompt() throws RemoteException {
- final TextView blockPrompt = findViewById(R.id.block_prompt);
+ private void bindChannelDetails() throws RemoteException {
bindName();
bindGroup();
- if (mIsNonblockable) {
- blockPrompt.setText(R.string.notification_unblockable_desc);
- }
}
private void bindName() {
@@ -450,110 +534,17 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
}
}
- private void bindButtons() {
- findViewById(R.id.undo).setOnClickListener(mOnUndo);
-
- boolean showInterruptivenessSettings =
- !mIsNonblockable
- && !mIsForeground
- && !mIsForBlockingHelper
- && NotificationUtils.useNewInterruptionModel(mContext);
- if (showInterruptivenessSettings) {
- findViewById(R.id.block_or_minimize).setVisibility(GONE);
- findViewById(R.id.interruptiveness_settings).setVisibility(VISIBLE);
- View done = findViewById(R.id.done_button);
- done.setOnClickListener(mOnDismissSettings);
- View block = findViewById(R.id.int_block_wrapper);
- View silent = findViewById(R.id.int_silent_wrapper);
- View alert = findViewById(R.id.int_alert_wrapper);
- block.setOnClickListener(mOnStopOrMinimizeNotifications);
- silent.setOnClickListener(mOnDeliverSilently);
- alert.setOnClickListener(mOnAlert);
- if (mNotificationBlockState != ACTION_NONE) {
- updateButtonsAndHelpText(mNotificationBlockState);
- } else if (mWasShownHighPriority) {
- updateButtonsAndHelpText(ACTION_ALERT);
- } else {
- updateButtonsAndHelpText(ACTION_DELIVER_SILENTLY);
- }
- } else {
- findViewById(R.id.block_or_minimize).setVisibility(VISIBLE);
- findViewById(R.id.interruptiveness_settings).setVisibility(GONE);
- View block = findViewById(R.id.block);
- TextView done = findViewById(R.id.done);
- View minimize = findViewById(R.id.minimize);
- View deliverSilently = findViewById(R.id.deliver_silently);
-
-
- block.setOnClickListener(mOnStopOrMinimizeNotifications);
- done.setOnClickListener(mOnKeepShowing);
- minimize.setOnClickListener(mOnStopOrMinimizeNotifications);
- deliverSilently.setOnClickListener(mOnDeliverSilently);
-
- if (mIsNonblockable) {
- done.setText(android.R.string.ok);
- block.setVisibility(GONE);
- minimize.setVisibility(GONE);
- deliverSilently.setVisibility(GONE);
- } else if (mIsForeground) {
- block.setVisibility(GONE);
- minimize.setVisibility(VISIBLE);
- } else {
- block.setVisibility(VISIBLE);
- minimize.setVisibility(GONE);
- }
-
- // Set up app settings link (i.e. Customize)
- View settingsLinkView = findViewById(R.id.app_settings);
- Intent settingsIntent = getAppSettingsIntent(mPm, mPackageName,
- mSingleNotificationChannel,
- mSbn.getId(), mSbn.getTag());
- if (!mIsForBlockingHelper
- && settingsIntent != null
- && !TextUtils.isEmpty(mSbn.getNotification().getSettingsText())) {
- settingsLinkView.setVisibility(VISIBLE);
- settingsLinkView.setOnClickListener((View view) -> {
- mAppSettingsClickListener.onClick(view, settingsIntent);
- });
- } else {
- settingsLinkView.setVisibility(View.GONE);
- }
- }
- }
-
- private void updateButtonsAndHelpText(int blockState) {
- mNotificationBlockState = blockState;
- ImageView block = findViewById(R.id.int_block);
- ImageView silent = findViewById(R.id.int_silent);
- ImageView alert = findViewById(R.id.int_alert);
- TextView hintText = findViewById(R.id.hint_text);
+ private void updateButtons(int blockState) {
+ View silent = findViewById(R.id.silent_row);
+ View alert = findViewById(R.id.alert_row);
switch (blockState) {
- case ACTION_BLOCK:
- block.setBackgroundResource(R.drawable.circle_blue_40dp);
- block.setColorFilter(Color.WHITE);
- silent.setBackgroundResource(R.drawable.circle_white_40dp);
- silent.setColorFilter(getResources().getColor(R.color.GM2_grey_400));
- alert.setBackgroundResource(R.drawable.circle_white_40dp);
- alert.setColorFilter(getResources().getColor(R.color.GM2_grey_400));
- hintText.setText(R.string.hint_text_block);
- break;
- case ACTION_DELIVER_SILENTLY:
- silent.setBackgroundResource(R.drawable.circle_blue_40dp);
- silent.setColorFilter(Color.WHITE);
- block.setBackgroundResource(R.drawable.circle_white_40dp);
- block.setColorFilter(getResources().getColor(R.color.GM2_grey_400));
- alert.setBackgroundResource(R.drawable.circle_white_40dp);
- alert.setColorFilter(getResources().getColor(R.color.GM2_grey_400));
- hintText.setText(R.string.hint_text_silent);
+ case ACTION_TOGGLE_SILENT:
+ silent.setBackground(mSelectedBackground);
+ alert.setBackground(null);
break;
case ACTION_ALERT:
- alert.setBackgroundResource(R.drawable.circle_blue_40dp);
- alert.setColorFilter(Color.WHITE);
- block.setBackgroundResource(R.drawable.circle_white_40dp);
- block.setColorFilter(getResources().getColor(R.color.GM2_grey_400));
- silent.setBackgroundResource(R.drawable.circle_white_40dp);
- silent.setColorFilter(getResources().getColor(R.color.GM2_grey_400));
- hintText.setText(R.string.hint_text_alert);
+ alert.setBackground(mSelectedBackground);
+ silent.setBackground(null);
break;
}
}
@@ -575,28 +566,20 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
mChosenImportance = IMPORTANCE_DEFAULT;
}
break;
- case ACTION_BLOCK:
- mExitReason = NotificationCounters.BLOCKING_HELPER_STOP_NOTIFICATIONS;
- if (mIsForeground) {
- mChosenImportance = IMPORTANCE_MIN;
- } else {
- mChosenImportance = IMPORTANCE_NONE;
- }
- break;
default:
throw new IllegalArgumentException();
}
}
+ // only used for blocking helper
private void swapContent(@NotificationInfoAction int action, boolean animate) {
if (mExpandAnimation != null) {
mExpandAnimation.cancel();
}
- View prompt = findViewById(R.id.prompt);
+ View blockingHelper = findViewById(R.id.blocking_helper);
ViewGroup confirmation = findViewById(R.id.confirmation);
TextView confirmationText = findViewById(R.id.confirmation_text);
- View header = findViewById(R.id.header);
saveImportanceAndExitReason(action);
@@ -606,33 +589,20 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
case ACTION_DELIVER_SILENTLY:
confirmationText.setText(R.string.notification_channel_silenced);
break;
- case ACTION_TOGGLE_SILENT:
- if (mWasShownHighPriority) {
- confirmationText.setText(R.string.notification_channel_silenced);
- } else {
- confirmationText.setText(R.string.notification_channel_unsilenced);
- }
- break;
- case ACTION_BLOCK:
- if (mIsForeground) {
- confirmationText.setText(R.string.notification_channel_minimized);
- } else {
- confirmationText.setText(R.string.notification_channel_disabled);
- }
- break;
default:
throw new IllegalArgumentException();
}
boolean isUndo = action == ACTION_UNDO;
- prompt.setVisibility(isUndo ? VISIBLE : GONE);
+ blockingHelper.setVisibility(isUndo ? VISIBLE : GONE);
+ findViewById(R.id.channel_info).setVisibility(isUndo ? VISIBLE : GONE);
+ findViewById(R.id.header).setVisibility(isUndo ? VISIBLE : GONE);
confirmation.setVisibility(isUndo ? GONE : VISIBLE);
- header.setVisibility(isUndo ? VISIBLE : GONE);
if (animate) {
- ObjectAnimator promptAnim = ObjectAnimator.ofFloat(prompt, View.ALPHA,
- prompt.getAlpha(), isUndo ? 1f : 0f);
+ ObjectAnimator promptAnim = ObjectAnimator.ofFloat(blockingHelper, View.ALPHA,
+ blockingHelper.getAlpha(), isUndo ? 1f : 0f);
promptAnim.setInterpolator(isUndo ? Interpolators.ALPHA_IN : Interpolators.ALPHA_OUT);
ObjectAnimator confirmAnim = ObjectAnimator.ofFloat(confirmation, View.ALPHA,
confirmation.getAlpha(), isUndo ? 0f : 1f);
@@ -652,7 +622,7 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
@Override
public void onAnimationEnd(Animator animation) {
if (!mCancelled) {
- prompt.setVisibility(isUndo ? VISIBLE : GONE);
+ blockingHelper.setVisibility(isUndo ? VISIBLE : GONE);
confirmation.setVisibility(isUndo ? GONE : VISIBLE);
}
}
@@ -674,15 +644,11 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
}
mExitReason = NotificationCounters.BLOCKING_HELPER_DISMISSED;
- View prompt = findViewById(R.id.prompt);
- ViewGroup confirmation = findViewById(R.id.confirmation);
- View header = findViewById(R.id.header);
- prompt.setVisibility(VISIBLE);
- prompt.setAlpha(1f);
- confirmation.setVisibility(GONE);
- confirmation.setAlpha(1f);
- header.setVisibility(VISIBLE);
- header.setAlpha(1f);
+ if (mIsForBlockingHelper) {
+ bindBlockingHelper();
+ } else {
+ bindInlineControls();
+ }
mMetricsLogger.write(notificationControlsLogMaker().setType(MetricsEvent.TYPE_CLOSE));
}
@@ -730,8 +696,8 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G
* commit the updated importance.
*
* <p><b>Note,</b> this will only get called once the view is dismissing. This means that the
- * user does not have the ability to undo the action anymore. See {@link #swapContent(boolean)}
- * for where undo is handled.
+ * user does not have the ability to undo the action anymore. See
+ * {@link #swapContent(boolean, boolean)} for where undo is handled.
*/
@VisibleForTesting
void closeControls(View v) {
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index 83ec33c69629..5412cde0df55 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -71,8 +71,8 @@ local_space := $(local_empty) $(local_empty)
# This appends a * to all classes and replace the space separators with commas.
jacoco_exclude := $(subst $(space),$(comma),$(patsubst %,%*,$(local_classes)))
-LOCAL_JACK_COVERAGE_INCLUDE_FILTER := com.android.systemui.*
-LOCAL_JACK_COVERAGE_EXCLUDE_FILTER := com.android.systemui.tests.*,$(jacoco_exclude)
+LOCAL_JACK_COVERAGE_INCLUDE_FILTER := com.android.systemui.*,com.android.keyguard.*
+LOCAL_JACK_COVERAGE_EXCLUDE_FILTER := $(jacoco_exclude)
ifeq ($(EXCLUDE_SYSTEMUI_TESTS),)
include $(BUILD_PACKAGE)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleStackViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleStackViewTest.java
new file mode 100644
index 000000000000..801308fc77da
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleStackViewTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.bubbles;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.View;
+import android.widget.TextView;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+public class BubbleStackViewTest extends SysuiTestCase {
+ private BubbleStackView mStackView;
+ @Mock private Bubble mBubble;
+ @Mock private NotificationEntry mNotifEntry;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mStackView = new BubbleStackView(mContext, new BubbleData(), null);
+ mBubble.entry = mNotifEntry;
+ }
+
+ @Test
+ public void testAnimateInFlyoutForBubble() throws InterruptedException {
+ when(mNotifEntry.getUpdateMessage(any())).thenReturn("Test Flyout Message.");
+ mStackView.animateInFlyoutForBubble(mBubble);
+
+ // Wait for the fade in.
+ Thread.sleep(200);
+
+ // Flyout should be visible and showing our text.
+ assertEquals(1f, mStackView.findViewById(R.id.bubble_flyout).getAlpha(), .01f);
+ assertEquals("Test Flyout Message.",
+ ((TextView) mStackView.findViewById(R.id.bubble_flyout_text)).getText());
+
+ // Wait until it should have gone away.
+ Thread.sleep(BubbleStackView.FLYOUT_HIDE_AFTER + 200);
+
+ // Flyout should be gone.
+ assertEquals(View.GONE, mStackView.findViewById(R.id.bubble_flyout).getVisibility());
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
new file mode 100644
index 000000000000..cca9f2834e93
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.collection;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.when;
+
+import android.app.Notification;
+import android.os.Bundle;
+import android.service.notification.StatusBarNotification;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class NotificationEntryTest extends SysuiTestCase {
+ @Mock
+ private StatusBarNotification mStatusBarNotification;
+ @Mock
+ private Notification mNotif;
+
+ private NotificationEntry mEntry;
+ private Bundle mExtras;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ when(mStatusBarNotification.getKey()).thenReturn("key");
+ when(mStatusBarNotification.getNotification()).thenReturn(mNotif);
+
+ mExtras = new Bundle();
+ mNotif.extras = mExtras;
+
+ mEntry = new NotificationEntry(mStatusBarNotification);
+ }
+
+ @Test
+ public void testGetUpdateMessage_default() {
+ final String msg = "Hello there!";
+ doReturn(Notification.Style.class).when(mNotif).getNotificationStyle();
+ mExtras.putCharSequence(Notification.EXTRA_TEXT, msg);
+ assertEquals(msg, mEntry.getUpdateMessage(mContext));
+ }
+
+ @Test
+ public void testGetUpdateMessage_bigText() {
+ final String msg = "A big hello there!";
+ doReturn(Notification.BigTextStyle.class).when(mNotif).getNotificationStyle();
+ mExtras.putCharSequence(Notification.EXTRA_TEXT, "A small hello there.");
+ mExtras.putCharSequence(Notification.EXTRA_BIG_TEXT, msg);
+
+ // Should be big text, not the small text.
+ assertEquals(msg, mEntry.getUpdateMessage(mContext));
+ }
+
+ @Test
+ public void testGetUpdateMessage_media() {
+ doReturn(Notification.MediaStyle.class).when(mNotif).getNotificationStyle();
+
+ // Media notifs don't get update messages.
+ assertNull(mEntry.getUpdateMessage(mContext));
+ }
+
+ @Test
+ public void testGetUpdateMessage_inboxStyle() {
+ doReturn(Notification.InboxStyle.class).when(mNotif).getNotificationStyle();
+ mExtras.putCharSequenceArray(
+ Notification.EXTRA_TEXT_LINES,
+ new CharSequence[]{
+ "How do you feel about tests?",
+ "They're okay, I guess.",
+ "I hate when they're flaky.",
+ "Really? I prefer them that way."});
+
+ // Should be the last one only.
+ assertEquals("Really? I prefer them that way.", mEntry.getUpdateMessage(mContext));
+ }
+
+ @Test
+ public void testGetUpdateMessage_messagingStyle() {
+ doReturn(Notification.MessagingStyle.class).when(mNotif).getNotificationStyle();
+ mExtras.putParcelableArray(
+ Notification.EXTRA_MESSAGES,
+ new Bundle[]{
+ new Notification.MessagingStyle.Message(
+ "Hello", 0, "Josh").toBundle(),
+ new Notification.MessagingStyle.Message(
+ "Oh, hello!", 0, "Mady").toBundle()});
+
+ // Should be the last one only.
+ assertEquals("Mady: Oh, hello!", mEntry.getUpdateMessage(mContext));
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManagerTest.java
index 4fe364a7654b..3c91b3f1bdd3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationBlockingHelperManagerTest.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.row;
+import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL;
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_POSITIVE;
@@ -24,11 +25,13 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.NotificationChannel;
import android.content.Context;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -130,6 +133,21 @@ public class NotificationBlockingHelperManagerTest extends SysuiTestCase {
verify(mGutsManager).openGuts(row, 0, 0, mMenuItem);
}
+ @Test
+ public void testPerhapsShowBlockingHelper_notShownForMultiChannelGroup() throws Exception {
+ ExpandableNotificationRow groupRow = createBlockableGroupRowSpy(10);
+ int i = 0;
+ for (ExpandableNotificationRow childRow : groupRow.getNotificationChildren()) {
+ childRow.getEntry().channel =
+ new NotificationChannel(Integer.toString(i++), "", IMPORTANCE_DEFAULT);
+ }
+
+ groupRow.getEntry().userSentiment = USER_SENTIMENT_NEGATIVE;
+
+ assertFalse(mBlockingHelperManager.perhapsShowBlockingHelper(groupRow, mMenuRow));
+
+ verify(mGutsManager, never()).openGuts(groupRow, 0, 0, mMenuItem);
+ }
@Test
public void testPerhapsShowBlockingHelper_shownForLargeGroup() throws Exception {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
index ff849c3720f3..8380192ffd32 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java
@@ -325,7 +325,6 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
eq(false),
eq(false),
eq(true) /* isForBlockingHelper */,
- eq(true) /* isUserSentimentNegative */,
eq(0),
eq(false) /* wasShownHighPriority */);
}
@@ -354,7 +353,6 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
eq(false),
eq(false),
eq(false) /* isForBlockingHelper */,
- eq(true) /* isUserSentimentNegative */,
eq(0),
eq(false) /* wasShownHighPriority */);
}
@@ -385,7 +383,6 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
eq(false),
eq(false),
eq(true) /* isForBlockingHelper */,
- eq(true) /* isUserSentimentNegative */,
eq(IMPORTANCE_DEFAULT),
eq(true) /* wasShownHighPriority */);
}
@@ -415,7 +412,6 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
eq(true),
eq(false),
eq(false) /* isForBlockingHelper */,
- eq(true) /* isUserSentimentNegative */,
eq(0),
eq(false) /* wasShownHighPriority */);
}
@@ -444,7 +440,6 @@ public class NotificationGutsManagerTest extends SysuiTestCase {
eq(false),
eq(false),
eq(true) /* isForBlockingHelper */,
- eq(true) /* isUserSentimentNegative */,
eq(0),
eq(false) /* wasShownHighPriority */);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
index fb4fd314d363..d2f8e02311e6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
@@ -313,108 +313,20 @@ public class NotificationInfoTest extends SysuiTestCase {
}
@Test
- public void testBindNotification_BlockButton() throws Exception {
+ public void testBindNotification_BlockLink_BlockingHelper() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
- IMPORTANCE_DEFAULT, true);
- final View block = mNotificationInfo.findViewById(R.id.int_block);
- final View minimize = mNotificationInfo.findViewById(R.id.block_or_minimize);
- assertEquals(VISIBLE, block.getVisibility());
- assertEquals(GONE, minimize.getVisibility());
- }
-
- @Test
- public void testBindNotification_BlockButton_BlockingHelper() throws Exception {
- mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
- true /* isBlockingHelper */, false, IMPORTANCE_DEFAULT, true);
- final View block = mNotificationInfo.findViewById(R.id.block);
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, mock(
+ NotificationInfo.OnSettingsClickListener.class), null, true, false,
+ true /* isBlockingHelper */, IMPORTANCE_DEFAULT, true);
+ final View block =
+ mNotificationInfo.findViewById(R.id.blocking_helper_turn_off_notifications);
final View interruptivenessSettings = mNotificationInfo.findViewById(
- R.id.interruptiveness_settings);
+ R.id.inline_controls);
assertEquals(VISIBLE, block.getVisibility());
assertEquals(GONE, interruptivenessSettings.getVisibility());
}
@Test
- public void testBindNotification_SilenceButton_CurrentlyAlerting() throws Exception {
- mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
- mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
- IMPORTANCE_DEFAULT, true);
- final TextView silent = mNotificationInfo.findViewById(R.id.int_silent_label);
- assertEquals(VISIBLE, silent.getVisibility());
- assertEquals(
- mContext.getString(R.string.inline_silent_button_silent), silent.getText());
- }
-
- @Test
- public void testBindNotification_verifyButtonTexts() throws Exception {
- mNotificationChannel.setImportance(IMPORTANCE_LOW);
- mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
- IMPORTANCE_LOW, false);
- final TextView block = mNotificationInfo.findViewById(R.id.int_block_label);
- final TextView alert = mNotificationInfo.findViewById(R.id.int_alert_label);
- final TextView silent = mNotificationInfo.findViewById(R.id.int_silent_label);
- assertEquals(VISIBLE, silent.getVisibility());
- assertEquals(VISIBLE, block.getVisibility());
- assertEquals(VISIBLE, alert.getVisibility());
- assertEquals(
- mContext.getString(R.string.inline_silent_button_silent),
- silent.getText());
- assertEquals(
- mContext.getString(R.string.inline_silent_button_alert), alert.getText());
- assertEquals(
- mContext.getString(R.string.inline_block_button), block.getText());
- }
-
- @Test
- public void testBindNotification_verifyHintTextForSilent() throws Exception {
- mNotificationChannel.setImportance(IMPORTANCE_LOW);
- mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
- IMPORTANCE_LOW, false);
- TextView hintText = mNotificationInfo.findViewById(R.id.hint_text);
- assertEquals(mContext.getString(R.string.hint_text_silent), hintText.getText());
- }
-
- @Test
- public void testBindNotification_verifyHintTextForBlock() throws Exception {
- mNotificationChannel.setImportance(IMPORTANCE_LOW);
- mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
- IMPORTANCE_LOW, false);
- View blockWrapper = mNotificationInfo.findViewById(R.id.int_block_wrapper);
- blockWrapper.performClick();
- TextView hintText = mNotificationInfo.findViewById(R.id.hint_text);
- assertEquals(mContext.getString(R.string.hint_text_block), hintText.getText());
- }
-
- @Test
- public void testBindNotification_verifyHintTextForAlert() throws Exception {
- mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
- IMPORTANCE_DEFAULT, true);
- TextView hintText = mNotificationInfo.findViewById(R.id.hint_text);
- assertEquals(mContext.getString(R.string.hint_text_alert), hintText.getText());
- }
-
- @Test
- public void testBindNotification_MinButton() throws Exception {
- mSbn.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
- mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
- IMPORTANCE_DEFAULT, true);
- final View block = mNotificationInfo.findViewById(R.id.block);
- final View interruptivenessSettings = mNotificationInfo.findViewById(
- R.id.interruptiveness_settings);
- final View minimize = mNotificationInfo.findViewById(R.id.minimize);
- assertEquals(GONE, block.getVisibility());
- assertEquals(GONE, interruptivenessSettings.getVisibility());
- assertEquals(VISIBLE, minimize.getVisibility());
- }
-
- @Test
public void testBindNotification_SetsOnClickListenerForSettings() throws Exception {
final CountDownLatch latch = new CountDownLatch(1);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
@@ -484,7 +396,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn,
null, null, null,
false, true,
- true, true,
+ true,
IMPORTANCE_DEFAULT, true);
verify(mMetricsLogger).write(argThat(logMaker ->
logMaker.getCategory() == MetricsEvent.ACTION_NOTE_CONTROLS
@@ -499,7 +411,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn,
null, null, null,
false, true,
- true, true,
+ true,
IMPORTANCE_DEFAULT, true);
mNotificationInfo.logBlockingHelperCounter("HowCanNotifsBeRealIfAppsArent");
verify(mMetricsLogger).count(eq("HowCanNotifsBeRealIfAppsArent"), eq(1));
@@ -526,7 +438,7 @@ public class NotificationInfoTest extends SysuiTestCase {
throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, MULTIPLE_CHANNEL_COUNT, mSbn, null, null,
- null, true, true, IMPORTANCE_DEFAULT, true);
+ null, true, false, IMPORTANCE_DEFAULT, true);
final TextView channelNameView =
mNotificationInfo.findViewById(R.id.channel_name);
assertEquals(GONE, channelNameView.getVisibility());
@@ -537,20 +449,24 @@ public class NotificationInfoTest extends SysuiTestCase {
public void testStopInvisibleIfBundleFromDifferentChannels() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, MULTIPLE_CHANNEL_COUNT, mSbn, null, null,
- null, true, true, IMPORTANCE_DEFAULT, true);
- final TextView blockView = mNotificationInfo.findViewById(R.id.block);
- assertEquals(GONE, blockView.getVisibility());
+ null, true, false, IMPORTANCE_DEFAULT, true);
+ assertEquals(GONE, mNotificationInfo.findViewById(
+ R.id.interruptiveness_settings).getVisibility());
+ assertEquals(VISIBLE, mNotificationInfo.findViewById(
+ R.id.non_configurable_multichannel_text).getVisibility());
}
@Test
- public void testbindNotification_UnblockableTextVisibleWhenAppUnblockable() throws Exception {
+ public void testBindNotification_whenAppUnblockable() throws Exception {
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
IMPORTANCE_DEFAULT, true);
- final TextView view = mNotificationInfo.findViewById(R.id.block_prompt);
+ final TextView view = mNotificationInfo.findViewById(R.id.non_configurable_text);
assertEquals(View.VISIBLE, view.getVisibility());
assertEquals(mContext.getString(R.string.notification_unblockable_desc),
view.getText());
+ assertEquals(GONE,
+ mNotificationInfo.findViewById(R.id.interruptiveness_settings).getVisibility());
}
@Test
@@ -568,23 +484,9 @@ public class NotificationInfoTest extends SysuiTestCase {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
- IMPORTANCE_DEFAULT, false);
-
- mNotificationInfo.findViewById(R.id.int_block).performClick();
- mTestableLooper.processAllMessages();
- verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
- anyString(), eq(TEST_UID), any());
- }
-
- @Test
- public void testDoesNotUpdateNotificationChannelAfterImportanceChangedMin()
- throws Exception {
- mNotificationChannel.setImportance(IMPORTANCE_LOW);
- mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
- IMPORTANCE_DEFAULT, false);
+ IMPORTANCE_LOW, false);
- mNotificationInfo.findViewById(R.id.minimize).performClick();
+ mNotificationInfo.findViewById(R.id.alert_row).performClick();
mTestableLooper.processAllMessages();
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
anyString(), eq(TEST_UID), any());
@@ -598,21 +500,7 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
IMPORTANCE_DEFAULT, true);
- mNotificationInfo.findViewById(R.id.int_silent).performClick();
- mTestableLooper.processAllMessages();
- verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
- anyString(), eq(TEST_UID), any());
- }
-
- @Test
- public void testDoesNotUpdateNotificationChannelAfterImportanceChangedUnSilenced()
- throws Exception {
- mNotificationChannel.setImportance(IMPORTANCE_LOW);
- mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
- IMPORTANCE_DEFAULT, false);
-
- mNotificationInfo.findViewById(R.id.int_alert).performClick();
+ mNotificationInfo.findViewById(R.id.silent_row).performClick();
mTestableLooper.processAllMessages();
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
anyString(), eq(TEST_UID), any());
@@ -650,76 +538,6 @@ public class NotificationInfoTest extends SysuiTestCase {
}
@Test
- public void testHandleCloseControls_setsNotificationsDisabledForMultipleChannelNotifications()
- throws Exception {
- mNotificationChannel.setImportance(IMPORTANCE_LOW);
- mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel /* notificationChannel */,
- 10 /* numUniqueChannelsInRow */, mSbn, null /* checkSaveListener */,
- null /* onSettingsClick */, null /* onAppSettingsClick */,
- true, false /* isNonblockable */, IMPORTANCE_DEFAULT, false
- );
-
- mNotificationInfo.findViewById(R.id.int_block_wrapper).performClick();
- mNotificationInfo.findViewById(R.id.done_button).performClick();
- mNotificationInfo.handleCloseControls(true, false);
-
- mTestableLooper.processAllMessages();
- verify(mMockINotificationManager, times(1))
- .setNotificationsEnabledWithImportanceLockForPackage(
- anyString(), eq(TEST_UID), eq(false));
- }
-
-
- @Test
- public void testHandleCloseControls_keepsNotificationsEnabledForMultipleChannelNotifications()
- throws Exception {
- mNotificationChannel.setImportance(IMPORTANCE_LOW);
- mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel /* notificationChannel */,
- 10 /* numUniqueChannelsInRow */, mSbn, null /* checkSaveListener */,
- null /* onSettingsClick */, null /* onAppSettingsClick */,
- true, false /* isNonblockable */, IMPORTANCE_DEFAULT, false
- );
-
- mNotificationInfo.findViewById(R.id.int_block_wrapper).performClick();
- mNotificationInfo.findViewById(R.id.done_button).performClick();
- mNotificationInfo.handleCloseControls(true, false);
-
- mTestableLooper.processAllMessages();
- verify(mMockINotificationManager, times(1))
- .setNotificationsEnabledWithImportanceLockForPackage(
- anyString(), eq(TEST_UID), eq(false));
- }
-
- @Test
- public void testCloseControls_blockingHelperSavesImportanceForMultipleChannelNotifications()
- throws Exception {
- mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel /* notificationChannel */,
- 10 /* numUniqueChannelsInRow */, mSbn, null /* checkSaveListener */,
- null /* onSettingsClick */, null /* onAppSettingsClick */,
- true /* provisioned */,
- false /* isNonblockable */, true /* isForBlockingHelper */,
- true /* isUserSentimentNegative */, IMPORTANCE_DEFAULT, true);
-
- NotificationGuts guts = spy(new NotificationGuts(mContext, null));
- when(guts.getWindowToken()).thenReturn(mock(IBinder.class));
- doNothing().when(guts).animateClose(anyInt(), anyInt(), anyBoolean());
- doNothing().when(guts).setExposed(anyBoolean(), anyBoolean());
- guts.setGutsContent(mNotificationInfo);
- mNotificationInfo.setGutsParent(guts);
-
- mNotificationInfo.findViewById(R.id.done).performClick();
-
- verify(mBlockingHelperManager).dismissCurrentBlockingHelper();
- mTestableLooper.processAllMessages();
- verify(mMockINotificationManager, times(1))
- .setNotificationsEnabledWithImportanceLockForPackage(
- anyString(), eq(TEST_UID), eq(true));
- }
-
- @Test
public void testCloseControls_nonNullCheckSaveListenerDoesntDelayKeepShowing_BlockingHelper()
throws Exception {
NotificationInfo.CheckSaveListener listener =
@@ -729,7 +547,7 @@ public class NotificationInfoTest extends SysuiTestCase {
10 /* numUniqueChannelsInRow */, mSbn, listener /* checkSaveListener */,
null /* onSettingsClick */, null /* onAppSettingsClick */, true /* provisioned */,
false /* isNonblockable */, true /* isForBlockingHelper */,
- true /* isUserSentimentNegative */, IMPORTANCE_DEFAULT, true);
+ IMPORTANCE_DEFAULT, true);
NotificationGuts guts = spy(new NotificationGuts(mContext, null));
when(guts.getWindowToken()).thenReturn(mock(IBinder.class));
@@ -738,7 +556,7 @@ public class NotificationInfoTest extends SysuiTestCase {
guts.setGutsContent(mNotificationInfo);
mNotificationInfo.setGutsParent(guts);
- mNotificationInfo.findViewById(R.id.done).performClick();
+ mNotificationInfo.findViewById(R.id.keep_showing).performClick();
verify(mBlockingHelperManager).dismissCurrentBlockingHelper();
mTestableLooper.processAllMessages();
@@ -757,8 +575,7 @@ public class NotificationInfoTest extends SysuiTestCase {
10 /* numUniqueChannelsInRow */, mSbn, listener /* checkSaveListener */,
null /* onSettingsClick */, null /* onAppSettingsClick */,
false /* isNonblockable */, true /* isForBlockingHelper */,
- true, true /* isUserSentimentNegative */, /* isNoisy */
- IMPORTANCE_DEFAULT, true);
+ true, IMPORTANCE_DEFAULT, true);
mNotificationInfo.handleCloseControls(true /* save */, false /* force */);
@@ -777,9 +594,9 @@ public class NotificationInfoTest extends SysuiTestCase {
null /* onSettingsClick */, null /* onAppSettingsClick */,
true /* provisioned */,
false /* isNonblockable */, true /* isForBlockingHelper */,
- true /* isUserSentimentNegative */, IMPORTANCE_DEFAULT, true);
+ IMPORTANCE_DEFAULT, true);
- mNotificationInfo.findViewById(R.id.block).performClick();
+ mNotificationInfo.findViewById(R.id.deliver_silently).performClick();
mTestableLooper.processAllMessages();
verify(listener).checkSave(any(Runnable.class), eq(mSbn));
}
@@ -799,7 +616,6 @@ public class NotificationInfoTest extends SysuiTestCase {
false /* isNonblockable */,
true /* isForBlockingHelper */,
true,
- false /* isUserSentimentNegative */,
IMPORTANCE_DEFAULT, true);
NotificationGuts guts = mock(NotificationGuts.class);
doCallRealMethod().when(guts).closeControls(anyInt(), anyInt(), anyBoolean(), anyBoolean());
@@ -811,53 +627,9 @@ public class NotificationInfoTest extends SysuiTestCase {
}
@Test
- public void testNonBlockableAppDoesNotBecomeBlocked() throws Exception {
- mNotificationChannel.setImportance(IMPORTANCE_LOW);
- mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
- true, false, IMPORTANCE_DEFAULT, false);
- mNotificationInfo.findViewById(R.id.block).performClick();
- waitForUndoButton();
-
- mTestableLooper.processAllMessages();
- verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
- anyString(), eq(TEST_UID), any());
- }
-
- @Test
- public void testBlockChangedCallsUpdateNotificationChannel_notBlockingHelper()
+ public void testSilentlyChangedCallsUpdateNotificationChannel_blockingHelper()
throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
- mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn,
- null, null, null,
- true, false,
- IMPORTANCE_DEFAULT, false);
-
- mNotificationInfo.findViewById(R.id.int_block_wrapper).performClick();
- mNotificationInfo.findViewById(R.id.done_button).performClick();
- mNotificationInfo.handleCloseControls(true, false);
-
- ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
- verify(mMetricsLogger, times(2)).write(logMakerCaptor.capture());
- assertEquals(MetricsProto.MetricsEvent.TYPE_ACTION,
- logMakerCaptor.getValue().getType());
- assertEquals(IMPORTANCE_NONE - IMPORTANCE_LOW,
- logMakerCaptor.getValue().getSubtype());
-
- mTestableLooper.processAllMessages();
- ArgumentCaptor<NotificationChannel> updated =
- ArgumentCaptor.forClass(NotificationChannel.class);
- verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
- anyString(), eq(TEST_UID), updated.capture());
- assertTrue((updated.getValue().getUserLockedFields()
- & USER_LOCKED_IMPORTANCE) != 0);
- assertEquals(IMPORTANCE_NONE, updated.getValue().getImportance());
- }
-
- @Test
- public void testBlockChangedCallsUpdateNotificationChannel_blockingHelper() throws Exception {
- mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(
mMockPackageManager,
mMockINotificationManager,
@@ -871,21 +643,13 @@ public class NotificationInfoTest extends SysuiTestCase {
true /*provisioned */,
false /* isNonblockable */,
true /* isForBlockingHelper */,
- true /* isUserSentimentNegative */,
IMPORTANCE_DEFAULT,
false);
- mNotificationInfo.findViewById(R.id.block).performClick();
+ mNotificationInfo.findViewById(R.id.deliver_silently).performClick();
waitForUndoButton();
mNotificationInfo.handleCloseControls(true, false);
- ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
- verify(mMetricsLogger, times(3)).write(logMakerCaptor.capture());
- assertEquals(MetricsProto.MetricsEvent.TYPE_ACTION,
- logMakerCaptor.getValue().getType());
- assertEquals(IMPORTANCE_NONE - IMPORTANCE_LOW,
- logMakerCaptor.getValue().getSubtype());
-
mTestableLooper.processAllMessages();
ArgumentCaptor<NotificationChannel> updated =
ArgumentCaptor.forClass(NotificationChannel.class);
@@ -893,69 +657,17 @@ public class NotificationInfoTest extends SysuiTestCase {
anyString(), eq(TEST_UID), updated.capture());
assertTrue((updated.getValue().getUserLockedFields()
& USER_LOCKED_IMPORTANCE) != 0);
- assertEquals(IMPORTANCE_NONE, updated.getValue().getImportance());
+ assertEquals(IMPORTANCE_LOW, updated.getValue().getImportance());
}
-
@Test
- public void testNonBlockableAppDoesNotBecomeMin() throws Exception {
+ public void testKeepUpdatesNotificationChannel_blockingHelper() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
- true, false, IMPORTANCE_DEFAULT, false);
- mNotificationInfo.findViewById(R.id.minimize).performClick();
- waitForUndoButton();
-
- mTestableLooper.processAllMessages();
- verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
- anyString(), eq(TEST_UID), any());
- }
-
- @Test
- public void testMinChangedCallsUpdateNotificationChannel() throws Exception {
- mNotificationChannel.setImportance(IMPORTANCE_LOW);
- mSbn.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
- mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
- true, false, IMPORTANCE_DEFAULT, false);
-
- mNotificationInfo.findViewById(R.id.minimize).performClick();
- waitForUndoButton();
- mNotificationInfo.handleCloseControls(true, false);
-
- mTestableLooper.processAllMessages();
- ArgumentCaptor<NotificationChannel> updated =
- ArgumentCaptor.forClass(NotificationChannel.class);
- verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
- anyString(), eq(TEST_UID), updated.capture());
- assertTrue((updated.getValue().getUserLockedFields()
- & USER_LOCKED_IMPORTANCE) != 0);
- assertEquals(IMPORTANCE_MIN, updated.getValue().getImportance());
- }
-
- @Test
- public void testSilentlyChangedCallsUpdateNotificationChannel_blockingHelper()
- throws Exception {
- mNotificationChannel.setImportance(IMPORTANCE_LOW);
- mNotificationInfo.bindNotification(
- mMockPackageManager,
- mMockINotificationManager,
- TEST_PACKAGE_NAME,
- mNotificationChannel,
- 1 /* numChannels */,
- mSbn,
- null /* checkSaveListener */,
- null /* onSettingsClick */,
- null /* onAppSettingsClick */,
- true /*provisioned */,
- false /* isNonblockable */,
- true /* isForBlockingHelper */,
- true /* isUserSentimentNegative */,
- IMPORTANCE_DEFAULT,
- false);
+ IMPORTANCE_LOW, false);
- mNotificationInfo.findViewById(R.id.deliver_silently).performClick();
- waitForUndoButton();
+ mNotificationInfo.findViewById(R.id.keep_showing).performClick();
mNotificationInfo.handleCloseControls(true, false);
mTestableLooper.processAllMessages();
@@ -963,16 +675,15 @@ public class NotificationInfoTest extends SysuiTestCase {
ArgumentCaptor.forClass(NotificationChannel.class);
verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
anyString(), eq(TEST_UID), updated.capture());
- assertTrue((updated.getValue().getUserLockedFields()
- & USER_LOCKED_IMPORTANCE) != 0);
- assertEquals(IMPORTANCE_LOW, updated.getValue().getImportance());
+ assertTrue(0 != (mNotificationChannel.getUserLockedFields() & USER_LOCKED_IMPORTANCE));
+ assertEquals(IMPORTANCE_LOW, mNotificationChannel.getImportance());
}
@Test
- public void testKeepUpdatesNotificationChannel() throws Exception {
- mNotificationChannel.setImportance(IMPORTANCE_LOW);
+ public void testNoActionsUpdatesNotificationChannel_blockingHelper() throws Exception {
+ mNotificationChannel.setImportance(IMPORTANCE_DEFAULT);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
+ TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
IMPORTANCE_DEFAULT, false);
mNotificationInfo.handleCloseControls(true, false);
@@ -983,7 +694,7 @@ public class NotificationInfoTest extends SysuiTestCase {
verify(mMockINotificationManager, times(1)).updateNotificationChannelForPackage(
anyString(), eq(TEST_UID), updated.capture());
assertTrue(0 != (mNotificationChannel.getUserLockedFields() & USER_LOCKED_IMPORTANCE));
- assertEquals(IMPORTANCE_LOW, mNotificationChannel.getImportance());
+ assertEquals(IMPORTANCE_DEFAULT, mNotificationChannel.getImportance());
}
@Test
@@ -993,8 +704,8 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
IMPORTANCE_DEFAULT, true);
- mNotificationInfo.findViewById(R.id.int_silent_wrapper).performClick();
- mNotificationInfo.findViewById(R.id.done_button).performClick();
+ mNotificationInfo.findViewById(R.id.silent_row).performClick();
+ mNotificationInfo.findViewById(R.id.done).performClick();
mNotificationInfo.handleCloseControls(true, false);
mTestableLooper.processAllMessages();
@@ -1014,8 +725,8 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
IMPORTANCE_DEFAULT, false);
- mNotificationInfo.findViewById(R.id.int_alert_wrapper).performClick();
- mNotificationInfo.findViewById(R.id.done_button).performClick();
+ mNotificationInfo.findViewById(R.id.alert_row).performClick();
+ mNotificationInfo.findViewById(R.id.done).performClick();
mNotificationInfo.handleCloseControls(true, false);
mTestableLooper.processAllMessages();
@@ -1036,8 +747,8 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
IMPORTANCE_DEFAULT, true);
- mNotificationInfo.findViewById(R.id.int_silent_wrapper).performClick();
- mNotificationInfo.findViewById(R.id.done_button).performClick();
+ mNotificationInfo.findViewById(R.id.silent_row).performClick();
+ mNotificationInfo.findViewById(R.id.done).performClick();
mNotificationInfo.handleCloseControls(true, false);
mTestableLooper.processAllMessages();
@@ -1058,8 +769,8 @@ public class NotificationInfoTest extends SysuiTestCase {
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
IMPORTANCE_LOW, false);
- mNotificationInfo.findViewById(R.id.int_alert_wrapper).performClick();
- mNotificationInfo.findViewById(R.id.done_button).performClick();
+ mNotificationInfo.findViewById(R.id.alert_row).performClick();
+ mNotificationInfo.findViewById(R.id.done).performClick();
mNotificationInfo.handleCloseControls(true, false);
mTestableLooper.processAllMessages();
@@ -1073,30 +784,14 @@ public class NotificationInfoTest extends SysuiTestCase {
}
@Test
- public void testCloseControlsDoesNotUpdateMinIfSaveIsFalse() throws Exception {
- mNotificationChannel.setImportance(IMPORTANCE_LOW);
- mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
- true, false, IMPORTANCE_DEFAULT, false);
-
- mNotificationInfo.findViewById(R.id.minimize).performClick();
- waitForUndoButton();
- mNotificationInfo.handleCloseControls(false, false);
-
- mTestableLooper.processAllMessages();
- verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
- eq(TEST_PACKAGE_NAME), eq(TEST_UID), eq(mNotificationChannel));
- }
-
- @Test
public void testCloseControlsDoesNotUpdateIfSaveIsFalse() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, false,
- IMPORTANCE_DEFAULT, false);
+ IMPORTANCE_LOW, false);
- mNotificationInfo.findViewById(R.id.int_block_wrapper).performClick();
- mNotificationInfo.findViewById(R.id.done_button).performClick();
+ mNotificationInfo.findViewById(R.id.alert_row).performClick();
+ mNotificationInfo.findViewById(R.id.done).performClick();
mNotificationInfo.handleCloseControls(false, false);
mTestableLooper.processAllMessages();
@@ -1105,33 +800,17 @@ public class NotificationInfoTest extends SysuiTestCase {
}
@Test
- public void testBlockDoesNothingIfCheckSaveListenerIsNoOp() throws Exception {
- mNotificationChannel.setImportance(IMPORTANCE_LOW);
- mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn,
- (Runnable saveImportance, StatusBarNotification sbn) -> {
- }, null, null, true, true, IMPORTANCE_DEFAULT, false);
-
- mNotificationInfo.findViewById(R.id.int_block_wrapper).performClick();
- mTestableLooper.processAllMessages();
- mNotificationInfo.handleCloseControls(true, false);
-
- verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
- eq(TEST_PACKAGE_NAME), eq(TEST_UID), eq(mNotificationChannel));
- }
-
- @Test
public void testCloseControlsUpdatesWhenCheckSaveListenerUsesCallback() throws Exception {
mNotificationChannel.setImportance(IMPORTANCE_LOW);
mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn,
(Runnable saveImportance, StatusBarNotification sbn) -> {
saveImportance.run();
- }, null, null, true, false, IMPORTANCE_DEFAULT, false
+ }, null, null, true, false, IMPORTANCE_LOW, false
);
- mNotificationInfo.findViewById(R.id.int_block_wrapper).performClick();
- mNotificationInfo.findViewById(R.id.done_button).performClick();
+ mNotificationInfo.findViewById(R.id.alert_row).performClick();
+ mNotificationInfo.findViewById(R.id.done).performClick();
mTestableLooper.processAllMessages();
verify(mMockINotificationManager, never()).updateNotificationChannelForPackage(
eq(TEST_PACKAGE_NAME), eq(TEST_UID), eq(mNotificationChannel));
@@ -1147,18 +826,4 @@ public class NotificationInfoTest extends SysuiTestCase {
public void testWillBeRemovedReturnsFalseBeforeBind() throws Exception {
assertFalse(mNotificationInfo.willBeRemoved());
}
-
- @Test
- public void testUndoText_min() throws Exception {
- mSbn.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE;
- mNotificationChannel.setImportance(IMPORTANCE_LOW);
- mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
- TEST_PACKAGE_NAME, mNotificationChannel, 1, mSbn, null, null, null, true, true,
- true, false, IMPORTANCE_DEFAULT, false);
-
- mNotificationInfo.findViewById(R.id.minimize).performClick();
- waitForUndoButton();
- TextView confirmationText = mNotificationInfo.findViewById(R.id.confirmation_text);
- assertTrue(confirmationText.getText().toString().contains("minimized"));
- }
}
diff --git a/services/core/java/com/android/server/ServiceWatcher.java b/services/core/java/com/android/server/ServiceWatcher.java
index a5a515f93e75..e3dc3b7a9848 100644
--- a/services/core/java/com/android/server/ServiceWatcher.java
+++ b/services/core/java/com/android/server/ServiceWatcher.java
@@ -382,7 +382,13 @@ public class ServiceWatcher implements ServiceConnection {
/**
* Runs the given function synchronously if currently connected, and returns the default value
* if not currently connected or if any exception is thrown.
+ *
+ * @deprecated Using this function is an indication that your AIDL API is broken. Calls from
+ * system server to outside MUST be one-way, and so cannot return any result, and this
+ * method should not be needed or used. Use a separate callback interface to allow outside
+ * components to return results back to the system server.
*/
+ @Deprecated
public final <T> T runOnBinderBlocking(BlockingBinderRunner<T> runner, T defaultValue) {
try {
return runOnHandlerBlocking(() -> {
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 4598d3ef7f4b..307919223a2b 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -929,13 +929,20 @@ class StorageManagerService extends IStorageManager.Stub
private void initIfBootedAndConnected() {
Slog.d(TAG, "Thinking about init, mBootCompleted=" + mBootCompleted
+ ", mDaemonConnected=" + mDaemonConnected);
- if (mBootCompleted && mDaemonConnected
- && !StorageManager.isFileEncryptedNativeOnly()) {
- // When booting a device without native support, make sure that our
- // user directories are locked or unlocked based on the current
- // emulation status.
- final boolean initLocked = StorageManager.isFileEncryptedEmulatedOnly();
- Slog.d(TAG, "Setting up emulation state, initlocked=" + initLocked);
+ if (mBootCompleted && mDaemonConnected) {
+ // Tell vold to lock or unlock the user directories based on the
+ // current file-based encryption status.
+ final boolean initLocked;
+ if (StorageManager.isFileEncryptedNativeOrEmulated()) {
+ // For native FBE this is a no-op after reboot, but this is
+ // still needed in case of framework restarts.
+ Slog.d(TAG, "FBE is enabled; ensuring all user directories are locked.");
+ initLocked = true;
+ } else {
+ // This is in case FBE emulation was turned off.
+ Slog.d(TAG, "FBE is disabled; ensuring the FBE emulation state is cleared.");
+ initLocked = false;
+ }
final List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers();
for (UserInfo user : users) {
try {
@@ -3840,7 +3847,9 @@ class StorageManagerService extends IStorageManager.Stub
uid, packageName, READ_EXTERNAL_STORAGE, OP_READ_EXTERNAL_STORAGE);
final boolean hasWrite = StorageManager.checkPermissionAndAppOp(mContext, false, 0,
uid, packageName, WRITE_EXTERNAL_STORAGE, OP_WRITE_EXTERNAL_STORAGE);
- final boolean hasStorage = hasRead || hasWrite;
+ // STOPSHIP: remove this temporary hack once we have dynamic runtime
+ // permissions fully enabled again
+ final boolean hasStorage = hasRead || hasWrite || true;
// We're only willing to give out broad access if they also hold
// runtime permission; this is a firm CDD requirement
diff --git a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
index e42666c6a637..7ab70fad70d4 100644
--- a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
+++ b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
@@ -49,6 +49,7 @@ class ActivityManagerDebugConfig {
static final boolean DEBUG_BROADCAST_BACKGROUND = DEBUG_BROADCAST || false;
static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
static final boolean DEBUG_BROADCAST_DEFERRAL = DEBUG_BROADCAST || false;
+ static final boolean DEBUG_COMPACTION = DEBUG_ALL || false;
static final boolean DEBUG_LRU = DEBUG_ALL || false;
static final boolean DEBUG_MU = DEBUG_ALL || false;
static final boolean DEBUG_NETWORK = DEBUG_ALL || false;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index a5932ccc1a5c..1757c9816355 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -213,6 +213,7 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManagerInternal;
import android.content.pm.PackageManagerInternal.CheckPermissionDelegate;
+import android.content.pm.PackageParser;
import android.content.pm.ParceledListSlice;
import android.content.pm.PathPermission;
import android.content.pm.PermissionInfo;
@@ -18474,7 +18475,9 @@ public class ActivityManagerService extends IActivityManager.Stub
void updateApplicationInfoLocked(@NonNull List<String> packagesToUpdate, int userId) {
final boolean updateFrameworkRes = packagesToUpdate.contains("android");
-
+ if (updateFrameworkRes) {
+ PackageParser.readConfigUseRoundIcon(null);
+ }
mProcessList.updateApplicationInfoLocked(packagesToUpdate, userId, updateFrameworkRes);
if (updateFrameworkRes) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 8a462dabd14c..d1379b669563 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -16,6 +16,7 @@
package com.android.server.am;
+import static android.app.ActivityManagerInternal.ALLOW_NON_FULL;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.ActivityTaskManager.RESIZE_MODE_SYSTEM;
import static android.app.ActivityTaskManager.RESIZE_MODE_USER;
@@ -427,8 +428,12 @@ final class ActivityManagerShellCommand extends ShellCommand {
if (intent.getComponent() != null) {
packageName = intent.getComponent().getPackageName();
} else {
+ // queryIntentActivities does not convert user id, so we convert it here first
+ int userIdForQuery = mInternal.mUserController.handleIncomingUser(
+ Binder.getCallingPid(), Binder.getCallingUid(), mUserId, false,
+ ALLOW_NON_FULL, "ActivityManagerShellCommand", null);
List<ResolveInfo> activities = mPm.queryIntentActivities(intent, mimeType, 0,
- mUserId).getList();
+ userIdForQuery).getList();
if (activities == null || activities.size() <= 0) {
getErrPrintWriter().println("Error: Intent does not match any activities: "
+ intent);
diff --git a/services/core/java/com/android/server/am/AppCompactor.java b/services/core/java/com/android/server/am/AppCompactor.java
index ac1002689dc0..043dc8d00081 100644
--- a/services/core/java/com/android/server/am/AppCompactor.java
+++ b/services/core/java/com/android/server/am/AppCompactor.java
@@ -18,6 +18,9 @@ package com.android.server.am;
import static android.os.Process.THREAD_PRIORITY_FOREGROUND;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_COMPACTION;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+
import android.app.ActivityManager;
import android.app.ActivityThread;
import android.os.Debug;
@@ -30,6 +33,7 @@ import android.provider.DeviceConfig;
import android.provider.DeviceConfig.OnPropertyChangedListener;
import android.text.TextUtils;
import android.util.EventLog;
+import android.util.Slog;
import android.util.StatsLog;
import com.android.internal.annotations.GuardedBy;
@@ -39,7 +43,12 @@ import com.android.server.ServiceThread;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.Map;
import java.util.Random;
+import java.util.Set;
public final class AppCompactor {
@@ -55,6 +64,12 @@ public final class AppCompactor {
@VisibleForTesting static final String KEY_COMPACT_THROTTLE_6 = "compact_throttle_6";
@VisibleForTesting static final String KEY_COMPACT_STATSD_SAMPLE_RATE =
"compact_statsd_sample_rate";
+ @VisibleForTesting static final String KEY_COMPACT_FULL_RSS_THROTTLE_KB =
+ "compact_full_rss_throttle_kb";
+ @VisibleForTesting static final String KEY_COMPACT_FULL_DELTA_RSS_THROTTLE_KB =
+ "compact_full_delta_rss_throttle_kb";
+ @VisibleForTesting static final String KEY_COMPACT_PROC_STATE_THROTTLE =
+ "compact_proc_state_throttle";
// Phenotype sends int configurations and we map them to the strings we'll use on device,
// preventing a weird string value entering the kernel.
@@ -79,6 +94,11 @@ public final class AppCompactor {
@VisibleForTesting static final long DEFAULT_COMPACT_THROTTLE_6 = 10 * 60 * 1000;
// The sampling rate to push app compaction events into statsd for upload.
@VisibleForTesting static final float DEFAULT_STATSD_SAMPLE_RATE = 0.1f;
+ @VisibleForTesting static final long DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB = 12_000L;
+ @VisibleForTesting static final long DEFAULT_COMPACT_FULL_DELTA_RSS_THROTTLE_KB = 8_000L;
+ // Format of this string should be a comma separated list of integers.
+ @VisibleForTesting static final String DEFAULT_COMPACT_PROC_STATE_THROTTLE =
+ String.valueOf(ActivityManager.PROCESS_STATE_RECEIVER);
@VisibleForTesting
interface PropertyChangedCallbackForTest {
@@ -123,6 +143,12 @@ public final class AppCompactor {
updateCompactionThrottles();
} else if (KEY_COMPACT_STATSD_SAMPLE_RATE.equals(name)) {
updateStatsdSampleRate();
+ } else if (KEY_COMPACT_FULL_RSS_THROTTLE_KB.equals(name)) {
+ updateFullRssThrottle();
+ } else if (KEY_COMPACT_FULL_DELTA_RSS_THROTTLE_KB.equals(name)) {
+ updateFullDeltaRssThrottle();
+ } else if (KEY_COMPACT_PROC_STATE_THROTTLE.equals(name)) {
+ updateProcStateThrottle();
}
}
if (mTestCallback != null) {
@@ -154,18 +180,42 @@ public final class AppCompactor {
@VisibleForTesting volatile long mCompactThrottlePersistent = DEFAULT_COMPACT_THROTTLE_6;
@GuardedBy("mPhenotypeFlagLock")
private volatile boolean mUseCompaction = DEFAULT_USE_COMPACTION;
-
private final Random mRandom = new Random();
@GuardedBy("mPhenotypeFlagLock")
@VisibleForTesting volatile float mStatsdSampleRate = DEFAULT_STATSD_SAMPLE_RATE;
+ @GuardedBy("mPhenotypeFlagLock")
+ @VisibleForTesting volatile long mFullAnonRssThrottleKb =
+ DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB;
+ @GuardedBy("mPhenoypeFlagLock")
+ @VisibleForTesting volatile long mFullDeltaRssThrottleKb =
+ DEFAULT_COMPACT_FULL_DELTA_RSS_THROTTLE_KB;
+ @GuardedBy("mPhenoypeFlagLock")
+ @VisibleForTesting final Set<Integer> mProcStateThrottle;
// Handler on which compaction runs.
private Handler mCompactionHandler;
+ // Maps process ID to last compaction statistics for processes that we've fully compacted. Used
+ // when evaluating throttles that we only consider for "full" compaction, so we don't store
+ // data for "some" compactions.
+ private Map<Integer, LastCompactionStats> mLastCompactionStats =
+ new LinkedHashMap<Integer, LastCompactionStats>() {
+ @Override
+ protected boolean removeEldestEntry(Map.Entry eldest) {
+ return size() > 100;
+ }
+ };
+
+ private int mSomeCompactionCount;
+ private int mFullCompactionCount;
+ private int mPersistentCompactionCount;
+ private int mBfgsCompactionCount;
+
public AppCompactor(ActivityManagerService am) {
mAm = am;
mCompactionThread = new ServiceThread("CompactionThread",
THREAD_PRIORITY_FOREGROUND, true);
+ mProcStateThrottle = new HashSet<>();
}
@VisibleForTesting
@@ -186,10 +236,12 @@ public final class AppCompactor {
updateCompactionActions();
updateCompactionThrottles();
updateStatsdSampleRate();
+ updateFullRssThrottle();
+ updateFullDeltaRssThrottle();
+ updateProcStateThrottle();
}
Process.setThreadGroupAndCpuset(mCompactionThread.getThreadId(),
Process.THREAD_GROUP_SYSTEM);
-
}
/**
@@ -212,7 +264,33 @@ public final class AppCompactor {
pw.println(" " + KEY_COMPACT_THROTTLE_2 + "=" + mCompactThrottleSomeFull);
pw.println(" " + KEY_COMPACT_THROTTLE_3 + "=" + mCompactThrottleFullSome);
pw.println(" " + KEY_COMPACT_THROTTLE_4 + "=" + mCompactThrottleFullFull);
+ pw.println(" " + KEY_COMPACT_THROTTLE_5 + "=" + mCompactThrottleBFGS);
+ pw.println(" " + KEY_COMPACT_THROTTLE_6 + "=" + mCompactThrottlePersistent);
pw.println(" " + KEY_COMPACT_STATSD_SAMPLE_RATE + "=" + mStatsdSampleRate);
+ pw.println(" " + KEY_COMPACT_FULL_RSS_THROTTLE_KB + "="
+ + mFullAnonRssThrottleKb);
+ pw.println(" " + KEY_COMPACT_FULL_DELTA_RSS_THROTTLE_KB + "="
+ + mFullDeltaRssThrottleKb);
+ pw.println(" " + KEY_COMPACT_PROC_STATE_THROTTLE + "="
+ + Arrays.toString(mProcStateThrottle.toArray(new Integer[0])));
+
+ pw.println(" " + mSomeCompactionCount + " some, " + mFullCompactionCount
+ + " full, " + mPersistentCompactionCount + " persistent, "
+ + mBfgsCompactionCount + " BFGS compactions.");
+
+ if (mLastCompactionStats != null) {
+ pw.println(" Tracking last compaction stats for " + mLastCompactionStats.size()
+ + " processes.");
+ if (DEBUG_COMPACTION) {
+ for (Map.Entry<Integer, LastCompactionStats> entry
+ : mLastCompactionStats.entrySet()) {
+ int pid = entry.getKey();
+ LastCompactionStats stats = entry.getValue();
+ pw.println(" " + pid + ": "
+ + Arrays.toString(stats.getRssAfterCompaction()));
+ }
+ }
+ }
}
}
@@ -277,7 +355,7 @@ public final class AppCompactor {
/**
* Reads the flag value from DeviceConfig to determine whether app compaction
- * should be enabled, and starts/stops the compaction thread as needed.
+ * should be enabled, and starts the compaction thread if needed.
*/
@GuardedBy("mPhenotypeFlagLock")
private void updateUseCompaction() {
@@ -360,6 +438,58 @@ public final class AppCompactor {
mStatsdSampleRate = Math.min(1.0f, Math.max(0.0f, mStatsdSampleRate));
}
+ @GuardedBy("mPhenotypeFlagLock")
+ private void updateFullRssThrottle() {
+ mFullAnonRssThrottleKb = DeviceConfig.getLong(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_COMPACT_FULL_RSS_THROTTLE_KB, DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB);
+
+ // Don't allow negative values. 0 means don't apply the throttle.
+ if (mFullAnonRssThrottleKb < 0) {
+ mFullAnonRssThrottleKb = DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB;
+ }
+ }
+
+ @GuardedBy("mPhenotypeFlagLock")
+ private void updateFullDeltaRssThrottle() {
+ mFullDeltaRssThrottleKb = DeviceConfig.getLong(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ KEY_COMPACT_FULL_DELTA_RSS_THROTTLE_KB, DEFAULT_COMPACT_FULL_DELTA_RSS_THROTTLE_KB);
+
+ if (mFullDeltaRssThrottleKb < 0) {
+ mFullDeltaRssThrottleKb = DEFAULT_COMPACT_FULL_DELTA_RSS_THROTTLE_KB;
+ }
+ }
+
+ @GuardedBy("mPhenotypeFlagLock")
+ private void updateProcStateThrottle() {
+ String procStateThrottleString = DeviceConfig.getString(
+ DeviceConfig.NAMESPACE_ACTIVITY_MANAGER, KEY_COMPACT_PROC_STATE_THROTTLE,
+ DEFAULT_COMPACT_PROC_STATE_THROTTLE);
+ if (!parseProcStateThrottle(procStateThrottleString)) {
+ Slog.w(TAG_AM, "Unable to parse app compact proc state throttle \""
+ + procStateThrottleString + "\" falling back to default.");
+ if (!parseProcStateThrottle(DEFAULT_COMPACT_PROC_STATE_THROTTLE)) {
+ Slog.wtf(TAG_AM,
+ "Unable to parse default app compact proc state throttle "
+ + DEFAULT_COMPACT_PROC_STATE_THROTTLE);
+ }
+ }
+ }
+
+ private boolean parseProcStateThrottle(String procStateThrottleString) {
+ String[] procStates = TextUtils.split(procStateThrottleString, ",");
+ mProcStateThrottle.clear();
+ for (String procState : procStates) {
+ try {
+ mProcStateThrottle.add(Integer.parseInt(procState));
+ } catch (NumberFormatException e) {
+ Slog.e(TAG_AM, "Failed to parse default app compaction proc state: "
+ + procState);
+ return false;
+ }
+ }
+ return true;
+ }
+
@VisibleForTesting
static String compactActionIntToString(int action) {
switch(action) {
@@ -376,6 +506,22 @@ public final class AppCompactor {
}
}
+ @VisibleForTesting static String procStateListToString(Integer... processStates) {
+ return Arrays.toString(processStates);
+ }
+
+ private static final class LastCompactionStats {
+ private final long[] mRssAfterCompaction;
+
+ LastCompactionStats(long[] rss) {
+ mRssAfterCompaction = rss;
+ }
+
+ long[] getRssAfterCompaction() {
+ return mRssAfterCompaction;
+ }
+ }
+
private final class MemCompactionHandler extends Handler {
private MemCompactionHandler() {
super(mCompactionThread.getLooper());
@@ -392,24 +538,34 @@ public final class AppCompactor {
final String name;
int pendingAction, lastCompactAction;
long lastCompactTime;
+ LastCompactionStats lastCompactionStats;
+ int lastOomAdj = msg.arg1;
+ int procState = msg.arg2;
synchronized (mAm) {
proc = mPendingCompactionProcesses.remove(0);
pendingAction = proc.reqCompactAction;
+ pid = proc.pid;
+ name = proc.processName;
// don't compact if the process has returned to perceptible
// and this is only a cached/home/prev compaction
if ((pendingAction == COMPACT_PROCESS_SOME
|| pendingAction == COMPACT_PROCESS_FULL)
&& (proc.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ)) {
+ if (DEBUG_COMPACTION) {
+ Slog.d(TAG_AM,
+ "Skipping compaction as process " + name + " is "
+ + "now perceptible.");
+ }
return;
}
- pid = proc.pid;
- name = proc.processName;
-
lastCompactAction = proc.lastCompactAction;
lastCompactTime = proc.lastCompactTime;
+ // remove rather than get so that insertion order will be updated when we
+ // put the post-compaction stats back into the map.
+ lastCompactionStats = mLastCompactionStats.remove(pid);
}
if (pid == 0) {
@@ -431,6 +587,12 @@ public final class AppCompactor {
|| (lastCompactAction == COMPACT_PROCESS_FULL
&& (start - lastCompactTime
< mCompactThrottleSomeFull))) {
+ if (DEBUG_COMPACTION) {
+ Slog.d(TAG_AM, "Skipping some compaction for " + name
+ + ": too soon. throttle=" + mCompactThrottleSomeSome
+ + "/" + mCompactThrottleSomeFull + " last="
+ + (start - lastCompactTime) + "ms ago");
+ }
return;
}
} else if (pendingAction == COMPACT_PROCESS_FULL) {
@@ -439,18 +601,35 @@ public final class AppCompactor {
|| (lastCompactAction == COMPACT_PROCESS_FULL
&& (start - lastCompactTime
< mCompactThrottleFullFull))) {
+ if (DEBUG_COMPACTION) {
+ Slog.d(TAG_AM, "Skipping full compaction for " + name
+ + ": too soon. throttle=" + mCompactThrottleFullSome
+ + "/" + mCompactThrottleFullFull + " last="
+ + (start - lastCompactTime) + "ms ago");
+ }
return;
}
} else if (pendingAction == COMPACT_PROCESS_PERSISTENT) {
if (start - lastCompactTime < mCompactThrottlePersistent) {
+ if (DEBUG_COMPACTION) {
+ Slog.d(TAG_AM, "Skipping persistent compaction for " + name
+ + ": too soon. throttle=" + mCompactThrottlePersistent
+ + " last=" + (start - lastCompactTime) + "ms ago");
+ }
return;
}
} else if (pendingAction == COMPACT_PROCESS_BFGS) {
if (start - lastCompactTime < mCompactThrottleBFGS) {
+ if (DEBUG_COMPACTION) {
+ Slog.d(TAG_AM, "Skipping bfgs compaction for " + name
+ + ": too soon. throttle=" + mCompactThrottleBFGS
+ + " last=" + (start - lastCompactTime) + "ms ago");
+ }
return;
}
}
}
+
switch (pendingAction) {
case COMPACT_PROCESS_SOME:
action = mCompactActionSome;
@@ -470,12 +649,77 @@ public final class AppCompactor {
return;
}
+ if (mProcStateThrottle.contains(procState)) {
+ if (DEBUG_COMPACTION) {
+ Slog.d(TAG_AM, "Skipping full compaction for process " + name
+ + "; proc state is " + procState);
+ }
+ return;
+ }
+
+ long[] rssBefore = Process.getRss(pid);
+ long anonRssBefore = rssBefore[2];
+
+ if (rssBefore[0] == 0 && rssBefore[1] == 0 && rssBefore[2] == 0
+ && rssBefore[3] == 0) {
+ if (DEBUG_COMPACTION) {
+ Slog.d(TAG_AM, "Skipping compaction for" + "process " + pid
+ + " with no memory usage. Dead?");
+ }
+ return;
+ }
+
+ if (action.equals(COMPACT_ACTION_FULL) || action.equals(COMPACT_ACTION_ANON)) {
+ if (mFullAnonRssThrottleKb > 0L
+ && anonRssBefore < mFullAnonRssThrottleKb) {
+ if (DEBUG_COMPACTION) {
+ Slog.d(TAG_AM, "Skipping full compaction for process "
+ + name + "; anon RSS is too small: " + anonRssBefore
+ + "KB.");
+ }
+ return;
+ }
+
+ if (lastCompactionStats != null && mFullDeltaRssThrottleKb > 0L) {
+ long[] lastRss = lastCompactionStats.getRssAfterCompaction();
+ long absDelta = Math.abs(rssBefore[1] - lastRss[1])
+ + Math.abs(rssBefore[2] - lastRss[2])
+ + Math.abs(rssBefore[3] - lastRss[3]);
+ if (absDelta <= mFullDeltaRssThrottleKb) {
+ if (DEBUG_COMPACTION) {
+ Slog.d(TAG_AM, "Skipping full compaction for process "
+ + name + "; abs delta is too small: " + absDelta
+ + "KB.");
+ }
+ return;
+ }
+ }
+ }
+
+ // Now we've passed through all the throttles and are going to compact, update
+ // bookkeeping.
+ switch (pendingAction) {
+ case COMPACT_PROCESS_SOME:
+ mSomeCompactionCount++;
+ break;
+ case COMPACT_PROCESS_FULL:
+ mFullCompactionCount++;
+ break;
+ case COMPACT_PROCESS_PERSISTENT:
+ mPersistentCompactionCount++;
+ break;
+ case COMPACT_PROCESS_BFGS:
+ mBfgsCompactionCount++;
+ break;
+ default:
+ break;
+ }
+
try {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Compact "
+ ((pendingAction == COMPACT_PROCESS_SOME) ? "some" : "full")
+ ": " + name);
long zramFreeKbBefore = Debug.getZramFreeKb();
- long[] rssBefore = Process.getRss(pid);
FileOutputStream fos = new FileOutputStream("/proc/" + pid + "/reclaim");
fos.write(action.getBytes());
fos.close();
@@ -487,8 +731,9 @@ public final class AppCompactor {
rssBefore[0], rssBefore[1], rssBefore[2], rssBefore[3],
rssAfter[0] - rssBefore[0], rssAfter[1] - rssBefore[1],
rssAfter[2] - rssBefore[2], rssAfter[3] - rssBefore[3], time,
- lastCompactAction, lastCompactTime, msg.arg1, msg.arg2,
+ lastCompactAction, lastCompactTime, lastOomAdj, procState,
zramFreeKbBefore, zramFreeKbAfter - zramFreeKbBefore);
+
// Note that as above not taking mPhenoTypeFlagLock here to avoid locking
// on every single compaction for a flag that will seldom change and the
// impact of reading the wrong value here is low.
@@ -496,17 +741,23 @@ public final class AppCompactor {
StatsLog.write(StatsLog.APP_COMPACTED, pid, name, pendingAction,
rssBefore[0], rssBefore[1], rssBefore[2], rssBefore[3],
rssAfter[0], rssAfter[1], rssAfter[2], rssAfter[3], time,
- lastCompactAction, lastCompactTime, msg.arg1,
- ActivityManager.processStateAmToProto(msg.arg2),
+ lastCompactAction, lastCompactTime, lastOomAdj,
+ ActivityManager.processStateAmToProto(procState),
zramFreeKbBefore, zramFreeKbAfter);
}
+
synchronized (mAm) {
proc.lastCompactTime = end;
proc.lastCompactAction = pendingAction;
}
- Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
+
+ if (action.equals(COMPACT_ACTION_FULL)
+ || action.equals(COMPACT_ACTION_ANON)) {
+ mLastCompactionStats.put(pid, new LastCompactionStats(rssAfter));
+ }
} catch (Exception e) {
// nothing to do, presumably the process died
+ } finally {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
break;
diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java
index 1681c5bc61d3..bc78d1ad751f 100644
--- a/services/core/java/com/android/server/attention/AttentionManagerService.java
+++ b/services/core/java/com/android/server/attention/AttentionManagerService.java
@@ -19,6 +19,7 @@ package com.android.server.attention;
import static android.provider.DeviceConfig.NAMESPACE_ATTENTION_MANAGER_SERVICE;
import static android.provider.Settings.System.ADAPTIVE_SLEEP;
import static android.service.attention.AttentionService.ATTENTION_FAILURE_CANCELLED;
+import static android.service.attention.AttentionService.ATTENTION_FAILURE_UNKNOWN;
import android.Manifest;
import android.annotation.NonNull;
@@ -249,6 +250,7 @@ public class AttentionManagerService extends SystemService {
if (userState.mPendingAttentionCheck != null
&& userState.mPendingAttentionCheck.mCallbackInternal.equals(
callbackInternal)) {
+ userState.mPendingAttentionCheck.cancel(ATTENTION_FAILURE_UNKNOWN);
userState.mPendingAttentionCheck = null;
}
return;
@@ -624,7 +626,7 @@ public class AttentionManagerService extends SystemService {
if (userState == null) {
return;
}
- cancel(userState, AttentionService.ATTENTION_FAILURE_UNKNOWN);
+ cancel(userState, ATTENTION_FAILURE_UNKNOWN);
mContext.unbindService(userState.mConnection);
userState.mConnection.cleanupService();
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/AnnouncementAggregator.java b/services/core/java/com/android/server/broadcastradio/hal2/AnnouncementAggregator.java
index 0bbaf25aaa12..53076975849b 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/AnnouncementAggregator.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/AnnouncementAggregator.java
@@ -90,7 +90,11 @@ public class AnnouncementAggregator extends ICloseHandle.Stub {
for (ModuleWatcher watcher : mModuleWatchers) {
combined.addAll(watcher.currentList);
}
- TunerCallback.dispatch(() -> mListener.onListUpdated(combined));
+ try {
+ mListener.onListUpdated(combined);
+ } catch (RemoteException ex) {
+ Slog.e(TAG, "mListener.onListUpdated() failed: ", ex);
+ }
}
}
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java b/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java
index 2df89821611c..5e79c5943d7b 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java
@@ -54,13 +54,6 @@ public class BroadcastRadioService {
@GuardedBy("mLock")
private final Map<Integer, RadioModule> mModules = new HashMap<>();
- // Map from module ID to TunerSession created by openSession().
- //
- // Because this service currently implements a 1 AIDL to 1 HAL policy, mTunerSessions is used to
- // enforce the "aggresive open" policy mandated for IBroadcastRadio.openSession(). In the
- // future, this solution will be replaced with a multiple-AIDL to 1 HAL implementation.
- private final Map<Integer, TunerSession> mTunerSessions = new HashMap<>();
-
private IServiceNotification.Stub mServiceListener = new IServiceNotification.Stub() {
@Override
public void onRegistration(String fqName, String serviceName, boolean preexisting) {
@@ -81,8 +74,10 @@ public class BroadcastRadioService {
}
Slog.v(TAG, "loaded broadcast radio module " + moduleId + ": " + serviceName
+ " (HAL 2.0)");
- closeTunerSessionLocked(moduleId);
- mModules.put(moduleId, module);
+ RadioModule prevModule = mModules.put(moduleId, module);
+ if (prevModule != null) {
+ prevModule.closeSessions(RadioTuner.ERROR_HARDWARE_FAILURE);
+ }
if (newService) {
mServiceNameToModuleIdMap.put(serviceName, moduleId);
@@ -105,8 +100,10 @@ public class BroadcastRadioService {
Slog.v(TAG, "serviceDied(" + cookie + ")");
synchronized (mLock) {
int moduleId = (int) cookie;
- mModules.remove(moduleId);
- closeTunerSessionLocked(moduleId);
+ RadioModule prevModule = mModules.remove(moduleId);
+ if (prevModule != null) {
+ prevModule.closeSessions(RadioTuner.ERROR_HARDWARE_FAILURE);
+ }
for (Map.Entry<String, Integer> entry : mServiceNameToModuleIdMap.entrySet()) {
if (entry.getValue() == moduleId) {
@@ -166,13 +163,9 @@ public class BroadcastRadioService {
if (module == null) {
throw new IllegalArgumentException("Invalid module ID");
}
- closeTunerSessionLocked(moduleId);
}
TunerSession tunerSession = module.openSession(callback);
- synchronized (mLock) {
- mTunerSessions.put(moduleId, tunerSession);
- }
if (legacyConfig != null) {
tunerSession.setConfiguration(legacyConfig);
}
@@ -198,12 +191,4 @@ public class BroadcastRadioService {
}
return aggregator;
}
-
- private void closeTunerSessionLocked(int moduleId) {
- TunerSession tunerSession = mTunerSessions.remove(moduleId);
- if (tunerSession != null) {
- Slog.d(TAG, "Closing previous TunerSession");
- tunerSession.close(RadioTuner.ERROR_HARDWARE_FAILURE);
- }
- }
}
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
index 832f8e1c9205..acb0207ff11f 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
@@ -26,16 +26,26 @@ import android.hardware.broadcastradio.V2_0.DabTableEntry;
import android.hardware.broadcastradio.V2_0.IAnnouncementListener;
import android.hardware.broadcastradio.V2_0.IBroadcastRadio;
import android.hardware.broadcastradio.V2_0.ICloseHandle;
+import android.hardware.broadcastradio.V2_0.ITunerCallback;
import android.hardware.broadcastradio.V2_0.ITunerSession;
+import android.hardware.broadcastradio.V2_0.ProgramInfo;
+import android.hardware.broadcastradio.V2_0.ProgramListChunk;
+import android.hardware.broadcastradio.V2_0.ProgramSelector;
import android.hardware.broadcastradio.V2_0.Result;
+import android.hardware.broadcastradio.V2_0.VendorKeyValue;
import android.hardware.radio.RadioManager;
+import android.os.DeadObjectException;
import android.os.RemoteException;
import android.util.MutableInt;
import android.util.Slog;
+import com.android.internal.annotations.GuardedBy;
+
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
import java.util.Objects;
+import java.util.Set;
import java.util.stream.Collectors;
class RadioModule {
@@ -44,8 +54,63 @@ class RadioModule {
@NonNull private final IBroadcastRadio mService;
@NonNull public final RadioManager.ModuleProperties mProperties;
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
+ private ITunerSession mHalTunerSession;
+
+ // Tracks antenna state reported by HAL (if any).
+ @GuardedBy("mLock")
+ private Boolean mAntennaConnected = null;
+
+ @GuardedBy("mLock")
+ private RadioManager.ProgramInfo mProgramInfo = null;
+
+ // Callback registered with the HAL to relay callbacks to AIDL clients.
+ private final ITunerCallback mHalTunerCallback = new ITunerCallback.Stub() {
+ @Override
+ public void onTuneFailed(int result, ProgramSelector programSelector) {
+ fanoutAidlCallback(cb -> cb.onTuneFailed(result, Convert.programSelectorFromHal(
+ programSelector)));
+ }
+
+ @Override
+ public void onCurrentProgramInfoChanged(ProgramInfo halProgramInfo) {
+ RadioManager.ProgramInfo programInfo = Convert.programInfoFromHal(halProgramInfo);
+ synchronized (mLock) {
+ mProgramInfo = programInfo;
+ fanoutAidlCallbackLocked(cb -> cb.onCurrentProgramInfoChanged(programInfo));
+ }
+ }
+
+ @Override
+ public void onProgramListUpdated(ProgramListChunk programListChunk) {
+ // TODO: Cache per-AIDL client filters, send union of filters to HAL, use filters to fan
+ // back out to clients.
+ fanoutAidlCallback(cb -> cb.onProgramListUpdated(Convert.programListChunkFromHal(
+ programListChunk)));
+ }
+
+ @Override
+ public void onAntennaStateChange(boolean connected) {
+ synchronized (mLock) {
+ mAntennaConnected = connected;
+ fanoutAidlCallbackLocked(cb -> cb.onAntennaState(connected));
+ }
+ }
+
+ @Override
+ public void onParametersUpdated(ArrayList<VendorKeyValue> parameters) {
+ fanoutAidlCallback(cb -> cb.onParametersUpdated(Convert.vendorInfoFromHal(parameters)));
+ }
+ };
+
+ // Collection of active AIDL tuner sessions created through openSession().
+ @GuardedBy("mLock")
+ private final Set<TunerSession> mAidlTunerSessions = new HashSet<>();
+
private RadioModule(@NonNull IBroadcastRadio service,
- @NonNull RadioManager.ModuleProperties properties) {
+ @NonNull RadioManager.ModuleProperties properties) throws RemoteException {
mProperties = Objects.requireNonNull(properties);
mService = Objects.requireNonNull(service);
}
@@ -81,21 +146,85 @@ class RadioModule {
public @NonNull TunerSession openSession(@NonNull android.hardware.radio.ITunerCallback userCb)
throws RemoteException {
- TunerCallback cb = new TunerCallback(Objects.requireNonNull(userCb));
- Mutable<ITunerSession> hwSession = new Mutable<>();
- MutableInt halResult = new MutableInt(Result.UNKNOWN_ERROR);
+ synchronized (mLock) {
+ if (mHalTunerSession == null) {
+ Mutable<ITunerSession> hwSession = new Mutable<>();
+ mService.openSession(mHalTunerCallback, (result, session) -> {
+ Convert.throwOnError("openSession", result);
+ hwSession.value = session;
+ });
+ mHalTunerSession = Objects.requireNonNull(hwSession.value);
+ }
+ TunerSession tunerSession = new TunerSession(this, mHalTunerSession, userCb);
+ mAidlTunerSessions.add(tunerSession);
- synchronized (mService) {
- mService.openSession(cb, (result, session) -> {
- hwSession.value = session;
- halResult.value = result;
- });
+ // Propagate state to new client. Note: These callbacks are invoked while holding mLock
+ // to prevent race conditions with new callbacks from the HAL.
+ if (mAntennaConnected != null) {
+ userCb.onAntennaState(mAntennaConnected);
+ }
+ if (mProgramInfo != null) {
+ userCb.onCurrentProgramInfoChanged(mProgramInfo);
+ }
+
+ return tunerSession;
+ }
+ }
+
+ public void closeSessions(Integer error) {
+ // Copy the contents of mAidlTunerSessions into a local array because TunerSession.close()
+ // must be called without mAidlTunerSessions locked because it can call
+ // onTunerSessionClosed().
+ TunerSession[] tunerSessions;
+ synchronized (mLock) {
+ tunerSessions = new TunerSession[mAidlTunerSessions.size()];
+ mAidlTunerSessions.toArray(tunerSessions);
+ mAidlTunerSessions.clear();
+ }
+ for (TunerSession tunerSession : tunerSessions) {
+ tunerSession.close(error);
+ }
+ }
+
+ void onTunerSessionClosed(TunerSession tunerSession) {
+ synchronized (mLock) {
+ mAidlTunerSessions.remove(tunerSession);
+ if (mAidlTunerSessions.isEmpty() && mHalTunerSession != null) {
+ Slog.v(TAG, "closing HAL tuner session");
+ try {
+ mHalTunerSession.close();
+ } catch (RemoteException ex) {
+ Slog.e(TAG, "mHalTunerSession.close() failed: ", ex);
+ }
+ mHalTunerSession = null;
+ }
}
+ }
- Convert.throwOnError("openSession", halResult.value);
- Objects.requireNonNull(hwSession.value);
+ interface AidlCallbackRunnable {
+ void run(android.hardware.radio.ITunerCallback callback) throws RemoteException;
+ }
- return new TunerSession(this, hwSession.value, cb);
+ // Invokes runnable with each TunerSession currently open.
+ void fanoutAidlCallback(AidlCallbackRunnable runnable) {
+ synchronized (mLock) {
+ fanoutAidlCallbackLocked(runnable);
+ }
+ }
+
+ private void fanoutAidlCallbackLocked(AidlCallbackRunnable runnable) {
+ for (TunerSession tunerSession : mAidlTunerSessions) {
+ try {
+ runnable.run(tunerSession.mCallback);
+ } catch (DeadObjectException ex) {
+ // The other side died without calling close(), so just purge it from our
+ // records.
+ Slog.e(TAG, "Removing dead TunerSession");
+ mAidlTunerSessions.remove(tunerSession);
+ } catch (RemoteException ex) {
+ Slog.e(TAG, "Failed to invoke ITunerCallback: ", ex);
+ }
+ }
}
public android.hardware.radio.ICloseHandle addAnnouncementListener(@NonNull int[] enabledTypes,
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/TunerCallback.java b/services/core/java/com/android/server/broadcastradio/hal2/TunerCallback.java
deleted file mode 100644
index 3c4b49c91cf2..000000000000
--- a/services/core/java/com/android/server/broadcastradio/hal2/TunerCallback.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/**
- * Copyright (C) 2017 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.broadcastradio.hal2;
-
-import android.annotation.NonNull;
-import android.hardware.broadcastradio.V2_0.ITunerCallback;
-import android.hardware.broadcastradio.V2_0.ProgramInfo;
-import android.hardware.broadcastradio.V2_0.ProgramListChunk;
-import android.hardware.broadcastradio.V2_0.ProgramSelector;
-import android.hardware.broadcastradio.V2_0.VendorKeyValue;
-import android.os.RemoteException;
-import android.util.Slog;
-
-import java.util.ArrayList;
-import java.util.Objects;
-
-class TunerCallback extends ITunerCallback.Stub {
- private static final String TAG = "BcRadio2Srv.cb";
-
- final android.hardware.radio.ITunerCallback mClientCb;
-
- interface RunnableThrowingRemoteException {
- void run() throws RemoteException;
- }
-
- TunerCallback(@NonNull android.hardware.radio.ITunerCallback clientCallback) {
- mClientCb = Objects.requireNonNull(clientCallback);
- }
-
- static void dispatch(RunnableThrowingRemoteException func) {
- try {
- func.run();
- } catch (RemoteException ex) {
- Slog.e(TAG, "callback call failed", ex);
- }
- }
-
- @Override
- public void onTuneFailed(int result, ProgramSelector selector) {
- dispatch(() -> mClientCb.onTuneFailed(result, Convert.programSelectorFromHal(selector)));
- }
-
- @Override
- public void onCurrentProgramInfoChanged(ProgramInfo info) {
- dispatch(() -> mClientCb.onCurrentProgramInfoChanged(Convert.programInfoFromHal(info)));
- }
-
- @Override
- public void onProgramListUpdated(ProgramListChunk chunk) {
- dispatch(() -> mClientCb.onProgramListUpdated(Convert.programListChunkFromHal(chunk)));
- }
-
- @Override
- public void onAntennaStateChange(boolean connected) {
- dispatch(() -> mClientCb.onAntennaState(connected));
- }
-
- @Override
- public void onParametersUpdated(ArrayList<VendorKeyValue> parameters) {
- dispatch(() -> mClientCb.onParametersUpdated(Convert.vendorInfoFromHal(parameters)));
- }
-}
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
index 05ca144ed3b9..008fea5831ad 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
@@ -43,7 +43,7 @@ class TunerSession extends ITuner.Stub {
private final RadioModule mModule;
private final ITunerSession mHwSession;
- private final TunerCallback mCallback;
+ final android.hardware.radio.ITunerCallback mCallback;
private boolean mIsClosed = false;
private boolean mIsMuted = false;
@@ -51,7 +51,7 @@ class TunerSession extends ITuner.Stub {
private RadioManager.BandConfig mDummyConfig = null;
TunerSession(@NonNull RadioModule module, @NonNull ITunerSession hwSession,
- @NonNull TunerCallback callback) {
+ @NonNull android.hardware.radio.ITunerCallback callback) {
mModule = Objects.requireNonNull(module);
mHwSession = Objects.requireNonNull(hwSession);
mCallback = Objects.requireNonNull(callback);
@@ -73,9 +73,14 @@ class TunerSession extends ITuner.Stub {
synchronized (mLock) {
if (mIsClosed) return;
if (error != null) {
- TunerCallback.dispatch(() -> mCallback.mClientCb.onError(error));
+ try {
+ mCallback.onError(error);
+ } catch (RemoteException ex) {
+ Slog.w(TAG, "mCallback.onError() failed: ", ex);
+ }
}
mIsClosed = true;
+ mModule.onTunerSessionClosed(this);
}
}
@@ -96,7 +101,7 @@ class TunerSession extends ITuner.Stub {
checkNotClosedLocked();
mDummyConfig = Objects.requireNonNull(config);
Slog.i(TAG, "Ignoring setConfiguration - not applicable for broadcastradio HAL 2.x");
- TunerCallback.dispatch(() -> mCallback.mClientCb.onConfigurationChanged(config));
+ mModule.fanoutAidlCallback(cb -> cb.onConfigurationChanged(config));
}
}
@@ -174,7 +179,7 @@ class TunerSession extends ITuner.Stub {
@Override
public boolean startBackgroundScan() {
Slog.i(TAG, "Explicit background scan trigger is not supported with HAL 2.x");
- TunerCallback.dispatch(() -> mCallback.mClientCb.onBackgroundScanComplete());
+ mModule.fanoutAidlCallback(cb -> cb.onBackgroundScanComplete());
return true;
}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 2a91b4f5eef0..cec4d693ad32 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -1846,6 +1846,7 @@ public class InputManagerService extends IInputManager.Stub
// Native callback.
private void onPointerDownOutsideFocus(IBinder touchedToken) {
+ mWindowManagerCallbacks.onPointerDownOutsideFocus(touchedToken);
}
// Native callback.
@@ -2060,6 +2061,14 @@ public class InputManagerService extends IInputManager.Stub
public int getPointerLayer();
public int getPointerDisplayId();
+
+ /**
+ * Notifies window manager that a {@link android.view.MotionEvent#ACTION_DOWN} pointer event
+ * occurred on a window that did not have focus.
+ *
+ * @param touchedToken The token for the window that received the input event.
+ */
+ void onPointerDownOutsideFocus(IBinder touchedToken);
}
/**
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index f24a3b46950d..e62714e7b5fe 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -476,6 +476,7 @@ public class PackageManagerService extends IPackageManager.Stub
static final int SCAN_AS_VENDOR = 1 << 20;
static final int SCAN_AS_PRODUCT = 1 << 21;
static final int SCAN_AS_PRODUCT_SERVICES = 1 << 22;
+ static final int SCAN_AS_ODM = 1 << 23;
@IntDef(flag = true, prefix = { "SCAN_" }, value = {
SCAN_NO_DEX,
@@ -594,6 +595,8 @@ public class PackageManagerService extends IPackageManager.Stub
private static final String PRODUCT_SERVICES_OVERLAY_DIR = "/product_services/overlay";
+ private static final String ODM_OVERLAY_DIR = "/odm/overlay";
+
/** Canonical intent used to identify what counts as a "web browser" app */
private static final Intent sBrowserIntent;
static {
@@ -2523,6 +2526,13 @@ public class PackageManagerService extends IPackageManager.Stub
| SCAN_AS_SYSTEM
| SCAN_AS_PRODUCT_SERVICES,
0);
+ scanDirTracedLI(new File(ODM_OVERLAY_DIR),
+ mDefParseFlags
+ | PackageParser.PARSE_IS_SYSTEM_DIR,
+ scanFlags
+ | SCAN_AS_SYSTEM
+ | SCAN_AS_ODM,
+ 0);
mParallelPackageParserCallback.findStaticOverlayPackages();
@@ -3226,6 +3236,8 @@ public class PackageManagerService extends IPackageManager.Stub
// once we have a booted system.
mInstaller.setWarnIfHeld(mPackages);
+ PackageParser.readConfigUseRoundIcon(mContext.getResources());
+
mServiceStartWithDelay = SystemClock.uptimeMillis() + (60 * 1000L);
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
@@ -10399,6 +10411,7 @@ public class PackageManagerService extends IPackageManager.Stub
* <li>{@link #SCAN_AS_PRODUCT_SERVICES}</li>
* <li>{@link #SCAN_AS_INSTANT_APP}</li>
* <li>{@link #SCAN_AS_VIRTUAL_PRELOAD}</li>
+ * <li>{@link #SCAN_AS_ODM}</li>
* </ul>
*/
private @ScanFlags int adjustScanFlags(@ScanFlags int scanFlags,
@@ -10435,6 +10448,10 @@ public class PackageManagerService extends IPackageManager.Stub
& ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES) != 0) {
scanFlags |= SCAN_AS_PRODUCT_SERVICES;
}
+ if ((systemPkgSetting.pkgPrivateFlags
+ & ApplicationInfo.PRIVATE_FLAG_ODM) != 0) {
+ scanFlags |= SCAN_AS_ODM;
+ }
}
if (pkgSetting != null) {
final int userId = ((user == null) ? 0 : user.getIdentifier());
@@ -11206,6 +11223,10 @@ public class PackageManagerService extends IPackageManager.Stub
pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES;
}
+ if ((scanFlags & SCAN_AS_ODM) != 0) {
+ pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_ODM;
+ }
+
// Check if the package is signed with the same key as the platform package.
if (PLATFORM_PACKAGE_NAME.equals(pkg.packageName) ||
(platformPkg != null && compareSignatures(
@@ -11532,17 +11553,44 @@ public class PackageManagerService extends IPackageManager.Stub
" is static but not pre-installed.");
}
- // The only case where we allow installation of a non-system overlay is when
- // its signature is signed with the platform certificate.
- PackageSetting platformPkgSetting = mSettings.getPackageLPr("android");
- if ((platformPkgSetting.signatures.mSigningDetails
- != PackageParser.SigningDetails.UNKNOWN)
- && (compareSignatures(
- platformPkgSetting.signatures.mSigningDetails.signatures,
- pkg.mSigningDetails.signatures)
- != PackageManager.SIGNATURE_MATCH)) {
- throw new PackageManagerException("Overlay " + pkg.packageName +
- " must be signed with the platform certificate.");
+ // A non-preloaded overlay packages must have targetSdkVersion >= Q, or be
+ // signed with the platform certificate. Check this in increasing order of
+ // computational cost.
+ if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.Q) {
+ final PackageSetting platformPkgSetting =
+ mSettings.getPackageLPr("android");
+ if ((platformPkgSetting.signatures.mSigningDetails
+ != PackageParser.SigningDetails.UNKNOWN)
+ && (compareSignatures(
+ platformPkgSetting.signatures.mSigningDetails.signatures,
+ pkg.mSigningDetails.signatures)
+ != PackageManager.SIGNATURE_MATCH)) {
+ throw new PackageManagerException("Overlay " + pkg.packageName
+ + " must target Q or later, "
+ + "or be signed with the platform certificate");
+ }
+ }
+
+ // A non-preloaded overlay package, without <overlay android:targetName>, will
+ // only be used if it is signed with the same certificate as its target. If the
+ // target is already installed, check this here to augment the last line of
+ // defence which is OMS.
+ if (pkg.mOverlayTargetName == null) {
+ final PackageSetting targetPkgSetting =
+ mSettings.getPackageLPr(pkg.mOverlayTarget);
+ if (targetPkgSetting != null) {
+ if ((targetPkgSetting.signatures.mSigningDetails
+ != PackageParser.SigningDetails.UNKNOWN)
+ && (compareSignatures(
+ targetPkgSetting.signatures.mSigningDetails.signatures,
+ pkg.mSigningDetails.signatures)
+ != PackageManager.SIGNATURE_MATCH)) {
+ throw new PackageManagerException("Overlay " + pkg.packageName
+ + " and target " + pkg.mOverlayTarget + " signed with"
+ + " different certificates, and the overlay lacks"
+ + " <overlay android:targetName>");
+ }
+ }
}
}
}
@@ -12128,6 +12176,8 @@ public class PackageManagerService extends IPackageManager.Stub
codeRoot = Environment.getProductDirectory();
} else if (FileUtils.contains(Environment.getProductServicesDirectory(), codePath)) {
codeRoot = Environment.getProductServicesDirectory();
+ } else if (FileUtils.contains(Environment.getOdmDirectory(), codePath)) {
+ codeRoot = Environment.getOdmDirectory();
} else {
// Unrecognized code path; take its top real segment as the apk root:
// e.g. /something/app/blah.apk => /something
@@ -17215,13 +17265,15 @@ public class PackageManagerService extends IPackageManager.Stub
final boolean oem = isOemApp(oldPackage);
final boolean vendor = isVendorApp(oldPackage);
final boolean product = isProductApp(oldPackage);
+ final boolean odm = isOdmApp(oldPackage);
final @ParseFlags int systemParseFlags = parseFlags;
final @ScanFlags int systemScanFlags = scanFlags
| SCAN_AS_SYSTEM
| (privileged ? SCAN_AS_PRIVILEGED : 0)
| (oem ? SCAN_AS_OEM : 0)
| (vendor ? SCAN_AS_VENDOR : 0)
- | (product ? SCAN_AS_PRODUCT : 0);
+ | (product ? SCAN_AS_PRODUCT : 0)
+ | (odm ? SCAN_AS_ODM : 0);
if (DEBUG_INSTALL) {
Slog.d(TAG, "replaceSystemPackageLI: new=" + pkg
@@ -17552,6 +17604,10 @@ public class PackageManagerService extends IPackageManager.Stub
& ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES) != 0;
}
+ private static boolean isOdmApp(PackageParser.Package pkg) {
+ return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_ODM) != 0;
+ }
+
private static boolean hasDomainURLs(PackageParser.Package pkg) {
return (pkg.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS) != 0;
}
@@ -18326,6 +18382,15 @@ public class PackageManagerService extends IPackageManager.Stub
return false;
}
+ static boolean locationIsOdm(String path) {
+ try {
+ return path.startsWith(Environment.getOdmDirectory().getCanonicalPath() + "/");
+ } catch (IOException e) {
+ Slog.e(TAG, "Unable to access code path " + path);
+ }
+ return false;
+ }
+
/*
* Tries to delete system package.
*/
@@ -18439,6 +18504,9 @@ public class PackageManagerService extends IPackageManager.Stub
if (locationIsProductServices(codePathString)) {
scanFlags |= SCAN_AS_PRODUCT_SERVICES;
}
+ if (locationIsOdm(codePathString)) {
+ scanFlags |= SCAN_AS_ODM;
+ }
final File codePath = new File(codePathString);
final PackageParser.Package pkg =
@@ -20841,6 +20909,7 @@ public class PackageManagerService extends IPackageManager.Stub
mContext.getContentResolver(),
android.provider.Settings.Global.COMPATIBILITY_MODE, 1) == 1;
PackageParser.setCompatibilityModeEnabled(compatibilityModeEnabled);
+
if (DEBUG_SETTINGS) {
Log.d(TAG, "compatibility mode:" + compatibilityModeEnabled);
}
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 2c2cc7ea78f9..ead09b424d61 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -152,6 +152,10 @@ public final class PackageSetting extends PackageSettingBase {
return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES) != 0;
}
+ public boolean isOdm() {
+ return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_ODM) != 0;
+ }
+
public boolean isSystem() {
return (pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0;
}
diff --git a/services/core/java/com/android/server/pm/SettingBase.java b/services/core/java/com/android/server/pm/SettingBase.java
index fbf54391209c..a24818f04f52 100644
--- a/services/core/java/com/android/server/pm/SettingBase.java
+++ b/services/core/java/com/android/server/pm/SettingBase.java
@@ -64,6 +64,7 @@ abstract class SettingBase {
| ApplicationInfo.PRIVATE_FLAG_VENDOR
| ApplicationInfo.PRIVATE_FLAG_PRODUCT
| ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES
- | ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER);
+ | ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER
+ | ApplicationInfo.PRIVATE_FLAG_ODM);
}
}
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index f0f9f723b64a..4f81fd9f7a9f 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -777,7 +777,8 @@ public final class Settings {
| ApplicationInfo.PRIVATE_FLAG_OEM
| ApplicationInfo.PRIVATE_FLAG_VENDOR
| ApplicationInfo.PRIVATE_FLAG_PRODUCT
- | ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES);
+ | ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES
+ | ApplicationInfo.PRIVATE_FLAG_ODM);
pkgSetting.pkgFlags |= pkgFlags & ApplicationInfo.FLAG_SYSTEM;
pkgSetting.pkgPrivateFlags |=
pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
@@ -789,6 +790,8 @@ public final class Settings {
pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT;
pkgSetting.pkgPrivateFlags |=
pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES;
+ pkgSetting.pkgPrivateFlags |=
+ pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_ODM;
pkgSetting.primaryCpuAbiString = primaryCpuAbi;
pkgSetting.secondaryCpuAbiString = secondaryCpuAbi;
if (childPkgNames != null) {
@@ -4420,6 +4423,7 @@ public final class Settings {
ApplicationInfo.PRIVATE_FLAG_PRODUCT, "PRODUCT",
ApplicationInfo.PRIVATE_FLAG_PRODUCT_SERVICES, "PRODUCT_SERVICES",
ApplicationInfo.PRIVATE_FLAG_VIRTUAL_PRELOAD, "VIRTUAL_PRELOAD",
+ ApplicationInfo.PRIVATE_FLAG_ODM, "ODM",
};
void dumpVersionLPr(IndentingPrintWriter pw) {
diff --git a/services/core/java/com/android/server/wm/InputManagerCallback.java b/services/core/java/com/android/server/wm/InputManagerCallback.java
index f46835eb51fc..6b500967f429 100644
--- a/services/core/java/com/android/server/wm/InputManagerCallback.java
+++ b/services/core/java/com/android/server/wm/InputManagerCallback.java
@@ -6,6 +6,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowManagerService.H.ON_POINTER_DOWN_OUTSIDE_FOCUS;
import android.os.Debug;
import android.os.IBinder;
@@ -232,6 +233,11 @@ final class InputManagerCallback implements InputManagerService.WindowManagerCal
}
}
+ @Override
+ public void onPointerDownOutsideFocus(IBinder touchedToken) {
+ mService.mH.obtainMessage(ON_POINTER_DOWN_OUTSIDE_FOCUS, touchedToken).sendToTarget();
+ }
+
/** Waits until the built-in input devices have been configured. */
public boolean waitForInputDevicesReady(long timeoutMillis) {
synchronized (mInputDevicesReadyMonitor) {
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index f85fdb6c3882..d3dba90fe4e6 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -63,6 +63,7 @@ final class InputMonitor {
// When true, need to call updateInputWindowsLw().
private boolean mUpdateInputWindowsNeeded = true;
private boolean mUpdateInputWindowsPending;
+ private boolean mApplyImmediately;
// Currently focused input window handle.
private InputWindowHandle mFocusedInputWindowHandle;
@@ -152,7 +153,7 @@ final class InputMonitor {
mService = service;
mDisplayContent = mService.mRoot.getDisplayContent(displayId);
mDisplayId = displayId;
- mInputTransaction = mDisplayContent.getPendingTransaction();
+ mInputTransaction = mService.mTransactionFactory.make();
mHandler = AnimationThread.getHandler();
mUpdateInputForAllWindowsConsumer = new UpdateInputForAllWindowsConsumer();
}
@@ -319,6 +320,14 @@ final class InputMonitor {
}
}
+ void updateInputWindowsImmediately() {
+ if (mUpdateInputWindowsPending) {
+ mApplyImmediately = true;
+ mUpdateInputWindows.run();
+ mApplyImmediately = false;
+ }
+ }
+
/* Called when the current input focus changes.
* Layer assignment is assumed to be complete by the time this is called.
*/
@@ -433,7 +442,12 @@ final class InputMonitor {
wallpaperInputConsumer.show(mInputTransaction, 0);
}
- mDisplayContent.scheduleAnimation();
+ if (mApplyImmediately) {
+ mInputTransaction.apply();
+ } else {
+ mDisplayContent.getPendingTransaction().merge(mInputTransaction);
+ mDisplayContent.scheduleAnimation();
+ }
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index f1560d961209..144efb49e84a 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -17,8 +17,6 @@
package com.android.server.wm;
import static android.app.ActivityManager.START_TASK_TO_FRONT;
-import static android.app.AppOpsManager.OP_ASSIST_STRUCTURE;
-import static android.app.AppOpsManager.OP_NONE;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
@@ -34,25 +32,16 @@ import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_T
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RECENTS_ANIMATIONS;
import android.app.ActivityOptions;
-import android.app.AppOpsManager;
import android.app.IAssistDataReceiver;
import android.content.ComponentName;
-import android.content.Context;
import android.content.Intent;
-import android.os.Bundle;
-import android.os.IBinder;
import android.os.RemoteException;
import android.os.Trace;
import android.util.Slog;
import android.view.IRecentsAnimationRunner;
-import com.android.server.LocalServices;
-import com.android.server.am.AssistDataRequester;
-import com.android.server.contentcapture.ContentCaptureManagerInternal;
import com.android.server.wm.RecentsAnimationController.RecentsAnimationCallbacks;
-import java.util.List;
-
/**
* Manages the recents animation, including the reordering of the stacks for the transition and
* cleanup. See {@link com.android.server.wm.RecentsAnimationController}.
@@ -70,7 +59,6 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
private final int mCallingPid;
private int mTargetActivityType;
- private AssistDataRequester mAssistDataRequester;
// The stack to restore the target stack behind when the animation is finished
private ActivityStack mRestoreTargetBehindStack;
@@ -135,9 +123,6 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
mWindowManager.deferSurfaceLayout();
try {
- // Kick off the assist data request in the background before showing the target activity
- requestAssistData(recentsComponent, recentsUid, assistDataReceiver);
-
if (hasExistingActivity) {
// Move the recents activity into place for the animation if it is not top most
mDefaultDisplay.moveStackBehindBottomMostVisibleStack(targetStack);
@@ -216,78 +201,12 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
}
}
- /**
- * Requests assist data for the top visible activities.
- */
- private void requestAssistData(ComponentName recentsComponent, int recentsUid,
- @Deprecated IAssistDataReceiver assistDataReceiver) {
- final AppOpsManager appOpsManager = (AppOpsManager)
- mService.mContext.getSystemService(Context.APP_OPS_SERVICE);
- final List<IBinder> topActivities =
- mService.mRootActivityContainer.getTopVisibleActivities();
- final AssistDataRequester.AssistDataRequesterCallbacks assistDataCallbacks;
- if (assistDataReceiver != null) {
- assistDataCallbacks = new AssistDataReceiverProxy(assistDataReceiver,
- recentsComponent.getPackageName()) {
- @Override
- public void onAssistDataReceivedLocked(Bundle data, int activityIndex,
- int activityCount) {
- // Try to notify the intelligence service first
- final ContentCaptureManagerInternal imService =
- LocalServices.getService(ContentCaptureManagerInternal.class);
- final IBinder activityToken = topActivities.get(activityIndex);
- final ActivityRecord r = ActivityRecord.forTokenLocked(activityToken);
- if (r != null && (imService == null
- || !imService.sendActivityAssistData(r.mUserId, activityToken, data))) {
- // Otherwise, use the provided assist data receiver
- super.onAssistDataReceivedLocked(data, activityIndex, activityCount);
- }
- }
- };
- } else {
- final ContentCaptureManagerInternal imService =
- LocalServices.getService(ContentCaptureManagerInternal.class);
- if (imService == null) {
- // There is no intelligence service, so there is no point requesting assist data
- return;
- }
-
- assistDataCallbacks = new AssistDataRequester.AssistDataRequesterCallbacks() {
- @Override
- public boolean canHandleReceivedAssistDataLocked() {
- return true;
- }
-
- @Override
- public void onAssistDataReceivedLocked(Bundle data, int activityIndex,
- int activityCount) {
- // Try to notify the intelligence service
- final IBinder activityToken = topActivities.get(activityIndex);
- final ActivityRecord r = ActivityRecord.forTokenLocked(activityToken);
- if (r != null) {
- imService.sendActivityAssistData(r.mUserId, activityToken, data);
- }
- }
- };
- }
- mAssistDataRequester = new AssistDataRequester(mService.mContext, mWindowManager,
- appOpsManager, assistDataCallbacks, this, OP_ASSIST_STRUCTURE, OP_NONE);
- mAssistDataRequester.requestAutofillData(topActivities,
- recentsUid, recentsComponent.getPackageName());
- }
-
private void finishAnimation(@RecentsAnimationController.ReorderMode int reorderMode) {
synchronized (mService.mGlobalLock) {
if (DEBUG) Slog.d(TAG, "onAnimationFinished(): controller="
+ mWindowManager.getRecentsAnimationController()
+ " reorderMode=" + reorderMode);
- // Cancel the associated assistant data request
- if (mAssistDataRequester != null) {
- mAssistDataRequester.cancel();
- mAssistDataRequester = null;
- }
-
// Unregister for stack order changes
mDefaultDisplay.unregisterStackOrderChangedListener(this);
diff --git a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
index 4ff552ec3c91..79baab6bfbb6 100644
--- a/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
+++ b/services/core/java/com/android/server/wm/TaskTapPointerEventListener.java
@@ -22,12 +22,9 @@ import static android.view.PointerIcon.TYPE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW;
import static android.view.PointerIcon.TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW;
import static android.view.PointerIcon.TYPE_VERTICAL_DOUBLE_ARROW;
-import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
-
import android.graphics.Rect;
import android.graphics.Region;
import android.hardware.input.InputManager;
-import android.os.Handler;
import android.view.MotionEvent;
import android.view.WindowManagerPolicyConstants.PointerEventListener;
@@ -40,67 +37,15 @@ import com.android.server.wm.WindowManagerService.H;
public class TaskTapPointerEventListener implements PointerEventListener {
private final Region mTouchExcludeRegion = new Region();
- private final Region mTmpRegion = new Region();
private final WindowManagerService mService;
private final DisplayContent mDisplayContent;
- private final Handler mHandler;
- private final Runnable mMoveDisplayToTop;
private final Rect mTmpRect = new Rect();
private int mPointerIconType = TYPE_NOT_SPECIFIED;
- private int mLastDownX;
- private int mLastDownY;
public TaskTapPointerEventListener(WindowManagerService service,
DisplayContent displayContent) {
mService = service;
mDisplayContent = displayContent;
- mHandler = new Handler(mService.mH.getLooper());
- mMoveDisplayToTop = () -> {
- int x;
- int y;
- synchronized (this) {
- x = mLastDownX;
- y = mLastDownY;
- }
- synchronized (mService.mGlobalLock) {
- if (!mService.mPerDisplayFocusEnabled
- && mService.mRoot.getTopFocusedDisplayContent() != mDisplayContent
- && inputMethodWindowContains(x, y)) {
- // In a single focus system, if the input method window and the input method
- // target window are on the different displays, when the user is tapping on the
- // input method window, we don't move its display to top. Otherwise, the input
- // method target window will lose the focus.
- return;
- }
- final Region windowTapExcludeRegion = Region.obtain();
- mDisplayContent.amendWindowTapExcludeRegion(windowTapExcludeRegion);
- if (windowTapExcludeRegion.contains(x, y)) {
- windowTapExcludeRegion.recycle();
- // The user is tapping on the window tap exclude region. We don't move this
- // display to top. A window tap exclude region, for example, may be set by an
- // ActivityView, and the region would match the bounds of both the ActivityView
- // and the virtual display in it. In this case, we would take the tap that is on
- // the embedded virtual display instead of this display.
- return;
- }
- windowTapExcludeRegion.recycle();
- WindowContainer parent = mDisplayContent.getParent();
- if (parent != null && parent.getTopChild() != mDisplayContent) {
- parent.positionChildAt(WindowContainer.POSITION_TOP, mDisplayContent,
- true /* includingParents */);
- // For compatibility, only the topmost activity is allowed to be resumed for
- // pre-Q app. Ensure the topmost activities are resumed whenever a display is
- // moved to top.
- // TODO(b/123761773): Investigate whether we can move this into
- // RootActivityContainer#updateTopResumedActivityIfNeeded(). Currently, it is
- // risky to do so because it seems possible to resume activities as part of a
- // larger transaction and it's too early to resume based on current order
- // when performing updateTopResumedActivityIfNeeded().
- mDisplayContent.mAcitvityDisplay.ensureActivitiesVisible(null /* starting */,
- 0 /* configChanges */, !PRESERVE_WINDOWS, true /* notifyClients */);
- }
- }
- };
}
@Override
@@ -115,9 +60,6 @@ public class TaskTapPointerEventListener implements PointerEventListener {
mService.mTaskPositioningController.handleTapOutsideTask(
mDisplayContent, x, y);
}
- mLastDownX = x;
- mLastDownY = y;
- mHandler.post(mMoveDisplayToTop);
}
}
break;
@@ -178,17 +120,4 @@ public class TaskTapPointerEventListener implements PointerEventListener {
mTouchExcludeRegion.set(newRegion);
}
}
-
- private int getDisplayId() {
- return mDisplayContent.getDisplayId();
- }
-
- private boolean inputMethodWindowContains(int x, int y) {
- final WindowState inputMethodWindow = mDisplayContent.mInputMethodWindow;
- if (inputMethodWindow == null || !inputMethodWindow.isVisibleLw()) {
- return false;
- }
- inputMethodWindow.getTouchableRegion(mTmpRegion);
- return mTmpRegion.contains(x, y);
- }
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 20d02ee5355e..8dfb02efb526 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -73,6 +73,7 @@ import static com.android.internal.util.LatencyTracker.ACTION_ROTATE_SCREEN;
import static com.android.server.LockGuard.INDEX_WINDOW;
import static com.android.server.LockGuard.installLock;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_BOOT;
@@ -4519,6 +4520,7 @@ public class WindowManagerService extends IWindowManager.Stub
public static final int SET_RUNNING_REMOTE_ANIMATION = 59;
public static final int ANIMATION_FAILSAFE = 60;
public static final int RECOMPUTE_FOCUS = 61;
+ public static final int ON_POINTER_DOWN_OUTSIDE_FOCUS = 62;
/**
* Used to denote that an integer field in a message will not be used.
@@ -4910,6 +4912,13 @@ public class WindowManagerService extends IWindowManager.Stub
}
break;
}
+ case ON_POINTER_DOWN_OUTSIDE_FOCUS: {
+ synchronized (mGlobalLock) {
+ final IBinder touchedToken = (IBinder) msg.obj;
+ onPointerDownOutsideFocusLocked(touchedToken);
+ }
+ break;
+ }
}
if (DEBUG_WINDOW_TRACE) {
Slog.v(TAG_WM, "handleMessage: exit");
@@ -7522,22 +7531,24 @@ public class WindowManagerService extends IWindowManager.Stub
@Override
public boolean injectInputAfterTransactionsApplied(InputEvent ev, int mode) {
- boolean shouldWaitForAnimComplete = false;
+ boolean shouldWaitForAnimToComplete = false;
if (ev instanceof KeyEvent) {
KeyEvent keyEvent = (KeyEvent) ev;
- shouldWaitForAnimComplete = keyEvent.getSource() == InputDevice.SOURCE_MOUSE
+ shouldWaitForAnimToComplete = keyEvent.getSource() == InputDevice.SOURCE_MOUSE
|| keyEvent.getAction() == KeyEvent.ACTION_DOWN;
} else if (ev instanceof MotionEvent) {
MotionEvent motionEvent = (MotionEvent) ev;
- shouldWaitForAnimComplete = motionEvent.getSource() == InputDevice.SOURCE_MOUSE
+ shouldWaitForAnimToComplete = motionEvent.getSource() == InputDevice.SOURCE_MOUSE
|| motionEvent.getAction() == MotionEvent.ACTION_DOWN;
}
- if (shouldWaitForAnimComplete) {
+ if (shouldWaitForAnimToComplete) {
waitForAnimationsToComplete();
synchronized (mGlobalLock) {
mWindowPlacerLocked.performSurfacePlacementIfScheduled();
+ mRoot.forAllDisplays(displayContent ->
+ displayContent.getInputMonitor().updateInputWindowsImmediately());
}
new SurfaceControl.Transaction().syncInputWindows().apply(true);
@@ -7569,4 +7580,37 @@ public class WindowManagerService extends IWindowManager.Stub
mGlobalLock.notifyAll();
}
}
+
+ private void onPointerDownOutsideFocusLocked(IBinder touchedToken) {
+ final WindowState touchedWindow = windowForClientLocked(null, touchedToken, false);
+ if (touchedWindow == null) {
+ return;
+ }
+
+ final DisplayContent displayContent = touchedWindow.getDisplayContent();
+ if (displayContent == null) {
+ return;
+ }
+
+ if (!touchedWindow.canReceiveKeys()) {
+ // If the window that received the input event cannot receive keys, don't move the
+ // display it's on to the top since that window won't be able to get focus anyway.
+ return;
+ }
+
+ final WindowContainer parent = displayContent.getParent();
+ if (parent != null && parent.getTopChild() != displayContent) {
+ parent.positionChildAt(WindowContainer.POSITION_TOP, displayContent,
+ true /* includingParents */);
+ // For compatibility, only the topmost activity is allowed to be resumed for pre-Q
+ // app. Ensure the topmost activities are resumed whenever a display is moved to top.
+ // TODO(b/123761773): Investigate whether we can move this into
+ // RootActivityContainer#updateTopResumedActivityIfNeeded(). Currently, it is risky
+ // to do so because it seems possible to resume activities as part of a larger
+ // transaction and it's too early to resume based on current order when performing
+ // updateTopResumedActivityIfNeeded().
+ displayContent.mAcitvityDisplay.ensureActivitiesVisible(null /* starting */,
+ 0 /* configChanges */, !PRESERVE_WINDOWS, true /* notifyClients */);
+ }
+ }
}
diff --git a/services/net/Android.bp b/services/net/Android.bp
index 8f48f5b3d292..f73a285c1a94 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -59,6 +59,7 @@ java_library_static {
srcs: ["java/**/*.java"],
static_libs: [
"dnsresolver_aidl_interface-java",
+ "ipmemorystore-client",
"netd_aidl_interface-java",
"networkstack-aidl-interfaces-java",
]
diff --git a/services/net/java/android/net/IIpMemoryStore.aidl b/services/net/java/android/net/IIpMemoryStore.aidl
index 6f88dec8dee9..63feae65756f 100644
--- a/services/net/java/android/net/IIpMemoryStore.aidl
+++ b/services/net/java/android/net/IIpMemoryStore.aidl
@@ -20,8 +20,8 @@ import android.net.ipmemorystore.Blob;
import android.net.ipmemorystore.NetworkAttributesParcelable;
import android.net.ipmemorystore.IOnBlobRetrievedListener;
import android.net.ipmemorystore.IOnL2KeyResponseListener;
-import android.net.ipmemorystore.IOnNetworkAttributesRetrieved;
-import android.net.ipmemorystore.IOnSameNetworkResponseListener;
+import android.net.ipmemorystore.IOnNetworkAttributesRetrievedListener;
+import android.net.ipmemorystore.IOnSameL3NetworkResponseListener;
import android.net.ipmemorystore.IOnStatusListener;
/** {@hide} */
@@ -84,7 +84,7 @@ oneway interface IIpMemoryStore {
* @param listener The listener that will be invoked to return the answer.
* @return (through the listener) A SameL3NetworkResponse containing the answer and confidence.
*/
- void isSameNetwork(String l2Key1, String l2Key2, IOnSameNetworkResponseListener listener);
+ void isSameNetwork(String l2Key1, String l2Key2, IOnSameL3NetworkResponseListener listener);
/**
* Retrieve the network attributes for a key.
@@ -95,7 +95,7 @@ oneway interface IIpMemoryStore {
* @return (through the listener) The network attributes and the L2 key associated with
* the query.
*/
- void retrieveNetworkAttributes(String l2Key, IOnNetworkAttributesRetrieved listener);
+ void retrieveNetworkAttributes(String l2Key, IOnNetworkAttributesRetrievedListener listener);
/**
* Retrieve previously stored private data.
diff --git a/services/net/java/android/net/IpMemoryStoreClient.java b/services/net/java/android/net/IpMemoryStoreClient.java
index 2f4fdbd8a4a7..379c017b2990 100644
--- a/services/net/java/android/net/IpMemoryStoreClient.java
+++ b/services/net/java/android/net/IpMemoryStoreClient.java
@@ -20,14 +20,13 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.net.ipmemorystore.Blob;
-import android.net.ipmemorystore.IOnBlobRetrievedListener;
-import android.net.ipmemorystore.IOnL2KeyResponseListener;
-import android.net.ipmemorystore.IOnNetworkAttributesRetrieved;
-import android.net.ipmemorystore.IOnSameNetworkResponseListener;
-import android.net.ipmemorystore.IOnStatusListener;
import android.net.ipmemorystore.NetworkAttributes;
+import android.net.ipmemorystore.OnBlobRetrievedListener;
+import android.net.ipmemorystore.OnL2KeyResponseListener;
+import android.net.ipmemorystore.OnNetworkAttributesRetrievedListener;
+import android.net.ipmemorystore.OnSameL3NetworkResponseListener;
+import android.net.ipmemorystore.OnStatusListener;
import android.net.ipmemorystore.Status;
-import android.net.ipmemorystore.StatusParcelable;
import android.os.RemoteException;
import android.util.Log;
@@ -50,12 +49,6 @@ public abstract class IpMemoryStoreClient {
@NonNull
protected abstract IIpMemoryStore getService() throws InterruptedException, ExecutionException;
- protected StatusParcelable internalErrorStatus() {
- final StatusParcelable error = new StatusParcelable();
- error.resultCode = Status.ERROR_UNKNOWN;
- return error;
- }
-
/**
* Store network attributes for a given L2 key.
* If L2Key is null, choose automatically from the attributes ; passing null is equivalent to
@@ -74,12 +67,13 @@ public abstract class IpMemoryStoreClient {
*/
public void storeNetworkAttributes(@NonNull final String l2Key,
@NonNull final NetworkAttributes attributes,
- @Nullable final IOnStatusListener listener) {
+ @Nullable final OnStatusListener listener) {
try {
try {
- getService().storeNetworkAttributes(l2Key, attributes.toParcelable(), listener);
+ getService().storeNetworkAttributes(l2Key, attributes.toParcelable(),
+ OnStatusListener.toAIDL(listener));
} catch (InterruptedException | ExecutionException m) {
- listener.onComplete(internalErrorStatus());
+ listener.onComplete(new Status(Status.ERROR_UNKNOWN));
}
} catch (RemoteException e) {
Log.e(TAG, "Error storing network attributes", e);
@@ -99,12 +93,13 @@ public abstract class IpMemoryStoreClient {
*/
public void storeBlob(@NonNull final String l2Key, @NonNull final String clientId,
@NonNull final String name, @NonNull final Blob data,
- @Nullable final IOnStatusListener listener) {
+ @Nullable final OnStatusListener listener) {
try {
try {
- getService().storeBlob(l2Key, clientId, name, data, listener);
+ getService().storeBlob(l2Key, clientId, name, data,
+ OnStatusListener.toAIDL(listener));
} catch (InterruptedException | ExecutionException m) {
- listener.onComplete(internalErrorStatus());
+ listener.onComplete(new Status(Status.ERROR_UNKNOWN));
}
} catch (RemoteException e) {
Log.e(TAG, "Error storing blob", e);
@@ -126,12 +121,13 @@ public abstract class IpMemoryStoreClient {
* Through the listener, returns the L2 key if one matched, or null.
*/
public void findL2Key(@NonNull final NetworkAttributes attributes,
- @NonNull final IOnL2KeyResponseListener listener) {
+ @NonNull final OnL2KeyResponseListener listener) {
try {
try {
- getService().findL2Key(attributes.toParcelable(), listener);
+ getService().findL2Key(attributes.toParcelable(),
+ OnL2KeyResponseListener.toAIDL(listener));
} catch (InterruptedException | ExecutionException m) {
- listener.onL2KeyResponse(internalErrorStatus(), null);
+ listener.onL2KeyResponse(new Status(Status.ERROR_UNKNOWN), null);
}
} catch (RemoteException e) {
Log.e(TAG, "Error finding L2 Key", e);
@@ -148,12 +144,13 @@ public abstract class IpMemoryStoreClient {
* Through the listener, a SameL3NetworkResponse containing the answer and confidence.
*/
public void isSameNetwork(@NonNull final String l2Key1, @NonNull final String l2Key2,
- @NonNull final IOnSameNetworkResponseListener listener) {
+ @NonNull final OnSameL3NetworkResponseListener listener) {
try {
try {
- getService().isSameNetwork(l2Key1, l2Key2, listener);
+ getService().isSameNetwork(l2Key1, l2Key2,
+ OnSameL3NetworkResponseListener.toAIDL(listener));
} catch (InterruptedException | ExecutionException m) {
- listener.onSameNetworkResponse(internalErrorStatus(), null);
+ listener.onSameL3NetworkResponse(new Status(Status.ERROR_UNKNOWN), null);
}
} catch (RemoteException e) {
Log.e(TAG, "Error checking for network sameness", e);
@@ -170,12 +167,13 @@ public abstract class IpMemoryStoreClient {
* the query.
*/
public void retrieveNetworkAttributes(@NonNull final String l2Key,
- @NonNull final IOnNetworkAttributesRetrieved listener) {
+ @NonNull final OnNetworkAttributesRetrievedListener listener) {
try {
try {
- getService().retrieveNetworkAttributes(l2Key, listener);
+ getService().retrieveNetworkAttributes(l2Key,
+ OnNetworkAttributesRetrievedListener.toAIDL(listener));
} catch (InterruptedException | ExecutionException m) {
- listener.onNetworkAttributesRetrieved(internalErrorStatus(), null, null);
+ listener.onNetworkAttributesRetrieved(new Status(Status.ERROR_UNKNOWN), null, null);
}
} catch (RemoteException e) {
Log.e(TAG, "Error retrieving network attributes", e);
@@ -194,12 +192,13 @@ public abstract class IpMemoryStoreClient {
* and the name of the data associated with the query.
*/
public void retrieveBlob(@NonNull final String l2Key, @NonNull final String clientId,
- @NonNull final String name, @NonNull final IOnBlobRetrievedListener listener) {
+ @NonNull final String name, @NonNull final OnBlobRetrievedListener listener) {
try {
try {
- getService().retrieveBlob(l2Key, clientId, name, listener);
+ getService().retrieveBlob(l2Key, clientId, name,
+ OnBlobRetrievedListener.toAIDL(listener));
} catch (InterruptedException | ExecutionException m) {
- listener.onBlobRetrieved(internalErrorStatus(), null, null, null);
+ listener.onBlobRetrieved(new Status(Status.ERROR_UNKNOWN), null, null, null);
}
} catch (RemoteException e) {
Log.e(TAG, "Error retrieving blob", e);
diff --git a/services/net/java/android/net/ipmemorystore/IOnNetworkAttributesRetrieved.aidl b/services/net/java/android/net/ipmemorystore/IOnNetworkAttributesRetrievedListener.aidl
index fb4ca3b97895..870e217eb5b7 100644
--- a/services/net/java/android/net/ipmemorystore/IOnNetworkAttributesRetrieved.aidl
+++ b/services/net/java/android/net/ipmemorystore/IOnNetworkAttributesRetrievedListener.aidl
@@ -20,7 +20,7 @@ import android.net.ipmemorystore.NetworkAttributesParcelable;
import android.net.ipmemorystore.StatusParcelable;
/** {@hide} */
-oneway interface IOnNetworkAttributesRetrieved {
+oneway interface IOnNetworkAttributesRetrievedListener {
/**
* Network attributes were fetched for the specified L2 key. While the L2 key will never
* be null, the attributes may be if no data is stored about this L2 key.
diff --git a/services/net/java/android/net/ipmemorystore/IOnSameNetworkResponseListener.aidl b/services/net/java/android/net/ipmemorystore/IOnSameL3NetworkResponseListener.aidl
index 294bd3bd4012..b8ccfb99fddd 100644
--- a/services/net/java/android/net/ipmemorystore/IOnSameNetworkResponseListener.aidl
+++ b/services/net/java/android/net/ipmemorystore/IOnSameL3NetworkResponseListener.aidl
@@ -20,10 +20,10 @@ import android.net.ipmemorystore.SameL3NetworkResponseParcelable;
import android.net.ipmemorystore.StatusParcelable;
/** {@hide} */
-oneway interface IOnSameNetworkResponseListener {
+oneway interface IOnSameL3NetworkResponseListener {
/**
* The memory store has come up with the answer to a query that was sent.
*/
- void onSameNetworkResponse(in StatusParcelable status,
+ void onSameL3NetworkResponse(in StatusParcelable status,
in SameL3NetworkResponseParcelable response);
}
diff --git a/services/net/java/android/net/ipmemorystore/OnBlobRetrievedListener.java b/services/net/java/android/net/ipmemorystore/OnBlobRetrievedListener.java
new file mode 100644
index 000000000000..9685ff6dd3ca
--- /dev/null
+++ b/services/net/java/android/net/ipmemorystore/OnBlobRetrievedListener.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.ipmemorystore;
+
+import android.annotation.NonNull;
+
+/**
+ * A listener for the IpMemoryStore to return a blob.
+ * @hide
+ */
+public interface OnBlobRetrievedListener {
+ /**
+ * The memory store has come up with the answer to a query that was sent.
+ */
+ void onBlobRetrieved(Status status, String l2Key, String name, Blob blob);
+
+ /** Converts this OnBlobRetrievedListener to a parcelable object */
+ @NonNull
+ static IOnBlobRetrievedListener toAIDL(final OnBlobRetrievedListener listener) {
+ return new IOnBlobRetrievedListener.Stub() {
+ @Override
+ public void onBlobRetrieved(final StatusParcelable statusParcelable, final String l2Key,
+ final String name, final Blob blob) {
+ listener.onBlobRetrieved(new Status(statusParcelable), l2Key, name, blob);
+ }
+ };
+ }
+}
diff --git a/services/net/java/android/net/ipmemorystore/OnL2KeyResponseListener.java b/services/net/java/android/net/ipmemorystore/OnL2KeyResponseListener.java
new file mode 100644
index 000000000000..80209c574203
--- /dev/null
+++ b/services/net/java/android/net/ipmemorystore/OnL2KeyResponseListener.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.ipmemorystore;
+
+import android.annotation.NonNull;
+
+/**
+ * A listener for the IpMemoryStore to return a L2 key.
+ * @hide
+ */
+public interface OnL2KeyResponseListener {
+ /**
+ * The operation has completed with the specified status.
+ */
+ void onL2KeyResponse(Status status, String l2Key);
+
+ /** Converts this OnL2KeyResponseListener to a parcelable object */
+ @NonNull
+ static IOnL2KeyResponseListener toAIDL(final OnL2KeyResponseListener listener) {
+ return new IOnL2KeyResponseListener.Stub() {
+ @Override
+ public void onL2KeyResponse(final StatusParcelable statusParcelable,
+ final String l2Key) {
+ listener.onL2KeyResponse(new Status(statusParcelable), l2Key);
+ }
+ };
+ }
+}
diff --git a/services/net/java/android/net/ipmemorystore/OnNetworkAttributesRetrievedListener.java b/services/net/java/android/net/ipmemorystore/OnNetworkAttributesRetrievedListener.java
new file mode 100644
index 000000000000..f0f6f4016139
--- /dev/null
+++ b/services/net/java/android/net/ipmemorystore/OnNetworkAttributesRetrievedListener.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.ipmemorystore;
+
+import android.annotation.NonNull;
+
+/**
+ * A listener for the IpMemoryStore to return network attributes.
+ * @hide
+ */
+public interface OnNetworkAttributesRetrievedListener {
+ /**
+ * The memory store has come up with the answer to a query that was sent.
+ */
+ void onNetworkAttributesRetrieved(Status status, String l2Key, NetworkAttributes attributes);
+
+ /** Converts this OnNetworkAttributesRetrievedListener to a parcelable object */
+ @NonNull
+ static IOnNetworkAttributesRetrievedListener toAIDL(
+ final OnNetworkAttributesRetrievedListener listener) {
+ return new IOnNetworkAttributesRetrievedListener.Stub() {
+ @Override
+ public void onNetworkAttributesRetrieved(final StatusParcelable statusParcelable,
+ final String l2Key,
+ final NetworkAttributesParcelable networkAttributesParcelable) {
+ listener.onNetworkAttributesRetrieved(
+ new Status(statusParcelable), l2Key,
+ new NetworkAttributes(networkAttributesParcelable));
+ }
+ };
+ }
+}
diff --git a/services/net/java/android/net/ipmemorystore/OnSameL3NetworkResponseListener.java b/services/net/java/android/net/ipmemorystore/OnSameL3NetworkResponseListener.java
new file mode 100644
index 000000000000..ba1e0e6f2b9f
--- /dev/null
+++ b/services/net/java/android/net/ipmemorystore/OnSameL3NetworkResponseListener.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.ipmemorystore;
+
+import android.annotation.NonNull;
+
+/**
+ * A listener for the IpMemoryStore to return a response about network sameness.
+ * @hide
+ */
+public interface OnSameL3NetworkResponseListener {
+ /**
+ * The memory store has come up with the answer to a query that was sent.
+ */
+ void onSameL3NetworkResponse(Status status, SameL3NetworkResponse response);
+
+ /** Converts this OnSameL3NetworkResponseListener to a parcelable object */
+ @NonNull
+ static IOnSameL3NetworkResponseListener toAIDL(final OnSameL3NetworkResponseListener listener) {
+ return new IOnSameL3NetworkResponseListener.Stub() {
+ @Override
+ public void onSameL3NetworkResponse(final StatusParcelable statusParcelable,
+ final SameL3NetworkResponseParcelable sameL3NetworkResponseParcelable) {
+ listener.onSameL3NetworkResponse(
+ new Status(statusParcelable),
+ new SameL3NetworkResponse(sameL3NetworkResponseParcelable));
+ }
+ };
+ }
+}
diff --git a/services/net/java/android/net/ipmemorystore/OnStatusListener.java b/services/net/java/android/net/ipmemorystore/OnStatusListener.java
new file mode 100644
index 000000000000..0de16660ff5f
--- /dev/null
+++ b/services/net/java/android/net/ipmemorystore/OnStatusListener.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.ipmemorystore;
+
+import android.annotation.NonNull;
+
+/**
+ * A listener for the IpMemoryStore to return a status to a client.
+ * @hide
+ */
+public interface OnStatusListener {
+ /**
+ * The operation has completed with the specified status.
+ */
+ void onComplete(Status status);
+
+ /** Converts this OnStatusListener to a parcelable object */
+ @NonNull
+ static IOnStatusListener toAIDL(final OnStatusListener listener) {
+ return new IOnStatusListener.Stub() {
+ @Override
+ public void onComplete(final StatusParcelable statusParcelable) {
+ listener.onComplete(new Status(statusParcelable));
+ }
+ };
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/AppCompactorTest.java b/services/tests/mockingservicestests/src/com/android/server/am/AppCompactorTest.java
index b0c97d1b4f48..475901a75d0d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/AppCompactorTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/AppCompactorTest.java
@@ -25,6 +25,7 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.platform.test.annotations.Presubmit;
import android.provider.DeviceConfig;
+import android.text.TextUtils;
import com.android.server.appop.AppOpsService;
import com.android.server.testables.TestableDeviceConfig;
@@ -38,6 +39,8 @@ import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import java.io.File;
+import java.util.HashSet;
+import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -103,6 +106,22 @@ public final class AppCompactorTest {
AppCompactor.DEFAULT_COMPACT_THROTTLE_4);
assertThat(mCompactorUnderTest.mStatsdSampleRate).isEqualTo(
AppCompactor.DEFAULT_STATSD_SAMPLE_RATE);
+ assertThat(mCompactorUnderTest.mFullAnonRssThrottleKb).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB);
+ assertThat(mCompactorUnderTest.mCompactThrottleBFGS).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_5);
+ assertThat(mCompactorUnderTest.mCompactThrottlePersistent).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_6);
+ assertThat(mCompactorUnderTest.mFullAnonRssThrottleKb).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB);
+ assertThat(mCompactorUnderTest.mFullDeltaRssThrottleKb).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_FULL_DELTA_RSS_THROTTLE_KB);
+
+ Set<Integer> expected = new HashSet<>();
+ for (String s : TextUtils.split(AppCompactor.DEFAULT_COMPACT_PROC_STATE_THROTTLE, ",")) {
+ expected.add(Integer.parseInt(s));
+ }
+ assertThat(mCompactorUnderTest.mProcStateThrottle).containsExactlyElementsIn(expected);
}
@Test
@@ -139,6 +158,14 @@ public final class AppCompactorTest {
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
AppCompactor.KEY_COMPACT_STATSD_SAMPLE_RATE,
Float.toString(AppCompactor.DEFAULT_STATSD_SAMPLE_RATE + 0.1f), false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ AppCompactor.KEY_COMPACT_FULL_RSS_THROTTLE_KB,
+ Long.toString(AppCompactor.DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB + 1), false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ AppCompactor.KEY_COMPACT_FULL_DELTA_RSS_THROTTLE_KB,
+ Long.toString(AppCompactor.DEFAULT_COMPACT_FULL_DELTA_RSS_THROTTLE_KB + 1), false);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ AppCompactor.KEY_COMPACT_PROC_STATE_THROTTLE, "1,2,3", false);
// Then calling init will read and set that flag.
mCompactorUnderTest.init();
@@ -157,12 +184,19 @@ public final class AppCompactorTest {
AppCompactor.DEFAULT_COMPACT_THROTTLE_3 + 1);
assertThat(mCompactorUnderTest.mCompactThrottleFullFull).isEqualTo(
AppCompactor.DEFAULT_COMPACT_THROTTLE_4 + 1);
+ assertThat(mCompactorUnderTest.mCompactThrottleBFGS).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_5 + 1);
+ assertThat(mCompactorUnderTest.mCompactThrottlePersistent).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_6 + 1);
assertThat(mCompactorUnderTest.mStatsdSampleRate).isEqualTo(
AppCompactor.DEFAULT_STATSD_SAMPLE_RATE + 0.1f);
assertThat(mCompactorUnderTest.mCompactThrottleBFGS).isEqualTo(
AppCompactor.DEFAULT_COMPACT_THROTTLE_5 + 1);
assertThat(mCompactorUnderTest.mCompactThrottlePersistent).isEqualTo(
AppCompactor.DEFAULT_COMPACT_THROTTLE_6 + 1);
+ assertThat(mCompactorUnderTest.mFullAnonRssThrottleKb).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB + 1);
+ assertThat(mCompactorUnderTest.mProcStateThrottle).containsExactly(1, 2, 3);
}
@Test
@@ -321,6 +355,10 @@ public final class AppCompactorTest {
AppCompactor.DEFAULT_COMPACT_THROTTLE_3);
assertThat(mCompactorUnderTest.mCompactThrottleFullFull).isEqualTo(
AppCompactor.DEFAULT_COMPACT_THROTTLE_4);
+ assertThat(mCompactorUnderTest.mCompactThrottleBFGS).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_5);
+ assertThat(mCompactorUnderTest.mCompactThrottlePersistent).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_6);
// Repeat for each of the throttle keys.
mCountDown = new CountDownLatch(1);
@@ -335,6 +373,10 @@ public final class AppCompactorTest {
AppCompactor.DEFAULT_COMPACT_THROTTLE_3);
assertThat(mCompactorUnderTest.mCompactThrottleFullFull).isEqualTo(
AppCompactor.DEFAULT_COMPACT_THROTTLE_4);
+ assertThat(mCompactorUnderTest.mCompactThrottleBFGS).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_5);
+ assertThat(mCompactorUnderTest.mCompactThrottlePersistent).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_6);
mCountDown = new CountDownLatch(1);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
@@ -348,6 +390,10 @@ public final class AppCompactorTest {
AppCompactor.DEFAULT_COMPACT_THROTTLE_3);
assertThat(mCompactorUnderTest.mCompactThrottleFullFull).isEqualTo(
AppCompactor.DEFAULT_COMPACT_THROTTLE_4);
+ assertThat(mCompactorUnderTest.mCompactThrottleBFGS).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_5);
+ assertThat(mCompactorUnderTest.mCompactThrottlePersistent).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_6);
mCountDown = new CountDownLatch(1);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
@@ -361,13 +407,51 @@ public final class AppCompactorTest {
AppCompactor.DEFAULT_COMPACT_THROTTLE_3);
assertThat(mCompactorUnderTest.mCompactThrottleFullFull).isEqualTo(
AppCompactor.DEFAULT_COMPACT_THROTTLE_4);
+ assertThat(mCompactorUnderTest.mCompactThrottleBFGS).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_5);
+ assertThat(mCompactorUnderTest.mCompactThrottlePersistent).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_6);
+
+ mCountDown = new CountDownLatch(1);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ AppCompactor.KEY_COMPACT_THROTTLE_5, "foo", false);
+ assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
+ assertThat(mCompactorUnderTest.mCompactThrottleSomeSome).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_1);
+ assertThat(mCompactorUnderTest.mCompactThrottleSomeFull).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_2);
+ assertThat(mCompactorUnderTest.mCompactThrottleFullSome).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_3);
+ assertThat(mCompactorUnderTest.mCompactThrottleFullFull).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_4);
+ assertThat(mCompactorUnderTest.mCompactThrottleBFGS).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_5);
+ assertThat(mCompactorUnderTest.mCompactThrottlePersistent).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_6);
+
+ mCountDown = new CountDownLatch(1);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ AppCompactor.KEY_COMPACT_THROTTLE_6, "foo", false);
+ assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
+ assertThat(mCompactorUnderTest.mCompactThrottleSomeSome).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_1);
+ assertThat(mCompactorUnderTest.mCompactThrottleSomeFull).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_2);
+ assertThat(mCompactorUnderTest.mCompactThrottleFullSome).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_3);
+ assertThat(mCompactorUnderTest.mCompactThrottleFullFull).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_4);
+ assertThat(mCompactorUnderTest.mCompactThrottleBFGS).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_5);
+ assertThat(mCompactorUnderTest.mCompactThrottlePersistent).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_THROTTLE_6);
}
@Test
public void statsdSampleRate_listensToDeviceConfigChanges() throws InterruptedException {
mCompactorUnderTest.init();
- // When we override mStatsdSampleRate with a reasonable values ...
+ // When we override mStatsdSampleRate with a reasonable value ...
mCountDown = new CountDownLatch(1);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
AppCompactor.KEY_COMPACT_STATSD_SAMPLE_RATE,
@@ -380,11 +464,11 @@ public final class AppCompactorTest {
}
@Test
- public void statsdSanokeRate_listensToDeviceConfigChangesBadValues()
+ public void statsdSampleRate_listensToDeviceConfigChangesBadValues()
throws InterruptedException {
mCompactorUnderTest.init();
- // When we override mStatsdSampleRate with a reasonable values ...
+ // When we override mStatsdSampleRate with an unreasonable value ...
mCountDown = new CountDownLatch(1);
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
AppCompactor.KEY_COMPACT_STATSD_SAMPLE_RATE, "foo", false);
@@ -396,7 +480,7 @@ public final class AppCompactorTest {
}
@Test
- public void statsdSanokeRate_listensToDeviceConfigChangesOutOfRangeValues()
+ public void statsdSampleRate_listensToDeviceConfigChangesOutOfRangeValues()
throws InterruptedException {
mCompactorUnderTest.init();
@@ -420,6 +504,147 @@ public final class AppCompactorTest {
assertThat(mCompactorUnderTest.mStatsdSampleRate).isEqualTo(1.0f);
}
+ @Test
+ public void fullCompactionRssThrottleKb_listensToDeviceConfigChanges()
+ throws InterruptedException {
+ mCompactorUnderTest.init();
+
+ // When we override mStatsdSampleRate with a reasonable value ...
+ mCountDown = new CountDownLatch(1);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ AppCompactor.KEY_COMPACT_FULL_RSS_THROTTLE_KB,
+ Long.toString(AppCompactor.DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB + 1), false);
+ assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
+
+ // Then that override is reflected in the compactor.
+ assertThat(mCompactorUnderTest.mFullAnonRssThrottleKb).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB + 1);
+ }
+
+ @Test
+ public void fullCompactionRssThrottleKb_listensToDeviceConfigChangesBadValues()
+ throws InterruptedException {
+ mCompactorUnderTest.init();
+
+ // When we override mStatsdSampleRate with an unreasonable value ...
+ mCountDown = new CountDownLatch(1);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ AppCompactor.KEY_COMPACT_FULL_RSS_THROTTLE_KB, "foo", false);
+ assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
+
+ // Then that override is reflected in the compactor.
+ assertThat(mCompactorUnderTest.mFullAnonRssThrottleKb).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB);
+
+ mCountDown = new CountDownLatch(1);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ AppCompactor.KEY_COMPACT_FULL_RSS_THROTTLE_KB, "-100", false);
+ assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
+
+ // Then that override is reflected in the compactor.
+ assertThat(mCompactorUnderTest.mFullAnonRssThrottleKb).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_FULL_RSS_THROTTLE_KB);
+ }
+
+ @Test
+ public void fullCompactionDeltaRssThrottleKb_listensToDeviceConfigChanges()
+ throws InterruptedException {
+ mCompactorUnderTest.init();
+
+ // When we override mStatsdSampleRate with a reasonable value ...
+ mCountDown = new CountDownLatch(1);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ AppCompactor.KEY_COMPACT_FULL_DELTA_RSS_THROTTLE_KB,
+ Long.toString(AppCompactor.DEFAULT_COMPACT_FULL_DELTA_RSS_THROTTLE_KB + 1), false);
+ assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
+
+ // Then that override is reflected in the compactor.
+ assertThat(mCompactorUnderTest.mFullDeltaRssThrottleKb).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_FULL_DELTA_RSS_THROTTLE_KB + 1);
+ }
+
+ @Test
+ public void fullCompactionDeltaRssThrottleKb_listensToDeviceConfigChangesBadValues()
+ throws InterruptedException {
+ mCompactorUnderTest.init();
+
+ // When we override mStatsdSampleRate with an unreasonable value ...
+ mCountDown = new CountDownLatch(1);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ AppCompactor.KEY_COMPACT_FULL_DELTA_RSS_THROTTLE_KB, "foo", false);
+ assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
+
+ // Then that override is reflected in the compactor.
+ assertThat(mCompactorUnderTest.mFullDeltaRssThrottleKb).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_FULL_DELTA_RSS_THROTTLE_KB);
+
+ mCountDown = new CountDownLatch(1);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ AppCompactor.KEY_COMPACT_FULL_DELTA_RSS_THROTTLE_KB, "-100", false);
+ assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
+
+ // Then that override is reflected in the compactor.
+ assertThat(mCompactorUnderTest.mFullDeltaRssThrottleKb).isEqualTo(
+ AppCompactor.DEFAULT_COMPACT_FULL_DELTA_RSS_THROTTLE_KB);
+ }
+
+ @Test
+ public void procStateThrottle_listensToDeviceConfigChanges()
+ throws InterruptedException {
+ mCompactorUnderTest.init();
+ mCountDown = new CountDownLatch(1);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ AppCompactor.KEY_COMPACT_PROC_STATE_THROTTLE, "1,2,3", false);
+ assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
+ assertThat(mCompactorUnderTest.mProcStateThrottle).containsExactly(1, 2, 3);
+
+ mCountDown = new CountDownLatch(1);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ AppCompactor.KEY_COMPACT_PROC_STATE_THROTTLE, "", false);
+ assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
+ assertThat(mCompactorUnderTest.mProcStateThrottle).isEmpty();
+ }
+
+ @Test
+ public void procStateThrottle_listensToDeviceConfigChangesBadValues()
+ throws InterruptedException {
+ mCompactorUnderTest.init();
+
+ Set<Integer> expected = new HashSet<>();
+ for (String s : TextUtils.split(AppCompactor.DEFAULT_COMPACT_PROC_STATE_THROTTLE, ",")) {
+ expected.add(Integer.parseInt(s));
+ }
+
+ // Not numbers
+ mCountDown = new CountDownLatch(1);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ AppCompactor.KEY_COMPACT_PROC_STATE_THROTTLE, "foo", false);
+ assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
+ assertThat(mCompactorUnderTest.mProcStateThrottle).containsExactlyElementsIn(expected);
+ mCountDown = new CountDownLatch(1);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ AppCompactor.KEY_COMPACT_PROC_STATE_THROTTLE, "1,foo", false);
+ assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
+ assertThat(mCompactorUnderTest.mProcStateThrottle).containsExactlyElementsIn(expected);
+
+ // Empty splits
+ mCountDown = new CountDownLatch(1);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ AppCompactor.KEY_COMPACT_PROC_STATE_THROTTLE, ",", false);
+ assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
+ assertThat(mCompactorUnderTest.mProcStateThrottle).containsExactlyElementsIn(expected);
+ mCountDown = new CountDownLatch(1);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ AppCompactor.KEY_COMPACT_PROC_STATE_THROTTLE, ",,3", false);
+ assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
+ assertThat(mCompactorUnderTest.mProcStateThrottle).containsExactlyElementsIn(expected);
+ mCountDown = new CountDownLatch(1);
+ DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+ AppCompactor.KEY_COMPACT_PROC_STATE_THROTTLE, "1,,3", false);
+ assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
+ assertThat(mCompactorUnderTest.mProcStateThrottle).containsExactlyElementsIn(expected);
+ }
+
private class TestInjector extends Injector {
@Override
public AppOpsService getAppOpsService(File file, Handler handler) {
diff --git a/telephony/java/android/telephony/DataSpecificRegistrationInfo.java b/telephony/java/android/telephony/DataSpecificRegistrationInfo.java
index 465c2b1be3d9..2cb369d28029 100644
--- a/telephony/java/android/telephony/DataSpecificRegistrationInfo.java
+++ b/telephony/java/android/telephony/DataSpecificRegistrationInfo.java
@@ -78,7 +78,7 @@ public final class DataSpecificRegistrationInfo implements Parcelable {
*
* @hide
*/
- public final boolean isUsingCarrierAggregation;
+ public boolean mIsUsingCarrierAggregation;
/**
* @hide
@@ -92,7 +92,7 @@ public final class DataSpecificRegistrationInfo implements Parcelable {
this.isNrAvailable = isNrAvailable;
this.isEnDcAvailable = isEnDcAvailable;
this.mLteVopsSupportInfo = lteVops;
- this.isUsingCarrierAggregation = isUsingCarrierAggregation;
+ this.mIsUsingCarrierAggregation = isUsingCarrierAggregation;
}
private DataSpecificRegistrationInfo(Parcel source) {
@@ -101,7 +101,7 @@ public final class DataSpecificRegistrationInfo implements Parcelable {
isNrAvailable = source.readBoolean();
isEnDcAvailable = source.readBoolean();
mLteVopsSupportInfo = LteVopsSupportInfo.CREATOR.createFromParcel(source);
- isUsingCarrierAggregation = source.readBoolean();
+ mIsUsingCarrierAggregation = source.readBoolean();
}
@Override
@@ -111,7 +111,7 @@ public final class DataSpecificRegistrationInfo implements Parcelable {
dest.writeBoolean(isNrAvailable);
dest.writeBoolean(isEnDcAvailable);
mLteVopsSupportInfo.writeToParcel(dest, flags);
- dest.writeBoolean(isUsingCarrierAggregation);
+ dest.writeBoolean(mIsUsingCarrierAggregation);
}
@Override
@@ -128,7 +128,7 @@ public final class DataSpecificRegistrationInfo implements Parcelable {
.append(" isNrAvailable = " + isNrAvailable)
.append(" isEnDcAvailable = " + isEnDcAvailable)
.append(" " + mLteVopsSupportInfo.toString())
- .append(" isUsingCarrierAggregation = " + isUsingCarrierAggregation)
+ .append(" mIsUsingCarrierAggregation = " + mIsUsingCarrierAggregation)
.append(" }")
.toString();
}
@@ -136,7 +136,7 @@ public final class DataSpecificRegistrationInfo implements Parcelable {
@Override
public int hashCode() {
return Objects.hash(maxDataCalls, isDcNrRestricted, isNrAvailable, isEnDcAvailable,
- mLteVopsSupportInfo, isUsingCarrierAggregation);
+ mLteVopsSupportInfo, mIsUsingCarrierAggregation);
}
@Override
@@ -151,7 +151,7 @@ public final class DataSpecificRegistrationInfo implements Parcelable {
&& this.isNrAvailable == other.isNrAvailable
&& this.isEnDcAvailable == other.isEnDcAvailable
&& this.mLteVopsSupportInfo.equals(other.mLteVopsSupportInfo)
- && this.isUsingCarrierAggregation == other.isUsingCarrierAggregation;
+ && this.mIsUsingCarrierAggregation == other.mIsUsingCarrierAggregation;
}
public static final @NonNull Parcelable.Creator<DataSpecificRegistrationInfo> CREATOR =
@@ -174,4 +174,22 @@ public final class DataSpecificRegistrationInfo implements Parcelable {
public LteVopsSupportInfo getLteVopsSupportInfo() {
return mLteVopsSupportInfo;
}
+
+ /**
+ * Set the flag indicating if using carrier aggregation.
+ *
+ * @param isUsingCarrierAggregation {@code true} if using carrier aggregation.
+ * @hide
+ */
+ public void setIsUsingCarrierAggregation(boolean isUsingCarrierAggregation) {
+ mIsUsingCarrierAggregation = isUsingCarrierAggregation;
+ }
+
+ /**
+ * @return {@code true} if using carrier aggregation.
+ * @hide
+ */
+ public boolean isUsingCarrierAggregation() {
+ return mIsUsingCarrierAggregation;
+ }
}
diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java
index 2bb02e7af1e0..7b9f6d5eb8a1 100644
--- a/telephony/java/android/telephony/NetworkRegistrationInfo.java
+++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java
@@ -368,6 +368,13 @@ public final class NetworkRegistrationInfo implements Parcelable {
* @hide
*/
public void setAccessNetworkTechnology(@NetworkType int tech) {
+ if (tech == TelephonyManager.NETWORK_TYPE_LTE_CA) {
+ // For old device backward compatibility support
+ tech = TelephonyManager.NETWORK_TYPE_LTE;
+ if (mDataSpecificInfo != null) {
+ mDataSpecificInfo.setIsUsingCarrierAggregation(true);
+ }
+ }
mAccessNetworkTechnology = tech;
}
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 549c04420ce0..b75e51577fdb 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -2016,7 +2016,16 @@ public class PhoneNumberUtils {
private static boolean isEmergencyNumberInternal(int subId, String number,
String defaultCountryIso,
boolean useExactMatch) {
- return TelephonyManager.getDefault().isEmergencyNumber(number);
+ try {
+ if (useExactMatch) {
+ return TelephonyManager.getDefault().isEmergencyNumber(number);
+ } else {
+ return TelephonyManager.getDefault().isPotentialEmergencyNumber(number);
+ }
+ } catch (RuntimeException ex) {
+ Rlog.e(LOG_TAG, "isEmergencyNumberInternal: RuntimeException: " + ex);
+ }
+ return false;
}
/**
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index a794ba12f202..d2c070593401 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -312,18 +312,6 @@ public class ServiceState implements Parcelable {
private boolean mIsManualNetworkSelection;
private boolean mIsEmergencyOnly;
- /**
- * TODO: remove mRilVoiceRadioTechnology after completely migrate to
- * {@link TelephonyManager.NetworkType}
- */
- @RilRadioTechnology
- private int mRilVoiceRadioTechnology;
- /**
- * TODO: remove mRilDataRadioTechnology after completely migrate to
- * {@link TelephonyManager.NetworkType}
- */
- @RilRadioTechnology
- private int mRilDataRadioTechnology;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private boolean mCssIndicator;
@@ -340,9 +328,6 @@ public class ServiceState implements Parcelable {
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private int mCdmaEriIconMode;
- @UnsupportedAppUsage
- private boolean mIsUsingCarrierAggregation;
-
@FrequencyRange
private int mNrFrequencyRange;
private int mChannelNumber;
@@ -420,8 +405,6 @@ public class ServiceState implements Parcelable {
mDataOperatorAlphaShort = s.mDataOperatorAlphaShort;
mDataOperatorNumeric = s.mDataOperatorNumeric;
mIsManualNetworkSelection = s.mIsManualNetworkSelection;
- mRilVoiceRadioTechnology = s.mRilVoiceRadioTechnology;
- mRilDataRadioTechnology = s.mRilDataRadioTechnology;
mCssIndicator = s.mCssIndicator;
mNetworkId = s.mNetworkId;
mSystemId = s.mSystemId;
@@ -430,7 +413,6 @@ public class ServiceState implements Parcelable {
mCdmaEriIconIndex = s.mCdmaEriIconIndex;
mCdmaEriIconMode = s.mCdmaEriIconMode;
mIsEmergencyOnly = s.mIsEmergencyOnly;
- mIsUsingCarrierAggregation = s.mIsUsingCarrierAggregation;
mChannelNumber = s.mChannelNumber;
mCellBandwidths = s.mCellBandwidths == null ? null :
Arrays.copyOf(s.mCellBandwidths, s.mCellBandwidths.length);
@@ -457,8 +439,6 @@ public class ServiceState implements Parcelable {
mDataOperatorAlphaShort = in.readString();
mDataOperatorNumeric = in.readString();
mIsManualNetworkSelection = in.readInt() != 0;
- mRilVoiceRadioTechnology = in.readInt();
- mRilDataRadioTechnology = in.readInt();
mCssIndicator = (in.readInt() != 0);
mNetworkId = in.readInt();
mSystemId = in.readInt();
@@ -467,7 +447,6 @@ public class ServiceState implements Parcelable {
mCdmaEriIconIndex = in.readInt();
mCdmaEriIconMode = in.readInt();
mIsEmergencyOnly = in.readInt() != 0;
- mIsUsingCarrierAggregation = in.readInt() != 0;
mLteEarfcnRsrpBoost = in.readInt();
mNetworkRegistrationInfos = new ArrayList<>();
in.readList(mNetworkRegistrationInfos, NetworkRegistrationInfo.class.getClassLoader());
@@ -486,8 +465,6 @@ public class ServiceState implements Parcelable {
out.writeString(mDataOperatorAlphaShort);
out.writeString(mDataOperatorNumeric);
out.writeInt(mIsManualNetworkSelection ? 1 : 0);
- out.writeInt(mRilVoiceRadioTechnology);
- out.writeInt(mRilDataRadioTechnology);
out.writeInt(mCssIndicator ? 1 : 0);
out.writeInt(mNetworkId);
out.writeInt(mSystemId);
@@ -496,7 +473,6 @@ public class ServiceState implements Parcelable {
out.writeInt(mCdmaEriIconIndex);
out.writeInt(mCdmaEriIconMode);
out.writeInt(mIsEmergencyOnly ? 1 : 0);
- out.writeInt(mIsUsingCarrierAggregation ? 1 : 0);
out.writeInt(mLteEarfcnRsrpBoost);
out.writeList(mNetworkRegistrationInfos);
out.writeInt(mChannelNumber);
@@ -568,7 +544,7 @@ public class ServiceState implements Parcelable {
@DuplexMode
public int getDuplexMode() {
// only support LTE duplex mode
- if (!isLte(mRilDataRadioTechnology)) {
+ if (!isLte(getRilDataRadioTechnology())) {
return DUPLEX_MODE_UNKNOWN;
}
@@ -850,8 +826,6 @@ public class ServiceState implements Parcelable {
mDataOperatorAlphaShort,
mDataOperatorNumeric,
mIsManualNetworkSelection,
- mRilVoiceRadioTechnology,
- mRilDataRadioTechnology,
mCssIndicator,
mNetworkId,
mSystemId,
@@ -860,7 +834,6 @@ public class ServiceState implements Parcelable {
mCdmaEriIconIndex,
mCdmaEriIconMode,
mIsEmergencyOnly,
- mIsUsingCarrierAggregation,
mLteEarfcnRsrpBoost,
mNetworkRegistrationInfos,
mNrFrequencyRange);
@@ -871,7 +844,7 @@ public class ServiceState implements Parcelable {
if (!(o instanceof ServiceState)) return false;
ServiceState s = (ServiceState) o;
- return (mVoiceRegState == s.mVoiceRegState
+ return mVoiceRegState == s.mVoiceRegState
&& mDataRegState == s.mDataRegState
&& mIsManualNetworkSelection == s.mIsManualNetworkSelection
&& mChannelNumber == s.mChannelNumber
@@ -882,8 +855,6 @@ public class ServiceState implements Parcelable {
&& equalsHandlesNulls(mDataOperatorAlphaLong, s.mDataOperatorAlphaLong)
&& equalsHandlesNulls(mDataOperatorAlphaShort, s.mDataOperatorAlphaShort)
&& equalsHandlesNulls(mDataOperatorNumeric, s.mDataOperatorNumeric)
- && equalsHandlesNulls(mRilVoiceRadioTechnology, s.mRilVoiceRadioTechnology)
- && equalsHandlesNulls(mRilDataRadioTechnology, s.mRilDataRadioTechnology)
&& equalsHandlesNulls(mCssIndicator, s.mCssIndicator)
&& equalsHandlesNulls(mNetworkId, s.mNetworkId)
&& equalsHandlesNulls(mSystemId, s.mSystemId)
@@ -891,7 +862,6 @@ public class ServiceState implements Parcelable {
&& equalsHandlesNulls(mCdmaDefaultRoamingIndicator,
s.mCdmaDefaultRoamingIndicator)
&& mIsEmergencyOnly == s.mIsEmergencyOnly
- && mIsUsingCarrierAggregation == s.mIsUsingCarrierAggregation)
&& (mNetworkRegistrationInfos == null
? s.mNetworkRegistrationInfos == null : s.mNetworkRegistrationInfos != null
&& mNetworkRegistrationInfos.containsAll(s.mNetworkRegistrationInfos))
@@ -1035,27 +1005,27 @@ public class ServiceState implements Parcelable {
.append(", mDataOperatorAlphaShort=").append(mDataOperatorAlphaShort)
.append(", isManualNetworkSelection=").append(mIsManualNetworkSelection)
.append(mIsManualNetworkSelection ? "(manual)" : "(automatic)")
- .append(", mRilVoiceRadioTechnology=").append(mRilVoiceRadioTechnology)
- .append("(" + rilRadioTechnologyToString(mRilVoiceRadioTechnology) + ")")
- .append(", mRilDataRadioTechnology=").append(mRilDataRadioTechnology)
- .append("(" + rilRadioTechnologyToString(mRilDataRadioTechnology) + ")")
+ .append(", getRilVoiceRadioTechnology=").append(getRilVoiceRadioTechnology())
+ .append("(" + rilRadioTechnologyToString(getRilVoiceRadioTechnology()) + ")")
+ .append(", getRilDataRadioTechnology=").append(getRilDataRadioTechnology())
+ .append("(" + rilRadioTechnologyToString(getRilDataRadioTechnology()) + ")")
.append(", mCssIndicator=").append(mCssIndicator ? "supported" : "unsupported")
.append(", mNetworkId=").append(mNetworkId)
.append(", mSystemId=").append(mSystemId)
.append(", mCdmaRoamingIndicator=").append(mCdmaRoamingIndicator)
.append(", mCdmaDefaultRoamingIndicator=").append(mCdmaDefaultRoamingIndicator)
.append(", mIsEmergencyOnly=").append(mIsEmergencyOnly)
- .append(", mIsUsingCarrierAggregation=").append(mIsUsingCarrierAggregation)
+ .append(", isUsingCarrierAggregation=").append(isUsingCarrierAggregation())
.append(", mLteEarfcnRsrpBoost=").append(mLteEarfcnRsrpBoost)
.append(", mNetworkRegistrationInfos=").append(mNetworkRegistrationInfos)
.append(", mNrFrequencyRange=").append(mNrFrequencyRange)
.append("}").toString();
}
- private void setNullState(int state) {
- if (DBG) Rlog.d(LOG_TAG, "[ServiceState] setNullState=" + state);
- mVoiceRegState = state;
- mDataRegState = state;
+ private void init() {
+ if (DBG) Rlog.d(LOG_TAG, "init");
+ mVoiceRegState = STATE_OUT_OF_SERVICE;
+ mDataRegState = STATE_OUT_OF_SERVICE;
mChannelNumber = -1;
mCellBandwidths = new int[0];
mVoiceOperatorAlphaLong = null;
@@ -1065,8 +1035,6 @@ public class ServiceState implements Parcelable {
mDataOperatorAlphaShort = null;
mDataOperatorNumeric = null;
mIsManualNetworkSelection = false;
- mRilVoiceRadioTechnology = 0;
- mRilDataRadioTechnology = 0;
mCssIndicator = false;
mNetworkId = -1;
mSystemId = -1;
@@ -1075,18 +1043,28 @@ public class ServiceState implements Parcelable {
mCdmaEriIconIndex = -1;
mCdmaEriIconMode = -1;
mIsEmergencyOnly = false;
- mIsUsingCarrierAggregation = false;
mLteEarfcnRsrpBoost = 0;
- mNetworkRegistrationInfos = new ArrayList<>();
mNrFrequencyRange = FREQUENCY_RANGE_UNKNOWN;
+ addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
+ .setDomain(NetworkRegistrationInfo.DOMAIN_CS)
+ .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
+ .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN)
+ .build());
+ addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
+ .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
+ .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
+ .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN)
+ .build());
}
public void setStateOutOfService() {
- setNullState(STATE_OUT_OF_SERVICE);
+ init();
}
public void setStateOff() {
- setNullState(STATE_POWER_OFF);
+ init();
+ mVoiceRegState = STATE_POWER_OFF;
+ mDataRegState = STATE_POWER_OFF;
}
public void setState(int state) {
@@ -1304,8 +1282,8 @@ public class ServiceState implements Parcelable {
m.putString("data-operator-alpha-short", mDataOperatorAlphaShort);
m.putString("data-operator-numeric", mDataOperatorNumeric);
m.putBoolean("manual", mIsManualNetworkSelection);
- m.putInt("radioTechnology", mRilVoiceRadioTechnology);
- m.putInt("dataRadioTechnology", mRilDataRadioTechnology);
+ m.putInt("radioTechnology", getRilVoiceRadioTechnology());
+ m.putInt("dataRadioTechnology", getRadioTechnology());
m.putBoolean("cssIndicator", mCssIndicator);
m.putInt("networkId", mNetworkId);
m.putInt("systemId", mSystemId);
@@ -1313,7 +1291,7 @@ public class ServiceState implements Parcelable {
m.putInt("cdmaDefaultRoamingIndicator", mCdmaDefaultRoamingIndicator);
m.putBoolean("emergencyOnly", mIsEmergencyOnly);
m.putBoolean("isDataRoamingFromRegistration", getDataRoamingFromRegistration());
- m.putBoolean("isUsingCarrierAggregation", mIsUsingCarrierAggregation);
+ m.putBoolean("isUsingCarrierAggregation", isUsingCarrierAggregation());
m.putInt("LteEarfcnRsrpBoost", mLteEarfcnRsrpBoost);
m.putInt("ChannelNumber", mChannelNumber);
m.putIntArray("CellBandwidths", mCellBandwidths);
@@ -1323,13 +1301,9 @@ public class ServiceState implements Parcelable {
/** @hide */
@TestApi
public void setRilVoiceRadioTechnology(@RilRadioTechnology int rt) {
- if (rt == RIL_RADIO_TECHNOLOGY_LTE_CA) {
- rt = RIL_RADIO_TECHNOLOGY_LTE;
- }
-
- this.mRilVoiceRadioTechnology = rt;
-
- // sync to network registration state
+ Rlog.e(LOG_TAG, "ServiceState.setRilVoiceRadioTechnology() called. It's encouraged to "
+ + "use addNetworkRegistrationInfo() instead *******");
+ // Sync to network registration state
NetworkRegistrationInfo regState = getNetworkRegistrationInfo(
NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
if (regState == null) {
@@ -1339,24 +1313,18 @@ public class ServiceState implements Parcelable {
.build();
addNetworkRegistrationInfo(regState);
}
- regState.setAccessNetworkTechnology(
- rilRadioTechnologyToNetworkType(mRilVoiceRadioTechnology));
+ regState.setAccessNetworkTechnology(rilRadioTechnologyToNetworkType(rt));
}
+
/** @hide */
@TestApi
public void setRilDataRadioTechnology(@RilRadioTechnology int rt) {
- if (rt == RIL_RADIO_TECHNOLOGY_LTE_CA) {
- rt = RIL_RADIO_TECHNOLOGY_LTE;
- this.mIsUsingCarrierAggregation = true;
- } else {
- this.mIsUsingCarrierAggregation = false;
- }
- this.mRilDataRadioTechnology = rt;
- if (VDBG) Rlog.d(LOG_TAG, "[ServiceState] setRilDataRadioTechnology=" +
- mRilDataRadioTechnology);
-
- // sync to network registration state
+ Rlog.e(LOG_TAG, "ServiceState.setRilDataRadioTechnology() called. It's encouraged to "
+ + "use addNetworkRegistrationInfo() instead *******");
+ // Sync to network registration state. Always write down the WWAN transport. For AP-assisted
+ // mode device, use addNetworkRegistrationInfo() to set the correct transport if RAT
+ // is IWLAN.
NetworkRegistrationInfo regState = getNetworkRegistrationInfo(
NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
@@ -1367,18 +1335,32 @@ public class ServiceState implements Parcelable {
.build();
addNetworkRegistrationInfo(regState);
}
- regState.setAccessNetworkTechnology(
- rilRadioTechnologyToNetworkType(mRilDataRadioTechnology));
+ regState.setAccessNetworkTechnology(rilRadioTechnologyToNetworkType(rt));
}
/** @hide */
public boolean isUsingCarrierAggregation() {
- return mIsUsingCarrierAggregation;
+ NetworkRegistrationInfo nri = getNetworkRegistrationInfo(
+ NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+ if (nri != null) {
+ DataSpecificRegistrationInfo dsri = nri.getDataSpecificInfo();
+ if (dsri != null) {
+ return dsri.isUsingCarrierAggregation();
+ }
+ }
+ return false;
}
/** @hide */
public void setIsUsingCarrierAggregation(boolean ca) {
- mIsUsingCarrierAggregation = ca;
+ NetworkRegistrationInfo nri = getNetworkRegistrationInfo(
+ NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+ if (nri != null) {
+ DataSpecificRegistrationInfo dsri = nri.getDataSpecificInfo();
+ if (dsri != null) {
+ dsri.setIsUsingCarrierAggregation(ca);
+ }
+ }
}
/**
@@ -1435,12 +1417,29 @@ public class ServiceState implements Parcelable {
/** @hide */
@UnsupportedAppUsage
public int getRilVoiceRadioTechnology() {
- return this.mRilVoiceRadioTechnology;
+ NetworkRegistrationInfo wwanRegInfo = getNetworkRegistrationInfo(
+ NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+ if (wwanRegInfo != null) {
+ return networkTypeToRilRadioTechnology(wwanRegInfo.getAccessNetworkTechnology());
+ }
+ return RIL_RADIO_TECHNOLOGY_UNKNOWN;
}
/** @hide */
@UnsupportedAppUsage
public int getRilDataRadioTechnology() {
- return this.mRilDataRadioTechnology;
+ NetworkRegistrationInfo wwanRegInfo = getNetworkRegistrationInfo(
+ NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+ NetworkRegistrationInfo wlanRegInfo = getNetworkRegistrationInfo(
+ NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
+ if (wlanRegInfo != null
+ && wlanRegInfo.getAccessNetworkTechnology() == TelephonyManager.NETWORK_TYPE_IWLAN
+ && wlanRegInfo.getRegistrationState()
+ == NetworkRegistrationInfo.REGISTRATION_STATE_HOME) {
+ return RIL_RADIO_TECHNOLOGY_IWLAN;
+ } else if (wwanRegInfo != null) {
+ return networkTypeToRilRadioTechnology(wwanRegInfo.getAccessNetworkTechnology());
+ }
+ return RIL_RADIO_TECHNOLOGY_UNKNOWN;
}
/**
* @hide
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index f393cba4b8f1..bdd01e2f69fb 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -10861,24 +10861,28 @@ public class TelephonyManager {
}
/**
- * Get whether reboot is required or not after making changes to modem configurations.
+ * Get whether making changes to modem configurations by {@link #switchMultiSimConfig(int)} will
+ * trigger device reboot.
* The modem configuration change refers to switching from single SIM configuration to DSDS
* or the other way around.
- * @Return {@code true} if reboot is required after making changes to modem configurations,
- * otherwise return {@code false}.
*
- * @hide
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} or that the
+ * calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
+ *
+ * @return {@code true} if reboot will be triggered after making changes to modem
+ * configurations, otherwise return {@code false}.
*/
- @SystemApi
- @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- public boolean isRebootRequiredForModemConfigChange() {
+ @RequiresPermission(Manifest.permission.READ_PHONE_STATE)
+ public boolean doesSwitchMultiSimConfigTriggerReboot() {
try {
ITelephony service = getITelephony();
if (service != null) {
- return service.isRebootRequiredForModemConfigChange();
+ return service.doesSwitchMultiSimConfigTriggerReboot(getSubId(),
+ getOpPackageName());
}
} catch (RemoteException e) {
- Log.e(TAG, "isRebootRequiredForModemConfigChange RemoteException", e);
+ Log.e(TAG, "doesSwitchMultiSimConfigTriggerReboot RemoteException", e);
}
return false;
}
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index cde10ea7cd09..96a2514e8ff0 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -485,7 +485,7 @@ public class EuiccManager {
public boolean isEnabled() {
// In the future, this may reach out to IEuiccController (if non-null) to check any dynamic
// restrictions.
- return getIEuiccController() != null;
+ return getIEuiccController() != null && refreshCardIdIfUninitialized();
}
/**
@@ -499,7 +499,7 @@ public class EuiccManager {
*/
@Nullable
public String getEid() {
- if (!refreshCardIdIfUninitialized()) {
+ if (!isEnabled()) {
return null;
}
try {
@@ -522,7 +522,7 @@ public class EuiccManager {
@SystemApi
@RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public int getOtaStatus() {
- if (!refreshCardIdIfUninitialized()) {
+ if (!isEnabled()) {
return EUICC_OTA_STATUS_UNAVAILABLE;
}
try {
@@ -557,7 +557,7 @@ public class EuiccManager {
@RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void downloadSubscription(DownloadableSubscription subscription,
boolean switchAfterDownload, PendingIntent callbackIntent) {
- if (!refreshCardIdIfUninitialized()) {
+ if (!isEnabled()) {
sendUnavailableError(callbackIntent);
return;
}
@@ -619,7 +619,7 @@ public class EuiccManager {
@SystemApi
@RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void continueOperation(Intent resolutionIntent, Bundle resolutionExtras) {
- if (!refreshCardIdIfUninitialized()) {
+ if (!isEnabled()) {
PendingIntent callbackIntent =
resolutionIntent.getParcelableExtra(
EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_RESOLUTION_CALLBACK_INTENT);
@@ -656,7 +656,7 @@ public class EuiccManager {
@RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void getDownloadableSubscriptionMetadata(
DownloadableSubscription subscription, PendingIntent callbackIntent) {
- if (!refreshCardIdIfUninitialized()) {
+ if (!isEnabled()) {
sendUnavailableError(callbackIntent);
return;
}
@@ -686,7 +686,7 @@ public class EuiccManager {
@SystemApi
@RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void getDefaultDownloadableSubscriptionList(PendingIntent callbackIntent) {
- if (!refreshCardIdIfUninitialized()) {
+ if (!isEnabled()) {
sendUnavailableError(callbackIntent);
return;
}
@@ -705,7 +705,7 @@ public class EuiccManager {
*/
@Nullable
public EuiccInfo getEuiccInfo() {
- if (!refreshCardIdIfUninitialized()) {
+ if (!isEnabled()) {
return null;
}
try {
@@ -730,7 +730,7 @@ public class EuiccManager {
*/
@RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void deleteSubscription(int subscriptionId, PendingIntent callbackIntent) {
- if (!refreshCardIdIfUninitialized()) {
+ if (!isEnabled()) {
sendUnavailableError(callbackIntent);
return;
}
@@ -770,7 +770,7 @@ public class EuiccManager {
*/
@RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void switchToSubscription(int subscriptionId, PendingIntent callbackIntent) {
- if (!refreshCardIdIfUninitialized()) {
+ if (!isEnabled()) {
sendUnavailableError(callbackIntent);
return;
}
@@ -796,7 +796,7 @@ public class EuiccManager {
@RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void updateSubscriptionNickname(
int subscriptionId, @Nullable String nickname, @NonNull PendingIntent callbackIntent) {
- if (!refreshCardIdIfUninitialized()) {
+ if (!isEnabled()) {
sendUnavailableError(callbackIntent);
return;
}
@@ -820,7 +820,7 @@ public class EuiccManager {
@SystemApi
@RequiresPermission(Manifest.permission.WRITE_EMBEDDED_SUBSCRIPTIONS)
public void eraseSubscriptions(PendingIntent callbackIntent) {
- if (!refreshCardIdIfUninitialized()) {
+ if (!isEnabled()) {
sendUnavailableError(callbackIntent);
return;
}
@@ -850,7 +850,7 @@ public class EuiccManager {
* @hide
*/
public void retainSubscriptionsForFactoryReset(PendingIntent callbackIntent) {
- if (!refreshCardIdIfUninitialized()) {
+ if (!isEnabled()) {
sendUnavailableError(callbackIntent);
return;
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 8332ffe889f3..c8cd2495bdd9 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1945,10 +1945,10 @@ interface ITelephony {
void switchMultiSimConfig(int numOfSims);
/**
- * Get if reboot is required upon altering modems configurations
+ * Get if altering modems configurations will trigger reboot.
* @hide
*/
- boolean isRebootRequiredForModemConfigChange();
+ boolean doesSwitchMultiSimConfigTriggerReboot(int subId, String callingPackage);
/**
* Get the mapping from logical slots to physical slots.
diff --git a/tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java b/tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java
index fb84611cb662..a83faf34776d 100644
--- a/tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java
+++ b/tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.net.ipmemorystore;
+package com.android.server.connectivity.ipmemorystore;
import static org.junit.Assert.assertEquals;